kuinetic 0.2.1 → 0.2.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.
Files changed (64) hide show
  1. package/README.md +15 -8
  2. package/dist/esm/advanced/index.mjs +5 -5
  3. package/dist/esm/{chunk-U43BX5O2.mjs → chunk-FASAEQDR.mjs} +54 -7
  4. package/dist/esm/{chunk-BN2Y4UKB.mjs → chunk-FYMZW5N2.mjs} +2373 -541
  5. package/dist/esm/{chunk-RVTYN6NZ.mjs → chunk-MZQG2VMG.mjs} +208 -2
  6. package/dist/esm/core/index.mjs +21 -3
  7. package/dist/esm/effects/index.mjs +2 -2
  8. package/dist/esm/index.mjs +35 -4
  9. package/dist/esm/notes/index.mjs +1075 -0
  10. package/dist/kuinetic.advanced.js +63 -25
  11. package/dist/kuinetic.advanced.min.js +3 -3
  12. package/dist/kuinetic.all.js +2658 -538
  13. package/dist/kuinetic.all.min.js +2 -2
  14. package/dist/kuinetic.css +238 -65
  15. package/dist/kuinetic.js +2657 -537
  16. package/dist/kuinetic.min.css +1 -1
  17. package/dist/kuinetic.min.js +2 -2
  18. package/dist/kuinetic.notes.js +1 -0
  19. package/dist/types/3d/flattening.d.ts +8 -7
  20. package/dist/types/advanced/camera-3d.d.ts +0 -4
  21. package/dist/types/advanced/fluid-cursor.d.ts +0 -4
  22. package/dist/types/advanced/particles.d.ts +0 -4
  23. package/dist/types/advanced/scenes.d.ts +0 -4
  24. package/dist/types/browser/boot.d.ts +9 -4
  25. package/dist/types/core/activation.d.ts +11 -0
  26. package/dist/types/core/compile.d.ts +7 -0
  27. package/dist/types/core/deck-viewer.d.ts +87 -0
  28. package/dist/types/core/derived/types.d.ts +0 -1
  29. package/dist/types/core/describe.d.ts +174 -0
  30. package/dist/types/core/gesture.d.ts +16 -1
  31. package/dist/types/core/index.d.ts +6 -2
  32. package/dist/types/core/stagger.d.ts +1 -1
  33. package/dist/types/core/target.d.ts +28 -0
  34. package/dist/types/core/timing-contract.d.ts +61 -0
  35. package/dist/types/core/types.d.ts +59 -0
  36. package/dist/types/effects/auto-motion.d.ts +169 -0
  37. package/dist/types/effects/carousel/deck.d.ts +170 -0
  38. package/dist/types/effects/carousel/drag.d.ts +6 -0
  39. package/dist/types/effects/carousel/fit.d.ts +130 -0
  40. package/dist/types/effects/carousel/index.d.ts +6 -23
  41. package/dist/types/effects/carousel/stack.d.ts +77 -0
  42. package/dist/types/effects/catalog/interaction-reveal.d.ts +69 -9
  43. package/dist/types/effects/forms/primitives.d.ts +1 -2
  44. package/dist/types/effects/gestures/index.d.ts +3 -4
  45. package/dist/types/effects/shared.d.ts +3 -30
  46. package/dist/types/effects/step-index.d.ts +48 -10
  47. package/dist/types/effects/swipe-event.d.ts +75 -0
  48. package/dist/types/index.d.ts +26 -0
  49. package/dist/types/notes/catalog-core.d.ts +3 -0
  50. package/dist/types/notes/catalog.d.ts +3 -0
  51. package/dist/types/notes/index.d.ts +13 -0
  52. package/dist/types/notes/interaction-reveal.d.ts +3 -0
  53. package/dist/types/notes/interaction.d.ts +6 -0
  54. package/dist/types/notes/keys.d.ts +7 -0
  55. package/dist/types/notes/mechanics.d.ts +7 -0
  56. package/dist/types/notes/scroll-nav-forms.d.ts +6 -0
  57. package/dist/types/notes/shared.d.ts +6 -0
  58. package/dist/types/notes/showcase.d.ts +7 -0
  59. package/dist/types/notes/text.d.ts +3 -0
  60. package/dist/types/showcase/compare.d.ts +9 -0
  61. package/dist/types/showcase/index.d.ts +3 -0
  62. package/dist/types/showcase/lightbox.d.ts +23 -1
  63. package/dist/types/showcase/modal-shell.d.ts +11 -0
  64. package/package.json +10 -4
package/README.md CHANGED
@@ -10,7 +10,7 @@ wherever CSS can do it. Standalone, MIT, npm + CDN, framework-agnostic. No produ
10
10
  <h1 data-kui="fade-up">Hello.</h1>
11
11
  ```
12
12
 
13
- 302 named effects across scroll reveals, hover/interaction, text, numbers, layout, SVG, 3D, and
13
+ 305 named effects across scroll reveals, hover/interaction, text, numbers, layout, SVG, 3D, and
14
14
  gesture-driven motion. 3,800+ unit tests. The jsdom suite holds `src/` at 100%
15
15
  line/branch/function/statement coverage with two carve-outs: the WebGL tier in `src/advanced/`
16
16
  (`shaders.ts`, `gl-utils.ts`, `fluid-cursor.ts`, `particles.ts`), whose GPU paths cannot execute
@@ -123,16 +123,23 @@ its readable, unminified twin, about twice the transfer size; use it only for de
123
123
  `kuinetic.advanced.min.js` is a tier: it needs core on the page, in either order, and never carries
124
124
  a copy of it.
125
125
 
126
- Every one of those browser bundles starts itself once the document is ready. `data-kui-manual` on a
127
- `<script>` tag turns that off for that file. Importing from npm does **not** start anything — a
128
- module import stays side-effect-free, which is the guarantee the bundler path is built on.
126
+ Every one of those browser bundles starts itself once the document is ready. Importing from npm does
127
+ **not** start anything — a module import stays side-effect-free, which is the guarantee the bundler
128
+ path is built on.
129
+
130
+ To drive it by hand, put `data-kui-manual` on the tag. On `kuinetic.js` that turns off the
131
+ *auto-start* only: nothing is created or started until you call `kuinetic.kuinetic({ ... }).start()`,
132
+ and any tier bundle you load (`kuinetic.advanced.js`, ...) still registers into the animator you
133
+ build, in either tag order. On a tier's own tag it takes that tier out entirely.
129
134
 
130
135
  > **Changed in 0.2.** These bundles used to do nothing until you called
131
136
  > `kuinetic.kuinetic({ observe: true }).start()` yourself, and `kuinetic.all.js` started itself the
132
137
  > instant it parsed rather than at `DOMContentLoaded`. If you already write that call, it keeps
133
- > working and your animator is still the one the page uses — you will see one console line saying
134
- > the call is now redundant. Add `data-kui-manual` to the tag to silence it and go back to driving
135
- > everything by hand.
138
+ > working and your animator is still the one the page uses. A call that names its own options — a
139
+ > `reporter`, a scoped `root`, a `registry` — is how you configure the auto-started animator, and it
140
+ > is adopted without comment. A call with no options, or only `{ observe: true }`, does nothing the
141
+ > script tag has not already done, so you will see one console line saying it is now redundant. Delete
142
+ > it, or add `data-kui-manual` to the tag to go back to driving everything by hand.
136
143
 
137
144
  ## Your first animation
138
145
 
@@ -179,7 +186,7 @@ untrusted input — see Getting Started for the full note.
179
186
  ## Docs
180
187
 
181
188
  - **Getting Started** — install, first animation, timing, composition, common mistakes.
182
- - **Catalog** — all 302 named effects, grouped by category, with renderer and channel metadata.
189
+ - **Catalog** — all 305 named effects, grouped by category, with renderer and channel metadata.
183
190
  - **Architecture** — the attribute grammar, the composition model, and why the library is built
184
191
  the way it is (`docs/design.md` in this repo).
185
192
 
@@ -1836,7 +1836,7 @@ function parseAngleRadians(raw) {
1836
1836
  if (!match) return 0;
1837
1837
  const value = parseFloat(match[1]);
1838
1838
  if (!Number.isFinite(value)) return 0;
1839
- return value * (ANGLE_UNITS[(match[2] ?? "deg").toLowerCase()] ?? ANGLE_UNITS.deg);
1839
+ return value * ANGLE_UNITS[(match[2] ?? "deg").toLowerCase()];
1840
1840
  }
1841
1841
  var PALETTE_SIZE = 5;
1842
1842
  var DEFAULT_PALETTE = [
@@ -2067,7 +2067,7 @@ function paintBoxOf(content, natural, cs) {
2067
2067
  if (bw <= 0 || bh <= 0) return content;
2068
2068
  const [dw, dh] = fittedSize(cs.objectFit || "fill", bw, bh, natural);
2069
2069
  const tokens = (cs.objectPosition || "50% 50%").trim().split(/\s+/);
2070
- const left = content.left + positionOffset(tokens[0] ?? "50%", bw - dw);
2070
+ const left = content.left + positionOffset(tokens[0], bw - dw);
2071
2071
  const top = content.top + positionOffset(tokens[1] ?? "50%", bh - dh);
2072
2072
  return { left, top, right: left + dw, bottom: top + dh };
2073
2073
  }
@@ -2333,7 +2333,7 @@ function extractShaderOptions(params, createCanvas) {
2333
2333
  ...readDuotoneColors(c1Text, c2Text, createCanvas),
2334
2334
  blendMode: blendMap[params.text("blend", "normal")] ?? 0,
2335
2335
  to: params.text("to", ""),
2336
- progress: params.num ? params.num("progress", -1) : -1,
2336
+ progress: params.num("progress", -1),
2337
2337
  // Compared against the one enabling word rather than "not `off`", so — exactly as with
2338
2338
  // `audioBand` below — a caller passing an unvalidated accessor, or an author who typed
2339
2339
  // `scrub: scrol`, cannot turn the bridge on by accident.
@@ -2770,7 +2770,7 @@ function restoreInstanceOpacity(el, state) {
2770
2770
  if (!state.hiddenByRenderer) return;
2771
2771
  state.hiddenByRenderer = false;
2772
2772
  const style = styleOf(state.ledgers, el);
2773
- if (style) style.set("opacity", style.peek("opacity") ?? "");
2773
+ if (style) style.set("opacity", style.peek("opacity"));
2774
2774
  }
2775
2775
  var SHADER_TEXTURE_GRACE_MS = 5e3;
2776
2776
  function acquireRenderer(info, held) {
@@ -3938,7 +3938,7 @@ function prepareCameraScene(el, params, ctx) {
3938
3938
  const controller = new CameraController(htmlEl, options, resolvedEnv);
3939
3939
  const layerEls = ownedDescendants(htmlEl, "camera-scene", "camera-layer");
3940
3940
  for (const layer of layerEls) {
3941
- const kui = layer.getAttribute("data-kui") || "";
3941
+ const kui = layer.getAttribute("data-kui");
3942
3942
  const zMatch = /z:([+-]?[0-9.]+)(?:px)?/.exec(kui);
3943
3943
  const depthZ = zMatch ? parseDepth(zMatch[1]) : 0;
3944
3944
  controller.addLayer(layer, depthZ);
@@ -36,6 +36,10 @@ function scopeParam(params, fallback) {
36
36
  function queryScoped(el, ctx, selector, scope) {
37
37
  return [...(scope === "page" ? ctx.doc : el).querySelectorAll(selector)];
38
38
  }
39
+ function queryControls(el, ctx, selector) {
40
+ const inside = [...el.querySelectorAll(selector)];
41
+ return inside.length > 0 ? inside : [...ctx.doc.querySelectorAll(selector)];
42
+ }
39
43
 
40
44
  // src/core/event-sources.ts
41
45
  function createEventSourceBindings() {
@@ -541,18 +545,25 @@ function defaultObserverFactory() {
541
545
  if (typeof IntersectionObserver === "undefined") return void 0;
542
546
  return (callback, init) => new IntersectionObserver(callback, init);
543
547
  }
548
+ function onlyBoundLate(name, claims) {
549
+ const authorising = authorisingActivations(name);
550
+ if (!authorising.includes("enter")) return false;
551
+ const suits = (claim) => authorising.some((named) => claim.supported.includes(named));
552
+ if (!claims.some((claim) => claim.entrance && suits(claim))) return false;
553
+ return claims.every((claim) => suits(claim) || claim.supported.includes("load"));
554
+ }
544
555
  function warnAboutActivation(request) {
545
556
  warnUnsupported(request);
546
557
  warnUnknownEvents(request);
547
558
  }
548
- function warnUnsupported({ el, spec, supported, reporter }) {
549
- if (supported.length === 0) return;
559
+ function warnUnsupported({ el, spec, supported, claims, reporter }) {
560
+ const declaredAny = supported.length > 0 || (claims?.some((claim) => claim.supported.length > 0) ?? false);
561
+ if (!declaredAny) return;
562
+ const shared = supported.length > 0 ? supported.join(", ") : "none in common across the composed effects";
550
563
  for (const name of spec.names) {
551
564
  if (authorisingActivations(name).some((named) => supported.includes(named))) continue;
552
- reporter.warn(
553
- `activation "${name}" is not supported by this effect (supports: ${supported.join(", ")})`,
554
- el
555
- );
565
+ if (claims && onlyBoundLate(name, claims)) continue;
566
+ reporter.warn(`activation "${name}" is not supported by this effect (supports: ${shared})`, el);
556
567
  }
557
568
  }
558
569
  function warnUnknownEvents({ el, spec, reporter }) {
@@ -615,6 +626,10 @@ var CHANNEL = {
615
626
  */
616
627
  skew: "skew"
617
628
  };
629
+ function attributeChannel(attribute) {
630
+ return `attr:${attribute}`;
631
+ }
632
+ var SUBTREE_CHANNEL = "subtree";
618
633
  function inertInstance(destroy = () => {
619
634
  }) {
620
635
  return {
@@ -2055,6 +2070,21 @@ function emitLifecycle(el, type, detail) {
2055
2070
  el.dispatchEvent(new Ctor(type, { detail, bubbles: true, composed: true }));
2056
2071
  }
2057
2072
 
2073
+ // src/core/timing-contract.ts
2074
+ var ALL_TIMING_TOKENS = ["duration", "delay", "ease"];
2075
+ var CONTRACTS = /* @__PURE__ */ new WeakMap();
2076
+ function declareTimingContract(prepare, contract) {
2077
+ CONTRACTS.set(prepare, contract);
2078
+ return prepare;
2079
+ }
2080
+ function inheritTimingContract(inner, outer) {
2081
+ const contract = CONTRACTS.get(inner);
2082
+ return contract ? declareTimingContract(outer, contract) : outer;
2083
+ }
2084
+ function timingContractOf(primitive) {
2085
+ return primitive.prepare ? CONTRACTS.get(primitive.prepare) : void 0;
2086
+ }
2087
+
2058
2088
  // src/core/params.ts
2059
2089
  var DANGEROUS = /[;<]|\/\*|url\s*\(|expression\s*\(|@import|image-set\s*\(/i;
2060
2090
  var ABSOLUTE_OR_PROTOCOL_RELATIVE = /^(?:[a-z][a-z0-9+.-]*:|[/\\]{2})/i;
@@ -2682,11 +2712,20 @@ function createRootResolver(options) {
2682
2712
  const windowRoot = windowScrollRoot(win);
2683
2713
  return (el) => {
2684
2714
  for (let node = el.parentElement; node; node = node.parentElement) {
2715
+ if (scrollsTheViewport(node, win)) return windowRoot;
2685
2716
  if (isScrollable(node)) return elementScrollRoot(node, win);
2686
2717
  }
2687
2718
  return windowRoot;
2688
2719
  };
2689
2720
  }
2721
+ function scrollsTheViewport(node, win) {
2722
+ const root = win.document.documentElement;
2723
+ if (node === root) return true;
2724
+ if (node !== win.document.body) return false;
2725
+ const rootStyle = win.getComputedStyle(root);
2726
+ return !CLIPPING_OVERFLOW.has(rootStyle.overflowX) && !CLIPPING_OVERFLOW.has(rootStyle.overflowY);
2727
+ }
2728
+ var CLIPPING_OVERFLOW = /* @__PURE__ */ new Set(["auto", "scroll", "overlay", "hidden", "clip"]);
2690
2729
  var SCROLLABLE_OVERFLOW = /* @__PURE__ */ new Set(["auto", "scroll", "overlay"]);
2691
2730
  function defaultIsScrollable(win) {
2692
2731
  return (el) => {
@@ -2920,12 +2959,14 @@ export {
2920
2959
  SCOPE_PARAM,
2921
2960
  scopeParam,
2922
2961
  queryScoped,
2962
+ queryControls,
2923
2963
  resolveActivationSpec,
2924
2964
  startKindOf,
2925
2965
  isOneShot,
2926
2966
  createActivationBinder,
2927
2967
  warnAboutActivation,
2928
2968
  ATTR,
2969
+ BREAKPOINT_NAMES,
2929
2970
  gatedAnimationName,
2930
2971
  gateMatches,
2931
2972
  gatesOverlap,
@@ -2945,6 +2986,8 @@ export {
2945
2986
  warnAboutToggleActions,
2946
2987
  applyToggleVerb,
2947
2988
  CHANNEL,
2989
+ attributeChannel,
2990
+ SUBTREE_CHANNEL,
2948
2991
  inertInstance,
2949
2992
  SEGMENT_HOIST_KEYS,
2950
2993
  splitTopLevel,
@@ -2980,5 +3023,9 @@ export {
2980
3023
  createCssInstance,
2981
3024
  continuousSetup,
2982
3025
  deferredInstance,
2983
- deferPrepare
3026
+ deferPrepare,
3027
+ ALL_TIMING_TOKENS,
3028
+ declareTimingContract,
3029
+ inheritTimingContract,
3030
+ timingContractOf
2984
3031
  };