kuinetic 0.1.2 → 0.1.3
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 +3 -3
- package/dist/esm/{chunk-WPU33HDL.mjs → chunk-5DON3UFQ.mjs} +1195 -214
- package/dist/esm/{chunk-LWS4OSLX.mjs → chunk-JT4PZL3A.mjs} +50 -7
- package/dist/esm/{chunk-5EVG7CIY.mjs → chunk-QUVFODSQ.mjs} +27 -13
- package/dist/esm/core/index.mjs +2 -2
- package/dist/esm/effects/index.mjs +2 -2
- package/dist/esm/index.mjs +3 -3
- package/dist/kuinetic.all.js +1269 -233
- package/dist/kuinetic.css +1392 -52
- package/dist/kuinetic.js +1268 -232
- package/dist/types/core/instances.d.ts +34 -3
- package/dist/types/core/path-morph.d.ts +19 -0
- package/dist/types/core/style-plan.d.ts +6 -1
- package/dist/types/core/types.d.ts +93 -1
- package/dist/types/effects/catalog/index.d.ts +0 -6
- package/dist/types/effects/catalog/media-shared.d.ts +124 -0
- package/dist/types/effects/catalog/media.d.ts +4 -0
- package/dist/types/effects/catalog/numbers-shared.d.ts +5 -1
- package/dist/types/effects/catalog/shared.d.ts +0 -1
- package/dist/types/effects/catalog/subtree-capture.d.ts +23 -0
- package/dist/types/effects/catalog/text-shared.d.ts +5 -2
- package/dist/types/effects/gestures/index.d.ts +0 -1
- package/dist/types/effects/layout/index.d.ts +0 -2
- package/dist/types/effects/scroll-mechanics/index.d.ts +0 -4
- package/dist/types/effects/scroll-mechanics/scroll-spy.d.ts +26 -0
- package/dist/types/effects/scroll-mechanics/tracker.d.ts +61 -3
- package/dist/types/effects/step-marking.d.ts +99 -0
- package/dist/types/effects/three-d/index.d.ts +0 -7
- package/package.json +9 -2
|
@@ -114,7 +114,18 @@ var CHANNEL = {
|
|
|
114
114
|
background: "background",
|
|
115
115
|
color: "color",
|
|
116
116
|
stroke: "stroke",
|
|
117
|
-
text: "text"
|
|
117
|
+
text: "text",
|
|
118
|
+
/**
|
|
119
|
+
* Skew is the one transform CSS never gave an independent property to — there is no `skew:`
|
|
120
|
+
* beside `translate:`/`rotate:`/`scale:`, so it can only be written through the `transform`
|
|
121
|
+
* shorthand. That makes it its own channel: anything writing `transform` clobbers the whole
|
|
122
|
+
* shorthand, so every primitive that does is on this channel, whatever the transform is for.
|
|
123
|
+
* `scroll-skew` is one member; `flip-face` (`effects/three-d`) and `flip-3d`
|
|
124
|
+
* (`effects/catalog/core`, the `flip-in-*`/`flip-out-*` family) are the other two — both need
|
|
125
|
+
* the `perspective()` transform *function* for an element to have depth on itself, which
|
|
126
|
+
* likewise only exists inside `transform`.
|
|
127
|
+
*/
|
|
128
|
+
skew: "skew"
|
|
118
129
|
};
|
|
119
130
|
function inertInstance(destroy = () => {
|
|
120
131
|
}) {
|
|
@@ -146,7 +157,7 @@ var PATTERNS = {
|
|
|
146
157
|
var HEX_COLOR = /^#[0-9a-f]{3,8}$/i;
|
|
147
158
|
var COLOR_FUNCTIONS = /^(?:rgba?|hsla?|okl(?:ch|ab)|l(?:ch|ab)|color)\([^()]*\)$/i;
|
|
148
159
|
var COLOR_KEYWORD = /^[a-z]+$/i;
|
|
149
|
-
var EASING_KEYWORD = /^(?:linear|ease|step-start|step-end|spring|[a-z]+-(?:in|out|in-out))$/i;
|
|
160
|
+
var EASING_KEYWORD = /^(?:linear|ease|step-start|step-end|spring|bounce|[a-z]+-(?:in|out|in-out))$/i;
|
|
150
161
|
var EASING_FUNCTION = /^(?:cubic-bezier|steps|linear)\([^()]*\)$/i;
|
|
151
162
|
var CALC_TYPES = /* @__PURE__ */ new Set(["length", "percentage", "number"]);
|
|
152
163
|
var CALC_CHARACTER = /^[\d.\s+\-*/%a-z,]$/i;
|
|
@@ -445,7 +456,22 @@ function windowScrollRoot(win) {
|
|
|
445
456
|
viewportLeft: 0
|
|
446
457
|
}),
|
|
447
458
|
onScroll: (handler) => listen(win, "scroll", handler),
|
|
448
|
-
|
|
459
|
+
/*
|
|
460
|
+
* The document's own height counts as a resize, not just the window's.
|
|
461
|
+
*
|
|
462
|
+
* `elementScrollRoot` has observed its element's size since it was written, for the reason
|
|
463
|
+
* stated three doc comments down: "images loading, fonts swapping, a container changing size,
|
|
464
|
+
* or content being inserted". Every one of those applies at least as strongly to the page
|
|
465
|
+
* itself, and the page root was the one that only listened for `window.resize` — so on any
|
|
466
|
+
* document with lazy-loaded media below the fold, every cached content offset silently drifted
|
|
467
|
+
* by however much the page grew after it was measured, with no epoch bump to correct it.
|
|
468
|
+
*
|
|
469
|
+
* Measured on `demo/scroll.html` (32,000px of lazy screenshots): the horizontal track's stage
|
|
470
|
+
* moved ~840px between page load and reaching it, which is a third of that effect's whole
|
|
471
|
+
* scroll range. Nothing was wrong with the maths; the number it was doing the maths on was
|
|
472
|
+
* taken before forty images existed.
|
|
473
|
+
*/
|
|
474
|
+
onResize: (handler) => observeSize(win.document.documentElement, win, handler)
|
|
449
475
|
};
|
|
450
476
|
}
|
|
451
477
|
function elementScrollRoot(el, win) {
|
|
@@ -553,7 +579,7 @@ function restartCssAnimation(el, ledger) {
|
|
|
553
579
|
flushComputedAnimationName(el);
|
|
554
580
|
ledger.set("animation-name", name);
|
|
555
581
|
}
|
|
556
|
-
function createCssInstance(el, ledger, animationNames) {
|
|
582
|
+
function createCssInstance(el, ledger, animationNames, scrubbed = false) {
|
|
557
583
|
const ownedNames = new Set(animationNames);
|
|
558
584
|
let settle;
|
|
559
585
|
let finished = new Promise((resolve) => {
|
|
@@ -572,6 +598,10 @@ function createCssInstance(el, ledger, animationNames) {
|
|
|
572
598
|
finished = new Promise((resolve) => {
|
|
573
599
|
settle = resolve;
|
|
574
600
|
});
|
|
601
|
+
if (scrubbed) {
|
|
602
|
+
settle?.();
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
575
605
|
let animations = ownedAnimationsOf(el, ownedNames);
|
|
576
606
|
if (!activatedBefore) {
|
|
577
607
|
restartCssAnimation(el, ledger);
|
|
@@ -604,6 +634,9 @@ function createCssInstance(el, ledger, animationNames) {
|
|
|
604
634
|
}
|
|
605
635
|
};
|
|
606
636
|
}
|
|
637
|
+
function continuousSetup(cleanup) {
|
|
638
|
+
return { cleanup, continuous: true };
|
|
639
|
+
}
|
|
607
640
|
function cleanupOf(result) {
|
|
608
641
|
if (result === void 0) return void 0;
|
|
609
642
|
return typeof result === "function" ? result : result.cleanup;
|
|
@@ -620,7 +653,7 @@ function deferredInstance(setup) {
|
|
|
620
653
|
return createJsInstance({
|
|
621
654
|
activate() {
|
|
622
655
|
running = setup();
|
|
623
|
-
if (typeof running === "function") return;
|
|
656
|
+
if (typeof running === "function" || "continuous" in running) return;
|
|
624
657
|
const work = running.finished;
|
|
625
658
|
finished = new Promise((resolve) => {
|
|
626
659
|
settle = resolve;
|
|
@@ -629,11 +662,14 @@ function deferredInstance(setup) {
|
|
|
629
662
|
},
|
|
630
663
|
cancel: teardown,
|
|
631
664
|
finish() {
|
|
632
|
-
if (typeof running === "object") running.finish?.();
|
|
665
|
+
if (typeof running === "object" && "finish" in running) running.finish?.();
|
|
633
666
|
settle?.();
|
|
634
667
|
},
|
|
635
668
|
destroy: teardown,
|
|
636
|
-
finished: () => finished
|
|
669
|
+
finished: () => finished,
|
|
670
|
+
// Only an explicit marker counts. A bare `Cleanup` deliberately does not — see
|
|
671
|
+
// `ContinuousSetup` above for why the two cannot be told apart by shape.
|
|
672
|
+
continuous: () => typeof running === "object" && "continuous" in running
|
|
637
673
|
});
|
|
638
674
|
}
|
|
639
675
|
function deferPrepare(setup) {
|
|
@@ -657,6 +693,9 @@ function createJsInstance(hooks) {
|
|
|
657
693
|
get finished() {
|
|
658
694
|
return hooks.finished?.() ?? Promise.resolve();
|
|
659
695
|
},
|
|
696
|
+
get continuous() {
|
|
697
|
+
return hooks.continuous?.() ?? false;
|
|
698
|
+
},
|
|
660
699
|
destroy() {
|
|
661
700
|
active = false;
|
|
662
701
|
hooks.destroy();
|
|
@@ -668,6 +707,7 @@ function createJsInstance(hooks) {
|
|
|
668
707
|
function createStyleLedger(el) {
|
|
669
708
|
const style = el.style;
|
|
670
709
|
const previous = /* @__PURE__ */ new Map();
|
|
710
|
+
const authoredStyleAttribute = el.hasAttribute("style");
|
|
671
711
|
function remember(property) {
|
|
672
712
|
if (previous.has(property)) return;
|
|
673
713
|
const existing = style.getPropertyValue(property);
|
|
@@ -685,6 +725,8 @@ function createStyleLedger(el) {
|
|
|
685
725
|
else style.setProperty(property, value);
|
|
686
726
|
}
|
|
687
727
|
previous.clear();
|
|
728
|
+
if (!authoredStyleAttribute && style.length === 0 && !el.getAttribute("style"))
|
|
729
|
+
el.removeAttribute("style");
|
|
688
730
|
},
|
|
689
731
|
owned: () => [...previous.keys()]
|
|
690
732
|
};
|
|
@@ -722,6 +764,7 @@ export {
|
|
|
722
764
|
clamp01,
|
|
723
765
|
createMeasureCache,
|
|
724
766
|
createCssInstance,
|
|
767
|
+
continuousSetup,
|
|
725
768
|
deferPrepare,
|
|
726
769
|
createStyleLedger,
|
|
727
770
|
createAttributeLedger,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
resolveParams,
|
|
11
11
|
suggest,
|
|
12
12
|
timingProperty
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-JT4PZL3A.mjs";
|
|
14
14
|
|
|
15
15
|
// src/core/attrs.ts
|
|
16
16
|
var ATTR = {
|
|
@@ -30,7 +30,7 @@ var ATTR = {
|
|
|
30
30
|
|
|
31
31
|
// src/core/element-config.ts
|
|
32
32
|
var ACTIVATIONS = /* @__PURE__ */ new Set(["load", "enter", "hover", "focus", "click", "manual"]);
|
|
33
|
-
var TIMELINES = /* @__PURE__ */ new Set(["time", "view", "scroll", "pointer"]);
|
|
33
|
+
var TIMELINES = /* @__PURE__ */ new Set(["time", "view", "scroll", "pointer", "pin"]);
|
|
34
34
|
function readAttributes(el) {
|
|
35
35
|
return {
|
|
36
36
|
source: el.getAttribute(ATTR.source) ?? "",
|
|
@@ -282,7 +282,7 @@ function buildPlan(entries, timeline, unknown, warnings) {
|
|
|
282
282
|
plan.vars,
|
|
283
283
|
resolveParams(entry.spec.params, primitive.parameters, (m) => warnings.push(m))
|
|
284
284
|
);
|
|
285
|
-
if (primitive.renderer === "css-keyframes") pushTrack(tracks, entry);
|
|
285
|
+
if (primitive.renderer === "css-keyframes") pushTrack(tracks, entry, timeline);
|
|
286
286
|
else plan.jsEffects.push(entry);
|
|
287
287
|
}
|
|
288
288
|
Object.assign(plan.declarations, declarationsFor(tracks));
|
|
@@ -298,12 +298,13 @@ function intersect(accumulated, supported) {
|
|
|
298
298
|
function iterationCountProperty(presetName) {
|
|
299
299
|
return `--kui-fx-${presetName}-iterations`;
|
|
300
300
|
}
|
|
301
|
-
function pushTrack(tracks, entry) {
|
|
301
|
+
function pushTrack(tracks, entry, timeline) {
|
|
302
302
|
const { spec, resolved } = entry;
|
|
303
303
|
const id = resolved.primitive.id;
|
|
304
304
|
tracks.names.push(resolved.preset.keyframes ?? `kui-${resolved.preset.name}`);
|
|
305
|
-
|
|
306
|
-
tracks.
|
|
305
|
+
const duration = spec.duration ?? `var(${timingProperty(id, "duration")}, 600ms)`;
|
|
306
|
+
tracks.durations.push(duration);
|
|
307
|
+
tracks.delays.push(staggerDelay(spec.delay, id, timeline, duration));
|
|
307
308
|
tracks.easings.push(easingValue(spec.easing, id));
|
|
308
309
|
tracks.iterationCounts.push(`var(${iterationCountProperty(resolved.preset.name)}, 1)`);
|
|
309
310
|
}
|
|
@@ -327,9 +328,12 @@ function warnUnsupportedTimeline(name, supported, timeline, warnings) {
|
|
|
327
328
|
`"${name}" does not support timeline "${timeline}" (supports: ${supported.join(", ")})`
|
|
328
329
|
);
|
|
329
330
|
}
|
|
330
|
-
function staggerDelay(delay, primitiveId) {
|
|
331
|
+
function staggerDelay(delay, primitiveId, timeline, duration) {
|
|
331
332
|
const base = delay ?? `var(${timingProperty(primitiveId, "delay")}, 0ms)`;
|
|
332
|
-
|
|
333
|
+
const staggered = `${base} + var(--kui-i, 0) * var(--kui-stagger, 0ms)`;
|
|
334
|
+
if (timeline !== "pin") return `calc(${staggered})`;
|
|
335
|
+
const span = `${duration} + (var(--kui-stagger-count, 1) - 1) * var(--kui-stagger, 0ms)`;
|
|
336
|
+
return `calc(${staggered} - var(--kui-progress, 0) * (${span}))`;
|
|
333
337
|
}
|
|
334
338
|
function easingValue(easing, primitiveId) {
|
|
335
339
|
if (!easing) return `var(${timingProperty(primitiveId, "ease")}, ease-out)`;
|
|
@@ -499,7 +503,8 @@ var EASING_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
499
503
|
"back-in-out",
|
|
500
504
|
"quart-out",
|
|
501
505
|
"circ-out",
|
|
502
|
-
"spring"
|
|
506
|
+
"spring",
|
|
507
|
+
"bounce"
|
|
503
508
|
]);
|
|
504
509
|
function splitTopLevel(input, delimiter, warnings = []) {
|
|
505
510
|
const parts = [];
|
|
@@ -775,6 +780,8 @@ function indexStaggerGroup(group) {
|
|
|
775
780
|
index++;
|
|
776
781
|
}
|
|
777
782
|
}
|
|
783
|
+
;
|
|
784
|
+
group.style.setProperty("--kui-stagger-count", String(Math.max(index, 1)));
|
|
778
785
|
}
|
|
779
786
|
function applyStagger(root) {
|
|
780
787
|
const selector = `[${ATTR.stagger}]`;
|
|
@@ -786,12 +793,14 @@ function applyStagger(root) {
|
|
|
786
793
|
function planStyles(input) {
|
|
787
794
|
const { plan, config, capabilities, respectReducedMotion } = input;
|
|
788
795
|
const reduce = respectReducedMotion && capabilities.reducedMotion;
|
|
789
|
-
const
|
|
796
|
+
const scrubbed = config.timeline === "pin" && plan.supportedTimelines.includes("pin");
|
|
797
|
+
const useNativeTimeline = !scrubbed && supportsTimeline(config.timeline, capabilities) && plan.supportedTimelines.includes(config.timeline);
|
|
790
798
|
const properties = { ...plan.vars, ...plan.declarations };
|
|
791
799
|
Object.assign(properties, timelineProperties(config, capabilities, useNativeTimeline));
|
|
792
800
|
const hasCssAnimation = Object.keys(plan.declarations).length > 0;
|
|
793
801
|
const gate = resolveGate({
|
|
794
802
|
useNativeTimeline,
|
|
803
|
+
scrubbed: scrubbed && hasCssAnimation,
|
|
795
804
|
reduce,
|
|
796
805
|
activation: config.activation,
|
|
797
806
|
// JS effects are gated too. They emit no `animation` declaration, so only the play-state
|
|
@@ -806,7 +815,7 @@ function planStyles(input) {
|
|
|
806
815
|
// already applied under reduced motion.
|
|
807
816
|
unsupportedTransform: needsIndividualTransforms(plan.channels, capabilities)
|
|
808
817
|
});
|
|
809
|
-
if (gate === "deferred") properties["animation-play-state"] = "paused";
|
|
818
|
+
if (gate === "deferred" || gate === "scrubbed") properties["animation-play-state"] = "paused";
|
|
810
819
|
return {
|
|
811
820
|
properties,
|
|
812
821
|
attributes: {
|
|
@@ -830,6 +839,7 @@ function timelineProperties(config, capabilities, useNativeTimeline) {
|
|
|
830
839
|
}
|
|
831
840
|
function resolveGate(input) {
|
|
832
841
|
if (input.useNativeTimeline) return "native-timeline";
|
|
842
|
+
if (input.scrubbed) return "scrubbed";
|
|
833
843
|
if (!input.hasWork) return "immediate";
|
|
834
844
|
if (input.reduce || input.activation === "load" || input.unsupportedTransform) return "immediate";
|
|
835
845
|
return "deferred";
|
|
@@ -1010,7 +1020,9 @@ var Animator = class {
|
|
|
1010
1020
|
this.liveElements.add(el);
|
|
1011
1021
|
if (Object.keys(stylePlan.properties).some((property) => property.startsWith("animation-"))) {
|
|
1012
1022
|
const animationNames = (plan.declarations["animation-name"] ?? "").split(",").map((name) => name.trim()).filter(Boolean);
|
|
1013
|
-
state.instances.push(
|
|
1023
|
+
state.instances.push(
|
|
1024
|
+
createCssInstance(el, ledger, animationNames, stylePlan.gate === "scrubbed")
|
|
1025
|
+
);
|
|
1014
1026
|
}
|
|
1015
1027
|
state.instances.push(
|
|
1016
1028
|
...this.jsEffectPreparer.prepare({ el, plan, signal: controller.signal, ledger })
|
|
@@ -1071,7 +1083,9 @@ var Animator = class {
|
|
|
1071
1083
|
state.attributes.set(ATTR.state, "failed");
|
|
1072
1084
|
return;
|
|
1073
1085
|
}
|
|
1074
|
-
|
|
1086
|
+
const timed = started.filter((instance) => !instance.continuous);
|
|
1087
|
+
if (timed.length === 0 && started.length > 0) return;
|
|
1088
|
+
void Promise.all(timed.map((instance) => instance.finished)).then(() => {
|
|
1075
1089
|
if (this.states.get(el) !== state || state.status !== "running") return;
|
|
1076
1090
|
state.status = "finished";
|
|
1077
1091
|
state.attributes.set(ATTR.state, "finished");
|
package/dist/esm/core/index.mjs
CHANGED
|
@@ -10,12 +10,12 @@ import {
|
|
|
10
10
|
resolveTargets,
|
|
11
11
|
silentReporter,
|
|
12
12
|
toAttributeValue
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-QUVFODSQ.mjs";
|
|
14
14
|
import {
|
|
15
15
|
CHANNEL,
|
|
16
16
|
Registry,
|
|
17
17
|
inertInstance
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-JT4PZL3A.mjs";
|
|
19
19
|
export {
|
|
20
20
|
ATTR,
|
|
21
21
|
Animator,
|
package/dist/esm/index.mjs
CHANGED
|
@@ -10,18 +10,18 @@ import {
|
|
|
10
10
|
resolveTargets,
|
|
11
11
|
silentReporter,
|
|
12
12
|
toAttributeValue
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-QUVFODSQ.mjs";
|
|
14
14
|
import {
|
|
15
15
|
COMBOS,
|
|
16
16
|
PRESETS,
|
|
17
17
|
PRIMITIVES,
|
|
18
18
|
createRegistry
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-5DON3UFQ.mjs";
|
|
20
20
|
import {
|
|
21
21
|
CHANNEL,
|
|
22
22
|
Registry,
|
|
23
23
|
inertInstance
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-JT4PZL3A.mjs";
|
|
25
25
|
|
|
26
26
|
// src/index.ts
|
|
27
27
|
function kuinetic(options = {}) {
|