@tamagui/style-grammar 0.0.0-bootstrap.0 → 3.0.0-beta.643.1

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 (458) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -1
  3. package/dist/cjs/backgroundFamily.cjs +176 -0
  4. package/dist/cjs/backgroundFamily.native.cjs +195 -0
  5. package/dist/cjs/backgroundFamily.native.js +197 -0
  6. package/dist/cjs/backgroundFamily.native.js.map +1 -0
  7. package/dist/cjs/borderFamily.cjs +169 -0
  8. package/dist/cjs/borderFamily.native.cjs +247 -0
  9. package/dist/cjs/borderFamily.native.js +249 -0
  10. package/dist/cjs/borderFamily.native.js.map +1 -0
  11. package/dist/cjs/candidate.cjs +608 -0
  12. package/dist/cjs/candidate.native.cjs +821 -0
  13. package/dist/cjs/candidate.native.js +823 -0
  14. package/dist/cjs/candidate.native.js.map +1 -0
  15. package/dist/cjs/candidateTarget.cjs +50 -0
  16. package/dist/cjs/candidateTarget.native.cjs +88 -0
  17. package/dist/cjs/candidateTarget.native.js +90 -0
  18. package/dist/cjs/candidateTarget.native.js.map +1 -0
  19. package/dist/cjs/clauseCapability.cjs +130 -0
  20. package/dist/cjs/clauseCapability.native.cjs +152 -0
  21. package/dist/cjs/clauseCapability.native.js +154 -0
  22. package/dist/cjs/clauseCapability.native.js.map +1 -0
  23. package/dist/cjs/clausePrecedence.cjs +153 -0
  24. package/dist/cjs/clausePrecedence.native.cjs +204 -0
  25. package/dist/cjs/clausePrecedence.native.js +206 -0
  26. package/dist/cjs/clausePrecedence.native.js.map +1 -0
  27. package/dist/cjs/clauseSources.cjs +47 -0
  28. package/dist/cjs/clauseSources.native.cjs +49 -0
  29. package/dist/cjs/clauseSources.native.js +51 -0
  30. package/dist/cjs/clauseSources.native.js.map +1 -0
  31. package/dist/cjs/config.cjs +130 -0
  32. package/dist/cjs/config.native.cjs +185 -0
  33. package/dist/cjs/config.native.js +187 -0
  34. package/dist/cjs/config.native.js.map +1 -0
  35. package/dist/cjs/evaluateProgram.cjs +65 -0
  36. package/dist/cjs/evaluateProgram.native.cjs +70 -0
  37. package/dist/cjs/evaluateProgram.native.js +72 -0
  38. package/dist/cjs/evaluateProgram.native.js.map +1 -0
  39. package/dist/cjs/fontShorthand.cjs +207 -0
  40. package/dist/cjs/fontShorthand.native.cjs +260 -0
  41. package/dist/cjs/fontShorthand.native.js +262 -0
  42. package/dist/cjs/fontShorthand.native.js.map +1 -0
  43. package/dist/cjs/geometricShorthand.cjs +122 -0
  44. package/dist/cjs/geometricShorthand.native.cjs +128 -0
  45. package/dist/cjs/geometricShorthand.native.js +130 -0
  46. package/dist/cjs/geometricShorthand.native.js.map +1 -0
  47. package/dist/cjs/index.cjs +19 -0
  48. package/dist/cjs/index.native.cjs +21 -0
  49. package/dist/cjs/index.native.js +23 -0
  50. package/dist/cjs/index.native.js.map +1 -0
  51. package/dist/cjs/lowerProgram.cjs +205 -0
  52. package/dist/cjs/lowerProgram.native.cjs +257 -0
  53. package/dist/cjs/lowerProgram.native.js +259 -0
  54. package/dist/cjs/lowerProgram.native.js.map +1 -0
  55. package/dist/cjs/mergeFlatValues.cjs +50 -0
  56. package/dist/cjs/mergeFlatValues.native.cjs +71 -0
  57. package/dist/cjs/mergeFlatValues.native.js +73 -0
  58. package/dist/cjs/mergeFlatValues.native.js.map +1 -0
  59. package/dist/cjs/modifierRegistry.cjs +246 -0
  60. package/dist/cjs/modifierRegistry.native.cjs +426 -0
  61. package/dist/cjs/modifierRegistry.native.js +428 -0
  62. package/dist/cjs/modifierRegistry.native.js.map +1 -0
  63. package/dist/cjs/payloadShape.cjs +69 -0
  64. package/dist/cjs/payloadShape.native.cjs +71 -0
  65. package/dist/cjs/payloadShape.native.js +73 -0
  66. package/dist/cjs/payloadShape.native.js.map +1 -0
  67. package/dist/cjs/programEligibility.cjs +46 -0
  68. package/dist/cjs/programEligibility.native.cjs +48 -0
  69. package/dist/cjs/programEligibility.native.js +50 -0
  70. package/dist/cjs/programEligibility.native.js.map +1 -0
  71. package/dist/cjs/programHash.cjs +86 -0
  72. package/dist/cjs/programHash.native.cjs +106 -0
  73. package/dist/cjs/programHash.native.js +108 -0
  74. package/dist/cjs/programHash.native.js.map +1 -0
  75. package/dist/cjs/programs.cjs +128 -0
  76. package/dist/cjs/programs.native.cjs +220 -0
  77. package/dist/cjs/programs.native.js +222 -0
  78. package/dist/cjs/programs.native.js.map +1 -0
  79. package/dist/cjs/registry.cjs +629 -0
  80. package/dist/cjs/registry.native.cjs +635 -0
  81. package/dist/cjs/registry.native.js +637 -0
  82. package/dist/cjs/registry.native.js.map +1 -0
  83. package/dist/cjs/resolvePayload.cjs +296 -0
  84. package/dist/cjs/resolvePayload.native.cjs +302 -0
  85. package/dist/cjs/resolvePayload.native.js +304 -0
  86. package/dist/cjs/resolvePayload.native.js.map +1 -0
  87. package/dist/cjs/runtime.cjs +50 -0
  88. package/dist/cjs/runtime.native.cjs +52 -0
  89. package/dist/cjs/runtime.native.js +54 -0
  90. package/dist/cjs/runtime.native.js.map +1 -0
  91. package/dist/cjs/safeAreaVariables.cjs +42 -0
  92. package/dist/cjs/safeAreaVariables.native.cjs +44 -0
  93. package/dist/cjs/safeAreaVariables.native.js +46 -0
  94. package/dist/cjs/safeAreaVariables.native.js.map +1 -0
  95. package/dist/cjs/scanFlatValue.cjs +181 -0
  96. package/dist/cjs/scanFlatValue.native.cjs +183 -0
  97. package/dist/cjs/scanFlatValue.native.js +185 -0
  98. package/dist/cjs/scanFlatValue.native.js.map +1 -0
  99. package/dist/cjs/serializePayload.cjs +149 -0
  100. package/dist/cjs/serializePayload.native.cjs +187 -0
  101. package/dist/cjs/serializePayload.native.js +189 -0
  102. package/dist/cjs/serializePayload.native.js.map +1 -0
  103. package/dist/cjs/stateModifiers.cjs +43 -0
  104. package/dist/cjs/stateModifiers.native.cjs +45 -0
  105. package/dist/cjs/stateModifiers.native.js +47 -0
  106. package/dist/cjs/stateModifiers.native.js.map +1 -0
  107. package/dist/cjs/states.cjs +97 -0
  108. package/dist/cjs/states.native.cjs +131 -0
  109. package/dist/cjs/states.native.js +133 -0
  110. package/dist/cjs/states.native.js.map +1 -0
  111. package/dist/cjs/table.cjs +54 -0
  112. package/dist/cjs/table.native.cjs +135 -0
  113. package/dist/cjs/table.native.js +137 -0
  114. package/dist/cjs/table.native.js.map +1 -0
  115. package/dist/cjs/textDecorationFamily.cjs +129 -0
  116. package/dist/cjs/textDecorationFamily.native.cjs +199 -0
  117. package/dist/cjs/textDecorationFamily.native.js +201 -0
  118. package/dist/cjs/textDecorationFamily.native.js.map +1 -0
  119. package/dist/cjs/tooling.cjs +26 -0
  120. package/dist/cjs/tooling.native.cjs +28 -0
  121. package/dist/cjs/tooling.native.js +30 -0
  122. package/dist/cjs/tooling.native.js.map +1 -0
  123. package/dist/cjs/toolingAnnotations.cjs +105 -0
  124. package/dist/cjs/toolingAnnotations.native.cjs +133 -0
  125. package/dist/cjs/toolingAnnotations.native.js +135 -0
  126. package/dist/cjs/toolingAnnotations.native.js.map +1 -0
  127. package/dist/cjs/toolingDiagnostics.cjs +459 -0
  128. package/dist/cjs/toolingDiagnostics.native.cjs +788 -0
  129. package/dist/cjs/toolingDiagnostics.native.js +790 -0
  130. package/dist/cjs/toolingDiagnostics.native.js.map +1 -0
  131. package/dist/cjs/toolingRegistry.cjs +159 -0
  132. package/dist/cjs/toolingRegistry.native.cjs +164 -0
  133. package/dist/cjs/toolingRegistry.native.js +166 -0
  134. package/dist/cjs/toolingRegistry.native.js.map +1 -0
  135. package/dist/cjs/transformFamily.cjs +425 -0
  136. package/dist/cjs/transformFamily.native.cjs +517 -0
  137. package/dist/cjs/transformFamily.native.js +519 -0
  138. package/dist/cjs/transformFamily.native.js.map +1 -0
  139. package/dist/cjs/transition.cjs +459 -0
  140. package/dist/cjs/transition.native.cjs +499 -0
  141. package/dist/cjs/transition.native.js +501 -0
  142. package/dist/cjs/transition.native.js.map +1 -0
  143. package/dist/cjs/transitionAlign.cjs +115 -0
  144. package/dist/cjs/transitionAlign.native.cjs +154 -0
  145. package/dist/cjs/transitionAlign.native.js +156 -0
  146. package/dist/cjs/transitionAlign.native.js.map +1 -0
  147. package/dist/cjs/transitionLegacy.cjs +217 -0
  148. package/dist/cjs/transitionLegacy.native.cjs +260 -0
  149. package/dist/cjs/transitionLegacy.native.js +262 -0
  150. package/dist/cjs/transitionLegacy.native.js.map +1 -0
  151. package/dist/cjs/transitionNative.cjs +281 -0
  152. package/dist/cjs/transitionNative.native.cjs +285 -0
  153. package/dist/cjs/transitionNative.native.js +287 -0
  154. package/dist/cjs/transitionNative.native.js.map +1 -0
  155. package/dist/cjs/unitlessNumbers.cjs +86 -0
  156. package/dist/cjs/unitlessNumbers.native.cjs +106 -0
  157. package/dist/cjs/unitlessNumbers.native.js +108 -0
  158. package/dist/cjs/unitlessNumbers.native.js.map +1 -0
  159. package/dist/cjs/v6ThemeNames.cjs +47 -0
  160. package/dist/cjs/v6ThemeNames.native.cjs +53 -0
  161. package/dist/cjs/v6ThemeNames.native.js +55 -0
  162. package/dist/cjs/v6ThemeNames.native.js.map +1 -0
  163. package/dist/cjs/valueParser.cjs +148 -0
  164. package/dist/cjs/valueParser.native.cjs +150 -0
  165. package/dist/cjs/valueParser.native.js +152 -0
  166. package/dist/cjs/valueParser.native.js.map +1 -0
  167. package/dist/cjs/valueTypes.cjs +38 -0
  168. package/dist/cjs/valueTypes.native.cjs +40 -0
  169. package/dist/cjs/valueTypes.native.js +42 -0
  170. package/dist/cjs/valueTypes.native.js.map +1 -0
  171. package/dist/esm/backgroundFamily.mjs +150 -0
  172. package/dist/esm/backgroundFamily.mjs.map +1 -0
  173. package/dist/esm/backgroundFamily.native.js +167 -0
  174. package/dist/esm/backgroundFamily.native.js.map +1 -0
  175. package/dist/esm/borderFamily.mjs +146 -0
  176. package/dist/esm/borderFamily.mjs.map +1 -0
  177. package/dist/esm/borderFamily.native.js +222 -0
  178. package/dist/esm/borderFamily.native.js.map +1 -0
  179. package/dist/esm/candidate.mjs +581 -0
  180. package/dist/esm/candidate.mjs.map +1 -0
  181. package/dist/esm/candidate.native.js +792 -0
  182. package/dist/esm/candidate.native.js.map +1 -0
  183. package/dist/esm/candidateTarget.mjs +29 -0
  184. package/dist/esm/candidateTarget.mjs.map +1 -0
  185. package/dist/esm/candidateTarget.native.js +65 -0
  186. package/dist/esm/candidateTarget.native.js.map +1 -0
  187. package/dist/esm/clauseCapability.mjs +107 -0
  188. package/dist/esm/clauseCapability.mjs.map +1 -0
  189. package/dist/esm/clauseCapability.native.js +127 -0
  190. package/dist/esm/clauseCapability.native.js.map +1 -0
  191. package/dist/esm/clausePrecedence.mjs +121 -0
  192. package/dist/esm/clausePrecedence.mjs.map +1 -0
  193. package/dist/esm/clausePrecedence.native.js +170 -0
  194. package/dist/esm/clausePrecedence.native.js.map +1 -0
  195. package/dist/esm/clauseSources.mjs +23 -0
  196. package/dist/esm/clauseSources.mjs.map +1 -0
  197. package/dist/esm/clauseSources.native.js +23 -0
  198. package/dist/esm/clauseSources.native.js.map +1 -0
  199. package/dist/esm/config.mjs +103 -0
  200. package/dist/esm/config.mjs.map +1 -0
  201. package/dist/esm/config.native.js +156 -0
  202. package/dist/esm/config.native.js.map +1 -0
  203. package/dist/esm/evaluateProgram.mjs +45 -0
  204. package/dist/esm/evaluateProgram.mjs.map +1 -0
  205. package/dist/esm/evaluateProgram.native.js +48 -0
  206. package/dist/esm/evaluateProgram.native.js.map +1 -0
  207. package/dist/esm/fontShorthand.mjs +184 -0
  208. package/dist/esm/fontShorthand.mjs.map +1 -0
  209. package/dist/esm/fontShorthand.native.js +235 -0
  210. package/dist/esm/fontShorthand.native.js.map +1 -0
  211. package/dist/esm/geometricShorthand.mjs +102 -0
  212. package/dist/esm/geometricShorthand.mjs.map +1 -0
  213. package/dist/esm/geometricShorthand.native.js +106 -0
  214. package/dist/esm/geometricShorthand.native.js.map +1 -0
  215. package/dist/esm/index.mjs +1 -0
  216. package/dist/esm/index.native.js +1 -0
  217. package/dist/esm/lowerProgram.mjs +182 -0
  218. package/dist/esm/lowerProgram.mjs.map +1 -0
  219. package/dist/esm/lowerProgram.native.js +232 -0
  220. package/dist/esm/lowerProgram.native.js.map +1 -0
  221. package/dist/esm/mergeFlatValues.mjs +27 -0
  222. package/dist/esm/mergeFlatValues.mjs.map +1 -0
  223. package/dist/esm/mergeFlatValues.native.js +46 -0
  224. package/dist/esm/mergeFlatValues.native.js.map +1 -0
  225. package/dist/esm/modifierRegistry.mjs +219 -0
  226. package/dist/esm/modifierRegistry.mjs.map +1 -0
  227. package/dist/esm/modifierRegistry.native.js +397 -0
  228. package/dist/esm/modifierRegistry.native.js.map +1 -0
  229. package/dist/esm/payloadShape.mjs +49 -0
  230. package/dist/esm/payloadShape.mjs.map +1 -0
  231. package/dist/esm/payloadShape.native.js +49 -0
  232. package/dist/esm/payloadShape.native.js.map +1 -0
  233. package/dist/esm/programEligibility.mjs +22 -0
  234. package/dist/esm/programEligibility.mjs.map +1 -0
  235. package/dist/esm/programEligibility.native.js +22 -0
  236. package/dist/esm/programEligibility.native.js.map +1 -0
  237. package/dist/esm/programHash.mjs +62 -0
  238. package/dist/esm/programHash.mjs.map +1 -0
  239. package/dist/esm/programHash.native.js +80 -0
  240. package/dist/esm/programHash.native.js.map +1 -0
  241. package/dist/esm/programs.mjs +103 -0
  242. package/dist/esm/programs.mjs.map +1 -0
  243. package/dist/esm/programs.native.js +193 -0
  244. package/dist/esm/programs.native.js.map +1 -0
  245. package/dist/esm/registry.mjs +595 -0
  246. package/dist/esm/registry.mjs.map +1 -0
  247. package/dist/esm/registry.native.js +599 -0
  248. package/dist/esm/registry.native.js.map +1 -0
  249. package/dist/esm/resolvePayload.mjs +273 -0
  250. package/dist/esm/resolvePayload.mjs.map +1 -0
  251. package/dist/esm/resolvePayload.native.js +277 -0
  252. package/dist/esm/resolvePayload.native.js.map +1 -0
  253. package/dist/esm/runtime.mjs +63 -0
  254. package/dist/esm/runtime.native.js +63 -0
  255. package/dist/esm/safeAreaVariables.mjs +18 -0
  256. package/dist/esm/safeAreaVariables.mjs.map +1 -0
  257. package/dist/esm/safeAreaVariables.native.js +18 -0
  258. package/dist/esm/safeAreaVariables.native.js.map +1 -0
  259. package/dist/esm/scanFlatValue.mjs +160 -0
  260. package/dist/esm/scanFlatValue.mjs.map +1 -0
  261. package/dist/esm/scanFlatValue.native.js +160 -0
  262. package/dist/esm/scanFlatValue.native.js.map +1 -0
  263. package/dist/esm/serializePayload.mjs +125 -0
  264. package/dist/esm/serializePayload.mjs.map +1 -0
  265. package/dist/esm/serializePayload.native.js +161 -0
  266. package/dist/esm/serializePayload.native.js.map +1 -0
  267. package/dist/esm/stateModifiers.mjs +19 -0
  268. package/dist/esm/stateModifiers.mjs.map +1 -0
  269. package/dist/esm/stateModifiers.native.js +19 -0
  270. package/dist/esm/stateModifiers.native.js.map +1 -0
  271. package/dist/esm/states.mjs +69 -0
  272. package/dist/esm/states.mjs.map +1 -0
  273. package/dist/esm/states.native.js +101 -0
  274. package/dist/esm/states.native.js.map +1 -0
  275. package/dist/esm/table.mjs +31 -0
  276. package/dist/esm/table.mjs.map +1 -0
  277. package/dist/esm/table.native.js +110 -0
  278. package/dist/esm/table.native.js.map +1 -0
  279. package/dist/esm/textDecorationFamily.mjs +106 -0
  280. package/dist/esm/textDecorationFamily.mjs.map +1 -0
  281. package/dist/esm/textDecorationFamily.native.js +174 -0
  282. package/dist/esm/textDecorationFamily.native.js.map +1 -0
  283. package/dist/esm/tooling.mjs +15 -0
  284. package/dist/esm/tooling.native.js +15 -0
  285. package/dist/esm/toolingAnnotations.mjs +85 -0
  286. package/dist/esm/toolingAnnotations.mjs.map +1 -0
  287. package/dist/esm/toolingAnnotations.native.js +111 -0
  288. package/dist/esm/toolingAnnotations.native.js.map +1 -0
  289. package/dist/esm/toolingDiagnostics.mjs +428 -0
  290. package/dist/esm/toolingDiagnostics.mjs.map +1 -0
  291. package/dist/esm/toolingDiagnostics.native.js +755 -0
  292. package/dist/esm/toolingDiagnostics.native.js.map +1 -0
  293. package/dist/esm/toolingRegistry.mjs +135 -0
  294. package/dist/esm/toolingRegistry.mjs.map +1 -0
  295. package/dist/esm/toolingRegistry.native.js +138 -0
  296. package/dist/esm/toolingRegistry.native.js.map +1 -0
  297. package/dist/esm/transformFamily.mjs +392 -0
  298. package/dist/esm/transformFamily.mjs.map +1 -0
  299. package/dist/esm/transformFamily.native.js +482 -0
  300. package/dist/esm/transformFamily.native.js.map +1 -0
  301. package/dist/esm/transition.mjs +434 -0
  302. package/dist/esm/transition.mjs.map +1 -0
  303. package/dist/esm/transition.native.js +472 -0
  304. package/dist/esm/transition.native.js.map +1 -0
  305. package/dist/esm/transitionAlign.mjs +95 -0
  306. package/dist/esm/transitionAlign.mjs.map +1 -0
  307. package/dist/esm/transitionAlign.native.js +132 -0
  308. package/dist/esm/transitionAlign.native.js.map +1 -0
  309. package/dist/esm/transitionLegacy.mjs +197 -0
  310. package/dist/esm/transitionLegacy.mjs.map +1 -0
  311. package/dist/esm/transitionLegacy.native.js +238 -0
  312. package/dist/esm/transitionLegacy.native.js.map +1 -0
  313. package/dist/esm/transitionNative.mjs +257 -0
  314. package/dist/esm/transitionNative.mjs.map +1 -0
  315. package/dist/esm/transitionNative.native.js +259 -0
  316. package/dist/esm/transitionNative.native.js.map +1 -0
  317. package/dist/esm/unitlessNumbers.mjs +65 -0
  318. package/dist/esm/unitlessNumbers.mjs.map +1 -0
  319. package/dist/esm/unitlessNumbers.native.js +83 -0
  320. package/dist/esm/unitlessNumbers.native.js.map +1 -0
  321. package/dist/esm/v6ThemeNames.mjs +23 -0
  322. package/dist/esm/v6ThemeNames.mjs.map +1 -0
  323. package/dist/esm/v6ThemeNames.native.js +27 -0
  324. package/dist/esm/v6ThemeNames.native.js.map +1 -0
  325. package/dist/esm/valueParser.mjs +125 -0
  326. package/dist/esm/valueParser.mjs.map +1 -0
  327. package/dist/esm/valueParser.native.js +125 -0
  328. package/dist/esm/valueParser.native.js.map +1 -0
  329. package/dist/esm/valueTypes.mjs +14 -0
  330. package/dist/esm/valueTypes.mjs.map +1 -0
  331. package/dist/esm/valueTypes.native.js +14 -0
  332. package/dist/esm/valueTypes.native.js.map +1 -0
  333. package/package.json +98 -4
  334. package/src/backgroundFamily.ts +182 -0
  335. package/src/borderFamily.ts +172 -0
  336. package/src/candidate.ts +691 -0
  337. package/src/candidateTarget.ts +67 -0
  338. package/src/clauseCapability.ts +209 -0
  339. package/src/clausePrecedence.ts +198 -0
  340. package/src/clauseSources.ts +29 -0
  341. package/src/config.ts +169 -0
  342. package/src/evaluateProgram.ts +91 -0
  343. package/src/fontShorthand.ts +177 -0
  344. package/src/geometricShorthand.ts +105 -0
  345. package/src/index.ts +1 -0
  346. package/src/lowerProgram.ts +398 -0
  347. package/src/modifierRegistry.ts +340 -0
  348. package/src/payloadShape.ts +92 -0
  349. package/src/programEligibility.ts +46 -0
  350. package/src/programHash.ts +128 -0
  351. package/src/programs.ts +95 -0
  352. package/src/registry.ts +367 -0
  353. package/src/resolvePayload.ts +480 -0
  354. package/src/runtime.ts +32 -0
  355. package/src/safeAreaVariables.ts +19 -0
  356. package/src/scanFlatValue.ts +327 -0
  357. package/src/serializePayload.ts +199 -0
  358. package/src/stateModifiers.ts +36 -0
  359. package/src/states.ts +128 -0
  360. package/src/table.ts +47 -0
  361. package/src/textDecorationFamily.ts +119 -0
  362. package/src/tooling.ts +8 -0
  363. package/src/toolingAnnotations.ts +151 -0
  364. package/src/toolingDiagnostics.ts +735 -0
  365. package/src/toolingRegistry.ts +130 -0
  366. package/src/transformFamily.ts +590 -0
  367. package/src/transition.ts +553 -0
  368. package/src/transitionAlign.ts +165 -0
  369. package/src/transitionLegacy.ts +237 -0
  370. package/src/transitionNative.ts +357 -0
  371. package/src/unitlessNumbers.ts +61 -0
  372. package/src/v6ThemeNames.ts +40 -0
  373. package/src/valueParser.ts +193 -0
  374. package/src/valueTypes.ts +136 -0
  375. package/types/backgroundFamily.d.ts +17 -0
  376. package/types/backgroundFamily.d.ts.map +11 -0
  377. package/types/borderFamily.d.ts +23 -0
  378. package/types/borderFamily.d.ts.map +11 -0
  379. package/types/candidate.d.ts +52 -0
  380. package/types/candidate.d.ts.map +11 -0
  381. package/types/candidateTarget.d.ts +32 -0
  382. package/types/candidateTarget.d.ts.map +11 -0
  383. package/types/clauseCapability.d.ts +69 -0
  384. package/types/clauseCapability.d.ts.map +11 -0
  385. package/types/clausePrecedence.d.ts +30 -0
  386. package/types/clausePrecedence.d.ts.map +11 -0
  387. package/types/clauseSources.d.ts +12 -0
  388. package/types/clauseSources.d.ts.map +11 -0
  389. package/types/config.d.ts +44 -0
  390. package/types/config.d.ts.map +11 -0
  391. package/types/evaluateProgram.d.ts +27 -0
  392. package/types/evaluateProgram.d.ts.map +11 -0
  393. package/types/fontShorthand.d.ts +25 -0
  394. package/types/fontShorthand.d.ts.map +11 -0
  395. package/types/geometricShorthand.d.ts +21 -0
  396. package/types/geometricShorthand.d.ts.map +11 -0
  397. package/types/index.d.ts +3 -0
  398. package/types/index.d.ts.map +11 -0
  399. package/types/lowerProgram.d.ts +73 -0
  400. package/types/lowerProgram.d.ts.map +11 -0
  401. package/types/mergeFlatValues.d.ts +14 -0
  402. package/types/mergeFlatValues.d.ts.map +11 -0
  403. package/types/modifierRegistry.d.ts +70 -0
  404. package/types/modifierRegistry.d.ts.map +11 -0
  405. package/types/payloadShape.d.ts +15 -0
  406. package/types/payloadShape.d.ts.map +11 -0
  407. package/types/programEligibility.d.ts +23 -0
  408. package/types/programEligibility.d.ts.map +11 -0
  409. package/types/programHash.d.ts +20 -0
  410. package/types/programHash.d.ts.map +11 -0
  411. package/types/programs.d.ts +18 -0
  412. package/types/programs.d.ts.map +11 -0
  413. package/types/registry.d.ts +24 -0
  414. package/types/registry.d.ts.map +11 -0
  415. package/types/resolvePayload.d.ts +75 -0
  416. package/types/resolvePayload.d.ts.map +11 -0
  417. package/types/runtime.d.ts +34 -0
  418. package/types/runtime.d.ts.map +11 -0
  419. package/types/safeAreaVariables.d.ts +5 -0
  420. package/types/safeAreaVariables.d.ts.map +11 -0
  421. package/types/scanFlatValue.d.ts +29 -0
  422. package/types/scanFlatValue.d.ts.map +11 -0
  423. package/types/serializePayload.d.ts +13 -0
  424. package/types/serializePayload.d.ts.map +11 -0
  425. package/types/stateModifiers.d.ts +14 -0
  426. package/types/stateModifiers.d.ts.map +11 -0
  427. package/types/states.d.ts +22 -0
  428. package/types/states.d.ts.map +11 -0
  429. package/types/table.d.ts +4 -0
  430. package/types/table.d.ts.map +11 -0
  431. package/types/textDecorationFamily.d.ts +23 -0
  432. package/types/textDecorationFamily.d.ts.map +11 -0
  433. package/types/tooling.d.ts +10 -0
  434. package/types/tooling.d.ts.map +11 -0
  435. package/types/toolingAnnotations.d.ts +29 -0
  436. package/types/toolingAnnotations.d.ts.map +11 -0
  437. package/types/toolingDiagnostics.d.ts +114 -0
  438. package/types/toolingDiagnostics.d.ts.map +11 -0
  439. package/types/toolingRegistry.d.ts +10 -0
  440. package/types/toolingRegistry.d.ts.map +11 -0
  441. package/types/transformFamily.d.ts +83 -0
  442. package/types/transformFamily.d.ts.map +11 -0
  443. package/types/transition.d.ts +65 -0
  444. package/types/transition.d.ts.map +11 -0
  445. package/types/transitionAlign.d.ts +15 -0
  446. package/types/transitionAlign.d.ts.map +11 -0
  447. package/types/transitionLegacy.d.ts +9 -0
  448. package/types/transitionLegacy.d.ts.map +11 -0
  449. package/types/transitionNative.d.ts +41 -0
  450. package/types/transitionNative.d.ts.map +11 -0
  451. package/types/unitlessNumbers.d.ts +3 -0
  452. package/types/unitlessNumbers.d.ts.map +11 -0
  453. package/types/v6ThemeNames.d.ts +7 -0
  454. package/types/v6ThemeNames.d.ts.map +11 -0
  455. package/types/valueParser.d.ts +36 -0
  456. package/types/valueParser.d.ts.map +11 -0
  457. package/types/valueTypes.d.ts +66 -0
  458. package/types/valueTypes.d.ts.map +11 -0
@@ -0,0 +1,193 @@
1
+ // The universal flat value parser.
2
+ //
3
+ // value := base? clause*
4
+ // clause := modifier (":" modifier)* ":" payload
5
+ //
6
+ // See plans/dom-tailwind-flat-values.md — "The universal value grammar". The
7
+ // parser only splits: `base` and every `payload` come back as trimmed raw CSS
8
+ // component-value sequences with no interpretation and no token resolution.
9
+ //
10
+ // The split itself is `scanFlatValue`, the one lexer every implementation of
11
+ // this grammar drives; this file is what that split MEANS, which is the part
12
+ // the registry decides. Read `scanFlatValue.ts` for why a top-level colon,
13
+ // brace or semicolon is structural and everything inside a string or a paren is
14
+ // not.
15
+
16
+ import {
17
+ scanFlatValue,
18
+ type FlatScanErrorCode,
19
+ type FlatValueVisitor,
20
+ } from './scanFlatValue'
21
+ import type {
22
+ ModifierRegistryView,
23
+ ParsedClause,
24
+ ValueParseError,
25
+ ValueParseErrorCode,
26
+ ValueParseResult,
27
+ } from './valueTypes'
28
+
29
+ const CHAR_COLON = 58
30
+
31
+ const noClauses: readonly ParsedClause[] = Object.freeze([])
32
+
33
+ export interface ValueSourceSpan {
34
+ kind: 'base' | 'payload' | 'modifier' | 'word'
35
+ start: number
36
+ end: number
37
+ }
38
+
39
+ export interface ValueParseWithSourceSpans {
40
+ result: ValueParseResult
41
+ spans: readonly ValueSourceSpan[]
42
+ }
43
+
44
+ /**
45
+ * NOT A SAFETY CHECK. A successful parse says the value is well-formed FLAT
46
+ * VALUE SYNTAX. It does not say the value is safe to interpolate into CSS.
47
+ *
48
+ * `scanFlatValue` tracks the same constructs CSS's tokenizer does (comments,
49
+ * strings that a newline ends, `url()`, paren nesting), so a value whose
50
+ * delimiters do not actually close is an error rather than silently trusted.
51
+ * That covers the constructs a value can leave OPEN; it is not an injection
52
+ * guard. `emitValue` and `getStyleObject` used to call a
53
+ * `carriesTopLevelInjection` guard independently; it was removed by owner
54
+ * decision, on the grounds that a style value is authored rather than user
55
+ * input, and the web lowering emits payloads verbatim by contract.
56
+ *
57
+ * So the rule lives upstream of this file: never put a user-controlled string
58
+ * in a style value. A payload carrying `;}` closes its own rule and everything
59
+ * after it is a selector block the author never wrote. Do not gate emission on
60
+ * `parseValue(...).ok` either; it answers a syntax question, not a safety one.
61
+ */
62
+ export function parseValue(
63
+ input: string,
64
+ registry: ModifierRegistryView
65
+ ): ValueParseResult {
66
+ return parseValueInternal(input, registry)
67
+ }
68
+
69
+ /**
70
+ * Parses through the runtime scanner while also retaining source boundaries for
71
+ * editor tooling. The ordinary runtime path does not allocate these spans.
72
+ */
73
+ export function parseValueWithSourceSpans(
74
+ input: string,
75
+ registry: ModifierRegistryView
76
+ ): ValueParseWithSourceSpans {
77
+ const spans: ValueSourceSpan[] = []
78
+ return {
79
+ result: parseValueInternal(input, registry, spans),
80
+ spans,
81
+ }
82
+ }
83
+
84
+ function scanErrorMessage(code: FlatScanErrorCode, input: string, index: number): string {
85
+ if (code === 'invalid-character') {
86
+ return `"${input[index]}" cannot appear in a value: it would end the declaration or rule`
87
+ }
88
+ if (code === 'unterminated-string') {
89
+ return `unterminated ${input[index]} string`
90
+ }
91
+ if (code === 'unterminated-comment') {
92
+ return 'unterminated "/*" comment: it would swallow the rules after this one'
93
+ }
94
+ if (code === 'stray-comment-close') {
95
+ return 'stray "*/": it would close a comment opened somewhere else'
96
+ }
97
+ return 'unterminated "(" in value'
98
+ }
99
+
100
+ function parseValueInternal(
101
+ input: string,
102
+ registry: ModifierRegistryView,
103
+ sourceSpans?: ValueSourceSpan[]
104
+ ): ValueParseResult {
105
+ let errors: ValueParseError[] | null = null
106
+ let base: string | null = null
107
+ let clauses: ParsedClause[] | null = null
108
+ // modifiers of the clause whose payload is currently being collected
109
+ let pending: string[] | null = null
110
+ // where the base, or the current payload, starts before trimming, which is
111
+ // what an empty payload has to point its diagnostic at
112
+ let segmentStart = 0
113
+
114
+ const addError = (
115
+ code: ValueParseErrorCode,
116
+ index: number,
117
+ message: string,
118
+ modifier?: string
119
+ ): void => {
120
+ ;(errors ||= []).push(
121
+ modifier === undefined
122
+ ? { code, index, message }
123
+ : { code, index, message, modifier }
124
+ )
125
+ }
126
+
127
+ const visitor: FlatValueVisitor = {
128
+ segment(start, end, isBase) {
129
+ sourceSpans?.push({ kind: isBase ? 'base' : 'payload', start, end })
130
+ if (isBase) {
131
+ base = start < end ? input.slice(start, end) : null
132
+ return
133
+ }
134
+ if (start >= end) {
135
+ addError(
136
+ 'empty-payload',
137
+ segmentStart,
138
+ `the "${pending!.join(':')}:" clause has no value`
139
+ )
140
+ return
141
+ }
142
+ ;(clauses ||= []).push({ modifiers: pending!, payload: input.slice(start, end) })
143
+ },
144
+
145
+ // a clause word ended: everything before its last top-level colon is the
146
+ // modifier chain, everything after it begins the payload
147
+ chain(chainStart, chainEnd) {
148
+ const modifiers: string[] = []
149
+ let nameStart = chainStart
150
+ for (let index = chainStart; index <= chainEnd; index++) {
151
+ if (index !== chainEnd && input.charCodeAt(index) !== CHAR_COLON) continue
152
+ if (index === nameStart) {
153
+ addError('empty-modifier', index, 'a modifier chain has an empty segment')
154
+ } else {
155
+ const name = input.slice(nameStart, index)
156
+ sourceSpans?.push({ kind: 'modifier', start: nameStart, end: index })
157
+ if (registry.get(name) === undefined) {
158
+ addError(
159
+ 'unregistered-modifier',
160
+ nameStart,
161
+ `"${name}" is not a registered modifier`,
162
+ name
163
+ )
164
+ }
165
+ modifiers.push(name)
166
+ }
167
+ nameStart = index + 1
168
+ }
169
+ pending = modifiers
170
+ segmentStart = chainEnd + 1
171
+ return true
172
+ },
173
+
174
+ error(code, index) {
175
+ addError(code, index, scanErrorMessage(code, input, index))
176
+ },
177
+ }
178
+
179
+ if (sourceSpans) {
180
+ // only the trailing bare word is a completion position the spans have no
181
+ // other name for: every earlier word is inside a base or a payload span
182
+ visitor.word = (start, end, isChain) => {
183
+ if (!isChain && end === input.length) {
184
+ sourceSpans.push({ kind: 'word', start, end })
185
+ }
186
+ }
187
+ }
188
+
189
+ scanFlatValue(input, visitor)
190
+
191
+ if (errors !== null) return { ok: false, errors }
192
+ return { ok: true, value: { base, clauses: clauses ?? noClauses } }
193
+ }
@@ -0,0 +1,136 @@
1
+ // The shared IR for the universal flat value grammar.
2
+ //
3
+ // This file is the contract between the value parser, the per-longhand program
4
+ // merge engine, the compiler, and every frontend (props, Tailwind classes,
5
+ // styled skins). See plans/dom-tailwind-flat-values.md on main — "The universal
6
+ // value grammar" and "Programs and merging" — for the full design. The rules
7
+ // that matter are restated here so this file can be read standalone.
8
+ //
9
+ // Grammar:
10
+ //
11
+ // value := base? clause*
12
+ // clause := modifier (":" modifier)* ":" payload
13
+ //
14
+ // - `base` and each `payload` are plain CSS component-value sequences. They are
15
+ // NOT interpreted here; the parser only splits, it never resolves.
16
+ // - Clause detection is purely syntactic: a top-level colon (outside strings
17
+ // and outside any paren nesting, url() included) always starts a clause. A
18
+ // top-level colon is never valid inside a CSS component value, so this is
19
+ // unambiguous with zero configuration.
20
+ // - The identifier chain before the colon must be entirely registered
21
+ // modifiers. An unregistered modifier is a hard parse error (`hver:` never
22
+ // silently becomes part of a value).
23
+ // - An empty payload is a parse error. A clause with no preceding base is fine
24
+ // (`bg="hover:red"`).
25
+ //
26
+ // Programs:
27
+ //
28
+ // - Every authored prop expands (via shorthand + family tables) to one or more
29
+ // CSS longhands. Each longhand accumulates one program in authored order.
30
+ // Contributions merge by base or normalized condition-set slot, so a later
31
+ // clause replaces only that slot and unrelated earlier clauses persist.
32
+
33
+ export type ModifierKind =
34
+ | 'state'
35
+ | 'theme'
36
+ | 'media'
37
+ | 'platform'
38
+ | 'group'
39
+ /** container queries: `@sm:` nearest container, `@sm/card:` named */
40
+ | 'container'
41
+
42
+ /** Maximum distinct non-platform conditions one emitted clause can encode. */
43
+ export const grammarMaxNonPlatformDepth = 5
44
+
45
+ /**
46
+ * What the parser needs to know about registered modifiers. Implementations
47
+ * project the user config (media keys, root themes, platform names) plus the
48
+ * built-in state vocabulary into this view. Parameterized modifiers
49
+ * (`group-<name>-<state>`) are the implementation's concern — `get` receives
50
+ * the full authored spelling.
51
+ */
52
+ export interface ModifierRegistryView {
53
+ get(name: string): ModifierKind | undefined
54
+ /**
55
+ * Config-derived modifier trie lookup for authoring one canonical chain.
56
+ * Implementations that only parse values may omit it; tooling refuses to
57
+ * invent a completion vocabulary when it is absent.
58
+ */
59
+ next?(modifiers: readonly string[]): readonly string[]
60
+ }
61
+
62
+ /** one `modifiers ":" payload` clause, modifiers in authored order */
63
+ export interface ParsedClause {
64
+ modifiers: readonly string[]
65
+ /** trimmed raw CSS component-value sequence; never empty */
66
+ payload: string
67
+ }
68
+
69
+ export interface ParsedValue {
70
+ /** trimmed unconditional leading value, or null when the string starts with a clause */
71
+ base: string | null
72
+ clauses: readonly ParsedClause[]
73
+ }
74
+
75
+ export type ValueParseErrorCode =
76
+ | 'unregistered-modifier'
77
+ | 'empty-payload'
78
+ | 'empty-modifier'
79
+ | 'unterminated-string'
80
+ | 'unterminated-function'
81
+ /**
82
+ * an opened comment that never closes. `getAllRules()` joins rules into one
83
+ * blob for SSR, so an open comment blanks the rules after it until some later
84
+ * close delimiter turns them back on
85
+ */
86
+ | 'unterminated-comment'
87
+ /** a close delimiter with nothing open, which closes another rule's comment */
88
+ | 'stray-comment-close'
89
+ /**
90
+ * a top-level `{`, `}`, or `;` — never valid in a CSS component value, and
91
+ * rejecting them here is what makes rule/selector injection through a
92
+ * payload structurally impossible in the web lowering
93
+ */
94
+ | 'invalid-character'
95
+
96
+ export interface ValueParseError {
97
+ code: ValueParseErrorCode
98
+ /** character offset into the source string where the error was detected */
99
+ index: number
100
+ message: string
101
+ /** the offending modifier spelling, for unregistered-modifier */
102
+ modifier?: string
103
+ }
104
+
105
+ export type ValueParseResult =
106
+ | { ok: true; value: ParsedValue }
107
+ | { ok: false; errors: readonly ValueParseError[] }
108
+
109
+ /**
110
+ * CSS-wide keywords and universal values that resolve as literal CSS even when
111
+ * ident resolution is config-first. A token may never take one of these names;
112
+ * config creation must reject it. Shared by the parser's ident resolution and
113
+ * config-time validation.
114
+ */
115
+ export const reservedCssIdents: ReadonlySet<string> = new Set([
116
+ 'inherit',
117
+ 'initial',
118
+ 'unset',
119
+ 'revert',
120
+ 'none',
121
+ 'auto',
122
+ 'transparent',
123
+ 'currentColor',
124
+ ])
125
+
126
+ /**
127
+ * One longhand's merged program: which CSS longhand, the parsed value that owns
128
+ * it, and which authored prop contributed it (for diagnostics and devtools).
129
+ */
130
+ export interface LonghandProgram {
131
+ /** camelCase longhand matching React Native / react style keys */
132
+ property: string
133
+ value: ParsedValue
134
+ /** the authored prop name that won this longhand */
135
+ sourceProp: string
136
+ }
@@ -0,0 +1,17 @@
1
+ import type { ParsedValue } from "./valueTypes";
2
+ export declare const namedCssColors: ReadonlySet<string>;
3
+ export declare function splitTopLevelComponents(value: string): string[];
4
+ export declare function classifyComponent(component: string, colorTokens: ReadonlySet<string>): "color" | "image" | null;
5
+ export declare function splitBackgroundValue(value: ParsedValue, colorTokens: ReadonlySet<string>): {
6
+ entries: Array<{
7
+ property: "backgroundColor" | "backgroundImage";
8
+ value: ParsedValue;
9
+ }>;
10
+ errors: Array<{
11
+ code: "unsupported-bg-component";
12
+ component: string;
13
+ where: "base" | number;
14
+ }>;
15
+ };
16
+
17
+ //# sourceMappingURL=backgroundFamily.d.ts.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "mappings": "AAAA,cAA4B,mBAAmB;AAE/C,OAAO,cAAM,gBAAgB;AAmB7B,OAAO,iBAAS,wBAAwB;AAiDxC,OAAO,iBAAS,kBACd,mBACA,aAAa,sBACZ,UAAU;AAyBb,OAAO,iBAAS,qBACd,OAAO,aACP,aAAa,sBACZ;CACD,SAAS,MAAM;EACb,UAAU,oBAAoB;EAC9B,OAAO;;CAET,QAAQ,MAAM;EACZ,MAAM;EACN;EACA,OAAO",
3
+ "names": [],
4
+ "sources": [
5
+ "src/backgroundFamily.ts"
6
+ ],
7
+ "version": 3,
8
+ "sourcesContent": [
9
+ "import type { ParsedClause, ParsedValue } from './valueTypes'\n\nexport const namedCssColors: ReadonlySet<string> = new Set(\n 'aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen darkslateblue darkslategray darkslategrey darkturquoise darkviolet deeppink deepskyblue dimgray dimgrey dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray green greenyellow grey honeydew hotpink indianred indigo ivory khaki lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen lightskyblue lightslategray lightslategrey lightsteelblue lightyellow lime limegreen linen magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum powderblue purple rebeccapurple red rosybrown royalblue saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue slateblue slategray slategrey snow springgreen steelblue tan teal thistle tomato turquoise violet wheat white whitesmoke yellow yellowgreen'.split(\n ' '\n )\n)\n\nconst colorFunctions = new Set([\n 'rgb',\n 'rgba',\n 'hsl',\n 'hsla',\n 'hwb',\n 'lab',\n 'lch',\n 'oklab',\n 'oklch',\n 'color',\n])\n\nexport function splitTopLevelComponents(value: string): string[] {\n const components: string[] = []\n let current = ''\n let depth = 0\n let quote = ''\n let escaped = false\n\n for (let index = 0; index < value.length; index++) {\n const char = value[index]\n if (escaped) {\n current += char\n escaped = false\n continue\n }\n if (char === '\\\\') {\n current += char\n escaped = true\n continue\n }\n if (quote) {\n current += char\n if (char === quote) quote = ''\n continue\n }\n if (char === '\"' || char === \"'\") {\n current += char\n quote = char\n continue\n }\n if (char === '(') depth++\n if (char === ')') depth--\n\n const code = value.charCodeAt(index)\n const whitespace =\n code === 9 || code === 10 || code === 12 || code === 13 || code === 32\n if (depth === 0 && whitespace) {\n if (current) {\n components.push(current)\n current = ''\n }\n } else {\n current += char\n }\n }\n\n if (current) components.push(current)\n return components\n}\n\nexport function classifyComponent(\n component: string,\n colorTokens: ReadonlySet<string>\n): 'color' | 'image' | null {\n const functionMatch = /^([a-z][a-z0-9-]*)\\([\\s\\S]*\\)$/i.exec(component)\n if (functionMatch) {\n const name = functionMatch[1].toLowerCase()\n if (name === 'url' || name === 'image-set' || name.endsWith('-gradient')) {\n return 'image'\n }\n if (colorFunctions.has(name)) return 'color'\n }\n\n if (/^#[\\da-f]{3}(?:[\\da-f]{1}|[\\da-f]{3}(?:[\\da-f]{2})?)?$/i.test(component)) {\n return 'color'\n }\n\n const tokenName = component.replace(/\\/\\d+$/, '')\n if (colorTokens.has(tokenName)) return 'color'\n\n const lower = component.toLowerCase()\n if (lower === 'transparent' || lower === 'currentcolor' || namedCssColors.has(lower)) {\n return 'color'\n }\n\n return null\n}\n\nexport function splitBackgroundValue(\n value: ParsedValue,\n colorTokens: ReadonlySet<string>\n): {\n entries: Array<{\n property: 'backgroundColor' | 'backgroundImage'\n value: ParsedValue\n }>\n errors: Array<{\n code: 'unsupported-bg-component'\n component: string\n where: 'base' | number\n }>\n} {\n const colorProgram: { base: string | null; clauses: ParsedClause[] } = {\n base: null,\n clauses: [],\n }\n const imageProgram: { base: string | null; clauses: ParsedClause[] } = {\n base: null,\n clauses: [],\n }\n const errors: Array<{\n code: 'unsupported-bg-component'\n component: string\n where: 'base' | number\n }> = []\n let hasColor = false\n let hasImage = false\n\n for (let clauseIndex = -1; clauseIndex < value.clauses.length; clauseIndex++) {\n const isBase = clauseIndex === -1\n const payload = isBase ? value.base : value.clauses[clauseIndex].payload\n if (payload === null) continue\n\n let colorComponent: string | null = null\n let imageComponent: string | null = null\n const where = isBase ? 'base' : clauseIndex\n\n for (const component of splitTopLevelComponents(payload)) {\n const kind = classifyComponent(component, colorTokens)\n if (kind === 'image' && imageComponent === null) {\n imageComponent = component\n } else if (kind === 'color' && colorComponent === null) {\n colorComponent = component\n } else {\n errors.push({ code: 'unsupported-bg-component', component, where })\n }\n }\n\n if (colorComponent !== null) {\n hasColor = true\n if (isBase) {\n colorProgram.base = colorComponent\n } else {\n colorProgram.clauses.push({\n modifiers: value.clauses[clauseIndex].modifiers,\n payload: colorComponent,\n })\n }\n }\n\n if (imageComponent !== null) {\n hasImage = true\n if (isBase) {\n imageProgram.base = imageComponent\n } else {\n imageProgram.clauses.push({\n modifiers: value.clauses[clauseIndex].modifiers,\n payload: imageComponent,\n })\n }\n }\n }\n\n const entries: Array<{\n property: 'backgroundColor' | 'backgroundImage'\n value: ParsedValue\n }> = []\n if (hasColor) entries.push({ property: 'backgroundColor', value: colorProgram })\n if (hasImage) entries.push({ property: 'backgroundImage', value: imageProgram })\n\n return { entries, errors }\n}\n"
10
+ ]
11
+ }
@@ -0,0 +1,23 @@
1
+ import type { ParsedValue } from "./valueTypes";
2
+ interface BorderFamilyTargets {
3
+ width: readonly string[];
4
+ style: readonly string[];
5
+ color: readonly string[];
6
+ }
7
+ /** authored prop -> the true longhands each component kind lands on */
8
+ export declare const borderFamilyTargets: Readonly<Record<string, BorderFamilyTargets>>;
9
+ export interface BorderFamilyError {
10
+ code: "unsupported-border-component";
11
+ component: string;
12
+ where: "base" | number;
13
+ }
14
+ export declare function splitBorderValue(property: string, value: ParsedValue, colorTokens: ReadonlySet<string>): {
15
+ entries: Array<{
16
+ property: string;
17
+ value: ParsedValue;
18
+ }>;
19
+ errors: BorderFamilyError[];
20
+ };
21
+ export {};
22
+
23
+ //# sourceMappingURL=borderFamily.d.ts.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "mappings": "AASA,cAA4B,mBAAmB;UAErC,oBAAoB;CAC5B;CACA;CACA;;;AAMF,OAAO,cAAM,qBAAqB,SAAS,eAAe;AAuE1D,iBAAiB,kBAAkB;CACjC,MAAM;CACN;CACA,OAAO;;AAST,OAAO,iBAAS,iBACd,kBACA,OAAO,aACP,aAAa,sBACZ;CACD,SAAS,MAAM;EAAE;EAAkB,OAAO;;CAC1C,QAAQ",
3
+ "names": [],
4
+ "sources": [
5
+ "src/borderFamily.ts"
6
+ ],
7
+ "version": 3,
8
+ "sourcesContent": [
9
+ "// The border family: value-dependent splitting of the resetting CSS border\n// shorthands into per-longhand programs, the background family's model applied\n// to width/style/color. A program must never sit on a resetting shorthand —\n// the order-free cross-program encoding depends on every program owning one\n// true longhand — so `border=\"2px solid red hover:blue\"` becomes width, style,\n// and color programs per side, and a later `borderColor` restates exactly the\n// color longhands.\n\nimport { classifyComponent, splitTopLevelComponents } from './backgroundFamily'\nimport type { ParsedClause, ParsedValue } from './valueTypes'\n\ninterface BorderFamilyTargets {\n width: readonly string[]\n style: readonly string[]\n color: readonly string[]\n}\n\nconst sides = ['Top', 'Right', 'Bottom', 'Left'] as const\n\n/** authored prop -> the true longhands each component kind lands on */\nexport const borderFamilyTargets: Readonly<Record<string, BorderFamilyTargets>> = {\n border: {\n width: sides.map((side) => `border${side}Width`),\n style: sides.map((side) => `border${side}Style`),\n color: sides.map((side) => `border${side}Color`),\n },\n ...Object.fromEntries(\n sides.map((side) => [\n `border${side}`,\n {\n width: [`border${side}Width`],\n style: [`border${side}Style`],\n color: [`border${side}Color`],\n },\n ])\n ),\n outline: {\n width: ['outlineWidth'],\n style: ['outlineStyle'],\n color: ['outlineColor'],\n },\n // logical shorthands split into CSS logical longhands. web lowers them\n // verbatim; RN has no logical block/inline border properties, so native\n // evaluation diagnoses and drops these longhands (no silent physical\n // approximation — the mapping depends on writing mode)\n borderBlock: {\n width: ['borderBlockStartWidth', 'borderBlockEndWidth'],\n style: ['borderBlockStartStyle', 'borderBlockEndStyle'],\n color: ['borderBlockStartColor', 'borderBlockEndColor'],\n },\n borderInline: {\n width: ['borderInlineStartWidth', 'borderInlineEndWidth'],\n style: ['borderInlineStartStyle', 'borderInlineEndStyle'],\n color: ['borderInlineStartColor', 'borderInlineEndColor'],\n },\n}\n\nconst lineStyles = new Set([\n 'none',\n 'hidden',\n 'dotted',\n 'dashed',\n 'solid',\n 'double',\n 'groove',\n 'ridge',\n 'inset',\n 'outset',\n])\n\nconst widthKeywords = new Set(['thin', 'medium', 'thick'])\n\n// a length: bare number (RN spelling), number+unit, or a width keyword.\n// calc() and var() also measure as widths when nothing else claims them\nconst lengthPattern = /^-?(\\d+\\.?\\d*|\\.\\d+)([a-z%]+)?$/i\n\nfunction classifyBorderComponent(\n component: string,\n property: string,\n colorTokens: ReadonlySet<string>\n): 'width' | 'style' | 'color' | null {\n const lower = component.toLowerCase()\n if (lineStyles.has(lower)) return 'style'\n // outline-style additionally allows auto\n if (lower === 'auto' && property === 'outline') return 'style'\n if (widthKeywords.has(lower) || lengthPattern.test(component)) return 'width'\n if (classifyComponent(component, colorTokens) === 'color') return 'color'\n if (/^(calc|var|min|max|clamp)\\(/i.test(component)) return 'width'\n return null\n}\n\nexport interface BorderFamilyError {\n code: 'unsupported-border-component'\n component: string\n where: 'base' | number\n}\n\ninterface MutableProgram {\n base: string | null\n clauses: ParsedClause[]\n present: boolean\n}\n\nexport function splitBorderValue(\n property: string,\n value: ParsedValue,\n colorTokens: ReadonlySet<string>\n): {\n entries: Array<{ property: string; value: ParsedValue }>\n errors: BorderFamilyError[]\n} {\n const targets = borderFamilyTargets[property]\n const errors: BorderFamilyError[] = []\n const kinds = ['width', 'style', 'color'] as const\n const programs: Record<(typeof kinds)[number], MutableProgram> = {\n width: { base: null, clauses: [], present: false },\n style: { base: null, clauses: [], present: false },\n color: { base: null, clauses: [], present: false },\n }\n\n for (let clauseIndex = -1; clauseIndex < value.clauses.length; clauseIndex++) {\n const isBase = clauseIndex === -1\n const payload = isBase ? value.base : value.clauses[clauseIndex].payload\n if (payload === null) continue\n const where = isBase ? ('base' as const) : clauseIndex\n\n const found: Partial<Record<(typeof kinds)[number], string>> = {}\n for (const component of splitTopLevelComponents(payload)) {\n const kind = classifyBorderComponent(component, property, colorTokens)\n if (kind === null || found[kind] !== undefined) {\n errors.push({ code: 'unsupported-border-component', component, where })\n continue\n }\n found[kind] = component\n }\n\n // Carry the shorthand's effective zero width explicitly. Web receives an\n // equivalent reset, and native does not have to rely on style `none` alone\n // to hide an edge whose width was supplied by another contribution.\n if (found.style === 'none' && found.width === undefined) {\n found.width = '0'\n }\n\n for (const kind of kinds) {\n const component = found[kind]\n if (component === undefined) continue\n const program = programs[kind]\n program.present = true\n if (isBase) {\n program.base = component\n } else {\n program.clauses.push({\n modifiers: value.clauses[clauseIndex].modifiers,\n payload: component,\n })\n }\n }\n }\n\n const entries: Array<{ property: string; value: ParsedValue }> = []\n for (const kind of kinds) {\n const program = programs[kind]\n if (!program.present) continue\n const shared: ParsedValue = { base: program.base, clauses: program.clauses }\n for (const longhand of targets[kind]) {\n // programs are immutable, so every side may alias the same value\n entries.push({ property: longhand, value: shared })\n }\n }\n\n return { entries, errors }\n}\n"
10
+ ]
11
+ }
@@ -0,0 +1,52 @@
1
+ import { type GrammarEntry, type TokenCategory } from "./registry";
2
+ type Names = readonly string[] | ReadonlySet<string> | Readonly<Record<string, unknown>>;
3
+ export interface GrammarConfigView {
4
+ shorthands?: Readonly<Record<string, string>>;
5
+ mediaNames?: Names;
6
+ themeNames?: Names;
7
+ platformNames?: Names;
8
+ tokenNames?: Partial<Record<TokenCategory, Names>>;
9
+ /**
10
+ * the media keys that measure a size, so `@key:` is a meaningful container
11
+ * query. derived by createGrammarConfigView when the media input carries
12
+ * query information; absent means UNKNOWN, and the modifier registry then
13
+ * refuses container claims with a diagnostic rather than over-claiming
14
+ */
15
+ containerSizeNames?: readonly string[];
16
+ }
17
+ export interface ParsedCandidate {
18
+ candidate: string;
19
+ base: string;
20
+ modifiers: readonly string[];
21
+ negative: boolean;
22
+ kind: "utility" | "dynamic";
23
+ valueKind: "token" | "arbitrary" | "enum" | "convenience";
24
+ properties?: Readonly<Record<string, string | number>>;
25
+ entry?: GrammarEntry;
26
+ prefix?: string;
27
+ rawValue?: string;
28
+ arbitrary?: boolean;
29
+ convenience?: string;
30
+ }
31
+ export type CandidateClassification = {
32
+ kind: "tamagui";
33
+ parsed: ParsedCandidate;
34
+ } | {
35
+ kind: "passthrough";
36
+ reason: string;
37
+ };
38
+ export declare function hasTokenName(config: GrammarConfigView, category: TokenCategory, name: string): boolean;
39
+ export declare function parseCandidate(candidate: string, config: GrammarConfigView): ParsedCandidate | null;
40
+ export declare function classifyCandidate(candidate: string, config: GrammarConfigView): CandidateClassification;
41
+ export interface FormatCandidateInput {
42
+ prop: string;
43
+ value: string;
44
+ valueKind: ParsedCandidate["valueKind"];
45
+ modifiers?: readonly string[];
46
+ }
47
+ export declare function formatCandidate({ prop, value, valueKind, modifiers }: FormatCandidateInput, config?: GrammarConfigView): string | null;
48
+ export declare function encodeArbitrary(value: string): string;
49
+ export declare function decodeArbitrary(value: string): string;
50
+ export {};
51
+
52
+ //# sourceMappingURL=candidate.d.ts.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "mappings": "AAAA,cAUO,mBACA,qBACA;KAMF,4BAA4B,sBAAsB,SAAS;AAEhE,iBAAiB,kBAAkB;CACjC,aAAa,SAAS;CACtB,aAAa;CACb,aAAa;CACb,gBAAgB;CAChB,aAAa,QAAQ,OAAO,eAAe;;;;;;;CAO3C;;AAGF,iBAAiB,gBAAgB;CAC/B;CACA;CACA;CACA;CACA,MAAM,YAAY;CAClB,WAAW,UAAU,cAAc,SAAS;CAC5C,aAAa,SAAS;CACtB,QAAQ;CACR;CACA;CACA;CACA;;AAGF,YAAY,0BACR;CAAE,MAAM;CAAW,QAAQ;IAC3B;CAAE,MAAM;CAAe;;AA0H3B,OAAO,iBAAS,aACd,QAAQ,mBACR,UAAU,eACV;AAqPF,OAAO,iBAAS,eACd,mBACA,QAAQ,oBACP;AAmFH,OAAO,iBAAS,kBACd,mBACA,QAAQ,oBACP;AAOH,iBAAiB,qBAAqB;CACpC;CACA;CACA,WAAW,gBAAgB;CAC3B;;AAuBF,OAAO,iBAAS,gBACd,EAAE,MAAM,OAAO,WAAW,aAAkB,sBAC5C,SAAS;AAsHX,OAAO,iBAAS,gBAAgB;AAchC,OAAO,iBAAS,gBAAgB",
3
+ "names": [],
4
+ "sources": [
5
+ "src/candidate.ts"
6
+ ],
7
+ "version": 3,
8
+ "sourcesContent": [
9
+ "import {\n grammarEntries,\n fontWeightNames,\n modifierAliases,\n prefixToEntries,\n radiusCornerProps,\n standaloneValueProps,\n textAlignKeywords,\n wholeClassConveniences,\n wholeClassUtilities,\n type GrammarEntry,\n type TokenCategory,\n} from './registry'\nimport { createModifierRegistry } from './modifierRegistry'\nimport { splitColorOpacitySuffix } from './resolvePayload'\nimport { getSafeAreaEdge } from './safeAreaVariables'\nimport type { ModifierKind, ModifierRegistryView } from './valueTypes'\n\ntype Names = readonly string[] | ReadonlySet<string> | Readonly<Record<string, unknown>>\n\nexport interface GrammarConfigView {\n shorthands?: Readonly<Record<string, string>>\n mediaNames?: Names\n themeNames?: Names\n platformNames?: Names\n tokenNames?: Partial<Record<TokenCategory, Names>>\n /**\n * the media keys that measure a size, so `@key:` is a meaningful container\n * query. derived by createGrammarConfigView when the media input carries\n * query information; absent means UNKNOWN, and the modifier registry then\n * refuses container claims with a diagnostic rather than over-claiming\n */\n containerSizeNames?: readonly string[]\n}\n\nexport interface ParsedCandidate {\n candidate: string\n base: string\n modifiers: readonly string[]\n negative: boolean\n kind: 'utility' | 'dynamic'\n valueKind: 'token' | 'arbitrary' | 'enum' | 'convenience'\n properties?: Readonly<Record<string, string | number>>\n entry?: GrammarEntry\n prefix?: string\n rawValue?: string\n arbitrary?: boolean\n convenience?: string\n}\n\nexport type CandidateClassification =\n | { kind: 'tamagui'; parsed: ParsedCandidate }\n | { kind: 'passthrough'; reason: string }\n\nconst sizingConveniences = new Set(['full', 'auto', 'screen', 'min', 'max', 'fit'])\nconst fontGenerics = new Set(['sans', 'serif', 'mono'])\nconst numericPattern = /^\\d+(?:\\.\\d+)?$/\nconst extraPrefixes = [\n 'border-x',\n 'border-y',\n 'rounded-t',\n 'rounded-r',\n 'rounded-b',\n 'rounded-l',\n]\nconst negativeTokenProps = new Set([\n 'margin',\n 'marginTop',\n 'marginRight',\n 'marginBottom',\n 'marginLeft',\n 'marginHorizontal',\n 'marginVertical',\n 'top',\n 'right',\n 'bottom',\n 'left',\n 'inset',\n 'x',\n 'y',\n 'letterSpacing',\n])\nconst borderWidthKeywords = new Set(['thin', 'medium', 'thick'])\nconst ambiguousCssKeywords = new Set([\n 'auto',\n 'dashed',\n 'dotted',\n 'double',\n 'groove',\n 'hidden',\n 'inherit',\n 'initial',\n 'inset',\n 'none',\n 'outset',\n 'revert',\n 'revert-layer',\n 'ridge',\n 'solid',\n 'unset',\n])\nconst cssLengthUnits =\n '(?:px|em|rem|ex|ch|cap|ic|lh|rlh|vw|vh|vmin|vmax|svw|svh|svmin|svmax|lvw|lvh|lvmin|lvmax|dvw|dvh|dvmin|dvmax|cm|mm|q|in|pt|pc)'\nconst cssLengthPattern = new RegExp(`^-?(?:\\\\d+|\\\\d*\\\\.\\\\d+)${cssLengthUnits}$`, 'i')\n\nfunction hasName(names: Names | undefined, name: string): boolean {\n if (!names) return false\n if (Array.isArray(names)) return names.includes(name)\n if (names instanceof Set) return names.has(name)\n return Object.prototype.hasOwnProperty.call(names, name)\n}\n\nfunction splitCandidate(candidate: string): { modifiers: string[]; base: string } | null {\n const parts: string[] = []\n let current = ''\n let bracketDepth = 0\n let escaped = false\n for (const char of candidate) {\n if (escaped) {\n current += char\n escaped = false\n continue\n }\n if (char === '\\\\') {\n current += char\n escaped = true\n continue\n }\n if (char === '[') bracketDepth++\n if (char === ']') bracketDepth--\n if (char === ':' && bracketDepth === 0) {\n parts.push(current)\n current = ''\n } else {\n current += char\n }\n }\n if (!current || bracketDepth !== 0) return null\n return { modifiers: parts, base: current }\n}\n\nconst modifierRegistryCache = new WeakMap<GrammarConfigView, ModifierRegistryView>()\n\nfunction getModifierRegistry(config: GrammarConfigView): ModifierRegistryView {\n let registry = modifierRegistryCache.get(config)\n if (!registry) {\n registry = createModifierRegistry(config).registry\n modifierRegistryCache.set(config, registry)\n }\n return registry\n}\n\nfunction modifierKind(modifier: string, config: GrammarConfigView): ModifierKind | null {\n const canonical = modifierAliases[modifier] || modifier\n return getModifierRegistry(config).get(canonical) || null\n}\n\nfunction modifiersAreKnown(\n modifiers: readonly string[],\n config: GrammarConfigView\n): boolean {\n const seen = new Set<ModifierKind>()\n for (const modifier of modifiers) {\n const kind = modifierKind(modifier, config)\n if (!kind || seen.has(kind)) return false\n seen.add(kind)\n }\n return true\n}\n\nfunction hasTokenDomain(config: GrammarConfigView, category: TokenCategory): boolean {\n return config.tokenNames?.[category] !== undefined\n}\n\nexport function hasTokenName(\n config: GrammarConfigView,\n category: TokenCategory,\n name: string\n): boolean {\n return hasName(config.tokenNames?.[category], name)\n}\n\nfunction resolveEntries(\n prefix: string,\n config: GrammarConfigView\n): readonly GrammarEntry[] {\n const registered = prefixToEntries[prefix]\n if (registered) return registered\n if (prefix === 'border-x' || prefix === 'border-y') {\n const props =\n prefix === 'border-x'\n ? ['borderLeft', 'borderRight']\n : ['borderTop', 'borderBottom']\n return grammarEntries.filter((entry) =>\n props.some((prop) => entry.prop === `${prop}Width` || entry.prop === `${prop}Color`)\n )\n }\n if (prefix.startsWith('rounded-')) {\n const props = radiusCornerProps[prefix.slice('rounded-'.length)]\n return props ? grammarEntries.filter((entry) => props.includes(entry.prop)) : []\n }\n const expanded = config.shorthands?.[prefix]\n if (!expanded) return []\n return grammarEntries.filter((entry) => entry.prop === expanded)\n}\n\nfunction findPrefix(base: string, config: GrammarConfigView): string | null {\n const prefixes = new Set(Object.keys(prefixToEntries))\n for (const prefix of extraPrefixes) prefixes.add(prefix)\n for (const shorthand in config.shorthands) prefixes.add(shorthand)\n let found: string | null = null\n for (const prefix of prefixes) {\n if (base.startsWith(`${prefix}-`) && (!found || prefix.length > found.length)) {\n found = prefix\n }\n }\n return found\n}\n\nfunction arbitraryInner(rawValue: string): string | null {\n if (rawValue.length <= 2 || rawValue[0] !== '[' || rawValue.at(-1) !== ']') {\n return null\n }\n const inner = rawValue.slice(1, -1)\n return arbitraryValueIsBalanced(decodeArbitrary(inner)) ? inner : null\n}\n\nfunction arbitraryValueIsBalanced(value: string): boolean {\n const opening = new Set(['(', '[', '{'])\n const matching: Readonly<Record<string, string>> = { ')': '(', ']': '[', '}': '{' }\n const stack: string[] = []\n let quote = ''\n let escaped = false\n for (const char of value) {\n if (escaped) {\n escaped = false\n continue\n }\n if (char === '\\\\') {\n escaped = true\n continue\n }\n if (quote) {\n if (char === quote) quote = ''\n continue\n }\n if (char === '\"' || char === \"'\") {\n quote = char\n continue\n }\n if (opening.has(char)) {\n stack.push(char)\n continue\n }\n const expected = matching[char]\n if (expected && stack.pop() !== expected) return false\n }\n return !escaped && !quote && stack.length === 0\n}\n\nfunction fractionIsValid(value: string): boolean {\n const fraction = /^(\\d+)\\/(\\d+)$/.exec(value)\n return !!fraction && Number(fraction[2]) !== 0\n}\n\nfunction arbitraryBorderKind(value: string): 'width' | 'color' | null {\n if (/^-?(?:\\d+|\\d*\\.\\d+)$/.test(value)) return 'width'\n if (cssLengthPattern.test(value) || borderWidthKeywords.has(value)) return 'width'\n if (/^(?:calc|min|max|clamp)\\(/.test(value)) return 'width'\n if (ambiguousCssKeywords.has(value) || value.startsWith('var(')) return null\n if (\n value.startsWith('#') ||\n /^(?:rgb|hsl|hwb|lab|lch|oklab|oklch|color|color-mix|light-dark)\\(/.test(value) ||\n /^[a-zA-Z][a-zA-Z0-9-]*$/.test(value)\n ) {\n return 'color'\n }\n return null\n}\n\nfunction tokenLookupName(category: TokenCategory, value: string): string {\n if (category !== 'color') return value\n const suffix = splitColorOpacitySuffix(value)\n return suffix.kind === 'none' ? value : suffix.name\n}\n\nfunction chooseEntry(\n entries: readonly GrammarEntry[],\n prefix: string,\n rawValue: string,\n negative: boolean,\n config: GrammarConfigView\n): {\n entry: GrammarEntry\n valueKind: ParsedCandidate['valueKind']\n convenience?: string\n} | null {\n if (getSafeAreaEdge(rawValue)) {\n const entry = entries.find(\n ({ tokenCategory }) =>\n tokenCategory === 'space' ||\n tokenCategory === 'size' ||\n tokenCategory === 'radius' ||\n tokenCategory === 'fontSize' ||\n tokenCategory === 'lineHeight' ||\n tokenCategory === 'letterSpacing'\n )\n if (entry) {\n return { entry, valueKind: 'convenience', convenience: 'safe-area' }\n }\n }\n\n const arbitrary = arbitraryInner(rawValue)\n if (arbitrary !== null) {\n if (!arbitrary) return null\n if (prefix.startsWith('border')) {\n const width = entries.find((entry) => entry.prop.endsWith('Width'))\n const color = entries.find((entry) => entry.prop.endsWith('Color'))\n const kind = arbitraryBorderKind(decodeArbitrary(arbitrary))\n if (!kind || !width || !color) return null\n return {\n entry: kind === 'width' ? width : color,\n valueKind: 'arbitrary',\n }\n }\n if (prefix === 'text') {\n return {\n entry: entries.find((entry) => entry.prop === 'fontSize')!,\n valueKind: 'arbitrary',\n }\n }\n if (prefix === 'font') {\n return {\n entry: entries.find((entry) => entry.prop === 'fontFamily')!,\n valueKind: 'arbitrary',\n }\n }\n return { entry: entries[0], valueKind: 'arbitrary' }\n }\n\n if (prefix === 'text') {\n const fontSize = entries.find((entry) => entry.prop === 'fontSize')\n if (fontSize && hasTokenName(config, 'fontSize', rawValue)) {\n return { entry: fontSize, valueKind: 'token' }\n }\n if (textAlignKeywords.has(rawValue)) {\n return {\n entry: entries.find((entry) => entry.prop === 'textAlign')!,\n valueKind: 'enum',\n }\n }\n return null\n }\n\n if (prefix === 'font') {\n const fontFamily = entries.find((entry) => entry.prop === 'fontFamily')\n const fontWeight = entries.find((entry) => entry.prop === 'fontWeight')\n if (!fontFamily) return null\n const matchesFamily = hasTokenName(config, 'fontFamily', rawValue)\n const matchesWeight = fontWeight && hasTokenName(config, 'fontWeight', rawValue)\n // a name configured as both a family and a weight is ambiguous, like the\n // border width/color rule above\n if (matchesFamily && matchesWeight) return null\n if (matchesFamily) {\n return { entry: fontFamily, valueKind: 'token' }\n }\n if (matchesWeight) {\n return { entry: fontWeight, valueKind: 'token' }\n }\n return fontGenerics.has(rawValue)\n ? { entry: fontFamily, valueKind: 'convenience', convenience: 'font-generic' }\n : null\n }\n\n if (prefix.startsWith('border')) {\n const width = entries.find((entry) => entry.prop.endsWith('Width'))\n const color = entries.find((entry) => entry.prop.endsWith('Color'))\n const token = negative ? `-${rawValue}` : rawValue\n const matchesWidth = width && hasTokenName(config, 'space', token)\n const colorName = tokenLookupName('color', rawValue)\n const matchesColor = color && hasTokenName(config, 'color', colorName)\n if (matchesWidth && matchesColor) return null\n if (matchesWidth) {\n return { entry: width, valueKind: 'token' }\n }\n if (matchesColor) {\n return { entry: color, valueKind: 'token' }\n }\n return null\n }\n\n for (const entry of entries) {\n if (entry.tokenCategory) {\n const name = negative ? `-${rawValue}` : rawValue\n const tokenName = tokenLookupName(entry.tokenCategory, name)\n if (hasTokenName(config, entry.tokenCategory, tokenName)) {\n return { entry, valueKind: 'token' }\n }\n if (\n entry.tokenCategory === 'size' &&\n (sizingConveniences.has(rawValue) || fractionIsValid(rawValue))\n ) {\n return { entry, valueKind: 'convenience', convenience: 'sizing-keyword' }\n }\n if (entry.tokenCategory === 'zIndex' && numericPattern.test(rawValue)) {\n return { entry, valueKind: 'convenience', convenience: 'integer' }\n }\n continue\n }\n if (prefix === 'opacity' || prefix === 'scale') {\n if (numericPattern.test(rawValue)) {\n return { entry, valueKind: 'convenience', convenience: 'percentage' }\n }\n continue\n }\n if (entry.prop === 'zIndex' && numericPattern.test(rawValue)) {\n return { entry, valueKind: 'convenience', convenience: 'integer' }\n }\n }\n return null\n}\n\nexport function parseCandidate(\n candidate: string,\n config: GrammarConfigView\n): ParsedCandidate | null {\n const split = splitCandidate(candidate)\n if (!split || !modifiersAreKnown(split.modifiers, config)) {\n return null\n }\n const modifiers = split.modifiers.map(\n (modifier) => modifierAliases[modifier] || modifier\n )\n\n const negative = split.base[0] === '-'\n const core = negative ? split.base.slice(1) : split.base\n const prefix = findPrefix(core, config)\n let dynamic:\n | {\n prefix: string\n rawValue: string\n selected: NonNullable<ReturnType<typeof chooseEntry>>\n }\n | undefined\n if (prefix) {\n const rawValue = core.slice(prefix.length + 1)\n if (rawValue) {\n const entries = resolveEntries(prefix, config)\n const selected = chooseEntry(entries, prefix, rawValue, negative, config)\n if (\n selected &&\n (!negative ||\n (selected.valueKind === 'token' && negativeTokenProps.has(selected.entry.prop)))\n ) {\n dynamic = { prefix, rawValue, selected }\n // An exact configured token owns its spelling before a reserved whole utility. Other\n // dynamic forms defer to the whole utility and are used only when no whole form exists.\n if (selected.valueKind === 'token') {\n return {\n candidate,\n base: split.base,\n modifiers,\n negative,\n kind: 'dynamic',\n prefix,\n rawValue,\n arbitrary: arbitraryInner(rawValue) !== null,\n entry: selected.entry,\n valueKind: selected.valueKind,\n convenience: selected.convenience,\n }\n }\n }\n }\n }\n\n const direct = wholeClassUtilities[split.base]\n if (!negative && direct) {\n const convenience = wholeClassConveniences[split.base]\n return {\n candidate,\n base: split.base,\n modifiers,\n kind: 'utility',\n valueKind: convenience ? 'convenience' : 'enum',\n properties: direct,\n convenience,\n negative: false,\n }\n }\n if (dynamic) {\n return {\n candidate,\n base: split.base,\n modifiers,\n negative,\n kind: 'dynamic',\n prefix: dynamic.prefix,\n rawValue: dynamic.rawValue,\n arbitrary: arbitraryInner(dynamic.rawValue) !== null,\n entry: dynamic.selected.entry,\n valueKind: dynamic.selected.valueKind,\n convenience: dynamic.selected.convenience,\n }\n }\n return null\n}\n\nexport function classifyCandidate(\n candidate: string,\n config: GrammarConfigView\n): CandidateClassification {\n const parsed = parseCandidate(candidate, config)\n return parsed\n ? { kind: 'tamagui', parsed }\n : { kind: 'passthrough', reason: 'not in the configured Tamagui grammar' }\n}\n\nexport interface FormatCandidateInput {\n prop: string\n value: string\n valueKind: ParsedCandidate['valueKind']\n modifiers?: readonly string[]\n}\n\nfunction tokenValidationConfig(\n entry: GrammarEntry,\n value: string,\n config: GrammarConfigView | undefined\n): GrammarConfigView {\n const tokenNames: Partial<Record<TokenCategory, Names>> = {\n ...config?.tokenNames,\n }\n const category = entry.tokenCategory!\n if (tokenNames[category] === undefined) {\n tokenNames[category] = [tokenLookupName(category, value)]\n }\n for (const other of prefixToEntries[entry.prefix] || []) {\n if (other.tokenCategory && tokenNames[other.tokenCategory] === undefined) {\n tokenNames[other.tokenCategory] = []\n }\n }\n return { ...config, tokenNames }\n}\n\nexport function formatCandidate(\n { prop, value, valueKind, modifiers = [] }: FormatCandidateInput,\n config?: GrammarConfigView\n): string | null {\n const entry = grammarEntries.find((candidate) => candidate.prop === prop)\n if (!entry) return null\n if (valueKind === 'arbitrary' && value === '') return null\n if (!modifiersAreKnown(modifiers, config || {})) return null\n const normalizedModifiers = modifiers.map(\n (modifier) => modifierAliases[modifier] || modifier\n )\n\n if (valueKind === 'enum') {\n const whole = standaloneValueProps[prop]?.[value]\n if (whole) {\n const candidate = normalizedModifiers.length\n ? `${normalizedModifiers.join(':')}:${whole}`\n : whole\n if (config) {\n const parsed = parseCandidate(candidate, config)\n if (!parsed?.properties || parsed.properties[prop] !== value) return null\n }\n return candidate\n }\n if (prop === 'fontWeight') {\n const name = fontWeightNames[value]\n if (!name) return null\n const core = `font-${name}`\n if (String(wholeClassUtilities[core]?.fontWeight) !== value) return null\n const candidate = normalizedModifiers.length\n ? `${normalizedModifiers.join(':')}:${core}`\n : core\n if (config) {\n const parsed = parseCandidate(candidate, config)\n if (!parsed?.properties || String(parsed.properties.fontWeight) !== value) {\n return null\n }\n }\n return candidate\n }\n }\n if (!entry.prefix) return null\n if (valueKind === 'token') {\n if (!entry.tokenCategory) return null\n const sourceDomainKnown = !!config && hasTokenDomain(config, entry.tokenCategory)\n const lookupName = tokenLookupName(entry.tokenCategory, value)\n if (sourceDomainKnown && !hasTokenName(config!, entry.tokenCategory, lookupName))\n return null\n const colliding = prefixToEntries[entry.prefix].filter(\n (other) => other.prop !== prop && other.tokenCategory\n )\n if (colliding.length) {\n if (!config || !sourceDomainKnown) return null\n for (const other of colliding) {\n if (!hasTokenDomain(config, other.tokenCategory!)) return null\n if (hasTokenName(config, other.tokenCategory!, value)) return null\n }\n }\n }\n const formattedValue = valueKind === 'arbitrary' ? `[${encodeArbitrary(value)}]` : value\n const core =\n formattedValue[0] === '-' && formattedValue[1] !== '['\n ? `-${entry.prefix}-${formattedValue.slice(1)}`\n : formattedValue\n ? `${entry.prefix}-${formattedValue}`\n : entry.prefix\n const candidate = normalizedModifiers.length\n ? `${normalizedModifiers.join(':')}:${core}`\n : core\n const whole = wholeClassUtilities[core]\n if (whole) {\n if (valueKind === 'token') {\n if (!config || !hasTokenDomain(config, entry.tokenCategory!)) return null\n } else if (config) {\n const parsed = parseCandidate(candidate, config)\n if (parsed?.kind === 'utility') {\n return Object.prototype.hasOwnProperty.call(parsed.properties, prop) &&\n String(parsed.properties?.[prop]) === value\n ? candidate\n : null\n }\n return parsed?.entry?.prop === prop && parsed.valueKind === valueKind\n ? candidate\n : null\n } else if (\n Object.prototype.hasOwnProperty.call(whole, prop) &&\n String(whole[prop]) === value\n ) {\n return candidate\n } else {\n return null\n }\n }\n if (valueKind === 'token') {\n if (\n !hasTokenDomain(config || {}, entry.tokenCategory!) &&\n parseCandidate(candidate, config || {})\n ) {\n return null\n }\n const parsed = parseCandidate(candidate, tokenValidationConfig(entry, value, config))\n const parsedValue = parsed?.rawValue\n ? `${parsed.negative ? '-' : ''}${parsed.rawValue}`\n : null\n if (\n parsed?.kind !== 'dynamic' ||\n parsed.entry?.prop !== prop ||\n parsed.valueKind !== 'token' ||\n parsedValue !== value\n ) {\n return null\n }\n return candidate\n }\n const parsed = parseCandidate(candidate, config || {})\n if (!parsed || parsed.entry?.prop !== prop || parsed.valueKind !== valueKind)\n return null\n return candidate\n}\n\nexport function encodeArbitrary(value: string): string {\n let encoded = ''\n for (const char of value) {\n if (char === '\\\\' || char === '_' || char === '[' || char === ']') {\n encoded += `\\\\${char}`\n } else if (/\\s/.test(char)) {\n encoded += '_'\n } else {\n encoded += char\n }\n }\n return encoded\n}\n\nexport function decodeArbitrary(value: string): string {\n let decoded = ''\n for (let index = 0; index < value.length; index++) {\n const char = value[index]\n if (char === '\\\\' && index + 1 < value.length) {\n decoded += value[++index]\n } else {\n decoded += char === '_' ? ' ' : char\n }\n }\n return decoded\n}\n"
10
+ ]
11
+ }
@@ -0,0 +1,32 @@
1
+ import type { TokenCategory } from "./registry";
2
+ export interface CandidateContribution {
3
+ property: string;
4
+ /** the token category this contribution binds through, when config-derived */
5
+ tokenCategory?: TokenCategory;
6
+ }
7
+ export interface CandidatePropertyMismatch {
8
+ code: "candidate-property-mismatch";
9
+ candidate: string;
10
+ property: string;
11
+ contributedProperties: readonly string[];
12
+ message: string;
13
+ }
14
+ export type CandidateTargetResult<Contribution extends CandidateContribution> = {
15
+ ok: true;
16
+ contribution: Contribution;
17
+ } | {
18
+ ok: false;
19
+ diagnostic: CandidatePropertyMismatch;
20
+ };
21
+ /**
22
+ * selects the contribution addressed by an overloaded family prop.
23
+ *
24
+ * candidate resolution happens before this function, so both the compiler and
25
+ * runtime pass the same family contributions here. A candidate is valid only
26
+ * when it contributes to the authored property itself. This keeps shared
27
+ * families such as `text-*` from accepting a color candidate for `fontSize`,
28
+ * or a font-size candidate for `color`.
29
+ */
30
+ export declare function resolveCandidateTarget<Contribution extends CandidateContribution>(property: string, candidate: string, contributions: readonly Contribution[]): CandidateTargetResult<Contribution>;
31
+
32
+ //# sourceMappingURL=candidateTarget.d.ts.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "mappings": "AAAA,cAAc,qBAAqB;AAEnC,iBAAiB,sBAAsB;CACrC;;CAEA,gBAAgB;;AAGlB,iBAAiB,0BAA0B;CACzC,MAAM;CACN;CACA;CACA;CACA;;AAGF,YAAY,sBAAsB,qBAAqB,yBACnD;CACE,IAAI;CACJ,cAAc;IAEhB;CACE,IAAI;CACJ,YAAY;;;;;;;;;;;AAYlB,OAAO,iBAAS,uBAAuB,qBAAqB,uBAC1D,kBACA,mBACA,wBAAwB,iBACvB,sBAAsB",
3
+ "names": [],
4
+ "sources": [
5
+ "src/candidateTarget.ts"
6
+ ],
7
+ "version": 3,
8
+ "sourcesContent": [
9
+ "import type { TokenCategory } from './registry'\n\nexport interface CandidateContribution {\n property: string\n /** the token category this contribution binds through, when config-derived */\n tokenCategory?: TokenCategory\n}\n\nexport interface CandidatePropertyMismatch {\n code: 'candidate-property-mismatch'\n candidate: string\n property: string\n contributedProperties: readonly string[]\n message: string\n}\n\nexport type CandidateTargetResult<Contribution extends CandidateContribution> =\n | {\n ok: true\n contribution: Contribution\n }\n | {\n ok: false\n diagnostic: CandidatePropertyMismatch\n }\n\n/**\n * selects the contribution addressed by an overloaded family prop.\n *\n * candidate resolution happens before this function, so both the compiler and\n * runtime pass the same family contributions here. A candidate is valid only\n * when it contributes to the authored property itself. This keeps shared\n * families such as `text-*` from accepting a color candidate for `fontSize`,\n * or a font-size candidate for `color`.\n */\nexport function resolveCandidateTarget<Contribution extends CandidateContribution>(\n property: string,\n candidate: string,\n contributions: readonly Contribution[]\n): CandidateTargetResult<Contribution> {\n for (const contribution of contributions) {\n if (contribution.property === property) {\n return { ok: true, contribution }\n }\n }\n\n const contributedProperties: string[] = []\n for (const contribution of contributions) {\n if (!contributedProperties.includes(contribution.property)) {\n contributedProperties.push(contribution.property)\n }\n }\n\n return {\n ok: false,\n diagnostic: {\n code: 'candidate-property-mismatch',\n candidate,\n property,\n contributedProperties,\n message:\n contributedProperties.length === 0\n ? `\"${candidate}\" does not contribute to \"${property}\"`\n : `\"${candidate}\" contributes to ${contributedProperties.map((name) => `\"${name}\"`).join(', ')}, not \"${property}\"`,\n },\n }\n}\n"
10
+ ]
11
+ }
@@ -0,0 +1,69 @@
1
+ import type { ModifierKind, ModifierRegistryView } from "./valueTypes";
2
+ export interface ClauseCapability {
3
+ /** the clause can lower to web CSS */
4
+ web: boolean;
5
+ /** the clause can evaluate on native */
6
+ native: boolean;
7
+ /** why a side is unsupported, for diagnostics */
8
+ note?: string;
9
+ }
10
+ /**
11
+ * Per-modifier capability. `kind` comes from the same registry the value was
12
+ * parsed against; an unregistered modifier is a parse error upstream and
13
+ * reports unsupported on both targets here.
14
+ */
15
+ export declare function clauseCapability(modifier: string, kind: ModifierKind | undefined): ClauseCapability;
16
+ /** file-extension intent: shared files must support BOTH targets */
17
+ export type ConversionTargets = "shared" | "web" | "native";
18
+ /**
19
+ * Host validity as the consumer already holds it — a projection of the
20
+ * component's staticConfig, never a table of this package's own.
21
+ */
22
+ export interface HostView {
23
+ /** does this host accept `prop` as a style (validStyles + accept) */
24
+ accepts(prop: string): boolean;
25
+ /** for diagnostics: the component label the author sees */
26
+ displayName?: string;
27
+ }
28
+ export interface ConversionReason {
29
+ dimension: "property" | "clause" | "host";
30
+ modifier?: string;
31
+ message: string;
32
+ /** the action the author takes, stated concretely */
33
+ remedy: string;
34
+ }
35
+ export interface ConversionAssessment {
36
+ /**
37
+ * clean: convertible AND evaluable where authored, with ALL THREE
38
+ * dimensions verified — clean is a promise, so an unchecked dimension can
39
+ * never produce it. needs-relocation: the conversion is syntactically
40
+ * right but this site was DETERMINED unable to evaluate it — the remedy
41
+ * names where it goes. unknown-host: property and clauses verified but the
42
+ * component identity could not be established, so host validity is
43
+ * UNVERIFIED rather than fine — the site needs review, not relocation.
44
+ * ineligible: this property cannot carry the clause spelling at all.
45
+ */
46
+ verdict: "clean" | "needs-relocation" | "unknown-host" | "ineligible";
47
+ reasons: readonly ConversionReason[];
48
+ }
49
+ export interface ConversionInput {
50
+ property: string;
51
+ /** modifiers used across the value's clauses, deduplicated by the caller or not */
52
+ modifiers?: readonly string[];
53
+ targets: ConversionTargets;
54
+ /**
55
+ * absent means the consumer could NOT establish the component's identity
56
+ * (structural provenance proves only direct View/Text and traceable styled
57
+ * bases today) — the verdict is then at best 'unknown-host', never 'clean'
58
+ */
59
+ host?: HostView;
60
+ }
61
+ /**
62
+ * The one call a converter, lint rule, or report makes before claiming a
63
+ * flat-value suggestion is safe. Composes property eligibility, per-target
64
+ * clause capability, and host validity; consumers never combine axes
65
+ * themselves.
66
+ */
67
+ export declare function assessFlatConversion(input: ConversionInput, registry: ModifierRegistryView): ConversionAssessment;
68
+
69
+ //# sourceMappingURL=clauseCapability.d.ts.map