@yahoo/uds-create-config 5.5.0 → 5.7.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/system.js +3 -1
- package/dist/entities/system/Component.d.ts +5 -2
- package/dist/entities/system/Component.js +46 -6
- package/dist/entities/system/Motion.d.ts +41 -9
- package/dist/entities/system/Motion.js +73 -6
- package/dist/entities/system/Token.js +1 -1
- package/dist/entities/system/defineComponent.js +2 -7
- package/dist/entities/system/linked-token-values.js +1 -1
- package/dist/entities/system/motion-presets.d.ts +32 -0
- package/dist/entities/system/motion-presets.js +239 -0
- package/dist/entities/system/motion-variants.d.ts +73 -0
- package/dist/entities/system/motion-variants.js +270 -0
- package/dist/framework/Config.d.ts +8 -1
- package/dist/framework/Config.js +34 -3
- package/dist/framework/class-names.d.ts +11 -1
- package/dist/framework/class-names.js +42 -1
- package/dist/framework/defineSubEntity.d.ts +7 -2
- package/dist/framework/defineSubEntity.js +11 -3
- package/dist/framework/projections.js +1 -0
- package/dist/framework/render-spec.d.ts +5 -1
- package/dist/framework/render-spec.js +21 -2
- package/dist/framework/schema-version.d.ts +1 -1
- package/dist/framework/schema-version.js +5 -5
- package/dist/index.d.ts +6 -4
- package/dist/index.js +8 -6
- package/dist/migrations/2.0.0/v1-artifact.js +1 -1
- package/dist/migrations/20261006125609_motion_variants_and_layout.d.ts +10 -0
- package/dist/migrations/20261006125609_motion_variants_and_layout.js +10 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/configs/system.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Composite } from "../entities/system/Composite.js";
|
|
|
4
4
|
import { Modifier } from "../entities/system/Modifier.js";
|
|
5
5
|
import { Settings } from "../entities/system/Settings.js";
|
|
6
6
|
import { StyleProperty } from "../entities/system/StyleProperty.js";
|
|
7
|
+
import { Motion } from "../entities/system/Motion.js";
|
|
7
8
|
import { File } from "../entities/system/File.js";
|
|
8
9
|
import { WEB_CONFIG_NAME } from "./platform.js";
|
|
9
10
|
import { Token } from "../entities/system/Token.js";
|
|
@@ -19,7 +20,6 @@ import { GlobalStyle } from "../entities/system/GlobalStyle.js";
|
|
|
19
20
|
import { Guidance } from "../entities/system/Guidance.js";
|
|
20
21
|
import { GuidanceStyle } from "../entities/system/GuidanceStyle.js";
|
|
21
22
|
import { LinkedSystem } from "../entities/system/LinkedSystem.js";
|
|
22
|
-
import { Motion } from "../entities/system/Motion.js";
|
|
23
23
|
import { loadV1Artifact } from "../migrations/2.0.0/v1-artifact.js";
|
|
24
24
|
import { settingsAsKindMigration } from "../migrations/20260908171448_settings_as_kind.js";
|
|
25
25
|
import { visibleStatePointerMigration } from "../migrations/20260908194245_visible_state_pointer.js";
|
|
@@ -57,6 +57,7 @@ import { oklchAndEmitFieldsMigration } from "../migrations/20261001162046_oklch_
|
|
|
57
57
|
import { globalStyleOnMigration } from "../migrations/20261005212405_global_style_on.js";
|
|
58
58
|
import { addAndSubtractMigration } from "../migrations/20261005220312_add_and_subtract.js";
|
|
59
59
|
import { systemIncludeMigration } from "../migrations/20261005225949_system_include.js";
|
|
60
|
+
import { motionVariantsAndLayoutMigration } from "../migrations/20261006125609_motion_variants_and_layout.js";
|
|
60
61
|
const System = defineConfig({
|
|
61
62
|
name: WEB_CONFIG_NAME,
|
|
62
63
|
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.",
|
|
@@ -125,5 +126,6 @@ if (!registeredSchemaMigrations().has(20261001162046)) registerSchemaMigrations(
|
|
|
125
126
|
if (!registeredSchemaMigrations().has(20261005212405)) registerSchemaMigrations(globalStyleOnMigration);
|
|
126
127
|
if (!registeredSchemaMigrations().has(20261005220312)) registerSchemaMigrations(addAndSubtractMigration);
|
|
127
128
|
if (!registeredSchemaMigrations().has(20261005225949)) registerSchemaMigrations(systemIncludeMigration);
|
|
129
|
+
if (!registeredSchemaMigrations().has(20261006125609)) registerSchemaMigrations(motionVariantsAndLayoutMigration);
|
|
128
130
|
//#endregion
|
|
129
131
|
export { System };
|
|
@@ -874,8 +874,11 @@ type ComponentReference<Contract = ComponentContractOf<string>, Path extends str
|
|
|
874
874
|
type ExtensionDefaults<Contract, Delta> = {
|
|
875
875
|
readonly defaultProps?: DefaultsOf<ResolvedProps<Contract, Delta>>;
|
|
876
876
|
};
|
|
877
|
-
/**
|
|
878
|
-
*
|
|
877
|
+
/**
|
|
878
|
+
* Two style rules with the same condition, as the one rule they are: each layer's bag merged, the
|
|
879
|
+
* later rule's keys winning ({@link mergeRuleBags}). The list form of `styles` keys rules by their
|
|
880
|
+
* condition, so a second `{ when: { disabled: true } }` would otherwise replace the first whole.
|
|
881
|
+
*/
|
|
879
882
|
/** A component body as `register` takes one. */
|
|
880
883
|
type ComponentCreateInput = CreateInput<typeof componentFields>;
|
|
881
884
|
/** `Component.item`'s body: the stored fields, with `styles` also taking the rule list
|
|
@@ -15,6 +15,7 @@ import { Style, addBagKeyIssues, anatomyPropValue, bagNameEdges, bagRewriteName,
|
|
|
15
15
|
import { storedPreview } from "../../framework/preview-store.js";
|
|
16
16
|
import { glyphPropsOf, propOwner, propValueDomain, refListOf, resolveComponentProps, stylePropValueLeaves, validateComponentProps } from "../../framework/projections.js";
|
|
17
17
|
import { carriesContent, intoName, isValueSlot, renderBoundProp, routedPropIn, routesContent } from "../../framework/prop-surface.js";
|
|
18
|
+
import { inlineJsMotion } from "./Motion.js";
|
|
18
19
|
import { slotAnatomyPropOf, slotTargetsOf, withoutTruthyTerm } from "../../framework/render-spec.js";
|
|
19
20
|
import { listSlots, namedSlots, slotHostedBy, slotOf, slotsFor } from "../../spec/slot.js";
|
|
20
21
|
import { cellAt } from "../../spec/cell.js";
|
|
@@ -730,6 +731,7 @@ function buildBagFor(config, layerElement) {
|
|
|
730
731
|
}).optional();
|
|
731
732
|
}
|
|
732
733
|
shape.as ??= z.string().optional();
|
|
734
|
+
shape.motion = z.union([shape.motion ?? z.union([refSchema, z.string()]), inlineJsMotion], { error: "a layer's `motion` is a preset (`Motion.ref('<path>')`) or a JS preset written in place — `{ \"whileHover\": { \"scale\": 1.05 }, \"transition\": { … } }`, the fields `Motion.item` takes with `runtime: 'js'`. A CSS preset is named with `Motion.item`." }).optional();
|
|
733
735
|
let bag;
|
|
734
736
|
const nested = z.lazy(() => bag).optional();
|
|
735
737
|
for (const mod of config.list("modifier")) shape[`_${mod.leaf}`] = nested;
|
|
@@ -1541,7 +1543,7 @@ const componentFields = z.strictObject({
|
|
|
1541
1543
|
* forwards nothing rather than being quietly translated.
|
|
1542
1544
|
*/
|
|
1543
1545
|
forwards: Forward.optional(),
|
|
1544
|
-
styles: orList(StyleRule).optional(),
|
|
1546
|
+
styles: orList(StyleRule, { merge: mergeStyleRules }).optional(),
|
|
1545
1547
|
/** The props the render reads that the component neither declares nor forwards — its render
|
|
1546
1548
|
* extras (`.render<{ swatchColor?: string }>()`). Read off the render at build like `anatomy`,
|
|
1547
1549
|
* never authored as data. The module consumes them; a component painted out of its anatomy has
|
|
@@ -2344,14 +2346,52 @@ subtree: z.boolean().default(true) }).optional()
|
|
|
2344
2346
|
]
|
|
2345
2347
|
});
|
|
2346
2348
|
const baseComponentRef = ComponentEntity.ref.bind(ComponentEntity);
|
|
2349
|
+
/**
|
|
2350
|
+
* Two layer bags of rules with one condition, as one: the later bag's keys win, key by key, and a
|
|
2351
|
+
* modifier block (`_hover`) is merged the same way inside. Rules apply in order and a later one wins
|
|
2352
|
+
* on the property it sets, so this is what the two said; replacing the earlier bag dropped every key
|
|
2353
|
+
* only it set.
|
|
2354
|
+
*/
|
|
2355
|
+
function mergeRuleBags(earlier, later) {
|
|
2356
|
+
const out = { ...earlier };
|
|
2357
|
+
for (const [key, value] of Object.entries(later)) {
|
|
2358
|
+
const before = out[key];
|
|
2359
|
+
out[key] = key.startsWith("_") && typeof before === "object" && before !== null && !Array.isArray(before) && typeof value === "object" && value !== null && !Array.isArray(value) ? mergeRuleBags(before, value) : value;
|
|
2360
|
+
}
|
|
2361
|
+
return out;
|
|
2362
|
+
}
|
|
2363
|
+
/**
|
|
2364
|
+
* Two style rules with the same condition, as the one rule they are: each layer's bag merged, the
|
|
2365
|
+
* later rule's keys winning ({@link mergeRuleBags}). The list form of `styles` keys rules by their
|
|
2366
|
+
* condition, so a second `{ when: { disabled: true } }` would otherwise replace the first whole.
|
|
2367
|
+
*/
|
|
2368
|
+
function mergeStyleRules(earlier, later) {
|
|
2369
|
+
const layers = { ...earlier.layers ?? {} };
|
|
2370
|
+
for (const [layer, bag] of Object.entries(later.layers ?? {})) {
|
|
2371
|
+
const before = layers[layer];
|
|
2372
|
+
layers[layer] = typeof before === "object" && before !== null ? mergeRuleBags(before, bag ?? {}) : bag;
|
|
2373
|
+
}
|
|
2374
|
+
return {
|
|
2375
|
+
...earlier,
|
|
2376
|
+
...later,
|
|
2377
|
+
layers
|
|
2378
|
+
};
|
|
2379
|
+
}
|
|
2347
2380
|
/** Style rules as a list, the form `defineComponent.styles` takes, in the stored form: keyed by each
|
|
2348
|
-
* rule's condition. Two rules with the same condition are one rule
|
|
2381
|
+
* rule's condition. Two rules with the same condition are one rule ({@link mergeStyleRules}), in the
|
|
2382
|
+
* later one's place. */
|
|
2349
2383
|
function storedStyleRules(rules) {
|
|
2350
2384
|
const styles = {};
|
|
2351
|
-
for (const rule of rules)
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2385
|
+
for (const rule of rules) {
|
|
2386
|
+
const key = canonicalWhen(rule.when);
|
|
2387
|
+
const stored = {
|
|
2388
|
+
when: rule.when ?? null,
|
|
2389
|
+
layers: rule.layers
|
|
2390
|
+
};
|
|
2391
|
+
const earlier = styles[key];
|
|
2392
|
+
delete styles[key];
|
|
2393
|
+
styles[key] = earlier ? mergeStyleRules(earlier, stored) : stored;
|
|
2394
|
+
}
|
|
2355
2395
|
return styles;
|
|
2356
2396
|
}
|
|
2357
2397
|
function componentItem(def) {
|
|
@@ -3,6 +3,28 @@ import { Named } from "../../framework/named.js";
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
//#region src/entities/system/Motion.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* A JS preset written in place, as a style rule's `motion` on a layer rather than a `Motion.ref`: the
|
|
8
|
+
* same fields, with `runtime` optional since in place it can only be `js`. A CSS preset is a class
|
|
9
|
+
* the stylesheet emits under the preset's name, so one written in place has nothing to emit as; name
|
|
10
|
+
* it with `Motion.item` instead.
|
|
11
|
+
*/
|
|
12
|
+
declare const inlineJsMotion: z.ZodObject<{
|
|
13
|
+
transition: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
14
|
+
exit: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
15
|
+
layout: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"position">, z.ZodLiteral<"size">, z.ZodLiteral<"preserve-aspect">]>>;
|
|
16
|
+
initial: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>, z.ZodLiteral<false>]>>;
|
|
17
|
+
variants: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
18
|
+
animate: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
19
|
+
whileHover: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
20
|
+
whileTap: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
21
|
+
whileFocus: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
22
|
+
whileDrag: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
23
|
+
drag: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>;
|
|
24
|
+
dragConstraints: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
|
|
25
|
+
dragElastic: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
runtime: z.ZodOptional<z.ZodLiteral<"js">>;
|
|
27
|
+
}, z.core.$strict>;
|
|
6
28
|
/** The fields of a JS preset that `motion.create` reads as props, in schema order. The emitter
|
|
7
29
|
* reads this rather than restating the schema, so a field added here reaches every emitted preset. */
|
|
8
30
|
declare const jsMotionPropFields: readonly string[];
|
|
@@ -17,19 +39,29 @@ declare const MotionDefinition: EntityClass<z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
17
39
|
fillMode: z.ZodOptional<z.ZodString>;
|
|
18
40
|
}, z.core.$strict>, z.ZodObject<{
|
|
19
41
|
runtime: z.ZodLiteral<"js">;
|
|
20
|
-
initial: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
21
|
-
animate: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
22
|
-
exit: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
42
|
+
initial: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>, z.ZodLiteral<false>]>>;
|
|
43
|
+
animate: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
44
|
+
exit: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
23
45
|
transition: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
24
|
-
whileHover: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
25
|
-
whileTap: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
26
|
-
whileFocus: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
27
|
-
whileDrag: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
46
|
+
whileHover: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
47
|
+
whileTap: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
48
|
+
whileFocus: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
49
|
+
whileDrag: z.ZodOptional<z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
50
|
+
variants: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
51
|
+
layout: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodLiteral<"position">, z.ZodLiteral<"size">, z.ZodLiteral<"preserve-aspect">]>>;
|
|
28
52
|
drag: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>;
|
|
29
53
|
dragConstraints: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
|
|
30
54
|
dragElastic: z.ZodOptional<z.ZodNumber>;
|
|
31
|
-
}, z.core.$strict>], "runtime">, z.ZodObject<Record<never, never>, z.core.$strip>, "motion", {
|
|
55
|
+
}, z.core.$strict>], "runtime">, z.ZodObject<Record<never, never>, z.core.$strip>, "motion", {
|
|
56
|
+
readonly 'rename-variant': {
|
|
57
|
+
readonly input: z.ZodObject<{
|
|
58
|
+
path: z.ZodType<string, string | undefined, z.core.$ZodTypeInternals<string, string | undefined>>;
|
|
59
|
+
key: z.ZodString;
|
|
60
|
+
to: z.ZodString;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
};
|
|
63
|
+
}, Record<never, never>, false, Record<never, never>, Record<never, never>>;
|
|
32
64
|
interface MotionClass extends Named<typeof MotionDefinition> {}
|
|
33
65
|
declare const Motion: MotionClass;
|
|
34
66
|
//#endregion
|
|
35
|
-
export { Motion, MotionClass, jsMotionPropFields };
|
|
67
|
+
export { Motion, MotionClass, inlineJsMotion, jsMotionPropFields };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { pathInput } from "../../framework/schemas.js";
|
|
1
2
|
import { defineEntity } from "../../framework/defineEntity.js";
|
|
3
|
+
import { renameMotionVariant } from "./motion-variants.js";
|
|
2
4
|
import { z } from "zod";
|
|
3
5
|
//#region src/entities/system/Motion.ts
|
|
4
6
|
/**
|
|
@@ -7,7 +9,9 @@ import { z } from "zod";
|
|
|
7
9
|
* - `css` → `keyframes` REQUIRED (codegen emits `@keyframes` from them); a css preset with
|
|
8
10
|
* no keyframes — which used to validate and silently emit nothing — is now rejected.
|
|
9
11
|
* - `js` → no keyframes; carries the interaction state the client drives, `exit` included,
|
|
10
|
-
* which runs under an `AnimatePresence` ancestor when the element unmounts.
|
|
12
|
+
* which runs under an `AnimatePresence` ancestor when the element unmounts. Each state is a set
|
|
13
|
+
* of values or the name of one of the preset's `variants`, and `layout` animates the element's
|
|
14
|
+
* own size and position as they change.
|
|
11
15
|
* Illegal cross-runtime mixes (a css preset with `animate`, a js preset with `keyframes`)
|
|
12
16
|
* can't be represented — each member is strict.
|
|
13
17
|
*
|
|
@@ -15,7 +19,17 @@ import { z } from "zod";
|
|
|
15
19
|
* it silently: the first version declared three js fields, so every gesture preset in a real system
|
|
16
20
|
* lost `whileHover`/`whileTap`/`drag` on the way in and animated nothing.
|
|
17
21
|
*/
|
|
18
|
-
const
|
|
22
|
+
const values = z.record(z.string(), z.unknown());
|
|
23
|
+
/**
|
|
24
|
+
* A state: the values themselves, or the name of a variant — or several, applied in order — which
|
|
25
|
+
* `motion/react` looks up in the preset's `variants` and, for a child that declares none of its own
|
|
26
|
+
* gestures, in the variants its parent is animating to.
|
|
27
|
+
*/
|
|
28
|
+
const gesture = z.union([
|
|
29
|
+
values,
|
|
30
|
+
z.string(),
|
|
31
|
+
z.array(z.string())
|
|
32
|
+
]).optional();
|
|
19
33
|
const RUNTIME = "Which runtime plays the preset, and so which fields apply.";
|
|
20
34
|
const CssMotion = z.strictObject({
|
|
21
35
|
runtime: z.literal("css").describe(RUNTIME),
|
|
@@ -29,18 +43,37 @@ const CssMotion = z.strictObject({
|
|
|
29
43
|
});
|
|
30
44
|
const JsMotion = z.strictObject({
|
|
31
45
|
runtime: z.literal("js").describe(RUNTIME),
|
|
32
|
-
initial:
|
|
46
|
+
initial: z.union([
|
|
47
|
+
values,
|
|
48
|
+
z.string(),
|
|
49
|
+
z.array(z.string()),
|
|
50
|
+
z.literal(false)
|
|
51
|
+
]).optional().describe("The starting values, as `motion/react` reads them, or `false` to start at `animate` without playing on mount."),
|
|
33
52
|
animate: gesture.describe("The values to animate to."),
|
|
34
53
|
exit: gesture.describe("The values to animate to as the element leaves."),
|
|
35
|
-
transition:
|
|
54
|
+
transition: values.optional().describe("How the animation moves, such as a spring."),
|
|
36
55
|
whileHover: gesture.describe("Values held while the element is hovered."),
|
|
37
56
|
whileTap: gesture.describe("Values held while the element is pressed."),
|
|
38
57
|
whileFocus: gesture.describe("Values held while the element has focus."),
|
|
39
58
|
whileDrag: gesture.describe("Values held while the element is dragged."),
|
|
59
|
+
variants: z.record(z.string(), values).optional().describe("Named states, each a set of values, that `initial`, `animate`, `exit` and the gestures name."),
|
|
60
|
+
layout: z.union([
|
|
61
|
+
z.boolean(),
|
|
62
|
+
z.literal("position"),
|
|
63
|
+
z.literal("size"),
|
|
64
|
+
z.literal("preserve-aspect")
|
|
65
|
+
]).optional().describe("Animates the element to its new size and position when they change, such as a height that follows its content."),
|
|
40
66
|
drag: z.union([z.boolean(), z.string()]).optional().describe("Whether, and along which axis, the element can be dragged."),
|
|
41
67
|
dragConstraints: z.record(z.string(), z.number()).optional().describe("The box a drag stays within."),
|
|
42
68
|
dragElastic: z.number().optional().describe("How far past its constraints a drag can stretch.")
|
|
43
69
|
});
|
|
70
|
+
/**
|
|
71
|
+
* A JS preset written in place, as a style rule's `motion` on a layer rather than a `Motion.ref`: the
|
|
72
|
+
* same fields, with `runtime` optional since in place it can only be `js`. A CSS preset is a class
|
|
73
|
+
* the stylesheet emits under the preset's name, so one written in place has nothing to emit as; name
|
|
74
|
+
* it with `Motion.item` instead.
|
|
75
|
+
*/
|
|
76
|
+
const inlineJsMotion = JsMotion.omit({ runtime: true }).extend({ runtime: z.literal("js").optional().describe(RUNTIME) }).describe("A JS motion preset written in place: `initial`, `animate`, `while*`, `variants`, `transition` and the rest, as `Motion.item` takes them with `runtime: 'js'`.");
|
|
44
77
|
/** The fields of a JS preset that `motion.create` reads as props, in schema order. The emitter
|
|
45
78
|
* reads this rather than restating the schema, so a field added here reaches every emitted preset. */
|
|
46
79
|
const jsMotionPropFields = Object.keys(JsMotion.shape).filter((field) => field !== "runtime");
|
|
@@ -48,7 +81,41 @@ const Motion = defineEntity({
|
|
|
48
81
|
kind: "motion",
|
|
49
82
|
label: "Motion",
|
|
50
83
|
labelPlural: "Motion presets",
|
|
51
|
-
fields: z.discriminatedUnion("runtime", [CssMotion, JsMotion])
|
|
84
|
+
fields: z.discriminatedUnion("runtime", [CssMotion, JsMotion]),
|
|
85
|
+
schemas: {
|
|
86
|
+
/**
|
|
87
|
+
* A variant name is a string the presets that animate together match by, not a ref, so nothing
|
|
88
|
+
* cascades it. Renaming one in a single preset's `variants` leaves its own states and every inner
|
|
89
|
+
* layer that answers it naming the old one, which animates to nothing and says nothing.
|
|
90
|
+
*/
|
|
91
|
+
"rename-variant": {
|
|
92
|
+
input: z.object({
|
|
93
|
+
path: pathInput("motion"),
|
|
94
|
+
key: z.string().min(1),
|
|
95
|
+
to: z.string().min(1)
|
|
96
|
+
}),
|
|
97
|
+
readOnly: false,
|
|
98
|
+
label: "Rename variant",
|
|
99
|
+
description: "Rename one of a JS preset's `variants` (`key` → `to`) wherever the name is used: the preset's own `variants` and states (`initial`, `animate`, `exit`, `while*`), and every preset that animates with it, since a root's gestures name the variants its inner layers' presets declare. \"Animates with\" is the presets a component's style rules put on its layers, joined across a component that renders another. Refused when a preset in that set already declares `to`.",
|
|
100
|
+
scope: "item",
|
|
101
|
+
title: (entity) => `Rename ${entity} variant`,
|
|
102
|
+
example: ({ config }) => {
|
|
103
|
+
for (const preset of config.list("motion")) {
|
|
104
|
+
const variants = preset.toJSON().variants;
|
|
105
|
+
const [key] = Object.keys(variants ?? {});
|
|
106
|
+
if (key !== void 0) return {
|
|
107
|
+
path: preset.path,
|
|
108
|
+
key,
|
|
109
|
+
to: `${key}-renamed`
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
handler: (input, config) => renameMotionVariant(config, {
|
|
114
|
+
path: String(input.path),
|
|
115
|
+
from: String(input.key),
|
|
116
|
+
to: String(input.to)
|
|
117
|
+
})
|
|
118
|
+
} }
|
|
52
119
|
});
|
|
53
120
|
//#endregion
|
|
54
|
-
export { Motion, jsMotionPropFields };
|
|
121
|
+
export { Motion, inlineJsMotion, jsMotionPropFields };
|
|
@@ -4,9 +4,9 @@ import { defineEntity } from "../../framework/defineEntity.js";
|
|
|
4
4
|
import { defineSubEntity } from "../../framework/defineSubEntity.js";
|
|
5
5
|
import { Font } from "./Font.js";
|
|
6
6
|
import { Modifier } from "./Modifier.js";
|
|
7
|
+
import { spellTokenRead } from "./token-values.js";
|
|
7
8
|
import { WEB_CONFIG_NAME } from "../../configs/platform.js";
|
|
8
9
|
import { authoringPhantom } from "../../framework/utils/authoring-phantom.js";
|
|
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
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { canonicalCondition, isRef, kindOf, memberRef, pathOf } from "../../framework/utils/refs.js";
|
|
2
2
|
import { glyphIdentityOf, glyphPackageRefOf, isComponentType } from "./glyph-identity.js";
|
|
3
3
|
import "../../framework/preview-store.js";
|
|
4
|
-
import { Component,
|
|
4
|
+
import { Component, layerRef, storedStyleRules } from "./Component.js";
|
|
5
5
|
//#region src/entities/system/defineComponent.ts
|
|
6
6
|
function build(body) {
|
|
7
7
|
const handle = (() => null);
|
|
@@ -364,14 +364,9 @@ function toStored(body) {
|
|
|
364
364
|
if (body.forwards && typeof body.forwards === "object") stored.forwards = storedForwards(body.forwards, body.layers);
|
|
365
365
|
const rules = body.styles;
|
|
366
366
|
if (!Array.isArray(rules)) return stored;
|
|
367
|
-
const styles = {};
|
|
368
|
-
for (const rule of rules) styles[canonicalWhen(rule.when)] = {
|
|
369
|
-
when: rule.when ?? null,
|
|
370
|
-
layers: rule.layers
|
|
371
|
-
};
|
|
372
367
|
return {
|
|
373
368
|
...stored,
|
|
374
|
-
styles
|
|
369
|
+
styles: storedStyleRules(rules)
|
|
375
370
|
};
|
|
376
371
|
}
|
|
377
372
|
/**
|
|
@@ -2,8 +2,8 @@ import { hasRefMarker } from "../../framework/utils/refs.js";
|
|
|
2
2
|
import { isCalc } from "./calc.js";
|
|
3
3
|
import { isOklchColor } from "./color.js";
|
|
4
4
|
import { literalValueOf } from "../../framework/projections.js";
|
|
5
|
-
import "../../configs/platform.js";
|
|
6
5
|
import { rootFontSize } from "./token-values.js";
|
|
6
|
+
import "../../configs/platform.js";
|
|
7
7
|
//#region src/entities/system/linked-token-values.ts
|
|
8
8
|
/**
|
|
9
9
|
* Adapt a linked token for the system reading it. The source keeps its authored value; only the
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Config } from "../../framework/Config.js";
|
|
2
|
+
|
|
3
|
+
//#region src/entities/system/motion-presets.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* A value a JS preset holds that `motion/react` cannot be handed as written: a token a mode or state
|
|
6
|
+
* decides (`conditional`), which a preset animates as its base value; a token that comes to nothing a
|
|
7
|
+
* preset can carry (`unresolved`); or an `ease` that is no easing `motion/react` reads (`easing`),
|
|
8
|
+
* from a token or written in place. The last two leave the field out.
|
|
9
|
+
*/
|
|
10
|
+
interface MotionPresetToken {
|
|
11
|
+
readonly preset: string;
|
|
12
|
+
/** The field the value sits under, as a dotted path: `transition.stiffness`. */
|
|
13
|
+
readonly at: string;
|
|
14
|
+
/** The token the value comes from; absent for an `ease` written in place. */
|
|
15
|
+
readonly token?: string;
|
|
16
|
+
readonly problem: 'conditional' | 'unresolved' | 'easing';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Every JS-runtime preset, by path, as the props the wrapper spreads onto the animated component.
|
|
20
|
+
* A token a preset names reaches `motion/react` as its value — `Token.ref('springStiffness/snappy')`
|
|
21
|
+
* as `400`, a `200ms` duration as `0.2` — since it reads numbers and seconds, not variables.
|
|
22
|
+
*/
|
|
23
|
+
declare function jsMotionPresets(config: Config): Record<string, Record<string, unknown>>;
|
|
24
|
+
/** Every JS preset a style rule writes in place, by its id, resolved as {@link jsMotionPresets} are. */
|
|
25
|
+
declare function inlineMotionProps(config: Config): Record<string, Record<string, unknown>>;
|
|
26
|
+
/** Whether anything in the system animates through `motion/react`: a JS preset, named or written in
|
|
27
|
+
* place in a style rule. */
|
|
28
|
+
declare function hasJsMotion(config: Config): boolean;
|
|
29
|
+
/** The tokens JS presets name that a preset cannot carry as one value, for the build to report. */
|
|
30
|
+
declare function motionPresetTokens(config: Config): MotionPresetToken[];
|
|
31
|
+
//#endregion
|
|
32
|
+
export { MotionPresetToken, hasJsMotion, inlineMotionProps, jsMotionPresets, motionPresetTokens };
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { collectRefs, isRef, kindOf, pathOf } from "../../framework/utils/refs.js";
|
|
2
|
+
import { composedValueFormOf } from "./composed-values.js";
|
|
3
|
+
import { createSliceMemo } from "../../framework/memo.js";
|
|
4
|
+
import { inlineMotions } from "./motion-variants.js";
|
|
5
|
+
import { jsMotionPropFields } from "./Motion.js";
|
|
6
|
+
import { tokenValueRow } from "./token-values.js";
|
|
7
|
+
import { renderValue } from "./value-render.js";
|
|
8
|
+
//#region src/entities/system/motion-presets.ts
|
|
9
|
+
/** A time spelled in CSS, which `motion/react` reads in seconds. */
|
|
10
|
+
const CSS_TIME = /^(-?(?:\d+(?:\.\d*)?|\.\d+))(ms|s)$/;
|
|
11
|
+
/** A bare number, which a token's value is often written as a string of. */
|
|
12
|
+
const BARE_NUMBER = /^-?(?:\d+(?:\.\d*)?|\.\d+)$/;
|
|
13
|
+
/**
|
|
14
|
+
* One token's value as `motion/react` reads it: a time in seconds, a bare number as a number, and
|
|
15
|
+
* anything else as its CSS, which `motion/react` reads for a length or a colour (`'8px'`, `'#fff'`).
|
|
16
|
+
*/
|
|
17
|
+
function motionValue(css) {
|
|
18
|
+
if (typeof css === "number") return css;
|
|
19
|
+
const text = css.trim();
|
|
20
|
+
const time = CSS_TIME.exec(text);
|
|
21
|
+
if (time) return time[2] === "ms" ? Number(time[1]) / 1e3 : Number(time[1]);
|
|
22
|
+
return BARE_NUMBER.test(text) ? Number(text) : text;
|
|
23
|
+
}
|
|
24
|
+
/** The easings `motion/react` names for itself, which a preset may write as they are. */
|
|
25
|
+
const MOTION_EASINGS = new Set([
|
|
26
|
+
"linear",
|
|
27
|
+
"easeIn",
|
|
28
|
+
"easeOut",
|
|
29
|
+
"easeInOut",
|
|
30
|
+
"circIn",
|
|
31
|
+
"circOut",
|
|
32
|
+
"circInOut",
|
|
33
|
+
"backIn",
|
|
34
|
+
"backOut",
|
|
35
|
+
"backInOut",
|
|
36
|
+
"anticipate"
|
|
37
|
+
]);
|
|
38
|
+
/** CSS's easing keywords, as `motion/react` spells them. `ease` has no name there, so it is its curve. */
|
|
39
|
+
const CSS_EASINGS = {
|
|
40
|
+
linear: "linear",
|
|
41
|
+
"ease-in": "easeIn",
|
|
42
|
+
"ease-out": "easeOut",
|
|
43
|
+
"ease-in-out": "easeInOut",
|
|
44
|
+
ease: [
|
|
45
|
+
.25,
|
|
46
|
+
.1,
|
|
47
|
+
.25,
|
|
48
|
+
1
|
|
49
|
+
]
|
|
50
|
+
};
|
|
51
|
+
const CUBIC_BEZIER = /^cubic-bezier\(\s*([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*([^,\s)]+)\s*\)$/;
|
|
52
|
+
/**
|
|
53
|
+
* An `ease` as `motion/react` reads it: one of its own names, a CSS keyword as its name, a
|
|
54
|
+
* `cubic-bezier(a, b, c, d)` as `[a, b, c, d]`, a curve already written as four numbers, or a list of
|
|
55
|
+
* any of those (one per keyframe). `undefined` for anything else, which `motion/react` would ignore.
|
|
56
|
+
*/
|
|
57
|
+
function motionEasing(value) {
|
|
58
|
+
if (typeof value === "string") {
|
|
59
|
+
const text = value.trim();
|
|
60
|
+
if (MOTION_EASINGS.has(text)) return text;
|
|
61
|
+
if (Object.hasOwn(CSS_EASINGS, text)) {
|
|
62
|
+
const easing = CSS_EASINGS[text];
|
|
63
|
+
return Array.isArray(easing) ? [...easing] : easing;
|
|
64
|
+
}
|
|
65
|
+
const curve = CUBIC_BEZIER.exec(text);
|
|
66
|
+
if (!curve) return void 0;
|
|
67
|
+
const points = curve.slice(1).map(Number);
|
|
68
|
+
return points.every(Number.isFinite) ? points : void 0;
|
|
69
|
+
}
|
|
70
|
+
if (Array.isArray(value)) {
|
|
71
|
+
if (value.length === 4 && value.every((n) => typeof n === "number")) return value;
|
|
72
|
+
const easings = value.map(motionEasing);
|
|
73
|
+
return easings.length > 0 && easings.every((e) => e !== void 0) ? easings : void 0;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A preset's value with every token it names resolved, or `undefined` when one of them resolves to
|
|
78
|
+
* nothing. Values and keyframe lists are walked; a ref, a string with refs in it and a composed value
|
|
79
|
+
* are each read to their literal. A token a mode decides is read as its base value and reported.
|
|
80
|
+
*/
|
|
81
|
+
function resolvePresetValue({ config, value, at, report }) {
|
|
82
|
+
const refs = collectRefs(value).filter((target) => kindOf(target) === "token");
|
|
83
|
+
const container = Array.isArray(value) || typeof value === "object" && value !== null && !isRef(value) && !composedValueFormOf(value);
|
|
84
|
+
if (refs.length === 0 && !container) return { value };
|
|
85
|
+
if (isRef(value)) {
|
|
86
|
+
const row = tokenValueRow({
|
|
87
|
+
config,
|
|
88
|
+
target: value.__ref
|
|
89
|
+
});
|
|
90
|
+
if (row?.state.kind === "value") return { value: motionValue(row.state.value.css) };
|
|
91
|
+
}
|
|
92
|
+
if (Array.isArray(value)) {
|
|
93
|
+
const items = [];
|
|
94
|
+
for (const [index, item] of value.entries()) {
|
|
95
|
+
const resolved = resolvePresetValue({
|
|
96
|
+
config,
|
|
97
|
+
value: item,
|
|
98
|
+
at: `${at}.${index}`,
|
|
99
|
+
report
|
|
100
|
+
});
|
|
101
|
+
if (!resolved) return void 0;
|
|
102
|
+
items.push(resolved.value);
|
|
103
|
+
}
|
|
104
|
+
return { value: items };
|
|
105
|
+
}
|
|
106
|
+
if (typeof value === "object" && value !== null && !isRef(value) && !composedValueFormOf(value)) {
|
|
107
|
+
const fields = {};
|
|
108
|
+
for (const [key, inner] of Object.entries(value)) {
|
|
109
|
+
const resolved = resolvePresetValue({
|
|
110
|
+
config,
|
|
111
|
+
value: inner,
|
|
112
|
+
at: `${at}.${key}`,
|
|
113
|
+
report
|
|
114
|
+
});
|
|
115
|
+
if (!resolved) continue;
|
|
116
|
+
if (key !== "ease") {
|
|
117
|
+
fields[key] = resolved.value;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const easing = motionEasing(resolved.value);
|
|
121
|
+
if (easing !== void 0) {
|
|
122
|
+
fields[key] = easing;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const tokens = collectRefs(inner).filter((target) => kindOf(target) === "token");
|
|
126
|
+
if (tokens.length === 0) report({
|
|
127
|
+
at: `${at}.${key}`,
|
|
128
|
+
problem: "easing"
|
|
129
|
+
});
|
|
130
|
+
for (const target of tokens) report({
|
|
131
|
+
at: `${at}.${key}`,
|
|
132
|
+
token: pathOf(target),
|
|
133
|
+
problem: "easing"
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
return { value: fields };
|
|
137
|
+
}
|
|
138
|
+
for (const target of refs) if (tokenValueRow({
|
|
139
|
+
config,
|
|
140
|
+
target
|
|
141
|
+
})?.state.kind === "conditional") report({
|
|
142
|
+
at,
|
|
143
|
+
token: pathOf(target),
|
|
144
|
+
problem: "conditional"
|
|
145
|
+
});
|
|
146
|
+
const literal = renderValue({
|
|
147
|
+
config,
|
|
148
|
+
value,
|
|
149
|
+
refs: "literal"
|
|
150
|
+
});
|
|
151
|
+
if (literal === void 0) {
|
|
152
|
+
const missing = refs.filter((target) => {
|
|
153
|
+
const kind = tokenValueRow({
|
|
154
|
+
config,
|
|
155
|
+
target
|
|
156
|
+
})?.state.kind;
|
|
157
|
+
return kind === void 0 || kind === "unresolved";
|
|
158
|
+
});
|
|
159
|
+
for (const target of missing.length > 0 ? missing : refs) report({
|
|
160
|
+
at,
|
|
161
|
+
token: pathOf(target),
|
|
162
|
+
problem: "unresolved"
|
|
163
|
+
});
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
return { value: motionValue(literal) };
|
|
167
|
+
}
|
|
168
|
+
/** One preset body as the props `motion.create` reads, reporting under `preset` what it could not carry. */
|
|
169
|
+
function resolveBody(config, preset, body, tokens) {
|
|
170
|
+
const props = {};
|
|
171
|
+
for (const field of jsMotionPropFields) {
|
|
172
|
+
if (body[field] === void 0) continue;
|
|
173
|
+
const resolved = resolvePresetValue({
|
|
174
|
+
config,
|
|
175
|
+
value: body[field],
|
|
176
|
+
at: field,
|
|
177
|
+
report: (problem) => tokens.push({
|
|
178
|
+
preset,
|
|
179
|
+
...problem
|
|
180
|
+
})
|
|
181
|
+
});
|
|
182
|
+
if (resolved) props[field] = resolved.value;
|
|
183
|
+
}
|
|
184
|
+
return props;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Every JS preset as the props `motion.create` reads, with the tokens they name resolved, and the
|
|
188
|
+
* tokens that could not be handed over as one value: the named presets by path, and the ones a style
|
|
189
|
+
* rule writes in place by the id `inlineMotionId` gives them.
|
|
190
|
+
*/
|
|
191
|
+
const resolveJsMotionPresets = createSliceMemo({
|
|
192
|
+
kinds: [
|
|
193
|
+
"motion",
|
|
194
|
+
"component",
|
|
195
|
+
"token",
|
|
196
|
+
"settings",
|
|
197
|
+
"font"
|
|
198
|
+
],
|
|
199
|
+
compute: (config) => {
|
|
200
|
+
const presets = {};
|
|
201
|
+
const inline = {};
|
|
202
|
+
const tokens = [];
|
|
203
|
+
for (const preset of config.list("motion")) {
|
|
204
|
+
const body = preset.toJSON();
|
|
205
|
+
if (body.runtime !== "js") continue;
|
|
206
|
+
presets[preset.path] = resolveBody(config, preset.path, body, tokens);
|
|
207
|
+
}
|
|
208
|
+
for (const entry of inlineMotions(config).valid) inline[entry.id] = resolveBody(config, entry.id, entry.body, tokens);
|
|
209
|
+
return {
|
|
210
|
+
presets,
|
|
211
|
+
inline,
|
|
212
|
+
tokens
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
/**
|
|
217
|
+
* Every JS-runtime preset, by path, as the props the wrapper spreads onto the animated component.
|
|
218
|
+
* A token a preset names reaches `motion/react` as its value — `Token.ref('springStiffness/snappy')`
|
|
219
|
+
* as `400`, a `200ms` duration as `0.2` — since it reads numbers and seconds, not variables.
|
|
220
|
+
*/
|
|
221
|
+
function jsMotionPresets(config) {
|
|
222
|
+
return resolveJsMotionPresets(config).presets;
|
|
223
|
+
}
|
|
224
|
+
/** Every JS preset a style rule writes in place, by its id, resolved as {@link jsMotionPresets} are. */
|
|
225
|
+
function inlineMotionProps(config) {
|
|
226
|
+
return resolveJsMotionPresets(config).inline;
|
|
227
|
+
}
|
|
228
|
+
/** Whether anything in the system animates through `motion/react`: a JS preset, named or written in
|
|
229
|
+
* place in a style rule. */
|
|
230
|
+
function hasJsMotion(config) {
|
|
231
|
+
const { presets, inline } = resolveJsMotionPresets(config);
|
|
232
|
+
return Object.keys(presets).length > 0 || Object.keys(inline).length > 0;
|
|
233
|
+
}
|
|
234
|
+
/** The tokens JS presets name that a preset cannot carry as one value, for the build to report. */
|
|
235
|
+
function motionPresetTokens(config) {
|
|
236
|
+
return resolveJsMotionPresets(config).tokens;
|
|
237
|
+
}
|
|
238
|
+
//#endregion
|
|
239
|
+
export { hasJsMotion, inlineMotionProps, jsMotionPresets, motionPresetTokens };
|