flipfolio 0.2.0 → 0.3.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 +27 -6
- package/dist/{chunk-Q2NKZMCC.js → chunk-RFBZ3WPG.js} +165 -76
- package/dist/chunk-RFBZ3WPG.js.map +1 -0
- package/dist/element.cjs +176 -59
- package/dist/element.cjs.map +1 -1
- package/dist/element.d.ts +6 -0
- package/dist/element.js +19 -1
- package/dist/element.js.map +1 -1
- package/dist/folder-gallery.css +34 -24
- package/dist/index.cjs +165 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +39 -1
- package/dist/index.js +3 -1
- package/dist/react.cjs +193 -95
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +3 -0
- package/dist/react.js +36 -27
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +187 -63
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.ts +18 -3
- package/dist/vue.js +30 -5
- package/dist/vue.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-Q2NKZMCC.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,22 +1,7 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __defProp = Object.defineProperty;
|
|
3
2
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
-
var __spreadValues = (a, b) => {
|
|
10
|
-
for (var prop in b || (b = {}))
|
|
11
|
-
if (__hasOwnProp.call(b, prop))
|
|
12
|
-
__defNormalProp(a, prop, b[prop]);
|
|
13
|
-
if (__getOwnPropSymbols)
|
|
14
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
15
|
-
if (__propIsEnum.call(b, prop))
|
|
16
|
-
__defNormalProp(a, prop, b[prop]);
|
|
17
|
-
}
|
|
18
|
-
return a;
|
|
19
|
-
};
|
|
20
5
|
var __export = (target, all) => {
|
|
21
6
|
for (var name in all)
|
|
22
7
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -34,12 +19,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
34
19
|
// src/folder-gallery.js
|
|
35
20
|
var folder_gallery_exports = {};
|
|
36
21
|
__export(folder_gallery_exports, {
|
|
22
|
+
FOLDER_PATHS: () => FOLDER_PATHS,
|
|
37
23
|
createFolderGallery: () => createFolderGallery,
|
|
38
24
|
default: () => folder_gallery_default
|
|
39
25
|
});
|
|
40
26
|
module.exports = __toCommonJS(folder_gallery_exports);
|
|
41
27
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
42
28
|
var DEFAULT_FOLDER_PATH = "M 0 22 C 0 10 10 0 22 0 L 155 0 C 168 0 172 6 176 14 C 180 24 188 32 204 32 L 458 32 C 470 32 480 42 480 54 L 480 320 C 480 332 470 342 458 342 L 22 342 C 10 342 0 332 0 320 Z";
|
|
29
|
+
var FOLDER_PATHS = {
|
|
30
|
+
left: DEFAULT_FOLDER_PATH,
|
|
31
|
+
right: "M 480 22 C 480 10 470 0 458 0 L 325 0 C 312 0 308 6 304 14 C 300 24 292 32 276 32 L 22 32 C 10 32 0 42 0 54 L 0 320 C 0 332 10 342 22 342 L 458 342 C 470 342 480 332 480 320 Z",
|
|
32
|
+
tray: "M 0 22 C 0 10 10 0 22 0 L 458 0 C 470 0 480 10 480 22 L 480 320 C 480 332 470 342 458 342 L 22 342 C 10 342 0 332 0 320 Z"
|
|
33
|
+
};
|
|
43
34
|
var DEFAULTS = {
|
|
44
35
|
mode: "stack",
|
|
45
36
|
// 'stack' | 'grid' | 'carousel'
|
|
@@ -57,15 +48,20 @@ var DEFAULTS = {
|
|
|
57
48
|
};
|
|
58
49
|
var PEEK_MODES = /* @__PURE__ */ new Set(["hover", "always", "off"]);
|
|
59
50
|
var DRAG_MODES = /* @__PURE__ */ new Set(["fling", "off"]);
|
|
51
|
+
var INSTANCES = /* @__PURE__ */ new WeakMap();
|
|
60
52
|
var MODE_WIDTHS = { stack: 480, grid: 720, carousel: 720 };
|
|
61
53
|
var SCROLL_THRESHOLD = 30;
|
|
62
54
|
var SCROLL_COOLDOWN = { stack: 450, carousel: 300 };
|
|
63
55
|
function hexToRgb(hex) {
|
|
64
|
-
|
|
56
|
+
let h = String(hex).trim().replace(/^#/, "");
|
|
57
|
+
if (h.length === 3) h = h.replace(/./g, (c) => c + c);
|
|
58
|
+
if (!/^[0-9a-f]{6}$/i.test(h)) return null;
|
|
65
59
|
return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
|
|
66
60
|
}
|
|
67
61
|
function folderColors(hex) {
|
|
68
|
-
const
|
|
62
|
+
const rgb = hexToRgb(hex);
|
|
63
|
+
if (!rgb) return null;
|
|
64
|
+
const [r, g, b] = rgb;
|
|
69
65
|
const dn = (v) => Math.max(v - 30, 0);
|
|
70
66
|
const up = (v, o) => Math.min(v + o, 255);
|
|
71
67
|
const fr = up(r, 35);
|
|
@@ -79,6 +75,34 @@ function folderColors(hex) {
|
|
|
79
75
|
label: yiq >= 128 ? "#1c1c1a" : "#ffffff"
|
|
80
76
|
};
|
|
81
77
|
}
|
|
78
|
+
function paintFolder(card, hex) {
|
|
79
|
+
const c = folderColors(hex);
|
|
80
|
+
if (!c) return;
|
|
81
|
+
card.style.setProperty("--fg-folder-bg", hex);
|
|
82
|
+
card.style.setProperty("--fg-front", c.front);
|
|
83
|
+
card.style.setProperty("--fg-front-solid", c.frontSolid);
|
|
84
|
+
card.style.setProperty("--fg-label-on-color", c.label);
|
|
85
|
+
const path = card.querySelector(".fg-folder path");
|
|
86
|
+
if (path) path.setAttribute("fill", c.back);
|
|
87
|
+
}
|
|
88
|
+
function paintGradient(card, gradient) {
|
|
89
|
+
const front = card.querySelector(".fg-front");
|
|
90
|
+
if (!front) return;
|
|
91
|
+
let layer = front.querySelector(".fg-gradient");
|
|
92
|
+
if (!gradient) {
|
|
93
|
+
if (layer) layer.remove();
|
|
94
|
+
card.classList.remove("fg-card--gradient");
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (!layer) {
|
|
98
|
+
layer = document.createElement("div");
|
|
99
|
+
layer.className = "fg-gradient";
|
|
100
|
+
layer.setAttribute("aria-hidden", "true");
|
|
101
|
+
front.insertBefore(layer, front.firstChild);
|
|
102
|
+
}
|
|
103
|
+
layer.style.background = gradient;
|
|
104
|
+
card.classList.add("fg-card--gradient");
|
|
105
|
+
}
|
|
82
106
|
function defaultContentRenderer(card, item) {
|
|
83
107
|
const wrap = document.createElement("div");
|
|
84
108
|
wrap.className = "fg-content";
|
|
@@ -98,12 +122,17 @@ function defaultContentRenderer(card, item) {
|
|
|
98
122
|
card.appendChild(wrap);
|
|
99
123
|
}
|
|
100
124
|
function createFolderGallery(root, options = {}) {
|
|
101
|
-
if (!root ||
|
|
102
|
-
const
|
|
125
|
+
if (!root || root.nodeType !== 1) throw new Error("createFolderGallery: a root element is required");
|
|
126
|
+
const prior = INSTANCES.get(root);
|
|
127
|
+
if (prior) prior();
|
|
128
|
+
const provided = {};
|
|
129
|
+
for (const k in options) if (options[k] !== void 0) provided[k] = options[k];
|
|
130
|
+
const opts = { ...DEFAULTS, ...provided };
|
|
103
131
|
const items = Array.isArray(opts.items) ? opts.items : [];
|
|
104
132
|
const n = items.length;
|
|
105
133
|
const renderContent = typeof opts.contentRenderer === "function" ? opts.contentRenderer : defaultContentRenderer;
|
|
106
|
-
const
|
|
134
|
+
const reducedQuery = opts.reducedMotion === "auto" && typeof matchMedia === "function" ? matchMedia("(prefers-reduced-motion: reduce)") : null;
|
|
135
|
+
let reduced = opts.reducedMotion === "force" || (reducedQuery ? reducedQuery.matches : false);
|
|
107
136
|
let mode = MODE_WIDTHS[opts.mode] ? opts.mode : "stack";
|
|
108
137
|
let active = Math.min(Math.max(opts.defaultActiveIndex | 0, 0), Math.max(n - 1, 0));
|
|
109
138
|
let scrollCooldown = false;
|
|
@@ -114,6 +143,25 @@ function createFolderGallery(root, options = {}) {
|
|
|
114
143
|
cleanups.push(() => el.removeEventListener(ev, fn, o));
|
|
115
144
|
};
|
|
116
145
|
const emit = (name, detail) => root.dispatchEvent(new CustomEvent(name, { detail, bubbles: true }));
|
|
146
|
+
let destroyed = false;
|
|
147
|
+
const timers = /* @__PURE__ */ new Set();
|
|
148
|
+
const rafs = /* @__PURE__ */ new Set();
|
|
149
|
+
const later = (fn, ms) => {
|
|
150
|
+
const id = setTimeout(() => {
|
|
151
|
+
timers.delete(id);
|
|
152
|
+
fn();
|
|
153
|
+
}, ms);
|
|
154
|
+
timers.add(id);
|
|
155
|
+
return id;
|
|
156
|
+
};
|
|
157
|
+
const frame = (fn) => {
|
|
158
|
+
const id = requestAnimationFrame(() => {
|
|
159
|
+
rafs.delete(id);
|
|
160
|
+
fn();
|
|
161
|
+
});
|
|
162
|
+
rafs.add(id);
|
|
163
|
+
return id;
|
|
164
|
+
};
|
|
117
165
|
root.classList.add("fg-root");
|
|
118
166
|
root.setAttribute("data-fg-mode", mode);
|
|
119
167
|
root.setAttribute("data-fg-peek", PEEK_MODES.has(opts.peek) ? opts.peek : "hover");
|
|
@@ -132,6 +180,12 @@ function createFolderGallery(root, options = {}) {
|
|
|
132
180
|
live.setAttribute("aria-atomic", "true");
|
|
133
181
|
root.append(scene, dotsEl, live);
|
|
134
182
|
function teardown() {
|
|
183
|
+
if (destroyed) return;
|
|
184
|
+
destroyed = true;
|
|
185
|
+
timers.forEach(clearTimeout);
|
|
186
|
+
timers.clear();
|
|
187
|
+
rafs.forEach(cancelAnimationFrame);
|
|
188
|
+
rafs.clear();
|
|
135
189
|
cleanups.forEach((fn) => fn());
|
|
136
190
|
cleanups.length = 0;
|
|
137
191
|
root.replaceChildren();
|
|
@@ -139,21 +193,34 @@ function createFolderGallery(root, options = {}) {
|
|
|
139
193
|
root.removeAttribute("data-fg-mode");
|
|
140
194
|
root.removeAttribute("data-fg-peek");
|
|
141
195
|
root.removeAttribute("data-fg-drag");
|
|
196
|
+
INSTANCES.delete(root);
|
|
142
197
|
}
|
|
143
198
|
if (n === 0) {
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
199
|
+
const noop = () => {
|
|
200
|
+
};
|
|
201
|
+
INSTANCES.set(root, teardown);
|
|
202
|
+
return {
|
|
203
|
+
next: noop,
|
|
204
|
+
prev: noop,
|
|
205
|
+
goTo: noop,
|
|
206
|
+
setMode: noop,
|
|
207
|
+
setPeek: noop,
|
|
208
|
+
setColor: noop,
|
|
209
|
+
setGradient: noop,
|
|
210
|
+
getActiveIndex: () => -1,
|
|
211
|
+
getMode: () => mode,
|
|
212
|
+
getPeek: () => root.getAttribute("data-fg-peek"),
|
|
213
|
+
getColor: () => void 0,
|
|
214
|
+
getGradient: () => void 0,
|
|
215
|
+
getItems: () => [],
|
|
216
|
+
destroy: teardown
|
|
217
|
+
};
|
|
150
218
|
}
|
|
151
219
|
function setCardTransform(card, { x, y, z, rx, ry, s, zIndex, opacity, isActive }) {
|
|
152
220
|
if (!card.classList.contains("fg-card--flung")) {
|
|
153
221
|
card.style.transform = `translate3d(${x}px,${y}px,${z}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${s})`;
|
|
154
222
|
card.style.opacity = String(opacity);
|
|
155
223
|
}
|
|
156
|
-
card.style.transformOrigin = "center bottom";
|
|
157
224
|
card.style.zIndex = String(zIndex);
|
|
158
225
|
card.setAttribute("aria-selected", isActive ? "true" : "false");
|
|
159
226
|
card.classList.toggle("is-active", isActive);
|
|
@@ -164,13 +231,9 @@ function createFolderGallery(root, options = {}) {
|
|
|
164
231
|
card.tabIndex = i === active ? 0 : -1;
|
|
165
232
|
card.setAttribute("role", "option");
|
|
166
233
|
card.setAttribute("aria-label", item.label || `Item ${i + 1}`);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
card.style.setProperty("--fg-front", c.front);
|
|
171
|
-
card.style.setProperty("--fg-front-solid", c.frontSolid);
|
|
172
|
-
card.style.setProperty("--fg-label-on-color", c.label);
|
|
173
|
-
}
|
|
234
|
+
card.setAttribute("aria-setsize", String(n));
|
|
235
|
+
card.setAttribute("aria-posinset", String(i + 1));
|
|
236
|
+
card.setAttribute("data-fg-index", String(i));
|
|
174
237
|
const svg = document.createElementNS(SVG_NS, "svg");
|
|
175
238
|
svg.setAttribute("class", "fg-folder");
|
|
176
239
|
svg.setAttribute("viewBox", "0 0 480 342");
|
|
@@ -178,7 +241,7 @@ function createFolderGallery(root, options = {}) {
|
|
|
178
241
|
svg.setAttribute("aria-hidden", "true");
|
|
179
242
|
const path = document.createElementNS(SVG_NS, "path");
|
|
180
243
|
path.setAttribute("d", opts.folderPath);
|
|
181
|
-
path.setAttribute("fill",
|
|
244
|
+
path.setAttribute("fill", "var(--fg-folder-bg)");
|
|
182
245
|
svg.appendChild(path);
|
|
183
246
|
card.appendChild(svg);
|
|
184
247
|
renderContent(card, item, i);
|
|
@@ -201,6 +264,8 @@ function createFolderGallery(root, options = {}) {
|
|
|
201
264
|
front.appendChild(label);
|
|
202
265
|
}
|
|
203
266
|
card.appendChild(front);
|
|
267
|
+
if (item.color) paintFolder(card, item.color);
|
|
268
|
+
if (item.gradient) paintGradient(card, item.gradient);
|
|
204
269
|
scene.appendChild(card);
|
|
205
270
|
return card;
|
|
206
271
|
});
|
|
@@ -214,9 +279,13 @@ function createFolderGallery(root, options = {}) {
|
|
|
214
279
|
dotsEl.appendChild(dot);
|
|
215
280
|
return dot;
|
|
216
281
|
});
|
|
282
|
+
const clearGridWidth = (card) => {
|
|
283
|
+
if (card.style.width) card.style.width = "";
|
|
284
|
+
};
|
|
217
285
|
function layoutStack() {
|
|
218
286
|
scene.style.height = "";
|
|
219
287
|
cardEls.forEach((card, i) => {
|
|
288
|
+
clearGridWidth(card);
|
|
220
289
|
const behind = (i - active + n) % n;
|
|
221
290
|
if (behind === 0) {
|
|
222
291
|
setCardTransform(card, { x: 0, y: 100, z: 20, rx: 0, ry: 0, s: 1, zIndex: n + 1, opacity: 1, isActive: true });
|
|
@@ -232,33 +301,31 @@ function createFolderGallery(root, options = {}) {
|
|
|
232
301
|
}
|
|
233
302
|
function layoutGrid() {
|
|
234
303
|
const sceneW = scene.clientWidth || MODE_WIDTHS.grid;
|
|
235
|
-
const
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
const
|
|
240
|
-
const
|
|
241
|
-
const scaledH = cardH * sc;
|
|
242
|
-
const tabScaled = 22 * sc;
|
|
304
|
+
const gap = Number.isFinite(opts.grid && opts.grid.gap) ? opts.grid.gap : 16;
|
|
305
|
+
const cols = Math.max(1, Math.round(
|
|
306
|
+
opts.grid && opts.grid.columns ? opts.grid.columns : sceneW < 520 ? 2 : n <= 4 ? 2 : 3
|
|
307
|
+
));
|
|
308
|
+
const cellW = (sceneW - (cols - 1) * gap) / cols;
|
|
309
|
+
const cellH = cellW * (2 / 3);
|
|
243
310
|
const rows = Math.ceil(n / cols);
|
|
244
311
|
cardEls.forEach((card, i) => {
|
|
245
312
|
const col = i % cols;
|
|
246
313
|
const row = Math.floor(i / cols);
|
|
247
314
|
const itemsInRow = Math.min(cols, n - row * cols);
|
|
248
|
-
const rowW = itemsInRow *
|
|
315
|
+
const rowW = itemsInRow * cellW + (itemsInRow - 1) * gap;
|
|
249
316
|
const rowStartX = (sceneW - rowW) / 2;
|
|
250
|
-
const
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
setCardTransform(card, { x: tx, y: ty, z: 0, rx: 0, ry: 0, s: sc, zIndex: i === active ? 2 : 1, opacity: 1, isActive: i === active });
|
|
317
|
+
const x = rowStartX + col * (cellW + gap);
|
|
318
|
+
const y = row * (cellH + gap);
|
|
319
|
+
card.style.width = cellW + "px";
|
|
320
|
+
setCardTransform(card, { x, y, z: 0, rx: 0, ry: 0, s: 1, zIndex: i === active ? 2 : 1, opacity: 1, isActive: i === active });
|
|
255
321
|
});
|
|
256
|
-
scene.style.height = rows *
|
|
322
|
+
scene.style.height = rows * cellH + (rows - 1) * gap + "px";
|
|
257
323
|
}
|
|
258
324
|
function layoutCarousel() {
|
|
259
325
|
const sceneW = scene.clientWidth || MODE_WIDTHS.carousel;
|
|
260
326
|
const cardW = sceneW;
|
|
261
327
|
const cardH = cardW * (2 / 3);
|
|
328
|
+
cardEls.forEach(clearGridWidth);
|
|
262
329
|
const activeSc = 0.62;
|
|
263
330
|
const activeW = cardW * activeSc;
|
|
264
331
|
const sceneH = Math.max(cardH * activeSc + 40, 180);
|
|
@@ -293,26 +360,30 @@ function createFolderGallery(root, options = {}) {
|
|
|
293
360
|
live.textContent = cur && cur.label ? `${active + 1} of ${n}: ${cur.label}` : `${active + 1} of ${n}`;
|
|
294
361
|
}
|
|
295
362
|
function goTo(i) {
|
|
296
|
-
|
|
363
|
+
if (destroyed) return;
|
|
364
|
+
const t = Number.isFinite(+i) ? Math.trunc(+i) : active;
|
|
365
|
+
const next = opts.loop ? (t % n + n) % n : Math.min(Math.max(t, 0), n - 1);
|
|
297
366
|
if (next === active) return;
|
|
298
367
|
active = next;
|
|
299
368
|
applyLayout();
|
|
300
369
|
emit("fg-activechange", { index: active, item: items[active] });
|
|
301
370
|
}
|
|
302
371
|
function select(i) {
|
|
372
|
+
if (destroyed) return;
|
|
303
373
|
emit("fg-select", { index: i, item: items[i] });
|
|
304
374
|
if (typeof opts.onSelect === "function") opts.onSelect(items[i], i);
|
|
305
375
|
}
|
|
306
376
|
function setMode(m) {
|
|
307
|
-
if (m === mode || !MODE_WIDTHS[m]) return;
|
|
377
|
+
if (destroyed || m === mode || !MODE_WIDTHS[m]) return;
|
|
308
378
|
mode = m;
|
|
309
379
|
root.setAttribute("data-fg-mode", mode);
|
|
310
380
|
applyLayout();
|
|
311
381
|
emit("fg-modechange", { mode });
|
|
312
382
|
}
|
|
313
383
|
function setPeek(p) {
|
|
314
|
-
if (!PEEK_MODES.has(p)) return;
|
|
384
|
+
if (destroyed || !PEEK_MODES.has(p) || p === root.getAttribute("data-fg-peek")) return;
|
|
315
385
|
root.setAttribute("data-fg-peek", p);
|
|
386
|
+
emit("fg-peekchange", { peek: p });
|
|
316
387
|
}
|
|
317
388
|
const dragEnabled = opts.drag !== "off";
|
|
318
389
|
let suppressClick = false;
|
|
@@ -387,7 +458,7 @@ function createFolderGallery(root, options = {}) {
|
|
|
387
458
|
scrollAccum = 0;
|
|
388
459
|
scrollCooldown = true;
|
|
389
460
|
goTo(active + dir);
|
|
390
|
-
|
|
461
|
+
later(() => {
|
|
391
462
|
scrollCooldown = false;
|
|
392
463
|
scrollAccum = 0;
|
|
393
464
|
}, SCROLL_COOLDOWN[mode] || 300);
|
|
@@ -476,8 +547,11 @@ function createFolderGallery(root, options = {}) {
|
|
|
476
547
|
card.style.transform = dragBase;
|
|
477
548
|
return;
|
|
478
549
|
}
|
|
550
|
+
const semantic = dir > 0 ? "next" : "prev";
|
|
551
|
+
emit("fg-flingstart", { index: active, direction: semantic });
|
|
479
552
|
if (reduced) {
|
|
480
553
|
goTo(target);
|
|
554
|
+
emit("fg-flingend", { index: target, direction: semantic });
|
|
481
555
|
return;
|
|
482
556
|
}
|
|
483
557
|
const offX = horizontal ? Math.sign(dragDX) * Math.max(window.innerWidth * 0.7, 480) : dragDX * 3;
|
|
@@ -486,7 +560,7 @@ function createFolderGallery(root, options = {}) {
|
|
|
486
560
|
card.style.transform = `${dragBase} translate3d(${offX}px, ${offY}px, 40px) rotate(${Math.sign(dragDX || 1) * 18}deg)`;
|
|
487
561
|
card.style.opacity = "0";
|
|
488
562
|
goTo(target);
|
|
489
|
-
|
|
563
|
+
later(() => {
|
|
490
564
|
card.classList.add("fg-card--snap");
|
|
491
565
|
card.classList.remove("fg-card--flung");
|
|
492
566
|
applyLayout();
|
|
@@ -494,12 +568,15 @@ function createFolderGallery(root, options = {}) {
|
|
|
494
568
|
const slotOpacity = card.style.opacity;
|
|
495
569
|
card.style.transform = `${slot} translate3d(0, -90px, 0)`;
|
|
496
570
|
card.style.opacity = "0";
|
|
497
|
-
|
|
571
|
+
frame(() => frame(() => {
|
|
498
572
|
card.classList.remove("fg-card--snap");
|
|
499
573
|
card.classList.add("fg-card--entering");
|
|
500
574
|
card.style.transform = slot;
|
|
501
575
|
card.style.opacity = slotOpacity;
|
|
502
|
-
|
|
576
|
+
later(() => {
|
|
577
|
+
card.classList.remove("fg-card--entering");
|
|
578
|
+
emit("fg-flingend", { index: target, direction: semantic });
|
|
579
|
+
}, 700);
|
|
503
580
|
}));
|
|
504
581
|
}, 400);
|
|
505
582
|
};
|
|
@@ -509,23 +586,52 @@ function createFolderGallery(root, options = {}) {
|
|
|
509
586
|
let resizeTimer;
|
|
510
587
|
on(window, "resize", () => {
|
|
511
588
|
clearTimeout(resizeTimer);
|
|
512
|
-
resizeTimer =
|
|
589
|
+
resizeTimer = later(applyLayout, 150);
|
|
513
590
|
});
|
|
591
|
+
if (reducedQuery && reducedQuery.addEventListener) {
|
|
592
|
+
on(reducedQuery, "change", (e) => {
|
|
593
|
+
if (!destroyed) {
|
|
594
|
+
reduced = e.matches;
|
|
595
|
+
applyLayout();
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
}
|
|
514
599
|
applyLayout();
|
|
515
|
-
|
|
600
|
+
const handle = {
|
|
516
601
|
next: () => goTo(active + 1),
|
|
517
602
|
prev: () => goTo(active - 1),
|
|
518
603
|
goTo,
|
|
519
604
|
setMode,
|
|
520
605
|
setPeek,
|
|
606
|
+
setColor: (i, hex) => {
|
|
607
|
+
const card = cardEls[i];
|
|
608
|
+
if (card && !destroyed) paintFolder(card, hex);
|
|
609
|
+
},
|
|
610
|
+
setGradient: (i, gradient) => {
|
|
611
|
+
const card = cardEls[i];
|
|
612
|
+
if (card && !destroyed) paintGradient(card, gradient);
|
|
613
|
+
},
|
|
521
614
|
getActiveIndex: () => active,
|
|
522
615
|
getMode: () => mode,
|
|
616
|
+
getPeek: () => root.getAttribute("data-fg-peek"),
|
|
617
|
+
getColor: (i) => {
|
|
618
|
+
const card = cardEls[i];
|
|
619
|
+
return card ? card.style.getPropertyValue("--fg-folder-bg") || void 0 : void 0;
|
|
620
|
+
},
|
|
621
|
+
getGradient: (i) => {
|
|
622
|
+
const layer = cardEls[i] && cardEls[i].querySelector(".fg-gradient");
|
|
623
|
+
return layer ? layer.style.background || void 0 : void 0;
|
|
624
|
+
},
|
|
625
|
+
getItems: () => items.slice(),
|
|
523
626
|
destroy: teardown
|
|
524
627
|
};
|
|
628
|
+
INSTANCES.set(root, teardown);
|
|
629
|
+
return handle;
|
|
525
630
|
}
|
|
526
631
|
var folder_gallery_default = createFolderGallery;
|
|
527
632
|
// Annotate the CommonJS export names for ESM import in node:
|
|
528
633
|
0 && (module.exports = {
|
|
634
|
+
FOLDER_PATHS,
|
|
529
635
|
createFolderGallery
|
|
530
636
|
});
|
|
531
637
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/folder-gallery.js"],"sourcesContent":["/* ============================================================================\n * folder-gallery - a framework-agnostic 3D folder gallery (core, v0.1.0, WIP)\n *\n * import { createFolderGallery } from 'folder-gallery';\n * import 'folder-gallery/styles.css';\n *\n * const gallery = createFolderGallery(rootEl, {\n * items: [{ label, color, src }, ...], // or { content: Node | html }\n * mode: 'stack', // 'stack' | 'grid' | 'carousel'\n * onSelect: (item, index) => { ... },\n * });\n * gallery.next(); gallery.setMode('grid'); gallery.destroy();\n *\n * Ported from a hand-built portfolio engine. No framework, no dependencies.\n * Owns its own DOM and removes every listener on destroy().\n * ========================================================================== */\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\n\n/* Default manila-folder-with-tab silhouette (viewBox 0 0 480 342). */\nconst DEFAULT_FOLDER_PATH =\n 'M 0 22 C 0 10 10 0 22 0 L 155 0 C 168 0 172 6 176 14 C 180 24 188 32 204 32 ' +\n 'L 458 32 C 470 32 480 42 480 54 L 480 320 C 480 332 470 342 458 342 ' +\n 'L 22 342 C 10 342 0 332 0 320 Z';\n\nconst DEFAULTS = {\n mode: 'stack', // 'stack' | 'grid' | 'carousel'\n folderPath: DEFAULT_FOLDER_PATH,\n loop: true,\n scrollNav: true,\n reducedMotion: 'auto', // 'auto' | 'off' | 'force'\n peek: 'hover', // 'hover' | 'always' | 'off'\n drag: 'fling', // 'fling' | 'off' - grab the active folder and throw it (stack mode)\n defaultActiveIndex: 0,\n label: 'Folder gallery',\n};\n\nconst PEEK_MODES = new Set(['hover', 'always', 'off']);\nconst DRAG_MODES = new Set(['fling', 'off']);\n\nconst MODE_WIDTHS = { stack: 480, grid: 720, carousel: 720 };\nconst SCROLL_THRESHOLD = 30;\nconst SCROLL_COOLDOWN = { stack: 450, carousel: 300 };\n\nfunction hexToRgb(hex) {\n const h = String(hex).replace('#', '');\n return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];\n}\n/* Derive the folder's three surfaces from one base color (same offsets as the\n * original engine): back/tab −30, frosted front +40 at 0.55, solid front +35.\n * The solid variant is what keeps NON-active cards fully opaque - only the\n * active card gets the translucent frosted treatment. Also picks a label\n * color (white or ink) by the frontSolid surface's YIQ brightness, so a\n * dark folder color doesn't leave the label unreadable regardless of theme. */\nfunction folderColors(hex) {\n const [r, g, b] = hexToRgb(hex);\n const dn = (v) => Math.max(v - 30, 0);\n const up = (v, o) => Math.min(v + o, 255);\n const fr = up(r, 35);\n const fg = up(g, 35);\n const fb = up(b, 35);\n const yiq = (fr * 299 + fg * 587 + fb * 114) / 1000;\n return {\n back: `rgb(${dn(r)},${dn(g)},${dn(b)})`,\n front: `rgba(${up(r, 40)},${up(g, 40)},${up(b, 40)},0.55)`,\n frontSolid: `rgb(${fr},${fg},${fb})`,\n label: yiq >= 128 ? '#1c1c1a' : '#ffffff',\n };\n}\n\n/* Built-in default content renderer. Accepts item.content (a Node or HTML\n * string) or item.src (an image). Consumers pass their own contentRenderer\n * (card, item, index) to hold arbitrary content - that's the whole point. */\nfunction defaultContentRenderer(card, item /* , index */) {\n const wrap = document.createElement('div');\n wrap.className = 'fg-content';\n // Duck-type DOM nodes (nodeType) rather than `instanceof Node` - `Node`\n // isn't a global in every embedding (SSR shims, minimal DOM harnesses).\n if (item.content && typeof item.content === 'object' && typeof item.content.nodeType === 'number') {\n wrap.appendChild(item.content);\n } else if (typeof item.content === 'string') {\n wrap.innerHTML = item.content;\n } else if (item.src) {\n const img = document.createElement('img');\n img.className = 'fg-image';\n img.src = item.src;\n img.alt = item.label || '';\n img.loading = 'lazy';\n img.decoding = 'async';\n wrap.appendChild(img);\n }\n card.appendChild(wrap);\n}\n\nexport function createFolderGallery(root, options = {}) {\n if (!root || !root.nodeType) throw new Error('createFolderGallery: a root element is required');\n\n const opts = { ...DEFAULTS, ...options };\n const items = Array.isArray(opts.items) ? opts.items : [];\n const n = items.length;\n const renderContent =\n typeof opts.contentRenderer === 'function' ? opts.contentRenderer : defaultContentRenderer;\n\n const reduced =\n opts.reducedMotion === 'force' ||\n (opts.reducedMotion !== 'off' &&\n typeof matchMedia === 'function' &&\n matchMedia('(prefers-reduced-motion: reduce)').matches);\n\n let mode = MODE_WIDTHS[opts.mode] ? opts.mode : 'stack';\n let active = Math.min(Math.max(opts.defaultActiveIndex | 0, 0), Math.max(n - 1, 0));\n let scrollCooldown = false;\n let scrollAccum = 0;\n\n /* ── Listener bookkeeping for destroy() ── */\n const cleanups = [];\n const on = (el, ev, fn, o) => { el.addEventListener(ev, fn, o); cleanups.push(() => el.removeEventListener(ev, fn, o)); };\n const emit = (name, detail) => root.dispatchEvent(new CustomEvent(name, { detail, bubbles: true }));\n\n /* ── Build own DOM (no page scaffold assumed) ── */\n root.classList.add('fg-root');\n root.setAttribute('data-fg-mode', mode);\n root.setAttribute('data-fg-peek', PEEK_MODES.has(opts.peek) ? opts.peek : 'hover');\n root.setAttribute('data-fg-drag', DRAG_MODES.has(opts.drag) ? opts.drag : 'fling');\n const scene = document.createElement('div');\n scene.className = 'fg-scene';\n scene.setAttribute('role', 'listbox');\n scene.setAttribute('aria-label', opts.label);\n scene.setAttribute('aria-roledescription', 'folder gallery');\n const dotsEl = document.createElement('div');\n dotsEl.className = 'fg-dots';\n dotsEl.setAttribute('role', 'tablist');\n const live = document.createElement('div');\n live.className = 'fg-sr-only';\n live.setAttribute('aria-live', 'polite');\n live.setAttribute('aria-atomic', 'true');\n root.append(scene, dotsEl, live);\n\n function teardown() {\n cleanups.forEach((fn) => fn());\n cleanups.length = 0;\n root.replaceChildren();\n root.classList.remove('fg-root');\n root.removeAttribute('data-fg-mode');\n root.removeAttribute('data-fg-peek');\n root.removeAttribute('data-fg-drag');\n }\n\n if (n === 0) {\n return { next() {}, prev() {}, goTo() {}, setMode() {}, setPeek() {}, getActiveIndex: () => -1, getMode: () => mode, destroy: teardown };\n }\n\n /* ── Normalized transform - identical function list for every mode ── */\n function setCardTransform(card, { x, y, z, rx, ry, s, zIndex, opacity, isActive }) {\n /* A card mid-throw owns its own motion: layout updates its role\n (selection, stacking) but leaves transform and opacity to the fling,\n so the pile can shuffle immediately while the thrown folder finishes\n its flight. The fling handler relayouts it once it has faded out. */\n if (!card.classList.contains('fg-card--flung')) {\n card.style.transform = `translate3d(${x}px,${y}px,${z}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${s})`;\n card.style.opacity = String(opacity);\n }\n card.style.transformOrigin = 'center bottom';\n card.style.zIndex = String(zIndex);\n card.setAttribute('aria-selected', isActive ? 'true' : 'false');\n card.classList.toggle('is-active', isActive);\n }\n\n /* ── Build cards ── */\n const cardEls = items.map((item, i) => {\n const card = document.createElement('div');\n card.className = 'fg-card';\n card.tabIndex = i === active ? 0 : -1; // roving tabindex\n card.setAttribute('role', 'option');\n card.setAttribute('aria-label', item.label || `Item ${i + 1}`);\n if (item.color) {\n const c = folderColors(item.color);\n card.style.setProperty('--fg-folder-bg', item.color);\n card.style.setProperty('--fg-front', c.front);\n card.style.setProperty('--fg-front-solid', c.frontSolid);\n card.style.setProperty('--fg-label-on-color', c.label);\n }\n\n const svg = document.createElementNS(SVG_NS, 'svg');\n svg.setAttribute('class', 'fg-folder');\n svg.setAttribute('viewBox', '0 0 480 342');\n svg.setAttribute('preserveAspectRatio', 'none');\n svg.setAttribute('aria-hidden', 'true');\n const path = document.createElementNS(SVG_NS, 'path');\n path.setAttribute('d', opts.folderPath);\n path.setAttribute('fill', item.color ? folderColors(item.color).back : 'var(--fg-folder-bg)');\n svg.appendChild(path);\n\n card.appendChild(svg);\n\n renderContent(card, item, i);\n\n const front = document.createElement('div');\n front.className = 'fg-front';\n /* Decal: the photo prints on the folder's FRONT PANEL. The back and tab\n keep their color, so the folder stays a folder: colored tabs in the\n stack, a real material boundary at the front's lip. */\n if (item.decal) {\n card.classList.add('fg-card--decal');\n const photo = document.createElement('img');\n photo.className = 'fg-decal';\n photo.src = item.decal;\n photo.alt = '';\n photo.loading = 'lazy';\n photo.decoding = 'async';\n front.appendChild(photo);\n }\n if (item.label) {\n const label = document.createElement('div');\n label.className = 'fg-label';\n label.textContent = item.label;\n front.appendChild(label);\n }\n card.appendChild(front);\n\n scene.appendChild(card);\n return card;\n });\n\n /* ── Dots ── */\n const dots = cardEls.map((_, i) => {\n const dot = document.createElement('button');\n dot.type = 'button';\n dot.className = 'fg-dot';\n dot.setAttribute('role', 'tab');\n dot.setAttribute('aria-label', items[i].label || `Go to ${i + 1}`);\n on(dot, 'click', () => goTo(i));\n dotsEl.appendChild(dot);\n return dot;\n });\n\n /* ── Layouts ── */\n function layoutStack() {\n scene.style.height = '';\n cardEls.forEach((card, i) => {\n const behind = (i - active + n) % n;\n if (behind === 0) {\n setCardTransform(card, { x: 0, y: 100, z: 20, rx: 0, ry: 0, s: 1, zIndex: n + 1, opacity: 1, isActive: true });\n return;\n }\n const safeN = Math.max(n - 1, 1);\n const tz = -behind * 25 - behind * behind * 3;\n const rx = reduced ? 0 : -behind * 3;\n const ty = 100 - behind * 28 - behind * behind * 2;\n const sc = 1 - behind * 0.06 - (behind / safeN) * (behind / safeN) * 0.04;\n setCardTransform(card, { x: 0, y: ty, z: tz, rx, ry: 0, s: Math.max(sc, 0.5), zIndex: n - behind, opacity: 1 - behind * 0.08, isActive: false });\n });\n }\n function layoutGrid() {\n const sceneW = scene.clientWidth || MODE_WIDTHS.grid;\n // Two columns on narrow scenes so folders stay tappable and readable.\n const cols = sceneW < 520 ? 2 : n <= 4 ? 2 : 3;\n const gap = 16;\n const cardW = sceneW;\n const cardH = sceneW * (2 / 3);\n const sc = (sceneW - (cols - 1) * gap) / (cols * cardW);\n const scaledW = cardW * sc;\n const scaledH = cardH * sc;\n const tabScaled = 22 * sc;\n const rows = Math.ceil(n / cols);\n cardEls.forEach((card, i) => {\n const col = i % cols;\n const row = Math.floor(i / cols);\n const itemsInRow = Math.min(cols, n - row * cols);\n const rowW = itemsInRow * scaledW + (itemsInRow - 1) * gap;\n const rowStartX = (sceneW - rowW) / 2;\n const cellLeft = rowStartX + col * (scaledW + gap);\n const cellTop = row * (scaledH + tabScaled + gap) + tabScaled;\n const tx = cellLeft + scaledW / 2 - cardW / 2;\n const ty = cellTop + scaledH - cardH;\n setCardTransform(card, { x: tx, y: ty, z: 0, rx: 0, ry: 0, s: sc, zIndex: i === active ? 2 : 1, opacity: 1, isActive: i === active });\n });\n scene.style.height = rows * (scaledH + tabScaled + gap) + 20 + 'px';\n }\n function layoutCarousel() {\n const sceneW = scene.clientWidth || MODE_WIDTHS.carousel;\n const cardW = sceneW;\n const cardH = cardW * (2 / 3);\n const activeSc = 0.62;\n const activeW = cardW * activeSc;\n const sceneH = Math.max(cardH * activeSc + 40, 180);\n scene.style.height = sceneH + 'px';\n const offsetStep = Math.min(130, (sceneW - activeW) / 4);\n cardEls.forEach((card, i) => {\n let offset = i - active;\n if (n > 2 && offset > Math.floor(n / 2)) offset -= n;\n if (n > 2 && offset < -Math.floor(n / 2)) offset += n;\n const sc = Math.max(activeSc - Math.abs(offset) * 0.06, 0.28);\n const z = -Math.abs(offset) * 50;\n const op = Math.max(1 - Math.abs(offset) * 0.25, 0.15);\n const tx = sceneW / 2 + offset * offsetStep - cardW / 2;\n const ty = sceneH - 20 - cardH;\n setCardTransform(card, { x: tx, y: ty, z, rx: 0, ry: 0, s: sc, zIndex: n - Math.abs(offset), opacity: op, isActive: offset === 0 });\n });\n }\n // Scene width tracks the active mode so the layout math (which assumes the\n // mode's logical width) matches the actually-rendered card width. Layouts\n // then read scene.clientWidth, so everything stays self-consistent at any size.\n function sizeScene() {\n scene.style.width = `min(${MODE_WIDTHS[mode]}px, 92vw)`;\n }\n function applyLayout() {\n sizeScene();\n (mode === 'grid' ? layoutGrid : mode === 'carousel' ? layoutCarousel : layoutStack)();\n dots.forEach((d, i) => {\n d.classList.toggle('is-active', i === active);\n d.setAttribute('aria-selected', i === active ? 'true' : 'false');\n });\n cardEls.forEach((c, i) => { c.tabIndex = i === active ? 0 : -1; });\n const cur = items[active];\n live.textContent = cur && cur.label ? `${active + 1} of ${n}: ${cur.label}` : `${active + 1} of ${n}`;\n }\n\n /* ── Navigation ── */\n function goTo(i) {\n const next = opts.loop ? ((i % n) + n) % n : Math.min(Math.max(i, 0), n - 1);\n if (next === active) return;\n active = next;\n applyLayout();\n emit('fg-activechange', { index: active, item: items[active] });\n }\n function select(i) {\n emit('fg-select', { index: i, item: items[i] });\n if (typeof opts.onSelect === 'function') opts.onSelect(items[i], i);\n }\n function setMode(m) {\n if (m === mode || !MODE_WIDTHS[m]) return;\n mode = m;\n root.setAttribute('data-fg-mode', mode);\n applyLayout();\n emit('fg-modechange', { mode });\n }\n function setPeek(p) {\n if (!PEEK_MODES.has(p)) return;\n root.setAttribute('data-fg-peek', p);\n }\n\n /* ── Interaction ── */\n const dragEnabled = opts.drag !== 'off';\n let suppressClick = false; // a real drag eats the click that follows pointerup\n\n cardEls.forEach((card, i) => {\n on(card, 'click', () => {\n if (suppressClick) { suppressClick = false; return; }\n i === active ? select(i) : goTo(i);\n });\n on(card, 'keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); select(i); }\n });\n });\n /* Arrow keys work two ways, matching the reference implementation:\n 1. Focus already inside the gallery (Tab to a card/dot) - bubbles here\n and re-focuses the new active card, standard roving-tabindex UX.\n 2. Mouse hovering the gallery, focus anywhere else on the page - a\n document-level listener picks it up. Without this route, arrow\n keys only work AFTER a click puts focus on a card - and a click is\n also what fires onSelect, which in real use is often a link. Making\n keyboard nav depend on that first click means the only way to\n \"activate\" arrows is to risk navigating away. Hover is enough. */\n function handleArrowKeys(e) {\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') { e.preventDefault(); goTo(active + 1); return true; }\n if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') { e.preventDefault(); goTo(active - 1); return true; }\n if (e.key === 'Home') { e.preventDefault(); goTo(0); return true; }\n if (e.key === 'End') { e.preventDefault(); goTo(n - 1); return true; }\n return false;\n }\n on(scene, 'keydown', (e) => { if (handleArrowKeys(e)) cardEls[active].focus(); });\n on(dotsEl, 'keydown', (e) => { if (handleArrowKeys(e)) cardEls[active].focus(); });\n\n let hovered = false;\n on(root, 'mouseenter', () => { hovered = true; });\n on(root, 'mouseleave', () => { hovered = false; });\n on(document, 'keydown', (e) => {\n if (!hovered) return;\n // Don't hijack arrows if focus is on an interactive control outside\n // the gallery (nav link, a form field elsewhere on the page).\n const ae = document.activeElement;\n if (ae && ae !== document.body && !root.contains(ae)) return;\n handleArrowKeys(e); // no forced focus - the user hasn't tabbed in\n });\n\n if (opts.scrollNav) {\n /* Bound to root, not just the scene box: root is the widget's full\n footprint (scene + dots), so wheel events over the dots row or any\n gap the consumer's own layout leaves around the gallery still cycle\n it, instead of requiring the pointer over the exact folder art. */\n on(root, 'wheel', (e) => {\n if (mode === 'grid') return;\n const atStart = !opts.loop && active === 0 && e.deltaY < 0;\n const atEnd = !opts.loop && active === n - 1 && e.deltaY > 0;\n if (atStart || atEnd) return;\n e.preventDefault();\n if (scrollCooldown) return;\n scrollAccum += e.deltaY;\n if (Math.abs(scrollAccum) >= SCROLL_THRESHOLD) {\n const dir = scrollAccum > 0 ? 1 : -1;\n scrollAccum = 0;\n scrollCooldown = true;\n goTo(active + dir);\n setTimeout(() => { scrollCooldown = false; scrollAccum = 0; }, SCROLL_COOLDOWN[mode] || 300);\n }\n }, { passive: false });\n }\n\n /* Dominant-axis swipe: up or left advances, down or right goes back.\n Horizontal is the natural phone gesture in carousel; vertical matches\n the wheel direction on the stack. Both work everywhere. */\n let touchStartX = 0;\n let touchStartY = 0;\n on(scene, 'touchstart', (e) => {\n touchStartX = e.touches[0].clientX;\n touchStartY = e.touches[0].clientY;\n }, { passive: true });\n on(scene, 'touchend', (e) => {\n // In stack mode the pointer-based drag below owns the gesture; letting\n // both fire would advance twice per swipe.\n if (dragEnabled && mode === 'stack') return;\n const dx = touchStartX - e.changedTouches[0].clientX;\n const dy = touchStartY - e.changedTouches[0].clientY;\n const ax = Math.abs(dx);\n const ay = Math.abs(dy);\n if (Math.max(ax, ay) < 40) return;\n const dir = ax > ay ? (dx > 0 ? 1 : -1) : (dy > 0 ? 1 : -1);\n goTo(active + dir);\n }, { passive: true });\n\n /* ── Drag: grab the active folder and throw it (stack mode) ──\n Pointer Events give one code path for mouse, touch, and pen. The\n gesture constants come from the folder-deck prototype this feature is\n ported from: rotation follows the drag at 0.04deg/px, a release past\n 90px of travel (or a genuine throw, over 0.5px/ms) flings the folder\n off along the dominant axis and advances; anything shorter springs\n back into the pile on the card's own transition. Direction keeps the\n swipe semantics: left or up is next, right or down is previous. */\n if (dragEnabled) {\n const DRAG_ROT = 0.04;\n const FLING_DIST = 90;\n const FLING_VEL = 0.5;\n const TAP_SLOP = 6;\n let dragCard = null;\n let dragBase = '';\n let startPX = 0, startPY = 0, dragDX = 0, dragDY = 0;\n let lastX = 0, lastY = 0, lastT = 0, velX = 0, velY = 0;\n\n on(scene, 'pointerdown', (e) => {\n if (mode !== 'stack') return;\n if (e.button !== undefined && e.button !== 0) return;\n const card = e.target && e.target.closest ? e.target.closest('.fg-card') : null;\n if (!card || !card.classList.contains('is-active')) return;\n dragCard = card;\n dragBase = card.style.transform;\n startPX = e.clientX; startPY = e.clientY;\n dragDX = 0; dragDY = 0;\n lastX = e.clientX; lastY = e.clientY;\n lastT = (typeof performance !== 'undefined' ? performance.now() : Date.now());\n velX = 0; velY = 0;\n card.classList.add('fg-card--dragging');\n if (card.setPointerCapture && e.pointerId !== undefined) {\n try { card.setPointerCapture(e.pointerId); } catch (_) { /* jsdom / detached */ }\n }\n });\n on(window, 'pointermove', (e) => {\n if (!dragCard) return;\n dragDX = e.clientX - startPX;\n dragDY = e.clientY - startPY;\n const now = (typeof performance !== 'undefined' ? performance.now() : Date.now());\n const dt = Math.max(now - lastT, 1);\n velX = (e.clientX - lastX) / dt;\n velY = (e.clientY - lastY) / dt;\n lastX = e.clientX; lastY = e.clientY; lastT = now;\n // translateZ lifts the grabbed folder clear of every plane in the\n // pile (tilted tops can poke past the active card's resting depth)\n // and reads as physically picking it up.\n dragCard.style.transform = `${dragBase} translate3d(${dragDX}px, ${dragDY}px, 40px) rotate(${(dragDX * DRAG_ROT).toFixed(2)}deg)`;\n });\n const endDrag = () => {\n if (!dragCard) return;\n const card = dragCard;\n dragCard = null;\n card.classList.remove('fg-card--dragging');\n const dist = Math.hypot(dragDX, dragDY);\n if (dist < TAP_SLOP) { card.style.transform = dragBase; return; } // a tap: the click handler owns it\n suppressClick = true;\n const horizontal = Math.abs(dragDX) >= Math.abs(dragDY);\n const flung = dist > FLING_DIST || Math.hypot(velX, velY) > FLING_VEL;\n const dir = horizontal ? (dragDX > 0 ? -1 : 1) : (dragDY > 0 ? -1 : 1);\n const target = active + dir;\n const blocked = !opts.loop && (target < 0 || target > n - 1);\n if (!flung || blocked) { card.style.transform = dragBase; return; } // spring back into the pile\n if (reduced) { goTo(target); return; }\n const offX = horizontal ? Math.sign(dragDX) * Math.max(window.innerWidth * 0.7, 480) : dragDX * 3;\n const offY = horizontal ? dragDY * 3 : Math.sign(dragDY) * Math.max(window.innerHeight * 0.7, 480);\n /* Choreography: the pile answers the throw IMMEDIATELY (goTo below;\n layout skips the flung card), while the thrown folder finishes its\n own flight - a longer, momentum-eased sail that fades over 340ms.\n Once it is fully invisible, it re-enters by DROPPING IN from above\n its new slot: never straight from off-screen, which would cross\n the other folders' 3D planes and slice them visibly. */\n card.classList.add('fg-card--flung');\n card.style.transform = `${dragBase} translate3d(${offX}px, ${offY}px, 40px) rotate(${Math.sign(dragDX || 1) * 18}deg)`;\n card.style.opacity = '0';\n goTo(target); // shuffle starts now; the flung card is exempt from this relayout\n setTimeout(() => {\n card.classList.add('fg-card--snap');\n card.classList.remove('fg-card--flung');\n applyLayout(); // now it takes its slot transform (invisible, transitions off)\n const slot = card.style.transform;\n const slotOpacity = card.style.opacity;\n card.style.transform = `${slot} translate3d(0, -90px, 0)`;\n card.style.opacity = '0';\n /* Phase boundary via double rAF, NOT a synchronous reflow flush:\n WebKit does not treat forced reflows as transition boundaries and\n will compute the transition from the last PAINTED state (the\n fling-off position), which flashes the card across the pile.\n Painting one real frame at the staging point (invisible,\n transitions off) gives every engine the same before-state. */\n requestAnimationFrame(() => requestAnimationFrame(() => {\n card.classList.remove('fg-card--snap');\n card.classList.add('fg-card--entering'); // quicker settle curve for the drop\n card.style.transform = slot; // descend into the pile\n card.style.opacity = slotOpacity;\n setTimeout(() => card.classList.remove('fg-card--entering'), 700);\n }));\n }, 400); // after the 340ms flung fade, with margin: never snap a visible card\n };\n on(window, 'pointerup', endDrag);\n on(window, 'pointercancel', endDrag);\n }\n\n let resizeTimer;\n on(window, 'resize', () => { clearTimeout(resizeTimer); resizeTimer = setTimeout(applyLayout, 150); });\n\n applyLayout();\n\n /* ── Public handle ── */\n return {\n next: () => goTo(active + 1),\n prev: () => goTo(active - 1),\n goTo,\n setMode,\n setPeek,\n getActiveIndex: () => active,\n getMode: () => mode,\n destroy: teardown,\n };\n}\n\nexport default createFolderGallery;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/folder-gallery.js"],"sourcesContent":["/* ============================================================================\n * flipfolio - a framework-agnostic 3D folder gallery (core)\n *\n * import { createFolderGallery } from 'flipfolio';\n * import 'flipfolio/styles.css';\n *\n * const gallery = createFolderGallery(rootEl, {\n * items: [{ label, color, src }, ...], // or { content: Node | html }\n * mode: 'stack', // 'stack' | 'grid' | 'carousel'\n * onSelect: (item, index) => { ... },\n * });\n * gallery.next(); gallery.setMode('grid'); gallery.destroy();\n *\n * Ported from a hand-built portfolio engine. No framework, no dependencies.\n * Owns its own DOM and removes every listener on destroy().\n * ========================================================================== */\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\n\n/* Default manila-folder-with-tab silhouette (viewBox 0 0 480 342). */\nconst DEFAULT_FOLDER_PATH =\n 'M 0 22 C 0 10 10 0 22 0 L 155 0 C 168 0 172 6 176 14 C 180 24 188 32 204 32 ' +\n 'L 458 32 C 470 32 480 42 480 54 L 480 320 C 480 332 470 342 458 342 ' +\n 'L 22 342 C 10 342 0 332 0 320 Z';\n\n/* A right-side tab is the default mirrored across the viewBox midline; a tabless\n * tray drops the tab notch entirely. Consumers pass one as `folderPath` instead\n * of hand-authoring an SVG path. The default (left tab) stays FOLDER_PATHS.left. */\nexport const FOLDER_PATHS = {\n left: DEFAULT_FOLDER_PATH,\n right:\n 'M 480 22 C 480 10 470 0 458 0 L 325 0 C 312 0 308 6 304 14 C 300 24 292 32 276 32 ' +\n 'L 22 32 C 10 32 0 42 0 54 L 0 320 C 0 332 10 342 22 342 ' +\n 'L 458 342 C 470 342 480 332 480 320 Z',\n tray:\n 'M 0 22 C 0 10 10 0 22 0 L 458 0 C 470 0 480 10 480 22 L 480 320 ' +\n 'C 480 332 470 342 458 342 L 22 342 C 10 342 0 332 0 320 Z',\n};\n\nconst DEFAULTS = {\n mode: 'stack', // 'stack' | 'grid' | 'carousel'\n folderPath: DEFAULT_FOLDER_PATH,\n loop: true,\n scrollNav: true,\n reducedMotion: 'auto', // 'auto' | 'off' | 'force'\n peek: 'hover', // 'hover' | 'always' | 'off'\n drag: 'fling', // 'fling' | 'off' - grab the active folder and throw it (stack mode)\n defaultActiveIndex: 0,\n label: 'Folder gallery',\n};\n\nconst PEEK_MODES = new Set(['hover', 'always', 'off']);\nconst DRAG_MODES = new Set(['fling', 'off']);\n\n/* Track the live instance per root so re-initializing the same element tears the\n * previous one down first (its window/document listeners are otherwise\n * unreachable and would leak, plus its DOM would be duplicated). */\nconst INSTANCES = new WeakMap();\n\nconst MODE_WIDTHS = { stack: 480, grid: 720, carousel: 720 };\nconst SCROLL_THRESHOLD = 30;\nconst SCROLL_COOLDOWN = { stack: 450, carousel: 300 };\n\n/* Parse #rgb or #rrggbb (with or without the hash) to [r,g,b]. Returns null for\n * anything else so callers can no-op instead of painting rgb(NaN,...) surfaces. */\nfunction hexToRgb(hex) {\n let h = String(hex).trim().replace(/^#/, '');\n if (h.length === 3) h = h.replace(/./g, (c) => c + c);\n if (!/^[0-9a-f]{6}$/i.test(h)) return null;\n return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];\n}\n/* Derive the folder's three surfaces from one base color (same offsets as the\n * original engine): back/tab −30, frosted front +40 at 0.55, solid front +35.\n * The solid variant is what keeps NON-active cards fully opaque - only the\n * active card gets the translucent frosted treatment. Also picks a label\n * color (white or ink) by the frontSolid surface's YIQ brightness, so a\n * dark folder color doesn't leave the label unreadable regardless of theme. */\nfunction folderColors(hex) {\n const rgb = hexToRgb(hex);\n if (!rgb) return null;\n const [r, g, b] = rgb;\n const dn = (v) => Math.max(v - 30, 0);\n const up = (v, o) => Math.min(v + o, 255);\n const fr = up(r, 35);\n const fg = up(g, 35);\n const fb = up(b, 35);\n const yiq = (fr * 299 + fg * 587 + fb * 114) / 1000;\n return {\n back: `rgb(${dn(r)},${dn(g)},${dn(b)})`,\n front: `rgba(${up(r, 40)},${up(g, 40)},${up(b, 40)},0.55)`,\n frontSolid: `rgb(${fr},${fg},${fb})`,\n label: yiq >= 128 ? '#1c1c1a' : '#ffffff',\n };\n}\n\n/* Paint a folder's whole palette from a single hex: the SVG back, the frosted\n * and solid front surfaces, and the auto-contrast label color. Shared by the\n * build-time pass and the runtime setColor() handle method so both derive the\n * palette identically. */\nfunction paintFolder(card, hex) {\n const c = folderColors(hex);\n if (!c) return; // ignore a malformed color rather than paint rgb(NaN,...)\n card.style.setProperty('--fg-folder-bg', hex);\n card.style.setProperty('--fg-front', c.front);\n card.style.setProperty('--fg-front-solid', c.frontSolid);\n card.style.setProperty('--fg-label-on-color', c.label);\n const path = card.querySelector('.fg-folder path');\n if (path) path.setAttribute('fill', c.back);\n}\n\n/* Paint a CSS gradient across the folder's front panel, beneath the label and\n * any peek contents. A falsy gradient clears it. */\nfunction paintGradient(card, gradient) {\n const front = card.querySelector('.fg-front');\n if (!front) return;\n let layer = front.querySelector('.fg-gradient');\n if (!gradient) {\n if (layer) layer.remove();\n card.classList.remove('fg-card--gradient');\n return;\n }\n if (!layer) {\n layer = document.createElement('div');\n layer.className = 'fg-gradient';\n layer.setAttribute('aria-hidden', 'true');\n front.insertBefore(layer, front.firstChild);\n }\n layer.style.background = gradient;\n card.classList.add('fg-card--gradient');\n}\n\n/* Built-in default content renderer. Accepts item.content (a Node or HTML\n * string) or item.src (an image). Consumers pass their own contentRenderer\n * (card, item, index) to hold arbitrary content - that's the whole point. */\nfunction defaultContentRenderer(card, item /* , index */) {\n const wrap = document.createElement('div');\n wrap.className = 'fg-content';\n // Duck-type DOM nodes (nodeType) rather than `instanceof Node` - `Node`\n // isn't a global in every embedding (SSR shims, minimal DOM harnesses).\n if (item.content && typeof item.content === 'object' && typeof item.content.nodeType === 'number') {\n wrap.appendChild(item.content);\n } else if (typeof item.content === 'string') {\n wrap.innerHTML = item.content;\n } else if (item.src) {\n const img = document.createElement('img');\n img.className = 'fg-image';\n img.src = item.src;\n img.alt = item.label || '';\n img.loading = 'lazy';\n img.decoding = 'async';\n wrap.appendChild(img);\n }\n card.appendChild(wrap);\n}\n\nexport function createFolderGallery(root, options = {}) {\n if (!root || root.nodeType !== 1) throw new Error('createFolderGallery: a root element is required');\n\n // Re-init on the same root: tear the old instance down so it can't leak.\n const prior = INSTANCES.get(root);\n if (prior) prior();\n\n // Drop undefined values before merging: a wrapper passing an unset prop\n // (loop, scrollNav, ...) as `undefined` must NOT clobber the real default.\n const provided = {};\n for (const k in options) if (options[k] !== undefined) provided[k] = options[k];\n const opts = { ...DEFAULTS, ...provided };\n const items = Array.isArray(opts.items) ? opts.items : [];\n const n = items.length;\n const renderContent =\n typeof opts.contentRenderer === 'function' ? opts.contentRenderer : defaultContentRenderer;\n\n const reducedQuery =\n opts.reducedMotion === 'auto' && typeof matchMedia === 'function'\n ? matchMedia('(prefers-reduced-motion: reduce)')\n : null;\n // `let` so an OS reduced-motion toggle after init re-syncs the JS motion\n // branches (fling short-circuit, stack tilt) with the CSS, which updates live.\n let reduced = opts.reducedMotion === 'force' || (reducedQuery ? reducedQuery.matches : false);\n\n let mode = MODE_WIDTHS[opts.mode] ? opts.mode : 'stack';\n let active = Math.min(Math.max(opts.defaultActiveIndex | 0, 0), Math.max(n - 1, 0));\n let scrollCooldown = false;\n let scrollAccum = 0;\n\n /* ── Listener bookkeeping for destroy() ── */\n const cleanups = [];\n const on = (el, ev, fn, o) => { el.addEventListener(ev, fn, o); cleanups.push(() => el.removeEventListener(ev, fn, o)); };\n const emit = (name, detail) => root.dispatchEvent(new CustomEvent(name, { detail, bubbles: true }));\n let destroyed = false;\n\n // Tracked timers/frames so teardown() can cancel anything the fling\n // choreography or the resize debounce has in flight (they mutate layout).\n const timers = new Set();\n const rafs = new Set();\n const later = (fn, ms) => { const id = setTimeout(() => { timers.delete(id); fn(); }, ms); timers.add(id); return id; };\n const frame = (fn) => { const id = requestAnimationFrame(() => { rafs.delete(id); fn(); }); rafs.add(id); return id; };\n\n /* ── Build own DOM (no page scaffold assumed) ── */\n root.classList.add('fg-root');\n root.setAttribute('data-fg-mode', mode);\n root.setAttribute('data-fg-peek', PEEK_MODES.has(opts.peek) ? opts.peek : 'hover');\n root.setAttribute('data-fg-drag', DRAG_MODES.has(opts.drag) ? opts.drag : 'fling');\n const scene = document.createElement('div');\n scene.className = 'fg-scene';\n scene.setAttribute('role', 'listbox');\n scene.setAttribute('aria-label', opts.label);\n scene.setAttribute('aria-roledescription', 'folder gallery');\n const dotsEl = document.createElement('div');\n dotsEl.className = 'fg-dots';\n dotsEl.setAttribute('role', 'tablist');\n const live = document.createElement('div');\n live.className = 'fg-sr-only';\n live.setAttribute('aria-live', 'polite');\n live.setAttribute('aria-atomic', 'true');\n root.append(scene, dotsEl, live);\n\n function teardown() {\n if (destroyed) return;\n destroyed = true;\n timers.forEach(clearTimeout); timers.clear();\n rafs.forEach(cancelAnimationFrame); rafs.clear();\n cleanups.forEach((fn) => fn());\n cleanups.length = 0;\n root.replaceChildren();\n root.classList.remove('fg-root');\n root.removeAttribute('data-fg-mode');\n root.removeAttribute('data-fg-peek');\n root.removeAttribute('data-fg-drag');\n INSTANCES.delete(root);\n }\n\n if (n === 0) {\n // Full no-op surface so an empty gallery matches the handle type: calling\n // any method (setColor, getItems, ...) is safe rather than a TypeError.\n const noop = () => {};\n INSTANCES.set(root, teardown);\n return {\n next: noop, prev: noop, goTo: noop, setMode: noop, setPeek: noop,\n setColor: noop, setGradient: noop,\n getActiveIndex: () => -1, getMode: () => mode,\n getPeek: () => root.getAttribute('data-fg-peek'),\n getColor: () => undefined, getGradient: () => undefined, getItems: () => [],\n destroy: teardown,\n };\n }\n\n /* ── Normalized transform - identical function list for every mode ── */\n function setCardTransform(card, { x, y, z, rx, ry, s, zIndex, opacity, isActive }) {\n /* A card mid-throw owns its own motion: layout updates its role\n (selection, stacking) but leaves transform and opacity to the fling,\n so the pile can shuffle immediately while the thrown folder finishes\n its flight. The fling handler relayouts it once it has faded out. */\n if (!card.classList.contains('fg-card--flung')) {\n card.style.transform = `translate3d(${x}px,${y}px,${z}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${s})`;\n card.style.opacity = String(opacity);\n }\n // transform-origin: center bottom is set once in CSS on .fg-card.\n card.style.zIndex = String(zIndex);\n card.setAttribute('aria-selected', isActive ? 'true' : 'false');\n card.classList.toggle('is-active', isActive);\n }\n\n /* ── Build cards ── */\n const cardEls = items.map((item, i) => {\n const card = document.createElement('div');\n card.className = 'fg-card';\n card.tabIndex = i === active ? 0 : -1; // roving tabindex\n card.setAttribute('role', 'option');\n card.setAttribute('aria-label', item.label || `Item ${i + 1}`);\n card.setAttribute('aria-setsize', String(n));\n card.setAttribute('aria-posinset', String(i + 1));\n card.setAttribute('data-fg-index', String(i)); // lets consumers target one folder in CSS/JS\n\n const svg = document.createElementNS(SVG_NS, 'svg');\n svg.setAttribute('class', 'fg-folder');\n svg.setAttribute('viewBox', '0 0 480 342');\n svg.setAttribute('preserveAspectRatio', 'none');\n svg.setAttribute('aria-hidden', 'true');\n const path = document.createElementNS(SVG_NS, 'path');\n path.setAttribute('d', opts.folderPath);\n path.setAttribute('fill', 'var(--fg-folder-bg)');\n svg.appendChild(path);\n\n card.appendChild(svg);\n\n renderContent(card, item, i);\n\n const front = document.createElement('div');\n front.className = 'fg-front';\n /* Decal: the photo prints on the folder's FRONT PANEL. The back and tab\n keep their color, so the folder stays a folder: colored tabs in the\n stack, a real material boundary at the front's lip. */\n if (item.decal) {\n card.classList.add('fg-card--decal');\n const photo = document.createElement('img');\n photo.className = 'fg-decal';\n photo.src = item.decal;\n photo.alt = '';\n photo.loading = 'lazy';\n photo.decoding = 'async';\n front.appendChild(photo);\n }\n if (item.label) {\n const label = document.createElement('div');\n label.className = 'fg-label';\n label.textContent = item.label;\n front.appendChild(label);\n }\n card.appendChild(front);\n\n // Palette + optional gradient front (both derive from item; paintFolder\n // needs the SVG path in place, so it runs after the folder is assembled).\n if (item.color) paintFolder(card, item.color);\n if (item.gradient) paintGradient(card, item.gradient);\n\n scene.appendChild(card);\n return card;\n });\n\n /* ── Dots ── */\n const dots = cardEls.map((_, i) => {\n const dot = document.createElement('button');\n dot.type = 'button';\n dot.className = 'fg-dot';\n dot.setAttribute('role', 'tab');\n dot.setAttribute('aria-label', items[i].label || `Go to ${i + 1}`);\n on(dot, 'click', () => goTo(i));\n dotsEl.appendChild(dot);\n return dot;\n });\n\n /* ── Layouts ── */\n // Grid renders each folder at its true cell width (not a full-scene card\n // scaled down), so absolute-unit content stays crisp and legible. Stack and\n // carousel use the full scene width, so they clear any grid width first.\n const clearGridWidth = (card) => { if (card.style.width) card.style.width = ''; };\n\n function layoutStack() {\n scene.style.height = '';\n cardEls.forEach((card, i) => {\n clearGridWidth(card);\n const behind = (i - active + n) % n;\n if (behind === 0) {\n setCardTransform(card, { x: 0, y: 100, z: 20, rx: 0, ry: 0, s: 1, zIndex: n + 1, opacity: 1, isActive: true });\n return;\n }\n const safeN = Math.max(n - 1, 1);\n const tz = -behind * 25 - behind * behind * 3;\n const rx = reduced ? 0 : -behind * 3;\n const ty = 100 - behind * 28 - behind * behind * 2;\n const sc = 1 - behind * 0.06 - (behind / safeN) * (behind / safeN) * 0.04;\n setCardTransform(card, { x: 0, y: ty, z: tz, rx, ry: 0, s: Math.max(sc, 0.5), zIndex: n - behind, opacity: 1 - behind * 0.08, isActive: false });\n });\n }\n function layoutGrid() {\n const sceneW = scene.clientWidth || MODE_WIDTHS.grid;\n const gap = Number.isFinite(opts.grid && opts.grid.gap) ? opts.grid.gap : 16;\n // A pinned column count wins; otherwise two columns on narrow scenes (so\n // folders stay tappable) or for small sets, three otherwise.\n const cols = Math.max(1, Math.round(\n opts.grid && opts.grid.columns ? opts.grid.columns : sceneW < 520 ? 2 : n <= 4 ? 2 : 3\n ));\n // Each card is sized to its cell and rendered at scale 1 (no shrink-to-blur),\n // so the folder art and any content inside read at their true size.\n const cellW = (sceneW - (cols - 1) * gap) / cols;\n const cellH = cellW * (2 / 3);\n const rows = Math.ceil(n / cols);\n cardEls.forEach((card, i) => {\n const col = i % cols;\n const row = Math.floor(i / cols);\n const itemsInRow = Math.min(cols, n - row * cols);\n const rowW = itemsInRow * cellW + (itemsInRow - 1) * gap;\n const rowStartX = (sceneW - rowW) / 2;\n const x = rowStartX + col * (cellW + gap);\n const y = row * (cellH + gap);\n card.style.width = cellW + 'px';\n setCardTransform(card, { x, y, z: 0, rx: 0, ry: 0, s: 1, zIndex: i === active ? 2 : 1, opacity: 1, isActive: i === active });\n });\n scene.style.height = rows * cellH + (rows - 1) * gap + 'px';\n }\n function layoutCarousel() {\n const sceneW = scene.clientWidth || MODE_WIDTHS.carousel;\n const cardW = sceneW;\n const cardH = cardW * (2 / 3);\n cardEls.forEach(clearGridWidth);\n const activeSc = 0.62;\n const activeW = cardW * activeSc;\n const sceneH = Math.max(cardH * activeSc + 40, 180);\n scene.style.height = sceneH + 'px';\n const offsetStep = Math.min(130, (sceneW - activeW) / 4);\n cardEls.forEach((card, i) => {\n let offset = i - active;\n if (n > 2 && offset > Math.floor(n / 2)) offset -= n;\n if (n > 2 && offset < -Math.floor(n / 2)) offset += n;\n const sc = Math.max(activeSc - Math.abs(offset) * 0.06, 0.28);\n const z = -Math.abs(offset) * 50;\n const op = Math.max(1 - Math.abs(offset) * 0.25, 0.15);\n const tx = sceneW / 2 + offset * offsetStep - cardW / 2;\n const ty = sceneH - 20 - cardH;\n setCardTransform(card, { x: tx, y: ty, z, rx: 0, ry: 0, s: sc, zIndex: n - Math.abs(offset), opacity: op, isActive: offset === 0 });\n });\n }\n // Scene width tracks the active mode so the layout math (which assumes the\n // mode's logical width) matches the actually-rendered card width. Layouts\n // then read scene.clientWidth, so everything stays self-consistent at any size.\n function sizeScene() {\n scene.style.width = `min(${MODE_WIDTHS[mode]}px, 92vw)`;\n }\n function applyLayout() {\n sizeScene();\n (mode === 'grid' ? layoutGrid : mode === 'carousel' ? layoutCarousel : layoutStack)();\n dots.forEach((d, i) => {\n d.classList.toggle('is-active', i === active);\n d.setAttribute('aria-selected', i === active ? 'true' : 'false');\n });\n cardEls.forEach((c, i) => { c.tabIndex = i === active ? 0 : -1; });\n const cur = items[active];\n live.textContent = cur && cur.label ? `${active + 1} of ${n}: ${cur.label}` : `${active + 1} of ${n}`;\n }\n\n /* ── Navigation ── */\n function goTo(i) {\n if (destroyed) return;\n // Coerce first: an unvalidated NaN/undefined would set active to NaN and\n // blank every card (translate3d(NaNpx,...)) plus emit index: NaN.\n const t = Number.isFinite(+i) ? Math.trunc(+i) : active;\n const next = opts.loop ? ((t % n) + n) % n : Math.min(Math.max(t, 0), n - 1);\n if (next === active) return;\n active = next;\n applyLayout();\n emit('fg-activechange', { index: active, item: items[active] });\n }\n function select(i) {\n if (destroyed) return;\n emit('fg-select', { index: i, item: items[i] });\n if (typeof opts.onSelect === 'function') opts.onSelect(items[i], i);\n }\n function setMode(m) {\n if (destroyed || m === mode || !MODE_WIDTHS[m]) return;\n mode = m;\n root.setAttribute('data-fg-mode', mode);\n applyLayout();\n emit('fg-modechange', { mode });\n }\n function setPeek(p) {\n if (destroyed || !PEEK_MODES.has(p) || p === root.getAttribute('data-fg-peek')) return;\n root.setAttribute('data-fg-peek', p);\n emit('fg-peekchange', { peek: p });\n }\n\n /* ── Interaction ── */\n const dragEnabled = opts.drag !== 'off';\n let suppressClick = false; // a real drag eats the click that follows pointerup\n\n cardEls.forEach((card, i) => {\n on(card, 'click', () => {\n if (suppressClick) { suppressClick = false; return; }\n i === active ? select(i) : goTo(i);\n });\n on(card, 'keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); select(i); }\n });\n });\n /* Arrow keys work two ways, matching the reference implementation:\n 1. Focus already inside the gallery (Tab to a card/dot) - bubbles here\n and re-focuses the new active card, standard roving-tabindex UX.\n 2. Mouse hovering the gallery, focus anywhere else on the page - a\n document-level listener picks it up. Without this route, arrow\n keys only work AFTER a click puts focus on a card - and a click is\n also what fires onSelect, which in real use is often a link. Making\n keyboard nav depend on that first click means the only way to\n \"activate\" arrows is to risk navigating away. Hover is enough. */\n function handleArrowKeys(e) {\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') { e.preventDefault(); goTo(active + 1); return true; }\n if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') { e.preventDefault(); goTo(active - 1); return true; }\n if (e.key === 'Home') { e.preventDefault(); goTo(0); return true; }\n if (e.key === 'End') { e.preventDefault(); goTo(n - 1); return true; }\n return false;\n }\n on(scene, 'keydown', (e) => { if (handleArrowKeys(e)) cardEls[active].focus(); });\n on(dotsEl, 'keydown', (e) => { if (handleArrowKeys(e)) cardEls[active].focus(); });\n\n let hovered = false;\n on(root, 'mouseenter', () => { hovered = true; });\n on(root, 'mouseleave', () => { hovered = false; });\n on(document, 'keydown', (e) => {\n if (!hovered) return;\n // Don't hijack arrows if focus is on an interactive control outside\n // the gallery (nav link, a form field elsewhere on the page).\n const ae = document.activeElement;\n if (ae && ae !== document.body && !root.contains(ae)) return;\n handleArrowKeys(e); // no forced focus - the user hasn't tabbed in\n });\n\n if (opts.scrollNav) {\n /* Bound to root, not just the scene box: root is the widget's full\n footprint (scene + dots), so wheel events over the dots row or any\n gap the consumer's own layout leaves around the gallery still cycle\n it, instead of requiring the pointer over the exact folder art. */\n on(root, 'wheel', (e) => {\n if (mode === 'grid') return;\n const atStart = !opts.loop && active === 0 && e.deltaY < 0;\n const atEnd = !opts.loop && active === n - 1 && e.deltaY > 0;\n if (atStart || atEnd) return;\n e.preventDefault();\n if (scrollCooldown) return;\n scrollAccum += e.deltaY;\n if (Math.abs(scrollAccum) >= SCROLL_THRESHOLD) {\n const dir = scrollAccum > 0 ? 1 : -1;\n scrollAccum = 0;\n scrollCooldown = true;\n goTo(active + dir);\n later(() => { scrollCooldown = false; scrollAccum = 0; }, SCROLL_COOLDOWN[mode] || 300);\n }\n }, { passive: false });\n }\n\n /* Dominant-axis swipe: up or left advances, down or right goes back.\n Horizontal is the natural phone gesture in carousel; vertical matches\n the wheel direction on the stack. Both work everywhere. */\n let touchStartX = 0;\n let touchStartY = 0;\n on(scene, 'touchstart', (e) => {\n touchStartX = e.touches[0].clientX;\n touchStartY = e.touches[0].clientY;\n }, { passive: true });\n on(scene, 'touchend', (e) => {\n // In stack mode the pointer-based drag below owns the gesture; letting\n // both fire would advance twice per swipe.\n if (dragEnabled && mode === 'stack') return;\n const dx = touchStartX - e.changedTouches[0].clientX;\n const dy = touchStartY - e.changedTouches[0].clientY;\n const ax = Math.abs(dx);\n const ay = Math.abs(dy);\n if (Math.max(ax, ay) < 40) return;\n const dir = ax > ay ? (dx > 0 ? 1 : -1) : (dy > 0 ? 1 : -1);\n goTo(active + dir);\n }, { passive: true });\n\n /* ── Drag: grab the active folder and throw it (stack mode) ──\n Pointer Events give one code path for mouse, touch, and pen. The\n gesture constants come from the folder-deck prototype this feature is\n ported from: rotation follows the drag at 0.04deg/px, a release past\n 90px of travel (or a genuine throw, over 0.5px/ms) flings the folder\n off along the dominant axis and advances; anything shorter springs\n back into the pile on the card's own transition. Direction keeps the\n swipe semantics: left or up is next, right or down is previous. */\n if (dragEnabled) {\n const DRAG_ROT = 0.04;\n const FLING_DIST = 90;\n const FLING_VEL = 0.5;\n const TAP_SLOP = 6;\n let dragCard = null;\n let dragBase = '';\n let startPX = 0, startPY = 0, dragDX = 0, dragDY = 0;\n let lastX = 0, lastY = 0, lastT = 0, velX = 0, velY = 0;\n\n on(scene, 'pointerdown', (e) => {\n if (mode !== 'stack') return;\n if (e.button !== undefined && e.button !== 0) return;\n const card = e.target && e.target.closest ? e.target.closest('.fg-card') : null;\n if (!card || !card.classList.contains('is-active')) return;\n dragCard = card;\n dragBase = card.style.transform;\n startPX = e.clientX; startPY = e.clientY;\n dragDX = 0; dragDY = 0;\n lastX = e.clientX; lastY = e.clientY;\n lastT = (typeof performance !== 'undefined' ? performance.now() : Date.now());\n velX = 0; velY = 0;\n card.classList.add('fg-card--dragging');\n if (card.setPointerCapture && e.pointerId !== undefined) {\n try { card.setPointerCapture(e.pointerId); } catch (_) { /* jsdom / detached */ }\n }\n });\n on(window, 'pointermove', (e) => {\n if (!dragCard) return;\n dragDX = e.clientX - startPX;\n dragDY = e.clientY - startPY;\n const now = (typeof performance !== 'undefined' ? performance.now() : Date.now());\n const dt = Math.max(now - lastT, 1);\n velX = (e.clientX - lastX) / dt;\n velY = (e.clientY - lastY) / dt;\n lastX = e.clientX; lastY = e.clientY; lastT = now;\n // translateZ lifts the grabbed folder clear of every plane in the\n // pile (tilted tops can poke past the active card's resting depth)\n // and reads as physically picking it up.\n dragCard.style.transform = `${dragBase} translate3d(${dragDX}px, ${dragDY}px, 40px) rotate(${(dragDX * DRAG_ROT).toFixed(2)}deg)`;\n });\n const endDrag = () => {\n if (!dragCard) return;\n const card = dragCard;\n dragCard = null;\n card.classList.remove('fg-card--dragging');\n const dist = Math.hypot(dragDX, dragDY);\n if (dist < TAP_SLOP) { card.style.transform = dragBase; return; } // a tap: the click handler owns it\n suppressClick = true;\n const horizontal = Math.abs(dragDX) >= Math.abs(dragDY);\n const flung = dist > FLING_DIST || Math.hypot(velX, velY) > FLING_VEL;\n const dir = horizontal ? (dragDX > 0 ? -1 : 1) : (dragDY > 0 ? -1 : 1);\n const target = active + dir;\n const blocked = !opts.loop && (target < 0 || target > n - 1);\n if (!flung || blocked) { card.style.transform = dragBase; return; } // spring back into the pile\n const semantic = dir > 0 ? 'next' : 'prev';\n emit('fg-flingstart', { index: active, direction: semantic });\n if (reduced) { goTo(target); emit('fg-flingend', { index: target, direction: semantic }); return; }\n const offX = horizontal ? Math.sign(dragDX) * Math.max(window.innerWidth * 0.7, 480) : dragDX * 3;\n const offY = horizontal ? dragDY * 3 : Math.sign(dragDY) * Math.max(window.innerHeight * 0.7, 480);\n /* Choreography: the pile answers the throw IMMEDIATELY (goTo below;\n layout skips the flung card), while the thrown folder finishes its\n own flight - a longer, momentum-eased sail that fades over 340ms.\n Once it is fully invisible, it re-enters by DROPPING IN from above\n its new slot: never straight from off-screen, which would cross\n the other folders' 3D planes and slice them visibly. */\n card.classList.add('fg-card--flung');\n card.style.transform = `${dragBase} translate3d(${offX}px, ${offY}px, 40px) rotate(${Math.sign(dragDX || 1) * 18}deg)`;\n card.style.opacity = '0';\n goTo(target); // shuffle starts now; the flung card is exempt from this relayout\n later(() => {\n card.classList.add('fg-card--snap');\n card.classList.remove('fg-card--flung');\n applyLayout(); // now it takes its slot transform (invisible, transitions off)\n const slot = card.style.transform;\n const slotOpacity = card.style.opacity;\n card.style.transform = `${slot} translate3d(0, -90px, 0)`;\n card.style.opacity = '0';\n /* Phase boundary via double rAF, NOT a synchronous reflow flush:\n WebKit does not treat forced reflows as transition boundaries and\n will compute the transition from the last PAINTED state (the\n fling-off position), which flashes the card across the pile.\n Painting one real frame at the staging point (invisible,\n transitions off) gives every engine the same before-state. */\n frame(() => frame(() => {\n card.classList.remove('fg-card--snap');\n card.classList.add('fg-card--entering'); // quicker settle curve for the drop\n card.style.transform = slot; // descend into the pile\n card.style.opacity = slotOpacity;\n later(() => {\n card.classList.remove('fg-card--entering');\n emit('fg-flingend', { index: target, direction: semantic });\n }, 700);\n }));\n }, 400); // after the 340ms flung fade, with margin: never snap a visible card\n };\n on(window, 'pointerup', endDrag);\n on(window, 'pointercancel', endDrag);\n }\n\n let resizeTimer;\n on(window, 'resize', () => { clearTimeout(resizeTimer); resizeTimer = later(applyLayout, 150); });\n\n // Keep `reduced` in sync if the OS setting changes while mounted (the CSS\n // updates live; this re-runs the JS motion branches to match).\n if (reducedQuery && reducedQuery.addEventListener) {\n on(reducedQuery, 'change', (e) => { if (!destroyed) { reduced = e.matches; applyLayout(); } });\n }\n\n applyLayout();\n\n /* ── Public handle ── */\n const handle = {\n next: () => goTo(active + 1),\n prev: () => goTo(active - 1),\n goTo,\n setMode,\n setPeek,\n setColor: (i, hex) => { const card = cardEls[i]; if (card && !destroyed) paintFolder(card, hex); },\n setGradient: (i, gradient) => { const card = cardEls[i]; if (card && !destroyed) paintGradient(card, gradient); },\n getActiveIndex: () => active,\n getMode: () => mode,\n getPeek: () => root.getAttribute('data-fg-peek'),\n getColor: (i) => { const card = cardEls[i]; return card ? card.style.getPropertyValue('--fg-folder-bg') || undefined : undefined; },\n getGradient: (i) => {\n const layer = cardEls[i] && cardEls[i].querySelector('.fg-gradient');\n return layer ? layer.style.background || undefined : undefined;\n },\n getItems: () => items.slice(),\n destroy: teardown,\n };\n INSTANCES.set(root, teardown);\n return handle;\n}\n\nexport default createFolderGallery;\n"],"mappings":"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","names":[]}
|