diff --git a/packages/ui-kit/docs/css-architecture.md b/packages/ui-kit/docs/css-architecture.md new file mode 100644 index 0000000..9038166 --- /dev/null +++ b/packages/ui-kit/docs/css-architecture.md @@ -0,0 +1,364 @@ +# CSS Architecture & Cascade Documentation + +## Overview + +The ui-kit uses a **three-layer CSS architecture** that provides bulletproof theming with +multiple fallback levels. This document explains how the stylesheets interact and how to avoid conflicts. + +## ๐Ÿ—๏ธ Architecture Overview + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ CSS CASCADE FLOW โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ 1. DaisyUI Variables โ†’ --p, --b1, --bc (Source Tokens) โ”‚ +โ”‚ 2. theme.css โ†’ Dynamic Bridge with Fallbacks โ”‚ +โ”‚ 3. globals.css โ†’ Tailwind + Hardcoded Fallbacks โ”‚ +โ”‚ 4. Tailwind Classes โ†’ border, bg-background โ”‚ +โ”‚ 5. Components โ†’ Consistent Theme Variables โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +## ๐Ÿ“ File Structure & Responsibilities + +### `src/theme/theme.css` - Dynamic Bridge + +**Role**: Maps DaisyUI design tokens to Shadcn variables with fallbacks + +**Contains**: + +- โœ… Dynamic variable mappings: `--border: hsl(var(--b2, 0 0% 90%))` +- โœ… Light/dark mode selectors: `:root` and `.dark` +- โœ… Semantic Shadcn naming: `--primary`, `--background`, `--border` + +**Does NOT Contain**: + +- โŒ Tailwind directives (`@tailwind`, `@apply`) +- โŒ Base element styles (`*`, `body`) +- โŒ Hardcoded final fallbacks + +### `src/styles/globals.css` - Foundation & Safety Net + +**Role**: Tailwind setup and hardcoded fallback values + +**Contains**: + +- โœ… Tailwind imports: `@tailwind base`, `@components`, `@utilities` +- โœ… theme.css import: `@import "../theme/theme.css"` +- โœ… Hardcoded fallbacks in `@layer base` +- โœ… Base element styles and utilities + +**Does NOT Contain**: + +- โŒ DaisyUI variable mappings +- โŒ Dynamic `var()` fallbacks +- โŒ Component-specific styles + +## ๐Ÿ”„ CSS Cascade Flow + +### 1. Normal Operation (DaisyUI Present) + +```css +/* DaisyUI provides tokens */ +:root { + --b2: 210 40% 90%; +} + +/* theme.css maps with fallback */ +:root { + --border: hsl(var(--b2, 0 0% 90%)); +} +/* Result: --border = hsl(210 40% 90%) */ + +/* globals.css @layer base defines static fallback */ +@layer base { + :root { + --border: 0 0% 89.8%; + } +} +/* Not used because theme.css already defined it */ + +/* Component uses theme variable */ +.border { + border-color: hsl(var(--border)); +} +/* Result: hsl(210 40% 90%) - themed color! */ +``` + +### 2. Fallback Operation (DaisyUI Missing) + +```css +/* DaisyUI tokens missing */ +/* :root { --b2: undefined; } */ + +/* theme.css fallback activates */ +:root { + --border: hsl(var(--b2, 0 0% 90%)); +} +/* Result: --border = hsl(0 0% 90%) */ + +/* globals.css @layer base still available as backup */ +@layer base { + :root { + --border: 0 0% 89.8%; + } +} +/* Not needed because theme.css fallback worked */ + +/* Component gets fallback color */ +.border { + border-color: hsl(var(--border)); +} +/* Result: hsl(0 0% 90%) - fallback color! */ +``` + +### 3. Emergency Fallback (theme.css Import Fails) + +```css +/* theme.css import fails completely */ +/* @import "../theme/theme.css"; โ† FAILED */ + +/* Only globals.css fallbacks remain */ +@layer base { + :root { + --border: 0 0% 89.8%; + } +} +/* Result: --border = 0 0% 89.8% */ + +/* Component gets emergency fallback */ +.border { + border-color: hsl(var(--border)); +} +/* Result: hsl(0 0% 89.8%) - emergency fallback! */ +``` + +## ๐ŸŽฏ Variable Naming Strategy + +### DaisyUI Source Tokens (Input) + +```css +--p /* Primary color */ +--b1 /* Background level 1 */ +--b2 /* Background level 2 */ +--bc /* Base content (text) */ +``` + +### Shadcn Semantic Variables (Output) + +```css +--primary /* Mapped from --p */ +--background /* Mapped from --b1 */ +--border /* Mapped from --b2 */ +--foreground /* Mapped from --bc */ +``` + +### Component Usage + +```css +/* โœ… Use semantic names in components */ +.card { + background: hsl(var(--background)); + border: 1px solid hsl(var(--border)); + color: hsl(var(--foreground)); +} + +/* โŒ Never use DaisyUI tokens directly */ +.card { + background: hsl(var(--b1)); /* NO! */ +} +``` + +## โš ๏ธ Conflict Prevention Rules + +### Import Order (CRITICAL) + +```css +/* globals.css - NEVER change this order! */ +@import "../theme/theme.css"; /* โ† MUST BE FIRST */ +@tailwind base; /* โ† Static fallbacks */ +@tailwind components; +@tailwind utilities; +``` + +### Variable Definition Rules + +#### theme.css - Dynamic Variables Only + +```css +/* โœ… Correct: Dynamic with fallback */ +--border: hsl(var(--b2, 0 0% 90%)); + +/* โŒ Wrong: Hardcoded value */ +--border: 0 0% 90%; + +/* โŒ Wrong: No fallback */ +--border: hsl(var(--b2)); +``` + +#### globals.css - Static Variables Only + +```css +/* โœ… Correct: Hardcoded in @layer base */ +@layer base { + :root { + --border: 0 0% 89.8%; + } +} + +/* โŒ Wrong: Dynamic fallback */ +@layer base { + :root { + --border: hsl(var(--b2, 0 0% 90%)); + } +} +``` + +### Layer Usage Rules + +```css +/* โœ… theme.css: NO @layer directives */ +:root { + --border: hsl(var(--b2, 0 0% 90%)); +} + +/* โœ… globals.css: Use @layer base for static fallbacks */ +@layer base { + :root { + --border: 0 0% 89.8%; + } +} +``` + +## ๐Ÿงช Testing Strategy + +### 1. Test With DaisyUI + +```css +/* Simulate DaisyUI present */ +:root { + --b2: 210 40% 85%; +} +/* Expected: Components use themed color */ +``` + +### 2. Test Without DaisyUI + +```css +/* Comment out DaisyUI or remove it */ +/* :root { --b2: 210 40% 85%; } */ +/* Expected: Components use theme.css fallbacks */ +``` + +### 3. Test Without theme.css + +```css +/* Comment out theme import */ +/* @import "../theme/theme.css"; */ +/* Expected: Components use globals.css fallbacks */ +``` + +### 4. Visual Tests + +- **Light mode**: Backgrounds should be bright (90%+ lightness) +- **Dark mode**: Backgrounds should be dark (15%- lightness) +- **Borders**: Should NEVER be black (`hsl()` = black) +- **Text**: Should have sufficient contrast + +## ๐Ÿšจ Common Pitfalls & Solutions + +### Pitfall 1: Black Borders + +**Cause**: Missing fallback in variable definition + +```css +/* โŒ Problematic */ +--border: hsl(var(--b2)); /* โ†’ hsl() = black when --b2 missing */ + +/* โœ… Solution */ +--border: hsl(var(--b2, 0 0% 90%)); /* โ†’ fallback prevents black */ +``` + +### Pitfall 2: Variable Conflicts + +**Cause**: Defining same variable in multiple places with different values + +```css +/* โŒ Problematic */ +/* theme.css */ +--border: hsl(var(--b2, 0 0% 90%)); + +/* globals.css (not in @layer) */ +--border: 0 0% 85%; /* Conflicts! */ + +/* โœ… Solution */ +/* theme.css */ +--border: hsl(var(--b2, 0 0% 90%)); + +/* globals.css (in @layer base) */ +@layer base { + --border: 0 0% 89.8%; /* Lower specificity */ +} +``` + +### Pitfall 3: Import Order Issues + +**Cause**: Wrong import order breaks cascade + +```css +/* โŒ Problematic */ +@tailwind base; +@import "../theme/theme.css"; /* Too late! */ + +/* โœ… Solution */ +@import "../theme/theme.css"; /* First! */ +@tailwind base; +``` + +## ๐Ÿ” Debugging CSS Variables + +### Browser DevTools + +1. **Inspect Element** โ†’ Computed Styles +2. Look for CSS variable values +3. Check if they resolve to expected colors +4. Use `hsl()` = black as indicator of missing fallbacks + +### CSS Custom Property Trace + +```css +/* Add temporary debugging */ +.debug-border { + border: 10px solid var(--border); + background: var(--background); + color: var(--foreground); +} +``` + +### Console Commands + +```javascript +// Check variable values +getComputedStyle(document.documentElement).getPropertyValue("--border"); + +// Check if DaisyUI variables exist +getComputedStyle(document.documentElement).getPropertyValue("--b2"); +``` + +## ๐Ÿ“‹ Maintenance Checklist + +When modifying CSS architecture: + +- [ ] โœ… Maintain import order in globals.css +- [ ] โœ… All theme.css variables have fallbacks +- [ ] โœ… globals.css uses @layer base for static fallbacks +- [ ] โœ… No DaisyUI tokens used directly in components +- [ ] โœ… Test with/without DaisyUI loaded +- [ ] โœ… Test light/dark mode switching +- [ ] โœ… No black borders in any scenario +- [ ] โœ… Variable naming follows Shadcn conventions +- [ ] โœ… Documentation updated for new variables + +--- + +**Remember**: The goal is **bulletproof theming** where borders are never black and components always look good, regardless of whether DaisyUI is loaded or theme switching works perfectly. diff --git a/packages/ui-kit/package.json b/packages/ui-kit/package.json index ff85858..5a2d229 100644 --- a/packages/ui-kit/package.json +++ b/packages/ui-kit/package.json @@ -1,6 +1,6 @@ { "name": "@etherisc/ui-kit", - "version": "0.6.1", + "version": "0.7.1", "type": "module", "license": "Apache-2.0", "main": "./dist/index.cjs", diff --git a/packages/ui-kit/src/styles/globals.css b/packages/ui-kit/src/styles/globals.css index b336408..9eca700 100644 --- a/packages/ui-kit/src/styles/globals.css +++ b/packages/ui-kit/src/styles/globals.css @@ -1,3 +1,56 @@ +/* + * ============================================================================= + * GLOBALS.CSS - Tailwind Foundation & Final Fallbacks + * ============================================================================= + * + * PURPOSE: + * This file sets up Tailwind CSS foundation and provides hardcoded fallback + * values as the ultimate safety net when theme.css dynamic mappings fail. + * + * CSS CASCADE POSITION: + * 1. โฌ‡๏ธ Imports theme.css FIRST (dynamic DaisyUI โ†’ Shadcn mappings) + * 2. โœ… THEN applies Tailwind @base layer (hardcoded fallbacks override dynamic) + * 3. โฌ‡๏ธ Then @components and @utilities layers + * + * IMPORT ORDER CRITICAL: + * @import "../theme/theme.css"; โ† MUST BE FIRST! + * @tailwind base; โ† Overwrites with static fallbacks + * + * WHAT THIS FILE DOES: + * - Sets up Tailwind CSS (@tailwind base, components, utilities) + * - Provides hardcoded CSS variable fallbacks in @layer base + * - Applies base styles to HTML elements (*, body) + * - Defines utility overrides for placeholders, etc. + * - Serves as final safety net when dynamic theming fails + * + * WHAT THIS FILE SHOULD NOT CONTAIN: + * โŒ DaisyUI variable mappings (those go in theme.css) + * โŒ Dynamic fallbacks with var() functions + * โŒ Theme switching logic (.dark overrides) + * โŒ Component-specific styles (those go in component files) + * + * VARIABLE HIERARCHY: + * 1. ๐ŸŒˆ DaisyUI variables (--p, --b1) - when available + * 2. ๐ŸŒ‰ theme.css mappings with fallbacks - hsl(var(--b2, 0 0% 90%)) + * 3. ๐Ÿ”’ globals.css @layer base - hardcoded values (THIS FILE) + * + * FALLBACK STRATEGY: + * - Use hardcoded HSL values: --border: 0 0% 89.8% + * - NO var() functions here - these are final fallbacks + * - Values should match theme.css fallbacks for consistency + * - Light/dark mode handled by same variable names in different selectors + * + * CONFLICT PREVENTION: + * ๐Ÿšจ NEVER change the @import order - theme.css MUST come first + * ๐Ÿšจ NEVER use dynamic fallbacks - use hardcoded values only + * ๐Ÿšจ NEVER remove @layer base - required for proper CSS cascade + * โœ… Only define variables that theme.css also defines + * โœ… Values here are STATIC SAFETY NET, theme.css is DYNAMIC BRIDGE + * โœ… Test by temporarily disabling theme.css import + * + * ============================================================================= + */ + /* Import theme variables */ @import "../theme/theme.css"; diff --git a/packages/ui-kit/src/theme/theme.css b/packages/ui-kit/src/theme/theme.css index fa806b9..53a7831 100644 --- a/packages/ui-kit/src/theme/theme.css +++ b/packages/ui-kit/src/theme/theme.css @@ -1,3 +1,49 @@ +/* + * ============================================================================= + * THEME.CSS - DaisyUI โ†” Shadcn CSS Variable Bridge + * ============================================================================= + * + * PURPOSE: + * This file serves as the dynamic bridge between DaisyUI design tokens and + * Shadcn CSS variables, enabling theme switching while providing fallback values. + * + * CSS CASCADE POSITION: + * 1. โœ… IMPORTED FIRST by globals.css + * 2. โฌ‡๏ธ Then Tailwind @base layer applies hardcoded fallbacks + * 3. โฌ‡๏ธ Then Tailwind @components and @utilities + * + * WHAT THIS FILE DOES: + * - Maps DaisyUI variables (--p, --b1, --bc) to Shadcn names (--primary, --background, --foreground) + * - Provides fallback values when DaisyUI variables are missing: hsl(var(--b2, 0 0% 90%)) + * - Handles light/dark mode switching via .dark selector + * - Prevents black borders by ensuring --border always has a value + * + * WHAT THIS FILE SHOULD NOT CONTAIN: + * โŒ Tailwind directives (@tailwind, @apply) + * โŒ Hardcoded final fallback values (those go in globals.css) + * โŒ Base element styles (*, body, etc.) + * โŒ Component-specific styles + * + * VARIABLE NAMING CONVENTION: + * - Use Shadcn naming: --primary, --background, --border, --muted + * - NOT DaisyUI naming: --p, --b1, --bc (those are source tokens) + * + * FALLBACK STRATEGY: + * - Always provide fallback: hsl(var(--source-token, fallback-value)) + * - Fallback values should be reasonable defaults for the semantic meaning + * - Light mode fallbacks: bright backgrounds (90%+), dark text (10%-) + * - Dark mode fallbacks: dark backgrounds (15%-), light text (85%+) + * + * CONFLICT PREVENTION: + * ๐Ÿšจ NEVER override variables defined in globals.css @layer base + * ๐Ÿšจ NEVER use @layer directives here (conflicts with Tailwind) + * ๐Ÿšจ NEVER define variables without fallbacks + * โœ… Always test both with and without DaisyUI loaded + * โœ… Variables here should be DYNAMIC, globals.css should be STATIC + * + * ============================================================================= + */ + :root { /* DaisyUI HSL tokens โ†’ Shadcn variables */ /* Base colors */