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/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'
@@ -50,19 +41,27 @@ var DEFAULTS = {
50
41
  // 'auto' | 'off' | 'force'
51
42
  peek: "hover",
52
43
  // 'hover' | 'always' | 'off'
44
+ drag: "fling",
45
+ // 'fling' | 'off' - grab the active folder and throw it (stack mode)
53
46
  defaultActiveIndex: 0,
54
47
  label: "Folder gallery"
55
48
  };
56
49
  var PEEK_MODES = /* @__PURE__ */ new Set(["hover", "always", "off"]);
50
+ var DRAG_MODES = /* @__PURE__ */ new Set(["fling", "off"]);
51
+ var INSTANCES = /* @__PURE__ */ new WeakMap();
57
52
  var MODE_WIDTHS = { stack: 480, grid: 720, carousel: 720 };
58
53
  var SCROLL_THRESHOLD = 30;
59
54
  var SCROLL_COOLDOWN = { stack: 450, carousel: 300 };
60
55
  function hexToRgb(hex) {
61
- const h = String(hex).replace("#", "");
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;
62
59
  return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
63
60
  }
64
61
  function folderColors(hex) {
65
- const [r, g, b] = hexToRgb(hex);
62
+ const rgb = hexToRgb(hex);
63
+ if (!rgb) return null;
64
+ const [r, g, b] = rgb;
66
65
  const dn = (v) => Math.max(v - 30, 0);
67
66
  const up = (v, o) => Math.min(v + o, 255);
68
67
  const fr = up(r, 35);
@@ -76,6 +75,34 @@ function folderColors(hex) {
76
75
  label: yiq >= 128 ? "#1c1c1a" : "#ffffff"
77
76
  };
78
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
+ }
79
106
  function defaultContentRenderer(card, item) {
80
107
  const wrap = document.createElement("div");
81
108
  wrap.className = "fg-content";
@@ -95,12 +122,17 @@ function defaultContentRenderer(card, item) {
95
122
  card.appendChild(wrap);
96
123
  }
97
124
  function createFolderGallery(root, options = {}) {
98
- if (!root || !root.nodeType) throw new Error("createFolderGallery: a root element is required");
99
- const opts = __spreadValues(__spreadValues({}, DEFAULTS), options);
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 };
100
131
  const items = Array.isArray(opts.items) ? opts.items : [];
101
132
  const n = items.length;
102
133
  const renderContent = typeof opts.contentRenderer === "function" ? opts.contentRenderer : defaultContentRenderer;
103
- const reduced = opts.reducedMotion === "force" || opts.reducedMotion !== "off" && typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
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);
104
136
  let mode = MODE_WIDTHS[opts.mode] ? opts.mode : "stack";
105
137
  let active = Math.min(Math.max(opts.defaultActiveIndex | 0, 0), Math.max(n - 1, 0));
106
138
  let scrollCooldown = false;
@@ -111,9 +143,29 @@ function createFolderGallery(root, options = {}) {
111
143
  cleanups.push(() => el.removeEventListener(ev, fn, o));
112
144
  };
113
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
+ };
114
165
  root.classList.add("fg-root");
115
166
  root.setAttribute("data-fg-mode", mode);
116
167
  root.setAttribute("data-fg-peek", PEEK_MODES.has(opts.peek) ? opts.peek : "hover");
168
+ root.setAttribute("data-fg-drag", DRAG_MODES.has(opts.drag) ? opts.drag : "fling");
117
169
  const scene = document.createElement("div");
118
170
  scene.className = "fg-scene";
119
171
  scene.setAttribute("role", "listbox");
@@ -128,26 +180,48 @@ function createFolderGallery(root, options = {}) {
128
180
  live.setAttribute("aria-atomic", "true");
129
181
  root.append(scene, dotsEl, live);
130
182
  function teardown() {
183
+ if (destroyed) return;
184
+ destroyed = true;
185
+ timers.forEach(clearTimeout);
186
+ timers.clear();
187
+ rafs.forEach(cancelAnimationFrame);
188
+ rafs.clear();
131
189
  cleanups.forEach((fn) => fn());
132
190
  cleanups.length = 0;
133
191
  root.replaceChildren();
134
192
  root.classList.remove("fg-root");
135
193
  root.removeAttribute("data-fg-mode");
136
194
  root.removeAttribute("data-fg-peek");
195
+ root.removeAttribute("data-fg-drag");
196
+ INSTANCES.delete(root);
137
197
  }
138
198
  if (n === 0) {
139
- return { next() {
140
- }, prev() {
141
- }, goTo() {
142
- }, setMode() {
143
- }, setPeek() {
144
- }, getActiveIndex: () => -1, getMode: () => mode, destroy: teardown };
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
+ };
145
218
  }
146
219
  function setCardTransform(card, { x, y, z, rx, ry, s, zIndex, opacity, isActive }) {
147
- card.style.transform = `translate3d(${x}px,${y}px,${z}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${s})`;
148
- card.style.transformOrigin = "center bottom";
220
+ if (!card.classList.contains("fg-card--flung")) {
221
+ card.style.transform = `translate3d(${x}px,${y}px,${z}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${s})`;
222
+ card.style.opacity = String(opacity);
223
+ }
149
224
  card.style.zIndex = String(zIndex);
150
- card.style.opacity = String(opacity);
151
225
  card.setAttribute("aria-selected", isActive ? "true" : "false");
152
226
  card.classList.toggle("is-active", isActive);
153
227
  }
@@ -157,13 +231,9 @@ function createFolderGallery(root, options = {}) {
157
231
  card.tabIndex = i === active ? 0 : -1;
158
232
  card.setAttribute("role", "option");
159
233
  card.setAttribute("aria-label", item.label || `Item ${i + 1}`);
160
- if (item.color) {
161
- const c = folderColors(item.color);
162
- card.style.setProperty("--fg-folder-bg", item.color);
163
- card.style.setProperty("--fg-front", c.front);
164
- card.style.setProperty("--fg-front-solid", c.frontSolid);
165
- card.style.setProperty("--fg-label-on-color", c.label);
166
- }
234
+ card.setAttribute("aria-setsize", String(n));
235
+ card.setAttribute("aria-posinset", String(i + 1));
236
+ card.setAttribute("data-fg-index", String(i));
167
237
  const svg = document.createElementNS(SVG_NS, "svg");
168
238
  svg.setAttribute("class", "fg-folder");
169
239
  svg.setAttribute("viewBox", "0 0 480 342");
@@ -171,7 +241,7 @@ function createFolderGallery(root, options = {}) {
171
241
  svg.setAttribute("aria-hidden", "true");
172
242
  const path = document.createElementNS(SVG_NS, "path");
173
243
  path.setAttribute("d", opts.folderPath);
174
- path.setAttribute("fill", item.color ? folderColors(item.color).back : "var(--fg-folder-bg)");
244
+ path.setAttribute("fill", "var(--fg-folder-bg)");
175
245
  svg.appendChild(path);
176
246
  card.appendChild(svg);
177
247
  renderContent(card, item, i);
@@ -194,6 +264,8 @@ function createFolderGallery(root, options = {}) {
194
264
  front.appendChild(label);
195
265
  }
196
266
  card.appendChild(front);
267
+ if (item.color) paintFolder(card, item.color);
268
+ if (item.gradient) paintGradient(card, item.gradient);
197
269
  scene.appendChild(card);
198
270
  return card;
199
271
  });
@@ -207,9 +279,13 @@ function createFolderGallery(root, options = {}) {
207
279
  dotsEl.appendChild(dot);
208
280
  return dot;
209
281
  });
282
+ const clearGridWidth = (card) => {
283
+ if (card.style.width) card.style.width = "";
284
+ };
210
285
  function layoutStack() {
211
286
  scene.style.height = "";
212
287
  cardEls.forEach((card, i) => {
288
+ clearGridWidth(card);
213
289
  const behind = (i - active + n) % n;
214
290
  if (behind === 0) {
215
291
  setCardTransform(card, { x: 0, y: 100, z: 20, rx: 0, ry: 0, s: 1, zIndex: n + 1, opacity: 1, isActive: true });
@@ -225,33 +301,31 @@ function createFolderGallery(root, options = {}) {
225
301
  }
226
302
  function layoutGrid() {
227
303
  const sceneW = scene.clientWidth || MODE_WIDTHS.grid;
228
- const cols = sceneW < 520 ? 2 : n <= 4 ? 2 : 3;
229
- const gap = 16;
230
- const cardW = sceneW;
231
- const cardH = sceneW * (2 / 3);
232
- const sc = (sceneW - (cols - 1) * gap) / (cols * cardW);
233
- const scaledW = cardW * sc;
234
- const scaledH = cardH * sc;
235
- 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);
236
310
  const rows = Math.ceil(n / cols);
237
311
  cardEls.forEach((card, i) => {
238
312
  const col = i % cols;
239
313
  const row = Math.floor(i / cols);
240
314
  const itemsInRow = Math.min(cols, n - row * cols);
241
- const rowW = itemsInRow * scaledW + (itemsInRow - 1) * gap;
315
+ const rowW = itemsInRow * cellW + (itemsInRow - 1) * gap;
242
316
  const rowStartX = (sceneW - rowW) / 2;
243
- const cellLeft = rowStartX + col * (scaledW + gap);
244
- const cellTop = row * (scaledH + tabScaled + gap) + tabScaled;
245
- const tx = cellLeft + scaledW / 2 - cardW / 2;
246
- const ty = cellTop + scaledH - cardH;
247
- 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 });
248
321
  });
249
- scene.style.height = rows * (scaledH + tabScaled + gap) + 20 + "px";
322
+ scene.style.height = rows * cellH + (rows - 1) * gap + "px";
250
323
  }
251
324
  function layoutCarousel() {
252
325
  const sceneW = scene.clientWidth || MODE_WIDTHS.carousel;
253
326
  const cardW = sceneW;
254
327
  const cardH = cardW * (2 / 3);
328
+ cardEls.forEach(clearGridWidth);
255
329
  const activeSc = 0.62;
256
330
  const activeW = cardW * activeSc;
257
331
  const sceneH = Math.max(cardH * activeSc + 40, 180);
@@ -286,29 +360,39 @@ function createFolderGallery(root, options = {}) {
286
360
  live.textContent = cur && cur.label ? `${active + 1} of ${n}: ${cur.label}` : `${active + 1} of ${n}`;
287
361
  }
288
362
  function goTo(i) {
289
- const next = opts.loop ? (i % n + n) % n : Math.min(Math.max(i, 0), n - 1);
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);
290
366
  if (next === active) return;
291
367
  active = next;
292
368
  applyLayout();
293
369
  emit("fg-activechange", { index: active, item: items[active] });
294
370
  }
295
371
  function select(i) {
372
+ if (destroyed) return;
296
373
  emit("fg-select", { index: i, item: items[i] });
297
374
  if (typeof opts.onSelect === "function") opts.onSelect(items[i], i);
298
375
  }
299
376
  function setMode(m) {
300
- if (m === mode || !MODE_WIDTHS[m]) return;
377
+ if (destroyed || m === mode || !MODE_WIDTHS[m]) return;
301
378
  mode = m;
302
379
  root.setAttribute("data-fg-mode", mode);
303
380
  applyLayout();
304
381
  emit("fg-modechange", { mode });
305
382
  }
306
383
  function setPeek(p) {
307
- if (!PEEK_MODES.has(p)) return;
384
+ if (destroyed || !PEEK_MODES.has(p) || p === root.getAttribute("data-fg-peek")) return;
308
385
  root.setAttribute("data-fg-peek", p);
386
+ emit("fg-peekchange", { peek: p });
309
387
  }
388
+ const dragEnabled = opts.drag !== "off";
389
+ let suppressClick = false;
310
390
  cardEls.forEach((card, i) => {
311
391
  on(card, "click", () => {
392
+ if (suppressClick) {
393
+ suppressClick = false;
394
+ return;
395
+ }
312
396
  i === active ? select(i) : goTo(i);
313
397
  });
314
398
  on(card, "keydown", (e) => {
@@ -374,7 +458,7 @@ function createFolderGallery(root, options = {}) {
374
458
  scrollAccum = 0;
375
459
  scrollCooldown = true;
376
460
  goTo(active + dir);
377
- setTimeout(() => {
461
+ later(() => {
378
462
  scrollCooldown = false;
379
463
  scrollAccum = 0;
380
464
  }, SCROLL_COOLDOWN[mode] || 300);
@@ -388,6 +472,7 @@ function createFolderGallery(root, options = {}) {
388
472
  touchStartY = e.touches[0].clientY;
389
473
  }, { passive: true });
390
474
  on(scene, "touchend", (e) => {
475
+ if (dragEnabled && mode === "stack") return;
391
476
  const dx = touchStartX - e.changedTouches[0].clientX;
392
477
  const dy = touchStartY - e.changedTouches[0].clientY;
393
478
  const ax = Math.abs(dx);
@@ -396,26 +481,157 @@ function createFolderGallery(root, options = {}) {
396
481
  const dir = ax > ay ? dx > 0 ? 1 : -1 : dy > 0 ? 1 : -1;
397
482
  goTo(active + dir);
398
483
  }, { passive: true });
484
+ if (dragEnabled) {
485
+ const DRAG_ROT = 0.04;
486
+ const FLING_DIST = 90;
487
+ const FLING_VEL = 0.5;
488
+ const TAP_SLOP = 6;
489
+ let dragCard = null;
490
+ let dragBase = "";
491
+ let startPX = 0, startPY = 0, dragDX = 0, dragDY = 0;
492
+ let lastX = 0, lastY = 0, lastT = 0, velX = 0, velY = 0;
493
+ on(scene, "pointerdown", (e) => {
494
+ if (mode !== "stack") return;
495
+ if (e.button !== void 0 && e.button !== 0) return;
496
+ const card = e.target && e.target.closest ? e.target.closest(".fg-card") : null;
497
+ if (!card || !card.classList.contains("is-active")) return;
498
+ dragCard = card;
499
+ dragBase = card.style.transform;
500
+ startPX = e.clientX;
501
+ startPY = e.clientY;
502
+ dragDX = 0;
503
+ dragDY = 0;
504
+ lastX = e.clientX;
505
+ lastY = e.clientY;
506
+ lastT = typeof performance !== "undefined" ? performance.now() : Date.now();
507
+ velX = 0;
508
+ velY = 0;
509
+ card.classList.add("fg-card--dragging");
510
+ if (card.setPointerCapture && e.pointerId !== void 0) {
511
+ try {
512
+ card.setPointerCapture(e.pointerId);
513
+ } catch (_) {
514
+ }
515
+ }
516
+ });
517
+ on(window, "pointermove", (e) => {
518
+ if (!dragCard) return;
519
+ dragDX = e.clientX - startPX;
520
+ dragDY = e.clientY - startPY;
521
+ const now = typeof performance !== "undefined" ? performance.now() : Date.now();
522
+ const dt = Math.max(now - lastT, 1);
523
+ velX = (e.clientX - lastX) / dt;
524
+ velY = (e.clientY - lastY) / dt;
525
+ lastX = e.clientX;
526
+ lastY = e.clientY;
527
+ lastT = now;
528
+ dragCard.style.transform = `${dragBase} translate3d(${dragDX}px, ${dragDY}px, 40px) rotate(${(dragDX * DRAG_ROT).toFixed(2)}deg)`;
529
+ });
530
+ const endDrag = () => {
531
+ if (!dragCard) return;
532
+ const card = dragCard;
533
+ dragCard = null;
534
+ card.classList.remove("fg-card--dragging");
535
+ const dist = Math.hypot(dragDX, dragDY);
536
+ if (dist < TAP_SLOP) {
537
+ card.style.transform = dragBase;
538
+ return;
539
+ }
540
+ suppressClick = true;
541
+ const horizontal = Math.abs(dragDX) >= Math.abs(dragDY);
542
+ const flung = dist > FLING_DIST || Math.hypot(velX, velY) > FLING_VEL;
543
+ const dir = horizontal ? dragDX > 0 ? -1 : 1 : dragDY > 0 ? -1 : 1;
544
+ const target = active + dir;
545
+ const blocked = !opts.loop && (target < 0 || target > n - 1);
546
+ if (!flung || blocked) {
547
+ card.style.transform = dragBase;
548
+ return;
549
+ }
550
+ const semantic = dir > 0 ? "next" : "prev";
551
+ emit("fg-flingstart", { index: active, direction: semantic });
552
+ if (reduced) {
553
+ goTo(target);
554
+ emit("fg-flingend", { index: target, direction: semantic });
555
+ return;
556
+ }
557
+ const offX = horizontal ? Math.sign(dragDX) * Math.max(window.innerWidth * 0.7, 480) : dragDX * 3;
558
+ const offY = horizontal ? dragDY * 3 : Math.sign(dragDY) * Math.max(window.innerHeight * 0.7, 480);
559
+ card.classList.add("fg-card--flung");
560
+ card.style.transform = `${dragBase} translate3d(${offX}px, ${offY}px, 40px) rotate(${Math.sign(dragDX || 1) * 18}deg)`;
561
+ card.style.opacity = "0";
562
+ goTo(target);
563
+ later(() => {
564
+ card.classList.add("fg-card--snap");
565
+ card.classList.remove("fg-card--flung");
566
+ applyLayout();
567
+ const slot = card.style.transform;
568
+ const slotOpacity = card.style.opacity;
569
+ card.style.transform = `${slot} translate3d(0, -90px, 0)`;
570
+ card.style.opacity = "0";
571
+ frame(() => frame(() => {
572
+ card.classList.remove("fg-card--snap");
573
+ card.classList.add("fg-card--entering");
574
+ card.style.transform = slot;
575
+ card.style.opacity = slotOpacity;
576
+ later(() => {
577
+ card.classList.remove("fg-card--entering");
578
+ emit("fg-flingend", { index: target, direction: semantic });
579
+ }, 700);
580
+ }));
581
+ }, 400);
582
+ };
583
+ on(window, "pointerup", endDrag);
584
+ on(window, "pointercancel", endDrag);
585
+ }
399
586
  let resizeTimer;
400
587
  on(window, "resize", () => {
401
588
  clearTimeout(resizeTimer);
402
- resizeTimer = setTimeout(applyLayout, 150);
589
+ resizeTimer = later(applyLayout, 150);
403
590
  });
591
+ if (reducedQuery && reducedQuery.addEventListener) {
592
+ on(reducedQuery, "change", (e) => {
593
+ if (!destroyed) {
594
+ reduced = e.matches;
595
+ applyLayout();
596
+ }
597
+ });
598
+ }
404
599
  applyLayout();
405
- return {
600
+ const handle = {
406
601
  next: () => goTo(active + 1),
407
602
  prev: () => goTo(active - 1),
408
603
  goTo,
409
604
  setMode,
410
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
+ },
411
614
  getActiveIndex: () => active,
412
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(),
413
626
  destroy: teardown
414
627
  };
628
+ INSTANCES.set(root, teardown);
629
+ return handle;
415
630
  }
416
631
  var folder_gallery_default = createFolderGallery;
417
632
  // Annotate the CommonJS export names for ESM import in node:
418
633
  0 && (module.exports = {
634
+ FOLDER_PATHS,
419
635
  createFolderGallery
420
636
  });
421
637
  //# sourceMappingURL=index.cjs.map