@yahoo/uds-create-config 5.19.1 → 5.20.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/documentation.js +1 -1
- package/dist/configs/system.d.ts +607 -2
- package/dist/configs/system.js +6 -0
- package/dist/entities/documentation/Documentation.d.ts +1 -1
- package/dist/entities/system/Component.js +1 -2
- package/dist/entities/system/LinkedSystem.d.ts +17 -2
- package/dist/entities/system/Modifier.d.ts +5 -2
- package/dist/entities/system/Modifier.js +5 -2
- package/dist/entities/system/Motion.d.ts +578 -4
- package/dist/entities/system/Motion.js +233 -70
- package/dist/entities/system/css-motion-reach.d.ts +62 -0
- package/dist/entities/system/css-motion-reach.js +195 -0
- package/dist/entities/system/css-motion.d.ts +55 -0
- package/dist/entities/system/css-motion.js +445 -0
- package/dist/entities/system/css-timing.d.ts +40 -0
- package/dist/entities/system/css-timing.js +247 -0
- package/dist/entities/system/easings.d.ts +29 -0
- package/dist/entities/system/easings.js +99 -0
- package/dist/entities/system/motion-convert.d.ts +42 -0
- package/dist/entities/system/motion-convert.js +517 -0
- package/dist/entities/system/motion-presets.d.ts +9 -1
- package/dist/entities/system/motion-presets.js +27 -38
- package/dist/entities/system/motion-variants.js +66 -49
- package/dist/entities/system/reduced-motion.d.ts +20 -0
- package/dist/entities/system/reduced-motion.js +42 -0
- package/dist/framework/Config.d.ts +7 -2
- package/dist/framework/Config.js +47 -5
- package/dist/framework/class-names.d.ts +2 -1
- package/dist/framework/class-names.js +31 -13
- package/dist/framework/defineEntity.d.ts +3 -1
- package/dist/framework/defineEntity.js +2 -0
- package/dist/framework/registered.d.ts +8 -1
- package/dist/framework/registry.d.ts +38 -1
- package/dist/framework/registry.js +3 -1
- package/dist/framework/render-spec.js +7 -2
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/framework/signature.js +4 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/migrations/2.0.0/v1-artifact.d.ts +606 -2
- package/dist/migrations/20261009000514_css_motion_states.d.ts +11 -0
- package/dist/migrations/20261009000514_css_motion_states.js +10 -0
- package/dist/migrations/20261009022722_starting_style_modifier.d.ts +9 -0
- package/dist/migrations/20261009022722_starting_style_modifier.js +10 -0
- package/dist/migrations/20261009181635_css_motion_strict.d.ts +23 -0
- package/dist/migrations/20261009181635_css_motion_strict.js +152 -0
- package/dist/spec/motion.d.ts +7 -0
- package/dist/spec/motion.js +7 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -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 };
|