@yahoo/uds-create-config 4.57.2 → 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 +3 -3
- package/dist/configs/system.d.ts +2 -2
- package/dist/configs/system.js +4 -0
- package/dist/css/value-type.js +2 -2
- package/dist/entities/native/NativeStyleProperty.d.ts +4 -4
- package/dist/entities/system/GlobalStyle.d.ts +2 -0
- package/dist/entities/system/GlobalStyle.js +10 -1
- package/dist/entities/system/Modifier.d.ts +1 -1
- package/dist/entities/system/Token.js +21 -8
- 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/modifier-axis.d.ts +1 -1
- 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 +19 -4
- package/dist/framework/projections.js +33 -9
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/framework/source-integrity.d.ts +1 -1
- package/dist/framework/utils/refs.d.ts +1 -2
- package/dist/framework/utils/refs.js +0 -5
- package/dist/index.d.ts +7 -7
- package/dist/index.js +3 -3
- package/dist/migrations/2.0.0/v1-artifact.d.ts +2 -2
- package/dist/migrations/20261005212405_global_style_on.d.ts +11 -0
- package/dist/migrations/20261005212405_global_style_on.js +10 -0
- 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
|
@@ -7,6 +7,7 @@ import { EntityClass } from "../framework/defineEntity.js";
|
|
|
7
7
|
import { ConfigClass } from "../framework/defineConfig.js";
|
|
8
8
|
import { Named } from "../framework/named.js";
|
|
9
9
|
import { PackageClass } from "../entities/system/Package.js";
|
|
10
|
+
import { CompositeClass } from "../entities/system/Composite.js";
|
|
10
11
|
import { OverrideCondition } from "../entities/system/Token.js";
|
|
11
12
|
import { StylePropValue } from "../entities/system/StyleProperty.js";
|
|
12
13
|
import { ComponentClass } from "../entities/system/Component.js";
|
|
@@ -14,7 +15,6 @@ import { LinkedSystemClass } from "../entities/system/LinkedSystem.js";
|
|
|
14
15
|
import { IconClass } from "../entities/system/Icon.js";
|
|
15
16
|
import { NativeModifierClass } from "../entities/native/NativeModifier.js";
|
|
16
17
|
import { CanvasRoleClass } from "../entities/system/CanvasRole.js";
|
|
17
|
-
import { CompositeClass } from "../entities/system/Composite.js";
|
|
18
18
|
import { DeviceClass } from "../entities/system/Device.js";
|
|
19
19
|
import { FileClass } from "../entities/system/File.js";
|
|
20
20
|
import { FontClass } from "../entities/system/Font.js";
|
|
@@ -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.d.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { ConfigClass } from "../framework/defineConfig.js";
|
|
2
2
|
import { Named } from "../framework/named.js";
|
|
3
3
|
import { PackageClass } from "../entities/system/Package.js";
|
|
4
|
+
import { CompositeClass } from "../entities/system/Composite.js";
|
|
5
|
+
import { ModifierClass } from "../entities/system/Modifier.js";
|
|
4
6
|
import { TokenClass } from "../entities/system/Token.js";
|
|
5
7
|
import { StylePropertyClass } from "../entities/system/StyleProperty.js";
|
|
6
8
|
import { ComponentClass } from "../entities/system/Component.js";
|
|
7
9
|
import { LinkedSystemClass } from "../entities/system/LinkedSystem.js";
|
|
8
10
|
import { IconClass } from "../entities/system/Icon.js";
|
|
9
11
|
import { CanvasRoleClass } from "../entities/system/CanvasRole.js";
|
|
10
|
-
import { CompositeClass } from "../entities/system/Composite.js";
|
|
11
12
|
import { DeviceClass } from "../entities/system/Device.js";
|
|
12
13
|
import { FileClass } from "../entities/system/File.js";
|
|
13
14
|
import { FontClass } from "../entities/system/Font.js";
|
|
14
15
|
import { GlobalStyleClass } from "../entities/system/GlobalStyle.js";
|
|
15
16
|
import { GuidanceClass } from "../entities/system/Guidance.js";
|
|
16
17
|
import { GuidanceStyleClass } from "../entities/system/GuidanceStyle.js";
|
|
17
|
-
import { ModifierClass } from "../entities/system/Modifier.js";
|
|
18
18
|
import { MotionClass } from "../entities/system/Motion.js";
|
|
19
19
|
import { OperationClass } from "../entities/system/Operation.js";
|
|
20
20
|
import { SettingsClass } from "../entities/system/Settings.js";
|
package/dist/configs/system.js
CHANGED
|
@@ -54,6 +54,8 @@ import { styleRulesAsListMigration } from "../migrations/20261001112308_style_ru
|
|
|
54
54
|
import { motionExitAndElementDuplicateMigration } from "../migrations/20261001130958_motion_exit_and_element_duplicate.js";
|
|
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
|
+
import { globalStyleOnMigration } from "../migrations/20261005212405_global_style_on.js";
|
|
58
|
+
import { addAndSubtractMigration } from "../migrations/20261005220312_add_and_subtract.js";
|
|
57
59
|
const System = defineConfig({
|
|
58
60
|
name: WEB_CONFIG_NAME,
|
|
59
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.",
|
|
@@ -119,5 +121,7 @@ if (!registeredSchemaMigrations().has(20261001112308)) registerSchemaMigrations(
|
|
|
119
121
|
if (!registeredSchemaMigrations().has(20261001130958)) registerSchemaMigrations(motionExitAndElementDuplicateMigration);
|
|
120
122
|
if (!registeredSchemaMigrations().has(20261001131e3)) registerSchemaMigrations(layerStyleAndForwardOpsMigration);
|
|
121
123
|
if (!registeredSchemaMigrations().has(20261001162046)) registerSchemaMigrations(oklchAndEmitFieldsMigration);
|
|
124
|
+
if (!registeredSchemaMigrations().has(20261005212405)) registerSchemaMigrations(globalStyleOnMigration);
|
|
125
|
+
if (!registeredSchemaMigrations().has(20261005220312)) registerSchemaMigrations(addAndSubtractMigration);
|
|
122
126
|
//#endregion
|
|
123
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,6 +1,7 @@
|
|
|
1
1
|
import { DerivedColor, OklchColor } from "./color.js";
|
|
2
2
|
import { EntityClass } from "../../framework/defineEntity.js";
|
|
3
3
|
import { Named } from "../../framework/named.js";
|
|
4
|
+
import { ModifierClass } from "./Modifier.js";
|
|
4
5
|
import { z } from "zod";
|
|
5
6
|
|
|
6
7
|
//#region src/entities/system/GlobalStyle.d.ts
|
|
@@ -17,6 +18,7 @@ declare const GlobalStyleDefinition: EntityClass<z.ZodObject<{
|
|
|
17
18
|
selector: z.ZodString;
|
|
18
19
|
declarations: z.ZodRecord<z.ZodString, z.ZodType<Declared, unknown, z.core.$ZodTypeInternals<Declared, unknown>>>;
|
|
19
20
|
important: z.ZodOptional<z.ZodBoolean>;
|
|
21
|
+
on: z.ZodOptional<z.ZodUnion<readonly [ModifierClass, z.ZodArray<ModifierClass>]>>;
|
|
20
22
|
}, z.core.$strict>, z.ZodObject<Record<never, never>, z.core.$strip>, "global-style", {}, Record<never, never>, false, Record<never, never>, Record<never, never>>;
|
|
21
23
|
interface GlobalStyleClass extends Named<typeof GlobalStyleDefinition> {}
|
|
22
24
|
declare const GlobalStyle: GlobalStyleClass;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { refSchema } from "../../framework/utils/refs.js";
|
|
2
2
|
import { derivedColor, oklchColor } from "./color.js";
|
|
3
3
|
import { defineEntity } from "../../framework/defineEntity.js";
|
|
4
|
+
import { overrideConditionSchema } from "./Token.js";
|
|
4
5
|
import { z } from "zod";
|
|
5
6
|
//#region src/entities/system/GlobalStyle.ts
|
|
6
7
|
/**
|
|
@@ -41,7 +42,15 @@ const GlobalStyle = defineEntity({
|
|
|
41
42
|
* layered and a third party's stylesheet (React Flow, CodeMirror's injected theme) is not, so a
|
|
42
43
|
* rule meant to beat one has to say so; the flag lets it while its values stay refs.
|
|
43
44
|
*/
|
|
44
|
-
important: z.boolean().optional().describe("Emit every declaration `!important`, to beat a third party's unlayered stylesheet.")
|
|
45
|
+
important: z.boolean().optional().describe("Emit every declaration `!important`, to beat a third party's unlayered stylesheet."),
|
|
46
|
+
/**
|
|
47
|
+
* The modifier the rule applies under, or several that all hold at once — the same shape as a
|
|
48
|
+
* token override's `on`. The rule is written through each modifier's own activation, as a
|
|
49
|
+
* component rule is: a state composes onto the selector, a selector mode stands before it as its
|
|
50
|
+
* ancestor (`:root` takes the mode's selector itself), and a media query wraps it. A ref, so
|
|
51
|
+
* renaming the modifier cascades into the rule instead of leaving a hand-copied `.dark` behind.
|
|
52
|
+
*/
|
|
53
|
+
on: overrideConditionSchema.optional().describe("The modifier the rule applies under, or a list that all hold at once: `{ \"__ref\": \"modifier:colorMode/dark\" }`. A state composes onto the selector, a selector mode is its ancestor (`:root` takes the mode itself), a media query wraps the rule. Rules inside `@media` or `@supports` take it too; `@keyframes` and `@font-face` are written as they are.")
|
|
45
54
|
})
|
|
46
55
|
});
|
|
47
56
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { EntityClass } from "../../framework/defineEntity.js";
|
|
2
2
|
import { Named } from "../../framework/named.js";
|
|
3
|
-
import { Config } from "../../framework/Config.js";
|
|
4
3
|
import { CompositeClass } from "./Composite.js";
|
|
5
4
|
import { modifierAxis, modifierCategory } from "./modifier-axis.js";
|
|
5
|
+
import { Config } from "../../framework/Config.js";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
8
8
|
//#region src/entities/system/Modifier.d.ts
|
|
@@ -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,16 +156,29 @@ 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
|
}
|
|
169
182
|
const Token = Object.assign(TokenEntity, { ref: tokenRef });
|
|
170
183
|
//#endregion
|
|
171
|
-
export { Token, defineOverride, overrideCondition, overrideKey, overrideKeyModifiers, overrideModifiers };
|
|
184
|
+
export { Token, defineOverride, overrideCondition, overrideConditionSchema, overrideKey, overrideKeyModifiers, overrideModifiers };
|
|
@@ -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}\`.`;
|