@griddle/vue 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/LoopGrid.vue","../src/GriddleGrid.vue","../src/useGriddle.ts"],"sourcesContent":["<template>\n <div\n ref=\"viewportEl\"\n :class=\"className\"\n :style=\"viewportStyle\"\n @pointerdown=\"onContainerPointerDown\"\n @click.capture=\"onClickCapture\"\n >\n <div ref=\"planeEl\" :style=\"planeStyle\">\n <div\n v-if=\"indicatorRect\"\n class=\"griddle-drop-indicator\"\n :style=\"{\n position: 'absolute',\n left: indicatorRect.left + 'px',\n top: indicatorRect.top + 'px',\n width: indicatorRect.width + 'px',\n height: indicatorRect.height + 'px',\n boxSizing: 'border-box',\n border: '2px dashed rgba(59, 91, 219, 0.55)',\n background: 'rgba(59, 91, 219, 0.08)',\n borderRadius: (config.tileRadius ?? 4) + 'px',\n pointerEvents: 'none',\n zIndex: 5,\n }\"\n ></div>\n <template v-for=\"inst in instances\" :key=\"inst.key\">\n <div\n v-if=\"!(drag && inst.tile.id === drag.tileId)\"\n :data-griddle-tile=\"inst.tile.id\"\n :data-griddle-instance=\"inst.key\"\n :data-griddle-ghost=\"isGhost(inst) ? '' : undefined\"\n :aria-hidden=\"isBase(inst) ? undefined : true\"\n :class=\"['griddle-tile', {\n 'griddle-resizing': resize?.instanceKey === inst.key,\n 'griddle-selected': editable && isBase(inst) && selection.has(inst.tile.id),\n }]\"\n :style=\"instanceStyle(inst)\"\n :ref=\"(el) => registerNode(inst.key, el as HTMLDivElement | null)\"\n @pointerdown=\"(e) => onTilePointerDown(e, inst)\"\n >\n <slot name=\"tile\" :tile=\"inst.tile\" :selected=\"editable && isBase(inst) && selection.has(inst.tile.id)\" />\n <template v-if=\"editable && isBase(inst) && inst.tile.resizable !== false\">\n <div\n v-for=\"c in tileHandles(inst.tile)\"\n :key=\"c\"\n :data-griddle-handle=\"c\"\n :style=\"handleStyle(c)\"\n @pointerdown=\"(e) => onResizeHandleDown(e, inst, c)\"\n ></div>\n </template>\n </div>\n </template>\n <div\n v-if=\"drag && draggedTile\"\n :data-griddle-tile=\"draggedTile.id\"\n class=\"griddle-tile griddle-dragging\"\n :style=\"dragOverlayStyle\"\n >\n <slot name=\"tile\" :tile=\"draggedTile\" :selected=\"selection.has(draggedTile.id)\" />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n// Loop-mode renderer (\"object looping\") — see @griddle/core loop.ts for the\n// coordinate model. Mirrors the React GriddleLoopGrid: an overflow-hidden\n// viewport, a transform-translated plane driven by an unbounded camera, and\n// NO native scrolling (wheel deltas feed the camera directly).\nimport { computed, onBeforeUnmount, onMounted, ref, watch, nextTick } from 'vue';\nimport type { CameraState, CellPos, Corner, Tile } from '@griddle/core';\nimport {\n DragController,\n PanController,\n loopInstances,\n loopPeriod,\n resolveLoop,\n} from '@griddle/core';\nimport type { LoopTileInstance } from '@griddle/core';\nimport type { GriddleApi } from './useGriddle.js';\n\nconst props = defineProps<{\n api: GriddleApi;\n className?: string;\n height?: number | string;\n showGrid?: boolean;\n selection?: Set<string>;\n}>();\n\nconst emit = defineEmits<{\n (e: 'selectionChange', selection: Set<string>): void;\n (e: 'dragStart', tileId: string): void;\n (e: 'dragEnd', tileId: string, committed: boolean): void;\n (e: 'resizeStart', tileId: string): void;\n (e: 'resizeEnd', tileId: string, committed: boolean): void;\n (e: 'cameraChange', camera: CameraState): void;\n}>();\n\nconst DEFAULT_DRAG_IGNORE = 'a, button, input, textarea, select, [contenteditable]';\nconst PAN_THRESHOLD_PX = 4;\n\nconst viewportEl = ref<HTMLDivElement | null>(null);\nconst planeEl = ref<HTMLDivElement | null>(null);\n\nconst config = computed(() => props.api.config.value);\nconst loop = computed(() => resolveLoop(config.value));\nconst editable = computed(() => loop.value?.interaction === 'edit');\nconst gap = computed(() => config.value.gap ?? 0);\nconst halfGap = computed(() => gap.value / 2);\nconst colSize = computed(() => config.value.unitWidth + gap.value);\nconst rowSize = computed(() => config.value.unitHeight + gap.value);\nconst period = computed(() => loopPeriod(config.value, props.api.tiles.value));\n\n// ---- camera plumbing ------------------------------------------------------\nconst pan = new PanController();\nwatch(loop, (l) => {\n if (l) pan.setPhysics({ friction: l.friction, ease: l.ease, maxVelocity: l.maxVelocity });\n}, { immediate: true });\n\nconst view = ref({ cxCell: 0, cyCell: 0, vw: 1000, vh: 800 });\nlet lastCam: CameraState | null = null;\nlet raf = 0;\nlet resizeObserver: ResizeObserver | null = null;\n\nfunction onWheel(e: WheelEvent) {\n e.preventDefault();\n const k = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? 100 : 1;\n pan.scrollBy(e.deltaX * k, e.deltaY * k);\n}\n\nfunction frame(now: number) {\n raf = requestAnimationFrame(frame);\n const st = pan.tick(now);\n\n const plane = planeEl.value;\n if (plane) {\n plane.style.transform = `translate3d(${-st.x}px, ${-st.y}px, 0)`;\n }\n const el = viewportEl.value;\n if (el && props.showGrid !== false) {\n el.style.backgroundPosition = `${-st.x % colSize.value}px ${-st.y % rowSize.value}px`;\n }\n\n const cxCell = Math.floor(st.x / colSize.value);\n const cyCell = Math.floor(st.y / rowSize.value);\n const cur = view.value;\n if (cxCell !== cur.cxCell || cyCell !== cur.cyCell) {\n view.value = { ...cur, cxCell, cyCell };\n }\n\n if (\n !lastCam || lastCam.x !== st.x || lastCam.y !== st.y ||\n lastCam.isMoving !== st.isMoving || lastCam.isDragging !== st.isDragging\n ) {\n lastCam = st;\n emit('cameraChange', st);\n }\n}\n\nconst instances = computed(() => {\n void props.api.version.value; // re-run on grid changes\n const bufX = 2 * colSize.value;\n const bufY = 2 * rowSize.value;\n return loopInstances(config.value, props.api.tiles.value, {\n x: view.value.cxCell * colSize.value - bufX,\n y: view.value.cyCell * rowSize.value - bufY,\n width: view.value.vw + colSize.value + 2 * bufX,\n height: view.value.vh + rowSize.value + 2 * bufY,\n });\n});\n\n// ---- pan gesture ----------------------------------------------------------\nlet panGesture: { pointerId: number; startX: number; startY: number; moved: boolean } | null = null;\nlet suppressClick = false;\n\nfunction onContainerPointerDown(e: PointerEvent) {\n const onTile = !!(e.target as HTMLElement).closest('[data-griddle-tile]');\n if (editable.value && !onTile) setSelection(new Set());\n // Tiles that start drags stopPropagation, so reaching here from a tile\n // means it was not draggable — panning is the right fallback.\n if (!loop.value?.dragPan || e.button !== 0) return;\n const ignoreSelector = config.value.dragIgnoreFrom ?? DEFAULT_DRAG_IGNORE;\n if (ignoreSelector && (e.target as HTMLElement).closest(ignoreSelector)) return;\n panGesture = { pointerId: e.pointerId, startX: e.clientX, startY: e.clientY, moved: false };\n}\n\nfunction onClickCapture(e: MouseEvent) {\n if (suppressClick) {\n suppressClick = false;\n e.preventDefault();\n e.stopPropagation();\n }\n}\n\n// ---- selection ('edit' interaction) ---------------------------------------\nconst internalSelection = ref<Set<string>>(new Set());\nconst selection = computed(() => props.selection ?? internalSelection.value);\nfunction setSelection(next: Set<string>) {\n if (!props.selection) internalSelection.value = next;\n emit('selectionChange', next);\n}\n\n// ---- tile drag / resize ('edit' interaction) ------------------------------\nconst dragController = new DragController(props.api.grid);\n\ninterface LoopDragVisual {\n tileId: string;\n instanceLeft: number;\n instanceTop: number;\n pickupCol: number;\n pickupRow: number;\n deltaX: number;\n deltaY: number;\n indicatorCol: number | null;\n indicatorRow: number | null;\n}\nconst drag = ref<LoopDragVisual | null>(null);\nlet dragStartPointerX = 0;\nlet dragStartPointerY = 0;\n\ninterface LoopResizeState {\n tileId: string;\n instanceKey: string;\n instanceDx: number;\n instanceDy: number;\n corner: Corner;\n startPointerX: number;\n startPointerY: number;\n startW: number;\n startH: number;\n startCol: number;\n startRow: number;\n previewW: number;\n previewH: number;\n previewCol: number;\n previewRow: number;\n}\nconst resize = ref<LoopResizeState | null>(null);\n\nfunction syncTiles() {\n props.api.tiles.value = props.api.grid.tiles;\n props.api.version.value++;\n}\n\nfunction isBase(inst: LoopTileInstance): boolean {\n return inst.kx === 0 && inst.ky === 0;\n}\nfunction isGhost(inst: LoopTileInstance): boolean {\n return editable.value && !isBase(inst);\n}\n\nfunction onTilePointerDown(e: PointerEvent, inst: LoopTileInstance) {\n if (!editable.value) return; // pan mode: container pan handler takes it\n if (!isBase(inst)) return; // ghosts are display-only\n const tile = inst.tile;\n if (tile.draggable === false) return;\n if ((e.target as HTMLElement).dataset.griddleHandle) return;\n const ignoreSelector = config.value.dragIgnoreFrom ?? DEFAULT_DRAG_IGNORE;\n if (ignoreSelector && (e.target as HTMLElement).closest(ignoreSelector)) return;\n\n if (e.metaKey || e.ctrlKey) {\n e.preventDefault();\n const next = new Set(selection.value);\n if (next.has(tile.id)) next.delete(tile.id);\n else next.add(tile.id);\n setSelection(next);\n e.stopPropagation();\n return;\n }\n setSelection(new Set([tile.id]));\n\n // No pointer capture: the grabbed instance unmounts (drag renders as an\n // overlay), which would release the capture mid-gesture.\n if (!dragController.start(tile.id)) return;\n dragStartPointerX = e.clientX;\n dragStartPointerY = e.clientY;\n drag.value = {\n tileId: tile.id,\n instanceLeft: inst.left,\n instanceTop: inst.top,\n pickupCol: tile.col,\n pickupRow: tile.row,\n deltaX: 0,\n deltaY: 0,\n indicatorCol: tile.col,\n indicatorRow: tile.row,\n };\n emit('dragStart', tile.id);\n e.stopPropagation();\n}\n\nfunction onResizeHandleDown(e: PointerEvent, inst: LoopTileInstance, c: Corner) {\n if (!editable.value) return;\n const tile = inst.tile;\n if (tile.resizable === false) return;\n (e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId);\n const baseLeft = tile.col * colSize.value + halfGap.value;\n const baseTop = tile.row * rowSize.value + halfGap.value;\n resize.value = {\n tileId: tile.id,\n instanceKey: inst.key,\n instanceDx: inst.left - baseLeft,\n instanceDy: inst.top - baseTop,\n corner: c,\n startPointerX: e.clientX,\n startPointerY: e.clientY,\n startW: tile.w,\n startH: tile.h,\n startCol: tile.col,\n startRow: tile.row,\n previewW: tile.w,\n previewH: tile.h,\n previewCol: tile.col,\n previewRow: tile.row,\n };\n emit('resizeStart', tile.id);\n e.stopPropagation();\n}\n\nfunction onPointerMove(e: PointerEvent) {\n if (panGesture && e.pointerId === panGesture.pointerId) {\n const now = performance.now();\n if (!panGesture.moved) {\n const dist = Math.hypot(e.clientX - panGesture.startX, e.clientY - panGesture.startY);\n if (dist >= PAN_THRESHOLD_PX) {\n panGesture.moved = true;\n pan.dragStart(panGesture.startX, panGesture.startY, now);\n pan.dragMove(e.clientX, e.clientY, now);\n }\n } else {\n pan.dragMove(e.clientX, e.clientY, now);\n }\n return;\n }\n\n const d = drag.value;\n if (d) {\n // Ghost edit: plain grid semantics in the base copy — no wrapping.\n const dx = e.clientX - dragStartPointerX;\n const dy = e.clientY - dragStartPointerY;\n const candidate: CellPos = {\n col: d.pickupCol + Math.round(dx / colSize.value),\n row: d.pickupRow + Math.round(dy / rowSize.value),\n };\n const result = dragController.update(candidate);\n drag.value = {\n ...d,\n deltaX: dx,\n deltaY: dy,\n indicatorCol: result.indicatorCell ? result.indicatorCell.col : null,\n indicatorRow: result.indicatorCell ? result.indicatorCell.row : null,\n };\n if (result.changed) syncTiles();\n }\n\n const r = resize.value;\n if (r) {\n const dx = e.clientX - r.startPointerX;\n const dy = e.clientY - r.startPointerY;\n let dw = 0, dh = 0, dcol = 0, drow = 0;\n const stepsX = Math.round(dx / colSize.value);\n const stepsY = Math.round(dy / rowSize.value);\n if (r.corner === 'se' || r.corner === 'ne') dw = stepsX;\n if (r.corner === 'se' || r.corner === 'sw') dh = stepsY;\n if (r.corner === 'sw' || r.corner === 'nw') { dw = -stepsX; dcol = stepsX; }\n if (r.corner === 'ne' || r.corner === 'nw') { dh = -stepsY; drow = stepsY; }\n const tile = props.api.grid.getTile(r.tileId);\n const minW = tile?.minW ?? 1;\n const minH = tile?.minH ?? 1;\n const maxW = Math.min(tile?.maxW ?? Infinity, config.value.cols);\n const maxH = Math.min(tile?.maxH ?? Infinity, config.value.rows);\n const nW = Math.min(maxW, Math.max(minW, r.startW + dw));\n const nH = Math.min(maxH, Math.max(minH, r.startH + dh));\n const nC = r.startCol + dcol;\n const nR = r.startRow + drow;\n if (nW !== r.previewW || nH !== r.previewH || nC !== r.previewCol || nR !== r.previewRow) {\n resize.value = { ...r, previewW: nW, previewH: nH, previewCol: nC, previewRow: nR };\n }\n }\n}\n\nfunction onPointerUp(e: PointerEvent) {\n if (panGesture && e.pointerId === panGesture.pointerId) {\n if (panGesture.moved) {\n pan.dragEnd(performance.now());\n suppressClick = true;\n }\n panGesture = null;\n return;\n }\n\n if (drag.value) {\n const tileId = drag.value.tileId;\n const { committed } = dragController.end();\n drag.value = null;\n syncTiles();\n emit('dragEnd', tileId, committed);\n }\n const r = resize.value;\n if (r) {\n const t = props.api.grid.getTile(r.tileId);\n let committed = false;\n if (t) {\n const target = { col: r.previewCol, row: r.previewRow };\n if (target.col !== t.col || target.row !== t.row) {\n props.api.moveTile(r.tileId, target);\n }\n if (r.previewW !== t.w || r.previewH !== t.h) {\n committed = props.api.resizeTile(r.tileId, { w: r.previewW, h: r.previewH });\n } else {\n committed = r.previewCol !== r.startCol || r.previewRow !== r.startRow\n || r.previewW !== r.startW || r.previewH !== r.startH;\n }\n }\n resize.value = null;\n emit('resizeEnd', r.tileId, committed);\n }\n}\n\nfunction onKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape' && editable.value) setSelection(new Set());\n}\n\nonMounted(() => {\n const el = viewportEl.value;\n if (el) {\n el.addEventListener('wheel', onWheel, { passive: false });\n const measure = () => {\n const cur = view.value;\n if (el.clientWidth !== cur.vw || el.clientHeight !== cur.vh) {\n view.value = { ...cur, vw: el.clientWidth, vh: el.clientHeight };\n }\n };\n measure();\n resizeObserver = new ResizeObserver(measure);\n resizeObserver.observe(el);\n }\n raf = requestAnimationFrame(frame);\n window.addEventListener('pointermove', onPointerMove);\n window.addEventListener('pointerup', onPointerUp);\n window.addEventListener('pointercancel', onPointerUp);\n window.addEventListener('keydown', onKeyDown);\n});\nonBeforeUnmount(() => {\n cancelAnimationFrame(raf);\n viewportEl.value?.removeEventListener('wheel', onWheel);\n resizeObserver?.disconnect();\n window.removeEventListener('pointermove', onPointerMove);\n window.removeEventListener('pointerup', onPointerUp);\n window.removeEventListener('pointercancel', onPointerUp);\n window.removeEventListener('keydown', onKeyDown);\n});\n\n// ---- FLIP for edit-mode repacks (keyed by world key) ----------------------\nconst tileNodes = new Map<string, HTMLDivElement>();\nconst prevRects = new Map<string, { x: number; y: number }>();\nfunction registerNode(key: string, el: HTMLDivElement | null) {\n if (el) tileNodes.set(key, el);\n else tileNodes.delete(key);\n}\n\nwatch(() => props.api.version.value, async () => {\n await nextTick();\n const draggerId = drag.value?.tileId ?? null;\n const seen = new Set<string>();\n for (const inst of instances.value) {\n const key = inst.key;\n seen.add(key);\n const x = inst.left;\n const y = inst.top;\n if (editable.value && inst.tile.id !== draggerId) {\n const p = prevRects.get(key);\n const node = tileNodes.get(key);\n if (p && node) {\n const dx = p.x - x;\n const dy = p.y - y;\n if (\n (dx !== 0 || dy !== 0) &&\n Math.abs(dx) < period.value.width / 2 &&\n Math.abs(dy) < period.value.height / 2\n ) {\n node.style.transition = 'none';\n node.style.transform = `translate(${dx}px, ${dy}px)`;\n requestAnimationFrame(() => {\n node.style.transition = 'transform 220ms cubic-bezier(.2,.7,.2,1)';\n node.style.transform = 'translate(0,0)';\n });\n }\n }\n }\n prevRects.set(key, { x, y });\n }\n for (const key of prevRects.keys()) {\n if (!seen.has(key)) prevRects.delete(key);\n }\n});\n\n// ---- styles ----------------------------------------------------------------\nconst viewportStyle = computed(() => {\n const showGrid = props.showGrid !== false;\n const bg = showGrid\n ? {\n backgroundImage: `linear-gradient(to right, rgba(0,0,0,0.08) 1px, transparent 1px), linear-gradient(to bottom, rgba(0,0,0,0.08) 1px, transparent 1px)`,\n backgroundSize: `${colSize.value}px ${rowSize.value}px`,\n backgroundPosition: '0 0',\n }\n : {};\n return {\n position: 'relative' as const,\n overflow: 'hidden' as const,\n height: typeof props.height === 'number' ? props.height + 'px' : (props.height ?? '100%'),\n touchAction: 'none' as const,\n userSelect: 'none' as const,\n cursor: !editable.value && loop.value?.dragPan ? 'grab' : undefined,\n ['--griddle-tile-radius' as string]: (config.value.tileRadius ?? 4) + 'px',\n ...bg,\n };\n});\n\nconst planeStyle = computed(() => ({\n position: 'absolute' as const,\n top: '0',\n left: '0',\n width: '0',\n height: '0',\n willChange: 'transform',\n}));\n\nfunction instanceStyle(inst: LoopTileInstance) {\n const r = resize.value;\n const isResizingInst = r?.instanceKey === inst.key;\n let left = inst.left;\n let top = inst.top;\n let width = inst.width;\n let heightPx = inst.height;\n if (isResizingInst && r) {\n left = r.previewCol * colSize.value + halfGap.value + r.instanceDx;\n top = r.previewRow * rowSize.value + halfGap.value + r.instanceDy;\n width = r.previewW * config.value.unitWidth + (r.previewW - 1) * gap.value;\n heightPx = r.previewH * config.value.unitHeight + (r.previewH - 1) * gap.value;\n }\n const ghost = isGhost(inst);\n const isSelected = editable.value && isBase(inst) && selection.value.has(inst.tile.id);\n return {\n position: 'absolute' as const,\n left: left + 'px',\n top: top + 'px',\n width: width + 'px',\n height: heightPx + 'px',\n boxSizing: 'border-box' as const,\n cursor: editable.value && isBase(inst) ? 'grab' : undefined,\n userSelect: 'none' as const,\n // Ghosts are display-only: pointer-transparent (so the gesture falls\n // through to drag-pan) and dimmed to mark the editable copy.\n pointerEvents: ghost ? ('none' as const) : undefined,\n zIndex: isResizingInst ? 10 : 1,\n opacity: isResizingInst ? 0.85 : ghost ? 0.55 : 1,\n boxShadow: isSelected\n ? '0 0 0 3px rgba(59, 91, 219, 0.85), inset 0 0 0 1px rgba(59, 91, 219, 0.3)'\n : '',\n borderRadius: (config.value.tileRadius ?? 4) + 'px',\n };\n}\n\nconst draggedTile = computed<Tile | null>(() =>\n drag.value ? props.api.grid.getTile(drag.value.tileId) ?? null : null,\n);\n\nconst dragOverlayStyle = computed(() => {\n const d = drag.value;\n const t = draggedTile.value;\n if (!d || !t) return {};\n return {\n position: 'absolute' as const,\n left: d.instanceLeft + 'px',\n top: d.instanceTop + 'px',\n width: t.w * config.value.unitWidth + (t.w - 1) * gap.value + 'px',\n height: t.h * config.value.unitHeight + (t.h - 1) * gap.value + 'px',\n boxSizing: 'border-box' as const,\n cursor: 'grabbing',\n userSelect: 'none' as const,\n zIndex: 20,\n opacity: 0.85,\n transform: `translate(${d.deltaX}px, ${d.deltaY}px)`,\n filter: 'drop-shadow(0 8px 16px rgba(0,0,0,0.18))',\n borderRadius: (config.value.tileRadius ?? 4) + 'px',\n pointerEvents: 'none' as const,\n };\n});\n\n// Drop indicator: rendered in the base copy (ghost edit is plain-grid).\nconst indicatorRect = computed(() => {\n const d = drag.value;\n if (!d || d.indicatorCol === null || d.indicatorRow === null) return null;\n const t = props.api.grid.getTile(d.tileId);\n if (!t) return null;\n return {\n left: d.indicatorCol * colSize.value + halfGap.value,\n top: d.indicatorRow * rowSize.value + halfGap.value,\n width: t.w * config.value.unitWidth + (t.w - 1) * gap.value,\n height: t.h * config.value.unitHeight + (t.h - 1) * gap.value,\n };\n});\n\nfunction tileHandles(tile: Tile): Corner[] {\n return tile.resizeHandles ?? config.value.resizeHandles ?? ['se'];\n}\n\nfunction handleStyle(c: Corner) {\n const size = 12;\n const base = {\n position: 'absolute' as const,\n width: size + 'px',\n height: size + 'px',\n background: 'rgba(60,60,60,0.7)',\n border: '2px solid white',\n borderRadius: '3px',\n cursor: `${c}-resize`,\n touchAction: 'none' as const,\n } as Record<string, unknown>;\n if (c === 'nw') return { ...base, top: -size / 2 + 'px', left: -size / 2 + 'px' };\n if (c === 'ne') return { ...base, top: -size / 2 + 'px', right: -size / 2 + 'px' };\n if (c === 'sw') return { ...base, bottom: -size / 2 + 'px', left: -size / 2 + 'px' };\n return { ...base, bottom: -size / 2 + 'px', right: -size / 2 + 'px' };\n}\n\nconst className = computed(() => props.className ?? '');\n</script>\n","<template>\n <GriddleLoopGrid\n v-if=\"loopOn\"\n :api=\"api\"\n :class-name=\"className\"\n :height=\"height\"\n :show-grid=\"showGrid\"\n :selection=\"props.selection\"\n @selection-change=\"(s) => emit('selectionChange', s)\"\n @drag-start=\"(id) => emit('dragStart', id)\"\n @drag-end=\"(id, c) => emit('dragEnd', id, c)\"\n @resize-start=\"(id) => emit('resizeStart', id)\"\n @resize-end=\"(id, c) => emit('resizeEnd', id, c)\"\n @camera-change=\"(cam) => emit('cameraChange', cam)\"\n >\n <template #tile=\"slotProps\">\n <slot name=\"tile\" v-bind=\"slotProps\" />\n </template>\n </GriddleLoopGrid>\n <div\n v-else\n ref=\"scrollEl\"\n :class=\"className\"\n :style=\"scrollStyle\"\n @pointerdown=\"onBackgroundPointerDown\"\n >\n <div :style=\"contentStyle\">\n <div\n v-if=\"indicatorRect\"\n class=\"griddle-drop-indicator\"\n :style=\"{\n position: 'absolute',\n left: indicatorRect.left + 'px',\n top: indicatorRect.top + 'px',\n width: indicatorRect.width + 'px',\n height: indicatorRect.height + 'px',\n boxSizing: 'border-box',\n border: '2px dashed rgba(59, 91, 219, 0.55)',\n background: 'rgba(59, 91, 219, 0.08)',\n borderRadius: (config.tileRadius ?? 4) + 'px',\n pointerEvents: 'none',\n zIndex: 5,\n }\"\n ></div>\n <div\n v-if=\"drawGhostRect\"\n class=\"griddle-draw-ghost\"\n :style=\"{\n position: 'absolute',\n left: drawGhostRect.left + 'px',\n top: drawGhostRect.top + 'px',\n width: drawGhostRect.width + 'px',\n height: drawGhostRect.height + 'px',\n boxSizing: 'border-box',\n border: '2px dashed rgba(59, 91, 219, 0.55)',\n background: 'rgba(59, 91, 219, 0.08)',\n borderRadius: (config.tileRadius ?? 4) + 'px',\n pointerEvents: 'none',\n zIndex: 5,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '14px',\n fontWeight: '600',\n color: 'rgba(59, 91, 219, 0.8)',\n userSelect: 'none',\n }\"\n >{{ drawGhostRect.label }}</div>\n <div\n v-for=\"tile in rendered\"\n :key=\"tile.id\"\n :data-griddle-tile=\"tile.id\"\n :class=\"['griddle-tile', {\n 'griddle-dragging': drag?.tileId === tile.id || pinDrag?.tileId === tile.id || (groupDrag !== null && groupDragSet.has(tile.id)),\n 'griddle-resizing': resize?.tileId === tile.id,\n 'griddle-selected': selection.has(tile.id),\n }]\"\n :style=\"tileStyle(tile)\"\n @pointerdown=\"(e) => onTilePointerDown(e, tile)\"\n :ref=\"(el) => registerNode(tile.id, el as HTMLDivElement | null)\"\n >\n <slot name=\"tile\" :tile=\"tile\" :selected=\"selection.has(tile.id)\" />\n <template v-if=\"tile.resizable !== false\">\n <div\n v-for=\"c in tileHandles(tile)\"\n :key=\"c\"\n :data-griddle-handle=\"c\"\n :style=\"handleStyle(c)\"\n @pointerdown=\"(e) => onResizeHandleDown(e, tile, c)\"\n ></div>\n </template>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch, nextTick } from 'vue';\nimport type { CameraState, Corner, Tile } from '@griddle/core';\nimport GriddleLoopGrid from './LoopGrid.vue';\nimport {\n visibleRange,\n visibleTiles,\n gridContentSize,\n DragController,\n GroupDragController,\n computeTileLayout,\n resolveStickyStacking,\n isOutOfFlow,\n pixelsToPin,\n} from '@griddle/core';\nimport type { TileLayout } from '@griddle/core';\nimport type { GriddleApi } from './useGriddle.js';\n\nconst props = defineProps<{\n api: GriddleApi;\n className?: string;\n height?: number | string;\n showGrid?: boolean;\n /** Controlled selection. If omitted, managed internally. */\n selection?: Set<string>;\n}>();\n\nconst emit = defineEmits<{\n (e: 'selectionChange', selection: Set<string>): void;\n (e: 'drawCreate', rect: { col: number; row: number; w: number; h: number }): void;\n (e: 'dragStart', tileId: string): void;\n (e: 'dragEnd', tileId: string, committed: boolean): void;\n (e: 'resizeStart', tileId: string): void;\n (e: 'resizeEnd', tileId: string, committed: boolean): void;\n (e: 'cameraChange', camera: CameraState): void;\n}>();\n\n/** Loop mode delegates rendering to GriddleLoopGrid. */\nconst loopOn = computed(() => props.api.config.value.loop?.enabled === true);\n\nconst scrollEl = ref<HTMLDivElement | null>(null);\nconst viewport = ref({ scrollX: 0, scrollY: 0, width: 1000, height: 800 });\n\nconst config = computed(() => props.api.config.value);\nconst gap = computed(() => config.value.gap ?? 0);\nconst halfGap = computed(() => gap.value / 2);\nconst colSize = computed(() => config.value.unitWidth + gap.value);\nconst rowSize = computed(() => config.value.unitHeight + gap.value);\n\nconst range = computed(() => visibleRange(config.value, viewport.value, 4));\nconst rendered = computed(() => visibleTiles(props.api.tiles.value, range.value));\nconst contentSize = computed(() => gridContentSize(config.value, props.api.tiles.value));\n\nconst scrollStyle = computed(() => {\n // 'none' scroll mode: the grid sizes to content and lets the host page own\n // scrolling/panning — no internal scroll box, no touch-action lock.\n const contained = config.value.scroll !== 'none';\n const style: Record<string, string | number> = {\n position: 'relative',\n overflow: contained ? 'auto' : 'visible',\n height: contained ? (props.height ?? '100%') : (props.height ?? 'auto'),\n };\n if (contained) style.touchAction = 'none';\n return style;\n});\n\nconst contentStyle = computed(() => {\n const showGrid = props.showGrid !== false;\n const bg = showGrid\n ? {\n backgroundImage: `linear-gradient(to right, rgba(0,0,0,0.08) 1px, transparent 1px), linear-gradient(to bottom, rgba(0,0,0,0.08) 1px, transparent 1px)`,\n backgroundSize: `${colSize.value}px ${rowSize.value}px`,\n }\n : {};\n return {\n position: 'relative' as const,\n width: contentSize.value.width || '100%',\n height: contentSize.value.height || '100%',\n minWidth: '100%',\n minHeight: '100%',\n // Expose tile radius as a CSS variable so user tile content can pick it up.\n ['--griddle-tile-radius' as string]: (config.value.tileRadius ?? 4) + 'px',\n ...bg,\n };\n});\n\n// Selection state\nconst internalSelection = ref<Set<string>>(new Set());\nconst selection = computed(() => props.selection ?? internalSelection.value);\nconst groupDragSet = computed(() => new Set(groupDrag.value?.tileIds ?? []));\nfunction setSelection(next: Set<string>) {\n if (!props.selection) internalSelection.value = next;\n emit('selectionChange', next);\n}\n\nconst DEFAULT_DRAG_IGNORE = 'a, button, input, textarea, select, [contenteditable]';\n\nconst dragController = new DragController(props.api.grid);\nconst groupDragController = new GroupDragController(props.api.grid);\n\ninterface DragVisual {\n tileId: string;\n pickupCol: number;\n pickupRow: number;\n deltaX: number;\n deltaY: number;\n indicatorCol: number | null;\n indicatorRow: number | null;\n}\nconst drag = ref<DragVisual | null>(null);\nlet dragStartPointerX = 0;\nlet dragStartPointerY = 0;\n\ninterface GroupDragVisual {\n tileIds: string[];\n deltaX: number;\n deltaY: number;\n committedDcol: number;\n committedDrow: number;\n}\nconst groupDrag = ref<GroupDragVisual | null>(null);\n\ninterface PinDragState {\n tileId: string;\n startPinPx: { x: number; y: number };\n startPointerX: number;\n startPointerY: number;\n}\nconst pinDrag = ref<PinDragState | null>(null);\n\ninterface ResizeState {\n tileId: string;\n corner: Corner;\n startPointerX: number;\n startPointerY: number;\n startW: number;\n startH: number;\n startCol: number;\n startRow: number;\n previewW: number;\n previewH: number;\n previewCol: number;\n previewRow: number;\n}\nconst resize = ref<ResizeState | null>(null);\n\ninterface DrawState {\n anchorCol: number;\n anchorRow: number;\n currentCol: number;\n currentRow: number;\n}\nconst drawState = ref<DrawState | null>(null);\n\nfunction onTilePointerDown(e: PointerEvent, tile: Tile) {\n if (tile.draggable === false) return;\n if ((e.target as HTMLElement).dataset.griddleHandle) return;\n\n const ignoreSelector = config.value.dragIgnoreFrom ?? DEFAULT_DRAG_IGNORE;\n if (ignoreSelector && (e.target as HTMLElement).closest(ignoreSelector)) return;\n\n const metaKey = e.metaKey || e.ctrlKey;\n\n // Out-of-flow tiles get free-pixel drag (no selection).\n if (config.value.enablePositioning && isOutOfFlow(tile)) {\n (e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId);\n const layout = computeTileLayout({\n tile,\n config: config.value,\n scrollX: viewport.value.scrollX,\n scrollY: viewport.value.scrollY,\n viewportWidth: viewport.value.width,\n viewportHeight: viewport.value.height,\n });\n const startPinPx =\n tile.position === 'fixed'\n ? { x: layout.left - viewport.value.scrollX, y: layout.top - viewport.value.scrollY }\n : { x: layout.left, y: layout.top };\n pinDrag.value = {\n tileId: tile.id,\n startPinPx,\n startPointerX: e.clientX,\n startPointerY: e.clientY,\n };\n emit('dragStart', tile.id);\n e.stopPropagation();\n return;\n }\n\n // Cmd/Ctrl+click toggles selection without starting a drag.\n if (metaKey) {\n e.preventDefault();\n const next = new Set(selection.value);\n if (next.has(tile.id)) {\n next.delete(tile.id);\n } else {\n next.add(tile.id);\n }\n setSelection(next);\n e.stopPropagation();\n return;\n }\n\n const tileIsSelected = selection.value.has(tile.id);\n\n if (!tileIsSelected) {\n setSelection(new Set([tile.id]));\n }\n\n // Capture pointer only when starting a drag.\n (e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId);\n\n // Group drag if 2+ tiles selected including this one.\n const effectiveSelection = tileIsSelected ? selection.value : new Set([tile.id]);\n if (effectiveSelection.size > 1) {\n const ids = Array.from(effectiveSelection);\n if (!groupDragController.start(ids)) return;\n dragStartPointerX = e.clientX;\n dragStartPointerY = e.clientY;\n groupDrag.value = {\n tileIds: ids,\n deltaX: 0,\n deltaY: 0,\n committedDcol: 0,\n committedDrow: 0,\n };\n emit('dragStart', tile.id);\n e.stopPropagation();\n return;\n }\n\n // Single tile drag.\n if (!dragController.start(tile.id)) return;\n dragStartPointerX = e.clientX;\n dragStartPointerY = e.clientY;\n drag.value = {\n tileId: tile.id,\n pickupCol: tile.col,\n pickupRow: tile.row,\n deltaX: 0,\n deltaY: 0,\n indicatorCol: tile.col,\n indicatorRow: tile.row,\n };\n emit('dragStart', tile.id);\n e.stopPropagation();\n}\n\nfunction onBackgroundPointerDown(e: PointerEvent) {\n if ((e.target as HTMLElement).closest('[data-griddle-tile]')) return;\n // Draw-to-create is gated by config (default on). When disabled, empty-space\n // pointer-downs are a no-op so the host page keeps its native scroll/pan.\n if (config.value.interactive?.drawToCreate === false) return;\n setSelection(new Set());\n\n const el = scrollEl.value;\n if (!el) return;\n const rect = el.getBoundingClientRect();\n const x = e.clientX - rect.left + el.scrollLeft;\n const y = e.clientY - rect.top + el.scrollTop;\n const col = Math.floor(x / colSize.value);\n const row = Math.floor(y / rowSize.value);\n drawState.value = { anchorCol: col, anchorRow: row, currentCol: col, currentRow: row };\n (el as HTMLDivElement).setPointerCapture(e.pointerId);\n}\n\nfunction onResizeHandleDown(e: PointerEvent, tile: Tile, c: Corner) {\n if (tile.resizable === false) return;\n (e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId);\n resize.value = {\n tileId: tile.id,\n corner: c,\n startPointerX: e.clientX,\n startPointerY: e.clientY,\n startW: tile.w,\n startH: tile.h,\n startCol: tile.col,\n startRow: tile.row,\n previewW: tile.w,\n previewH: tile.h,\n previewCol: tile.col,\n previewRow: tile.row,\n };\n emit('resizeStart', tile.id);\n e.stopPropagation();\n}\n\nfunction onPointerMove(e: PointerEvent) {\n if (drawState.value) {\n const el = scrollEl.value;\n if (el) {\n const rect = el.getBoundingClientRect();\n const x = e.clientX - rect.left + el.scrollLeft;\n const y = e.clientY - rect.top + el.scrollTop;\n const col = Math.max(0, Math.floor(x / colSize.value));\n const row = Math.max(0, Math.floor(y / rowSize.value));\n drawState.value = { ...drawState.value, currentCol: col, currentRow: row };\n }\n return;\n }\n const pd = pinDrag.value;\n const gd = groupDrag.value;\n const d = drag.value;\n const r = resize.value;\n if (pd) {\n const dx = e.clientX - pd.startPointerX;\n const dy = e.clientY - pd.startPointerY;\n const newPinPx = { x: pd.startPinPx.x + dx, y: pd.startPinPx.y + dy };\n const newPin = pixelsToPin(newPinPx, config.value);\n props.api.grid.setTilePinned(pd.tileId, newPin);\n }\n if (gd) {\n const dx = e.clientX - dragStartPointerX;\n const dy = e.clientY - dragStartPointerY;\n const dcol = Math.round(dx / colSize.value);\n const drow = Math.round(dy / rowSize.value);\n const result = groupDragController.update({ dcol, drow });\n groupDrag.value = {\n ...gd,\n deltaX: dx,\n deltaY: dy,\n committedDcol: result.indicatorDelta?.dcol ?? gd.committedDcol,\n committedDrow: result.indicatorDelta?.drow ?? gd.committedDrow,\n };\n if (result.changed) syncTiles();\n }\n if (d) {\n const dx = e.clientX - dragStartPointerX;\n const dy = e.clientY - dragStartPointerY;\n const candidateCol = d.pickupCol + Math.round(dx / colSize.value);\n const candidateRow = d.pickupRow + Math.round(dy / rowSize.value);\n const result = dragController.update({ col: candidateCol, row: candidateRow });\n drag.value = {\n ...d,\n deltaX: dx,\n deltaY: dy,\n indicatorCol: result.indicatorCell ? result.indicatorCell.col : null,\n indicatorRow: result.indicatorCell ? result.indicatorCell.row : null,\n };\n // DragController.restoreTiles() doesn't emit change events, so when the\n // candidate cell changes (especially returning to pickup), force-sync the\n // reactive tiles ref so the FLIP animation picks up displaced tile resets.\n if (result.changed) syncTiles();\n }\n if (r) {\n const dx = e.clientX - r.startPointerX;\n const dy = e.clientY - r.startPointerY;\n let dw = 0, dh = 0, dcol = 0, drow = 0;\n const stepsX = Math.round(dx / colSize.value);\n const stepsY = Math.round(dy / rowSize.value);\n if (r.corner === 'se' || r.corner === 'ne') dw = stepsX;\n if (r.corner === 'se' || r.corner === 'sw') dh = stepsY;\n if (r.corner === 'sw' || r.corner === 'nw') { dw = -stepsX; dcol = stepsX; }\n if (r.corner === 'ne' || r.corner === 'nw') { dh = -stepsY; drow = stepsY; }\n const tile = props.api.grid.getTile(r.tileId);\n const minW = tile?.minW ?? 1;\n const minH = tile?.minH ?? 1;\n const maxW = tile?.maxW ?? Infinity;\n const maxH = tile?.maxH ?? Infinity;\n const nW = Math.min(maxW, Math.max(minW, r.startW + dw));\n const nH = Math.min(maxH, Math.max(minH, r.startH + dh));\n const nC = r.startCol + dcol;\n const nR = r.startRow + drow;\n if (nW !== r.previewW || nH !== r.previewH || nC !== r.previewCol || nR !== r.previewRow) {\n resize.value = { ...r, previewW: nW, previewH: nH, previewCol: nC, previewRow: nR };\n }\n }\n}\n\nfunction syncTiles() {\n // DragController/GroupDragController may restore grid snapshots without\n // emitting change events. Force-sync the reactive tiles ref so the UI\n // reflects the grid's true state after a drag ends.\n props.api.tiles.value = props.api.grid.tiles;\n props.api.version.value++;\n}\n\nfunction onPointerUp() {\n if (drawState.value) {\n const ds = drawState.value;\n const col = Math.min(ds.anchorCol, ds.currentCol);\n const row = Math.min(ds.anchorRow, ds.currentRow);\n const w = Math.max(1, Math.abs(ds.currentCol - ds.anchorCol) + 1);\n const h = Math.max(1, Math.abs(ds.currentRow - ds.anchorRow) + 1);\n drawState.value = null;\n emit('drawCreate', { col, row, w, h });\n return;\n }\n if (pinDrag.value) {\n const tileId = pinDrag.value.tileId;\n pinDrag.value = null;\n emit('dragEnd', tileId, true);\n }\n if (groupDrag.value) {\n const tileIds = groupDrag.value.tileIds;\n const { committed } = groupDragController.end();\n groupDrag.value = null;\n syncTiles();\n const firstId = tileIds[0];\n if (firstId !== undefined) emit('dragEnd', firstId, committed);\n }\n if (drag.value) {\n const tileId = drag.value.tileId;\n const { committed } = dragController.end();\n drag.value = null;\n syncTiles();\n emit('dragEnd', tileId, committed);\n }\n const r = resize.value;\n if (r) {\n const t = props.api.grid.getTile(r.tileId);\n let committed = false;\n if (t) {\n if (r.previewCol !== t.col || r.previewRow !== t.row) {\n props.api.moveTile(r.tileId, { col: r.previewCol, row: r.previewRow });\n }\n if (r.previewW !== t.w || r.previewH !== t.h) {\n committed = props.api.resizeTile(r.tileId, { w: r.previewW, h: r.previewH });\n } else {\n committed = r.previewCol !== r.startCol || r.previewRow !== r.startRow\n || r.previewW !== r.startW || r.previewH !== r.startH;\n }\n }\n resize.value = null;\n emit('resizeEnd', r.tileId, committed);\n }\n}\n\nfunction updateViewport() {\n const el = scrollEl.value;\n if (!el) return;\n viewport.value = {\n scrollX: el.scrollLeft,\n scrollY: el.scrollTop,\n width: el.clientWidth,\n height: el.clientHeight,\n };\n}\n\nfunction onKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') setSelection(new Set());\n}\n\nlet ro: ResizeObserver | null = null;\nonMounted(() => {\n updateViewport();\n // scrollEl is absent while loop mode delegates to GriddleLoopGrid.\n const el = scrollEl.value;\n if (el) {\n el.addEventListener('scroll', updateViewport, { passive: true });\n ro = new ResizeObserver(updateViewport);\n ro.observe(el);\n }\n window.addEventListener('pointermove', onPointerMove);\n window.addEventListener('pointerup', onPointerUp);\n window.addEventListener('pointercancel', onPointerUp);\n window.addEventListener('keydown', onKeyDown);\n});\nonBeforeUnmount(() => {\n const el = scrollEl.value;\n if (el) el.removeEventListener('scroll', updateViewport);\n ro?.disconnect();\n window.removeEventListener('pointermove', onPointerMove);\n window.removeEventListener('pointerup', onPointerUp);\n window.removeEventListener('pointercancel', onPointerUp);\n window.removeEventListener('keydown', onKeyDown);\n});\n\nconst tileNodes = new Map<string, HTMLDivElement>();\nconst prevRects = new Map<string, { x: number; y: number }>();\nfunction registerNode(id: string, el: HTMLDivElement | null) {\n if (el) tileNodes.set(id, el);\n else tileNodes.delete(id);\n}\n\nwatch(() => props.api.version.value, async () => {\n await nextTick();\n const draggerId = drag.value?.tileId ?? null;\n const gdSet = groupDragSet.value;\n for (const t of props.api.tiles.value) {\n const x = t.col * colSize.value + halfGap.value;\n const y = t.row * rowSize.value + halfGap.value;\n if (t.id === draggerId || gdSet.has(t.id)) {\n prevRects.set(t.id, { x, y });\n continue;\n }\n const p = prevRects.get(t.id);\n const node = tileNodes.get(t.id);\n if (p && node) {\n const dx = p.x - x;\n const dy = p.y - y;\n if (dx !== 0 || dy !== 0) {\n node.style.transition = 'none';\n node.style.transform = `translate(${dx}px, ${dy}px)`;\n requestAnimationFrame(() => {\n node.style.transition = 'transform 220ms cubic-bezier(.2,.7,.2,1)';\n node.style.transform = 'translate(0,0)';\n });\n }\n }\n prevRects.set(t.id, { x, y });\n }\n});\n\n// Compute layouts for all rendered tiles in one pass so resolveStickyStacking\n// can see every sticky tile and adjust them as a group. Recomputes whenever\n// rendered, config, viewport, drag, resize, or pinDrag change.\nconst tileLayouts = computed(() => {\n const out = new Map<string, TileLayout>();\n const stickyEntries: { tile: Tile; layout: TileLayout }[] = [];\n const gd = groupDrag.value;\n const gdIds = groupDragSet.value;\n for (const tile of rendered.value) {\n let layout: TileLayout;\n if (resize.value?.tileId === tile.id) {\n const w = resize.value.previewW;\n const h = resize.value.previewH;\n layout = {\n left: resize.value.previewCol * colSize.value + halfGap.value,\n top: resize.value.previewRow * rowSize.value + halfGap.value,\n width: w * config.value.unitWidth + (w - 1) * gap.value,\n height: h * config.value.unitHeight + (h - 1) * gap.value,\n zIndex: 10,\n effective: 'static',\n };\n } else if (drag.value?.tileId === tile.id) {\n const d = drag.value;\n layout = {\n left: d.pickupCol * colSize.value + halfGap.value,\n top: d.pickupRow * rowSize.value + halfGap.value,\n width: tile.w * config.value.unitWidth + (tile.w - 1) * gap.value,\n height: tile.h * config.value.unitHeight + (tile.h - 1) * gap.value,\n transform: `translate(${d.deltaX}px, ${d.deltaY}px)`,\n zIndex: 20,\n effective: 'static',\n };\n } else if (gd && gdIds.has(tile.id)) {\n const pickup = groupDragController.pickupCell(tile.id);\n const left = (pickup ? pickup.col * colSize.value : tile.col * colSize.value) + halfGap.value;\n const top = (pickup ? pickup.row * rowSize.value : tile.row * rowSize.value) + halfGap.value;\n layout = {\n left,\n top,\n width: tile.w * config.value.unitWidth + (tile.w - 1) * gap.value,\n height: tile.h * config.value.unitHeight + (tile.h - 1) * gap.value,\n transform: `translate(${gd.deltaX}px, ${gd.deltaY}px)`,\n zIndex: 20,\n effective: 'static',\n };\n } else {\n layout = computeTileLayout({\n tile,\n config: config.value,\n scrollX: viewport.value.scrollX,\n scrollY: viewport.value.scrollY,\n viewportWidth: viewport.value.width,\n viewportHeight: viewport.value.height,\n });\n if (layout.effective === 'sticky') {\n stickyEntries.push({ tile, layout });\n }\n }\n out.set(tile.id, layout);\n }\n if (stickyEntries.length > 1) resolveStickyStacking(stickyEntries);\n return out;\n});\n\nfunction tileStyle(tile: Tile) {\n const isDragging = drag.value?.tileId === tile.id;\n const isGroupDragging = groupDragSet.value.has(tile.id) && groupDrag.value !== null;\n const isPinDragging = pinDrag.value?.tileId === tile.id;\n const isResizing = resize.value?.tileId === tile.id;\n const isSelected = selection.value.has(tile.id);\n const layout = tileLayouts.value.get(tile.id) ?? {\n left: 0, top: 0, width: 0, height: 0, zIndex: 1, effective: 'static' as const,\n };\n const lifted = isDragging || isPinDragging || isGroupDragging;\n return {\n position: 'absolute' as const,\n left: layout.left + 'px',\n top: layout.top + 'px',\n width: layout.width + 'px',\n height: layout.height + 'px',\n boxSizing: 'border-box' as const,\n cursor: lifted ? 'grabbing' : 'grab',\n userSelect: 'none' as const,\n zIndex: layout.zIndex,\n opacity: lifted || isResizing ? 0.85 : 1,\n willChange: 'transform',\n transform: layout.transform ?? '',\n filter: lifted ? 'drop-shadow(0 8px 16px rgba(0,0,0,0.18))' : '',\n transition: lifted ? 'filter 120ms ease-out, opacity 120ms ease-out' : '',\n boxShadow: isSelected\n ? '0 0 0 3px rgba(59, 91, 219, 0.85), inset 0 0 0 1px rgba(59, 91, 219, 0.3)'\n : '',\n borderRadius: (config.value.tileRadius ?? 4) + 'px',\n };\n}\n\n\nconst indicatorRect = computed(() => {\n const d = drag.value;\n if (!d || d.indicatorCol === null || d.indicatorRow === null) return null;\n const t = props.api.grid.getTile(d.tileId);\n if (!t) return null;\n return {\n left: d.indicatorCol * colSize.value + halfGap.value,\n top: d.indicatorRow * rowSize.value + halfGap.value,\n width: t.w * config.value.unitWidth + (t.w - 1) * gap.value,\n height: t.h * config.value.unitHeight + (t.h - 1) * gap.value,\n };\n});\n\nconst drawGhostRect = computed(() => {\n const ds = drawState.value;\n if (!ds) return null;\n const col = Math.min(ds.anchorCol, ds.currentCol);\n const row = Math.min(ds.anchorRow, ds.currentRow);\n const w = Math.max(1, Math.abs(ds.currentCol - ds.anchorCol) + 1);\n const h = Math.max(1, Math.abs(ds.currentRow - ds.anchorRow) + 1);\n return {\n left: col * colSize.value + halfGap.value,\n top: row * rowSize.value + halfGap.value,\n width: w * config.value.unitWidth + (w - 1) * gap.value,\n height: h * config.value.unitHeight + (h - 1) * gap.value,\n label: `${w}×${h}`,\n };\n});\n\nfunction tileHandles(tile: Tile): Corner[] {\n return tile.resizeHandles ?? config.value.resizeHandles ?? ['se'];\n}\n\nfunction handleStyle(c: Corner) {\n const size = 12;\n const base = {\n position: 'absolute' as const,\n width: size + 'px',\n height: size + 'px',\n background: 'rgba(60,60,60,0.7)',\n border: '2px solid white',\n borderRadius: '3px',\n cursor: `${c}-resize`,\n touchAction: 'none' as const,\n } as Record<string, unknown>;\n if (c === 'nw') return { ...base, top: -size / 2 + 'px', left: -size / 2 + 'px' };\n if (c === 'ne') return { ...base, top: -size / 2 + 'px', right: -size / 2 + 'px' };\n if (c === 'sw') return { ...base, bottom: -size / 2 + 'px', left: -size / 2 + 'px' };\n return { ...base, bottom: -size / 2 + 'px', right: -size / 2 + 'px' };\n}\n\nconst className = computed(() => props.className ?? '');\n</script>\n","// Vue composable that wraps a Grid instance with reactive state.\n\nimport { onBeforeUnmount, reactive, ref, shallowRef } from 'vue';\nimport { Grid } from '@griddle/core';\nimport type { GridConfig, Tile, GridSnapshot } from '@griddle/core';\n\nexport interface UseGriddleInit {\n config: GridConfig;\n tiles?: Tile[];\n}\n\nexport function useGriddle(init: UseGriddleInit) {\n const grid = new Grid(init.config, init.tiles ?? []);\n\n // Reactive mirrors of tiles and config. We re-assign on changes.\n const tiles = shallowRef<Tile[]>(grid.tiles);\n const config = shallowRef<GridConfig>(grid.config);\n const version = ref(0);\n\n const off = grid.changes.on(() => {\n tiles.value = grid.tiles;\n config.value = grid.config;\n version.value++;\n });\n onBeforeUnmount(off);\n\n const api = {\n grid,\n tiles,\n config,\n version,\n moveTile: (id: string, target: { col: number; row: number }) => grid.moveTile(id, target),\n resizeTile: (id: string, size: { w: number; h: number }) => grid.resizeTile(id, size),\n addTile: (t: Tile) => grid.addTile(t),\n removeTile: (id: string) => grid.removeTile(id),\n updateConfig: (patch: Partial<GridConfig>) => grid.updateConfig(patch),\n toJSON: () => grid.toJSON(),\n loadJSON: (snap: GridSnapshot) => grid.loadJSON(snap),\n };\n return api;\n}\n\nexport type GriddleApi = ReturnType<typeof useGriddle>;\n"],"names":["DEFAULT_DRAG_IGNORE","PAN_THRESHOLD_PX","props","__props","emit","__emit","viewportEl","ref","planeEl","config","computed","loop","resolveLoop","editable","_a","gap","halfGap","colSize","rowSize","period","loopPeriod","pan","PanController","watch","l","view","lastCam","raf","resizeObserver","onWheel","e","k","frame","now","st","plane","el","cxCell","cyCell","cur","instances","bufX","bufY","loopInstances","panGesture","suppressClick","onContainerPointerDown","onTile","setSelection","ignoreSelector","onClickCapture","internalSelection","selection","next","dragController","DragController","drag","dragStartPointerX","dragStartPointerY","resize","syncTiles","isBase","inst","isGhost","onTilePointerDown","tile","onResizeHandleDown","c","baseLeft","baseTop","onPointerMove","d","dx","dy","candidate","result","r","dw","dh","dcol","drow","stepsX","stepsY","minW","minH","maxW","maxH","nW","nH","nC","nR","onPointerUp","tileId","committed","t","target","onKeyDown","onMounted","measure","onBeforeUnmount","tileNodes","prevRects","registerNode","key","nextTick","draggerId","seen","x","y","p","node","viewportStyle","bg","planeStyle","instanceStyle","isResizingInst","left","top","width","heightPx","ghost","isSelected","draggedTile","dragOverlayStyle","indicatorRect","tileHandles","handleStyle","base","className","_createElementBlock","_createElementVNode","_normalizeStyle","_Fragment","_renderList","_normalizeClass","_renderSlot","_ctx","_openBlock","loopOn","scrollEl","viewport","range","visibleRange","rendered","visibleTiles","contentSize","gridContentSize","scrollStyle","contained","style","contentStyle","groupDragSet","groupDrag","groupDragController","GroupDragController","pinDrag","drawState","metaKey","isOutOfFlow","layout","computeTileLayout","startPinPx","tileIsSelected","effectiveSelection","ids","onBackgroundPointerDown","rect","col","row","pd","gd","newPinPx","newPin","pixelsToPin","_b","candidateCol","candidateRow","ds","w","h","tileIds","firstId","updateViewport","ro","id","gdSet","tileLayouts","out","stickyEntries","gdIds","pickup","resolveStickyStacking","tileStyle","isDragging","isGroupDragging","isPinDragging","isResizing","_c","lifted","drawGhostRect","_createBlock","GriddleLoopGrid","_cache","s","cam","_withCtx","slotProps","_toDisplayString","useGriddle","init","grid","Grid","tiles","shallowRef","version","off","size","patch","snap"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/LoopGrid.vue","../src/GriddleGrid.vue","../src/useGriddle.ts"],"sourcesContent":["<template>\n <div\n ref=\"viewportEl\"\n :class=\"className\"\n :style=\"viewportStyle\"\n @pointerdown=\"onContainerPointerDown\"\n @click.capture=\"onClickCapture\"\n >\n <div ref=\"planeEl\" :style=\"planeStyle\">\n <div\n v-if=\"indicatorRect\"\n class=\"griddle-drop-indicator\"\n :style=\"{\n position: 'absolute',\n left: indicatorRect.left + 'px',\n top: indicatorRect.top + 'px',\n width: indicatorRect.width + 'px',\n height: indicatorRect.height + 'px',\n boxSizing: 'border-box',\n border: '2px dashed rgba(59, 91, 219, 0.55)',\n background: 'rgba(59, 91, 219, 0.08)',\n borderRadius: (config.tileRadius ?? 4) + 'px',\n pointerEvents: 'none',\n zIndex: 5,\n }\"\n ></div>\n <template v-for=\"inst in instances\" :key=\"inst.key\">\n <div\n v-if=\"!(drag && inst.tile.id === drag.tileId)\"\n :data-griddle-tile=\"inst.tile.id\"\n :data-griddle-instance=\"inst.key\"\n :data-griddle-ghost=\"isGhost(inst) ? '' : undefined\"\n :aria-hidden=\"isBase(inst) ? undefined : true\"\n :class=\"['griddle-tile', {\n 'griddle-resizing': resize?.instanceKey === inst.key,\n 'griddle-selected': editable && isBase(inst) && selection.has(inst.tile.id),\n }]\"\n :style=\"instanceStyle(inst)\"\n :ref=\"(el) => registerNode(inst.key, el as HTMLDivElement | null)\"\n @pointerdown=\"(e) => onTilePointerDown(e, inst)\"\n >\n <slot name=\"tile\" :tile=\"inst.tile\" :selected=\"editable && isBase(inst) && selection.has(inst.tile.id)\" />\n <template v-if=\"editable && isBase(inst) && inst.tile.resizable !== false\">\n <div\n v-for=\"c in tileHandles(inst.tile)\"\n :key=\"c\"\n :data-griddle-handle=\"c\"\n :style=\"handleStyle(c)\"\n @pointerdown=\"(e) => onResizeHandleDown(e, inst, c)\"\n ></div>\n </template>\n </div>\n </template>\n <div\n v-if=\"drag && draggedTile\"\n :data-griddle-tile=\"draggedTile.id\"\n class=\"griddle-tile griddle-dragging\"\n :style=\"dragOverlayStyle\"\n >\n <slot name=\"tile\" :tile=\"draggedTile\" :selected=\"selection.has(draggedTile.id)\" />\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n// Loop-mode renderer (\"object looping\") — see @griddle/core loop.ts for the\n// coordinate model. Mirrors the React GriddleLoopGrid: an overflow-hidden\n// viewport, a transform-translated plane driven by an unbounded camera, and\n// NO native scrolling (wheel deltas feed the camera directly).\nimport { computed, onBeforeUnmount, onMounted, ref, watch, nextTick } from 'vue';\nimport type { CameraState, CellPos, Corner, Tile } from '@griddle/core';\nimport {\n DragController,\n PanController,\n loopInstances,\n loopPeriod,\n resolveLoop,\n} from '@griddle/core';\nimport type { LoopTileInstance } from '@griddle/core';\nimport type { GriddleApi } from './useGriddle.js';\nimport { animateReposition } from './animation.js';\n\nconst props = defineProps<{\n api: GriddleApi;\n className?: string;\n height?: number | string;\n showGrid?: boolean;\n selection?: Set<string>;\n}>();\n\nconst emit = defineEmits<{\n (e: 'selectionChange', selection: Set<string>): void;\n (e: 'dragStart', tileId: string): void;\n (e: 'dragEnd', tileId: string, committed: boolean): void;\n (e: 'resizeStart', tileId: string): void;\n (e: 'resizeEnd', tileId: string, committed: boolean): void;\n (e: 'cameraChange', camera: CameraState): void;\n}>();\n\nconst DEFAULT_DRAG_IGNORE = 'a, button, input, textarea, select, [contenteditable]';\nconst PAN_THRESHOLD_PX = 4;\n\nconst viewportEl = ref<HTMLDivElement | null>(null);\nconst planeEl = ref<HTMLDivElement | null>(null);\n\nconst config = computed(() => props.api.config.value);\nconst loop = computed(() => resolveLoop(config.value));\nconst editable = computed(() => loop.value?.interaction === 'edit');\nconst gap = computed(() => config.value.gap ?? 0);\nconst halfGap = computed(() => gap.value / 2);\nconst colSize = computed(() => config.value.unitWidth + gap.value);\nconst rowSize = computed(() => config.value.unitHeight + gap.value);\nconst period = computed(() => loopPeriod(config.value, props.api.tiles.value));\n\n// ---- camera plumbing ------------------------------------------------------\nconst pan = new PanController();\nwatch(loop, (l) => {\n if (l) pan.setPhysics({ friction: l.friction, ease: l.ease, maxVelocity: l.maxVelocity });\n}, { immediate: true });\n\nconst view = ref({ cxCell: 0, cyCell: 0, vw: 1000, vh: 800 });\nlet lastCam: CameraState | null = null;\nlet raf = 0;\nlet resizeObserver: ResizeObserver | null = null;\n\nfunction onWheel(e: WheelEvent) {\n e.preventDefault();\n const k = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? 100 : 1;\n pan.scrollBy(e.deltaX * k, e.deltaY * k);\n}\n\nfunction frame(now: number) {\n raf = requestAnimationFrame(frame);\n const st = pan.tick(now);\n\n const plane = planeEl.value;\n if (plane) {\n plane.style.transform = `translate3d(${-st.x}px, ${-st.y}px, 0)`;\n }\n const el = viewportEl.value;\n if (el && props.showGrid !== false) {\n el.style.backgroundPosition = `${-st.x % colSize.value}px ${-st.y % rowSize.value}px`;\n }\n\n const cxCell = Math.floor(st.x / colSize.value);\n const cyCell = Math.floor(st.y / rowSize.value);\n const cur = view.value;\n if (cxCell !== cur.cxCell || cyCell !== cur.cyCell) {\n view.value = { ...cur, cxCell, cyCell };\n }\n\n if (\n !lastCam || lastCam.x !== st.x || lastCam.y !== st.y ||\n lastCam.isMoving !== st.isMoving || lastCam.isDragging !== st.isDragging\n ) {\n lastCam = st;\n emit('cameraChange', st);\n }\n}\n\nconst instances = computed(() => {\n void props.api.version.value; // re-run on grid changes\n const bufX = 2 * colSize.value;\n const bufY = 2 * rowSize.value;\n return loopInstances(config.value, props.api.tiles.value, {\n x: view.value.cxCell * colSize.value - bufX,\n y: view.value.cyCell * rowSize.value - bufY,\n width: view.value.vw + colSize.value + 2 * bufX,\n height: view.value.vh + rowSize.value + 2 * bufY,\n });\n});\n\n// ---- pan gesture ----------------------------------------------------------\nlet panGesture: { pointerId: number; startX: number; startY: number; moved: boolean } | null = null;\nlet suppressClick = false;\n\nfunction onContainerPointerDown(e: PointerEvent) {\n const onTile = !!(e.target as HTMLElement).closest('[data-griddle-tile]');\n if (editable.value && !onTile) setSelection(new Set());\n // Tiles that start drags stopPropagation, so reaching here from a tile\n // means it was not draggable — panning is the right fallback.\n if (!loop.value?.dragPan || e.button !== 0) return;\n const ignoreSelector = config.value.dragIgnoreFrom ?? DEFAULT_DRAG_IGNORE;\n if (ignoreSelector && (e.target as HTMLElement).closest(ignoreSelector)) return;\n panGesture = { pointerId: e.pointerId, startX: e.clientX, startY: e.clientY, moved: false };\n}\n\nfunction onClickCapture(e: MouseEvent) {\n if (suppressClick) {\n suppressClick = false;\n e.preventDefault();\n e.stopPropagation();\n }\n}\n\n// ---- selection ('edit' interaction) ---------------------------------------\nconst internalSelection = ref<Set<string>>(new Set());\nconst selection = computed(() => props.selection ?? internalSelection.value);\nfunction setSelection(next: Set<string>) {\n if (!props.selection) internalSelection.value = next;\n emit('selectionChange', next);\n}\n\n// ---- tile drag / resize ('edit' interaction) ------------------------------\nconst dragController = new DragController(props.api.grid);\n\ninterface LoopDragVisual {\n tileId: string;\n instanceLeft: number;\n instanceTop: number;\n pickupCol: number;\n pickupRow: number;\n deltaX: number;\n deltaY: number;\n indicatorCol: number | null;\n indicatorRow: number | null;\n}\nconst drag = ref<LoopDragVisual | null>(null);\nlet dragStartPointerX = 0;\nlet dragStartPointerY = 0;\n\ninterface LoopResizeState {\n tileId: string;\n instanceKey: string;\n instanceDx: number;\n instanceDy: number;\n corner: Corner;\n startPointerX: number;\n startPointerY: number;\n startW: number;\n startH: number;\n startCol: number;\n startRow: number;\n previewW: number;\n previewH: number;\n previewCol: number;\n previewRow: number;\n}\nconst resize = ref<LoopResizeState | null>(null);\n\nfunction syncTiles() {\n props.api.tiles.value = props.api.grid.tiles;\n props.api.version.value++;\n}\n\nfunction isBase(inst: LoopTileInstance): boolean {\n return inst.kx === 0 && inst.ky === 0;\n}\nfunction isGhost(inst: LoopTileInstance): boolean {\n return editable.value && !isBase(inst);\n}\n\nfunction onTilePointerDown(e: PointerEvent, inst: LoopTileInstance) {\n if (!editable.value) return; // pan mode: container pan handler takes it\n if (!isBase(inst)) return; // ghosts are display-only\n const tile = inst.tile;\n if (tile.draggable === false) return;\n if ((e.target as HTMLElement).dataset.griddleHandle) return;\n const ignoreSelector = config.value.dragIgnoreFrom ?? DEFAULT_DRAG_IGNORE;\n if (ignoreSelector && (e.target as HTMLElement).closest(ignoreSelector)) return;\n\n if (e.metaKey || e.ctrlKey) {\n e.preventDefault();\n const next = new Set(selection.value);\n if (next.has(tile.id)) next.delete(tile.id);\n else next.add(tile.id);\n setSelection(next);\n e.stopPropagation();\n return;\n }\n setSelection(new Set([tile.id]));\n\n // No pointer capture: the grabbed instance unmounts (drag renders as an\n // overlay), which would release the capture mid-gesture.\n if (!dragController.start(tile.id)) return;\n dragStartPointerX = e.clientX;\n dragStartPointerY = e.clientY;\n drag.value = {\n tileId: tile.id,\n instanceLeft: inst.left,\n instanceTop: inst.top,\n pickupCol: tile.col,\n pickupRow: tile.row,\n deltaX: 0,\n deltaY: 0,\n indicatorCol: tile.col,\n indicatorRow: tile.row,\n };\n emit('dragStart', tile.id);\n e.stopPropagation();\n}\n\nfunction onResizeHandleDown(e: PointerEvent, inst: LoopTileInstance, c: Corner) {\n if (!editable.value) return;\n const tile = inst.tile;\n if (tile.resizable === false) return;\n (e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId);\n const baseLeft = tile.col * colSize.value + halfGap.value;\n const baseTop = tile.row * rowSize.value + halfGap.value;\n resize.value = {\n tileId: tile.id,\n instanceKey: inst.key,\n instanceDx: inst.left - baseLeft,\n instanceDy: inst.top - baseTop,\n corner: c,\n startPointerX: e.clientX,\n startPointerY: e.clientY,\n startW: tile.w,\n startH: tile.h,\n startCol: tile.col,\n startRow: tile.row,\n previewW: tile.w,\n previewH: tile.h,\n previewCol: tile.col,\n previewRow: tile.row,\n };\n emit('resizeStart', tile.id);\n e.stopPropagation();\n}\n\nfunction onPointerMove(e: PointerEvent) {\n if (panGesture && e.pointerId === panGesture.pointerId) {\n const now = performance.now();\n if (!panGesture.moved) {\n const dist = Math.hypot(e.clientX - panGesture.startX, e.clientY - panGesture.startY);\n if (dist >= PAN_THRESHOLD_PX) {\n panGesture.moved = true;\n pan.dragStart(panGesture.startX, panGesture.startY, now);\n pan.dragMove(e.clientX, e.clientY, now);\n }\n } else {\n pan.dragMove(e.clientX, e.clientY, now);\n }\n return;\n }\n\n const d = drag.value;\n if (d) {\n // Ghost edit: plain grid semantics in the base copy — no wrapping.\n const dx = e.clientX - dragStartPointerX;\n const dy = e.clientY - dragStartPointerY;\n const candidate: CellPos = {\n col: d.pickupCol + Math.round(dx / colSize.value),\n row: d.pickupRow + Math.round(dy / rowSize.value),\n };\n const result = dragController.update(candidate);\n drag.value = {\n ...d,\n deltaX: dx,\n deltaY: dy,\n indicatorCol: result.indicatorCell ? result.indicatorCell.col : null,\n indicatorRow: result.indicatorCell ? result.indicatorCell.row : null,\n };\n if (result.changed) syncTiles();\n }\n\n const r = resize.value;\n if (r) {\n const dx = e.clientX - r.startPointerX;\n const dy = e.clientY - r.startPointerY;\n let dw = 0, dh = 0, dcol = 0, drow = 0;\n const stepsX = Math.round(dx / colSize.value);\n const stepsY = Math.round(dy / rowSize.value);\n if (r.corner === 'se' || r.corner === 'ne') dw = stepsX;\n if (r.corner === 'se' || r.corner === 'sw') dh = stepsY;\n if (r.corner === 'sw' || r.corner === 'nw') { dw = -stepsX; dcol = stepsX; }\n if (r.corner === 'ne' || r.corner === 'nw') { dh = -stepsY; drow = stepsY; }\n const tile = props.api.grid.getTile(r.tileId);\n const minW = tile?.minW ?? 1;\n const minH = tile?.minH ?? 1;\n const maxW = Math.min(tile?.maxW ?? Infinity, config.value.cols);\n const maxH = Math.min(tile?.maxH ?? Infinity, config.value.rows);\n const nW = Math.min(maxW, Math.max(minW, r.startW + dw));\n const nH = Math.min(maxH, Math.max(minH, r.startH + dh));\n const nC = r.startCol + dcol;\n const nR = r.startRow + drow;\n if (nW !== r.previewW || nH !== r.previewH || nC !== r.previewCol || nR !== r.previewRow) {\n resize.value = { ...r, previewW: nW, previewH: nH, previewCol: nC, previewRow: nR };\n }\n }\n}\n\nfunction onPointerUp(e: PointerEvent) {\n if (panGesture && e.pointerId === panGesture.pointerId) {\n if (panGesture.moved) {\n pan.dragEnd(performance.now());\n suppressClick = true;\n }\n panGesture = null;\n return;\n }\n\n if (drag.value) {\n const tileId = drag.value.tileId;\n const { committed } = dragController.end();\n drag.value = null;\n syncTiles();\n emit('dragEnd', tileId, committed);\n }\n const r = resize.value;\n if (r) {\n const t = props.api.grid.getTile(r.tileId);\n let committed = false;\n if (t) {\n const target = { col: r.previewCol, row: r.previewRow };\n if (target.col !== t.col || target.row !== t.row) {\n props.api.moveTile(r.tileId, target);\n }\n if (r.previewW !== t.w || r.previewH !== t.h) {\n committed = props.api.resizeTile(r.tileId, { w: r.previewW, h: r.previewH });\n } else {\n committed = r.previewCol !== r.startCol || r.previewRow !== r.startRow\n || r.previewW !== r.startW || r.previewH !== r.startH;\n }\n }\n resize.value = null;\n emit('resizeEnd', r.tileId, committed);\n }\n}\n\nfunction onKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape' && editable.value) setSelection(new Set());\n}\n\nonMounted(() => {\n const el = viewportEl.value;\n if (el) {\n el.addEventListener('wheel', onWheel, { passive: false });\n const measure = () => {\n const cur = view.value;\n if (el.clientWidth !== cur.vw || el.clientHeight !== cur.vh) {\n view.value = { ...cur, vw: el.clientWidth, vh: el.clientHeight };\n }\n };\n measure();\n resizeObserver = new ResizeObserver(measure);\n resizeObserver.observe(el);\n }\n raf = requestAnimationFrame(frame);\n window.addEventListener('pointermove', onPointerMove);\n window.addEventListener('pointerup', onPointerUp);\n window.addEventListener('pointercancel', onPointerUp);\n window.addEventListener('keydown', onKeyDown);\n});\nonBeforeUnmount(() => {\n cancelAnimationFrame(raf);\n viewportEl.value?.removeEventListener('wheel', onWheel);\n resizeObserver?.disconnect();\n window.removeEventListener('pointermove', onPointerMove);\n window.removeEventListener('pointerup', onPointerUp);\n window.removeEventListener('pointercancel', onPointerUp);\n window.removeEventListener('keydown', onKeyDown);\n});\n\n// ---- FLIP for edit-mode repacks (keyed by world key) ----------------------\nconst tileNodes = new Map<string, HTMLDivElement>();\nconst prevRects = new Map<string, { x: number; y: number }>();\nfunction registerNode(key: string, el: HTMLDivElement | null) {\n if (el) tileNodes.set(key, el);\n else tileNodes.delete(key);\n}\n\nwatch(() => props.api.version.value, async () => {\n await nextTick();\n const draggerId = drag.value?.tileId ?? null;\n const seen = new Set<string>();\n for (const inst of instances.value) {\n const key = inst.key;\n seen.add(key);\n const x = inst.left;\n const y = inst.top;\n if (editable.value && inst.tile.id !== draggerId) {\n const p = prevRects.get(key);\n const node = tileNodes.get(key);\n if (p && node) {\n const dx = p.x - x;\n const dy = p.y - y;\n if (\n (dx !== 0 || dy !== 0) &&\n Math.abs(dx) < period.value.width / 2 &&\n Math.abs(dy) < period.value.height / 2\n ) {\n animateReposition(node, dx, dy, config.value.animation);\n }\n }\n }\n prevRects.set(key, { x, y });\n }\n for (const key of prevRects.keys()) {\n if (!seen.has(key)) prevRects.delete(key);\n }\n});\n\n// ---- styles ----------------------------------------------------------------\nconst viewportStyle = computed(() => {\n const showGrid = props.showGrid !== false;\n const bg = showGrid\n ? {\n backgroundImage: `linear-gradient(to right, rgba(0,0,0,0.08) 1px, transparent 1px), linear-gradient(to bottom, rgba(0,0,0,0.08) 1px, transparent 1px)`,\n backgroundSize: `${colSize.value}px ${rowSize.value}px`,\n backgroundPosition: '0 0',\n }\n : {};\n return {\n position: 'relative' as const,\n overflow: 'hidden' as const,\n height: typeof props.height === 'number' ? props.height + 'px' : (props.height ?? '100%'),\n touchAction: 'none' as const,\n userSelect: 'none' as const,\n willChange: 'translate',\n cursor: !editable.value && loop.value?.dragPan ? 'grab' : undefined,\n ['--griddle-tile-radius' as string]: (config.value.tileRadius ?? 4) + 'px',\n ...bg,\n };\n});\n\nconst planeStyle = computed(() => ({\n position: 'absolute' as const,\n top: '0',\n left: '0',\n width: '0',\n height: '0',\n willChange: 'transform',\n}));\n\nfunction instanceStyle(inst: LoopTileInstance) {\n const r = resize.value;\n const isResizingInst = r?.instanceKey === inst.key;\n let left = inst.left;\n let top = inst.top;\n let width = inst.width;\n let heightPx = inst.height;\n if (isResizingInst && r) {\n left = r.previewCol * colSize.value + halfGap.value + r.instanceDx;\n top = r.previewRow * rowSize.value + halfGap.value + r.instanceDy;\n width = r.previewW * config.value.unitWidth + (r.previewW - 1) * gap.value;\n heightPx = r.previewH * config.value.unitHeight + (r.previewH - 1) * gap.value;\n }\n const ghost = isGhost(inst);\n const isSelected = editable.value && isBase(inst) && selection.value.has(inst.tile.id);\n return {\n position: 'absolute' as const,\n left: left + 'px',\n top: top + 'px',\n width: width + 'px',\n height: heightPx + 'px',\n boxSizing: 'border-box' as const,\n cursor: editable.value && isBase(inst) ? 'grab' : undefined,\n userSelect: 'none' as const,\n // Ghosts are display-only: pointer-transparent (so the gesture falls\n // through to drag-pan) and dimmed to mark the editable copy.\n pointerEvents: ghost ? ('none' as const) : undefined,\n zIndex: isResizingInst ? 10 : 1,\n opacity: isResizingInst ? 0.85 : ghost ? 0.55 : 1,\n boxShadow: isSelected\n ? '0 0 0 3px rgba(59, 91, 219, 0.85), inset 0 0 0 1px rgba(59, 91, 219, 0.3)'\n : '',\n borderRadius: (config.value.tileRadius ?? 4) + 'px',\n };\n}\n\nconst draggedTile = computed<Tile | null>(() =>\n drag.value ? props.api.grid.getTile(drag.value.tileId) ?? null : null,\n);\n\nconst dragOverlayStyle = computed(() => {\n const d = drag.value;\n const t = draggedTile.value;\n if (!d || !t) return {};\n return {\n position: 'absolute' as const,\n left: d.instanceLeft + 'px',\n top: d.instanceTop + 'px',\n width: t.w * config.value.unitWidth + (t.w - 1) * gap.value + 'px',\n height: t.h * config.value.unitHeight + (t.h - 1) * gap.value + 'px',\n boxSizing: 'border-box' as const,\n cursor: 'grabbing',\n userSelect: 'none' as const,\n zIndex: 20,\n opacity: 0.85,\n transform: `translate(${d.deltaX}px, ${d.deltaY}px)`,\n filter: 'drop-shadow(0 8px 16px rgba(0,0,0,0.18))',\n borderRadius: (config.value.tileRadius ?? 4) + 'px',\n pointerEvents: 'none' as const,\n };\n});\n\n// Drop indicator: rendered in the base copy (ghost edit is plain-grid).\nconst indicatorRect = computed(() => {\n const d = drag.value;\n if (!d || d.indicatorCol === null || d.indicatorRow === null) return null;\n const t = props.api.grid.getTile(d.tileId);\n if (!t) return null;\n return {\n left: d.indicatorCol * colSize.value + halfGap.value,\n top: d.indicatorRow * rowSize.value + halfGap.value,\n width: t.w * config.value.unitWidth + (t.w - 1) * gap.value,\n height: t.h * config.value.unitHeight + (t.h - 1) * gap.value,\n };\n});\n\nfunction tileHandles(tile: Tile): Corner[] {\n return tile.resizeHandles ?? config.value.resizeHandles ?? ['se'];\n}\n\nfunction handleStyle(c: Corner) {\n const size = 12;\n const base = {\n position: 'absolute' as const,\n width: size + 'px',\n height: size + 'px',\n background: 'rgba(60,60,60,0.7)',\n border: '2px solid white',\n borderRadius: '3px',\n cursor: `${c}-resize`,\n touchAction: 'none' as const,\n } as Record<string, unknown>;\n if (c === 'nw') return { ...base, top: -size / 2 + 'px', left: -size / 2 + 'px' };\n if (c === 'ne') return { ...base, top: -size / 2 + 'px', right: -size / 2 + 'px' };\n if (c === 'sw') return { ...base, bottom: -size / 2 + 'px', left: -size / 2 + 'px' };\n return { ...base, bottom: -size / 2 + 'px', right: -size / 2 + 'px' };\n}\n\nconst className = computed(() => props.className ?? '');\n</script>\n","<template>\n <GriddleLoopGrid\n v-if=\"loopOn\"\n :api=\"api\"\n :class-name=\"className\"\n :height=\"height\"\n :show-grid=\"showGrid\"\n :selection=\"props.selection\"\n @selection-change=\"(s) => emit('selectionChange', s)\"\n @drag-start=\"(id) => emit('dragStart', id)\"\n @drag-end=\"(id, c) => emit('dragEnd', id, c)\"\n @resize-start=\"(id) => emit('resizeStart', id)\"\n @resize-end=\"(id, c) => emit('resizeEnd', id, c)\"\n @camera-change=\"(cam) => emit('cameraChange', cam)\"\n >\n <template #tile=\"slotProps\">\n <slot name=\"tile\" v-bind=\"slotProps\" />\n </template>\n </GriddleLoopGrid>\n <div\n v-else\n ref=\"scrollEl\"\n :class=\"className\"\n :style=\"scrollStyle\"\n @pointerdown=\"onBackgroundPointerDown\"\n >\n <div :style=\"contentStyle\">\n <div\n v-if=\"indicatorRect\"\n class=\"griddle-drop-indicator\"\n :style=\"{\n position: 'absolute',\n left: indicatorRect.left + 'px',\n top: indicatorRect.top + 'px',\n width: indicatorRect.width + 'px',\n height: indicatorRect.height + 'px',\n boxSizing: 'border-box',\n border: '2px dashed rgba(59, 91, 219, 0.55)',\n background: 'rgba(59, 91, 219, 0.08)',\n borderRadius: (config.tileRadius ?? 4) + 'px',\n pointerEvents: 'none',\n zIndex: 5,\n }\"\n ></div>\n <div\n v-if=\"drawGhostRect\"\n class=\"griddle-draw-ghost\"\n :style=\"{\n position: 'absolute',\n left: drawGhostRect.left + 'px',\n top: drawGhostRect.top + 'px',\n width: drawGhostRect.width + 'px',\n height: drawGhostRect.height + 'px',\n boxSizing: 'border-box',\n border: '2px dashed rgba(59, 91, 219, 0.55)',\n background: 'rgba(59, 91, 219, 0.08)',\n borderRadius: (config.tileRadius ?? 4) + 'px',\n pointerEvents: 'none',\n zIndex: 5,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: '14px',\n fontWeight: '600',\n color: 'rgba(59, 91, 219, 0.8)',\n userSelect: 'none',\n }\"\n >{{ drawGhostRect.label }}</div>\n <div\n v-for=\"tile in rendered\"\n :key=\"tile.id\"\n :data-griddle-tile=\"tile.id\"\n :class=\"['griddle-tile', {\n 'griddle-dragging': drag?.tileId === tile.id || pinDrag?.tileId === tile.id || (groupDrag !== null && groupDragSet.has(tile.id)),\n 'griddle-resizing': resize?.tileId === tile.id,\n 'griddle-selected': selection.has(tile.id),\n }]\"\n :style=\"tileStyle(tile)\"\n @pointerdown=\"(e) => onTilePointerDown(e, tile)\"\n :ref=\"(el) => registerNode(tile.id, el as HTMLDivElement | null)\"\n >\n <slot name=\"tile\" :tile=\"tile\" :selected=\"selection.has(tile.id)\" />\n <template v-if=\"tile.resizable !== false\">\n <div\n v-for=\"c in tileHandles(tile)\"\n :key=\"c\"\n :data-griddle-handle=\"c\"\n :style=\"handleStyle(c)\"\n @pointerdown=\"(e) => onResizeHandleDown(e, tile, c)\"\n ></div>\n </template>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch, nextTick } from 'vue';\nimport type { CameraState, Corner, Tile } from '@griddle/core';\nimport GriddleLoopGrid from './LoopGrid.vue';\nimport {\n visibleRange,\n visibleTiles,\n gridContentSize,\n DragController,\n GroupDragController,\n computeTileLayout,\n resolveStickyStacking,\n isOutOfFlow,\n pixelsToPin,\n} from '@griddle/core';\nimport type { TileLayout } from '@griddle/core';\nimport type { GriddleApi } from './useGriddle.js';\nimport { animateReposition, liftTransition } from './animation.js';\n\nconst props = defineProps<{\n api: GriddleApi;\n className?: string;\n height?: number | string;\n showGrid?: boolean;\n /** Controlled selection. If omitted, managed internally. */\n selection?: Set<string>;\n}>();\n\nconst emit = defineEmits<{\n (e: 'selectionChange', selection: Set<string>): void;\n (e: 'drawCreate', rect: { col: number; row: number; w: number; h: number }): void;\n (e: 'dragStart', tileId: string): void;\n (e: 'dragEnd', tileId: string, committed: boolean): void;\n (e: 'resizeStart', tileId: string): void;\n (e: 'resizeEnd', tileId: string, committed: boolean): void;\n (e: 'cameraChange', camera: CameraState): void;\n}>();\n\n/** Loop mode delegates rendering to GriddleLoopGrid. */\nconst loopOn = computed(() => props.api.config.value.loop?.enabled === true);\n\nconst scrollEl = ref<HTMLDivElement | null>(null);\nconst viewport = ref({ scrollX: 0, scrollY: 0, width: 1000, height: 800 });\n\nconst config = computed(() => props.api.config.value);\nconst gap = computed(() => config.value.gap ?? 0);\nconst halfGap = computed(() => gap.value / 2);\nconst colSize = computed(() => config.value.unitWidth + gap.value);\nconst rowSize = computed(() => config.value.unitHeight + gap.value);\n\nconst range = computed(() => visibleRange(config.value, viewport.value, 4));\nconst rendered = computed(() => visibleTiles(props.api.tiles.value, range.value));\nconst contentSize = computed(() => gridContentSize(config.value, props.api.tiles.value));\n\nconst scrollStyle = computed(() => {\n // 'none' scroll mode: the grid sizes to content and lets the host page own\n // scrolling/panning — no internal scroll box, no touch-action lock.\n const contained = config.value.scroll !== 'none';\n const style: Record<string, string | number> = {\n position: 'relative',\n overflow: contained ? 'auto' : 'visible',\n height: contained ? (props.height ?? '100%') : (props.height ?? 'auto'),\n };\n if (contained) style.touchAction = 'none';\n return style;\n});\n\nconst contentStyle = computed(() => {\n const showGrid = props.showGrid !== false;\n const bg = showGrid\n ? {\n backgroundImage: `linear-gradient(to right, rgba(0,0,0,0.08) 1px, transparent 1px), linear-gradient(to bottom, rgba(0,0,0,0.08) 1px, transparent 1px)`,\n backgroundSize: `${colSize.value}px ${rowSize.value}px`,\n }\n : {};\n return {\n position: 'relative' as const,\n width: contentSize.value.width || '100%',\n height: contentSize.value.height || '100%',\n minWidth: '100%',\n minHeight: '100%',\n // Expose tile radius as a CSS variable so user tile content can pick it up.\n ['--griddle-tile-radius' as string]: (config.value.tileRadius ?? 4) + 'px',\n ...bg,\n };\n});\n\n// Selection state\nconst internalSelection = ref<Set<string>>(new Set());\nconst selection = computed(() => props.selection ?? internalSelection.value);\nconst groupDragSet = computed(() => new Set(groupDrag.value?.tileIds ?? []));\nfunction setSelection(next: Set<string>) {\n if (!props.selection) internalSelection.value = next;\n emit('selectionChange', next);\n}\n\nconst DEFAULT_DRAG_IGNORE = 'a, button, input, textarea, select, [contenteditable]';\n\nconst dragController = new DragController(props.api.grid);\nconst groupDragController = new GroupDragController(props.api.grid);\n\ninterface DragVisual {\n tileId: string;\n pickupCol: number;\n pickupRow: number;\n deltaX: number;\n deltaY: number;\n indicatorCol: number | null;\n indicatorRow: number | null;\n}\nconst drag = ref<DragVisual | null>(null);\nlet dragStartPointerX = 0;\nlet dragStartPointerY = 0;\n\ninterface GroupDragVisual {\n tileIds: string[];\n deltaX: number;\n deltaY: number;\n committedDcol: number;\n committedDrow: number;\n}\nconst groupDrag = ref<GroupDragVisual | null>(null);\n\ninterface PinDragState {\n tileId: string;\n startPinPx: { x: number; y: number };\n startPointerX: number;\n startPointerY: number;\n}\nconst pinDrag = ref<PinDragState | null>(null);\n\ninterface ResizeState {\n tileId: string;\n corner: Corner;\n startPointerX: number;\n startPointerY: number;\n startW: number;\n startH: number;\n startCol: number;\n startRow: number;\n previewW: number;\n previewH: number;\n previewCol: number;\n previewRow: number;\n}\nconst resize = ref<ResizeState | null>(null);\n\ninterface DrawState {\n anchorCol: number;\n anchorRow: number;\n currentCol: number;\n currentRow: number;\n}\nconst drawState = ref<DrawState | null>(null);\n\nfunction onTilePointerDown(e: PointerEvent, tile: Tile) {\n if (tile.draggable === false) return;\n if ((e.target as HTMLElement).dataset.griddleHandle) return;\n\n const ignoreSelector = config.value.dragIgnoreFrom ?? DEFAULT_DRAG_IGNORE;\n if (ignoreSelector && (e.target as HTMLElement).closest(ignoreSelector)) return;\n\n const metaKey = e.metaKey || e.ctrlKey;\n\n // Out-of-flow tiles get free-pixel drag (no selection).\n if (config.value.enablePositioning && isOutOfFlow(tile)) {\n (e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId);\n const layout = computeTileLayout({\n tile,\n config: config.value,\n scrollX: viewport.value.scrollX,\n scrollY: viewport.value.scrollY,\n viewportWidth: viewport.value.width,\n viewportHeight: viewport.value.height,\n });\n const startPinPx =\n tile.position === 'fixed'\n ? { x: layout.left - viewport.value.scrollX, y: layout.top - viewport.value.scrollY }\n : { x: layout.left, y: layout.top };\n pinDrag.value = {\n tileId: tile.id,\n startPinPx,\n startPointerX: e.clientX,\n startPointerY: e.clientY,\n };\n emit('dragStart', tile.id);\n e.stopPropagation();\n return;\n }\n\n // Cmd/Ctrl+click toggles selection without starting a drag.\n if (metaKey) {\n e.preventDefault();\n const next = new Set(selection.value);\n if (next.has(tile.id)) {\n next.delete(tile.id);\n } else {\n next.add(tile.id);\n }\n setSelection(next);\n e.stopPropagation();\n return;\n }\n\n const tileIsSelected = selection.value.has(tile.id);\n\n if (!tileIsSelected) {\n setSelection(new Set([tile.id]));\n }\n\n // Capture pointer only when starting a drag.\n (e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId);\n\n // Group drag if 2+ tiles selected including this one.\n const effectiveSelection = tileIsSelected ? selection.value : new Set([tile.id]);\n if (effectiveSelection.size > 1) {\n const ids = Array.from(effectiveSelection);\n if (!groupDragController.start(ids)) return;\n dragStartPointerX = e.clientX;\n dragStartPointerY = e.clientY;\n groupDrag.value = {\n tileIds: ids,\n deltaX: 0,\n deltaY: 0,\n committedDcol: 0,\n committedDrow: 0,\n };\n emit('dragStart', tile.id);\n e.stopPropagation();\n return;\n }\n\n // Single tile drag.\n if (!dragController.start(tile.id)) return;\n dragStartPointerX = e.clientX;\n dragStartPointerY = e.clientY;\n drag.value = {\n tileId: tile.id,\n pickupCol: tile.col,\n pickupRow: tile.row,\n deltaX: 0,\n deltaY: 0,\n indicatorCol: tile.col,\n indicatorRow: tile.row,\n };\n emit('dragStart', tile.id);\n e.stopPropagation();\n}\n\nfunction onBackgroundPointerDown(e: PointerEvent) {\n if ((e.target as HTMLElement).closest('[data-griddle-tile]')) return;\n // Draw-to-create is gated by config (default on). When disabled, empty-space\n // pointer-downs are a no-op so the host page keeps its native scroll/pan.\n if (config.value.interactive?.drawToCreate === false) return;\n setSelection(new Set());\n\n const el = scrollEl.value;\n if (!el) return;\n const rect = el.getBoundingClientRect();\n const x = e.clientX - rect.left + el.scrollLeft;\n const y = e.clientY - rect.top + el.scrollTop;\n const col = Math.floor(x / colSize.value);\n const row = Math.floor(y / rowSize.value);\n drawState.value = { anchorCol: col, anchorRow: row, currentCol: col, currentRow: row };\n (el as HTMLDivElement).setPointerCapture(e.pointerId);\n}\n\nfunction onResizeHandleDown(e: PointerEvent, tile: Tile, c: Corner) {\n if (tile.resizable === false) return;\n (e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId);\n resize.value = {\n tileId: tile.id,\n corner: c,\n startPointerX: e.clientX,\n startPointerY: e.clientY,\n startW: tile.w,\n startH: tile.h,\n startCol: tile.col,\n startRow: tile.row,\n previewW: tile.w,\n previewH: tile.h,\n previewCol: tile.col,\n previewRow: tile.row,\n };\n emit('resizeStart', tile.id);\n e.stopPropagation();\n}\n\nfunction onPointerMove(e: PointerEvent) {\n if (drawState.value) {\n const el = scrollEl.value;\n if (el) {\n const rect = el.getBoundingClientRect();\n const x = e.clientX - rect.left + el.scrollLeft;\n const y = e.clientY - rect.top + el.scrollTop;\n const col = Math.max(0, Math.floor(x / colSize.value));\n const row = Math.max(0, Math.floor(y / rowSize.value));\n drawState.value = { ...drawState.value, currentCol: col, currentRow: row };\n }\n return;\n }\n const pd = pinDrag.value;\n const gd = groupDrag.value;\n const d = drag.value;\n const r = resize.value;\n if (pd) {\n const dx = e.clientX - pd.startPointerX;\n const dy = e.clientY - pd.startPointerY;\n const newPinPx = { x: pd.startPinPx.x + dx, y: pd.startPinPx.y + dy };\n const newPin = pixelsToPin(newPinPx, config.value);\n props.api.grid.setTilePinned(pd.tileId, newPin);\n }\n if (gd) {\n const dx = e.clientX - dragStartPointerX;\n const dy = e.clientY - dragStartPointerY;\n const dcol = Math.round(dx / colSize.value);\n const drow = Math.round(dy / rowSize.value);\n const result = groupDragController.update({ dcol, drow });\n groupDrag.value = {\n ...gd,\n deltaX: dx,\n deltaY: dy,\n committedDcol: result.indicatorDelta?.dcol ?? gd.committedDcol,\n committedDrow: result.indicatorDelta?.drow ?? gd.committedDrow,\n };\n if (result.changed) syncTiles();\n }\n if (d) {\n const dx = e.clientX - dragStartPointerX;\n const dy = e.clientY - dragStartPointerY;\n const candidateCol = d.pickupCol + Math.round(dx / colSize.value);\n const candidateRow = d.pickupRow + Math.round(dy / rowSize.value);\n const result = dragController.update({ col: candidateCol, row: candidateRow });\n drag.value = {\n ...d,\n deltaX: dx,\n deltaY: dy,\n indicatorCol: result.indicatorCell ? result.indicatorCell.col : null,\n indicatorRow: result.indicatorCell ? result.indicatorCell.row : null,\n };\n // DragController.restoreTiles() doesn't emit change events, so when the\n // candidate cell changes (especially returning to pickup), force-sync the\n // reactive tiles ref so the FLIP animation picks up displaced tile resets.\n if (result.changed) syncTiles();\n }\n if (r) {\n const dx = e.clientX - r.startPointerX;\n const dy = e.clientY - r.startPointerY;\n let dw = 0, dh = 0, dcol = 0, drow = 0;\n const stepsX = Math.round(dx / colSize.value);\n const stepsY = Math.round(dy / rowSize.value);\n if (r.corner === 'se' || r.corner === 'ne') dw = stepsX;\n if (r.corner === 'se' || r.corner === 'sw') dh = stepsY;\n if (r.corner === 'sw' || r.corner === 'nw') { dw = -stepsX; dcol = stepsX; }\n if (r.corner === 'ne' || r.corner === 'nw') { dh = -stepsY; drow = stepsY; }\n const tile = props.api.grid.getTile(r.tileId);\n const minW = tile?.minW ?? 1;\n const minH = tile?.minH ?? 1;\n const maxW = tile?.maxW ?? Infinity;\n const maxH = tile?.maxH ?? Infinity;\n const nW = Math.min(maxW, Math.max(minW, r.startW + dw));\n const nH = Math.min(maxH, Math.max(minH, r.startH + dh));\n const nC = r.startCol + dcol;\n const nR = r.startRow + drow;\n if (nW !== r.previewW || nH !== r.previewH || nC !== r.previewCol || nR !== r.previewRow) {\n resize.value = { ...r, previewW: nW, previewH: nH, previewCol: nC, previewRow: nR };\n }\n }\n}\n\nfunction syncTiles() {\n // DragController/GroupDragController may restore grid snapshots without\n // emitting change events. Force-sync the reactive tiles ref so the UI\n // reflects the grid's true state after a drag ends.\n props.api.tiles.value = props.api.grid.tiles;\n props.api.version.value++;\n}\n\nfunction onPointerUp() {\n if (drawState.value) {\n const ds = drawState.value;\n const col = Math.min(ds.anchorCol, ds.currentCol);\n const row = Math.min(ds.anchorRow, ds.currentRow);\n const w = Math.max(1, Math.abs(ds.currentCol - ds.anchorCol) + 1);\n const h = Math.max(1, Math.abs(ds.currentRow - ds.anchorRow) + 1);\n drawState.value = null;\n emit('drawCreate', { col, row, w, h });\n return;\n }\n if (pinDrag.value) {\n const tileId = pinDrag.value.tileId;\n pinDrag.value = null;\n emit('dragEnd', tileId, true);\n }\n if (groupDrag.value) {\n const tileIds = groupDrag.value.tileIds;\n const { committed } = groupDragController.end();\n groupDrag.value = null;\n syncTiles();\n const firstId = tileIds[0];\n if (firstId !== undefined) emit('dragEnd', firstId, committed);\n }\n if (drag.value) {\n const tileId = drag.value.tileId;\n const { committed } = dragController.end();\n drag.value = null;\n syncTiles();\n emit('dragEnd', tileId, committed);\n }\n const r = resize.value;\n if (r) {\n const t = props.api.grid.getTile(r.tileId);\n let committed = false;\n if (t) {\n if (r.previewCol !== t.col || r.previewRow !== t.row) {\n props.api.moveTile(r.tileId, { col: r.previewCol, row: r.previewRow });\n }\n if (r.previewW !== t.w || r.previewH !== t.h) {\n committed = props.api.resizeTile(r.tileId, { w: r.previewW, h: r.previewH });\n } else {\n committed = r.previewCol !== r.startCol || r.previewRow !== r.startRow\n || r.previewW !== r.startW || r.previewH !== r.startH;\n }\n }\n resize.value = null;\n emit('resizeEnd', r.tileId, committed);\n }\n}\n\nfunction updateViewport() {\n const el = scrollEl.value;\n if (!el) return;\n viewport.value = {\n scrollX: el.scrollLeft,\n scrollY: el.scrollTop,\n width: el.clientWidth,\n height: el.clientHeight,\n };\n}\n\nfunction onKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') setSelection(new Set());\n}\n\nlet ro: ResizeObserver | null = null;\nonMounted(() => {\n updateViewport();\n // scrollEl is absent while loop mode delegates to GriddleLoopGrid.\n const el = scrollEl.value;\n if (el) {\n el.addEventListener('scroll', updateViewport, { passive: true });\n ro = new ResizeObserver(updateViewport);\n ro.observe(el);\n }\n window.addEventListener('pointermove', onPointerMove);\n window.addEventListener('pointerup', onPointerUp);\n window.addEventListener('pointercancel', onPointerUp);\n window.addEventListener('keydown', onKeyDown);\n});\nonBeforeUnmount(() => {\n const el = scrollEl.value;\n if (el) el.removeEventListener('scroll', updateViewport);\n ro?.disconnect();\n window.removeEventListener('pointermove', onPointerMove);\n window.removeEventListener('pointerup', onPointerUp);\n window.removeEventListener('pointercancel', onPointerUp);\n window.removeEventListener('keydown', onKeyDown);\n});\n\nconst tileNodes = new Map<string, HTMLDivElement>();\nconst prevRects = new Map<string, { x: number; y: number }>();\nfunction registerNode(id: string, el: HTMLDivElement | null) {\n if (el) tileNodes.set(id, el);\n else tileNodes.delete(id);\n}\n\nwatch(() => props.api.version.value, async () => {\n await nextTick();\n const draggerId = drag.value?.tileId ?? null;\n const gdSet = groupDragSet.value;\n for (const t of props.api.tiles.value) {\n const x = t.col * colSize.value + halfGap.value;\n const y = t.row * rowSize.value + halfGap.value;\n if (t.id === draggerId || gdSet.has(t.id)) {\n prevRects.set(t.id, { x, y });\n continue;\n }\n const p = prevRects.get(t.id);\n const node = tileNodes.get(t.id);\n if (p && node) {\n const dx = p.x - x;\n const dy = p.y - y;\n if (dx !== 0 || dy !== 0) {\n animateReposition(node, dx, dy, config.value.animation);\n }\n }\n prevRects.set(t.id, { x, y });\n }\n});\n\n// Compute layouts for all rendered tiles in one pass so resolveStickyStacking\n// can see every sticky tile and adjust them as a group. Recomputes whenever\n// rendered, config, viewport, drag, resize, or pinDrag change.\nconst tileLayouts = computed(() => {\n const out = new Map<string, TileLayout>();\n const stickyEntries: { tile: Tile; layout: TileLayout }[] = [];\n const gd = groupDrag.value;\n const gdIds = groupDragSet.value;\n for (const tile of rendered.value) {\n let layout: TileLayout;\n if (resize.value?.tileId === tile.id) {\n const w = resize.value.previewW;\n const h = resize.value.previewH;\n layout = {\n left: resize.value.previewCol * colSize.value + halfGap.value,\n top: resize.value.previewRow * rowSize.value + halfGap.value,\n width: w * config.value.unitWidth + (w - 1) * gap.value,\n height: h * config.value.unitHeight + (h - 1) * gap.value,\n zIndex: 10,\n effective: 'static',\n };\n } else if (drag.value?.tileId === tile.id) {\n const d = drag.value;\n layout = {\n left: d.pickupCol * colSize.value + halfGap.value,\n top: d.pickupRow * rowSize.value + halfGap.value,\n width: tile.w * config.value.unitWidth + (tile.w - 1) * gap.value,\n height: tile.h * config.value.unitHeight + (tile.h - 1) * gap.value,\n transform: `translate(${d.deltaX}px, ${d.deltaY}px)`,\n zIndex: 20,\n effective: 'static',\n };\n } else if (gd && gdIds.has(tile.id)) {\n const pickup = groupDragController.pickupCell(tile.id);\n const left = (pickup ? pickup.col * colSize.value : tile.col * colSize.value) + halfGap.value;\n const top = (pickup ? pickup.row * rowSize.value : tile.row * rowSize.value) + halfGap.value;\n layout = {\n left,\n top,\n width: tile.w * config.value.unitWidth + (tile.w - 1) * gap.value,\n height: tile.h * config.value.unitHeight + (tile.h - 1) * gap.value,\n transform: `translate(${gd.deltaX}px, ${gd.deltaY}px)`,\n zIndex: 20,\n effective: 'static',\n };\n } else {\n layout = computeTileLayout({\n tile,\n config: config.value,\n scrollX: viewport.value.scrollX,\n scrollY: viewport.value.scrollY,\n viewportWidth: viewport.value.width,\n viewportHeight: viewport.value.height,\n });\n if (layout.effective === 'sticky') {\n stickyEntries.push({ tile, layout });\n }\n }\n out.set(tile.id, layout);\n }\n if (stickyEntries.length > 1) resolveStickyStacking(stickyEntries);\n return out;\n});\n\nfunction tileStyle(tile: Tile) {\n const isDragging = drag.value?.tileId === tile.id;\n const isGroupDragging = groupDragSet.value.has(tile.id) && groupDrag.value !== null;\n const isPinDragging = pinDrag.value?.tileId === tile.id;\n const isResizing = resize.value?.tileId === tile.id;\n const isSelected = selection.value.has(tile.id);\n const layout = tileLayouts.value.get(tile.id) ?? {\n left: 0, top: 0, width: 0, height: 0, zIndex: 1, effective: 'static' as const,\n };\n const lifted = isDragging || isPinDragging || isGroupDragging;\n return {\n position: 'absolute' as const,\n left: layout.left + 'px',\n top: layout.top + 'px',\n width: layout.width + 'px',\n height: layout.height + 'px',\n boxSizing: 'border-box' as const,\n cursor: lifted ? 'grabbing' : 'grab',\n userSelect: 'none' as const,\n zIndex: layout.zIndex,\n opacity: lifted || isResizing ? 0.85 : 1,\n willChange: 'transform, translate',\n transform: layout.transform ?? '',\n filter: lifted ? 'drop-shadow(0 8px 16px rgba(0,0,0,0.18))' : '',\n transition: lifted ? liftTransition(config.value.animation) : '',\n boxShadow: isSelected\n ? '0 0 0 3px rgba(59, 91, 219, 0.85), inset 0 0 0 1px rgba(59, 91, 219, 0.3)'\n : '',\n borderRadius: (config.value.tileRadius ?? 4) + 'px',\n };\n}\n\n\nconst indicatorRect = computed(() => {\n const d = drag.value;\n if (!d || d.indicatorCol === null || d.indicatorRow === null) return null;\n const t = props.api.grid.getTile(d.tileId);\n if (!t) return null;\n return {\n left: d.indicatorCol * colSize.value + halfGap.value,\n top: d.indicatorRow * rowSize.value + halfGap.value,\n width: t.w * config.value.unitWidth + (t.w - 1) * gap.value,\n height: t.h * config.value.unitHeight + (t.h - 1) * gap.value,\n };\n});\n\nconst drawGhostRect = computed(() => {\n const ds = drawState.value;\n if (!ds) return null;\n const col = Math.min(ds.anchorCol, ds.currentCol);\n const row = Math.min(ds.anchorRow, ds.currentRow);\n const w = Math.max(1, Math.abs(ds.currentCol - ds.anchorCol) + 1);\n const h = Math.max(1, Math.abs(ds.currentRow - ds.anchorRow) + 1);\n return {\n left: col * colSize.value + halfGap.value,\n top: row * rowSize.value + halfGap.value,\n width: w * config.value.unitWidth + (w - 1) * gap.value,\n height: h * config.value.unitHeight + (h - 1) * gap.value,\n label: `${w}×${h}`,\n };\n});\n\nfunction tileHandles(tile: Tile): Corner[] {\n return tile.resizeHandles ?? config.value.resizeHandles ?? ['se'];\n}\n\nfunction handleStyle(c: Corner) {\n const size = 12;\n const base = {\n position: 'absolute' as const,\n width: size + 'px',\n height: size + 'px',\n background: 'rgba(60,60,60,0.7)',\n border: '2px solid white',\n borderRadius: '3px',\n cursor: `${c}-resize`,\n touchAction: 'none' as const,\n } as Record<string, unknown>;\n if (c === 'nw') return { ...base, top: -size / 2 + 'px', left: -size / 2 + 'px' };\n if (c === 'ne') return { ...base, top: -size / 2 + 'px', right: -size / 2 + 'px' };\n if (c === 'sw') return { ...base, bottom: -size / 2 + 'px', left: -size / 2 + 'px' };\n return { ...base, bottom: -size / 2 + 'px', right: -size / 2 + 'px' };\n}\n\nconst className = computed(() => props.className ?? '');\n</script>\n","// Vue composable that wraps a Grid instance with reactive state.\n\nimport { onBeforeUnmount, reactive, ref, shallowRef } from 'vue';\nimport { Grid } from '@griddle/core';\nimport type { GridConfig, Tile, GridSnapshot } from '@griddle/core';\n\nexport interface UseGriddleInit {\n config: GridConfig;\n tiles?: Tile[];\n}\n\nexport function useGriddle(init: UseGriddleInit) {\n const grid = new Grid(init.config, init.tiles ?? []);\n\n // Reactive mirrors of tiles and config. We re-assign on changes.\n const tiles = shallowRef<Tile[]>(grid.tiles);\n const config = shallowRef<GridConfig>(grid.config);\n const version = ref(0);\n\n const off = grid.changes.on(() => {\n tiles.value = grid.tiles;\n config.value = grid.config;\n version.value++;\n });\n onBeforeUnmount(off);\n\n const api = {\n grid,\n tiles,\n config,\n version,\n moveTile: (id: string, target: { col: number; row: number }) => grid.moveTile(id, target),\n resizeTile: (id: string, size: { w: number; h: number }) => grid.resizeTile(id, size),\n addTile: (t: Tile) => grid.addTile(t),\n removeTile: (id: string) => grid.removeTile(id),\n updateConfig: (patch: Partial<GridConfig>) => grid.updateConfig(patch),\n toJSON: () => grid.toJSON(),\n loadJSON: (snap: GridSnapshot) => grid.loadJSON(snap),\n };\n return api;\n}\n\nexport type GriddleApi = ReturnType<typeof useGriddle>;\n"],"names":["DEFAULT_DRAG_IGNORE","PAN_THRESHOLD_PX","props","__props","emit","__emit","viewportEl","ref","planeEl","config","computed","loop","resolveLoop","editable","_a","gap","halfGap","colSize","rowSize","period","loopPeriod","pan","PanController","watch","l","view","lastCam","raf","resizeObserver","onWheel","e","k","frame","now","st","plane","el","cxCell","cyCell","cur","instances","bufX","bufY","loopInstances","panGesture","suppressClick","onContainerPointerDown","onTile","setSelection","ignoreSelector","onClickCapture","internalSelection","selection","next","dragController","DragController","drag","dragStartPointerX","dragStartPointerY","resize","syncTiles","isBase","inst","isGhost","onTilePointerDown","tile","onResizeHandleDown","c","baseLeft","baseTop","onPointerMove","d","dx","dy","candidate","result","r","dw","dh","dcol","drow","stepsX","stepsY","minW","minH","maxW","maxH","nW","nH","nC","nR","onPointerUp","tileId","committed","t","target","onKeyDown","onMounted","measure","onBeforeUnmount","tileNodes","prevRects","registerNode","key","nextTick","draggerId","seen","x","y","p","node","animateReposition","viewportStyle","bg","planeStyle","instanceStyle","isResizingInst","left","top","width","heightPx","ghost","isSelected","draggedTile","dragOverlayStyle","indicatorRect","tileHandles","handleStyle","base","className","_createElementBlock","_createElementVNode","_normalizeStyle","_Fragment","_renderList","_normalizeClass","_renderSlot","_ctx","_openBlock","loopOn","scrollEl","viewport","range","visibleRange","rendered","visibleTiles","contentSize","gridContentSize","scrollStyle","contained","style","contentStyle","groupDragSet","groupDrag","groupDragController","GroupDragController","pinDrag","drawState","metaKey","isOutOfFlow","layout","computeTileLayout","startPinPx","tileIsSelected","effectiveSelection","ids","onBackgroundPointerDown","rect","col","row","pd","gd","newPinPx","newPin","pixelsToPin","_b","candidateCol","candidateRow","ds","w","h","tileIds","firstId","updateViewport","ro","id","gdSet","tileLayouts","out","stickyEntries","gdIds","pickup","resolveStickyStacking","tileStyle","isDragging","isGroupDragging","isPinDragging","isResizing","_c","lifted","liftTransition","drawGhostRect","_createBlock","GriddleLoopGrid","_cache","s","cam","_withCtx","slotProps","_toDisplayString","useGriddle","init","grid","Grid","tiles","shallowRef","version","off","size","patch","snap"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@griddle/vue",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Vue 3 bindings for Griddle — a headless, zero-dependency grid/canvas engine.",
5
5
  "keywords": [
6
6
  "grid",
@@ -48,15 +48,16 @@
48
48
  },
49
49
  "scripts": {
50
50
  "build": "vite build && vue-tsc -p tsconfig.json",
51
- "prepublishOnly": "npm run build"
51
+ "test": "node --test test/animation.test.mjs",
52
+ "prepublishOnly": "npm run build && npm test"
52
53
  },
53
54
  "peerDependencies": {
54
55
  "vue": "^3.3.0",
55
- "@griddle/core": "^0.1.0"
56
+ "@griddle/core": "^0.1.2"
56
57
  },
57
58
  "devDependencies": {
58
59
  "vue": "^3.4.0",
59
- "@griddle/core": "^0.1.0",
60
+ "@griddle/core": "^0.1.2",
60
61
  "vite": "^5.4.0",
61
62
  "@vitejs/plugin-vue": "^5.2.0",
62
63
  "vue-tsc": "^2.2.0"
@@ -111,6 +111,7 @@ import {
111
111
  } from '@griddle/core';
112
112
  import type { TileLayout } from '@griddle/core';
113
113
  import type { GriddleApi } from './useGriddle.js';
114
+ import { animateReposition, liftTransition } from './animation.js';
114
115
 
115
116
  const props = defineProps<{
116
117
  api: GriddleApi;
@@ -586,12 +587,7 @@ watch(() => props.api.version.value, async () => {
586
587
  const dx = p.x - x;
587
588
  const dy = p.y - y;
588
589
  if (dx !== 0 || dy !== 0) {
589
- node.style.transition = 'none';
590
- node.style.transform = `translate(${dx}px, ${dy}px)`;
591
- requestAnimationFrame(() => {
592
- node.style.transition = 'transform 220ms cubic-bezier(.2,.7,.2,1)';
593
- node.style.transform = 'translate(0,0)';
594
- });
590
+ animateReposition(node, dx, dy, config.value.animation);
595
591
  }
596
592
  }
597
593
  prevRects.set(t.id, { x, y });
@@ -683,10 +679,10 @@ function tileStyle(tile: Tile) {
683
679
  userSelect: 'none' as const,
684
680
  zIndex: layout.zIndex,
685
681
  opacity: lifted || isResizing ? 0.85 : 1,
686
- willChange: 'transform',
682
+ willChange: 'transform, translate',
687
683
  transform: layout.transform ?? '',
688
684
  filter: lifted ? 'drop-shadow(0 8px 16px rgba(0,0,0,0.18))' : '',
689
- transition: lifted ? 'filter 120ms ease-out, opacity 120ms ease-out' : '',
685
+ transition: lifted ? liftTransition(config.value.animation) : '',
690
686
  boxShadow: isSelected
691
687
  ? '0 0 0 3px rgba(59, 91, 219, 0.85), inset 0 0 0 1px rgba(59, 91, 219, 0.3)'
692
688
  : '',
package/src/LoopGrid.vue CHANGED
@@ -79,6 +79,7 @@ import {
79
79
  } from '@griddle/core';
80
80
  import type { LoopTileInstance } from '@griddle/core';
81
81
  import type { GriddleApi } from './useGriddle.js';
82
+ import { animateReposition } from './animation.js';
82
83
 
83
84
  const props = defineProps<{
84
85
  api: GriddleApi;
@@ -480,12 +481,7 @@ watch(() => props.api.version.value, async () => {
480
481
  Math.abs(dx) < period.value.width / 2 &&
481
482
  Math.abs(dy) < period.value.height / 2
482
483
  ) {
483
- node.style.transition = 'none';
484
- node.style.transform = `translate(${dx}px, ${dy}px)`;
485
- requestAnimationFrame(() => {
486
- node.style.transition = 'transform 220ms cubic-bezier(.2,.7,.2,1)';
487
- node.style.transform = 'translate(0,0)';
488
- });
484
+ animateReposition(node, dx, dy, config.value.animation);
489
485
  }
490
486
  }
491
487
  }
@@ -512,6 +508,7 @@ const viewportStyle = computed(() => {
512
508
  height: typeof props.height === 'number' ? props.height + 'px' : (props.height ?? '100%'),
513
509
  touchAction: 'none' as const,
514
510
  userSelect: 'none' as const,
511
+ willChange: 'translate',
515
512
  cursor: !editable.value && loop.value?.dragPan ? 'grab' : undefined,
516
513
  ['--griddle-tile-radius' as string]: (config.value.tileRadius ?? 4) + 'px',
517
514
  ...bg,
@@ -0,0 +1,62 @@
1
+ import {
2
+ resolveAnimationConfig,
3
+ type GridAnimationConfig,
4
+ } from '@griddle/core';
5
+
6
+ const pendingFrames = new WeakMap<HTMLElement, number>();
7
+
8
+ function reducedMotionRequested(config: GridAnimationConfig | undefined): boolean {
9
+ const animation = resolveAnimationConfig(config);
10
+ return animation.respectReducedMotion &&
11
+ typeof window !== 'undefined' &&
12
+ typeof window.matchMedia === 'function' &&
13
+ window.matchMedia('(prefers-reduced-motion: reduce)').matches;
14
+ }
15
+
16
+ function currentTranslation(node: HTMLElement): { x: number; y: number } {
17
+ if (typeof window === 'undefined') return { x: 0, y: 0 };
18
+ const translate = window.getComputedStyle(node).translate;
19
+ if (!translate || translate === 'none') return { x: 0, y: 0 };
20
+ const [x = '0', y = '0'] = translate.split(/\s+/);
21
+ return { x: Number.parseFloat(x) || 0, y: Number.parseFloat(y) || 0 };
22
+ }
23
+
24
+ /** Continue rapid repacks from the tile's current visual position. */
25
+ export function animateReposition(
26
+ node: HTMLElement,
27
+ deltaX: number,
28
+ deltaY: number,
29
+ config?: GridAnimationConfig,
30
+ ): void {
31
+ const pending = pendingFrames.get(node);
32
+ if (pending !== undefined) cancelAnimationFrame(pending);
33
+
34
+ const animation = resolveAnimationConfig(config);
35
+ if (!animation.enabled || animation.repositionDurationMs === 0 || reducedMotionRequested(config)) {
36
+ node.style.transition = 'none';
37
+ node.style.translate = '0px 0px';
38
+ pendingFrames.delete(node);
39
+ return;
40
+ }
41
+
42
+ const current = currentTranslation(node);
43
+ node.style.transition = 'none';
44
+ node.style.translate = `${deltaX + current.x}px ${deltaY + current.y}px`;
45
+ void node.offsetWidth;
46
+
47
+ const frame = requestAnimationFrame(() => {
48
+ pendingFrames.delete(node);
49
+ node.style.transition =
50
+ `translate ${animation.repositionDurationMs}ms ${animation.repositionEasing}`;
51
+ node.style.translate = '0px 0px';
52
+ });
53
+ pendingFrames.set(node, frame);
54
+ }
55
+
56
+ export function liftTransition(config?: GridAnimationConfig): string {
57
+ const animation = resolveAnimationConfig(config);
58
+ const duration = !animation.enabled || reducedMotionRequested(config)
59
+ ? 0
60
+ : animation.liftDurationMs;
61
+ return `filter ${duration}ms ${animation.liftEasing}, opacity ${duration}ms ${animation.liftEasing}`;
62
+ }