boss-css 0.0.13 → 0.0.15

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 (187) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -1
  3. package/dist/ai/server.cjs +1 -0
  4. package/dist/ai/server.mjs +1 -0
  5. package/dist/ai/skills.cjs +3 -0
  6. package/dist/ai/skills.mjs +3 -0
  7. package/dist/cli/tasks/init.cjs +43 -21
  8. package/dist/cli/tasks/init.mjs +43 -21
  9. package/dist/cli/templates/init.cjs +5 -5
  10. package/dist/cli/templates/init.mjs +5 -5
  11. package/dist/compile/jsx.cjs +4 -2
  12. package/dist/compile/jsx.mjs +4 -2
  13. package/dist/devtools-app/index.mjs +320 -0
  14. package/dist/devtools-app/monaco/vs/_commonjsHelpers-CT9FvmAN.js +1 -0
  15. package/dist/devtools-app/monaco/vs/abap-D-t0cyap.js +1 -0
  16. package/dist/devtools-app/monaco/vs/apex-CcIm7xu6.js +1 -0
  17. package/dist/devtools-app/monaco/vs/assets/css.worker-HnVq6Ewq.js +93 -0
  18. package/dist/devtools-app/monaco/vs/assets/editor.worker-Be8ye1pW.js +26 -0
  19. package/dist/devtools-app/monaco/vs/assets/html.worker-B51mlPHg.js +470 -0
  20. package/dist/devtools-app/monaco/vs/assets/json.worker-DKiEKt88.js +58 -0
  21. package/dist/devtools-app/monaco/vs/assets/ts.worker-CMbG-7ft.js +67731 -0
  22. package/dist/devtools-app/monaco/vs/azcli-BA0tQDCg.js +1 -0
  23. package/dist/devtools-app/monaco/vs/basic-languages/monaco.contribution.js +1 -0
  24. package/dist/devtools-app/monaco/vs/bat-C397hTD6.js +1 -0
  25. package/dist/devtools-app/monaco/vs/bicep-DF5aW17k.js +2 -0
  26. package/dist/devtools-app/monaco/vs/cameligo-plsz8qhj.js +1 -0
  27. package/dist/devtools-app/monaco/vs/clojure-Y2auQMzK.js +1 -0
  28. package/dist/devtools-app/monaco/vs/coffee-Bu45yuWE.js +1 -0
  29. package/dist/devtools-app/monaco/vs/cpp-CkKPQIni.js +1 -0
  30. package/dist/devtools-app/monaco/vs/csharp-CX28MZyh.js +1 -0
  31. package/dist/devtools-app/monaco/vs/csp-D8uWnyxW.js +1 -0
  32. package/dist/devtools-app/monaco/vs/css-CaeNmE3S.js +3 -0
  33. package/dist/devtools-app/monaco/vs/cssMode-CjiAH6dQ.js +1 -0
  34. package/dist/devtools-app/monaco/vs/cypher-DVThT8BS.js +1 -0
  35. package/dist/devtools-app/monaco/vs/dart-CmGfCvrO.js +1 -0
  36. package/dist/devtools-app/monaco/vs/dockerfile-CZqqYdch.js +1 -0
  37. package/dist/devtools-app/monaco/vs/ecl-30fUercY.js +1 -0
  38. package/dist/devtools-app/monaco/vs/editor/editor.main.css +1 -0
  39. package/dist/devtools-app/monaco/vs/editor/editor.main.js +5 -0
  40. package/dist/devtools-app/monaco/vs/editor.api-CalNCsUg.js +903 -0
  41. package/dist/devtools-app/monaco/vs/elixir-xjPaIfzF.js +1 -0
  42. package/dist/devtools-app/monaco/vs/flow9-DqtmStfK.js +1 -0
  43. package/dist/devtools-app/monaco/vs/freemarker2-Cz_sV6Md.js +3 -0
  44. package/dist/devtools-app/monaco/vs/fsharp-BOMdg4U1.js +1 -0
  45. package/dist/devtools-app/monaco/vs/go-D_hbi-Jt.js +1 -0
  46. package/dist/devtools-app/monaco/vs/graphql-CKUU4kLG.js +1 -0
  47. package/dist/devtools-app/monaco/vs/handlebars-OwglfO-1.js +1 -0
  48. package/dist/devtools-app/monaco/vs/hcl-DTaboeZW.js +1 -0
  49. package/dist/devtools-app/monaco/vs/html-Pa1xEWsY.js +1 -0
  50. package/dist/devtools-app/monaco/vs/htmlMode-Bz67EXwp.js +1 -0
  51. package/dist/devtools-app/monaco/vs/ini-CsNwO04R.js +1 -0
  52. package/dist/devtools-app/monaco/vs/java-CI4ZMsH9.js +1 -0
  53. package/dist/devtools-app/monaco/vs/javascript-PczUCGdz.js +1 -0
  54. package/dist/devtools-app/monaco/vs/jsonMode-DULH5oaX.js +7 -0
  55. package/dist/devtools-app/monaco/vs/julia-BwzEvaQw.js +1 -0
  56. package/dist/devtools-app/monaco/vs/kotlin-IUYPiTV8.js +1 -0
  57. package/dist/devtools-app/monaco/vs/language/css/monaco.contribution.js +1 -0
  58. package/dist/devtools-app/monaco/vs/language/html/monaco.contribution.js +1 -0
  59. package/dist/devtools-app/monaco/vs/language/json/monaco.contribution.js +1 -0
  60. package/dist/devtools-app/monaco/vs/language/typescript/monaco.contribution.js +1 -0
  61. package/dist/devtools-app/monaco/vs/less-C0eDYdqa.js +2 -0
  62. package/dist/devtools-app/monaco/vs/lexon-iON-Kj97.js +1 -0
  63. package/dist/devtools-app/monaco/vs/liquid-DqKjdPGy.js +1 -0
  64. package/dist/devtools-app/monaco/vs/loader.js +1368 -0
  65. package/dist/devtools-app/monaco/vs/lspLanguageFeatures-kM9O9rjY.js +4 -0
  66. package/dist/devtools-app/monaco/vs/lua-DtygF91M.js +1 -0
  67. package/dist/devtools-app/monaco/vs/m3-CsR4AuFi.js +1 -0
  68. package/dist/devtools-app/monaco/vs/markdown-C_rD0bIw.js +1 -0
  69. package/dist/devtools-app/monaco/vs/mdx-DEWtB1K5.js +1 -0
  70. package/dist/devtools-app/monaco/vs/mips-CiYP61RB.js +1 -0
  71. package/dist/devtools-app/monaco/vs/monaco.contribution-D2OdxNBt.js +1 -0
  72. package/dist/devtools-app/monaco/vs/monaco.contribution-DO3azKX8.js +1 -0
  73. package/dist/devtools-app/monaco/vs/monaco.contribution-EcChJV6a.js +1 -0
  74. package/dist/devtools-app/monaco/vs/monaco.contribution-qLAYrEOP.js +1 -0
  75. package/dist/devtools-app/monaco/vs/msdax-C38-sJlp.js +1 -0
  76. package/dist/devtools-app/monaco/vs/mysql-CdtbpvbG.js +1 -0
  77. package/dist/devtools-app/monaco/vs/nls.messages-loader.js +1 -0
  78. package/dist/devtools-app/monaco/vs/nls.messages.cs.js.js +17 -0
  79. package/dist/devtools-app/monaco/vs/nls.messages.de.js.js +17 -0
  80. package/dist/devtools-app/monaco/vs/nls.messages.es.js.js +17 -0
  81. package/dist/devtools-app/monaco/vs/nls.messages.fr.js.js +15 -0
  82. package/dist/devtools-app/monaco/vs/nls.messages.it.js.js +15 -0
  83. package/dist/devtools-app/monaco/vs/nls.messages.ja.js.js +17 -0
  84. package/dist/devtools-app/monaco/vs/nls.messages.js.js +10 -0
  85. package/dist/devtools-app/monaco/vs/nls.messages.ko.js.js +25 -0
  86. package/dist/devtools-app/monaco/vs/nls.messages.pl.js.js +17 -0
  87. package/dist/devtools-app/monaco/vs/nls.messages.pt-br.js.js +6 -0
  88. package/dist/devtools-app/monaco/vs/nls.messages.ru.js.js +17 -0
  89. package/dist/devtools-app/monaco/vs/nls.messages.tr.js.js +15 -0
  90. package/dist/devtools-app/monaco/vs/nls.messages.zh-cn.js.js +17 -0
  91. package/dist/devtools-app/monaco/vs/nls.messages.zh-tw.js.js +15 -0
  92. package/dist/devtools-app/monaco/vs/objective-c-CntZFaHX.js +1 -0
  93. package/dist/devtools-app/monaco/vs/pascal-r6kuqfl_.js +1 -0
  94. package/dist/devtools-app/monaco/vs/pascaligo-BiXoTmXh.js +1 -0
  95. package/dist/devtools-app/monaco/vs/perl-DABw_TcH.js +1 -0
  96. package/dist/devtools-app/monaco/vs/pgsql-me_jFXeX.js +1 -0
  97. package/dist/devtools-app/monaco/vs/php-D_kh-9LK.js +1 -0
  98. package/dist/devtools-app/monaco/vs/pla-VfZjczW0.js +1 -0
  99. package/dist/devtools-app/monaco/vs/postiats-BBSzz8Pk.js +1 -0
  100. package/dist/devtools-app/monaco/vs/powerquery-Dt-g_2cc.js +1 -0
  101. package/dist/devtools-app/monaco/vs/powershell-B-7ap1zc.js +1 -0
  102. package/dist/devtools-app/monaco/vs/protobuf-BmtuEB1A.js +2 -0
  103. package/dist/devtools-app/monaco/vs/pug-BRpRNeEb.js +1 -0
  104. package/dist/devtools-app/monaco/vs/python-Cr0UkIbn.js +1 -0
  105. package/dist/devtools-app/monaco/vs/qsharp-BzsFaUU9.js +1 -0
  106. package/dist/devtools-app/monaco/vs/r-f8dDdrp4.js +1 -0
  107. package/dist/devtools-app/monaco/vs/razor-BYAHOTkz.js +1 -0
  108. package/dist/devtools-app/monaco/vs/redis-fvZQY4PI.js +1 -0
  109. package/dist/devtools-app/monaco/vs/redshift-45Et0LQi.js +1 -0
  110. package/dist/devtools-app/monaco/vs/restructuredtext-C7UUFKFD.js +1 -0
  111. package/dist/devtools-app/monaco/vs/ruby-CZO8zYTz.js +1 -0
  112. package/dist/devtools-app/monaco/vs/rust-Bfetafyc.js +1 -0
  113. package/dist/devtools-app/monaco/vs/sb-3GYllVck.js +1 -0
  114. package/dist/devtools-app/monaco/vs/scala-foMgrKo1.js +1 -0
  115. package/dist/devtools-app/monaco/vs/scheme-CHdMtr7p.js +1 -0
  116. package/dist/devtools-app/monaco/vs/scss-C1cmLt9V.js +3 -0
  117. package/dist/devtools-app/monaco/vs/shell-ClXCKCEW.js +1 -0
  118. package/dist/devtools-app/monaco/vs/solidity-MZ6ExpPy.js +1 -0
  119. package/dist/devtools-app/monaco/vs/sophia-DWkuSsPQ.js +1 -0
  120. package/dist/devtools-app/monaco/vs/sparql-AUGFYSyk.js +1 -0
  121. package/dist/devtools-app/monaco/vs/sql-32GpJSV2.js +1 -0
  122. package/dist/devtools-app/monaco/vs/st-CuDFIVZ_.js +1 -0
  123. package/dist/devtools-app/monaco/vs/swift-n-2HociN.js +3 -0
  124. package/dist/devtools-app/monaco/vs/systemverilog-Ch4vA8Yt.js +1 -0
  125. package/dist/devtools-app/monaco/vs/tcl-D74tq1nH.js +1 -0
  126. package/dist/devtools-app/monaco/vs/tsMode-CZz1Umrk.js +11 -0
  127. package/dist/devtools-app/monaco/vs/twig-C6taOxMV.js +1 -0
  128. package/dist/devtools-app/monaco/vs/typescript-DfOrAzoV.js +1 -0
  129. package/dist/devtools-app/monaco/vs/typespec-D-PIh9Xw.js +1 -0
  130. package/dist/devtools-app/monaco/vs/vb-Dyb2648j.js +1 -0
  131. package/dist/devtools-app/monaco/vs/wgsl-BhLXMOR0.js +298 -0
  132. package/dist/devtools-app/monaco/vs/workers-DcJshg-q.js +1 -0
  133. package/dist/devtools-app/monaco/vs/xml-CdsdnY8S.js +1 -0
  134. package/dist/devtools-app/monaco/vs/yaml-DYGvmE88.js +1 -0
  135. package/dist/eslint-plugin/index.cjs +5 -2
  136. package/dist/eslint-plugin/index.mjs +5 -2
  137. package/dist/eslint-plugin/rules/prefer-unitless-values.cjs +217 -0
  138. package/dist/eslint-plugin/rules/prefer-unitless-values.mjs +217 -0
  139. package/dist/eslint-plugin/utils/api.cjs +3 -4
  140. package/dist/eslint-plugin/utils/api.mjs +2 -2
  141. package/dist/native/browser.cjs +14 -1
  142. package/dist/native/browser.mjs +14 -1
  143. package/dist/native/server.cjs +4 -4
  144. package/dist/native/server.mjs +4 -4
  145. package/dist/parser/classname/server.cjs +2 -0
  146. package/dist/parser/classname/server.mjs +2 -0
  147. package/dist/parser/jsx/server.cjs +13 -7
  148. package/dist/parser/jsx/server.mjs +13 -7
  149. package/dist/prop/at/server.cjs +6 -4
  150. package/dist/prop/at/server.mjs +6 -4
  151. package/dist/prop/at/shared.cjs +3 -3
  152. package/dist/prop/at/shared.mjs +3 -3
  153. package/dist/prop/bosswind/browser.cjs +3 -0
  154. package/dist/prop/bosswind/browser.mjs +3 -0
  155. package/dist/prop/bosswind/runtime-only.cjs +3 -0
  156. package/dist/prop/bosswind/runtime-only.mjs +3 -0
  157. package/dist/prop/bosswind/selectors.cjs +18 -0
  158. package/dist/prop/bosswind/selectors.mjs +16 -0
  159. package/dist/prop/bosswind/shared.cjs +93 -32
  160. package/dist/prop/bosswind/shared.mjs +94 -32
  161. package/dist/prop/child/server.cjs +3 -2
  162. package/dist/prop/child/server.mjs +3 -2
  163. package/dist/prop/css/server.cjs +2 -1
  164. package/dist/prop/css/server.mjs +2 -1
  165. package/dist/prop/pseudo/server.cjs +3 -2
  166. package/dist/prop/pseudo/server.mjs +3 -2
  167. package/dist/strategy/classname-first/browser.cjs +7 -1
  168. package/dist/strategy/classname-first/browser.mjs +7 -1
  169. package/dist/strategy/classname-first/runtime-only.cjs +15 -4
  170. package/dist/strategy/classname-first/runtime-only.mjs +15 -4
  171. package/dist/strategy/classname-first/server.cjs +1 -1
  172. package/dist/strategy/classname-first/server.mjs +1 -1
  173. package/dist/transform/cache.cjs +0 -3
  174. package/dist/transform/cache.mjs +0 -2
  175. package/dist/use/token/browser.cjs +17 -9
  176. package/dist/use/token/browser.mjs +18 -10
  177. package/dist/use/token/normalize.cjs +474 -0
  178. package/dist/use/token/normalize.mjs +473 -0
  179. package/dist/use/token/propMap.cjs +34 -5
  180. package/dist/use/token/propMap.mjs +34 -6
  181. package/dist/use/token/runtime-only.cjs +36 -47
  182. package/dist/use/token/runtime-only.mjs +37 -48
  183. package/dist/use/token/server.cjs +84 -17
  184. package/dist/use/token/server.mjs +85 -19
  185. package/dist/use/token/vars.cjs +14 -2
  186. package/dist/use/token/vars.mjs +15 -2
  187. package/package.json +13 -7
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Boss CSS contributors
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 +1,146 @@
1
- boss-css
1
+ <p align="center">
2
+ <img src="./boss-logo.webp" alt="Boss CSS logo" width="520" />
3
+ </p>
4
+
5
+ <h1 align="center">Boss CSS</h1>
6
+
7
+ <p align="center">
8
+ Polymorphic, usage-driven CSS-in-JS.
9
+ </p>
10
+
11
+ <p align="center">
12
+ <strong>Warning:</strong> Boss CSS is not production-ready yet. Expect breaking changes and stability issues.
13
+ </p>
14
+
15
+ <p align="center">
16
+ <a href="https://www.npmjs.com/package/boss-css"><img src="https://img.shields.io/npm/v/boss-css.svg" alt="npm version" /></a>
17
+ <a href="./package.json"><img src="https://img.shields.io/npm/l/boss-css.svg" alt="license" /></a>
18
+ </p>
19
+
20
+ <p align="center">
21
+ <a href="https://bosscss.com">Website</a> | <a href="https://bosscss.com/docs">Documentation</a>
22
+ </p>
23
+
24
+ ## Table of Contents
25
+
26
+ - [Key Features](#key-features)
27
+ - [Quick Start](#quick-start)
28
+ - [Examples](#examples)
29
+ - [Strategy Modes](#strategy-modes)
30
+ - [License](#license)
31
+
32
+ ## Key Features
33
+
34
+ - Polymorphic `$$` authoring with framework-aware runtime adapters.
35
+ - Style props and className parsing in one unified API.
36
+ - Strong generated TypeScript types for style props and prepared components.
37
+ - Plugin-driven parser and prop pipeline (`parser`, `prop`, `strategy`, `use`).
38
+ - Server output and browser runtime support with configurable strategy behavior.
39
+ - Zero-runtime compilation
40
+ - Runtime-only mode for client CSS injection when needed.
41
+ - Token support, pseudo selectors, media/breakpoint props, and nested child selectors.
42
+ - CLI tooling for init/compile/dev workflows.
43
+
44
+ ## Quick Start
45
+
46
+ Install and scaffold:
47
+
48
+ ```bash
49
+ npx boss-css init
50
+ ```
51
+
52
+ Import the generated runtime once near your app root:
53
+
54
+ ```tsx
55
+ import './.bo$$'
56
+ ```
57
+
58
+ ## Examples
59
+
60
+ Write styles directly with `$$`:
61
+
62
+ ```tsx
63
+ export default function Demo() {
64
+ return (
65
+ <$$
66
+ display="flex"
67
+ gap={12}
68
+ padding={16}
69
+ borderRadius={12}
70
+ backgroundColor="#111"
71
+ color="#fff"
72
+ hover={{ backgroundColor: '#222' }}
73
+ >
74
+ Hello Boss CSS
75
+ </$$>
76
+ )
77
+ }
78
+ ```
79
+
80
+ ClassName syntax (`prop:value` tokens):
81
+
82
+ ```tsx
83
+ export function Badge() {
84
+ return (
85
+ <span className="display:inline-block padding:6_10 border-radius:999 color:white background-color:#ed4b9b">
86
+ New
87
+ </span>
88
+ )
89
+ }
90
+ ```
91
+
92
+ Grouped pseudo and responsive className:
93
+
94
+ ```tsx
95
+ export function Button() {
96
+ return (
97
+ <button className="mobile:hover:{color:white;background-color:black} hover:{text-decoration:underline;color:red}">
98
+ Hover me
99
+ </button>
100
+ )
101
+ }
102
+ ```
103
+
104
+ Mix static className and dynamic props:
105
+
106
+ ```tsx
107
+ export function Mixed({ bgColor }: { bgColor: string }) {
108
+ return <div className="display:flex gap:12 border-radius:12" backgroundColor={bgColor} />
109
+ }
110
+ ```
111
+
112
+ Compose className conditionals with `cx`:
113
+
114
+ ```tsx
115
+ import { cx } from 'boss-css/variants'
116
+
117
+ const className = cx('display:flex gap:8', { 'hover:color:purple': true })
118
+ ```
119
+
120
+ Bosswind plugin for Tailwind-like utilities:
121
+
122
+ ```tsx
123
+ const Box = () => <div className="flex w:100 bg:blue-500 p:4 hover:bg:blue-700">Tailwind-like Box using classNames</div>
124
+
125
+ const BoxProps = () => (
126
+ <$$ flex width="100" bg="blue-500" p="4" hover={{ bg: 'blue-700' }}>
127
+ Tailwind-like Box using props
128
+ </$$>
129
+ )
130
+ ```
131
+
132
+ ## Strategy Modes
133
+
134
+ Boss CSS supports multiple output strategies:
135
+
136
+ - `inline-first` (default): Inline everything that's possible => smallest CSS output, lowest possible unused styles,
137
+ instant critical CSS.
138
+ - `classname-first`: Use class names everywhere possible, variables for dynamic cases.
139
+ - `classname-only`: Static class parsing with zero runtime output. (aka TailwindCSS).
140
+ - `runtime`: Runtime-only or hybrid behavior, for cases where styles need to be generated at runtime.
141
+
142
+ Read more: https://bosscss.com/docs/concepts/runtime-strategy
143
+
144
+ ## License
145
+
146
+ MIT
@@ -34,6 +34,7 @@ const STATIC_DOC = `### Syntax
34
34
 
35
35
  ### Values
36
36
  - Prefer unitless numbers (padding:12) and use _ for space-separated values (padding:10_20).
37
+ - Avoid hardcoded default unit suffixes in class tokens (border:1_solid, not border:1px_solid).
37
38
  - Prefer arrays for shorthands (padding={[0, 10]}).
38
39
  - For custom shadows, use arrays (boxShadow={[1, 1, 0, '#fff']}).
39
40
 
@@ -32,6 +32,7 @@ const STATIC_DOC = `### Syntax
32
32
 
33
33
  ### Values
34
34
  - Prefer unitless numbers (padding:12) and use _ for space-separated values (padding:10_20).
35
+ - Avoid hardcoded default unit suffixes in class tokens (border:1_solid, not border:1px_solid).
35
36
  - Prefer arrays for shorthands (padding={[0, 10]}).
36
37
  - For custom shadows, use arrays (boxShadow={[1, 1, 0, '#fff']}).
37
38
 
@@ -19,6 +19,7 @@ Apply Boss CSS props cleanly with tokens and selectors.
19
19
  - In classname-first, return $$.token.* from dynamic functions when using tokens.
20
20
  - Use child for nested selectors instead of manual selector strings.
21
21
  - Prefer unitless values (padding:12). Use _ for spaces (padding:10_20).
22
+ - Avoid hardcoded default unit suffixes in class tokens (border:1_solid, not border:1px_solid).
22
23
  - Prefer arrays for shorthands (padding={[0, 10]}).
23
24
 
24
25
  # References
@@ -128,6 +129,7 @@ Write correct className tokens and shorthands.
128
129
  # Guidance
129
130
  - className tokens are mostly CSS prop:value (1:1 with props).
130
131
  - Use unitless values (padding:12), and _ for space-separated values (padding:10_20).
132
+ - Avoid hardcoded default unit suffixes in class tokens (border:1_solid, not border:1px_solid).
131
133
  - Prefer shorthand pseudos and breakpoints: hover:color:red, mobile:gap:12.
132
134
  - For @at, prefer shorthand (mobile:...) over at:mobile:... when available.
133
135
 
@@ -145,6 +147,7 @@ Use Boss-friendly value forms for consistent output.
145
147
 
146
148
  # Guidance
147
149
  - Prefer unitless numbers for numeric props (padding:12).
150
+ - Avoid hardcoded default unit suffixes in class tokens (border:1_solid, not border:1px_solid).
148
151
  - Use arrays for shorthands: padding={[0, 10]}.
149
152
  - Use token shorthands when available (boxShadow="md").
150
153
  - For custom shadow values, use arrays: boxShadow={[1, 1, 0, '#fff']}.
@@ -18,6 +18,7 @@ Apply Boss CSS props cleanly with tokens and selectors.
18
18
  - In classname-first, return $$.token.* from dynamic functions when using tokens.
19
19
  - Use child for nested selectors instead of manual selector strings.
20
20
  - Prefer unitless values (padding:12). Use _ for spaces (padding:10_20).
21
+ - Avoid hardcoded default unit suffixes in class tokens (border:1_solid, not border:1px_solid).
21
22
  - Prefer arrays for shorthands (padding={[0, 10]}).
22
23
 
23
24
  # References
@@ -127,6 +128,7 @@ Write correct className tokens and shorthands.
127
128
  # Guidance
128
129
  - className tokens are mostly CSS prop:value (1:1 with props).
129
130
  - Use unitless values (padding:12), and _ for space-separated values (padding:10_20).
131
+ - Avoid hardcoded default unit suffixes in class tokens (border:1_solid, not border:1px_solid).
130
132
  - Prefer shorthand pseudos and breakpoints: hover:color:red, mobile:gap:12.
131
133
  - For @at, prefer shorthand (mobile:...) over at:mobile:... when available.
132
134
 
@@ -144,6 +146,7 @@ Use Boss-friendly value forms for consistent output.
144
146
 
145
147
  # Guidance
146
148
  - Prefer unitless numbers for numeric props (padding:12).
149
+ - Avoid hardcoded default unit suffixes in class tokens (border:1_solid, not border:1px_solid).
147
150
  - Use arrays for shorthands: padding={[0, 10]}.
148
151
  - Use token shorthands when available (boxShadow="md").
149
152
  - For custom shadow values, use arrays: boxShadow={[1, 1, 0, '#fff']}.
@@ -301,7 +301,7 @@ const init = async (config) => {
301
301
  enabled: shouldConfigureEslint
302
302
  });
303
303
  const outputDir = node_path.default.resolve(cwd, normalizedConfigDir);
304
- if (!await confirmOverwriteIfExists(outputDir, flags.yes)) return false;
304
+ const overwriteMode = await confirmOverwriteIfExists(outputDir, flags.yes, flags.overwrite);
305
305
  const contentGlobs = buildContentGlobs({
306
306
  srcRoot: normalizedSrcRoot,
307
307
  isNext
@@ -353,7 +353,8 @@ const init = async (config) => {
353
353
  srcRoot: normalizedSrcRoot,
354
354
  configDir: normalizedConfigDir,
355
355
  globalsEnabled,
356
- cssAutoLoad
356
+ cssAutoLoad,
357
+ overwriteConfigDir: overwriteMode === "overwrite"
357
358
  });
358
359
  await generateRuntime({
359
360
  outputDir,
@@ -362,7 +363,8 @@ const init = async (config) => {
362
363
  contentGlobs,
363
364
  globalsEnabled,
364
365
  cssAutoLoad,
365
- selectedStrategyId
366
+ selectedStrategyId,
367
+ overwriteConfigDir: overwriteMode === "overwrite"
366
368
  });
367
369
  if (isStencil) await ensureStencilSetup({
368
370
  cwd,
@@ -525,7 +527,8 @@ const parseFlags = (argv) => {
525
527
  strategy: getStringArg(argv, ["strategy"]),
526
528
  postcss: normalizePostcssMode(getArg(argv, ["postcss"])) ?? void 0,
527
529
  globals: normalizeBooleanArg(getArg(argv, ["globals"])),
528
- eslintPlugin: normalizeBooleanArg(getArg(argv, ["eslintPlugin", "eslint-plugin"]))
530
+ eslintPlugin: normalizeBooleanArg(getArg(argv, ["eslintPlugin", "eslint-plugin"])),
531
+ overwrite: normalizeBooleanArg(getArg(argv, ["overwrite"]))
529
532
  };
530
533
  };
531
534
  const getArg = (argv, keys) => {
@@ -1304,7 +1307,7 @@ const findMatchingIndex = (content, startIndex, openChar, closeChar) => {
1304
1307
  }
1305
1308
  return -1;
1306
1309
  };
1307
- const writeInitFiles = async ({ outputDir, configFolder, contentGlobs, pluginState, selectedStrategyId, isNext, postcssMode, postcssDetection, includeAutoprefixer, packageJson, dirDependencies, usePostcssOptions, srcRoot, configDir, globalsEnabled, cssAutoLoad }) => {
1310
+ const writeInitFiles = async ({ outputDir, configFolder, contentGlobs, pluginState, selectedStrategyId, isNext, postcssMode, postcssDetection, includeAutoprefixer, packageJson, dirDependencies, usePostcssOptions, srcRoot, configDir, globalsEnabled, cssAutoLoad, overwriteConfigDir }) => {
1308
1311
  await node_fs_promises.default.mkdir(outputDir, { recursive: true });
1309
1312
  const isRuntimeStrategy = selectedStrategyId === "runtime-only" || selectedStrategyId === "runtime-hybrid";
1310
1313
  const configText = (0, pluvo.default)(require_init.configTemplate, {
@@ -1318,9 +1321,9 @@ const writeInitFiles = async ({ outputDir, configFolder, contentGlobs, pluginSta
1318
1321
  runtimeOnly: selectedStrategyId === "runtime-only",
1319
1322
  cssAutoLoad
1320
1323
  }, { commentStyles: INIT_COMMENT_STYLES });
1321
- await writeFile(node_path.default.join(outputDir, "config.js"), configText);
1322
- await writeFile(node_path.default.join(outputDir, "jsconfig.json"), require_init.jsconfigTemplate);
1323
- await writeFile(node_path.default.join(outputDir, "package.json"), require_init.packageTemplate);
1324
+ await writeFile(node_path.default.join(outputDir, "config.js"), configText, overwriteConfigDir);
1325
+ await writeFile(node_path.default.join(outputDir, "jsconfig.json"), require_init.jsconfigTemplate, overwriteConfigDir);
1326
+ await writeFile(node_path.default.join(outputDir, "package.json"), require_init.packageTemplate, overwriteConfigDir);
1324
1327
  await ensureFile(node_path.default.join(outputDir, "styles.css"));
1325
1328
  if (postcssMode === "auto") {
1326
1329
  if (!postcssDetection.hasConfigFile && !postcssDetection.hasPackageConfig) {
@@ -1530,22 +1533,35 @@ const getImportInsertIndex = (lines) => {
1530
1533
  }
1531
1534
  return index;
1532
1535
  };
1533
- const generateRuntime = async ({ outputDir, configFolder, pluginState, contentGlobs, globalsEnabled, cssAutoLoad, selectedStrategyId }) => {
1536
+ const generateRuntime = async ({ outputDir, configFolder, pluginState, contentGlobs, globalsEnabled, cssAutoLoad, selectedStrategyId, overwriteConfigDir }) => {
1534
1537
  if (selectedStrategyId === "classname-only") return;
1535
1538
  const enabledPlugins = pluginState.filter((plugin) => plugin.enabled);
1539
+ const hasJsxPlugin = enabledPlugins.some((plugin) => plugin.id === "jsx");
1536
1540
  const modules = enabledPlugins.map((plugin) => PLUGIN_MODULES[plugin.id]).filter(Boolean);
1537
- if (globalsEnabled && enabledPlugins.some((plugin) => plugin.id === "jsx")) require_parser_jsx_server.settings.set?.("globals", true);
1538
- if (enabledPlugins.some((plugin) => plugin.id === "jsx")) require_parser_jsx_server.settings.set?.("emitRuntime", true);
1541
+ if (hasJsxPlugin) require_parser_jsx_server.settings.set?.("emitRuntime", true);
1539
1542
  if (enabledPlugins.some((plugin) => plugin.id === "inline-first")) require_strategy_inline_first_server.settings.set?.("emitRuntime", true);
1540
1543
  if (enabledPlugins.some((plugin) => plugin.id === "classname-first")) require_strategy_classname_first_server.settings.set?.("emitRuntime", true);
1541
1544
  const api = await require_api_server.createApi({
1542
1545
  folder: configFolder,
1543
1546
  plugins: modules,
1544
1547
  content: contentGlobs,
1548
+ jsx: hasJsxPlugin ? { globals: globalsEnabled } : void 0,
1545
1549
  css: cssAutoLoad ? void 0 : { autoLoad: false }
1546
1550
  }, true);
1547
- await api.file.js.write();
1548
- if (api.file.native?.hasContent) await api.file.native.write();
1551
+ const jsText = api.file.js.text;
1552
+ if (jsText) {
1553
+ await writeFile(node_path.default.join(outputDir, api.file.js.options.path), jsText, overwriteConfigDir);
1554
+ const dtsText = api.file.js.dts.text;
1555
+ if (dtsText) await writeFile(node_path.default.join(outputDir, api.file.js.dts.options.path), dtsText, overwriteConfigDir);
1556
+ }
1557
+ if (api.file.native?.hasContent) {
1558
+ const nativeText = api.file.native.text;
1559
+ if (nativeText) {
1560
+ await writeFile(node_path.default.join(outputDir, api.file.native.options.path), nativeText, overwriteConfigDir);
1561
+ const nativeDtsText = api.file.native.dts.text;
1562
+ if (nativeDtsText) await writeFile(node_path.default.join(outputDir, api.file.native.dts.options.path), nativeDtsText, overwriteConfigDir);
1563
+ }
1564
+ }
1549
1565
  };
1550
1566
  const warnIfPostcssPluginMissing = async (configFilePath) => {
1551
1567
  if ((await node_fs_promises.default.readFile(configFilePath, "utf-8")).includes("boss-css/postcss")) return;
@@ -1696,15 +1712,17 @@ const getIndentFromIndex = (content, index) => {
1696
1712
  const match = content.slice(lineStart + 1).match(/^\s+/);
1697
1713
  return match ? match[0] : "";
1698
1714
  };
1699
- const confirmOverwriteIfExists = async (dirPath, yes) => {
1700
- if (!await exists(dirPath)) return true;
1701
- if (yes) return true;
1702
- const shouldContinue = await (0, _clack_prompts.confirm)({
1703
- message: `Existing ${node_path.default.basename(dirPath)} folder detected. Overwrite its contents?`,
1715
+ const confirmOverwriteIfExists = async (dirPath, yes, overwrite) => {
1716
+ if (!await exists(dirPath)) return "overwrite";
1717
+ if (overwrite === false) return "merge";
1718
+ if (overwrite === true) return "overwrite";
1719
+ if (yes) return "overwrite";
1720
+ const shouldOverwrite = await (0, _clack_prompts.confirm)({
1721
+ message: `Existing ${node_path.default.basename(dirPath)} folder detected. Overwrite its contents? (No keeps existing files)`,
1704
1722
  initialValue: false
1705
1723
  });
1706
- require_utils.cancelIf(shouldContinue);
1707
- return shouldContinue;
1724
+ require_utils.cancelIf(shouldOverwrite);
1725
+ return shouldOverwrite ? "overwrite" : "merge";
1708
1726
  };
1709
1727
  const readPackageJson = async (cwd) => {
1710
1728
  const filePath = node_path.default.join(cwd, "package.json");
@@ -1728,8 +1746,12 @@ const writePackageJson = async (cwd, data, indent, newline) => {
1728
1746
  const output = JSON.stringify(data, null, indent) + (newline || "\n");
1729
1747
  await node_fs_promises.default.writeFile(filePath, output);
1730
1748
  };
1731
- const writeFile = async (filePath, content) => {
1749
+ const writeFile = async (filePath, content, overwrite = true) => {
1732
1750
  await node_fs_promises.default.mkdir(node_path.default.dirname(filePath), { recursive: true });
1751
+ if (!overwrite) try {
1752
+ await node_fs_promises.default.access(filePath);
1753
+ return;
1754
+ } catch {}
1733
1755
  await node_fs_promises.default.writeFile(filePath, content.trimEnd() + "\n");
1734
1756
  };
1735
1757
  const ensureFile = async (filePath) => {
@@ -297,7 +297,7 @@ const init = async (config) => {
297
297
  enabled: shouldConfigureEslint
298
298
  });
299
299
  const outputDir = path.resolve(cwd, normalizedConfigDir);
300
- if (!await confirmOverwriteIfExists(outputDir, flags.yes)) return false;
300
+ const overwriteMode = await confirmOverwriteIfExists(outputDir, flags.yes, flags.overwrite);
301
301
  const contentGlobs = buildContentGlobs({
302
302
  srcRoot: normalizedSrcRoot,
303
303
  isNext
@@ -349,7 +349,8 @@ const init = async (config) => {
349
349
  srcRoot: normalizedSrcRoot,
350
350
  configDir: normalizedConfigDir,
351
351
  globalsEnabled,
352
- cssAutoLoad
352
+ cssAutoLoad,
353
+ overwriteConfigDir: overwriteMode === "overwrite"
353
354
  });
354
355
  await generateRuntime({
355
356
  outputDir,
@@ -358,7 +359,8 @@ const init = async (config) => {
358
359
  contentGlobs,
359
360
  globalsEnabled,
360
361
  cssAutoLoad,
361
- selectedStrategyId
362
+ selectedStrategyId,
363
+ overwriteConfigDir: overwriteMode === "overwrite"
362
364
  });
363
365
  if (isStencil) await ensureStencilSetup({
364
366
  cwd,
@@ -521,7 +523,8 @@ const parseFlags = (argv) => {
521
523
  strategy: getStringArg(argv, ["strategy"]),
522
524
  postcss: normalizePostcssMode(getArg(argv, ["postcss"])) ?? void 0,
523
525
  globals: normalizeBooleanArg(getArg(argv, ["globals"])),
524
- eslintPlugin: normalizeBooleanArg(getArg(argv, ["eslintPlugin", "eslint-plugin"]))
526
+ eslintPlugin: normalizeBooleanArg(getArg(argv, ["eslintPlugin", "eslint-plugin"])),
527
+ overwrite: normalizeBooleanArg(getArg(argv, ["overwrite"]))
525
528
  };
526
529
  };
527
530
  const getArg = (argv, keys) => {
@@ -1300,7 +1303,7 @@ const findMatchingIndex = (content, startIndex, openChar, closeChar) => {
1300
1303
  }
1301
1304
  return -1;
1302
1305
  };
1303
- const writeInitFiles = async ({ outputDir, configFolder, contentGlobs, pluginState, selectedStrategyId, isNext, postcssMode, postcssDetection, includeAutoprefixer, packageJson, dirDependencies, usePostcssOptions, srcRoot, configDir, globalsEnabled, cssAutoLoad }) => {
1306
+ const writeInitFiles = async ({ outputDir, configFolder, contentGlobs, pluginState, selectedStrategyId, isNext, postcssMode, postcssDetection, includeAutoprefixer, packageJson, dirDependencies, usePostcssOptions, srcRoot, configDir, globalsEnabled, cssAutoLoad, overwriteConfigDir }) => {
1304
1307
  await fs.mkdir(outputDir, { recursive: true });
1305
1308
  const isRuntimeStrategy = selectedStrategyId === "runtime-only" || selectedStrategyId === "runtime-hybrid";
1306
1309
  const configText = pluvo(configTemplate, {
@@ -1314,9 +1317,9 @@ const writeInitFiles = async ({ outputDir, configFolder, contentGlobs, pluginSta
1314
1317
  runtimeOnly: selectedStrategyId === "runtime-only",
1315
1318
  cssAutoLoad
1316
1319
  }, { commentStyles: INIT_COMMENT_STYLES });
1317
- await writeFile(path.join(outputDir, "config.js"), configText);
1318
- await writeFile(path.join(outputDir, "jsconfig.json"), jsconfigTemplate);
1319
- await writeFile(path.join(outputDir, "package.json"), packageTemplate);
1320
+ await writeFile(path.join(outputDir, "config.js"), configText, overwriteConfigDir);
1321
+ await writeFile(path.join(outputDir, "jsconfig.json"), jsconfigTemplate, overwriteConfigDir);
1322
+ await writeFile(path.join(outputDir, "package.json"), packageTemplate, overwriteConfigDir);
1320
1323
  await ensureFile(path.join(outputDir, "styles.css"));
1321
1324
  if (postcssMode === "auto") {
1322
1325
  if (!postcssDetection.hasConfigFile && !postcssDetection.hasPackageConfig) {
@@ -1526,22 +1529,35 @@ const getImportInsertIndex = (lines) => {
1526
1529
  }
1527
1530
  return index;
1528
1531
  };
1529
- const generateRuntime = async ({ outputDir, configFolder, pluginState, contentGlobs, globalsEnabled, cssAutoLoad, selectedStrategyId }) => {
1532
+ const generateRuntime = async ({ outputDir, configFolder, pluginState, contentGlobs, globalsEnabled, cssAutoLoad, selectedStrategyId, overwriteConfigDir }) => {
1530
1533
  if (selectedStrategyId === "classname-only") return;
1531
1534
  const enabledPlugins = pluginState.filter((plugin) => plugin.enabled);
1535
+ const hasJsxPlugin = enabledPlugins.some((plugin) => plugin.id === "jsx");
1532
1536
  const modules = enabledPlugins.map((plugin) => PLUGIN_MODULES[plugin.id]).filter(Boolean);
1533
- if (globalsEnabled && enabledPlugins.some((plugin) => plugin.id === "jsx")) settings.set?.("globals", true);
1534
- if (enabledPlugins.some((plugin) => plugin.id === "jsx")) settings.set?.("emitRuntime", true);
1537
+ if (hasJsxPlugin) settings.set?.("emitRuntime", true);
1535
1538
  if (enabledPlugins.some((plugin) => plugin.id === "inline-first")) settings$1.set?.("emitRuntime", true);
1536
1539
  if (enabledPlugins.some((plugin) => plugin.id === "classname-first")) settings$2.set?.("emitRuntime", true);
1537
1540
  const api = await createApi({
1538
1541
  folder: configFolder,
1539
1542
  plugins: modules,
1540
1543
  content: contentGlobs,
1544
+ jsx: hasJsxPlugin ? { globals: globalsEnabled } : void 0,
1541
1545
  css: cssAutoLoad ? void 0 : { autoLoad: false }
1542
1546
  }, true);
1543
- await api.file.js.write();
1544
- if (api.file.native?.hasContent) await api.file.native.write();
1547
+ const jsText = api.file.js.text;
1548
+ if (jsText) {
1549
+ await writeFile(path.join(outputDir, api.file.js.options.path), jsText, overwriteConfigDir);
1550
+ const dtsText = api.file.js.dts.text;
1551
+ if (dtsText) await writeFile(path.join(outputDir, api.file.js.dts.options.path), dtsText, overwriteConfigDir);
1552
+ }
1553
+ if (api.file.native?.hasContent) {
1554
+ const nativeText = api.file.native.text;
1555
+ if (nativeText) {
1556
+ await writeFile(path.join(outputDir, api.file.native.options.path), nativeText, overwriteConfigDir);
1557
+ const nativeDtsText = api.file.native.dts.text;
1558
+ if (nativeDtsText) await writeFile(path.join(outputDir, api.file.native.dts.options.path), nativeDtsText, overwriteConfigDir);
1559
+ }
1560
+ }
1545
1561
  };
1546
1562
  const warnIfPostcssPluginMissing = async (configFilePath) => {
1547
1563
  if ((await fs.readFile(configFilePath, "utf-8")).includes("boss-css/postcss")) return;
@@ -1692,15 +1708,17 @@ const getIndentFromIndex = (content, index) => {
1692
1708
  const match = content.slice(lineStart + 1).match(/^\s+/);
1693
1709
  return match ? match[0] : "";
1694
1710
  };
1695
- const confirmOverwriteIfExists = async (dirPath, yes) => {
1696
- if (!await exists(dirPath)) return true;
1697
- if (yes) return true;
1698
- const shouldContinue = await confirm({
1699
- message: `Existing ${path.basename(dirPath)} folder detected. Overwrite its contents?`,
1711
+ const confirmOverwriteIfExists = async (dirPath, yes, overwrite) => {
1712
+ if (!await exists(dirPath)) return "overwrite";
1713
+ if (overwrite === false) return "merge";
1714
+ if (overwrite === true) return "overwrite";
1715
+ if (yes) return "overwrite";
1716
+ const shouldOverwrite = await confirm({
1717
+ message: `Existing ${path.basename(dirPath)} folder detected. Overwrite its contents? (No keeps existing files)`,
1700
1718
  initialValue: false
1701
1719
  });
1702
- cancelIf(shouldContinue);
1703
- return shouldContinue;
1720
+ cancelIf(shouldOverwrite);
1721
+ return shouldOverwrite ? "overwrite" : "merge";
1704
1722
  };
1705
1723
  const readPackageJson = async (cwd) => {
1706
1724
  const filePath = path.join(cwd, "package.json");
@@ -1724,8 +1742,12 @@ const writePackageJson = async (cwd, data, indent, newline) => {
1724
1742
  const output = JSON.stringify(data, null, indent) + (newline || "\n");
1725
1743
  await fs.writeFile(filePath, output);
1726
1744
  };
1727
- const writeFile = async (filePath, content) => {
1745
+ const writeFile = async (filePath, content, overwrite = true) => {
1728
1746
  await fs.mkdir(path.dirname(filePath), { recursive: true });
1747
+ if (!overwrite) try {
1748
+ await fs.access(filePath);
1749
+ return;
1750
+ } catch {}
1729
1751
  await fs.writeFile(filePath, content.trimEnd() + "\n");
1730
1752
  };
1731
1753
  const ensureFile = async (filePath) => {
@@ -8,15 +8,15 @@ import * as /* @@@ echo $.plugin.importName */token/* @@@ endecho */ from '/* @@
8
8
  // @@@ endif
9
9
  // @@@ endeach
10
10
 
11
- // @@@ if $.jsxEnabled && $.globalsEnabled
12
- // globalThis.$$
13
- jsx.settings.set('globals', true)
14
- // @@@ endif
15
-
16
11
  /** @type {import('boss-css/api/config').UserConfig} */
17
12
  export default {
18
13
  // Path from your project root
19
14
  folder: /* @@@ echo JSON.stringify($.folder) */'./.bo$$'/* @@@ endecho */,
15
+ // @@@ if $.jsxEnabled
16
+ jsx: {
17
+ globals: /* @@@ echo $.globalsEnabled ? 'true' : 'false' */true/* @@@ endecho */,
18
+ },
19
+ // @@@ endif
20
20
  // @@@ if $.cssAutoLoad === false
21
21
  css: {
22
22
  autoLoad: false,
@@ -7,15 +7,15 @@ import * as /* @@@ echo $.plugin.importName */token/* @@@ endecho */ from '/* @@
7
7
  // @@@ endif
8
8
  // @@@ endeach
9
9
 
10
- // @@@ if $.jsxEnabled && $.globalsEnabled
11
- // globalThis.$$
12
- jsx.settings.set('globals', true)
13
- // @@@ endif
14
-
15
10
  /** @type {import('boss-css/api/config').UserConfig} */
16
11
  export default {
17
12
  // Path from your project root
18
13
  folder: /* @@@ echo JSON.stringify($.folder) */'./.bo$$'/* @@@ endecho */,
14
+ // @@@ if $.jsxEnabled
15
+ jsx: {
16
+ globals: /* @@@ echo $.globalsEnabled ? 'true' : 'false' */true/* @@@ endecho */,
17
+ },
18
+ // @@@ endif
19
19
  // @@@ if $.cssAutoLoad === false
20
20
  css: {
21
21
  autoLoad: false,
@@ -465,7 +465,8 @@ const buildInlineFirstOutput = (tree, tag, state) => {
465
465
  if (!expr) continue;
466
466
  if (shouldInline) styleProps.set(propName, expr);
467
467
  else {
468
- classNames.add(state.api.contextToClassName(propName, null, contexts, false, state.api.selectorPrefix));
468
+ const selectorName = prop.selectorName ?? propName;
469
+ classNames.add(state.api.contextToClassName(selectorName, null, contexts, false, state.api.selectorPrefix));
469
470
  styleProps.set(state.api.contextToCSSVariable(propName, null, contexts, state.api.selectorPrefix), expr);
470
471
  }
471
472
  }
@@ -500,7 +501,8 @@ const buildClassnameFirstOutput = (tree, tag, state) => {
500
501
  const isDynamicFn = prop.dynamic && prop.isFn;
501
502
  const selectorValue = isDynamicFn ? null : resolveSelectorValue(prop);
502
503
  const propName = resolved.name;
503
- classNames.add(state.api.contextToClassName(propName, selectorValue, contexts, false, state.api.selectorPrefix));
504
+ const selectorName = prop.selectorName ?? propName;
505
+ classNames.add(state.api.contextToClassName(selectorName, selectorValue, contexts, false, state.api.selectorPrefix));
504
506
  if (!isDynamicFn) continue;
505
507
  const expr = propToDynamicExpression(prop, propName, state);
506
508
  if (!expr) continue;
@@ -464,7 +464,8 @@ const buildInlineFirstOutput = (tree, tag, state) => {
464
464
  if (!expr) continue;
465
465
  if (shouldInline) styleProps.set(propName, expr);
466
466
  else {
467
- classNames.add(state.api.contextToClassName(propName, null, contexts, false, state.api.selectorPrefix));
467
+ const selectorName = prop.selectorName ?? propName;
468
+ classNames.add(state.api.contextToClassName(selectorName, null, contexts, false, state.api.selectorPrefix));
468
469
  styleProps.set(state.api.contextToCSSVariable(propName, null, contexts, state.api.selectorPrefix), expr);
469
470
  }
470
471
  }
@@ -499,7 +500,8 @@ const buildClassnameFirstOutput = (tree, tag, state) => {
499
500
  const isDynamicFn = prop.dynamic && prop.isFn;
500
501
  const selectorValue = isDynamicFn ? null : resolveSelectorValue(prop);
501
502
  const propName = resolved.name;
502
- classNames.add(state.api.contextToClassName(propName, selectorValue, contexts, false, state.api.selectorPrefix));
503
+ const selectorName = prop.selectorName ?? propName;
504
+ classNames.add(state.api.contextToClassName(selectorName, selectorValue, contexts, false, state.api.selectorPrefix));
503
505
  if (!isDynamicFn) continue;
504
506
  const expr = propToDynamicExpression(prop, propName, state);
505
507
  if (!expr) continue;