@yahoo/uds-create-config 4.58.0 → 5.0.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/configs/react-native-system.d.ts +2 -2
- package/dist/configs/system.js +2 -0
- package/dist/css/value-type.js +2 -2
- package/dist/entities/native/NativeStyleProperty.d.ts +4 -4
- package/dist/entities/system/Token.js +20 -7
- package/dist/entities/system/calc.d.ts +40 -6
- package/dist/entities/system/calc.js +123 -32
- package/dist/entities/system/composed-values.d.ts +2 -2
- package/dist/entities/system/composed-values.js +25 -8
- package/dist/entities/system/icon-library.js +2 -2
- package/dist/entities/system/linked-token-values.js +2 -2
- package/dist/entities/system/style-bag.js +2 -1
- package/dist/entities/system/token-values.d.ts +32 -9
- package/dist/entities/system/token-values.js +5 -3
- package/dist/framework/Config.d.ts +1 -1
- package/dist/framework/Config.js +1 -1
- package/dist/framework/class-names.js +2 -2
- package/dist/framework/projections.d.ts +12 -1
- package/dist/framework/projections.js +23 -6
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/framework/utils/refs.d.ts +1 -2
- package/dist/framework/utils/refs.js +0 -5
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -3
- package/dist/migrations/20261005220312_add_and_subtract.d.ts +13 -0
- package/dist/migrations/20261005220312_add_and_subtract.js +10 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -105,14 +105,14 @@ declare const ReactNativeSystemDefinition: ConfigClass<{
|
|
|
105
105
|
properties: _$zod.ZodArray<_$zod.ZodPipe<_$zod.ZodPipe<_$zod.ZodString, _$zod.ZodTransform<string, string>>, _$zod.ZodEnum<{
|
|
106
106
|
transform: "transform";
|
|
107
107
|
filter: "filter";
|
|
108
|
-
left: "left";
|
|
109
|
-
right: "right";
|
|
110
108
|
color: "color";
|
|
111
109
|
inset: "inset";
|
|
112
110
|
position: "position";
|
|
113
111
|
end: "end";
|
|
114
112
|
start: "start";
|
|
115
113
|
bottom: "bottom";
|
|
114
|
+
left: "left";
|
|
115
|
+
right: "right";
|
|
116
116
|
top: "top";
|
|
117
117
|
flex: "flex";
|
|
118
118
|
cursor: "cursor";
|
package/dist/configs/system.js
CHANGED
|
@@ -55,6 +55,7 @@ import { motionExitAndElementDuplicateMigration } from "../migrations/2026100113
|
|
|
55
55
|
import { layerStyleAndForwardOpsMigration } from "../migrations/20261001131000_layer_style_and_forward_ops.js";
|
|
56
56
|
import { oklchAndEmitFieldsMigration } from "../migrations/20261001162046_oklch_and_emit_fields.js";
|
|
57
57
|
import { globalStyleOnMigration } from "../migrations/20261005212405_global_style_on.js";
|
|
58
|
+
import { addAndSubtractMigration } from "../migrations/20261005220312_add_and_subtract.js";
|
|
58
59
|
const System = defineConfig({
|
|
59
60
|
name: WEB_CONFIG_NAME,
|
|
60
61
|
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.",
|
|
@@ -121,5 +122,6 @@ if (!registeredSchemaMigrations().has(20261001130958)) registerSchemaMigrations(
|
|
|
121
122
|
if (!registeredSchemaMigrations().has(20261001131e3)) registerSchemaMigrations(layerStyleAndForwardOpsMigration);
|
|
122
123
|
if (!registeredSchemaMigrations().has(20261001162046)) registerSchemaMigrations(oklchAndEmitFieldsMigration);
|
|
123
124
|
if (!registeredSchemaMigrations().has(20261005212405)) registerSchemaMigrations(globalStyleOnMigration);
|
|
125
|
+
if (!registeredSchemaMigrations().has(20261005220312)) registerSchemaMigrations(addAndSubtractMigration);
|
|
124
126
|
//#endregion
|
|
125
127
|
export { System };
|
package/dist/css/value-type.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { evaluateCalc,
|
|
1
|
+
import { evaluateCalc, isCalc } from "../entities/system/calc.js";
|
|
2
2
|
import { composedValueFormOf } from "../entities/system/composed-values.js";
|
|
3
3
|
//#region src/css/value-type.ts
|
|
4
4
|
/**
|
|
@@ -89,7 +89,7 @@ function startsWithAny(value, heads) {
|
|
|
89
89
|
function sniffValueType(value) {
|
|
90
90
|
const formType = composedValueFormOf(value)?.valueType;
|
|
91
91
|
if (formType) return formType;
|
|
92
|
-
if (
|
|
92
|
+
if (isCalc(value)) {
|
|
93
93
|
const literal = evaluateCalc(value, (part) => typeof part === "object" ? void 0 : part);
|
|
94
94
|
return literal === void 0 ? void 0 : sniffValueType(String(literal));
|
|
95
95
|
}
|
|
@@ -8,14 +8,14 @@ import { z } from "zod";
|
|
|
8
8
|
declare const rnStyleKey: z.ZodEnum<{
|
|
9
9
|
transform: "transform";
|
|
10
10
|
filter: "filter";
|
|
11
|
-
left: "left";
|
|
12
|
-
right: "right";
|
|
13
11
|
color: "color";
|
|
14
12
|
inset: "inset";
|
|
15
13
|
position: "position";
|
|
16
14
|
end: "end";
|
|
17
15
|
start: "start";
|
|
18
16
|
bottom: "bottom";
|
|
17
|
+
left: "left";
|
|
18
|
+
right: "right";
|
|
19
19
|
top: "top";
|
|
20
20
|
flex: "flex";
|
|
21
21
|
cursor: "cursor";
|
|
@@ -180,14 +180,14 @@ declare const NativeStyleProperty: EntityClass<z.ZodObject<Omit<{
|
|
|
180
180
|
properties: z.ZodArray<z.ZodPipe<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>, z.ZodEnum<{
|
|
181
181
|
transform: "transform";
|
|
182
182
|
filter: "filter";
|
|
183
|
-
left: "left";
|
|
184
|
-
right: "right";
|
|
185
183
|
color: "color";
|
|
186
184
|
inset: "inset";
|
|
187
185
|
position: "position";
|
|
188
186
|
end: "end";
|
|
189
187
|
start: "start";
|
|
190
188
|
bottom: "bottom";
|
|
189
|
+
left: "left";
|
|
190
|
+
right: "right";
|
|
191
191
|
top: "top";
|
|
192
192
|
flex: "flex";
|
|
193
193
|
cursor: "cursor";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isRef, pathOf, ref, sourceOf } from "../../framework/utils/refs.js";
|
|
1
|
+
import { isRef, pathOf, ref, refKey, sourceOf } from "../../framework/utils/refs.js";
|
|
2
2
|
import { composedValueSchemas } from "./composed-values.js";
|
|
3
3
|
import { defineEntity } from "../../framework/defineEntity.js";
|
|
4
4
|
import { defineSubEntity } from "../../framework/defineSubEntity.js";
|
|
@@ -6,7 +6,7 @@ import { Font } from "./Font.js";
|
|
|
6
6
|
import { Modifier } from "./Modifier.js";
|
|
7
7
|
import { WEB_CONFIG_NAME } from "../../configs/platform.js";
|
|
8
8
|
import { authoringPhantom } from "../../framework/utils/authoring-phantom.js";
|
|
9
|
-
import {
|
|
9
|
+
import { spellTokenRead } from "./token-values.js";
|
|
10
10
|
import { prepareLinkedTokenBody } from "./linked-token-values.js";
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
//#region src/entities/system/Token.ts
|
|
@@ -156,13 +156,26 @@ const TokenEntity = defineEntity({
|
|
|
156
156
|
const baseTokenRef = TokenEntity.ref.bind(TokenEntity);
|
|
157
157
|
function tokenRef(path) {
|
|
158
158
|
const value = baseTokenRef(path);
|
|
159
|
-
|
|
159
|
+
const phantom = (reader) => () => authoringPhantom({ spelled: spellTokenRead({
|
|
160
|
+
path,
|
|
161
|
+
reader
|
|
162
|
+
}) });
|
|
163
|
+
for (const reader of [
|
|
164
|
+
"value",
|
|
165
|
+
"px",
|
|
166
|
+
"ms"
|
|
167
|
+
]) Object.defineProperty(value, reader, {
|
|
168
|
+
enumerable: false,
|
|
169
|
+
configurable: false,
|
|
170
|
+
value: phantom(reader)
|
|
171
|
+
});
|
|
172
|
+
Object.defineProperty(value, "cssVariable", {
|
|
160
173
|
enumerable: false,
|
|
161
174
|
configurable: false,
|
|
162
|
-
value: (
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
})
|
|
175
|
+
value: Object.freeze({
|
|
176
|
+
name: () => refKey(value.__ref),
|
|
177
|
+
var: phantom("cssVariable.var")
|
|
178
|
+
})
|
|
166
179
|
});
|
|
167
180
|
return value;
|
|
168
181
|
}
|
|
@@ -2,27 +2,61 @@ import { Ref } from "../../framework/utils/refs.js";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
4
|
//#region src/entities/system/calc.d.ts
|
|
5
|
-
/**
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* One term of the arithmetic: a number, a CSS length such as `0.25rem`, a ref to a token, or more
|
|
7
|
+
* arithmetic — `add(Token.ref('gap'), multiply(Token.ref('spacing'), 2))`.
|
|
8
|
+
*/
|
|
9
|
+
type CalcOperand = number | string | Ref | Calc;
|
|
7
10
|
interface Multiply {
|
|
8
11
|
readonly multiply: readonly [CalcOperand, CalcOperand];
|
|
9
12
|
}
|
|
10
13
|
interface Divide {
|
|
11
14
|
readonly divide: readonly [CalcOperand, CalcOperand];
|
|
12
15
|
}
|
|
16
|
+
/** The terms summed, in order: `calc(a + b + c)`. */
|
|
17
|
+
interface Add {
|
|
18
|
+
readonly add: readonly CalcOperand[];
|
|
19
|
+
}
|
|
20
|
+
/** The first term less each of the rest, in order: `calc(a - b - c)`. */
|
|
21
|
+
interface Subtract {
|
|
22
|
+
readonly subtract: readonly CalcOperand[];
|
|
23
|
+
}
|
|
24
|
+
/** Any arithmetic on values. */
|
|
25
|
+
type Calc = Multiply | Divide | Add | Subtract;
|
|
13
26
|
/** Whether a value is a `multiply(…)`. */
|
|
14
27
|
declare function isMultiply(value: unknown): value is Multiply;
|
|
15
28
|
/** Whether a value is a `divide(…)`. */
|
|
16
29
|
declare function isDivide(value: unknown): value is Divide;
|
|
30
|
+
/** Whether a value is an `add(…)`. */
|
|
31
|
+
declare function isAdd(value: unknown): value is Add;
|
|
32
|
+
/** Whether a value is a `subtract(…)`. */
|
|
33
|
+
declare function isSubtract(value: unknown): value is Subtract;
|
|
34
|
+
/** Whether a value is arithmetic of any kind. */
|
|
35
|
+
declare function isCalc(value: unknown): value is Calc;
|
|
36
|
+
/** The CSS operator an arithmetic value applies between its terms. */
|
|
37
|
+
declare function calcOperator(value: Calc): '*' | '/' | '+' | '-';
|
|
38
|
+
/** An arithmetic value's terms, in order. */
|
|
39
|
+
declare function calcOperands(value: Calc): readonly CalcOperand[];
|
|
17
40
|
/** `multiply(Token.ref('spacing'), 4)` — the first operand times the second. */
|
|
18
41
|
declare function multiply(left: CalcOperand, right: CalcOperand): Multiply;
|
|
19
42
|
/** `divide(1.25, 0.875)` — the first operand over the second. */
|
|
20
43
|
declare function divide(left: CalcOperand, right: CalcOperand): Divide;
|
|
44
|
+
/** `add(Token.ref('gap'), Token.ref('spacing'))` — every term summed, two or more. */
|
|
45
|
+
declare function add(first: CalcOperand, second: CalcOperand, ...rest: CalcOperand[]): Add;
|
|
46
|
+
/** `subtract(Token.ref('track'), Token.ref('handle'))` — the first term less each of the rest. */
|
|
47
|
+
declare function subtract(first: CalcOperand, second: CalcOperand, ...rest: CalcOperand[]): Subtract;
|
|
21
48
|
/**
|
|
22
49
|
* What the arithmetic comes to, given each operand's literal — `1rem` for `0.25rem` times 4,
|
|
23
|
-
* `1.4286` for `1.25` over `0.875` — or `undefined` when the
|
|
24
|
-
* their units don't combine. `literal` resolves an operand (a
|
|
50
|
+
* `1.4286` for `1.25` over `0.875`, `1.5rem` for `1rem` plus `0.5rem` — or `undefined` when the
|
|
51
|
+
* operands are not plain quantities or their units don't combine. `literal` resolves an operand (a
|
|
52
|
+
* ref to the token's value); a term that is arithmetic itself is worked out first, with the same
|
|
53
|
+
* `literal`.
|
|
54
|
+
*
|
|
55
|
+
* A sum or a difference takes terms of one unit, since that is the only case that comes to one
|
|
56
|
+
* quantity here: `1rem + 4px` is real CSS the browser works out, and has no literal of its own.
|
|
57
|
+
* A plain number and a length don't add, in CSS or here: `calc(0 + 4px)` is invalid, so a zero
|
|
58
|
+
* term needs its unit (`'0px'`).
|
|
25
59
|
*/
|
|
26
|
-
declare function evaluateCalc(value:
|
|
60
|
+
declare function evaluateCalc(value: Calc, literal: (part: Exclude<CalcOperand, Calc>) => string | number | undefined): string | number | undefined;
|
|
27
61
|
//#endregion
|
|
28
|
-
export { CalcOperand, Divide, Multiply, divide, evaluateCalc, isDivide, isMultiply, multiply };
|
|
62
|
+
export { Add, Calc, CalcOperand, Divide, Multiply, Subtract, add, calcOperands, calcOperator, divide, evaluateCalc, isAdd, isCalc, isDivide, isMultiply, isSubtract, multiply, subtract };
|
|
@@ -3,28 +3,65 @@ import { z } from "zod";
|
|
|
3
3
|
//#region src/entities/system/calc.ts
|
|
4
4
|
/**
|
|
5
5
|
* A value that is arithmetic on others — `multiply(Token.ref('spacing'), 4)` is
|
|
6
|
-
* `calc(var(--spacing) * 4)`,
|
|
6
|
+
* `calc(var(--spacing) * 4)`, `divide(1.25, 0.875)` is `calc(1.25 / 0.875)`, and
|
|
7
|
+
* `add(Token.ref('gap'), Token.ref('spacing'))` is `calc(var(--gap) + var(--spacing))`.
|
|
7
8
|
*
|
|
8
9
|
* Held as its operands rather than as the `calc()` string so a ref in it stays a ref: a rename
|
|
9
10
|
* follows into it, the dependency graph sees it, and a reader can work out what it comes to
|
|
10
11
|
* (`spacing` at `0.25rem` times 4 is `1rem`) where a string would only be text.
|
|
11
12
|
*/
|
|
12
|
-
const operand = z.union([
|
|
13
|
+
const operand = z.lazy(() => z.union([
|
|
13
14
|
z.number(),
|
|
14
15
|
z.string().min(1),
|
|
15
|
-
refSchema
|
|
16
|
-
|
|
16
|
+
refSchema,
|
|
17
|
+
multiplyValue,
|
|
18
|
+
divideValue,
|
|
19
|
+
addValue,
|
|
20
|
+
subtractValue
|
|
21
|
+
]));
|
|
17
22
|
const operands = z.tuple([operand, operand]);
|
|
23
|
+
/** A sum or a difference takes two terms or more, so `add(a, b, c)` needs no nesting. */
|
|
24
|
+
const terms = z.array(operand).min(2);
|
|
18
25
|
const multiplyValue = z.strictObject({ multiply: operands });
|
|
19
26
|
const divideValue = z.strictObject({ divide: operands });
|
|
27
|
+
const addValue = z.strictObject({ add: terms });
|
|
28
|
+
const subtractValue = z.strictObject({ subtract: terms });
|
|
20
29
|
const isPair = (value) => Array.isArray(value) && value.length === 2;
|
|
30
|
+
const isTerms = (value) => Array.isArray(value) && value.length >= 2;
|
|
31
|
+
const isObject = (value) => typeof value === "object" && value !== null;
|
|
21
32
|
/** Whether a value is a `multiply(…)`. */
|
|
22
33
|
function isMultiply(value) {
|
|
23
|
-
return
|
|
34
|
+
return isObject(value) && isPair(value.multiply);
|
|
24
35
|
}
|
|
25
36
|
/** Whether a value is a `divide(…)`. */
|
|
26
37
|
function isDivide(value) {
|
|
27
|
-
return
|
|
38
|
+
return isObject(value) && isPair(value.divide);
|
|
39
|
+
}
|
|
40
|
+
/** Whether a value is an `add(…)`. */
|
|
41
|
+
function isAdd(value) {
|
|
42
|
+
return isObject(value) && isTerms(value.add);
|
|
43
|
+
}
|
|
44
|
+
/** Whether a value is a `subtract(…)`. */
|
|
45
|
+
function isSubtract(value) {
|
|
46
|
+
return isObject(value) && isTerms(value.subtract);
|
|
47
|
+
}
|
|
48
|
+
/** Whether a value is arithmetic of any kind. */
|
|
49
|
+
function isCalc(value) {
|
|
50
|
+
return isMultiply(value) || isDivide(value) || isAdd(value) || isSubtract(value);
|
|
51
|
+
}
|
|
52
|
+
/** The CSS operator an arithmetic value applies between its terms. */
|
|
53
|
+
function calcOperator(value) {
|
|
54
|
+
if (isMultiply(value)) return "*";
|
|
55
|
+
if (isDivide(value)) return "/";
|
|
56
|
+
if (isAdd(value)) return "+";
|
|
57
|
+
return "-";
|
|
58
|
+
}
|
|
59
|
+
/** An arithmetic value's terms, in order. */
|
|
60
|
+
function calcOperands(value) {
|
|
61
|
+
if (isMultiply(value)) return value.multiply;
|
|
62
|
+
if (isDivide(value)) return value.divide;
|
|
63
|
+
if (isAdd(value)) return value.add;
|
|
64
|
+
return value.subtract;
|
|
28
65
|
}
|
|
29
66
|
/** `multiply(Token.ref('spacing'), 4)` — the first operand times the second. */
|
|
30
67
|
function multiply(left, right) {
|
|
@@ -34,15 +71,33 @@ function multiply(left, right) {
|
|
|
34
71
|
function divide(left, right) {
|
|
35
72
|
return { divide: [left, right] };
|
|
36
73
|
}
|
|
37
|
-
/**
|
|
38
|
-
function
|
|
39
|
-
|
|
40
|
-
|
|
74
|
+
/** `add(Token.ref('gap'), Token.ref('spacing'))` — every term summed, two or more. */
|
|
75
|
+
function add(first, second, ...rest) {
|
|
76
|
+
return { add: [
|
|
77
|
+
first,
|
|
78
|
+
second,
|
|
79
|
+
...rest
|
|
80
|
+
] };
|
|
81
|
+
}
|
|
82
|
+
/** `subtract(Token.ref('track'), Token.ref('handle'))` — the first term less each of the rest. */
|
|
83
|
+
function subtract(first, second, ...rest) {
|
|
84
|
+
return { subtract: [
|
|
85
|
+
first,
|
|
86
|
+
second,
|
|
87
|
+
...rest
|
|
88
|
+
] };
|
|
41
89
|
}
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Arithmetic as CSS — `calc(var(--spacing) * 4)`, `calc(var(--gap) + var(--spacing))` — with
|
|
92
|
+
* `render` resolving each term. A term that is arithmetic itself is written as its parenthesised
|
|
93
|
+
* expression rather than a second `calc()`, which says the same and reads as the formula it is:
|
|
94
|
+
* `calc(var(--gap) + (var(--spacing) * 2))`. `+` and `-` are spaced, as CSS requires.
|
|
95
|
+
*/
|
|
96
|
+
function renderCalc(value, render) {
|
|
97
|
+
return `calc(${calcOperands(value).map((part) => {
|
|
98
|
+
const css = render(part);
|
|
99
|
+
return isCalc(part) && css.startsWith("calc(") ? css.slice(4) : css;
|
|
100
|
+
}).join(` ${calcOperator(value)} `)})`;
|
|
46
101
|
}
|
|
47
102
|
function multiplyAuthoring(value) {
|
|
48
103
|
return {
|
|
@@ -56,6 +111,18 @@ function divideAuthoring(value) {
|
|
|
56
111
|
args: [...value.divide]
|
|
57
112
|
};
|
|
58
113
|
}
|
|
114
|
+
function addAuthoring(value) {
|
|
115
|
+
return {
|
|
116
|
+
helper: "add",
|
|
117
|
+
args: [...value.add]
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function subtractAuthoring(value) {
|
|
121
|
+
return {
|
|
122
|
+
helper: "subtract",
|
|
123
|
+
args: [...value.subtract]
|
|
124
|
+
};
|
|
125
|
+
}
|
|
59
126
|
const isDigit = (char) => char !== void 0 && char >= "0" && char <= "9";
|
|
60
127
|
/**
|
|
61
128
|
* The plain number a string starts with — an optional minus, digits, and an optional fraction
|
|
@@ -92,30 +159,54 @@ function quantityOf(value) {
|
|
|
92
159
|
}
|
|
93
160
|
/**
|
|
94
161
|
* What the arithmetic comes to, given each operand's literal — `1rem` for `0.25rem` times 4,
|
|
95
|
-
* `1.4286` for `1.25` over `0.875` — or `undefined` when the
|
|
96
|
-
* their units don't combine. `literal` resolves an operand (a
|
|
162
|
+
* `1.4286` for `1.25` over `0.875`, `1.5rem` for `1rem` plus `0.5rem` — or `undefined` when the
|
|
163
|
+
* operands are not plain quantities or their units don't combine. `literal` resolves an operand (a
|
|
164
|
+
* ref to the token's value); a term that is arithmetic itself is worked out first, with the same
|
|
165
|
+
* `literal`.
|
|
166
|
+
*
|
|
167
|
+
* A sum or a difference takes terms of one unit, since that is the only case that comes to one
|
|
168
|
+
* quantity here: `1rem + 4px` is real CSS the browser works out, and has no literal of its own.
|
|
169
|
+
* A plain number and a length don't add, in CSS or here: `calc(0 + 4px)` is invalid, so a zero
|
|
170
|
+
* term needs its unit (`'0px'`).
|
|
97
171
|
*/
|
|
98
172
|
function evaluateCalc(value, literal) {
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
173
|
+
const quantities = [];
|
|
174
|
+
for (const part of calcOperands(value)) {
|
|
175
|
+
const quantity = quantityOf(isCalc(part) ? evaluateCalc(part, literal) : literal(part));
|
|
176
|
+
if (!quantity) return void 0;
|
|
177
|
+
quantities.push(quantity);
|
|
178
|
+
}
|
|
179
|
+
const result = combine(value, quantities);
|
|
180
|
+
if (!result) return void 0;
|
|
181
|
+
const amount = Math.round(result.amount * 1e4) / 1e4;
|
|
182
|
+
return result.unit ? `${amount}${result.unit}` : amount;
|
|
183
|
+
}
|
|
184
|
+
/** The terms' quantities combined by the value's operator, or `undefined` when their units don't. */
|
|
185
|
+
function combine(value, terms) {
|
|
186
|
+
if (isMultiply(value) || isDivide(value)) {
|
|
187
|
+
const [a, b] = terms;
|
|
188
|
+
if (isMultiply(value)) {
|
|
189
|
+
if (a.unit && b.unit) return void 0;
|
|
190
|
+
return {
|
|
191
|
+
amount: a.amount * b.amount,
|
|
192
|
+
unit: a.unit || b.unit
|
|
193
|
+
};
|
|
194
|
+
}
|
|
111
195
|
if (b.amount === 0 || b.unit && b.unit !== a.unit) return void 0;
|
|
112
|
-
|
|
196
|
+
return {
|
|
113
197
|
amount: a.amount / b.amount,
|
|
114
198
|
unit: b.unit ? "" : a.unit
|
|
115
199
|
};
|
|
116
200
|
}
|
|
117
|
-
const
|
|
118
|
-
|
|
201
|
+
const units = new Set(terms.map((term) => term.unit));
|
|
202
|
+
if (units.size > 1) return void 0;
|
|
203
|
+
const unit = [...units][0] ?? "";
|
|
204
|
+
const sign = isAdd(value) ? 1 : -1;
|
|
205
|
+
const [first, ...rest] = terms;
|
|
206
|
+
return {
|
|
207
|
+
amount: rest.reduce((sum, term) => sum + sign * term.amount, first.amount),
|
|
208
|
+
unit
|
|
209
|
+
};
|
|
119
210
|
}
|
|
120
211
|
//#endregion
|
|
121
|
-
export { divide, divideAuthoring, divideValue, evaluateCalc, isDivide, isMultiply, leadingNumber, multiply, multiplyAuthoring, multiplyValue,
|
|
212
|
+
export { add, addAuthoring, addValue, calcOperands, calcOperator, divide, divideAuthoring, divideValue, evaluateCalc, isAdd, isCalc, isDivide, isMultiply, isSubtract, leadingNumber, multiply, multiplyAuthoring, multiplyValue, renderCalc, subtract, subtractAuthoring, subtractValue };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { ValueType } from "../../css/value-type.js";
|
|
2
|
-
import { Divide, Multiply } from "./calc.js";
|
|
2
|
+
import { Add, Divide, Multiply, Subtract } from "./calc.js";
|
|
3
3
|
import { DerivedColor, Gradient, OklchColor } from "./color.js";
|
|
4
4
|
import { Shadow } from "./shadow.js";
|
|
5
5
|
import { Transition } from "./transition.js";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
8
8
|
//#region src/entities/system/composed-values.d.ts
|
|
9
|
-
type ComposedValue = Multiply | Divide | OklchColor | DerivedColor | Gradient | Transition | Shadow;
|
|
9
|
+
type ComposedValue = Multiply | Divide | Add | Subtract | OklchColor | DerivedColor | Gradient | Transition | Shadow;
|
|
10
10
|
/** How the write engine spells a stored value: the helper's name and its positional arguments. */
|
|
11
11
|
interface ComposedValueAuthoring {
|
|
12
12
|
readonly helper: string;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { divideAuthoring, divideValue, evaluateCalc, isDivide, isMultiply, multiplyAuthoring, multiplyValue,
|
|
1
|
+
import { addAuthoring, addValue, calcOperands, divideAuthoring, divideValue, evaluateCalc, isAdd, isCalc, isDivide, isMultiply, isSubtract, multiplyAuthoring, multiplyValue, renderCalc, subtractAuthoring, subtractValue } from "./calc.js";
|
|
2
2
|
import { derivedColor, derivedColorAuthoring, gradient, gradientAuthoring, isDerivedColor, isGradient, isOklchColor, oklchAuthoring, oklchColor, renderDerivedColor, renderGradient, renderOklch } from "./color.js";
|
|
3
3
|
import { isShadow, renderShadow, shadowAuthoring, shadowValue } from "./shadow.js";
|
|
4
4
|
import { isTransition, renderTransition, transitionAuthoring, transitionValue } from "./transition.js";
|
|
5
5
|
//#region src/entities/system/composed-values.ts
|
|
6
|
-
/** Arithmetic as a formula: `spacing × 4`, `1.25 ÷ 0.875`.
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/** Arithmetic as a formula: `spacing × 4`, `1.25 ÷ 0.875`, `gap + (spacing × 2)`. A term that is
|
|
7
|
+
* arithmetic itself is parenthesised, so the formula reads the way it computes. */
|
|
8
|
+
function describeCalc(operator, value, describe) {
|
|
9
|
+
return calcOperands(value).map((part) => isCalc(part) ? `(${describe(part)})` : describe(part)).join(` ${operator} `);
|
|
9
10
|
}
|
|
10
11
|
/** A derived colour as its op: `darken(brand, 10%)`, `mix(brand, white, 30%)`. */
|
|
11
12
|
function describeDerivedColor(value, describe) {
|
|
@@ -23,19 +24,35 @@ const composedValueForms = [
|
|
|
23
24
|
form({
|
|
24
25
|
schema: multiplyValue,
|
|
25
26
|
is: isMultiply,
|
|
26
|
-
render:
|
|
27
|
-
describe: (value, describe) => describeCalc("×", value
|
|
27
|
+
render: renderCalc,
|
|
28
|
+
describe: (value, describe) => describeCalc("×", value, describe),
|
|
28
29
|
evaluate: evaluateCalc,
|
|
29
30
|
authoring: multiplyAuthoring
|
|
30
31
|
}),
|
|
31
32
|
form({
|
|
32
33
|
schema: divideValue,
|
|
33
34
|
is: isDivide,
|
|
34
|
-
render:
|
|
35
|
-
describe: (value, describe) => describeCalc("÷", value
|
|
35
|
+
render: renderCalc,
|
|
36
|
+
describe: (value, describe) => describeCalc("÷", value, describe),
|
|
36
37
|
evaluate: evaluateCalc,
|
|
37
38
|
authoring: divideAuthoring
|
|
38
39
|
}),
|
|
40
|
+
form({
|
|
41
|
+
schema: addValue,
|
|
42
|
+
is: isAdd,
|
|
43
|
+
render: renderCalc,
|
|
44
|
+
describe: (value, describe) => describeCalc("+", value, describe),
|
|
45
|
+
evaluate: evaluateCalc,
|
|
46
|
+
authoring: addAuthoring
|
|
47
|
+
}),
|
|
48
|
+
form({
|
|
49
|
+
schema: subtractValue,
|
|
50
|
+
is: isSubtract,
|
|
51
|
+
render: renderCalc,
|
|
52
|
+
describe: (value, describe) => describeCalc("−", value, describe),
|
|
53
|
+
evaluate: evaluateCalc,
|
|
54
|
+
authoring: subtractAuthoring
|
|
55
|
+
}),
|
|
39
56
|
form({
|
|
40
57
|
schema: oklchColor,
|
|
41
58
|
is: isOklchColor,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createSliceMemo } from "../../framework/memo.js";
|
|
2
|
-
import { glyphComponentOf, glyphLibrariesOf, iconToolFor, iconToolsOf, resolveComponentProps } from "../../framework/projections.js";
|
|
2
|
+
import { glyphComponentOf, glyphLibrariesOf, iconToolFor, iconToolsOf, isCustomPropertyKey, resolveComponentProps } from "../../framework/projections.js";
|
|
3
3
|
import { isValueSlot } from "../../framework/prop-surface.js";
|
|
4
4
|
import { Component } from "./Component.js";
|
|
5
5
|
import { parseGlyphType } from "../../spec/glyph-jsx.js";
|
|
@@ -290,7 +290,7 @@ function isDeclaredElementProp(config, elementType, propName) {
|
|
|
290
290
|
const component = Component.get(config, elementType);
|
|
291
291
|
if (component) {
|
|
292
292
|
if (resolveComponentProps(config, component.path)[propName] !== void 0) return true;
|
|
293
|
-
if (propName
|
|
293
|
+
if (isCustomPropertyKey(propName)) return false;
|
|
294
294
|
return config.resolve("style-property", propName) === void 0;
|
|
295
295
|
}
|
|
296
296
|
const parsed = parseGlyphType(elementType);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { hasRefMarker } from "../../framework/utils/refs.js";
|
|
2
|
-
import {
|
|
2
|
+
import { isCalc } from "./calc.js";
|
|
3
3
|
import { isOklchColor } from "./color.js";
|
|
4
4
|
import { literalValueOf } from "../../framework/projections.js";
|
|
5
5
|
import "../../configs/platform.js";
|
|
@@ -88,7 +88,7 @@ function prepareLinkedTokenBody({ path, body, source, config, destinationPlatfor
|
|
|
88
88
|
*/
|
|
89
89
|
function nativeLiteral({ config, value, remBase }) {
|
|
90
90
|
const marked = typeof value === "string" && hasRefMarker(value);
|
|
91
|
-
const calc =
|
|
91
|
+
const calc = isCalc(value);
|
|
92
92
|
if (!marked && !calc && !isOklchColor(value)) return value;
|
|
93
93
|
const literal = literalValueOf(config, value);
|
|
94
94
|
if (literal === void 0) return value;
|
|
@@ -4,7 +4,7 @@ import { defineSubEntity } from "../../framework/defineSubEntity.js";
|
|
|
4
4
|
import { isCssProperty, kebabCase } from "../../css/values.js";
|
|
5
5
|
import { valueSchemaOf } from "../../framework/value-domain.js";
|
|
6
6
|
import { glyphLeafOf, glyphPackageRef } from "./glyph-identity.js";
|
|
7
|
-
import { glyphPropsOfBody, refListOf, stylePropTokenPath } from "../../framework/projections.js";
|
|
7
|
+
import { glyphPropsOfBody, isCustomPropertyKey, refListOf, stylePropTokenPath } from "../../framework/projections.js";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
//#region src/entities/system/style-bag.ts
|
|
10
10
|
/** The explicit type annotation breaks the `z.lazy` self-reference cycle and keeps the
|
|
@@ -211,6 +211,7 @@ function stylePropertyBehind(config, cssProperty) {
|
|
|
211
211
|
*/
|
|
212
212
|
function bagKeyIssue(config, key, declared, { cssBehind = true } = {}) {
|
|
213
213
|
if (key.startsWith("data-") || key.startsWith("aria-")) return void 0;
|
|
214
|
+
if (isCustomPropertyKey(key)) return void 0;
|
|
214
215
|
if (key.includes("-")) {
|
|
215
216
|
const camel = camelCase(key);
|
|
216
217
|
if (config.resolve("style-property", camel)) return `\`${key}\` is not a style property; a layer key is the style-prop name, \`${camel}\`.`;
|
|
@@ -100,13 +100,22 @@ declare function tokenExists({
|
|
|
100
100
|
* where the token resolves to one value, which is what makes `px('brand')` on a colour an error.
|
|
101
101
|
*/
|
|
102
102
|
interface RegisteredTokenValues {}
|
|
103
|
+
/** A group's readers of one token's custom property, by alias. */
|
|
104
|
+
interface TokenGroupVariableReader<All extends string = string> {
|
|
105
|
+
/** The custom property's name, `--uds-spacing-2_5`, for code that sets or reads the variable
|
|
106
|
+
* itself (`style.setProperty`, a third-party prop that takes a name). */
|
|
107
|
+
name(alias: All): string;
|
|
108
|
+
/** `var(--uds-spacing-2_5)`, the reference the stylesheet's own rules use, so it follows modes. */
|
|
109
|
+
var(alias: All): string;
|
|
110
|
+
}
|
|
103
111
|
/**
|
|
104
|
-
* One token group's readers. `
|
|
105
|
-
* build resolved to one value, so a mode-dependent token is a type error
|
|
112
|
+
* One token group's readers. `cssVariable` is available for every token that declares one; the others
|
|
113
|
+
* only for the tokens the build resolved to one value, so a mode-dependent token is a type error
|
|
114
|
+
* everywhere but `cssVariable`.
|
|
106
115
|
*/
|
|
107
116
|
interface TokenGroupReader<All extends string = string, Static extends string = string, Px extends string = string, Ms extends string = string> {
|
|
108
|
-
/**
|
|
109
|
-
|
|
117
|
+
/** The token's custom property: its `name` and the `var()` that reads it. */
|
|
118
|
+
readonly cssVariable: TokenGroupVariableReader<All>;
|
|
110
119
|
/** The resolved CSS value, `'0.625rem'`. */
|
|
111
120
|
value(alias: Static): string;
|
|
112
121
|
/** The value as CSS pixels: `rem` against the page's root font size (`settings.css.rem`), `px`
|
|
@@ -118,15 +127,28 @@ interface TokenGroupReader<All extends string = string, Static extends string =
|
|
|
118
127
|
/**
|
|
119
128
|
* The readers a token ref offers, by what the build resolved that path to. A path the augmentation
|
|
120
129
|
* knows narrows to the readers its value supports, so `.px()` on a colour is a compile error; a path it
|
|
121
|
-
* does not know — before a build, or a template a prop fills in — keeps all
|
|
130
|
+
* does not know — before a build, or a template a prop fills in — keeps them all.
|
|
122
131
|
*/
|
|
123
132
|
type TokenReaders<P extends string> = P extends keyof RegisteredTokenValues ? ReadersOf<RegisteredTokenValues[P]> : ReadersOf<{
|
|
124
133
|
css: string;
|
|
125
134
|
px: number;
|
|
126
135
|
ms: number;
|
|
127
136
|
}>;
|
|
137
|
+
/** A token ref's readers of the custom property it declares. */
|
|
138
|
+
interface TokenVariableReaders {
|
|
139
|
+
/**
|
|
140
|
+
* The variable's name. In a config it is the declaration key that sets the variable,
|
|
141
|
+
* `{ [Token.ref('button/scale-hover').cssVariable.name()]: Token.ref('scaleEffect/up') }`, in a
|
|
142
|
+
* style rule's layer bag, a global style or a style property's `properties` and `declarations`, so
|
|
143
|
+
* the variable is prefixed, renamed with the token and named through a link. In a render the build
|
|
144
|
+
* writes the name itself, `'--uds-button-scale-hover'`.
|
|
145
|
+
*/
|
|
146
|
+
name(): string;
|
|
147
|
+
/** `var(--uds-spacing-2_5)`, the reference the stylesheet's own rules use, so it follows modes. */
|
|
148
|
+
var(): string;
|
|
149
|
+
}
|
|
128
150
|
type ReadersOf<V> = {
|
|
129
|
-
/**
|
|
151
|
+
/** The token's custom property: its `name` and the `var()` that reads it. */readonly cssVariable: TokenVariableReaders;
|
|
130
152
|
} & (V extends {
|
|
131
153
|
css: string;
|
|
132
154
|
} ? {
|
|
@@ -140,8 +162,9 @@ type ReadersOf<V> = {
|
|
|
140
162
|
} ? {
|
|
141
163
|
ms(): number;
|
|
142
164
|
} : unknown);
|
|
143
|
-
/** The reader names, which is what the build recognizes on a `Token.ref(…)`.
|
|
144
|
-
|
|
165
|
+
/** The reader names, which is what the build recognizes on a `Token.ref(…)`. A dotted name is read
|
|
166
|
+
* through its parts, `Token.ref(path).cssVariable.name()`. */
|
|
167
|
+
declare const TOKEN_READERS: readonly ["value", "px", "ms", "cssVariable.name", "cssVariable.var"];
|
|
145
168
|
type TokenReader = (typeof TOKEN_READERS)[number];
|
|
146
169
|
declare function isTokenReader(name: string): name is TokenReader;
|
|
147
170
|
/** A read as an author spells it: `Token.ref("spacing/2.5").px()`. */
|
|
@@ -153,4 +176,4 @@ declare function spellTokenRead({
|
|
|
153
176
|
reader: TokenReader;
|
|
154
177
|
}): string;
|
|
155
178
|
//#endregion
|
|
156
|
-
export { RegisteredTokenValues, TOKEN_READERS, TokenGroupReader, TokenReader, TokenReaders, TokenValueEntry, TokenValueRow, TokenValueState, isTokenReader, parseTokenValue, rootFontSize, spellTokenRead, tokenExists, tokenValueRow, tokenValueRows };
|
|
179
|
+
export { RegisteredTokenValues, TOKEN_READERS, TokenGroupReader, TokenGroupVariableReader, TokenReader, TokenReaders, TokenValueEntry, TokenValueRow, TokenValueState, TokenVariableReaders, isTokenReader, parseTokenValue, rootFontSize, spellTokenRead, tokenExists, tokenValueRow, tokenValueRows };
|
|
@@ -144,12 +144,14 @@ function modeDecides(config, path, seen = /* @__PURE__ */ new Set()) {
|
|
|
144
144
|
return source ? modeDecides(source, pathOf(target), seen) : false;
|
|
145
145
|
});
|
|
146
146
|
}
|
|
147
|
-
/** The reader names, which is what the build recognizes on a `Token.ref(…)`.
|
|
147
|
+
/** The reader names, which is what the build recognizes on a `Token.ref(…)`. A dotted name is read
|
|
148
|
+
* through its parts, `Token.ref(path).cssVariable.name()`. */
|
|
148
149
|
const TOKEN_READERS = [
|
|
149
|
-
"var",
|
|
150
150
|
"value",
|
|
151
151
|
"px",
|
|
152
|
-
"ms"
|
|
152
|
+
"ms",
|
|
153
|
+
"cssVariable.name",
|
|
154
|
+
"cssVariable.var"
|
|
153
155
|
];
|
|
154
156
|
function isTokenReader(name) {
|
|
155
157
|
return TOKEN_READERS.includes(name);
|
|
@@ -72,7 +72,7 @@ interface RecordedSource {
|
|
|
72
72
|
* The dense-counter `2` a short-lived scheme stamped before the chain existed reads as the mint
|
|
73
73
|
* that replaced it (see `detectedWireVersion`).
|
|
74
74
|
*/
|
|
75
|
-
declare const SERIALIZED_CONFIG_VERSION =
|
|
75
|
+
declare const SERIALIZED_CONFIG_VERSION = 20261005220312;
|
|
76
76
|
interface SerializedConfig {
|
|
77
77
|
/** See {@link SERIALIZED_CONFIG_VERSION}. Always written; a stored artifact may lack it. */
|
|
78
78
|
readonly version: number;
|