flipfolio 0.1.0 → 0.2.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 +9 -3
- package/dist/{chunk-DT6YOBGV.js → chunk-Q2NKZMCC.js} +113 -3
- package/dist/chunk-Q2NKZMCC.js.map +1 -0
- package/dist/element.cjs +114 -3
- package/dist/element.cjs.map +1 -1
- package/dist/element.js +3 -2
- package/dist/element.js.map +1 -1
- package/dist/folder-gallery.css +32 -0
- package/dist/index.cjs +112 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -1
- package/dist/react.cjs +116 -3
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.ts +2 -1
- package/dist/react.js +5 -2
- package/dist/react.js.map +1 -1
- package/dist/vue.cjs +115 -2
- package/dist/vue.cjs.map +1 -1
- package/dist/vue.d.ts +2 -1
- package/dist/vue.js +4 -1
- package/dist/vue.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-DT6YOBGV.js.map +0 -1
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 defaultActiveIndex: 0,\n label: 'Folder gallery',\n};\n\nconst PEEK_MODES = new Set(['hover', 'always', '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 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 }\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 card.style.transform = `translate3d(${x}px,${y}px,${z}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${s})`;\n card.style.transformOrigin = 'center bottom';\n card.style.zIndex = String(zIndex);\n card.style.opacity = String(opacity);\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 cardEls.forEach((card, i) => {\n on(card, 'click', () => { i === active ? select(i) : goTo(i); });\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 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 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 * 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":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export interface FolderItem {
|
|
|
15
15
|
|
|
16
16
|
export type GalleryMode = 'stack' | 'grid' | 'carousel';
|
|
17
17
|
export type PeekMode = 'hover' | 'always' | 'off';
|
|
18
|
+
export type DragMode = 'fling' | 'off';
|
|
18
19
|
|
|
19
20
|
export interface FolderGalleryOptions {
|
|
20
21
|
items?: FolderItem[];
|
|
@@ -30,6 +31,8 @@ export interface FolderGalleryOptions {
|
|
|
30
31
|
reducedMotion?: 'auto' | 'off' | 'force';
|
|
31
32
|
/** Contents sliding out of the folder: on hover (default), always, or off. */
|
|
32
33
|
peek?: PeekMode;
|
|
34
|
+
/** Grab the active folder and throw it to navigate (stack mode). Default 'fling'. */
|
|
35
|
+
drag?: DragMode;
|
|
33
36
|
defaultActiveIndex?: number;
|
|
34
37
|
/** aria-label for the listbox. */
|
|
35
38
|
label?: string;
|
package/dist/index.js
CHANGED
package/dist/react.cjs
CHANGED
|
@@ -65,10 +65,13 @@ var DEFAULTS = {
|
|
|
65
65
|
// 'auto' | 'off' | 'force'
|
|
66
66
|
peek: "hover",
|
|
67
67
|
// 'hover' | 'always' | 'off'
|
|
68
|
+
drag: "fling",
|
|
69
|
+
// 'fling' | 'off' - grab the active folder and throw it (stack mode)
|
|
68
70
|
defaultActiveIndex: 0,
|
|
69
71
|
label: "Folder gallery"
|
|
70
72
|
};
|
|
71
73
|
var PEEK_MODES = /* @__PURE__ */ new Set(["hover", "always", "off"]);
|
|
74
|
+
var DRAG_MODES = /* @__PURE__ */ new Set(["fling", "off"]);
|
|
72
75
|
var MODE_WIDTHS = { stack: 480, grid: 720, carousel: 720 };
|
|
73
76
|
var SCROLL_THRESHOLD = 30;
|
|
74
77
|
var SCROLL_COOLDOWN = { stack: 450, carousel: 300 };
|
|
@@ -129,6 +132,7 @@ function createFolderGallery(root, options = {}) {
|
|
|
129
132
|
root.classList.add("fg-root");
|
|
130
133
|
root.setAttribute("data-fg-mode", mode);
|
|
131
134
|
root.setAttribute("data-fg-peek", PEEK_MODES.has(opts.peek) ? opts.peek : "hover");
|
|
135
|
+
root.setAttribute("data-fg-drag", DRAG_MODES.has(opts.drag) ? opts.drag : "fling");
|
|
132
136
|
const scene = document.createElement("div");
|
|
133
137
|
scene.className = "fg-scene";
|
|
134
138
|
scene.setAttribute("role", "listbox");
|
|
@@ -149,6 +153,7 @@ function createFolderGallery(root, options = {}) {
|
|
|
149
153
|
root.classList.remove("fg-root");
|
|
150
154
|
root.removeAttribute("data-fg-mode");
|
|
151
155
|
root.removeAttribute("data-fg-peek");
|
|
156
|
+
root.removeAttribute("data-fg-drag");
|
|
152
157
|
}
|
|
153
158
|
if (n === 0) {
|
|
154
159
|
return { next() {
|
|
@@ -159,10 +164,12 @@ function createFolderGallery(root, options = {}) {
|
|
|
159
164
|
}, getActiveIndex: () => -1, getMode: () => mode, destroy: teardown };
|
|
160
165
|
}
|
|
161
166
|
function setCardTransform(card, { x, y, z, rx, ry, s, zIndex, opacity, isActive }) {
|
|
162
|
-
card.
|
|
167
|
+
if (!card.classList.contains("fg-card--flung")) {
|
|
168
|
+
card.style.transform = `translate3d(${x}px,${y}px,${z}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${s})`;
|
|
169
|
+
card.style.opacity = String(opacity);
|
|
170
|
+
}
|
|
163
171
|
card.style.transformOrigin = "center bottom";
|
|
164
172
|
card.style.zIndex = String(zIndex);
|
|
165
|
-
card.style.opacity = String(opacity);
|
|
166
173
|
card.setAttribute("aria-selected", isActive ? "true" : "false");
|
|
167
174
|
card.classList.toggle("is-active", isActive);
|
|
168
175
|
}
|
|
@@ -322,8 +329,14 @@ function createFolderGallery(root, options = {}) {
|
|
|
322
329
|
if (!PEEK_MODES.has(p)) return;
|
|
323
330
|
root.setAttribute("data-fg-peek", p);
|
|
324
331
|
}
|
|
332
|
+
const dragEnabled = opts.drag !== "off";
|
|
333
|
+
let suppressClick = false;
|
|
325
334
|
cardEls.forEach((card, i) => {
|
|
326
335
|
on(card, "click", () => {
|
|
336
|
+
if (suppressClick) {
|
|
337
|
+
suppressClick = false;
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
327
340
|
i === active ? select(i) : goTo(i);
|
|
328
341
|
});
|
|
329
342
|
on(card, "keydown", (e) => {
|
|
@@ -403,6 +416,7 @@ function createFolderGallery(root, options = {}) {
|
|
|
403
416
|
touchStartY = e.touches[0].clientY;
|
|
404
417
|
}, { passive: true });
|
|
405
418
|
on(scene, "touchend", (e) => {
|
|
419
|
+
if (dragEnabled && mode === "stack") return;
|
|
406
420
|
const dx = touchStartX - e.changedTouches[0].clientX;
|
|
407
421
|
const dy = touchStartY - e.changedTouches[0].clientY;
|
|
408
422
|
const ax = Math.abs(dx);
|
|
@@ -411,6 +425,102 @@ function createFolderGallery(root, options = {}) {
|
|
|
411
425
|
const dir = ax > ay ? dx > 0 ? 1 : -1 : dy > 0 ? 1 : -1;
|
|
412
426
|
goTo(active + dir);
|
|
413
427
|
}, { passive: true });
|
|
428
|
+
if (dragEnabled) {
|
|
429
|
+
const DRAG_ROT = 0.04;
|
|
430
|
+
const FLING_DIST = 90;
|
|
431
|
+
const FLING_VEL = 0.5;
|
|
432
|
+
const TAP_SLOP = 6;
|
|
433
|
+
let dragCard = null;
|
|
434
|
+
let dragBase = "";
|
|
435
|
+
let startPX = 0, startPY = 0, dragDX = 0, dragDY = 0;
|
|
436
|
+
let lastX = 0, lastY = 0, lastT = 0, velX = 0, velY = 0;
|
|
437
|
+
on(scene, "pointerdown", (e) => {
|
|
438
|
+
if (mode !== "stack") return;
|
|
439
|
+
if (e.button !== void 0 && e.button !== 0) return;
|
|
440
|
+
const card = e.target && e.target.closest ? e.target.closest(".fg-card") : null;
|
|
441
|
+
if (!card || !card.classList.contains("is-active")) return;
|
|
442
|
+
dragCard = card;
|
|
443
|
+
dragBase = card.style.transform;
|
|
444
|
+
startPX = e.clientX;
|
|
445
|
+
startPY = e.clientY;
|
|
446
|
+
dragDX = 0;
|
|
447
|
+
dragDY = 0;
|
|
448
|
+
lastX = e.clientX;
|
|
449
|
+
lastY = e.clientY;
|
|
450
|
+
lastT = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
451
|
+
velX = 0;
|
|
452
|
+
velY = 0;
|
|
453
|
+
card.classList.add("fg-card--dragging");
|
|
454
|
+
if (card.setPointerCapture && e.pointerId !== void 0) {
|
|
455
|
+
try {
|
|
456
|
+
card.setPointerCapture(e.pointerId);
|
|
457
|
+
} catch (_) {
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
on(window, "pointermove", (e) => {
|
|
462
|
+
if (!dragCard) return;
|
|
463
|
+
dragDX = e.clientX - startPX;
|
|
464
|
+
dragDY = e.clientY - startPY;
|
|
465
|
+
const now = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
466
|
+
const dt = Math.max(now - lastT, 1);
|
|
467
|
+
velX = (e.clientX - lastX) / dt;
|
|
468
|
+
velY = (e.clientY - lastY) / dt;
|
|
469
|
+
lastX = e.clientX;
|
|
470
|
+
lastY = e.clientY;
|
|
471
|
+
lastT = now;
|
|
472
|
+
dragCard.style.transform = `${dragBase} translate3d(${dragDX}px, ${dragDY}px, 40px) rotate(${(dragDX * DRAG_ROT).toFixed(2)}deg)`;
|
|
473
|
+
});
|
|
474
|
+
const endDrag = () => {
|
|
475
|
+
if (!dragCard) return;
|
|
476
|
+
const card = dragCard;
|
|
477
|
+
dragCard = null;
|
|
478
|
+
card.classList.remove("fg-card--dragging");
|
|
479
|
+
const dist = Math.hypot(dragDX, dragDY);
|
|
480
|
+
if (dist < TAP_SLOP) {
|
|
481
|
+
card.style.transform = dragBase;
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
suppressClick = true;
|
|
485
|
+
const horizontal = Math.abs(dragDX) >= Math.abs(dragDY);
|
|
486
|
+
const flung = dist > FLING_DIST || Math.hypot(velX, velY) > FLING_VEL;
|
|
487
|
+
const dir = horizontal ? dragDX > 0 ? -1 : 1 : dragDY > 0 ? -1 : 1;
|
|
488
|
+
const target = active + dir;
|
|
489
|
+
const blocked = !opts.loop && (target < 0 || target > n - 1);
|
|
490
|
+
if (!flung || blocked) {
|
|
491
|
+
card.style.transform = dragBase;
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (reduced) {
|
|
495
|
+
goTo(target);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
const offX = horizontal ? Math.sign(dragDX) * Math.max(window.innerWidth * 0.7, 480) : dragDX * 3;
|
|
499
|
+
const offY = horizontal ? dragDY * 3 : Math.sign(dragDY) * Math.max(window.innerHeight * 0.7, 480);
|
|
500
|
+
card.classList.add("fg-card--flung");
|
|
501
|
+
card.style.transform = `${dragBase} translate3d(${offX}px, ${offY}px, 40px) rotate(${Math.sign(dragDX || 1) * 18}deg)`;
|
|
502
|
+
card.style.opacity = "0";
|
|
503
|
+
goTo(target);
|
|
504
|
+
setTimeout(() => {
|
|
505
|
+
card.classList.add("fg-card--snap");
|
|
506
|
+
card.classList.remove("fg-card--flung");
|
|
507
|
+
applyLayout();
|
|
508
|
+
const slot = card.style.transform;
|
|
509
|
+
const slotOpacity = card.style.opacity;
|
|
510
|
+
card.style.transform = `${slot} translate3d(0, -90px, 0)`;
|
|
511
|
+
card.style.opacity = "0";
|
|
512
|
+
requestAnimationFrame(() => requestAnimationFrame(() => {
|
|
513
|
+
card.classList.remove("fg-card--snap");
|
|
514
|
+
card.classList.add("fg-card--entering");
|
|
515
|
+
card.style.transform = slot;
|
|
516
|
+
card.style.opacity = slotOpacity;
|
|
517
|
+
setTimeout(() => card.classList.remove("fg-card--entering"), 700);
|
|
518
|
+
}));
|
|
519
|
+
}, 400);
|
|
520
|
+
};
|
|
521
|
+
on(window, "pointerup", endDrag);
|
|
522
|
+
on(window, "pointercancel", endDrag);
|
|
523
|
+
}
|
|
414
524
|
let resizeTimer;
|
|
415
525
|
on(window, "resize", () => {
|
|
416
526
|
clearTimeout(resizeTimer);
|
|
@@ -435,6 +545,7 @@ var FolderGallery = (0, import_react.forwardRef)(function FolderGallery2(props,
|
|
|
435
545
|
items,
|
|
436
546
|
mode = "stack",
|
|
437
547
|
peek = "hover",
|
|
548
|
+
drag = "fling",
|
|
438
549
|
contentRenderer,
|
|
439
550
|
onSelect,
|
|
440
551
|
onActiveChange,
|
|
@@ -451,6 +562,7 @@ var FolderGallery = (0, import_react.forwardRef)(function FolderGallery2(props,
|
|
|
451
562
|
"items",
|
|
452
563
|
"mode",
|
|
453
564
|
"peek",
|
|
565
|
+
"drag",
|
|
454
566
|
"contentRenderer",
|
|
455
567
|
"onSelect",
|
|
456
568
|
"onActiveChange",
|
|
@@ -475,6 +587,7 @@ var FolderGallery = (0, import_react.forwardRef)(function FolderGallery2(props,
|
|
|
475
587
|
items,
|
|
476
588
|
mode,
|
|
477
589
|
peek,
|
|
590
|
+
drag,
|
|
478
591
|
folderPath,
|
|
479
592
|
loop,
|
|
480
593
|
scrollNav,
|
|
@@ -504,7 +617,7 @@ var FolderGallery = (0, import_react.forwardRef)(function FolderGallery2(props,
|
|
|
504
617
|
handle.destroy();
|
|
505
618
|
handleRef.current = null;
|
|
506
619
|
};
|
|
507
|
-
}, [items, folderPath, loop, scrollNav, reducedMotion, defaultActiveIndex, label]);
|
|
620
|
+
}, [items, drag, folderPath, loop, scrollNav, reducedMotion, defaultActiveIndex, label]);
|
|
508
621
|
(0, import_react.useEffect)(() => {
|
|
509
622
|
if (handleRef.current && handleRef.current.getMode() !== mode) {
|
|
510
623
|
handleRef.current.setMode(mode);
|
package/dist/react.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/folder-gallery-react.js","../src/folder-gallery.js"],"sourcesContent":["/* ============================================================================\n * folder-gallery/react - thin React wrapper over the framework-agnostic core.\n *\n * import { FolderGallery } from 'folder-gallery/react';\n * import 'folder-gallery/styles.css';\n *\n * <FolderGallery\n * items={items}\n * mode=\"stack\"\n * onSelect={(item, i) => ...}\n * ref={galleryRef} // -> { next, prev, goTo, setMode, getActiveIndex, getMode }\n * />\n *\n * Written without JSX so the package builds with no React toolchain;\n * React is a peer dependency and only resolved in the consumer's app.\n * ========================================================================== */\n\nimport { createElement, forwardRef, useEffect, useImperativeHandle, useRef } from 'react';\nimport { createFolderGallery } from './folder-gallery.js';\n\nexport const FolderGallery = forwardRef(function FolderGallery(props, ref) {\n const {\n items,\n mode = 'stack',\n peek = 'hover',\n contentRenderer,\n onSelect,\n onActiveChange,\n onModeChange,\n folderPath,\n loop,\n scrollNav,\n reducedMotion,\n defaultActiveIndex,\n label,\n className,\n style,\n ...rest\n } = props;\n\n const rootRef = useRef(null);\n const handleRef = useRef(null);\n\n // Callbacks live in refs so a new inline closure per render doesn't force a\n // full gallery rebuild (and the core never holds a stale reference).\n const callbacksRef = useRef({});\n callbacksRef.current = { onSelect, onActiveChange, onModeChange, contentRenderer };\n\n // (Re)build when the structural inputs change.\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return undefined;\n\n const handle = createFolderGallery(root, {\n items,\n mode,\n peek,\n folderPath,\n loop,\n scrollNav,\n reducedMotion,\n defaultActiveIndex,\n label,\n contentRenderer: callbacksRef.current.contentRenderer\n ? (card, item, i) => callbacksRef.current.contentRenderer(card, item, i)\n : undefined,\n onSelect: (item, i) => {\n const fn = callbacksRef.current.onSelect;\n if (fn) fn(item, i);\n },\n });\n handleRef.current = handle;\n\n const onActive = (e) => {\n const fn = callbacksRef.current.onActiveChange;\n if (fn) fn(e.detail.index, e.detail.item);\n };\n const onModeEv = (e) => {\n const fn = callbacksRef.current.onModeChange;\n if (fn) fn(e.detail.mode);\n };\n root.addEventListener('fg-activechange', onActive);\n root.addEventListener('fg-modechange', onModeEv);\n\n return () => {\n root.removeEventListener('fg-activechange', onActive);\n root.removeEventListener('fg-modechange', onModeEv);\n handle.destroy();\n handleRef.current = null;\n };\n // mode and peek are handled by the effects below without a rebuild.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [items, folderPath, loop, scrollNav, reducedMotion, defaultActiveIndex, label]);\n\n // Mode changes reuse the live instance.\n useEffect(() => {\n if (handleRef.current && handleRef.current.getMode() !== mode) {\n handleRef.current.setMode(mode);\n }\n }, [mode]);\n\n // Peek changes reuse the live instance too.\n useEffect(() => {\n if (handleRef.current) handleRef.current.setPeek(peek);\n }, [peek]);\n\n useImperativeHandle(ref, () => ({\n next: () => handleRef.current && handleRef.current.next(),\n prev: () => handleRef.current && handleRef.current.prev(),\n goTo: (i) => handleRef.current && handleRef.current.goTo(i),\n setMode: (m) => handleRef.current && handleRef.current.setMode(m),\n setPeek: (p) => handleRef.current && handleRef.current.setPeek(p),\n getActiveIndex: () => (handleRef.current ? handleRef.current.getActiveIndex() : -1),\n getMode: () => (handleRef.current ? handleRef.current.getMode() : mode),\n }), [mode]);\n\n return createElement('div', { ref: rootRef, className, style, ...rest });\n});\n\nexport default FolderGallery;\n","/* ============================================================================\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 defaultActiveIndex: 0,\n label: 'Folder gallery',\n};\n\nconst PEEK_MODES = new Set(['hover', 'always', '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 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 }\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 card.style.transform = `translate3d(${x}px,${y}px,${z}px) rotateX(${rx}deg) rotateY(${ry}deg) scale(${s})`;\n card.style.transformOrigin = 'center bottom';\n card.style.zIndex = String(zIndex);\n card.style.opacity = String(opacity);\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 cardEls.forEach((card, i) => {\n on(card, 'click', () => { i === active ? select(i) : goTo(i); });\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 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 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":["FolderGallery"]}
|
|
1
|
+
{"version":3,"sources":["../src/folder-gallery-react.js","../src/folder-gallery.js"],"sourcesContent":["/* ============================================================================\n * folder-gallery/react - thin React wrapper over the framework-agnostic core.\n *\n * import { FolderGallery } from 'folder-gallery/react';\n * import 'folder-gallery/styles.css';\n *\n * <FolderGallery\n * items={items}\n * mode=\"stack\"\n * onSelect={(item, i) => ...}\n * ref={galleryRef} // -> { next, prev, goTo, setMode, getActiveIndex, getMode }\n * />\n *\n * Written without JSX so the package builds with no React toolchain;\n * React is a peer dependency and only resolved in the consumer's app.\n * ========================================================================== */\n\nimport { createElement, forwardRef, useEffect, useImperativeHandle, useRef } from 'react';\nimport { createFolderGallery } from './folder-gallery.js';\n\nexport const FolderGallery = forwardRef(function FolderGallery(props, ref) {\n const {\n items,\n mode = 'stack',\n peek = 'hover',\n drag = 'fling',\n contentRenderer,\n onSelect,\n onActiveChange,\n onModeChange,\n folderPath,\n loop,\n scrollNav,\n reducedMotion,\n defaultActiveIndex,\n label,\n className,\n style,\n ...rest\n } = props;\n\n const rootRef = useRef(null);\n const handleRef = useRef(null);\n\n // Callbacks live in refs so a new inline closure per render doesn't force a\n // full gallery rebuild (and the core never holds a stale reference).\n const callbacksRef = useRef({});\n callbacksRef.current = { onSelect, onActiveChange, onModeChange, contentRenderer };\n\n // (Re)build when the structural inputs change.\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return undefined;\n\n const handle = createFolderGallery(root, {\n items,\n mode,\n peek,\n drag,\n folderPath,\n loop,\n scrollNav,\n reducedMotion,\n defaultActiveIndex,\n label,\n contentRenderer: callbacksRef.current.contentRenderer\n ? (card, item, i) => callbacksRef.current.contentRenderer(card, item, i)\n : undefined,\n onSelect: (item, i) => {\n const fn = callbacksRef.current.onSelect;\n if (fn) fn(item, i);\n },\n });\n handleRef.current = handle;\n\n const onActive = (e) => {\n const fn = callbacksRef.current.onActiveChange;\n if (fn) fn(e.detail.index, e.detail.item);\n };\n const onModeEv = (e) => {\n const fn = callbacksRef.current.onModeChange;\n if (fn) fn(e.detail.mode);\n };\n root.addEventListener('fg-activechange', onActive);\n root.addEventListener('fg-modechange', onModeEv);\n\n return () => {\n root.removeEventListener('fg-activechange', onActive);\n root.removeEventListener('fg-modechange', onModeEv);\n handle.destroy();\n handleRef.current = null;\n };\n // mode and peek are handled by the effects below without a rebuild.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [items, drag, folderPath, loop, scrollNav, reducedMotion, defaultActiveIndex, label]);\n\n // Mode changes reuse the live instance.\n useEffect(() => {\n if (handleRef.current && handleRef.current.getMode() !== mode) {\n handleRef.current.setMode(mode);\n }\n }, [mode]);\n\n // Peek changes reuse the live instance too.\n useEffect(() => {\n if (handleRef.current) handleRef.current.setPeek(peek);\n }, [peek]);\n\n useImperativeHandle(ref, () => ({\n next: () => handleRef.current && handleRef.current.next(),\n prev: () => handleRef.current && handleRef.current.prev(),\n goTo: (i) => handleRef.current && handleRef.current.goTo(i),\n setMode: (m) => handleRef.current && handleRef.current.setMode(m),\n setPeek: (p) => handleRef.current && handleRef.current.setPeek(p),\n getActiveIndex: () => (handleRef.current ? handleRef.current.getActiveIndex() : -1),\n getMode: () => (handleRef.current ? handleRef.current.getMode() : mode),\n }), [mode]);\n\n return createElement('div', { ref: rootRef, className, style, ...rest });\n});\n\nexport default FolderGallery;\n","/* ============================================================================\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":["FolderGallery"]}
|
package/dist/react.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { ComponentType, CSSProperties, Ref } from 'react';
|
|
2
|
-
import type { FolderItem, GalleryMode, PeekMode, FolderGalleryOptions, FolderGalleryHandle } from './index';
|
|
2
|
+
import type { FolderItem, GalleryMode, PeekMode, DragMode, FolderGalleryOptions, FolderGalleryHandle } from './index';
|
|
3
3
|
|
|
4
4
|
export interface FolderGalleryProps {
|
|
5
5
|
items: FolderItem[];
|
|
6
6
|
mode?: GalleryMode;
|
|
7
7
|
peek?: PeekMode;
|
|
8
|
+
drag?: DragMode;
|
|
8
9
|
contentRenderer?: FolderGalleryOptions['contentRenderer'];
|
|
9
10
|
onSelect?: (item: FolderItem, index: number) => void;
|
|
10
11
|
onActiveChange?: (index: number, item: FolderItem) => void;
|