@tenphi/tasty 0.0.0-snapshot.09c74e2

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 (243) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +539 -0
  3. package/dist/_virtual/_rolldown/runtime.js +8 -0
  4. package/dist/chunks/cacheKey.js +70 -0
  5. package/dist/chunks/cacheKey.js.map +1 -0
  6. package/dist/chunks/definitions.d.ts +37 -0
  7. package/dist/chunks/definitions.js +260 -0
  8. package/dist/chunks/definitions.js.map +1 -0
  9. package/dist/chunks/renderChunk.js +61 -0
  10. package/dist/chunks/renderChunk.js.map +1 -0
  11. package/dist/config.d.ts +280 -0
  12. package/dist/config.js +403 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/core/index.d.ts +33 -0
  15. package/dist/core/index.js +26 -0
  16. package/dist/debug.d.ts +204 -0
  17. package/dist/debug.js +733 -0
  18. package/dist/debug.js.map +1 -0
  19. package/dist/hooks/useGlobalStyles.d.ts +27 -0
  20. package/dist/hooks/useGlobalStyles.js +56 -0
  21. package/dist/hooks/useGlobalStyles.js.map +1 -0
  22. package/dist/hooks/useKeyframes.d.ts +56 -0
  23. package/dist/hooks/useKeyframes.js +54 -0
  24. package/dist/hooks/useKeyframes.js.map +1 -0
  25. package/dist/hooks/useProperty.d.ts +79 -0
  26. package/dist/hooks/useProperty.js +91 -0
  27. package/dist/hooks/useProperty.js.map +1 -0
  28. package/dist/hooks/useRawCSS.d.ts +53 -0
  29. package/dist/hooks/useRawCSS.js +28 -0
  30. package/dist/hooks/useRawCSS.js.map +1 -0
  31. package/dist/hooks/useStyles.d.ts +40 -0
  32. package/dist/hooks/useStyles.js +169 -0
  33. package/dist/hooks/useStyles.js.map +1 -0
  34. package/dist/index.d.ts +48 -0
  35. package/dist/index.js +33 -0
  36. package/dist/injector/index.d.ts +157 -0
  37. package/dist/injector/index.js +154 -0
  38. package/dist/injector/index.js.map +1 -0
  39. package/dist/injector/injector.d.ts +139 -0
  40. package/dist/injector/injector.js +404 -0
  41. package/dist/injector/injector.js.map +1 -0
  42. package/dist/injector/sheet-manager.d.ts +127 -0
  43. package/dist/injector/sheet-manager.js +714 -0
  44. package/dist/injector/sheet-manager.js.map +1 -0
  45. package/dist/injector/types.d.ts +135 -0
  46. package/dist/keyframes/index.js +206 -0
  47. package/dist/keyframes/index.js.map +1 -0
  48. package/dist/parser/classify.js +319 -0
  49. package/dist/parser/classify.js.map +1 -0
  50. package/dist/parser/const.js +33 -0
  51. package/dist/parser/const.js.map +1 -0
  52. package/dist/parser/lru.js +109 -0
  53. package/dist/parser/lru.js.map +1 -0
  54. package/dist/parser/parser.d.ts +25 -0
  55. package/dist/parser/parser.js +116 -0
  56. package/dist/parser/parser.js.map +1 -0
  57. package/dist/parser/tokenizer.js +69 -0
  58. package/dist/parser/tokenizer.js.map +1 -0
  59. package/dist/parser/types.d.ts +51 -0
  60. package/dist/parser/types.js +46 -0
  61. package/dist/parser/types.js.map +1 -0
  62. package/dist/pipeline/conditions.d.ts +134 -0
  63. package/dist/pipeline/conditions.js +406 -0
  64. package/dist/pipeline/conditions.js.map +1 -0
  65. package/dist/pipeline/exclusive.js +231 -0
  66. package/dist/pipeline/exclusive.js.map +1 -0
  67. package/dist/pipeline/index.d.ts +53 -0
  68. package/dist/pipeline/index.js +660 -0
  69. package/dist/pipeline/index.js.map +1 -0
  70. package/dist/pipeline/materialize.js +844 -0
  71. package/dist/pipeline/materialize.js.map +1 -0
  72. package/dist/pipeline/parseStateKey.d.ts +15 -0
  73. package/dist/pipeline/parseStateKey.js +438 -0
  74. package/dist/pipeline/parseStateKey.js.map +1 -0
  75. package/dist/pipeline/simplify.js +516 -0
  76. package/dist/pipeline/simplify.js.map +1 -0
  77. package/dist/pipeline/warnings.js +18 -0
  78. package/dist/pipeline/warnings.js.map +1 -0
  79. package/dist/plugins/okhsl-plugin.d.ts +35 -0
  80. package/dist/plugins/okhsl-plugin.js +371 -0
  81. package/dist/plugins/okhsl-plugin.js.map +1 -0
  82. package/dist/plugins/types.d.ts +69 -0
  83. package/dist/properties/index.js +158 -0
  84. package/dist/properties/index.js.map +1 -0
  85. package/dist/states/index.d.ts +49 -0
  86. package/dist/states/index.js +416 -0
  87. package/dist/states/index.js.map +1 -0
  88. package/dist/static/index.d.ts +5 -0
  89. package/dist/static/index.js +5 -0
  90. package/dist/static/tastyStatic.d.ts +46 -0
  91. package/dist/static/tastyStatic.js +31 -0
  92. package/dist/static/tastyStatic.js.map +1 -0
  93. package/dist/static/types.d.ts +49 -0
  94. package/dist/static/types.js +24 -0
  95. package/dist/static/types.js.map +1 -0
  96. package/dist/styles/align.d.ts +15 -0
  97. package/dist/styles/align.js +14 -0
  98. package/dist/styles/align.js.map +1 -0
  99. package/dist/styles/border.d.ts +25 -0
  100. package/dist/styles/border.js +114 -0
  101. package/dist/styles/border.js.map +1 -0
  102. package/dist/styles/color.d.ts +14 -0
  103. package/dist/styles/color.js +23 -0
  104. package/dist/styles/color.js.map +1 -0
  105. package/dist/styles/createStyle.js +77 -0
  106. package/dist/styles/createStyle.js.map +1 -0
  107. package/dist/styles/dimension.js +97 -0
  108. package/dist/styles/dimension.js.map +1 -0
  109. package/dist/styles/display.d.ts +37 -0
  110. package/dist/styles/display.js +67 -0
  111. package/dist/styles/display.js.map +1 -0
  112. package/dist/styles/fade.d.ts +15 -0
  113. package/dist/styles/fade.js +58 -0
  114. package/dist/styles/fade.js.map +1 -0
  115. package/dist/styles/fill.d.ts +42 -0
  116. package/dist/styles/fill.js +52 -0
  117. package/dist/styles/fill.js.map +1 -0
  118. package/dist/styles/flow.d.ts +16 -0
  119. package/dist/styles/flow.js +12 -0
  120. package/dist/styles/flow.js.map +1 -0
  121. package/dist/styles/gap.d.ts +31 -0
  122. package/dist/styles/gap.js +37 -0
  123. package/dist/styles/gap.js.map +1 -0
  124. package/dist/styles/height.d.ts +17 -0
  125. package/dist/styles/height.js +20 -0
  126. package/dist/styles/height.js.map +1 -0
  127. package/dist/styles/index.d.ts +2 -0
  128. package/dist/styles/index.js +9 -0
  129. package/dist/styles/index.js.map +1 -0
  130. package/dist/styles/inset.d.ts +52 -0
  131. package/dist/styles/inset.js +150 -0
  132. package/dist/styles/inset.js.map +1 -0
  133. package/dist/styles/justify.d.ts +15 -0
  134. package/dist/styles/justify.js +14 -0
  135. package/dist/styles/justify.js.map +1 -0
  136. package/dist/styles/list.d.ts +16 -0
  137. package/dist/styles/list.js +98 -0
  138. package/dist/styles/list.js.map +1 -0
  139. package/dist/styles/margin.d.ts +24 -0
  140. package/dist/styles/margin.js +104 -0
  141. package/dist/styles/margin.js.map +1 -0
  142. package/dist/styles/outline.d.ts +29 -0
  143. package/dist/styles/outline.js +65 -0
  144. package/dist/styles/outline.js.map +1 -0
  145. package/dist/styles/padding.d.ts +24 -0
  146. package/dist/styles/padding.js +104 -0
  147. package/dist/styles/padding.js.map +1 -0
  148. package/dist/styles/predefined.d.ts +73 -0
  149. package/dist/styles/predefined.js +241 -0
  150. package/dist/styles/predefined.js.map +1 -0
  151. package/dist/styles/preset.d.ts +47 -0
  152. package/dist/styles/preset.js +126 -0
  153. package/dist/styles/preset.js.map +1 -0
  154. package/dist/styles/radius.d.ts +14 -0
  155. package/dist/styles/radius.js +51 -0
  156. package/dist/styles/radius.js.map +1 -0
  157. package/dist/styles/scrollbar.d.ts +21 -0
  158. package/dist/styles/scrollbar.js +112 -0
  159. package/dist/styles/scrollbar.js.map +1 -0
  160. package/dist/styles/shadow.d.ts +14 -0
  161. package/dist/styles/shadow.js +24 -0
  162. package/dist/styles/shadow.js.map +1 -0
  163. package/dist/styles/styledScrollbar.d.ts +47 -0
  164. package/dist/styles/styledScrollbar.js +38 -0
  165. package/dist/styles/styledScrollbar.js.map +1 -0
  166. package/dist/styles/transition.d.ts +14 -0
  167. package/dist/styles/transition.js +158 -0
  168. package/dist/styles/transition.js.map +1 -0
  169. package/dist/styles/types.d.ts +498 -0
  170. package/dist/styles/width.d.ts +17 -0
  171. package/dist/styles/width.js +20 -0
  172. package/dist/styles/width.js.map +1 -0
  173. package/dist/tasty.d.ts +982 -0
  174. package/dist/tasty.js +206 -0
  175. package/dist/tasty.js.map +1 -0
  176. package/dist/tokens/typography.d.ts +19 -0
  177. package/dist/tokens/typography.js +237 -0
  178. package/dist/tokens/typography.js.map +1 -0
  179. package/dist/types.d.ts +184 -0
  180. package/dist/utils/cache-wrapper.js +26 -0
  181. package/dist/utils/cache-wrapper.js.map +1 -0
  182. package/dist/utils/case-converter.js +8 -0
  183. package/dist/utils/case-converter.js.map +1 -0
  184. package/dist/utils/colors.d.ts +5 -0
  185. package/dist/utils/colors.js +9 -0
  186. package/dist/utils/colors.js.map +1 -0
  187. package/dist/utils/css-types.d.ts +7 -0
  188. package/dist/utils/dotize.d.ts +26 -0
  189. package/dist/utils/dotize.js +122 -0
  190. package/dist/utils/dotize.js.map +1 -0
  191. package/dist/utils/filter-base-props.d.ts +15 -0
  192. package/dist/utils/filter-base-props.js +45 -0
  193. package/dist/utils/filter-base-props.js.map +1 -0
  194. package/dist/utils/get-display-name.d.ts +7 -0
  195. package/dist/utils/get-display-name.js +10 -0
  196. package/dist/utils/get-display-name.js.map +1 -0
  197. package/dist/utils/hsl-to-rgb.js +38 -0
  198. package/dist/utils/hsl-to-rgb.js.map +1 -0
  199. package/dist/utils/is-dev-env.js +19 -0
  200. package/dist/utils/is-dev-env.js.map +1 -0
  201. package/dist/utils/is-valid-element-type.js +15 -0
  202. package/dist/utils/is-valid-element-type.js.map +1 -0
  203. package/dist/utils/merge-styles.d.ts +7 -0
  204. package/dist/utils/merge-styles.js +146 -0
  205. package/dist/utils/merge-styles.js.map +1 -0
  206. package/dist/utils/mod-attrs.d.ts +8 -0
  207. package/dist/utils/mod-attrs.js +21 -0
  208. package/dist/utils/mod-attrs.js.map +1 -0
  209. package/dist/utils/okhsl-to-rgb.js +296 -0
  210. package/dist/utils/okhsl-to-rgb.js.map +1 -0
  211. package/dist/utils/process-tokens.d.ts +31 -0
  212. package/dist/utils/process-tokens.js +171 -0
  213. package/dist/utils/process-tokens.js.map +1 -0
  214. package/dist/utils/resolve-recipes.d.ts +17 -0
  215. package/dist/utils/resolve-recipes.js +147 -0
  216. package/dist/utils/resolve-recipes.js.map +1 -0
  217. package/dist/utils/string.js +8 -0
  218. package/dist/utils/string.js.map +1 -0
  219. package/dist/utils/styles.d.ts +178 -0
  220. package/dist/utils/styles.js +590 -0
  221. package/dist/utils/styles.js.map +1 -0
  222. package/dist/utils/typography.d.ts +36 -0
  223. package/dist/utils/typography.js +53 -0
  224. package/dist/utils/typography.js.map +1 -0
  225. package/dist/utils/warnings.d.ts +16 -0
  226. package/dist/utils/warnings.js +16 -0
  227. package/dist/utils/warnings.js.map +1 -0
  228. package/dist/zero/babel.d.ts +108 -0
  229. package/dist/zero/babel.js +282 -0
  230. package/dist/zero/babel.js.map +1 -0
  231. package/dist/zero/css-writer.d.ts +45 -0
  232. package/dist/zero/css-writer.js +74 -0
  233. package/dist/zero/css-writer.js.map +1 -0
  234. package/dist/zero/extractor.d.ts +24 -0
  235. package/dist/zero/extractor.js +150 -0
  236. package/dist/zero/extractor.js.map +1 -0
  237. package/dist/zero/index.d.ts +3 -0
  238. package/dist/zero/index.js +4 -0
  239. package/dist/zero/next.d.ts +60 -0
  240. package/dist/zero/next.js +78 -0
  241. package/dist/zero/next.js.map +1 -0
  242. package/package.json +189 -0
  243. package/tasty.config.ts +14 -0
@@ -0,0 +1,158 @@
1
+ import { getRgbValuesFromRgbaString, strToRgb } from "../utils/styles.js";
2
+
3
+ //#region src/properties/index.ts
4
+ const PROPERTIES_KEY = "@properties";
5
+ /**
6
+ * Valid CSS custom property name pattern (after the -- prefix).
7
+ * Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.
8
+ */
9
+ const VALID_PROPERTY_NAME_PATTERN = /^[a-z_][a-z0-9-_]*$/i;
10
+ /**
11
+ * Validate a CSS custom property name (the part after --).
12
+ * Returns true if the name is valid for use as a CSS custom property.
13
+ */
14
+ function isValidPropertyName(name) {
15
+ return VALID_PROPERTY_NAME_PATTERN.test(name);
16
+ }
17
+ /**
18
+ * Check if styles object has local @properties definition.
19
+ * Fast path: single property lookup.
20
+ */
21
+ function hasLocalProperties(styles) {
22
+ return PROPERTIES_KEY in styles;
23
+ }
24
+ /**
25
+ * Extract local @properties from styles object.
26
+ * Returns null if no local properties (fast path).
27
+ */
28
+ function extractLocalProperties(styles) {
29
+ const properties = styles[PROPERTIES_KEY];
30
+ if (!properties || typeof properties !== "object") return null;
31
+ return properties;
32
+ }
33
+ /**
34
+ * Parse a property token name and return the CSS property name and whether it's a color.
35
+ * Supports tasty token syntax and validates the property name.
36
+ *
37
+ * Token formats:
38
+ * - `$name` → { cssName: '--name', isColor: false }
39
+ * - `#name` → { cssName: '--name-color', isColor: true }
40
+ * - `--name` → { cssName: '--name', isColor: false } (legacy, auto-detect color by suffix)
41
+ * - `name` → { cssName: '--name', isColor: false } (legacy)
42
+ *
43
+ * @param token - The property token to parse
44
+ * @returns Parsed result with cssName, isColor, isValid, and optional error
45
+ */
46
+ function parsePropertyToken(token) {
47
+ if (!token || typeof token !== "string") return {
48
+ cssName: "",
49
+ isColor: false,
50
+ isValid: false,
51
+ error: "Property token must be a non-empty string"
52
+ };
53
+ let name;
54
+ let isColor;
55
+ if (token.startsWith("$")) {
56
+ name = token.slice(1);
57
+ isColor = false;
58
+ } else if (token.startsWith("#")) {
59
+ name = token.slice(1);
60
+ isColor = true;
61
+ } else if (token.startsWith("--")) {
62
+ name = token.slice(2);
63
+ isColor = token.endsWith("-color");
64
+ } else {
65
+ name = token;
66
+ isColor = token.endsWith("-color");
67
+ }
68
+ if (!name) return {
69
+ cssName: "",
70
+ isColor,
71
+ isValid: false,
72
+ error: "Property name cannot be empty"
73
+ };
74
+ if (!isValidPropertyName(name)) return {
75
+ cssName: "",
76
+ isColor,
77
+ isValid: false,
78
+ error: `Invalid property name "${name}". Must start with a letter or underscore, followed by letters, digits, hyphens, or underscores.`
79
+ };
80
+ let cssName;
81
+ if (token.startsWith("#")) cssName = `--${name}-color`;
82
+ else cssName = `--${name}`;
83
+ return {
84
+ cssName,
85
+ isColor,
86
+ isValid: true
87
+ };
88
+ }
89
+ /**
90
+ * Normalize a property definition to a consistent string representation.
91
+ * Used for comparing definitions to detect changes/conflicts.
92
+ *
93
+ * Keys are sorted alphabetically to ensure consistent comparison:
94
+ * { inherits: true, syntax: '<color>' } === { syntax: '<color>', inherits: true }
95
+ */
96
+ function normalizePropertyDefinition(def) {
97
+ const normalized = {};
98
+ if (def.inherits !== void 0) normalized.inherits = def.inherits;
99
+ if (def.initialValue !== void 0) normalized.initialValue = String(def.initialValue);
100
+ if (def.syntax !== void 0) normalized.syntax = def.syntax;
101
+ return JSON.stringify(normalized);
102
+ }
103
+ /**
104
+ * Get the effective property definition for a token.
105
+ * For color tokens (#name), auto-sets syntax to '<color>' and defaults initialValue to 'transparent'.
106
+ *
107
+ * @param token - Property token ($name, #name, --name, or plain name)
108
+ * @param userDefinition - User-provided definition options
109
+ * @returns Effective definition with cssName, definition, isValid, and optional error
110
+ */
111
+ function getEffectiveDefinition(token, userDefinition) {
112
+ const parsed = parsePropertyToken(token);
113
+ if (!parsed.isValid) return {
114
+ cssName: "",
115
+ definition: userDefinition,
116
+ isColor: false,
117
+ isValid: false,
118
+ error: parsed.error
119
+ };
120
+ if (parsed.isColor) return {
121
+ cssName: parsed.cssName,
122
+ definition: {
123
+ syntax: "<color>",
124
+ inherits: userDefinition.inherits,
125
+ initialValue: userDefinition.initialValue ?? "transparent"
126
+ },
127
+ isColor: true,
128
+ isValid: true
129
+ };
130
+ return {
131
+ cssName: parsed.cssName,
132
+ definition: userDefinition,
133
+ isColor: false,
134
+ isValid: true
135
+ };
136
+ }
137
+ /**
138
+ * Extract RGB triplet string from a color initial value.
139
+ * Used when auto-creating the companion `-rgb` property for color @property definitions.
140
+ *
141
+ * @param initialValue - The color property's initial value (e.g., 'rgb(255 255 255)', 'transparent', '#fff')
142
+ * @returns Space-separated RGB triplet (e.g., '255 255 255'), defaults to '0 0 0'
143
+ */
144
+ function colorInitialValueToRgb(initialValue) {
145
+ if (initialValue == null) return "0 0 0";
146
+ const str = String(initialValue).trim();
147
+ if (!str || str === "transparent") return "0 0 0";
148
+ const rgba = strToRgb(str);
149
+ if (rgba) {
150
+ const values = getRgbValuesFromRgbaString(rgba);
151
+ if (values.length >= 3) return values.slice(0, 3).join(" ");
152
+ }
153
+ return "0 0 0";
154
+ }
155
+
156
+ //#endregion
157
+ export { colorInitialValueToRgb, extractLocalProperties, getEffectiveDefinition, hasLocalProperties, normalizePropertyDefinition };
158
+ //# sourceMappingURL=index.js.map
@@ -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,49 @@
1
+ import { Styles } from "../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' | 'parent' | '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
+ /**
44
+ * Create a state parser context from styles
45
+ */
46
+ declare function createStateParserContext(styles?: Styles, isSubElement?: boolean): StateParserContext;
47
+ //#endregion
48
+ export { AtRuleContext, ParsedAdvancedState, StateParserContext, createStateParserContext, getGlobalPredefinedStates, setGlobalPredefinedStates };
49
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,416 @@
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
+ "@parent",
22
+ "@own",
23
+ "@(",
24
+ "@starting",
25
+ "@keyframes",
26
+ "@properties",
27
+ "@supports",
28
+ "@inherit"
29
+ ];
30
+ let globalPredefinedStates = {};
31
+ const emittedWarnings = /* @__PURE__ */ new Set();
32
+ const devMode = isDevEnv();
33
+ /**
34
+ * Emit a warning only once
35
+ */
36
+ function warnOnce(key, message) {
37
+ if (devMode && !emittedWarnings.has(key)) {
38
+ emittedWarnings.add(key);
39
+ console.warn(message);
40
+ }
41
+ }
42
+ /**
43
+ * Configure global predefined states
44
+ */
45
+ function setGlobalPredefinedStates(states) {
46
+ if (hasStylesGenerated()) {
47
+ const newStateNames = Object.keys(states).join(", ");
48
+ warnOnce(`dynamic-states:${newStateNames}`, `[Tasty] Cannot update predefined states after styles have been generated.\nThe new definition(s) for ${newStateNames} will be ignored.`);
49
+ return;
50
+ }
51
+ for (const [name, value] of Object.entries(states)) {
52
+ if (!/^@[A-Za-z][A-Za-z0-9-]*$/.test(name)) {
53
+ warnOnce(`invalid-state-name:${name}`, `[Tasty] Invalid predefined state name '${name}'. Must start with '@' followed by a letter.`);
54
+ continue;
55
+ }
56
+ if (BUILTIN_STATES.has(name)) {
57
+ warnOnce(`reserved-state:${name}`, `[Tasty] Cannot define predefined state '${name}'. This name is reserved for built-in functionality.`);
58
+ continue;
59
+ }
60
+ if (name === "@media" || name === "@root" || name === "@parent" || name === "@own" || name.startsWith("@(")) {
61
+ warnOnce(`reserved-prefix:${name}`, `[Tasty] Cannot define predefined state '${name}'. This prefix is reserved for built-in functionality.`);
62
+ continue;
63
+ }
64
+ const crossRefs = extractPredefinedStateRefs(value);
65
+ if (crossRefs.length > 0) {
66
+ 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.`);
67
+ continue;
68
+ }
69
+ if (globalPredefinedStates[name] && globalPredefinedStates[name] !== value) warnOnce(`duplicate-state:${name}`, `[Tasty] Duplicate predefined state '${name}' in configure(). The last definition will be used.`);
70
+ globalPredefinedStates[name] = value;
71
+ }
72
+ }
73
+ /**
74
+ * Get global predefined states
75
+ */
76
+ function getGlobalPredefinedStates() {
77
+ return globalPredefinedStates;
78
+ }
79
+ /**
80
+ * Regex to match predefined state references in a string
81
+ * Matches @name that is NOT followed by ( or : and is a complete word
82
+ * Uses word boundary and negative lookahead
83
+ */
84
+ const PREDEFINED_STATE_PATTERN = /@([A-Za-z][A-Za-z0-9-]*)(?![A-Za-z0-9-:(])/g;
85
+ /**
86
+ * Extract predefined state references from a string
87
+ */
88
+ function extractPredefinedStateRefs(value) {
89
+ const matches = value.matchAll(PREDEFINED_STATE_PATTERN);
90
+ const refs = [];
91
+ for (const match of matches) {
92
+ const stateName = "@" + match[1];
93
+ if (!BUILTIN_STATES.has(stateName) && !refs.includes(stateName)) refs.push(stateName);
94
+ }
95
+ return refs;
96
+ }
97
+ /**
98
+ * Check if a state key is a predefined state reference
99
+ */
100
+ function isPredefinedStateRef(stateKey) {
101
+ if (!stateKey.startsWith("@")) return false;
102
+ if (BUILTIN_STATES.has(stateKey)) return false;
103
+ for (const prefix of RESERVED_PREFIXES) if (stateKey === prefix || stateKey.startsWith(prefix)) {
104
+ if (stateKey === "@media" || stateKey.startsWith("@media(") || stateKey.startsWith("@media:")) return false;
105
+ if (stateKey === "@root" || stateKey.startsWith("@root(")) return false;
106
+ if (stateKey === "@parent" || stateKey.startsWith("@parent(")) return false;
107
+ if (stateKey === "@own" || stateKey.startsWith("@own(")) return false;
108
+ if (stateKey.startsWith("@(")) return false;
109
+ }
110
+ return /^@[A-Za-z][A-Za-z0-9-]*$/.test(stateKey);
111
+ }
112
+ /**
113
+ * Extract local predefined states from a styles object
114
+ * Local predefined states are top-level keys starting with @ that have string values
115
+ * and are valid predefined state names (not built-in like @media, @root, etc.)
116
+ */
117
+ function extractLocalPredefinedStates(styles) {
118
+ const localStates = {};
119
+ if (!styles || typeof styles !== "object") return localStates;
120
+ for (const [key, value] of Object.entries(styles)) if (key.startsWith("@") && typeof value === "string") {
121
+ if (!/^@[A-Za-z][A-Za-z0-9-]*$/.test(key)) continue;
122
+ if (BUILTIN_STATES.has(key)) continue;
123
+ if (key === "@media" || key === "@root" || key === "@parent" || key === "@own" || key.startsWith("@(")) continue;
124
+ const crossRefs = extractPredefinedStateRefs(value);
125
+ if (crossRefs.length > 0) {
126
+ 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.`);
127
+ continue;
128
+ }
129
+ localStates[key] = value;
130
+ }
131
+ return localStates;
132
+ }
133
+ /**
134
+ * Create a state parser context from styles
135
+ */
136
+ function createStateParserContext(styles, isSubElement) {
137
+ return {
138
+ localPredefinedStates: styles ? extractLocalPredefinedStates(styles) : {},
139
+ globalPredefinedStates: getGlobalPredefinedStates(),
140
+ isSubElement
141
+ };
142
+ }
143
+ /**
144
+ * Resolve a predefined state reference to its value
145
+ * Returns the resolved value or null if not found
146
+ */
147
+ function resolvePredefinedState(stateKey, ctx) {
148
+ if (ctx.localPredefinedStates[stateKey]) return ctx.localPredefinedStates[stateKey];
149
+ if (ctx.globalPredefinedStates[stateKey]) return ctx.globalPredefinedStates[stateKey];
150
+ warnOnce(`undefined-state:${stateKey}`, `[Tasty] Undefined predefined state '${stateKey}'.\nDefine it in configure({ states: { '${stateKey}': '...' } }) or in the component's styles.`);
151
+ return null;
152
+ }
153
+ /**
154
+ * Expand dimension shorthands in a condition string
155
+ * w -> width, h -> height, is -> inline-size, bs -> block-size
156
+ */
157
+ function expandDimensionShorthands(condition) {
158
+ let result = condition;
159
+ result = result.replace(/\bw\b/g, "width");
160
+ result = result.replace(/\bh\b/g, "height");
161
+ result = result.replace(/\bis\b/g, "inline-size");
162
+ result = result.replace(/\bbs\b/g, "block-size");
163
+ return result;
164
+ }
165
+ /**
166
+ * Convert tasty units in a string (e.g., 40x -> calc(var(--gap) * 40))
167
+ */
168
+ function expandTastyUnits(value) {
169
+ return value.replace(/(\d+(?:\.\d+)?)\s*x\b/g, (_, num) => {
170
+ return `calc(var(--gap) * ${num})`;
171
+ });
172
+ }
173
+ /**
174
+ * Parse an advanced state key and return its type and components
175
+ */
176
+ function parseAdvancedState(stateKey, ctx) {
177
+ const raw = stateKey;
178
+ if (stateKey === "@starting") return {
179
+ type: "starting",
180
+ condition: "",
181
+ raw
182
+ };
183
+ if (stateKey.startsWith("@media:")) {
184
+ const mediaType = stateKey.slice(7);
185
+ if (![
186
+ "all",
187
+ "screen",
188
+ "print",
189
+ "speech"
190
+ ].includes(mediaType)) warnOnce(`unknown-media-type:${mediaType}`, `[Tasty] Unknown media type '${mediaType}'. Valid types: all, screen, print, speech.`);
191
+ return {
192
+ type: "media",
193
+ condition: "",
194
+ mediaType,
195
+ raw
196
+ };
197
+ }
198
+ if (stateKey.startsWith("@media(")) {
199
+ const endParen = findMatchingParen(stateKey, 6);
200
+ if (endParen === -1) {
201
+ warnOnce(`unclosed-media:${stateKey}`, `[Tasty] Unclosed media query '${stateKey}'. Missing closing parenthesis.`);
202
+ return {
203
+ type: "modifier",
204
+ condition: stateKey,
205
+ raw
206
+ };
207
+ }
208
+ let condition = stateKey.slice(7, endParen);
209
+ if (!condition.trim()) {
210
+ warnOnce(`empty-media:${stateKey}`, `[Tasty] Empty media query condition '${stateKey}'.`);
211
+ return {
212
+ type: "modifier",
213
+ condition: stateKey,
214
+ raw
215
+ };
216
+ }
217
+ condition = expandDimensionShorthands(condition);
218
+ condition = expandTastyUnits(condition);
219
+ return {
220
+ type: "media",
221
+ condition,
222
+ raw
223
+ };
224
+ }
225
+ if (stateKey.startsWith("@root(")) {
226
+ const endParen = findMatchingParen(stateKey, 5);
227
+ if (endParen === -1) {
228
+ warnOnce(`unclosed-root:${stateKey}`, `[Tasty] Unclosed root state '${stateKey}'. Missing closing parenthesis.`);
229
+ return {
230
+ type: "modifier",
231
+ condition: stateKey,
232
+ raw
233
+ };
234
+ }
235
+ const condition = stateKey.slice(6, endParen);
236
+ if (!condition.trim()) {
237
+ warnOnce(`empty-root:${stateKey}`, `[Tasty] Empty root state condition '${stateKey}'.`);
238
+ return {
239
+ type: "modifier",
240
+ condition: stateKey,
241
+ raw
242
+ };
243
+ }
244
+ return {
245
+ type: "root",
246
+ condition,
247
+ raw
248
+ };
249
+ }
250
+ if (stateKey.startsWith("@parent(")) {
251
+ const endParen = findMatchingParen(stateKey, 7);
252
+ if (endParen === -1) {
253
+ warnOnce(`unclosed-parent:${stateKey}`, `[Tasty] Unclosed parent state '${stateKey}'. Missing closing parenthesis.`);
254
+ return {
255
+ type: "modifier",
256
+ condition: stateKey,
257
+ raw
258
+ };
259
+ }
260
+ const condition = stateKey.slice(8, endParen);
261
+ if (!condition.trim()) {
262
+ warnOnce(`empty-parent:${stateKey}`, `[Tasty] Empty parent state condition '${stateKey}'.`);
263
+ return {
264
+ type: "modifier",
265
+ condition: stateKey,
266
+ raw
267
+ };
268
+ }
269
+ return {
270
+ type: "parent",
271
+ condition,
272
+ raw
273
+ };
274
+ }
275
+ if (stateKey.startsWith("@own(")) {
276
+ const endParen = findMatchingParen(stateKey, 4);
277
+ if (endParen === -1) {
278
+ warnOnce(`unclosed-own:${stateKey}`, `[Tasty] Unclosed own state '${stateKey}'. Missing closing parenthesis.`);
279
+ return {
280
+ type: "modifier",
281
+ condition: stateKey,
282
+ raw
283
+ };
284
+ }
285
+ const condition = stateKey.slice(5, endParen);
286
+ if (!condition.trim()) {
287
+ warnOnce(`empty-own:${stateKey}`, `[Tasty] Empty own state condition '${stateKey}'.`);
288
+ return {
289
+ type: "modifier",
290
+ condition: stateKey,
291
+ raw
292
+ };
293
+ }
294
+ if (!ctx.isSubElement) {
295
+ 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?`);
296
+ return {
297
+ type: "modifier",
298
+ condition,
299
+ raw
300
+ };
301
+ }
302
+ return {
303
+ type: "own",
304
+ condition,
305
+ raw
306
+ };
307
+ }
308
+ if (stateKey.startsWith("@(")) {
309
+ const endParen = findMatchingParen(stateKey, 1);
310
+ if (endParen === -1) {
311
+ warnOnce(`unclosed-container:${stateKey}`, `[Tasty] Unclosed container query '${stateKey}'. Missing closing parenthesis.`);
312
+ return {
313
+ type: "modifier",
314
+ condition: stateKey,
315
+ raw
316
+ };
317
+ }
318
+ const content = stateKey.slice(2, endParen);
319
+ if (!content.trim()) {
320
+ warnOnce(`empty-container:${stateKey}`, `[Tasty] Empty container query '${stateKey}'.`);
321
+ return {
322
+ type: "modifier",
323
+ condition: stateKey,
324
+ raw
325
+ };
326
+ }
327
+ const commaIndex = findTopLevelComma(content);
328
+ let containerName;
329
+ let condition;
330
+ if (commaIndex !== -1) {
331
+ containerName = content.slice(0, commaIndex).trim();
332
+ condition = content.slice(commaIndex + 1).trim();
333
+ } else condition = content.trim();
334
+ if (condition.startsWith("$")) {
335
+ const styleCondition = parseStyleQuery(condition);
336
+ if (!styleCondition) {
337
+ warnOnce(`invalid-style-query:${stateKey}`, `[Tasty] Invalid style query '${condition}' in container query.`);
338
+ return {
339
+ type: "modifier",
340
+ condition: stateKey,
341
+ raw
342
+ };
343
+ }
344
+ condition = styleCondition;
345
+ } else if (/^[a-zA-Z][\w-]*\s*\(/.test(condition)) {} else {
346
+ condition = expandDimensionShorthands(condition);
347
+ condition = expandTastyUnits(condition);
348
+ }
349
+ return {
350
+ type: "container",
351
+ condition,
352
+ containerName,
353
+ raw
354
+ };
355
+ }
356
+ if (isPredefinedStateRef(stateKey)) {
357
+ const resolved = resolvePredefinedState(stateKey, ctx);
358
+ if (resolved) return {
359
+ ...parseAdvancedState(resolved, ctx),
360
+ raw
361
+ };
362
+ return {
363
+ type: "modifier",
364
+ condition: stateKey,
365
+ raw
366
+ };
367
+ }
368
+ return {
369
+ type: "modifier",
370
+ condition: stateKey,
371
+ raw
372
+ };
373
+ }
374
+ /**
375
+ * Parse a style query condition (e.g., $compact, $variant=compact, $variant="very compact")
376
+ */
377
+ function parseStyleQuery(condition) {
378
+ const query = condition.slice(1);
379
+ if (/[<>]/.test(query)) {
380
+ warnOnce(`style-query-comparison:${condition}`, `[Tasty] Style queries only support equality. '${condition}' is invalid. Use '${condition.split(/[<>]/)[0]}=...' instead.`);
381
+ return null;
382
+ }
383
+ const eqIndex = query.indexOf("=");
384
+ if (eqIndex === -1) return `style(--${query})`;
385
+ const propName = query.slice(0, eqIndex).trim();
386
+ let value = query.slice(eqIndex + 1).trim();
387
+ if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) {} else value = `"${value}"`;
388
+ value = expandTastyUnits(value);
389
+ return `style(--${propName}: ${value})`;
390
+ }
391
+ /**
392
+ * Find the index of the first comma at parentheses depth 0.
393
+ * Returns -1 if no top-level comma is found.
394
+ * This prevents splitting on commas inside function calls like scroll-state(a, b).
395
+ */
396
+ function findTopLevelComma(s) {
397
+ let depth = 0;
398
+ for (let i = 0; i < s.length; i++) if (s[i] === "(") depth++;
399
+ else if (s[i] === ")") depth--;
400
+ else if (s[i] === "," && depth === 0) return i;
401
+ return -1;
402
+ }
403
+ function findMatchingParen(str, startIndex) {
404
+ let depth = 1;
405
+ let i = startIndex + 1;
406
+ while (i < str.length && depth > 0) {
407
+ if (str[i] === "(") depth++;
408
+ else if (str[i] === ")") depth--;
409
+ i++;
410
+ }
411
+ return depth === 0 ? i - 1 : -1;
412
+ }
413
+
414
+ //#endregion
415
+ export { createStateParserContext, expandDimensionShorthands, expandTastyUnits, extractLocalPredefinedStates, extractPredefinedStateRefs, findTopLevelComma, getGlobalPredefinedStates, parseAdvancedState, resolvePredefinedState, setGlobalPredefinedStates };
416
+ //# sourceMappingURL=index.js.map