@yahoo/uds-create-config 5.48.2 → 5.48.3

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.
@@ -2,6 +2,7 @@ import { Ref } from "../framework/utils/ref-grammar.js";
2
2
  import { SubEntityClass } from "../framework/defineSubEntity.js";
3
3
  import { ComputedInput } from "../framework/registry.js";
4
4
  import { DerivedColor, Gradient } from "../entities/system/color.js";
5
+ import { Shadow } from "../entities/system/shadow.js";
5
6
  import { ComposedValue } from "../entities/system/composed-values.js";
6
7
  import { EntityClass } from "../framework/defineEntity.js";
7
8
  import { ConfigClass } from "../framework/defineConfig.js";
@@ -97,13 +98,13 @@ declare const ReactNativeSystemDefinition: ConfigClass<{
97
98
  }, _$zod_v4_core0.$strict>>;
98
99
  cssVariable: _$zod.ZodOptional<_$zod.ZodUnion<readonly [_$zod.ZodString, _$zod.ZodLiteral<false>]>>;
99
100
  }, "value" | "overrides" | "property" | "cssVariable"> & {
100
- value: _$zod.ZodType<string | number | boolean | Ref | DerivedColor | Gradient | {
101
+ value: _$zod.ZodType<string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
101
102
  flexGrow: number;
102
103
  flexShrink: number;
103
104
  flexBasis: string | number;
104
105
  } | {
105
106
  fontSizeMultiplier: number;
106
- }, unknown, _$zod_v4_core0.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor | Gradient | {
107
+ }, unknown, _$zod_v4_core0.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
107
108
  flexGrow: number;
108
109
  flexShrink: number;
109
110
  flexBasis: string | number;
@@ -112,13 +113,13 @@ declare const ReactNativeSystemDefinition: ConfigClass<{
112
113
  }, unknown>>;
113
114
  overrides: _$zod.ZodOptional<_$zod.ZodUnion<readonly [_$zod.ZodPipe<_$zod.ZodArray<_$zod.ZodObject<{
114
115
  on: _$zod.ZodType<OverrideCondition, unknown, _$zod_v4_core0.$ZodTypeInternals<OverrideCondition, unknown>>;
115
- value: _$zod.ZodType<string | number | boolean | Ref | DerivedColor | Gradient | {
116
+ value: _$zod.ZodType<string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
116
117
  flexGrow: number;
117
118
  flexShrink: number;
118
119
  flexBasis: string | number;
119
120
  } | {
120
121
  fontSizeMultiplier: number;
121
- }, unknown, _$zod_v4_core0.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor | Gradient | {
122
+ }, unknown, _$zod_v4_core0.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
122
123
  flexGrow: number;
123
124
  flexShrink: number;
124
125
  flexBasis: string | number;
@@ -127,7 +128,7 @@ declare const ReactNativeSystemDefinition: ConfigClass<{
127
128
  }, unknown>>;
128
129
  }, _$zod_v4_core0.$strip>>, _$zod.ZodTransform<Record<string, {
129
130
  on: OverrideCondition;
130
- value: string | number | boolean | Ref | DerivedColor | Gradient | {
131
+ value: string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
131
132
  flexGrow: number;
132
133
  flexShrink: number;
133
134
  flexBasis: string | number;
@@ -136,7 +137,7 @@ declare const ReactNativeSystemDefinition: ConfigClass<{
136
137
  };
137
138
  }>, {
138
139
  on: OverrideCondition;
139
- value: string | number | boolean | Ref | DerivedColor | Gradient | {
140
+ value: string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
140
141
  flexGrow: number;
141
142
  flexShrink: number;
142
143
  flexBasis: string | number;
@@ -145,13 +146,13 @@ declare const ReactNativeSystemDefinition: ConfigClass<{
145
146
  };
146
147
  }[]>>, SubEntityClass<_$zod.ZodObject<{
147
148
  on: _$zod.ZodType<OverrideCondition, unknown, _$zod_v4_core0.$ZodTypeInternals<OverrideCondition, unknown>>;
148
- value: _$zod.ZodType<string | number | boolean | Ref | DerivedColor | Gradient | {
149
+ value: _$zod.ZodType<string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
149
150
  flexGrow: number;
150
151
  flexShrink: number;
151
152
  flexBasis: string | number;
152
153
  } | {
153
154
  fontSizeMultiplier: number;
154
- }, unknown, _$zod_v4_core0.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor | Gradient | {
155
+ }, unknown, _$zod_v4_core0.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
155
156
  flexGrow: number;
156
157
  flexShrink: number;
157
158
  flexBasis: string | number;
@@ -26,6 +26,7 @@ import { buildExcludeMigration } from "../migrations/20261019165323_build_exclud
26
26
  import { nativeLinearGradientsMigration } from "../migrations/20261020173914_native_linear_gradients.js";
27
27
  import { linkedDirMigration } from "../migrations/20261020182408_linked_dir.js";
28
28
  import { lintSettingsMigration } from "../migrations/20261020183330_lint_settings.js";
29
+ import { directLayerCompositesMigration } from "../migrations/20261022124223_direct_layer_composites.js";
29
30
  import { CanvasRole } from "../entities/system/CanvasRole.js";
30
31
  import { GlobalStyle } from "../entities/system/GlobalStyle.js";
31
32
  import { Guidance } from "../entities/system/Guidance.js";
@@ -182,6 +183,9 @@ if (!registeredSchemaMigrations().has(20261016201727)) registerSchemaMigrations(
182
183
  if (!registeredSchemaMigrations().has(20261019165323)) registerSchemaMigrations(buildExcludeMigration);
183
184
  if (!registeredSchemaMigrations().has(20261020173914)) registerSchemaMigrations(nativeLinearGradientsMigration);
184
185
  if (!registeredSchemaMigrations().has(20261020182408)) registerSchemaMigrations(linkedDirMigration);
185
- if (!registeredSchemaMigrations().has(20261020183330)) registerSchemaMigrations(lintSettingsMigration);
186
+ if (!registeredSchemaMigrations().has(20261020183330)) {
187
+ registerSchemaMigrations(lintSettingsMigration);
188
+ registerSchemaMigrations(directLayerCompositesMigration);
189
+ }
186
190
  //#endregion
187
191
  export { System };
@@ -2,6 +2,7 @@ import { Ref } from "../../framework/utils/ref-grammar.js";
2
2
  import { Ref as Ref$1 } from "../../framework/utils/refs.js";
3
3
  import { SubEntityClass } from "../../framework/defineSubEntity.js";
4
4
  import { DerivedColor, Gradient } from "../system/color.js";
5
+ import { Shadow } from "../system/shadow.js";
5
6
  import { ComposedValue } from "../system/composed-values.js";
6
7
  import { EntityClass } from "../../framework/defineEntity.js";
7
8
  import { OverrideCondition } from "../system/Token.js";
@@ -10,7 +11,7 @@ import { RelativeLineHeightValue } from "../system/linked-line-height-values.js"
10
11
  import { z } from "zod";
11
12
 
12
13
  //#region src/entities/native/NativeToken.d.ts
13
- declare const nativeTokenValue: z.ZodType<number | boolean | string | Ref$1 | DerivedColor | Gradient | NativeFlexValue | RelativeLineHeightValue>;
14
+ declare const nativeTokenValue: z.ZodType<number | boolean | string | Ref$1 | DerivedColor | Gradient | Shadow | NativeFlexValue | RelativeLineHeightValue>;
14
15
  declare const NativeToken: EntityClass<z.ZodObject<Omit<{
15
16
  value: z.ZodType<string | number | Ref | ComposedValue, unknown, z.core.$ZodTypeInternals<string | number | Ref | ComposedValue, unknown>>;
16
17
  type: z.ZodOptional<z.ZodString>;
@@ -34,13 +35,13 @@ declare const NativeToken: EntityClass<z.ZodObject<Omit<{
34
35
  }, z.core.$strict>>;
35
36
  cssVariable: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodLiteral<false>]>>;
36
37
  }, "value" | "overrides" | "property" | "cssVariable"> & {
37
- value: z.ZodType<string | number | boolean | Ref | DerivedColor | Gradient | {
38
+ value: z.ZodType<string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
38
39
  flexGrow: number;
39
40
  flexShrink: number;
40
41
  flexBasis: string | number;
41
42
  } | {
42
43
  fontSizeMultiplier: number;
43
- }, unknown, z.core.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor | Gradient | {
44
+ }, unknown, z.core.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
44
45
  flexGrow: number;
45
46
  flexShrink: number;
46
47
  flexBasis: string | number;
@@ -49,13 +50,13 @@ declare const NativeToken: EntityClass<z.ZodObject<Omit<{
49
50
  }, unknown>>;
50
51
  overrides: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodObject<{
51
52
  on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
52
- value: z.ZodType<string | number | boolean | Ref | DerivedColor | Gradient | {
53
+ value: z.ZodType<string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
53
54
  flexGrow: number;
54
55
  flexShrink: number;
55
56
  flexBasis: string | number;
56
57
  } | {
57
58
  fontSizeMultiplier: number;
58
- }, unknown, z.core.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor | Gradient | {
59
+ }, unknown, z.core.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
59
60
  flexGrow: number;
60
61
  flexShrink: number;
61
62
  flexBasis: string | number;
@@ -64,7 +65,7 @@ declare const NativeToken: EntityClass<z.ZodObject<Omit<{
64
65
  }, unknown>>;
65
66
  }, z.core.$strip>>, z.ZodTransform<Record<string, {
66
67
  on: OverrideCondition;
67
- value: string | number | boolean | Ref | DerivedColor | Gradient | {
68
+ value: string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
68
69
  flexGrow: number;
69
70
  flexShrink: number;
70
71
  flexBasis: string | number;
@@ -73,7 +74,7 @@ declare const NativeToken: EntityClass<z.ZodObject<Omit<{
73
74
  };
74
75
  }>, {
75
76
  on: OverrideCondition;
76
- value: string | number | boolean | Ref | DerivedColor | Gradient | {
77
+ value: string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
77
78
  flexGrow: number;
78
79
  flexShrink: number;
79
80
  flexBasis: string | number;
@@ -82,13 +83,13 @@ declare const NativeToken: EntityClass<z.ZodObject<Omit<{
82
83
  };
83
84
  }[]>>, SubEntityClass<z.ZodObject<{
84
85
  on: z.ZodType<OverrideCondition, unknown, z.core.$ZodTypeInternals<OverrideCondition, unknown>>;
85
- value: z.ZodType<string | number | boolean | Ref | DerivedColor | Gradient | {
86
+ value: z.ZodType<string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
86
87
  flexGrow: number;
87
88
  flexShrink: number;
88
89
  flexBasis: string | number;
89
90
  } | {
90
91
  fontSizeMultiplier: number;
91
- }, unknown, z.core.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor | Gradient | {
92
+ }, unknown, z.core.$ZodTypeInternals<string | number | boolean | Ref | DerivedColor | Gradient | Shadow | {
92
93
  flexGrow: number;
93
94
  flexShrink: number;
94
95
  flexBasis: string | number;
@@ -1,6 +1,7 @@
1
1
  import { NATIVE_CONFIG_NAME } from "../../configs/platform.js";
2
2
  import { refSchema } from "../../framework/utils/refs.js";
3
3
  import { oklchColor } from "../system/color.js";
4
+ import { shadowValue } from "../system/shadow.js";
4
5
  import { orList } from "../../framework/defineSubEntity.js";
5
6
  import { Font } from "../system/Font.js";
6
7
  import { nativeFlexValue } from "../system/linked-flex-values.js";
@@ -15,7 +16,8 @@ import { z } from "zod";
15
16
  * (`'45deg'`, `'50%'`, a hex or RGB color, `'transparent'`), an alias to another token, a font-family
16
17
  * ref, a derived color (`mix()`/`alpha()` resolve to a concrete color, so they carry), or explicit
17
18
  * native flex declarations (a linked shorthand needs all three longhands), or a relative line
18
- * height resolved against the destination text layer's font size, or a structured linear gradient. What
19
+ * height resolved against the destination text layer's font size, or a structured linear gradient
20
+ * or shadow whose colors resolve with the theme. What
19
21
  * deliberately does not validate is web's open string arm — `'1rem'`, `calc(…)`, `'50vh'` mean
20
22
  * nothing off the web, and refusing them here is the platform model: the config is the platform,
21
23
  * so a native config cannot hold a web value.
@@ -76,6 +78,7 @@ const nativeTokenValue = z.union([
76
78
  Font,
77
79
  nativeDerivedColor,
78
80
  nativeGradient,
81
+ shadowValue,
79
82
  nativeFlexValue,
80
83
  relativeLineHeightValue
81
84
  ]);
@@ -14,7 +14,7 @@ import { listedIn } from "../../framework/utils/enumerated.js";
14
14
  import { valueSchemaOf } from "../../framework/value-domain.js";
15
15
  import { Package } from "./Package.js";
16
16
  import { bindPreviewGlyphs, glyphMemberRefIn } from "./glyph-identity.js";
17
- import { Style, addBagKeyIssues, anatomyPropValue, bagNameEdges, bagRewriteName, bindBagTokens, collectBag, isPlainRecord, nativeStyleArray, openBag, styleValueFor } from "./style-bag.js";
17
+ import { Style, addBagKeyIssues, anatomyPropValue, bagNameEdges, bagRewriteName, bindBagTokens, collectBag, compositeApplication, isPlainRecord, nativeStyleArray, openBag, styleValueFor } from "./style-bag.js";
18
18
  import { storedPreview } from "../../framework/preview-store.js";
19
19
  import { glyphPropsOf, glyphPropsOfBody, propOwner, propValueDomain, refListOf, resolveComponentProps, stylePropNumberUnit, stylePropValueLeaves, validateComponentProps } from "../../framework/projections.js";
20
20
  import { carriesContent, intoName, isValueSlot, renderBoundProp, routedPropIn, routesContent, surfaceProps } from "../../framework/prop-surface.js";
@@ -1063,7 +1063,7 @@ const StyleRule = defineSubEntity({
1063
1063
  const body = parent;
1064
1064
  if (!config || !body) return z.object({
1065
1065
  when: z.record(z.string(), z.unknown()).nullable().default(null),
1066
- layers: z.record(z.string(), z.record(z.string(), z.union([styleValueFor(config), z.never()], { error: "a layer bag value is a style-prop value — a token leaf such as `surface`, a keyword, a bracketed literal such as `[13px]` — or a modifier block holding more of them. Content is not set in a style rule: a glyph or a nested element is an anatomy node under the layer's node, `{ \"element\": { \"__ref\": \"icon:<library>/<Name>\" }, \"visible\": { \"$state\": \"<prop>\", \"eq\": \"<value>\" } }` to show one per variant value." })), { error: ruleShapeError })
1066
+ layers: z.record(z.string(), z.object({ composite: compositeApplication.optional() }).catchall(z.union([styleValueFor(config), z.never()], { error: "a layer bag value is a style-prop value — a token leaf such as `surface`, a keyword, a bracketed literal such as `[13px]` — or a modifier block holding more of them. Content is not set in a style rule: a glyph or a nested element is an anatomy node under the layer's node, `{ \"element\": { \"__ref\": \"icon:<library>/<Name>\" }, \"visible\": { \"$state\": \"<prop>\", \"eq\": \"<value>\" } }` to show one per variant value." })), { error: ruleShapeError })
1067
1067
  }, { error: ruleShapeError });
1068
1068
  return perOwner({
1069
1069
  cache: ruleSchemas,
@@ -1,6 +1,6 @@
1
1
  import { defineEntity } from "../../framework/defineEntity.js";
2
2
  import { translateLinkedStyleBags } from "./linked-style-values.js";
3
- import { Style, bagNameEdges, bagRewriteName, collectBag } from "./style-bag.js";
3
+ import { Style, bagNameEdges, bagRewriteName, collectBag, compositeApplication } from "./style-bag.js";
4
4
  import { z } from "zod";
5
5
  //#region src/entities/system/Composite.ts
6
6
  /** A composite's one bag. Same shape as a component's, so the same hooks read it. */
@@ -18,6 +18,11 @@ const Composite = defineEntity({
18
18
  ...args,
19
19
  bags: compositeBags
20
20
  }),
21
+ layerKeys: { composite: {
22
+ preserveRefs: true,
23
+ schema: () => compositeApplication.describe("Apply one Composite.ref or an ordered list directly to this layer. Later composites win; explicit layer styles win over them. This does not declare a public prop."),
24
+ reach: () => "none"
25
+ } },
21
26
  label: "Composite style",
22
27
  labelPlural: "Composite styles",
23
28
  fields: z.object({ styles: Style.describe("The style values the composite bundles. Each declaration is a member, so an editor writes one key at a time.") }),
@@ -43,8 +43,8 @@ type ModifierGroupMeta = z.infer<typeof modifierGroupFields> & {
43
43
  };
44
44
  declare const ModifierDefinition: EntityClass<z.ZodObject<{
45
45
  type: z.ZodEnum<{
46
- selector: "selector";
47
46
  composite: "composite";
47
+ selector: "selector";
48
48
  "media-query": "media-query";
49
49
  "starting-style": "starting-style";
50
50
  }>;
@@ -0,0 +1,9 @@
1
+ import { Config } from "../../framework/Config.js";
2
+
3
+ //#region src/entities/system/applied-composites.d.ts
4
+ /** Resolve fixed composite selections before emitting CSS, native data or editor values.
5
+ * Later selections win; explicit declarations win over every selection. Modifier blocks merge.
6
+ * References remain in stored config so edits, renames and dependency tracking retain the link. */
7
+ declare function resolveAppliedComposites(config: Config, bag: Record<string, unknown>, ancestry?: readonly string[]): Record<string, unknown>;
8
+ //#endregion
9
+ export { resolveAppliedComposites };
@@ -0,0 +1,47 @@
1
+ import { isRef, kindOf, memberOf, pathOf, sourceOf } from "../../framework/utils/refs.js";
2
+ //#region src/entities/system/applied-composites.ts
3
+ /** Resolve fixed composite selections before emitting CSS, native data or editor values.
4
+ * Later selections win; explicit declarations win over every selection. Modifier blocks merge.
5
+ * References remain in stored config so edits, renames and dependency tracking retain the link. */
6
+ function resolveAppliedComposites(config, bag, ancestry = []) {
7
+ const selection = bag.composite;
8
+ let base = {};
9
+ for (const selected of selection === void 0 ? [] : Array.isArray(selection) ? selection : [selection]) {
10
+ if (!isRef(selected) || kindOf(selected) !== "composite" || memberOf(selected) !== void 0) throw new Error("A layer composite must be a Composite.ref to an item.");
11
+ const path = pathOf(selected);
12
+ const identity = selected.__ref;
13
+ if (ancestry.includes(identity)) throw new Error(`Circular composite application: ${[...ancestry, identity].join(" -> ")}`);
14
+ const slug = sourceOf(selected);
15
+ const body = slug === void 0 || config.configFor(selected) === config ? config.resolve("composite", path)?.toJSON() : config.copyOf({
16
+ slug,
17
+ kind: "composite",
18
+ path
19
+ });
20
+ if (!body) throw new Error(`Cannot apply composite:${path}: expected a composite item.`);
21
+ const { styles = {} } = body;
22
+ base = mergeStyleBags(base, resolveAppliedComposites(config, styles, [...ancestry, identity]));
23
+ }
24
+ const own = {};
25
+ let changed = selection !== void 0;
26
+ for (const [key, value] of Object.entries(bag)) {
27
+ if (key === "composite") continue;
28
+ own[key] = key.startsWith("_") && isPlainBlock(value) ? resolveAppliedComposites(config, value, ancestry) : value;
29
+ changed ||= own[key] !== value;
30
+ }
31
+ return changed ? mergeStyleBags(base, own) : bag;
32
+ }
33
+ /** `over` laid on `base`, with a modifier block (`_md`, `_hover`) merged key by key rather than
34
+ * replaced, so a bag that adds one breakpoint value keeps the composite's others. */
35
+ function mergeStyleBags(base, over) {
36
+ const out = { ...base };
37
+ for (const [key, value] of Object.entries(over)) {
38
+ const prior = out[key];
39
+ out[key] = key.startsWith("_") && isPlainBlock(prior) && isPlainBlock(value) ? mergeStyleBags(prior, value) : value;
40
+ }
41
+ return out;
42
+ }
43
+ function isPlainBlock(value) {
44
+ return typeof value === "object" && value !== null && !isRef(value);
45
+ }
46
+ //#endregion
47
+ export { mergeStyleBags, resolveAppliedComposites };
@@ -16,7 +16,7 @@ import { contentKey } from "../../framework/utils/content-key.js";
16
16
  * The shared compiler/runtime contract. Bump whenever codegen can produce different module bytes
17
17
  * from identical config-visible inputs (shim contracts, entry shape, transforms, and so on).
18
18
  */
19
- const COMPONENT_MODULE_BUILD_VERSION = 6;
19
+ const COMPONENT_MODULE_BUILD_VERSION = 7;
20
20
  /**
21
21
  * Generated web runtime inputs shared by every component module. These are intentionally separate
22
22
  * from the per-file closure: editing an unrelated component should not invalidate this module, but
@@ -1,3 +1,4 @@
1
+ import { Ref } from "../../framework/utils/refs.js";
1
2
  import { SubEntityClass } from "../../framework/defineSubEntity.js";
2
3
  import { RegisteredModifiers, RegisteredStyleProps } from "../../framework/registered.js";
3
4
  import { ComposedValue } from "./composed-values.js";
@@ -16,7 +17,9 @@ import { z } from "zod";
16
17
  */
17
18
  type StyleValue = string | number | boolean | {
18
19
  readonly __ref: string;
19
- } | ComposedValue | readonly (string | number | boolean)[] | {
20
+ } | ComposedValue | readonly (string | number | boolean)[] | readonly {
21
+ readonly __ref: string;
22
+ }[] | {
20
23
  readonly [key: string]: StyleValue;
21
24
  };
22
25
  /**
@@ -32,7 +35,9 @@ type StyleValue = string | number | boolean | {
32
35
  declare const StyleDefinition: SubEntityClass<z.ZodType<StyleValue, unknown, z.core.$ZodTypeInternals<StyleValue, unknown>>>;
33
36
  interface StyleClass extends Named<typeof StyleDefinition> {}
34
37
  /** The style props the system registers, each taking any value a bag stores. */
35
- type RegisteredStyleBag = { [K in keyof RegisteredStyleProps]?: StyleValue };
38
+ type RegisteredStyleBag = { [K in keyof RegisteredStyleProps]?: StyleValue } & {
39
+ composite?: Ref | readonly Ref[];
40
+ };
36
41
  /**
37
42
  * A bag as a config file writes one when nothing but style props and modifiers may key it: the style
38
43
  * props the system registers, and a `_modifier` block of the same. Open until the build has filled
@@ -1,5 +1,5 @@
1
1
  import "../../configs/platform.js";
2
- import { isExtendedRef, isRef, ref, refSchema, splitRef } from "../../framework/utils/refs.js";
2
+ import { isExtendedRef, isRef, kindOf, ref, refSchema, splitRef } from "../../framework/utils/refs.js";
3
3
  import { composedValueSchemas } from "./composed-values.js";
4
4
  import { defineSubEntity } from "../../framework/defineSubEntity.js";
5
5
  import { isCssProperty, kebabCase } from "../../css/values.js";
@@ -8,6 +8,9 @@ import { glyphMemberRefIn, glyphPackageRef } from "./glyph-identity.js";
8
8
  import { glyphPropsOfBody, isCustomPropertyKey, refListOf, stylePropTokenPath } from "../../framework/projections.js";
9
9
  import { z } from "zod";
10
10
  //#region src/entities/system/style-bag.ts
11
+ /** Fixed style composition, separate from the selectable members of a public composite prop. */
12
+ const compositeReference = refSchema.refine((value) => kindOf(value) === "composite", "Expected a Composite.ref to a composite item.");
13
+ const compositeApplication = z.union([compositeReference, z.array(compositeReference)]);
11
14
  /** Literal arrays such as React Native Text fontVariant; element trees remain anatomy. */
12
15
  const nativeStyleArray = z.array(z.union([
13
16
  z.string(),
@@ -25,7 +28,7 @@ function styleValueSchema(arrays) {
25
28
  ...composedValueSchemas,
26
29
  glyphPackageRef,
27
30
  ...arrays ? [nativeStyleArray] : [],
28
- z.record(z.string(), value)
31
+ z.object({ composite: compositeApplication.optional() }).catchall(value)
29
32
  ]));
30
33
  return value;
31
34
  }
@@ -67,7 +70,10 @@ const Style = defineSubEntity({
67
70
  */
68
71
  fields: ({ config, parent, key }) => {
69
72
  const value = styleValueFor(config);
73
+ if (key === "composite") return compositeApplication;
70
74
  if (!config || key === void 0) return styleValue;
75
+ const owned = config.layerKeys().get(key);
76
+ if (owned) return owned.schema(void 0);
71
77
  if (key.startsWith("_")) return openBag(config);
72
78
  const bound = (config, declaration) => z.union([valueSchemaOf(declaration, config), value]);
73
79
  const declared = parent?.props?.[key];
@@ -283,4 +289,4 @@ function openBag(config, { cssBehind = true, values = styleValueFor(config) } =
283
289
  })).transform((bag) => bindBagTokens(config, bag));
284
290
  }
285
291
  //#endregion
286
- export { Style, addBagKeyIssues, anatomyPropValue, bagNameEdges, bagRewriteName, bindBagTokens, camelCase, collectBag, isPlainRecord, nativeStyleArray, openBag, styleValueFor };
292
+ export { Style, addBagKeyIssues, anatomyPropValue, bagNameEdges, bagRewriteName, bindBagTokens, camelCase, collectBag, compositeApplication, isPlainRecord, nativeStyleArray, openBag, styleValueFor };
@@ -73,7 +73,7 @@ interface RecordedSource {
73
73
  * The dense-counter `2` a short-lived scheme stamped before the chain existed reads as the mint
74
74
  * that replaced it (see `detectedWireVersion`).
75
75
  */
76
- declare const SERIALIZED_CONFIG_VERSION = 20261020183330;
76
+ declare const SERIALIZED_CONFIG_VERSION = 20261022124223;
77
77
  interface SerializedConfig {
78
78
  /** See {@link SERIALIZED_CONFIG_VERSION}. Always written; a stored artifact may lack it. */
79
79
  readonly version: number;
@@ -2196,6 +2196,9 @@ declare class Config {
2196
2196
  * Sorted, so anything built from it is deterministic.
2197
2197
  */
2198
2198
  sourceClosure(slug: string, kind?: string): string[];
2199
+ /** Prose mentions remain in the reference graph and saved source data, but do not
2200
+ * require executable copies or runtime dependencies in the consuming system. */
2201
+ private dependencyBody;
2199
2202
  /** References used after local overrides; sourceClosure also preserves the original bases. */
2200
2203
  runtimeSourceClosure({
2201
2204
  slug,
@@ -4431,6 +4431,12 @@ var Config = class Config {
4431
4431
  cache.set(slug, targets);
4432
4432
  return kind === void 0 ? targets : targets.filter((target) => kindOf(target) === kind);
4433
4433
  }
4434
+ /** Prose mentions remain in the reference graph and saved source data, but do not
4435
+ * require executable copies or runtime dependencies in the consuming system. */
4436
+ dependencyBody(kind, body) {
4437
+ const mentions = this.entityOf(kind)?.mentionFields;
4438
+ return mentions?.length ? Object.fromEntries(Object.entries(body).filter(([key]) => !mentions.includes(key))) : body;
4439
+ }
4434
4440
  /** References used after local overrides; sourceClosure also preserves the original bases. */
4435
4441
  runtimeSourceClosure({ slug, kind }) {
4436
4442
  let targets = this.caches.runtimeClosures.get(slug);
@@ -4465,7 +4471,7 @@ var Config = class Config {
4465
4471
  queue.push(`${kindOf(target)}:${pathOf(target)}`);
4466
4472
  }
4467
4473
  }
4468
- for (const item of this.list(owned)) for (const target of collectRefs(item.toJSON())) {
4474
+ for (const item of this.list(owned)) for (const target of collectRefs(includeExtensionBases ? item.toJSON() : this.dependencyBody(owned, item.toJSON()))) {
4469
4475
  if (sourceOf(target) !== slug) continue;
4470
4476
  queue.push(`${kindOf(target)}:${pathOf(target)}`);
4471
4477
  }
@@ -4485,7 +4491,7 @@ var Config = class Config {
4485
4491
  for (const member of source.members(kindOf(target), pathOf(target))) queue.push(`${kindOf(target)}:${member.path}`);
4486
4492
  continue;
4487
4493
  }
4488
- for (const nested of collectRefs(entity.toJSON())) {
4494
+ for (const nested of collectRefs(includeExtensionBases ? entity.toJSON() : source.dependencyBody(kindOf(target), entity.toJSON()))) {
4489
4495
  if (sourceOf(nested) !== void 0) continue;
4490
4496
  queue.push(`${kindOf(nested)}:${pathOf(nested)}`);
4491
4497
  }
@@ -5072,7 +5078,7 @@ var Config = class Config {
5072
5078
  }
5073
5079
  };
5074
5080
  const visitEntity = (kind, body, theirs = false, linked = false) => {
5075
- visit(body, theirs, linked);
5081
+ visit((theirs ? source : this).dependencyBody(kind, body), theirs, linked);
5076
5082
  if (theirs) visitBags(kind, body, linked);
5077
5083
  };
5078
5084
  /**
@@ -5867,7 +5873,7 @@ var Config = class Config {
5867
5873
  * links from the provided sources. A declared `linkedKind` with no provided source throws. */
5868
5874
  hydrateFrom(stored, options) {
5869
5875
  const claimed = schemaVersionOf(stored);
5870
- if (claimed > 20261020183330) throw new SchemaVersionTooNew(claimed);
5876
+ if (claimed > 20261022124223) throw new SchemaVersionTooNew(claimed);
5871
5877
  const wire = upgradeSerializedConfig(stored);
5872
5878
  if (!Array.isArray(wire.ownedKinds) || typeof wire.items !== "object" || wire.items === null) throw new ConfigFormatError(`Config "${stored.name ?? "system-config"}" cannot be hydrated: this is not a serialized config-v2 config (no "ownedKinds"/"items"). A pre-cutover build artifact converts through the registered cutover migration — import the config type's module (e.g. \`configs/system\`) before hydrating.`);
5873
5879
  const leftover = wire.options;
@@ -206,7 +206,7 @@ declare function componentPropComposites(config: Config, path: string, state?: R
206
206
  * `element` is the layer's element. A key is a composite when the element declares it as one, so a
207
207
  * plain-tag layer (which declares nothing) and a key naming no member are left as they are.
208
208
  */
209
- declare function inlineRuleComposites(config: Config, element: unknown, bag: Record<string, unknown>): Record<string, unknown>;
209
+ declare function inlineRuleComposites(config: Config, element: unknown, authored: Record<string, unknown>): Record<string, unknown>;
210
210
  /**
211
211
  * The props a style rule's bag sends to each layer's ELEMENT rather than to the stylesheet, for one
212
212
  * instance. The same split the emitted module makes when it builds a layer's routed bundle.
@@ -6,6 +6,7 @@ import "./component-states.js";
6
6
  import { storedPreview } from "./preview-store.js";
7
7
  import { authoredValue, className, isCustomPropertyKey, negatedCssValue, renderStyleValue, resolveComponentProps, stylePropEntries, stylePropLeafForToken, stylePropNumberLeaf, stylePropNumberUnit, stylePropValueLeaves, stylePropertyPathFor } from "./projections.js";
8
8
  import { inlineMotionId, isInlineMotion, jsMotionBody } from "../entities/system/motion-variants.js";
9
+ import { mergeStyleBags, resolveAppliedComposites } from "../entities/system/applied-composites.js";
9
10
  import { ruleApplies } from "./layer-styles.js";
10
11
  //#region src/framework/class-names.ts
11
12
  /**
@@ -524,7 +525,8 @@ const compositePropsCache = createSliceMemo({
524
525
  * `element` is the layer's element. A key is a composite when the element declares it as one, so a
525
526
  * plain-tag layer (which declares nothing) and a key naming no member are left as they are.
526
527
  */
527
- function inlineRuleComposites(config, element, bag) {
528
+ function inlineRuleComposites(config, element, authored) {
529
+ const bag = resolveAppliedComposites(config, authored);
528
530
  if (!isRef(element)) return bag;
529
531
  const declared = resolveComponentProps(config, pathOf(element.__ref));
530
532
  let inlined;
@@ -549,19 +551,6 @@ function inlineRuleComposites(config, element, bag) {
549
551
  }
550
552
  return inlined ? mergeStyleBags(inlined, rest) : bag;
551
553
  }
552
- /** `over` laid on `base`, with a modifier block (`_md`, `_hover`) merged key by key rather than
553
- * replaced, so a bag that adds one breakpoint value keeps the composite's others. */
554
- function mergeStyleBags(base, over) {
555
- const out = { ...base };
556
- for (const [key, value] of Object.entries(over)) {
557
- const prior = out[key];
558
- out[key] = key.startsWith("_") && isPlainBlock(prior) && isPlainBlock(value) ? mergeStyleBags(prior, value) : value;
559
- }
560
- return out;
561
- }
562
- function isPlainBlock(value) {
563
- return typeof value === "object" && value !== null && !isRef(value);
564
- }
565
554
  /**
566
555
  * The props a style rule's bag sends to each layer's ELEMENT rather than to the stylesheet, for one
567
556
  * instance. The same split the emitted module makes when it builds a layer's routed bundle.
@@ -1,6 +1,27 @@
1
1
  import { isRef, refLeaf } from "./utils/refs.js";
2
2
  import { authoredBag } from "./projections.js";
3
+ import { resolveAppliedComposites } from "../entities/system/applied-composites.js";
3
4
  //#region src/framework/layer-styles.ts
5
+ /**
6
+ * What each of a component's layers is STYLED WITH, for one instance.
7
+ *
8
+ * The class projection ({@link componentRuleClasses}) answers the same question in the form a
9
+ * stylesheet needs — which classes go on which element. This answers it in the form a person needs:
10
+ * the property values themselves, per layer, so a properties panel can show that this layer's padding
11
+ * is `3` and a matrix cell can paint a variant it has no compiled classes for yet.
12
+ *
13
+ * Both read the component's `styles` and the same condition test, so they cannot disagree about which
14
+ * rules apply — which is the whole reason this lives here rather than being re-derived per surface.
15
+ *
16
+ * Unconditional rules sit at zero specificity in `:where()`. Every conditional rule emits ONE
17
+ * class selector, whether its condition names one prop or several. Conditional rules therefore
18
+ * tie at that level and retain authored order; counting props would disagree with the stylesheet.
19
+ *
20
+ * A forced state weighs what its stylesheet twin does: each interaction a rule's condition names,
21
+ * and each forced block a value sits under, adds one attribute's worth on top of the rule's own.
22
+ * So `variant=secondary`'s `_active` block beats a later `active=true&variant=secondary` rule, as
23
+ * `.x-variant-secondary:active` beats `.x-active-true-variant-secondary` in the sheet.
24
+ */
4
25
  /** Native component rules' ordering. CSS gives every conditional rule one class selector; only
5
26
  * unconditional `:where()` rules rank lower. Stable sorting preserves authored order among
6
27
  * conditions with different numbers of props. */
@@ -73,7 +94,7 @@ function layerStyles(config, path, props = {}, options = {}) {
73
94
  Object.values(styles).forEach((rule, index) => {
74
95
  if (!ruleApplies(rule.when, state)) return;
75
96
  for (const [layer, bag] of Object.entries(rule.layers ?? {})) collectBag({
76
- bag: authoredBag(config, bag ?? {}),
97
+ bag: authoredBag(config, resolveAppliedComposites(config, bag ?? {})),
77
98
  forced,
78
99
  specificity: ruleSpecificity(rule.when),
79
100
  push: (key, value, specificity) => declarations.push({
@@ -770,6 +770,7 @@ function authoredValue(config, key, value) {
770
770
  return authoredLeaf(config, key, value.__ref) ?? value;
771
771
  }
772
772
  function authoredLeaf(config, key, stored) {
773
+ if (config.layerKeys().get(key)?.preserveRefs) return void 0;
773
774
  const path = pathOf(stored);
774
775
  if (kindOf(stored) === "token" && config.resolve("style-property", key) !== void 0) return stylePropLeafForToken(config, key, path);
775
776
  if (kindOf(stored) === "motion") return path;
@@ -52,6 +52,8 @@ type AuthoredValueForm = (ctx: {
52
52
  * style property: `motion` names a preset, `reducedMotion` says how the layer treats the OS setting.
53
53
  */
54
54
  interface LayerKey {
55
+ /** Keep authored references intact rather than reading them as selectable prop leaves. */
56
+ readonly preserveRefs?: boolean;
55
57
  /** What the key takes. `declared` is the element's own prop of the same name, where it declares
56
58
  * one, which the key's value can also be. */
57
59
  readonly schema: (declared: z.ZodTypeAny | undefined) => z.ZodTypeAny;
@@ -15,7 +15,7 @@ import { Patch, SerializedConfig } from "./Config.js";
15
15
  * sets this constant to its own older timestamp; the merge ref then carries a registered migration
16
16
  * newer than the constant, and the assertion fails until the author re-mints.
17
17
  */
18
- declare const CURRENT_SCHEMA_VERSION = 20261020183330;
18
+ declare const CURRENT_SCHEMA_VERSION = 20261022124223;
19
19
  /** What the walkers need to see of an envelope — loose on purpose, so a typed `SerializedConfig`
20
20
  * and a raw old-shape record both flow in without casts. */
21
21
  interface VersionStamped {
@@ -13,7 +13,7 @@ import { ConfigFormatError } from "./rejection.js";
13
13
  * sets this constant to its own older timestamp; the merge ref then carries a registered migration
14
14
  * newer than the constant, and the assertion fails until the author re-mints.
15
15
  */
16
- const CURRENT_SCHEMA_VERSION = 20261020183330;
16
+ const CURRENT_SCHEMA_VERSION = 20261022124223;
17
17
  /** The mint that moved `options` into the `settings` kind — restated here, rather than imported
18
18
  * from the migration that owns it, because that migration imports this module. */
19
19
  const SETTINGS_AS_KIND_VERSION = 20260908171448;
@@ -45,7 +45,7 @@ function registerSchemaMigrations(...migrations) {
45
45
  for (const migration of migrations) {
46
46
  if (migration.version !== 1 && !isMintTimestamp(migration.version)) throw new Error(`Schema migration version ${migration.version} is not a mint timestamp — mint one with \`date +%Y%m%d%H%M%S\`, like a supabase migration.`);
47
47
  if (REGISTERED.has(migration.version)) throw new Error(`A schema migration at version ${migration.version} is already registered.`);
48
- if (migration.version > 20261020183330) throw new Error(`Schema migration ${migration.version} is newer than CURRENT_SCHEMA_VERSION (${CURRENT_SCHEMA_VERSION}) — a stale branch merged, or the mint forgot to bump the constant. Re-mint: set CURRENT_SCHEMA_VERSION to the newest migration version.`);
48
+ if (migration.version > 20261022124223) throw new Error(`Schema migration ${migration.version} is newer than CURRENT_SCHEMA_VERSION (${CURRENT_SCHEMA_VERSION}) — a stale branch merged, or the mint forgot to bump the constant. Re-mint: set CURRENT_SCHEMA_VERSION to the newest migration version.`);
49
49
  REGISTERED.set(migration.version, migration);
50
50
  }
51
51
  }
@@ -102,7 +102,7 @@ function pendingFor(version, target, options) {
102
102
  * Already-current input passes through untouched — same reference, so hot paths pay nothing.
103
103
  */
104
104
  function upgradeSerializedConfig(json, options) {
105
- const target = options?.target ?? 20261020183330;
105
+ const target = options?.target ?? 20261022124223;
106
106
  const version = detectedWireVersion(json);
107
107
  if (version > target) throw new SchemaVersionTooNew(version, target);
108
108
  const raw = json;
@@ -160,7 +160,7 @@ function upgradedSources(json, options) {
160
160
  * meaning under the current schema and replay skips it — reported by the caller, not swallowed here.
161
161
  */
162
162
  function upgradePatch(patch, writtenAt, options) {
163
- const target = options?.target ?? 20261020183330;
163
+ const target = options?.target ?? 20261022124223;
164
164
  if (writtenAt > target) throw new SchemaVersionTooNew(writtenAt, target);
165
165
  let current = patch;
166
166
  for (const migration of pendingFor(writtenAt, target, options)) {
@@ -179,7 +179,7 @@ function upgradePatch(patch, writtenAt, options) {
179
179
  * stamp would cause.
180
180
  */
181
181
  function upgradeDraftEntries(draft, options) {
182
- const target = options?.target ?? 20261020183330;
182
+ const target = options?.target ?? 20261022124223;
183
183
  const entries = [];
184
184
  const held = [];
185
185
  const retired = [];