@yahoo/uds-create-config 5.32.10 → 5.34.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/entities/canvas/node-gestures.js +28 -2
- package/dist/entities/system/motion-presets.d.ts +5 -3
- package/dist/entities/system/motion-presets.js +65 -15
- package/dist/framework/Config.js +1 -1
- package/dist/migrations/2.0.0/v1-artifact.js +7 -9
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -242,15 +242,41 @@ function remove(config, input) {
|
|
|
242
242
|
path
|
|
243
243
|
}))];
|
|
244
244
|
}
|
|
245
|
+
/** The annotations on `paths`, oldest first, as a layer lists them. */
|
|
246
|
+
function annotationsOn({ config, paths }) {
|
|
247
|
+
return config.list("annotation").map((note) => ({
|
|
248
|
+
...note.body,
|
|
249
|
+
path: note.path
|
|
250
|
+
})).filter((note) => paths.has(pathOf(note.target))).sort((left, right) => (left.authoredAt ?? "").localeCompare(right.authoredAt ?? "") || left.path.localeCompare(right.path));
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Each copy of a duplicated element carries copies of the annotations on it. A copy names no author: the
|
|
254
|
+
* writer who duplicates is its author, and stamps it where the write lands.
|
|
255
|
+
*/
|
|
245
256
|
function duplicate(config, input) {
|
|
246
257
|
const place = placeOf(config, input.path, ["path"]);
|
|
247
258
|
const fresh = freshPaths(config, rootOf(input.path));
|
|
248
259
|
const subtree = subtreeOf(config, input.path);
|
|
260
|
+
const notes = annotationsOn({
|
|
261
|
+
config,
|
|
262
|
+
paths: new Set(subtree)
|
|
263
|
+
});
|
|
249
264
|
const count = input.data?.count ?? 1;
|
|
250
265
|
const patches = [];
|
|
266
|
+
const annotationPatches = [];
|
|
251
267
|
const copies = [];
|
|
252
268
|
for (let n = 0; n < count; n++) {
|
|
253
269
|
const pathFor = new Map(subtree.map((path) => [path, fresh(path.split("/").at(-1) ?? path)]));
|
|
270
|
+
for (const note of notes) annotationPatches.push({
|
|
271
|
+
kind: "annotation",
|
|
272
|
+
operation: "create",
|
|
273
|
+
path: crypto.randomUUID(),
|
|
274
|
+
data: {
|
|
275
|
+
target: ref("node", pathFor.get(pathOf(note.target))),
|
|
276
|
+
...note.layer ? { layer: note.layer } : {},
|
|
277
|
+
content: note.content
|
|
278
|
+
}
|
|
279
|
+
});
|
|
254
280
|
const remap = (entry) => {
|
|
255
281
|
const to = pathFor.get(pathOf(entry));
|
|
256
282
|
return to ? ref("node", to) : entry;
|
|
@@ -272,7 +298,7 @@ function duplicate(config, input) {
|
|
|
272
298
|
}
|
|
273
299
|
const list = [...place.list];
|
|
274
300
|
list.splice(place.index + 1, 0, ...copies);
|
|
275
|
-
patches.push(placeUpdate(place, list));
|
|
301
|
+
patches.push(placeUpdate(place, list), ...annotationPatches);
|
|
276
302
|
return patches;
|
|
277
303
|
}
|
|
278
304
|
function unwrap(config, input) {
|
|
@@ -537,7 +563,7 @@ const nodeGestureOps = {
|
|
|
537
563
|
input: duplicateInput,
|
|
538
564
|
readOnly: false,
|
|
539
565
|
label: "Duplicate an element",
|
|
540
|
-
description: "Copy this element and everything inside it (\"duplicate\", \"make 3 more of these\"): each copy lands right after it among its siblings, `count` of them.",
|
|
566
|
+
description: "Copy this element and everything inside it (\"duplicate\", \"make 3 more of these\"): each copy lands right after it among its siblings, `count` of them, with a copy of each annotation on the copied elements.",
|
|
541
567
|
scope: "item",
|
|
542
568
|
title: (entity) => `Duplicate ${entity}`,
|
|
543
569
|
example: () => ({
|
|
@@ -4,7 +4,8 @@ import { ReducedMotion } from "./reduced-motion.js";
|
|
|
4
4
|
//#region src/entities/system/motion-presets.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* A value a JS preset holds that `motion/react` cannot be handed as written: a token a mode or state
|
|
7
|
-
* decides (`conditional`),
|
|
7
|
+
* decides (`conditional`), or one a style rule sets that sits inside a composed value (`rule-set`),
|
|
8
|
+
* either of which a preset animates as its base value; a token that comes to nothing a
|
|
8
9
|
* preset can carry (`unresolved`); or an `ease` that is no easing `motion/react` reads (`easing`),
|
|
9
10
|
* from a token or written in place. The last two leave the field out.
|
|
10
11
|
*/
|
|
@@ -14,12 +15,13 @@ interface MotionPresetToken {
|
|
|
14
15
|
readonly at: string;
|
|
15
16
|
/** The token the value comes from; absent for an `ease` written in place. */
|
|
16
17
|
readonly token?: string;
|
|
17
|
-
readonly problem: 'conditional' | 'unresolved' | 'easing';
|
|
18
|
+
readonly problem: 'conditional' | 'rule-set' | 'unresolved' | 'easing';
|
|
18
19
|
}
|
|
19
20
|
/**
|
|
20
21
|
* Every JS-runtime preset, by path, as the props the wrapper spreads onto the animated component.
|
|
21
22
|
* A token a preset names reaches `motion/react` as its value — `Token.ref('springStiffness/snappy')`
|
|
22
|
-
* as `400`, a `200ms` duration as `0.2` — since it reads numbers and seconds, not variables.
|
|
23
|
+
* as `400`, a `200ms` duration as `0.2` — since it reads numbers and seconds, not variables. A token
|
|
24
|
+
* a style rule sets is the one exception: it reaches `motion/react` as its `var()`.
|
|
23
25
|
*/
|
|
24
26
|
declare function jsMotionPresets(config: Config): Record<string, Record<string, unknown>>;
|
|
25
27
|
/** Every JS preset a style rule writes in place, by its id, resolved as {@link jsMotionPresets} are. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { collectRefs, isRef, kindOf, pathOf } from "../../framework/utils/refs.js";
|
|
1
|
+
import { collectRefs, isRef, kindOf, pathOf, refOfKey } from "../../framework/utils/refs.js";
|
|
2
2
|
import { composedValueFormOf } from "./composed-values.js";
|
|
3
3
|
import { createSliceMemo } from "../../framework/memo.js";
|
|
4
4
|
import { tokenValueRow } from "./token-values.js";
|
|
@@ -43,12 +43,48 @@ function motionEasing(value) {
|
|
|
43
43
|
return easings.length > 0 && easings.every((e) => e !== void 0) ? easings : void 0;
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
+
/** The tokens under a bag's `{token:…}` keys, at any depth: a state's bag nests in the layer's. */
|
|
47
|
+
function collectKeyedTokens(bag, into) {
|
|
48
|
+
if (typeof bag !== "object" || bag === null || Array.isArray(bag)) return;
|
|
49
|
+
for (const [key, inner] of Object.entries(bag)) {
|
|
50
|
+
const keyed = refOfKey(key);
|
|
51
|
+
if (keyed && kindOf(keyed) === "token") into.add(pathOf(keyed));
|
|
52
|
+
collectKeyedTokens(inner, into);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The tokens whose variable a style rule or a global style sets, under the token's own key
|
|
57
|
+
* (`{ [Token.ref('switch/travel').cssVariable.name()]: … }`). Such a token holds a different value on
|
|
58
|
+
* each element a rule reaches, so no one literal stands for it.
|
|
59
|
+
*/
|
|
60
|
+
const ruleSetTokens = createSliceMemo({
|
|
61
|
+
kinds: ["component", "global-style"],
|
|
62
|
+
compute: (config) => {
|
|
63
|
+
const tokens = /* @__PURE__ */ new Set();
|
|
64
|
+
for (const component of config.list("component")) {
|
|
65
|
+
const { styles = {} } = component.toJSON();
|
|
66
|
+
for (const entry of Object.values(styles)) collectKeyedTokens(entry?.layers, tokens);
|
|
67
|
+
}
|
|
68
|
+
for (const style of config.list("global-style")) {
|
|
69
|
+
const { declarations } = style.toJSON();
|
|
70
|
+
collectKeyedTokens(declarations, tokens);
|
|
71
|
+
}
|
|
72
|
+
return tokens;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
46
75
|
/**
|
|
47
76
|
* A preset's value with every token it names resolved, or `undefined` when one of them resolves to
|
|
48
77
|
* nothing. Values and keyframe lists are walked; a ref, a string with refs in it and a composed value
|
|
49
78
|
* are each read to their literal. A token a mode decides is read as its base value and reported.
|
|
79
|
+
*
|
|
80
|
+
* With `variables`, a value a preset animates to that is a bare ref to a token a style rule sets
|
|
81
|
+
* ({@link ruleSetTokens}) is its `var()`, which `motion/react` reads off the element it animates as
|
|
82
|
+
* the animation starts, so it lands where the rule put it. In a composed value such a token is read as
|
|
83
|
+
* its base value and reported, since `motion/react` reads a `var()` only as the whole value. A
|
|
84
|
+
* `transition` is timing, not a value animated to, so a ref under one is read to its literal either
|
|
85
|
+
* way.
|
|
50
86
|
*/
|
|
51
|
-
function resolvePresetValue({ config, value, at, report }) {
|
|
87
|
+
function resolvePresetValue({ config, value, at, report, variables = false }) {
|
|
52
88
|
const refs = collectRefs(value).filter((target) => kindOf(target) === "token");
|
|
53
89
|
const container = Array.isArray(value) || typeof value === "object" && value !== null && !isRef(value) && !composedValueFormOf(value);
|
|
54
90
|
if (refs.length === 0 && !container) return { value };
|
|
@@ -57,6 +93,7 @@ function resolvePresetValue({ config, value, at, report }) {
|
|
|
57
93
|
config,
|
|
58
94
|
target: value.__ref
|
|
59
95
|
});
|
|
96
|
+
if (variables && row?.variable && ruleSetTokens(config).has(row.path)) return { value: `var(${row.variable})` };
|
|
60
97
|
if (row?.state.kind === "value") return { value: motionValue(row.state.value.css) };
|
|
61
98
|
}
|
|
62
99
|
if (Array.isArray(value)) {
|
|
@@ -66,7 +103,8 @@ function resolvePresetValue({ config, value, at, report }) {
|
|
|
66
103
|
config,
|
|
67
104
|
value: item,
|
|
68
105
|
at: `${at}.${index}`,
|
|
69
|
-
report
|
|
106
|
+
report,
|
|
107
|
+
variables
|
|
70
108
|
});
|
|
71
109
|
if (!resolved) return void 0;
|
|
72
110
|
items.push(resolved.value);
|
|
@@ -80,7 +118,8 @@ function resolvePresetValue({ config, value, at, report }) {
|
|
|
80
118
|
config,
|
|
81
119
|
value: inner,
|
|
82
120
|
at: `${at}.${key}`,
|
|
83
|
-
report
|
|
121
|
+
report,
|
|
122
|
+
variables: variables && key !== "transition"
|
|
84
123
|
});
|
|
85
124
|
if (!resolved) continue;
|
|
86
125
|
if (key !== "ease") {
|
|
@@ -105,14 +144,22 @@ function resolvePresetValue({ config, value, at, report }) {
|
|
|
105
144
|
}
|
|
106
145
|
return { value: fields };
|
|
107
146
|
}
|
|
108
|
-
for (const target of refs)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
147
|
+
for (const target of refs) {
|
|
148
|
+
const row = tokenValueRow({
|
|
149
|
+
config,
|
|
150
|
+
target
|
|
151
|
+
});
|
|
152
|
+
if (variables && row !== void 0 && ruleSetTokens(config).has(row.path)) report({
|
|
153
|
+
at,
|
|
154
|
+
token: pathOf(target),
|
|
155
|
+
problem: "rule-set"
|
|
156
|
+
});
|
|
157
|
+
else if (row?.state.kind === "conditional") report({
|
|
158
|
+
at,
|
|
159
|
+
token: pathOf(target),
|
|
160
|
+
problem: "conditional"
|
|
161
|
+
});
|
|
162
|
+
}
|
|
116
163
|
const literal = renderValue({
|
|
117
164
|
config,
|
|
118
165
|
value,
|
|
@@ -147,7 +194,8 @@ function resolveBody(config, preset, body, tokens) {
|
|
|
147
194
|
report: (problem) => tokens.push({
|
|
148
195
|
preset,
|
|
149
196
|
...problem
|
|
150
|
-
})
|
|
197
|
+
}),
|
|
198
|
+
variables: field !== "transition"
|
|
151
199
|
});
|
|
152
200
|
if (resolved) props[field] = resolved.value;
|
|
153
201
|
}
|
|
@@ -165,7 +213,8 @@ const resolveJsMotionPresets = createSliceMemo({
|
|
|
165
213
|
"component",
|
|
166
214
|
"token",
|
|
167
215
|
"settings",
|
|
168
|
-
"font"
|
|
216
|
+
"font",
|
|
217
|
+
"global-style"
|
|
169
218
|
],
|
|
170
219
|
compute: (config) => {
|
|
171
220
|
const presets = {};
|
|
@@ -187,7 +236,8 @@ const resolveJsMotionPresets = createSliceMemo({
|
|
|
187
236
|
/**
|
|
188
237
|
* Every JS-runtime preset, by path, as the props the wrapper spreads onto the animated component.
|
|
189
238
|
* A token a preset names reaches `motion/react` as its value — `Token.ref('springStiffness/snappy')`
|
|
190
|
-
* as `400`, a `200ms` duration as `0.2` — since it reads numbers and seconds, not variables.
|
|
239
|
+
* as `400`, a `200ms` duration as `0.2` — since it reads numbers and seconds, not variables. A token
|
|
240
|
+
* a style rule sets is the one exception: it reaches `motion/react` as its `var()`.
|
|
191
241
|
*/
|
|
192
242
|
function jsMotionPresets(config) {
|
|
193
243
|
return resolveJsMotionPresets(config).presets;
|
package/dist/framework/Config.js
CHANGED
|
@@ -5864,7 +5864,7 @@ var Config = class Config {
|
|
|
5864
5864
|
const claimed = schemaVersionOf(stored);
|
|
5865
5865
|
if (claimed > 20261013201548) throw new SchemaVersionTooNew(claimed);
|
|
5866
5866
|
const wire = upgradeSerializedConfig(stored);
|
|
5867
|
-
if (!Array.isArray(wire.ownedKinds) || typeof wire.items !== "object" || wire.items === null) throw new ConfigFormatError(`Config "${stored.name ?? "system-config"}" cannot be hydrated: this is not a serialized config-v2 config (no "ownedKinds"/"items"). A pre-cutover build artifact converts through the registered cutover migration — import the config type's module (e.g. \`configs/system\`) before hydrating
|
|
5867
|
+
if (!Array.isArray(wire.ownedKinds) || typeof wire.items !== "object" || wire.items === null) throw new ConfigFormatError(`Config "${stored.name ?? "system-config"}" cannot be hydrated: this is not a serialized config-v2 config (no "ownedKinds"/"items"). A pre-cutover build artifact converts through the registered cutover migration — import the config type's module (e.g. \`configs/system\`) before hydrating.`);
|
|
5868
5868
|
const leftover = wire.options;
|
|
5869
5869
|
if (isPlainObject(leftover) && Object.keys(leftover).length > 0) throw new ConfigFormatError(`Config "${stored.name ?? "system-config"}" carries an \`options\` slot holding ${Object.keys(leftover).map((key) => `"${key}"`).join(", ")} after every migration ran — this config type has nowhere to keep them. Rebuild it: \`uds build\` and \`uds push\` for a system with a repo; for a system created in Create, reset the local database that holds it.`);
|
|
5870
5870
|
const meta = this.metaDraft();
|
|
@@ -19,18 +19,16 @@ import { parseRawCss } from "./raw-css.js";
|
|
|
19
19
|
import { System } from "../../configs/system.js";
|
|
20
20
|
//#region src/migrations/2.0.0/v1-artifact.ts
|
|
21
21
|
/**
|
|
22
|
-
* The v1 → config-v2 reader,
|
|
22
|
+
* The v1 → config-v2 reader, run by the cutover schema migration in `configs/system.ts`.
|
|
23
23
|
*
|
|
24
24
|
* A v1 system's authoring vocabulary is gone, so its `uds.config.ts` cannot be imported — but what
|
|
25
|
-
* that config
|
|
26
|
-
* artifact into a config-v2 `System
|
|
25
|
+
* that config described survives in the flat `config.json` its last build wrote. This reads that
|
|
26
|
+
* artifact into a config-v2 `System`.
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* rather than failing the load, so a config read through here is the
|
|
33
|
-
* starting point for a migration, not a faithful copy of a system.
|
|
28
|
+
* Runtime code doesn't come through here directly. `Config.fromJSON` is the one door to a stored
|
|
29
|
+
* artifact, and it reaches this only for one stamped before config-v2. It is best-effort: the few
|
|
30
|
+
* old shapes config-v2 doesn't model (color expressions, component `preview`) pass through or drop
|
|
31
|
+
* rather than failing the load, so a config read through here is not a faithful copy of a system.
|
|
34
32
|
*/
|
|
35
33
|
/**
|
|
36
34
|
* Default authoring guidance seeded onto a system that declares none — the stop-gap that fills
|