@yahoo/uds-create-config 5.17.6 → 5.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,8 @@ declare const BUILD_DEFAULTS: {
7
7
  readonly registryDir: "src/uds/registry"; /** Where a system that declares no `inputDir` keeps its sources, for what sits beside them. */
8
8
  readonly inputRoot: "src/uds"; /** The prefix a system's sources are imported by: `@/uds/components/card`. */
9
9
  readonly sourceAlias: "@/uds"; /** The prefix its build output is imported by: `#uds/components/card`. */
10
- readonly outputAlias: "#uds";
10
+ readonly outputAlias: "#uds"; /** The React major the app runs, which decides how an emitted component takes its `ref`. */
11
+ readonly react: 19;
11
12
  };
12
13
  //#endregion
13
14
  export { BUILD_DEFAULTS };
@@ -34,7 +34,9 @@ const BUILD_DEFAULTS = {
34
34
  /** The prefix a system's sources are imported by: `@/uds/components/card`. */
35
35
  sourceAlias: "@/uds",
36
36
  /** The prefix its build output is imported by: `#uds/components/card`. */
37
- outputAlias: "#uds"
37
+ outputAlias: "#uds",
38
+ /** The React major the app runs, which decides how an emitted component takes its `ref`. */
39
+ react: 19
38
40
  };
39
41
  const buildFields = z.strictObject({
40
42
  /**
@@ -113,6 +115,21 @@ const buildFields = z.strictObject({
113
115
  title: "Registry directory",
114
116
  description: `Where \`uds install\` places the sources of linked systems, relative to the config. Unset, \`registry/\` beside the system's components: \`${BUILD_DEFAULTS.registryDir}\` unless \`inputDir\` names another root.`,
115
117
  default: BUILD_DEFAULTS.registryDir
118
+ }).optional(),
119
+ /**
120
+ * The React major the app this repo builds for runs — see `appBuildReact` in the CLI.
121
+ *
122
+ * React 19 hands a function component its call site's `ref` as a prop, and every emitted module
123
+ * relies on that: the ref rides the props bag onto the root like any other attribute. React 18
124
+ * strips it before the component runs, so for 18 each web module is wrapped in `forwardRef` and the
125
+ * ref goes back into the bag. Declared rather than detected from the installed React, so a build
126
+ * says the same thing on every machine. Only a repo's own `uds build` and `uds dev` read it; what
127
+ * Create builds runs on Create's React.
128
+ */
129
+ react: z.union([z.literal(18), z.literal(19)]).meta({
130
+ title: "React version",
131
+ description: `The React major the app this repo builds for runs. \`18\` wraps each emitted web component in \`forwardRef\`, so a call site's \`ref\` reaches its element. Unset, \`${BUILD_DEFAULTS.react}\`.`,
132
+ default: BUILD_DEFAULTS.react
116
133
  }).optional()
117
134
  });
118
135
  //#endregion
@@ -39,6 +39,7 @@ declare const ReactNativeSystemDefinition: ConfigClass<{
39
39
  sourceAlias: _$zod.ZodOptional<_$zod.ZodString>;
40
40
  outputAlias: _$zod.ZodOptional<_$zod.ZodString>;
41
41
  registryDir: _$zod.ZodOptional<_$zod.ZodString>;
42
+ react: _$zod.ZodOptional<_$zod.ZodUnion<readonly [_$zod.ZodLiteral<18>, _$zod.ZodLiteral<19>]>>;
42
43
  }, _$zod_v4_core0.$strict>>;
43
44
  css: _$zod.ZodOptional<_$zod.ZodObject<{
44
45
  prefix: _$zod.ZodOptional<_$zod.ZodUnion<readonly [_$zod.ZodString, _$zod.ZodObject<{
@@ -60,6 +60,7 @@ import { systemIncludeMigration } from "../migrations/20261005225949_system_incl
60
60
  import { motionVariantsAndLayoutMigration } from "../migrations/20261006125609_motion_variants_and_layout.js";
61
61
  import { systemScriptsMigration } from "../migrations/20261007182932_system_scripts.js";
62
62
  import { styleNumbersNameNumericValuesMigration } from "../migrations/20261007210309_style_numbers_name_numeric_values.js";
63
+ import { buildReactMigration } from "../migrations/20261008181849_build_react.js";
63
64
  const System = defineConfig({
64
65
  name: WEB_CONFIG_NAME,
65
66
  description: "A design system: the values, primitives and compositions an app is built from. A ref is written `{ \"__ref\": \"<kind>:<path>\" }`, so a token is `{ \"__ref\": \"token:<group>/<name>\" }` and a token group is `{ \"__ref\": \"token:<group>\" }`. Build it in this order. Tokens first, in groups by purpose (colors, spacing, radii, type sizes), since everything else names them. Then style properties, each with `values` holding one ref to the token group whose members it accepts (`{ \"__ref\": \"token:color\" }`), so a prop takes token names rather than raw CSS; add a string keyword only for a value no token holds. A style rule's bag holds a prop's values (`\"padding\": \"4\"`, `\"bg\": \"brand\"`), never raw CSS. Then a few primitive components, one layer each, whose props are style properties (a box for layout and surface, a text for type, a pressable for interaction). Then every other component composed from those primitives: its layers name a primitive or an element, its anatomy places them (a node renders a layer, a tag or `Slot` where a slot prop's content lands; `children` is the edge list; `visible` is `{ \"$state\": \"<prop>\" }`; a prop shown in a nested layer is a `forward` route, and `$state` never sits in a node's props), and its style rules set style-property values per layer, keyed by prop values when a variant changes them. Modes (a dark mode is `{ type: \"selector\", value: \".dark\" }`) change token values through a token's `overrides`, so a component never restyles for a mode; modifiers (hover, focus, disabled) name a state, and a style rule applies under one as a `_hover` block inside a layer bag. Composites bundle style values that recur. Last, register canvas roles: the canvas draws with them, one entity per tool (`frame` for the layout primitive, `text` for the text primitive, `image`) whose entries name the components that tool inserts, and a tool whose role is unregistered is disabled. Give each component a `preview` entry under `*` so it shows content, and never write a CSS property name where a style-property name belongs.",
@@ -131,5 +132,6 @@ if (!registeredSchemaMigrations().has(20261005225949)) registerSchemaMigrations(
131
132
  if (!registeredSchemaMigrations().has(20261006125609)) registerSchemaMigrations(motionVariantsAndLayoutMigration);
132
133
  if (!registeredSchemaMigrations().has(20261007182932)) registerSchemaMigrations(systemScriptsMigration);
133
134
  if (!registeredSchemaMigrations().has(20261007210309)) registerSchemaMigrations(styleNumbersNameNumericValuesMigration);
135
+ if (!registeredSchemaMigrations().has(20261008181849)) registerSchemaMigrations(buildReactMigration);
134
136
  //#endregion
135
137
  export { System };
@@ -30,6 +30,7 @@ declare const NativeSettings: EntityClass<z.ZodObject<Omit<{
30
30
  sourceAlias: z.ZodOptional<z.ZodString>;
31
31
  outputAlias: z.ZodOptional<z.ZodString>;
32
32
  registryDir: z.ZodOptional<z.ZodString>;
33
+ react: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<18>, z.ZodLiteral<19>]>>;
33
34
  }, z.core.$strict>>;
34
35
  css: z.ZodOptional<z.ZodObject<{
35
36
  prefix: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
@@ -23,6 +23,7 @@ declare const BuildSectionDefinition: SubEntityClass<z.ZodObject<{
23
23
  sourceAlias: z.ZodOptional<z.ZodString>;
24
24
  outputAlias: z.ZodOptional<z.ZodString>;
25
25
  registryDir: z.ZodOptional<z.ZodString>;
26
+ react: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<18>, z.ZodLiteral<19>]>>;
26
27
  }, z.core.$strict>>;
27
28
  interface BuildSectionClass extends Named<typeof BuildSectionDefinition> {}
28
29
  declare const BuildSection: BuildSectionClass;
@@ -105,6 +106,7 @@ declare const SettingsDefinition: EntityClass<z.ZodObject<{
105
106
  sourceAlias: z.ZodOptional<z.ZodString>;
106
107
  outputAlias: z.ZodOptional<z.ZodString>;
107
108
  registryDir: z.ZodOptional<z.ZodString>;
109
+ react: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<18>, z.ZodLiteral<19>]>>;
108
110
  }, z.core.$strict>>;
109
111
  css: z.ZodOptional<z.ZodObject<{
110
112
  prefix: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
@@ -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 = 20261007210309;
76
+ declare const SERIALIZED_CONFIG_VERSION = 20261008181849;
77
77
  interface SerializedConfig {
78
78
  /** See {@link SERIALIZED_CONFIG_VERSION}. Always written; a stored artifact may lack it. */
79
79
  readonly version: number;
@@ -5425,7 +5425,7 @@ var Config = class Config {
5425
5425
  * links from the provided sources. A declared `linkedKind` with no provided source throws. */
5426
5426
  hydrateFrom(stored, options) {
5427
5427
  const claimed = schemaVersionOf(stored);
5428
- if (claimed > 20261007210309) throw new SchemaVersionTooNew(claimed);
5428
+ if (claimed > 20261008181849) throw new SchemaVersionTooNew(claimed);
5429
5429
  const wire = upgradeSerializedConfig(stored);
5430
5430
  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, or port the repo once with \`uds migrate\`.`);
5431
5431
  const leftover = wire.options;
@@ -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 = 20261007210309;
18
+ declare const CURRENT_SCHEMA_VERSION = 20261008181849;
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 = 20261007210309;
16
+ const CURRENT_SCHEMA_VERSION = 20261008181849;
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 > 20261007210309) 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 > 20261008181849) 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 ?? 20261007210309;
105
+ const target = options?.target ?? 20261008181849;
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 ?? 20261007210309;
163
+ const target = options?.target ?? 20261008181849;
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 ?? 20261007210309;
182
+ const target = options?.target ?? 20261008181849;
183
183
  const entries = [];
184
184
  const held = [];
185
185
  const retired = [];
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Additions only, so the envelope passes through as it is:
3
+ *
4
+ * - A system's `settings.build` may name `react`: the React major (`18` or `19`) the app this repo
5
+ * builds for runs. `18` has a local build wrap each emitted web component in `forwardRef`.
6
+ */
7
+ import type { SchemaMigration } from '../framework/schema-version';
8
+ export declare const BUILD_REACT_VERSION = 20261008181849;
9
+ export declare const buildReactMigration: SchemaMigration;
@@ -0,0 +1,10 @@
1
+ //#region src/migrations/20261008181849_build_react.ts
2
+ const BUILD_REACT_VERSION = 20261008181849;
3
+ const buildReactMigration = {
4
+ version: BUILD_REACT_VERSION,
5
+ up(json) {
6
+ return json;
7
+ }
8
+ };
9
+ //#endregion
10
+ export { BUILD_REACT_VERSION, buildReactMigration };
@@ -112,18 +112,27 @@ function runtimeComponent(componentRef, scope) {
112
112
  const rebuilding = status === "loading";
113
113
  const failed = status === "failed";
114
114
  const error = failed ? store?.error?.(componentRef) : void 0;
115
- useEffect(() => store?.activate(componentRef), [store, rebuilding]);
115
+ useEffect(() => store?.activate(componentRef), [
116
+ store,
117
+ componentRef,
118
+ rebuilding
119
+ ]);
116
120
  useEffect(() => {
117
121
  if (!reportRebuild || !rebuilding) return;
118
122
  reportRebuild(componentRef, 1);
119
123
  return () => reportRebuild(componentRef, -1);
120
- }, [reportRebuild, rebuilding]);
124
+ }, [
125
+ reportRebuild,
126
+ componentRef,
127
+ rebuilding
128
+ ]);
121
129
  useEffect(() => {
122
130
  if (!reportFailure || !failed) return;
123
131
  reportFailure(componentRef, error, 1);
124
132
  return () => reportFailure(componentRef, error, -1);
125
133
  }, [
126
134
  reportFailure,
135
+ componentRef,
127
136
  failed,
128
137
  error
129
138
  ]);