@yahoo/uds-create-config 5.32.2 → 5.32.4

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 (31) hide show
  1. package/dist/configs/CanvasConfig.d.ts +3 -3
  2. package/dist/configs/react-native-system.d.ts +58 -26
  3. package/dist/configs/react-native-system.js +1 -1
  4. package/dist/configs/system.js +2 -2
  5. package/dist/entities/native/NativeModifier.d.ts +2 -2
  6. package/dist/entities/native/NativeStyleProperty.d.ts +39 -39
  7. package/dist/entities/native/NativeToken.d.ts +40 -7
  8. package/dist/entities/native/NativeToken.js +8 -4
  9. package/dist/entities/system/Component.js +28 -6
  10. package/dist/entities/system/Composite.js +5 -0
  11. package/dist/entities/system/Modifier.d.ts +2 -2
  12. package/dist/entities/system/Motion.d.ts +1 -1
  13. package/dist/entities/system/Settings.js +1 -1
  14. package/dist/entities/system/Token.js +5 -4
  15. package/dist/entities/system/component-module.js +1 -1
  16. package/dist/entities/system/defineComponent.d.ts +14 -8
  17. package/dist/entities/system/linked-flex-values.d.ts +19 -0
  18. package/dist/entities/system/linked-flex-values.js +77 -0
  19. package/dist/entities/system/linked-style-values.d.ts +11 -0
  20. package/dist/entities/system/linked-style-values.js +47 -0
  21. package/dist/entities/system/linked-token-values.d.ts +6 -3
  22. package/dist/entities/system/linked-token-values.js +19 -7
  23. package/dist/entities/system/motion-presets.js +1 -1
  24. package/dist/framework/Config.d.ts +3 -1
  25. package/dist/framework/Config.js +22 -11
  26. package/dist/framework/projections.js +1 -1
  27. package/dist/framework/registry.d.ts +5 -2
  28. package/dist/index.d.ts +2 -1
  29. package/dist/index.js +10 -9
  30. package/dist/tsconfig.tsbuildinfo +1 -1
  31. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { reject, rejectData } from "../../framework/rejection.js";
2
- import { canonicalCondition, collectRefs, isRef, kindOf, memberRef, pathOf, ref, refLeaf, refSchema, splitRef } from "../../framework/utils/refs.js";
2
+ import { canonicalCondition, collectRefs, isRef, kindOf, memberRef, pathOf, ref, refLeaf, refSchema, sourceOf, splitRef } from "../../framework/utils/refs.js";
3
3
  import { isPlainObject } from "../../framework/utils/field-path.js";
4
4
  import { pathInput } from "../../framework/schemas.js";
5
5
  import { derivedColor, gradient, oklchColor } from "./color.js";
@@ -8,6 +8,7 @@ import { defineEntity } from "../../framework/defineEntity.js";
8
8
  import { defineSubEntity, orList } from "../../framework/defineSubEntity.js";
9
9
  import { childrenPolicy, forwardedPropName } from "./element.js";
10
10
  import { interactionKey, interactionModifiers } from "../../framework/interaction-conditions.js";
11
+ import { translateLinkedStyleBags } from "./linked-style-values.js";
11
12
  import { listedIn } from "../../framework/utils/enumerated.js";
12
13
  import { valueSchemaOf } from "../../framework/value-domain.js";
13
14
  import { Package } from "./Package.js";
@@ -600,13 +601,21 @@ function declaringInto(config, layers, decl) {
600
601
  const minted = (route) => {
601
602
  if (!isRef(route.target)) return route;
602
603
  const element = layers?.[pathOf(route.target)];
603
- if (!isRef(element)) return route;
604
+ if (element === void 0 || element === null) return route;
604
605
  const name = intoName(route.into);
605
- const owner = propOwner(config, pathOf(element), name);
606
- if (!owner || isRef(route.into) && pathOf(route.into) === owner) return route;
606
+ if (!isRef(element) || kindOf(element) !== "component") return route.into === name ? route : {
607
+ ...route,
608
+ into: name
609
+ };
610
+ const ownerConfig = config.configFor(element);
611
+ if (!ownerConfig) return route;
612
+ const owner = propOwner(ownerConfig, pathOf(element), name);
613
+ if (!owner && !isRef(route.into)) return route;
614
+ const into = memberRef("component", owner ?? pathOf(element), "props", name, sourceOf(element));
615
+ if (isRef(route.into) && route.into.__ref === into.__ref) return route;
607
616
  return {
608
617
  ...route,
609
- into: memberRef("component", owner, "props", name)
618
+ into
610
619
  };
611
620
  };
612
621
  const first = minted(decl);
@@ -1808,7 +1817,7 @@ const componentBags = (data) => {
1808
1817
  if (!isPlainRecord(layers)) continue;
1809
1818
  for (const [layer, bag] of Object.entries(layers)) collectBag(bag, (next) => {
1810
1819
  layers[layer] = next;
1811
- }, out);
1820
+ }, out, body?.layers?.[layer]);
1812
1821
  }
1813
1822
  for (const node of Object.values(body?.anatomy ?? {})) {
1814
1823
  if (!isPlainRecord(node)) continue;
@@ -1823,6 +1832,19 @@ const componentBags = (data) => {
1823
1832
  };
1824
1833
  const ComponentEntity = defineEntity({
1825
1834
  kind: "component",
1835
+ rebaseLinkedBody: (args) => translateLinkedStyleBags({
1836
+ ...args,
1837
+ bags: componentBags,
1838
+ owner: args.path
1839
+ }),
1840
+ prepareLinkedBody: ({ body, config }) => {
1841
+ if (!isPlainObject(body.props)) return body;
1842
+ const layers = isPlainObject(body.layers) ? body.layers : void 0;
1843
+ return {
1844
+ ...body,
1845
+ props: Object.fromEntries(Object.entries(body.props).map(([name, decl]) => [name, declaringInto(config, layers, decl)]))
1846
+ };
1847
+ },
1826
1848
  fields: componentFields,
1827
1849
  groupFields: z.object({ icon: z.string().optional() }),
1828
1850
  subEntities: {
@@ -1,4 +1,5 @@
1
1
  import { defineEntity } from "../../framework/defineEntity.js";
2
+ import { translateLinkedStyleBags } from "./linked-style-values.js";
2
3
  import { Style, bagNameEdges, bagRewriteName, collectBag } from "./style-bag.js";
3
4
  import { z } from "zod";
4
5
  //#region src/entities/system/Composite.ts
@@ -13,6 +14,10 @@ const compositeBags = (data) => {
13
14
  };
14
15
  const Composite = defineEntity({
15
16
  kind: "composite",
17
+ rebaseLinkedBody: (args) => translateLinkedStyleBags({
18
+ ...args,
19
+ bags: compositeBags
20
+ }),
16
21
  label: "Composite style",
17
22
  labelPlural: "Composite styles",
18
23
  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.") }),
@@ -30,8 +30,8 @@ type WebActivation = (typeof WEB_ACTIVATIONS)[number];
30
30
  */
31
31
  declare const modifierGroupFields: z.ZodObject<{
32
32
  type: z.ZodOptional<z.ZodEnum<{
33
- mode: "mode";
34
33
  state: "state";
34
+ mode: "mode";
35
35
  }>>;
36
36
  default: z.ZodOptional<z.ZodObject<{
37
37
  __ref: z.ZodString;
@@ -53,8 +53,8 @@ declare const ModifierDefinition: EntityClass<z.ZodObject<{
53
53
  declarations: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
54
54
  }, z.core.$strip>, z.ZodObject<{
55
55
  type: z.ZodOptional<z.ZodEnum<{
56
- mode: "mode";
57
56
  state: "state";
57
+ mode: "mode";
58
58
  }>>;
59
59
  default: z.ZodOptional<z.ZodObject<{
60
60
  __ref: z.ZodString;
@@ -11,9 +11,9 @@ import { z } from "zod";
11
11
  */
12
12
  declare const inlineJsMotion: z.ZodObject<{
13
13
  transition: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
14
+ initial: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>, z.ZodLiteral<false>]>>;
14
15
  exit: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
15
16
  layout: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"position">, z.ZodLiteral<"size">, z.ZodLiteral<"preserve-aspect">]>>;
16
- initial: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>, z.ZodLiteral<false>]>>;
17
17
  variants: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
18
18
  animate: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
19
19
  whileHover: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
@@ -2,8 +2,8 @@ import { splitRef } from "../../framework/utils/refs.js";
2
2
  import { defineEntity } from "../../framework/defineEntity.js";
3
3
  import { defineSubEntity } from "../../framework/defineSubEntity.js";
4
4
  import { createSliceMemo } from "../../framework/memo.js";
5
- import { buildFields } from "../../configs/build-options.js";
6
5
  import { parseRootFontSize } from "../../css/root-font-size.js";
6
+ import { buildFields } from "../../configs/build-options.js";
7
7
  import { resolveInputDir } from "../../framework/registry-dir.js";
8
8
  import { safelistSchema } from "./safelist.js";
9
9
  import { z } from "zod";
@@ -3,9 +3,9 @@ import { composedValueSchemas } from "./composed-values.js";
3
3
  import { defineEntity } from "../../framework/defineEntity.js";
4
4
  import { defineSubEntity, orList } from "../../framework/defineSubEntity.js";
5
5
  import { Font } from "./Font.js";
6
- import { Modifier } from "./Modifier.js";
7
- import { spellTokenRead } from "./token-values.js";
8
6
  import { WEB_CONFIG_NAME } from "../../configs/platform.js";
7
+ import { spellTokenRead } from "./token-values.js";
8
+ import { Modifier } from "./Modifier.js";
9
9
  import { authoringPhantom } from "../../framework/utils/authoring-phantom.js";
10
10
  import { prepareLinkedTokenBody } from "./linked-token-values.js";
11
11
  import { z } from "zod";
@@ -119,12 +119,13 @@ function defineOverride(value) {
119
119
  const Override = defineOverride(tokenValue);
120
120
  const TokenEntity = defineEntity({
121
121
  kind: "token",
122
- prepareLinkedBody: ({ path, body, source, config }) => prepareLinkedTokenBody({
122
+ prepareLinkedBody: ({ path, body, source, config, extend }) => prepareLinkedTokenBody({
123
123
  path,
124
124
  body,
125
125
  source,
126
126
  config,
127
- destinationPlatform: WEB_CONFIG_NAME
127
+ destinationPlatform: WEB_CONFIG_NAME,
128
+ extend
128
129
  }),
129
130
  fields: z.object({
130
131
  value: tokenValue.describe("The base value: a literal, a ref to another token, or a composed value such as a gradient."),
@@ -1,8 +1,8 @@
1
1
  import { isRef, kindOf, pathOf, ref, routedSource, sourceHops, splitRef } from "../../framework/utils/refs.js";
2
2
  import { createSliceMemo } from "../../framework/memo.js";
3
+ import { isNativeConfig } from "../../configs/platform.js";
3
4
  import { Settings, classPrefixOf, prefixed, varPrefixOf } from "./Settings.js";
4
5
  import { File } from "./File.js";
5
- import { isNativeConfig } from "../../configs/platform.js";
6
6
  import { Component } from "./Component.js";
7
7
  import { contentKey } from "../../framework/utils/content-key.js";
8
8
  //#region src/entities/system/component-module.ts
@@ -380,6 +380,18 @@ type LayerBag<Self, K extends PropertyKey> = Self extends ((props: infer Props)
380
380
  */
381
381
  type SlotValueOf<D, Self, K extends PropertyKey, View extends SlotView> = View extends 'render' ? OwnSlotValue<D, 'render'> | null : string extends K ? // An open prop map (`PropMap` itself, read at a constraint) names no prop in particular, so
382
382
  OwnSlotValue<D, 'consumer'> | null : OwnSlotValue<D, 'consumer'> | SlotCodeValue<D, Self, K> | null;
383
+ /** A forward's address in authored and stored contracts. Ownership refs identify the prop;
384
+ * the effective layer map still decides which element receives it. */
385
+ type ForwardPath<D> = D extends {
386
+ type: 'forward';
387
+ target: infer Target;
388
+ } ? Target extends string ? Target : Target extends readonly [infer First extends string, ...unknown[]] ? First : Target extends {
389
+ readonly __ref: `layer:${infer Layer}`;
390
+ } ? D extends {
391
+ into: infer Into;
392
+ } ? Into extends string ? `${Layer}/${Into}` : Into extends {
393
+ readonly __ref: `component:${string}#props/${infer Prop}`;
394
+ } ? `${Layer}/${Prop}` : never : `${Layer}/children` : never : never;
383
395
  /** The declaration arms of {@link ValueOf}, after the two ref arms. */
384
396
  type ValueOfDeclaration<D, Self, K extends PropertyKey, View extends SlotView> = D extends {
385
397
  type: 'variant';
@@ -395,10 +407,7 @@ type ValueOfDeclaration<D, Self, K extends PropertyKey, View extends SlotView> =
395
407
  } ? SlotValueOf<D, Self, K, View> : D extends {
396
408
  type: 'forward';
397
409
  text: true;
398
- } ? string : D extends {
399
- type: 'forward';
400
- target: `${string}/children` | readonly [`${string}/children`, ...unknown[]];
401
- } ? ReactNode : unknown;
410
+ } ? string : [ForwardPath<D>] extends [never] ? unknown : ForwardPath<D> extends `${string}/children` ? ReactNode : unknown;
402
411
  /**
403
412
  * A prop type's DECLARED props — everything but its index signature.
404
413
  *
@@ -422,10 +431,7 @@ type DeclaredProps<P, L extends LayerMap = LayerMap, Self = unknown, View extend
422
431
  type RoutedValueOf<L extends LayerMap, D, Self = unknown, K extends PropertyKey = never, View extends SlotView = 'consumer'> = D extends {
423
432
  type: 'forward';
424
433
  text: true;
425
- } ? string : D extends {
426
- type: 'forward';
427
- target: `${infer Layer}/${infer Prop}` | readonly [`${infer Layer}/${infer Prop}`, ...unknown[]];
428
- } ? Prop extends 'children' ? ReactNode : Layer extends keyof L ? Prop extends keyof ElementPropsOf<L[Layer]> ? ElementPropsOf<L[Layer]>[Prop] : unknown : unknown : ValueOf<D, Self, K, View>;
434
+ } ? string : [ForwardPath<D>] extends [never] ? ValueOf<D, Self, K, View> : ForwardPath<D> extends `${infer Layer}/${infer Prop}` ? Prop extends 'children' ? ReactNode : Layer extends keyof L ? Prop extends keyof ElementPropsOf<L[Layer]> ? ElementPropsOf<L[Layer]>[Prop] : unknown : unknown : ValueOf<D, Self, K, View>;
429
435
  /**
430
436
  * The props the rendered ELEMENT contributes, `ref` included.
431
437
  *
@@ -0,0 +1,19 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/entities/system/linked-flex-values.d.ts
4
+ /** Native has no flex shorthand string. Its equivalent is these three style declarations. */
5
+ declare const nativeFlexValue: z.ZodObject<{
6
+ flexGrow: z.ZodNumber;
7
+ flexShrink: z.ZodNumber;
8
+ flexBasis: z.ZodUnion<readonly [z.ZodNumber, z.ZodLiteral<"auto">, z.ZodString]>;
9
+ }, z.core.$strict>;
10
+ type NativeFlexValue = z.infer<typeof nativeFlexValue>;
11
+ declare function isNativeFlexValue(value: unknown): value is NativeFlexValue;
12
+ /** The supported CSS flex grammar, resolved to RN longhands without losing its basis or shrink. */
13
+ declare function webFlexToNative(value: string | number, remBase?: number): NativeFlexValue;
14
+ /** RN numeric flex is not CSS numeric flex: Yoga's native defaults use shrink=0, and positive
15
+ * numbers use a 0pt basis. Negative flex supplies shrink while retaining auto basis.
16
+ * See Yoga Node::resolveFlexGrow/resolveFlexShrink/processFlexBasis with useWebDefaults=false. */
17
+ declare function nativeFlexToWeb(value: NativeFlexValue | number): string;
18
+ //#endregion
19
+ export { NativeFlexValue, isNativeFlexValue, nativeFlexToWeb, webFlexToNative };
@@ -0,0 +1,77 @@
1
+ import { z } from "zod";
2
+ //#region src/entities/system/linked-flex-values.ts
3
+ /** Native has no flex shorthand string. Its equivalent is these three style declarations. */
4
+ const nativeFlexValue = z.strictObject({
5
+ flexGrow: z.number().nonnegative(),
6
+ flexShrink: z.number().nonnegative(),
7
+ flexBasis: z.union([
8
+ z.number().nonnegative(),
9
+ z.literal("auto"),
10
+ z.string().regex(/^(?:\d+(?:\.\d+)?|\.\d+)%$/)
11
+ ])
12
+ });
13
+ function isNativeFlexValue(value) {
14
+ return typeof value === "object" && value !== null && "flexGrow" in value && nativeFlexValue.safeParse(value).success;
15
+ }
16
+ const NUMBER = /^(?:\d+(?:\.\d+)?|\.\d+)$/;
17
+ /** The supported CSS flex grammar, resolved to RN longhands without losing its basis or shrink. */
18
+ function webFlexToNative(value, remBase) {
19
+ const text = String(value).trim();
20
+ if (text === "none") return {
21
+ flexGrow: 0,
22
+ flexShrink: 0,
23
+ flexBasis: "auto"
24
+ };
25
+ if (text === "auto") return {
26
+ flexGrow: 1,
27
+ flexShrink: 1,
28
+ flexBasis: "auto"
29
+ };
30
+ if (text === "initial") return {
31
+ flexGrow: 0,
32
+ flexShrink: 1,
33
+ flexBasis: "auto"
34
+ };
35
+ const parts = text.split(/\s+/);
36
+ let grow = 1;
37
+ let shrink = 1;
38
+ let basis = "0%";
39
+ if (parts.length <= 3 && NUMBER.test(parts[0] ?? "")) {
40
+ grow = Number(parts.shift());
41
+ if (parts.length && NUMBER.test(parts[0] ?? "")) shrink = Number(parts.shift());
42
+ if (parts.length === 1) basis = parts.shift() ?? "";
43
+ } else if (parts.length === 1) basis = parts.shift() ?? "";
44
+ if (parts.length === 0) {
45
+ if (basis === "auto" || /^(?:\d+(?:\.\d+)?|\.\d+)%$/.test(basis)) return {
46
+ flexGrow: grow,
47
+ flexShrink: shrink,
48
+ flexBasis: basis
49
+ };
50
+ const length = /^(\d+(?:\.\d+)?|\.\d+)(px|rem)?$/.exec(basis);
51
+ if (length && (length[2] || Number(length[1]) === 0)) {
52
+ if (length[2] !== "rem" || remBase !== void 0) return {
53
+ flexGrow: grow,
54
+ flexShrink: shrink,
55
+ flexBasis: Number(length[1]) * (length[2] === "rem" ? remBase : 1)
56
+ };
57
+ }
58
+ }
59
+ throw new Error(`[uds] Cannot translate Web flex ${JSON.stringify(value)} to native. Use none, auto, initial, or numeric grow/shrink with an auto, percentage, px, or fixed-rem basis.`);
60
+ }
61
+ /** RN numeric flex is not CSS numeric flex: Yoga's native defaults use shrink=0, and positive
62
+ * numbers use a 0pt basis. Negative flex supplies shrink while retaining auto basis.
63
+ * See Yoga Node::resolveFlexGrow/resolveFlexShrink/processFlexBasis with useWebDefaults=false. */
64
+ function nativeFlexToWeb(value) {
65
+ const { flexGrow, flexShrink, flexBasis } = typeof value !== "number" ? value : value > 0 ? {
66
+ flexGrow: value,
67
+ flexShrink: 0,
68
+ flexBasis: 0
69
+ } : {
70
+ flexGrow: 0,
71
+ flexShrink: -value,
72
+ flexBasis: "auto"
73
+ };
74
+ return `${flexGrow} ${flexShrink} ${typeof flexBasis === "number" ? `${flexBasis}px` : flexBasis}`;
75
+ }
76
+ //#endregion
77
+ export { isNativeFlexValue, nativeFlexToWeb, nativeFlexValue, webFlexToNative };
@@ -0,0 +1,11 @@
1
+ import type { Config } from '../../framework/Config';
2
+ import type { BagSites } from './style-bag';
3
+ /** Translate inherited literals before merging the destination's own style overrides. Refs keep
4
+ * their identity: the linked-token adapter handles their values and mode overrides. */
5
+ export declare function translateLinkedStyleBags({ body, source, config, bags, owner, }: {
6
+ body: Record<string, unknown>;
7
+ source?: Config;
8
+ config: Config;
9
+ bags: BagSites;
10
+ owner?: string;
11
+ }): Record<string, unknown>;
@@ -0,0 +1,47 @@
1
+ import { isRef, pathOf } from "../../framework/utils/refs.js";
2
+ import { NATIVE_CONFIG_NAME } from "../../configs/platform.js";
3
+ import { isNativeFlexValue, nativeFlexToWeb, webFlexToNative } from "./linked-flex-values.js";
4
+ import { rootFontSize } from "./token-values.js";
5
+ import { stylePropEntries, stylePropertyPathFor } from "../../framework/projections.js";
6
+ //#region src/entities/system/linked-style-values.ts
7
+ /** Translate inherited literals before merging the destination's own style overrides. Refs keep
8
+ * their identity: the linked-token adapter handles their values and mode overrides. */
9
+ function translateLinkedStyleBags({ body, source, config, bags, owner }) {
10
+ if (!source || source.name === config.name) return body;
11
+ if (!["system-config", "react-native-system"].includes(source.name)) return body;
12
+ if (!["system-config", "react-native-system"].includes(config.name)) return body;
13
+ const native = config.name === NATIVE_CONFIG_NAME;
14
+ const translate = (bag, element) => Object.fromEntries(Object.entries(bag).map(([key, raw]) => {
15
+ if (key.startsWith("_")) return [key, raw];
16
+ const propPath = stylePropertyPathFor({
17
+ config: source,
18
+ key,
19
+ through: [isRef(element) ? pathOf(element) : typeof element === "string" ? element : owner]
20
+ });
21
+ const properties = propPath ? source.resolve("style-property", propPath)?.toJSON().properties : void 0;
22
+ if (!propPath || !Array.isArray(properties) || properties.length !== 1 || isRef(raw)) return [key, raw];
23
+ const property = String(properties[0]).replace(/-([a-z])/g, (_, c) => c.toUpperCase());
24
+ if (![
25
+ "flex",
26
+ "flexGrow",
27
+ "flexShrink"
28
+ ].includes(property)) return [key, raw];
29
+ const alias = stylePropEntries(source, propPath).find((entry) => entry.leaf === String(raw));
30
+ if (alias?.declarations) return [key, raw];
31
+ const resolved = alias ? alias.numeric && /^(?:\d+(?:\.\d+)?|\.\d+)$/.test(alias.value) ? Number(alias.value) : alias.value : raw;
32
+ const value = typeof resolved === "string" && resolved.startsWith("[") && resolved.endsWith("]") ? resolved.slice(1, -1) : resolved;
33
+ if (property === "flex") {
34
+ if (native && (typeof value === "string" || typeof value === "number")) return [key, webFlexToNative(value, rootFontSize(source).px)];
35
+ if (!native && (typeof value === "number" || isNativeFlexValue(value))) return [key, `[${nativeFlexToWeb(value)}]`];
36
+ } else if (typeof value === "string" || typeof value === "number") {
37
+ if (!/^(?:\d+(?:\.\d+)?|\.\d+)$/.test(String(value)) || !Number.isFinite(Number(value))) throw new Error(`[uds] Cannot translate ${property} ${JSON.stringify(value)}: expected a non-negative unitless number.`);
38
+ return [key, native ? Number(value) : `[${value}]`];
39
+ }
40
+ return [key, raw];
41
+ }));
42
+ const translated = structuredClone(body);
43
+ for (const site of [...bags(translated)].reverse()) site.write(translate(site.bag, site.element));
44
+ return translated;
45
+ }
46
+ //#endregion
47
+ export { translateLinkedStyleBags };
@@ -1,5 +1,6 @@
1
1
  import { Config } from "../../framework/Config.js";
2
2
  import { NATIVE_CONFIG_NAME, WEB_CONFIG_NAME } from "../../configs/platform.js";
3
+ import { NativeFlexValue } from "./linked-flex-values.js";
3
4
 
4
5
  //#region src/entities/system/linked-token-values.d.ts
5
6
  type Platform = typeof WEB_CONFIG_NAME | typeof NATIVE_CONFIG_NAME;
@@ -11,24 +12,26 @@ declare function convertLinkedTokenValue({
11
12
  remBase
12
13
  }: {
13
14
  path: string;
14
- value: string | number | boolean;
15
+ value: string | number | boolean | NativeFlexValue;
15
16
  sourcePlatform: string;
16
17
  destinationPlatform: Platform; /** The pinned web source's fixed root size, only needed for web rem → native points. */
17
18
  remBase?: number;
18
- }): string | number | boolean;
19
+ }): string | number | boolean | NativeFlexValue;
19
20
  /** The one adapter for base and mode values before a linked body is parsed by its destination. */
20
21
  declare function prepareLinkedTokenBody({
21
22
  path,
22
23
  body,
23
24
  source,
24
25
  config,
25
- destinationPlatform
26
+ destinationPlatform,
27
+ extend
26
28
  }: {
27
29
  path: string;
28
30
  body: Record<string, unknown>;
29
31
  source: Config; /** The config whose refs the body spells; a source's own body spells them in the source. */
30
32
  config: Config;
31
33
  destinationPlatform: Platform;
34
+ extend?: Record<string, unknown>;
32
35
  }): Record<string, unknown>;
33
36
  //#endregion
34
37
  export { convertLinkedTokenValue, prepareLinkedTokenBody };
@@ -1,9 +1,10 @@
1
1
  import { hasRefMarker } from "../../framework/utils/refs.js";
2
2
  import { isCalc } from "./calc.js";
3
3
  import { isOklchColor } from "./color.js";
4
- import { literalValueOf } from "../../framework/projections.js";
5
- import { rootFontSize } from "./token-values.js";
6
4
  import "../../configs/platform.js";
5
+ import { isNativeFlexValue, nativeFlexToWeb, webFlexToNative } from "./linked-flex-values.js";
6
+ import { rootFontSize } from "./token-values.js";
7
+ import { literalValueOf } from "../../framework/projections.js";
7
8
  //#region src/entities/system/linked-token-values.ts
8
9
  /**
9
10
  * Adapt a linked token for the system reading it. The source keeps its authored value; only the
@@ -12,10 +13,12 @@ import "../../configs/platform.js";
12
13
  */
13
14
  const LENGTH_GROUPS = new Set([
14
15
  "spacing",
16
+ "size",
15
17
  "radius",
16
18
  "borderRadius",
17
19
  "iconSize",
18
20
  "borderWidth",
21
+ "outlineOffset",
19
22
  "fontSize",
20
23
  "fontLineHeight",
21
24
  "fontLetterSpacing"
@@ -23,7 +26,9 @@ const LENGTH_GROUPS = new Set([
23
26
  const NUMBER_GROUPS = new Set([
24
27
  "opacity",
25
28
  "zIndex",
26
- "fontWeight"
29
+ "fontWeight",
30
+ "flexGrow",
31
+ "flexShrink"
27
32
  ]);
28
33
  const LENGTH = /^(-?(?:\d+(?:\.\d+)?|\.\d+))(px|rem)$/;
29
34
  const NUMBER = /^-?(?:\d+(?:\.\d+)?|\.\d+)$/;
@@ -33,9 +38,16 @@ const OKLCH = /^oklch\(\s*(-?[\d.]+)(%?)\s+(-?[\d.]+)(%?)\s+(-?[\d.]+|none)(?:de
33
38
  function convertLinkedTokenValue({ path, value, sourcePlatform, destinationPlatform, remBase }) {
34
39
  if (sourcePlatform === destinationPlatform) return value;
35
40
  const group = path.split("/")[0];
41
+ if (group === "flex") {
42
+ if (destinationPlatform === "react-native-system") {
43
+ if (isNativeFlexValue(value)) return value;
44
+ if (typeof value === "string" || typeof value === "number") return webFlexToNative(value, remBase);
45
+ } else if (sourcePlatform === "react-native-system" && (typeof value === "number" || isNativeFlexValue(value))) return nativeFlexToWeb(value);
46
+ }
36
47
  if (destinationPlatform === "react-native-system") {
37
48
  if (LENGTH_GROUPS.has(group)) {
38
49
  if (typeof value === "number") return value;
50
+ if (group === "size" && typeof value === "string" && /^-?(?:\d+(?:\.\d+)?|\.\d+)%$/.test(value)) return value;
39
51
  const match = typeof value === "string" ? LENGTH.exec(value) : null;
40
52
  if (!match) throw unsupported("native", path, value, "a px or rem length");
41
53
  if (match[2] === "rem" && remBase === void 0) throw new Error(`[uds] Linked native token "${path}" has value ${JSON.stringify(value)}, but its source has no fixed root font size for rem conversion.`);
@@ -60,7 +72,7 @@ function convertLinkedTokenValue({ path, value, sourcePlatform, destinationPlatf
60
72
  return value;
61
73
  }
62
74
  /** The one adapter for base and mode values before a linked body is parsed by its destination. */
63
- function prepareLinkedTokenBody({ path, body, source, config, destinationPlatform }) {
75
+ function prepareLinkedTokenBody({ path, body, source, config, destinationPlatform, extend }) {
64
76
  if (source.name === destinationPlatform) return body;
65
77
  const remBase = source.name === "system-config" ? rootFontSize(source).px : void 0;
66
78
  const convert = (value) => {
@@ -69,7 +81,7 @@ function prepareLinkedTokenBody({ path, body, source, config, destinationPlatfor
69
81
  value,
70
82
  remBase
71
83
  }) : value;
72
- return typeof literal === "string" || typeof literal === "number" || typeof literal === "boolean" ? convertLinkedTokenValue({
84
+ return typeof literal === "string" || typeof literal === "number" || typeof literal === "boolean" || isNativeFlexValue(literal) ? convertLinkedTokenValue({
73
85
  path,
74
86
  value: literal,
75
87
  sourcePlatform: source.name,
@@ -80,10 +92,10 @@ function prepareLinkedTokenBody({ path, body, source, config, destinationPlatfor
80
92
  const overrides = body.overrides;
81
93
  return {
82
94
  ...body,
83
- value: convert(body.value),
95
+ value: extend && Object.hasOwn(extend, "value") ? body.value : convert(body.value),
84
96
  ...overrides && typeof overrides === "object" && !Array.isArray(overrides) ? { overrides: Object.fromEntries(Object.entries(overrides).map(([key, raw]) => [key, raw && typeof raw === "object" && !Array.isArray(raw) ? {
85
97
  ...raw,
86
- value: convert(raw.value)
98
+ value: Object.hasOwn((extend?.overrides)?.[key] ?? {}, "value") ? raw.value : convert(raw.value)
87
99
  } : raw])) } : {}
88
100
  };
89
101
  }
@@ -1,11 +1,11 @@
1
1
  import { collectRefs, isRef, kindOf, pathOf } from "../../framework/utils/refs.js";
2
2
  import { composedValueFormOf } from "./composed-values.js";
3
3
  import { createSliceMemo } from "../../framework/memo.js";
4
+ import { tokenValueRow } from "./token-values.js";
4
5
  import { MOTION_EASING_NAMES, bezierPoints, motionOfCssKeyword } from "./easings.js";
5
6
  import { inlineMotions } from "./motion-variants.js";
6
7
  import { isReducedMotion } from "./reduced-motion.js";
7
8
  import { jsMotionPropFields } from "./Motion.js";
8
- import { tokenValueRow } from "./token-values.js";
9
9
  import { renderValue } from "./value-render.js";
10
10
  //#region src/entities/system/motion-presets.ts
11
11
  /** A time spelled in CSS, which `motion/react` reads in seconds. */
@@ -1415,12 +1415,14 @@ declare class Config {
1415
1415
  kind,
1416
1416
  path,
1417
1417
  body,
1418
- extend
1418
+ extend,
1419
+ source
1419
1420
  }: {
1420
1421
  kind: string;
1421
1422
  path: string;
1422
1423
  body: Record<string, unknown>;
1423
1424
  extend: Record<string, unknown>;
1425
+ source?: Config;
1424
1426
  }): Record<string, unknown>;
1425
1427
  /** The body of the entity a re-pointed path names, or `undefined` when there is none to read. */
1426
1428
  private redirectedBody;
@@ -2074,7 +2074,8 @@ var Config = class Config {
2074
2074
  kind: patch.kind,
2075
2075
  path: pathOf(extension),
2076
2076
  body: current.source,
2077
- extend: current.overlay
2077
+ extend: current.overlay,
2078
+ source: this.configFor(extension)
2078
2079
  }) : resolved.toJSON();
2079
2080
  const materialized = snapshot.withChanges([itemChange(entry, patch.kind, patch.path, inherited)]);
2080
2081
  const changed = this.applySub(materialized, patch, materialized.get(patch.kind, patch.path) ?? resolved, mode);
@@ -2164,7 +2165,8 @@ var Config = class Config {
2164
2165
  kind: patch.kind,
2165
2166
  path: pathOf(extension),
2166
2167
  body: current.source,
2167
- extend: current.overlay
2168
+ extend: current.overlay,
2169
+ source: this.configFor(extension)
2168
2170
  }) : resolved.toJSON(), delta, isField);
2169
2171
  const local = { ...current ? current.overlay : extension.extend };
2170
2172
  for (const field of touched) if (Object.hasOwn(delta, field) && delta[field] === null) delete local[field];
@@ -2176,7 +2178,8 @@ var Config = class Config {
2176
2178
  kind: patch.kind,
2177
2179
  path: pathOf(extension),
2178
2180
  body: sourceBody,
2179
- extend: local
2181
+ extend: local,
2182
+ source: this.configFor(extension)
2180
2183
  });
2181
2184
  const createSchema = wholeBodySchema(entry, { config: this });
2182
2185
  let merged = candidate;
@@ -2926,13 +2929,15 @@ var Config = class Config {
2926
2929
  kind,
2927
2930
  path: pathOf(extension),
2928
2931
  body: inherited,
2929
- extend: extension.extend ?? {}
2932
+ extend: extension.extend ?? {},
2933
+ source
2930
2934
  });
2931
2935
  return this.entityOf(kind)?.prepareLinkedBody?.({
2932
2936
  path: pathOf(extension),
2933
2937
  body: merged,
2934
2938
  source,
2935
- config: this
2939
+ config: this,
2940
+ extend: extension.extend ?? {}
2936
2941
  }) ?? merged;
2937
2942
  }
2938
2943
  /**
@@ -2947,7 +2952,7 @@ var Config = class Config {
2947
2952
  * nothing. The pin's invariants refuse the last two when they're written, and the build reports a
2948
2953
  * missing target (`brokenLinkRedirects`).
2949
2954
  */
2950
- laidLinkedBody({ kind, path, body, extend }) {
2955
+ laidLinkedBody({ kind, path, body, extend, source }) {
2951
2956
  const { target, rest } = redirectOf(extend);
2952
2957
  const base = target === void 0 ? body : this.redirectedBody({
2953
2958
  kind,
@@ -2958,7 +2963,9 @@ var Config = class Config {
2958
2963
  entry: this.entityOf(kind),
2959
2964
  path,
2960
2965
  body: base,
2961
- extend: rest
2966
+ extend: rest,
2967
+ config: this,
2968
+ source: target === void 0 ? source : this.configFor({ __ref: target })
2962
2969
  }), rest);
2963
2970
  }
2964
2971
  /** The body of the entity a re-pointed path names, or `undefined` when there is none to read. */
@@ -3892,7 +3899,8 @@ var Config = class Config {
3892
3899
  kind,
3893
3900
  path,
3894
3901
  body: theirs,
3895
- extend: laid
3902
+ extend: laid,
3903
+ source: this.sourceFor(slug)
3896
3904
  });
3897
3905
  return laid ? {
3898
3906
  ...theirs,
@@ -5111,7 +5119,8 @@ var Config = class Config {
5111
5119
  source: slug,
5112
5120
  owns: (name) => source.ownedKinds().includes(name)
5113
5121
  }),
5114
- extend: extension.extend
5122
+ extend: extension.extend,
5123
+ source
5115
5124
  });
5116
5125
  visitEntity(kind, body, false, linked);
5117
5126
  visitBags(kind, body, linked);
@@ -6035,11 +6044,13 @@ function redirectOf(extend) {
6035
6044
  }
6036
6045
  /** A source's body as an extension reads it before its `extend` merges in: the kind's
6037
6046
  * {@link EntityKind.rebaseLinkedBody}, where it declares one. */
6038
- function rebasedLinkedBody({ entry, path, body, extend }) {
6047
+ function rebasedLinkedBody({ entry, path, body, extend, source, config }) {
6039
6048
  return entry?.rebaseLinkedBody?.({
6040
6049
  path,
6041
6050
  body,
6042
- extend
6051
+ extend,
6052
+ source,
6053
+ config
6043
6054
  }) ?? body;
6044
6055
  }
6045
6056
  function overlayBody({ overlay, theirs }) {
@@ -6,9 +6,9 @@ import { modifierCategory } from "../entities/system/modifier-axis.js";
6
6
  import { forwardedPropName, forwardsOf, rootLayerOf } from "../entities/system/element.js";
7
7
  import { createSliceMemo } from "./memo.js";
8
8
  import { fontFamilyStack } from "../entities/system/Font.js";
9
+ import { classPrefixOf, prefixed, varPrefixOf } from "../entities/system/Settings.js";
9
10
  import { listedIn } from "./utils/enumerated.js";
10
11
  import "../entities/system/Modifier.js";
11
- import { classPrefixOf, prefixed, varPrefixOf } from "../entities/system/Settings.js";
12
12
  import { StyleProperty, leavesOfStylePropValue, numberUnitRefusal } from "../entities/system/StyleProperty.js";
13
13
  import { componentStates } from "./component-states.js";
14
14
  import { isConditionalPreview, storedPreview, unconditionalPreviewProps } from "./preview-store.js";