kiso 0.5.2.pre → 0.6.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/tailwind/kiso/button.css +12 -3
  3. data/app/assets/tailwind/kiso/checkbox.css +13 -2
  4. data/app/assets/tailwind/kiso/color-mode.css +15 -3
  5. data/app/assets/tailwind/kiso/dashboard.css +97 -44
  6. data/app/assets/tailwind/kiso/dialog.css +39 -5
  7. data/app/assets/tailwind/kiso/engine.css +117 -34
  8. data/app/assets/tailwind/kiso/input-otp.css +24 -4
  9. data/app/assets/tailwind/kiso/palettes/blue.css +14 -5
  10. data/app/assets/tailwind/kiso/palettes/green.css +9 -5
  11. data/app/assets/tailwind/kiso/palettes/orange.css +9 -5
  12. data/app/assets/tailwind/kiso/palettes/violet.css +9 -5
  13. data/app/assets/tailwind/kiso/palettes/zinc.css +11 -7
  14. data/app/assets/tailwind/kiso/radio-group.css +11 -4
  15. data/app/assets/tailwind/kiso/slider.css +25 -6
  16. data/app/assets/tailwind/kiso/tooltip.css +37 -11
  17. data/app/helpers/kiso/app_component_helper.rb +83 -34
  18. data/app/helpers/kiso/component_helper.rb +227 -70
  19. data/app/helpers/kiso/icon_helper.rb +101 -39
  20. data/app/helpers/kiso/theme_helper.rb +50 -9
  21. data/app/helpers/kiso/ui_context_helper.rb +87 -35
  22. data/app/javascript/controllers/kiso/combobox_controller.js +10 -2
  23. data/app/javascript/controllers/kiso/command_controller.js +2 -0
  24. data/app/javascript/controllers/kiso/command_dialog_controller.js +4 -0
  25. data/app/javascript/controllers/kiso/dialog_controller.js +6 -1
  26. data/app/javascript/controllers/kiso/dialog_trigger_controller.js +1 -1
  27. data/app/javascript/controllers/kiso/dropdown_menu_controller.js +23 -5
  28. data/app/javascript/controllers/kiso/index.js +25 -0
  29. data/app/javascript/controllers/kiso/input_otp_controller.js +5 -3
  30. data/app/javascript/controllers/kiso/popover_controller.js +18 -4
  31. data/app/javascript/controllers/kiso/select_controller.js +10 -2
  32. data/app/javascript/controllers/kiso/sidebar_controller.js +26 -4
  33. data/app/javascript/controllers/kiso/slider_controller.js +3 -3
  34. data/app/javascript/controllers/kiso/theme_controller.js +2 -1
  35. data/app/javascript/controllers/kiso/toggle_controller.js +2 -0
  36. data/app/javascript/controllers/kiso/toggle_group_controller.js +3 -0
  37. data/app/javascript/controllers/kiso/tooltip_controller.js +3 -0
  38. data/app/javascript/kiso/utils/focusable.js +14 -0
  39. data/app/javascript/kiso/utils/highlight.js +15 -1
  40. data/app/views/kiso/components/_alert.html.erb +2 -0
  41. data/app/views/kiso/components/_alert_dialog.html.erb +5 -2
  42. data/app/views/kiso/components/_app.html.erb +2 -0
  43. data/app/views/kiso/components/_aspect_ratio.html.erb +1 -0
  44. data/app/views/kiso/components/_avatar.html.erb +6 -2
  45. data/app/views/kiso/components/_button.html.erb +3 -0
  46. data/app/views/kiso/components/_checkbox.html.erb +1 -0
  47. data/app/views/kiso/components/_color_mode_button.html.erb +2 -0
  48. data/app/views/kiso/components/_color_mode_select.html.erb +2 -0
  49. data/app/views/kiso/components/_combobox.html.erb +3 -0
  50. data/app/views/kiso/components/_command.html.erb +2 -0
  51. data/app/views/kiso/components/_dashboard_group.html.erb +4 -0
  52. data/app/views/kiso/components/_dashboard_navbar.html.erb +2 -0
  53. data/app/views/kiso/components/_dashboard_panel.html.erb +1 -0
  54. data/app/views/kiso/components/_dashboard_sidebar.html.erb +2 -0
  55. data/app/views/kiso/components/_dashboard_toolbar.html.erb +2 -0
  56. data/app/views/kiso/components/_dialog.html.erb +3 -0
  57. data/app/views/kiso/components/_dropdown_menu.html.erb +2 -0
  58. data/app/views/kiso/components/_empty.html.erb +2 -0
  59. data/app/views/kiso/components/_field.html.erb +2 -0
  60. data/app/views/kiso/components/_field_group.html.erb +1 -0
  61. data/app/views/kiso/components/_field_set.html.erb +1 -0
  62. data/app/views/kiso/components/_input_group.html.erb +1 -0
  63. data/app/views/kiso/components/_input_otp.html.erb +3 -0
  64. data/app/views/kiso/components/_nav.html.erb +2 -0
  65. data/app/views/kiso/components/_page_card.html.erb +3 -0
  66. data/app/views/kiso/components/_page_header.html.erb +3 -0
  67. data/app/views/kiso/components/_page_section.html.erb +2 -0
  68. data/app/views/kiso/components/_pagination.html.erb +2 -0
  69. data/app/views/kiso/components/_popover.html.erb +3 -0
  70. data/app/views/kiso/components/_select.html.erb +3 -0
  71. data/app/views/kiso/components/_select_native.html.erb +2 -0
  72. data/app/views/kiso/components/_separator.html.erb +2 -0
  73. data/app/views/kiso/components/_skeleton.html.erb +1 -0
  74. data/app/views/kiso/components/_slider.html.erb +4 -0
  75. data/app/views/kiso/components/_spinner.html.erb +2 -0
  76. data/app/views/kiso/components/_stats_card.html.erb +2 -0
  77. data/app/views/kiso/components/_stats_grid.html.erb +1 -0
  78. data/app/views/kiso/components/_switch.html.erb +2 -0
  79. data/app/views/kiso/components/_table.html.erb +2 -0
  80. data/app/views/kiso/components/_textarea.html.erb +3 -0
  81. data/app/views/kiso/components/_toggle.html.erb +2 -0
  82. data/app/views/kiso/components/_toggle_group.html.erb +2 -0
  83. data/app/views/kiso/components/_tooltip.html.erb +3 -0
  84. data/app/views/kiso/components/alert_dialog/_action.html.erb +1 -0
  85. data/app/views/kiso/components/alert_dialog/_cancel.html.erb +1 -0
  86. data/app/views/kiso/components/alert_dialog/_description.html.erb +1 -0
  87. data/app/views/kiso/components/alert_dialog/_title.html.erb +1 -0
  88. data/app/views/kiso/components/avatar/_image.html.erb +1 -0
  89. data/app/views/kiso/components/breadcrumb/_separator.html.erb +3 -0
  90. data/app/views/kiso/components/combobox/_chips.html.erb +3 -0
  91. data/app/views/kiso/components/command/_dialog.html.erb +2 -0
  92. data/app/views/kiso/components/dashboard_sidebar/_collapse.html.erb +2 -0
  93. data/app/views/kiso/components/dialog/_close.html.erb +1 -0
  94. data/app/views/kiso/components/field/_error.html.erb +4 -0
  95. data/app/views/kiso/components/field/_label.html.erb +2 -0
  96. data/app/views/kiso/components/field/_separator.html.erb +3 -0
  97. data/app/views/kiso/components/input_otp/_separator.html.erb +2 -0
  98. data/app/views/kiso/components/input_otp/_slot.html.erb +2 -0
  99. data/app/views/kiso/components/nav/_section.html.erb +4 -0
  100. data/app/views/kiso/components/tooltip/_content.html.erb +2 -0
  101. data/lib/generators/kiso/install/USAGE +23 -0
  102. data/lib/generators/kiso/install/install_generator.rb +91 -0
  103. data/lib/generators/kiso/install/templates/design_system.md.tt +190 -0
  104. data/lib/generators/kiso/install/templates/initializer.rb.tt +40 -0
  105. data/lib/kiso/cli/make.rb +6 -3
  106. data/lib/kiso/cli.rb +10 -0
  107. data/lib/kiso/color_utils.rb +31 -8
  108. data/lib/kiso/configuration.rb +11 -0
  109. data/lib/kiso/engine.rb +9 -2
  110. data/lib/kiso/propshaft_tailwind_stub_filter.rb +9 -2
  111. data/lib/kiso/themes/avatar.rb +40 -6
  112. data/lib/kiso/themes/badge.rb +5 -1
  113. data/lib/kiso/themes/color_mode_button.rb +11 -0
  114. data/lib/kiso/themes/color_mode_select.rb +7 -0
  115. data/lib/kiso/themes/dashboard.rb +28 -0
  116. data/lib/kiso/themes/dropdown_menu.rb +2 -2
  117. data/lib/kiso/themes/input_otp.rb +6 -3
  118. data/lib/kiso/themes/nav.rb +17 -0
  119. data/lib/kiso/themes/pagination.rb +9 -4
  120. data/lib/kiso/themes/shared.rb +27 -7
  121. data/lib/kiso/version.rb +5 -2
  122. metadata +5 -1
@@ -1,7 +1,23 @@
1
- /* Kiso Engine CSS — imported by host apps via tailwindcss-rails engine bundling.
2
- Component CSS files go here for transitions, animations, and pseudo-states
3
- that are awkward to express in ERB. Most styling lives in Ruby theme modules
4
- (lib/kiso/themes/) as computed Tailwind classes. */
1
+ /* ── Kiso Engine CSS ──────────────────────────────────────────────────────────
2
+ Main entry point for Kiso's CSS, imported by host apps via tailwindcss-rails
3
+ engine bundling. This file aggregates:
4
+
5
+ 1. Per-component CSS for transitions, animations, pseudo-states, and layout
6
+ mechanics that ERB partials cannot express (most styling lives in Ruby
7
+ theme modules at lib/kiso/themes/ as computed Tailwind classes).
8
+ 2. Tailwind @source directives so the engine's own class references are
9
+ scanned during the host app's Tailwind build.
10
+ 3. @font-face declarations for the Geist typeface family.
11
+ 4. @theme blocks defining structural tokens (radius, container) and the full
12
+ semantic color system (light + dark mode via .dark class).
13
+ 5. @layer base defaults for <body>.
14
+ ──────────────────────────────────────────────────────────────────────────── */
15
+
16
+ /* === Component CSS Imports ===
17
+ Each file handles CSS-only concerns for a specific component or component
18
+ family: animations, pseudo-element indicators, popover overrides, layout
19
+ grid mechanics, etc. If a component needs no CSS beyond Tailwind utilities,
20
+ it does not have a file here. */
5
21
 
6
22
  @import "./button.css";
7
23
  @import "./checkbox.css";
@@ -13,18 +29,22 @@
13
29
  @import "./slider.css";
14
30
  @import "./tooltip.css";
15
31
 
16
- /* Scan Kiso's own files so host apps don't need to know the gem's internals.
32
+ /* === Tailwind Source Scanning ===
33
+ Tell Tailwind v4 to scan Kiso's own source files for class references.
34
+ Without these, utility classes referenced in ERB partials, helpers, theme
35
+ modules, and presets would not be generated in the host app's CSS output.
17
36
  Paths are relative to THIS file (app/assets/tailwind/kiso/engine.css).
18
- Count carefully — wrong paths fail SILENTLY (classes just won't generate). */
37
+ WARNING: wrong paths fail SILENTLY classes simply won't generate. */
19
38
  @source "../../../views"; /* → app/views */
20
39
  @source "../../../helpers"; /* → app/helpers */
21
40
  @source "../../../../lib/kiso/themes"; /* → lib/kiso/themes */
22
41
  @source "../../../../lib/kiso/presets"; /* → lib/kiso/presets */
23
42
 
24
43
  /* === Geist Font (by Vercel) ===
25
- Self-hosted variable fonts — no CDN dependency.
26
- Licensed under the SIL Open Font License (see OFL.txt).
27
- Host apps can override --font-sans / --font-mono in their own @theme block. */
44
+ Self-hosted variable fonts loaded from the engine's asset pipeline — no CDN
45
+ dependency. Licensed under the SIL Open Font License (see OFL.txt in the
46
+ fonts directory). Host apps can override --font-sans / --font-mono in their
47
+ own @theme block to use a different typeface. */
28
48
 
29
49
  @font-face {
30
50
  font-family: "Geist";
@@ -42,20 +62,61 @@
42
62
  src: url("/kiso/GeistMonoVF.woff2") format("woff2");
43
63
  }
44
64
 
45
- /* Set Geist as the default sans and mono fonts.
46
- Host apps can override by redefining --font-sans / --font-mono. */
65
+ /* Register Geist as the default sans and mono font stacks.
66
+ Using @theme inline so these values are inlined into the generated CSS
67
+ rather than emitted as separate custom properties (reduces output size).
68
+ Host apps can override by redefining --font-sans / --font-mono in their
69
+ own @theme block — Tailwind v4 merges @theme blocks, last definition wins. */
47
70
  @theme inline {
48
71
  --font-sans: "Geist", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
49
72
  --font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
50
73
  }
51
74
 
75
+ /* === Structural Tokens ===
76
+ Framework-level layout primitives that host apps can tune. These are
77
+ namespaced with --kiso- to avoid collisions with Tailwind's own variables.
78
+ Override in the host app's own @theme block:
79
+ @theme { --kiso-radius: 0.5rem; --kiso-container: 64rem; } */
80
+
81
+ @theme {
82
+ /* Base radius unit — the single knob that controls the entire border-radius
83
+ scale. Namespaced as --kiso-radius (our variable) vs --radius-* (Tailwind's
84
+ built-in scale that we override below). */
85
+ --kiso-radius: 0.25rem;
86
+
87
+ /* Maximum content width, used by the Container component. */
88
+ --kiso-container: 80rem;
89
+
90
+ /* Computed radius scale — overrides Tailwind's built-in --radius-* variables
91
+ with values derived from --kiso-radius using the same multiplier system as
92
+ Nuxt UI's --ui-radius. This wires rounded-sm, rounded-md, rounded-lg, etc.
93
+ through our base variable so changing --kiso-radius shifts every component's
94
+ border-radius proportionally.
95
+
96
+ At the default 0.25rem, computed values match Tailwind's defaults exactly,
97
+ making this invisible until a host app changes --kiso-radius. */
98
+ --radius-xs: calc(var(--kiso-radius) * 0.5); /* 0.125rem */
99
+ --radius-sm: var(--kiso-radius); /* 0.25rem */
100
+ --radius-md: calc(var(--kiso-radius) * 1.5); /* 0.375rem */
101
+ --radius-lg: calc(var(--kiso-radius) * 2); /* 0.5rem */
102
+ --radius-xl: calc(var(--kiso-radius) * 3); /* 0.75rem */
103
+ --radius-2xl: calc(var(--kiso-radius) * 4); /* 1rem */
104
+ --radius-3xl: calc(var(--kiso-radius) * 6); /* 1.5rem */
105
+ --radius-4xl: calc(var(--kiso-radius) * 8); /* 2rem */
106
+ }
107
+
52
108
  /* === Semantic Color Tokens ===
53
- Purpose-named tokens that flip in dark mode. Components use bg-primary,
54
- text-foreground, etc. never raw palette shades or dark: prefixes.
109
+ Purpose-named CSS custom properties that flip automatically in dark mode
110
+ (via the .dark class below). Components reference these tokens through
111
+ Tailwind utilities — bg-primary, text-foreground, border-border, etc. —
112
+ and never use raw palette shades or Tailwind dark: prefixes.
55
113
 
56
- Two ways to customize brand colors:
114
+ Each semantic color has a -foreground companion for accessible text pairing:
115
+ bg-primary + text-primary-foreground is always readable.
57
116
 
58
- 1. Define a shade scale (Tailwind-native):
117
+ Host apps can customize brand colors in two ways:
118
+
119
+ 1. Define a shade scale (Tailwind-native approach):
59
120
  @theme {
60
121
  --color-primary-50: oklch(...);
61
122
  --color-primary-500: oklch(...);
@@ -66,10 +127,15 @@
66
127
 
67
128
  2. Override the semantic token directly:
68
129
  @theme { --color-primary: oklch(0.55 0.10 237); }
130
+
131
+ See project/design-system.md for the full token table and compound variant
132
+ formulas that use these tokens.
69
133
  */
70
134
 
71
135
  @theme {
72
- /* Brand / action colors — auto-wire from shade scale, fall back to defaults */
136
+ /* ── Brand / Action Colors ──
137
+ Auto-wire from shade scale (if host defines --color-*-500 etc.),
138
+ falling back to Tailwind's built-in palette colors as defaults. */
73
139
  --color-primary: var(--color-primary-500, var(--color-rose-500));
74
140
  --color-primary-foreground: var(--color-primary-50, white);
75
141
 
@@ -88,31 +154,40 @@
88
154
  --color-error: var(--color-error-500, var(--color-red-600));
89
155
  --color-error-foreground: var(--color-error-50, white);
90
156
 
91
- /* Surface tokens */
92
- --color-background: white;
93
- --color-foreground: var(--color-zinc-950);
157
+ /* ── Surface Tokens ──
158
+ Neutral tokens for page backgrounds, text, borders, and UI chrome.
159
+ These map to Tailwind's zinc scale by default. */
160
+ --color-background: white; /* Page background */
161
+ --color-foreground: var(--color-zinc-950); /* Default text color */
94
162
 
95
- --color-muted: var(--color-zinc-100);
96
- --color-muted-foreground: var(--color-zinc-500);
163
+ --color-muted: var(--color-zinc-100); /* Subdued backgrounds (e.g., table headers) */
164
+ --color-muted-foreground: var(--color-zinc-500); /* Secondary/helper text */
97
165
 
98
- --color-accent: var(--color-zinc-100);
99
- --color-accent-foreground: var(--color-zinc-900);
166
+ --color-accent: var(--color-zinc-100); /* Interactive hover backgrounds */
167
+ --color-accent-foreground: var(--color-zinc-900); /* Text on accent backgrounds */
100
168
 
101
- --color-inverted: var(--color-zinc-900);
102
- --color-inverted-foreground: white;
103
- --color-elevated: var(--color-zinc-100);
104
- --color-accented: var(--color-zinc-300);
169
+ --color-inverted: var(--color-zinc-900); /* Inverse surface (solid neutral variant bg) */
170
+ --color-inverted-foreground: white; /* Text on inverted surface */
171
+ --color-elevated: var(--color-zinc-100); /* Soft/subtle neutral variant background */
172
+ --color-accented: var(--color-zinc-300); /* Subtle neutral variant ring color */
105
173
 
106
- --color-border: var(--color-zinc-200);
107
- --color-border-accented: var(--color-zinc-300);
174
+ --color-border: var(--color-zinc-200); /* Default borders (cards, inputs) */
175
+ --color-border-accented: var(--color-zinc-300); /* Emphasized borders */
108
176
 
109
- --color-ring: var(--color-zinc-400);
177
+ --color-ring: var(--color-zinc-400); /* Focus rings */
110
178
  }
111
179
 
112
180
  /* === Dark Mode ===
113
- Redefine tokens under .dark components never use dark: prefixes. */
181
+ Redefine every semantic token under .dark so components never need Tailwind
182
+ dark: prefixes. The .dark class is set on <html> by kiso_theme_script (a
183
+ blocking inline script that runs before first paint to avoid FOUC).
184
+
185
+ Brand colors shift from shade 500 → 400 (brighter on dark backgrounds).
186
+ Foreground companions shift from shade 50 → 950 (dark text on bright bg).
187
+ Surface tokens invert: light grays become dark grays, white becomes near-black. */
114
188
 
115
189
  .dark {
190
+ /* ── Brand / Action Colors (dark) ── */
116
191
  --color-primary: var(--color-primary-400, var(--color-rose-400));
117
192
  --color-primary-foreground: var(--color-primary-950, var(--color-zinc-950));
118
193
 
@@ -131,6 +206,7 @@
131
206
  --color-error: var(--color-error-400, var(--color-red-400));
132
207
  --color-error-foreground: var(--color-error-950, var(--color-zinc-950));
133
208
 
209
+ /* ── Surface Tokens (dark) ── */
134
210
  --color-background: var(--color-zinc-950);
135
211
  --color-foreground: var(--color-zinc-50);
136
212
 
@@ -152,9 +228,16 @@
152
228
  }
153
229
 
154
230
  /* === Page Defaults ===
155
- Kiso automatically applies sensible base styles to <body> so host apps
156
- start with the correct colors and rendering. Uses @layer base (lowest
157
- Tailwind priority) utility classes on <body> override automatically. */
231
+ Apply sensible base styles to <body> so host apps start with the correct
232
+ semantic colors and font rendering. Uses @layer base (lowest Tailwind
233
+ priority) so any utility classes on <body> override automatically.
234
+
235
+ - bg-background / text-foreground: wires semantic tokens, auto-flips in
236
+ dark mode without host app doing anything
237
+ - antialiased: subpixel rendering for crisp text
238
+ - font-synthesis-weight: none: prevents browsers from synthesizing bold
239
+ weights for the variable font (Geist handles all weights natively)
240
+ - text-rendering: optimizeLegibility: enables kerning and ligatures */
158
241
 
159
242
  @layer base {
160
243
  body {
@@ -1,4 +1,17 @@
1
- /* InputOTP caret blink animation — the blinking cursor in the active empty slot. */
1
+ /* ── Input OTP ───────────────────────────────────────────────────────────────
2
+ Caret animation and separator-adjacent border-radius for the OTP input
3
+ component (kui(:input_otp)).
4
+
5
+ Why CSS instead of ERB?
6
+ 1. The blinking caret requires a @keyframes animation.
7
+ 2. Separator-adjacent slot rounding requires :has() and adjacent-sibling
8
+ selectors, which cannot be expressed as Tailwind utility classes.
9
+ ──────────────────────────────────────────────────────────────────────────── */
10
+
11
+ /* ── Caret blink animation ─────────────────────────────────────────────────
12
+ A blinking cursor shown in the active (focused, empty) OTP slot. Registered
13
+ as a Tailwind animation token via @theme inline so it can be applied with
14
+ the `animate-caret-blink` utility class in the theme module. */
2
15
 
3
16
  @theme inline {
4
17
  --animate-caret-blink: caret-blink 1s ease-out infinite;
@@ -9,9 +22,16 @@
9
22
  20%, 50% { opacity: 0; }
10
23
  }
11
24
 
12
- /* Separator-adjacent rounding — when a separator sits inside a group,
13
- round the slot edges next to it so each visual cluster has proper corners.
14
- Also reset the negative margin so the slot after a separator starts fresh. */
25
+ /* ── Separator-adjacent slot rounding ──────────────────────────────────────
26
+ OTP slots are visually joined (negative margin, no individual rounding) to
27
+ form a continuous row. When a separator element sits between slots, the
28
+ slots on either side of it need rounded corners to form distinct visual
29
+ groups. The :has() selector rounds the right edge of the slot before a
30
+ separator, and the adjacent-sibling selector rounds the left edge of the
31
+ slot after a separator (and resets its negative margin).
32
+
33
+ Uses @layer utilities so these rules participate in Tailwind's specificity
34
+ layer, matching the border-radius utilities used on the first/last slots. */
15
35
 
16
36
  @layer utilities {
17
37
  [data-slot="input-otp-slot"]:has(+ [data-slot="input-otp-separator"]) {
@@ -1,21 +1,29 @@
1
- /* Kiso Color Palette: Blue
1
+ /* ── Kiso Color Palette: Blue ─────────────────────────────────────────────────
2
2
  A professional blue palette — classic SaaS/enterprise feel.
3
3
  Based on shadcn/ui's Blue theme with OKLCH color values.
4
4
 
5
+ Palettes override Kiso's default semantic color tokens (defined in engine.css)
6
+ using a [data-palette] attribute selector. This lets host apps switch color
7
+ schemes without redefining @theme variables.
8
+
5
9
  Usage:
6
- 1. Import in your CSS: @import "../builds/tailwind/kiso/palettes/blue.css";
10
+ 1. Import in your Tailwind CSS: @import "kiso/palettes/blue.css";
7
11
  2. Add to your HTML: <html data-palette="blue"> or <body data-palette="blue">
8
- */
12
+
13
+ Dark mode is handled by a companion rule below that targets either
14
+ `.dark [data-palette="blue"]` (dark class on an ancestor) or
15
+ `[data-palette="blue"].dark` (dark class on the same element).
16
+ ──────────────────────────────────────────────────────────────────────────── */
9
17
 
10
18
  [data-palette="blue"] {
11
- /* Brand / action colors — vibrant blue */
19
+ /* ── Brand / action colors — vibrant blue ── */
12
20
  --color-primary: oklch(0.488 0.243 264.376);
13
21
  --color-primary-foreground: oklch(0.97 0.014 254.604);
14
22
 
15
23
  --color-secondary: oklch(0.967 0.001 286.375);
16
24
  --color-secondary-foreground: oklch(0.21 0.006 285.885);
17
25
 
18
- /* Surface tokens — slate-tinted neutrals */
26
+ /* ── Surface tokens — slate-tinted neutrals ── */
19
27
  --color-background: oklch(1 0 0);
20
28
  --color-foreground: oklch(0.13 0.028 261.692);
21
29
 
@@ -36,6 +44,7 @@
36
44
  --color-ring: oklch(0.488 0.243 264.376);
37
45
  }
38
46
 
47
+ /* Dark mode overrides */
39
48
  .dark [data-palette="blue"],
40
49
  [data-palette="blue"].dark {
41
50
  --color-primary: oklch(0.42 0.18 266);
@@ -1,21 +1,24 @@
1
- /* Kiso Color Palette: Green
1
+ /* ── Kiso Color Palette: Green ────────────────────────────────────────────────
2
2
  A fresh, natural green palette — great for eco, health, or finance apps.
3
3
  Based on shadcn/ui's Green theme with OKLCH color values.
4
4
 
5
+ Palettes override Kiso's default semantic color tokens (defined in engine.css)
6
+ using a [data-palette] attribute selector. See blue.css for full documentation.
7
+
5
8
  Usage:
6
- 1. Import in your CSS: @import "../builds/tailwind/kiso/palettes/green.css";
9
+ 1. Import in your Tailwind CSS: @import "kiso/palettes/green.css";
7
10
  2. Add to your HTML: <html data-palette="green"> or <body data-palette="green">
8
- */
11
+ ──────────────────────────────────────────────────────────────────────────── */
9
12
 
10
13
  [data-palette="green"] {
11
- /* Brand / action colors — vivid green */
14
+ /* ── Brand / action colors — vivid green ── */
12
15
  --color-primary: oklch(0.648 0.2 131.684);
13
16
  --color-primary-foreground: oklch(0.986 0.031 120.757);
14
17
 
15
18
  --color-secondary: oklch(0.967 0.001 286.375);
16
19
  --color-secondary-foreground: oklch(0.21 0.006 285.885);
17
20
 
18
- /* Surface tokens — zinc neutrals */
21
+ /* ── Surface tokens — zinc neutrals ── */
19
22
  --color-background: oklch(1 0 0);
20
23
  --color-foreground: oklch(0.141 0.005 285.823);
21
24
 
@@ -36,6 +39,7 @@
36
39
  --color-ring: oklch(0.648 0.2 131.684);
37
40
  }
38
41
 
42
+ /* Dark mode overrides */
39
43
  .dark [data-palette="green"],
40
44
  [data-palette="green"].dark {
41
45
  --color-primary: oklch(0.648 0.2 131.684);
@@ -1,21 +1,24 @@
1
- /* Kiso Color Palette: Orange
1
+ /* ── Kiso Color Palette: Orange ───────────────────────────────────────────────
2
2
  A warm, energetic palette — great for creative, food, or community apps.
3
3
  Based on shadcn/ui's Orange theme with OKLCH color values.
4
4
 
5
+ Palettes override Kiso's default semantic color tokens (defined in engine.css)
6
+ using a [data-palette] attribute selector. See blue.css for full documentation.
7
+
5
8
  Usage:
6
- 1. Import in your CSS: @import "../builds/tailwind/kiso/palettes/orange.css";
9
+ 1. Import in your Tailwind CSS: @import "kiso/palettes/orange.css";
7
10
  2. Add to your HTML: <html data-palette="orange"> or <body data-palette="orange">
8
- */
11
+ ──────────────────────────────────────────────────────────────────────────── */
9
12
 
10
13
  [data-palette="orange"] {
11
- /* Brand / action colors — warm orange */
14
+ /* ── Brand / action colors — warm orange ── */
12
15
  --color-primary: oklch(0.646 0.222 41.116);
13
16
  --color-primary-foreground: oklch(0.98 0.016 73.684);
14
17
 
15
18
  --color-secondary: oklch(0.97 0.001 106.424);
16
19
  --color-secondary-foreground: oklch(0.216 0.006 56.043);
17
20
 
18
- /* Surface tokens — warm stone neutrals */
21
+ /* ── Surface tokens — warm stone neutrals ── */
19
22
  --color-background: oklch(1 0 0);
20
23
  --color-foreground: oklch(0.147 0.004 49.25);
21
24
 
@@ -36,6 +39,7 @@
36
39
  --color-ring: oklch(0.646 0.222 41.116);
37
40
  }
38
41
 
42
+ /* Dark mode overrides */
39
43
  .dark [data-palette="orange"],
40
44
  [data-palette="orange"].dark {
41
45
  --color-primary: oklch(0.705 0.213 47.604);
@@ -1,21 +1,24 @@
1
- /* Kiso Color Palette: Violet
1
+ /* ── Kiso Color Palette: Violet ───────────────────────────────────────────────
2
2
  A rich, creative purple palette — great for design tools or premium brands.
3
3
  Based on shadcn/ui's Violet theme with OKLCH color values.
4
4
 
5
+ Palettes override Kiso's default semantic color tokens (defined in engine.css)
6
+ using a [data-palette] attribute selector. See blue.css for full documentation.
7
+
5
8
  Usage:
6
- 1. Import in your CSS: @import "../builds/tailwind/kiso/palettes/violet.css";
9
+ 1. Import in your Tailwind CSS: @import "kiso/palettes/violet.css";
7
10
  2. Add to your HTML: <html data-palette="violet"> or <body data-palette="violet">
8
- */
11
+ ──────────────────────────────────────────────────────────────────────────── */
9
12
 
10
13
  [data-palette="violet"] {
11
- /* Brand / action colors — vivid violet */
14
+ /* ── Brand / action colors — vivid violet ── */
12
15
  --color-primary: oklch(0.541 0.281 293.009);
13
16
  --color-primary-foreground: oklch(0.969 0.016 293.756);
14
17
 
15
18
  --color-secondary: oklch(0.967 0.001 286.375);
16
19
  --color-secondary-foreground: oklch(0.21 0.006 285.885);
17
20
 
18
- /* Surface tokens — gray neutrals */
21
+ /* ── Surface tokens — gray neutrals ── */
19
22
  --color-background: oklch(1 0 0);
20
23
  --color-foreground: oklch(0.13 0.028 261.692);
21
24
 
@@ -36,6 +39,7 @@
36
39
  --color-ring: oklch(0.541 0.281 293.009);
37
40
  }
38
41
 
42
+ /* Dark mode overrides */
39
43
  .dark [data-palette="violet"],
40
44
  [data-palette="violet"].dark {
41
45
  --color-primary: oklch(0.606 0.25 292.717);
@@ -1,21 +1,24 @@
1
- /* Kiso Color Palette: Zinc
2
- A neutral, cool-toned palette using the Zinc scale.
3
- Based on shadcn/ui's Zinc theme with OKLCH color values.
1
+ /* ── Kiso Color Palette: Zinc ─────────────────────────────────────────────────
2
+ A neutral, cool-toned palette using the Zinc scale — minimal color,
3
+ maximum content focus. Based on shadcn/ui's Zinc theme with OKLCH values.
4
+
5
+ Palettes override Kiso's default semantic color tokens (defined in engine.css)
6
+ using a [data-palette] attribute selector. See blue.css for full documentation.
4
7
 
5
8
  Usage:
6
- 1. Import in your CSS: @import "../builds/tailwind/kiso/palettes/zinc.css";
9
+ 1. Import in your Tailwind CSS: @import "kiso/palettes/zinc.css";
7
10
  2. Add to your HTML: <html data-palette="zinc"> or <body data-palette="zinc">
8
- */
11
+ ──────────────────────────────────────────────────────────────────────────── */
9
12
 
10
13
  [data-palette="zinc"] {
11
- /* Brand / action colors — zinc primary (near-black in light, near-white in dark) */
14
+ /* ── Brand / action colors — near-black primary (inverts in dark mode) ── */
12
15
  --color-primary: oklch(0.21 0.006 285.885);
13
16
  --color-primary-foreground: oklch(0.985 0 0);
14
17
 
15
18
  --color-secondary: oklch(0.967 0.001 286.375);
16
19
  --color-secondary-foreground: oklch(0.21 0.006 285.885);
17
20
 
18
- /* Surface tokens */
21
+ /* ── Surface tokens ── */
19
22
  --color-background: oklch(1 0 0);
20
23
  --color-foreground: oklch(0.141 0.005 285.823);
21
24
 
@@ -36,6 +39,7 @@
36
39
  --color-ring: oklch(0.705 0.015 286.067);
37
40
  }
38
41
 
42
+ /* Dark mode overrides */
39
43
  .dark [data-palette="zinc"],
40
44
  [data-palette="zinc"].dark {
41
45
  --color-primary: oklch(0.92 0.004 286.32);
@@ -1,7 +1,14 @@
1
- /* RadioGroupItem indicator CSS ::after for the filled circle dot since
2
- native <input type="radio"> can't contain child elements. Uses currentColor
3
- which inherits from checked:text-{color}-foreground set by compound variants.
4
- Follows the same pattern as Checkbox (mask-image with currentColor). */
1
+ /* ── Radio Group ─────────────────────────────────────────────────────────────
2
+ Filled-circle indicator via CSS ::after pseudo-element for radio inputs.
3
+
4
+ Why CSS instead of ERB?
5
+ Native <input type="radio"> cannot contain child elements, so the selected
6
+ indicator dot must be rendered as a pseudo-element. Same pattern as
7
+ Checkbox — uses currentColor for the fill, which inherits the text color
8
+ set by compound variants (e.g., checked:text-primary-foreground).
9
+
10
+ The grid + place-content: center pattern centers the ::after dot within
11
+ the radio circle regardless of its size variant. */
5
12
 
6
13
  [data-radio-group-part="item"] {
7
14
  display: grid;
@@ -1,25 +1,44 @@
1
+ /* ── Slider ──────────────────────────────────────────────────────────────────
2
+ Thumb positioning and disabled state for the custom Slider component.
3
+
4
+ Why CSS instead of ERB?
5
+ The slider thumb is positioned via inline `left: N%` styles set by the
6
+ kiso--slider Stimulus controller. CSS handles the centering transform
7
+ (translateX(-50%)) and vertical alignment that must work in concert with
8
+ that dynamic inline style. The disabled state uses :has(input:disabled)
9
+ which cannot be expressed as a Tailwind utility.
10
+
11
+ Uses @layer components so utility classes can override if needed.
12
+ ──────────────────────────────────────────────────────────────────────────── */
13
+
1
14
  @layer components {
2
- /* Center the thumb over its left % position */
15
+ /* Center the thumb horizontally over its left % position, and vertically
16
+ within the track. The negative margin-top pulls the thumb up by half
17
+ its own height (--thumb-offset) so it sits centered on the track line. */
3
18
  [data-slot="slider-thumb"] {
4
19
  transform: translateX(-50%);
5
20
  top: 50%;
6
21
  margin-top: calc(-1 * var(--thumb-offset, 0.5rem));
7
22
  }
8
23
 
9
- /* Size-specific thumb offsets (half the thumb size) */
24
+ /* Size-specific thumb offsets each size variant has a different thumb
25
+ diameter, so the vertical centering offset must match. Uses :where()
26
+ to keep specificity low (0,0,0 for the class selector), allowing
27
+ the theme module's size classes to remain the authority on thumb size. */
10
28
  [data-slot="slider"] :where([data-slot="slider-thumb"].size-3) {
11
- --thumb-offset: 0.375rem;
29
+ --thumb-offset: 0.375rem; /* half of 0.75rem (size-3) */
12
30
  }
13
31
 
14
32
  [data-slot="slider"] :where([data-slot="slider-thumb"].size-4) {
15
- --thumb-offset: 0.5rem;
33
+ --thumb-offset: 0.5rem; /* half of 1rem (size-4) */
16
34
  }
17
35
 
18
36
  [data-slot="slider"] :where([data-slot="slider-thumb"].size-5) {
19
- --thumb-offset: 0.625rem;
37
+ --thumb-offset: 0.625rem; /* half of 1.25rem (size-5) */
20
38
  }
21
39
 
22
- /* Disabled state */
40
+ /* Disabled state — dim the entire slider and prevent interaction.
41
+ Uses :has(input:disabled) to detect the hidden range input's state. */
23
42
  [data-slot="slider"]:has(input:disabled) {
24
43
  opacity: 0.5;
25
44
  pointer-events: none;
@@ -1,33 +1,57 @@
1
- /* Tooltip entry/exit animations and arrow positioning. */
1
+ /* ── Tooltip ─────────────────────────────────────────────────────────────────
2
+ Display overrides, popover UA stylesheet resets, entry/exit animations,
3
+ and reduced-motion support for the Tooltip component.
2
4
 
3
- /* Tooltip root inline-flex via @layer components so utilities can override */
5
+ Why CSS instead of ERB?
6
+ Tooltips use [popover="manual"] for positioning (via Floating UI) and need
7
+ CSS to work around browser UA stylesheet conflicts, animate entry/exit,
8
+ and handle the :popover-open pseudo-class. None of this can be expressed
9
+ as Tailwind utility classes.
10
+
11
+ Key browser issue: the UA stylesheet hides [popover]:not(:popover-open)
12
+ with display: none in the UA layer. But Tailwind's `flex` utility class
13
+ (in the author layer) has higher specificity and overrides it, making
14
+ non-open popovers visible. We fix this with an explicit author-layer rule.
15
+ See MEMORY.md for the full explanation.
16
+ ──────────────────────────────────────────────────────────────────────────── */
17
+
18
+ /* ── Root display ──────────────────────────────────────────────────────────
19
+ Same pattern as Button: @layer components so utility classes can override. */
4
20
  @layer components {
5
21
  [data-slot="tooltip"] {
6
22
  display: inline-flex;
7
23
  }
8
24
  }
9
25
 
10
- /* The browser UA stylesheet hides [popover]:not(:popover-open) with
11
- display: none, but Tailwind's `flex` utility (author layer) overrides it.
12
- Explicitly enforce hidden state for non-open popovers. */
26
+ /* ── Popover UA stylesheet overrides ──────────────────────────────────────
27
+ Two browser UA stylesheet behaviors must be explicitly overridden:
28
+
29
+ 1. Hidden state: the UA hides non-open popovers with display: none, but
30
+ Tailwind's `flex` utility (author layer) overrides the UA layer. This
31
+ rule enforces hidden state in the author layer to match the UA intent.
32
+
33
+ 2. Positioning reset: browsers apply inset: 0, margin: auto, and
34
+ width/height: fit-content to :popover-open elements, which fights
35
+ Floating UI's inline positioning styles. We reset inset and margin
36
+ so Floating UI has full control over placement. */
13
37
  [data-slot="tooltip-content"]:not(:popover-open) {
14
38
  display: none;
15
39
  }
16
40
 
17
- /* Reset UA popover styles — browsers apply inset: 0, margin: auto, and
18
- width/height: fit-content to [popover]:popover-open, which overrides
19
- Floating UI's inline-style positioning. */
20
41
  [data-slot="tooltip-content"] {
21
42
  inset: unset;
22
43
  margin: 0;
23
44
  }
24
45
 
25
- /* Entry animation — fade + scale from 95% */
46
+ /* ── Entry/exit animations ────────────────────────────────────────────────
47
+ data-state is set by the kiso--tooltip Stimulus controller:
48
+ - "open" on show (after showPopover()) → fade in + scale up from 95%
49
+ - "closed" on hide (before hidePopover()) → fade out + scale down to 95%
50
+ with `forwards` fill to hold opacity: 0 until hidePopover() removes it */
26
51
  [data-slot="tooltip-content"][data-state="open"] {
27
52
  animation: kiso-tooltip-in 150ms ease-out;
28
53
  }
29
54
 
30
- /* Exit animation — fade out + scale to 95% */
31
55
  [data-slot="tooltip-content"][data-state="closed"] {
32
56
  animation: kiso-tooltip-out 100ms ease-in forwards;
33
57
  }
@@ -39,7 +63,9 @@
39
63
  to { opacity: 0; transform: scale(0.95); }
40
64
  }
41
65
 
42
- /* Respect reduced motion */
66
+ /* ── Reduced motion ───────────────────────────────────────────────────────
67
+ Disable animations for users who prefer reduced motion. The tooltip will
68
+ still appear/disappear, just without the fade/scale transition. */
43
69
  @media (prefers-reduced-motion: reduce) {
44
70
  [data-slot="tooltip-content"][data-state="open"],
45
71
  [data-slot="tooltip-content"][data-state="closed"] {