@yahoo/uds-create-config 2.44.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. package/README.md +129 -0
  2. package/dist/ai-lanes.d.ts +23 -0
  3. package/dist/ai-lanes.js +34 -0
  4. package/dist/authoring/define-component.d.ts +85 -0
  5. package/dist/configs/CanvasConfig.d.ts +3237 -0
  6. package/dist/configs/CanvasConfig.js +332 -0
  7. package/dist/configs/build-options.d.ts +10 -0
  8. package/dist/configs/build-options.js +68 -0
  9. package/dist/configs/platform.d.ts +15 -0
  10. package/dist/configs/platform.js +17 -0
  11. package/dist/configs/react-native-system.d.ts +3026 -0
  12. package/dist/configs/react-native-system.js +64 -0
  13. package/dist/configs/system.d.ts +2771 -0
  14. package/dist/configs/system.js +74 -0
  15. package/dist/css/properties.generated.d.ts +14 -0
  16. package/dist/css/properties.generated.js +6260 -0
  17. package/dist/css/value-type.d.ts +48 -0
  18. package/dist/css/value-type.js +131 -0
  19. package/dist/css/values.d.ts +33 -0
  20. package/dist/css/values.js +116 -0
  21. package/dist/entities/native/NativeModifier.d.ts +25 -0
  22. package/dist/entities/native/NativeModifier.js +41 -0
  23. package/dist/entities/native/NativeSettings.d.ts +44 -0
  24. package/dist/entities/native/NativeSettings.js +39 -0
  25. package/dist/entities/native/NativeStyleProperty.d.ts +355 -0
  26. package/dist/entities/native/NativeStyleProperty.js +28 -0
  27. package/dist/entities/native/NativeToken.d.ts +31 -0
  28. package/dist/entities/native/NativeToken.js +49 -0
  29. package/dist/entities/system/CanvasRole.d.ts +34 -0
  30. package/dist/entities/system/CanvasRole.js +45 -0
  31. package/dist/entities/system/Component.d.ts +1287 -0
  32. package/dist/entities/system/Component.js +1840 -0
  33. package/dist/entities/system/Composite.d.ts +12 -0
  34. package/dist/entities/system/Composite.js +26 -0
  35. package/dist/entities/system/Device.d.ts +11 -0
  36. package/dist/entities/system/Device.js +18 -0
  37. package/dist/entities/system/File.d.ts +72 -0
  38. package/dist/entities/system/File.js +136 -0
  39. package/dist/entities/system/Font.d.ts +48 -0
  40. package/dist/entities/system/Font.js +56 -0
  41. package/dist/entities/system/GlobalStyle.d.ts +26 -0
  42. package/dist/entities/system/GlobalStyle.js +54 -0
  43. package/dist/entities/system/Guidance.d.ts +85 -0
  44. package/dist/entities/system/Guidance.js +59 -0
  45. package/dist/entities/system/GuidanceStyle.d.ts +14 -0
  46. package/dist/entities/system/GuidanceStyle.js +8 -0
  47. package/dist/entities/system/Icon.d.ts +46 -0
  48. package/dist/entities/system/Icon.js +46 -0
  49. package/dist/entities/system/LinkedSystem.d.ts +504 -0
  50. package/dist/entities/system/LinkedSystem.js +814 -0
  51. package/dist/entities/system/Modifier.d.ts +92 -0
  52. package/dist/entities/system/Modifier.js +120 -0
  53. package/dist/entities/system/Motion.d.ts +28 -0
  54. package/dist/entities/system/Motion.js +48 -0
  55. package/dist/entities/system/Operation.d.ts +100 -0
  56. package/dist/entities/system/Operation.js +236 -0
  57. package/dist/entities/system/Package.d.ts +42 -0
  58. package/dist/entities/system/Package.js +75 -0
  59. package/dist/entities/system/Settings.d.ts +94 -0
  60. package/dist/entities/system/Settings.js +166 -0
  61. package/dist/entities/system/StyleProperty.d.ts +135 -0
  62. package/dist/entities/system/StyleProperty.js +438 -0
  63. package/dist/entities/system/Token.d.ts +67 -0
  64. package/dist/entities/system/Token.js +129 -0
  65. package/dist/entities/system/Tool.d.ts +134 -0
  66. package/dist/entities/system/Tool.js +124 -0
  67. package/dist/entities/system/color.d.ts +64 -0
  68. package/dist/entities/system/color.js +123 -0
  69. package/dist/entities/system/component-module.d.ts +63 -0
  70. package/dist/entities/system/component-module.js +258 -0
  71. package/dist/entities/system/copy-plan.d.ts +98 -0
  72. package/dist/entities/system/copy-plan.js +451 -0
  73. package/dist/entities/system/defineComponent.d.ts +428 -0
  74. package/dist/entities/system/defineComponent.js +337 -0
  75. package/dist/entities/system/element.d.ts +101 -0
  76. package/dist/entities/system/element.js +171 -0
  77. package/dist/entities/system/icon-library.d.ts +64 -0
  78. package/dist/entities/system/icon-library.js +112 -0
  79. package/dist/entities/system/icon-metadata.d.ts +72 -0
  80. package/dist/entities/system/icon-metadata.js +111 -0
  81. package/dist/entities/system/link-declaration.d.ts +27 -0
  82. package/dist/entities/system/link-declaration.js +64 -0
  83. package/dist/entities/system/link-plan.d.ts +160 -0
  84. package/dist/entities/system/link-plan.js +770 -0
  85. package/dist/entities/system/runtime-modules.d.ts +25 -0
  86. package/dist/entities/system/runtime-modules.js +38 -0
  87. package/dist/entities/system/style-bag.d.ts +20 -0
  88. package/dist/entities/system/style-bag.js +246 -0
  89. package/dist/entities/system/token-index.d.ts +89 -0
  90. package/dist/entities/system/token-index.js +112 -0
  91. package/dist/framework/Config.d.ts +2472 -0
  92. package/dist/framework/Config.js +5023 -0
  93. package/dist/framework/Entity.d.ts +127 -0
  94. package/dist/framework/Entity.js +125 -0
  95. package/dist/framework/authoring.d.ts +24 -0
  96. package/dist/framework/authoring.js +7 -0
  97. package/dist/framework/change-hooks.d.ts +119 -0
  98. package/dist/framework/change-hooks.js +131 -0
  99. package/dist/framework/changes.d.ts +88 -0
  100. package/dist/framework/changes.js +246 -0
  101. package/dist/framework/class-names.d.ts +260 -0
  102. package/dist/framework/class-names.js +630 -0
  103. package/dist/framework/coalesce.d.ts +25 -0
  104. package/dist/framework/coalesce.js +60 -0
  105. package/dist/framework/config-op.d.ts +76 -0
  106. package/dist/framework/config-op.js +43 -0
  107. package/dist/framework/config-operation-kind.d.ts +14 -0
  108. package/dist/framework/config-operation-kind.js +14 -0
  109. package/dist/framework/config-ops.d.ts +34 -0
  110. package/dist/framework/config-ops.js +187 -0
  111. package/dist/framework/defineConfig.d.ts +196 -0
  112. package/dist/framework/defineConfig.js +100 -0
  113. package/dist/framework/defineDerivedEntity.d.ts +74 -0
  114. package/dist/framework/defineDerivedEntity.js +83 -0
  115. package/dist/framework/defineEntity.d.ts +318 -0
  116. package/dist/framework/defineEntity.js +183 -0
  117. package/dist/framework/defineSubEntity.d.ts +148 -0
  118. package/dist/framework/defineSubEntity.js +121 -0
  119. package/dist/framework/derived-mutations.d.ts +20 -0
  120. package/dist/framework/derived-mutations.js +38 -0
  121. package/dist/framework/entity-search.d.ts +29 -0
  122. package/dist/framework/entity-search.js +117 -0
  123. package/dist/framework/inline-sources.d.ts +49 -0
  124. package/dist/framework/inline-sources.js +388 -0
  125. package/dist/framework/layer-styles.d.ts +25 -0
  126. package/dist/framework/layer-styles.js +49 -0
  127. package/dist/framework/memo.d.ts +48 -0
  128. package/dist/framework/memo.js +84 -0
  129. package/dist/framework/overlay.d.ts +49 -0
  130. package/dist/framework/overlay.js +17 -0
  131. package/dist/framework/plan.d.ts +49 -0
  132. package/dist/framework/plan.js +73 -0
  133. package/dist/framework/projections.d.ts +480 -0
  134. package/dist/framework/projections.js +974 -0
  135. package/dist/framework/prop-surface.d.ts +132 -0
  136. package/dist/framework/prop-surface.js +278 -0
  137. package/dist/framework/ref-graph.d.ts +71 -0
  138. package/dist/framework/ref-graph.js +158 -0
  139. package/dist/framework/ref-integrity.d.ts +55 -0
  140. package/dist/framework/ref-integrity.js +171 -0
  141. package/dist/framework/registered.d.ts +95 -0
  142. package/dist/framework/registry-dir.d.ts +42 -0
  143. package/dist/framework/registry-dir.js +48 -0
  144. package/dist/framework/registry.d.ts +300 -0
  145. package/dist/framework/registry.js +104 -0
  146. package/dist/framework/rejection.d.ts +58 -0
  147. package/dist/framework/rejection.js +111 -0
  148. package/dist/framework/rename-inference.d.ts +26 -0
  149. package/dist/framework/rename-inference.js +50 -0
  150. package/dist/framework/render-spec.d.ts +296 -0
  151. package/dist/framework/render-spec.js +809 -0
  152. package/dist/framework/schema-version.d.ts +140 -0
  153. package/dist/framework/schema-version.js +214 -0
  154. package/dist/framework/schemas.d.ts +109 -0
  155. package/dist/framework/schemas.js +615 -0
  156. package/dist/framework/session.d.ts +196 -0
  157. package/dist/framework/session.js +367 -0
  158. package/dist/framework/signature.d.ts +15 -0
  159. package/dist/framework/signature.js +83 -0
  160. package/dist/framework/snapshot.d.ts +115 -0
  161. package/dist/framework/snapshot.js +277 -0
  162. package/dist/framework/source-integrity.d.ts +226 -0
  163. package/dist/framework/source-integrity.js +478 -0
  164. package/dist/framework/sources.d.ts +211 -0
  165. package/dist/framework/sources.js +89 -0
  166. package/dist/framework/utils/compiled-schema.d.ts +23 -0
  167. package/dist/framework/utils/compiled-schema.js +46 -0
  168. package/dist/framework/utils/content-key.d.ts +15 -0
  169. package/dist/framework/utils/content-key.js +33 -0
  170. package/dist/framework/utils/enumerated.d.ts +13 -0
  171. package/dist/framework/utils/enumerated.js +19 -0
  172. package/dist/framework/utils/field-path.d.ts +95 -0
  173. package/dist/framework/utils/field-path.js +136 -0
  174. package/dist/framework/utils/field-schema.d.ts +55 -0
  175. package/dist/framework/utils/field-schema.js +183 -0
  176. package/dist/framework/utils/group.d.ts +37 -0
  177. package/dist/framework/utils/group.js +13 -0
  178. package/dist/framework/utils/package-path.d.ts +37 -0
  179. package/dist/framework/utils/package-path.js +61 -0
  180. package/dist/framework/utils/refs.d.ts +194 -0
  181. package/dist/framework/utils/refs.js +403 -0
  182. package/dist/framework/validate-spec.d.ts +27 -0
  183. package/dist/framework/validate-spec.js +45 -0
  184. package/dist/framework/value-domain.d.ts +26 -0
  185. package/dist/framework/value-domain.js +202 -0
  186. package/dist/framework/views-facade.d.ts +15 -0
  187. package/dist/framework/views-facade.js +19 -0
  188. package/dist/index.d.ts +90 -42
  189. package/dist/index.js +86 -37
  190. package/dist/migrations/2.0.0/raw-css.d.ts +11 -0
  191. package/dist/migrations/2.0.0/raw-css.js +72 -0
  192. package/dist/migrations/2.0.0/v1-artifact.d.ts +1559 -0
  193. package/dist/migrations/2.0.0/v1-artifact.js +1018 -0
  194. package/dist/migrations/20260908171448_settings_as_kind.d.ts +22 -0
  195. package/dist/migrations/20260908171448_settings_as_kind.js +89 -0
  196. package/dist/migrations/20260908194245_visible_state_pointer.d.ts +19 -0
  197. package/dist/migrations/20260908194245_visible_state_pointer.js +115 -0
  198. package/dist/migrations/20260909183001_icon_knockout_variants.d.ts +18 -0
  199. package/dist/migrations/20260909183001_icon_knockout_variants.js +8 -0
  200. package/dist/migrations/20260910212453_linked_system_link_ops.d.ts +13 -0
  201. package/dist/migrations/20260910212453_linked_system_link_ops.js +8 -0
  202. package/dist/migrations/index.d.ts +2 -0
  203. package/dist/migrations/index.js +2 -0
  204. package/dist/react-native/style-keys.generated.d.ts +10 -0
  205. package/dist/react-native/style-keys.generated.js +167 -0
  206. package/dist/renderer/RendererErrorBoundary.d.ts +32 -5
  207. package/dist/renderer/RendererErrorBoundary.js +59 -10
  208. package/dist/renderer/UdsRenderer.d.ts +11 -10
  209. package/dist/renderer/UdsRenderer.js +1 -1
  210. package/dist/renderer/assetEntries.d.ts +37 -0
  211. package/dist/renderer/assetEntries.js +39 -0
  212. package/dist/renderer/assetRenderable.d.ts +14 -6
  213. package/dist/renderer/assetRenderable.js +8 -2
  214. package/dist/renderer/componentEntry.d.ts +58 -0
  215. package/dist/renderer/componentEntry.js +71 -0
  216. package/dist/renderer/icon-library.d.ts +20 -0
  217. package/dist/renderer/index.d.ts +7 -7
  218. package/dist/renderer/index.js +5 -5
  219. package/dist/renderer/primitives/SlotRenderer.d.ts +1 -1
  220. package/dist/renderer/primitives/SlotRenderer.js +1 -1
  221. package/dist/renderer/runtimeComponent.d.ts +33 -0
  222. package/dist/renderer/runtimeComponent.js +113 -0
  223. package/dist/renderer/spec-content.d.ts +43 -0
  224. package/dist/renderer/spec-content.js +95 -0
  225. package/dist/renderer/wrapRegistry.d.ts +22 -37
  226. package/dist/renderer/wrapRegistry.js +10 -20
  227. package/dist/renderer/wrappers/event-bridge.js +6 -5
  228. package/dist/renderer/wrappers/hex-normalize.js +6 -5
  229. package/dist/renderer/wrappers/html-aliases.d.ts +7 -2
  230. package/dist/renderer/wrappers/html-aliases.js +36 -19
  231. package/dist/renderer/wrappers/inline-styles.js +7 -6
  232. package/dist/spec/asset-jsx.d.ts +18 -5
  233. package/dist/spec/asset-jsx.js +27 -16
  234. package/dist/spec/collapse-text-labels.d.ts +5 -15
  235. package/dist/spec/collapse-text-labels.js +26 -19
  236. package/dist/spec/empty-node-slots.d.ts +56 -34
  237. package/dist/spec/empty-node-slots.js +87 -47
  238. package/dist/spec/index.d.ts +21 -10
  239. package/dist/spec/index.js +21 -10
  240. package/dist/spec/jsxToSpec.d.ts +14 -9
  241. package/dist/spec/jsxToSpec.js +20 -3
  242. package/dist/spec/preview-elements.d.ts +63 -0
  243. package/dist/spec/preview-elements.js +89 -0
  244. package/dist/spec/rewrite-refs.d.ts +58 -0
  245. package/dist/spec/rewrite-refs.js +250 -0
  246. package/dist/spec/specToJsx.js +18 -29
  247. package/dist/tsconfig.tsbuildinfo +1 -1
  248. package/package.json +39 -52
  249. package/dist/AssetGroup.d.ts +0 -77
  250. package/dist/AssetGroup.js +0 -125
  251. package/dist/Component.d.ts +0 -333
  252. package/dist/Component.js +0 -1061
  253. package/dist/ComponentGroup.d.ts +0 -22
  254. package/dist/ComponentGroup.js +0 -51
  255. package/dist/CompositeStyle.d.ts +0 -30
  256. package/dist/CompositeStyle.js +0 -59
  257. package/dist/Config.d.ts +0 -528
  258. package/dist/Config.js +0 -1712
  259. package/dist/Mode.d.ts +0 -41
  260. package/dist/Mode.js +0 -81
  261. package/dist/Modifier.d.ts +0 -51
  262. package/dist/Modifier.js +0 -97
  263. package/dist/MotionDef.d.ts +0 -81
  264. package/dist/MotionDef.js +0 -212
  265. package/dist/Props.d.ts +0 -332
  266. package/dist/Props.js +0 -35
  267. package/dist/Provider.d.ts +0 -20
  268. package/dist/Provider.js +0 -14
  269. package/dist/StyleProp.d.ts +0 -145
  270. package/dist/StyleProp.js +0 -239
  271. package/dist/Token.d.ts +0 -76
  272. package/dist/Token.js +0 -133
  273. package/dist/TokenGroup.d.ts +0 -33
  274. package/dist/TokenGroup.js +0 -69
  275. package/dist/asset-kind.d.ts +0 -55
  276. package/dist/asset-kind.js +0 -29
  277. package/dist/asset-value.d.ts +0 -23
  278. package/dist/asset-value.js +0 -40
  279. package/dist/brands.d.ts +0 -30
  280. package/dist/brands.js +0 -20
  281. package/dist/captureCallerPath.d.ts +0 -48
  282. package/dist/captureCallerPath.js +0 -95
  283. package/dist/colorExpressions.d.ts +0 -131
  284. package/dist/colorExpressions.js +0 -148
  285. package/dist/component-referrers.d.ts +0 -30
  286. package/dist/component-referrers.js +0 -40
  287. package/dist/config-diagnostics.d.ts +0 -21
  288. package/dist/config-diagnostics.js +0 -12
  289. package/dist/defineAssetGroup.d.ts +0 -200
  290. package/dist/defineAssetGroup.js +0 -323
  291. package/dist/defineProvider.d.ts +0 -29
  292. package/dist/defineProvider.js +0 -60
  293. package/dist/element-marker.d.ts +0 -63
  294. package/dist/element-marker.js +0 -113
  295. package/dist/entity-utils.d.ts +0 -56
  296. package/dist/entity-utils.js +0 -105
  297. package/dist/extension.d.ts +0 -55
  298. package/dist/extension.js +0 -214
  299. package/dist/factories.d.ts +0 -863
  300. package/dist/factories.js +0 -475
  301. package/dist/font-face.d.ts +0 -25
  302. package/dist/font-face.js +0 -72
  303. package/dist/foreign-component-name.d.ts +0 -21
  304. package/dist/foreign-component-name.js +0 -42
  305. package/dist/interpolate.d.ts +0 -20
  306. package/dist/interpolate.js +0 -10
  307. package/dist/jsx/__fixtures__/cross-component-preview.d.ts +0 -3
  308. package/dist/jsx/__fixtures__/cross-component-preview.js +0 -15
  309. package/dist/jsx/jsx-dev-runtime.d.ts +0 -15
  310. package/dist/jsx/jsx-dev-runtime.js +0 -11
  311. package/dist/jsx/jsx-runtime.d.ts +0 -48
  312. package/dist/jsx/jsx-runtime.js +0 -305
  313. package/dist/linked-system-pins.d.ts +0 -30
  314. package/dist/linked-system-pins.js +0 -45
  315. package/dist/linkedNodePrefixes.d.ts +0 -73
  316. package/dist/linkedNodePrefixes.js +0 -99
  317. package/dist/markers.d.ts +0 -235
  318. package/dist/markers.js +0 -70
  319. package/dist/motion-constants.d.ts +0 -37
  320. package/dist/motion-constants.js +0 -61
  321. package/dist/native/NativeConfig.d.ts +0 -56
  322. package/dist/native/NativeConfig.js +0 -162
  323. package/dist/native/assets.d.ts +0 -20
  324. package/dist/native/assets.js +0 -17
  325. package/dist/native/components.d.ts +0 -139
  326. package/dist/native/components.js +0 -67
  327. package/dist/native/index.d.ts +0 -18
  328. package/dist/native/index.js +0 -17
  329. package/dist/native/modes.d.ts +0 -10
  330. package/dist/native/modes.js +0 -11
  331. package/dist/native/types.d.ts +0 -95
  332. package/dist/native/types.js +0 -0
  333. package/dist/native/validation.d.ts +0 -8
  334. package/dist/native/validation.js +0 -885
  335. package/dist/native/values.d.ts +0 -7
  336. package/dist/native/values.js +0 -15
  337. package/dist/native.d.ts +0 -12
  338. package/dist/native.js +0 -10
  339. package/dist/refs.d.ts +0 -204
  340. package/dist/refs.js +0 -129
  341. package/dist/registry-aliases.d.ts +0 -33
  342. package/dist/registry-aliases.js +0 -35
  343. package/dist/registry-dir.d.ts +0 -22
  344. package/dist/registry-dir.js +0 -10
  345. package/dist/renderer/makeRegistry.d.ts +0 -34
  346. package/dist/renderer/makeRegistry.js +0 -52
  347. package/dist/renderer/makeUdsRenderer.d.ts +0 -13
  348. package/dist/renderer/makeUdsRenderer.js +0 -51
  349. package/dist/renderer/wrappers/component-slots.d.ts +0 -41
  350. package/dist/renderer/wrappers/component-slots.js +0 -66
  351. package/dist/renderer/wrappers/slot-resolution.d.ts +0 -25
  352. package/dist/renderer/wrappers/slot-resolution.js +0 -68
  353. package/dist/renderer/wrappers/void-elements.d.ts +0 -37
  354. package/dist/renderer/wrappers/void-elements.js +0 -40
  355. package/dist/spec/layer-props.d.ts +0 -52
  356. package/dist/spec/layer-props.js +0 -149
  357. package/dist/spec/preview-controls.d.ts +0 -44
  358. package/dist/spec/preview-controls.js +0 -139
  359. package/dist/spec/slot-refs.d.ts +0 -39
  360. package/dist/spec/slot-refs.js +0 -56
  361. package/dist/token-override-rows.d.ts +0 -68
  362. package/dist/token-override-rows.js +0 -233
  363. package/dist/tokenValueType.d.ts +0 -34
  364. package/dist/tokenValueType.js +0 -138
  365. package/dist/types/css-properties.d.ts +0 -233
  366. package/dist/types/css-properties.js +0 -14
  367. package/dist/types/css-property-keywords.d.ts +0 -156
  368. package/dist/types/css-property-keywords.js +0 -616
  369. package/dist/types/css-values.d.ts +0 -63
  370. package/dist/types/css-values.js +0 -16
  371. package/dist/types.d.ts +0 -1138
  372. package/dist/types.js +0 -12
  373. package/dist/units.d.ts +0 -14
  374. package/dist/units.js +0 -16
  375. package/dist/utils/index.d.ts +0 -4
  376. package/dist/utils/index.js +0 -4
@@ -0,0 +1,438 @@
1
+ import { isRef, kindOf, pathOf, ref, refSchema, sourceOf, splitRef } from "../../framework/utils/refs.js";
2
+ import { defineEntity } from "../../framework/defineEntity.js";
3
+ import { cssValueIssue, isCssProperty } from "../../css/values.js";
4
+ import { camelCase } from "./style-bag.js";
5
+ import { z } from "zod";
6
+ //#region src/entities/system/StyleProperty.ts
7
+ /**
8
+ * A style property: a prop a component can expose, mapped to CSS properties with an allowed value set.
9
+ * The forms a `values` entry takes come first, each a zod schema built from its context, and the
10
+ * entity's fields read them.
11
+ */
12
+ /** A style property's path is the JSX prop a component exposes, so each segment is an identifier. */
13
+ const IDENTIFIER = /^[A-Za-z_$][\w$]*$/;
14
+ /** A token group's ref. Through the framework helper rather than `Token.ref`: `Token` reaches this
15
+ * module through `Modifier` and `Composite`, so importing it here is a cycle. */
16
+ const tokenGroup = (group) => ref("token", group);
17
+ /** A token ref as a model writes it, spelled from the ref itself so the prose can't drift. */
18
+ const spelled = (path) => JSON.stringify(tokenGroup(path));
19
+ const stylePropertyPath = z.string().check((ctx) => {
20
+ const bad = ctx.value.split("/").find((segment) => !IDENTIFIER.test(segment));
21
+ if (bad === void 0) return;
22
+ ctx.issues.push({
23
+ code: "custom",
24
+ input: ctx.value,
25
+ message: `a style property's name is the JSX prop a component exposes (\`<Box ${camelCase(bad)}="…" />\`), and \`${bad}\` is not a valid prop name. Write it camelCase — \`${camelCase(bad)}\` — and put the CSS property in \`properties\`.`
26
+ });
27
+ });
28
+ /** A number alias is a number whose CSS form is not the number: `6` resolves to
29
+ * `repeat(6, minmax(0, 1fr))`. */
30
+ const aliasName = z.union([z.string(), z.number()]);
31
+ /** The first property among `properties` that refuses `text`, as the refusal. A property the table
32
+ * can't judge says nothing. */
33
+ function cssIssue(properties, text, grammar) {
34
+ for (const property of properties ?? []) {
35
+ const issue = cssValueIssue({
36
+ property,
37
+ value: text,
38
+ grammar
39
+ });
40
+ if (issue !== void 0 && issue !== "unknown") return issue;
41
+ }
42
+ }
43
+ /** A check refusing CSS text no property takes, on the schema whose value is that text. A value the
44
+ * table can't judge goes to the grammar the config carries, when a write lane armed it with one. */
45
+ const cssText = ({ properties, config }, textOf) => (ctx) => {
46
+ const issue = cssIssue(properties, textOf(ctx.value), config?.cssGrammar);
47
+ if (issue === void 0) return;
48
+ ctx.issues.push({
49
+ code: "custom",
50
+ input: ctx.value,
51
+ message: issue
52
+ });
53
+ };
54
+ /** Whether a ref addresses one item, asked of the config that holds it. */
55
+ function refNamesItem(config, target) {
56
+ const { kind, path, source, member } = splitRef(target);
57
+ if (member !== void 0 || path === "") return false;
58
+ return (source === void 0 ? config : config.configFor(target))?.resolve(kind, path) !== void 0;
59
+ }
60
+ /** A check on a ref schema that admits only one of the two things a token ref can name. */
61
+ const namesItem = (config, wanted) => (ctx) => {
62
+ if (config === void 0 || refNamesItem(config, ctx.value) === wanted) return;
63
+ ctx.issues.push({
64
+ code: "custom",
65
+ input: ctx.value,
66
+ message: wanted ? "names a group, not one token" : "names one token, not a group"
67
+ });
68
+ };
69
+ /**
70
+ * Every form, keyed by kind, in the order a stored entry is matched against them. A ref is a record
71
+ * of one string too, so `aliasToken` comes before `aliasDeclarations`; a boolean alias is a flag
72
+ * whatever its value holds, so `flag` comes before the named aliases. `token` and `tokenGroup` are
73
+ * one stored shape; with a config each refuses what the other admits, and without one a ref reads
74
+ * as `token`.
75
+ */
76
+ /** A declaration bag's key. A ref is a record of one string too, so the ref marker is not a key here,
77
+ * or a ref no ref form admits would read as a bag. */
78
+ const declarationKey = z.string().regex(/^(?!__ref$)/);
79
+ const STYLE_PROP_VALUE_FORMS = {
80
+ keyword: (ctx = {}) => z.string().meta({
81
+ title: "Keyword",
82
+ description: "A literal whose authored form is its resolved form: `row`, `flex`."
83
+ }).check(cssText(ctx, (value) => value)),
84
+ number: (_ctx = {}) => z.number().meta({
85
+ title: "Number",
86
+ description: "A scale whose values are numbers (`gridTemplateColumns: [1, …, 12]`), stored as authored."
87
+ }),
88
+ token: ({ config } = {}) => refSchema.meta({
89
+ title: "Token",
90
+ description: "A ref to one token, emitted as its `var()`."
91
+ }).check(namesItem(config, true)),
92
+ tokenGroup: ({ config } = {}) => refSchema.meta({
93
+ title: "Token group",
94
+ description: "A ref to a token group, which offers every token in it and follows the group as it changes."
95
+ }).check(namesItem(config, false)),
96
+ flag: (_ctx = {}) => z.strictObject({
97
+ alias: z.boolean(),
98
+ value: z.union([
99
+ z.string(),
100
+ refSchema,
101
+ z.record(z.string(), z.string())
102
+ ])
103
+ }).meta({
104
+ title: "Flag",
105
+ description: "A boolean alias for a boolean-shaped prop: `<Box border />` sets `border-width: 1px`."
106
+ }),
107
+ aliasToken: ({ config } = {}) => z.strictObject({
108
+ alias: aliasName,
109
+ value: refSchema.check(namesItem(config, true))
110
+ }).meta({
111
+ title: "Token alias",
112
+ description: "One token under a name of the prop's own, still emitted as its `var()`."
113
+ }),
114
+ aliasLiteral: (ctx = {}) => z.strictObject({
115
+ alias: aliasName,
116
+ value: z.string()
117
+ }).meta({
118
+ title: "Alias",
119
+ description: "The authored key and the CSS value it resolves to: `{ alias: \"col\", value: \"column\" }`."
120
+ }).check(cssText(ctx, (value) => value.value)),
121
+ aliasDeclarations: (_ctx = {}) => z.strictObject({
122
+ alias: aliasName,
123
+ value: z.record(declarationKey, z.string())
124
+ }).meta({
125
+ title: "Declarations",
126
+ description: "A leaf that stands for a whole declaration bag: `truncate` sets `overflow`, `text-overflow` and `white-space`."
127
+ })
128
+ };
129
+ const KINDS = Object.keys(STYLE_PROP_VALUE_FORMS);
130
+ /** The value half of a flag as leaves carry it. */
131
+ function flagValue(value, members) {
132
+ if (typeof value === "string") return [{ value }];
133
+ if ("__ref" in value && typeof value.__ref === "string") return members(value).map(({ path }) => ({ value: path }));
134
+ return [{
135
+ value: "",
136
+ declarations: value
137
+ }];
138
+ }
139
+ /**
140
+ * What each form's stored entry stands for as leaves. `members` expands a ref to what it names, one
141
+ * entry for an item and one per member for a folder, since that walk is the config's. A flag's
142
+ * `true` is the bare prop, an empty leaf so the class is its prefix; `false` is its absence and
143
+ * authors nothing. A numeric alias is a leaf once it is a string: `6` names `.uds-grid-cols-6`.
144
+ */
145
+ const STYLE_PROP_VALUE_LEAVES = {
146
+ keyword: (entry) => [{
147
+ leaf: entry,
148
+ value: entry
149
+ }],
150
+ number: (entry) => [{
151
+ leaf: String(entry),
152
+ value: String(entry)
153
+ }],
154
+ token: (entry, members) => members(entry).map(({ leaf, path }) => ({
155
+ leaf,
156
+ value: path
157
+ })),
158
+ tokenGroup: (entry, members) => members(entry).map(({ leaf, path }) => ({
159
+ leaf,
160
+ value: path
161
+ })),
162
+ flag: (entry, members) => entry.alias ? flagValue(entry.value, members).map((rest) => ({
163
+ leaf: "",
164
+ ...rest
165
+ })) : [],
166
+ aliasToken: (entry, members) => members(entry.value).map(({ path }) => ({
167
+ leaf: String(entry.alias),
168
+ value: path
169
+ })),
170
+ aliasLiteral: (entry) => [{
171
+ leaf: String(entry.alias),
172
+ value: entry.value
173
+ }],
174
+ aliasDeclarations: (entry) => [{
175
+ leaf: String(entry.alias),
176
+ value: "",
177
+ declarations: entry.value
178
+ }]
179
+ };
180
+ /** The leaves one stored entry stands for; none for a value no form admits. */
181
+ function leavesOfStylePropValue(entry, members) {
182
+ const kind = stylePropValueFormOf(entry);
183
+ if (kind === void 0) return [];
184
+ const leaves = STYLE_PROP_VALUE_LEAVES[kind];
185
+ return leaves(entry, members);
186
+ }
187
+ /** Every form built against `ctx`, in matching order. */
188
+ function formsFor(ctx) {
189
+ return KINDS.map((kind) => STYLE_PROP_VALUE_FORMS[kind](ctx));
190
+ }
191
+ /** The `values` field's member schema against `ctx`: the union of every form. With no context it is
192
+ * the storage shape; with a config and the owner's properties it is also the judge. */
193
+ function stylePropValueSchema(ctx = {}) {
194
+ return z.union(formsFor(ctx));
195
+ }
196
+ /** The form a stored entry is, or `undefined` for a value no form admits. With a config, a ref is
197
+ * `token` or `tokenGroup` as the config says; without one it reads as `token`. */
198
+ function stylePropValueFormOf(entry, ctx = {}) {
199
+ return KINDS.find((kind) => STYLE_PROP_VALUE_FORMS[kind](ctx).safeParse(entry).success);
200
+ }
201
+ /** Which form a stored entry is, asked of the config that holds it. */
202
+ function classifyStylePropValue({ config, entry }) {
203
+ const kind = stylePropValueFormOf(entry, { config });
204
+ if (kind === void 0) throw new Error(`A style property value fits no form: ${JSON.stringify(entry)}`);
205
+ return kind;
206
+ }
207
+ /**
208
+ * A CSS property name in CSS spelling. A leading dash is a vendor or custom property, written as
209
+ * authored. `custom`, so a stored artifact written before the check hydrates.
210
+ */
211
+ const cssPropertyName = z.string().check((ctx) => {
212
+ const name = ctx.value;
213
+ if (name.startsWith("-")) return;
214
+ if (/[A-Z]/.test(name)) {
215
+ const css = name.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
216
+ ctx.issues.push({
217
+ code: "custom",
218
+ input: name,
219
+ message: `\`${name}\` is JSX spelling; a style property's \`properties\` are CSS names, written into the stylesheet as-is, so write \`"properties": ["${css}"]\` — and keep the camelCase name as the \`path\` (\`${name}\`), which is the prop a component exposes.`
220
+ });
221
+ return;
222
+ }
223
+ if (isCssProperty(name)) return;
224
+ ctx.issues.push({
225
+ code: "custom",
226
+ input: name,
227
+ message: `\`${name}\` is not a CSS property, so the declaration would paint nothing. \`properties\` are CSS property names in CSS spelling (\`background-color\`).`
228
+ });
229
+ });
230
+ /** A stored value's identity, with object keys in one order so two spellings of one alias compare equal. */
231
+ function valueKey(entry) {
232
+ if (typeof entry !== "object" || entry === null) return JSON.stringify(entry);
233
+ const sorted = Object.fromEntries(Object.entries(entry).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => [key, typeof value === "object" && value !== null ? JSON.parse(valueKey(value)) : value]));
234
+ return JSON.stringify(sorted);
235
+ }
236
+ /** A value listed twice paints the same rule twice; the second is refused where it sits. */
237
+ function eachValueOnce(ctx) {
238
+ const seen = /* @__PURE__ */ new Set();
239
+ ctx.value.forEach((entry, index) => {
240
+ const key = valueKey(entry);
241
+ if (!seen.has(key)) {
242
+ seen.add(key);
243
+ return;
244
+ }
245
+ ctx.issues.push({
246
+ code: "custom",
247
+ input: entry,
248
+ path: [index],
249
+ message: `\`values\` lists ${key} twice. Each value once.`
250
+ });
251
+ });
252
+ }
253
+ /** One comparable form for a CSS value, so `#FFFFFF` and `#ffffff ` read as the same value. */
254
+ const comparable = (value) => typeof value === "string" || typeof value === "number" ? String(value).trim().toLowerCase() : void 0;
255
+ /** Whether `values` reaches the token at `path` — through the token itself, an alias naming it, or
256
+ * a group above it. */
257
+ function reaches(values, path) {
258
+ return values.some((entry) => {
259
+ const target = isRef(entry) ? entry : entry?.value;
260
+ if (!isRef(target) || kindOf(target) !== "token") return false;
261
+ const named = pathOf(target);
262
+ return named === path || path.startsWith(`${named}/`);
263
+ });
264
+ }
265
+ /** The token ref an entry carries, itself or as an alias's value. */
266
+ function tokenRefOf(entry) {
267
+ if (isRef(entry)) return entry;
268
+ const value = entry?.value;
269
+ return isRef(value) ? value : void 0;
270
+ }
271
+ /**
272
+ * A check refusing an entry that copies a token the prop doesn't reference.
273
+ *
274
+ * `{ alias: 'white', value: '#FFFFFF' }` on a prop that never names the `color` group is the token
275
+ * `color/white` written out by hand: the class emits the literal, so a mode override or an edit to the
276
+ * token never reaches it, and the system now says the same colour twice. The group ref is the form
277
+ * that stays connected, and a model writing a system from scratch reaches for the copy unless the
278
+ * schema says no. A prop that already reaches the token may alias it under another name — `sm` for
279
+ * `spacing/2` — since that is one value with two spellings, not two values.
280
+ */
281
+ const copiesNoToken = (config) => (ctx) => {
282
+ const tokens = /* @__PURE__ */ new Map();
283
+ for (const token of config.list("token")) {
284
+ const value = comparable(token.body.value);
285
+ if (value !== void 0 && !tokens.has(value)) tokens.set(value, token.path);
286
+ }
287
+ ctx.value.forEach((entry, index) => {
288
+ if (typeof entry !== "object" || entry === null || !("value" in entry)) return;
289
+ const value = comparable(entry.value);
290
+ const token = value === void 0 ? void 0 : tokens.get(value);
291
+ if (!token || reaches(ctx.value, token)) return;
292
+ const group = token.slice(0, token.lastIndexOf("/"));
293
+ ctx.issues.push({
294
+ code: "custom",
295
+ input: entry,
296
+ path: [index],
297
+ message: `copies \`${entry.value}\`, which is the token \`${token}\`, and this prop doesn't reference it. Reference the token — \`${spelled(token)}\` — or its whole group, \`${spelled(group)}\`, to offer every token in it; either follows the token and its mode overrides, where a restated value never does.`
298
+ });
299
+ });
300
+ };
301
+ /** A check refusing a ref to a token or group nothing declares: it offers no values, and the prop
302
+ * paints nothing. */
303
+ const namesDeclaredTokens = (config) => (ctx) => {
304
+ ctx.value.forEach((entry, index) => {
305
+ const target = tokenRefOf(entry);
306
+ if (!target || kindOf(target) !== "token" || sourceOf(target) !== void 0 || pathOf(target) === "" || config.resolve("token", pathOf(target)) || config.members("token", pathOf(target)).length > 0) return;
307
+ const groups = config.groups("token").map((group) => `\`${group.path}\``).join(", ");
308
+ ctx.issues.push({
309
+ code: "custom",
310
+ input: entry,
311
+ path: [index],
312
+ message: `\`${target.__ref}\` names no token or token group this system has, so the prop would offer no values. Create its tokens first (\`token/create ${pathOf(target)}/<name>\`), or point at a group that exists${groups ? `: ${groups}` : ""}.`
313
+ });
314
+ });
315
+ };
316
+ /** The CSS properties a body writes, which its value forms judge their text against. */
317
+ function cssPropertiesOf(body) {
318
+ const properties = body?.properties;
319
+ if (!Array.isArray(properties)) return [];
320
+ return properties.filter((name) => typeof name === "string" && !name.startsWith("-") && isCssProperty(name));
321
+ }
322
+ /** The `values` array for the write `ctx` describes: every form, and the checks that lane carries. */
323
+ function valuesField({ config, body, linked }) {
324
+ if (!config) return z.array(stylePropValueSchema());
325
+ const declared = z.array(stylePropValueSchema({
326
+ config,
327
+ properties: linked ? void 0 : cssPropertiesOf(body)
328
+ })).check(eachValueOnce).check(namesDeclaredTokens(config));
329
+ return linked ? declared : declared.check(copiesNoToken(config));
330
+ }
331
+ /**
332
+ * The fields, built for the write. With a config in hand a style property is held to painting: its
333
+ * `properties` are CSS properties, and each value form judges itself against them, since a bare
334
+ * string in `values` is written into the stylesheet as-is and `borderRadius: ['sm']` paints
335
+ * `border-radius: sm`. Without one (`register`, hydration, tool derivation) this is the storage
336
+ * shape, and stores what it is given. A variant with a vocabulary of its own swaps `properties` and
337
+ * `values` (`NativeStyleProperty`).
338
+ *
339
+ * A body that arrived through a link is held to the forms alone. The CSS-text and token-copy checks
340
+ * are guidance for a write made here, and the source already emits this body as it stands.
341
+ */
342
+ const styleFields = ({ config, body, linked } = {}) => z.object({
343
+ properties: z.array(config ? cssPropertyName : z.string()).describe("The CSS properties this prop sets, all to the same value, in CSS spelling (`background-color`, never `backgroundColor`): the name is written into the stylesheet as-is."),
344
+ values: valuesField({
345
+ config,
346
+ body,
347
+ linked
348
+ }).optional().describe("What the prop accepts. A ref to a token GROUP (`{ \"__ref\": \"token:color\" }`) makes every member a value, named by its path under the group, and is how a prop takes tokens; a string or number is a keyword; `{ \"alias\": \"full\", \"value\": \"9999px\" }` names a literal; `{ \"alias\": \"brand\", \"value\": { \"__ref\": \"token:color/green\" } }` names one token under another name. One group ref usually replaces listing tokens one by one."),
349
+ responsive: z.boolean().default(false),
350
+ /**
351
+ * The class-name segment this prop contributes — `borderStyle` emits `.uds-border-style-solid`,
352
+ * and a prop whose values are already self-describing sets `''` so `position: absolute` emits
353
+ * `.uds-absolute` rather than `.uds-position-absolute`.
354
+ *
355
+ * Not derivable: whether a value needs its prop's name to be unambiguous is an authoring
356
+ * decision, and the same decision decides the class a consumer's markup already ships. Defaults
357
+ * to the prop's own path, which is the common case.
358
+ */
359
+ classPrefix: z.string().optional(),
360
+ arbitrary: z.boolean().default(false),
361
+ /**
362
+ * The prop applies the NEGATION of its value — `offsetX="3"` paints `margin-inline: calc(var(…) *
363
+ * -1)`.
364
+ *
365
+ * It exists so one scale can be used in both directions. A system that wants to pull an element
366
+ * out of its container's padding needs the same steps it padded with, negated; without this it
367
+ * would need a parallel set of negative tokens that could drift from the positive ones, or every
368
+ * call site would write an off-scale literal and leave the scale behind. So the values stay
369
+ * positive and the PROP carries the direction.
370
+ *
371
+ * Not derivable from anything else, which is why it's a field: the negation is invisible in the
372
+ * values (a positive spacing token) and in the properties (`margin-inline` either way). A class
373
+ * name conventionally spells it (`-mx`), but a name is not a rule — reading the leading dash as
374
+ * one would make a rename silently change what a prop paints.
375
+ */
376
+ negates: z.boolean().default(false),
377
+ /**
378
+ * The style prop whose alpha this one controls — `bgOpacity` is the opacity of `bg`.
379
+ *
380
+ * The pairing is modelled from the SIBLING's side, and the sibling is a real entity. The old model
381
+ * did neither: an opacity prop existed only as a field on its parent (`bg.opacityPair.as`), never
382
+ * registered, so a component exposing `bgOpacity` referenced something that wasn't there. Every
383
+ * config converted to v2 carries three of those dangling refs today.
384
+ *
385
+ * As an entity it resolves, the dep graph sees the relationship (so renaming `bg` cascades), and
386
+ * an emitter builds its parent→sibling map in the same one pass as before — just reading a ref
387
+ * instead of an implied name. Such a prop sets no CSS property of its own, hence an empty
388
+ * `properties`: it modulates its target rather than declaring anything.
389
+ */
390
+ opacityOf: z.lazy(() => StyleProperty).optional()
391
+ });
392
+ /** `path` if no style property holds it, else the first free numbered variant of it. */
393
+ function freePath(config, path) {
394
+ let candidate = path;
395
+ for (let n = 2; config.resolve("style-property", candidate); n += 1) candidate = `${path}${n}`;
396
+ return candidate;
397
+ }
398
+ /** StyleProperty (`flex/direction`) — a prop a component can expose, mapped to a CSS
399
+ * property with an allowed value set. Grouping (`flex`) is emergent from the path. */
400
+ const StyleProperty = defineEntity({
401
+ kind: "style-property",
402
+ label: "Style property",
403
+ labelPlural: "Style properties",
404
+ fields: styleFields,
405
+ schemas: {
406
+ rename: { to: stylePropertyPath },
407
+ create: {
408
+ path: stylePropertyPath,
409
+ description: `Create a style property — the prop a component exposes for one CSS effect. \`path\` is the prop's JSX name, camelCase (\`borderRadius\`), never a CSS name; the CSS goes in \`properties\`. \`values\` is a ref to a token GROUP (\`${spelled("<group>")}\`), which offers every token in it and keeps the prop in step with modes and edits; \`{ "alias": "brand", "value": ${spelled("<group>/<name>")} }\` offers one token under a name of the prop's own; a literal (\`"row"\`, \`{ "alias": "full", "value": "9999px" }\`) is for a keyword the system has no token for. Restating a token's value as a literal instead of referencing it is refused.`,
410
+ example: ({ config }) => {
411
+ const existing = config.list("style-property").find((entry) => entry.borrowedFrom === void 0);
412
+ if (!existing) return void 0;
413
+ return {
414
+ path: freePath(config, existing.path),
415
+ data: existing.toJSON()
416
+ };
417
+ }
418
+ }
419
+ }
420
+ });
421
+ /** `flexDirection` → `flex-direction`. A name already spelled as CSS comes back unchanged. */
422
+ function toCssPropertyName(property) {
423
+ return property.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
424
+ }
425
+ /**
426
+ * The CSS property names a style property governs, as the spec spells them.
427
+ *
428
+ * A web style property stores CSS names. A native one stores React Native style keys
429
+ * (`flexDirection`), so a surface keyed on CSS names, the designer panel's controls or a Figma
430
+ * paste's promotion, compares through this rather than against `properties` directly. A key only
431
+ * React Native defines (`paddingHorizontal`) comes back hyphenated and matches no CSS-keyed control,
432
+ * which is the right answer.
433
+ */
434
+ function cssPropertyNames(styleProp) {
435
+ return styleProp.properties.map(toCssPropertyName);
436
+ }
437
+ //#endregion
438
+ export { STYLE_PROP_VALUE_FORMS, STYLE_PROP_VALUE_LEAVES, StyleProperty, classifyStylePropValue, cssPropertyNames, leavesOfStylePropValue, stylePropValueFormOf, stylePropValueSchema, toCssPropertyName };
@@ -0,0 +1,67 @@
1
+ import { Ref } from "../../framework/utils/refs.js";
2
+ import { SubEntityClass } from "../../framework/defineSubEntity.js";
3
+ import { EntityClass } from "../../framework/defineEntity.js";
4
+ import { DerivedColor, Gradient } from "./color.js";
5
+ import { z } from "zod";
6
+
7
+ //#region src/entities/system/Token.d.ts
8
+ /** An override's `on`: a modifier ref, or a list of them that all hold at once. */
9
+ type OverrideCondition = Ref | Ref[];
10
+ /** The modifier paths an override's `on` names, in the order written. */
11
+ declare function overrideModifiers(on: unknown): string[];
12
+ /**
13
+ * An override's key, derived from its condition: the modifier's leaf, or for several modifiers
14
+ * their leaves sorted and joined with `&` (`dark&lg`), so one set of conditions has one key however
15
+ * the caller listed them. The leaf, because a modifier's leaf names it on its own (`uniqueLeaves`)
16
+ * and a key is what a bag's `_dark` and a force attribute spell too.
17
+ */
18
+ declare function overrideKey(on: unknown): string;
19
+ /** The modifier leaves an override key names — the inverse of {@link overrideKey}. Each resolves
20
+ * through `config.resolve('modifier', leaf)`. */
21
+ declare function overrideKeyModifiers(key: string): string[];
22
+ /**
23
+ * The `on` an override key stands for: one modifier ref, or the list a compound key names. Spelled
24
+ * by leaf; the write canonicalizes each to the modifier's path ({@link declaredCondition}).
25
+ */
26
+ declare function overrideCondition(key: string): OverrideCondition;
27
+ /**
28
+ * One conditional value — what a token becomes when `on` holds. The value domain is the caller's,
29
+ * since a native token takes values a web token does not; everything else about an override is the
30
+ * same for both.
31
+ *
32
+ * Its key is DERIVED from `on`, so a token can't hold two overrides for one condition and the key
33
+ * can't drift from the refs it names (the framework recomputes it on every write, and on a
34
+ * cascading rename). A write may leave the key out; the framework computes it. A write is checked
35
+ * against the config's modifiers; a load is not, since the stored data is what it is.
36
+ */
37
+ declare function defineOverride<TValue extends z.ZodTypeAny>(value: TValue): SubEntityClass<z.ZodObject<{
38
+ on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
39
+ value: TValue;
40
+ }, z.core.$strip>>;
41
+ declare const tokenFields: z.ZodObject<{
42
+ value: z.ZodType<string | number | Ref | DerivedColor | Gradient, unknown, z.core.$ZodTypeInternals<string | number | Ref | DerivedColor | Gradient, unknown>>;
43
+ type: z.ZodOptional<z.ZodString>;
44
+ overrides: z.ZodOptional<SubEntityClass<z.ZodObject<{
45
+ on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
46
+ value: z.ZodType<string | number | Ref | DerivedColor | Gradient, unknown, z.core.$ZodTypeInternals<string | number | Ref | DerivedColor | Gradient, unknown>>;
47
+ }, z.core.$strip>>>;
48
+ }, z.core.$strip>;
49
+ /** A token's stored body — what a `create` writes and what `Token.get` hands back typed. Exported
50
+ * so a consumer building one names the entity's own shape instead of restating it. */
51
+ type TokenBody = z.infer<typeof tokenFields>;
52
+ declare const Token: EntityClass<z.ZodObject<{
53
+ value: z.ZodType<string | number | Ref | DerivedColor | Gradient, unknown, z.core.$ZodTypeInternals<string | number | Ref | DerivedColor | Gradient, unknown>>;
54
+ type: z.ZodOptional<z.ZodString>;
55
+ overrides: z.ZodOptional<SubEntityClass<z.ZodObject<{
56
+ on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
57
+ value: z.ZodType<string | number | Ref | DerivedColor | Gradient, unknown, z.core.$ZodTypeInternals<string | number | Ref | DerivedColor | Gradient, unknown>>;
58
+ }, z.core.$strip>>>;
59
+ }, z.core.$strip>, z.ZodObject<{
60
+ cssPrefix: z.ZodOptional<z.ZodString>;
61
+ }, z.core.$strip>, "token", {
62
+ readonly create: {
63
+ readonly description: `Create a token at \`<group>/<name>\` \u2014 \`data.value\` is the CSS value. The first path segment is its group, and a style property takes a whole group as one ref (\`${string}\`), so put the tokens one prop should offer in one group rather than listing values on the prop.`;
64
+ };
65
+ }, Record<never, never>, false>;
66
+ //#endregion
67
+ export { OverrideCondition, Token, TokenBody, defineOverride, overrideCondition, overrideKey, overrideKeyModifiers, overrideModifiers };
@@ -0,0 +1,129 @@
1
+ import { isRef, pathOf, ref, sourceOf } from "../../framework/utils/refs.js";
2
+ import { defineEntity } from "../../framework/defineEntity.js";
3
+ import { defineSubEntity } from "../../framework/defineSubEntity.js";
4
+ import { derivedColor, gradient } from "./color.js";
5
+ import { Modifier } from "./Modifier.js";
6
+ import { Font } from "./Font.js";
7
+ import { z } from "zod";
8
+ //#region src/entities/system/Token.ts
9
+ /**
10
+ * A demo entity — note what's here: ONLY its fields, as a plain `z.object`. No ctor, no
11
+ * toJSON, no createSchema, no register method, no group class. `defineEntity` derives the
12
+ * whole typed toolkit (`Token.item`/`Token.group`/`Token.ref`, validation, serialization,
13
+ * grouping) from it.
14
+ */
15
+ /** A token's value slot — a literal, a ref to ANOTHER token (a `token(...)` alias), or a ref to a
16
+ * `Font` — reused for the base value and every per-mode override. Both refs are typed to their
17
+ * kind rather than being a generic ref: a token value aliases a token or names a font family, and
18
+ * nothing else. `z.lazy` on `Token` because it's a SELF-reference — `Token` isn't defined until the
19
+ * `defineEntity` call below returns; the explicit annotation breaks the circular type inference
20
+ * (same pattern as any recursive zod schema).
21
+ *
22
+ * A `font:` value is what makes "which fonts do I use, and where" an ordinary reverse-graph
23
+ * question: the family a `font-family` token resolves to is an EDGE, so renaming a font cascades
24
+ * and deleting one reports what breaks. Spelling it as the family's literal name instead would
25
+ * leave both to a string match. */
26
+ const tokenValue = z.union([
27
+ z.string(),
28
+ z.number(),
29
+ z.lazy(() => Token),
30
+ Font,
31
+ derivedColor,
32
+ gradient
33
+ ], { error: "a token's `value` is one CSS value as a string (`#1DB954`, `4px`, `\"Circular\", sans-serif`), a number, a ref to another token or to a font (`{ \"__ref\": \"font:<name>\" }`), a derived color (`{ \"op\": \"darken\", \"color\": { \"__ref\": \"token:color/brand\" }, \"amount\": 10 }`) or a gradient. It is required; a font family is a string value or a `font` entity, never a field of its own." });
34
+ /**
35
+ * What an override applies under: one modifier, or several that all hold at once (`dark` and `lg`
36
+ * together). Each is a ref, so the override is an ordinary edge: the dependency graph sees every
37
+ * modifier it names, and renaming one cascades like anywhere else. Nothing here says what kind of
38
+ * condition a modifier is, because the `Modifier` carries that in its `type` and its group.
39
+ */
40
+ const overrideConditionSchema = z.union([Modifier, z.array(Modifier).min(1)], { error: "an override applies under a modifier: `\"on\": { \"__ref\": \"modifier:<name>\" }`, or a list of them that all hold at once." });
41
+ /** The modifier paths an override's `on` names, in the order written. */
42
+ function overrideModifiers(on) {
43
+ return (Array.isArray(on) ? on : [on]).filter(isRef).map(pathOf);
44
+ }
45
+ /**
46
+ * An override's key, derived from its condition: the modifier's leaf, or for several modifiers
47
+ * their leaves sorted and joined with `&` (`dark&lg`), so one set of conditions has one key however
48
+ * the caller listed them. The leaf, because a modifier's leaf names it on its own (`uniqueLeaves`)
49
+ * and a key is what a bag's `_dark` and a force attribute spell too.
50
+ */
51
+ function overrideKey(on) {
52
+ return overrideModifiers(on).map(leafOf).sort((a, b) => a.localeCompare(b)).join("&");
53
+ }
54
+ /** The modifier leaves an override key names — the inverse of {@link overrideKey}. Each resolves
55
+ * through `config.resolve('modifier', leaf)`. */
56
+ function overrideKeyModifiers(key) {
57
+ return key.split("&");
58
+ }
59
+ /**
60
+ * The `on` an override key stands for: one modifier ref, or the list a compound key names. Spelled
61
+ * by leaf; the write canonicalizes each to the modifier's path ({@link declaredCondition}).
62
+ */
63
+ function overrideCondition(key) {
64
+ const refs = overrideKeyModifiers(key).map((leaf) => ({ __ref: `modifier:${leaf}` }));
65
+ return refs.length === 1 ? refs[0] : refs;
66
+ }
67
+ const leafOf = (path) => path.slice(path.lastIndexOf("/") + 1);
68
+ /**
69
+ * The condition, narrowed to modifiers `config` declares and spelled by their paths. A write naming
70
+ * a modifier this config does not have would store a condition nothing can activate, and the emitter
71
+ * would drop the override with nothing said. A ref written by leaf (`modifier:dark`) is stored as
72
+ * the path (`modifier:colorMode/dark`), so the graph holds one spelling and a rename cascade finds it.
73
+ * A ref through a link is the source's to answer for and is not judged here.
74
+ */
75
+ function declaredCondition(config) {
76
+ const canonical = (ref) => {
77
+ if (sourceOf(ref) !== void 0) return ref;
78
+ const path = config.resolve("modifier", pathOf(ref))?.path;
79
+ return path === void 0 || path === pathOf(ref) ? ref : { __ref: `modifier:${path}` };
80
+ };
81
+ return overrideConditionSchema.superRefine((on, ctx) => {
82
+ const refs = Array.isArray(on) ? on : [on];
83
+ for (const ref of refs) {
84
+ if (sourceOf(ref) !== void 0) continue;
85
+ const path = pathOf(ref);
86
+ if (config.resolve("modifier", path)) continue;
87
+ ctx.addIssue({
88
+ code: "custom",
89
+ message: `names modifier "${path}", which this config does not declare`
90
+ });
91
+ }
92
+ }).transform((on) => Array.isArray(on) ? on.map(canonical) : canonical(on));
93
+ }
94
+ /**
95
+ * One conditional value — what a token becomes when `on` holds. The value domain is the caller's,
96
+ * since a native token takes values a web token does not; everything else about an override is the
97
+ * same for both.
98
+ *
99
+ * Its key is DERIVED from `on`, so a token can't hold two overrides for one condition and the key
100
+ * can't drift from the refs it names (the framework recomputes it on every write, and on a
101
+ * cascading rename). A write may leave the key out; the framework computes it. A write is checked
102
+ * against the config's modifiers; a load is not, since the stored data is what it is.
103
+ */
104
+ function defineOverride(value) {
105
+ return defineSubEntity({
106
+ name: "override",
107
+ label: "Override",
108
+ fields: ({ config }) => z.object({
109
+ on: config ? declaredCondition(config) : overrideConditionSchema,
110
+ value
111
+ }),
112
+ key: (override) => overrideKey(override.on)
113
+ });
114
+ }
115
+ const Override = defineOverride(tokenValue);
116
+ const Token = defineEntity({
117
+ kind: "token",
118
+ fields: z.object({
119
+ value: tokenValue,
120
+ type: z.string().optional(),
121
+ overrides: Override.optional()
122
+ }),
123
+ groupFields: z.object({ cssPrefix: z.string().optional() }),
124
+ localGroupFields: ["cssPrefix"],
125
+ subEntities: { overrides: Override },
126
+ schemas: { create: { description: `Create a token at \`<group>/<name>\` — \`data.value\` is the CSS value. The first path segment is its group, and a style property takes a whole group as one ref (\`${JSON.stringify(ref("token", "<group>"))}\`), so put the tokens one prop should offer in one group rather than listing values on the prop.` } }
127
+ });
128
+ //#endregion
129
+ export { Token, defineOverride, overrideCondition, overrideKey, overrideKeyModifiers, overrideModifiers };