@yahoo/uds-create-config 4.0.3 → 4.0.5

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.
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { useStateStore } from "@json-render/react";
3
+ import { resolveActionParam } from "@json-render/core";
3
4
  //#region src/renderer/wrappers/event-bridge.tsx
4
5
  /**
5
6
  * Map json-render `on.*` event bindings to React callback prop names.
@@ -21,6 +22,14 @@ const EVENT_TO_CALLBACKS = {
21
22
  valueCommit: ["onValueCommit"],
22
23
  dismiss: ["onDismiss"]
23
24
  };
25
+ /** `checkedChange` → `onCheckedChange`, `selectedChange` → `onSelectedChange`: the callback a
26
+ * controlled prop's change is reported through, by the convention every UDS control follows. */
27
+ function changeCallbackOf(eventName) {
28
+ const match = /^([a-z][A-Za-z0-9]*)Change$/.exec(eventName);
29
+ if (!match?.[1]) return void 0;
30
+ const prop = match[1];
31
+ return [`on${prop[0]?.toUpperCase()}${prop.slice(1)}Change`];
32
+ }
24
33
  /**
25
34
  * Bridge json-render's `on.*` event bindings to React callback props.
26
35
  *
@@ -44,7 +53,7 @@ function wrapEventBridge(reg) {
44
53
  if (!on) return React.createElement(Comp, renderProps);
45
54
  const callbackProps = {};
46
55
  for (const [eventName, binding] of Object.entries(on)) {
47
- const callbackNames = EVENT_TO_CALLBACKS[eventName];
56
+ const callbackNames = EVENT_TO_CALLBACKS[eventName] ?? changeCallbackOf(eventName);
48
57
  if (!callbackNames) continue;
49
58
  const bindings = Array.isArray(binding) ? binding : [binding];
50
59
  const handler = (...args) => {
@@ -52,7 +61,7 @@ function wrapEventBridge(reg) {
52
61
  for (const b of bindings) {
53
62
  const action = b;
54
63
  if (action.action === "setState" && action.params?.statePath) {
55
- const val = "value" in (action.params ?? {}) ? action.params.value : callbackValue;
64
+ const val = "value" in (action.params ?? {}) ? resolveActionParam(action.params.value, { stateModel: stateStore.getSnapshot() }) : callbackValue;
56
65
  stateStore.set(action.params.statePath, val);
57
66
  } else emit(eventName);
58
67
  }
@@ -1,6 +1,6 @@
1
1
  import { AcceptsChildNodes, ChildNodesClassification, ClassifyChildNodes, buildAcceptsChildNodes, buildClassifyChildNodes, namedSlotTargets, stripInjectedSlots, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots } from "./empty-node-slots.js";
2
2
  import { GraftableElement, GraftableSpec, PreviewElement, PreviewSpecNode, PreviewValue, graftPreviewElements, hasPreviewElementDeep, isPreviewElement, previewElementNodes, previewElementType } from "./preview-elements.js";
3
- import { DocumentRename, RewritableSpec, SpecRewrite, rewriteSpecRefs } from "./rewrite-refs.js";
3
+ import { DocumentRename, RewritableSpec, SpecRewrite, documentRenamesFromPatches, rewriteSpecRefs } from "./rewrite-refs.js";
4
4
  import { applyForcedModifiers, collectForcedModifierProps } from "./apply-forced-modifiers.js";
5
5
  import { AssetComponentMap, AssetJsxForm, AssetNodeResolver, assetJsxForm, jsxIdentifier, parseAssetType } from "./asset-jsx.js";
6
6
  import { CollapseTextLabelsResult, CollapsedTextLabel, collapseWrappedTextLabels } from "./collapse-text-labels.js";
@@ -26,4 +26,4 @@ import { SpecToJsxOptions, SpecToJsxResult, specToJsx } from "./specToJsx.js";
26
26
  * element, without changing the rendered layer hierarchy. */
27
27
  declare const SYNTHETIC_TEXT_SLOT_PROP = "data-uds-synthetic-text-slot";
28
28
  //#endregion
29
- export { type AcceptsChildNodes, type AssetComponentMap, type AssetJsxForm, type AssetNodeResolver, type ChildNodesClassification, type ClassifyChildNodes, type CollapseTextLabelsResult, type CollapsedTextLabel, type DocumentRename, type GraftableElement, type GraftableSpec, type JsxToSpecOptions, type PreviewElement, type PreviewSpecNode, type PreviewValue, type RewritableSpec, SYNTHETIC_TEXT_SLOT_PROP, type SpecRewrite, type SpecToJsxOptions, type SpecToJsxResult, UNRESOLVED, applyForcedModifiers, assetJsxForm, buildAcceptsChildNodes, buildClassifyChildNodes, collapseWrappedTextLabels, collectForcedModifierProps, graftPreviewElements, hasPreviewElementDeep, hasUnresolvedProps, isPreviewElement, jsxIdentifier, jsxToSpec, namedSlotTargets, parseAssetType, previewElementNodes, previewElementType, rewriteSpecRefs, specToJsx, stripInjectedSlots, stripUnresolvedProps, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots };
29
+ export { type AcceptsChildNodes, type AssetComponentMap, type AssetJsxForm, type AssetNodeResolver, type ChildNodesClassification, type ClassifyChildNodes, type CollapseTextLabelsResult, type CollapsedTextLabel, type DocumentRename, type GraftableElement, type GraftableSpec, type JsxToSpecOptions, type PreviewElement, type PreviewSpecNode, type PreviewValue, type RewritableSpec, SYNTHETIC_TEXT_SLOT_PROP, type SpecRewrite, type SpecToJsxOptions, type SpecToJsxResult, UNRESOLVED, applyForcedModifiers, assetJsxForm, buildAcceptsChildNodes, buildClassifyChildNodes, collapseWrappedTextLabels, collectForcedModifierProps, documentRenamesFromPatches, graftPreviewElements, hasPreviewElementDeep, hasUnresolvedProps, isPreviewElement, jsxIdentifier, jsxToSpec, namedSlotTargets, parseAssetType, previewElementNodes, previewElementType, rewriteSpecRefs, specToJsx, stripInjectedSlots, stripUnresolvedProps, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots };
@@ -4,7 +4,7 @@ import { buildAcceptsChildNodes, buildClassifyChildNodes, namedSlotTargets, stri
4
4
  import { applyForcedModifiers, collectForcedModifierProps } from "./apply-forced-modifiers.js";
5
5
  import { collapseWrappedTextLabels } from "./collapse-text-labels.js";
6
6
  import { UNRESOLVED, hasUnresolvedProps, jsxToSpec, stripUnresolvedProps } from "./jsxToSpec.js";
7
- import { rewriteSpecRefs } from "./rewrite-refs.js";
7
+ import { documentRenamesFromPatches, rewriteSpecRefs } from "./rewrite-refs.js";
8
8
  import { specToJsx } from "./specToJsx.js";
9
9
  //#region src/spec/index.ts
10
10
  /**
@@ -25,4 +25,4 @@ import { specToJsx } from "./specToJsx.js";
25
25
  * element, without changing the rendered layer hierarchy. */
26
26
  const SYNTHETIC_TEXT_SLOT_PROP = "data-uds-synthetic-text-slot";
27
27
  //#endregion
28
- export { SYNTHETIC_TEXT_SLOT_PROP, UNRESOLVED, applyForcedModifiers, assetJsxForm, buildAcceptsChildNodes, buildClassifyChildNodes, collapseWrappedTextLabels, collectForcedModifierProps, graftPreviewElements, hasPreviewElementDeep, hasUnresolvedProps, isPreviewElement, jsxIdentifier, jsxToSpec, namedSlotTargets, parseAssetType, previewElementNodes, previewElementType, rewriteSpecRefs, specToJsx, stripInjectedSlots, stripUnresolvedProps, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots };
28
+ export { SYNTHETIC_TEXT_SLOT_PROP, UNRESOLVED, applyForcedModifiers, assetJsxForm, buildAcceptsChildNodes, buildClassifyChildNodes, collapseWrappedTextLabels, collectForcedModifierProps, documentRenamesFromPatches, graftPreviewElements, hasPreviewElementDeep, hasUnresolvedProps, isPreviewElement, jsxIdentifier, jsxToSpec, namedSlotTargets, parseAssetType, previewElementNodes, previewElementType, rewriteSpecRefs, specToJsx, stripInjectedSlots, stripUnresolvedProps, withContainerChildSlots, withEmptyNodeSlots, withRenderSlots };
@@ -35,6 +35,18 @@ type DocumentRename = /** A component's path — `element.type` and a node's own
35
35
  readonly from: string;
36
36
  readonly to: string;
37
37
  };
38
+ /**
39
+ * The renames a list of patches recorded, oldest first — the only source that names both halves of every case.
40
+ *
41
+ * A renamed prop, variant value, layer, style property, token or modifier leaves no trace in the set of paths a
42
+ * config holds, and a component renamed to an unrelated name is indistinguishable from a delete plus a create.
43
+ * The patch says what happened, so nothing here has to infer it. That makes this the one place a rename becomes
44
+ * a document rewrite, whatever recorded the patch: a config's own pending edits, or a branch's stored rows.
45
+ *
46
+ * Replay order is preserved because renames compose — a component renamed twice in one draft only lands on the
47
+ * last name if the pairs are applied in the order they were made.
48
+ */
49
+ declare function documentRenamesFromPatches(patches: readonly Record<string, unknown>[]): DocumentRename[];
38
50
  /** A spec as this reads it: the structural subset, loose because the rows are whatever was written months ago. */
39
51
  interface RewritableSpec {
40
52
  elements?: Record<string, {
@@ -55,4 +67,4 @@ interface SpecRewrite {
55
67
  */
56
68
  declare function rewriteSpecRefs(config: Config, spec: RewritableSpec, renames: readonly DocumentRename[]): SpecRewrite;
57
69
  //#endregion
58
- export { DocumentRename, RewritableSpec, SpecRewrite, rewriteSpecRefs };
70
+ export { DocumentRename, RewritableSpec, SpecRewrite, documentRenamesFromPatches, rewriteSpecRefs };
@@ -12,36 +12,99 @@ import { Component } from "../entities/system/Component.js";
12
12
  * the config cascades through `cascadeRename` — which walks the ref index — and reaches none of the documents,
13
13
  * because a document holds no ref that index can see.
14
14
  *
15
- * So the rename has to be applied here, and the difficulty is that a spec's positions are CONTEXT-DEPENDENT:
15
+ * So the rename has to be applied here, and the difficulty is that a spec's positions are context-dependent:
16
16
  *
17
17
  * - `props.variant` is `Button`'s own prop only on elements whose type is `Button`. Rewriting the key wherever
18
18
  * it appears would rename an unrelated component's `variant` too.
19
- * - `props.bg` is the `bg` STYLE PROPERTY — unless the element's component declares its own `bg`, in which case
19
+ * - `props.bg` is the `bg` style property — unless the element's component declares its own `bg`, in which case
20
20
  * the component's declaration wins and a style-property rename must leave it alone.
21
- * - `props.bg = 'primary'` is a token LEAF inside whatever group the `bg` style property draws from, so a token
21
+ * - `props.bg = 'primary'` is a token leaf inside whatever group the `bg` style property draws from, so a token
22
22
  * rename only touches values on props that draw from that token's group.
23
23
  *
24
24
  * Every one of those questions is answered by the config (`resolveComponentProps`, the prop's declaration, the
25
25
  * style property's own `values`), which is why this takes one and resolves rather than matching strings.
26
26
  *
27
- * A MODIFIER is the one position that answers for itself. `_hover` is a prop bag keyed by a modifier's path, and
27
+ * A modifier is the one position that answers for itself. `_hover` is a prop bag keyed by a modifier's path, and
28
28
  * nothing else in a spec is `_`-prefixed — a component can't declare such a prop, and both the style resolver and
29
29
  * the prop validator skip the prefix on sight. So a modifier rename moves the key unconditionally, with no
30
- * component to scope it by. What the block CONTAINS is a second props bag against the same element, which is why
31
- * every other rename here descends into it: `_hover: { bg: 'accent' }` sets the same style property and the same
32
- * token as the bag around it, and stopping at the top level would leave the conditional half of a component
30
+ * component to scope it by. The block it prefixes contains a second props bag against the same element, which is
31
+ * why every other rename here descends into it: `_hover: { bg: 'accent' }` sets the same style property and the
32
+ * same token as the bag around it, and stopping at the top level would leave the conditional half of a component
33
33
  * stale while the base half moved.
34
34
  *
35
- * `layerProps` is the same shape with one twist: its keys are the component's LAYER names, and each bag under one
36
- * belongs to what that layer RENDERS rather than to the component around it. So a layer rename moves the key —
35
+ * `layerProps` is the same shape with one twist: its keys are the component's layer names, and each bag under one
36
+ * belongs to what that layer renders rather than to the component around it. So a layer rename moves the key —
37
37
  * scoped to its component, since `text` on one component is a different layer from `text` on another — and every
38
38
  * other rename descends with the layer's own declarations, because `layerProps.text.variant` is `Text`'s variant.
39
39
  * A layer that renders a component can itself be overridden through `layerProps`, and that nests the same way.
40
40
  *
41
- * Renames arrive TYPED and EXACT, from the patch that recorded them never inferred. The config supports a
41
+ * Renames arrive typed and exact, from the patch that recorded them, never inferred. The config supports a
42
42
  * rename op per kind and a sub-rename for a component's `props` and `props/value`, so the patch log names both
43
43
  * halves of every case below.
44
44
  */
45
+ /**
46
+ * The renames a list of patches recorded, oldest first — the only source that names both halves of every case.
47
+ *
48
+ * A renamed prop, variant value, layer, style property, token or modifier leaves no trace in the set of paths a
49
+ * config holds, and a component renamed to an unrelated name is indistinguishable from a delete plus a create.
50
+ * The patch says what happened, so nothing here has to infer it. That makes this the one place a rename becomes
51
+ * a document rewrite, whatever recorded the patch: a config's own pending edits, or a branch's stored rows.
52
+ *
53
+ * Replay order is preserved because renames compose — a component renamed twice in one draft only lands on the
54
+ * last name if the pairs are applied in the order they were made.
55
+ */
56
+ function documentRenamesFromPatches(patches) {
57
+ const renames = [];
58
+ for (const patch of patches) {
59
+ const { kind, operation, path, to, field, key } = patch;
60
+ if (typeof to !== "string" || typeof path !== "string") continue;
61
+ if (operation === "rename") {
62
+ if (kind === "component" && path !== to) renames.push({
63
+ kind: "component",
64
+ from: path,
65
+ to
66
+ });
67
+ else if (kind === "style-property" && path !== to) renames.push({
68
+ kind: "style-property",
69
+ from: path,
70
+ to
71
+ });
72
+ else if (kind === "token" && path !== to) renames.push({
73
+ kind: "token",
74
+ from: path,
75
+ to
76
+ });
77
+ else if (kind === "modifier" && path !== to) renames.push({
78
+ kind: "modifier",
79
+ from: path,
80
+ to
81
+ });
82
+ continue;
83
+ }
84
+ if (operation === "sub-rename" && kind === "component") {
85
+ if (field === "props" && typeof key === "string" && key !== to) renames.push({
86
+ kind: "component-prop",
87
+ component: path,
88
+ from: key,
89
+ to
90
+ });
91
+ else if (field === "layers" && typeof key === "string" && key !== to) renames.push({
92
+ kind: "layer",
93
+ component: path,
94
+ from: key,
95
+ to
96
+ });
97
+ else if (field === "props/value" && typeof key === "string" && typeof patch.prop === "string" && key !== to) renames.push({
98
+ kind: "variant-value",
99
+ component: path,
100
+ prop: patch.prop,
101
+ from: key,
102
+ to
103
+ });
104
+ }
105
+ }
106
+ return renames;
107
+ }
45
108
  /** Whether a stored `type` names this component path, in either form it may be written in. */
46
109
  function namesComponent(type, path) {
47
110
  if (typeof type !== "string") return false;
@@ -247,4 +310,4 @@ function rewriteSpecRefs(config, spec, renames) {
247
310
  };
248
311
  }
249
312
  //#endregion
250
- export { rewriteSpecRefs };
313
+ export { documentRenamesFromPatches, rewriteSpecRefs };