@rokkit/themes 1.0.0-next.132 → 1.0.0-next.135

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 (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +68 -80
  3. package/build.mjs +148 -150
  4. package/dist/base.css +689 -623
  5. package/dist/glass.css +212 -203
  6. package/dist/index.css +1464 -1257
  7. package/dist/material.css +203 -171
  8. package/dist/minimal.css +171 -147
  9. package/dist/rokkit.css +189 -113
  10. package/package.json +11 -4
  11. package/src/base/breadcrumbs.css +28 -28
  12. package/src/base/button.css +10 -3
  13. package/src/base/card.css +17 -17
  14. package/src/base/carousel.css +67 -67
  15. package/src/base/display.css +8 -8
  16. package/src/base/floating-navigation.css +32 -8
  17. package/src/base/graph-paper.css +49 -49
  18. package/src/base/pill.css +35 -35
  19. package/src/base/progress.css +21 -21
  20. package/src/base/range.css +57 -57
  21. package/src/base/rating.css +20 -18
  22. package/src/base/reveal.css +16 -16
  23. package/src/base/search-filter.css +61 -61
  24. package/src/base/shine.css +7 -7
  25. package/src/base/stepper.css +75 -75
  26. package/src/base/switch.css +55 -55
  27. package/src/base/table.css +49 -49
  28. package/src/base/tilt.css +4 -4
  29. package/src/base/timeline.css +38 -38
  30. package/src/base/tree.css +48 -15
  31. package/src/glass/button.css +11 -10
  32. package/src/glass/card.css +16 -13
  33. package/src/glass/floating-action.css +13 -13
  34. package/src/glass/floating-navigation.css +2 -2
  35. package/src/glass/input.css +32 -30
  36. package/src/glass/list.css +21 -21
  37. package/src/glass/menu.css +16 -16
  38. package/src/glass/range.css +10 -10
  39. package/src/glass/search-filter.css +8 -8
  40. package/src/glass/select.css +32 -32
  41. package/src/glass/switch.css +6 -6
  42. package/src/glass/table.css +14 -14
  43. package/src/glass/tabs.css +3 -3
  44. package/src/glass/timeline.css +8 -8
  45. package/src/glass/toggle.css +7 -7
  46. package/src/glass/toolbar.css +15 -15
  47. package/src/glass/tree.css +27 -21
  48. package/src/material/button.css +12 -8
  49. package/src/material/card.css +1 -1
  50. package/src/material/input.css +30 -14
  51. package/src/material/list.css +27 -23
  52. package/src/material/menu.css +16 -16
  53. package/src/material/range.css +11 -11
  54. package/src/material/search-filter.css +8 -8
  55. package/src/material/select.css +31 -31
  56. package/src/material/switch.css +6 -6
  57. package/src/material/table.css +20 -16
  58. package/src/material/timeline.css +8 -8
  59. package/src/material/toggle.css +7 -7
  60. package/src/material/toolbar.css +17 -16
  61. package/src/material/tree.css +22 -19
  62. package/src/minimal/button.css +7 -4
  63. package/src/minimal/card.css +13 -11
  64. package/src/minimal/floating-action.css +11 -11
  65. package/src/minimal/floating-navigation.css +1 -1
  66. package/src/minimal/input.css +14 -10
  67. package/src/minimal/list.css +27 -23
  68. package/src/minimal/menu.css +15 -15
  69. package/src/minimal/range.css +10 -10
  70. package/src/minimal/search-filter.css +8 -8
  71. package/src/minimal/select.css +4 -2
  72. package/src/minimal/switch.css +6 -6
  73. package/src/minimal/table.css +17 -15
  74. package/src/minimal/tabs.css +5 -3
  75. package/src/minimal/timeline.css +7 -7
  76. package/src/minimal/toggle.css +7 -7
  77. package/src/minimal/toolbar.css +17 -16
  78. package/src/minimal/tree.css +26 -20
  79. package/src/rokkit/button.css +40 -11
  80. package/src/rokkit/card.css +16 -14
  81. package/src/rokkit/floating-navigation.css +2 -2
  82. package/src/rokkit/input.css +10 -6
  83. package/src/rokkit/list.css +7 -2
  84. package/src/rokkit/range.css +11 -11
  85. package/src/rokkit/search-filter.css +8 -8
  86. package/src/rokkit/select.css +41 -36
  87. package/src/rokkit/switch.css +6 -6
  88. package/src/rokkit/table.css +17 -15
  89. package/src/rokkit/tabs.css +11 -6
  90. package/src/rokkit/timeline.css +8 -8
  91. package/src/rokkit/tree.css +35 -9
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Jerry Thomas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,122 +1,110 @@
1
1
  # @rokkit/themes
2
2
 
3
- Theme styles for `@rokkit/ui` headless components.
3
+ Pre-built CSS themes for `@rokkit/ui` components.
4
4
 
5
- ## Architecture
5
+ ## Install
6
6
 
7
- This package follows a **headless component + themed styles** pattern:
7
+ ```sh
8
+ npm install @rokkit/themes
9
+ # or
10
+ bun add @rokkit/themes
11
+ ```
8
12
 
9
- - **Components** (`@rokkit/ui`) - Provide structure, behavior, and accessibility via data attributes
10
- - **Themes** (`@rokkit/themes`) - Provide visual styling that targets those data attributes
13
+ ## Overview
11
14
 
12
- ### Directory Structure
15
+ `@rokkit/themes` provides visual styles for `@rokkit/ui` components. Components in `@rokkit/ui` are unstyled by default — themes layer on top without requiring changes to component markup. Styles target semantic `data-*` attributes that components emit (e.g. `[data-button]`, `[data-list-item]`).
13
16
 
14
- ```
15
- src/
16
- ├── base/ # Structural styles (layout, positioning)
17
- │ ├── index.css # All base styles
18
- └── menu.css # Menu structural styles
19
- ├── rokkit/ # Default theme (gradients + borders)
20
- │ ├── index.css # All rokkit theme styles
21
- │ └── menu.css # Menu themed styles
22
- ├── minimal/ # Clean + subtle theme
23
- ├── material/ # Elevation + shadows theme
24
- ├── glass/ # Blur + transparency theme
25
- └── index.css # Main entry (imports base + all themes)
26
- ```
17
+ Available themes:
18
+
19
+ | Theme | Description |
20
+ | ---------- | -------------------------------------------------------------------- |
21
+ | `rokkit` | Default gradients and glowing borders |
22
+ | `minimal` | Clean and subtle |
23
+ | `material` | Elevation and shadows |
24
+ | `glass` | Blur and transparency |
25
+ | `base` | Structural styles only (layout and positioning, no visual treatment) |
27
26
 
28
27
  ## Usage
29
28
 
30
- ### Full Theme (base + all themes)
29
+ ### Full bundle (base + all themes)
31
30
 
32
- ```ts
33
- import '@rokkit/themes'
31
+ ```css
32
+ @import '@rokkit/themes';
34
33
  ```
35
34
 
36
- ### Base Only (for custom theming)
35
+ Or in JavaScript/TypeScript:
37
36
 
38
- ```ts
39
- import '@rokkit/themes/base'
37
+ ```js
38
+ import '@rokkit/themes'
40
39
  ```
41
40
 
42
- ### Rokkit Theme Only
41
+ ### Single theme
43
42
 
44
- ```ts
45
- import '@rokkit/themes/rokkit'
43
+ ```css
44
+ @import '@rokkit/themes/rokkit.css';
45
+ /* or */
46
+ @import '@rokkit/themes/minimal.css';
47
+ /* or */
48
+ @import '@rokkit/themes/material.css';
49
+ /* or */
50
+ @import '@rokkit/themes/glass.css';
46
51
  ```
47
52
 
48
- ### Individual Component Styles
53
+ ### Base structural styles only
49
54
 
50
- ```ts
51
- import '@rokkit/themes/base/menu.css'
52
- import '@rokkit/themes/rokkit/menu.css'
55
+ ```css
56
+ @import '@rokkit/themes/base';
53
57
  ```
54
58
 
55
- ## Data Attributes
56
-
57
- Components use semantic data attributes for styling hooks:
58
-
59
- ### Common Attributes
59
+ Useful when writing a fully custom theme — imports layout and positioning rules without any visual styling.
60
60
 
61
- | Attribute | Values | Description |
62
- | --------------- | ---------------- | -------------- |
63
- | `data-size` | `sm`, `md`, `lg` | Size variant |
64
- | `data-disabled` | `true` | Disabled state |
65
- | `data-align` | `left`, `right` | Alignment |
61
+ ### Individual component styles
66
62
 
67
- ### Menu-Specific Attributes
68
-
69
- | Attribute | Description |
70
- | ----------------------- | ----------------------- |
71
- | `data-menu` | Menu container |
72
- | `data-menu-trigger` | Trigger button |
73
- | `data-menu-dropdown` | Dropdown panel |
74
- | `data-menu-item` | Menu item |
75
- | `data-menu-item-custom` | Custom snippet wrapper |
76
- | `data-menu-group` | Group container |
77
- | `data-menu-group-label` | Group header |
78
- | `data-menu-divider` | Divider line |
79
- | `data-menu-open` | Open state on container |
63
+ ```css
64
+ @import '@rokkit/themes/base/button.css';
65
+ @import '@rokkit/themes/rokkit/button.css';
66
+ ```
80
67
 
81
- ## Theme Scoping
68
+ ## Theme scoping
82
69
 
83
- Rokkit is the default theme its styles apply without any wrapper.
70
+ The `rokkit` theme is the default and applies without any wrapper element.
84
71
 
85
- Other themes are scoped with `data-style` to allow switching:
72
+ Other themes are scoped using the `data-style` attribute:
86
73
 
87
74
  ```html
75
+ <!-- Apply minimal theme to a section -->
88
76
  <div data-style="minimal">
89
- <!-- Components here use minimal theme -->
77
+ <!-- @rokkit/ui components here use the minimal theme -->
90
78
  </div>
91
- ```
92
79
 
93
- For global application, set on the root element:
94
-
95
- ```html
80
+ <!-- Apply a theme globally -->
96
81
  <html data-style="material"></html>
97
82
  ```
98
83
 
99
- ## Creating Custom Themes
84
+ Switching themes at runtime is a matter of updating the `data-style` attribute.
100
85
 
101
- 1. Copy `src/rokkit/` to `src/my-theme/`
102
- 2. Modify styles using same data attribute selectors
103
- 3. Wrap selectors with `[data-style='my-theme']` scope
104
- 4. Import your theme alongside or instead of rokkit
86
+ ## Custom themes
105
87
 
106
- ## CSS Custom Properties
88
+ To build your own theme:
107
89
 
108
- Themes use semantic CSS custom properties for consistency:
90
+ 1. Import `@rokkit/themes/base` for structural styles.
91
+ 2. Write CSS targeting the same `data-*` attribute selectors used by the built-in themes.
92
+ 3. Scope your selectors with `[data-style='my-theme']` to enable runtime switching.
109
93
 
110
- ```css
111
- /* Surface colors (backgrounds) */
112
- --surface-z0 through --surface-z10
94
+ Component attribute hooks follow the pattern `[data-style='my-theme'] [data-button]`, `[data-style='my-theme'] [data-list-item]`, etc.
113
95
 
114
- /* Text colors */
115
- --text-primary, --text-secondary, --text-muted
116
-
117
- /* Interactive colors */
118
- --primary, --primary-hover, --primary-active
96
+ ## Architecture
119
97
 
120
- /* State colors */
121
- --success, --warning, --error, --info
122
98
  ```
99
+ src/
100
+ base/ -- Structural styles (layout, spacing, positioning)
101
+ rokkit/ -- Default theme (gradients + borders)
102
+ minimal/ -- Clean + subtle theme
103
+ material/ -- Elevation + shadows theme
104
+ glass/ -- Blur + transparency theme
105
+ index.css -- Full bundle entry point
106
+ ```
107
+
108
+ ---
109
+
110
+ Part of [Rokkit](https://github.com/jerrythomas/rokkit) — a Svelte 5 component library and design system.
package/build.mjs CHANGED
@@ -31,36 +31,36 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
31
31
  const theme = new Theme()
32
32
 
33
33
  const uno = await createGenerator({
34
- presets: [
35
- presetWind3({
36
- dark: {
37
- light: '[data-mode="light"]',
38
- dark: '[data-mode="dark"]'
39
- }
40
- })
41
- ],
42
- shortcuts: [
43
- ['skin-default', theme.getPalette()],
44
- ...theme.getShortcuts('surface'),
45
- ...theme.getShortcuts('primary'),
46
- ...theme.getShortcuts('secondary'),
47
- ...theme.getShortcuts('accent'),
48
- ...theme.getShortcuts('success'),
49
- ...theme.getShortcuts('warning'),
50
- ...theme.getShortcuts('danger'),
51
- ...theme.getShortcuts('error'),
52
- ...theme.getShortcuts('info'),
53
- ['text-on-primary', 'text-surface-50'],
54
- ['text-on-secondary', 'text-surface-50'],
55
- ['text-on-info', 'text-surface-50'],
56
- ['text-on-success', 'text-surface-50'],
57
- ['text-on-warning', 'text-surface-50'],
58
- ['text-on-error', 'text-surface-50'],
59
- ['text-on-surface', 'text-surface-50']
60
- ],
61
- theme: {
62
- colors: theme.getColorRules()
63
- }
34
+ presets: [
35
+ presetWind3({
36
+ dark: {
37
+ light: '[data-mode="light"]',
38
+ dark: '[data-mode="dark"]'
39
+ }
40
+ })
41
+ ],
42
+ shortcuts: [
43
+ ['skin-default', theme.getPalette()],
44
+ ...theme.getShortcuts('surface'),
45
+ ...theme.getShortcuts('primary'),
46
+ ...theme.getShortcuts('secondary'),
47
+ ...theme.getShortcuts('accent'),
48
+ ...theme.getShortcuts('success'),
49
+ ...theme.getShortcuts('warning'),
50
+ ...theme.getShortcuts('danger'),
51
+ ...theme.getShortcuts('error'),
52
+ ...theme.getShortcuts('info'),
53
+ ['text-on-primary', 'text-surface-50'],
54
+ ['text-on-secondary', 'text-surface-50'],
55
+ ['text-on-info', 'text-surface-50'],
56
+ ['text-on-success', 'text-surface-50'],
57
+ ['text-on-warning', 'text-surface-50'],
58
+ ['text-on-error', 'text-surface-50'],
59
+ ['text-on-surface', 'text-surface-50']
60
+ ],
61
+ theme: {
62
+ colors: theme.getColorRules()
63
+ }
64
64
  })
65
65
 
66
66
  // ─── CSS @import resolver ─────────────────────────────────────────────────────
@@ -70,17 +70,17 @@ const uno = await createGenerator({
70
70
  * External imports (http, @, ~) are left unchanged.
71
71
  */
72
72
  function resolveImports(filePath, seen = new Set()) {
73
- if (seen.has(filePath)) return ''
74
- seen.add(filePath)
75
-
76
- const content = readFileSync(filePath, 'utf-8')
77
- return content.replace(/@import\s+['"]([^'"]+)['"]\s*;/g, (match, importPath) => {
78
- if (importPath.startsWith('http') || importPath.startsWith('@') || importPath.startsWith('~')) {
79
- return match
80
- }
81
- const resolvedPath = resolve(dirname(filePath), importPath)
82
- return resolveImports(resolvedPath, seen)
83
- })
73
+ if (seen.has(filePath)) return ''
74
+ seen.add(filePath)
75
+
76
+ const content = readFileSync(filePath, 'utf-8')
77
+ return content.replace(/@import\s+['"]([^'"]+)['"]\s*;/g, (match, importPath) => {
78
+ if (importPath.startsWith('http') || importPath.startsWith('@') || importPath.startsWith('~')) {
79
+ return match
80
+ }
81
+ const resolvedPath = resolve(dirname(filePath), importPath)
82
+ return resolveImports(resolvedPath, seen)
83
+ })
84
84
  }
85
85
 
86
86
  // ─── UnoCSS @apply processor ─────────────────────────────────────────────────
@@ -88,13 +88,13 @@ function resolveImports(filePath, seen = new Set()) {
88
88
  const transformer = transformerDirectives()
89
89
 
90
90
  async function processCSS(content, filename) {
91
- const s = new MagicString(content)
92
- await transformer.transform(s, filename, {
93
- uno,
94
- tokens: new Set(),
95
- generate: async (tokens) => uno.generate(tokens, { preflights: false })
96
- })
97
- return s.toString()
91
+ const s = new MagicString(content)
92
+ await transformer.transform(s, filename, {
93
+ uno,
94
+ tokens: new Set(),
95
+ generate: async (tokens) => uno.generate(tokens, { preflights: false })
96
+ })
97
+ return s.toString()
98
98
  }
99
99
 
100
100
  // ─── Post-processing: fix dark mode selectors ─────────────────────────────────
@@ -112,77 +112,77 @@ async function processCSS(content, filename) {
112
112
  * Both forms are emitted so either usage pattern works.
113
113
  */
114
114
  function fixModeSelectors(css) {
115
- const modePattern = /\[data-mode="(?:dark|light)"\] \[data-style="[^"]+"\]/
116
-
117
- let result = ''
118
- let i = 0
119
-
120
- while (i < css.length) {
121
- // Find next { (opening of a declarations block)
122
- const braceOpen = css.indexOf('{', i)
123
- if (braceOpen === -1) {
124
- result += css.slice(i)
125
- break
126
- }
127
-
128
- const selectorText = css.slice(i, braceOpen)
129
-
130
- // Only expand selectors that contain the problematic pattern
131
- if (modePattern.test(selectorText)) {
132
- // Split on comma, but only top-level commas (not inside :not(), :is(), etc.)
133
- const parts = splitTopLevelSelectors(selectorText)
134
- const expanded = []
135
-
136
- for (const part of parts) {
137
- const m = part.match(/^(\s*)(\[data-mode="(?:dark|light)"\]) (\[data-style="[^"]+"\])(.*)$/)
138
- if (m) {
139
- const [, ws, modeSelector, styleSelector, rest] = m
140
- // Compound form: [data-mode="X"][data-style="Y"]rest (same-element match)
141
- expanded.push(`${ws}${modeSelector}${styleSelector}${rest}`)
142
- }
143
- // Always include original descendant form
144
- expanded.push(part)
145
- }
146
-
147
- result += expanded.join(',') + '{'
148
- } else {
149
- result += selectorText + '{'
150
- }
151
-
152
- // Find the matching closing brace, handling nesting
153
- let depth = 1
154
- let j = braceOpen + 1
155
- while (j < css.length && depth > 0) {
156
- if (css[j] === '{') depth++
157
- else if (css[j] === '}') depth--
158
- j++
159
- }
160
-
161
- result += css.slice(braceOpen + 1, j)
162
- i = j
163
- }
164
-
165
- return result
115
+ const modePattern = /\[data-mode="(?:dark|light)"\] \[data-style="[^"]+"\]/
116
+
117
+ let result = ''
118
+ let i = 0
119
+
120
+ while (i < css.length) {
121
+ // Find next { (opening of a declarations block)
122
+ const braceOpen = css.indexOf('{', i)
123
+ if (braceOpen === -1) {
124
+ result += css.slice(i)
125
+ break
126
+ }
127
+
128
+ const selectorText = css.slice(i, braceOpen)
129
+
130
+ // Only expand selectors that contain the problematic pattern
131
+ if (modePattern.test(selectorText)) {
132
+ // Split on comma, but only top-level commas (not inside :not(), :is(), etc.)
133
+ const parts = splitTopLevelSelectors(selectorText)
134
+ const expanded = []
135
+
136
+ for (const part of parts) {
137
+ const m = part.match(/^(\s*)(\[data-mode="(?:dark|light)"\]) (\[data-style="[^"]+"\])(.*)$/)
138
+ if (m) {
139
+ const [, ws, modeSelector, styleSelector, rest] = m
140
+ // Compound form: [data-mode="X"][data-style="Y"]rest (same-element match)
141
+ expanded.push(`${ws}${modeSelector}${styleSelector}${rest}`)
142
+ }
143
+ // Always include original descendant form
144
+ expanded.push(part)
145
+ }
146
+
147
+ result += expanded.join(',') + '{'
148
+ } else {
149
+ result += selectorText + '{'
150
+ }
151
+
152
+ // Find the matching closing brace, handling nesting
153
+ let depth = 1
154
+ let j = braceOpen + 1
155
+ while (j < css.length && depth > 0) {
156
+ if (css[j] === '{') depth++
157
+ else if (css[j] === '}') depth--
158
+ j++
159
+ }
160
+
161
+ result += css.slice(braceOpen + 1, j)
162
+ i = j
163
+ }
164
+
165
+ return result
166
166
  }
167
167
 
168
168
  /**
169
169
  * Split a selector list by top-level commas only (not inside parentheses).
170
170
  */
171
171
  function splitTopLevelSelectors(text) {
172
- const parts = []
173
- let depth = 0
174
- let start = 0
175
-
176
- for (let i = 0; i < text.length; i++) {
177
- if (text[i] === '(') depth++
178
- else if (text[i] === ')') depth--
179
- else if (text[i] === ',' && depth === 0) {
180
- parts.push(text.slice(start, i))
181
- start = i + 1
182
- }
183
- }
184
- parts.push(text.slice(start))
185
- return parts
172
+ const parts = []
173
+ let depth = 0
174
+ let start = 0
175
+
176
+ for (let i = 0; i < text.length; i++) {
177
+ if (text[i] === '(') depth++
178
+ else if (text[i] === ')') depth--
179
+ else if (text[i] === ',' && depth === 0) {
180
+ parts.push(text.slice(start, i))
181
+ start = i + 1
182
+ }
183
+ }
184
+ parts.push(text.slice(start))
185
+ return parts
186
186
  }
187
187
 
188
188
  // ─── Build ────────────────────────────────────────────────────────────────────
@@ -191,47 +191,45 @@ const srcDir = join(__dirname, 'src')
191
191
  const distDir = join(__dirname, 'dist')
192
192
 
193
193
  async function buildFile(inputPath, outputName, label) {
194
- const fullCSS = resolveImports(inputPath)
195
- const compiled = await processCSS(fullCSS, outputName)
196
- const fixed = fixModeSelectors(compiled)
197
- writeFileSync(join(distDir, outputName), fixed, 'utf-8')
198
- console.log(`✓ dist/${outputName} (${label})`)
194
+ const fullCSS = resolveImports(inputPath)
195
+ const compiled = await processCSS(fullCSS, outputName)
196
+ const fixed = fixModeSelectors(compiled)
197
+ writeFileSync(join(distDir, outputName), fixed, 'utf-8')
198
+ console.log(`✓ dist/${outputName} (${label})`)
199
199
  }
200
200
 
201
201
  async function build() {
202
- mkdirSync(distDir, { recursive: true })
203
-
204
- // base.css: structural styles + palette CSS variable defaults
205
- const paletteCSS = readFileSync(join(srcDir, 'palette.css'), 'utf-8')
206
- const compiledPalette = await processCSS(paletteCSS, 'palette.css')
207
- const baseCSS = resolveImports(join(srcDir, 'base', 'index.css'))
208
- const compiledBase = await processCSS(baseCSS, 'base.css')
209
- const baseFull = fixModeSelectors(compiledPalette + '\n' + compiledBase)
210
- writeFileSync(join(distDir, 'base.css'), baseFull, 'utf-8')
211
- console.log('✓ dist/base.css (structural styles + palette defaults)')
212
-
213
- // Per-theme files
214
- for (const [name, label] of [
215
- ['rokkit', 'gradients + glowing borders'],
216
- ['minimal', 'clean + subtle'],
217
- ['material', 'elevation + shadows'],
218
- ['glass', 'blur + transparency']
219
- ]) {
220
- await buildFile(join(srcDir, name, 'index.css'), `${name}.css`, label)
221
- }
222
-
223
- // Full bundle: base + all themes
224
- const allThemes = ['base', 'rokkit', 'minimal', 'material', 'glass']
225
- const bundleParts = allThemes.map((name) =>
226
- readFileSync(join(distDir, `${name}.css`), 'utf-8')
227
- )
228
- writeFileSync(join(distDir, 'index.css'), bundleParts.join('\n'), 'utf-8')
229
- console.log('✓ dist/index.css (full bundle)')
230
-
231
- console.log('\n@rokkit/themes build complete.')
202
+ mkdirSync(distDir, { recursive: true })
203
+
204
+ // base.css: structural styles + palette CSS variable defaults
205
+ const paletteCSS = readFileSync(join(srcDir, 'palette.css'), 'utf-8')
206
+ const compiledPalette = await processCSS(paletteCSS, 'palette.css')
207
+ const baseCSS = resolveImports(join(srcDir, 'base', 'index.css'))
208
+ const compiledBase = await processCSS(baseCSS, 'base.css')
209
+ const baseFull = fixModeSelectors(compiledPalette + '\n' + compiledBase)
210
+ writeFileSync(join(distDir, 'base.css'), baseFull, 'utf-8')
211
+ console.log('✓ dist/base.css (structural styles + palette defaults)')
212
+
213
+ // Per-theme files
214
+ for (const [name, label] of [
215
+ ['rokkit', 'gradients + glowing borders'],
216
+ ['minimal', 'clean + subtle'],
217
+ ['material', 'elevation + shadows'],
218
+ ['glass', 'blur + transparency']
219
+ ]) {
220
+ await buildFile(join(srcDir, name, 'index.css'), `${name}.css`, label)
221
+ }
222
+
223
+ // Full bundle: base + all themes
224
+ const allThemes = ['base', 'rokkit', 'minimal', 'material', 'glass']
225
+ const bundleParts = allThemes.map((name) => readFileSync(join(distDir, `${name}.css`), 'utf-8'))
226
+ writeFileSync(join(distDir, 'index.css'), bundleParts.join('\n'), 'utf-8')
227
+ console.log('✓ dist/index.css (full bundle)')
228
+
229
+ console.log('\n@rokkit/themes build complete.')
232
230
  }
233
231
 
234
232
  build().catch((err) => {
235
- console.error('Build failed:', err)
236
- process.exit(1)
233
+ console.error('Build failed:', err)
234
+ process.exit(1)
237
235
  })