flipfolio 0.1.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 +34 -7
- package/dist/{chunk-DT6YOBGV.js → chunk-RFBZ3WPG.js} +274 -75
- package/dist/chunk-RFBZ3WPG.js.map +1 -0
- package/dist/element.cjs +287 -59
- package/dist/element.cjs.map +1 -1
- package/dist/element.d.ts +6 -0
- package/dist/element.js +21 -2
- package/dist/element.js.map +1 -1
- package/dist/folder-gallery.css +66 -24
- package/dist/index.cjs +274 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +42 -1
- package/dist/index.js +3 -1
- package/dist/react.cjs +305 -94
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +5 -1
- package/dist/react.js +39 -27
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +299 -62
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.ts +20 -4
- package/dist/vue.js +33 -5
- package/dist/vue.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-DT6YOBGV.js.map +0 -1
package/dist/react.cjs
CHANGED
|
@@ -1,34 +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
|
-
var __objRest = (source, exclude) => {
|
|
21
|
-
var target = {};
|
|
22
|
-
for (var prop in source)
|
|
23
|
-
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
24
|
-
target[prop] = source[prop];
|
|
25
|
-
if (source != null && __getOwnPropSymbols)
|
|
26
|
-
for (var prop of __getOwnPropSymbols(source)) {
|
|
27
|
-
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
28
|
-
target[prop] = source[prop];
|
|
29
|
-
}
|
|
30
|
-
return target;
|
|
31
|
-
};
|
|
32
5
|
var __export = (target, all) => {
|
|
33
6
|
for (var name in all)
|
|
34
7
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -65,19 +38,27 @@ var DEFAULTS = {
|
|
|
65
38
|
// 'auto' | 'off' | 'force'
|
|
66
39
|
peek: "hover",
|
|
67
40
|
// 'hover' | 'always' | 'off'
|
|
41
|
+
drag: "fling",
|
|
42
|
+
// 'fling' | 'off' - grab the active folder and throw it (stack mode)
|
|
68
43
|
defaultActiveIndex: 0,
|
|
69
44
|
label: "Folder gallery"
|
|
70
45
|
};
|
|
71
46
|
var PEEK_MODES = /* @__PURE__ */ new Set(["hover", "always", "off"]);
|
|
47
|
+
var DRAG_MODES = /* @__PURE__ */ new Set(["fling", "off"]);
|
|
48
|
+
var INSTANCES = /* @__PURE__ */ new WeakMap();
|
|
72
49
|
var MODE_WIDTHS = { stack: 480, grid: 720, carousel: 720 };
|
|
73
50
|
var SCROLL_THRESHOLD = 30;
|
|
74
51
|
var SCROLL_COOLDOWN = { stack: 450, carousel: 300 };
|
|
75
52
|
function hexToRgb(hex) {
|
|
76
|
-
|
|
53
|
+
let h = String(hex).trim().replace(/^#/, "");
|
|
54
|
+
if (h.length === 3) h = h.replace(/./g, (c) => c + c);
|
|
55
|
+
if (!/^[0-9a-f]{6}$/i.test(h)) return null;
|
|
77
56
|
return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
|
|
78
57
|
}
|
|
79
58
|
function folderColors(hex) {
|
|
80
|
-
const
|
|
59
|
+
const rgb = hexToRgb(hex);
|
|
60
|
+
if (!rgb) return null;
|
|
61
|
+
const [r, g, b] = rgb;
|
|
81
62
|
const dn = (v) => Math.max(v - 30, 0);
|
|
82
63
|
const up = (v, o) => Math.min(v + o, 255);
|
|
83
64
|
const fr = up(r, 35);
|
|
@@ -91,6 +72,34 @@ function folderColors(hex) {
|
|
|
91
72
|
label: yiq >= 128 ? "#1c1c1a" : "#ffffff"
|
|
92
73
|
};
|
|
93
74
|
}
|
|
75
|
+
function paintFolder(card, hex) {
|
|
76
|
+
const c = folderColors(hex);
|
|
77
|
+
if (!c) return;
|
|
78
|
+
card.style.setProperty("--fg-folder-bg", hex);
|
|
79
|
+
card.style.setProperty("--fg-front", c.front);
|
|
80
|
+
card.style.setProperty("--fg-front-solid", c.frontSolid);
|
|
81
|
+
card.style.setProperty("--fg-label-on-color", c.label);
|
|
82
|
+
const path = card.querySelector(".fg-folder path");
|
|
83
|
+
if (path) path.setAttribute("fill", c.back);
|
|
84
|
+
}
|
|
85
|
+
function paintGradient(card, gradient) {
|
|
86
|
+
const front = card.querySelector(".fg-front");
|
|
87
|
+
if (!front) return;
|
|
88
|
+
let layer = front.querySelector(".fg-gradient");
|
|
89
|
+
if (!gradient) {
|
|
90
|
+
if (layer) layer.remove();
|
|
91
|
+
card.classList.remove("fg-card--gradient");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (!layer) {
|
|
95
|
+
layer = document.createElement("div");
|
|
96
|
+
layer.className = "fg-gradient";
|
|
97
|
+
layer.setAttribute("aria-hidden", "true");
|
|
98
|
+
front.insertBefore(layer, front.firstChild);
|
|
99
|
+
}
|
|
100
|
+
layer.style.background = gradient;
|
|
101
|
+
card.classList.add("fg-card--gradient");
|
|
102
|
+
}
|
|
94
103
|
function defaultContentRenderer(card, item) {
|
|
95
104
|
const wrap = document.createElement("div");
|
|
96
105
|
wrap.className = "fg-content";
|
|
@@ -110,12 +119,17 @@ function defaultContentRenderer(card, item) {
|
|
|
110
119
|
card.appendChild(wrap);
|
|
111
120
|
}
|
|
112
121
|
function createFolderGallery(root, options = {}) {
|
|
113
|
-
if (!root ||
|
|
114
|
-
const
|
|
122
|
+
if (!root || root.nodeType !== 1) throw new Error("createFolderGallery: a root element is required");
|
|
123
|
+
const prior = INSTANCES.get(root);
|
|
124
|
+
if (prior) prior();
|
|
125
|
+
const provided = {};
|
|
126
|
+
for (const k in options) if (options[k] !== void 0) provided[k] = options[k];
|
|
127
|
+
const opts = { ...DEFAULTS, ...provided };
|
|
115
128
|
const items = Array.isArray(opts.items) ? opts.items : [];
|
|
116
129
|
const n = items.length;
|
|
117
130
|
const renderContent = typeof opts.contentRenderer === "function" ? opts.contentRenderer : defaultContentRenderer;
|
|
118
|
-
const
|
|
131
|
+
const reducedQuery = opts.reducedMotion === "auto" && typeof matchMedia === "function" ? matchMedia("(prefers-reduced-motion: reduce)") : null;
|
|
132
|
+
let reduced = opts.reducedMotion === "force" || (reducedQuery ? reducedQuery.matches : false);
|
|
119
133
|
let mode = MODE_WIDTHS[opts.mode] ? opts.mode : "stack";
|
|
120
134
|
let active = Math.min(Math.max(opts.defaultActiveIndex | 0, 0), Math.max(n - 1, 0));
|
|
121
135
|
let scrollCooldown = false;
|
|
@@ -126,9 +140,29 @@ function createFolderGallery(root, options = {}) {
|
|
|
126
140
|
cleanups.push(() => el.removeEventListener(ev, fn, o));
|
|
127
141
|
};
|
|
128
142
|
const emit = (name, detail) => root.dispatchEvent(new CustomEvent(name, { detail, bubbles: true }));
|
|
143
|
+
let destroyed = false;
|
|
144
|
+
const timers = /* @__PURE__ */ new Set();
|
|
145
|
+
const rafs = /* @__PURE__ */ new Set();
|
|
146
|
+
const later = (fn, ms) => {
|
|
147
|
+
const id = setTimeout(() => {
|
|
148
|
+
timers.delete(id);
|
|
149
|
+
fn();
|
|
150
|
+
}, ms);
|
|
151
|
+
timers.add(id);
|
|
152
|
+
return id;
|
|
153
|
+
};
|
|
154
|
+
const frame = (fn) => {
|
|
155
|
+
const id = requestAnimationFrame(() => {
|
|
156
|
+
rafs.delete(id);
|
|
157
|
+
fn();
|
|
158
|
+
});
|
|
159
|
+
rafs.add(id);
|
|
160
|
+
return id;
|
|
161
|
+
};
|
|
129
162
|
root.classList.add("fg-root");
|
|
130
163
|
root.setAttribute("data-fg-mode", mode);
|
|
131
164
|
root.setAttribute("data-fg-peek", PEEK_MODES.has(opts.peek) ? opts.peek : "hover");
|
|
165
|
+
root.setAttribute("data-fg-drag", DRAG_MODES.has(opts.drag) ? opts.drag : "fling");
|
|
132
166
|
const scene = document.createElement("div");
|
|
133
167
|
scene.className = "fg-scene";
|
|
134
168
|
scene.setAttribute("role", "listbox");
|
|
@@ -143,26 +177,48 @@ function createFolderGallery(root, options = {}) {
|
|
|
143
177
|
live.setAttribute("aria-atomic", "true");
|
|
144
178
|
root.append(scene, dotsEl, live);
|
|
145
179
|
function teardown() {
|
|
180
|
+
if (destroyed) return;
|
|
181
|
+
destroyed = true;
|
|
182
|
+
timers.forEach(clearTimeout);
|
|
183
|
+
timers.clear();
|
|
184
|
+
rafs.forEach(cancelAnimationFrame);
|
|
185
|
+
rafs.clear();
|
|
146
186
|
cleanups.forEach((fn) => fn());
|
|
147
187
|
cleanups.length = 0;
|
|
148
188
|
root.replaceChildren();
|
|
149
189
|
root.classList.remove("fg-root");
|
|
150
190
|
root.removeAttribute("data-fg-mode");
|
|
151
191
|
root.removeAttribute("data-fg-peek");
|
|
192
|
+
root.removeAttribute("data-fg-drag");
|
|
193
|
+
INSTANCES.delete(root);
|
|
152
194
|
}
|
|
153
195
|
if (n === 0) {
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
196
|
+
const noop = () => {
|
|
197
|
+
};
|
|
198
|
+
INSTANCES.set(root, teardown);
|
|
199
|
+
return {
|
|
200
|
+
next: noop,
|
|
201
|
+
prev: noop,
|
|
202
|
+
goTo: noop,
|
|
203
|
+
setMode: noop,
|
|
204
|
+
setPeek: noop,
|
|
205
|
+
setColor: noop,
|
|
206
|
+
setGradient: noop,
|
|
207
|
+
getActiveIndex: () => -1,
|
|
208
|
+
getMode: () => mode,
|
|
209
|
+
getPeek: () => root.getAttribute("data-fg-peek"),
|
|
210
|
+
getColor: () => void 0,
|
|
211
|
+
getGradient: () => void 0,
|
|
212
|
+
getItems: () => [],
|
|
213
|
+
destroy: teardown
|
|
214
|
+
};
|
|
160
215
|
}
|
|
161
216
|
function setCardTransform(card, { x, y, z, rx, ry, s, zIndex, opacity, isActive }) {
|
|
162
|
-
card.
|
|
163
|
-
|
|
217
|
+
if (!card.classList.contains("fg-card--flung")) {
|
|
218
|
+
card.style.transform = `translate3d(${x}px,${y}px,${z}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${s})`;
|
|
219
|
+
card.style.opacity = String(opacity);
|
|
220
|
+
}
|
|
164
221
|
card.style.zIndex = String(zIndex);
|
|
165
|
-
card.style.opacity = String(opacity);
|
|
166
222
|
card.setAttribute("aria-selected", isActive ? "true" : "false");
|
|
167
223
|
card.classList.toggle("is-active", isActive);
|
|
168
224
|
}
|
|
@@ -172,13 +228,9 @@ function createFolderGallery(root, options = {}) {
|
|
|
172
228
|
card.tabIndex = i === active ? 0 : -1;
|
|
173
229
|
card.setAttribute("role", "option");
|
|
174
230
|
card.setAttribute("aria-label", item.label || `Item ${i + 1}`);
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
card.style.setProperty("--fg-front", c.front);
|
|
179
|
-
card.style.setProperty("--fg-front-solid", c.frontSolid);
|
|
180
|
-
card.style.setProperty("--fg-label-on-color", c.label);
|
|
181
|
-
}
|
|
231
|
+
card.setAttribute("aria-setsize", String(n));
|
|
232
|
+
card.setAttribute("aria-posinset", String(i + 1));
|
|
233
|
+
card.setAttribute("data-fg-index", String(i));
|
|
182
234
|
const svg = document.createElementNS(SVG_NS, "svg");
|
|
183
235
|
svg.setAttribute("class", "fg-folder");
|
|
184
236
|
svg.setAttribute("viewBox", "0 0 480 342");
|
|
@@ -186,7 +238,7 @@ function createFolderGallery(root, options = {}) {
|
|
|
186
238
|
svg.setAttribute("aria-hidden", "true");
|
|
187
239
|
const path = document.createElementNS(SVG_NS, "path");
|
|
188
240
|
path.setAttribute("d", opts.folderPath);
|
|
189
|
-
path.setAttribute("fill",
|
|
241
|
+
path.setAttribute("fill", "var(--fg-folder-bg)");
|
|
190
242
|
svg.appendChild(path);
|
|
191
243
|
card.appendChild(svg);
|
|
192
244
|
renderContent(card, item, i);
|
|
@@ -209,6 +261,8 @@ function createFolderGallery(root, options = {}) {
|
|
|
209
261
|
front.appendChild(label);
|
|
210
262
|
}
|
|
211
263
|
card.appendChild(front);
|
|
264
|
+
if (item.color) paintFolder(card, item.color);
|
|
265
|
+
if (item.gradient) paintGradient(card, item.gradient);
|
|
212
266
|
scene.appendChild(card);
|
|
213
267
|
return card;
|
|
214
268
|
});
|
|
@@ -222,9 +276,13 @@ function createFolderGallery(root, options = {}) {
|
|
|
222
276
|
dotsEl.appendChild(dot);
|
|
223
277
|
return dot;
|
|
224
278
|
});
|
|
279
|
+
const clearGridWidth = (card) => {
|
|
280
|
+
if (card.style.width) card.style.width = "";
|
|
281
|
+
};
|
|
225
282
|
function layoutStack() {
|
|
226
283
|
scene.style.height = "";
|
|
227
284
|
cardEls.forEach((card, i) => {
|
|
285
|
+
clearGridWidth(card);
|
|
228
286
|
const behind = (i - active + n) % n;
|
|
229
287
|
if (behind === 0) {
|
|
230
288
|
setCardTransform(card, { x: 0, y: 100, z: 20, rx: 0, ry: 0, s: 1, zIndex: n + 1, opacity: 1, isActive: true });
|
|
@@ -240,33 +298,31 @@ function createFolderGallery(root, options = {}) {
|
|
|
240
298
|
}
|
|
241
299
|
function layoutGrid() {
|
|
242
300
|
const sceneW = scene.clientWidth || MODE_WIDTHS.grid;
|
|
243
|
-
const
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
const
|
|
248
|
-
const
|
|
249
|
-
const scaledH = cardH * sc;
|
|
250
|
-
const tabScaled = 22 * sc;
|
|
301
|
+
const gap = Number.isFinite(opts.grid && opts.grid.gap) ? opts.grid.gap : 16;
|
|
302
|
+
const cols = Math.max(1, Math.round(
|
|
303
|
+
opts.grid && opts.grid.columns ? opts.grid.columns : sceneW < 520 ? 2 : n <= 4 ? 2 : 3
|
|
304
|
+
));
|
|
305
|
+
const cellW = (sceneW - (cols - 1) * gap) / cols;
|
|
306
|
+
const cellH = cellW * (2 / 3);
|
|
251
307
|
const rows = Math.ceil(n / cols);
|
|
252
308
|
cardEls.forEach((card, i) => {
|
|
253
309
|
const col = i % cols;
|
|
254
310
|
const row = Math.floor(i / cols);
|
|
255
311
|
const itemsInRow = Math.min(cols, n - row * cols);
|
|
256
|
-
const rowW = itemsInRow *
|
|
312
|
+
const rowW = itemsInRow * cellW + (itemsInRow - 1) * gap;
|
|
257
313
|
const rowStartX = (sceneW - rowW) / 2;
|
|
258
|
-
const
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
setCardTransform(card, { x: tx, y: ty, z: 0, rx: 0, ry: 0, s: sc, zIndex: i === active ? 2 : 1, opacity: 1, isActive: i === active });
|
|
314
|
+
const x = rowStartX + col * (cellW + gap);
|
|
315
|
+
const y = row * (cellH + gap);
|
|
316
|
+
card.style.width = cellW + "px";
|
|
317
|
+
setCardTransform(card, { x, y, z: 0, rx: 0, ry: 0, s: 1, zIndex: i === active ? 2 : 1, opacity: 1, isActive: i === active });
|
|
263
318
|
});
|
|
264
|
-
scene.style.height = rows *
|
|
319
|
+
scene.style.height = rows * cellH + (rows - 1) * gap + "px";
|
|
265
320
|
}
|
|
266
321
|
function layoutCarousel() {
|
|
267
322
|
const sceneW = scene.clientWidth || MODE_WIDTHS.carousel;
|
|
268
323
|
const cardW = sceneW;
|
|
269
324
|
const cardH = cardW * (2 / 3);
|
|
325
|
+
cardEls.forEach(clearGridWidth);
|
|
270
326
|
const activeSc = 0.62;
|
|
271
327
|
const activeW = cardW * activeSc;
|
|
272
328
|
const sceneH = Math.max(cardH * activeSc + 40, 180);
|
|
@@ -301,29 +357,39 @@ function createFolderGallery(root, options = {}) {
|
|
|
301
357
|
live.textContent = cur && cur.label ? `${active + 1} of ${n}: ${cur.label}` : `${active + 1} of ${n}`;
|
|
302
358
|
}
|
|
303
359
|
function goTo(i) {
|
|
304
|
-
|
|
360
|
+
if (destroyed) return;
|
|
361
|
+
const t = Number.isFinite(+i) ? Math.trunc(+i) : active;
|
|
362
|
+
const next = opts.loop ? (t % n + n) % n : Math.min(Math.max(t, 0), n - 1);
|
|
305
363
|
if (next === active) return;
|
|
306
364
|
active = next;
|
|
307
365
|
applyLayout();
|
|
308
366
|
emit("fg-activechange", { index: active, item: items[active] });
|
|
309
367
|
}
|
|
310
368
|
function select(i) {
|
|
369
|
+
if (destroyed) return;
|
|
311
370
|
emit("fg-select", { index: i, item: items[i] });
|
|
312
371
|
if (typeof opts.onSelect === "function") opts.onSelect(items[i], i);
|
|
313
372
|
}
|
|
314
373
|
function setMode(m) {
|
|
315
|
-
if (m === mode || !MODE_WIDTHS[m]) return;
|
|
374
|
+
if (destroyed || m === mode || !MODE_WIDTHS[m]) return;
|
|
316
375
|
mode = m;
|
|
317
376
|
root.setAttribute("data-fg-mode", mode);
|
|
318
377
|
applyLayout();
|
|
319
378
|
emit("fg-modechange", { mode });
|
|
320
379
|
}
|
|
321
380
|
function setPeek(p) {
|
|
322
|
-
if (!PEEK_MODES.has(p)) return;
|
|
381
|
+
if (destroyed || !PEEK_MODES.has(p) || p === root.getAttribute("data-fg-peek")) return;
|
|
323
382
|
root.setAttribute("data-fg-peek", p);
|
|
383
|
+
emit("fg-peekchange", { peek: p });
|
|
324
384
|
}
|
|
385
|
+
const dragEnabled = opts.drag !== "off";
|
|
386
|
+
let suppressClick = false;
|
|
325
387
|
cardEls.forEach((card, i) => {
|
|
326
388
|
on(card, "click", () => {
|
|
389
|
+
if (suppressClick) {
|
|
390
|
+
suppressClick = false;
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
327
393
|
i === active ? select(i) : goTo(i);
|
|
328
394
|
});
|
|
329
395
|
on(card, "keydown", (e) => {
|
|
@@ -389,7 +455,7 @@ function createFolderGallery(root, options = {}) {
|
|
|
389
455
|
scrollAccum = 0;
|
|
390
456
|
scrollCooldown = true;
|
|
391
457
|
goTo(active + dir);
|
|
392
|
-
|
|
458
|
+
later(() => {
|
|
393
459
|
scrollCooldown = false;
|
|
394
460
|
scrollAccum = 0;
|
|
395
461
|
}, SCROLL_COOLDOWN[mode] || 300);
|
|
@@ -403,6 +469,7 @@ function createFolderGallery(root, options = {}) {
|
|
|
403
469
|
touchStartY = e.touches[0].clientY;
|
|
404
470
|
}, { passive: true });
|
|
405
471
|
on(scene, "touchend", (e) => {
|
|
472
|
+
if (dragEnabled && mode === "stack") return;
|
|
406
473
|
const dx = touchStartX - e.changedTouches[0].clientX;
|
|
407
474
|
const dy = touchStartY - e.changedTouches[0].clientY;
|
|
408
475
|
const ax = Math.abs(dx);
|
|
@@ -411,34 +478,168 @@ function createFolderGallery(root, options = {}) {
|
|
|
411
478
|
const dir = ax > ay ? dx > 0 ? 1 : -1 : dy > 0 ? 1 : -1;
|
|
412
479
|
goTo(active + dir);
|
|
413
480
|
}, { passive: true });
|
|
481
|
+
if (dragEnabled) {
|
|
482
|
+
const DRAG_ROT = 0.04;
|
|
483
|
+
const FLING_DIST = 90;
|
|
484
|
+
const FLING_VEL = 0.5;
|
|
485
|
+
const TAP_SLOP = 6;
|
|
486
|
+
let dragCard = null;
|
|
487
|
+
let dragBase = "";
|
|
488
|
+
let startPX = 0, startPY = 0, dragDX = 0, dragDY = 0;
|
|
489
|
+
let lastX = 0, lastY = 0, lastT = 0, velX = 0, velY = 0;
|
|
490
|
+
on(scene, "pointerdown", (e) => {
|
|
491
|
+
if (mode !== "stack") return;
|
|
492
|
+
if (e.button !== void 0 && e.button !== 0) return;
|
|
493
|
+
const card = e.target && e.target.closest ? e.target.closest(".fg-card") : null;
|
|
494
|
+
if (!card || !card.classList.contains("is-active")) return;
|
|
495
|
+
dragCard = card;
|
|
496
|
+
dragBase = card.style.transform;
|
|
497
|
+
startPX = e.clientX;
|
|
498
|
+
startPY = e.clientY;
|
|
499
|
+
dragDX = 0;
|
|
500
|
+
dragDY = 0;
|
|
501
|
+
lastX = e.clientX;
|
|
502
|
+
lastY = e.clientY;
|
|
503
|
+
lastT = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
504
|
+
velX = 0;
|
|
505
|
+
velY = 0;
|
|
506
|
+
card.classList.add("fg-card--dragging");
|
|
507
|
+
if (card.setPointerCapture && e.pointerId !== void 0) {
|
|
508
|
+
try {
|
|
509
|
+
card.setPointerCapture(e.pointerId);
|
|
510
|
+
} catch (_) {
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
on(window, "pointermove", (e) => {
|
|
515
|
+
if (!dragCard) return;
|
|
516
|
+
dragDX = e.clientX - startPX;
|
|
517
|
+
dragDY = e.clientY - startPY;
|
|
518
|
+
const now = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
519
|
+
const dt = Math.max(now - lastT, 1);
|
|
520
|
+
velX = (e.clientX - lastX) / dt;
|
|
521
|
+
velY = (e.clientY - lastY) / dt;
|
|
522
|
+
lastX = e.clientX;
|
|
523
|
+
lastY = e.clientY;
|
|
524
|
+
lastT = now;
|
|
525
|
+
dragCard.style.transform = `${dragBase} translate3d(${dragDX}px, ${dragDY}px, 40px) rotate(${(dragDX * DRAG_ROT).toFixed(2)}deg)`;
|
|
526
|
+
});
|
|
527
|
+
const endDrag = () => {
|
|
528
|
+
if (!dragCard) return;
|
|
529
|
+
const card = dragCard;
|
|
530
|
+
dragCard = null;
|
|
531
|
+
card.classList.remove("fg-card--dragging");
|
|
532
|
+
const dist = Math.hypot(dragDX, dragDY);
|
|
533
|
+
if (dist < TAP_SLOP) {
|
|
534
|
+
card.style.transform = dragBase;
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
suppressClick = true;
|
|
538
|
+
const horizontal = Math.abs(dragDX) >= Math.abs(dragDY);
|
|
539
|
+
const flung = dist > FLING_DIST || Math.hypot(velX, velY) > FLING_VEL;
|
|
540
|
+
const dir = horizontal ? dragDX > 0 ? -1 : 1 : dragDY > 0 ? -1 : 1;
|
|
541
|
+
const target = active + dir;
|
|
542
|
+
const blocked = !opts.loop && (target < 0 || target > n - 1);
|
|
543
|
+
if (!flung || blocked) {
|
|
544
|
+
card.style.transform = dragBase;
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
const semantic = dir > 0 ? "next" : "prev";
|
|
548
|
+
emit("fg-flingstart", { index: active, direction: semantic });
|
|
549
|
+
if (reduced) {
|
|
550
|
+
goTo(target);
|
|
551
|
+
emit("fg-flingend", { index: target, direction: semantic });
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
const offX = horizontal ? Math.sign(dragDX) * Math.max(window.innerWidth * 0.7, 480) : dragDX * 3;
|
|
555
|
+
const offY = horizontal ? dragDY * 3 : Math.sign(dragDY) * Math.max(window.innerHeight * 0.7, 480);
|
|
556
|
+
card.classList.add("fg-card--flung");
|
|
557
|
+
card.style.transform = `${dragBase} translate3d(${offX}px, ${offY}px, 40px) rotate(${Math.sign(dragDX || 1) * 18}deg)`;
|
|
558
|
+
card.style.opacity = "0";
|
|
559
|
+
goTo(target);
|
|
560
|
+
later(() => {
|
|
561
|
+
card.classList.add("fg-card--snap");
|
|
562
|
+
card.classList.remove("fg-card--flung");
|
|
563
|
+
applyLayout();
|
|
564
|
+
const slot = card.style.transform;
|
|
565
|
+
const slotOpacity = card.style.opacity;
|
|
566
|
+
card.style.transform = `${slot} translate3d(0, -90px, 0)`;
|
|
567
|
+
card.style.opacity = "0";
|
|
568
|
+
frame(() => frame(() => {
|
|
569
|
+
card.classList.remove("fg-card--snap");
|
|
570
|
+
card.classList.add("fg-card--entering");
|
|
571
|
+
card.style.transform = slot;
|
|
572
|
+
card.style.opacity = slotOpacity;
|
|
573
|
+
later(() => {
|
|
574
|
+
card.classList.remove("fg-card--entering");
|
|
575
|
+
emit("fg-flingend", { index: target, direction: semantic });
|
|
576
|
+
}, 700);
|
|
577
|
+
}));
|
|
578
|
+
}, 400);
|
|
579
|
+
};
|
|
580
|
+
on(window, "pointerup", endDrag);
|
|
581
|
+
on(window, "pointercancel", endDrag);
|
|
582
|
+
}
|
|
414
583
|
let resizeTimer;
|
|
415
584
|
on(window, "resize", () => {
|
|
416
585
|
clearTimeout(resizeTimer);
|
|
417
|
-
resizeTimer =
|
|
586
|
+
resizeTimer = later(applyLayout, 150);
|
|
418
587
|
});
|
|
588
|
+
if (reducedQuery && reducedQuery.addEventListener) {
|
|
589
|
+
on(reducedQuery, "change", (e) => {
|
|
590
|
+
if (!destroyed) {
|
|
591
|
+
reduced = e.matches;
|
|
592
|
+
applyLayout();
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
}
|
|
419
596
|
applyLayout();
|
|
420
|
-
|
|
597
|
+
const handle = {
|
|
421
598
|
next: () => goTo(active + 1),
|
|
422
599
|
prev: () => goTo(active - 1),
|
|
423
600
|
goTo,
|
|
424
601
|
setMode,
|
|
425
602
|
setPeek,
|
|
603
|
+
setColor: (i, hex) => {
|
|
604
|
+
const card = cardEls[i];
|
|
605
|
+
if (card && !destroyed) paintFolder(card, hex);
|
|
606
|
+
},
|
|
607
|
+
setGradient: (i, gradient) => {
|
|
608
|
+
const card = cardEls[i];
|
|
609
|
+
if (card && !destroyed) paintGradient(card, gradient);
|
|
610
|
+
},
|
|
426
611
|
getActiveIndex: () => active,
|
|
427
612
|
getMode: () => mode,
|
|
613
|
+
getPeek: () => root.getAttribute("data-fg-peek"),
|
|
614
|
+
getColor: (i) => {
|
|
615
|
+
const card = cardEls[i];
|
|
616
|
+
return card ? card.style.getPropertyValue("--fg-folder-bg") || void 0 : void 0;
|
|
617
|
+
},
|
|
618
|
+
getGradient: (i) => {
|
|
619
|
+
const layer = cardEls[i] && cardEls[i].querySelector(".fg-gradient");
|
|
620
|
+
return layer ? layer.style.background || void 0 : void 0;
|
|
621
|
+
},
|
|
622
|
+
getItems: () => items.slice(),
|
|
428
623
|
destroy: teardown
|
|
429
624
|
};
|
|
625
|
+
INSTANCES.set(root, teardown);
|
|
626
|
+
return handle;
|
|
430
627
|
}
|
|
431
628
|
|
|
432
629
|
// src/folder-gallery-react.js
|
|
433
630
|
var FolderGallery = (0, import_react.forwardRef)(function FolderGallery2(props, ref) {
|
|
434
|
-
const
|
|
631
|
+
const {
|
|
435
632
|
items,
|
|
436
633
|
mode = "stack",
|
|
437
634
|
peek = "hover",
|
|
635
|
+
drag = "fling",
|
|
438
636
|
contentRenderer,
|
|
439
637
|
onSelect,
|
|
440
638
|
onActiveChange,
|
|
441
639
|
onModeChange,
|
|
640
|
+
onPeekChange,
|
|
641
|
+
onFlingStart,
|
|
642
|
+
onFlingEnd,
|
|
442
643
|
folderPath,
|
|
443
644
|
loop,
|
|
444
645
|
scrollNav,
|
|
@@ -446,28 +647,13 @@ var FolderGallery = (0, import_react.forwardRef)(function FolderGallery2(props,
|
|
|
446
647
|
defaultActiveIndex,
|
|
447
648
|
label,
|
|
448
649
|
className,
|
|
449
|
-
style
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
"mode",
|
|
453
|
-
"peek",
|
|
454
|
-
"contentRenderer",
|
|
455
|
-
"onSelect",
|
|
456
|
-
"onActiveChange",
|
|
457
|
-
"onModeChange",
|
|
458
|
-
"folderPath",
|
|
459
|
-
"loop",
|
|
460
|
-
"scrollNav",
|
|
461
|
-
"reducedMotion",
|
|
462
|
-
"defaultActiveIndex",
|
|
463
|
-
"label",
|
|
464
|
-
"className",
|
|
465
|
-
"style"
|
|
466
|
-
]);
|
|
650
|
+
style,
|
|
651
|
+
...rest
|
|
652
|
+
} = props;
|
|
467
653
|
const rootRef = (0, import_react.useRef)(null);
|
|
468
654
|
const handleRef = (0, import_react.useRef)(null);
|
|
469
655
|
const callbacksRef = (0, import_react.useRef)({});
|
|
470
|
-
callbacksRef.current = { onSelect, onActiveChange, onModeChange, contentRenderer };
|
|
656
|
+
callbacksRef.current = { onSelect, onActiveChange, onModeChange, onPeekChange, onFlingStart, onFlingEnd, contentRenderer };
|
|
471
657
|
(0, import_react.useEffect)(() => {
|
|
472
658
|
const root = rootRef.current;
|
|
473
659
|
if (!root) return void 0;
|
|
@@ -475,6 +661,7 @@ var FolderGallery = (0, import_react.forwardRef)(function FolderGallery2(props,
|
|
|
475
661
|
items,
|
|
476
662
|
mode,
|
|
477
663
|
peek,
|
|
664
|
+
drag,
|
|
478
665
|
folderPath,
|
|
479
666
|
loop,
|
|
480
667
|
scrollNav,
|
|
@@ -496,15 +683,33 @@ var FolderGallery = (0, import_react.forwardRef)(function FolderGallery2(props,
|
|
|
496
683
|
const fn = callbacksRef.current.onModeChange;
|
|
497
684
|
if (fn) fn(e.detail.mode);
|
|
498
685
|
};
|
|
686
|
+
const onPeekEv = (e) => {
|
|
687
|
+
const fn = callbacksRef.current.onPeekChange;
|
|
688
|
+
if (fn) fn(e.detail.peek);
|
|
689
|
+
};
|
|
690
|
+
const onFlingStartEv = (e) => {
|
|
691
|
+
const fn = callbacksRef.current.onFlingStart;
|
|
692
|
+
if (fn) fn(e.detail.index, e.detail.direction);
|
|
693
|
+
};
|
|
694
|
+
const onFlingEndEv = (e) => {
|
|
695
|
+
const fn = callbacksRef.current.onFlingEnd;
|
|
696
|
+
if (fn) fn(e.detail.index, e.detail.direction);
|
|
697
|
+
};
|
|
499
698
|
root.addEventListener("fg-activechange", onActive);
|
|
500
699
|
root.addEventListener("fg-modechange", onModeEv);
|
|
700
|
+
root.addEventListener("fg-peekchange", onPeekEv);
|
|
701
|
+
root.addEventListener("fg-flingstart", onFlingStartEv);
|
|
702
|
+
root.addEventListener("fg-flingend", onFlingEndEv);
|
|
501
703
|
return () => {
|
|
502
704
|
root.removeEventListener("fg-activechange", onActive);
|
|
503
705
|
root.removeEventListener("fg-modechange", onModeEv);
|
|
706
|
+
root.removeEventListener("fg-peekchange", onPeekEv);
|
|
707
|
+
root.removeEventListener("fg-flingstart", onFlingStartEv);
|
|
708
|
+
root.removeEventListener("fg-flingend", onFlingEndEv);
|
|
504
709
|
handle.destroy();
|
|
505
710
|
handleRef.current = null;
|
|
506
711
|
};
|
|
507
|
-
}, [items, folderPath, loop, scrollNav, reducedMotion, defaultActiveIndex, label]);
|
|
712
|
+
}, [items, drag, folderPath, loop, scrollNav, reducedMotion, defaultActiveIndex, label]);
|
|
508
713
|
(0, import_react.useEffect)(() => {
|
|
509
714
|
if (handleRef.current && handleRef.current.getMode() !== mode) {
|
|
510
715
|
handleRef.current.setMode(mode);
|
|
@@ -519,10 +724,16 @@ var FolderGallery = (0, import_react.forwardRef)(function FolderGallery2(props,
|
|
|
519
724
|
goTo: (i) => handleRef.current && handleRef.current.goTo(i),
|
|
520
725
|
setMode: (m) => handleRef.current && handleRef.current.setMode(m),
|
|
521
726
|
setPeek: (p) => handleRef.current && handleRef.current.setPeek(p),
|
|
727
|
+
setColor: (i, hex) => handleRef.current && handleRef.current.setColor(i, hex),
|
|
728
|
+
setGradient: (i, gradient) => handleRef.current && handleRef.current.setGradient(i, gradient),
|
|
522
729
|
getActiveIndex: () => handleRef.current ? handleRef.current.getActiveIndex() : -1,
|
|
523
|
-
getMode: () => handleRef.current ? handleRef.current.getMode() : mode
|
|
524
|
-
|
|
525
|
-
|
|
730
|
+
getMode: () => handleRef.current ? handleRef.current.getMode() : mode,
|
|
731
|
+
getPeek: () => handleRef.current ? handleRef.current.getPeek() : peek,
|
|
732
|
+
getColor: (i) => handleRef.current ? handleRef.current.getColor(i) : void 0,
|
|
733
|
+
getGradient: (i) => handleRef.current ? handleRef.current.getGradient(i) : void 0,
|
|
734
|
+
getItems: () => handleRef.current ? handleRef.current.getItems() : []
|
|
735
|
+
}), [mode, peek]);
|
|
736
|
+
return (0, import_react.createElement)("div", { ref: rootRef, className, style, ...rest });
|
|
526
737
|
});
|
|
527
738
|
var folder_gallery_react_default = FolderGallery;
|
|
528
739
|
// Annotate the CommonJS export names for ESM import in node:
|