@yahoo/uds-create-config 5.15.1 → 5.16.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.
- package/dist/capture/class-grammar.js +1 -1
- package/dist/configs/react-native-system.d.ts +31 -1
- package/dist/configs/system.js +2 -0
- package/dist/entities/native/NativeStyleProperty.d.ts +31 -1
- package/dist/entities/system/Component.js +7 -4
- package/dist/entities/system/StyleProperty.d.ts +43 -2
- package/dist/entities/system/StyleProperty.js +86 -6
- package/dist/framework/Config.d.ts +12 -1
- package/dist/framework/Config.js +46 -3
- package/dist/framework/class-names.d.ts +16 -2
- package/dist/framework/class-names.js +45 -9
- package/dist/framework/projections.d.ts +85 -2
- package/dist/framework/projections.js +280 -8
- package/dist/framework/render-spec.js +3 -1
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/framework/value-domain.js +9 -8
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/migrations/20261007210309_style_numbers_name_numeric_values.d.ts +23 -0
- package/dist/migrations/20261007210309_style_numbers_name_numeric_values.js +217 -0
- package/dist/spec/index.d.ts +2 -2
- package/dist/spec/index.js +2 -2
- package/dist/spec/rewrite-refs.d.ts +31 -1
- package/dist/spec/rewrite-refs.js +34 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Ref } from "./utils/refs.js";
|
|
2
2
|
import { ItemOf } from "./defineEntity.js";
|
|
3
|
-
import { StylePropLeaf, StyleProperty } from "../entities/system/StyleProperty.js";
|
|
3
|
+
import { StylePropLeaf, StylePropNumberUnit, StyleProperty } from "../entities/system/StyleProperty.js";
|
|
4
4
|
import { StoredPreviewCondition, UNCONDITIONAL_PREVIEW_KEY, storedPreview, unconditionalPreviewProps } from "./preview-store.js";
|
|
5
5
|
import { Config, ListOptions } from "./Config.js";
|
|
6
6
|
|
|
@@ -142,6 +142,89 @@ declare function stylePropValueLeaves(config: Config, path: string, opts?: ListO
|
|
|
142
142
|
* when the leaf isn't in the prop's domain.
|
|
143
143
|
*/
|
|
144
144
|
declare function stylePropValueFromLeaf(config: Config, path: string, leaf: string): string | undefined;
|
|
145
|
+
/**
|
|
146
|
+
* The leaves a style property's body declares AS NUMBERS: a numeric literal (`values: [1, 2]`) or a
|
|
147
|
+
* numeric alias (`{ alias: 3, value: 'repeat(3, minmax(0, 1fr))' }`). Only these match a bare number
|
|
148
|
+
* — `columns={3}` — while a token's name is a string however it reads (`spacing="4"`, never
|
|
149
|
+
* `spacing={4}`), as is a string alias.
|
|
150
|
+
*/
|
|
151
|
+
declare function bodyNumberLeaves(stored: unknown): string[];
|
|
152
|
+
/** The leaves a style prop declares as numbers ({@link StylePropLeaf.numeric}), by path. */
|
|
153
|
+
declare function stylePropNumberLeaves(config: Config, path: string): string[];
|
|
154
|
+
/**
|
|
155
|
+
* The leaf a bare number names on a style prop — `columns={3}` → `'3'` — or `undefined` when the
|
|
156
|
+
* prop declares no such number (`spacing={4}`, whose `4` is a token's name) or the value isn't a
|
|
157
|
+
* number.
|
|
158
|
+
*/
|
|
159
|
+
declare function stylePropNumberLeaf(config: Config, path: string, value: unknown): string | undefined;
|
|
160
|
+
/** The unit a style property's body reads a bare number in, or `undefined` when it takes none. */
|
|
161
|
+
declare function bodyNumberUnit(stored: unknown): StylePropNumberUnit | undefined;
|
|
162
|
+
/** The unit a style prop reads a bare number in (`maxWidth={600}` with `arbitrary: 'px'`), or
|
|
163
|
+
* `undefined` when it takes none. */
|
|
164
|
+
declare function stylePropNumberUnit(config: Config, path: string): StylePropNumberUnit | undefined;
|
|
165
|
+
/**
|
|
166
|
+
* The CSS a bare number on a style prop is written as, in the unit the prop declares (`arbitrary`):
|
|
167
|
+
* `maxWidth={600}` with `arbitrary: 'px'` is `600px`, `lineHeight={1.5}` with `arbitrary: 'unitless'` is
|
|
168
|
+
* `1.5`. `undefined` for a prop that declares none, for any other value, and for a number the
|
|
169
|
+
* prop declares as a value ({@link stylePropNumberLeaf}), which is that value. A token's name never
|
|
170
|
+
* reads as a number, so `spacing="4"` is the step wherever `spacing={4}` is a length.
|
|
171
|
+
*
|
|
172
|
+
* Read wherever a bag value meets a style prop: the canvas split, a rule's declarations, and the
|
|
173
|
+
* emitted runtime, which carries the same facts in its table.
|
|
174
|
+
*/
|
|
175
|
+
declare function stylePropNumberCss(config: Config, path: string, value: unknown): string | undefined;
|
|
176
|
+
/**
|
|
177
|
+
* The value a bare number on a style prop spelled before a value's type decided what it names: `gap: 6`
|
|
178
|
+
* → `'6'`, where `'6'` is one of the prop's values (UDS-4828). `undefined` when the prop reads the
|
|
179
|
+
* number itself — a number it declares (`columns={3}`) or a length in its unit (`maxWidth={600}`) —
|
|
180
|
+
* and when no value is spelled that way, which validation refuses.
|
|
181
|
+
*
|
|
182
|
+
* Read where a design meets numbers written under the old reading: rows stored before the change,
|
|
183
|
+
* a model's unquoted YAML, the code view's `gap={6}`.
|
|
184
|
+
*/
|
|
185
|
+
declare function stylePropNumberName(config: Config, path: string, value: unknown): string | undefined;
|
|
186
|
+
/**
|
|
187
|
+
* Why a style prop can't read a bare number in a unit, or `undefined` when it can — what an editor
|
|
188
|
+
* says beside its unit picker instead of offering one the config refuses.
|
|
189
|
+
*/
|
|
190
|
+
declare function stylePropNumberUnitRefusal(config: Config, path: string): string | undefined;
|
|
191
|
+
/**
|
|
192
|
+
* A style prop's values whose names are numbers it doesn't declare as numbers — a spacing step `'4'`,
|
|
193
|
+
* an opacity `'50'`. On a prop with a unit these and a bare number part ways: `opacity="50"` is the
|
|
194
|
+
* value, `opacity={50}` is 50 in the unit. Empty when no value is named that way.
|
|
195
|
+
*/
|
|
196
|
+
declare function stylePropNumberNamedLeaves(config: Config, path: string): string[];
|
|
197
|
+
/**
|
|
198
|
+
* `props` with `rewrite` applied to each bare number on a style prop — in modifier blocks, and in
|
|
199
|
+
* `layerProps` bags against the layer's own component. `rewrite` gets the style property the key writes
|
|
200
|
+
* and the number, and answers what to store instead, or `undefined` to keep it. The same object when
|
|
201
|
+
* nothing changed, so a reader can tell a row it rewrote from one it didn't.
|
|
202
|
+
*/
|
|
203
|
+
declare function rewriteStyleNumbers(config: Config, elementType: string | undefined, props: Record<string, unknown>, rewrite: (path: string, value: number) => string | undefined, depth?: number): Record<string, unknown>;
|
|
204
|
+
/** `props` with each bare number spelled as the value it names ({@link stylePropNumberName}). */
|
|
205
|
+
declare function nameStyleNumbers(config: Config, elementType: string | undefined, props: Record<string, unknown>): Record<string, unknown>;
|
|
206
|
+
/**
|
|
207
|
+
* A bare number on a style prop as it painted while the prop read numbers in `before` — a unit, or none
|
|
208
|
+
* — written in a form that paints the same whatever unit the prop reads in: the value it names (`'6'`)
|
|
209
|
+
* or its bracket literal (`[6px]`). `undefined` when it painted nothing then, and for a number the prop
|
|
210
|
+
* declares (`columns={3}`), which reads the same under any unit.
|
|
211
|
+
*
|
|
212
|
+
* What a stored number becomes when its prop's unit changes, so the change doesn't reread it: `gap: 6`
|
|
213
|
+
* named the token `'6'` until `gap` took `px`, and stays that token after.
|
|
214
|
+
*/
|
|
215
|
+
declare function styleNumberAsPainted(config: Config, path: string, value: number, before: StylePropNumberUnit | undefined): string | undefined;
|
|
216
|
+
/**
|
|
217
|
+
* The style properties whose bare-number reading differs between two versions of a config, each with
|
|
218
|
+
* the unit it read numbers in before (`undefined` for none) — what {@link pinStyleNumbers} takes. A
|
|
219
|
+
* property only one version holds isn't a change of reading.
|
|
220
|
+
*/
|
|
221
|
+
declare function styleNumberReadingChanges(before: Config, after: Config): Map<string, StylePropNumberUnit | undefined>;
|
|
222
|
+
/**
|
|
223
|
+
* `props` with each bare number on a prop whose unit changed written as it painted before
|
|
224
|
+
* ({@link styleNumberAsPainted}). `before` maps each such style property's path to the unit it read
|
|
225
|
+
* numbers in before the change, `undefined` for none.
|
|
226
|
+
*/
|
|
227
|
+
declare function pinStyleNumbers(config: Config, elementType: string | undefined, props: Record<string, unknown>, before: ReadonlyMap<string, StylePropNumberUnit | undefined>): Record<string, unknown>;
|
|
145
228
|
/**
|
|
146
229
|
* The token a style-prop leaf binds, as a qualified path — `('bg', 'brand')` → `color/brand`.
|
|
147
230
|
* `undefined` when the leaf is a keyword the system declared rather than a token (`row`,
|
|
@@ -732,4 +815,4 @@ declare function propValueFromAxis(config: Config, path: string, prop: string, v
|
|
|
732
815
|
/** The `value` a string, number or boolean prop declares as its default, per prop. */
|
|
733
816
|
declare function declaredPropDefaults(props: Record<string, unknown> | undefined): Record<string, unknown>;
|
|
734
817
|
//#endregion
|
|
735
|
-
export { IconTool, IndexedPreviewCondition, PreviewMatrix, PropDeclaration, StyleDeclarationGroup, StylePropEntry, StylePropertyItem, VarNaming, authoredBag, authoredValue, className, cssPropValue, cssVar, cssVarRef, declarationKeyName, declaredPropDefaults, declaredPropRouting, declaresCssVariable, glyphComponentOf, glyphLibrariesOf, glyphPropsOf, heldLinked, holdingPreviewConditions, iconToolAxisOptions, iconToolFor, iconToolOf, iconToolsOf, isCustomPropertyKey, keyedPreviewConditions, linkedVarNaming, literalValueOf, memberFromLeaf, memberLeaves, negatedCssValue, opacityPercentage, previewConditionalProps, previewConditions, previewDefaults, previewMatrix, propOwner, propValueDomain, propValueFromAxis, refListOf, renderInterpolated, renderStyleValue, resolveComponentProps, resolveFieldValue, resolveTokenValue, resolveTokenValueUnder, routedBag, sourceVarPrefix, styleAliasesOf, styleDeclarationGroups, styleDeclarations, stylePropEntries, stylePropLeafForToken, stylePropNegates, stylePropTokenGroup, stylePropTokenPath, stylePropTokenValues, stylePropValueFromLeaf, stylePropValueLeaves, stylePropValues, stylePropertiesWriting, stylePropertyAccepts, stylePropertyFor, stylePropertyPathFor, tokenReference, validateComponentProps };
|
|
818
|
+
export { IconTool, IndexedPreviewCondition, PreviewMatrix, PropDeclaration, StyleDeclarationGroup, StylePropEntry, StylePropertyItem, VarNaming, authoredBag, authoredValue, bodyNumberLeaves, bodyNumberUnit, className, cssPropValue, cssVar, cssVarRef, declarationKeyName, declaredPropDefaults, declaredPropRouting, declaresCssVariable, glyphComponentOf, glyphLibrariesOf, glyphPropsOf, heldLinked, holdingPreviewConditions, iconToolAxisOptions, iconToolFor, iconToolOf, iconToolsOf, isCustomPropertyKey, keyedPreviewConditions, linkedVarNaming, literalValueOf, memberFromLeaf, memberLeaves, nameStyleNumbers, negatedCssValue, opacityPercentage, pinStyleNumbers, previewConditionalProps, previewConditions, previewDefaults, previewMatrix, propOwner, propValueDomain, propValueFromAxis, refListOf, renderInterpolated, renderStyleValue, resolveComponentProps, resolveFieldValue, resolveTokenValue, resolveTokenValueUnder, rewriteStyleNumbers, routedBag, sourceVarPrefix, styleAliasesOf, styleDeclarationGroups, styleDeclarations, styleNumberAsPainted, styleNumberReadingChanges, stylePropEntries, stylePropLeafForToken, stylePropNegates, stylePropNumberCss, stylePropNumberLeaf, stylePropNumberLeaves, stylePropNumberName, stylePropNumberNamedLeaves, stylePropNumberUnit, stylePropNumberUnitRefusal, stylePropTokenGroup, stylePropTokenPath, stylePropTokenValues, stylePropValueFromLeaf, stylePropValueLeaves, stylePropValues, stylePropertiesWriting, stylePropertyAccepts, stylePropertyFor, stylePropertyPathFor, tokenReference, validateComponentProps };
|
|
@@ -9,7 +9,7 @@ import { listedIn } from "./utils/enumerated.js";
|
|
|
9
9
|
import "../entities/system/Modifier.js";
|
|
10
10
|
import { createSliceMemo } from "./memo.js";
|
|
11
11
|
import { classPrefixOf, prefixed, varPrefixOf } from "../entities/system/Settings.js";
|
|
12
|
-
import { StyleProperty, leavesOfStylePropValue } from "../entities/system/StyleProperty.js";
|
|
12
|
+
import { StyleProperty, leavesOfStylePropValue, numberUnitRefusal } from "../entities/system/StyleProperty.js";
|
|
13
13
|
import { isConditionalPreview, storedPreview, unconditionalPreviewProps } from "./preview-store.js";
|
|
14
14
|
//#region src/framework/projections.ts
|
|
15
15
|
/**
|
|
@@ -457,6 +457,265 @@ function stylePropValueFromLeaf(config, path, leaf) {
|
|
|
457
457
|
return stylePropEntries(config, path).find((entry) => entry.leaf === leaf)?.value;
|
|
458
458
|
}
|
|
459
459
|
/**
|
|
460
|
+
* The leaves a style property's body declares AS NUMBERS: a numeric literal (`values: [1, 2]`) or a
|
|
461
|
+
* numeric alias (`{ alias: 3, value: 'repeat(3, minmax(0, 1fr))' }`). Only these match a bare number
|
|
462
|
+
* — `columns={3}` — while a token's name is a string however it reads (`spacing="4"`, never
|
|
463
|
+
* `spacing={4}`), as is a string alias.
|
|
464
|
+
*/
|
|
465
|
+
function bodyNumberLeaves(stored) {
|
|
466
|
+
const values = stored?.values ?? [];
|
|
467
|
+
const out = [];
|
|
468
|
+
for (const entry of values) if (typeof entry === "number") out.push(String(entry));
|
|
469
|
+
else if (entry && typeof entry === "object" && "alias" in entry && typeof entry.alias === "number") out.push(String(entry.alias));
|
|
470
|
+
return out;
|
|
471
|
+
}
|
|
472
|
+
/** The leaves a style prop declares as numbers ({@link StylePropLeaf.numeric}), by path. */
|
|
473
|
+
function stylePropNumberLeaves(config, path) {
|
|
474
|
+
return stylePropEntries(config, path).filter((entry) => entry.numeric).map((entry) => entry.leaf);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* The leaf a bare number names on a style prop — `columns={3}` → `'3'` — or `undefined` when the
|
|
478
|
+
* prop declares no such number (`spacing={4}`, whose `4` is a token's name) or the value isn't a
|
|
479
|
+
* number.
|
|
480
|
+
*/
|
|
481
|
+
function stylePropNumberLeaf(config, path, value) {
|
|
482
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
|
|
483
|
+
const leaf = String(value);
|
|
484
|
+
return stylePropNumberLeaves(config, path).includes(leaf) ? leaf : void 0;
|
|
485
|
+
}
|
|
486
|
+
/** The unit a style property's body reads a bare number in, or `undefined` when it takes none. */
|
|
487
|
+
function bodyNumberUnit(stored) {
|
|
488
|
+
const body = stored;
|
|
489
|
+
if (!body?.properties?.length || body.selector || Object.keys(body.declarations ?? {}).length > 0) return;
|
|
490
|
+
return typeof body.arbitrary === "string" ? body.arbitrary : void 0;
|
|
491
|
+
}
|
|
492
|
+
/** The unit a style prop reads a bare number in (`maxWidth={600}` with `arbitrary: 'px'`), or
|
|
493
|
+
* `undefined` when it takes none. */
|
|
494
|
+
function stylePropNumberUnit(config, path) {
|
|
495
|
+
return bodyNumberUnit(config.resolve("style-property", path)?.toJSON());
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* The CSS a bare number on a style prop is written as, in the unit the prop declares (`arbitrary`):
|
|
499
|
+
* `maxWidth={600}` with `arbitrary: 'px'` is `600px`, `lineHeight={1.5}` with `arbitrary: 'unitless'` is
|
|
500
|
+
* `1.5`. `undefined` for a prop that declares none, for any other value, and for a number the
|
|
501
|
+
* prop declares as a value ({@link stylePropNumberLeaf}), which is that value. A token's name never
|
|
502
|
+
* reads as a number, so `spacing="4"` is the step wherever `spacing={4}` is a length.
|
|
503
|
+
*
|
|
504
|
+
* Read wherever a bag value meets a style prop: the canvas split, a rule's declarations, and the
|
|
505
|
+
* emitted runtime, which carries the same facts in its table.
|
|
506
|
+
*/
|
|
507
|
+
function stylePropNumberCss(config, path, value) {
|
|
508
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
|
|
509
|
+
const unit = stylePropNumberUnit(config, path);
|
|
510
|
+
if (unit === void 0) return void 0;
|
|
511
|
+
if (stylePropNumberLeaf(config, path, value) !== void 0) return void 0;
|
|
512
|
+
return unit === "unitless" ? String(value) : `${value}${unit}`;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* The value a bare number on a style prop spelled before a value's type decided what it names: `gap: 6`
|
|
516
|
+
* → `'6'`, where `'6'` is one of the prop's values (UDS-4828). `undefined` when the prop reads the
|
|
517
|
+
* number itself — a number it declares (`columns={3}`) or a length in its unit (`maxWidth={600}`) —
|
|
518
|
+
* and when no value is spelled that way, which validation refuses.
|
|
519
|
+
*
|
|
520
|
+
* Read where a design meets numbers written under the old reading: rows stored before the change,
|
|
521
|
+
* a model's unquoted YAML, the code view's `gap={6}`.
|
|
522
|
+
*/
|
|
523
|
+
function stylePropNumberName(config, path, value) {
|
|
524
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
|
|
525
|
+
if (stylePropNumberLeaf(config, path, value) !== void 0) return void 0;
|
|
526
|
+
if (stylePropNumberUnit(config, path) !== void 0) return void 0;
|
|
527
|
+
const leaf = String(value);
|
|
528
|
+
return stylePropEntries(config, path).some((entry) => entry.leaf === leaf) ? leaf : void 0;
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Why a style prop can't read a bare number in a unit, or `undefined` when it can — what an editor
|
|
532
|
+
* says beside its unit picker instead of offering one the config refuses.
|
|
533
|
+
*/
|
|
534
|
+
function stylePropNumberUnitRefusal(config, path) {
|
|
535
|
+
const body = config.resolve("style-property", path)?.toJSON();
|
|
536
|
+
if (!body) return void 0;
|
|
537
|
+
return numberUnitRefusal({
|
|
538
|
+
...body,
|
|
539
|
+
properties: body.properties ?? []
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* A style prop's values whose names are numbers it doesn't declare as numbers — a spacing step `'4'`,
|
|
544
|
+
* an opacity `'50'`. On a prop with a unit these and a bare number part ways: `opacity="50"` is the
|
|
545
|
+
* value, `opacity={50}` is 50 in the unit. Empty when no value is named that way.
|
|
546
|
+
*/
|
|
547
|
+
function stylePropNumberNamedLeaves(config, path) {
|
|
548
|
+
const numeric = new Set(stylePropNumberLeaves(config, path));
|
|
549
|
+
return stylePropEntries(config, path).map((entry) => entry.leaf).filter((leaf) => leaf !== "" && !numeric.has(leaf) && Number.isFinite(Number(leaf)) && String(Number(leaf)) === leaf);
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* `props` with `rewrite` applied to each bare number on a style prop — in modifier blocks, and in
|
|
553
|
+
* `layerProps` bags against the layer's own component. `rewrite` gets the style property the key writes
|
|
554
|
+
* and the number, and answers what to store instead, or `undefined` to keep it. The same object when
|
|
555
|
+
* nothing changed, so a reader can tell a row it rewrote from one it didn't.
|
|
556
|
+
*/
|
|
557
|
+
function rewriteStyleNumbers(config, elementType, props, rewrite, depth = 0) {
|
|
558
|
+
let next;
|
|
559
|
+
const set = (key, value) => {
|
|
560
|
+
next ??= { ...props };
|
|
561
|
+
next[key] = value;
|
|
562
|
+
};
|
|
563
|
+
for (const [key, value] of Object.entries(props)) if (key === "layerProps") {
|
|
564
|
+
if (depth >= 5 || !isBag(value)) continue;
|
|
565
|
+
const layers = ((elementType ? config.resolve("component", pathOf(elementType)) : void 0)?.body)?.layers;
|
|
566
|
+
let layerProps;
|
|
567
|
+
for (const [layer, bag] of Object.entries(value)) {
|
|
568
|
+
if (!isBag(bag)) continue;
|
|
569
|
+
const element = layers?.[layer];
|
|
570
|
+
const written = rewriteStyleNumbers(config, isRef(element) ? pathOf(element) : void 0, bag, rewrite, depth + 1);
|
|
571
|
+
if (written !== bag) {
|
|
572
|
+
layerProps ??= { ...value };
|
|
573
|
+
layerProps[layer] = written;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
if (layerProps) set(key, layerProps);
|
|
577
|
+
} else if (key.startsWith("_")) {
|
|
578
|
+
if (!isBag(value)) continue;
|
|
579
|
+
const written = rewriteStyleNumbers(config, elementType, value, rewrite, depth);
|
|
580
|
+
if (written !== value) set(key, written);
|
|
581
|
+
} else if (typeof value === "number" && Number.isFinite(value)) {
|
|
582
|
+
const path = stylePropertyPathFor({
|
|
583
|
+
config,
|
|
584
|
+
through: [elementType],
|
|
585
|
+
key
|
|
586
|
+
});
|
|
587
|
+
const written = path === void 0 ? void 0 : rewrite(path, value);
|
|
588
|
+
if (written !== void 0) set(key, written);
|
|
589
|
+
}
|
|
590
|
+
return next ?? props;
|
|
591
|
+
}
|
|
592
|
+
/** `props` with each bare number spelled as the value it names ({@link stylePropNumberName}). */
|
|
593
|
+
function nameStyleNumbers(config, elementType, props) {
|
|
594
|
+
return rewriteStyleNumbers(config, elementType, props, (path, value) => stylePropNumberName(config, path, value));
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* A bare number on a style prop as it painted while the prop read numbers in `before` — a unit, or none
|
|
598
|
+
* — written in a form that paints the same whatever unit the prop reads in: the value it names (`'6'`)
|
|
599
|
+
* or its bracket literal (`[6px]`). `undefined` when it painted nothing then, and for a number the prop
|
|
600
|
+
* declares (`columns={3}`), which reads the same under any unit.
|
|
601
|
+
*
|
|
602
|
+
* What a stored number becomes when its prop's unit changes, so the change doesn't reread it: `gap: 6`
|
|
603
|
+
* named the token `'6'` until `gap` took `px`, and stays that token after.
|
|
604
|
+
*/
|
|
605
|
+
function styleNumberAsPainted(config, path, value, before) {
|
|
606
|
+
if (!Number.isFinite(value)) return void 0;
|
|
607
|
+
if (stylePropNumberLeaf(config, path, value) !== void 0) return void 0;
|
|
608
|
+
if (before !== void 0) return `[${value}${before === "unitless" ? "" : before}]`;
|
|
609
|
+
const leaf = String(value);
|
|
610
|
+
return stylePropEntries(config, path).some((entry) => entry.leaf === leaf) ? leaf : void 0;
|
|
611
|
+
}
|
|
612
|
+
/** A keyed collection with `rewrite` applied to each entry; the same object when none changed. */
|
|
613
|
+
function eachMember(collection, rewrite) {
|
|
614
|
+
if (!isBag(collection)) return collection;
|
|
615
|
+
let next;
|
|
616
|
+
for (const [key, entry] of Object.entries(collection)) {
|
|
617
|
+
const written = isBag(entry) ? rewrite(entry) : entry;
|
|
618
|
+
if (written !== entry) {
|
|
619
|
+
next ??= { ...collection };
|
|
620
|
+
next[key] = written;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
return next ?? collection;
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* A stored component or canvas-role body with {@link pinStyleNumbers} applied to every bag it keeps: a
|
|
627
|
+
* component's style rules (each layer's bag against the component that layer renders), `defaultProps`
|
|
628
|
+
* and `preview` props, an `extend` delta's the same way, and the `defaultProps` a canvas role inserts its
|
|
629
|
+
* component with. The same object when nothing changed.
|
|
630
|
+
*/
|
|
631
|
+
function pinBodyStyleNumbers(config, kind, body, before, self) {
|
|
632
|
+
if (kind === "canvas-role") {
|
|
633
|
+
if (!Array.isArray(body.entries)) return body;
|
|
634
|
+
let changed = false;
|
|
635
|
+
const entries = body.entries.map((entry) => {
|
|
636
|
+
if (!isBag(entry) || !isBag(entry.defaultProps)) return entry;
|
|
637
|
+
const defaultProps = pinStyleNumbers(config, isRef(entry.component) ? pathOf(entry.component) : void 0, entry.defaultProps, before);
|
|
638
|
+
if (defaultProps === entry.defaultProps) return entry;
|
|
639
|
+
changed = true;
|
|
640
|
+
return {
|
|
641
|
+
...entry,
|
|
642
|
+
defaultProps
|
|
643
|
+
};
|
|
644
|
+
});
|
|
645
|
+
return changed ? {
|
|
646
|
+
...body,
|
|
647
|
+
entries
|
|
648
|
+
} : body;
|
|
649
|
+
}
|
|
650
|
+
if (kind !== "component") return body;
|
|
651
|
+
if (isBag(body.extend) && isRef(body)) {
|
|
652
|
+
const extend = pinBodyStyleNumbers(config, kind, body.extend, before, pathOf(body));
|
|
653
|
+
return extend === body.extend ? body : {
|
|
654
|
+
...body,
|
|
655
|
+
extend
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
const layers = isBag(body.layers) ? body.layers : {};
|
|
659
|
+
const layerType = (layer) => {
|
|
660
|
+
const element = layers[layer];
|
|
661
|
+
return isRef(element) ? pathOf(element) : void 0;
|
|
662
|
+
};
|
|
663
|
+
const pin = (type, bag) => isBag(bag) ? pinStyleNumbers(config, type, bag, before) : bag;
|
|
664
|
+
let next;
|
|
665
|
+
const set = (field, value) => {
|
|
666
|
+
if (value === body[field]) return;
|
|
667
|
+
next ??= { ...body };
|
|
668
|
+
next[field] = value;
|
|
669
|
+
};
|
|
670
|
+
set("styles", eachMember(body.styles, (rule) => {
|
|
671
|
+
if (!isBag(rule.layers)) return rule;
|
|
672
|
+
let written;
|
|
673
|
+
for (const [layer, bag] of Object.entries(rule.layers)) {
|
|
674
|
+
const pinned = pin(layerType(layer), bag);
|
|
675
|
+
if (pinned !== bag) {
|
|
676
|
+
written ??= { ...rule.layers };
|
|
677
|
+
written[layer] = pinned;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return written ? {
|
|
681
|
+
...rule,
|
|
682
|
+
layers: written
|
|
683
|
+
} : rule;
|
|
684
|
+
}));
|
|
685
|
+
set("defaultProps", pin(self, body.defaultProps));
|
|
686
|
+
set("preview", eachMember(body.preview, (entry) => {
|
|
687
|
+
const props = pin(self, entry.props);
|
|
688
|
+
return props === entry.props ? entry : {
|
|
689
|
+
...entry,
|
|
690
|
+
props
|
|
691
|
+
};
|
|
692
|
+
}));
|
|
693
|
+
return next ?? body;
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* The style properties whose bare-number reading differs between two versions of a config, each with
|
|
697
|
+
* the unit it read numbers in before (`undefined` for none) — what {@link pinStyleNumbers} takes. A
|
|
698
|
+
* property only one version holds isn't a change of reading.
|
|
699
|
+
*/
|
|
700
|
+
function styleNumberReadingChanges(before, after) {
|
|
701
|
+
const changes = /* @__PURE__ */ new Map();
|
|
702
|
+
for (const prop of StyleProperty.list(after)) {
|
|
703
|
+
if (!before.resolve("style-property", prop.path)) continue;
|
|
704
|
+
const was = stylePropNumberUnit(before, prop.path);
|
|
705
|
+
if (was !== stylePropNumberUnit(after, prop.path)) changes.set(prop.path, was);
|
|
706
|
+
}
|
|
707
|
+
return changes;
|
|
708
|
+
}
|
|
709
|
+
/**
|
|
710
|
+
* `props` with each bare number on a prop whose unit changed written as it painted before
|
|
711
|
+
* ({@link styleNumberAsPainted}). `before` maps each such style property's path to the unit it read
|
|
712
|
+
* numbers in before the change, `undefined` for none.
|
|
713
|
+
*/
|
|
714
|
+
function pinStyleNumbers(config, elementType, props, before) {
|
|
715
|
+
if (before.size === 0) return props;
|
|
716
|
+
return rewriteStyleNumbers(config, elementType, props, (path, value) => before.has(path) ? styleNumberAsPainted(config, path, value, before.get(path)) : void 0);
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
460
719
|
* The token a style-prop leaf binds, as a qualified path — `('bg', 'brand')` → `color/brand`.
|
|
461
720
|
* `undefined` when the leaf is a keyword the system declared rather than a token (`row`,
|
|
462
721
|
* `flex-start`), or isn't in the prop's domain at all.
|
|
@@ -1045,9 +1304,10 @@ function propDeclarations({ config, body, namespace }) {
|
|
|
1045
1304
|
* A flag is written bare (`truncate: true`) and its entry sits under the empty leaf, which is the same
|
|
1046
1305
|
* entry the class `.uds-truncate` is built from. `false` is the prop's absence and has no entry.
|
|
1047
1306
|
*/
|
|
1048
|
-
function leafAuthoredFor(value) {
|
|
1307
|
+
function leafAuthoredFor(config, key, value) {
|
|
1049
1308
|
if (typeof value === "boolean") return value ? "" : void 0;
|
|
1050
|
-
if (typeof value === "string"
|
|
1309
|
+
if (typeof value === "string") return value;
|
|
1310
|
+
if (typeof value === "number") return stylePropNumberLeaf(config, key, value);
|
|
1051
1311
|
}
|
|
1052
1312
|
/**
|
|
1053
1313
|
* The declarations a bag sets on the element itself. Declarations a prop scopes to a `selector` or a
|
|
@@ -1124,7 +1384,7 @@ function styleDeclarationGroups({ config, bag, namespace }) {
|
|
|
1124
1384
|
const keyed = refOfKey(property);
|
|
1125
1385
|
return keyed ? cssVar(config, "token", pathOf(keyed), namespace) : property;
|
|
1126
1386
|
}) : [];
|
|
1127
|
-
const authoredLeafValue = leafAuthoredFor(value);
|
|
1387
|
+
const authoredLeafValue = leafAuthoredFor(config, key, value);
|
|
1128
1388
|
const entry = authoredLeafValue === void 0 ? void 0 : stylePropEntries(config, key).find((candidate) => candidate.leaf === authoredLeafValue);
|
|
1129
1389
|
if (entry?.declarations) {
|
|
1130
1390
|
for (const [key, declaredValue] of Object.entries(entry.declarations)) target[declarationKeyName({
|
|
@@ -1171,11 +1431,14 @@ function styleDeclarationGroups({ config, bag, namespace }) {
|
|
|
1171
1431
|
}
|
|
1172
1432
|
/** One bag value as CSS text, or `undefined` for a flag turned off. */
|
|
1173
1433
|
function renderBagValue({ config, key, value, namespace }) {
|
|
1434
|
+
const number = stylePropNumberCss(config, key, value);
|
|
1435
|
+
if (number !== void 0) return number;
|
|
1174
1436
|
let resolved = value;
|
|
1175
|
-
|
|
1176
|
-
|
|
1437
|
+
const leaf = typeof value === "string" ? value : stylePropNumberLeaf(config, key, value);
|
|
1438
|
+
if (leaf !== void 0) {
|
|
1439
|
+
const qualified = stylePropValueFromLeaf(config, key, leaf);
|
|
1177
1440
|
if (qualified !== void 0) resolved = qualified;
|
|
1178
|
-
}
|
|
1441
|
+
} else if (typeof value === "number") return;
|
|
1179
1442
|
if (typeof value === "boolean") {
|
|
1180
1443
|
if (!value) return void 0;
|
|
1181
1444
|
const bare = stylePropValueFromLeaf(config, key, "");
|
|
@@ -1536,6 +1799,15 @@ function validateComponentProps(config, componentPath, props) {
|
|
|
1536
1799
|
errors.push(`unknown prop \`${name}\``);
|
|
1537
1800
|
continue;
|
|
1538
1801
|
}
|
|
1802
|
+
if (decl.type === "styleProperty" && isRef(decl.value) && stylePropNumberCss(config, splitRef(decl.value.__ref).qualifiedPath, value) !== void 0) continue;
|
|
1803
|
+
if (decl.type === "styleProperty" && typeof value === "number" && isRef(decl.value)) {
|
|
1804
|
+
const path = splitRef(decl.value.__ref).qualifiedPath;
|
|
1805
|
+
if (stylePropNumberLeaf(config, path, value) === void 0) {
|
|
1806
|
+
const declared = stylePropNumberLeaves(config, path);
|
|
1807
|
+
errors.push(declared.length > 0 ? `\`${name}\`: ${value} is not one of the numbers it takes (${declared.join(" | ")})` : `\`${name}\`: takes no number; a value named \`${value}\` is written as the string '${value}'`);
|
|
1808
|
+
}
|
|
1809
|
+
continue;
|
|
1810
|
+
}
|
|
1539
1811
|
const domain = propValueDomain(config, decl);
|
|
1540
1812
|
if (domain && !domain.accepts(String(value))) {
|
|
1541
1813
|
const shown = domain.leaves.slice(0, 8).map((leaf) => `'${leaf}'`).join(" | ");
|
|
@@ -1729,4 +2001,4 @@ function declaredPropDefaults(props) {
|
|
|
1729
2001
|
return out;
|
|
1730
2002
|
}
|
|
1731
2003
|
//#endregion
|
|
1732
|
-
export { LAYER_PROPS, authoredBag, authoredValue, className, cssPropValue, cssVar, cssVarRef, declarationKeyName, declaredPropDefaults, declaredPropRouting, declaresCssVariable, fontStackOf, glyphComponentOf, glyphLibrariesOf, glyphPropsOf, glyphPropsOfBody, heldLinked, holdingPreviewConditions, iconToolAxisOptions, iconToolFor, iconToolOf, iconToolsOf, isCustomPropertyKey, keyedPreviewConditions, layerPropsErrors, linkedVarNaming, literalValueOf, memberFromLeaf, memberLeaves, negatedCssValue, opacityPercentage, previewConditionalProps, previewConditions, previewDefaults, previewMatrix, propOwner, propValueDomain, propValueFromAxis, refListOf, renderInterpolated, renderStyleValue, resolveComponentProps, resolveFieldValue, resolveTokenValue, resolveTokenValueUnder, routedBag, sourceVarPrefix, styleAliasesOf, styleDeclarationGroups, styleDeclarations, stylePropEntries, stylePropLeafForToken, stylePropNegates, stylePropTokenGroup, stylePropTokenPath, stylePropTokenValues, stylePropValueFromLeaf, stylePropValueLeaves, stylePropValues, stylePropertiesWriting, stylePropertyAccepts, stylePropertyFor, stylePropertyPathFor, takenByForward, tokenReference, validateComponentProps };
|
|
2004
|
+
export { LAYER_PROPS, authoredBag, authoredValue, bodyNumberLeaves, bodyNumberUnit, className, cssPropValue, cssVar, cssVarRef, declarationKeyName, declaredPropDefaults, declaredPropRouting, declaresCssVariable, fontStackOf, glyphComponentOf, glyphLibrariesOf, glyphPropsOf, glyphPropsOfBody, heldLinked, holdingPreviewConditions, iconToolAxisOptions, iconToolFor, iconToolOf, iconToolsOf, isCustomPropertyKey, keyedPreviewConditions, layerPropsErrors, linkedVarNaming, literalValueOf, memberFromLeaf, memberLeaves, nameStyleNumbers, negatedCssValue, opacityPercentage, pinBodyStyleNumbers, pinStyleNumbers, previewConditionalProps, previewConditions, previewDefaults, previewMatrix, propOwner, propValueDomain, propValueFromAxis, refListOf, renderInterpolated, renderStyleValue, resolveComponentProps, resolveFieldValue, resolveTokenValue, resolveTokenValueUnder, rewriteStyleNumbers, routedBag, sourceVarPrefix, styleAliasesOf, styleDeclarationGroups, styleDeclarations, styleNumberAsPainted, styleNumberReadingChanges, stylePropEntries, stylePropLeafForToken, stylePropNegates, stylePropNumberCss, stylePropNumberLeaf, stylePropNumberLeaves, stylePropNumberName, stylePropNumberNamedLeaves, stylePropNumberUnit, stylePropNumberUnitRefusal, stylePropTokenGroup, stylePropTokenPath, stylePropTokenValues, stylePropValueFromLeaf, stylePropValueLeaves, stylePropValues, stylePropertiesWriting, stylePropertyAccepts, stylePropertyFor, stylePropertyPathFor, takenByForward, tokenReference, validateComponentProps };
|
|
@@ -1216,6 +1216,7 @@ function expandInstance(sink, path, instanceProps, content, hint, instanceSlots)
|
|
|
1216
1216
|
routes.push(route);
|
|
1217
1217
|
valueRoutes.set(route.layer, routes);
|
|
1218
1218
|
}
|
|
1219
|
+
const forwardsClassName = [...valueRoutes.values()].some((routes) => routes.some((route) => route.from === "className"));
|
|
1219
1220
|
const supplied = {
|
|
1220
1221
|
...declaredDefaults,
|
|
1221
1222
|
...body.defaultProps ?? {},
|
|
@@ -1356,7 +1357,8 @@ function expandInstance(sink, path, instanceProps, content, hint, instanceSlots)
|
|
|
1356
1357
|
...layerProps[layer],
|
|
1357
1358
|
className: classesFor(config, path, layer, state, [
|
|
1358
1359
|
isRoot ? styleClasses : void 0,
|
|
1359
|
-
isRoot ? instanceProps.className : void 0,
|
|
1360
|
+
isRoot && !forwardsClassName ? instanceProps.className : void 0,
|
|
1361
|
+
...(valueRoutes.get(layer) ?? []).filter(({ into }) => into === "className").map(({ from }) => state[from]),
|
|
1360
1362
|
layerProps[layer]?.className
|
|
1361
1363
|
]) || void 0
|
|
1362
1364
|
} : {
|
|
@@ -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 =
|
|
18
|
+
declare const CURRENT_SCHEMA_VERSION = 20261007210309;
|
|
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 =
|
|
16
|
+
const CURRENT_SCHEMA_VERSION = 20261007210309;
|
|
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 >
|
|
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.`);
|
|
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 ??
|
|
105
|
+
const target = options?.target ?? 20261007210309;
|
|
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 ??
|
|
163
|
+
const target = options?.target ?? 20261007210309;
|
|
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 ??
|
|
182
|
+
const target = options?.target ?? 20261007210309;
|
|
183
183
|
const entries = [];
|
|
184
184
|
const held = [];
|
|
185
185
|
const retired = [];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isRef, kindOf, memberOf, pathOf, ref, refSchema } from "./utils/refs.js";
|
|
2
2
|
import { listedIn } from "./utils/enumerated.js";
|
|
3
|
-
import { memberFromLeaf, memberLeaves, refListOf, stylePropValueFromLeaf, stylePropValueLeaves } from "./projections.js";
|
|
3
|
+
import { bodyNumberLeaves, bodyNumberUnit, memberFromLeaf, memberLeaves, refListOf, stylePropValueFromLeaf, stylePropValueLeaves } from "./projections.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
//#region src/framework/value-domain.ts
|
|
6
6
|
/**
|
|
@@ -132,12 +132,12 @@ function buildRefDomainSchema(target, config, seen) {
|
|
|
132
132
|
if (enumerated === void 0) return z.unknown();
|
|
133
133
|
const property = stylePropertyOf(target, config);
|
|
134
134
|
const also = [];
|
|
135
|
-
if (property?.arbitrary
|
|
135
|
+
if (property?.arbitrary) also.push(arbitraryValue);
|
|
136
136
|
if (isFlag(property)) also.push(z.boolean());
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
137
|
+
const numbered = oneOf(bodyNumberLeaves(property));
|
|
138
|
+
if (numbered !== void 0) also.push(z.number().transform(String).pipe(numbered));
|
|
139
|
+
const unit = bodyNumberUnit(property);
|
|
140
|
+
if (unit) also.push(z.number().finite());
|
|
141
141
|
const own = config.entityOf(kindOf(target))?.authoredValue?.({
|
|
142
142
|
config,
|
|
143
143
|
target,
|
|
@@ -150,8 +150,9 @@ function buildRefDomainSchema(target, config, seen) {
|
|
|
150
150
|
refSchema
|
|
151
151
|
], { error: () => {
|
|
152
152
|
const forms = [`one of ${spellValues(leaves)}`];
|
|
153
|
-
if (property?.arbitrary
|
|
154
|
-
if (
|
|
153
|
+
if (property?.arbitrary) forms.push("a bracketed literal such as `[13px]`");
|
|
154
|
+
if (unit) forms.push(unit === "unitless" ? "a number, written as it is" : `a number of \`${unit}\` such as \`600\``);
|
|
155
|
+
else if (numbered !== void 0) forms.push("a number it declares as a value");
|
|
155
156
|
if (isFlag(property)) forms.push("a boolean");
|
|
156
157
|
return `${forms.join(", ")}, or a ref to one of those tokens (\`{ "__ref": "${target}/<name>" }\`)`;
|
|
157
158
|
} }).transform((value) => typeof value === "string" ? refForLeaf(target, value, config) ?? value : value);
|