@yahoo/uds-create-config 4.5.2 → 4.7.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 (72) hide show
  1. package/dist/configs/CanvasConfig.d.ts +900 -80
  2. package/dist/configs/react-native-system.d.ts +603 -55
  3. package/dist/configs/system.d.ts +603 -55
  4. package/dist/configs/system.js +7 -1
  5. package/dist/entities/system/Component.d.ts +480 -39
  6. package/dist/entities/system/Component.js +264 -93
  7. package/dist/entities/system/File.d.ts +1 -1
  8. package/dist/entities/system/LinkedSystem.d.ts +2 -2
  9. package/dist/entities/system/Operation.d.ts +1 -1
  10. package/dist/entities/system/StyleProperty.d.ts +8 -0
  11. package/dist/entities/system/StyleProperty.js +12 -1
  12. package/dist/entities/system/Tool.d.ts +1 -1
  13. package/dist/entities/system/component-module.js +1 -1
  14. package/dist/entities/system/defineComponent.d.ts +45 -7
  15. package/dist/entities/system/defineComponent.js +52 -25
  16. package/dist/framework/Config.d.ts +8 -2
  17. package/dist/framework/Config.js +97 -23
  18. package/dist/framework/class-names.d.ts +4 -2
  19. package/dist/framework/class-names.js +56 -17
  20. package/dist/framework/defineDerivedEntity.d.ts +1 -1
  21. package/dist/framework/defineEntity.d.ts +2 -2
  22. package/dist/framework/defineSubEntity.d.ts +3 -2
  23. package/dist/framework/preview-store.d.ts +19 -0
  24. package/dist/framework/preview-store.js +18 -0
  25. package/dist/framework/projections.d.ts +28 -8
  26. package/dist/framework/projections.js +50 -16
  27. package/dist/framework/prop-surface.d.ts +21 -1
  28. package/dist/framework/prop-surface.js +99 -21
  29. package/dist/framework/render-spec.d.ts +103 -3
  30. package/dist/framework/render-spec.js +285 -37
  31. package/dist/framework/schema-version.d.ts +1 -1
  32. package/dist/framework/schema-version.js +5 -5
  33. package/dist/framework/source-integrity.d.ts +14 -1
  34. package/dist/framework/utils/refs.js +10 -1
  35. package/dist/framework/validate-spec.d.ts +2 -0
  36. package/dist/framework/validate-spec.js +13 -0
  37. package/dist/index.d.ts +15 -12
  38. package/dist/index.js +7 -6
  39. package/dist/migrations/2.0.0/v1-artifact.d.ts +305 -29
  40. package/dist/migrations/20260919051027_prop_conditions_and_anatomy_positions_at_rest.d.ts +22 -0
  41. package/dist/migrations/20260919051027_prop_conditions_and_anatomy_positions_at_rest.js +10 -0
  42. package/dist/migrations/20260920004019_preview_conditions_keyed.d.ts +27 -0
  43. package/dist/migrations/20260920004019_preview_conditions_keyed.js +148 -0
  44. package/dist/migrations/20260920161309_prefixed_token_group.d.ts +12 -0
  45. package/dist/migrations/20260920161309_prefixed_token_group.js +10 -0
  46. package/dist/renderer/wrapRegistry.js +8 -2
  47. package/dist/renderer/wrappers/component-refs.d.ts +14 -0
  48. package/dist/renderer/wrappers/component-refs.js +79 -0
  49. package/dist/renderer/wrappers/hex-normalize.d.ts +5 -7
  50. package/dist/renderer/wrappers/hex-normalize.js +11 -10
  51. package/dist/spec/cell.d.ts +171 -0
  52. package/dist/spec/cell.js +361 -0
  53. package/dist/spec/detach.d.ts +125 -0
  54. package/dist/spec/detach.js +511 -0
  55. package/dist/spec/empty-node-slots.d.ts +11 -23
  56. package/dist/spec/empty-node-slots.js +12 -39
  57. package/dist/spec/index.d.ts +5 -3
  58. package/dist/spec/index.js +3 -3
  59. package/dist/spec/instance.d.ts +77 -0
  60. package/dist/spec/instance.js +80 -0
  61. package/dist/spec/preview-content.d.ts +95 -0
  62. package/dist/spec/preview-content.js +149 -0
  63. package/dist/spec/preview-elements.d.ts +54 -15
  64. package/dist/spec/preview-elements.js +109 -29
  65. package/dist/spec/prop-conditions.d.ts +28 -0
  66. package/dist/spec/prop-conditions.js +39 -0
  67. package/dist/spec/slot.d.ts +206 -0
  68. package/dist/spec/slot.js +542 -0
  69. package/dist/spec/visibility.d.ts +82 -0
  70. package/dist/spec/visibility.js +109 -0
  71. package/dist/tsconfig.tsbuildinfo +1 -1
  72. package/package.json +18 -2
@@ -1,4 +1,4 @@
1
- import { isRef, kindOf, memberOf, pathOf } from "./utils/refs.js";
1
+ import { isRef, kindOf, memberOf, pathOf, refLeaf } from "./utils/refs.js";
2
2
  import { forwardsOf, rootLayerOf } from "../entities/system/element.js";
3
3
  import { propValueDomain, resolveComponentProps } from "./projections.js";
4
4
  import { Component } from "../entities/system/Component.js";
@@ -19,6 +19,34 @@ import { Component } from "../entities/system/Component.js";
19
19
  * its domain (an icon prop drawing its names from the icon library rather than copying them in),
20
20
  * which is why value lists are never read straight off `value`.
21
21
  */
22
+ /** A stored condition as leaves, one list per prop it names; `undefined` for none. */
23
+ function conditionLeaves(when) {
24
+ if (when === null || typeof when !== "object" || Array.isArray(when)) return;
25
+ const entries = Object.entries(when).filter(([, value]) => value !== void 0 && value !== null).map(([name, value]) => [name, (Array.isArray(value) ? value : [value]).map(refLeaf)]);
26
+ return entries.length > 0 ? Object.fromEntries(entries) : void 0;
27
+ }
28
+ /** The projected prop under ITS OWN condition. A forward resolved through carries the far prop's
29
+ * condition, which speaks of that component's siblings and means nothing here. */
30
+ function conditioned(prop, when) {
31
+ const { when: _far, ...own } = prop;
32
+ return when ? {
33
+ ...own,
34
+ when
35
+ } : own;
36
+ }
37
+ /**
38
+ * Whether a prop applies under the values in force — every prop its condition names holds one of the
39
+ * leaves listed for it. A prop with no condition always applies; an unset prop satisfies nothing.
40
+ * Compared as strings, since a control hands back what it displays.
41
+ */
42
+ function propApplies(prop, values) {
43
+ if (!prop.when) return true;
44
+ return Object.entries(prop.when).every(([name, leaves]) => {
45
+ const value = values[name];
46
+ if (value === void 0 || value === null) return false;
47
+ return leaves.some((leaf) => String(leaf) === String(value));
48
+ });
49
+ }
22
50
  /** The tail of a ref, when the value is one. */
23
51
  function refPath(value) {
24
52
  return isRef(value) ? pathOf(value.__ref) : void 0;
@@ -82,25 +110,62 @@ function routedProp(config, componentPath, decl) {
82
110
  return routedPropIn(config, body?.layers, decl);
83
111
  }
84
112
  function routesContent(config, layers, decl) {
85
- const routed = routedPropIn(config, layers, decl);
86
- if (routed) return routed.type === "slot";
87
- return refPath(decl.target) !== void 0 && intoName(decl.into) === "children";
113
+ const end = routeEnd(config, layers, decl);
114
+ if (!end) return false;
115
+ if (end.decl) return end.decl.type === "slot";
116
+ return refPath(end.route.target) !== void 0 && intoName(end.route.into) === "children";
117
+ }
118
+ /**
119
+ * Whether a route is typed in place once every forward between is followed: it lands on a text slot,
120
+ * or the last forward it follows says `text` itself. A message's `badge` routes into `Badge.children`,
121
+ * which forwards onto Badge's text layer, so the route is text although neither end of the first hop
122
+ * says so. The declaration the route starts from is the caller's to read.
123
+ */
124
+ function routesIntoText(config, layers, decl) {
125
+ const end = routeEnd(config, layers, decl);
126
+ if (!end) return false;
127
+ if (end.decl?.type === "slot" && end.decl.text === true) return true;
128
+ return end.route.text === true;
129
+ }
130
+ /**
131
+ * Where a route ends once every forward between is followed. A message's `badge` routes into
132
+ * `Badge.children`, which is itself a forward onto Badge's text layer; the route ends where that one
133
+ * does. `decl` is the declaration it lands on, absent for a layer that renders a tag or a prop nobody
134
+ * declares, and `route` is the last forward followed, whose `into` names what it asked that layer
135
+ * for. `undefined` for a route that comes back around to itself.
136
+ */
137
+ function routeEnd(config, layers, decl, seen = /* @__PURE__ */ new Set()) {
138
+ const landed = routedPropIn(config, layers, decl);
139
+ if (landed?.type !== "forward") return {
140
+ decl: landed,
141
+ route: decl
142
+ };
143
+ const layerKey = refPath(decl.target);
144
+ const target = layerKey ? refPath(layers?.[layerKey]) : void 0;
145
+ if (!target) return {
146
+ decl: landed,
147
+ route: decl
148
+ };
149
+ const key = `${target}#${intoName(decl.into)}`;
150
+ if (seen.has(key)) return void 0;
151
+ const farLayers = (Component.get(config, target)?.toJSON())?.layers;
152
+ return routeEnd(config, farLayers, landed, new Set([...seen, key]));
88
153
  }
89
154
  function slotProp(config, componentPath, name, decl) {
90
155
  const refs = acceptsRefs(decl.accepts);
91
156
  const icons = refs.find((ref) => kindOf(ref) === "icon");
92
- const routed = routedProp(config, componentPath, decl);
157
+ const layers = (Component.get(config, componentPath)?.toJSON())?.layers;
158
+ const routed = routeEnd(config, layers, decl)?.decl;
93
159
  const routedKind = routed?.type;
94
160
  const targetLayer = refPath(decl.target);
95
- const routesIntoText = routed?.type === "slot" && routed.text === true;
96
161
  return {
97
162
  name,
98
163
  kind: "slot",
99
164
  required: decl.required === true,
100
- text: decl.text === true || routesIntoText,
165
+ text: decl.text === true || routesIntoText(config, layers, decl),
101
166
  ...targetLayer ? {
102
167
  targetLayer,
103
- into: decl.into ?? "children"
168
+ into: intoName(decl.into)
104
169
  } : {},
105
170
  accepts: refs.filter((ref) => kindOf(ref) === "component").map((ref) => pathOf(ref)),
106
171
  ...icons ? { acceptsIconLibrary: pathOf(icons) } : {},
@@ -121,61 +186,62 @@ function surfaceProps(config, componentPath, seen = /* @__PURE__ */ new Set()) {
121
186
  const props = [];
122
187
  for (const [name, decl] of Object.entries(declared)) {
123
188
  const required = decl.required === true;
189
+ const when = conditionLeaves(decl.when);
124
190
  if (decl.type === "forward") {
125
191
  if (routesContent(config, layers, decl)) {
126
- props.push(slotProp(config, componentPath, name, decl));
192
+ props.push(conditioned(slotProp(config, componentPath, name, decl), when));
127
193
  continue;
128
194
  }
129
195
  const routed = boundProp(config, layers, decl, seen);
130
- if (routed) props.push({
196
+ if (routed) props.push(conditioned({
131
197
  ...routed,
132
198
  name,
133
199
  required
134
- });
200
+ }, when));
135
201
  continue;
136
202
  }
137
203
  if (decl.type === "slot") {
138
- props.push(slotProp(config, componentPath, name, decl));
204
+ props.push(conditioned(slotProp(config, componentPath, name, decl), when));
139
205
  continue;
140
206
  }
141
207
  if (decl.type === "variant") {
142
208
  const iconLibrary = variantIconLibrary(config, decl.value);
143
- props.push({
209
+ props.push(conditioned({
144
210
  name,
145
211
  kind: "variant",
146
212
  required,
147
213
  values: propValueDomain(config, decl)?.leaves ?? [],
148
214
  ...iconLibrary !== void 0 ? { iconLibrary } : {}
149
- });
215
+ }, when));
150
216
  continue;
151
217
  }
152
218
  if (decl.type === "styleProperty") {
153
219
  const styleProperty = refPath(decl.value);
154
220
  if (!styleProperty) continue;
155
- props.push({
221
+ props.push(conditioned({
156
222
  name,
157
223
  kind: "styleProperty",
158
224
  required,
159
225
  styleProperty
160
- });
226
+ }, when));
161
227
  continue;
162
228
  }
163
229
  if (decl.type === "composite") {
164
230
  const compositeName = refPath(decl.value);
165
231
  if (!compositeName) continue;
166
- props.push({
232
+ props.push(conditioned({
167
233
  name,
168
234
  kind: "composite",
169
235
  required,
170
236
  compositeName
171
- });
237
+ }, when));
172
238
  continue;
173
239
  }
174
- if (decl.type === "string" || decl.type === "number" || decl.type === "boolean" || decl.type === "motion") props.push({
240
+ if (decl.type === "string" || decl.type === "number" || decl.type === "boolean" || decl.type === "motion") props.push(conditioned({
175
241
  name,
176
242
  kind: decl.type,
177
243
  required
178
- });
244
+ }, when));
179
245
  }
180
246
  return props;
181
247
  }
@@ -198,6 +264,18 @@ function surfaceProp(config, componentPath, name) {
198
264
  return surfaceProps(config, componentPath).find((prop) => prop.name === name);
199
265
  }
200
266
  /**
267
+ * The registry entity a prop writes through, as a path: its composite, its style property, or the
268
+ * ref a variant's values come from. Resolved through a route, so a prop forwarded into a layer's
269
+ * composite names that composite. `undefined` for a prop with none.
270
+ */
271
+ function propRegistryRef(config, componentPath, name) {
272
+ const surfaced = surfaceProp(config, componentPath, name);
273
+ if (surfaced?.kind === "composite") return surfaced.compositeName;
274
+ if (surfaced?.kind === "styleProperty") return surfaced.styleProperty;
275
+ const decl = resolveComponentProps(config, componentPath)[name];
276
+ return decl?.type === "variant" ? refPath(decl.value) : void 0;
277
+ }
278
+ /**
201
279
  * The one precedence walk behind {@link forwardedLayers} and {@link forwardClaims}: every name a
202
280
  * `forwards` entry exposes, attributed to the layer that delivers it.
203
281
  *
@@ -275,4 +353,4 @@ function forwardClaims(config, componentPath) {
275
353
  };
276
354
  }
277
355
  //#endregion
278
- export { forwardClaims, forwardedLayers, intoName, routedProp, routedPropIn, routesContent, surfaceProp, surfaceProps };
356
+ export { forwardClaims, forwardedLayers, intoName, propApplies, propRegistryRef, routedProp, routedPropIn, routesContent, routesIntoText, surfaceProp, surfaceProps };
@@ -204,6 +204,54 @@ type VisibilityOperator = Exclude<keyof StateCondition, '$state' | 'not'>;
204
204
  declare function readStatePointer(state: Record<string, unknown>, pointer: string): unknown;
205
205
  /** The prop a `$state` pointer reads — its first segment, for a pointer into an object prop. */
206
206
  declare function statePointerProp(pointer: string): string;
207
+ /**
208
+ * The marker on an element a render placed inline, naming its anatomy node. A layer is addressed by
209
+ * `data-uds-layer`; this is for the node between layers that has no bag of its own. Stamped by the
210
+ * emitted module and by both projections, so a rendered element and a projected one read alike.
211
+ */
212
+ declare const ANATOMY_MARKER = "data-uds-anatomy";
213
+ /**
214
+ * The value prop a component paints as a layer's text: the anatomy node rendering `layer` binds its
215
+ * `children` to `{ $state: '/<prop>' }`, and that prop is declared a string or number. A forward
216
+ * surfaces its layer on the prop itself; this answers for a render that reads a value prop and
217
+ * writes it into a layer by hand, the way a `title` string reaches a heading.
218
+ */
219
+ declare function layerTextProp({
220
+ config,
221
+ path,
222
+ layer
223
+ }: {
224
+ config: Config;
225
+ path: string;
226
+ layer: string;
227
+ }): string | undefined;
228
+ /**
229
+ * The value prop a component hands an element it placed inline: the anatomy node `element` binds
230
+ * `into` to `{ $state: '/<prop>' }`, and that prop is a string or number. `into` is `children` for
231
+ * text the element shows itself, or the far component's prop the render passed it to
232
+ * (`<CommentHeader title={title} />` binds `title`).
233
+ */
234
+ declare function anatomyTextProp({
235
+ config,
236
+ path,
237
+ element,
238
+ into
239
+ }: {
240
+ config: Config;
241
+ path: string;
242
+ element: string;
243
+ into: string;
244
+ }): string | undefined;
245
+ /** The component an inline anatomy element renders, when it is one (`component:<path>`). */
246
+ declare function anatomyElementComponent({
247
+ config,
248
+ path,
249
+ element
250
+ }: {
251
+ config: Config;
252
+ path: string;
253
+ element: string;
254
+ }): string | undefined;
207
255
  /** A value in json-render's `visible` grammar, resolved against a prop bag. `undefined` when this
208
256
  * reader can't settle it, which leaves the condition on the element for the renderer to judge. */
209
257
  declare function resolveVisibility(condition: unknown, state: Record<string, unknown>): boolean | undefined;
@@ -301,10 +349,62 @@ interface SlotTarget {
301
349
  * the layer meant to hold it renders empty. Every one of Studio's own components shaped that way
302
350
  * (`Badge`, `StudioButton`, `Toggle`, …) painted as an empty shell in the component editor.
303
351
  *
304
- * Exported so the answer has ONE owner. An untargeted slot still resolves to the root here — that is
305
- * `slotTargets`' rule, not a caller's assumption, and it is the same rule the expansion renders by.
352
+ * Exported so the answer has ONE owner. An untargeted slot is hosted by the layer the anatomy
353
+ * places its content-position node in — a row's `leading` slot sits in its `leading` Box — and by the
354
+ * root when the anatomy records no position for it, which is where the expansion renders it.
306
355
  */
307
356
  declare function slotTargetsOf(config: Config, path: string): SlotTarget[];
357
+ /**
358
+ * Layer → the forwards that hand a VALUE to one of its props.
359
+ *
360
+ * `startIcon: { type: 'forward', target: 'startIcon/name' }` and `swatch: { type: 'forward', target:
361
+ * 'swatch/swatchColor' }` are this shape: the instance's value lands on the layer's element as the
362
+ * prop the forward names, the way the emitted module spreads it into that layer's bundle. A forward
363
+ * whose target prop is a slot is content instead, and {@link slotTargetsOf} answers for it.
364
+ */
365
+ declare function valueForwardsOf(config: Config, path: string): SlotTarget[];
366
+ /**
367
+ * The instance props whose values or content reach `layer`: content routed into it, values
368
+ * forwarded onto one of its props, and the props the layer exposes through `forwards`. A file
369
+ * editing a placed instance can change exactly these about the layer; the layer's own styles are
370
+ * the component's.
371
+ */
372
+ /**
373
+ * The instance prop whose content or value lands on `into` of `layer`, or `undefined` when the
374
+ * layer owns that prop itself. A change to the layer's prop in a cell is then a change to the
375
+ * instance prop's preview value, not a style.
376
+ */
377
+ declare function propInto({
378
+ config,
379
+ path,
380
+ layer,
381
+ into
382
+ }: {
383
+ config: Config;
384
+ path: string;
385
+ layer: string;
386
+ into: string;
387
+ }): string | undefined;
388
+ /** The route a prop's content or value takes into a layer, or `undefined` for a prop that reaches
389
+ * no layer. */
390
+ declare function routeOf({
391
+ config,
392
+ path,
393
+ prop
394
+ }: {
395
+ config: Config;
396
+ path: string;
397
+ prop: string;
398
+ }): SlotTarget | undefined;
399
+ declare function propsIntoLayer({
400
+ config,
401
+ path,
402
+ layer
403
+ }: {
404
+ config: Config;
405
+ path: string;
406
+ layer: string;
407
+ }): string[];
308
408
  /**
309
409
  * Expand every component element the renderer can't name into the tree it is made of.
310
410
  *
@@ -323,4 +423,4 @@ declare function expandSpec(config: Config, spec: RenderSpec, options?: ExpandOp
323
423
  */
324
424
  declare function expandComponent(config: Config, path: string, props?: Record<string, unknown>, options?: ExpandOptions): ExpansionResult;
325
425
  //#endregion
326
- export { ComponentSpec, ComponentSpecs, ExpandOptions, ExpansionResult, RenderElement, RenderSpec, SlotTarget, VisibilityOperator, VisibilityTerm, boundElementType, componentSpec, deriveSpec, entryKeyOf, expandComponent, expandSpec, instanceSpec, liveStateProps, previewSpec, readStatePointer, resolveVisibility, slotTargetsOf, specWithResolvedVisibility, statePointerProp, visibilityStateProps, visibilityTerms, withoutTruthyTerm, wrappedElementKey };
426
+ export { ANATOMY_MARKER, ComponentSpec, ComponentSpecs, ExpandOptions, ExpansionResult, RenderElement, RenderSpec, SlotTarget, VisibilityOperator, VisibilityTerm, anatomyElementComponent, anatomyTextProp, boundElementType, componentSpec, deriveSpec, entryKeyOf, expandComponent, expandSpec, instanceSpec, layerTextProp, liveStateProps, previewSpec, propInto, propsIntoLayer, readStatePointer, resolveVisibility, routeOf, slotTargetsOf, specWithResolvedVisibility, statePointerProp, valueForwardsOf, visibilityStateProps, visibilityTerms, withoutTruthyTerm, wrappedElementKey };