@michaelyagi/shoji 0.1.0-beta.5 → 0.1.0-beta.7
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/core/shoji-core.js +30 -1
- package/dist/core/shoji-core.js.map +1 -1
- package/dist/core/shoji-core.min.js +1 -1
- package/dist/core/shoji-core.min.js.map +1 -1
- package/dist/esm/core/Gallery.d.ts +8 -0
- package/dist/esm/core/index.js +22 -1
- package/dist/esm/core/index.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/plugins/rotateFlip/index.js +1 -1
- package/dist/esm/plugins/zoom/index.js +1 -1
- package/dist/esm/{zoomTransition-BbnYTxY-.js → zoomTransition-CQG__VzO.js} +10 -2
- package/dist/esm/zoomTransition-CQG__VzO.js.map +1 -0
- package/dist/plugins/rotateFlip.js.map +1 -1
- package/dist/plugins/rotateFlip.min.js.map +1 -1
- package/dist/plugins/zoom.js.map +1 -1
- package/dist/plugins/zoom.min.js.map +1 -1
- package/dist/shoji.js +31 -2
- package/dist/shoji.js.map +1 -1
- package/dist/shoji.min.js +1 -1
- package/dist/shoji.min.js.map +1 -1
- package/package.json +1 -1
- package/dist/esm/zoomTransition-BbnYTxY-.js.map +0 -1
package/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
[](https://github.com/MichaelYagi/shoji/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/@michaelyagi/shoji)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
> **AI-authored.** 100% of the code was written by Claude (Anthropic); I shaped the architecture, scope, and every decision, and did all the testing.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
A zero-dependency, plugin-first TypeScript lightbox/gallery. Drop in two `<script>`/`<link>` tags, or install from npm — everything beyond the minimal lightbox, including every official plugin, is opt-in.
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
@@ -14,7 +14,7 @@ A zero-dependency, plugin-first TypeScript lightbox/gallery. Drop in two `<scrip
|
|
|
14
14
|
- **Plugin system** — zoom (pinch/pan/wheel), fullscreen, rotate/flip, autoplay/slideshow, active-thumbnail sync, YouTube video embeds, and a grid/masonry/justified layout engine, each independently opt-in.
|
|
15
15
|
- **Accessibility is not a plugin** — keyboard nav, focus trapping, ARIA roles, and screen-reader announcements live in core.
|
|
16
16
|
- **Themeable via CSS custom properties** — no hardcoded colors/sizes in JS.
|
|
17
|
-
- **
|
|
17
|
+
- **Three distributions** — single-file (`dist/shoji.js` + `dist/shoji.css`, core + every plugin, self-registering) for zero-setup `<script>` tag use; core + individual plugin files (`dist/core/shoji-core.(min.)js` + `dist/plugins/{name}.(min.)js`) for `<script>`-tag consumers who want to pick exactly which plugins ship; and tree-shakable per-plugin ESM entries for bundler users.
|
|
18
18
|
- Size-budgeted and CI-enforced: core ≤ 21 kB, each plugin ≤ 8 kB, full bundle ≤ 90 kB (all min+gzip).
|
|
19
19
|
|
|
20
20
|
## Install
|
package/dist/core/shoji-core.js
CHANGED
|
@@ -534,8 +534,16 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
534
534
|
const translateY = to.top + to.height / 2 - (from.top + from.height / 2);
|
|
535
535
|
return `translate3d(${translateX}px, ${translateY}px, 0) scale3d(${scale}, ${scale}, 1)`;
|
|
536
536
|
}
|
|
537
|
+
function effectiveOriginBox(origin) {
|
|
538
|
+
const img = origin.querySelector("img");
|
|
539
|
+
if (img) {
|
|
540
|
+
const rect = img.getBoundingClientRect();
|
|
541
|
+
if (rect.width > 0 && rect.height > 0) return rect;
|
|
542
|
+
}
|
|
543
|
+
return origin.getBoundingClientRect();
|
|
544
|
+
}
|
|
537
545
|
function computeTransform(origin, target, aspectRatio, naturalSize) {
|
|
538
|
-
const originRect = origin
|
|
546
|
+
const originRect = effectiveOriginBox(origin);
|
|
539
547
|
const targetRect = effectiveTargetBox(target, aspectRatio, naturalSize);
|
|
540
548
|
if (targetRect.width === 0 || targetRect.height === 0 || originRect.width === 0 || originRect.height === 0) {
|
|
541
549
|
return null;
|
|
@@ -1894,6 +1902,19 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
1894
1902
|
__publicField(this, "captureGestureStartState", () => {
|
|
1895
1903
|
this.controlsHiddenAtGestureStart = this.autoHidden;
|
|
1896
1904
|
});
|
|
1905
|
+
/**
|
|
1906
|
+
* A real mobile bug (DESIGN.md §2.6a): after scrolling far enough to
|
|
1907
|
+
* collapse a mobile browser's own URL bar, `window.innerHeight` grows
|
|
1908
|
+
* but `.shoji-outer`'s painted size didn't follow, off-centering the
|
|
1909
|
+
* photo. `visualViewport.height` reflects the true visible area;
|
|
1910
|
+
* `window`'s `resize` is the fallback where it's unsupported.
|
|
1911
|
+
*/
|
|
1912
|
+
__publicField(this, "syncViewportHeight", () => {
|
|
1913
|
+
var _a;
|
|
1914
|
+
if (!this.dom) return;
|
|
1915
|
+
const height = ((_a = window.visualViewport) == null ? void 0 : _a.height) ?? window.innerHeight;
|
|
1916
|
+
this.dom.outer.style.height = `${height}px`;
|
|
1917
|
+
});
|
|
1897
1918
|
__publicField(this, "onKeydown", (event) => {
|
|
1898
1919
|
if (document.activeElement instanceof HTMLVideoElement && event.key !== "Escape") return;
|
|
1899
1920
|
this.onActivity();
|
|
@@ -2931,6 +2952,10 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
2931
2952
|
naturalSize && !((_a = this.itemList[index]) == null ? void 0 : _a.video) ? this.resolveOpenPlaceholderSrc(this.itemList[index], origin) : void 0
|
|
2932
2953
|
);
|
|
2933
2954
|
this.dom.outer.classList.add("shoji-open");
|
|
2955
|
+
this.syncViewportHeight();
|
|
2956
|
+
if (window.visualViewport)
|
|
2957
|
+
window.visualViewport.addEventListener("resize", this.syncViewportHeight);
|
|
2958
|
+
else window.addEventListener("resize", this.syncViewportHeight);
|
|
2934
2959
|
document.addEventListener("keydown", this.onKeydown);
|
|
2935
2960
|
this.focusTrap.activate(this.dom.dialog);
|
|
2936
2961
|
this.scheduleAutoHide();
|
|
@@ -3155,8 +3180,12 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
3155
3180
|
this.opened = false;
|
|
3156
3181
|
unlockBodyScroll();
|
|
3157
3182
|
document.removeEventListener("keydown", this.onKeydown);
|
|
3183
|
+
if (window.visualViewport)
|
|
3184
|
+
window.visualViewport.removeEventListener("resize", this.syncViewportHeight);
|
|
3185
|
+
else window.removeEventListener("resize", this.syncViewportHeight);
|
|
3158
3186
|
this.focusTrap.deactivate();
|
|
3159
3187
|
(_a = this.dom) == null ? void 0 : _a.outer.classList.remove("shoji-open");
|
|
3188
|
+
if (this.dom) this.dom.outer.style.height = "";
|
|
3160
3189
|
if (this.dom) this.dom.backdrop.style.opacity = "";
|
|
3161
3190
|
if (this.autoHideTimer !== null) {
|
|
3162
3191
|
clearTimeout(this.autoHideTimer);
|