@rokkit/themes 1.0.0-next.99 → 1.0.2

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 (370) hide show
  1. package/README.md +118 -9
  2. package/build.mjs +254 -0
  3. package/dist/ant-design.css +2129 -0
  4. package/dist/base.css +6378 -0
  5. package/dist/bits-ui.css +2113 -0
  6. package/dist/carbon.css +2123 -0
  7. package/dist/daisy-ui.css +2138 -0
  8. package/dist/frosted.css +1953 -0
  9. package/dist/grada-ui.css +1915 -0
  10. package/dist/index.css +27231 -0
  11. package/dist/material.css +1924 -0
  12. package/dist/minimal.css +1978 -0
  13. package/dist/rokkit.css +2471 -0
  14. package/dist/shadcn.css +2099 -0
  15. package/package.json +221 -48
  16. package/src/ant-design/button.css +190 -0
  17. package/src/ant-design/card.css +100 -0
  18. package/src/ant-design/chart.css +34 -0
  19. package/src/ant-design/connector.css +11 -0
  20. package/src/ant-design/dropdown.css +50 -0
  21. package/src/ant-design/floating-action.css +63 -0
  22. package/src/ant-design/floating-navigation.css +70 -0
  23. package/src/ant-design/grid.css +46 -0
  24. package/src/ant-design/index.css +35 -0
  25. package/src/ant-design/input.css +151 -0
  26. package/src/ant-design/list.css +126 -0
  27. package/src/ant-design/menu.css +88 -0
  28. package/src/ant-design/message.css +35 -0
  29. package/src/ant-design/range.css +61 -0
  30. package/src/ant-design/search-filter.css +49 -0
  31. package/src/ant-design/select.css +158 -0
  32. package/src/ant-design/status-list.css +66 -0
  33. package/src/ant-design/step-indicator.css +38 -0
  34. package/src/ant-design/switch.css +29 -0
  35. package/src/ant-design/table.css +91 -0
  36. package/src/ant-design/tabs.css +153 -0
  37. package/src/ant-design/timeline.css +45 -0
  38. package/src/ant-design/toc.css +18 -0
  39. package/src/ant-design/toggle.css +48 -0
  40. package/src/ant-design/toolbar.css +85 -0
  41. package/src/ant-design/tree.css +137 -0
  42. package/src/ant-design/upload-progress.css +102 -0
  43. package/src/ant-design/upload-target.css +50 -0
  44. package/src/base/alert-list.css +91 -0
  45. package/src/base/avatar.css +82 -0
  46. package/src/base/badge.css +41 -0
  47. package/src/base/breadcrumbs.css +47 -0
  48. package/src/base/button.css +254 -0
  49. package/src/base/card.css +39 -0
  50. package/src/base/carousel.css +122 -12
  51. package/src/base/chart.css +94 -0
  52. package/src/base/connector.css +92 -0
  53. package/src/base/density.css +51 -0
  54. package/src/base/display.css +91 -0
  55. package/src/base/divider.css +49 -0
  56. package/src/base/dropdown.css +167 -0
  57. package/src/base/floating-action.css +388 -0
  58. package/src/base/floating-navigation.css +405 -0
  59. package/src/base/graph-paper.css +83 -0
  60. package/src/base/grid.css +93 -0
  61. package/src/base/index.css +57 -0
  62. package/src/base/input.css +290 -0
  63. package/src/base/item.css +78 -0
  64. package/src/base/list.css +188 -0
  65. package/src/base/menu.css +277 -0
  66. package/src/base/message.css +62 -0
  67. package/src/base/nav-content.css +48 -0
  68. package/src/base/pill.css +57 -0
  69. package/src/base/progress.css +34 -0
  70. package/src/base/range.css +121 -0
  71. package/src/base/rating.css +42 -0
  72. package/src/base/responsive-grid.css +8 -0
  73. package/src/base/reveal.css +37 -0
  74. package/src/base/search-filter.css +132 -0
  75. package/src/base/select.css +413 -0
  76. package/src/base/shine.css +14 -0
  77. package/src/base/stack.css +76 -0
  78. package/src/base/status-list.css +19 -0
  79. package/src/base/step-indicator.css +74 -0
  80. package/src/base/stepper.css +140 -0
  81. package/src/base/swatch.css +85 -0
  82. package/src/base/switch.css +152 -0
  83. package/src/base/table.css +193 -33
  84. package/src/base/tabs.css +171 -0
  85. package/src/base/tilt.css +14 -0
  86. package/src/base/timeline.css +84 -0
  87. package/src/base/toc.css +50 -0
  88. package/src/base/toggle.css +138 -0
  89. package/src/base/toolbar.css +341 -0
  90. package/src/base/tooltip.css +64 -0
  91. package/src/base/tree.css +228 -11
  92. package/src/base/typography.css +31 -0
  93. package/src/base/upload-progress.css +155 -0
  94. package/src/base/upload-target.css +77 -0
  95. package/src/bits-ui/button.css +176 -0
  96. package/src/bits-ui/card.css +99 -0
  97. package/src/bits-ui/chart.css +34 -0
  98. package/src/bits-ui/connector.css +11 -0
  99. package/src/bits-ui/dropdown.css +50 -0
  100. package/src/bits-ui/floating-action.css +63 -0
  101. package/src/bits-ui/floating-navigation.css +70 -0
  102. package/src/bits-ui/grid.css +46 -0
  103. package/src/bits-ui/index.css +35 -0
  104. package/src/bits-ui/input.css +154 -0
  105. package/src/bits-ui/list.css +126 -0
  106. package/src/bits-ui/menu.css +88 -0
  107. package/src/bits-ui/message.css +35 -0
  108. package/src/bits-ui/range.css +61 -0
  109. package/src/bits-ui/search-filter.css +49 -0
  110. package/src/bits-ui/select.css +158 -0
  111. package/src/bits-ui/status-list.css +66 -0
  112. package/src/bits-ui/step-indicator.css +40 -0
  113. package/src/bits-ui/switch.css +29 -0
  114. package/src/bits-ui/table.css +89 -0
  115. package/src/bits-ui/tabs.css +151 -0
  116. package/src/bits-ui/timeline.css +45 -0
  117. package/src/bits-ui/toc.css +18 -0
  118. package/src/bits-ui/toggle.css +48 -0
  119. package/src/bits-ui/toolbar.css +85 -0
  120. package/src/bits-ui/tree.css +135 -0
  121. package/src/bits-ui/upload-progress.css +102 -0
  122. package/src/bits-ui/upload-target.css +50 -0
  123. package/src/carbon/button.css +186 -0
  124. package/src/carbon/card.css +97 -0
  125. package/src/carbon/chart.css +34 -0
  126. package/src/carbon/connector.css +11 -0
  127. package/src/carbon/dropdown.css +50 -0
  128. package/src/carbon/floating-action.css +63 -0
  129. package/src/carbon/floating-navigation.css +70 -0
  130. package/src/carbon/grid.css +46 -0
  131. package/src/carbon/index.css +34 -0
  132. package/src/carbon/input.css +148 -0
  133. package/src/carbon/list.css +124 -0
  134. package/src/carbon/menu.css +88 -0
  135. package/src/carbon/message.css +37 -0
  136. package/src/carbon/range.css +61 -0
  137. package/src/carbon/search-filter.css +49 -0
  138. package/src/carbon/select.css +158 -0
  139. package/src/carbon/status-list.css +66 -0
  140. package/src/carbon/step-indicator.css +40 -0
  141. package/src/carbon/switch.css +31 -0
  142. package/src/carbon/table.css +93 -0
  143. package/src/carbon/tabs.css +151 -0
  144. package/src/carbon/timeline.css +45 -0
  145. package/src/carbon/toc.css +22 -0
  146. package/src/carbon/toggle.css +48 -0
  147. package/src/carbon/toolbar.css +84 -0
  148. package/src/carbon/tree.css +135 -0
  149. package/src/carbon/upload-progress.css +102 -0
  150. package/src/carbon/upload-target.css +50 -0
  151. package/src/daisy-ui/button.css +196 -0
  152. package/src/daisy-ui/card.css +99 -0
  153. package/src/daisy-ui/chart.css +34 -0
  154. package/src/daisy-ui/connector.css +11 -0
  155. package/src/daisy-ui/dropdown.css +50 -0
  156. package/src/daisy-ui/floating-action.css +63 -0
  157. package/src/daisy-ui/floating-navigation.css +70 -0
  158. package/src/daisy-ui/grid.css +46 -0
  159. package/src/daisy-ui/index.css +34 -0
  160. package/src/daisy-ui/input.css +148 -0
  161. package/src/daisy-ui/list.css +127 -0
  162. package/src/daisy-ui/menu.css +88 -0
  163. package/src/daisy-ui/message.css +37 -0
  164. package/src/daisy-ui/range.css +61 -0
  165. package/src/daisy-ui/search-filter.css +49 -0
  166. package/src/daisy-ui/select.css +158 -0
  167. package/src/daisy-ui/status-list.css +66 -0
  168. package/src/daisy-ui/step-indicator.css +37 -0
  169. package/src/daisy-ui/switch.css +31 -0
  170. package/src/daisy-ui/table.css +91 -0
  171. package/src/daisy-ui/tabs.css +153 -0
  172. package/src/daisy-ui/timeline.css +45 -0
  173. package/src/daisy-ui/toc.css +22 -0
  174. package/src/daisy-ui/toggle.css +48 -0
  175. package/src/daisy-ui/toolbar.css +85 -0
  176. package/src/daisy-ui/tree.css +137 -0
  177. package/src/daisy-ui/upload-progress.css +102 -0
  178. package/src/daisy-ui/upload-target.css +50 -0
  179. package/src/frosted/button.css +224 -0
  180. package/src/frosted/card.css +130 -0
  181. package/src/frosted/chart.css +38 -0
  182. package/src/frosted/dropdown.css +66 -0
  183. package/src/frosted/floating-action.css +61 -0
  184. package/src/frosted/floating-navigation.css +74 -0
  185. package/src/frosted/index.css +31 -0
  186. package/src/frosted/input.css +135 -0
  187. package/src/frosted/list.css +122 -0
  188. package/src/frosted/menu.css +108 -0
  189. package/src/frosted/message.css +35 -0
  190. package/src/frosted/range.css +61 -0
  191. package/src/frosted/search-filter.css +49 -0
  192. package/src/frosted/select.css +178 -0
  193. package/src/frosted/status-list.css +66 -0
  194. package/src/frosted/step-indicator.css +41 -0
  195. package/src/frosted/swatch.css +21 -0
  196. package/src/frosted/switch.css +43 -0
  197. package/src/frosted/table.css +106 -0
  198. package/src/frosted/tabs.css +58 -0
  199. package/src/frosted/timeline.css +46 -0
  200. package/src/frosted/toc.css +18 -0
  201. package/src/frosted/toggle.css +48 -0
  202. package/src/frosted/toolbar.css +84 -0
  203. package/src/frosted/tree.css +110 -0
  204. package/src/grada-ui/button.css +249 -0
  205. package/src/grada-ui/card.css +96 -0
  206. package/src/grada-ui/chart.css +34 -0
  207. package/src/grada-ui/dropdown.css +58 -0
  208. package/src/grada-ui/floating-action.css +66 -0
  209. package/src/grada-ui/floating-navigation.css +69 -0
  210. package/src/grada-ui/index.css +56 -0
  211. package/src/grada-ui/input.css +154 -0
  212. package/src/grada-ui/list.css +124 -0
  213. package/src/grada-ui/menu.css +81 -0
  214. package/src/grada-ui/message.css +48 -0
  215. package/src/grada-ui/range.css +59 -0
  216. package/src/grada-ui/search-filter.css +47 -0
  217. package/src/grada-ui/select.css +190 -0
  218. package/src/grada-ui/status-list.css +66 -0
  219. package/src/grada-ui/step-indicator.css +37 -0
  220. package/src/grada-ui/switch.css +35 -0
  221. package/src/grada-ui/table.css +79 -0
  222. package/src/grada-ui/tabs.css +59 -0
  223. package/src/grada-ui/timeline.css +46 -0
  224. package/src/grada-ui/toc.css +24 -0
  225. package/src/grada-ui/toggle.css +47 -0
  226. package/src/grada-ui/toolbar.css +91 -0
  227. package/src/grada-ui/tree.css +100 -0
  228. package/src/index.css +18 -0
  229. package/src/index.js +25 -3
  230. package/src/material/button.css +178 -0
  231. package/src/material/card.css +99 -0
  232. package/src/material/chart.css +38 -0
  233. package/src/material/dropdown.css +50 -0
  234. package/src/material/floating-action.css +64 -0
  235. package/src/material/floating-navigation.css +74 -0
  236. package/src/material/index.css +31 -0
  237. package/src/material/input.css +139 -40
  238. package/src/material/list.css +94 -64
  239. package/src/material/menu.css +92 -0
  240. package/src/material/message.css +35 -0
  241. package/src/material/range.css +62 -0
  242. package/src/material/search-filter.css +49 -0
  243. package/src/material/select.css +177 -0
  244. package/src/material/status-list.css +66 -0
  245. package/src/material/step-indicator.css +41 -0
  246. package/src/material/swatch.css +21 -0
  247. package/src/material/switch.css +28 -0
  248. package/src/material/table.css +110 -0
  249. package/src/material/tabs.css +88 -0
  250. package/src/material/timeline.css +46 -0
  251. package/src/material/toc.css +18 -0
  252. package/src/material/toggle.css +48 -0
  253. package/src/material/toolbar.css +85 -0
  254. package/src/material/tree.css +134 -0
  255. package/src/minimal/button.css +176 -0
  256. package/src/minimal/card.css +99 -0
  257. package/src/minimal/chart.css +38 -0
  258. package/src/minimal/dropdown.css +50 -0
  259. package/src/minimal/floating-action.css +63 -0
  260. package/src/minimal/floating-navigation.css +70 -0
  261. package/src/minimal/index.css +31 -0
  262. package/src/minimal/input.css +137 -120
  263. package/src/minimal/list.css +96 -104
  264. package/src/minimal/menu.css +88 -0
  265. package/src/minimal/message.css +35 -0
  266. package/src/minimal/range.css +61 -0
  267. package/src/minimal/search-filter.css +49 -0
  268. package/src/minimal/select.css +170 -0
  269. package/src/minimal/status-list.css +66 -0
  270. package/src/minimal/step-indicator.css +40 -0
  271. package/src/minimal/swatch.css +21 -0
  272. package/src/minimal/switch.css +32 -0
  273. package/src/minimal/table.css +108 -0
  274. package/src/minimal/tabs.css +135 -28
  275. package/src/minimal/timeline.css +45 -0
  276. package/src/minimal/toc.css +18 -0
  277. package/src/minimal/toggle.css +48 -0
  278. package/src/minimal/toolbar.css +85 -0
  279. package/src/minimal/tree.css +135 -0
  280. package/src/palette.css +2 -20
  281. package/src/rokkit/avatar.css +29 -0
  282. package/src/rokkit/badge.css +29 -0
  283. package/src/rokkit/button.css +290 -0
  284. package/src/rokkit/card.css +102 -0
  285. package/src/rokkit/chart.css +38 -0
  286. package/src/rokkit/connector.css +11 -0
  287. package/src/rokkit/divider.css +26 -0
  288. package/src/rokkit/dropdown.css +70 -0
  289. package/src/rokkit/floating-action.css +65 -0
  290. package/src/rokkit/floating-navigation.css +83 -0
  291. package/src/rokkit/grid.css +46 -0
  292. package/src/rokkit/index.css +40 -0
  293. package/src/rokkit/input.css +124 -26
  294. package/src/rokkit/list.css +177 -0
  295. package/src/rokkit/menu.css +93 -0
  296. package/src/rokkit/message.css +44 -0
  297. package/src/rokkit/range.css +62 -0
  298. package/src/rokkit/search-filter.css +49 -0
  299. package/src/rokkit/select.css +190 -0
  300. package/src/rokkit/stack.css +6 -0
  301. package/src/rokkit/status-list.css +68 -0
  302. package/src/rokkit/step-indicator.css +41 -0
  303. package/src/rokkit/swatch.css +20 -0
  304. package/src/rokkit/switch.css +29 -0
  305. package/src/rokkit/table.css +88 -37
  306. package/src/rokkit/tabs.css +111 -0
  307. package/src/rokkit/timeline.css +46 -0
  308. package/src/rokkit/toc.css +18 -0
  309. package/src/rokkit/toggle.css +41 -11
  310. package/src/rokkit/toolbar.css +90 -0
  311. package/src/rokkit/tooltip.css +7 -0
  312. package/src/rokkit/tree.css +149 -0
  313. package/src/rokkit/upload-progress.css +102 -0
  314. package/src/rokkit/upload-target.css +50 -0
  315. package/src/shadcn/button.css +175 -0
  316. package/src/shadcn/card.css +99 -0
  317. package/src/shadcn/chart.css +34 -0
  318. package/src/shadcn/connector.css +11 -0
  319. package/src/shadcn/dropdown.css +50 -0
  320. package/src/shadcn/floating-action.css +63 -0
  321. package/src/shadcn/floating-navigation.css +70 -0
  322. package/src/shadcn/grid.css +46 -0
  323. package/src/shadcn/index.css +35 -0
  324. package/src/shadcn/input.css +143 -0
  325. package/src/shadcn/list.css +124 -0
  326. package/src/shadcn/menu.css +88 -0
  327. package/src/shadcn/message.css +35 -0
  328. package/src/shadcn/range.css +61 -0
  329. package/src/shadcn/search-filter.css +49 -0
  330. package/src/shadcn/select.css +158 -0
  331. package/src/shadcn/status-list.css +66 -0
  332. package/src/shadcn/step-indicator.css +37 -0
  333. package/src/shadcn/switch.css +31 -0
  334. package/src/shadcn/table.css +89 -0
  335. package/src/shadcn/tabs.css +151 -0
  336. package/src/shadcn/timeline.css +45 -0
  337. package/src/shadcn/toc.css +20 -0
  338. package/src/shadcn/toggle.css +48 -0
  339. package/src/shadcn/toolbar.css +84 -0
  340. package/src/shadcn/tree.css +135 -0
  341. package/src/shadcn/upload-progress.css +102 -0
  342. package/src/shadcn/upload-target.css +50 -0
  343. package/LICENSE +0 -21
  344. package/src/base/alert.css +0 -30
  345. package/src/base/animation.css +0 -22
  346. package/src/base/atoms.css +0 -58
  347. package/src/base/core.css +0 -92
  348. package/src/base/layout.css +0 -65
  349. package/src/base/molecules.css +0 -126
  350. package/src/base/organisms.css +0 -26
  351. package/src/base/scrollbar.css +0 -16
  352. package/src/base.css +0 -11
  353. package/src/constants.js +0 -8
  354. package/src/markdown.css +0 -955
  355. package/src/material/base.css +0 -12
  356. package/src/material/form.css +0 -30
  357. package/src/material.css +0 -9
  358. package/src/minimal/base.css +0 -8
  359. package/src/minimal/form.css +0 -87
  360. package/src/minimal.css +0 -11
  361. package/src/mixins/mixins.scss +0 -66
  362. package/src/mixins/palette.scss +0 -48
  363. package/src/prism.css +0 -102
  364. package/src/rokkit/alert.css +0 -4
  365. package/src/rokkit/atoms.css +0 -69
  366. package/src/rokkit/carousel.css +0 -19
  367. package/src/rokkit/layout.css +0 -17
  368. package/src/rokkit/molecules.css +0 -119
  369. package/src/rokkit/organisms.css +0 -315
  370. package/src/rokkit.css +0 -11
package/README.md CHANGED
@@ -1,13 +1,122 @@
1
- # Themes
1
+ # @rokkit/themes
2
2
 
3
- Contains the following themes for use with `Rokkit` components.
3
+ Pre-built CSS themes for `@rokkit/ui` components.
4
4
 
5
- - Rokkit
6
- - Modern
7
- - Material
5
+ ## Install
8
6
 
9
- This package also includes some mixins which make it easy to implement `light` and `dark` modes.
7
+ ```sh
8
+ npm install @rokkit/themes
9
+ # or
10
+ bun add @rokkit/themes
11
+ ```
10
12
 
11
- - markdown.css: A customized variant of Github flavored markdown
12
- - prism.css: A variation of the prism syntax highlighting colors using CSS variables to support light and dark modes.
13
- - palette.css: Light and dark palettes using CSS variables.
13
+ ## Overview
14
+
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]`).
16
+
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
+ | `frosted` | Frosted glass and blur |
25
+ | `shadcn` | Flat borders and ring focus |
26
+ | `daisy-ui` | Rounded-full and bold fills |
27
+ | `bits-ui` | Rounded-lg and shadow-sm |
28
+ | `carbon` | Square corners and bottom-border inputs |
29
+ | `ant-design` | Thin borders and dense layout |
30
+ | `grada-ui` | Coral/purple gradient identity |
31
+ | `base` | Structural styles only (layout and positioning, no visual treatment) |
32
+
33
+ ## Usage
34
+
35
+ ### Full bundle (base + all themes)
36
+
37
+ ```css
38
+ @import '@rokkit/themes';
39
+ ```
40
+
41
+ Or in JavaScript/TypeScript:
42
+
43
+ ```js
44
+ import '@rokkit/themes'
45
+ ```
46
+
47
+ ### Single theme
48
+
49
+ ```css
50
+ @import '@rokkit/themes/rokkit.css';
51
+ /* or */
52
+ @import '@rokkit/themes/minimal.css';
53
+ /* or */
54
+ @import '@rokkit/themes/material.css';
55
+ /* or */
56
+ @import '@rokkit/themes/frosted.css';
57
+ ```
58
+
59
+ ### Base structural styles only
60
+
61
+ ```css
62
+ @import '@rokkit/themes/base';
63
+ ```
64
+
65
+ Useful when writing a fully custom theme — imports layout and positioning rules without any visual styling.
66
+
67
+ ### Individual component styles
68
+
69
+ ```css
70
+ @import '@rokkit/themes/base/button.css';
71
+ @import '@rokkit/themes/rokkit/button.css';
72
+ ```
73
+
74
+ ## Theme scoping
75
+
76
+ The `rokkit` theme is the default and applies without any wrapper element.
77
+
78
+ Other themes are scoped using the `data-style` attribute:
79
+
80
+ ```html
81
+ <!-- Apply minimal theme to a section -->
82
+ <div data-style="minimal">
83
+ <!-- @rokkit/ui components here use the minimal theme -->
84
+ </div>
85
+
86
+ <!-- Apply a theme globally -->
87
+ <html data-style="material"></html>
88
+ ```
89
+
90
+ Switching themes at runtime is a matter of updating the `data-style` attribute.
91
+
92
+ ## Custom themes
93
+
94
+ To build your own theme:
95
+
96
+ 1. Import `@rokkit/themes/base` for structural styles.
97
+ 2. Write CSS targeting the same `data-*` attribute selectors used by the built-in themes.
98
+ 3. Scope your selectors with `[data-style='my-theme']` to enable runtime switching.
99
+
100
+ Component attribute hooks follow the pattern `[data-style='my-theme'] [data-button]`, `[data-style='my-theme'] [data-list-item]`, etc.
101
+
102
+ ## Architecture
103
+
104
+ ```
105
+ src/
106
+ base/ -- Structural styles (layout, spacing, positioning)
107
+ rokkit/ -- Default theme (gradients + borders)
108
+ minimal/ -- Clean + subtle theme
109
+ material/ -- Elevation + shadows theme
110
+ frosted/ -- Frosted glass + blur theme
111
+ shadcn/ -- Flat borders + ring focus theme
112
+ daisy-ui/ -- Rounded-full + bold fills theme
113
+ bits-ui/ -- Rounded-lg + shadow-sm theme
114
+ carbon/ -- Square + bottom-border inputs theme
115
+ ant-design/ -- Thin borders + dense layout theme
116
+ grada-ui/ -- Coral/purple gradient identity theme
117
+ index.css -- Full bundle entry point
118
+ ```
119
+
120
+ ---
121
+
122
+ Part of [Rokkit](https://github.com/jerrythomas/rokkit) — a Svelte 5 component library and design system.
package/build.mjs ADDED
@@ -0,0 +1,254 @@
1
+ /**
2
+ * @rokkit/themes — CSS Build Script
3
+ *
4
+ * Compiles theme CSS with UnoCSS, expanding @apply directives into real CSS
5
+ * (including correct dark mode sibling rules).
6
+ *
7
+ * Outputs separate files per theme:
8
+ * dist/base.css — structural styles + default CSS variable palette
9
+ * dist/rokkit.css — rokkit theme (gradients, glowing borders)
10
+ * dist/minimal.css — minimal theme (clean, subtle)
11
+ * dist/material.css — material theme (elevation, shadows)
12
+ * dist/frosted.css — frosted theme (blur, transparency)
13
+ *
14
+ * Post-processing: adds compound selector form so dark mode works when
15
+ * data-mode and data-style are on the SAME element (e.g. body):
16
+ * Generated: [data-mode="dark"] [data-style="rokkit"] [data-toggle]
17
+ * Added also: [data-mode="dark"][data-style="rokkit"] [data-toggle]
18
+ */
19
+
20
+ import { createGenerator, presetWind3, transformerDirectives } from 'unocss'
21
+ import { Theme } from '@rokkit/core'
22
+ import { readFileSync, writeFileSync, mkdirSync } from 'fs'
23
+ import { resolve, dirname, join } from 'path'
24
+ import { fileURLToPath } from 'url'
25
+ import MagicString from 'magic-string'
26
+
27
+ const __dirname = dirname(fileURLToPath(import.meta.url))
28
+
29
+ // ─── UnoCSS config ────────────────────────────────────────────────────────────
30
+
31
+ const theme = new Theme()
32
+
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(\/\d+)?$/, ([, end]) => `text-surface-50${end || ''}`],
54
+ [/^text-on-secondary(\/\d+)?$/, ([, end]) => `text-surface-50${end || ''}`],
55
+ [/^text-on-info(\/\d+)?$/, ([, end]) => `text-surface-50${end || ''}`],
56
+ [/^text-on-success(\/\d+)?$/, ([, end]) => `text-surface-50${end || ''}`],
57
+ [/^text-on-warning(\/\d+)?$/, ([, end]) => `text-surface-50${end || ''}`],
58
+ [/^text-on-error(\/\d+)?$/, ([, end]) => `text-surface-50${end || ''}`],
59
+ [/^text-on-surface(\/\d+)?$/, ([, end]) => `text-surface-50${end || ''}`]
60
+ ],
61
+ theme: {
62
+ colors: theme.getColorRules()
63
+ }
64
+ })
65
+
66
+ // ─── CSS @import resolver ─────────────────────────────────────────────────────
67
+
68
+ /**
69
+ * Recursively inlines local @import statements.
70
+ * External imports (http, @, ~) are left unchanged.
71
+ */
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
+ })
84
+ }
85
+
86
+ // ─── UnoCSS @apply processor ─────────────────────────────────────────────────
87
+
88
+ const transformer = transformerDirectives()
89
+
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()
98
+ }
99
+
100
+ // ─── Post-processing: fix dark mode selectors ─────────────────────────────────
101
+
102
+ /**
103
+ * UnoCSS generates dark mode rules as descendant selectors:
104
+ * [data-mode="dark"] [data-style="rokkit"] [data-component]
105
+ *
106
+ * This doesn't match when both data-mode and data-style are on the SAME element
107
+ * (e.g. <body data-mode="dark" data-style="rokkit">).
108
+ *
109
+ * For each such rule, we also add the compound selector form:
110
+ * [data-mode="dark"][data-style="rokkit"] [data-component]
111
+ *
112
+ * Both forms are emitted so either usage pattern works.
113
+ */
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
166
+ }
167
+
168
+ /**
169
+ * Split a selector list by top-level commas only (not inside parentheses).
170
+ */
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
186
+ }
187
+
188
+ // ─── Build ────────────────────────────────────────────────────────────────────
189
+
190
+ const srcDir = join(__dirname, 'src')
191
+ const distDir = join(__dirname, 'dist')
192
+
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})`)
199
+ }
200
+
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 zScaleCSS = theme.getZScaleCSS()
208
+ const baseCSS = resolveImports(join(srcDir, 'base', 'index.css'))
209
+ const compiledBase = await processCSS(baseCSS, 'base.css')
210
+ const baseFull = fixModeSelectors(compiledPalette + '\n' + zScaleCSS + '\n' + compiledBase)
211
+ writeFileSync(join(distDir, 'base.css'), baseFull, 'utf-8')
212
+ console.log('✓ dist/base.css (structural styles + palette defaults)')
213
+
214
+ // Per-theme files
215
+ for (const [name, label] of [
216
+ ['rokkit', 'gradients + glowing borders'],
217
+ ['minimal', 'clean + subtle'],
218
+ ['material', 'elevation + shadows'],
219
+ ['frosted', 'frosted glass + blur'],
220
+ ['grada-ui', 'coral/purple gradient identity'],
221
+ ['shadcn', 'flat borders + ring focus'],
222
+ ['daisy-ui', 'rounded-full + bold fills'],
223
+ ['bits-ui', 'rounded-lg + shadow-sm'],
224
+ ['carbon', 'square + bottom-border inputs'],
225
+ ['ant-design', 'thin borders + dense layout']
226
+ ]) {
227
+ await buildFile(join(srcDir, name, 'index.css'), `${name}.css`, label)
228
+ }
229
+
230
+ // Full bundle: base + all themes
231
+ const allThemes = [
232
+ 'base',
233
+ 'rokkit',
234
+ 'minimal',
235
+ 'material',
236
+ 'frosted',
237
+ 'grada-ui',
238
+ 'shadcn',
239
+ 'daisy-ui',
240
+ 'bits-ui',
241
+ 'carbon',
242
+ 'ant-design'
243
+ ]
244
+ const bundleParts = allThemes.map((name) => readFileSync(join(distDir, `${name}.css`), 'utf-8'))
245
+ writeFileSync(join(distDir, 'index.css'), bundleParts.join('\n'), 'utf-8')
246
+ console.log('✓ dist/index.css (full bundle)')
247
+
248
+ console.log('\n@rokkit/themes build complete.')
249
+ }
250
+
251
+ build().catch((err) => {
252
+ console.error('Build failed:', err)
253
+ process.exit(1)
254
+ })