@tenphi/tasty 0.1.0

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 (359) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +236 -0
  3. package/dist/_virtual/_rolldown/runtime.mjs +7 -0
  4. package/dist/chunks/cacheKey.d.ts +1 -0
  5. package/dist/chunks/cacheKey.js +70 -0
  6. package/dist/chunks/cacheKey.js.map +1 -0
  7. package/dist/chunks/cacheKey.mjs +70 -0
  8. package/dist/chunks/cacheKey.mjs.map +1 -0
  9. package/dist/chunks/definitions.d.ts +37 -0
  10. package/dist/chunks/definitions.js +260 -0
  11. package/dist/chunks/definitions.js.map +1 -0
  12. package/dist/chunks/definitions.mjs +260 -0
  13. package/dist/chunks/definitions.mjs.map +1 -0
  14. package/dist/chunks/index.d.ts +3 -0
  15. package/dist/chunks/renderChunk.d.ts +2 -0
  16. package/dist/chunks/renderChunk.js +61 -0
  17. package/dist/chunks/renderChunk.js.map +1 -0
  18. package/dist/chunks/renderChunk.mjs +61 -0
  19. package/dist/chunks/renderChunk.mjs.map +1 -0
  20. package/dist/config.d.ts +279 -0
  21. package/dist/config.js +400 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/config.mjs +231 -0
  24. package/dist/config.mjs.map +1 -0
  25. package/dist/css-writer.d.mts +45 -0
  26. package/dist/css-writer.mjs +74 -0
  27. package/dist/css-writer.mjs.map +1 -0
  28. package/dist/debug.d.ts +204 -0
  29. package/dist/debug.js +733 -0
  30. package/dist/debug.js.map +1 -0
  31. package/dist/extractor.d.mts +24 -0
  32. package/dist/extractor.mjs +150 -0
  33. package/dist/extractor.mjs.map +1 -0
  34. package/dist/hooks/index.d.ts +5 -0
  35. package/dist/hooks/useGlobalStyles.d.ts +27 -0
  36. package/dist/hooks/useGlobalStyles.js +56 -0
  37. package/dist/hooks/useGlobalStyles.js.map +1 -0
  38. package/dist/hooks/useKeyframes.d.ts +56 -0
  39. package/dist/hooks/useKeyframes.js +54 -0
  40. package/dist/hooks/useKeyframes.js.map +1 -0
  41. package/dist/hooks/useProperty.d.ts +79 -0
  42. package/dist/hooks/useProperty.js +91 -0
  43. package/dist/hooks/useProperty.js.map +1 -0
  44. package/dist/hooks/useRawCSS.d.ts +53 -0
  45. package/dist/hooks/useRawCSS.js +28 -0
  46. package/dist/hooks/useRawCSS.js.map +1 -0
  47. package/dist/hooks/useStyles.d.ts +40 -0
  48. package/dist/hooks/useStyles.js +169 -0
  49. package/dist/hooks/useStyles.js.map +1 -0
  50. package/dist/index.d.ts +38 -0
  51. package/dist/index.js +30 -0
  52. package/dist/injector/index.d.ts +157 -0
  53. package/dist/injector/index.js +154 -0
  54. package/dist/injector/index.js.map +1 -0
  55. package/dist/injector/injector.d.ts +139 -0
  56. package/dist/injector/injector.js +404 -0
  57. package/dist/injector/injector.js.map +1 -0
  58. package/dist/injector/injector.mjs +404 -0
  59. package/dist/injector/injector.mjs.map +1 -0
  60. package/dist/injector/sheet-manager.d.ts +127 -0
  61. package/dist/injector/sheet-manager.js +714 -0
  62. package/dist/injector/sheet-manager.js.map +1 -0
  63. package/dist/injector/sheet-manager.mjs +714 -0
  64. package/dist/injector/sheet-manager.mjs.map +1 -0
  65. package/dist/injector/types.d.mts +18 -0
  66. package/dist/injector/types.d.ts +135 -0
  67. package/dist/keyframes/index.js +206 -0
  68. package/dist/keyframes/index.js.map +1 -0
  69. package/dist/keyframes/index.mjs +156 -0
  70. package/dist/keyframes/index.mjs.map +1 -0
  71. package/dist/parser/classify.js +319 -0
  72. package/dist/parser/classify.js.map +1 -0
  73. package/dist/parser/classify.mjs +319 -0
  74. package/dist/parser/classify.mjs.map +1 -0
  75. package/dist/parser/const.js +33 -0
  76. package/dist/parser/const.js.map +1 -0
  77. package/dist/parser/const.mjs +33 -0
  78. package/dist/parser/const.mjs.map +1 -0
  79. package/dist/parser/lru.js +109 -0
  80. package/dist/parser/lru.js.map +1 -0
  81. package/dist/parser/lru.mjs +109 -0
  82. package/dist/parser/lru.mjs.map +1 -0
  83. package/dist/parser/parser.d.ts +25 -0
  84. package/dist/parser/parser.js +116 -0
  85. package/dist/parser/parser.js.map +1 -0
  86. package/dist/parser/parser.mjs +116 -0
  87. package/dist/parser/parser.mjs.map +1 -0
  88. package/dist/parser/tokenizer.js +69 -0
  89. package/dist/parser/tokenizer.js.map +1 -0
  90. package/dist/parser/tokenizer.mjs +69 -0
  91. package/dist/parser/tokenizer.mjs.map +1 -0
  92. package/dist/parser/types.d.mts +37 -0
  93. package/dist/parser/types.d.ts +46 -0
  94. package/dist/parser/types.js +46 -0
  95. package/dist/parser/types.js.map +1 -0
  96. package/dist/parser/types.mjs +46 -0
  97. package/dist/parser/types.mjs.map +1 -0
  98. package/dist/pipeline/conditions.js +377 -0
  99. package/dist/pipeline/conditions.js.map +1 -0
  100. package/dist/pipeline/conditions.mjs +377 -0
  101. package/dist/pipeline/conditions.mjs.map +1 -0
  102. package/dist/pipeline/exclusive.d.ts +1 -0
  103. package/dist/pipeline/exclusive.js +231 -0
  104. package/dist/pipeline/exclusive.js.map +1 -0
  105. package/dist/pipeline/exclusive.mjs +231 -0
  106. package/dist/pipeline/exclusive.mjs.map +1 -0
  107. package/dist/pipeline/index.d.ts +53 -0
  108. package/dist/pipeline/index.js +641 -0
  109. package/dist/pipeline/index.js.map +1 -0
  110. package/dist/pipeline/index.mjs +635 -0
  111. package/dist/pipeline/index.mjs.map +1 -0
  112. package/dist/pipeline/materialize.js +821 -0
  113. package/dist/pipeline/materialize.js.map +1 -0
  114. package/dist/pipeline/materialize.mjs +821 -0
  115. package/dist/pipeline/materialize.mjs.map +1 -0
  116. package/dist/pipeline/parseStateKey.d.ts +1 -0
  117. package/dist/pipeline/parseStateKey.js +418 -0
  118. package/dist/pipeline/parseStateKey.js.map +1 -0
  119. package/dist/pipeline/parseStateKey.mjs +418 -0
  120. package/dist/pipeline/parseStateKey.mjs.map +1 -0
  121. package/dist/pipeline/simplify.js +557 -0
  122. package/dist/pipeline/simplify.js.map +1 -0
  123. package/dist/pipeline/simplify.mjs +557 -0
  124. package/dist/pipeline/simplify.mjs.map +1 -0
  125. package/dist/plugins/index.d.ts +2 -0
  126. package/dist/plugins/okhsl-plugin.d.ts +35 -0
  127. package/dist/plugins/okhsl-plugin.js +371 -0
  128. package/dist/plugins/okhsl-plugin.js.map +1 -0
  129. package/dist/plugins/okhsl-plugin.mjs +345 -0
  130. package/dist/plugins/okhsl-plugin.mjs.map +1 -0
  131. package/dist/plugins/types.d.mts +49 -0
  132. package/dist/plugins/types.d.ts +69 -0
  133. package/dist/properties/index.js +158 -0
  134. package/dist/properties/index.js.map +1 -0
  135. package/dist/properties/index.mjs +141 -0
  136. package/dist/properties/index.mjs.map +1 -0
  137. package/dist/states/index.d.ts +45 -0
  138. package/dist/states/index.js +389 -0
  139. package/dist/states/index.js.map +1 -0
  140. package/dist/states/index.mjs +161 -0
  141. package/dist/states/index.mjs.map +1 -0
  142. package/dist/static/index.d.ts +5 -0
  143. package/dist/static/index.js +5 -0
  144. package/dist/static/tastyStatic.d.ts +46 -0
  145. package/dist/static/tastyStatic.js +31 -0
  146. package/dist/static/tastyStatic.js.map +1 -0
  147. package/dist/static/types.d.ts +49 -0
  148. package/dist/static/types.js +24 -0
  149. package/dist/static/types.js.map +1 -0
  150. package/dist/styles/align.d.ts +15 -0
  151. package/dist/styles/align.js +14 -0
  152. package/dist/styles/align.js.map +1 -0
  153. package/dist/styles/align.mjs +14 -0
  154. package/dist/styles/align.mjs.map +1 -0
  155. package/dist/styles/border.d.ts +25 -0
  156. package/dist/styles/border.js +114 -0
  157. package/dist/styles/border.js.map +1 -0
  158. package/dist/styles/border.mjs +114 -0
  159. package/dist/styles/border.mjs.map +1 -0
  160. package/dist/styles/color.d.ts +14 -0
  161. package/dist/styles/color.js +23 -0
  162. package/dist/styles/color.js.map +1 -0
  163. package/dist/styles/color.mjs +23 -0
  164. package/dist/styles/color.mjs.map +1 -0
  165. package/dist/styles/createStyle.js +77 -0
  166. package/dist/styles/createStyle.js.map +1 -0
  167. package/dist/styles/createStyle.mjs +77 -0
  168. package/dist/styles/createStyle.mjs.map +1 -0
  169. package/dist/styles/dimension.js +97 -0
  170. package/dist/styles/dimension.js.map +1 -0
  171. package/dist/styles/dimension.mjs +97 -0
  172. package/dist/styles/dimension.mjs.map +1 -0
  173. package/dist/styles/display.d.ts +37 -0
  174. package/dist/styles/display.js +67 -0
  175. package/dist/styles/display.js.map +1 -0
  176. package/dist/styles/display.mjs +67 -0
  177. package/dist/styles/display.mjs.map +1 -0
  178. package/dist/styles/fade.d.ts +15 -0
  179. package/dist/styles/fade.js +58 -0
  180. package/dist/styles/fade.js.map +1 -0
  181. package/dist/styles/fade.mjs +58 -0
  182. package/dist/styles/fade.mjs.map +1 -0
  183. package/dist/styles/fill.d.ts +44 -0
  184. package/dist/styles/fill.js +51 -0
  185. package/dist/styles/fill.js.map +1 -0
  186. package/dist/styles/fill.mjs +51 -0
  187. package/dist/styles/fill.mjs.map +1 -0
  188. package/dist/styles/flow.d.ts +16 -0
  189. package/dist/styles/flow.js +12 -0
  190. package/dist/styles/flow.js.map +1 -0
  191. package/dist/styles/flow.mjs +12 -0
  192. package/dist/styles/flow.mjs.map +1 -0
  193. package/dist/styles/gap.d.ts +31 -0
  194. package/dist/styles/gap.js +37 -0
  195. package/dist/styles/gap.js.map +1 -0
  196. package/dist/styles/gap.mjs +37 -0
  197. package/dist/styles/gap.mjs.map +1 -0
  198. package/dist/styles/height.d.ts +17 -0
  199. package/dist/styles/height.js +20 -0
  200. package/dist/styles/height.js.map +1 -0
  201. package/dist/styles/height.mjs +20 -0
  202. package/dist/styles/height.mjs.map +1 -0
  203. package/dist/styles/index.d.ts +2 -0
  204. package/dist/styles/index.js +9 -0
  205. package/dist/styles/index.js.map +1 -0
  206. package/dist/styles/index.mjs +9 -0
  207. package/dist/styles/index.mjs.map +1 -0
  208. package/dist/styles/inset.d.ts +50 -0
  209. package/dist/styles/inset.js +142 -0
  210. package/dist/styles/inset.js.map +1 -0
  211. package/dist/styles/inset.mjs +142 -0
  212. package/dist/styles/inset.mjs.map +1 -0
  213. package/dist/styles/justify.d.ts +15 -0
  214. package/dist/styles/justify.js +14 -0
  215. package/dist/styles/justify.js.map +1 -0
  216. package/dist/styles/justify.mjs +14 -0
  217. package/dist/styles/justify.mjs.map +1 -0
  218. package/dist/styles/list.d.ts +16 -0
  219. package/dist/styles/list.js +98 -0
  220. package/dist/styles/list.js.map +1 -0
  221. package/dist/styles/margin.d.ts +28 -0
  222. package/dist/styles/margin.js +96 -0
  223. package/dist/styles/margin.js.map +1 -0
  224. package/dist/styles/margin.mjs +96 -0
  225. package/dist/styles/margin.mjs.map +1 -0
  226. package/dist/styles/outline.d.ts +29 -0
  227. package/dist/styles/outline.js +65 -0
  228. package/dist/styles/outline.js.map +1 -0
  229. package/dist/styles/outline.mjs +65 -0
  230. package/dist/styles/outline.mjs.map +1 -0
  231. package/dist/styles/padding.d.ts +28 -0
  232. package/dist/styles/padding.js +96 -0
  233. package/dist/styles/padding.js.map +1 -0
  234. package/dist/styles/padding.mjs +96 -0
  235. package/dist/styles/padding.mjs.map +1 -0
  236. package/dist/styles/predefined.d.ts +74 -0
  237. package/dist/styles/predefined.js +241 -0
  238. package/dist/styles/predefined.js.map +1 -0
  239. package/dist/styles/predefined.mjs +232 -0
  240. package/dist/styles/predefined.mjs.map +1 -0
  241. package/dist/styles/preset.d.ts +47 -0
  242. package/dist/styles/preset.js +126 -0
  243. package/dist/styles/preset.js.map +1 -0
  244. package/dist/styles/preset.mjs +126 -0
  245. package/dist/styles/preset.mjs.map +1 -0
  246. package/dist/styles/radius.d.ts +14 -0
  247. package/dist/styles/radius.js +51 -0
  248. package/dist/styles/radius.js.map +1 -0
  249. package/dist/styles/radius.mjs +51 -0
  250. package/dist/styles/radius.mjs.map +1 -0
  251. package/dist/styles/scrollbar.d.ts +21 -0
  252. package/dist/styles/scrollbar.js +105 -0
  253. package/dist/styles/scrollbar.js.map +1 -0
  254. package/dist/styles/scrollbar.mjs +105 -0
  255. package/dist/styles/scrollbar.mjs.map +1 -0
  256. package/dist/styles/shadow.d.ts +14 -0
  257. package/dist/styles/shadow.js +24 -0
  258. package/dist/styles/shadow.js.map +1 -0
  259. package/dist/styles/shadow.mjs +24 -0
  260. package/dist/styles/shadow.mjs.map +1 -0
  261. package/dist/styles/styledScrollbar.d.ts +47 -0
  262. package/dist/styles/styledScrollbar.js +38 -0
  263. package/dist/styles/styledScrollbar.js.map +1 -0
  264. package/dist/styles/styledScrollbar.mjs +38 -0
  265. package/dist/styles/styledScrollbar.mjs.map +1 -0
  266. package/dist/styles/transition.d.ts +14 -0
  267. package/dist/styles/transition.js +138 -0
  268. package/dist/styles/transition.js.map +1 -0
  269. package/dist/styles/transition.mjs +138 -0
  270. package/dist/styles/transition.mjs.map +1 -0
  271. package/dist/styles/types.d.mts +492 -0
  272. package/dist/styles/types.d.ts +496 -0
  273. package/dist/styles/width.d.ts +17 -0
  274. package/dist/styles/width.js +20 -0
  275. package/dist/styles/width.js.map +1 -0
  276. package/dist/styles/width.mjs +20 -0
  277. package/dist/styles/width.mjs.map +1 -0
  278. package/dist/tasty.d.ts +983 -0
  279. package/dist/tasty.js +191 -0
  280. package/dist/tasty.js.map +1 -0
  281. package/dist/tokens/typography.d.ts +19 -0
  282. package/dist/tokens/typography.js +237 -0
  283. package/dist/tokens/typography.js.map +1 -0
  284. package/dist/types.d.ts +182 -0
  285. package/dist/utils/cache-wrapper.js +26 -0
  286. package/dist/utils/cache-wrapper.js.map +1 -0
  287. package/dist/utils/cache-wrapper.mjs +26 -0
  288. package/dist/utils/cache-wrapper.mjs.map +1 -0
  289. package/dist/utils/case-converter.js +8 -0
  290. package/dist/utils/case-converter.js.map +1 -0
  291. package/dist/utils/case-converter.mjs +8 -0
  292. package/dist/utils/case-converter.mjs.map +1 -0
  293. package/dist/utils/colors.d.ts +5 -0
  294. package/dist/utils/colors.js +9 -0
  295. package/dist/utils/colors.js.map +1 -0
  296. package/dist/utils/dotize.d.ts +26 -0
  297. package/dist/utils/dotize.js +122 -0
  298. package/dist/utils/dotize.js.map +1 -0
  299. package/dist/utils/filter-base-props.d.ts +15 -0
  300. package/dist/utils/filter-base-props.js +45 -0
  301. package/dist/utils/filter-base-props.js.map +1 -0
  302. package/dist/utils/get-display-name.d.ts +7 -0
  303. package/dist/utils/get-display-name.js +10 -0
  304. package/dist/utils/get-display-name.js.map +1 -0
  305. package/dist/utils/hsl-to-rgb.js +38 -0
  306. package/dist/utils/hsl-to-rgb.js.map +1 -0
  307. package/dist/utils/hsl-to-rgb.mjs +38 -0
  308. package/dist/utils/hsl-to-rgb.mjs.map +1 -0
  309. package/dist/utils/is-dev-env.js +19 -0
  310. package/dist/utils/is-dev-env.js.map +1 -0
  311. package/dist/utils/is-dev-env.mjs +19 -0
  312. package/dist/utils/is-dev-env.mjs.map +1 -0
  313. package/dist/utils/merge-styles.d.ts +7 -0
  314. package/dist/utils/merge-styles.js +146 -0
  315. package/dist/utils/merge-styles.js.map +1 -0
  316. package/dist/utils/merge-styles.mjs +146 -0
  317. package/dist/utils/merge-styles.mjs.map +1 -0
  318. package/dist/utils/mod-attrs.d.ts +8 -0
  319. package/dist/utils/mod-attrs.js +21 -0
  320. package/dist/utils/mod-attrs.js.map +1 -0
  321. package/dist/utils/okhsl-to-rgb.js +296 -0
  322. package/dist/utils/okhsl-to-rgb.js.map +1 -0
  323. package/dist/utils/okhsl-to-rgb.mjs +296 -0
  324. package/dist/utils/okhsl-to-rgb.mjs.map +1 -0
  325. package/dist/utils/process-tokens.d.ts +31 -0
  326. package/dist/utils/process-tokens.js +171 -0
  327. package/dist/utils/process-tokens.js.map +1 -0
  328. package/dist/utils/process-tokens.mjs +28 -0
  329. package/dist/utils/process-tokens.mjs.map +1 -0
  330. package/dist/utils/resolve-recipes.d.ts +17 -0
  331. package/dist/utils/resolve-recipes.js +143 -0
  332. package/dist/utils/resolve-recipes.js.map +1 -0
  333. package/dist/utils/resolve-recipes.mjs +143 -0
  334. package/dist/utils/resolve-recipes.mjs.map +1 -0
  335. package/dist/utils/string.js +8 -0
  336. package/dist/utils/string.js.map +1 -0
  337. package/dist/utils/string.mjs +8 -0
  338. package/dist/utils/string.mjs.map +1 -0
  339. package/dist/utils/styles.d.mts +18 -0
  340. package/dist/utils/styles.d.ts +183 -0
  341. package/dist/utils/styles.js +585 -0
  342. package/dist/utils/styles.js.map +1 -0
  343. package/dist/utils/styles.mjs +346 -0
  344. package/dist/utils/styles.mjs.map +1 -0
  345. package/dist/utils/typography.d.ts +36 -0
  346. package/dist/utils/typography.js +53 -0
  347. package/dist/utils/typography.js.map +1 -0
  348. package/dist/utils/warnings.d.ts +16 -0
  349. package/dist/utils/warnings.js +16 -0
  350. package/dist/utils/warnings.js.map +1 -0
  351. package/dist/zero/babel.d.mts +108 -0
  352. package/dist/zero/babel.mjs +282 -0
  353. package/dist/zero/babel.mjs.map +1 -0
  354. package/dist/zero/index.d.mts +3 -0
  355. package/dist/zero/index.mjs +4 -0
  356. package/dist/zero/next.d.mts +60 -0
  357. package/dist/zero/next.mjs +78 -0
  358. package/dist/zero/next.mjs.map +1 -0
  359. package/package.json +127 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/properties/index.ts"],"sourcesContent":["/**\n * Properties Utilities\n *\n * Utilities for extracting and processing CSS @property definitions in styles.\n * Unlike keyframes, properties are permanent once registered and don't need cleanup.\n *\n * Property names use tasty token syntax:\n * - `$name` for regular properties → `--name`\n * - `#name` for color properties → `--name-color` (auto-sets syntax: '<color>')\n */\n\nimport type { PropertyDefinition } from '../injector/types';\nimport type { Styles } from '../styles/types';\nimport { getRgbValuesFromRgbaString, strToRgb } from '../utils/styles';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst PROPERTIES_KEY = '@properties';\n\n/**\n * Valid CSS custom property name pattern (after the -- prefix).\n * Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.\n */\nconst VALID_PROPERTY_NAME_PATTERN = /^[a-z_][a-z0-9-_]*$/i;\n\n// ============================================================================\n// Validation Functions\n// ============================================================================\n\n/**\n * Validate a CSS custom property name (the part after --).\n * Returns true if the name is valid for use as a CSS custom property.\n */\nexport function isValidPropertyName(name: string): boolean {\n return VALID_PROPERTY_NAME_PATTERN.test(name);\n}\n\n/**\n * Result of parsing a property token.\n */\nexport interface ParsedPropertyToken {\n /** The CSS custom property name (e.g., '--my-prop') */\n cssName: string;\n /** Whether this is a color property */\n isColor: boolean;\n /** Whether the token was valid */\n isValid: boolean;\n /** Error message if invalid */\n error?: string;\n}\n\n// ============================================================================\n// Extraction Functions\n// ============================================================================\n\n/**\n * Check if styles object has local @properties definition.\n * Fast path: single property lookup.\n */\nexport function hasLocalProperties(styles: Styles): boolean {\n return PROPERTIES_KEY in styles;\n}\n\n/**\n * Extract local @properties from styles object.\n * Returns null if no local properties (fast path).\n */\nexport function extractLocalProperties(\n styles: Styles,\n): Record<string, PropertyDefinition> | null {\n const properties = styles[PROPERTIES_KEY];\n if (!properties || typeof properties !== 'object') {\n return null;\n }\n return properties as Record<string, PropertyDefinition>;\n}\n\n// ============================================================================\n// Token Parsing Functions\n// ============================================================================\n\n/**\n * Parse a property token name and return the CSS property name and whether it's a color.\n * Supports tasty token syntax and validates the property name.\n *\n * Token formats:\n * - `$name` → { cssName: '--name', isColor: false }\n * - `#name` → { cssName: '--name-color', isColor: true }\n * - `--name` → { cssName: '--name', isColor: false } (legacy, auto-detect color by suffix)\n * - `name` → { cssName: '--name', isColor: false } (legacy)\n *\n * @param token - The property token to parse\n * @returns Parsed result with cssName, isColor, isValid, and optional error\n */\nexport function parsePropertyToken(token: string): ParsedPropertyToken {\n if (!token || typeof token !== 'string') {\n return {\n cssName: '',\n isColor: false,\n isValid: false,\n error: 'Property token must be a non-empty string',\n };\n }\n\n let name: string;\n let isColor: boolean;\n\n if (token.startsWith('$')) {\n // Regular property token: $name → --name\n name = token.slice(1);\n isColor = false;\n } else if (token.startsWith('#')) {\n // Color property token: #name → --name-color\n name = token.slice(1);\n isColor = true;\n } else if (token.startsWith('--')) {\n // Legacy format with -- prefix\n name = token.slice(2);\n isColor = token.endsWith('-color');\n } else {\n // Legacy format without prefix\n name = token;\n isColor = token.endsWith('-color');\n }\n\n // Validate the name\n if (!name) {\n return {\n cssName: '',\n isColor,\n isValid: false,\n error: 'Property name cannot be empty',\n };\n }\n\n if (!isValidPropertyName(name)) {\n return {\n cssName: '',\n isColor,\n isValid: false,\n error: `Invalid property name \"${name}\". Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.`,\n };\n }\n\n // Build the CSS custom property name\n // For #name tokens, we add -color suffix\n // For legacy formats (--name-color or name-color), the name already includes -color\n let cssName: string;\n if (token.startsWith('#')) {\n // Color token: #name → --name-color\n cssName = `--${name}-color`;\n } else {\n // All other formats: just add -- prefix\n cssName = `--${name}`;\n }\n\n return {\n cssName,\n isColor,\n isValid: true,\n };\n}\n\n// ============================================================================\n// Normalization Functions\n// ============================================================================\n\n/**\n * Normalize a property name to the CSS custom property format.\n *\n * @deprecated Use parsePropertyToken instead for proper token handling\n */\nexport function normalizePropertyName(name: string): string {\n const result = parsePropertyToken(name);\n return result.isValid ? result.cssName : `--${name}`;\n}\n\n/**\n * Normalize a property definition to a consistent string representation.\n * Used for comparing definitions to detect changes/conflicts.\n *\n * Keys are sorted alphabetically to ensure consistent comparison:\n * { inherits: true, syntax: '<color>' } === { syntax: '<color>', inherits: true }\n */\nexport function normalizePropertyDefinition(def: PropertyDefinition): string {\n const normalized: Record<string, unknown> = {};\n\n // Add properties in alphabetical order\n if (def.inherits !== undefined) {\n normalized.inherits = def.inherits;\n }\n if (def.initialValue !== undefined) {\n normalized.initialValue = String(def.initialValue);\n }\n if (def.syntax !== undefined) {\n normalized.syntax = def.syntax;\n }\n\n return JSON.stringify(normalized);\n}\n\n/**\n * Result of getEffectiveDefinition.\n */\nexport interface EffectiveDefinitionResult {\n /** The CSS custom property name */\n cssName: string;\n /** The effective property definition */\n definition: PropertyDefinition;\n /** Whether this is a color property */\n isColor: boolean;\n /** Whether the token was valid */\n isValid: boolean;\n /** Error message if invalid */\n error?: string;\n}\n\n/**\n * Get the effective property definition for a token.\n * For color tokens (#name), auto-sets syntax to '<color>' and defaults initialValue to 'transparent'.\n *\n * @param token - Property token ($name, #name, --name, or plain name)\n * @param userDefinition - User-provided definition options\n * @returns Effective definition with cssName, definition, isValid, and optional error\n */\nexport function getEffectiveDefinition(\n token: string,\n userDefinition: PropertyDefinition,\n): EffectiveDefinitionResult {\n const parsed = parsePropertyToken(token);\n\n if (!parsed.isValid) {\n return {\n cssName: '',\n definition: userDefinition,\n isColor: false,\n isValid: false,\n error: parsed.error,\n };\n }\n\n if (parsed.isColor) {\n // Color properties have fixed syntax and default initialValue\n return {\n cssName: parsed.cssName,\n definition: {\n syntax: '<color>', // Always '<color>' for color tokens, cannot be overridden\n inherits: userDefinition.inherits, // Allow inherits to be customized\n initialValue: userDefinition.initialValue ?? 'transparent', // Default to transparent\n },\n isColor: true,\n isValid: true,\n };\n }\n\n // Regular properties use the definition as-is\n return {\n cssName: parsed.cssName,\n definition: userDefinition,\n isColor: false,\n isValid: true,\n };\n}\n\n// ============================================================================\n// Color RGB Companion Helpers\n// ============================================================================\n\n/**\n * Extract RGB triplet string from a color initial value.\n * Used when auto-creating the companion `-rgb` property for color @property definitions.\n *\n * @param initialValue - The color property's initial value (e.g., 'rgb(255 255 255)', 'transparent', '#fff')\n * @returns Space-separated RGB triplet (e.g., '255 255 255'), defaults to '0 0 0'\n */\nexport function colorInitialValueToRgb(initialValue?: string | number): string {\n if (initialValue == null) return '0 0 0';\n\n const str = String(initialValue).trim();\n if (!str || str === 'transparent') return '0 0 0';\n\n const rgba = strToRgb(str);\n if (rgba) {\n const values = getRgbValuesFromRgbaString(rgba);\n if (values.length >= 3) return values.slice(0, 3).join(' ');\n }\n\n return '0 0 0';\n}\n"],"mappings":";;;AAmBA,MAAM,iBAAiB;;;;;AAMvB,MAAM,8BAA8B;;;;;AAUpC,SAAgB,oBAAoB,MAAuB;AACzD,QAAO,4BAA4B,KAAK,KAAK;;;;;;AAyB/C,SAAgB,mBAAmB,QAAyB;AAC1D,QAAO,kBAAkB;;;;;;AAO3B,SAAgB,uBACd,QAC2C;CAC3C,MAAM,aAAa,OAAO;AAC1B,KAAI,CAAC,cAAc,OAAO,eAAe,SACvC,QAAO;AAET,QAAO;;;;;;;;;;;;;;;AAoBT,SAAgB,mBAAmB,OAAoC;AACrE,KAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO;EACL,SAAS;EACT,SAAS;EACT,SAAS;EACT,OAAO;EACR;CAGH,IAAI;CACJ,IAAI;AAEJ,KAAI,MAAM,WAAW,IAAI,EAAE;AAEzB,SAAO,MAAM,MAAM,EAAE;AACrB,YAAU;YACD,MAAM,WAAW,IAAI,EAAE;AAEhC,SAAO,MAAM,MAAM,EAAE;AACrB,YAAU;YACD,MAAM,WAAW,KAAK,EAAE;AAEjC,SAAO,MAAM,MAAM,EAAE;AACrB,YAAU,MAAM,SAAS,SAAS;QAC7B;AAEL,SAAO;AACP,YAAU,MAAM,SAAS,SAAS;;AAIpC,KAAI,CAAC,KACH,QAAO;EACL,SAAS;EACT;EACA,SAAS;EACT,OAAO;EACR;AAGH,KAAI,CAAC,oBAAoB,KAAK,CAC5B,QAAO;EACL,SAAS;EACT;EACA,SAAS;EACT,OAAO,0BAA0B,KAAK;EACvC;CAMH,IAAI;AACJ,KAAI,MAAM,WAAW,IAAI,CAEvB,WAAU,KAAK,KAAK;KAGpB,WAAU,KAAK;AAGjB,QAAO;EACL;EACA;EACA,SAAS;EACV;;;;;;;;;AAwBH,SAAgB,4BAA4B,KAAiC;CAC3E,MAAM,aAAsC,EAAE;AAG9C,KAAI,IAAI,aAAa,OACnB,YAAW,WAAW,IAAI;AAE5B,KAAI,IAAI,iBAAiB,OACvB,YAAW,eAAe,OAAO,IAAI,aAAa;AAEpD,KAAI,IAAI,WAAW,OACjB,YAAW,SAAS,IAAI;AAG1B,QAAO,KAAK,UAAU,WAAW;;;;;;;;;;AA2BnC,SAAgB,uBACd,OACA,gBAC2B;CAC3B,MAAM,SAAS,mBAAmB,MAAM;AAExC,KAAI,CAAC,OAAO,QACV,QAAO;EACL,SAAS;EACT,YAAY;EACZ,SAAS;EACT,SAAS;EACT,OAAO,OAAO;EACf;AAGH,KAAI,OAAO,QAET,QAAO;EACL,SAAS,OAAO;EAChB,YAAY;GACV,QAAQ;GACR,UAAU,eAAe;GACzB,cAAc,eAAe,gBAAgB;GAC9C;EACD,SAAS;EACT,SAAS;EACV;AAIH,QAAO;EACL,SAAS,OAAO;EAChB,YAAY;EACZ,SAAS;EACT,SAAS;EACV;;;;;;;;;AAcH,SAAgB,uBAAuB,cAAwC;AAC7E,KAAI,gBAAgB,KAAM,QAAO;CAEjC,MAAM,MAAM,OAAO,aAAa,CAAC,MAAM;AACvC,KAAI,CAAC,OAAO,QAAQ,cAAe,QAAO;CAE1C,MAAM,OAAO,SAAS,IAAI;AAC1B,KAAI,MAAM;EACR,MAAM,SAAS,2BAA2B,KAAK;AAC/C,MAAI,OAAO,UAAU,EAAG,QAAO,OAAO,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI;;AAG7D,QAAO"}
@@ -0,0 +1,141 @@
1
+ import { getRgbValuesFromRgbaString, strToRgb } from "../utils/styles.mjs";
2
+
3
+ //#region src/properties/index.ts
4
+ /**
5
+ * Valid CSS custom property name pattern (after the -- prefix).
6
+ * Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.
7
+ */
8
+ const VALID_PROPERTY_NAME_PATTERN = /^[a-z_][a-z0-9-_]*$/i;
9
+ /**
10
+ * Validate a CSS custom property name (the part after --).
11
+ * Returns true if the name is valid for use as a CSS custom property.
12
+ */
13
+ function isValidPropertyName(name) {
14
+ return VALID_PROPERTY_NAME_PATTERN.test(name);
15
+ }
16
+ /**
17
+ * Parse a property token name and return the CSS property name and whether it's a color.
18
+ * Supports tasty token syntax and validates the property name.
19
+ *
20
+ * Token formats:
21
+ * - `$name` → { cssName: '--name', isColor: false }
22
+ * - `#name` → { cssName: '--name-color', isColor: true }
23
+ * - `--name` → { cssName: '--name', isColor: false } (legacy, auto-detect color by suffix)
24
+ * - `name` → { cssName: '--name', isColor: false } (legacy)
25
+ *
26
+ * @param token - The property token to parse
27
+ * @returns Parsed result with cssName, isColor, isValid, and optional error
28
+ */
29
+ function parsePropertyToken(token) {
30
+ if (!token || typeof token !== "string") return {
31
+ cssName: "",
32
+ isColor: false,
33
+ isValid: false,
34
+ error: "Property token must be a non-empty string"
35
+ };
36
+ let name;
37
+ let isColor;
38
+ if (token.startsWith("$")) {
39
+ name = token.slice(1);
40
+ isColor = false;
41
+ } else if (token.startsWith("#")) {
42
+ name = token.slice(1);
43
+ isColor = true;
44
+ } else if (token.startsWith("--")) {
45
+ name = token.slice(2);
46
+ isColor = token.endsWith("-color");
47
+ } else {
48
+ name = token;
49
+ isColor = token.endsWith("-color");
50
+ }
51
+ if (!name) return {
52
+ cssName: "",
53
+ isColor,
54
+ isValid: false,
55
+ error: "Property name cannot be empty"
56
+ };
57
+ if (!isValidPropertyName(name)) return {
58
+ cssName: "",
59
+ isColor,
60
+ isValid: false,
61
+ error: `Invalid property name "${name}". Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.`
62
+ };
63
+ let cssName;
64
+ if (token.startsWith("#")) cssName = `--${name}-color`;
65
+ else cssName = `--${name}`;
66
+ return {
67
+ cssName,
68
+ isColor,
69
+ isValid: true
70
+ };
71
+ }
72
+ /**
73
+ * Normalize a property definition to a consistent string representation.
74
+ * Used for comparing definitions to detect changes/conflicts.
75
+ *
76
+ * Keys are sorted alphabetically to ensure consistent comparison:
77
+ * { inherits: true, syntax: '<color>' } === { syntax: '<color>', inherits: true }
78
+ */
79
+ function normalizePropertyDefinition(def) {
80
+ const normalized = {};
81
+ if (def.inherits !== void 0) normalized.inherits = def.inherits;
82
+ if (def.initialValue !== void 0) normalized.initialValue = String(def.initialValue);
83
+ if (def.syntax !== void 0) normalized.syntax = def.syntax;
84
+ return JSON.stringify(normalized);
85
+ }
86
+ /**
87
+ * Get the effective property definition for a token.
88
+ * For color tokens (#name), auto-sets syntax to '<color>' and defaults initialValue to 'transparent'.
89
+ *
90
+ * @param token - Property token ($name, #name, --name, or plain name)
91
+ * @param userDefinition - User-provided definition options
92
+ * @returns Effective definition with cssName, definition, isValid, and optional error
93
+ */
94
+ function getEffectiveDefinition(token, userDefinition) {
95
+ const parsed = parsePropertyToken(token);
96
+ if (!parsed.isValid) return {
97
+ cssName: "",
98
+ definition: userDefinition,
99
+ isColor: false,
100
+ isValid: false,
101
+ error: parsed.error
102
+ };
103
+ if (parsed.isColor) return {
104
+ cssName: parsed.cssName,
105
+ definition: {
106
+ syntax: "<color>",
107
+ inherits: userDefinition.inherits,
108
+ initialValue: userDefinition.initialValue ?? "transparent"
109
+ },
110
+ isColor: true,
111
+ isValid: true
112
+ };
113
+ return {
114
+ cssName: parsed.cssName,
115
+ definition: userDefinition,
116
+ isColor: false,
117
+ isValid: true
118
+ };
119
+ }
120
+ /**
121
+ * Extract RGB triplet string from a color initial value.
122
+ * Used when auto-creating the companion `-rgb` property for color @property definitions.
123
+ *
124
+ * @param initialValue - The color property's initial value (e.g., 'rgb(255 255 255)', 'transparent', '#fff')
125
+ * @returns Space-separated RGB triplet (e.g., '255 255 255'), defaults to '0 0 0'
126
+ */
127
+ function colorInitialValueToRgb(initialValue) {
128
+ if (initialValue == null) return "0 0 0";
129
+ const str = String(initialValue).trim();
130
+ if (!str || str === "transparent") return "0 0 0";
131
+ const rgba = strToRgb(str);
132
+ if (rgba) {
133
+ const values = getRgbValuesFromRgbaString(rgba);
134
+ if (values.length >= 3) return values.slice(0, 3).join(" ");
135
+ }
136
+ return "0 0 0";
137
+ }
138
+
139
+ //#endregion
140
+ export { colorInitialValueToRgb, getEffectiveDefinition, normalizePropertyDefinition };
141
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/properties/index.ts"],"sourcesContent":["/**\n * Properties Utilities\n *\n * Utilities for extracting and processing CSS @property definitions in styles.\n * Unlike keyframes, properties are permanent once registered and don't need cleanup.\n *\n * Property names use tasty token syntax:\n * - `$name` for regular properties → `--name`\n * - `#name` for color properties → `--name-color` (auto-sets syntax: '<color>')\n */\n\nimport type { PropertyDefinition } from '../injector/types';\nimport type { Styles } from '../styles/types';\nimport { getRgbValuesFromRgbaString, strToRgb } from '../utils/styles';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst PROPERTIES_KEY = '@properties';\n\n/**\n * Valid CSS custom property name pattern (after the -- prefix).\n * Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.\n */\nconst VALID_PROPERTY_NAME_PATTERN = /^[a-z_][a-z0-9-_]*$/i;\n\n// ============================================================================\n// Validation Functions\n// ============================================================================\n\n/**\n * Validate a CSS custom property name (the part after --).\n * Returns true if the name is valid for use as a CSS custom property.\n */\nexport function isValidPropertyName(name: string): boolean {\n return VALID_PROPERTY_NAME_PATTERN.test(name);\n}\n\n/**\n * Result of parsing a property token.\n */\nexport interface ParsedPropertyToken {\n /** The CSS custom property name (e.g., '--my-prop') */\n cssName: string;\n /** Whether this is a color property */\n isColor: boolean;\n /** Whether the token was valid */\n isValid: boolean;\n /** Error message if invalid */\n error?: string;\n}\n\n// ============================================================================\n// Extraction Functions\n// ============================================================================\n\n/**\n * Check if styles object has local @properties definition.\n * Fast path: single property lookup.\n */\nexport function hasLocalProperties(styles: Styles): boolean {\n return PROPERTIES_KEY in styles;\n}\n\n/**\n * Extract local @properties from styles object.\n * Returns null if no local properties (fast path).\n */\nexport function extractLocalProperties(\n styles: Styles,\n): Record<string, PropertyDefinition> | null {\n const properties = styles[PROPERTIES_KEY];\n if (!properties || typeof properties !== 'object') {\n return null;\n }\n return properties as Record<string, PropertyDefinition>;\n}\n\n// ============================================================================\n// Token Parsing Functions\n// ============================================================================\n\n/**\n * Parse a property token name and return the CSS property name and whether it's a color.\n * Supports tasty token syntax and validates the property name.\n *\n * Token formats:\n * - `$name` → { cssName: '--name', isColor: false }\n * - `#name` → { cssName: '--name-color', isColor: true }\n * - `--name` → { cssName: '--name', isColor: false } (legacy, auto-detect color by suffix)\n * - `name` → { cssName: '--name', isColor: false } (legacy)\n *\n * @param token - The property token to parse\n * @returns Parsed result with cssName, isColor, isValid, and optional error\n */\nexport function parsePropertyToken(token: string): ParsedPropertyToken {\n if (!token || typeof token !== 'string') {\n return {\n cssName: '',\n isColor: false,\n isValid: false,\n error: 'Property token must be a non-empty string',\n };\n }\n\n let name: string;\n let isColor: boolean;\n\n if (token.startsWith('$')) {\n // Regular property token: $name → --name\n name = token.slice(1);\n isColor = false;\n } else if (token.startsWith('#')) {\n // Color property token: #name → --name-color\n name = token.slice(1);\n isColor = true;\n } else if (token.startsWith('--')) {\n // Legacy format with -- prefix\n name = token.slice(2);\n isColor = token.endsWith('-color');\n } else {\n // Legacy format without prefix\n name = token;\n isColor = token.endsWith('-color');\n }\n\n // Validate the name\n if (!name) {\n return {\n cssName: '',\n isColor,\n isValid: false,\n error: 'Property name cannot be empty',\n };\n }\n\n if (!isValidPropertyName(name)) {\n return {\n cssName: '',\n isColor,\n isValid: false,\n error: `Invalid property name \"${name}\". Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.`,\n };\n }\n\n // Build the CSS custom property name\n // For #name tokens, we add -color suffix\n // For legacy formats (--name-color or name-color), the name already includes -color\n let cssName: string;\n if (token.startsWith('#')) {\n // Color token: #name → --name-color\n cssName = `--${name}-color`;\n } else {\n // All other formats: just add -- prefix\n cssName = `--${name}`;\n }\n\n return {\n cssName,\n isColor,\n isValid: true,\n };\n}\n\n// ============================================================================\n// Normalization Functions\n// ============================================================================\n\n/**\n * Normalize a property name to the CSS custom property format.\n *\n * @deprecated Use parsePropertyToken instead for proper token handling\n */\nexport function normalizePropertyName(name: string): string {\n const result = parsePropertyToken(name);\n return result.isValid ? result.cssName : `--${name}`;\n}\n\n/**\n * Normalize a property definition to a consistent string representation.\n * Used for comparing definitions to detect changes/conflicts.\n *\n * Keys are sorted alphabetically to ensure consistent comparison:\n * { inherits: true, syntax: '<color>' } === { syntax: '<color>', inherits: true }\n */\nexport function normalizePropertyDefinition(def: PropertyDefinition): string {\n const normalized: Record<string, unknown> = {};\n\n // Add properties in alphabetical order\n if (def.inherits !== undefined) {\n normalized.inherits = def.inherits;\n }\n if (def.initialValue !== undefined) {\n normalized.initialValue = String(def.initialValue);\n }\n if (def.syntax !== undefined) {\n normalized.syntax = def.syntax;\n }\n\n return JSON.stringify(normalized);\n}\n\n/**\n * Result of getEffectiveDefinition.\n */\nexport interface EffectiveDefinitionResult {\n /** The CSS custom property name */\n cssName: string;\n /** The effective property definition */\n definition: PropertyDefinition;\n /** Whether this is a color property */\n isColor: boolean;\n /** Whether the token was valid */\n isValid: boolean;\n /** Error message if invalid */\n error?: string;\n}\n\n/**\n * Get the effective property definition for a token.\n * For color tokens (#name), auto-sets syntax to '<color>' and defaults initialValue to 'transparent'.\n *\n * @param token - Property token ($name, #name, --name, or plain name)\n * @param userDefinition - User-provided definition options\n * @returns Effective definition with cssName, definition, isValid, and optional error\n */\nexport function getEffectiveDefinition(\n token: string,\n userDefinition: PropertyDefinition,\n): EffectiveDefinitionResult {\n const parsed = parsePropertyToken(token);\n\n if (!parsed.isValid) {\n return {\n cssName: '',\n definition: userDefinition,\n isColor: false,\n isValid: false,\n error: parsed.error,\n };\n }\n\n if (parsed.isColor) {\n // Color properties have fixed syntax and default initialValue\n return {\n cssName: parsed.cssName,\n definition: {\n syntax: '<color>', // Always '<color>' for color tokens, cannot be overridden\n inherits: userDefinition.inherits, // Allow inherits to be customized\n initialValue: userDefinition.initialValue ?? 'transparent', // Default to transparent\n },\n isColor: true,\n isValid: true,\n };\n }\n\n // Regular properties use the definition as-is\n return {\n cssName: parsed.cssName,\n definition: userDefinition,\n isColor: false,\n isValid: true,\n };\n}\n\n// ============================================================================\n// Color RGB Companion Helpers\n// ============================================================================\n\n/**\n * Extract RGB triplet string from a color initial value.\n * Used when auto-creating the companion `-rgb` property for color @property definitions.\n *\n * @param initialValue - The color property's initial value (e.g., 'rgb(255 255 255)', 'transparent', '#fff')\n * @returns Space-separated RGB triplet (e.g., '255 255 255'), defaults to '0 0 0'\n */\nexport function colorInitialValueToRgb(initialValue?: string | number): string {\n if (initialValue == null) return '0 0 0';\n\n const str = String(initialValue).trim();\n if (!str || str === 'transparent') return '0 0 0';\n\n const rgba = strToRgb(str);\n if (rgba) {\n const values = getRgbValuesFromRgbaString(rgba);\n if (values.length >= 3) return values.slice(0, 3).join(' ');\n }\n\n return '0 0 0';\n}\n"],"mappings":";;;;;;;AAyBA,MAAM,8BAA8B;;;;;AAUpC,SAAgB,oBAAoB,MAAuB;AACzD,QAAO,4BAA4B,KAAK,KAAK;;;;;;;;;;;;;;;AA4D/C,SAAgB,mBAAmB,OAAoC;AACrE,KAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO;EACL,SAAS;EACT,SAAS;EACT,SAAS;EACT,OAAO;EACR;CAGH,IAAI;CACJ,IAAI;AAEJ,KAAI,MAAM,WAAW,IAAI,EAAE;AAEzB,SAAO,MAAM,MAAM,EAAE;AACrB,YAAU;YACD,MAAM,WAAW,IAAI,EAAE;AAEhC,SAAO,MAAM,MAAM,EAAE;AACrB,YAAU;YACD,MAAM,WAAW,KAAK,EAAE;AAEjC,SAAO,MAAM,MAAM,EAAE;AACrB,YAAU,MAAM,SAAS,SAAS;QAC7B;AAEL,SAAO;AACP,YAAU,MAAM,SAAS,SAAS;;AAIpC,KAAI,CAAC,KACH,QAAO;EACL,SAAS;EACT;EACA,SAAS;EACT,OAAO;EACR;AAGH,KAAI,CAAC,oBAAoB,KAAK,CAC5B,QAAO;EACL,SAAS;EACT;EACA,SAAS;EACT,OAAO,0BAA0B,KAAK;EACvC;CAMH,IAAI;AACJ,KAAI,MAAM,WAAW,IAAI,CAEvB,WAAU,KAAK,KAAK;KAGpB,WAAU,KAAK;AAGjB,QAAO;EACL;EACA;EACA,SAAS;EACV;;;;;;;;;AAwBH,SAAgB,4BAA4B,KAAiC;CAC3E,MAAM,aAAsC,EAAE;AAG9C,KAAI,IAAI,aAAa,OACnB,YAAW,WAAW,IAAI;AAE5B,KAAI,IAAI,iBAAiB,OACvB,YAAW,eAAe,OAAO,IAAI,aAAa;AAEpD,KAAI,IAAI,WAAW,OACjB,YAAW,SAAS,IAAI;AAG1B,QAAO,KAAK,UAAU,WAAW;;;;;;;;;;AA2BnC,SAAgB,uBACd,OACA,gBAC2B;CAC3B,MAAM,SAAS,mBAAmB,MAAM;AAExC,KAAI,CAAC,OAAO,QACV,QAAO;EACL,SAAS;EACT,YAAY;EACZ,SAAS;EACT,SAAS;EACT,OAAO,OAAO;EACf;AAGH,KAAI,OAAO,QAET,QAAO;EACL,SAAS,OAAO;EAChB,YAAY;GACV,QAAQ;GACR,UAAU,eAAe;GACzB,cAAc,eAAe,gBAAgB;GAC9C;EACD,SAAS;EACT,SAAS;EACV;AAIH,QAAO;EACL,SAAS,OAAO;EAChB,YAAY;EACZ,SAAS;EACT,SAAS;EACV;;;;;;;;;AAcH,SAAgB,uBAAuB,cAAwC;AAC7E,KAAI,gBAAgB,KAAM,QAAO;CAEjC,MAAM,MAAM,OAAO,aAAa,CAAC,MAAM;AACvC,KAAI,CAAC,OAAO,QAAQ,cAAe,QAAO;CAE1C,MAAM,OAAO,SAAS,IAAI;AAC1B,KAAI,MAAM;EACR,MAAM,SAAS,2BAA2B,KAAK;AAC/C,MAAI,OAAO,UAAU,EAAG,QAAO,OAAO,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI;;AAG7D,QAAO"}
@@ -0,0 +1,45 @@
1
+ import "../styles/types.js";
2
+
3
+ //#region src/states/index.d.ts
4
+ /**
5
+ * Parsed advanced state information
6
+ */
7
+ interface ParsedAdvancedState {
8
+ type: 'media' | 'container' | 'root' | 'own' | 'starting' | 'predefined' | 'modifier';
9
+ condition: string;
10
+ containerName?: string;
11
+ raw: string;
12
+ mediaType?: string;
13
+ }
14
+ /**
15
+ * Context for state parsing operations
16
+ */
17
+ interface StateParserContext {
18
+ localPredefinedStates: Record<string, string>;
19
+ globalPredefinedStates: Record<string, string>;
20
+ isSubElement?: boolean;
21
+ }
22
+ /**
23
+ * At-rule context for CSS generation
24
+ */
25
+ interface AtRuleContext {
26
+ media?: string[];
27
+ container?: {
28
+ name?: string;
29
+ condition: string;
30
+ }[];
31
+ startingStyle?: boolean;
32
+ rootStates?: string[];
33
+ negatedRootStates?: string[];
34
+ }
35
+ /**
36
+ * Configure global predefined states
37
+ */
38
+ declare function setGlobalPredefinedStates(states: Record<string, string>): void;
39
+ /**
40
+ * Get global predefined states
41
+ */
42
+ declare function getGlobalPredefinedStates(): Record<string, string>;
43
+ //#endregion
44
+ export { AtRuleContext, ParsedAdvancedState, StateParserContext, getGlobalPredefinedStates, setGlobalPredefinedStates };
45
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,389 @@
1
+ import { isDevEnv } from "../utils/is-dev-env.js";
2
+ import { hasStylesGenerated } from "../config.js";
3
+
4
+ //#region src/states/index.ts
5
+ /**
6
+ * Advanced State Mapping - Predefined States Management
7
+ *
8
+ * This module handles global and local predefined states for the Tasty styling system.
9
+ * See ADVANCED_STATE_MAPPING.md for full specification.
10
+ */
11
+ const BUILTIN_STATES = new Set([
12
+ "@starting",
13
+ "@keyframes",
14
+ "@properties",
15
+ "@supports",
16
+ "@inherit"
17
+ ]);
18
+ const RESERVED_PREFIXES = [
19
+ "@media",
20
+ "@root",
21
+ "@own",
22
+ "@(",
23
+ "@starting",
24
+ "@keyframes",
25
+ "@properties",
26
+ "@supports",
27
+ "@inherit"
28
+ ];
29
+ let globalPredefinedStates = {};
30
+ const emittedWarnings = /* @__PURE__ */ new Set();
31
+ const devMode = isDevEnv();
32
+ /**
33
+ * Emit a warning only once
34
+ */
35
+ function warnOnce(key, message) {
36
+ if (devMode && !emittedWarnings.has(key)) {
37
+ emittedWarnings.add(key);
38
+ console.warn(message);
39
+ }
40
+ }
41
+ /**
42
+ * Configure global predefined states
43
+ */
44
+ function setGlobalPredefinedStates(states) {
45
+ if (hasStylesGenerated()) {
46
+ const newStateNames = Object.keys(states).join(", ");
47
+ warnOnce(`dynamic-states:${newStateNames}`, `[Tasty] Cannot update predefined states after styles have been generated.\nThe new definition(s) for ${newStateNames} will be ignored.`);
48
+ return;
49
+ }
50
+ for (const [name, value] of Object.entries(states)) {
51
+ if (!/^@[A-Za-z][A-Za-z0-9-]*$/.test(name)) {
52
+ warnOnce(`invalid-state-name:${name}`, `[Tasty] Invalid predefined state name '${name}'. Must start with '@' followed by a letter.`);
53
+ continue;
54
+ }
55
+ if (BUILTIN_STATES.has(name)) {
56
+ warnOnce(`reserved-state:${name}`, `[Tasty] Cannot define predefined state '${name}'. This name is reserved for built-in functionality.`);
57
+ continue;
58
+ }
59
+ if (name === "@media" || name === "@root" || name === "@own" || name.startsWith("@(")) {
60
+ warnOnce(`reserved-prefix:${name}`, `[Tasty] Cannot define predefined state '${name}'. This prefix is reserved for built-in functionality.`);
61
+ continue;
62
+ }
63
+ const crossRefs = extractPredefinedStateRefs(value);
64
+ if (crossRefs.length > 0) {
65
+ warnOnce(`cross-ref:${name}`, `[Tasty] Predefined state '${name}' references another predefined state '${crossRefs[0]}'.\nPredefined states cannot reference each other. Use the full definition instead.`);
66
+ continue;
67
+ }
68
+ if (globalPredefinedStates[name] && globalPredefinedStates[name] !== value) warnOnce(`duplicate-state:${name}`, `[Tasty] Duplicate predefined state '${name}' in configure(). The last definition will be used.`);
69
+ globalPredefinedStates[name] = value;
70
+ }
71
+ }
72
+ /**
73
+ * Get global predefined states
74
+ */
75
+ function getGlobalPredefinedStates() {
76
+ return globalPredefinedStates;
77
+ }
78
+ /**
79
+ * Regex to match predefined state references in a string
80
+ * Matches @name that is NOT followed by ( or : and is a complete word
81
+ * Uses word boundary and negative lookahead
82
+ */
83
+ const PREDEFINED_STATE_PATTERN = /@([A-Za-z][A-Za-z0-9-]*)(?![A-Za-z0-9-:(])/g;
84
+ /**
85
+ * Extract predefined state references from a string
86
+ */
87
+ function extractPredefinedStateRefs(value) {
88
+ const matches = value.matchAll(PREDEFINED_STATE_PATTERN);
89
+ const refs = [];
90
+ for (const match of matches) {
91
+ const stateName = "@" + match[1];
92
+ if (!BUILTIN_STATES.has(stateName) && !refs.includes(stateName)) refs.push(stateName);
93
+ }
94
+ return refs;
95
+ }
96
+ /**
97
+ * Check if a state key is a predefined state reference
98
+ */
99
+ function isPredefinedStateRef(stateKey) {
100
+ if (!stateKey.startsWith("@")) return false;
101
+ if (BUILTIN_STATES.has(stateKey)) return false;
102
+ for (const prefix of RESERVED_PREFIXES) if (stateKey === prefix || stateKey.startsWith(prefix)) {
103
+ if (stateKey === "@media" || stateKey.startsWith("@media(") || stateKey.startsWith("@media:")) return false;
104
+ if (stateKey === "@root" || stateKey.startsWith("@root(")) return false;
105
+ if (stateKey === "@own" || stateKey.startsWith("@own(")) return false;
106
+ if (stateKey.startsWith("@(")) return false;
107
+ }
108
+ return /^@[A-Za-z][A-Za-z0-9-]*$/.test(stateKey);
109
+ }
110
+ /**
111
+ * Extract local predefined states from a styles object
112
+ * Local predefined states are top-level keys starting with @ that have string values
113
+ * and are valid predefined state names (not built-in like @media, @root, etc.)
114
+ */
115
+ function extractLocalPredefinedStates(styles) {
116
+ const localStates = {};
117
+ if (!styles || typeof styles !== "object") return localStates;
118
+ for (const [key, value] of Object.entries(styles)) if (key.startsWith("@") && typeof value === "string") {
119
+ if (!/^@[A-Za-z][A-Za-z0-9-]*$/.test(key)) continue;
120
+ if (BUILTIN_STATES.has(key)) continue;
121
+ if (key === "@media" || key === "@root" || key === "@own" || key.startsWith("@(")) continue;
122
+ const crossRefs = extractPredefinedStateRefs(value);
123
+ if (crossRefs.length > 0) {
124
+ warnOnce(`local-cross-ref:${key}`, `[Tasty] Predefined state '${key}' references another predefined state '${crossRefs[0]}'.\nPredefined states cannot reference each other. Use the full definition instead.`);
125
+ continue;
126
+ }
127
+ localStates[key] = value;
128
+ }
129
+ return localStates;
130
+ }
131
+ /**
132
+ * Create a state parser context from styles
133
+ */
134
+ function createStateParserContext(styles, isSubElement) {
135
+ return {
136
+ localPredefinedStates: styles ? extractLocalPredefinedStates(styles) : {},
137
+ globalPredefinedStates: getGlobalPredefinedStates(),
138
+ isSubElement
139
+ };
140
+ }
141
+ /**
142
+ * Resolve a predefined state reference to its value
143
+ * Returns the resolved value or null if not found
144
+ */
145
+ function resolvePredefinedState(stateKey, ctx) {
146
+ if (ctx.localPredefinedStates[stateKey]) return ctx.localPredefinedStates[stateKey];
147
+ if (ctx.globalPredefinedStates[stateKey]) return ctx.globalPredefinedStates[stateKey];
148
+ warnOnce(`undefined-state:${stateKey}`, `[Tasty] Undefined predefined state '${stateKey}'.\nDefine it in configure({ states: { '${stateKey}': '...' } }) or in the component's styles.`);
149
+ return null;
150
+ }
151
+ /**
152
+ * Expand dimension shorthands in a condition string
153
+ * w -> width, h -> height, is -> inline-size, bs -> block-size
154
+ */
155
+ function expandDimensionShorthands(condition) {
156
+ let result = condition;
157
+ result = result.replace(/\bw\b/g, "width");
158
+ result = result.replace(/\bh\b/g, "height");
159
+ result = result.replace(/\bis\b/g, "inline-size");
160
+ result = result.replace(/\bbs\b/g, "block-size");
161
+ return result;
162
+ }
163
+ /**
164
+ * Convert tasty units in a string (e.g., 40x -> calc(var(--gap) * 40))
165
+ */
166
+ function expandTastyUnits(value) {
167
+ return value.replace(/(\d+(?:\.\d+)?)\s*x\b/g, (_, num) => {
168
+ return `calc(var(--gap) * ${num})`;
169
+ });
170
+ }
171
+ /**
172
+ * Parse an advanced state key and return its type and components
173
+ */
174
+ function parseAdvancedState(stateKey, ctx) {
175
+ const raw = stateKey;
176
+ if (stateKey === "@starting") return {
177
+ type: "starting",
178
+ condition: "",
179
+ raw
180
+ };
181
+ if (stateKey.startsWith("@media:")) {
182
+ const mediaType = stateKey.slice(7);
183
+ if (![
184
+ "all",
185
+ "screen",
186
+ "print",
187
+ "speech"
188
+ ].includes(mediaType)) warnOnce(`unknown-media-type:${mediaType}`, `[Tasty] Unknown media type '${mediaType}'. Valid types: all, screen, print, speech.`);
189
+ return {
190
+ type: "media",
191
+ condition: "",
192
+ mediaType,
193
+ raw
194
+ };
195
+ }
196
+ if (stateKey.startsWith("@media(")) {
197
+ const endParen = findMatchingParen(stateKey, 6);
198
+ if (endParen === -1) {
199
+ warnOnce(`unclosed-media:${stateKey}`, `[Tasty] Unclosed media query '${stateKey}'. Missing closing parenthesis.`);
200
+ return {
201
+ type: "modifier",
202
+ condition: stateKey,
203
+ raw
204
+ };
205
+ }
206
+ let condition = stateKey.slice(7, endParen);
207
+ if (!condition.trim()) {
208
+ warnOnce(`empty-media:${stateKey}`, `[Tasty] Empty media query condition '${stateKey}'.`);
209
+ return {
210
+ type: "modifier",
211
+ condition: stateKey,
212
+ raw
213
+ };
214
+ }
215
+ condition = expandDimensionShorthands(condition);
216
+ condition = expandTastyUnits(condition);
217
+ return {
218
+ type: "media",
219
+ condition,
220
+ raw
221
+ };
222
+ }
223
+ if (stateKey.startsWith("@root(")) {
224
+ const endParen = findMatchingParen(stateKey, 5);
225
+ if (endParen === -1) {
226
+ warnOnce(`unclosed-root:${stateKey}`, `[Tasty] Unclosed root state '${stateKey}'. Missing closing parenthesis.`);
227
+ return {
228
+ type: "modifier",
229
+ condition: stateKey,
230
+ raw
231
+ };
232
+ }
233
+ const condition = stateKey.slice(6, endParen);
234
+ if (!condition.trim()) {
235
+ warnOnce(`empty-root:${stateKey}`, `[Tasty] Empty root state condition '${stateKey}'.`);
236
+ return {
237
+ type: "modifier",
238
+ condition: stateKey,
239
+ raw
240
+ };
241
+ }
242
+ return {
243
+ type: "root",
244
+ condition,
245
+ raw
246
+ };
247
+ }
248
+ if (stateKey.startsWith("@own(")) {
249
+ const endParen = findMatchingParen(stateKey, 4);
250
+ if (endParen === -1) {
251
+ warnOnce(`unclosed-own:${stateKey}`, `[Tasty] Unclosed own state '${stateKey}'. Missing closing parenthesis.`);
252
+ return {
253
+ type: "modifier",
254
+ condition: stateKey,
255
+ raw
256
+ };
257
+ }
258
+ const condition = stateKey.slice(5, endParen);
259
+ if (!condition.trim()) {
260
+ warnOnce(`empty-own:${stateKey}`, `[Tasty] Empty own state condition '${stateKey}'.`);
261
+ return {
262
+ type: "modifier",
263
+ condition: stateKey,
264
+ raw
265
+ };
266
+ }
267
+ if (!ctx.isSubElement) {
268
+ warnOnce(`own-outside-subelement:${stateKey}`, `[Tasty] @own(${condition}) used outside sub-element context.\n@own() is equivalent to '${condition}' at the root level. Did you mean to use it inside a sub-element?`);
269
+ return {
270
+ type: "modifier",
271
+ condition,
272
+ raw
273
+ };
274
+ }
275
+ return {
276
+ type: "own",
277
+ condition,
278
+ raw
279
+ };
280
+ }
281
+ if (stateKey.startsWith("@(")) {
282
+ const endParen = findMatchingParen(stateKey, 1);
283
+ if (endParen === -1) {
284
+ warnOnce(`unclosed-container:${stateKey}`, `[Tasty] Unclosed container query '${stateKey}'. Missing closing parenthesis.`);
285
+ return {
286
+ type: "modifier",
287
+ condition: stateKey,
288
+ raw
289
+ };
290
+ }
291
+ const content = stateKey.slice(2, endParen);
292
+ if (!content.trim()) {
293
+ warnOnce(`empty-container:${stateKey}`, `[Tasty] Empty container query '${stateKey}'.`);
294
+ return {
295
+ type: "modifier",
296
+ condition: stateKey,
297
+ raw
298
+ };
299
+ }
300
+ const commaIndex = findTopLevelComma(content);
301
+ let containerName;
302
+ let condition;
303
+ if (commaIndex !== -1) {
304
+ containerName = content.slice(0, commaIndex).trim();
305
+ condition = content.slice(commaIndex + 1).trim();
306
+ } else condition = content.trim();
307
+ if (condition.startsWith("$")) {
308
+ const styleCondition = parseStyleQuery(condition);
309
+ if (!styleCondition) {
310
+ warnOnce(`invalid-style-query:${stateKey}`, `[Tasty] Invalid style query '${condition}' in container query.`);
311
+ return {
312
+ type: "modifier",
313
+ condition: stateKey,
314
+ raw
315
+ };
316
+ }
317
+ condition = styleCondition;
318
+ } else if (/^[a-zA-Z][\w-]*\s*\(/.test(condition)) {} else {
319
+ condition = expandDimensionShorthands(condition);
320
+ condition = expandTastyUnits(condition);
321
+ }
322
+ return {
323
+ type: "container",
324
+ condition,
325
+ containerName,
326
+ raw
327
+ };
328
+ }
329
+ if (isPredefinedStateRef(stateKey)) {
330
+ const resolved = resolvePredefinedState(stateKey, ctx);
331
+ if (resolved) return {
332
+ ...parseAdvancedState(resolved, ctx),
333
+ raw
334
+ };
335
+ return {
336
+ type: "modifier",
337
+ condition: stateKey,
338
+ raw
339
+ };
340
+ }
341
+ return {
342
+ type: "modifier",
343
+ condition: stateKey,
344
+ raw
345
+ };
346
+ }
347
+ /**
348
+ * Parse a style query condition (e.g., $compact, $variant=compact, $variant="very compact")
349
+ */
350
+ function parseStyleQuery(condition) {
351
+ const query = condition.slice(1);
352
+ if (/[<>]/.test(query)) {
353
+ warnOnce(`style-query-comparison:${condition}`, `[Tasty] Style queries only support equality. '${condition}' is invalid. Use '${condition.split(/[<>]/)[0]}=...' instead.`);
354
+ return null;
355
+ }
356
+ const eqIndex = query.indexOf("=");
357
+ if (eqIndex === -1) return `style(--${query})`;
358
+ const propName = query.slice(0, eqIndex).trim();
359
+ let value = query.slice(eqIndex + 1).trim();
360
+ if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) {} else value = `"${value}"`;
361
+ value = expandTastyUnits(value);
362
+ return `style(--${propName}: ${value})`;
363
+ }
364
+ /**
365
+ * Find the index of the first comma at parentheses depth 0.
366
+ * Returns -1 if no top-level comma is found.
367
+ * This prevents splitting on commas inside function calls like scroll-state(a, b).
368
+ */
369
+ function findTopLevelComma(s) {
370
+ let depth = 0;
371
+ for (let i = 0; i < s.length; i++) if (s[i] === "(") depth++;
372
+ else if (s[i] === ")") depth--;
373
+ else if (s[i] === "," && depth === 0) return i;
374
+ return -1;
375
+ }
376
+ function findMatchingParen(str, startIndex) {
377
+ let depth = 1;
378
+ let i = startIndex + 1;
379
+ while (i < str.length && depth > 0) {
380
+ if (str[i] === "(") depth++;
381
+ else if (str[i] === ")") depth--;
382
+ i++;
383
+ }
384
+ return depth === 0 ? i - 1 : -1;
385
+ }
386
+
387
+ //#endregion
388
+ export { createStateParserContext, expandDimensionShorthands, expandTastyUnits, extractLocalPredefinedStates, extractPredefinedStateRefs, findTopLevelComma, getGlobalPredefinedStates, parseAdvancedState, resolvePredefinedState, setGlobalPredefinedStates };
389
+ //# sourceMappingURL=index.js.map