@yahoo/uds-create-config 5.54.0 → 5.55.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/capture/node-ops.js +1 -1
  2. package/dist/configs/system.js +2 -0
  3. package/dist/entities/canvas/node-gestures.js +1 -1
  4. package/dist/entities/canvas/node-patches.js +1 -1
  5. package/dist/entities/system/Component.d.ts +5 -2
  6. package/dist/entities/system/Component.js +142 -16
  7. package/dist/entities/system/LinkedSystem.js +2 -2
  8. package/dist/entities/system/Operation.js +1 -1
  9. package/dist/entities/system/component-forwards.js +1 -1
  10. package/dist/entities/system/component-module.js +9 -9
  11. package/dist/entities/system/component-source-fields.js +1 -1
  12. package/dist/entities/system/component-style-set.js +1 -1
  13. package/dist/entities/system/conditional-defaults.d.ts +45 -0
  14. package/dist/entities/system/conditional-defaults.js +142 -0
  15. package/dist/entities/system/copy-plan.js +1 -1
  16. package/dist/entities/system/css-motion-reach.js +1 -1
  17. package/dist/entities/system/defineComponent.d.ts +11 -2
  18. package/dist/entities/system/defineComponent.js +3 -0
  19. package/dist/entities/system/link-plan.js +1 -1
  20. package/dist/entities/system/motion-convert.js +1 -1
  21. package/dist/entities/system/motion-variants.js +2 -2
  22. package/dist/framework/Config.d.ts +1 -1
  23. package/dist/framework/Config.js +21 -5
  24. package/dist/framework/class-names.js +18 -6
  25. package/dist/framework/default-conditions.d.ts +26 -0
  26. package/dist/framework/default-conditions.js +35 -0
  27. package/dist/framework/defineEntity.js +1 -1
  28. package/dist/framework/inline-sources.js +1 -1
  29. package/dist/framework/layer-styles.js +25 -3
  30. package/dist/framework/memo.d.ts +2 -2
  31. package/dist/framework/memo.js +7 -1
  32. package/dist/framework/plan.js +1 -1
  33. package/dist/framework/projections.js +18 -5
  34. package/dist/framework/prop-surface.d.ts +1 -0
  35. package/dist/framework/prop-surface.js +13 -0
  36. package/dist/framework/render-spec.d.ts +3 -16
  37. package/dist/framework/render-spec.js +10 -2
  38. package/dist/framework/schema-version.d.ts +1 -1
  39. package/dist/framework/schema-version.js +5 -5
  40. package/dist/framework/schemas.js +2 -2
  41. package/dist/framework/source-integrity.js +1 -1
  42. package/dist/index.d.ts +4 -2
  43. package/dist/index.js +5 -3
  44. package/dist/migrations/20261023152030_conditional_defaults.d.ts +6 -0
  45. package/dist/migrations/20261023152030_conditional_defaults.js +8 -0
  46. package/dist/spec/bake.js +14 -6
  47. package/dist/spec/cell.d.ts +2 -1
  48. package/dist/spec/cell.js +14 -6
  49. package/dist/spec/detach.js +5 -1
  50. package/dist/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
- import { rejectData } from "../framework/rejection.js";
2
1
  import { pathOf } from "../framework/utils/refs.js";
2
+ import { rejectData } from "../framework/rejection.js";
3
3
  import { pathInput } from "../framework/schemas.js";
4
4
  import { CapturedNode } from "./captured-tree.js";
5
5
  import { specFromCapture } from "./capture-to-spec.js";
@@ -29,6 +29,7 @@ import { lintSettingsMigration } from "../migrations/20261020183330_lint_setting
29
29
  import { directLayerCompositesMigration } from "../migrations/20261022124223_direct_layer_composites.js";
30
30
  import { cssContentScriptsMigration } from "../migrations/20261022152120_css_content_scripts.js";
31
31
  import { linkTypeMigration } from "../migrations/20261022184639_link_type.js";
32
+ import { conditionalDefaultsMigration } from "../migrations/20261023152030_conditional_defaults.js";
32
33
  import { CanvasRole } from "../entities/system/CanvasRole.js";
33
34
  import { GlobalStyle } from "../entities/system/GlobalStyle.js";
34
35
  import { Guidance } from "../entities/system/Guidance.js";
@@ -191,5 +192,6 @@ if (!registeredSchemaMigrations().has(20261020183330)) {
191
192
  }
192
193
  if (!registeredSchemaMigrations().has(20261022152120)) registerSchemaMigrations(cssContentScriptsMigration);
193
194
  if (!registeredSchemaMigrations().has(20261022184639)) registerSchemaMigrations(linkTypeMigration);
195
+ if (!registeredSchemaMigrations().has(20261023152030)) registerSchemaMigrations(conditionalDefaultsMigration);
194
196
  //#endregion
195
197
  export { System };
@@ -1,5 +1,5 @@
1
- import { rejectData } from "../../framework/rejection.js";
2
1
  import { pathOf, ref } from "../../framework/utils/refs.js";
2
+ import { rejectData } from "../../framework/rejection.js";
3
3
  import { pathInput } from "../../framework/schemas.js";
4
4
  import { childrenPolicy } from "../system/element.js";
5
5
  import { surfaceProps } from "../../framework/prop-surface.js";
@@ -1,5 +1,5 @@
1
- import { rejectData } from "../../framework/rejection.js";
2
1
  import { ref } from "../../framework/utils/refs.js";
2
+ import { rejectData } from "../../framework/rejection.js";
3
3
  //#region src/entities/canvas/node-patches.ts
4
4
  /**
5
5
  * A spec as the node rows of one new placed node. A placed node's content is its subtree rows, one
@@ -9,10 +9,11 @@ import { Named } from "../../framework/named.js";
9
9
  import { PackageClass } from "./Package.js";
10
10
  import { StyleClass } from "./style-bag.js";
11
11
  import { TokenClass } from "./Token.js";
12
+ import { StoredDefaultCondition } from "../../framework/default-conditions.js";
12
13
  import { StoredPreviewCondition } from "../../framework/preview-store.js";
13
14
  import { RepeatSpec } from "../../framework/render-spec.js";
14
15
  import { ComponentSourceInput } from "./component-source-fields.js";
15
- import { AsInput, DefaultsOf, LayerMap, PhantomCallProps, PhantomReadProps, PropMap, RenderArgs, StateMap, StyleRuleInput } from "./defineComponent.js";
16
+ import { AsInput, AuthoredDefaultsOf, LayerMap, PhantomCallProps, PhantomReadProps, PropMap, RenderArgs, StateMap, StyleRuleInput } from "./defineComponent.js";
16
17
  import { listSlots, namedSlots, slotHostedBy, slotOf, slotsFor } from "../../spec/slot.js";
17
18
  import { cellAt } from "../../spec/cell.js";
18
19
  import { instanceAt } from "../../spec/instance.js";
@@ -658,6 +659,7 @@ declare const componentFields: z.ZodObject<{
658
659
  renderProps: z.ZodOptional<z.ZodArray<z.ZodString>>;
659
660
  anatomy: z.ZodOptional<AnatomyNodeClass>;
660
661
  defaultProps: z.ZodOptional<StyleClass>;
662
+ defaultPropsWhen: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodType<StoredDefaultCondition, unknown, z.core.$ZodTypeInternals<StoredDefaultCondition, unknown>>>, z.ZodTransform<Record<string, StoredDefaultCondition>, StoredDefaultCondition[]>>, SubEntityClass<z.ZodType<StoredDefaultCondition, unknown, z.core.$ZodTypeInternals<StoredDefaultCondition, unknown>>>]>>;
661
663
  preview: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodType<StoredPreviewCondition, unknown, z.core.$ZodTypeInternals<StoredPreviewCondition, unknown>>>, z.ZodTransform<Record<string, StoredPreviewCondition>, StoredPreviewCondition[]>>, SubEntityClass<z.ZodType<StoredPreviewCondition, unknown, z.core.$ZodTypeInternals<StoredPreviewCondition, unknown>>>]>>;
662
664
  file: z.ZodOptional<z.ZodObject<{
663
665
  __ref: z.ZodString;
@@ -699,6 +701,7 @@ declare const ComponentEntity: EntityClass<z.ZodObject<{
699
701
  renderProps: z.ZodOptional<z.ZodArray<z.ZodString>>;
700
702
  anatomy: z.ZodOptional<AnatomyNodeClass>;
701
703
  defaultProps: z.ZodOptional<StyleClass>;
704
+ defaultPropsWhen: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodType<StoredDefaultCondition, unknown, z.core.$ZodTypeInternals<StoredDefaultCondition, unknown>>>, z.ZodTransform<Record<string, StoredDefaultCondition>, StoredDefaultCondition[]>>, SubEntityClass<z.ZodType<StoredDefaultCondition, unknown, z.core.$ZodTypeInternals<StoredDefaultCondition, unknown>>>]>>;
702
705
  preview: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodArray<z.ZodType<StoredPreviewCondition, unknown, z.core.$ZodTypeInternals<StoredPreviewCondition, unknown>>>, z.ZodTransform<Record<string, StoredPreviewCondition>, StoredPreviewCondition[]>>, SubEntityClass<z.ZodType<StoredPreviewCondition, unknown, z.core.$ZodTypeInternals<StoredPreviewCondition, unknown>>>]>>;
703
706
  file: z.ZodOptional<z.ZodObject<{
704
707
  __ref: z.ZodString;
@@ -954,7 +957,7 @@ type ComponentReference<Contract = ComponentContractOf<string>, Path extends str
954
957
  /** An extension's `defaultProps`, checked against the props it ends up with the way
955
958
  * `defineComponent` checks its own: a declared prop takes its values, and any other key stays open. */
956
959
  type ExtensionDefaults<Contract, Delta> = {
957
- readonly defaultProps?: DefaultsOf<ResolvedProps<Contract, Delta>>;
960
+ readonly defaultProps?: AuthoredDefaultsOf<ResolvedProps<Contract, Delta>>;
958
961
  };
959
962
  /**
960
963
  * Two style rules with the same condition, as the one rule they are: each layer's bag merged, the
@@ -1,7 +1,8 @@
1
1
  import "../../configs/platform.js";
2
- import { reject, rejectData } from "../../framework/rejection.js";
3
- import { canonicalCondition, collectRefs, isRef, kindOf, memberRef, pathOf, ref, refLeaf, refSchema, sourceOf, splitRef } from "../../framework/utils/refs.js";
4
2
  import { isPlainObject } from "../../framework/utils/field-path.js";
3
+ import { canonicalCondition, collectRefs, isRef, kindOf, memberRef, pathOf, ref, refLeaf, refSchema, sourceOf, splitRef } from "../../framework/utils/refs.js";
4
+ import { storedDefaultConditions } from "../../framework/default-conditions.js";
5
+ import { reject, rejectData } from "../../framework/rejection.js";
5
6
  import { pathInput } from "../../framework/schemas.js";
6
7
  import { derivedColor, gradient, oklchColor } from "./color.js";
7
8
  import { shadowValue } from "./shadow.js";
@@ -26,6 +27,7 @@ import { instanceAt } from "../../spec/instance.js";
26
27
  import { forwardOptions, forwardsWrite } from "./component-forwards.js";
27
28
  import { assertComponentSourceInput } from "./component-source-fields.js";
28
29
  import { checkStyleSet, styleSetEdits } from "./component-style-set.js";
30
+ import { storedDefaults } from "./conditional-defaults.js";
29
31
  import { forwardRouteInvariants, refusedRoutes } from "./forward-route-invariants.js";
30
32
  import { iconDomainInvariants } from "./icon-domain-invariants.js";
31
33
  import { rootLayerInvariants } from "./root-layer-invariants.js";
@@ -346,8 +348,16 @@ const VariantValue = defineSubEntity({
346
348
  * which takes its styling with it. */
347
349
  deprecated: z.boolean().optional()
348
350
  }),
349
- namedValuesIn: ["defaultProps", "preview/*/props"],
350
- orphans: ["styles", "preview"]
351
+ namedValuesIn: [
352
+ "defaultProps",
353
+ "preview/*/props",
354
+ "defaultPropsWhen/*/props"
355
+ ],
356
+ orphans: [
357
+ "styles",
358
+ "preview",
359
+ "defaultPropsWhen"
360
+ ]
351
361
  });
352
362
  /**
353
363
  * A variant's domain: the values it owns, a ref that delegates to whatever owns them, or a list of
@@ -557,8 +567,16 @@ const Prop = defineSubEntity({
557
567
  namespaces: "value",
558
568
  namesMembersOf: { when: "props" },
559
569
  subEntities: { value: VariantValue },
560
- keyedByNameIn: ["defaultProps", "preview/*/props"],
561
- orphans: ["styles", "preview"]
570
+ keyedByNameIn: [
571
+ "defaultProps",
572
+ "preview/*/props",
573
+ "defaultPropsWhen/*/props"
574
+ ],
575
+ orphans: [
576
+ "styles",
577
+ "preview",
578
+ "defaultPropsWhen"
579
+ ]
562
580
  });
563
581
  /** {@link Prop}'s per-owner schema. Reached only through the memo in its `fields`. */
564
582
  function propSchemaFor(config, owner) {
@@ -737,6 +755,17 @@ function withNone(value, declaration) {
737
755
  if (declaration?.required === true) return value;
738
756
  return z.union([value, z.literal(false)]);
739
757
  }
758
+ /** Optional values build their domain on first use, not while the bag enumerates its keys. */
759
+ function optionalBagValue(build) {
760
+ let schema;
761
+ return z.unknown().transform((input, ctx) => {
762
+ schema ??= build();
763
+ const result = schema.safeParse(input);
764
+ if (result.success) return result.data;
765
+ for (const issue of result.error.issues) ctx.addIssue({ ...issue });
766
+ return z.NEVER;
767
+ }).optional();
768
+ }
740
769
  /** One element's bag, built. Reached only through the memo above. */
741
770
  function buildBagFor(config, layerElement) {
742
771
  const shape = { ...stylePropShape(config) };
@@ -744,13 +773,15 @@ function buildBagFor(config, layerElement) {
744
773
  const glyphProps = component ? glyphPropsOf(config, component) : {};
745
774
  for (const [name, decl] of Object.entries(component ? resolveComponentProps(config, component) : {})) {
746
775
  const forwarded = decl?.type === "forward";
747
- const value = styleBagValue({
748
- config,
749
- declaration: decl,
750
- name,
751
- glyphLibraries: forwarded ? glyphProps[name] : void 0
776
+ shape[name] = optionalBagValue(() => {
777
+ const value = styleBagValue({
778
+ config,
779
+ declaration: decl,
780
+ name,
781
+ glyphLibraries: forwarded ? glyphProps[name] : void 0
782
+ });
783
+ return forwarded ? withNone(value, decl) : value;
752
784
  });
753
- shape[name] = (forwarded ? withNone(value, decl) : value).optional();
754
785
  }
755
786
  const declared = component ? (config.resolve("component", component)?.toJSON())?.props ?? {} : {};
756
787
  for (const [name, decl] of Object.entries(declared)) {
@@ -801,14 +832,14 @@ function stylePropShape(config) {
801
832
  const cached = stylePropShapes.get(config);
802
833
  if (cached) return cached;
803
834
  const shape = {};
804
- for (const prop of config.list("style-property")) shape[prop.path] = styleBagValue({
835
+ for (const prop of config.list("style-property")) shape[prop.path] = optionalBagValue(() => styleBagValue({
805
836
  config,
806
837
  declaration: {
807
838
  type: "styleProperty",
808
839
  value: { __ref: `style-property:${prop.path}` }
809
840
  },
810
841
  name: prop.path
811
- }).optional();
842
+ }));
812
843
  stylePropShapes.set(config, shape);
813
844
  return shape;
814
845
  }
@@ -1168,6 +1199,61 @@ const Preview = defineSubEntity({
1168
1199
  });
1169
1200
  }
1170
1201
  });
1202
+ const DEFAULT_CONDITIONS_DESCRIPTION = "Defaults that hold only under a condition on this component's other props, laid over `defaultProps` the way a style rule is over the unconditional one: a list of entries, each identified by its condition. `{ \"when\": { \"modal\": false }, \"props\": { \"includeScrim\": false } }` defaults `includeScrim` to `false` while `modal` is `false`, and to its `defaultProps` value otherwise. When several entries hold, the later one wins on the prop it sets. Both sides name the component's own variant, string, number or boolean props, a prop set here is never part of a condition, and a value the call site passes always wins. Authored as `conditionalDefault(fallback, [{ when, value }])` inside `.defaultProps`.";
1203
+ const defaultConditionShapeError = "a conditional default is `{ \"when\": { \"<prop>\": <value> }, \"props\": { \"<prop>\": <value> } }`: both name this component's own variant, string, number or boolean props (not `as`), `when` at one of their values.";
1204
+ const defaultConditionBase = z.object({
1205
+ when: z.record(z.string(), z.unknown()),
1206
+ props: z.record(z.string(), z.unknown())
1207
+ });
1208
+ const defaultConditionSchemas = /* @__PURE__ */ new WeakMap();
1209
+ /** The props a conditional default may set or condition on: the component's own scalar props, the
1210
+ * ones its module binds and tests. `as` decides the element, so it never depends on another prop. */
1211
+ function conditionallyDefaultable(props) {
1212
+ return Object.entries(props ?? {}).filter(([name, decl]) => {
1213
+ const type = decl?.type;
1214
+ return name !== "as" && (type === "variant" || type === "string" || type === "number" || type === "boolean");
1215
+ });
1216
+ }
1217
+ /** Whether a conditional default sets nothing: its `props` are empty. */
1218
+ function defaultConditionSetsNothing(entry) {
1219
+ const props = entry?.props;
1220
+ return !props || Object.keys(props).length === 0;
1221
+ }
1222
+ const DefaultCondition = defineSubEntity({
1223
+ name: "defaultCondition",
1224
+ label: "Conditional default",
1225
+ labelPlural: "Conditional defaults",
1226
+ key: (entry) => canonicalWhen(entry?.when),
1227
+ vacant: defaultConditionSetsNothing,
1228
+ namesMembersOf: { when: "props" },
1229
+ base: defaultConditionBase,
1230
+ fields: ({ config, parent }) => {
1231
+ const body = parent;
1232
+ if (!config || !body) return defaultConditionBase;
1233
+ return perOwner({
1234
+ cache: defaultConditionSchemas,
1235
+ config,
1236
+ owner: body,
1237
+ build: () => {
1238
+ const styleField = Style.fields;
1239
+ const when = {};
1240
+ const props = {};
1241
+ for (const [name, decl] of conditionallyDefaultable(body.props)) {
1242
+ when[name] = conditionValue(name, decl, config).optional();
1243
+ props[name] = styleField({
1244
+ config,
1245
+ parent: body,
1246
+ key: name
1247
+ }).optional();
1248
+ }
1249
+ return z.strictObject({
1250
+ when: z.strictObject(when, { error: defaultConditionShapeError }).refine((value) => Object.keys(value).length > 0, { error: "a conditional default holds under a condition; an unconditional one belongs in `defaultProps`." }),
1251
+ props: z.strictObject(props, { error: defaultConditionShapeError })
1252
+ }, { error: defaultConditionShapeError });
1253
+ }
1254
+ });
1255
+ }
1256
+ });
1171
1257
  /** Why a slot refuses an element, for a write the config turns away. */
1172
1258
  function slotRefusal({ slot, element }) {
1173
1259
  const named = isRef(element) ? element.__ref : String(element);
@@ -1724,6 +1810,9 @@ const componentFields = z.strictObject({
1724
1810
  renderProps: z.array(z.string()).optional().describe("Props the render reads beyond those declared, read off the source at build. Not authored: declare a prop in `props` instead."),
1725
1811
  anatomy: AnatomyNode.optional().describe("The tree of what this component renders, keyed by node. Each node names what it renders (a layer, for anything a style rule reaches) and lists its `children`; the node keyed `root` is the top. A one-layer component may omit it. Anatomy read from an extension's own source file replaces the inherited tree; edits to a borrowed render merge into its tree."),
1726
1812
  defaultProps: Style.optional(),
1813
+ /** The defaults that hold only under a condition on the component's other props — see
1814
+ * `conditionalDefault`. */
1815
+ defaultPropsWhen: orList(DefaultCondition).optional().describe(DEFAULT_CONDITIONS_DESCRIPTION),
1727
1816
  /** What the tile and the matrix render with — see `preview({ defaultProps, when })`. Read off
1728
1817
  * `.preview()` at build, and written per cell from the matrix. */
1729
1818
  preview: orList(Preview).optional().describe(PREVIEW_DESCRIPTION),
@@ -1769,6 +1858,39 @@ const componentFields = z.strictObject({
1769
1858
  message: `\`${name}\` conditions on itself. \`when\` names a sibling prop and one of its values.`
1770
1859
  });
1771
1860
  }
1861
+ const conditions = storedDefaultConditions(body);
1862
+ const defaulted = new Set(Object.values(conditions).flatMap(({ props }) => Object.keys(props ?? {})));
1863
+ const defaultable = new Set(conditionallyDefaultable(body.props).map(([name]) => name));
1864
+ for (const [key, { when, props }] of Object.entries(conditions)) {
1865
+ for (const [field, names] of [["when", Object.keys(when ?? {})], ["props", Object.keys(props ?? {})]]) for (const name of names) {
1866
+ if (defaultable.has(name)) continue;
1867
+ ctx.issues.push({
1868
+ code: "custom",
1869
+ input: field === "when" ? when : props,
1870
+ path: [
1871
+ "defaultPropsWhen",
1872
+ key,
1873
+ field,
1874
+ name
1875
+ ],
1876
+ message: `\`${name}\` isn't one of this component's own variant, string, number or boolean props, so a conditional default can't name it. ${defaultConditionShapeError}`
1877
+ });
1878
+ }
1879
+ for (const name of Object.keys(when ?? {})) {
1880
+ if (!defaulted.has(name)) continue;
1881
+ ctx.issues.push({
1882
+ code: "custom",
1883
+ input: when,
1884
+ path: [
1885
+ "defaultPropsWhen",
1886
+ key,
1887
+ "when",
1888
+ name
1889
+ ],
1890
+ message: `\`${name}\` has a conditional default of its own, so it can't be part of a condition. Condition on the props it depends on instead.`
1891
+ });
1892
+ }
1893
+ }
1772
1894
  if (isPlainObject(body.states) && Object.keys(body.states).length > 0) {
1773
1895
  const props = isPlainObject(body.props) ? body.props : {};
1774
1896
  if (Object.hasOwn(props, "states")) ctx.issues.push({
@@ -1905,7 +2027,8 @@ const ComponentEntity = defineEntity({
1905
2027
  styles: StyleRule,
1906
2028
  preview: Preview,
1907
2029
  anatomy: AnatomyNode,
1908
- defaultProps: Style
2030
+ defaultProps: Style,
2031
+ defaultPropsWhen: DefaultCondition
1909
2032
  },
1910
2033
  computed: {
1911
2034
  /**
@@ -2846,7 +2969,10 @@ function componentRef(path) {
2846
2969
  */
2847
2970
  const step = (delta) => {
2848
2971
  assertComponentSourceInput(delta);
2849
- const extended = base.extend(delta);
2972
+ const extended = base.extend({
2973
+ ...delta,
2974
+ ...storedDefaults(delta)
2975
+ });
2850
2976
  Object.defineProperty(extended, "render", {
2851
2977
  enumerable: false,
2852
2978
  configurable: false,
@@ -1,6 +1,6 @@
1
- import { rejectData } from "../../framework/rejection.js";
2
- import { isRef, kindOf, pathOf, refSchema } from "../../framework/utils/refs.js";
3
1
  import { isPlainObject } from "../../framework/utils/field-path.js";
2
+ import { isRef, kindOf, pathOf, refSchema } from "../../framework/utils/refs.js";
3
+ import { rejectData } from "../../framework/rejection.js";
4
4
  import { pathInput } from "../../framework/schemas.js";
5
5
  import { kindBorrowable } from "../../framework/registry.js";
6
6
  import { defineEntity } from "../../framework/defineEntity.js";
@@ -1,5 +1,5 @@
1
- import { CONFIG_OPERATION_KIND } from "../../framework/config-operation-kind.js";
2
1
  import { isPlainObject } from "../../framework/utils/field-path.js";
2
+ import { CONFIG_OPERATION_KIND } from "../../framework/config-operation-kind.js";
3
3
  import { resolveInputSchema } from "../../framework/schemas.js";
4
4
  import { opsForKind } from "../../framework/registry.js";
5
5
  import { opOf } from "../../framework/config-op.js";
@@ -1,5 +1,5 @@
1
- import { reject } from "../../framework/rejection.js";
2
1
  import { isRef, kindOf, memberRef, pathOf } from "../../framework/utils/refs.js";
2
+ import { reject } from "../../framework/rejection.js";
3
3
  import { forwardedPropName } from "./element.js";
4
4
  import { propOwner, resolveComponentProps } from "../../framework/projections.js";
5
5
  import { forwardClaims } from "../../framework/prop-surface.js";
@@ -55,7 +55,7 @@ function isCreatedComponent(config, path) {
55
55
  if (isNativeConfig(config)) return false;
56
56
  const component = Component.get(config, path);
57
57
  if (!component || component.source !== void 0) return false;
58
- const { file, export: exportName, anatomy } = component.body;
58
+ const { file, export: exportName, anatomy } = component;
59
59
  return !file && !exportName && Object.keys(anatomy ?? {}).length > 0;
60
60
  }
61
61
  /**
@@ -133,7 +133,7 @@ function componentsByFile(config) {
133
133
  if (cached) return cached;
134
134
  const byFile = /* @__PURE__ */ new Map();
135
135
  for (const component of Component.list(config)) {
136
- const { file, export: exportName } = component.body;
136
+ const { file, export: exportName } = component;
137
137
  if (!file || !exportName) continue;
138
138
  const ref = splitRef(file.__ref);
139
139
  if (ref.source) continue;
@@ -163,7 +163,7 @@ function componentRegistryImports(config, filePath) {
163
163
  const byExport = /* @__PURE__ */ new Map();
164
164
  const ambiguous = /* @__PURE__ */ new Set();
165
165
  for (const component of byFile.get(target.path) ?? []) {
166
- const { export: exportName } = component.body;
166
+ const { export: exportName } = component;
167
167
  if (!exportName) continue;
168
168
  if (byExport.has(exportName)) ambiguous.add(exportName);
169
169
  byExport.set(exportName, {
@@ -221,7 +221,8 @@ function componentModuleBuildPlan(config, filePath) {
221
221
  const parsed = splitRef(target);
222
222
  if (parsed.kind !== "component" || parsed.source) return false;
223
223
  const component = Component.get(config, parsed.path);
224
- const { file, export: exportName } = component?.body ?? {};
224
+ const file = component?.file;
225
+ const exportName = component?.export;
225
226
  if (!component || !file || !exportName) return false;
226
227
  const owner = splitRef(file.__ref);
227
228
  if (owner.kind !== "file" || owner.source) return false;
@@ -257,7 +258,7 @@ function componentModuleBuildPlan(config, filePath) {
257
258
  const file = File.get(config, next);
258
259
  if (!file?.hash) continue;
259
260
  recordEntity(`file:${next}`);
260
- const imports = file.body.imports ?? {};
261
+ const imports = file.imports ?? {};
261
262
  const registryImports = new Map(componentRegistryImports(config, next).map((entry) => [entry.specifier, entry]));
262
263
  for (const [specifier, imported] of Object.entries(imports)) {
263
264
  const registryImport = registryImports.get(specifier);
@@ -305,7 +306,7 @@ function componentModuleSource(config, componentPathOrRef) {
305
306
  if (isNativeConfig(config)) return void 0;
306
307
  const component = Component.get(config, componentPathOrRef);
307
308
  if (!component) return void 0;
308
- const { file, export: exportName } = component.body;
309
+ const { file, export: exportName } = component;
309
310
  if (!file || !exportName) {
310
311
  if (!isCreatedComponent(config, component.path)) return void 0;
311
312
  const moduleKey = createdModuleKey(config, component.path);
@@ -405,7 +406,7 @@ function cachedView(consumer, owner, slug, shadowed) {
405
406
  function linkedComponentModule(config, componentPathOrRef) {
406
407
  const component = Component.get(config, componentPathOrRef);
407
408
  if (!component) return void 0;
408
- const { file, export: exportName } = component.body;
409
+ const { file, export: exportName } = component;
409
410
  if (!file || !exportName) return void 0;
410
411
  const asked = typeof componentPathOrRef === "string" ? componentPathOrRef : componentPathOrRef.__ref;
411
412
  const parsed = asked.includes(":") ? splitRef(asked) : void 0;
@@ -422,8 +423,7 @@ function linkedComponentModule(config, componentPathOrRef) {
422
423
  const moduleKey = componentModuleKey(view, filePath);
423
424
  if (!moduleKey) return void 0;
424
425
  const authored = Component.list(owner).find((candidate) => {
425
- const fields = candidate.body;
426
- return fields.export === exportName && fields.file !== void 0 && splitRef(fields.file.__ref).path === filePath;
426
+ return candidate.export === exportName && candidate.file !== void 0 && splitRef(candidate.file.__ref).path === filePath;
427
427
  });
428
428
  return {
429
429
  source: {
@@ -1,5 +1,5 @@
1
- import { rejectData } from "../../framework/rejection.js";
2
1
  import { isPlainObject } from "../../framework/utils/field-path.js";
2
+ import { rejectData } from "../../framework/rejection.js";
3
3
  //#region src/entities/system/component-source-fields.ts
4
4
  /** Source constructors leave these facts to the render extractor and module build.
5
5
  * Stored component bodies, including Create drafts, still carry them. */
@@ -1,5 +1,5 @@
1
- import { reject } from "../../framework/rejection.js";
2
1
  import { canonicalCondition } from "../../framework/utils/refs.js";
2
+ import { reject } from "../../framework/rejection.js";
3
3
  //#region src/entities/system/component-style-set.ts
4
4
  /** A modifier as a style bag keys it: its leaf with a leading `_`. */
5
5
  function bagKey(modifier) {
@@ -0,0 +1,45 @@
1
+ import { StoredDefaultCondition } from "../../framework/default-conditions.js";
2
+
3
+ //#region src/entities/system/conditional-defaults.d.ts
4
+ declare const CONDITIONAL_DEFAULT: unique symbol;
5
+ /** One condition of a {@link ConditionalDefault}: the value the prop defaults to while `when` holds. */
6
+ interface ConditionalDefaultEntry<V = unknown> {
7
+ readonly when: Readonly<Record<string, unknown>>;
8
+ readonly value: V;
9
+ }
10
+ /** A default chosen by the component's other props — see {@link conditionalDefault}. */
11
+ interface ConditionalDefault<V = unknown> {
12
+ readonly [CONDITIONAL_DEFAULT]: true;
13
+ readonly fallback: V;
14
+ readonly entries: readonly ConditionalDefaultEntry<V>[];
15
+ }
16
+ /**
17
+ * A default that depends on the component's other props, for `.defaultProps` and
18
+ * `.extend({ defaultProps })` only.
19
+ *
20
+ * ```ts
21
+ * .defaultProps({
22
+ * modal: true,
23
+ * includeScrim: conditionalDefault(true, [{ when: { modal: false }, value: false }]),
24
+ * })
25
+ * ```
26
+ *
27
+ * `fallback` applies when no entry's `when` holds; when several hold, the later entry wins. A `when`
28
+ * is the grammar a style rule uses, over the component's own props. A value the call site passes
29
+ * still wins over any of it.
30
+ */
31
+ declare function conditionalDefault<const V>(fallback: V, entries: readonly ConditionalDefaultEntry<V>[]): ConditionalDefault<V>;
32
+ declare function isConditionalDefault(value: unknown): value is ConditionalDefault;
33
+ /**
34
+ * Stored defaults as authored: the inverse of {@link splitConditionalDefaults}, each prop
35
+ * `defaultPropsWhen` names given back as a {@link conditionalDefault} over its fallback.
36
+ */
37
+ declare function joinConditionalDefaults({
38
+ defaultProps,
39
+ defaultPropsWhen
40
+ }: {
41
+ defaultProps: Readonly<Record<string, unknown>> | undefined;
42
+ defaultPropsWhen: Readonly<Record<string, StoredDefaultCondition>> | undefined;
43
+ }): Record<string, unknown>;
44
+ //#endregion
45
+ export { ConditionalDefault, ConditionalDefaultEntry, conditionalDefault, isConditionalDefault, joinConditionalDefaults };
@@ -0,0 +1,142 @@
1
+ import { isPlainObject } from "../../framework/utils/field-path.js";
2
+ import { canonicalCondition } from "../../framework/utils/refs.js";
3
+ //#region src/entities/system/conditional-defaults.ts
4
+ const CONDITIONAL_DEFAULT = Symbol.for("uds.conditionalDefault");
5
+ /**
6
+ * A default that depends on the component's other props, for `.defaultProps` and
7
+ * `.extend({ defaultProps })` only.
8
+ *
9
+ * ```ts
10
+ * .defaultProps({
11
+ * modal: true,
12
+ * includeScrim: conditionalDefault(true, [{ when: { modal: false }, value: false }]),
13
+ * })
14
+ * ```
15
+ *
16
+ * `fallback` applies when no entry's `when` holds; when several hold, the later entry wins. A `when`
17
+ * is the grammar a style rule uses, over the component's own props. A value the call site passes
18
+ * still wins over any of it.
19
+ */
20
+ function conditionalDefault(fallback, entries) {
21
+ return {
22
+ [CONDITIONAL_DEFAULT]: true,
23
+ fallback,
24
+ entries
25
+ };
26
+ }
27
+ function isConditionalDefault(value) {
28
+ return typeof value === "object" && value !== null && value[CONDITIONAL_DEFAULT] === true;
29
+ }
30
+ /**
31
+ * Authored defaults as stored: each {@link conditionalDefault} leaves its fallback in `defaultProps`
32
+ * and its entries in `defaultPropsWhen`. `defaultPropsWhen` is `undefined` when nothing was
33
+ * conditional, so a body without one stores exactly what it did before.
34
+ *
35
+ * Stored by condition, every prop shares one order of conditions, while precedence is per prop. The
36
+ * order taken keeps each prop's own; two props that order the same two conditions oppositely can't
37
+ * share one, and are refused.
38
+ */
39
+ function splitConditionalDefaults(authored) {
40
+ const defaultProps = {};
41
+ const perProp = /* @__PURE__ */ new Map();
42
+ for (const [prop, value] of Object.entries(authored)) {
43
+ if (!isConditionalDefault(value)) {
44
+ defaultProps[prop] = value;
45
+ continue;
46
+ }
47
+ if (value.fallback !== void 0) defaultProps[prop] = value.fallback;
48
+ const entries = /* @__PURE__ */ new Map();
49
+ for (const entry of value.entries) {
50
+ const key = canonicalCondition(entry.when);
51
+ entries.delete(key);
52
+ entries.set(key, entry);
53
+ }
54
+ perProp.set(prop, entries);
55
+ }
56
+ if (perProp.size === 0) return { defaultProps };
57
+ const order = conditionOrder(perProp);
58
+ const defaultPropsWhen = {};
59
+ for (const key of order) {
60
+ let when;
61
+ const props = {};
62
+ for (const [prop, entries] of perProp) {
63
+ const entry = entries.get(key);
64
+ if (!entry) continue;
65
+ when ??= { ...entry.when };
66
+ props[prop] = entry.value;
67
+ }
68
+ if (when) defaultPropsWhen[key] = {
69
+ when,
70
+ props
71
+ };
72
+ }
73
+ return {
74
+ defaultProps,
75
+ defaultPropsWhen
76
+ };
77
+ }
78
+ /**
79
+ * `defaultProps` as stored: each `conditionalDefault` splits into its fallback, which stays in
80
+ * `defaultProps`, and its conditions, which go to `defaultPropsWhen`. Empty for a body whose
81
+ * defaults are all plain, so it stores what it did before.
82
+ */
83
+ function storedDefaults(body) {
84
+ if (!isPlainObject(body.defaultProps)) return {};
85
+ const { defaultProps, defaultPropsWhen } = splitConditionalDefaults(body.defaultProps);
86
+ return defaultPropsWhen ? {
87
+ defaultProps,
88
+ defaultPropsWhen
89
+ } : {};
90
+ }
91
+ /**
92
+ * One order of every condition that keeps each prop's own order, by first appearance where props
93
+ * don't constrain it.
94
+ */
95
+ function conditionOrder(perProp) {
96
+ const seen = [];
97
+ const after = /* @__PURE__ */ new Map();
98
+ for (const [prop, entries] of perProp) {
99
+ const keys = [...entries.keys()];
100
+ keys.forEach((key, at) => {
101
+ if (!seen.includes(key)) seen.push(key);
102
+ const earlier = after.get(key) ?? /* @__PURE__ */ new Map();
103
+ for (const before of keys.slice(0, at)) earlier.set(before, prop);
104
+ after.set(key, earlier);
105
+ });
106
+ }
107
+ for (const [key, earlier] of after) for (const [before, prop] of earlier) {
108
+ const other = after.get(before)?.get(key);
109
+ if (other === void 0) continue;
110
+ throw new Error(`\`${prop}\` puts \`${before}\` before \`${key}\` and \`${other}\` puts them the other way round. Conditional defaults share one order of conditions, so give both props the same order.`);
111
+ }
112
+ const order = [];
113
+ const placed = /* @__PURE__ */ new Set();
114
+ const placing = /* @__PURE__ */ new Set();
115
+ const place = (key) => {
116
+ if (placed.has(key)) return;
117
+ if (placing.has(key)) throw new Error(`Conditional defaults order \`${key}\` both before and after another condition across their props. They share one order of conditions, so give every prop the same order.`);
118
+ placing.add(key);
119
+ for (const before of after.get(key)?.keys() ?? []) place(before);
120
+ placing.delete(key);
121
+ placed.add(key);
122
+ order.push(key);
123
+ };
124
+ for (const key of seen) place(key);
125
+ return order;
126
+ }
127
+ /**
128
+ * Stored defaults as authored: the inverse of {@link splitConditionalDefaults}, each prop
129
+ * `defaultPropsWhen` names given back as a {@link conditionalDefault} over its fallback.
130
+ */
131
+ function joinConditionalDefaults({ defaultProps, defaultPropsWhen }) {
132
+ const out = { ...defaultProps };
133
+ const entries = /* @__PURE__ */ new Map();
134
+ for (const { when, props } of Object.values(defaultPropsWhen ?? {})) for (const [prop, value] of Object.entries(props ?? {})) entries.set(prop, [...entries.get(prop) ?? [], {
135
+ when,
136
+ value
137
+ }]);
138
+ for (const [prop, list] of entries) out[prop] = conditionalDefault(out[prop], list);
139
+ return out;
140
+ }
141
+ //#endregion
142
+ export { conditionalDefault, isConditionalDefault, joinConditionalDefaults, storedDefaults };
@@ -1,5 +1,5 @@
1
- import { rejectData } from "../../framework/rejection.js";
2
1
  import { MINTED, collectRefs, isMintedRow, kindOf, pathOf, rewriteRefs, sourceOf, splitRef } from "../../framework/utils/refs.js";
2
+ import { rejectData } from "../../framework/rejection.js";
3
3
  import { kindBorrowable } from "../../framework/registry.js";
4
4
  import { File } from "./File.js";
5
5
  import { componentModuleFilePaths, componentRegistryImports } from "./component-module.js";
@@ -1,5 +1,5 @@
1
- import { isRef, kindOf, pathOf } from "../../framework/utils/refs.js";
2
1
  import { isPlainObject } from "../../framework/utils/field-path.js";
2
+ import { isRef, kindOf, pathOf } from "../../framework/utils/refs.js";
3
3
  import { createSliceMemo } from "../../framework/memo.js";
4
4
  import { drawnMotionBody, drawnMotionName } from "./drawn-motion.js";
5
5
  import { convertMotion } from "./motion-convert.js";