kuinetic 0.1.4 → 0.2.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/README.md +93 -10
- package/dist/esm/advanced/index.mjs +4727 -0
- package/dist/esm/chunk-AEQGC2KM.mjs +189 -0
- package/dist/esm/chunk-MQSNMYRP.mjs +9332 -0
- package/dist/esm/chunk-RVTYN6NZ.mjs +3446 -0
- package/dist/esm/chunk-U43BX5O2.mjs +2984 -0
- package/dist/esm/core/index.mjs +16 -9
- package/dist/esm/effects/index.mjs +19 -4
- package/dist/esm/index.mjs +17 -10
- package/dist/kuinetic.advanced.js +5070 -0
- package/dist/kuinetic.advanced.min.js +749 -0
- package/dist/kuinetic.all.js +15147 -6039
- package/dist/kuinetic.all.min.js +2 -0
- package/dist/kuinetic.css +2801 -318
- package/dist/kuinetic.js +15147 -6038
- package/dist/kuinetic.min.css +1 -0
- package/dist/kuinetic.min.js +7 -0
- package/dist/types/3d/angles.d.ts +30 -0
- package/dist/types/3d/flattening.d.ts +49 -0
- package/dist/types/3d/index.d.ts +36 -0
- package/dist/types/3d/model-3d.d.ts +115 -0
- package/dist/types/3d/register.d.ts +26 -0
- package/dist/types/3d/webgl.d.ts +24 -0
- package/dist/types/advanced/audio.d.ts +322 -0
- package/dist/types/advanced/base.d.ts +233 -0
- package/dist/types/advanced/camera-3d.d.ts +236 -0
- package/dist/types/advanced/fluid-cursor.d.ts +149 -0
- package/dist/types/advanced/gl-utils.d.ts +52 -0
- package/dist/types/advanced/glsl.d.ts +60 -0
- package/dist/types/advanced/index.d.ts +23 -0
- package/dist/types/advanced/particles.d.ts +108 -0
- package/dist/types/advanced/scenes.d.ts +207 -0
- package/dist/types/advanced/shaders.d.ts +972 -0
- package/dist/types/browser/boot.d.ts +72 -0
- package/dist/types/core/activation.d.ts +227 -2
- package/dist/types/core/animator.d.ts +446 -11
- package/dist/types/core/attrs.d.ts +9 -0
- package/dist/types/core/breakpoints.d.ts +260 -0
- package/dist/types/core/bundles.d.ts +71 -0
- package/dist/types/core/callback.d.ts +64 -0
- package/dist/types/core/capabilities.d.ts +47 -0
- package/dist/types/core/channels.d.ts +120 -2
- package/dist/types/core/cloak-selectors.d.ts +47 -0
- package/dist/types/core/compile.d.ts +207 -2
- package/dist/types/core/control.d.ts +218 -0
- package/dist/types/core/declarations.d.ts +128 -0
- package/dist/types/core/derived/aggregate.d.ts +43 -0
- package/dist/types/core/derived/book.d.ts +30 -0
- package/dist/types/core/derived/diagnostics.d.ts +51 -0
- package/dist/types/core/derived/group-gate.d.ts +62 -0
- package/dist/types/core/derived/install.d.ts +110 -0
- package/dist/types/core/derived/late-matches.d.ts +19 -0
- package/dist/types/core/derived/types.d.ts +108 -0
- package/dist/types/core/easing.d.ts +57 -0
- package/dist/types/core/element-config.d.ts +47 -6
- package/dist/types/core/element-size.d.ts +23 -0
- package/dist/types/core/event-sources.d.ts +39 -0
- package/dist/types/core/flip.d.ts +34 -1
- package/dist/types/core/gesture.d.ts +12 -0
- package/dist/types/core/host-facts.d.ts +155 -0
- package/dist/types/core/index.d.ts +7 -3
- package/dist/types/core/owned-styles.d.ts +129 -2
- package/dist/types/core/params.d.ts +48 -0
- package/dist/types/core/parse.d.ts +28 -1
- package/dist/types/core/register-into.d.ts +29 -0
- package/dist/types/core/registry.d.ts +10 -3
- package/dist/types/core/repeat.d.ts +91 -0
- package/dist/types/core/sequence.d.ts +126 -0
- package/dist/types/core/stagger-config.d.ts +199 -0
- package/dist/types/core/stagger-keys.d.ts +63 -0
- package/dist/types/core/stagger.d.ts +187 -6
- package/dist/types/core/style-plan.d.ts +21 -16
- package/dist/types/core/target.d.ts +128 -0
- package/dist/types/core/threshold-reachability.d.ts +45 -0
- package/dist/types/core/time-scale.d.ts +9 -0
- package/dist/types/core/toggle-actions.d.ts +141 -0
- package/dist/types/core/travel.d.ts +59 -0
- package/dist/types/core/types.d.ts +699 -13
- package/dist/types/core/unquoted-selectors.d.ts +53 -0
- package/dist/types/effects/carousel/drag.d.ts +80 -0
- package/dist/types/effects/carousel/index.d.ts +149 -0
- package/dist/types/effects/catalog/discrete.d.ts +13 -0
- package/dist/types/effects/catalog/interaction-proximity.d.ts +24 -0
- package/dist/types/effects/catalog/interaction-reveal.d.ts +248 -0
- package/dist/types/effects/catalog/interaction-shared.d.ts +42 -0
- package/dist/types/effects/catalog/interaction-states.d.ts +68 -0
- package/dist/types/effects/catalog/materials.d.ts +67 -0
- package/dist/types/effects/catalog/media-shared.d.ts +3 -2
- package/dist/types/effects/catalog/numbers-shared.d.ts +8 -5
- package/dist/types/effects/catalog/shared.d.ts +1 -1
- package/dist/types/effects/catalog/text-shared.d.ts +86 -10
- package/dist/types/effects/catalog/transforms.d.ts +13 -0
- package/dist/types/effects/catalog/view-transitions.d.ts +13 -0
- package/dist/types/effects/forms/primitives.d.ts +15 -4
- package/dist/types/effects/gestures/index.d.ts +53 -0
- package/dist/types/effects/index.d.ts +5 -0
- package/dist/types/effects/layout/presets.d.ts +35 -0
- package/dist/types/effects/motion-path/index.d.ts +35 -0
- package/dist/types/effects/scroll-mechanics/params.d.ts +23 -0
- package/dist/types/effects/scroll-mechanics/presets.d.ts +51 -0
- package/dist/types/effects/scroll-mechanics/section-index.d.ts +47 -0
- package/dist/types/effects/shared.d.ts +124 -4
- package/dist/types/effects/step-index.d.ts +121 -0
- package/dist/types/effects/step-marking.d.ts +41 -33
- package/dist/types/effects/svg/icon-parts.d.ts +23 -0
- package/dist/types/effects/three-d/flip-parts.d.ts +46 -0
- package/dist/types/effects/tween/index.d.ts +57 -0
- package/dist/types/effects/tween/properties.d.ts +107 -0
- package/dist/types/effects/tween/waypoints.d.ts +106 -0
- package/dist/types/showcase/compare.d.ts +4 -0
- package/dist/types/showcase/device-frame.d.ts +3 -0
- package/dist/types/showcase/hotspots.d.ts +3 -0
- package/dist/types/showcase/index.d.ts +30 -0
- package/dist/types/showcase/lightbox.d.ts +3 -0
- package/dist/types/showcase/media-source.d.ts +13 -0
- package/dist/types/showcase/modal-shell.d.ts +22 -0
- package/dist/types/showcase/scroll-story.d.ts +4 -0
- package/dist/types/showcase/shared.d.ts +47 -0
- package/dist/types/showcase/slideshow.d.ts +3 -0
- package/dist/types/showcase/slow-mo.d.ts +5 -0
- package/package.json +14 -7
- package/dist/esm/chunk-7WMNPIOZ.mjs +0 -4883
- package/dist/esm/chunk-JT4PZL3A.mjs +0 -773
- package/dist/esm/chunk-TJDDIQRG.mjs +0 -1290
|
@@ -1,9 +1,91 @@
|
|
|
1
1
|
import type { Registry, ResolvedEffect } from './registry.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { SequenceStep } from './sequence.js';
|
|
3
|
+
import type { TargetScope } from './target.js';
|
|
4
|
+
import type { Activation, Channel, EffectSpec, EffectVariant, NamedActivation, ParameterSchema, ParsedValue, ReducedMotionPolicy, SegmentHoists, Timeline } from './types.js';
|
|
3
5
|
export interface Entry {
|
|
4
6
|
spec: EffectSpec;
|
|
5
7
|
resolved: ResolvedEffect;
|
|
8
|
+
/**
|
|
9
|
+
* Per-spec refinement from `primitive.variantFor`, computed once in `resolveEntries` and carried
|
|
10
|
+
* on the entry so nothing downstream has to call it a second time. Absent for every primitive
|
|
11
|
+
* that is fully described without seeing an attribute, which is all but the generic tween.
|
|
12
|
+
*/
|
|
13
|
+
variant?: EffectVariant;
|
|
14
|
+
/**
|
|
15
|
+
* Concrete milliseconds an `at:` position resolved to, for JS-rendered entries only.
|
|
16
|
+
*
|
|
17
|
+
* A CSS-rendered entry needs no such field: its position is a symbolic `calc()` the browser
|
|
18
|
+
* evaluates, which is both more accurate and re-evaluated when a stylesheet moves one of the
|
|
19
|
+
* durations underneath it (see `core/sequence.ts`). A JS-rendered one has no `animation-delay`
|
|
20
|
+
* to write to and needs a number, so the sequencer's numeric mirror is carried here and applied
|
|
21
|
+
* by `js-effect-preparer.ts` over whatever `readEffectTiming` read off the spec.
|
|
22
|
+
*
|
|
23
|
+
* Absent when the segment carries no `at:`, and when the position was refused — in both cases the
|
|
24
|
+
* effect keeps its own authored delay. There is no third case: a sequenced step always carries a
|
|
25
|
+
* real number, because the sequencer refuses a duration it cannot read rather than passing an
|
|
26
|
+
* unknown along.
|
|
27
|
+
*/
|
|
28
|
+
sequencedDelayMs?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Where the sequencer placed this segment, resolved once for the whole authored comma list
|
|
31
|
+
* before {@link compileTargets} partitions it by target — see that function's own comment for
|
|
32
|
+
* why the order matters. Always present once an entry leaves `compileTargets`; absent only on an
|
|
33
|
+
* `Entry` a test builds by hand without going through it.
|
|
34
|
+
*/
|
|
35
|
+
step?: SequenceStep;
|
|
36
|
+
/**
|
|
37
|
+
* Selector this entry retargets to, lifted out of `spec.params` by `resolveEntries` for any
|
|
38
|
+
* primitive that does not declare a `target` parameter of its own. Undefined means "compiles on
|
|
39
|
+
* the host", which is every entry today and every entry whose primitive owns `target:` itself
|
|
40
|
+
* (see `liftTarget`'s comment for the current set — they read the key from `spec.params`,
|
|
41
|
+
* unchanged).
|
|
42
|
+
*/
|
|
43
|
+
target?: string;
|
|
44
|
+
/** Which tree {@link target} is searched in. Only meaningful when `target` is set. */
|
|
45
|
+
scope?: TargetScope;
|
|
46
|
+
/**
|
|
47
|
+
* `animation-composition` for every track this entry compiles, when the composition resolver had
|
|
48
|
+
* to make it additive to let a same-channel neighbour survive — see {@link resolveComposition}.
|
|
49
|
+
*
|
|
50
|
+
* Absent means the CSS initial value, `replace`, which is what every entry compiled before this
|
|
51
|
+
* existed and what all but the handful of additively-resolved ones still compile to.
|
|
52
|
+
* `declarations.ts` omits the declaration entirely when no track sets it, the same way it already
|
|
53
|
+
* omits an all-`normal` `animation-direction`.
|
|
54
|
+
*/
|
|
55
|
+
composite?: 'add';
|
|
6
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Channels one entry actually writes — the primitive's declaration, widened by any variant.
|
|
59
|
+
*
|
|
60
|
+
* Read by conflict detection *and* by the plan's channel union, which must agree: a `tween x:100`
|
|
61
|
+
* that is checked for collisions on `translate` but reports no channel to `style-plan.ts` would
|
|
62
|
+
* compose correctly and then skip the individual-transform fallback that same channel exists to
|
|
63
|
+
* trigger.
|
|
64
|
+
*
|
|
65
|
+
* @complexity O(c) time and space in the entry's channel count.
|
|
66
|
+
* @overallScore 100
|
|
67
|
+
*/
|
|
68
|
+
export declare function channelsFor(entry: Entry): Channel[];
|
|
69
|
+
/**
|
|
70
|
+
* Authored parameter values in force for one entry — `spec.params`, or a variant's normalisation
|
|
71
|
+
* of them. Exported because the JS-effect path reads them too, and the two must not disagree about
|
|
72
|
+
* what the author wrote.
|
|
73
|
+
*
|
|
74
|
+
* @complexity O(1) time and space.
|
|
75
|
+
* @overallScore 100
|
|
76
|
+
*/
|
|
77
|
+
export declare function authoredParams(entry: Entry): Record<string, string>;
|
|
78
|
+
/**
|
|
79
|
+
* The parameter specs one entry's values are validated against — the primitive's declaration,
|
|
80
|
+
* extended by any its variant synthesised for keys the primitive could not declare statically.
|
|
81
|
+
*
|
|
82
|
+
* Merged rather than replaced: see `EffectVariant.schema`. The primitive's own specs stay in force,
|
|
83
|
+
* so a variant can add parameters but never relax one.
|
|
84
|
+
*
|
|
85
|
+
* @complexity O(p) time and space in the schema size, and only when a variant declares one.
|
|
86
|
+
* @overallScore 100
|
|
87
|
+
*/
|
|
88
|
+
export declare function schemaFor(entry: Entry): ParameterSchema;
|
|
7
89
|
export interface CompiledPlan {
|
|
8
90
|
/** Effect names to stamp into `data-kui-fx` for CSS hooks and debugging. */
|
|
9
91
|
fxNames: string[];
|
|
@@ -11,6 +93,18 @@ export interface CompiledPlan {
|
|
|
11
93
|
vars: Record<string, string>;
|
|
12
94
|
/** Longhand animation declarations, compiled as parallel lists so effects compose. */
|
|
13
95
|
declarations: Record<string, string>;
|
|
96
|
+
/**
|
|
97
|
+
* The bare `@keyframes` idents behind those declarations, one per track, in the same order.
|
|
98
|
+
*
|
|
99
|
+
* Carried separately because `animation-name` is no longer a list of idents that can be recovered
|
|
100
|
+
* by splitting it: a gated segment compiles to `var(--kui-above-md, kui-in-up)` (see
|
|
101
|
+
* `core/breakpoints.ts`), and `String.split(',')` shreds that into `var(--kui-above-md` and
|
|
102
|
+
* `kui-in-up)`. `animator.ts` hands this list to `createCssInstance`, which matches it against
|
|
103
|
+
* `getAnimations()` to decide which handles it owns — so a re-parse that produced `kui-in-up)`
|
|
104
|
+
* would own nothing, settle its completion promise immediately, and strand `data-kui-state` on
|
|
105
|
+
* `finished` while the animation was still visibly running.
|
|
106
|
+
*/
|
|
107
|
+
keyframeNames: string[];
|
|
14
108
|
/** Effects whose renderer needs JS setup. */
|
|
15
109
|
jsEffects: Entry[];
|
|
16
110
|
/** Names that are not registered. Must NOT be stamped, or the element is never rescanned. */
|
|
@@ -20,7 +114,7 @@ export interface CompiledPlan {
|
|
|
20
114
|
/** Activation preferred by the composed primitives when the author named none. */
|
|
21
115
|
defaultActivation?: Activation;
|
|
22
116
|
/** Activations every composed primitive supports, for enforcement by the animator. */
|
|
23
|
-
supportedActivations:
|
|
117
|
+
supportedActivations: NamedActivation[];
|
|
24
118
|
/**
|
|
25
119
|
* Timelines every composed primitive supports. Empty means none — `style-plan.ts` must not
|
|
26
120
|
* apply a native `view()`/`scroll()` timeline the author's effect doesn't declare support for,
|
|
@@ -30,6 +124,19 @@ export interface CompiledPlan {
|
|
|
30
124
|
supportedTimelines: Timeline[];
|
|
31
125
|
/** Union of channels every composed effect writes to, so callers can react to what actually moves. */
|
|
32
126
|
channels: Channel[];
|
|
127
|
+
/**
|
|
128
|
+
* Merged `transition` shorthand value for the composed effects' declared {@link TransitionSegment}s,
|
|
129
|
+
* or absent when none of them transitions anything. Consumed by the one
|
|
130
|
+
* `:where([data-kui-fx])` rule in `base.css` through the ledger, the same way `vars`/`declarations`
|
|
131
|
+
* are.
|
|
132
|
+
*
|
|
133
|
+
* Deliberately NOT folded into `declarations`: `style-plan.ts` reads that field's emptiness as
|
|
134
|
+
* "this element has a CSS animation" and would gate every one of these ten presets — all
|
|
135
|
+
* `renderer: 'javascript'` — behind `animation-play-state: paused`, pausing an animation that
|
|
136
|
+
* does not exist. Deliberately NOT folded into `vars` either: that field means "author parameter
|
|
137
|
+
* overrides", and several tests assert its exact contents with `toEqual`.
|
|
138
|
+
*/
|
|
139
|
+
transition?: string;
|
|
33
140
|
warnings: string[];
|
|
34
141
|
}
|
|
35
142
|
/**
|
|
@@ -47,3 +154,101 @@ export interface CompiledPlan {
|
|
|
47
154
|
* @overallScore 100
|
|
48
155
|
*/
|
|
49
156
|
export declare function compile(parsed: ParsedValue, registry: Registry, timeline: Timeline): CompiledPlan;
|
|
157
|
+
/**
|
|
158
|
+
* One `target:`-partitioned group of a compiled `data-kui` attribute — the plan for the segments
|
|
159
|
+
* that share one `(scope, selector)` pair, plus which pair that is.
|
|
160
|
+
*
|
|
161
|
+
* `selector: ''` is the host: the element the attribute is authored on, always present, always
|
|
162
|
+
* `CompiledDocument.targets[0]`. Every other entry names a `target:` a primitive did not claim for
|
|
163
|
+
* itself — see `Entry.target`'s own comment for which primitives those are.
|
|
164
|
+
*/
|
|
165
|
+
export interface CompiledTarget {
|
|
166
|
+
/** `''` for the host group. */
|
|
167
|
+
selector: string;
|
|
168
|
+
scope: TargetScope;
|
|
169
|
+
/**
|
|
170
|
+
* Segment-scoped hoists merged across this group's own member entries, or absent when none of
|
|
171
|
+
* them carried one — see `SegmentHoists` and `scopeHoists`. Not yet consumed at runtime (that is
|
|
172
|
+
* Phase 2's job, via `element-config.ts`'s `resolveGroupConfig`); documented here as the shape a
|
|
173
|
+
* derived host's own `ElementConfig` will be built from.
|
|
174
|
+
*/
|
|
175
|
+
hoists?: SegmentHoists;
|
|
176
|
+
/** This group's lifted specs (target/scope stripped, hoists kept), authored order — what a
|
|
177
|
+
* multi-group union recompiles from (2b `compileUnion`). */
|
|
178
|
+
specs: EffectSpec[];
|
|
179
|
+
plan: CompiledPlan;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* The full compilation of one authored `data-kui` value, before it is narrowed to a single plan.
|
|
183
|
+
*
|
|
184
|
+
* `warnings` here are the ones about the authored comma list as a whole rather than about any one
|
|
185
|
+
* target group: unknown effect names, the `at:` sequencer's own diagnostics, a refused container
|
|
186
|
+
* gate, a retarget the preset would not survive, and the hoisted `rm:`'s one-way-ratchet refusal.
|
|
187
|
+
* A group's own composition/parameter warnings live on `CompiledTarget.plan.warnings` instead,
|
|
188
|
+
* exactly where they always have.
|
|
189
|
+
*
|
|
190
|
+
* The two lists are disjoint, and that is load-bearing rather than tidy: `animator.ts` reports this
|
|
191
|
+
* one and then every group's, so a warning reachable through both would be printed twice — which is
|
|
192
|
+
* exactly what a shared array reference used to do to all of them.
|
|
193
|
+
*/
|
|
194
|
+
export interface CompiledDocument {
|
|
195
|
+
targets: CompiledTarget[];
|
|
196
|
+
warnings: string[];
|
|
197
|
+
/** 9b: stray segments that look like an unquoted selector list — surfaced by 5b in
|
|
198
|
+
* `data-kui-unmatched`. */
|
|
199
|
+
suspectSelectors?: string[];
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Compile a parsed `data-kui` value into one plan per `target:`/`scope:` group.
|
|
203
|
+
*
|
|
204
|
+
* The host group (selector `''`) is always present and always first, whether or not the author
|
|
205
|
+
* targeted anything — `install` in `animator.ts` loops every group the same way, and a page that
|
|
206
|
+
* never uses `target:` compiles to exactly the one group it always has.
|
|
207
|
+
*
|
|
208
|
+
* A fixed order, not to be reshuffled:
|
|
209
|
+
*
|
|
210
|
+
* 1. **Resolve and lift**, once, over the whole authored list (`resolveEntries`). Every entry gets
|
|
211
|
+
* a primitive; every entry whose primitive does not own `target:` itself gets `.target`/`.scope`
|
|
212
|
+
* pulled off its params here, before anything downstream can see them.
|
|
213
|
+
* 2. **Sanitize container gates** (`refuseContainerGate`), before composition sees them — see that
|
|
214
|
+
* function's own comment for why a stripped gate must not still count as "these can never
|
|
215
|
+
* collide".
|
|
216
|
+
* 3. **Sequence**, once, over the whole *unpartitioned* list. `at:` positions a segment against its
|
|
217
|
+
* neighbours in the authored comma list — `fade-up target:h1, slide-left target:p at:-200ms` is
|
|
218
|
+
* one author's clearly-linked pair, and partitioning first would make them neighbourless.
|
|
219
|
+
* 4. **Partition, then compose and build, per group.** Channel conflicts are only real within a
|
|
220
|
+
* group — two effects that land on different elements cannot collide — so `findConflicts`
|
|
221
|
+
* (inside `resolveComposition`) has to run after the split, not before it.
|
|
222
|
+
*
|
|
223
|
+
* @param parsed - Output of `parse`.
|
|
224
|
+
* @param registry - Effect catalog to resolve names against.
|
|
225
|
+
* @param timeline - Element-scoped timeline, used to warn on unsupported combinations.
|
|
226
|
+
* @complexity O(e * p) time in composed effects and their parameters; O(e) space.
|
|
227
|
+
* @overallScore 100
|
|
228
|
+
*/
|
|
229
|
+
export declare function compileTargets(parsed: ParsedValue, registry: Registry, timeline: Timeline): CompiledDocument;
|
|
230
|
+
/**
|
|
231
|
+
* Fold a targeted segment's provisional hoists (`spec.hoists`, from `parse.ts`) back onto the
|
|
232
|
+
* element-wide `ParsedValue` for any spec whose primitive is not itself a `target:`-declaring one
|
|
233
|
+
* (or is unknown) — see `types.ts`'s `SegmentHoists`.
|
|
234
|
+
*
|
|
235
|
+
* `parseSegment` cannot know, at parse time, whether a targeted segment's own primitive declares
|
|
236
|
+
* a `target` parameter — that requires the registry, which only `compile.ts` has. A segment whose
|
|
237
|
+
* primitive *does* declare `target` (the nine listed on `liftTarget`'s comment) never becomes a
|
|
238
|
+
* group at all: `target:` there means "this primitive's own participants", so its hoists were
|
|
239
|
+
* always meant to be element-wide, same as before this feature existed. An unknown name is folded
|
|
240
|
+
* the same way, for the same reason `resolveEntries` already treats it as staying on the host:
|
|
241
|
+
* there is no group to scope anything to.
|
|
242
|
+
*
|
|
243
|
+
* Called from `animator.ts`'s `process()`, right after `bundles.expand` and before
|
|
244
|
+
* `resolveConfig` — `resolveConfig` reads `parsed.activation`/`timeline`/etc. and must see the
|
|
245
|
+
* folded answer, not a value still sitting on a declaring spec's `hoists`.
|
|
246
|
+
*
|
|
247
|
+
* @param parsed - Output of `parse`/`bundles.expand`.
|
|
248
|
+
* @param registry - Effect catalog, needed to tell a declaring primitive from a retargeting one.
|
|
249
|
+
* @returns `parsed` unchanged (by reference) when nothing needed folding — the identity path for
|
|
250
|
+
* every attribute with no `target:` at all — or a new `ParsedValue` with the fold applied.
|
|
251
|
+
* @complexity O(s * k) time in spec count and the nine hoist keys; O(s) space.
|
|
252
|
+
* @overallScore 100
|
|
253
|
+
*/
|
|
254
|
+
export declare function scopeHoists(parsed: ParsedValue, registry: Registry): ParsedValue;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import type { Animator } from './animator.js';
|
|
2
|
+
import type { StyleLedger } from './owned-styles.js';
|
|
3
|
+
import type { Target } from './play.js';
|
|
4
|
+
import type { Activation, InstanceControl, PlaybackState, Timeline } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Control backed by the real `Animation` objects a compiled CSS effect produces.
|
|
7
|
+
*
|
|
8
|
+
* @param animations - Reader for the element's *owned* animation handles. A reader rather than an
|
|
9
|
+
* array because the set changes: `instances.ts` restarts an animation by rewriting
|
|
10
|
+
* `animation-name`, which replaces the handles wholesale, and a captured array would then be
|
|
11
|
+
* driving objects the element no longer has.
|
|
12
|
+
* @param ledger - The instance's style ledger, so a play-state write unwinds on teardown.
|
|
13
|
+
* @complexity O(a) per call in owned animations; O(1) space.
|
|
14
|
+
* @overallScore 100
|
|
15
|
+
*/
|
|
16
|
+
export declare function createCssControl(animations: () => Animation[], ledger: StyleLedger): InstanceControl;
|
|
17
|
+
/**
|
|
18
|
+
* A handle over one selection's playheads.
|
|
19
|
+
*
|
|
20
|
+
* Every mutator returns the handle so calls chain — `control('.hero').timeScale(0.25).seek(0.5)`
|
|
21
|
+
* reads the way the equivalent GSAP line does. Chaining is the reason these are methods rather
|
|
22
|
+
* than settable properties.
|
|
23
|
+
*/
|
|
24
|
+
export interface ControlHandle {
|
|
25
|
+
/** The elements this handle resolved to, in document order. */
|
|
26
|
+
readonly elements: Element[];
|
|
27
|
+
/**
|
|
28
|
+
* Effect names in the selection whose playhead no control call can reach — JavaScript-rendered
|
|
29
|
+
* effects, and anything driven by scroll rather than a clock.
|
|
30
|
+
*
|
|
31
|
+
* Readable so a caller can branch on it rather than discovering the gap by watching nothing
|
|
32
|
+
* happen. Every entry has also already been reported through the animator's reporter.
|
|
33
|
+
*
|
|
34
|
+
* "Playhead" is the operative word, and it is `pause`, `play`, `seek`, `timeScale` and `progress`
|
|
35
|
+
* that it governs. `reverse()` is the one method here that is not a playhead call — it asks the
|
|
36
|
+
* animator which way the element is travelling — so it answers to the animator's directional test
|
|
37
|
+
* instead, and a scroll-driven element is refused for its own reason rather than this one.
|
|
38
|
+
*/
|
|
39
|
+
readonly uncontrolled: string[];
|
|
40
|
+
pause(): ControlHandle;
|
|
41
|
+
play(): ControlHandle;
|
|
42
|
+
/**
|
|
43
|
+
* Play the selection backwards, ending at the from-state each element started from.
|
|
44
|
+
*
|
|
45
|
+
* Idempotent: calling it twice is one exit, not an exit and an entrance, on exactly the rule that
|
|
46
|
+
* makes two `pointerleave`s in a row one exit. It is also *recorded* — the animator knows the
|
|
47
|
+
* element is travelling backwards, so a subsequent paired-activation exit does not start a second
|
|
48
|
+
* reverse, and the element settles at `data-kui-state="ready"` with a `kui:reverse-finish`.
|
|
49
|
+
*
|
|
50
|
+
* To travel forwards again, activate the element (`play()`, `kui.activate()`, or the entrance
|
|
51
|
+
* half of its activation): the animator turns a reversing playhead around rather than restarting
|
|
52
|
+
* it. `play()` on this handle is the narrower thing its name says elsewhere in this file — the
|
|
53
|
+
* counterpart to `pause()` — and does not change direction.
|
|
54
|
+
*/
|
|
55
|
+
reverse(): ControlHandle;
|
|
56
|
+
/** Move every playhead to `progress` (0..1). Values outside the range are clamped. */
|
|
57
|
+
seek(progress: number): ControlHandle;
|
|
58
|
+
/** Multiply playback speed. `1` is authored speed; a negative value runs backwards. */
|
|
59
|
+
timeScale(rate: number): ControlHandle;
|
|
60
|
+
/**
|
|
61
|
+
* Position of the *least* advanced element in the selection, 0..1.
|
|
62
|
+
*
|
|
63
|
+
* The minimum rather than the maximum or the first, so `progress === 1` means every element is
|
|
64
|
+
* done — the reading an author actually gates on. `0` for a selection with nothing controllable.
|
|
65
|
+
*/
|
|
66
|
+
readonly progress: number;
|
|
67
|
+
readonly state: PlaybackState;
|
|
68
|
+
}
|
|
69
|
+
export interface ControlRequest {
|
|
70
|
+
animator: Animator;
|
|
71
|
+
root: ParentNode;
|
|
72
|
+
target: Target;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Build a control handle for a selection.
|
|
76
|
+
*
|
|
77
|
+
* Warnings are emitted once here, at construction, rather than on each call: an author who asks
|
|
78
|
+
* for control over an effect that has none should be told immediately, including when they only
|
|
79
|
+
* meant to *read* `progress` — and repeating the same sentence on every frame of a `seek` loop
|
|
80
|
+
* would bury it. The default reporter is silent, exactly as it is for an unknown effect name or an
|
|
81
|
+
* unsupported activation; `consoleReporter()` makes all of them loud together, which is the
|
|
82
|
+
* existing contract rather than a new one invented here.
|
|
83
|
+
*
|
|
84
|
+
* @param request - Animator, root, and target selection. Mirrors `play`'s request shape.
|
|
85
|
+
* @returns A handle whose mutators chain.
|
|
86
|
+
* @complexity O(n) time in selected elements and their instances; O(n) space.
|
|
87
|
+
* @overallScore 100
|
|
88
|
+
*/
|
|
89
|
+
export declare function control(request: ControlRequest): ControlHandle;
|
|
90
|
+
/**
|
|
91
|
+
* Lifecycle events.
|
|
92
|
+
*
|
|
93
|
+
* Before this module the library dispatched nothing at all — an author could start an animation
|
|
94
|
+
* from an attribute and then had no way whatsoever to learn that it had finished. Every escape
|
|
95
|
+
* hatch on offer (poll `data-kui-state`, race a `setTimeout` against the authored duration, wrap
|
|
96
|
+
* the element and watch it with a `MutationObserver`) is worse than the thing it replaces, and the
|
|
97
|
+
* last one is actively broken here — see the `MutationObserver` trap in
|
|
98
|
+
* `docs/implementation-outline-gsap-parity.md` §4.5.
|
|
99
|
+
*
|
|
100
|
+
* A `CustomEvent` on the animated element is the one answer that does not cost the author a
|
|
101
|
+
* library import. `addEventListener('kui:finish', ...)` is plain DOM, works from a framework's
|
|
102
|
+
* template, works from another script that has never heard of this library, and — because these
|
|
103
|
+
* bubble — works from one delegated listener on `document` for a whole page of animations. That is
|
|
104
|
+
* the same bet the attribute grammar makes: the author writes no library-specific JavaScript.
|
|
105
|
+
*/
|
|
106
|
+
/**
|
|
107
|
+
* Event names, in one place so the namespace is a single rename before publish — the same
|
|
108
|
+
* discipline `attrs.ts` applies to attribute names, and for the same reason.
|
|
109
|
+
*
|
|
110
|
+
* `kui:` rather than `kui-`: a colon cannot appear in an HTML `on*` content attribute, so there is
|
|
111
|
+
* no chance of an author writing `onkui-finish="..."` in markup, discovering it silently does
|
|
112
|
+
* nothing, and blaming the library. It also reads unambiguously as a namespace separator and
|
|
113
|
+
* cannot collide with any current or future native event name, which a bare `kui-` prefix cannot
|
|
114
|
+
* promise.
|
|
115
|
+
*/
|
|
116
|
+
export declare const KUI_EVENT: {
|
|
117
|
+
/** The element's effects have started. Fires once per activation. */
|
|
118
|
+
readonly start: "kui:start";
|
|
119
|
+
/** Every finite effect on the element has completed. */
|
|
120
|
+
readonly finish: "kui:finish";
|
|
121
|
+
/**
|
|
122
|
+
* The element has finished playing *backwards* and is sitting at its from-state again.
|
|
123
|
+
*
|
|
124
|
+
* A separate name rather than a second `kui:finish` with a different `reason`, because the
|
|
125
|
+
* commonest thing an author does with `kui:finish` is chain the next reveal off it, and a
|
|
126
|
+
* listener that has to remember to re-check `event.detail.reason` before doing so is a trap
|
|
127
|
+
* rather than an API — the one time they forget, a hover-out plays the next section in. Filtering
|
|
128
|
+
* by *name* is what `addEventListener` is for, and it is what a delegated document-level listener
|
|
129
|
+
* can do without reading the detail at all.
|
|
130
|
+
*
|
|
131
|
+
* The exit half of a paired activation (`data-kui-on="pointerenter/pointerleave"`) settles here,
|
|
132
|
+
* and so does a programmatic `control(el).reverse()`. Before this existed, a completed reverse
|
|
133
|
+
* dispatched nothing whatsoever, which left "the element is back where it started" the one
|
|
134
|
+
* lifecycle moment an author could only discover by polling `data-kui-state`.
|
|
135
|
+
*/
|
|
136
|
+
readonly reverseFinish: "kui:reverse-finish";
|
|
137
|
+
/** The element's effects were torn down or cancelled before completing. */
|
|
138
|
+
readonly cancel: "kui:cancel";
|
|
139
|
+
};
|
|
140
|
+
export type LifecycleEventType = (typeof KUI_EVENT)[keyof typeof KUI_EVENT];
|
|
141
|
+
/**
|
|
142
|
+
* Why the event fired.
|
|
143
|
+
*
|
|
144
|
+
* Carried because the *same* event name legitimately arrives from more than one route, and an
|
|
145
|
+
* author chaining animations needs to tell them apart. `finish` in particular fires both when an
|
|
146
|
+
* animation genuinely ran to its end and when reduced motion meant it never ran at all — see
|
|
147
|
+
* `'reduced-motion'` below.
|
|
148
|
+
*/
|
|
149
|
+
export type LifecycleReason =
|
|
150
|
+
/** `start`: an activation fired and at least one instance began. */
|
|
151
|
+
'activated'
|
|
152
|
+
/** `finish`: every finite instance resolved. */
|
|
153
|
+
| 'complete'
|
|
154
|
+
/**
|
|
155
|
+
* `reverse-finish`: every finite instance finished running backwards, so the element is back at
|
|
156
|
+
* the from-state it was in before it was ever activated — `data-kui-state` reads `ready` again.
|
|
157
|
+
*
|
|
158
|
+
* One reason on one event name today, unlike `finish`, which carries two. It is carried anyway
|
|
159
|
+
* because the two routes into a reverse (a paired activation's exit half, and a programmatic
|
|
160
|
+
* `control().reverse()`) are already distinguishable from `detail.activation`, and a listener
|
|
161
|
+
* that branches on `reason` for every other lifecycle event should not have to special-case this
|
|
162
|
+
* one for having none.
|
|
163
|
+
*/
|
|
164
|
+
| 'reversed'
|
|
165
|
+
/**
|
|
166
|
+
* `finish`: the effect declared `reducedMotion: 'disable'` and the visitor asked for reduced
|
|
167
|
+
* motion, so it was never started and the element is already at its final state.
|
|
168
|
+
*
|
|
169
|
+
* This is the one case where `finish` arrives with no preceding `start`, and it is deliberate.
|
|
170
|
+
* The alternative — staying silent — strands every author who uses these events to chain work,
|
|
171
|
+
* because their second step would simply never run for the visitors who most need the page to
|
|
172
|
+
* stay usable. Firing a synthetic `start` first would be the worse lie: nothing started.
|
|
173
|
+
*/
|
|
174
|
+
| 'reduced-motion'
|
|
175
|
+
/** `cancel`: the element's effects were torn down — `reset()`, `destroy()`, or DOM removal. */
|
|
176
|
+
| 'reset'
|
|
177
|
+
/** `cancel`: an explicit `cancel()` on the element or on a `play()` handle. */
|
|
178
|
+
| 'cancelled';
|
|
179
|
+
/**
|
|
180
|
+
* What every lifecycle event carries.
|
|
181
|
+
*
|
|
182
|
+
* `effects` is the same normalized name list `data-kui-fx` holds, so a delegated listener can tell
|
|
183
|
+
* *which* effect just finished without re-reading the element's attributes — which matters
|
|
184
|
+
* precisely because delegation is the case this is for: one listener on `document` seeing events
|
|
185
|
+
* from hundreds of elements needs the identity in the event, not in a DOM read per event.
|
|
186
|
+
*/
|
|
187
|
+
export interface LifecycleDetail {
|
|
188
|
+
/** Normalized effect names — the contents of `data-kui-fx`. */
|
|
189
|
+
effects: string[];
|
|
190
|
+
activation: Activation;
|
|
191
|
+
timeline: Timeline;
|
|
192
|
+
reason: LifecycleReason;
|
|
193
|
+
/** Set when the event fires on a derived match: its host. */
|
|
194
|
+
host?: Element;
|
|
195
|
+
}
|
|
196
|
+
/** A lifecycle event, narrowed so `event.detail` is typed at the listener. */
|
|
197
|
+
export type LifecycleEvent = CustomEvent<LifecycleDetail>;
|
|
198
|
+
/**
|
|
199
|
+
* Dispatch one lifecycle event on the animated element.
|
|
200
|
+
*
|
|
201
|
+
* `bubbles` is required by the design (delegation is the point) and `composed` follows from it: an
|
|
202
|
+
* animated element inside a shadow root whose event stopped at the shadow boundary would be
|
|
203
|
+
* invisible to exactly the document-level listener this exists to serve. Not `cancelable` — there
|
|
204
|
+
* is nothing for a listener to prevent; by the time any of these fire the decision has been made.
|
|
205
|
+
*
|
|
206
|
+
* The constructor is taken from the element's own window rather than the global one, so an
|
|
207
|
+
* animator driving a document in an `<iframe>` dispatches an event that element's own listeners
|
|
208
|
+
* recognise via `instanceof`. Falling back to the global keeps a jsdom-style environment working
|
|
209
|
+
* where `ownerDocument.defaultView` can be null, and the `typeof` guard keeps this module import-
|
|
210
|
+
* safe in a DOM-less process, the same rule `capabilities.ts` and `animator.ts` already follow.
|
|
211
|
+
*
|
|
212
|
+
* @param el - The animated element. The event's target and the element authors listen on.
|
|
213
|
+
* @param type - One of `KUI_EVENT`.
|
|
214
|
+
* @param detail - Identity and reason, readable as `event.detail`.
|
|
215
|
+
* @complexity O(n) time in the number of listeners on the propagation path; O(1) space.
|
|
216
|
+
* @overallScore 100
|
|
217
|
+
*/
|
|
218
|
+
export declare function emitLifecycle(el: Element, type: LifecycleEventType, detail: LifecycleDetail): void;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { Entry } from './compile.js';
|
|
2
|
+
import type { SequenceStep } from './sequence.js';
|
|
3
|
+
import type { Timeline } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* The CSS-emission half of the compiler: how one resolved entry becomes longhand declarations.
|
|
6
|
+
*
|
|
7
|
+
* `compile.ts` decides *what* animates — which effects resolve, which `target:` group they belong
|
|
8
|
+
* to, whether they may compose, what the reduced-motion policy is. This file decides *how that is
|
|
9
|
+
* spelled in CSS*: the parallel `animation-*` value lists that let composed effects share one
|
|
10
|
+
* declaration, and the merged `transition` shorthand that does the same job for the ten presets
|
|
11
|
+
* that transition rather than keyframe. Nothing here reads a registry, a parse tree, or a target
|
|
12
|
+
* group; nothing in `compile.ts` writes a CSS value string any more.
|
|
13
|
+
*
|
|
14
|
+
* The `Entry` import is deliberately type-only, so the module graph edge exists at type level and
|
|
15
|
+
* nowhere at runtime — `.dependency-cruiser.cjs` resolves the graph with `tsPreCompilationDeps:
|
|
16
|
+
* false` precisely because `import type` is erased by `verbatimModuleSyntax` and a mutual type
|
|
17
|
+
* reference is not an initialisation-order hazard. `Entry` stays in `compile.ts` because that is
|
|
18
|
+
* where entries are built and where every other consumer already imports it from.
|
|
19
|
+
*/
|
|
20
|
+
export interface AnimationTracks {
|
|
21
|
+
/** What is written to `animation-name` — an ident, or a `var()` around one when gated. */
|
|
22
|
+
names: string[];
|
|
23
|
+
/** The ident inside it, for `CompiledPlan.keyframeNames`. Same length, same order. */
|
|
24
|
+
keyframes: string[];
|
|
25
|
+
durations: string[];
|
|
26
|
+
/**
|
|
27
|
+
* Where each track *starts*, as an unwrapped `calc()` sum. Left unwrapped because
|
|
28
|
+
* {@link declarationsFor} is what finalizes it: on a pin timeline it folds the scrub head into
|
|
29
|
+
* the same expression, and `calc(calc(a + b) - c)` buries the arithmetic an author has to read
|
|
30
|
+
* in a devtools panel.
|
|
31
|
+
*/
|
|
32
|
+
delays: string[];
|
|
33
|
+
/**
|
|
34
|
+
* Where each track *ends* — its start plus its whole playback — as an unwrapped sum.
|
|
35
|
+
*
|
|
36
|
+
* Read only to size the pin scrub head, which has to span the element's longest track rather
|
|
37
|
+
* than each track's own playback. Accumulated for every timeline because it costs one string
|
|
38
|
+
* concatenation and knowing the timeline here would buy nothing else.
|
|
39
|
+
*/
|
|
40
|
+
ends: string[];
|
|
41
|
+
easings: string[];
|
|
42
|
+
iterationCounts: string[];
|
|
43
|
+
/**
|
|
44
|
+
* One `animation-direction` per track. Almost always every entry is `normal`, which is the CSS
|
|
45
|
+
* initial value — see {@link declarationsFor} for why that case emits no declaration at all.
|
|
46
|
+
*/
|
|
47
|
+
directions: string[];
|
|
48
|
+
/**
|
|
49
|
+
* One `animation-composition` per track — `replace` for all but the few the composition resolver
|
|
50
|
+
* had to sum, and handled exactly like {@link directions}: an all-`replace` list is the CSS
|
|
51
|
+
* initial value and emits no declaration at all.
|
|
52
|
+
*
|
|
53
|
+
* Per track and not per element for the reason `iterationCounts` is: CSS repeats a shorter value
|
|
54
|
+
* list to match the longest one across every `animation-*` longhand in the group, so a single
|
|
55
|
+
* `add` written for one effect would be handed to every neighbour composed beside it — including
|
|
56
|
+
* the ones whose keyframes write `opacity`, where adding to the underlying 1 deletes the fade.
|
|
57
|
+
*/
|
|
58
|
+
compositions: string[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A fresh accumulator for one plan's worth of tracks.
|
|
62
|
+
*
|
|
63
|
+
* @complexity O(1) time and space.
|
|
64
|
+
* @overallScore 100
|
|
65
|
+
*/
|
|
66
|
+
export declare function emptyTracks(): AnimationTracks;
|
|
67
|
+
/**
|
|
68
|
+
* Append one effect to the parallel animation lists, as one track per keyframe block it compiles.
|
|
69
|
+
*
|
|
70
|
+
* Separate rules cannot both contribute an `animation` declaration — the cascade discards one —
|
|
71
|
+
* so composition is expressed as parallel longhand value lists on a single declaration.
|
|
72
|
+
*
|
|
73
|
+
* Usually one block, so usually one track. A variant naming several (`keyframesFor`) gets the same
|
|
74
|
+
* timing repeated across all of them, which is the point: `tween x:100 opacity:0 800ms` is *one*
|
|
75
|
+
* effect the author gave one duration, rendered as two tracks only because CSS has no way to write
|
|
76
|
+
* two unrelated properties from one keyframe without also writing everything in between.
|
|
77
|
+
*
|
|
78
|
+
* @param step - Where the sequencer placed this segment. For a segment with no `at:` this is the
|
|
79
|
+
* segment's own delay, so the compiled output is unchanged from before sequencing existed.
|
|
80
|
+
* @complexity O(k) time in the entry's keyframe count; O(k) space in the tracks.
|
|
81
|
+
* @overallScore 100
|
|
82
|
+
*/
|
|
83
|
+
export declare function pushTrack(tracks: AnimationTracks, entry: Entry, step: SequenceStep): void;
|
|
84
|
+
/**
|
|
85
|
+
* Append one entry's declared {@link TransitionSegment}s to the element's merged transition list.
|
|
86
|
+
*
|
|
87
|
+
* Reuses `durationExpression`/`easingValue` — the same two functions `pushTrack` resolves an
|
|
88
|
+
* `animation-duration`/`-timing-function` through — so `data-kui="lift 400ms"` reaches a
|
|
89
|
+
* transitioned property and a keyframed one through one code path that cannot disagree with
|
|
90
|
+
* itself. The delay is a per-*preset* custom-property slot (`--kui-tx-delay-<name>`) rather than a
|
|
91
|
+
* shared `animation-delay`-style list: the CSS state rule (`:hover`, `[aria-expanded]`) that
|
|
92
|
+
* actually triggers the transition writes that slot directly (see `interaction.css`), and distinct
|
|
93
|
+
* property names per preset are what let two composed presets carry independent delays without a
|
|
94
|
+
* second clobber one level down.
|
|
95
|
+
*
|
|
96
|
+
* Mutates `segments`/`owners` rather than returning a value, the same accumulator shape `pushTrack`
|
|
97
|
+
* already uses for `tracks` — a per-entry return would need concatenating at every call site for no
|
|
98
|
+
* benefit, since every caller already owns one shared list for the whole composed entry set.
|
|
99
|
+
*
|
|
100
|
+
* @param segments - Accumulator of `"property duration easing delay"` strings, mutated in place.
|
|
101
|
+
* @param owners - property → the preset name that most recently claimed it, mutated in place, kept
|
|
102
|
+
* only to name both presets in the duplicate-property warning below.
|
|
103
|
+
* @param entry - The composed entry to read `preset.transitions` from.
|
|
104
|
+
* @param warnings - Diagnostic sink. Two presets transitioning the same property compose — the
|
|
105
|
+
* channel model does not forbid it, and CSS resolves the shorthand's last occurrence
|
|
106
|
+
* deterministically — but the author is owed a name for which one wins.
|
|
107
|
+
* @complexity O(t) time and space in the preset's declared transition segment count.
|
|
108
|
+
* @overallScore 100
|
|
109
|
+
*/
|
|
110
|
+
export declare function pushTransitions(segments: string[], owners: Map<string, string>, entry: Entry, warnings: string[]): void;
|
|
111
|
+
/**
|
|
112
|
+
* Collapse the parallel track lists into the `animation-*` longhands they compile to.
|
|
113
|
+
*
|
|
114
|
+
* Six of them unconditionally, and `animation-direction` only when some track actually alternates.
|
|
115
|
+
* That last one is not tidiness: `normal` is the CSS initial value, so emitting a list of them
|
|
116
|
+
* would be a no-op declaration written onto every animated element on every page for the sake of
|
|
117
|
+
* the rare one that uses `yoyo:`. Omitting it is what keeps an attribute written before `yoyo:`
|
|
118
|
+
* existed compiling byte-for-byte identically. When it *is* emitted it carries one value per
|
|
119
|
+
* track, the full length — a shorter list would be repeated by the browser to match
|
|
120
|
+
* `animation-name` and would silently alternate a neighbour that never asked to.
|
|
121
|
+
*
|
|
122
|
+
* The delays arrive unwrapped and are finalized here, because the pin scrub head is the one term
|
|
123
|
+
* in them that cannot be computed per track — see {@link pinnedDelays}.
|
|
124
|
+
*
|
|
125
|
+
* @complexity O(t) time and space in the track count.
|
|
126
|
+
* @overallScore 100
|
|
127
|
+
*/
|
|
128
|
+
export declare function declarationsFor(tracks: AnimationTracks, timeline: Timeline): Record<string, string>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CompiledTarget } from '../compile.js';
|
|
2
|
+
import type { AnimatorPort, DerivedInstallContext } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Recompute an aggregate host's `data-kui-state` from its derived matches' own states (D-A):
|
|
5
|
+
* `'running'` (+ host `kui:start`('activated')) when any derived match is running; `'finished'`
|
|
6
|
+
* (+ host `kui:finish`('complete', or `'reduced-motion'` if the host never ran any match; no event
|
|
7
|
+
* at all if every match was cancelled)) once every match has settled to `'finished'`/`'failed'`;
|
|
8
|
+
* back to `'ready'` (no event) if every match has been reset to `'ready'`. Idempotent, and a no-op
|
|
9
|
+
* for any host whose own state is not `aggregate: true`, or that `port.stateOf` does not (yet)
|
|
10
|
+
* know about.
|
|
11
|
+
*
|
|
12
|
+
* Checked in this order because the cases overlap: "any running" must win over "all failed" (a
|
|
13
|
+
* mix of running and failed is still running), and "all failed" must win over "all finished |
|
|
14
|
+
* failed" (a `failed`-only host reports `'failed'`, never a `kui:finish`). Any other mix — some
|
|
15
|
+
* settled, some still `ready` — leaves the host exactly where it was, per D-A: an aggregate host
|
|
16
|
+
* stays `running` until its last off-screen match finishes, however long that takes.
|
|
17
|
+
*
|
|
18
|
+
* @param port - The animator's narrow window.
|
|
19
|
+
* @param host - The candidate aggregate host.
|
|
20
|
+
* @complexity O(m) time in the host's derived match count; O(1) space.
|
|
21
|
+
* @overallScore 100
|
|
22
|
+
*/
|
|
23
|
+
export declare function syncAggregate(port: AnimatorPort, host: Element): void;
|
|
24
|
+
/**
|
|
25
|
+
* Compile one union group for a match claimed by two or more `target:` groups of the same host, so
|
|
26
|
+
* `resolveComposition`'s conflict detection runs over the combined spec list exactly as it would
|
|
27
|
+
* for a hand-written comma list on that element — a match must never see two groups' effects as
|
|
28
|
+
* unrelated just because they arrived through different selectors. Cached in `port.book.unions`,
|
|
29
|
+
* keyed by the sorted, `\u0001`-joined `${scope} ${selector}` list, so a second match claimed by
|
|
30
|
+
* the same group combination reuses the compile. Folds the host's own `rm:` policy in (a union
|
|
31
|
+
* belongs to no single authored segment to read it from). Reports its own warnings once per host,
|
|
32
|
+
* not once per match.
|
|
33
|
+
*
|
|
34
|
+
* @param port - The animator's narrow window.
|
|
35
|
+
* @param context - The host's derived-install context — what the union recompiles the timeline
|
|
36
|
+
* against.
|
|
37
|
+
* @param targets - Every group claiming the match, in authored group order.
|
|
38
|
+
* @returns The compiled union target.
|
|
39
|
+
* @complexity O(e * p) time in the combined spec/parameter count on a cache miss, O(1) on a hit;
|
|
40
|
+
* O(e) space for the freshly compiled target.
|
|
41
|
+
* @overallScore 100
|
|
42
|
+
*/
|
|
43
|
+
export declare function compileUnion(port: AnimatorPort, context: DerivedInstallContext, targets: CompiledTarget[]): CompiledTarget;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DerivedBook } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A fresh, empty derived-host book for one `Animator`.
|
|
4
|
+
*
|
|
5
|
+
* All WeakMaps, so a removed element takes its own entries with it rather than leaking for the
|
|
6
|
+
* animator's lifetime — the same discipline `animator.ts`'s own `states`/`currentRun`/`settleArmed`
|
|
7
|
+
* already follow.
|
|
8
|
+
*
|
|
9
|
+
* @complexity O(1) time and space.
|
|
10
|
+
* @overallScore 100
|
|
11
|
+
*/
|
|
12
|
+
export declare function createDerivedBook(): DerivedBook;
|
|
13
|
+
/**
|
|
14
|
+
* A host's derived matches as a fresh array, in document order.
|
|
15
|
+
*
|
|
16
|
+
* A copy rather than the live `Set`, so a caller may release matches while iterating without the
|
|
17
|
+
* iteration itself observing the mutation.
|
|
18
|
+
*
|
|
19
|
+
* @returns `[]` for a host with no derived matches (or that is not a host at all).
|
|
20
|
+
* @complexity O(n) time and space in the host's derived match count.
|
|
21
|
+
* @overallScore 100
|
|
22
|
+
*/
|
|
23
|
+
export declare function derivedOf(book: DerivedBook, el: Element): Element[];
|
|
24
|
+
/**
|
|
25
|
+
* The host that installed a derived match, if `el` is one.
|
|
26
|
+
*
|
|
27
|
+
* @complexity O(1) time and space.
|
|
28
|
+
* @overallScore 100
|
|
29
|
+
*/
|
|
30
|
+
export declare function hostOf(book: DerivedBook, el: Element): Element | undefined;
|