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/element.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 });
|
|
@@ -53,19 +38,27 @@ var DEFAULTS = {
|
|
|
53
38
|
// 'auto' | 'off' | 'force'
|
|
54
39
|
peek: "hover",
|
|
55
40
|
// 'hover' | 'always' | 'off'
|
|
41
|
+
drag: "fling",
|
|
42
|
+
// 'fling' | 'off' - grab the active folder and throw it (stack mode)
|
|
56
43
|
defaultActiveIndex: 0,
|
|
57
44
|
label: "Folder gallery"
|
|
58
45
|
};
|
|
59
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();
|
|
60
49
|
var MODE_WIDTHS = { stack: 480, grid: 720, carousel: 720 };
|
|
61
50
|
var SCROLL_THRESHOLD = 30;
|
|
62
51
|
var SCROLL_COOLDOWN = { stack: 450, carousel: 300 };
|
|
63
52
|
function hexToRgb(hex) {
|
|
64
|
-
|
|
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;
|
|
65
56
|
return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
|
|
66
57
|
}
|
|
67
58
|
function folderColors(hex) {
|
|
68
|
-
const
|
|
59
|
+
const rgb = hexToRgb(hex);
|
|
60
|
+
if (!rgb) return null;
|
|
61
|
+
const [r, g, b] = rgb;
|
|
69
62
|
const dn = (v) => Math.max(v - 30, 0);
|
|
70
63
|
const up = (v, o) => Math.min(v + o, 255);
|
|
71
64
|
const fr = up(r, 35);
|
|
@@ -79,6 +72,34 @@ function folderColors(hex) {
|
|
|
79
72
|
label: yiq >= 128 ? "#1c1c1a" : "#ffffff"
|
|
80
73
|
};
|
|
81
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
|
+
}
|
|
82
103
|
function defaultContentRenderer(card, item) {
|
|
83
104
|
const wrap = document.createElement("div");
|
|
84
105
|
wrap.className = "fg-content";
|
|
@@ -98,12 +119,17 @@ function defaultContentRenderer(card, item) {
|
|
|
98
119
|
card.appendChild(wrap);
|
|
99
120
|
}
|
|
100
121
|
function createFolderGallery(root, options = {}) {
|
|
101
|
-
if (!root ||
|
|
102
|
-
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 };
|
|
103
128
|
const items = Array.isArray(opts.items) ? opts.items : [];
|
|
104
129
|
const n = items.length;
|
|
105
130
|
const renderContent = typeof opts.contentRenderer === "function" ? opts.contentRenderer : defaultContentRenderer;
|
|
106
|
-
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);
|
|
107
133
|
let mode = MODE_WIDTHS[opts.mode] ? opts.mode : "stack";
|
|
108
134
|
let active = Math.min(Math.max(opts.defaultActiveIndex | 0, 0), Math.max(n - 1, 0));
|
|
109
135
|
let scrollCooldown = false;
|
|
@@ -114,9 +140,29 @@ function createFolderGallery(root, options = {}) {
|
|
|
114
140
|
cleanups.push(() => el.removeEventListener(ev, fn, o));
|
|
115
141
|
};
|
|
116
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
|
+
};
|
|
117
162
|
root.classList.add("fg-root");
|
|
118
163
|
root.setAttribute("data-fg-mode", mode);
|
|
119
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");
|
|
120
166
|
const scene = document.createElement("div");
|
|
121
167
|
scene.className = "fg-scene";
|
|
122
168
|
scene.setAttribute("role", "listbox");
|
|
@@ -131,26 +177,48 @@ function createFolderGallery(root, options = {}) {
|
|
|
131
177
|
live.setAttribute("aria-atomic", "true");
|
|
132
178
|
root.append(scene, dotsEl, live);
|
|
133
179
|
function teardown() {
|
|
180
|
+
if (destroyed) return;
|
|
181
|
+
destroyed = true;
|
|
182
|
+
timers.forEach(clearTimeout);
|
|
183
|
+
timers.clear();
|
|
184
|
+
rafs.forEach(cancelAnimationFrame);
|
|
185
|
+
rafs.clear();
|
|
134
186
|
cleanups.forEach((fn) => fn());
|
|
135
187
|
cleanups.length = 0;
|
|
136
188
|
root.replaceChildren();
|
|
137
189
|
root.classList.remove("fg-root");
|
|
138
190
|
root.removeAttribute("data-fg-mode");
|
|
139
191
|
root.removeAttribute("data-fg-peek");
|
|
192
|
+
root.removeAttribute("data-fg-drag");
|
|
193
|
+
INSTANCES.delete(root);
|
|
140
194
|
}
|
|
141
195
|
if (n === 0) {
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
+
};
|
|
148
215
|
}
|
|
149
216
|
function setCardTransform(card, { x, y, z, rx, ry, s, zIndex, opacity, isActive }) {
|
|
150
|
-
card.
|
|
151
|
-
|
|
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
|
+
}
|
|
152
221
|
card.style.zIndex = String(zIndex);
|
|
153
|
-
card.style.opacity = String(opacity);
|
|
154
222
|
card.setAttribute("aria-selected", isActive ? "true" : "false");
|
|
155
223
|
card.classList.toggle("is-active", isActive);
|
|
156
224
|
}
|
|
@@ -160,13 +228,9 @@ function createFolderGallery(root, options = {}) {
|
|
|
160
228
|
card.tabIndex = i === active ? 0 : -1;
|
|
161
229
|
card.setAttribute("role", "option");
|
|
162
230
|
card.setAttribute("aria-label", item.label || `Item ${i + 1}`);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
card.style.setProperty("--fg-front", c.front);
|
|
167
|
-
card.style.setProperty("--fg-front-solid", c.frontSolid);
|
|
168
|
-
card.style.setProperty("--fg-label-on-color", c.label);
|
|
169
|
-
}
|
|
231
|
+
card.setAttribute("aria-setsize", String(n));
|
|
232
|
+
card.setAttribute("aria-posinset", String(i + 1));
|
|
233
|
+
card.setAttribute("data-fg-index", String(i));
|
|
170
234
|
const svg = document.createElementNS(SVG_NS, "svg");
|
|
171
235
|
svg.setAttribute("class", "fg-folder");
|
|
172
236
|
svg.setAttribute("viewBox", "0 0 480 342");
|
|
@@ -174,7 +238,7 @@ function createFolderGallery(root, options = {}) {
|
|
|
174
238
|
svg.setAttribute("aria-hidden", "true");
|
|
175
239
|
const path = document.createElementNS(SVG_NS, "path");
|
|
176
240
|
path.setAttribute("d", opts.folderPath);
|
|
177
|
-
path.setAttribute("fill",
|
|
241
|
+
path.setAttribute("fill", "var(--fg-folder-bg)");
|
|
178
242
|
svg.appendChild(path);
|
|
179
243
|
card.appendChild(svg);
|
|
180
244
|
renderContent(card, item, i);
|
|
@@ -197,6 +261,8 @@ function createFolderGallery(root, options = {}) {
|
|
|
197
261
|
front.appendChild(label);
|
|
198
262
|
}
|
|
199
263
|
card.appendChild(front);
|
|
264
|
+
if (item.color) paintFolder(card, item.color);
|
|
265
|
+
if (item.gradient) paintGradient(card, item.gradient);
|
|
200
266
|
scene.appendChild(card);
|
|
201
267
|
return card;
|
|
202
268
|
});
|
|
@@ -210,9 +276,13 @@ function createFolderGallery(root, options = {}) {
|
|
|
210
276
|
dotsEl.appendChild(dot);
|
|
211
277
|
return dot;
|
|
212
278
|
});
|
|
279
|
+
const clearGridWidth = (card) => {
|
|
280
|
+
if (card.style.width) card.style.width = "";
|
|
281
|
+
};
|
|
213
282
|
function layoutStack() {
|
|
214
283
|
scene.style.height = "";
|
|
215
284
|
cardEls.forEach((card, i) => {
|
|
285
|
+
clearGridWidth(card);
|
|
216
286
|
const behind = (i - active + n) % n;
|
|
217
287
|
if (behind === 0) {
|
|
218
288
|
setCardTransform(card, { x: 0, y: 100, z: 20, rx: 0, ry: 0, s: 1, zIndex: n + 1, opacity: 1, isActive: true });
|
|
@@ -228,33 +298,31 @@ function createFolderGallery(root, options = {}) {
|
|
|
228
298
|
}
|
|
229
299
|
function layoutGrid() {
|
|
230
300
|
const sceneW = scene.clientWidth || MODE_WIDTHS.grid;
|
|
231
|
-
const
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
const
|
|
237
|
-
const scaledH = cardH * sc;
|
|
238
|
-
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);
|
|
239
307
|
const rows = Math.ceil(n / cols);
|
|
240
308
|
cardEls.forEach((card, i) => {
|
|
241
309
|
const col = i % cols;
|
|
242
310
|
const row = Math.floor(i / cols);
|
|
243
311
|
const itemsInRow = Math.min(cols, n - row * cols);
|
|
244
|
-
const rowW = itemsInRow *
|
|
312
|
+
const rowW = itemsInRow * cellW + (itemsInRow - 1) * gap;
|
|
245
313
|
const rowStartX = (sceneW - rowW) / 2;
|
|
246
|
-
const
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
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 });
|
|
251
318
|
});
|
|
252
|
-
scene.style.height = rows *
|
|
319
|
+
scene.style.height = rows * cellH + (rows - 1) * gap + "px";
|
|
253
320
|
}
|
|
254
321
|
function layoutCarousel() {
|
|
255
322
|
const sceneW = scene.clientWidth || MODE_WIDTHS.carousel;
|
|
256
323
|
const cardW = sceneW;
|
|
257
324
|
const cardH = cardW * (2 / 3);
|
|
325
|
+
cardEls.forEach(clearGridWidth);
|
|
258
326
|
const activeSc = 0.62;
|
|
259
327
|
const activeW = cardW * activeSc;
|
|
260
328
|
const sceneH = Math.max(cardH * activeSc + 40, 180);
|
|
@@ -289,29 +357,39 @@ function createFolderGallery(root, options = {}) {
|
|
|
289
357
|
live.textContent = cur && cur.label ? `${active + 1} of ${n}: ${cur.label}` : `${active + 1} of ${n}`;
|
|
290
358
|
}
|
|
291
359
|
function goTo(i) {
|
|
292
|
-
|
|
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);
|
|
293
363
|
if (next === active) return;
|
|
294
364
|
active = next;
|
|
295
365
|
applyLayout();
|
|
296
366
|
emit("fg-activechange", { index: active, item: items[active] });
|
|
297
367
|
}
|
|
298
368
|
function select(i) {
|
|
369
|
+
if (destroyed) return;
|
|
299
370
|
emit("fg-select", { index: i, item: items[i] });
|
|
300
371
|
if (typeof opts.onSelect === "function") opts.onSelect(items[i], i);
|
|
301
372
|
}
|
|
302
373
|
function setMode(m) {
|
|
303
|
-
if (m === mode || !MODE_WIDTHS[m]) return;
|
|
374
|
+
if (destroyed || m === mode || !MODE_WIDTHS[m]) return;
|
|
304
375
|
mode = m;
|
|
305
376
|
root.setAttribute("data-fg-mode", mode);
|
|
306
377
|
applyLayout();
|
|
307
378
|
emit("fg-modechange", { mode });
|
|
308
379
|
}
|
|
309
380
|
function setPeek(p) {
|
|
310
|
-
if (!PEEK_MODES.has(p)) return;
|
|
381
|
+
if (destroyed || !PEEK_MODES.has(p) || p === root.getAttribute("data-fg-peek")) return;
|
|
311
382
|
root.setAttribute("data-fg-peek", p);
|
|
383
|
+
emit("fg-peekchange", { peek: p });
|
|
312
384
|
}
|
|
385
|
+
const dragEnabled = opts.drag !== "off";
|
|
386
|
+
let suppressClick = false;
|
|
313
387
|
cardEls.forEach((card, i) => {
|
|
314
388
|
on(card, "click", () => {
|
|
389
|
+
if (suppressClick) {
|
|
390
|
+
suppressClick = false;
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
315
393
|
i === active ? select(i) : goTo(i);
|
|
316
394
|
});
|
|
317
395
|
on(card, "keydown", (e) => {
|
|
@@ -377,7 +455,7 @@ function createFolderGallery(root, options = {}) {
|
|
|
377
455
|
scrollAccum = 0;
|
|
378
456
|
scrollCooldown = true;
|
|
379
457
|
goTo(active + dir);
|
|
380
|
-
|
|
458
|
+
later(() => {
|
|
381
459
|
scrollCooldown = false;
|
|
382
460
|
scrollAccum = 0;
|
|
383
461
|
}, SCROLL_COOLDOWN[mode] || 300);
|
|
@@ -391,6 +469,7 @@ function createFolderGallery(root, options = {}) {
|
|
|
391
469
|
touchStartY = e.touches[0].clientY;
|
|
392
470
|
}, { passive: true });
|
|
393
471
|
on(scene, "touchend", (e) => {
|
|
472
|
+
if (dragEnabled && mode === "stack") return;
|
|
394
473
|
const dx = touchStartX - e.changedTouches[0].clientX;
|
|
395
474
|
const dy = touchStartY - e.changedTouches[0].clientY;
|
|
396
475
|
const ax = Math.abs(dx);
|
|
@@ -399,22 +478,152 @@ function createFolderGallery(root, options = {}) {
|
|
|
399
478
|
const dir = ax > ay ? dx > 0 ? 1 : -1 : dy > 0 ? 1 : -1;
|
|
400
479
|
goTo(active + dir);
|
|
401
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
|
+
}
|
|
402
583
|
let resizeTimer;
|
|
403
584
|
on(window, "resize", () => {
|
|
404
585
|
clearTimeout(resizeTimer);
|
|
405
|
-
resizeTimer =
|
|
586
|
+
resizeTimer = later(applyLayout, 150);
|
|
406
587
|
});
|
|
588
|
+
if (reducedQuery && reducedQuery.addEventListener) {
|
|
589
|
+
on(reducedQuery, "change", (e) => {
|
|
590
|
+
if (!destroyed) {
|
|
591
|
+
reduced = e.matches;
|
|
592
|
+
applyLayout();
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
}
|
|
407
596
|
applyLayout();
|
|
408
|
-
|
|
597
|
+
const handle = {
|
|
409
598
|
next: () => goTo(active + 1),
|
|
410
599
|
prev: () => goTo(active - 1),
|
|
411
600
|
goTo,
|
|
412
601
|
setMode,
|
|
413
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
|
+
},
|
|
414
611
|
getActiveIndex: () => active,
|
|
415
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(),
|
|
416
623
|
destroy: teardown
|
|
417
624
|
};
|
|
625
|
+
INSTANCES.set(root, teardown);
|
|
626
|
+
return handle;
|
|
418
627
|
}
|
|
419
628
|
|
|
420
629
|
// src/folder-gallery-element.js
|
|
@@ -423,7 +632,7 @@ var ElementBase = typeof HTMLElement !== "undefined" ? HTMLElement : class {
|
|
|
423
632
|
};
|
|
424
633
|
var FolderGalleryElement = class extends ElementBase {
|
|
425
634
|
static get observedAttributes() {
|
|
426
|
-
return ["mode", "peek", "loop", "scroll-nav", "reduced-motion", "default-active-index", "label", "folder-path"];
|
|
635
|
+
return ["mode", "peek", "drag", "loop", "scroll-nav", "reduced-motion", "default-active-index", "label", "folder-path"];
|
|
427
636
|
}
|
|
428
637
|
constructor() {
|
|
429
638
|
super();
|
|
@@ -466,6 +675,7 @@ var FolderGalleryElement = class extends ElementBase {
|
|
|
466
675
|
const opts = { items: this._items };
|
|
467
676
|
if (this.hasAttribute("mode")) opts.mode = this.getAttribute("mode");
|
|
468
677
|
if (this.hasAttribute("peek")) opts.peek = this.getAttribute("peek");
|
|
678
|
+
if (this.hasAttribute("drag")) opts.drag = this.getAttribute("drag");
|
|
469
679
|
if (this.hasAttribute("loop")) opts.loop = asBool(this.getAttribute("loop"));
|
|
470
680
|
if (this.hasAttribute("scroll-nav")) opts.scrollNav = asBool(this.getAttribute("scroll-nav"));
|
|
471
681
|
if (this.hasAttribute("reduced-motion")) opts.reducedMotion = this.getAttribute("reduced-motion");
|
|
@@ -502,12 +712,30 @@ var FolderGalleryElement = class extends ElementBase {
|
|
|
502
712
|
setPeek(p) {
|
|
503
713
|
this.setAttribute("peek", p);
|
|
504
714
|
}
|
|
715
|
+
setColor(i, hex) {
|
|
716
|
+
this._handle && this._handle.setColor(i, hex);
|
|
717
|
+
}
|
|
718
|
+
setGradient(i, gradient) {
|
|
719
|
+
this._handle && this._handle.setGradient(i, gradient);
|
|
720
|
+
}
|
|
505
721
|
getActiveIndex() {
|
|
506
722
|
return this._handle ? this._handle.getActiveIndex() : -1;
|
|
507
723
|
}
|
|
508
724
|
getMode() {
|
|
509
725
|
return this._handle ? this._handle.getMode() : this.getAttribute("mode") || "stack";
|
|
510
726
|
}
|
|
727
|
+
getPeek() {
|
|
728
|
+
return this._handle ? this._handle.getPeek() : this.getAttribute("peek") || "hover";
|
|
729
|
+
}
|
|
730
|
+
getColor(i) {
|
|
731
|
+
return this._handle ? this._handle.getColor(i) : void 0;
|
|
732
|
+
}
|
|
733
|
+
getGradient(i) {
|
|
734
|
+
return this._handle ? this._handle.getGradient(i) : void 0;
|
|
735
|
+
}
|
|
736
|
+
getItems() {
|
|
737
|
+
return this._handle ? this._handle.getItems() : [];
|
|
738
|
+
}
|
|
511
739
|
};
|
|
512
740
|
function defineFolderGallery(tag = "folder-gallery") {
|
|
513
741
|
if (typeof customElements !== "undefined" && !customElements.get(tag)) {
|