@yahoo/uds-create-config 5.19.1 → 5.21.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.
Files changed (56) hide show
  1. package/dist/configs/documentation.js +1 -1
  2. package/dist/configs/system.d.ts +607 -2
  3. package/dist/configs/system.js +8 -0
  4. package/dist/entities/documentation/Documentation.d.ts +1 -1
  5. package/dist/entities/system/Component.js +1 -2
  6. package/dist/entities/system/LinkedSystem.d.ts +45 -5
  7. package/dist/entities/system/LinkedSystem.js +55 -4
  8. package/dist/entities/system/Modifier.d.ts +5 -2
  9. package/dist/entities/system/Modifier.js +5 -2
  10. package/dist/entities/system/Motion.d.ts +578 -4
  11. package/dist/entities/system/Motion.js +233 -70
  12. package/dist/entities/system/css-motion-reach.d.ts +62 -0
  13. package/dist/entities/system/css-motion-reach.js +195 -0
  14. package/dist/entities/system/css-motion.d.ts +55 -0
  15. package/dist/entities/system/css-motion.js +445 -0
  16. package/dist/entities/system/css-timing.d.ts +40 -0
  17. package/dist/entities/system/css-timing.js +247 -0
  18. package/dist/entities/system/easings.d.ts +29 -0
  19. package/dist/entities/system/easings.js +99 -0
  20. package/dist/entities/system/motion-convert.d.ts +42 -0
  21. package/dist/entities/system/motion-convert.js +517 -0
  22. package/dist/entities/system/motion-presets.d.ts +9 -1
  23. package/dist/entities/system/motion-presets.js +27 -38
  24. package/dist/entities/system/motion-variants.js +66 -49
  25. package/dist/entities/system/reduced-motion.d.ts +20 -0
  26. package/dist/entities/system/reduced-motion.js +42 -0
  27. package/dist/framework/Config.d.ts +32 -2
  28. package/dist/framework/Config.js +117 -7
  29. package/dist/framework/class-names.d.ts +2 -1
  30. package/dist/framework/class-names.js +31 -13
  31. package/dist/framework/defineEntity.d.ts +3 -1
  32. package/dist/framework/defineEntity.js +2 -0
  33. package/dist/framework/registered.d.ts +8 -1
  34. package/dist/framework/registry.d.ts +38 -1
  35. package/dist/framework/registry.js +3 -1
  36. package/dist/framework/render-spec.js +7 -2
  37. package/dist/framework/schema-version.d.ts +1 -1
  38. package/dist/framework/schema-version.js +5 -5
  39. package/dist/framework/signature.js +4 -2
  40. package/dist/index.d.ts +2 -2
  41. package/dist/index.js +1 -1
  42. package/dist/migrations/2.0.0/v1-artifact.d.ts +606 -2
  43. package/dist/migrations/20261009000514_css_motion_states.d.ts +11 -0
  44. package/dist/migrations/20261009000514_css_motion_states.js +10 -0
  45. package/dist/migrations/20261009022722_starting_style_modifier.d.ts +9 -0
  46. package/dist/migrations/20261009022722_starting_style_modifier.js +10 -0
  47. package/dist/migrations/20261009181635_css_motion_strict.d.ts +23 -0
  48. package/dist/migrations/20261009181635_css_motion_strict.js +152 -0
  49. package/dist/migrations/20261009193004_link_override_ref.d.ts +9 -0
  50. package/dist/migrations/20261009193004_link_override_ref.js +10 -0
  51. package/dist/spec/links.d.ts +2 -0
  52. package/dist/spec/links.js +2 -0
  53. package/dist/spec/motion.d.ts +7 -0
  54. package/dist/spec/motion.js +7 -0
  55. package/dist/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +10 -2
@@ -0,0 +1,247 @@
1
+ import { bezierCss, bezierPoints, cssOfMotionEasing, curveOfCssKeyword } from "./easings.js";
2
+ //#region src/entities/system/css-timing.ts
3
+ /**
4
+ * A `motion/react` transition as the CSS timing that plays closest to it: a spring as a duration and
5
+ * a `linear()` easing sampled from the same equations `motion/react` runs, and a tween's named or
6
+ * bezier easing as its CSS spelling.
7
+ *
8
+ * The spring is a port of `motion-dom`'s generator (`animation/generators/spring.mjs`), with the
9
+ * rest thresholds it uses for a value that moves less than 5: a CSS transition plays one curve over
10
+ * a property's whole change, so the curve runs over progress from 0 to 1. Its duration is found and
11
+ * its curve sampled as `spring().toString()` does.
12
+ */
13
+ const DEFAULTS = {
14
+ stiffness: 100,
15
+ damping: 10,
16
+ mass: 1,
17
+ durationMs: 800,
18
+ bounce: .3,
19
+ restSpeed: .01,
20
+ restDelta: .005,
21
+ minDuration: .01,
22
+ maxDuration: 10,
23
+ minDamping: .05,
24
+ maxDamping: 1
25
+ };
26
+ /** The step a settle time is searched in, and the spacing of `linear()`'s points, in milliseconds. */
27
+ const DURATION_STEP = 50;
28
+ const POINT_SPACING = 30;
29
+ const MAX_DURATION = 2e4;
30
+ const clamp = ({ min, max, value }) => Math.min(Math.max(value, min), max);
31
+ const angularFrequency = ({ undamped, ratio }) => undamped * Math.sqrt(1 - ratio * ratio);
32
+ /** Stiffness and damping for a spring given as `duration` and `bounce`, as Framer resolves it. */
33
+ function findSpring({ durationMs, bounce, mass }) {
34
+ const ratio = clamp({
35
+ min: DEFAULTS.minDamping,
36
+ max: DEFAULTS.maxDamping,
37
+ value: 1 - bounce
38
+ });
39
+ const duration = clamp({
40
+ min: DEFAULTS.minDuration,
41
+ max: DEFAULTS.maxDuration,
42
+ value: durationMs / 1e3
43
+ });
44
+ const safeMin = .001;
45
+ let envelope;
46
+ let derivative;
47
+ if (ratio < 1) {
48
+ envelope = (frequency) => {
49
+ const decay = frequency * ratio;
50
+ return safeMin - decay / angularFrequency({
51
+ undamped: frequency,
52
+ ratio
53
+ }) * Math.exp(-decay * duration);
54
+ };
55
+ derivative = (frequency) => {
56
+ const decay = frequency * ratio;
57
+ const e = ratio ** 2 * frequency ** 2 * duration;
58
+ const f = Math.exp(-decay * duration);
59
+ const g = angularFrequency({
60
+ undamped: frequency ** 2,
61
+ ratio
62
+ });
63
+ return (-envelope(frequency) + safeMin > 0 ? -1 : 1) * (-e * f) / g;
64
+ };
65
+ } else {
66
+ envelope = (frequency) => -safeMin + Math.exp(-frequency * duration) * (frequency * duration + 1);
67
+ derivative = (frequency) => Math.exp(-frequency * duration) * (-frequency * duration * duration);
68
+ }
69
+ let frequency = 5 / duration;
70
+ for (let i = 1; i < 12; i++) frequency -= envelope(frequency) / derivative(frequency);
71
+ if (Number.isNaN(frequency)) return {
72
+ stiffness: DEFAULTS.stiffness,
73
+ damping: DEFAULTS.damping
74
+ };
75
+ const stiffness = frequency ** 2 * mass;
76
+ return {
77
+ stiffness,
78
+ damping: ratio * 2 * Math.sqrt(mass * stiffness)
79
+ };
80
+ }
81
+ /**
82
+ * The spring's physics, and the duration it was given when it was resolved from one. Stiffness,
83
+ * damping or mass take precedence over `duration` and `bounce`, as they do in `motion/react`.
84
+ */
85
+ function physicsOf(options) {
86
+ const physical = options.stiffness !== void 0 || options.damping !== void 0 || options.mass !== void 0;
87
+ const timed = options.duration !== void 0 || options.bounce !== void 0;
88
+ if (physical || !timed) return {
89
+ stiffness: options.stiffness ?? DEFAULTS.stiffness,
90
+ damping: options.damping ?? DEFAULTS.damping,
91
+ mass: options.mass ?? DEFAULTS.mass
92
+ };
93
+ if (options.visualDuration !== void 0) {
94
+ const root = 2 * Math.PI / (options.visualDuration * 1.2);
95
+ const stiffness = root * root;
96
+ return {
97
+ stiffness,
98
+ damping: 2 * clamp({
99
+ min: .05,
100
+ max: 1,
101
+ value: 1 - (options.bounce ?? 0)
102
+ }) * Math.sqrt(stiffness),
103
+ mass: DEFAULTS.mass
104
+ };
105
+ }
106
+ const durationMs = options.duration !== void 0 ? options.duration * 1e3 : DEFAULTS.durationMs;
107
+ return {
108
+ ...findSpring({
109
+ durationMs,
110
+ bounce: options.bounce ?? DEFAULTS.bounce,
111
+ mass: DEFAULTS.mass
112
+ }),
113
+ mass: DEFAULTS.mass,
114
+ fixedDurationMs: clamp({
115
+ min: DEFAULTS.minDuration * 1e3,
116
+ max: DEFAULTS.maxDuration * 1e3,
117
+ value: durationMs
118
+ })
119
+ };
120
+ }
121
+ /** The spring's progress from 0 to 1 at `t` milliseconds, and whether it has come to rest there. */
122
+ function springCurve({ stiffness, damping, mass, fixedDurationMs }) {
123
+ const ratio = damping / (2 * Math.sqrt(stiffness * mass));
124
+ const undamped = Math.sqrt(stiffness / mass) / 1e3;
125
+ let position;
126
+ let velocity;
127
+ if (ratio < 1) {
128
+ const frequency = angularFrequency({
129
+ undamped,
130
+ ratio
131
+ });
132
+ const a = ratio * undamped / frequency;
133
+ const sinCoefficient = ratio * undamped * a + frequency;
134
+ const cosCoefficient = ratio * undamped - a * frequency;
135
+ position = (t) => 1 - Math.exp(-ratio * undamped * t) * (a * Math.sin(frequency * t) + Math.cos(frequency * t));
136
+ velocity = (t) => Math.exp(-ratio * undamped * t) * (sinCoefficient * Math.sin(frequency * t) + cosCoefficient * Math.cos(frequency * t));
137
+ } else if (ratio === 1) {
138
+ position = (t) => 1 - Math.exp(-undamped * t) * (1 + undamped * t);
139
+ velocity = (t) => Math.exp(-undamped * t) * (undamped * undamped * t);
140
+ } else {
141
+ const damped = undamped * Math.sqrt(ratio * ratio - 1);
142
+ const p = ratio * undamped / damped;
143
+ const sinhCoefficient = ratio * undamped * p - damped;
144
+ const coshCoefficient = ratio * undamped - p * damped;
145
+ position = (t) => {
146
+ const capped = Math.min(damped * t, 300);
147
+ return 1 - Math.exp(-ratio * undamped * t) * (ratio * undamped * Math.sinh(capped) + damped * Math.cosh(capped)) / damped;
148
+ };
149
+ velocity = (t) => {
150
+ const capped = Math.min(damped * t, 300);
151
+ return Math.exp(-ratio * undamped * t) * (sinhCoefficient * Math.sinh(capped) + coshCoefficient * Math.cosh(capped));
152
+ };
153
+ }
154
+ return (t) => {
155
+ const current = position(t);
156
+ const done = fixedDurationMs !== void 0 ? t >= fixedDurationMs : Math.abs(velocity(t) * 1e3) <= DEFAULTS.restSpeed && Math.abs(1 - current) <= DEFAULTS.restDelta;
157
+ return {
158
+ value: done ? 1 : current,
159
+ done
160
+ };
161
+ };
162
+ }
163
+ /** A progress curve sampled into CSS `linear()`, one point per {@link POINT_SPACING} milliseconds. */
164
+ function linearEasing({ curve, duration }) {
165
+ const count = Math.max(Math.round(duration / POINT_SPACING), 2);
166
+ return `linear(${Array.from({ length: count }, (_, i) => Math.round(curve(i / (count - 1)) * 1e4) / 1e4).join(", ")})`;
167
+ }
168
+ /** A spring as the CSS duration and `linear()` easing that play it. */
169
+ function springTiming(options) {
170
+ const at = springCurve(physicsOf(options));
171
+ let duration = 0;
172
+ while (!at(duration).done && duration < MAX_DURATION) duration += DURATION_STEP;
173
+ return {
174
+ duration,
175
+ easing: linearEasing({
176
+ curve: (progress) => at(duration * progress).value,
177
+ duration
178
+ })
179
+ };
180
+ }
181
+ /** A cubic Bézier easing from 0 to 1, solved for x by bisection. */
182
+ function cubicBezier([x1, y1, x2, y2]) {
183
+ const at = (t, [a, b]) => ((1 - 3 * b + 3 * a) * t + (3 * b - 6 * a)) * t * t + 3 * a * t;
184
+ return (progress) => {
185
+ if (progress <= 0 || progress >= 1) return progress <= 0 ? 0 : 1;
186
+ let lower = 0;
187
+ let upper = 1;
188
+ let t = progress;
189
+ for (let i = 0; i < 24; i++) {
190
+ if (at(t, [x1, x2]) > progress) upper = t;
191
+ else lower = t;
192
+ t = (lower + upper) / 2;
193
+ }
194
+ return at(t, [y1, y2]);
195
+ };
196
+ }
197
+ const reverse = (easing) => (p) => 1 - easing(1 - p);
198
+ const mirror = (easing) => (p) => p <= .5 ? easing(2 * p) / 2 : (2 - easing(2 * (1 - p))) / 2;
199
+ const backIn = reverse(cubicBezier([
200
+ .33,
201
+ 1.53,
202
+ .69,
203
+ .99
204
+ ]));
205
+ const circIn = (p) => 1 - Math.sin(Math.acos(p));
206
+ function anticipate(p) {
207
+ if (p >= 1) return 1;
208
+ if (p < .5) return .5 * backIn(p * 2);
209
+ return .5 * (2 - 2 ** (-10 * (p * 2 - 1)));
210
+ }
211
+ /** The easings `motion/react` names that CSS has no keyword or Bézier for, as curves to sample. */
212
+ const SAMPLED_EASINGS = {
213
+ backIn,
214
+ backInOut: mirror(backIn),
215
+ circIn,
216
+ circOut: reverse(circIn),
217
+ circInOut: mirror(circIn),
218
+ anticipate
219
+ };
220
+ /**
221
+ * A tween's `ease` as CSS: a name `motion/react` gives, a curve of four numbers, or a CSS easing as it
222
+ * stands. `undefined` for anything else, such as a list of easings, one per keyframe.
223
+ */
224
+ function cssEasing({ ease, duration }) {
225
+ if (Array.isArray(ease) && ease.length === 4 && ease.every((n) => typeof n === "number")) return bezierCss(ease);
226
+ if (typeof ease !== "string") return void 0;
227
+ const name = ease.trim();
228
+ const named = cssOfMotionEasing(name);
229
+ if (named !== void 0) return named;
230
+ if (Object.hasOwn(SAMPLED_EASINGS, name)) return linearEasing({
231
+ curve: SAMPLED_EASINGS[name],
232
+ duration
233
+ });
234
+ return name.length > 0 ? name : void 0;
235
+ }
236
+ /**
237
+ * A CSS easing as the curve it plays, for `linear`, a keyword or a `cubic-bezier()`. `undefined` for
238
+ * any other, such as a `linear()` with points or a `var()`.
239
+ */
240
+ function easingCurve(easing) {
241
+ const text = easing.trim();
242
+ if (text === "linear") return (progress) => progress;
243
+ const curve = curveOfCssKeyword(text) ?? bezierPoints(text);
244
+ return curve ? cubicBezier(curve) : void 0;
245
+ }
246
+ //#endregion
247
+ export { cssEasing, easingCurve, linearEasing, springTiming };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The easings both runtimes name, in one table: `motion/react`'s names (`easeOut`), CSS's keywords
3
+ * (`ease-out`), and the Bézier curve each one is. A JS preset's `ease` is read to CSS through it, a CSS
4
+ * easing to `motion/react`'s through it, and a conversion between runtimes goes through both.
5
+ */
6
+ /** A cubic Bézier curve's four control-point coordinates. */
7
+ export type BezierCurve = readonly [number, number, number, number];
8
+ /** The names `motion/react` gives easings that are no Bézier curve, which CSS plays as a sampled
9
+ * `linear()`. */
10
+ export declare const SAMPLED_MOTION_EASINGS: readonly ["backIn", "backInOut", "circIn", "circOut", "circInOut", "anticipate"];
11
+ export type SampledMotionEasing = (typeof SAMPLED_MOTION_EASINGS)[number];
12
+ /** Every easing name `motion/react` reads. */
13
+ export declare const MOTION_EASING_NAMES: ReadonlySet<string>;
14
+ export declare const CUBIC_BEZIER: RegExp;
15
+ /** A `cubic-bezier()`'s four numbers, or `undefined` for any other text. */
16
+ export declare function bezierPoints(text: string): BezierCurve | undefined;
17
+ export declare const bezierCss: (curve: readonly number[]) => string;
18
+ /**
19
+ * A `motion/react` easing name as CSS: `linear`, or the `cubic-bezier()` it is. `undefined` for a name
20
+ * with no curve (the sampled ones) and for anything else.
21
+ */
22
+ export declare function cssOfMotionEasing(name: string): string | undefined;
23
+ /**
24
+ * A CSS keyword as `motion/react` takes it: its name, or the curve where `motion/react` has no name
25
+ * for it (`ease`). `undefined` for anything that is no keyword.
26
+ */
27
+ export declare function motionOfCssKeyword(keyword: string): string | BezierCurve | undefined;
28
+ /** A CSS keyword's curve, `undefined` for `linear` and for anything that is no keyword. */
29
+ export declare function curveOfCssKeyword(keyword: string): BezierCurve | undefined;
@@ -0,0 +1,99 @@
1
+ //#region src/entities/system/easings.ts
2
+ const NAMED_EASINGS = [
3
+ {
4
+ motion: "linear",
5
+ css: "linear"
6
+ },
7
+ {
8
+ motion: "easeIn",
9
+ css: "ease-in",
10
+ curve: [
11
+ .42,
12
+ 0,
13
+ 1,
14
+ 1
15
+ ]
16
+ },
17
+ {
18
+ motion: "easeOut",
19
+ css: "ease-out",
20
+ curve: [
21
+ 0,
22
+ 0,
23
+ .58,
24
+ 1
25
+ ]
26
+ },
27
+ {
28
+ motion: "easeInOut",
29
+ css: "ease-in-out",
30
+ curve: [
31
+ .42,
32
+ 0,
33
+ .58,
34
+ 1
35
+ ]
36
+ },
37
+ {
38
+ css: "ease",
39
+ curve: [
40
+ .25,
41
+ .1,
42
+ .25,
43
+ 1
44
+ ]
45
+ },
46
+ {
47
+ motion: "backOut",
48
+ curve: [
49
+ .33,
50
+ 1.53,
51
+ .69,
52
+ .99
53
+ ]
54
+ }
55
+ ];
56
+ /** The names `motion/react` gives easings that are no Bézier curve, which CSS plays as a sampled
57
+ * `linear()`. */
58
+ const SAMPLED_MOTION_EASINGS = [
59
+ "backIn",
60
+ "backInOut",
61
+ "circIn",
62
+ "circOut",
63
+ "circInOut",
64
+ "anticipate"
65
+ ];
66
+ /** Every easing name `motion/react` reads. */
67
+ const MOTION_EASING_NAMES = new Set([...NAMED_EASINGS.flatMap((easing) => easing.motion === void 0 ? [] : [easing.motion]), ...SAMPLED_MOTION_EASINGS]);
68
+ const CUBIC_BEZIER = /^cubic-bezier\(\s*([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*([^,\s)]+)\s*\)$/;
69
+ /** A `cubic-bezier()`'s four numbers, or `undefined` for any other text. */
70
+ function bezierPoints(text) {
71
+ const points = CUBIC_BEZIER.exec(text.trim())?.slice(1).map(Number);
72
+ if (!points?.every(Number.isFinite)) return void 0;
73
+ return points;
74
+ }
75
+ const bezierCss = (curve) => `cubic-bezier(${curve.join(", ")})`;
76
+ /**
77
+ * A `motion/react` easing name as CSS: `linear`, or the `cubic-bezier()` it is. `undefined` for a name
78
+ * with no curve (the sampled ones) and for anything else.
79
+ */
80
+ function cssOfMotionEasing(name) {
81
+ const easing = NAMED_EASINGS.find((entry) => entry.motion === name);
82
+ if (!easing) return void 0;
83
+ return easing.curve ? bezierCss(easing.curve) : easing.css;
84
+ }
85
+ /**
86
+ * A CSS keyword as `motion/react` takes it: its name, or the curve where `motion/react` has no name
87
+ * for it (`ease`). `undefined` for anything that is no keyword.
88
+ */
89
+ function motionOfCssKeyword(keyword) {
90
+ const easing = NAMED_EASINGS.find((entry) => entry.css === keyword);
91
+ if (!easing) return void 0;
92
+ return easing.motion ?? easing.curve;
93
+ }
94
+ /** A CSS keyword's curve, `undefined` for `linear` and for anything that is no keyword. */
95
+ function curveOfCssKeyword(keyword) {
96
+ return NAMED_EASINGS.find((entry) => entry.css === keyword)?.curve;
97
+ }
98
+ //#endregion
99
+ export { MOTION_EASING_NAMES, bezierCss, bezierPoints, cssOfMotionEasing, curveOfCssKeyword, motionOfCssKeyword };
@@ -0,0 +1,42 @@
1
+ //#region src/entities/system/motion-convert.d.ts
2
+ /** One field a conversion leaves out, plays differently, or can't carry over. */
3
+ interface MotionConversionNote {
4
+ /** Where the field sits, as a dotted path: `transition.opacity.repeat`. */
5
+ readonly at: string;
6
+ readonly reason: string;
7
+ }
8
+ interface MotionConversion {
9
+ /** The preset as the other runtime takes it. `undefined` when the conversion is refused. */
10
+ readonly body?: Record<string, unknown>;
11
+ /** Fields the other runtime has no counterpart for, left out. */
12
+ readonly dropped: readonly MotionConversionNote[];
13
+ /** Fields carried over that the other runtime plays differently than written. */
14
+ readonly approximated: readonly MotionConversionNote[];
15
+ /** Fields the other runtime can't represent, which refuse the conversion. */
16
+ readonly refused: readonly MotionConversionNote[];
17
+ }
18
+ type MotionRuntime = 'css' | 'js';
19
+ type Body = Record<string, unknown>;
20
+ /** `body` as the `to` runtime takes it, with what the conversion left out, changed or refused. */
21
+ declare function convertMotion({
22
+ body,
23
+ to
24
+ }: {
25
+ body: Body;
26
+ to: MotionRuntime;
27
+ }): MotionConversion;
28
+ /** What `motion/convert-plan` answers: the conversion `motion/convert` would make, and where it
29
+ * would write it. */
30
+ interface MotionConversionPlan {
31
+ readonly path: string;
32
+ readonly to: MotionRuntime;
33
+ /** The linked system the preset is borrowed from, whose link the conversion is written to. */
34
+ readonly link?: string;
35
+ readonly dropped: readonly MotionConversionNote[];
36
+ readonly approximated: readonly MotionConversionNote[];
37
+ readonly refused: readonly MotionConversionNote[];
38
+ /** Why the conversion would be refused. `undefined` when it would go through. */
39
+ readonly blocked?: string;
40
+ }
41
+ //#endregion
42
+ export { MotionConversion, MotionConversionNote, MotionConversionPlan, MotionRuntime, convertMotion };