@michaelyagi/shoji 0.1.0-alpha.6

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 (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +81 -0
  3. package/dist/esm/core/EventBus.d.ts +16 -0
  4. package/dist/esm/core/FocusTrap.d.ts +9 -0
  5. package/dist/esm/core/Gallery.d.ts +221 -0
  6. package/dist/esm/core/GestureController.d.ts +50 -0
  7. package/dist/esm/core/LiveRegion.d.ts +6 -0
  8. package/dist/esm/core/SlideManager.d.ts +83 -0
  9. package/dist/esm/core/bodyScrollLock.d.ts +2 -0
  10. package/dist/esm/core/dom.d.ts +27 -0
  11. package/dist/esm/core/icons.d.ts +6 -0
  12. package/dist/esm/core/index.d.ts +5 -0
  13. package/dist/esm/core/index.js +1966 -0
  14. package/dist/esm/core/index.js.map +1 -0
  15. package/dist/esm/core/plugin.d.ts +54 -0
  16. package/dist/esm/core/rotateFlipNormalize.d.ts +19 -0
  17. package/dist/esm/core/scan.d.ts +8 -0
  18. package/dist/esm/core/types.d.ts +268 -0
  19. package/dist/esm/core/zoomTransition.d.ts +33 -0
  20. package/dist/esm/gestures/GestureEngine.d.ts +78 -0
  21. package/dist/esm/index.css +475 -0
  22. package/dist/esm/index.d.ts +32 -0
  23. package/dist/esm/index.js +24 -0
  24. package/dist/esm/index.js.map +1 -0
  25. package/dist/esm/index2.css +22 -0
  26. package/dist/esm/index3.css +166 -0
  27. package/dist/esm/index4.css +27 -0
  28. package/dist/esm/plugins/activeThumbnail/index.d.ts +26 -0
  29. package/dist/esm/plugins/activeThumbnail/index.js +48 -0
  30. package/dist/esm/plugins/activeThumbnail/index.js.map +1 -0
  31. package/dist/esm/plugins/autoplay/icons.d.ts +3 -0
  32. package/dist/esm/plugins/autoplay/index.d.ts +17 -0
  33. package/dist/esm/plugins/autoplay/index.js +177 -0
  34. package/dist/esm/plugins/autoplay/index.js.map +1 -0
  35. package/dist/esm/plugins/fullscreen/icons.d.ts +3 -0
  36. package/dist/esm/plugins/fullscreen/index.d.ts +17 -0
  37. package/dist/esm/plugins/fullscreen/index.js +74 -0
  38. package/dist/esm/plugins/fullscreen/index.js.map +1 -0
  39. package/dist/esm/plugins/layout/index.d.ts +191 -0
  40. package/dist/esm/plugins/layout/index.js +746 -0
  41. package/dist/esm/plugins/layout/index.js.map +1 -0
  42. package/dist/esm/plugins/layout/justified.d.ts +68 -0
  43. package/dist/esm/plugins/layout/masonry.d.ts +92 -0
  44. package/dist/esm/plugins/rotateFlip/icons.d.ts +5 -0
  45. package/dist/esm/plugins/rotateFlip/index.d.ts +17 -0
  46. package/dist/esm/plugins/rotateFlip/index.js +138 -0
  47. package/dist/esm/plugins/rotateFlip/index.js.map +1 -0
  48. package/dist/esm/plugins/video/index.d.ts +13 -0
  49. package/dist/esm/plugins/video/index.js +95 -0
  50. package/dist/esm/plugins/video/index.js.map +1 -0
  51. package/dist/esm/plugins/video/youtube.d.ts +61 -0
  52. package/dist/esm/plugins/zoom/icons.d.ts +4 -0
  53. package/dist/esm/plugins/zoom/index.d.ts +30 -0
  54. package/dist/esm/plugins/zoom/index.js +274 -0
  55. package/dist/esm/plugins/zoom/index.js.map +1 -0
  56. package/dist/esm/plugins/zoom/zoomMath.d.ts +24 -0
  57. package/dist/esm/transitions/SlideTransition.d.ts +25 -0
  58. package/dist/esm/transitions/presets.d.ts +21 -0
  59. package/dist/esm/zoomTransition-bbKHpVpA.js +110 -0
  60. package/dist/esm/zoomTransition-bbKHpVpA.js.map +1 -0
  61. package/dist/shoji.css +690 -0
  62. package/dist/shoji.js +3605 -0
  63. package/dist/shoji.js.map +1 -0
  64. package/dist/shoji.min.css +1 -0
  65. package/dist/shoji.min.js +2 -0
  66. package/dist/shoji.min.js.map +1 -0
  67. package/package.json +77 -0
@@ -0,0 +1,110 @@
1
+ function prefersReducedMotion() {
2
+ return typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
3
+ }
4
+ function parseCssTime(value) {
5
+ var _a;
6
+ const first = ((_a = value.split(",")[0]) == null ? void 0 : _a.trim()) ?? "";
7
+ if (first.endsWith("ms")) return parseFloat(first);
8
+ if (first.endsWith("s")) return parseFloat(first) * 1e3;
9
+ return 0;
10
+ }
11
+ function containedBox(container, aspectRatio) {
12
+ const containerRatio = container.width / container.height;
13
+ const width = aspectRatio > containerRatio ? container.width : container.height * aspectRatio;
14
+ const height = aspectRatio > containerRatio ? container.width / aspectRatio : container.height;
15
+ return {
16
+ left: container.left + (container.width - width) / 2,
17
+ top: container.top + (container.height - height) / 2,
18
+ width,
19
+ height
20
+ };
21
+ }
22
+ function effectiveTargetBox(target, aspectRatio) {
23
+ const child = target.firstElementChild;
24
+ const isPlaceholder = child instanceof HTMLElement && (child.classList.contains("shoji-slide-spinner") || child.classList.contains("shoji-slide-open-placeholder"));
25
+ if (child instanceof HTMLElement && !isPlaceholder) {
26
+ const rect = child.getBoundingClientRect();
27
+ if (rect.width > 0 && rect.height > 0) return rect;
28
+ }
29
+ const containerRect = target.getBoundingClientRect();
30
+ if (aspectRatio && containerRect.width > 0 && containerRect.height > 0) {
31
+ return containedBox(containerRect, aspectRatio);
32
+ }
33
+ return containerRect;
34
+ }
35
+ function computeTransform(origin, target, aspectRatio) {
36
+ const originRect = origin.getBoundingClientRect();
37
+ const targetRect = effectiveTargetBox(target, aspectRatio);
38
+ if (targetRect.width === 0 || targetRect.height === 0 || originRect.width === 0 || originRect.height === 0) {
39
+ return null;
40
+ }
41
+ const scale = Math.min(
42
+ originRect.width / targetRect.width,
43
+ originRect.height / targetRect.height
44
+ );
45
+ const translateX = originRect.left + originRect.width / 2 - (targetRect.left + targetRect.width / 2);
46
+ const translateY = originRect.top + originRect.height / 2 - (targetRect.top + targetRect.height / 2);
47
+ return `translate3d(${translateX}px, ${translateY}px, 0) scale3d(${scale}, ${scale}, 1)`;
48
+ }
49
+ function waitForTransitionEnd(target, cb) {
50
+ const durationMs = parseCssTime(getComputedStyle(target).transitionDuration);
51
+ let done = false;
52
+ const finish = () => {
53
+ if (done) return;
54
+ done = true;
55
+ target.removeEventListener("transitionend", onEnd);
56
+ cb();
57
+ };
58
+ const onEnd = (event) => {
59
+ if (event.target === target && event.propertyName === "transform")
60
+ finish();
61
+ };
62
+ target.addEventListener("transitionend", onEnd);
63
+ setTimeout(finish, durationMs + 100);
64
+ }
65
+ function clearInlineTransform(target, expectedTransform) {
66
+ target.style.transition = "";
67
+ target.style.transformOrigin = "";
68
+ target.style.willChange = "";
69
+ if (target.style.transform === expectedTransform) target.style.transform = "";
70
+ }
71
+ function zoomIn({ origin, target, aspectRatio }) {
72
+ if (prefersReducedMotion()) return;
73
+ const transform = computeTransform(origin, target, aspectRatio);
74
+ if (!transform) return;
75
+ target.style.transition = "none";
76
+ target.style.transformOrigin = "center";
77
+ target.style.willChange = "transform";
78
+ target.style.transform = transform;
79
+ void target.offsetHeight;
80
+ target.style.transition = "transform var(--shoji-duration) var(--shoji-easing)";
81
+ target.style.transform = "none";
82
+ waitForTransitionEnd(target, () => clearInlineTransform(target, "none"));
83
+ }
84
+ function zoomOut({ origin, target, aspectRatio }, onComplete) {
85
+ if (prefersReducedMotion()) {
86
+ onComplete();
87
+ return;
88
+ }
89
+ const transform = computeTransform(origin, target, aspectRatio);
90
+ if (!transform) {
91
+ onComplete();
92
+ return;
93
+ }
94
+ target.style.transformOrigin = "center";
95
+ target.style.willChange = "transform";
96
+ target.style.transition = "transform var(--shoji-duration) var(--shoji-easing)";
97
+ void target.offsetHeight;
98
+ target.style.transform = transform;
99
+ const appliedTransform = target.style.transform;
100
+ waitForTransitionEnd(target, () => {
101
+ clearInlineTransform(target, appliedTransform);
102
+ onComplete();
103
+ });
104
+ }
105
+ export {
106
+ zoomOut as a,
107
+ waitForTransitionEnd as w,
108
+ zoomIn as z
109
+ };
110
+ //# sourceMappingURL=zoomTransition-bbKHpVpA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zoomTransition-bbKHpVpA.js","sources":["../../src/core/zoomTransition.ts"],"sourcesContent":["export interface ZoomTransitionTarget {\n /** The thumbnail element to animate to/from. */\n origin: HTMLElement;\n /** The `.shoji-slide-media` element being animated — not `.shoji-slide` itself, whose transform is already owned by pool-offset positioning. */\n target: HTMLElement;\n /** `item.width / item.height`, when known — `target` is always its full flex-box size, never the (usually smaller, letterboxed) rendered photo inside it; see `effectiveTargetBox`. */\n aspectRatio?: number;\n}\n\nfunction prefersReducedMotion(): boolean {\n return (\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches\n );\n}\n\n/** `\"300ms\"` / `\"0.3s\"` → milliseconds. Reads the *actual* computed value, not an assumed default, so a host overriding `--shoji-duration` still gets a correct fallback timeout below. */\nfunction parseCssTime(value: string): number {\n const first = value.split(',')[0]?.trim() ?? '';\n if (first.endsWith('ms')) return parseFloat(first);\n if (first.endsWith('s')) return parseFloat(first) * 1000;\n return 0;\n}\n\ninterface Box {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\n/** The `object-fit: contain` box for `aspectRatio` within `container` — computed analytically since the real image may not be loaded/attached yet. */\nfunction containedBox(container: Box, aspectRatio: number): Box {\n const containerRatio = container.width / container.height;\n const width = aspectRatio > containerRatio ? container.width : container.height * aspectRatio;\n const height = aspectRatio > containerRatio ? container.width / aspectRatio : container.height;\n return {\n left: container.left + (container.width - width) / 2,\n top: container.top + (container.height - height) / 2,\n width,\n height,\n };\n}\n\n/**\n * `target`'s effective visual box, not necessarily its own\n * `getBoundingClientRect()`. `target` is always its full flex-box size; the\n * photo inside is usually *smaller*, letterboxed to its own aspect ratio —\n * a real bug used the container's full rect, making the animation scale\n * from/to a box far bigger than the photo ever renders at, visibly\n * shrinking it to something much smaller than the thumbnail whenever the\n * aspect ratios didn't match (the common case). Preferred sources: the real\n * rendered media child, if attached; else an analytical contain-box from\n * `aspectRatio`; else the container's own rect as a last resort.\n *\n * A real bug this guards against: on a fresh open with nothing decoded yet,\n * `target`'s only child at this point is the loading spinner (§2.3) — a\n * fixed ~40px circle, not the photo. Trusting its rect as \"the real\n * rendered media child\" made the FLIP transition scale toward/from a box\n * far smaller than the actual photo, so the scale factor came out inverted\n * (>1 instead of <1) and the spinner rendered wildly oversized for the\n * transition's first frames before shrinking back down — never the actual\n * photo, which hadn't swapped in yet either way.\n *\n * Same reasoning excludes `.shoji-slide-open-placeholder` (§2.3's low-res\n * open() stand-in): it's a real, non-spinner `<img>`, but its own rendered\n * rect reflects *its* crop/aspect ratio, not the real photo's — trusting it\n * would scale toward the placeholder's shape instead of the real photo's,\n * only to visibly jump again once the real photo swaps in and this\n * transition (already run) no longer applies. Excluding it falls through to\n * the analytical `aspectRatio`-based box below, sized for the real photo\n * regardless of what shape the placeholder happens to be.\n */\nfunction effectiveTargetBox(target: HTMLElement, aspectRatio?: number): Box {\n const child = target.firstElementChild;\n const isPlaceholder =\n child instanceof HTMLElement &&\n (child.classList.contains('shoji-slide-spinner') ||\n child.classList.contains('shoji-slide-open-placeholder'));\n if (child instanceof HTMLElement && !isPlaceholder) {\n const rect = child.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) return rect;\n }\n const containerRect = target.getBoundingClientRect();\n if (aspectRatio && containerRect.width > 0 && containerRect.height > 0) {\n return containedBox(containerRect, aspectRatio);\n }\n return containerRect;\n}\n\n/**\n * Center-to-center translate + a single uniform scale that lands `target`'s\n * effective box (`effectiveTargetBox` above) *within* `origin`'s box,\n * without distorting it. `null` if either has no real size — nothing sane\n * to animate. One scale factor, not independent scaleX/scaleY: origin and\n * the photo essentially never share an exact aspect ratio, and scaling each\n * axis independently to force a rect match visibly squeezes/stretches the\n * image. `Math.min` keeps the box fully contained within origin's rect\n * (same tradeoff `object-fit: contain` makes); center always lands exactly\n * on origin's center, only the unconstrained axis's edges fall short.\n */\nfunction computeTransform(\n origin: HTMLElement,\n target: HTMLElement,\n aspectRatio?: number,\n): string | null {\n const originRect = origin.getBoundingClientRect();\n const targetRect = effectiveTargetBox(target, aspectRatio);\n if (\n targetRect.width === 0 ||\n targetRect.height === 0 ||\n originRect.width === 0 ||\n originRect.height === 0\n ) {\n return null;\n }\n const scale = Math.min(\n originRect.width / targetRect.width,\n originRect.height / targetRect.height,\n );\n const translateX =\n originRect.left + originRect.width / 2 - (targetRect.left + targetRect.width / 2);\n const translateY =\n originRect.top + originRect.height / 2 - (targetRect.top + targetRect.height / 2);\n // translate3d/scale3d, not translate()/scale() — forces the GPU\n // compositing path instead of a main-thread-painted 2D transform, the\n // same fix already validated for the Zoom plugin's own scale animation\n // (DESIGN.md §4.6): this is the identical technique (a large photo\n // scaled via `transform`) on the same element, just driven by open/close\n // instead of pinch/toolbar zoom.\n return `translate3d(${translateX}px, ${translateY}px, 0) scale3d(${scale}, ${scale}, 1)`;\n}\n\n/**\n * Waits for `target`'s own transform transition to end (with a safety-net\n * timeout in case transitionend never fires — an interrupted/removed\n * element, or a browser quirk) then calls `cb` exactly once. Exported: the\n * gesture-driven drag-to-navigate/drag-to-close settle animations (§2.4,\n * `Gallery.ts`) reuse this same wait-with-fallback logic rather than\n * duplicating it — same instant-jump-then-transition FLIP family of moves\n * as the zoom transition, just on a different element/property pairing.\n */\nexport function waitForTransitionEnd(target: HTMLElement, cb: () => void): void {\n const durationMs = parseCssTime(getComputedStyle(target).transitionDuration);\n let done = false;\n const finish = (): void => {\n if (done) return;\n done = true;\n target.removeEventListener('transitionend', onEnd);\n cb();\n };\n const onEnd = (event: Event): void => {\n if (event.target === target && (event as TransitionEvent).propertyName === 'transform')\n finish();\n };\n target.addEventListener('transitionend', onEnd);\n setTimeout(finish, durationMs + 100);\n}\n\n/**\n * A real bug: unconditionally clearing `transform` here could wipe out a\n * value another plugin (rotateFlip) legitimately set on the *same* element\n * in the time between this animation starting and its cleanup callback\n * firing (transitionend, or the fallback timeout — either can land well\n * after a quick click elsewhere). Only clears `transform` if it still\n * matches what this animation itself last wrote — nothing else has touched\n * it since — otherwise leaves it alone. `transition`/`transformOrigin`\n * are always safe to clear; nothing else in this codebase sets them.\n *\n * A second real bug, found via reopening the lightbox: `expectedTransform`\n * must be the value *read back* from `target.style.transform` right after\n * assigning it, not the raw string `computeTransform()` produced. Setting\n * `element.style.transform` to a string containing an arbitrary JS float\n * (e.g. `scale(0.10416666666666667)`, `computeTransform`'s un-rounded\n * `Math.min(...)` result) and reading it back gives a *differently\n * formatted* string — the browser's CSSOM serializer rounds/reformats\n * numeric values on its own (observed in Chromium: `scale(0.104167)`).\n * Comparing the raw JS string against that reformatted one here always\n * failed for any scale factor without a short, clean decimal, silently\n * skipping the clear — permanently leaving `zoomOut`'s shrink transform\n * applied to `.shoji-slide-media` after the lightbox closed. The next\n * `open()`'s `computeTransform` then measured that *already-shrunk*\n * element's `getBoundingClientRect()` as if it were the natural size,\n * computing a near-1 (barely visible) scale instead of a real zoom-in —\n * reads as \"doesn't zoom, just appears,\" and compounds on every further\n * open/close cycle since the stuck transform is never cleared either way.\n * `zoomIn`'s own `'none'` literal never hit this — a fixed string round-trips\n * through the CSSOM unchanged, unlike an arbitrary computed float.\n */\nfunction clearInlineTransform(target: HTMLElement, expectedTransform: string): void {\n target.style.transition = '';\n target.style.transformOrigin = '';\n target.style.willChange = '';\n if (target.style.transform === expectedTransform) target.style.transform = '';\n}\n\n/**\n * FLIP-style open: `target` starts visually at `origin`'s position/size (an\n * instant, untransitioned jump), then transitions to its natural layout —\n * reads as \"growing out of the thumbnail.\" Fire-and-forget: cleans up its\n * own inline styles once the transition ends, nothing to await.\n */\nexport function zoomIn({ origin, target, aspectRatio }: ZoomTransitionTarget): void {\n if (prefersReducedMotion()) return;\n const transform = computeTransform(origin, target, aspectRatio);\n if (!transform) return;\n\n target.style.transition = 'none';\n // computeTransform's translateX/Y is center-to-center math — must pair with\n // a center transform-origin (the CSS default), not 'top left', or the\n // scaled box ends up offset from origin by however far origin's center\n // sits from its own top-left corner.\n target.style.transformOrigin = 'center';\n // Promotes target onto its own compositing layer before the animated\n // transform starts, not mid-animation — same GPU-seam mitigation as the\n // Zoom plugin (DESIGN.md §4.6). Cleared in clearInlineTransform once the\n // transition ends, not left on permanently: this is the offset-0 pool\n // slot, alive for the gallery's whole lifetime, not a class scoped to\n // only-while-zoomed.\n target.style.willChange = 'transform';\n target.style.transform = transform;\n void target.offsetHeight; // force the instant jump to commit before transitioning away from it\n target.style.transition = 'transform var(--shoji-duration) var(--shoji-easing)';\n target.style.transform = 'none';\n\n waitForTransitionEnd(target, () => clearInlineTransform(target, 'none'));\n}\n\n/**\n * Reverse of `zoomIn`: `target` transitions from its natural position down\n * to `origin`'s rect — \"shrinking back into the thumbnail.\" `onComplete`\n * always fires exactly once, synchronously if there's nothing to animate\n * (reduced motion, or no valid rect), otherwise once the transition ends —\n * callers use this to know when it's safe to actually hide/finalize.\n */\nexport function zoomOut(\n { origin, target, aspectRatio }: ZoomTransitionTarget,\n onComplete: () => void,\n): void {\n if (prefersReducedMotion()) {\n onComplete();\n return;\n }\n const transform = computeTransform(origin, target, aspectRatio);\n if (!transform) {\n onComplete();\n return;\n }\n\n // computeTransform's translateX/Y is center-to-center math — must pair with\n // a center transform-origin (the CSS default), not 'top left', or the\n // scaled box ends up offset from origin by however far origin's center\n // sits from its own top-left corner.\n target.style.transformOrigin = 'center';\n target.style.willChange = 'transform'; // see zoomIn's doc comment on this line\n target.style.transition = 'transform var(--shoji-duration) var(--shoji-easing)';\n void target.offsetHeight;\n target.style.transform = transform;\n // Read back what the browser actually stored, not the raw string just\n // assigned — see clearInlineTransform's own doc comment for why the two\n // can differ (CSSOM float reformatting) and why that difference matters.\n const appliedTransform = target.style.transform;\n\n waitForTransitionEnd(target, () => {\n clearInlineTransform(target, appliedTransform);\n onComplete();\n });\n}\n"],"names":[],"mappings":"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"}