@dashfoo/react 0.6.0 → 0.6.1

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","names":["Panel"],"sources":["../src/lib/topmost-collision.ts","../src/hooks/drag-hooks.tsx","../src/hooks/persistence.ts","../src/hooks/responsive.ts","../src/hooks/store.ts","../src/lib/tab-insertion.ts","../src/components/drag-overlays.tsx","../src/components/drag-root.tsx","../src/hooks/layout-store.ts","../src/lib/warn-once.ts","../src/components/drag-adapter.tsx","../src/components/float-context.ts","../src/lib/float-geometry.ts","../src/components/float-resize-handles.ts","../src/components/layout-root.tsx","../src/lib/tab-ids.ts","../src/components/tabset/tabset-store.ts","../src/components/tabset/tabset-content.tsx","../src/components/tab-overflow.tsx","../src/components/tabset/tabset-overflow.tsx","../src/hooks/use-tab-overflow.ts","../src/lib/tab-selection.ts","../src/components/tabset/tabset-root.tsx","../src/lib/merge-refs.ts","../src/components/tabset/tabset-tab.tsx","../src/components/tabset-icons.tsx","../src/components/tabset/tabset-tab-controls.tsx","../src/components/tabset/tabset-tablist.tsx","../src/components/tabset/tabset-toolbar.tsx","../src/components/tabset/tabset-view.tsx","../src/components/row-view.tsx","../src/components/float-panel.tsx","../src/components/float-layer.tsx","../src/components/layout.tsx","../src/components/dashfoo-layout.tsx","../src/components/panel.tsx","../src/components/tabset/tabset.ts"],"sourcesContent":["import type { Collision, CollisionDetector, UniqueIdentifier } from \"@dnd-kit/abstract\";\nimport { CollisionPriority, CollisionType } from \"@dnd-kit/abstract\";\n\n// The collision detector behind every tabset droppable. dnd-kit's built-in\n// detectors are pure rect geometry with no notion of paint order, but docked\n// tabsets tile while floats overlay them — a tabset's rect can contain a point\n// that is actually over a float on top of it. elementFromPoint returns the\n// occluding element, so an occluded tabset's detector returns null and it never\n// becomes the drop target or shows a stale indicator. The drag overlays\n// (preview, indicator) are pointer-events:none, so they're ignored.\n//\n// Never reads droppable.shape: shapes ride a throttled PositionObserver, while\n// the live DOM answer is always current (auto-scroll, float moves mid-drag).\n\n// What the detector actually reads — a structural supertype of dnd-kit's\n// CollisionDetectorInput, so the same function serves dnd-kit at runtime and\n// plain objects in unit tests. The abstract Droppable carries no element; a\n// droppable without one can't be hit.\ntype TopmostDetectorInput = {\n dragOperation: { position: { current: { x: number; y: number } } };\n droppable: { element?: Element; id: UniqueIdentifier };\n};\n\ntype TopmostDetector = (input: TopmostDetectorInput) => Collision | null;\n\n// One elementFromPoint per collision pass, not per droppable: a pass runs\n// synchronously over every droppable at one pointer position, so the lookup is\n// cached by exact coordinates and dropped on the next microtask — before any\n// later pass (whose DOM may have scrolled under a stationary pointer) can read\n// a stale answer.\nconst createTopmostPointerIntersection = (\n topElementAt: (x: number, y: number) => Element | null = (x, y) =>\n document.elementFromPoint(x, y),\n): TopmostDetector => {\n let cached: { top: Element | null; x: number; y: number } | null = null;\n const topAt = (x: number, y: number): Element | null => {\n if (cached && cached.x === x && cached.y === y) {\n return cached.top;\n }\n const top = topElementAt(x, y);\n cached = { top, x, y };\n queueMicrotask(() => {\n cached = null;\n });\n return top;\n };\n\n return ({ dragOperation, droppable }) => {\n const { element } = droppable;\n if (!element) {\n return null;\n }\n const point = dragOperation.position.current;\n const top = topAt(point.x, point.y);\n if (!top || !element.contains(top)) {\n return null;\n }\n // At most one non-nested droppable contains the topmost element; when\n // droppables nest (a layout inside a tab), DOM depth makes the innermost\n // win deterministically.\n let depth = 0;\n for (let node: Element | null = element; node; node = node.parentElement) {\n depth += 1;\n }\n return {\n id: droppable.id,\n priority: CollisionPriority.High,\n type: CollisionType.PointerIntersection,\n value: depth,\n };\n };\n};\n\nconst topmostPointerIntersection: CollisionDetector = createTopmostPointerIntersection();\n\nexport { createTopmostPointerIntersection, topmostPointerIntersection };\nexport type { TopmostDetectorInput };\n","\"use client\";\n\nimport type { DragSubject, DropIntent, TabNode } from \"@dashfoo/core\";\nimport {\n Accessibility,\n Draggable,\n DragDropManager,\n Droppable,\n Feedback,\n PointerSensor,\n} from \"@dnd-kit/dom\";\nimport type { Context } from \"react\";\nimport { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef } from \"react\";\nimport type { StoreApi } from \"zustand\";\nimport { createStore, useStore } from \"zustand\";\n\nimport { topmostPointerIntersection } from \"../lib/topmost-collision\";\n\n// Shared drag contexts + the draggable/droppable hooks. Lives apart from\n// drag-adapter.tsx so the contexts can be owned here without a circular import:\n// drag-adapter imports these for DragProvider and re-exports the hooks, and this\n// module never reaches back into drag-adapter.\n\nconst INTERACTIVE_SELECTOR = `\n input:not([disabled]),\n select:not([disabled]),\n textarea:not([disabled]),\n button:not([disabled]),\n a[href],\n [contenteditable]:not([contenteditable=\"false\"])\n`;\n\n// The sensor's default preventActivation vetoes any pointerdown whose target is\n// an element child of the draggable: closest() walks up to the trigger button\n// itself and calls it \"interactive\". Plain-text labels dodge that (text nodes\n// are not elements), but custom labels render elements inside the trigger and\n// would silently lose dragging. Allow the draggable itself as the handle while\n// still refusing genuinely interactive children nested in a label.\nconst preventActivation = (event: PointerEvent, source: Draggable): boolean => {\n const { target } = event;\n if (!(target instanceof Element)) {\n return false;\n }\n const interactive = target.closest(INTERACTIVE_SELECTOR);\n return interactive !== null && interactive !== source.element;\n};\n\n// Plugins drop the screen-reader announcer (it stamps ARIA that is invalid on\n// role=tab) and reconfigure Feedback: it runs in overlay mode only — the chip\n// element is handed to its public `overlay` accessor (see DragPreviewOverlay),\n// so the source element is never promoted or placeholder-cloned — with the drop\n// animation off, since drops must settle immediately and new drags are ignored\n// while one animates. Sensors keep only a configured PointerSensor — the\n// KeyboardSensor's nudge model double-binds the arrow keys the tab strip\n// already uses for roving-tabindex navigation, so keyboard docking needs its\n// own interaction design rather than that sensor.\nconst createDragManager = (): DragDropManager =>\n new DragDropManager({\n plugins: (defaults) => [\n ...defaults.filter((plugin) => plugin !== Accessibility && plugin !== Feedback),\n Feedback.configure({ dropAnimation: null }),\n ],\n sensors: () => [PointerSensor.configure({ preventActivation })],\n });\n\ntype DragContextValue = {\n // Identifies the owning DragProvider: droppables carry it in `data` so each\n // layer can claim only its own targets from the manager-global winner.\n layerId: string;\n manager: DragDropManager;\n};\n\nconst DragContext = createContext<DragContextValue | null>(null);\n\n// A manager owned by DashfooDragProvider, shared between a layout and external\n// tab sources outside it so drags can cross that boundary. The annotation keeps\n// declaration emit from expanding @dnd-kit's non-exported generic defaults.\nconst SharedDragManagerContext: Context<DragDropManager | null> =\n createContext<DragDropManager | null>(null);\n\n// The live drag subject and drop intent ride a scoped zustand store instead of a\n// context value, so a drag start/end re-renders only the parts that select the\n// subject — never the provider subtree. The store is owned by the nearest\n// DashfooDragProvider when one exists (so anything under it, layout or not, can\n// observe drags) and by the DragLayer otherwise; the dragDockMachine\n// subscription feeds it. Intent updates are value-guarded by the adapter\n// (sameDropIntent) so OVER pulses only notify when the resolved drop changes.\n// intentOwner disambiguates layouts sharing one store: each layer claims only\n// its own droppables from the manager-global winner, so a null intent from one\n// layer must not erase the live intent the owning layer resolved — the write\n// order between layers on a winner handoff is unspecified.\ntype DragSubjectState = {\n intent: DropIntent | null;\n intentOwner: string | null;\n subject: DragSubject | null;\n};\n\ntype DragSubjectStore = StoreApi<DragSubjectState>;\n\nconst createDragSubjectStore = (): DragSubjectStore =>\n createStore<DragSubjectState>(() => ({ intent: null, intentOwner: null, subject: null }));\n\n// Whether two intents resolve the same drop. Intents are rebuilt on every\n// pointer move, so identity alone would notify subscribers on each pulse.\nconst sameDropIntent = (a: DropIntent | null, b: DropIntent | null): boolean =>\n a === b ||\n (a !== null &&\n b !== null &&\n a.index === b.index &&\n a.location === b.location &&\n a.targetId === b.targetId);\n\n// Whether two subjects describe the same drag. Layouts sharing a manager each\n// build their own subject object for the same drag, so identity alone would\n// write twice per drag start.\nconst sameDragSubject = (a: DragSubject | null, b: DragSubject | null): boolean =>\n a === b || (a !== null && b !== null && a.id === b.id && a.kind === b.kind);\n\n// Stable empty store so useDragSubject keeps an unconditional hook order (and\n// returns null) outside a DragLayer — parts must keep working drag-free.\nconst nullSubjectStore = createDragSubjectStore();\n\nconst DragSubjectStoreContext: Context<DragSubjectStore | null> =\n createContext<DragSubjectStore | null>(null);\n\n// Tracks a Draggable's element across renders without rebuilding it. Returned by\n// the draggable hooks; their effects own the Draggable's lifecycle.\ntype DraggableHandle = {\n draggableRef: { current: Draggable | null };\n elementRef: { current: Element | null };\n ref: (element: Element | null) => void;\n};\n\nconst useDraggableHandle = (): DraggableHandle => {\n const elementRef = useRef<Element | null>(null);\n const draggableRef = useRef<Draggable | null>(null);\n const ref = useCallback((element: Element | null): void => {\n elementRef.current = element;\n if (draggableRef.current) {\n draggableRef.current.element = element ?? undefined;\n }\n }, []);\n return { draggableRef, elementRef, ref };\n};\n\n// What a draggable carries: the dnd-kit id and the stable data (drag kind +\n// tabset id), both derived from identity. The chip label is passed separately so\n// it never sits in the construction effect's deps. data must be referentially\n// stable (the wrappers memoize it) so the construction effect tracks it without\n// rebuilding on every render.\ntype DraggableDescriptor = { data: Record<string, unknown>; id: string };\n\n// Owns the full Draggable lifecycle shared by the tab and tabset hooks. The\n// construction effect is keyed on identity only (manager, id, disabled, the\n// stable data) — never on the chip label — so a tab click or rename can't tear\n// down and rebuild the live instance. The label is folded into the live data by\n// a separate effect, since data is only read at drag start; both effects fire in\n// the same mount commit, so the label is current well before any pointer drag.\n// `Draggable.data` is a public accessor in @dnd-kit/abstract, so the in-place\n// update is type-safe.\nconst useDraggableEntity = (\n descriptor: DraggableDescriptor,\n disabled: boolean,\n label: string,\n): { ref: (element: Element | null) => void } => {\n const context = useContext(DragContext);\n // Internal draggables (tabs, grips) live under DragProvider; external tab\n // sources sit outside it and reach the manager via DashfooDragProvider.\n const sharedManager = useContext(SharedDragManagerContext);\n const manager = context?.manager ?? sharedManager;\n const { draggableRef, elementRef, ref } = useDraggableHandle();\n const { data, id } = descriptor;\n\n useEffect(() => {\n if (!manager || disabled) {\n return undefined;\n }\n const draggable = new Draggable({ data: { ...data, label: \"\" }, id }, manager);\n draggable.element = elementRef.current ?? undefined;\n draggableRef.current = draggable;\n return () => {\n draggable.destroy();\n draggableRef.current = null;\n };\n }, [data, disabled, draggableRef, elementRef, id, manager]);\n\n useEffect(() => {\n const draggable = draggableRef.current;\n if (draggable) {\n draggable.data = { ...data, label };\n }\n }, [data, draggableRef, label]);\n\n return { ref };\n};\n\nconst useTabDraggable = (\n tabId: string,\n disabled = false,\n label = \"\",\n): { ref: (element: Element | null) => void } => {\n const data = useMemo(() => ({ type: \"tab\" }), []);\n return useDraggableEntity({ data, id: tabId }, disabled, label);\n};\n\n// The whole tabset is draggable from its grip. A distinct dnd-kit id (grip-*)\n// avoids colliding with the tabset's own registered id; the real tabset id rides\n// in `data` and becomes the moveTabset subject. The label feeds the overlay chip.\nconst useTabsetDraggable = (\n tabsetId: string,\n disabled = false,\n label = \"\",\n): { ref: (element: Element | null) => void } => {\n const data = useMemo(() => ({ tabsetId, type: \"tabset\" }), [tabsetId]);\n return useDraggableEntity({ data, id: `grip-${tabsetId}` }, disabled, label);\n};\n\n// Registers the tabset as a dnd-kit Droppable with the occlusion-aware\n// detector, mirroring useDraggableEntity's lifecycle: the effect is keyed on\n// identity, the ref setter keeps `element` current across renders. Droppables\n// register on the manager (shared across layers), so the winning tabset is\n// resolved globally; `data.layerId` lets the owning DragProvider claim it.\nconst useTabsetDroppable = (tabsetId: string): { ref: (element: HTMLElement | null) => void } => {\n const context = useContext(DragContext);\n const elementRef = useRef<HTMLElement | null>(null);\n const droppableRef = useRef<Droppable | null>(null);\n const ref = useCallback((element: HTMLElement | null): void => {\n elementRef.current = element;\n if (droppableRef.current) {\n droppableRef.current.element = element ?? undefined;\n }\n }, []);\n const layerId = context?.layerId;\n const manager = context?.manager;\n\n useEffect(() => {\n if (!manager || layerId === undefined) {\n return undefined;\n }\n // Droppable ids must be manager-unique, but model tabset ids are only\n // unique within one layout — sibling layouts under a shared provider can\n // both have a \"ts1\", and dnd-kit's registry replaces the earlier entry on\n // an id collision. The layer prefix keeps registrations distinct; the\n // model id the adapter and reducer understand rides in data.\n const droppable = new Droppable(\n {\n collisionDetector: topmostPointerIntersection,\n data: { layerId, tabsetId, type: \"tabset\" },\n id: `${layerId}:${tabsetId}`,\n },\n manager,\n );\n droppable.element = elementRef.current ?? undefined;\n droppableRef.current = droppable;\n return () => {\n droppable.destroy();\n droppableRef.current = null;\n };\n }, [layerId, manager, tabsetId]);\n\n return { ref };\n};\n\ntype ExternalTabSourceOptions = {\n // Must return a fresh TabNode (unique id) per call — each drop inserts a new\n // tab, and duplicate ids would fail the model's invariants.\n createTab: () => TabNode;\n disabled?: boolean;\n label?: string;\n};\n\n// Makes any element outside a layout a drag source that inserts a new tab when\n// dropped on a DashfooLayout under the same DashfooDragProvider. The adapter\n// recognizes the { type: \"external\" } payload and commits an addNode instead of\n// a move. The ref-indirection keeps `data` referentially stable (the\n// construction effect tracks it) while drags always call the latest createTab.\nconst useExternalTabSource = ({\n createTab,\n disabled = false,\n label = \"\",\n}: ExternalTabSourceOptions): { ref: (element: Element | null) => void } => {\n const id = useId();\n const createTabRef = useRef(createTab);\n // Dependency-less on purpose: a plain ref sync so drags always call the latest createTab.\n useEffect(() => {\n createTabRef.current = createTab;\n });\n const data = useMemo(\n () => ({ createTab: (): TabNode => createTabRef.current(), type: \"external\" }),\n [],\n );\n return useDraggableEntity({ data, id: `external-${id}` }, disabled, label);\n};\n\nconst useDragSubject = (): DragSubject | null => {\n const store = useContext(DragSubjectStoreContext);\n return useStore(store ?? nullSubjectStore, (state) => state.subject);\n};\n\n// The live drop intent: where the drag would land if dropped right now, null\n// when nothing is dragging or the pointer is over no valid target (a no-op\n// drop, a non-editable layout, or empty space). Lets consumers render their own\n// drop indicators alongside the built-in one.\nconst useDropIntent = (): DropIntent | null => {\n const store = useContext(DragSubjectStoreContext);\n return useStore(store ?? nullSubjectStore, (state) => state.intent);\n};\n\nexport type { DragContextValue, DragSubjectStore, ExternalTabSourceOptions };\nexport {\n createDragManager,\n createDragSubjectStore,\n DragContext,\n DragSubjectStoreContext,\n sameDragSubject,\n sameDropIntent,\n SharedDragManagerContext,\n useDragSubject,\n useDropIntent,\n useExternalTabSource,\n useTabDraggable,\n useTabsetDraggable,\n useTabsetDroppable,\n};\n","\"use client\";\n\nimport type { Dashfoo } from \"@dashfoo/core\";\nimport { fromJSON, toJSON } from \"@dashfoo/core\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\n// A minimal localStorage-shaped backend so layouts can persist to anything: the\n// browser, sessionStorage, an in-memory map, or a custom store.\ntype StorageAdapter = {\n getItem: (key: string) => string | null;\n removeItem: (key: string) => void;\n setItem: (key: string, value: string) => void;\n};\n\nconst memoryStorageAdapter = (): StorageAdapter => {\n const store = new Map<string, string>();\n return {\n getItem: (key) => store.get(key) ?? null,\n removeItem: (key) => {\n store.delete(key);\n },\n setItem: (key, value) => {\n store.set(key, value);\n },\n };\n};\n\n// SSR-safe browser adapter: reads return null and writes are swallowed (with a\n// warning) when storage is unavailable or throws (no window, private mode, quota).\nconst localStorageAdapter: StorageAdapter = {\n getItem: (key) => {\n if (typeof window === \"undefined\") {\n return null;\n }\n try {\n return window.localStorage.getItem(key);\n } catch {\n return null;\n }\n },\n removeItem: (key) => {\n if (typeof window === \"undefined\") {\n return;\n }\n try {\n window.localStorage.removeItem(key);\n } catch {\n // storage unavailable — nothing to remove.\n }\n },\n setItem: (key, value) => {\n if (typeof window === \"undefined\") {\n return;\n }\n try {\n window.localStorage.setItem(key, value);\n } catch (error) {\n // A persistence failure (quota, private mode) must not be silent.\n // oxlint-disable-next-line no-console\n console.warn(\"[dashfoo] failed to persist layout\", error);\n }\n },\n};\n\n// A resolved persistence target: where to save and how often. DashfooLayout's\n// `persist` prop normalizes its input to this.\ntype PersistConfig = {\n debounceMs: number;\n key: string;\n storage: StorageAdapter;\n};\n\ntype Persistence = {\n clear: () => void;\n // undefined only in controlled mode, where no defaultModel seeds the load.\n initialModel: Dashfoo | undefined;\n save: (model: Dashfoo) => void;\n};\n\n// The load/save half of persistence, behind the DashfooLayout `persist` prop.\n// Loads the saved model once (validated via serialize.ts, falling back to\n// `defaultModel` on miss or corruption) and\n// debounce-saves every change. Resetting the live model is the caller's job —\n// this primitive only owns the storage side. A null config makes it a no-op, so\n// callers can run the hook unconditionally.\nconst usePersistence = (\n config: PersistConfig | null,\n defaultModel: Dashfoo | undefined,\n): Persistence => {\n // Refs keep the callbacks stable while always seeing the latest config; synced\n // in an effect (never written during render).\n const configRef = useRef(config);\n useEffect(() => {\n configRef.current = config;\n });\n\n // Load the saved model once. The initializer stays pure (no writes during\n // render); a corrupt stored value is pruned in the mount effect below.\n const [initialModel] = useState<Dashfoo | undefined>(() => {\n if (config === null || defaultModel === undefined) {\n return defaultModel;\n }\n const raw = config.storage.getItem(config.key);\n if (raw === null) {\n return defaultModel;\n }\n try {\n return fromJSON(raw);\n } catch {\n return defaultModel;\n }\n });\n\n useEffect(() => {\n const current = configRef.current;\n if (current === null) {\n return;\n }\n const raw = current.storage.getItem(current.key);\n if (raw === null) {\n return;\n }\n try {\n fromJSON(raw);\n } catch (error) {\n // Mirror the setItem warn: a discarded corrupt layout must not be silent.\n // oxlint-disable-next-line no-console\n console.warn(\"[dashfoo] discarding unreadable persisted layout\", error);\n current.storage.removeItem(current.key);\n }\n }, []);\n\n // We load + prune once, but save/flush/clear target the *current* key. Changing\n // config.key for a mounted layout would save the stale model under the new key\n // and clobber it; warn instead of doing that silently. Remounting is the fix.\n const loadedKey = useRef(config?.key);\n useEffect(() => {\n if (config !== null && config.key !== loadedKey.current) {\n // oxlint-disable-next-line no-console\n console.warn(\n \"[dashfoo] persist key changed for a mounted layout; the displayed layout still reflects the previous key — remount (key={persistKey}) to load the new key\",\n );\n loadedKey.current = config.key;\n }\n }, [config]);\n\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n // The pending write carries the key and storage it was produced for, so a\n // config change while a save is queued cannot write the old value into the\n // new target.\n const pending = useRef<{ key: string; storage: StorageAdapter; value: string } | null>(null);\n\n const flush = useCallback((): void => {\n if (timer.current !== null) {\n clearTimeout(timer.current);\n timer.current = null;\n }\n if (pending.current !== null) {\n pending.current.storage.setItem(pending.current.key, pending.current.value);\n pending.current = null;\n }\n }, []);\n\n const save = useCallback(\n (next: Dashfoo): void => {\n const current = configRef.current;\n if (current === null) {\n return;\n }\n pending.current = { key: current.key, storage: current.storage, value: toJSON(next) };\n if (timer.current !== null) {\n clearTimeout(timer.current);\n }\n timer.current = setTimeout(flush, current.debounceMs);\n },\n [flush],\n );\n\n // Flush a pending save on unmount so the last change is never lost — and on\n // page teardown: a reload or navigation never unmounts React, so the debounced\n // timer dies with the page. pagehide is the teardown signal (bfcache-safe);\n // visibilitychange→hidden covers backgrounded tabs killed without a pagehide\n // (mobile). flush() is idempotent, so overlapping signals are harmless.\n useEffect(() => {\n const handlePageHide = (): void => {\n flush();\n };\n const handleVisibilityChange = (): void => {\n if (document.visibilityState === \"hidden\") {\n flush();\n }\n };\n window.addEventListener(\"pagehide\", handlePageHide);\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n return () => {\n window.removeEventListener(\"pagehide\", handlePageHide);\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n flush();\n };\n }, [flush]);\n\n const clear = useCallback((): void => {\n if (timer.current !== null) {\n clearTimeout(timer.current);\n timer.current = null;\n }\n pending.current = null;\n const current = configRef.current;\n if (current !== null) {\n current.storage.removeItem(current.key);\n }\n }, []);\n\n // Memoized so callers can hold the whole object in hook deps without their\n // memoization dissolving on every render.\n return useMemo(() => ({ clear, initialModel, save }), [clear, initialModel, save]);\n};\n\nexport { localStorageAdapter, memoryStorageAdapter, usePersistence };\nexport type { Persistence, PersistConfig, StorageAdapter };\n","\"use client\";\n\nimport type { Dashfoo } from \"@dashfoo/core\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\ntype Breakpoint = {\n // When true, the active breakpoint locks every structural interaction (tab and\n // tabset drag, split resize) — the lock-on-mobile model. Pair it with a stacked\n // model so the narrow view is read-only and tap-navigable. Defaults to false.\n compact?: boolean;\n id: string;\n model: Dashfoo;\n query?: { maxWidth: number } | { media: string };\n};\n\ntype UseResponsiveModelOptions = { breakpoints: Array<Breakpoint> };\n\ntype ResponsiveModel = {\n breakpoint: string;\n containerRef: (element: HTMLElement | null) => void;\n draggableTabs: boolean;\n draggableTabsets: boolean;\n isCompact: boolean;\n model: Dashfoo;\n resizableSplits: boolean;\n};\n\nconst hasMatchMedia = (): boolean =>\n typeof window !== \"undefined\" && typeof window.matchMedia === \"function\";\n\n// Whether a breakpoint applies at a given container width. No query = catch-all;\n// a maxWidth matches at or below the width; a media query consults matchMedia.\nconst matchBreakpoint = (breakpoint: Breakpoint, width: number): boolean => {\n const { query } = breakpoint;\n if (!query) {\n return true;\n }\n if (\"maxWidth\" in query) {\n return width <= query.maxWidth;\n }\n return hasMatchMedia() && window.matchMedia(query.media).matches;\n};\n\n// The first breakpoint that matches, else the last (the expected catch-all).\nconst activeBreakpoint = (breakpoints: Array<Breakpoint>, width: number): Breakpoint => {\n const fallback = breakpoints.at(-1);\n if (!fallback) {\n throw new Error(\"useResponsiveModel requires at least one breakpoint.\");\n }\n return breakpoints.find((breakpoint) => matchBreakpoint(breakpoint, width)) ?? fallback;\n};\n\n// Tracks a single element's content-box width via ResizeObserver. Seeds\n// POSITIVE_INFINITY so server and first client render agree on the widest\n// breakpoint (no hydration mismatch, no compact flash on desktop); the observer\n// supplies the real width on mount. The returned ref callback is stable.\nconst useContainerWidth = (): [(element: HTMLElement | null) => void, number] => {\n const [width, setWidth] = useState<number>(Number.POSITIVE_INFINITY);\n const observerRef = useRef<ResizeObserver | null>(null);\n\n const containerRef = useCallback((element: HTMLElement | null): void => {\n observerRef.current?.disconnect();\n if (!element) {\n return;\n }\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (entry) {\n setWidth(entry.contentRect.width);\n }\n });\n observer.observe(element);\n observerRef.current = observer;\n }, []);\n\n useEffect(\n () => () => {\n observerRef.current?.disconnect();\n },\n [],\n );\n\n return [containerRef, width];\n};\n\n// Picks a model for the active breakpoint, keyed off the container's own width\n// (ResizeObserver) and/or media queries, and derives the structural-interaction\n// flags from the breakpoint's `compact`. Feed model + flags onto DashfooLayout\n// (or Layout.Root) as reactive props and attach containerRef to the wrapper —\n// no key/remount, so store, history, and tab state survive a breakpoint cross.\nconst useResponsiveModel = ({ breakpoints }: UseResponsiveModelOptions): ResponsiveModel => {\n const [containerRef, width] = useContainerWidth();\n const [, setMediaTick] = useState(0);\n\n useEffect(() => {\n if (!hasMatchMedia()) {\n return;\n }\n const lists = breakpoints.flatMap((breakpoint) =>\n breakpoint.query && \"media\" in breakpoint.query\n ? [window.matchMedia(breakpoint.query.media)]\n : [],\n );\n if (lists.length === 0) {\n return;\n }\n const handleChange = (): void => {\n setMediaTick((tick) => tick + 1);\n };\n for (const list of lists) {\n list.addEventListener(\"change\", handleChange);\n }\n return () => {\n for (const list of lists) {\n list.removeEventListener(\"change\", handleChange);\n }\n };\n }, [breakpoints]);\n\n const active = activeBreakpoint(breakpoints, width);\n const isCompact = active.compact === true;\n return {\n breakpoint: active.id,\n containerRef,\n draggableTabs: !isCompact,\n draggableTabsets: !isCompact,\n isCompact,\n model: active.model,\n resizableSplits: !isCompact,\n };\n};\n\nexport { activeBreakpoint, matchBreakpoint, useContainerWidth, useResponsiveModel };\nexport type { Breakpoint, ResponsiveModel, UseResponsiveModelOptions };\n","\"use client\";\n\nimport type { Action, Dashfoo } from \"@dashfoo/core\";\nimport { canRedo, canUndo, dashfooMachine, normalize, reducer } from \"@dashfoo/core\";\nimport { useActorRef, useSelector } from \"@xstate/react\";\nimport { useCallback, useEffect, useMemo } from \"react\";\n\ntype DashfooStore = {\n canRedo: () => boolean;\n canUndo: () => boolean;\n dispatch: (action: Action) => void;\n model: Dashfoo;\n redo: () => void;\n setModel: (model: Dashfoo) => void;\n undo: () => void;\n};\n\ntype UseDashfooStoreOptions = {\n defaultModel?: Dashfoo;\n model?: Dashfoo;\n onAction?: (action: Action) => Action | null;\n onActiveTabsetChange?: (tabsetId: string | undefined) => void;\n onMaximizedTabsetChange?: (tabsetId: string | undefined) => void;\n onModelChange?: (model: Dashfoo, action?: Action) => void;\n};\n\n// Binds a dashfooMachine actor to React. Uncontrolled (defaultModel) lets the\n// actor own the document with full undo/redo; controlled (model) makes the prop\n// the source of truth and routes every change through onModelChange. The\n// actor/inspector stays in sync once the host round-trips `after` back into the\n// `model` prop (it is not synced synchronously within dispatch).\nconst useDashfooStore = (options: UseDashfooStoreOptions): DashfooStore => {\n const {\n defaultModel,\n model: controlledModel,\n onAction,\n onActiveTabsetChange,\n onMaximizedTabsetChange,\n onModelChange,\n } = options;\n const initialModel = controlledModel ?? defaultModel;\n if (initialModel === undefined) {\n throw new Error(\"useDashfooStore requires either a `model` or a `defaultModel`.\");\n }\n\n // Normalize at the boundary so a host-supplied model satisfies the same\n // invariants (clamped selection, no empty tabsets, live maximizedTabsetId) the\n // reducer guarantees — every entry point holds a canonical model.\n const actorRef = useActorRef(dashfooMachine, { input: { model: normalize(initialModel) } });\n const history = useSelector(actorRef, (snapshot) => snapshot.context.history);\n\n useEffect(() => {\n if (controlledModel !== undefined) {\n actorRef.send({ model: normalize(controlledModel), type: \"SET_MODEL\" });\n }\n }, [actorRef, controlledModel]);\n\n const model = controlledModel ?? history.present;\n\n // Single notification path so dispatch and undo/redo stay in lockstep. The\n // Object.is guard makes a no-op transition (e.g. undo at the bottom of the\n // stack, where the history helper returns the same object) emit nothing, so we\n // never write spurious persistence on a change that did not happen.\n const notify = useCallback(\n (before: Dashfoo, after: Dashfoo, action?: Action) => {\n if (Object.is(before, after)) {\n return;\n }\n onModelChange?.(after, action);\n if (after.activeTabsetId !== before.activeTabsetId) {\n onActiveTabsetChange?.(after.activeTabsetId);\n }\n if (after.maximizedTabsetId !== before.maximizedTabsetId) {\n onMaximizedTabsetChange?.(after.maximizedTabsetId);\n }\n },\n [onModelChange, onActiveTabsetChange, onMaximizedTabsetChange],\n );\n\n const dispatch = useCallback(\n (action: Action) => {\n // onAction may veto (null) or replace the action before it mutates anything.\n const resolved = onAction ? onAction(action) : action;\n if (!resolved) {\n return;\n }\n // Uncontrolled: the actor owns history. Controlled: derive the next model by\n // hand (the host round-trips it through the model prop). normalize the\n // controlled `before` too, else a normalization-only id change fires spuriously.\n const transition = ((): { after: Dashfoo; before: Dashfoo } => {\n if (controlledModel === undefined) {\n const before = actorRef.getSnapshot().context.history.present;\n actorRef.send({ action: resolved, type: \"DISPATCH\" });\n return { after: actorRef.getSnapshot().context.history.present, before };\n }\n return { after: reducer(controlledModel, resolved), before: normalize(controlledModel) };\n })();\n notify(transition.before, transition.after, resolved);\n },\n [actorRef, controlledModel, notify, onAction],\n );\n\n const undo = useCallback(() => {\n // actor history is always empty in controlled mode, so undo would be a dead\n // send that still emitted a spurious onModelChange.\n if (controlledModel !== undefined) {\n return;\n }\n const before = actorRef.getSnapshot().context.history.present;\n actorRef.send({ type: \"UNDO\" });\n const after = actorRef.getSnapshot().context.history.present;\n notify(before, after);\n }, [actorRef, controlledModel, notify]);\n\n const redo = useCallback(() => {\n if (controlledModel !== undefined) {\n return;\n }\n const before = actorRef.getSnapshot().context.history.present;\n actorRef.send({ type: \"REDO\" });\n const after = actorRef.getSnapshot().context.history.present;\n notify(before, after);\n }, [actorRef, controlledModel, notify]);\n\n // Replace the whole document, resetting undo history. Drives an uncontrolled\n // reset (e.g. clearing a persisted layout back to its default) without a\n // remount; normalized at the boundary like every other entry point.\n const setModel = useCallback(\n (next: Dashfoo) => {\n actorRef.send({ model: normalize(next), type: \"SET_MODEL\" });\n },\n [actorRef],\n );\n\n // Functions, not booleans: they read the live actor snapshot so a caller\n // reading them right after undo/redo (e.g. inside onModelChange) sees the fresh\n // value, not the one-render-stale useSelector result. Memoized so callers can\n // hold the whole store in hook deps without their memoization dissolving on\n // every render.\n return useMemo(\n () => ({\n canRedo: () => canRedo(actorRef.getSnapshot().context.history),\n canUndo: () => canUndo(actorRef.getSnapshot().context.history),\n dispatch,\n model,\n redo,\n setModel,\n undo,\n }),\n [actorRef, dispatch, model, redo, setModel, undo],\n );\n};\n\nexport { useDashfooStore };\nexport type { DashfooStore, UseDashfooStoreOptions };\n","import type { Point, Rect } from \"@dashfoo/core\";\n\n// Pure drag math for the tab strip — rects in, geometry out. The drag adapter\n// gathers the rects from the DOM and feeds them here, so this stays unit-testable\n// without a live drag.\n\ntype Zone = { height: number; width: number; x: number; y: number };\n\n// Is the point inside the rect? (Rect is DOMRect-compatible: x/y/width/height.)\nconst pointInRect = (point: Point, rect: Rect): boolean =>\n point.x >= rect.x &&\n point.x <= rect.x + rect.width &&\n point.y >= rect.y &&\n point.y <= rect.y + rect.height;\n\n// Which slot in the strip the pointer is over: the first tab whose midpoint is\n// right of the pointer, else the end.\nconst insertionIndex = (rects: ReadonlyArray<Rect>, pointerX: number): number => {\n const found = rects.findIndex((rect) => pointerX < rect.x + rect.width / 2);\n return found === -1 ? rects.length : found;\n};\n\n// How wide the insertion line is, centered on the slot boundary.\nconst INSERTION_LINE_WIDTH = 4;\n\n// The thin vertical line marking where a tab will be inserted. Measured against\n// whole tab-item rects (label + close), so the \"after the last tab\" position sits\n// past the last close button rather than between the label and the close.\n// Clamped so the line never leaves the strip.\nconst insertionLineRect = (\n stripRect: Rect,\n itemRects: ReadonlyArray<Rect>,\n index: number,\n): Zone => {\n const at = itemRects[index];\n const last = itemRects.at(-1);\n const x = at?.x ?? (last ? last.x + last.width : stripRect.x);\n const left = x - INSERTION_LINE_WIDTH / 2;\n return {\n height: stripRect.height,\n width: INSERTION_LINE_WIDTH,\n x: Math.max(stripRect.x, Math.min(left, stripRect.x + stripRect.width - INSERTION_LINE_WIDTH)),\n y: stripRect.y,\n };\n};\n\n// Whether a drop should commit, or is a no-op to be suppressed: dragging a tabset\n// onto itself (grip id is `grip-${tabsetId}`), or the sole tab of a tabset back\n// onto that same tabset — both change nothing once empties collapse.\nconst shouldAllowDrop = (\n draggedId: string | undefined,\n targetId: string,\n tabIds: ReadonlyArray<string>,\n): boolean => {\n if (draggedId === `grip-${targetId}`) {\n return false;\n }\n if (tabIds.length === 1 && tabIds[0] === draggedId) {\n return false;\n }\n return true;\n};\n\nexport { insertionIndex, insertionLineRect, pointInRect, shouldAllowDrop };\nexport type { Zone };\n","\"use client\";\n\nimport type { dragDockMachine, Point } from \"@dashfoo/core\";\nimport { zoneRect } from \"@dashfoo/core\";\nimport type { DragDropManager } from \"@dnd-kit/dom\";\nimport { Feedback } from \"@dnd-kit/dom\";\nimport { useSelector } from \"@xstate/react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport type { ActorRefFrom } from \"xstate\";\n\nimport type { Zone } from \"../lib/tab-insertion\";\nimport { insertionLineRect } from \"../lib/tab-insertion\";\n\n// The drag adapter's two overlays: the dock indicator (where the drop will\n// land) and the pointer-anchored preview chip. Split from drag-adapter.tsx to\n// keep that module focused on wiring @dnd-kit to the drag machine.\n\ntype DragActor = ActorRefFrom<typeof dragDockMachine>;\n\nconst overlayBase: CSSProperties = {\n boxSizing: \"border-box\",\n pointerEvents: \"none\",\n position: \"fixed\",\n // Overridable so a theme can drop it under prefers-reduced-motion.\n transition: \"var(--dashfoo-dock-transition, left 60ms, top 60ms, width 60ms, height 60ms)\",\n zIndex: 9999,\n};\n\n// Only position/size are fixed inline; every visual property is an overridable\n// CSS var with a neutral fallback, so a consumer's data-dashfoo=\"dock-indicator\"\n// theme fully owns the look.\nconst paneStyle = (zone: Zone): CSSProperties => ({\n ...overlayBase,\n background: \"var(--dashfoo-dock-fill, oklch(0.556 0 0 / 0.18))\",\n border:\n \"var(--dashfoo-dock-border-width, 1px) solid var(--dashfoo-dock-border, oklch(0.708 0 0 / 0.75))\",\n borderRadius: \"var(--dashfoo-dock-radius, 6px)\",\n height: zone.height,\n left: zone.x,\n top: zone.y,\n width: zone.width,\n});\n\n// The insertion line shares the pane's fill and border, shrunk to a thin caret\n// between tabs, so the strip indicator and the dock panes read as one family.\nconst lineStyle = (zone: Zone): CSSProperties => ({\n ...paneStyle(zone),\n borderRadius: \"var(--dashfoo-dock-line-radius, 2px)\",\n});\n\n// Whole-tab-item rects (label + close button), excluding the dragged tab. The\n// insertion line lands on these boundaries so the \"after the last tab\" position\n// sits past the close button, not between the label and the close.\nconst tabItemRects = (strip: Element, excludeId?: string): Array<DOMRect> =>\n [...strip.querySelectorAll<HTMLElement>('[data-dashfoo=\"tab-item\"]')].flatMap((item) =>\n item.querySelector<HTMLElement>('[data-dashfoo=\"tab\"]')?.dataset.tabId === excludeId\n ? []\n : [item.getBoundingClientRect()],\n );\n\n// A \"where it will land\" indicator driven off the machine's live intent: an\n// insertion line in the tab bar for a stack, the matching content half for a\n// split. One unkeyed div, so React reuses the DOM node and the position/size\n// transition morphs between the two shapes instead of remounting.\nconst DockIndicator = ({\n actorRef,\n getTabsetElement,\n}: {\n actorRef: DragActor;\n getTabsetElement: (id: string) => HTMLElement | undefined;\n}): ReactNode => {\n const intent = useSelector(actorRef, (snapshot) => snapshot.context.intent);\n const draggedId = useSelector(actorRef, (snapshot) => snapshot.context.subject?.id);\n if (!intent) {\n return null;\n }\n const element = getTabsetElement(intent.targetId);\n if (!element) {\n return null;\n }\n // A docked target sits beneath the floating-panel layer, so its indicator must\n // too — otherwise the z:9999 overlay paints over a float that occludes the\n // target. A target inside a float stays above that float.\n const zIndex = element.closest('[data-dashfoo=\"float\"]') ? overlayBase.zIndex : \"auto\";\n if (intent.location === \"center\") {\n const strip = element.querySelector('[data-dashfoo=\"tabstrip\"]');\n if (strip) {\n const line = insertionLineRect(\n strip.getBoundingClientRect(),\n tabItemRects(strip, draggedId),\n intent.index ?? 0,\n );\n return <div data-dashfoo=\"dock-indicator\" style={{ ...lineStyle(line), zIndex }} />;\n }\n }\n const zone = zoneRect(element.getBoundingClientRect(), intent.location);\n return <div data-dashfoo=\"dock-indicator\" style={{ ...paneStyle(zone), zIndex }} />;\n};\n\n// The pointer-anchored preview chip keeps the cursor at this offset from its\n// top-left corner, exactly as before the Feedback adoption.\nconst PREVIEW_OFFSET: Point = { x: 12, y: 8 };\n\nconst labelOf = (source: { data?: Record<string, unknown> } | null): string => {\n const raw = source?.data?.label;\n return typeof raw === \"string\" ? raw : \"\";\n};\n\ntype ChipState = { label: string; x: number; y: number };\n\n// The drag-preview chip, positioned by dnd-kit's Feedback plugin. Feedback\n// anchors the wrapper to the source element's rect and drives it with the drag\n// delta; the one-shot inner offset (grab point within the source, plus\n// PREVIEW_OFFSET) re-anchors the chip to the pointer, preserving the\n// pointer-following feel. The wrapper stays mounted for the manager's lifetime:\n// Feedback's render effect runs synchronously at drag start, so `overlay` must\n// already be assigned — set mid-drag, Feedback would first promote the source\n// element itself, placeholder clone and all.\nconst DragPreviewOverlay = ({ manager }: { manager: DragDropManager }): ReactNode => {\n const [chip, setChip] = useState<ChipState | null>(null);\n\n useEffect(() => {\n const offStart = manager.monitor.addEventListener(\"dragstart\", (event) => {\n const source = event.operation.source;\n if (!source) {\n return;\n }\n const rect = source.element?.getBoundingClientRect();\n const point = event.operation.position.current;\n setChip({\n label: labelOf(source),\n x: PREVIEW_OFFSET.x + (rect ? point.x - rect.left : 0),\n y: PREVIEW_OFFSET.y + (rect ? point.y - rect.top : 0),\n });\n });\n const offEnd = manager.monitor.addEventListener(\"dragend\", () => setChip(null));\n return () => {\n offStart();\n offEnd();\n };\n }, [manager]);\n\n const attachOverlay = useCallback(\n (element: HTMLDivElement | null): void => {\n const feedback = manager.registry.plugins.get(Feedback);\n if (feedback) {\n feedback.overlay = element ?? undefined;\n }\n },\n [manager],\n );\n\n // data-dnd-overlay is ours to stamp (dnd-kit only references it, in the\n // injected CSS that hides the wrapper while no drag is live). popover and\n // data-dnd-dragging are Feedback-owned attributes — declaring them here would\n // fight its cleanup, which strips the attributes it added.\n return (\n <div data-dnd-overlay=\"\" ref={attachOverlay}>\n {chip === null ? null : (\n <div\n data-dashfoo=\"drag-preview\"\n style={{\n left: 0,\n position: \"absolute\",\n top: 0,\n transform: `translate(${chip.x}px, ${chip.y}px)`,\n // Absolute children shrink to the containing block, and the wrapper\n // is source-sized (a tabset grip is ~20px) — the chip sizes to its\n // own label instead.\n width: \"max-content\",\n }}\n >\n {chip.label}\n </div>\n )}\n </div>\n );\n};\n\nexport { DockIndicator, DragPreviewOverlay };\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useInsertionEffect, useState } from \"react\";\n\nimport {\n createDragManager,\n createDragSubjectStore,\n DragSubjectStoreContext,\n SharedDragManagerContext,\n} from \"../hooks/drag-hooks\";\n\nimport { DragPreviewOverlay } from \"./drag-overlays\";\n\n// Shares one DragDropManager between a DashfooLayout and external tab sources\n// (useExternalTabSource) rendered outside it, so a drag can start at a widget\n// list and end on the layout. Optional: a standalone DashfooLayout creates its\n// own manager and behaves as before.\nconst DashfooDragProvider = ({ children }: { children: ReactNode }): ReactNode => {\n // useState lazily constructs the manager once; the destroy rides a\n // useInsertionEffect cleanup (not useEffect) so StrictMode's simulated unmount\n // doesn't tear down the live instance — the same pattern DragProvider uses.\n const [manager] = useState(createDragManager);\n useInsertionEffect(() => () => manager.destroy(), [manager]);\n // Hosting the drag store here (the nested DragLayer adopts it instead of\n // creating its own) lets useDragSubject/useDropIntent observe the drag from\n // anywhere under the provider — widget lists, custom drop indicators — not\n // just from inside the layout.\n const [subjectStore] = useState(createDragSubjectStore);\n\n return (\n <SharedDragManagerContext.Provider value={manager}>\n <DragSubjectStoreContext.Provider value={subjectStore}>\n {children}\n {/* The manager owner renders the one chip — nested DragProviders\n sharing this manager render none, so cross-layout drags show a\n single preview instead of one per layer. */}\n <DragPreviewOverlay manager={manager} />\n </DragSubjectStoreContext.Provider>\n </SharedDragManagerContext.Provider>\n );\n};\n\nexport { DashfooDragProvider };\n","\"use client\";\n\nimport type { Action, SnapConfig, TabNode, TabsetNode } from \"@dashfoo/core\";\nimport type { ReactNode } from \"react\";\nimport { createContext, useContext } from \"react\";\nimport type { StoreApi } from \"zustand\";\nimport { createStore, useStore } from \"zustand\";\n\n// The layout-wide configuration every part below <Layout.Root> coordinates\n// through: resolved chrome flags, slot renderers, and the model dispatcher.\n// A scoped zustand store rather than a plain context value so parts subscribe\n// per-field — changing one flag re-renders only the parts that select it.\ntype LayoutState = {\n closableTabs: boolean;\n dispatch: (action: Action) => void;\n draggableTabs: boolean;\n draggableTabsets: boolean;\n editable: boolean;\n // Whether tabsets show a \"float into a movable panel\" control.\n floatable: boolean;\n keepMounted: boolean;\n maximizable: boolean;\n maximizedTabsetId: string | undefined;\n renamableTabs: boolean;\n renderTab: (tab: TabNode) => ReactNode;\n renderTabLabel: ((tab: TabNode) => ReactNode) | undefined;\n renderTabsetToolbar: ((tabset: TabsetNode) => ReactNode) | undefined;\n resizableSplits: boolean;\n // Magnetic snap defaults for split resize; null = no snapping. A row may still\n // override this via its own `snap` attribute (read in row-view).\n snap: SnapConfig | null;\n splitDock: boolean;\n tabLocation: \"bottom\" | \"top\";\n tabsetMinSize: number;\n tabStripEnabled: boolean;\n};\n\ntype LayoutStore = StoreApi<LayoutState>;\n\nconst createLayoutStore = (initial: LayoutState): LayoutStore =>\n createStore<LayoutState>(() => initial);\n\n// Carries only the store instance — state always flows through selectors.\nconst LayoutStoreContext = createContext<LayoutStore | null>(null);\n\nconst useLayout = <T>(selector: (state: LayoutState) => T): T => {\n const store = useContext(LayoutStoreContext);\n if (store === null) {\n throw new Error(\"dashfoo components must be rendered inside <DashfooLayout> or <Layout.Root>.\");\n }\n return useStore(store, selector);\n};\n\nexport { createLayoutStore, LayoutStoreContext, useLayout };\nexport type { LayoutState, LayoutStore };\n","// Dev warnings for soft misuse (duplicate parts, orphan tabs, missing editors)\n// fire once per key so a render loop can't flood the console, mirroring the\n// unregistered-component warning in dashfoo-layout.\nconst warned = new Set<string>();\n\nconst warnOnce = (key: string, message: string): void => {\n if (warned.has(key)) {\n return;\n }\n warned.add(key);\n // oxlint-disable-next-line no-console\n console.warn(`[dashfoo] ${message}`);\n};\n\nexport { warnOnce };\n","\"use client\";\n\nimport type { Action, DockLocation, DragSubject, DropIntent, Point } from \"@dashfoo/core\";\nimport { dragDockMachine, resolveDockTarget, tabNodeSchema } from \"@dashfoo/core\";\nimport type { DragEndEvent, DragStartEvent } from \"@dnd-kit/dom\";\nimport { useActorRef } from \"@xstate/react\";\nimport type { ReactNode } from \"react\";\nimport {\n useCallback,\n useContext,\n useEffect,\n useId,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport type { DragContextValue } from \"../hooks/drag-hooks\";\nimport {\n createDragManager,\n createDragSubjectStore,\n DragContext,\n DragSubjectStoreContext,\n sameDragSubject,\n sameDropIntent,\n SharedDragManagerContext,\n useDragSubject,\n useTabDraggable,\n useTabsetDraggable,\n useTabsetDroppable,\n} from \"../hooks/drag-hooks\";\nimport { LayoutStoreContext } from \"../hooks/layout-store\";\nimport { insertionIndex, pointInRect, shouldAllowDrop } from \"../lib/tab-insertion\";\nimport { warnOnce } from \"../lib/warn-once\";\n\nimport { DockIndicator, DragPreviewOverlay } from \"./drag-overlays\";\n\n// This module is the drag adapter: it (with ./drag-hooks) is where @dnd-kit is\n// touched. It wires the framework-agnostic @dnd-kit/dom core (no React bindings)\n// to the already unit-tested dragDockMachine — the PointerSensor supplies\n// activation + a live pointer, dnd-kit's collision pass resolves the tabset\n// droppable under it (each with dashfoo's occlusion-aware detector, see\n// ../lib/topmost-collision.ts), the adapter turns that target into a DropIntent,\n// and the machine owns the lifecycle and emits a moveNode COMMIT forwarded via\n// onCommit. The drag-preview chip rides the Feedback plugin's `overlay`\n// accessor (see DragPreviewOverlay): the source element is never promoted or\n// placeholder-cloned, and Feedback owns the chip's per-move positioning.\n\n// The dragged tab is excluded so its own slot never counts toward the order —\n// the insertion index and line are measured against the tabs it will land among.\nconst tabRects = (strip: Element, excludeId?: string): Array<DOMRect> =>\n [...strip.querySelectorAll<HTMLElement>('[data-dashfoo=\"tab\"]')].flatMap((tab) =>\n tab.dataset.tabId === excludeId ? [] : [tab.getBoundingClientRect()],\n );\n\n// The tab strip is always a \"stack as a tab\" target, with an insertion index that\n// places the tab at a specific slot. Only the content area below it resolves to\n// the center/split zones via resolveDockTarget (content center appends). The\n// adapter gathers rects from the DOM; the pure math lives in ./tab-insertion.\nconst intentForTabset = (\n id: string,\n element: HTMLElement,\n point: Point,\n draggedId?: string,\n): DropIntent => {\n const strip = element.querySelector('[data-dashfoo=\"tabstrip\"]');\n if (strip && pointInRect(point, strip.getBoundingClientRect())) {\n return {\n index: insertionIndex(tabRects(strip, draggedId), point.x),\n location: \"center\",\n targetId: id,\n };\n }\n const target = resolveDockTarget(point, element.getBoundingClientRect());\n const location: DockLocation = target.kind === \"tab\" ? \"center\" : `split-${target.edge}`;\n if (location === \"center\" && strip) {\n return { index: tabRects(strip, draggedId).length, location, targetId: id };\n }\n return { location, targetId: id };\n};\n\nconst isTabFactory = (value: unknown): value is () => unknown => typeof value === \"function\";\n\n// A tabset grip carries { tabsetId, type: \"tabset\" }; an external source\n// (useExternalTabSource) carries { createTab, type: \"external\" } and its tab is\n// built and validated at drag start; a plain tab carries its id. null aborts\n// the drag — the machine stays idle, so the following OVER/DROP are ignored.\nconst subjectFor = (source: {\n data?: Record<string, unknown>;\n id: string | number;\n}): DragSubject | null => {\n const data = source.data;\n if (data?.type === \"tabset\") {\n return { id: String(data.tabsetId), kind: \"tabset\" };\n }\n if (data?.type === \"external\") {\n if (!isTabFactory(data.createTab)) {\n // A wired-up source that can't produce a tab must not fail silently.\n // oxlint-disable-next-line no-console\n console.warn(\"[dashfoo] external drag source is missing its createTab function\");\n return null;\n }\n let candidate: unknown;\n try {\n candidate = data.createTab();\n } catch (error) {\n // A consumer callback that throws must abort the drag, not break dragging.\n // oxlint-disable-next-line no-console\n console.warn(\"[dashfoo] external drag source createTab threw\", error);\n return null;\n }\n const parsed = tabNodeSchema.safeParse(candidate);\n if (!parsed.success) {\n // oxlint-disable-next-line no-console\n console.warn(\"[dashfoo] external drag source returned an invalid tab\", parsed.error);\n return null;\n }\n return { id: String(source.id), kind: \"external\", tab: parsed.data };\n }\n return { id: String(source.id), kind: \"tab\" };\n};\n\ntype DragProviderProps = {\n children: ReactNode;\n // Defaults to the layout store's dispatch when rendered under Layout.Root.\n onCommit?: (action: Action) => void;\n // Defaults to the layout store's splitDock (model global), else true.\n splitDock?: boolean;\n};\n\nconst DragProvider = ({ children, onCommit, splitDock }: DragProviderProps): ReactNode => {\n const actorRef = useActorRef(dragDockMachine);\n // Nullable read on purpose (not the throwing useLayout hook): the drag layer\n // also works standalone with an explicit onCommit, e.g. in tests.\n const layoutStore = useContext(LayoutStoreContext);\n\n // One manager for the whole layout — the shared one when a DashfooDragProvider\n // sits above (so external sources participate in this layout's drags), else\n // our own. useState lazily constructs it once; the destroy rides a\n // useInsertionEffect cleanup (not useEffect) so StrictMode's simulated unmount\n // doesn't tear down the live instance — the same pattern @dnd-kit/react uses\n // internally.\n const sharedManager = useContext(SharedDragManagerContext);\n const [ownManager] = useState(() => (sharedManager ? null : createDragManager()));\n useInsertionEffect(() => () => ownManager?.destroy(), [ownManager]);\n const manager = sharedManager ?? ownManager;\n if (manager === null) {\n // Only reachable when a DashfooDragProvider unmounts while its layout stays\n // mounted — surface the misuse instead of dragging against a dead manager.\n throw new Error(\n \"[dashfoo] DashfooDragProvider unmounted while its layout is still mounted; keep the provider above the layout or remount the layout\",\n );\n }\n\n // The drag subject store: fed by the machine subscription, read by parts via\n // useDragSubject/useDropIntent selectors. Inherited from DashfooDragProvider\n // when one sits above (so consumers outside the layout can observe drags),\n // else owned here. Guarded so OVER pulses (every pointer move) don't notify\n // subscribers — only a subject change (drag start/end) or a value-level\n // intent change (the resolved drop moved) does. ownerId scopes intent writes:\n // layers sharing a store each claim only their own droppables from the\n // manager-global winner, so this layer's null must not erase an intent the\n // owning layer resolved.\n const inheritedStore = useContext(DragSubjectStoreContext);\n const [subjectStore] = useState(() => inheritedStore ?? createDragSubjectStore());\n const ownerId = useId();\n useEffect(() => {\n const subscription = actorRef.subscribe((snapshot) => {\n const { intent, subject } = snapshot.context;\n const state = subjectStore.getState();\n if (intent !== null) {\n if (!sameDropIntent(state.intent, intent) || state.intentOwner !== ownerId) {\n subjectStore.setState({ intent, intentOwner: ownerId });\n }\n } else if (state.intent !== null && state.intentOwner === ownerId) {\n subjectStore.setState({ intent: null, intentOwner: null });\n }\n if (!sameDragSubject(subjectStore.getState().subject, subject)) {\n subjectStore.setState({ subject });\n }\n });\n return () => {\n subscription.unsubscribe();\n };\n }, [actorRef, ownerId, subjectStore]);\n\n // Consumer-supplied inputs ride refs (the configRef pattern from\n // usePersistence) so the machine subscriptions below stay attached across\n // re-renders — an inline onCommit or a flipped splitDock must not tear down\n // and re-attach the listeners on a hot path.\n const onCommitRef = useRef(onCommit);\n const splitDockRef = useRef(splitDock);\n useEffect(() => {\n onCommitRef.current = onCommit;\n splitDockRef.current = splitDock;\n });\n\n // The DockIndicator's target lookup, against the manager-global droppable\n // registry (tabsets register there via useTabsetDroppable). The machine only\n // ever holds intents for this layer's own targets, so reconstructing this\n // layer's prefixed droppable id from the model tabset id is always right.\n const getTabsetElement = useCallback(\n (id: string): HTMLElement | undefined => {\n const element = manager.registry.droppables.get(`${ownerId}:${id}`)?.element;\n return element instanceof HTMLElement ? element : undefined;\n },\n [manager, ownerId],\n );\n\n useEffect(() => {\n const subscription = actorRef.on(\"COMMIT\", (emitted) => {\n // Mirrors the resolveIntent gate: even a drag whose `editable` was\n // flipped off mid-flight cannot land a structural action.\n if (layoutStore?.getState().editable === false) {\n return;\n }\n const commit = onCommitRef.current ?? layoutStore?.getState().dispatch;\n if (!commit) {\n warnOnce(\n \"drag-layer-no-commit\",\n \"Layout.DragLayer has neither an onCommit prop nor a <Layout.Root> above it; drops are ignored\",\n );\n return;\n }\n commit(emitted.action);\n });\n return () => {\n subscription.unsubscribe();\n };\n }, [actorRef, layoutStore]);\n\n // The helpers live inside the effect (per the React docs' \"move it into the\n // effect\" guidance) so the monitor listeners attach once per manager instead\n // of re-subscribing whenever a render rebuilds a callback.\n useEffect(() => {\n // The dock intent for a pointer over a tabset, or null when the drop would\n // be a no-op: a tabset dragged onto itself, or the sole tab of a tabset\n // dropped back onto that same tabset. Otherwise the tabset resolves to\n // center/split.\n const resolveIntent = (\n targetId: string,\n element: HTMLElement,\n point: Point,\n draggedId?: string,\n ): DropIntent | null => {\n // A non-editable layout is never a drop target — no indicator, no intent.\n // Read at drag time (getState, not a subscription) like splitDock below,\n // so a runtime flip is honored without re-rendering the layer; this also\n // rejects external-source drops arriving via a shared manager.\n if (layoutStore?.getState().editable === false) {\n return null;\n }\n const tabIds = [...element.querySelectorAll<HTMLElement>('[data-dashfoo=\"tab\"]')].map(\n (tab) => tab.dataset.tabId ?? \"\",\n );\n if (!shouldAllowDrop(draggedId, targetId, tabIds)) {\n return null;\n }\n const intent = intentForTabset(targetId, element, point, draggedId);\n // When splitting is disabled, a drop over the body stacks instead of\n // splits. Resolved at drag time (getState, not a subscription) so a model\n // global flip mid-session is honored without re-rendering the layer.\n const splitDockResolved = splitDockRef.current ?? layoutStore?.getState().splitDock ?? true;\n if (!splitDockResolved && intent.location.startsWith(\"split-\")) {\n return { location: \"center\", targetId };\n }\n return intent;\n };\n\n const handleStart = (event: DragStartEvent): void => {\n const source = event.operation.source;\n if (!source) {\n return;\n }\n const subject = subjectFor(source);\n if (!subject) {\n // Abort the dnd-kit operation too: the machine stays idle either way,\n // but a live Feedback drag would keep promoting the source element for\n // a gesture dashfoo will never commit.\n manager.actions.stop({ canceled: true });\n return;\n }\n actorRef.send({ subject, type: \"START\" });\n };\n\n // Feeds the machine the drop target dnd-kit's collision pass resolved\n // (manager-global, across every layer sharing this manager), claiming it\n // only when this layer owns it — otherwise OVER null, which clears this\n // layer's indicator while the owning layer shows its own.\n const syncIntent = (): void => {\n const operation = manager.dragOperation;\n const point = operation.position.current;\n const target = operation.target;\n // The droppable id is layer-prefixed (model tabset ids are only unique\n // per layout); the model id the machine and reducer understand rides in\n // the droppable's data, alongside the layer claim.\n const data = target?.data as { layerId?: string; tabsetId?: string } | undefined;\n const tabsetId = data?.layerId === ownerId ? data.tabsetId : undefined;\n const element = tabsetId === undefined ? undefined : target?.element;\n const draggedId = operation.source ? String(operation.source.id) : undefined;\n actorRef.send({\n intent:\n tabsetId !== undefined && element instanceof HTMLElement\n ? resolveIntent(tabsetId, element, point, draggedId)\n : null,\n type: \"OVER\",\n });\n };\n\n // Both events on purpose: inside a dragmove listener the target lags one\n // move behind (collisions recompute in a microtask after the dispatch), so\n // the collision event keeps target flips fresh — but it can skip pulses\n // while sliding within one tabset (the detector's value is constant per\n // tabset), so dragmove keeps the insertion index tracking the pointer.\n const handleMove = (): void => syncIntent();\n const handleCollision = (): void => syncIntent();\n\n // Recompute from the final operation state, then set the intent and commit\n // in one synchronous pair — the drop uses the authoritative final target,\n // not whatever the last pulse happened to report.\n const handleEnd = (event: DragEndEvent): void => {\n if (event.canceled) {\n actorRef.send({ type: \"CANCEL\" });\n return;\n }\n syncIntent();\n actorRef.send({ type: \"DROP\" });\n };\n const offStart = manager.monitor.addEventListener(\"dragstart\", handleStart);\n const offMove = manager.monitor.addEventListener(\"dragmove\", handleMove);\n const offCollision = manager.monitor.addEventListener(\"collision\", handleCollision);\n const offEnd = manager.monitor.addEventListener(\"dragend\", handleEnd);\n return () => {\n offStart();\n offMove();\n offCollision();\n offEnd();\n };\n }, [actorRef, layoutStore, manager, ownerId]);\n\n const contextValue = useMemo<DragContextValue>(\n () => ({ layerId: ownerId, manager }),\n [manager, ownerId],\n );\n\n return (\n <DragContext.Provider value={contextValue}>\n <DragSubjectStoreContext.Provider value={subjectStore}>\n {children}\n <DockIndicator actorRef={actorRef} getTabsetElement={getTabsetElement} />\n {/* One chip per manager: under a DashfooDragProvider the provider owns\n it, so N layouts sharing that manager don't stack N chips. */}\n {ownManager === null ? null : <DragPreviewOverlay manager={ownManager} />}\n </DragSubjectStoreContext.Provider>\n </DragContext.Provider>\n );\n};\n\n// The draggable/droppable hooks and the drag contexts live in ./drag-hooks to\n// keep this module under the size cap and avoid a circular import; re-exported\n// here so consumers still import the whole drag surface from \"./drag-adapter\".\nexport {\n DragProvider,\n subjectFor,\n useDragSubject,\n useTabDraggable,\n useTabsetDraggable,\n useTabsetDroppable,\n};\nexport type { DragProviderProps };\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\n\n// Standalone (leaf) module so the float control can ask \"is a FloatLayer present?\"\n// without importing float-layer.tsx — which pulls in float-panel → row-view →\n// the tabset tree and would close an import cycle back to the control.\nconst FloatLayerContext = createContext(false);\n\nconst useHasFloatLayer = (): boolean => useContext(FloatLayerContext);\n\nexport { FloatLayerContext, useHasFloatLayer };\n","\"use client\";\n\nimport type { Geometry } from \"@dashfoo/core\";\n\n// Pure rect math for floating panels, plus the one DOM measurement that seeds a\n// float's initial position. A float's `geometry` is in viewport CSS pixels (the\n// overlay is fixed), so a float can be dragged anywhere on the page, not just\n// within the layout container.\n\nconst MIN_WIDTH = 200;\nconst MIN_HEIGHT = 120;\n// A comfortable default window size. Floating a large docked panel opens at this\n// size rather than the panel's full footprint; a smaller source keeps its size.\nconst DEFAULT_WIDTH = 480;\nconst DEFAULT_HEIGHT = 340;\n// Nudge a freshly-floated panel down-right of where it was docked so it reads as\n// lifted rather than pixel-aligned on top of its old slot.\nconst LIFT_OFFSET = 16;\n\ntype Size = { height: number; width: number };\n\n// Keep a rect's origin inside the container. `size` is the footprint kept on\n// screen (defaults to the rect's own size; the minimized chip passes its smaller\n// footprint while the rect still carries the window dimensions). A footprint\n// larger than the bounds pins to 0 on that axis rather than going negative.\nconst clampToBounds = (rect: Geometry, bounds: Size, size: Size = rect): Geometry => ({\n height: rect.height,\n left: Math.max(0, Math.min(rect.left, Math.max(0, bounds.width - size.width))),\n top: Math.max(0, Math.min(rect.top, Math.max(0, bounds.height - size.height))),\n width: rect.width,\n});\n\n// The initial rect for a float: a sane window size (the source panel's footprint,\n// capped to the default so a large panel doesn't open huge), placed over where the\n// panel was docked (viewport coordinates) and lifted slightly, clamped on screen.\nconst measureFloatRect = (element: Element): Geometry => {\n const tabsetElement = element.closest('[data-dashfoo=\"tabset\"]') ?? element;\n const rect = tabsetElement.getBoundingClientRect();\n const seeded: Geometry = {\n height: Math.max(MIN_HEIGHT, Math.min(Math.round(rect.height), DEFAULT_HEIGHT)),\n left: Math.round(rect.left) + LIFT_OFFSET,\n top: Math.round(rect.top) + LIFT_OFFSET,\n width: Math.max(MIN_WIDTH, Math.min(Math.round(rect.width), DEFAULT_WIDTH)),\n };\n return clampToBounds(seeded, { height: window.innerHeight, width: window.innerWidth });\n};\n\n// Which edges a resize handle moves: -1 = the leading edge (left/top), 1 = the\n// trailing edge (right/bottom), 0 = fixed on that axis.\ntype ResizeEdges = { x: -1 | 0 | 1; y: -1 | 0 | 1 };\n\n// Apply a pointer delta to a rect for one resize handle. A leading edge moves the\n// origin and shrinks the size; the minimum size pins the moving edge.\nconst resizeRect = (start: Geometry, edges: ResizeEdges, dx: number, dy: number): Geometry => {\n let { height, left, top, width } = start;\n if (edges.x === 1) {\n width = Math.max(MIN_WIDTH, start.width + dx);\n } else if (edges.x === -1) {\n width = Math.max(MIN_WIDTH, start.width - dx);\n left = Math.max(0, start.left + (start.width - width));\n }\n if (edges.y === 1) {\n height = Math.max(MIN_HEIGHT, start.height + dy);\n } else if (edges.y === -1) {\n height = Math.max(MIN_HEIGHT, start.height - dy);\n top = Math.max(0, start.top + (start.height - height));\n }\n return { height, left, top, width };\n};\n\nexport { clampToBounds, measureFloatRect, resizeRect };\nexport type { ResizeEdges, Size };\n","import type { CSSProperties } from \"react\";\n\nimport type { ResizeEdges } from \"../lib/float-geometry\";\n\n// Edge grab band straddles the frame border evenly (half outside, half inside)\n// so the cursor lands on a real target whether the user aims slightly in or out.\nconst EDGE_THICKNESS = 12;\nconst EDGE_OFFSET = -(EDGE_THICKNESS / 2);\n// Corners sit mostly outside the frame and are larger for a forgiving grab.\nconst CORNER_SIZE = 20;\nconst CORNER_OFFSET = -8;\n// Each edge band starts where the corner handle ends, so the corner (painted\n// later, same zIndex) keeps its zone while the band covers the rest of the side.\nconst EDGE_INSET = CORNER_SIZE + CORNER_OFFSET;\n\n// data-edge encodes which edges the handle moves; style positions it on the frame.\nconst RESIZE_HANDLES: ReadonlyArray<{ edges: ResizeEdges; key: string; style: CSSProperties }> = [\n {\n edges: { x: 0, y: -1 },\n key: \"n\",\n style: {\n cursor: \"ns-resize\",\n height: EDGE_THICKNESS,\n insetInline: EDGE_INSET,\n top: EDGE_OFFSET,\n },\n },\n {\n edges: { x: 0, y: 1 },\n key: \"s\",\n style: {\n bottom: EDGE_OFFSET,\n cursor: \"ns-resize\",\n height: EDGE_THICKNESS,\n insetInline: EDGE_INSET,\n },\n },\n {\n edges: { x: 1, y: 0 },\n key: \"e\",\n style: {\n cursor: \"ew-resize\",\n insetBlock: EDGE_INSET,\n right: EDGE_OFFSET,\n width: EDGE_THICKNESS,\n },\n },\n {\n edges: { x: -1, y: 0 },\n key: \"w\",\n style: {\n cursor: \"ew-resize\",\n insetBlock: EDGE_INSET,\n left: EDGE_OFFSET,\n width: EDGE_THICKNESS,\n },\n },\n {\n edges: { x: 1, y: -1 },\n key: \"ne\",\n style: {\n cursor: \"nesw-resize\",\n height: CORNER_SIZE,\n right: CORNER_OFFSET,\n top: CORNER_OFFSET,\n width: CORNER_SIZE,\n },\n },\n {\n edges: { x: -1, y: -1 },\n key: \"nw\",\n style: {\n cursor: \"nwse-resize\",\n height: CORNER_SIZE,\n left: CORNER_OFFSET,\n top: CORNER_OFFSET,\n width: CORNER_SIZE,\n },\n },\n {\n edges: { x: 1, y: 1 },\n key: \"se\",\n style: {\n bottom: CORNER_OFFSET,\n cursor: \"nwse-resize\",\n height: CORNER_SIZE,\n right: CORNER_OFFSET,\n width: CORNER_SIZE,\n },\n },\n {\n edges: { x: -1, y: 1 },\n key: \"sw\",\n style: {\n bottom: CORNER_OFFSET,\n cursor: \"nesw-resize\",\n height: CORNER_SIZE,\n left: CORNER_OFFSET,\n width: CORNER_SIZE,\n },\n },\n];\n\n// Resolve a resize handle's data-edge back to its edges; a missing key (the title\n// bar or the minimized chip) means a move, not a resize.\nconst EDGE_BY_KEY = new Map<string, ResizeEdges>(RESIZE_HANDLES.map((h) => [h.key, h.edges]));\n\nexport { EDGE_BY_KEY, RESIZE_HANDLES };\n","\"use client\";\n\nimport type { Action, Dashfoo, SnapConfig, TabNode, TabsetNode } from \"@dashfoo/core\";\nimport type { ComponentProps, CSSProperties, ReactNode, Ref } from \"react\";\nimport { useLayoutEffect, useState } from \"react\";\n\nimport type { LayoutState } from \"../hooks/layout-store\";\nimport { createLayoutStore, LayoutStoreContext } from \"../hooks/layout-store\";\n\nconst DEFAULT_TABSET_MIN_SIZE = 320;\n\n// position: relative so the floating-panel overlay (absolute, inset 0) anchors to\n// the layout frame and floats are positioned in layout-container coordinates.\nconst rootStyle = { display: \"flex\", height: \"100%\", position: \"relative\", width: \"100%\" } as const;\n\ntype LayoutRootProps = Omit<ComponentProps<\"div\">, \"children\"> & {\n children: ReactNode;\n closableTabs?: boolean;\n dispatch: (action: Action) => void;\n draggableTabs?: boolean;\n draggableTabsets?: boolean;\n // The umbrella switch: false turns off every structural edit (tab/tabset drag,\n // close, rename, splitter resize, external drops) in one go, leaving view\n // interactions (tab selection, maximize, overflow) and dispatch untouched.\n editable?: boolean;\n // Tabsets show a control that floats the panel into a movable, resizable overlay.\n // Off by default — opt in, since it changes the model's `floats`.\n floatable?: boolean;\n keepMounted?: boolean;\n maximizable?: boolean;\n model: Dashfoo;\n renamableTabs?: boolean;\n renderTab: (tab: TabNode) => ReactNode;\n renderTabLabel?: (tab: TabNode) => ReactNode;\n renderTabsetToolbar?: (tabset: TabsetNode) => ReactNode;\n resizableSplits?: boolean;\n // Forwarded onto the root element so a width observer can measure the actual\n // container — the hook behind responsive lock-on-mobile.\n rootRef?: Ref<HTMLDivElement>;\n // Magnetic snap default for split resize; the prop replaces (not merges with)\n // model.global.snap when both are present.\n snap?: SnapConfig;\n};\n\n// The frame of a hand-built layout: creates the scoped layout store every part\n// below subscribes to. Takes the model and dispatch (the two store fields the\n// parts need) rather than a whole DashfooStore — wire useDashfooStore and pass\n// store.model / store.dispatch.\nconst LayoutRoot = ({\n children,\n closableTabs = true,\n dispatch,\n draggableTabs = true,\n draggableTabsets = true,\n editable = true,\n floatable = false,\n keepMounted = false,\n maximizable = true,\n model,\n renamableTabs = true,\n renderTab,\n renderTabLabel,\n renderTabsetToolbar,\n resizableSplits = true,\n rootRef,\n snap,\n style,\n ...props\n}: LayoutRootProps): ReactNode => {\n // Model-level globals act as a default layer under the component props: a\n // feature is on unless the prop, the global, or the per-node flag turns it off.\n // `editable` is an extra AND-term over every structural capability — but not\n // maximize, which is reversible view state (same class as tab selection) and\n // stays available in a static layout.\n const global = model.global;\n const snapshot: LayoutState = {\n closableTabs: editable && closableTabs && global.tabEnableClose !== false,\n dispatch,\n draggableTabs: editable && draggableTabs && global.tabEnableDrag !== false,\n draggableTabsets: editable && draggableTabsets,\n editable,\n floatable: editable && floatable,\n keepMounted,\n maximizable: maximizable && global.tabSetEnableMaximize !== false,\n maximizedTabsetId: model.maximizedTabsetId,\n renamableTabs: editable && renamableTabs && global.tabEnableRename !== false,\n renderTab,\n renderTabLabel,\n renderTabsetToolbar,\n resizableSplits: editable && resizableSplits && global.enableSplitResize !== false,\n snap: snap ?? global.snap ?? null,\n splitDock: global.enableSplitDock !== false,\n tabLocation: global.tabLocation ?? \"top\",\n tabsetMinSize: global.tabSetMinSize ?? DEFAULT_TABSET_MIN_SIZE,\n tabStripEnabled: global.tabSetEnableTabStrip !== false,\n };\n\n const [store] = useState(() => createLayoutStore(snapshot));\n // Props→store sync. useLayoutEffect so subscribers see fresh state before\n // paint; never during render — setState on an external store mid-render is\n // unsafe.\n useLayoutEffect(() => {\n store.setState(snapshot);\n });\n\n const layoutStyle: CSSProperties =\n global.splitterSize === undefined\n ? { ...rootStyle, ...style }\n : ({\n ...rootStyle,\n \"--dashfoo-splitter-size\": `${global.splitterSize}px`,\n ...style,\n } as CSSProperties);\n\n return (\n <LayoutStoreContext.Provider value={store}>\n <div {...props} data-dashfoo=\"layout\" ref={rootRef} style={layoutStyle}>\n {children}\n </div>\n </LayoutStoreContext.Provider>\n );\n};\n\nexport { LayoutRoot };\nexport type { LayoutRootProps };\n","// Stable ids wiring each tab to its panel (aria-controls / aria-labelledby).\n// Shared by tabset-view and tab-button so the wiring stays in one place with no\n// circular import between those two modules.\nconst tabDomId = (tabsetId: string, tabId: string): string => `dashfoo-tab-${tabsetId}-${tabId}`;\nconst panelDomId = (tabsetId: string): string => `dashfoo-panel-${tabsetId}`;\n\nexport { panelDomId, tabDomId };\n","\"use client\";\n\nimport type { Action, TabNode, TabsetNode } from \"@dashfoo/core\";\nimport { createContext, useContext } from \"react\";\nimport type { StoreApi } from \"zustand\";\nimport { createStore, useStore } from \"zustand\";\n\nimport { tabDomId } from \"../../lib/tab-ids\";\nimport { warnOnce } from \"../../lib/warn-once\";\nimport type { OverflowItem } from \"../tab-overflow\";\n\n// The per-tabset coordination store behind <Tabset.Root>. Model-derived fields\n// (node, visualSelected, flags) are synced in by Root each render; coordination\n// state (editingTabId, overflowItems, tablistElement, restoreFocus) lives here\n// so sibling parts stay in lockstep without prop threading; actions read live\n// state via get(). editingTabId being a single field guarantees at most one open\n// rename editor per tabset. restoreFocus is set by closeTab so Root's post-delete\n// effect knows to move focus to the newly-selected tab instead of leaving it on\n// <body>.\ntype TabsetState = {\n activeTab: TabNode | undefined;\n cancelRename: () => void;\n closeTab: (tabId: string) => void;\n commitRename: (tabId: string, value: string) => void;\n dispatch: (action: Action) => void;\n editingTabId: string | null;\n isMaximized: boolean;\n node: TabsetNode;\n overflowItems: Array<OverflowItem>;\n registerRenameInput: () => () => void;\n registerTablist: (element: HTMLDivElement | null) => void;\n renameInputCount: number;\n renameTab: (tabId: string, name: string) => void;\n restoreFocus: boolean;\n selectOverflowTab: (tabId: string) => void;\n selectTab: (index: number, options?: { focus?: boolean }) => void;\n showMaximize: boolean;\n startEditing: (tabId: string) => void;\n tablistElement: HTMLDivElement | null;\n tabsClosable: boolean;\n tabsRenamable: boolean;\n toggleMaximize: () => void;\n visualSelected: number;\n};\n\ntype TabsetStore = StoreApi<TabsetState>;\n\ntype TabsetSnapshot = Pick<\n TabsetState,\n | \"activeTab\"\n | \"dispatch\"\n | \"isMaximized\"\n | \"node\"\n | \"showMaximize\"\n | \"tabsClosable\"\n | \"tabsRenamable\"\n | \"visualSelected\"\n>;\n\nconst tabButtonIn = (\n scope: HTMLElement | null,\n tabsetId: string,\n tabId: string,\n): HTMLElement | null =>\n scope?.querySelector<HTMLElement>(`#${CSS.escape(tabDomId(tabsetId, tabId))}`) ?? null;\n\nconst createTabsetStore = (initial: TabsetSnapshot): TabsetStore =>\n createStore<TabsetState>((set, get) => ({\n ...initial,\n cancelRename: () => set({ editingTabId: null }),\n closeTab: (tabId) => {\n set({ restoreFocus: true });\n get().dispatch({ tabId, type: \"deleteTab\" });\n },\n commitRename: (tabId, value) => {\n set({ editingTabId: null });\n const { node, renameTab } = get();\n const trimmed = value.trim();\n const current = node.children.find((tab) => tab.id === tabId)?.name;\n if (trimmed && trimmed !== current) {\n renameTab(tabId, trimmed);\n }\n },\n editingTabId: null,\n overflowItems: [],\n registerRenameInput: () => {\n set((state) => ({ renameInputCount: state.renameInputCount + 1 }));\n return () => set((state) => ({ renameInputCount: state.renameInputCount - 1 }));\n },\n registerTablist: (element) => {\n if (element) {\n const current = get().tablistElement;\n if (current && current !== element) {\n warnOnce(\n `duplicate-tablist-${get().node.id}`,\n \"more than one <Tabset.Tablist> under the same <Tabset.Root>; the last one wins for keyboard focus and overflow\",\n );\n }\n set({ tablistElement: element });\n return;\n }\n set({ tablistElement: null });\n },\n renameInputCount: 0,\n renameTab: (tabId, name) => get().dispatch({ name, tabId, type: \"renameTab\" }),\n restoreFocus: false,\n selectOverflowTab: (tabId) => {\n const { dispatch, node, tablistElement } = get();\n const index = node.children.findIndex((tab) => tab.id === tabId);\n if (index === -1) {\n return;\n }\n dispatch({ index, tabsetId: node.id, type: \"selectTab\" });\n tabButtonIn(tablistElement, node.id, tabId)?.scrollIntoView({\n block: \"nearest\",\n inline: \"nearest\",\n });\n },\n selectTab: (index, options) => {\n const { dispatch, node, tablistElement } = get();\n dispatch({ index, tabsetId: node.id, type: \"selectTab\" });\n if (options?.focus) {\n const tabId = node.children[index]?.id;\n if (tabId) {\n tabButtonIn(tablistElement, node.id, tabId)?.focus();\n }\n }\n },\n startEditing: (tabId) => {\n const { node, renameInputCount, tabsRenamable } = get();\n const tab = node.children.find((child) => child.id === tabId);\n if (!tabsRenamable || tab?.enableRename === false) {\n return;\n }\n if (renameInputCount === 0) {\n // The trigger must not vanish into nothing when no editor is composed.\n warnOnce(\n `missing-rename-input-${node.id}`,\n \"startEditing needs a <Tabset.RenameInput> in the composition; ignoring\",\n );\n return;\n }\n set({ editingTabId: tabId });\n },\n tablistElement: null,\n toggleMaximize: () => {\n const { dispatch, isMaximized, node } = get();\n dispatch({ tabsetId: isMaximized ? null : node.id, type: \"setMaximizedTabset\" });\n },\n }));\n\n// Carries only the store instance — state always flows through selectors.\nconst TabsetStoreContext = createContext<TabsetStore | null>(null);\n\nconst useTabset = <T>(selector: (state: TabsetState) => T): T => {\n const store = useContext(TabsetStoreContext);\n if (store === null) {\n throw new Error(\"dashfoo Tabset parts must be rendered inside <Tabset.Root>.\");\n }\n return useStore(store, selector);\n};\n\n// Identity only — which tab a Trigger/CloseButton/RenameInput belongs to.\n// Derived state (selected, editing) comes from useTabset selectors.\ntype TabContextValue = { index: number; tab: TabNode };\n\nconst TabContext = createContext<TabContextValue | null>(null);\n\nconst useTab = (): TabContextValue => {\n const value = useContext(TabContext);\n if (value === null) {\n throw new Error(\"dashfoo tab parts must be rendered inside <Tabset.Tab>.\");\n }\n return value;\n};\n\nexport { createTabsetStore, TabContext, TabsetStoreContext, useTab, useTabset };\nexport type { TabContextValue, TabsetSnapshot, TabsetState, TabsetStore };\n","\"use client\";\n\nimport type { TabNode } from \"@dashfoo/core\";\nimport type { ComponentProps, CSSProperties, ReactNode } from \"react\";\n\nimport { useLayout } from \"../../hooks/layout-store\";\nimport { panelDomId, tabDomId } from \"../../lib/tab-ids\";\n\nimport { useTabset } from \"./tabset-store\";\n\nconst contentStyle: CSSProperties = { flex: 1, minHeight: 0, overflow: \"auto\" };\n\n// Content is resolved through a component (not inline) so the panel has a stable\n// element identity and React keeps its state across re-renders instead of\n// remounting the inline result. Covers both the registry default (renderTab)\n// and a consumer-supplied render prop.\nconst TabPanel = ({\n render,\n tab,\n}: {\n render?: (tab: TabNode) => ReactNode;\n tab: TabNode;\n}): ReactNode => {\n const renderTab = useLayout((state) => state.renderTab);\n return render ? render(tab) : renderTab(tab);\n};\n\ntype TabsetContentProps = Omit<ComponentProps<\"div\">, \"children\"> & {\n // Overrides the layout's renderTab for this tabset's panels.\n children?: (tab: TabNode) => ReactNode;\n};\n\nconst TabsetContent = ({ children, style, ...props }: TabsetContentProps): ReactNode => {\n const node = useTabset((state) => state.node);\n const visualSelected = useTabset((state) => state.visualSelected);\n const keepMounted = useLayout((state) => state.keepMounted);\n\n const mergedStyle = { ...contentStyle, ...style };\n\n // keepMounted renders every panel (inactive ones hidden) so their state\n // survives a tab switch; otherwise only the active panel mounts.\n if (keepMounted && node.children.length > 0) {\n return node.children.map((tab, index) => (\n <div\n key={tab.id}\n {...props}\n aria-labelledby={tabDomId(node.id, tab.id)}\n data-dashfoo=\"tabcontent\"\n hidden={index !== visualSelected || undefined}\n id={index === visualSelected ? panelDomId(node.id) : undefined}\n role={index === visualSelected ? \"tabpanel\" : undefined}\n style={mergedStyle}\n tabIndex={index === visualSelected ? 0 : undefined}\n >\n <TabPanel render={children} tab={tab} />\n </div>\n ));\n }\n\n const active = node.children[visualSelected];\n if (active) {\n return (\n <div\n {...props}\n aria-labelledby={tabDomId(node.id, active.id)}\n data-dashfoo=\"tabcontent\"\n id={panelDomId(node.id)}\n role=\"tabpanel\"\n style={mergedStyle}\n tabIndex={0}\n >\n <TabPanel render={children} tab={active} />\n </div>\n );\n }\n return <div {...props} data-dashfoo=\"tabcontent\" style={mergedStyle} />;\n};\n\nexport { TabsetContent };\nexport type { TabsetContentProps };\n","\"use client\";\n\nimport type { CSSProperties, FocusEvent, KeyboardEvent, ReactNode } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nconst OverflowIcon = (): ReactNode => (\n <svg aria-hidden=\"true\" fill=\"currentColor\" height=\"10\" viewBox=\"0 0 10 10\" width=\"10\">\n <circle cx=\"2\" cy=\"5\" r=\"1\" />\n <circle cx=\"5\" cy=\"5\" r=\"1\" />\n <circle cx=\"8\" cy=\"5\" r=\"1\" />\n </svg>\n);\n\nconst menuStyle: CSSProperties = {\n position: \"absolute\",\n right: 0,\n top: \"100%\",\n zIndex: 10,\n};\n\ntype OverflowItem = { id: string; name: string };\n\n// A dependency-free overflow control: a button that toggles a menu of the hidden\n// tabs. Implements the WAI-ARIA APG menu-button keyboard model — roving tabindex,\n// arrow/Home/End navigation, Escape-to-close with focus return. Closes on outside\n// pointerdown and focusout.\nconst TabOverflowMenu = ({\n items,\n onSelect,\n}: {\n items: Array<OverflowItem>;\n onSelect: (id: string) => void;\n}): ReactNode => {\n const [open, setOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(0);\n const rootRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n useEffect(() => {\n if (!open) {\n return;\n }\n const handlePointerDown = (event: PointerEvent): void => {\n if (event.target instanceof Node && !rootRef.current?.contains(event.target)) {\n setOpen(false);\n }\n };\n document.addEventListener(\"pointerdown\", handlePointerDown);\n return () => {\n document.removeEventListener(\"pointerdown\", handlePointerDown);\n };\n }, [open]);\n\n // moving DOM focus onto the first menuitem is a side effect of the menu becoming\n // visible, so it belongs in an effect rather than the click handler (the items don't\n // exist yet there). activeIndex is reset to 0 on open, so we always land on the first.\n useEffect(() => {\n if (open) {\n itemRefs.current[0]?.focus();\n }\n }, [open]);\n\n const closeAndReturnFocus = (): void => {\n setOpen(false);\n triggerRef.current?.focus();\n };\n\n const focusItem = (index: number): void => {\n setActiveIndex(index);\n itemRefs.current[index]?.focus();\n };\n\n const handleToggle = (): void => {\n setActiveIndex(0);\n setOpen((value) => !value);\n };\n\n const handleSelect = (id: string): void => {\n onSelect(id);\n closeAndReturnFocus();\n };\n\n const handleMenuKeyDown = (event: KeyboardEvent<HTMLDivElement>): void => {\n const last = items.length - 1;\n switch (event.key) {\n case \"ArrowDown\": {\n event.preventDefault();\n focusItem(activeIndex >= last ? 0 : activeIndex + 1);\n break;\n }\n case \"ArrowUp\": {\n event.preventDefault();\n focusItem(activeIndex <= 0 ? last : activeIndex - 1);\n break;\n }\n case \"Home\": {\n event.preventDefault();\n focusItem(0);\n break;\n }\n case \"End\": {\n event.preventDefault();\n focusItem(last);\n break;\n }\n case \"Escape\": {\n event.preventDefault();\n closeAndReturnFocus();\n break;\n }\n default: {\n break;\n }\n }\n };\n\n // Tab out of the menu (or any other focus leaving the root) closes it without\n // stealing focus, complementing the outside-pointerdown handler for keyboard users.\n const handleFocusOut = (event: FocusEvent<HTMLDivElement>): void => {\n if (event.relatedTarget instanceof Node && rootRef.current?.contains(event.relatedTarget)) {\n return;\n }\n setOpen(false);\n };\n\n return (\n <div data-dashfoo=\"tab-overflow-root\" ref={rootRef} style={{ position: \"relative\" }}>\n <button\n aria-expanded={open}\n aria-haspopup=\"menu\"\n aria-label=\"More tabs\"\n data-dashfoo=\"tab-overflow\"\n onClick={handleToggle}\n ref={triggerRef}\n title=\"More tabs\"\n type=\"button\"\n >\n <OverflowIcon />\n </button>\n {open ? (\n <div\n data-dashfoo=\"tab-overflow-menu\"\n onBlur={handleFocusOut}\n onKeyDown={handleMenuKeyDown}\n role=\"menu\"\n style={menuStyle}\n tabIndex={-1}\n >\n {items.map((item, index) => (\n <button\n data-dashfoo=\"tab-overflow-item\"\n key={item.id}\n onClick={() => handleSelect(item.id)}\n ref={(node) => {\n itemRefs.current[index] = node;\n }}\n role=\"menuitem\"\n tabIndex={index === activeIndex ? 0 : -1}\n type=\"button\"\n >\n {item.name}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n );\n};\n\nexport { TabOverflowMenu };\nexport type { OverflowItem };\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport { TabOverflowMenu } from \"../tab-overflow\";\n\nimport { useTabset } from \"./tabset-store\";\n\n// The menu of tabs clipped out of the tablist's visible box. Measurement lives\n// in Tabset.Root (the store's overflowItems); this part only renders the\n// APG menu-button when there is something to show.\nconst TabsetOverflowMenu = (): ReactNode => {\n const overflowItems = useTabset((state) => state.overflowItems);\n const selectOverflowTab = useTabset((state) => state.selectOverflowTab);\n\n if (overflowItems.length === 0) {\n return null;\n }\n return <TabOverflowMenu items={overflowItems} onSelect={selectOverflowTab} />;\n};\n\nexport { TabsetOverflowMenu };\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\n// The ids of the tabs clipped by the tablist's visible box — past the right edge\n// OR scrolled off before the left edge. +/-1 absorbs sub-pixel rounding. One\n// pass: keep the id only when the tab is both overflowing and identifiable.\nconst overflowingIds = (tablist: Element): Array<string> => {\n const box = tablist.getBoundingClientRect();\n return [...tablist.querySelectorAll<HTMLElement>('[data-dashfoo=\"tab\"]')].flatMap((tab) => {\n const rect = tab.getBoundingClientRect();\n const clipped = rect.right > box.right + 1 || rect.left < box.left - 1;\n return clipped && tab.dataset.tabId ? [tab.dataset.tabId] : [];\n });\n};\n\n// Recomputes the overflowing ids when the tablist resizes, scrolls, or its tab\n// labels/widths change. Takes the element (not a ref) so a tablist that mounts\n// late — or is swapped by a custom composition — re-arms the observers.\n// `signature` folds tab id+name so renames recompute even when the count is\n// unchanged. Returns [] until measured (and in jsdom, where rects are 0).\nconst useTabOverflow = (tablist: HTMLElement | null, signature: string): Array<string> => {\n const [overflow, setOverflow] = useState<Array<string>>([]);\n\n useEffect(() => {\n // No tablist (e.g. the strip is disabled) means nothing can overflow.\n const recompute = (): void => {\n setOverflow((previous) => {\n const next = tablist ? overflowingIds(tablist) : [];\n return next.length === 0 && previous.length === 0 ? previous : next;\n });\n };\n recompute();\n if (!tablist) {\n return;\n }\n const observer = new ResizeObserver(recompute);\n observer.observe(tablist);\n // Scrolling the strip changes which tabs are clipped on the left/right without\n // resizing it, so listen for scroll too.\n tablist.addEventListener(\"scroll\", recompute, { passive: true });\n return () => {\n observer.disconnect();\n tablist.removeEventListener(\"scroll\", recompute);\n };\n }, [tablist, signature]);\n\n return overflow;\n};\n\nexport { overflowingIds, useTabOverflow };\n","// The neighbour to show as active when the selected tab is dragged out: the next\n// tab if there is one, else the previous, else -1 (the tabset is emptying).\nconst fallbackSelectedIndex = (count: number, removedIndex: number): number =>\n removedIndex + 1 < count ? removedIndex + 1 : removedIndex - 1;\n\nexport { fallbackSelectedIndex };\n","\"use client\";\n\nimport type { TabsetNode } from \"@dashfoo/core\";\nimport type { ComponentProps, CSSProperties, ReactNode } from \"react\";\nimport { useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport { useStore } from \"zustand\";\n\nimport { useLayout } from \"../../hooks/layout-store\";\nimport { useTabOverflow } from \"../../hooks/use-tab-overflow\";\nimport { tabDomId } from \"../../lib/tab-ids\";\nimport { fallbackSelectedIndex } from \"../../lib/tab-selection\";\nimport { useDragSubject, useTabsetDroppable } from \"../drag-adapter\";\n\nimport type { TabsetSnapshot } from \"./tabset-store\";\nimport { createTabsetStore, TabsetStoreContext } from \"./tabset-store\";\n\n// height/width 100% (not flex:1) so the tabset fills its parent whether that\n// parent is a flex item or a plain block — rrp wraps panel content in a block\n// div, where flex:1 would collapse to content height.\nconst tabsetStyle: CSSProperties = {\n display: \"flex\",\n flexDirection: \"column\",\n height: \"100%\",\n minHeight: 0,\n minWidth: 0,\n width: \"100%\",\n};\n\ntype TabsetRootProps = ComponentProps<\"div\"> & { node: TabsetNode };\n\n// Creates the per-tabset store and owns everything that needs the whole tabset:\n// the droppable registration, the drag-out selection fallback, overflow\n// measurement, and focus restore after a close.\nconst TabsetRoot = ({\n children,\n node,\n ref: userRef,\n style,\n ...props\n}: TabsetRootProps): ReactNode => {\n const closableTabs = useLayout((state) => state.closableTabs);\n const dispatch = useLayout((state) => state.dispatch);\n const maximizable = useLayout((state) => state.maximizable);\n const maximizedTabsetId = useLayout((state) => state.maximizedTabsetId);\n const renamableTabs = useLayout((state) => state.renamableTabs);\n const tabLocation = useLayout((state) => state.tabLocation);\n\n const { ref } = useTabsetDroppable(node.id);\n const dragSubject = useDragSubject();\n const tabsetRef = useRef<HTMLDivElement | null>(null);\n\n const isMaximized = maximizedTabsetId === node.id;\n const showMaximize = maximizable && node.enableMaximize !== false;\n const tabsClosable = closableTabs && node.enableClose !== false;\n // Renaming has no tabset-level flag — only the layout flag and per-tab opt-out.\n const tabsRenamable = renamableTabs;\n\n // While the selected tab is being dragged out of THIS tabset, show a neighbour\n // as active so the strip + content preview \"as if that tab were already gone\".\n // Purely visual — the model selection is untouched and resumes on drop/cancel.\n const draggingTabIndex =\n dragSubject?.kind === \"tab\" ? node.children.findIndex((tab) => tab.id === dragSubject.id) : -1;\n const visualSelected =\n draggingTabIndex !== -1 && draggingTabIndex === node.selected\n ? fallbackSelectedIndex(node.children.length, draggingTabIndex)\n : node.selected;\n const activeTab = node.children[visualSelected];\n const isDragSource = dragSubject?.kind === \"tabset\" && dragSubject.id === node.id;\n\n const snapshot: TabsetSnapshot = {\n activeTab,\n dispatch,\n isMaximized,\n node,\n showMaximize,\n tabsClosable,\n tabsRenamable,\n visualSelected,\n };\n const [store] = useState(() => createTabsetStore(snapshot));\n\n // Props→store sync. useLayoutEffect (not useEffect) so subscribers re-render\n // before paint and DOM-focus effects below see fresh state; never during\n // render — setState on an external store mid-render is unsafe.\n useLayoutEffect(() => {\n store.setState(snapshot);\n });\n\n // Overflow measurement runs here (not in the menu part) because the default\n // composition's toolbar-visibility condition needs the count, and the tablist\n // element registration already lives in the store.\n const tablistElement = useStore(store, (state) => state.tablistElement);\n // A rename or scroll changes clipping without changing the count, so the\n // signature folds each tab's id+name into the deps the hook watches.\n const overflowSignature = node.children.map((tab) => `${tab.id}:${tab.name}`).join(\"|\");\n const overflow = useTabOverflow(tablistElement, overflowSignature);\n // Resolve overflowing ids to names once per change instead of a find() per item.\n const overflowItems = useMemo(() => {\n const names = new Map(node.children.map((tab) => [tab.id, tab.name]));\n return overflow.map((id) => ({ id, name: names.get(id) ?? id }));\n }, [overflow, node.children]);\n useLayoutEffect(() => {\n store.setState({ overflowItems });\n }, [overflowItems, store]);\n\n // Runs after a closeTab commits. Focus the now-active tab's button, or fall\n // back to the tabset container if the tabset emptied so focus never lands on\n // <body>. Scoped to the root (not the tablist) so tabs rendered outside a\n // tablist still get focus restore.\n useEffect(() => {\n if (!store.getState().restoreFocus) {\n return;\n }\n store.setState({ restoreFocus: false });\n const activeTabId = node.children[node.selected]?.id;\n if (activeTabId) {\n tabsetRef.current\n ?.querySelector<HTMLElement>(`#${CSS.escape(tabDomId(node.id, activeTabId))}`)\n ?.focus();\n } else {\n tabsetRef.current?.focus();\n }\n }, [node.children, node.selected, node.id, store]);\n\n return (\n <TabsetStoreContext.Provider value={store}>\n <div\n {...props}\n data-dashfoo=\"tabset\"\n data-dragging-source={isDragSource || undefined}\n data-tab-location={tabLocation}\n ref={(element) => {\n ref(element);\n tabsetRef.current = element;\n if (typeof userRef === \"function\") {\n userRef(element);\n } else if (userRef) {\n userRef.current = element;\n }\n }}\n style={{ ...tabsetStyle, ...style }}\n // -1 so an emptied tabset can receive focus on close without entering the\n // Tab order.\n tabIndex={-1}\n >\n {children}\n </div>\n </TabsetStoreContext.Provider>\n );\n};\n\nexport { TabsetRoot };\nexport type { TabsetRootProps };\n","import type { Ref } from \"react\";\n\nconst applyRef = <T>(ref: Ref<T> | undefined, value: T | null): void => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref) {\n ref.current = value;\n }\n};\n\n// Fans one element out to several refs so a part can keep its internal ref\n// (draggable wiring, focus lookups) while still honoring a consumer-supplied one.\nconst mergeRefs =\n <T>(...refs: Array<Ref<T> | undefined>) =>\n (value: T | null): void => {\n for (const ref of refs) {\n applyRef(ref, value);\n }\n };\n\nexport { mergeRefs };\n","\"use client\";\n\nimport type { TabNode } from \"@dashfoo/core\";\nimport type { ComponentProps, MouseEvent, ReactNode } from \"react\";\nimport { useContext, useEffect, useMemo, useRef } from \"react\";\n\nimport { useLayout } from \"../../hooks/layout-store\";\nimport { mergeRefs } from \"../../lib/merge-refs\";\nimport { panelDomId, tabDomId } from \"../../lib/tab-ids\";\nimport { warnOnce } from \"../../lib/warn-once\";\nimport { useDragSubject, useTabDraggable } from \"../drag-adapter\";\n\nimport { TabContext, TabsetStoreContext, useTab, useTabset } from \"./tabset-store\";\n\ntype TabsetTabProps = ComponentProps<\"span\"> & { tab: TabNode };\n\n// The per-tab wrapper: provides identity (which tab, which index) to Trigger,\n// CloseButton, and RenameInput, and owns the focus-return-after-rename effect.\nconst TabsetTab = ({ children, ref: userRef, tab, ...props }: TabsetTabProps): ReactNode => {\n const store = useContext(TabsetStoreContext);\n const node = useTabset((state) => state.node);\n const editing = useTabset((state) => state.editingTabId === tab.id);\n // `data-dragging` is driven off the drag machine's subject, which is\n // authoritative for the whole drag — the source tab stays in the strip (dimmed)\n // while the overlay chip follows the pointer.\n const dragSubject = useDragSubject();\n const isDragging = dragSubject?.kind === \"tab\" && dragSubject.id === tab.id;\n const itemRef = useRef<HTMLSpanElement | null>(null);\n const wasEditing = useRef(false);\n\n const index = node.children.findIndex((child) => child.id === tab.id);\n\n // The orphan check must not run at render time: right after a tab moves\n // between tabsets, this render sees the new `tab` prop against the store's\n // not-yet-synced node, so a legitimately moved tab transiently looks\n // orphaned (the index self-corrects before paint). The effect reads the live\n // store instead — Root's layout-effect sync always lands before any passive\n // effect flushes, so only a genuinely missing tab warns.\n const orphanAtRender = index === -1;\n useEffect(() => {\n const settled = store?.getState().node.children.some((child) => child.id === tab.id);\n if (settled === false) {\n warnOnce(\n `orphan-tab-${tab.id}`,\n `<Tabset.Tab> for \"${tab.id}\" is not a child of its Tabset.Root's node; it renders but can never be selected`,\n );\n }\n }, [orphanAtRender, store, tab.id]);\n\n // Return focus to the tab button once the inline editor closes.\n useEffect(() => {\n if (wasEditing.current && !editing) {\n itemRef.current?.querySelector<HTMLElement>('[data-dashfoo=\"tab\"]')?.focus();\n }\n wasEditing.current = editing;\n }, [editing]);\n\n const contextValue = useMemo(() => ({ index, tab }), [index, tab]);\n const refCallback = useMemo(() => mergeRefs<HTMLSpanElement>(itemRef, userRef), [userRef]);\n\n return (\n <TabContext.Provider value={contextValue}>\n <span\n {...props}\n data-dashfoo=\"tab-item\"\n data-dragging={isDragging || undefined}\n ref={refCallback}\n >\n {children}\n </span>\n </TabContext.Provider>\n );\n};\n\ntype TabsetTriggerProps = ComponentProps<\"button\">;\n\n// The tab button itself — a sibling of the close control (not its parent, which\n// would be invalid markup and would pollute the tab's accessible name). Hidden\n// while the rename editor is open; the draggable hook stays mounted so the\n// Draggable instance survives the swap.\nconst TabsetTrigger = ({\n children,\n onClick,\n onDoubleClick,\n ref: userRef,\n ...props\n}: TabsetTriggerProps): ReactNode => {\n const { index, tab } = useTab();\n const node = useTabset((state) => state.node);\n const editing = useTabset((state) => state.editingTabId === tab.id);\n const selectTab = useTabset((state) => state.selectTab);\n const startEditing = useTabset((state) => state.startEditing);\n const tabsRenamable = useTabset((state) => state.tabsRenamable);\n const visualSelected = useTabset((state) => state.visualSelected);\n const draggableTabs = useLayout((state) => state.draggableTabs);\n const renderTabLabel = useLayout((state) => state.renderTabLabel);\n const { ref } = useTabDraggable(tab.id, !draggableTabs || tab.enableDrag === false, tab.name);\n const refCallback = useMemo(() => mergeRefs<HTMLButtonElement>(ref, userRef), [ref, userRef]);\n\n if (editing) {\n return null;\n }\n\n const selected = index === visualSelected;\n const renamable = tabsRenamable && tab.enableRename !== false;\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>): void => {\n onClick?.(event);\n selectTab(index);\n };\n\n const handleDoubleClick = (event: MouseEvent<HTMLButtonElement>): void => {\n onDoubleClick?.(event);\n if (renamable) {\n startEditing(tab.id);\n }\n };\n\n return (\n <button\n aria-label={renderTabLabel ? tab.name : undefined}\n {...props}\n aria-controls={panelDomId(node.id)}\n aria-selected={selected}\n data-dashfoo=\"tab\"\n data-tab-id={tab.id}\n id={tabDomId(node.id, tab.id)}\n onClick={handleClick}\n onDoubleClick={handleDoubleClick}\n ref={refCallback}\n role=\"tab\"\n tabIndex={selected ? 0 : -1}\n type=\"button\"\n >\n {children ?? (renderTabLabel ? renderTabLabel(tab) : tab.name)}\n </button>\n );\n};\n\nexport { TabsetTab, TabsetTrigger };\nexport type { TabsetTabProps, TabsetTriggerProps };\n","import type { CSSProperties, ReactNode } from \"react\";\n\nconst iconStyle: CSSProperties = { pointerEvents: \"none\" };\n\n// Shared lucide-style icon frame (24-unit grid, currentColor stroke). iconStyle\n// sets pointer-events:none so a pointerdown on a grip lands on the button (the\n// draggable), not the svg path — otherwise the drag sensor never activates.\nconst Icon = ({ children }: { children: ReactNode }): ReactNode => (\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n height=\"12\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n style={iconStyle}\n viewBox=\"0 0 24 24\"\n width=\"12\"\n >\n {children}\n </svg>\n);\n\nconst CloseIcon = (): ReactNode => (\n <Icon>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </Icon>\n);\n\nconst GripIcon = (): ReactNode => (\n <Icon>\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"19\" cy=\"5\" r=\"1\" />\n <circle cx=\"5\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"19\" cy=\"12\" r=\"1\" />\n <circle cx=\"5\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n <circle cx=\"19\" cy=\"19\" r=\"1\" />\n <circle cx=\"5\" cy=\"19\" r=\"1\" />\n </Icon>\n);\n\nconst MaximizeIcon = ({ maximized }: { maximized: boolean }): ReactNode =>\n maximized ? (\n <Icon>\n <path d=\"m14 10 7-7\" />\n <path d=\"M20 10h-6V4\" />\n <path d=\"m3 21 7-7\" />\n <path d=\"M4 14h6v6\" />\n </Icon>\n ) : (\n <Icon>\n <path d=\"M15 3h6v6\" />\n <path d=\"m21 3-7 7\" />\n <path d=\"m3 21 7-7\" />\n <path d=\"M9 21H3v-6\" />\n </Icon>\n );\n\n// \"Float\" — a small panel lifted off the surface (a framed rect with a header).\nconst FloatIcon = (): ReactNode => (\n <Icon>\n <rect height=\"14\" rx=\"2\" width=\"18\" x=\"3\" y=\"6\" />\n <path d=\"M3 10h18\" />\n </Icon>\n);\n\n// \"Minimize\" — collapse to a chip.\nconst MinimizeIcon = (): ReactNode => (\n <Icon>\n <path d=\"M5 12h14\" />\n </Icon>\n);\n\n// \"Dock back\" — an arrow returning into a frame.\nconst DockIcon = (): ReactNode => (\n <Icon>\n <path d=\"M3 7V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2\" />\n <path d=\"M11 8 7 12l4 4\" />\n <path d=\"M7 12h10\" />\n </Icon>\n);\n\nexport { CloseIcon, DockIcon, FloatIcon, GripIcon, MaximizeIcon, MinimizeIcon };\n","\"use client\";\n\nimport type { ComponentProps, FocusEvent, KeyboardEvent, MouseEvent, ReactNode } from \"react\";\nimport { useEffect, useMemo, useRef } from \"react\";\n\nimport { mergeRefs } from \"../../lib/merge-refs\";\nimport { CloseIcon } from \"../tabset-icons\";\n\nimport { useTab, useTabset } from \"./tabset-store\";\n\ntype TabsetRenameInputProps = ComponentProps<\"input\">;\n\n// Inline rename editor. Enter/Escape set `done` so the unmount blur does not\n// re-commit after a deliberate commit or cancel. A separate inner component so\n// each editing session mounts fresh (autofocus + select, reset `done`).\nconst RenameEditor = ({\n defaultValue,\n onBlur,\n onKeyDown,\n ref: userRef,\n ...props\n}: TabsetRenameInputProps): ReactNode => {\n const { tab } = useTab();\n const cancelRename = useTabset((state) => state.cancelRename);\n const commitRename = useTabset((state) => state.commitRename);\n const ref = useRef<HTMLInputElement | null>(null);\n const done = useRef(false);\n const refCallback = useMemo(() => mergeRefs<HTMLInputElement>(ref, userRef), [userRef]);\n\n useEffect(() => {\n ref.current?.focus();\n ref.current?.select();\n }, []);\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>): void => {\n onKeyDown?.(event);\n if (event.key === \"Enter\") {\n done.current = true;\n commitRename(tab.id, event.currentTarget.value);\n } else if (event.key === \"Escape\") {\n done.current = true;\n cancelRename();\n }\n };\n\n const handleCommitOnBlur = (event: FocusEvent<HTMLInputElement>): void => {\n onBlur?.(event);\n if (done.current) {\n return;\n }\n done.current = true;\n commitRename(tab.id, event.currentTarget.value);\n };\n\n return (\n <input\n aria-label={`Rename ${tab.name}`}\n {...props}\n data-dashfoo=\"tab-rename\"\n defaultValue={defaultValue ?? tab.name}\n onBlur={handleCommitOnBlur}\n onKeyDown={handleKeyDown}\n ref={refCallback}\n type=\"text\"\n />\n );\n};\n\n// Renders only while its tab is being renamed. Always composed (it registers its\n// presence on mount so startEditing can warn when no editor exists), but inert\n// until the trigger's double-click flips editingTabId.\nconst TabsetRenameInput = (props: TabsetRenameInputProps): ReactNode => {\n const { tab } = useTab();\n const editing = useTabset((state) => state.editingTabId === tab.id);\n const registerRenameInput = useTabset((state) => state.registerRenameInput);\n\n useEffect(() => registerRenameInput(), [registerRenameInput]);\n\n if (!editing) {\n return null;\n }\n return <RenameEditor {...props} />;\n};\n\ntype TabsetCloseButtonProps = ComponentProps<\"button\">;\n\nconst TabsetCloseButton = ({ children, onClick, ...props }: TabsetCloseButtonProps): ReactNode => {\n const { index, tab } = useTab();\n const closeTab = useTabset((state) => state.closeTab);\n const editing = useTabset((state) => state.editingTabId === tab.id);\n const tabsClosable = useTabset((state) => state.tabsClosable);\n const visualSelected = useTabset((state) => state.visualSelected);\n\n const closable = tabsClosable && tab.enableClose !== false;\n if (!closable || editing) {\n return null;\n }\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>): void => {\n onClick?.(event);\n // Closing must not bubble into the trigger and select the closing tab.\n event.stopPropagation();\n closeTab(tab.id);\n };\n\n return (\n <button\n aria-label={`Close ${tab.name}`}\n title={`Close ${tab.name}`}\n {...props}\n data-dashfoo=\"tab-close\"\n onClick={handleClick}\n // Roving tabindex: only the active tab's close button is tabbable, so\n // Tab does not stop on a close button inside every tab in the tablist.\n tabIndex={index === visualSelected ? 0 : -1}\n type=\"button\"\n >\n {children ?? <CloseIcon />}\n </button>\n );\n};\n\nexport { TabsetCloseButton, TabsetRenameInput };\nexport type { TabsetCloseButtonProps, TabsetRenameInputProps };\n","\"use client\";\n\nimport type { ComponentProps, CSSProperties, KeyboardEvent, ReactNode } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { mergeRefs } from \"../../lib/merge-refs\";\n\nimport { useTabset } from \"./tabset-store\";\n\n// The strip is a presentational row: the tablist (the actual tabs) plus room for\n// a trailing toolbar. role=\"tablist\" lives on the inner tablist so the toolbar is\n// not announced as a tab. The drag adapter hit-tests [data-dashfoo=\"tabstrip\"],\n// so the attribute is applied after the spread — it is structural, not theming.\nconst stripStyle: CSSProperties = { display: \"flex\", flexShrink: 0 };\n\nconst tablistStyle: CSSProperties = { display: \"flex\", minWidth: 0, overflowX: \"auto\" };\n\ntype TabsetTabStripProps = ComponentProps<\"div\">;\n\nconst TabsetTabStrip = ({ style, ...props }: TabsetTabStripProps): ReactNode => (\n <div {...props} data-dashfoo=\"tabstrip\" style={{ ...stripStyle, ...style }} />\n);\n\ntype TabsetTablistProps = ComponentProps<\"div\">;\n\n// Owns the roving-tabindex keyboard model (WAI-ARIA APG Tabs): arrows move and\n// select, Home/End jump to the ends, and focus follows the new selection.\nconst TabsetTablist = ({\n onKeyDown,\n ref: userRef,\n style,\n ...props\n}: TabsetTablistProps): ReactNode => {\n const node = useTabset((state) => state.node);\n const registerTablist = useTabset((state) => state.registerTablist);\n const selectTab = useTabset((state) => state.selectTab);\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>): void => {\n onKeyDown?.(event);\n if (event.defaultPrevented) {\n return;\n }\n // Only act when the key comes from a tab — otherwise a focused close button\n // (a tablist child) would have its arrows/Home/End hijacked.\n if (!(event.target instanceof HTMLElement) || !event.target.closest('[role=\"tab\"]')) {\n return;\n }\n const count = node.children.length;\n if (count === 0) {\n return;\n }\n const targets: Record<string, number> = {\n ArrowLeft: (node.selected - 1 + count) % count,\n ArrowRight: (node.selected + 1) % count,\n End: count - 1,\n Home: 0,\n };\n const next = targets[event.key];\n if (next === undefined) {\n return;\n }\n event.preventDefault();\n selectTab(next, { focus: true });\n };\n\n // Stable callback ref so React doesn't detach/re-register the tablist on every\n // render (a fresh inline ref identity would churn the store registration).\n const refCallback = useMemo(\n () => mergeRefs<HTMLDivElement>(registerTablist, userRef),\n [registerTablist, userRef],\n );\n\n return (\n <div\n aria-label={node.name ?? \"Tabs\"}\n {...props}\n aria-orientation=\"horizontal\"\n data-dashfoo=\"tablist\"\n onKeyDown={handleKeyDown}\n ref={refCallback}\n role=\"tablist\"\n style={{ ...tablistStyle, ...style }}\n tabIndex={-1}\n />\n );\n};\n\nexport { TabsetTablist, TabsetTabStrip };\nexport type { TabsetTablistProps, TabsetTabStripProps };\n","\"use client\";\n\nimport type { ComponentProps, CSSProperties, MouseEvent, ReactNode } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { useLayout } from \"../../hooks/layout-store\";\nimport { measureFloatRect } from \"../../lib/float-geometry\";\nimport { mergeRefs } from \"../../lib/merge-refs\";\nimport { warnOnce } from \"../../lib/warn-once\";\nimport { useTabsetDraggable } from \"../drag-adapter\";\nimport { useHasFloatLayer } from \"../float-context\";\nimport { FloatIcon, GripIcon, MaximizeIcon } from \"../tabset-icons\";\n\nimport { useTabset } from \"./tabset-store\";\n\nconst toolbarStyle: CSSProperties = {\n alignItems: \"center\",\n display: \"flex\",\n flexShrink: 0,\n marginInlineStart: \"auto\",\n};\n\ntype TabsetToolbarProps = ComponentProps<\"div\">;\n\nconst TabsetToolbar = ({ style, ...props }: TabsetToolbarProps): ReactNode => (\n <div {...props} data-dashfoo=\"tabset-toolbar\" style={{ ...toolbarStyle, ...style }} />\n);\n\ntype TabsetGripProps = ComponentProps<\"button\">;\n\n// The whole tabset is draggable from its grip. It carries the active tab's name\n// so the drag overlay can label the chip. Self-hides when tabset dragging is off\n// or the tabset is maximized (nowhere to dock).\nconst TabsetGrip = ({ children, ref: userRef, ...props }: TabsetGripProps): ReactNode => {\n const activeTabName = useTabset((state) => state.activeTab?.name ?? \"\");\n const isMaximized = useTabset((state) => state.isMaximized);\n const node = useTabset((state) => state.node);\n const draggableTabsets = useLayout((state) => state.draggableTabsets);\n const hidden = !draggableTabsets || isMaximized;\n const { ref } = useTabsetDraggable(node.id, hidden, activeTabName);\n const refCallback = useMemo(() => mergeRefs<HTMLButtonElement>(ref, userRef), [ref, userRef]);\n\n if (hidden) {\n return null;\n }\n\n return (\n <button\n aria-label=\"Move tabset\"\n title=\"Move tabset\"\n {...props}\n data-dashfoo=\"tabset-grip\"\n ref={refCallback}\n type=\"button\"\n >\n {children ?? <GripIcon />}\n </button>\n );\n};\n\ntype TabsetMaximizeButtonProps = ComponentProps<\"button\">;\n\nconst TabsetMaximizeButton = ({\n children,\n onClick,\n ...props\n}: TabsetMaximizeButtonProps): ReactNode => {\n const isMaximized = useTabset((state) => state.isMaximized);\n const showMaximize = useTabset((state) => state.showMaximize);\n const toggleMaximize = useTabset((state) => state.toggleMaximize);\n\n if (!showMaximize) {\n return null;\n }\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>): void => {\n onClick?.(event);\n toggleMaximize();\n };\n\n return (\n <button\n aria-label={isMaximized ? \"Restore\" : \"Maximize\"}\n title={isMaximized ? \"Restore tabset\" : \"Maximize tabset\"}\n {...props}\n aria-pressed={isMaximized}\n data-dashfoo=\"tabset-maximize\"\n onClick={handleClick}\n type=\"button\"\n >\n {children ?? <MaximizeIcon maximized={isMaximized} />}\n </button>\n );\n};\n\ntype TabsetFloatButtonProps = ComponentProps<\"button\">;\n\n// Floats the whole tabset out into a draggable, resizable overlay (dispatches\n// `floatTabset` with a rect measured over the panel). Self-hides when floating is\n// off or the tabset is maximized (a maximized panel already owns the frame).\nconst TabsetFloatButton = ({ children, onClick, ...props }: TabsetFloatButtonProps): ReactNode => {\n const floatable = useLayout((state) => state.floatable);\n const dispatch = useLayout((state) => state.dispatch);\n const isMaximized = useTabset((state) => state.isMaximized);\n const node = useTabset((state) => state.node);\n const hasFloatLayer = useHasFloatLayer();\n\n if (!floatable || isMaximized) {\n return null;\n }\n\n // `floatable` is on but there is no <Layout.FloatLayer> to render the float (a\n // hand-built layout that forgot it — DashfooLayout always adds one). Hide the\n // control and warn rather than render a button that would float a panel into\n // nowhere.\n if (!hasFloatLayer) {\n warnOnce(\n \"float-no-layer\",\n \"Tabset.FloatButton needs a <Layout.FloatLayer> around the layout (DashfooLayout adds one); the float control is hidden\",\n );\n return null;\n }\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>): void => {\n onClick?.(event);\n const geometry = measureFloatRect(event.currentTarget);\n dispatch({ geometry, tabsetId: node.id, type: \"floatTabset\" });\n };\n\n return (\n <button\n aria-label=\"Float panel\"\n title=\"Float panel\"\n {...props}\n data-dashfoo=\"tabset-float\"\n onClick={handleClick}\n type=\"button\"\n >\n {children ?? <FloatIcon />}\n </button>\n );\n};\n\nexport { TabsetFloatButton, TabsetGrip, TabsetMaximizeButton, TabsetToolbar };\nexport type {\n TabsetFloatButtonProps,\n TabsetGripProps,\n TabsetMaximizeButtonProps,\n TabsetToolbarProps,\n};\n","\"use client\";\n\nimport type { TabsetNode } from \"@dashfoo/core\";\nimport type { ReactNode } from \"react\";\n\nimport { useLayout } from \"../../hooks/layout-store\";\n\nimport { TabsetContent } from \"./tabset-content\";\nimport { TabsetOverflowMenu } from \"./tabset-overflow\";\nimport { TabsetRoot } from \"./tabset-root\";\nimport { useTabset } from \"./tabset-store\";\nimport { TabsetTab, TabsetTrigger } from \"./tabset-tab\";\nimport { TabsetCloseButton, TabsetRenameInput } from \"./tabset-tab-controls\";\nimport { TabsetTablist, TabsetTabStrip } from \"./tabset-tablist\";\nimport {\n TabsetFloatButton,\n TabsetGrip,\n TabsetMaximizeButton,\n TabsetToolbar,\n} from \"./tabset-toolbar\";\n\n// Static JSX hoisted to module scope (elements are immutable, so one instance\n// is safely shared) — DefaultTabsetLayout re-renders on every selection change\n// and must not rebuild it each time.\nconst tabsetContent = <TabsetContent />;\n\n// The canonical composition of the Tabset parts — what DashfooLayout and\n// Layout.Rows render by default, and the reference for anyone composing the\n// parts by hand. Lives inside Tabset.Root because the toolbar-visibility\n// condition needs the store's overflow count.\nconst DefaultTabsetLayout = (): ReactNode => {\n const draggableTabsets = useLayout((state) => state.draggableTabsets);\n const floatable = useLayout((state) => state.floatable);\n const renderTabsetToolbar = useLayout((state) => state.renderTabsetToolbar);\n const tabLocation = useLayout((state) => state.tabLocation);\n const tabStripEnabled = useLayout((state) => state.tabStripEnabled);\n const isMaximized = useTabset((state) => state.isMaximized);\n const node = useTabset((state) => state.node);\n const overflowCount = useTabset((state) => state.overflowItems.length);\n const showMaximize = useTabset((state) => state.showMaximize);\n\n // The toolbar exists only when it has content; each part also self-hides so\n // the condition and the parts can never disagree.\n const showToolbar =\n showMaximize ||\n renderTabsetToolbar !== undefined ||\n overflowCount > 0 ||\n (floatable && !isMaximized) ||\n (draggableTabsets && !isMaximized);\n\n const strip = tabStripEnabled ? (\n <TabsetTabStrip>\n <TabsetTablist>\n {node.children.map((tab) => (\n <TabsetTab key={tab.id} tab={tab}>\n <TabsetTrigger />\n <TabsetRenameInput />\n <TabsetCloseButton />\n </TabsetTab>\n ))}\n </TabsetTablist>\n {showToolbar ? (\n <TabsetToolbar>\n <TabsetOverflowMenu />\n <TabsetGrip />\n {renderTabsetToolbar?.(node)}\n <TabsetFloatButton />\n <TabsetMaximizeButton />\n </TabsetToolbar>\n ) : null}\n </TabsetTabStrip>\n ) : null;\n\n return tabLocation === \"bottom\" ? (\n <>\n {tabsetContent}\n {strip}\n </>\n ) : (\n <>\n {strip}\n {tabsetContent}\n </>\n );\n};\n\ntype TabsetViewProps = { node: TabsetNode };\n\nconst TabsetView = ({ node }: TabsetViewProps): ReactNode => (\n <TabsetRoot node={node}>\n <DefaultTabsetLayout />\n </TabsetRoot>\n);\n\nexport { TabsetView };\nexport type { TabsetViewProps };\n","\"use client\";\n\nimport type { Dimension, RowNode, SnapConfig, TabsetNode } from \"@dashfoo/core\";\nimport { snapEnabled, snapSizes } from \"@dashfoo/core\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { Fragment, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport type { GroupImperativeHandle, Layout, Orientation } from \"react-resizable-panels\";\nimport { Group, Panel, Separator } from \"react-resizable-panels\";\n\nimport { useLayout } from \"../hooks/layout-store\";\n\nimport { TabsetView } from \"./tabset/tabset-view\";\n\n// This module is the resize adapter: the only place that imports\n// react-resizable-panels. It maps the model's responsive weights to rrp's\n// percentage layout and unit-typed min/max constraints to rrp sizes, and commits\n// a drag (on release) back to the document as an adjustSplit action.\n//\n// Magnetic snapping is layered on top: rrp's continuous onLayoutChange pulls the\n// dragged boundary onto a grid (groupRef.setLayout), and onLayoutChanged commits\n// the already-snapped weights as a single undo step on release.\n\nconst dimensionToSize = (dimension: Dimension): string => `${dimension.value}${dimension.unit}`;\nconst dimensionToPixels = (dimension: Dimension | undefined): number | undefined =>\n dimension?.unit === \"px\" ? dimension.value : undefined;\n\nconst groupStyle: CSSProperties = { display: \"flex\", flex: 1, minHeight: 0, minWidth: 0 };\nconst WEIGHT_EPSILON = 0.01;\n\ntype LayoutChild = RowNode[\"children\"][number];\n\nconst layoutFromWeights = (children: RowNode[\"children\"], total: number): Layout =>\n children.reduce<Layout>((layout, child) => {\n layout[child.id] = ((child.weight ?? 1) / total) * 100;\n return layout;\n }, {});\n\n// rrp's id-keyed Layout <-> the ordered percentage array the pure snap math wants.\nconst orderedFromLayout = (layout: Layout, children: RowNode[\"children\"]): Array<number> =>\n children.map((child) => layout[child.id] ?? 0);\n\nconst layoutFromOrdered = (sizes: Array<number>, children: RowNode[\"children\"]): Layout =>\n children.reduce<Layout>((layout, child, index) => {\n layout[child.id] = sizes[index] ?? 0;\n return layout;\n }, {});\n\nconst layoutsMatch = (current: Layout, expected: Layout): boolean => {\n const currentIds = Object.keys(current);\n const expectedIds = Object.keys(expected);\n if (currentIds.length !== expectedIds.length) {\n return false;\n }\n return expectedIds.every(\n (id) => Math.abs((current[id] ?? Number.NaN) - expected[id]) <= WEIGHT_EPSILON,\n );\n};\n\nconst descendantMinSize = (\n child: LayoutChild,\n axis: RowNode[\"orientation\"],\n tabsetMinSize: number,\n): number | undefined => {\n const explicit = dimensionToPixels(child.min);\n if (explicit !== undefined) {\n return explicit;\n }\n if (child.min !== undefined) {\n return undefined;\n }\n if (child.type === \"tabset\") {\n return tabsetMinSize;\n }\n\n const childMinimums: Array<number> = [];\n for (const grandchild of child.children) {\n const minimum = descendantMinSize(grandchild, axis, tabsetMinSize);\n if (minimum === undefined) {\n return undefined;\n }\n childMinimums.push(minimum);\n }\n if (childMinimums.length === 0) {\n return undefined;\n }\n\n return child.orientation === axis\n ? childMinimums.reduce((sum, value) => sum + value, 0)\n : Math.max(...childMinimums);\n};\n\ntype RowViewProps = {\n node: RowNode;\n // Substitutes a custom tabset composition at every leaf of the split tree;\n // defaults to the stock TabsetView.\n renderTabset?: (node: TabsetNode) => ReactNode;\n};\n\nconst RowView = ({ node, renderTabset }: RowViewProps): ReactNode => {\n const dispatch = useLayout((state) => state.dispatch);\n const resizableSplits = useLayout((state) => state.resizableSplits);\n const tabsetMinSize = useLayout((state) => state.tabsetMinSize);\n const globalSnap = useLayout((state) => state.snap);\n // A row's own snap attribute overrides the layout-wide default; an empty config\n // (or step 0 with no divisions) means this row does not snap.\n const effectiveSnap: SnapConfig | null = node.snap ?? globalSnap;\n const snapActive = snapEnabled(effectiveSnap);\n const orientation: Orientation = node.orientation === \"row\" ? \"horizontal\" : \"vertical\";\n const total = node.children.reduce((sum, child) => sum + (child.weight ?? 1), 0);\n const desiredLayout = useMemo(\n () => layoutFromWeights(node.children, total),\n [node.children, total],\n );\n\n // rrp fires onLayoutChanged once on mount with its measured layout. That is not\n // a user resize — committing it would rewrite the authored weights and push a\n // spurious undo entry — so the first call (per mount) is ignored.\n const measured = useRef(false);\n const groupRef = useRef<GroupImperativeHandle | null>(null);\n const groupElement = useRef<HTMLDivElement | null>(null);\n const syncing = useRef(false);\n // Which boundary the pointer grabbed (captured on the separator's pointerdown),\n // a re-entrancy guard for our own setLayout, and the snapped boundary mirrored\n // into state only on engage/disengage so the highlight re-renders ~twice a drag.\n const activeBoundary = useRef<number | null>(null);\n const snapping = useRef(false);\n const snappedBoundaryRef = useRef<number | null>(null);\n const [snappedBoundary, setSnappedBoundary] = useState<number | null>(null);\n\n const setHighlight = (boundary: number | null): void => {\n if (boundary !== snappedBoundaryRef.current) {\n snappedBoundaryRef.current = boundary;\n setSnappedBoundary(boundary);\n }\n };\n\n // Toggle the flex transition on the group imperatively (not via React state):\n // it must be live in the DOM before the snapping setLayout writes flex this same\n // frame, so the panels glide onto the grid line. Cleared on free-tracking frames\n // so dragging stays 1:1 with the pointer (snap-out is instant).\n const setSnapTransition = (active: boolean): void => {\n const element = groupElement.current;\n if (!element) {\n return;\n }\n if (active) {\n element.dataset.dashfooSnapping = \"true\";\n } else {\n delete element.dataset.dashfooSnapping;\n }\n };\n\n useLayoutEffect(() => {\n const group = groupRef.current;\n if (!group) {\n return;\n }\n const current = group.getLayout();\n const samePanelSet =\n Object.keys(current).length === Object.keys(desiredLayout).length &&\n Object.keys(desiredLayout).every((id) => id in current);\n if (!samePanelSet || layoutsMatch(current, desiredLayout)) {\n return;\n }\n\n syncing.current = true;\n group.setLayout(desiredLayout);\n const frame = requestAnimationFrame(() => {\n syncing.current = false;\n });\n return () => {\n cancelAnimationFrame(frame);\n syncing.current = false;\n };\n }, [desiredLayout]);\n\n // Fires on every pointer move during a drag. Pull the grabbed boundary onto the\n // nearest grid target and push it back into rrp so the panel visibly sticks. The\n // `snapping` guard plus the idempotence check keep our own setLayout from\n // re-triggering this and prevent jitter at the threshold edge, whatever rrp's\n // re-fire timing.\n const handleLayoutChange = (layout: Layout): void => {\n if (snapping.current || syncing.current || !resizableSplits) {\n return;\n }\n if (effectiveSnap === null || !snapActive) {\n return;\n }\n const boundary = activeBoundary.current;\n if (boundary === null) {\n return;\n }\n\n const { sizes, snapped } = snapSizes(\n orderedFromLayout(layout, node.children),\n boundary,\n effectiveSnap,\n );\n setHighlight(snapped ? boundary : null);\n if (!snapped) {\n // Pointer tracking resumes 1:1 — drop the transition so it never lags.\n setSnapTransition(false);\n return;\n }\n\n // Arm the glide before writing the snapped layout this frame.\n setSnapTransition(true);\n const group = groupRef.current;\n const target = layoutFromOrdered(sizes, node.children);\n if (!group || layoutsMatch(layout, target)) {\n return;\n }\n snapping.current = true;\n group.setLayout(target);\n snapping.current = false;\n };\n\n const handleLayoutChanged = (layout: Layout): void => {\n if (!measured.current) {\n measured.current = true;\n return;\n }\n if (syncing.current) {\n return;\n }\n const boundary = activeBoundary.current;\n activeBoundary.current = null;\n setHighlight(null);\n setSnapTransition(false);\n // Belt over the disabled Group/Separator: a non-resizable row never commits\n // an adjustSplit, even if rrp reports a layout change for another reason.\n if (!resizableSplits) {\n return;\n }\n let weights = node.children.map((child) => layout[child.id] ?? child.weight ?? 1);\n // Re-snap the committed value so the model lands exactly on the grid (one undo\n // step), regardless of where the final frame left rrp.\n if (boundary !== null && effectiveSnap !== null && snapActive) {\n weights = snapSizes(weights, boundary, effectiveSnap).sizes;\n }\n const weightsChanged = weights.some(\n (weight, index) => Math.abs(weight - (node.children[index]?.weight ?? 1)) > WEIGHT_EPSILON,\n );\n\n if (!weightsChanged) {\n return;\n }\n\n dispatch({\n rowId: node.id,\n type: \"adjustSplit\",\n weights,\n });\n };\n\n return (\n <Group\n data-dashfoo=\"row\"\n disabled={!resizableSplits}\n elementRef={groupElement}\n groupRef={groupRef}\n key={node.id}\n onLayoutChange={snapActive ? handleLayoutChange : undefined}\n onLayoutChanged={handleLayoutChanged}\n orientation={orientation}\n style={groupStyle}\n >\n {node.children.map((child, index) => {\n const percent = ((child.weight ?? 1) / total) * 100;\n let min = child.min ? dimensionToSize(child.min) : undefined;\n if (min === undefined) {\n const minimum = descendantMinSize(child, node.orientation, tabsetMinSize);\n min = minimum === undefined ? undefined : `${minimum}px`;\n }\n const max = child.max ? dimensionToSize(child.max) : undefined;\n\n return (\n <Fragment key={child.id}>\n {/* The separator stays mounted when resizing is off — removing it\n would collapse the theme-sized gutter and reflow every panel. */}\n {index > 0 ? (\n <Separator\n data-dashfoo=\"splitter\"\n data-dashfoo-snapped={snappedBoundary === index - 1 ? \"true\" : undefined}\n disabled={!resizableSplits}\n onPointerDown={\n snapActive && resizableSplits\n ? () => {\n activeBoundary.current = index - 1;\n }\n : undefined\n }\n />\n ) : null}\n <Panel defaultSize={`${percent}%`} id={child.id} maxSize={max} minSize={min}>\n {child.type === \"row\" ? (\n <RowView node={child} renderTabset={renderTabset} />\n ) : (\n (renderTabset?.(child) ?? <TabsetView node={child} />)\n )}\n </Panel>\n </Fragment>\n );\n })}\n </Group>\n );\n};\n\nexport { RowView };\nexport type { RowViewProps };\n","\"use client\";\n\nimport type { Action, Dashfoo, FloatNode, Geometry, GlobalAttributes } from \"@dashfoo/core\";\nimport type {\n CSSProperties,\n FocusEvent as ReactFocusEvent,\n KeyboardEvent as ReactKeyboardEvent,\n PointerEvent as ReactPointerEvent,\n ReactNode,\n} from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { useLayout } from \"../hooks/layout-store\";\nimport type { ResizeEdges, Size } from \"../lib/float-geometry\";\nimport { clampToBounds, resizeRect } from \"../lib/float-geometry\";\n\nimport { DragProvider } from \"./drag-adapter\";\nimport { EDGE_BY_KEY, RESIZE_HANDLES } from \"./float-resize-handles\";\nimport { LayoutRoot } from \"./layout-root\";\nimport { RowView } from \"./row-view\";\nimport { DockIcon, FloatIcon, GripIcon, MinimizeIcon } from \"./tabset-icons\";\n\n// One floating panel: an absolutely-positioned overlay over the layout, dragged by\n// its title bar and resized by edge/corner handles, with the panel itself rendered\n// through a nested Layout.Root (drag-dock, float, and maximize switched off — a\n// float is select/close/rename plus the title-bar \"Dock back\" control). Drag and\n// resize update the DOM imperatively during the gesture and commit one `moveFloat`\n// on release, so a drag is a single undo step and never re-renders per pointer move.\n\n// The window title is the float's own name (\"Panel\", \"Panel 1\", …), set when it is\n// floated and editable via the title bar — never the active tab's name.\nconst floatTitle = (node: FloatNode): string => node.name ?? \"Panel\";\n\nconst titleBarStyle: CSSProperties = {\n alignItems: \"center\",\n display: \"flex\",\n flexShrink: 0,\n gap: \"0.375rem\",\n touchAction: \"none\",\n};\n\nconst titleStyle: CSSProperties = {\n flex: 1,\n minWidth: 0,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n};\n\nconst dockButtonStyle: CSSProperties = {\n alignItems: \"center\",\n cursor: \"pointer\",\n display: \"inline-flex\",\n flexShrink: 0,\n};\n\nconst bodyStyle: CSSProperties = { flex: 1, minHeight: 0, position: \"relative\" };\n\n// Approximate footprint of the minimized chip, used to keep it on screen while it\n// is dragged (its window rect is preserved in geometry for restore).\nconst CHIP_SIZE: Size = { height: 34, width: 168 };\n// Pointer travel (px) past which a press counts as a drag, not a tap.\nconst TAP_SLOP = 4;\n\ntype Gesture = {\n bounds: Size;\n edges: ResizeEdges | null; // null = move (no edges), else resize\n pointerId: number;\n start: Geometry;\n startX: number;\n startY: number;\n};\n\ntype TitleProps = { dispatch: (action: Action) => void; node: FloatNode };\n\n// Inline title editor — mirrors the tab-rename pattern: focus + select on mount,\n// a `done` ref so the unmount blur doesn't re-commit after a deliberate\n// Enter/Escape, and stopPropagation so clicking into it doesn't start a drag.\nconst FloatTitleEditor = ({\n dispatch,\n node,\n onDone,\n}: TitleProps & { onDone: () => void }): ReactNode => {\n const ref = useRef<HTMLInputElement | null>(null);\n const done = useRef(false);\n useEffect(() => {\n ref.current?.focus();\n ref.current?.select();\n }, []);\n\n const commit = (value: string): void => {\n const trimmed = value.trim();\n if (trimmed && trimmed !== floatTitle(node)) {\n dispatch({ floatId: node.id, name: trimmed, type: \"renameFloat\" });\n }\n onDone();\n };\n\n const handleKeyDown = (event: ReactKeyboardEvent<HTMLInputElement>): void => {\n if (event.key === \"Enter\") {\n done.current = true;\n commit(event.currentTarget.value);\n } else if (event.key === \"Escape\") {\n done.current = true;\n onDone();\n }\n };\n\n const handleBlur = (event: ReactFocusEvent<HTMLInputElement>): void => {\n if (done.current) {\n return;\n }\n done.current = true;\n commit(event.currentTarget.value);\n };\n\n return (\n <input\n aria-label={`Rename ${floatTitle(node)}`}\n data-dashfoo=\"float-rename\"\n defaultValue={floatTitle(node)}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n onPointerDown={(event) => event.stopPropagation()}\n ref={ref}\n style={titleStyle}\n type=\"text\"\n />\n );\n};\n\n// The window title: the float's name, double-click to rename. A static layout\n// (renamable=false) shows the name as plain, non-editable text.\nconst FloatTitle = ({\n dispatch,\n node,\n renamable,\n}: TitleProps & { renamable: boolean }): ReactNode => {\n const [editing, setEditing] = useState(false);\n if (renamable && editing) {\n return <FloatTitleEditor dispatch={dispatch} node={node} onDone={() => setEditing(false)} />;\n }\n return (\n <span\n data-dashfoo=\"float-title\"\n onDoubleClick={renamable ? () => setEditing(true) : undefined}\n style={titleStyle}\n title={renamable ? \"Double-click to rename\" : undefined}\n >\n {floatTitle(node)}\n </span>\n );\n};\n\ntype FloatPanelProps = {\n global: GlobalAttributes;\n node: FloatNode;\n onFocus: () => void;\n zIndex: number;\n};\n\nconst FloatPanel = ({ global, node, onFocus, zIndex }: FloatPanelProps): ReactNode => {\n const dispatch = useLayout((state) => state.dispatch);\n const closableTabs = useLayout((state) => state.closableTabs);\n const draggableTabs = useLayout((state) => state.draggableTabs);\n const editable = useLayout((state) => state.editable);\n const renamableTabs = useLayout((state) => state.renamableTabs);\n const resizableSplits = useLayout((state) => state.resizableSplits);\n const keepMounted = useLayout((state) => state.keepMounted);\n const renderTab = useLayout((state) => state.renderTab);\n const renderTabLabel = useLayout((state) => state.renderTabLabel);\n const renderTabsetToolbar = useLayout((state) => state.renderTabsetToolbar);\n const snap = useLayout((state) => state.snap);\n\n const panelRef = useRef<HTMLElement | null>(null);\n const gestureRef = useRef<Gesture | null>(null);\n const latestRef = useRef<Geometry>(node.geometry);\n const movedRef = useRef(false);\n const setPanel = (element: HTMLElement | null): void => {\n panelRef.current = element;\n };\n\n // Restore (un-minimize) is a structural edit, so a static layout cannot do it.\n const restore = (): void => {\n if (!editable) {\n return;\n }\n dispatch({ floatId: node.id, minimized: false, type: \"setFloatMinimized\" });\n };\n\n // One pointerdown handler for the title bar / chip (move) and the resize handles;\n // the moving edges ride the target's data-edge, so it can be assigned directly to\n // onPointerDown (no per-render closure that reads refs). Raise-to-front is wired\n // separately (onPointerDownCapture on the frame), so it still works for body and\n // tab clicks — and even while a static layout has move/resize switched off.\n const handlePointerDown = (event: ReactPointerEvent<HTMLElement>): void => {\n const panel = panelRef.current;\n // A static layout never moves or resizes a float — no gesture, no moveFloat.\n if (!panel || !editable) {\n return;\n }\n // A new press supersedes any prior gesture. Release a capture the prior one\n // may still hold (a gesture whose pointerup/cancel was missed) so it neither\n // strands its pointer nor blocks this press — without this, a stale gesture\n // from a different pointerId would make the float permanently unmovable\n // (each touch has its own pointerId; the move handler ignores the mismatch).\n const prior = gestureRef.current;\n if (prior && panel.hasPointerCapture?.(prior.pointerId)) {\n panel.releasePointerCapture(prior.pointerId);\n }\n movedRef.current = false;\n const edgeKey = event.currentTarget.dataset.edge;\n // While minimized the chip keeps its small footprint on screen; otherwise the\n // whole window rect is clamped against the viewport (the overlay).\n const parent = panel.offsetParent as HTMLElement | null;\n const gesture: Gesture = {\n bounds: { height: parent?.clientHeight ?? 0, width: parent?.clientWidth ?? 0 },\n edges: edgeKey ? (EDGE_BY_KEY.get(edgeKey) ?? null) : null,\n pointerId: event.pointerId,\n start: node.geometry,\n startX: event.clientX,\n startY: event.clientY,\n };\n gestureRef.current = gesture;\n latestRef.current = node.geometry;\n // A resize has no tap/double-click meaning, so capture the pointer up front: a\n // fast drag that outruns the small handle must keep routing move/up events to\n // this panel. Without capture the first move lands on the layout beneath, its\n // pointerup never reaches us, and the orphaned gesture resumed when the cursor\n // came back over the float. The title bar and chip instead defer capture to\n // the first real move so a tap or double-click can still reach the rename /\n // restore handlers.\n if (gesture.edges) {\n panel.setPointerCapture(event.pointerId);\n }\n };\n\n const handlePointerUp = (event: ReactPointerEvent): void => {\n const gesture = gestureRef.current;\n if (!gesture || event.pointerId !== gesture.pointerId) {\n return;\n }\n gestureRef.current = null;\n // Resize captures eagerly (even a no-move click holds it), so always release.\n // Optional call: jsdom (and other non-DOM hosts) may not implement the API.\n const panel = panelRef.current;\n if (panel?.hasPointerCapture?.(event.pointerId)) {\n panel.releasePointerCapture(event.pointerId);\n }\n // A tap (never moved past the slop) restores the chip, or is a no-op on the\n // title bar — leaving the click/double-click to reach the title. Only a real\n // drag commits the new rect.\n if (!movedRef.current) {\n if (node.minimized) {\n restore();\n }\n return;\n }\n dispatch({ floatId: node.id, geometry: latestRef.current, type: \"moveFloat\" });\n };\n\n const handlePointerMove = (event: ReactPointerEvent): void => {\n const gesture = gestureRef.current;\n const panel = panelRef.current;\n if (!gesture || !panel || event.pointerId !== gesture.pointerId) {\n return;\n }\n // No button down means the pointerup was missed (it landed on a non-capturing\n // element mid-drag); end the gesture instead of chasing the released cursor.\n if (event.buttons === 0) {\n handlePointerUp(event);\n return;\n }\n const dx = event.clientX - gesture.startX;\n const dy = event.clientY - gesture.startY;\n if (!movedRef.current) {\n // Below the slop it is still a (possible) tap — don't move or capture yet.\n if (Math.hypot(dx, dy) <= TAP_SLOP) {\n return;\n }\n movedRef.current = true;\n // Resize already captured at pointerdown; the move gesture captures here.\n if (!gesture.edges) {\n panel.setPointerCapture(gesture.pointerId);\n }\n }\n const next = gesture.edges\n ? resizeRect(gesture.start, gesture.edges, dx, dy)\n : clampToBounds(\n { ...gesture.start, left: gesture.start.left + dx, top: gesture.start.top + dy },\n gesture.bounds,\n node.minimized ? CHIP_SIZE : undefined,\n );\n // next always carries the window's own width/height (the chip's footprint is\n // only used to clamp position), so restore reopens at the saved size.\n latestRef.current = next;\n panel.style.left = `${next.left}px`;\n panel.style.top = `${next.top}px`;\n // The chip's size is CSS-driven; only the window writes its own dimensions.\n if (!node.minimized) {\n panel.style.width = `${next.width}px`;\n panel.style.height = `${next.height}px`;\n }\n };\n\n // pointercancel means the OS took the pointer (a system gesture, a scroll that\n // won the touch). That is an abort, not a release: revert the imperative DOM to\n // where the drag started and never commit a half-finished rect. handlePointerUp\n // (a real release) is what commits.\n const handlePointerCancel = (event: ReactPointerEvent): void => {\n const gesture = gestureRef.current;\n const panel = panelRef.current;\n if (!gesture || !panel || event.pointerId !== gesture.pointerId) {\n return;\n }\n gestureRef.current = null;\n if (panel.hasPointerCapture?.(event.pointerId)) {\n panel.releasePointerCapture(event.pointerId);\n }\n if (!movedRef.current) {\n return;\n }\n panel.style.left = `${gesture.start.left}px`;\n panel.style.top = `${gesture.start.top}px`;\n if (!node.minimized) {\n panel.style.width = `${gesture.start.width}px`;\n panel.style.height = `${gesture.start.height}px`;\n }\n };\n\n if (node.minimized) {\n return (\n <button\n aria-label={`Restore ${floatTitle(node)} panel`}\n data-dashfoo=\"float-chip\"\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n restore();\n }\n }}\n onPointerCancel={handlePointerCancel}\n onPointerDown={handlePointerDown}\n onPointerDownCapture={onFocus}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n ref={setPanel}\n style={{\n left: node.geometry.left,\n pointerEvents: \"auto\",\n position: \"absolute\",\n top: node.geometry.top,\n zIndex,\n }}\n title={floatTitle(node)}\n type=\"button\"\n >\n <FloatIcon />\n <span data-dashfoo=\"float-chip-label\">{floatTitle(node)}</span>\n </button>\n );\n }\n\n const floatModel: Dashfoo = { global, layout: node.layout, version: 1 };\n\n return (\n <div\n data-dashfoo=\"float\"\n // Capture so a click anywhere in the float — body, tab, or chrome — raises it\n // above the others before any child handler runs, even when a static layout\n // has move/resize off.\n onPointerCancel={handlePointerCancel}\n onPointerDownCapture={onFocus}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n ref={setPanel}\n style={{\n height: node.geometry.height,\n left: node.geometry.left,\n // The overlay is pointer-events:none so it never blocks the docked layout;\n // each float opts back in.\n pointerEvents: \"auto\",\n position: \"absolute\",\n top: node.geometry.top,\n width: node.geometry.width,\n zIndex,\n }}\n >\n <div\n data-dashfoo=\"float-titlebar\"\n onPointerDown={handlePointerDown}\n // A static layout's title bar doesn't drag, so don't dangle a grab cursor.\n style={editable ? titleBarStyle : { ...titleBarStyle, cursor: \"default\" }}\n >\n <span aria-hidden=\"true\" data-dashfoo=\"float-grip\">\n <GripIcon />\n </span>\n <FloatTitle dispatch={dispatch} node={node} renamable={editable} />\n {editable && (\n <>\n <button\n aria-label=\"Minimize panel\"\n data-dashfoo=\"float-minimize\"\n onClick={() =>\n dispatch({ floatId: node.id, minimized: true, type: \"setFloatMinimized\" })\n }\n onPointerDown={(event) => event.stopPropagation()}\n style={dockButtonStyle}\n title=\"Minimize panel\"\n type=\"button\"\n >\n <MinimizeIcon />\n </button>\n <button\n aria-label=\"Dock panel back into the main layout\"\n data-dashfoo=\"float-dock\"\n onClick={() => dispatch({ floatId: node.id, type: \"dockFloat\" })}\n onPointerDown={(event) => event.stopPropagation()}\n style={dockButtonStyle}\n title=\"Dock panel back\"\n type=\"button\"\n >\n <DockIcon />\n </button>\n </>\n )}\n </div>\n <div data-dashfoo=\"float-body\" style={bodyStyle}>\n <LayoutRoot\n closableTabs={closableTabs}\n dispatch={dispatch}\n draggableTabs={draggableTabs}\n draggableTabsets={false}\n editable={editable}\n floatable={false}\n keepMounted={keepMounted}\n maximizable={false}\n model={floatModel}\n renamableTabs={renamableTabs}\n renderTab={renderTab}\n renderTabLabel={renderTabLabel}\n renderTabsetToolbar={renderTabsetToolbar}\n resizableSplits={resizableSplits}\n snap={snap ?? undefined}\n >\n {/* Its own drag layer, joined to the shared manager above, so tabs drag\n between this float and the main layout (and other floats). */}\n <DragProvider>\n <RowView node={node.layout} />\n </DragProvider>\n </LayoutRoot>\n </div>\n {editable &&\n RESIZE_HANDLES.map((handle) => (\n <div\n data-dashfoo=\"float-resize\"\n data-edge={handle.key}\n key={handle.key}\n onPointerDown={handlePointerDown}\n style={{ position: \"absolute\", touchAction: \"none\", zIndex: 1, ...handle.style }}\n />\n ))}\n </div>\n );\n};\n\nexport { FloatPanel };\nexport type { FloatPanelProps };\n","\"use client\";\n\nimport type { FloatNode, GlobalAttributes } from \"@dashfoo/core\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { useState } from \"react\";\n\nimport { FloatLayerContext } from \"./float-context\";\nimport { FloatPanel } from \"./float-panel\";\n\n// The floating-panel layer: the in-app counterpart of the drag layer. It renders\n// `model.floats` as draggable, resizable overlays over the docked layout, in the\n// SAME React tree — so context, events, and styling just work (no separate window,\n// no portal). Wrap the layout's content with <Layout.FloatLayer> and it drops an\n// absolutely-positioned overlay alongside the rows.\n\nconst overlayStyle: CSSProperties = {\n inset: 0,\n // Never block the docked layout underneath; each float opts pointer events back\n // in, so empty overlay space stays click-through. Fixed to the viewport so a\n // float can be dragged anywhere on the page, not just within the layout box.\n pointerEvents: \"none\",\n position: \"fixed\",\n // An explicit layer so a drop indicator aimed at a docked tabset (rendered at\n // z:auto) stays *behind* the floats that overlap it; a float's own indicator\n // opts back above this layer. See DockIndicator in drag-overlays.tsx.\n zIndex: 1,\n};\n\nconst FloatOverlay = ({\n floats,\n global,\n}: {\n floats: Array<FloatNode>;\n global: GlobalAttributes;\n}): ReactNode => {\n // The clicked float comes to the front; the rest share the lower band, stacking\n // by DOM (model) order.\n const [topId, setTopId] = useState<string | null>(null);\n if (floats.length === 0) {\n return null;\n }\n return (\n <div data-dashfoo=\"float-overlay\" style={overlayStyle}>\n {floats.map((node) => (\n <FloatPanel\n global={global}\n key={node.id}\n node={node}\n onFocus={() => setTopId(node.id)}\n zIndex={node.id === topId ? 2 : 1}\n />\n ))}\n </div>\n );\n};\n\ntype FloatLayerProps = {\n children: ReactNode;\n floats: Array<FloatNode>;\n global: GlobalAttributes;\n};\n\nconst FloatLayer = ({ children, floats, global }: FloatLayerProps): ReactNode => (\n <FloatLayerContext.Provider value>\n {children}\n <FloatOverlay floats={floats} global={global} />\n </FloatLayerContext.Provider>\n);\n\nexport { FloatLayer };\nexport type { FloatLayerProps };\n","\"use client\";\n\nimport { DragProvider } from \"./drag-adapter\";\nimport { FloatLayer } from \"./float-layer\";\nimport { LayoutRoot } from \"./layout-root\";\nimport { RowView } from \"./row-view\";\nimport { TabsetView } from \"./tabset/tabset-view\";\n\n// Compound namespace for hand-built layouts, same pattern as Panel/Tabset:\n// Root provides the layout store, DragLayer opts the tree into drag-dock,\n// Rows renders the split tree, and Tabset is the stock tabset composition for\n// leaves that don't need custom chrome. FloatLayer opts the layout into floating\n// panels: wrap the tree's content with it (passing `floats` + `global`) and it\n// renders each floated panel as a draggable, resizable overlay over the rows.\nconst Layout = {\n DragLayer: DragProvider,\n FloatLayer,\n Root: LayoutRoot,\n Rows: RowView,\n Tabset: TabsetView,\n} as const;\n\nexport { Layout };\nexport type { DragProviderProps as LayoutDragLayerProps } from \"./drag-adapter\";\nexport type { FloatLayerProps as LayoutFloatLayerProps } from \"./float-layer\";\nexport type { LayoutRootProps } from \"./layout-root\";\nexport type { RowViewProps as LayoutRowsProps } from \"./row-view\";\nexport type { TabsetViewProps as LayoutTabsetProps } from \"./tabset/tabset-view\";\n","\"use client\";\n\nimport type {\n Action,\n Dashfoo,\n DockLocation,\n Orientation,\n SnapConfig,\n TabNode,\n TabsetNode,\n} from \"@dashfoo/core\";\nimport { findTabset, stackModel } from \"@dashfoo/core\";\nimport type { ComponentType, ReactNode } from \"react\";\nimport { forwardRef, useCallback, useContext, useImperativeHandle, useMemo, useRef } from \"react\";\n\nimport { SharedDragManagerContext } from \"../hooks/drag-hooks\";\nimport type { PersistConfig, StorageAdapter } from \"../hooks/persistence\";\nimport { localStorageAdapter, usePersistence } from \"../hooks/persistence\";\nimport { useContainerWidth } from \"../hooks/responsive\";\nimport { useDashfooStore } from \"../hooks/store\";\n\nimport { DashfooDragProvider } from \"./drag-root\";\nimport { Layout } from \"./layout\";\n\nconst DEFAULT_PERSIST_DEBOUNCE_MS = 300;\n\n// `persist` accepts a bare localStorage key or a full target (custom storage,\n// debounce). Controlled mode (a `model` prop, no `defaultModel`) skips it —\n// persistence implies the library owns the state.\ntype PersistInput = string | { debounceMs?: number; key: string; storage?: StorageAdapter };\n\nconst resolvePersist = (\n persist: PersistInput | undefined,\n hasDefaultModel: boolean,\n): PersistConfig | null => {\n if (persist === undefined || !hasDefaultModel) {\n return null;\n }\n if (typeof persist === \"string\") {\n return { debounceMs: DEFAULT_PERSIST_DEBOUNCE_MS, key: persist, storage: localStorageAdapter };\n }\n return {\n debounceMs: persist.debounceMs ?? DEFAULT_PERSIST_DEBOUNCE_MS,\n key: persist.key,\n storage: persist.storage ?? localStorageAdapter,\n };\n};\n\ntype TabComponent = ComponentType<{ node: TabNode }>;\n\n// Component names already warned about, so the dev warning fires at most once each.\nconst warnedComponents = new Set<string>();\n\n// Imperative API exposed via ref — lets a host drive the layout from a toolbar,\n// command palette, or keyboard shortcuts without rebuilding the store's plumbing.\ntype DashfooHandle = {\n addTab: (\n tab: TabNode,\n target: { index?: number; location?: DockLocation; targetId: string },\n ) => void;\n canRedo: () => boolean;\n canUndo: () => boolean;\n closeTab: (tabId: string) => void;\n dispatch: (action: Action) => void;\n // Dock a floating panel back into the main layout.\n dockFloat: (floatId: string) => void;\n // Float a tab out into a movable, resizable panel.\n floatTab: (tabId: string) => void;\n getModel: () => Dashfoo;\n maximizeTabset: (tabsetId: string | null) => void;\n redo: () => void;\n renameTab: (tabId: string, name: string) => void;\n // Reset to the original defaultModel, clearing undo history and any persisted\n // copy. No-op in controlled mode (the host owns the model).\n resetLayout: () => void;\n selectTab: (tabsetId: string, index: number) => void;\n undo: () => void;\n};\n\ntype DashfooLayoutProps = {\n closableTabs?: boolean;\n components?: Record<string, TabComponent>;\n defaultModel?: Dashfoo;\n draggableTabs?: boolean;\n draggableTabsets?: boolean;\n // false renders a static dashboard: no drag, close, rename, or resize. Tab\n // selection, maximize, and the imperative ref API keep working.\n editable?: boolean;\n factory?: (tab: TabNode) => ReactNode;\n // Show a per-tabset control that floats the panel into a movable, resizable\n // overlay (and render any floating panels). Off by default — opt in. Floating\n // adds the panel to the model's `floats`.\n floatable?: boolean;\n keepMounted?: boolean;\n maximizable?: boolean;\n model?: Dashfoo;\n onAction?: (action: Action) => Action | null;\n onActiveTabsetChange?: (tabsetId: string | undefined) => void;\n onMaximizedTabsetChange?: (tabsetId: string | undefined) => void;\n onModelChange?: (model: Dashfoo, action?: Action) => void;\n persist?: PersistInput;\n renamableTabs?: boolean;\n renderTabLabel?: (tab: TabNode) => ReactNode;\n renderTabsetToolbar?: (tabset: TabsetNode) => ReactNode;\n // At or below `maxWidth` (the layout's own container width, not the viewport)\n // the layout renders one stacked column and locks drag and resize. The stack is\n // a view-only projection, so widening back is lossless and never remounts.\n // `orientation` defaults to \"column\".\n resizableSplits?: boolean;\n responsive?: { maxWidth: number; orientation?: Orientation };\n // Magnetic snap for split resize: the dragged boundary pulls to multiples of\n // `step` (percent of the group) within `threshold`. A row may override this via\n // its own `snap` attribute. Off when omitted; locked off in compact mode.\n snap?: SnapConfig;\n};\n\n// The batteries-included component: owns the store (controlled or uncontrolled),\n// resolves tab content via a components registry or a factory, and assembles the\n// same Layout/Tabset primitives a hand-built layout would use.\n// forwardRef (not the React 19 ref-as-prop) keeps the React 18 peer working.\nconst DashfooLayout = forwardRef<DashfooHandle, DashfooLayoutProps>((props, ref): ReactNode => {\n const {\n closableTabs = true,\n components,\n defaultModel,\n draggableTabs = true,\n draggableTabsets = true,\n editable = true,\n factory,\n floatable = false,\n keepMounted = false,\n maximizable = true,\n model,\n onAction,\n onActiveTabsetChange,\n onMaximizedTabsetChange,\n onModelChange,\n persist,\n renamableTabs = true,\n renderTabLabel,\n renderTabsetToolbar,\n resizableSplits = true,\n responsive,\n snap,\n } = props;\n\n const persistConfig = useMemo(\n () => resolvePersist(persist, defaultModel !== undefined),\n [persist, defaultModel],\n );\n const persistence = usePersistence(persistConfig, defaultModel);\n\n // The save side of persistence rides onModelChange; the consumer's own handler\n // still fires after it.\n const handleModelChange = useCallback(\n (next: Dashfoo, action?: Action): void => {\n persistence.save(next);\n onModelChange?.(next, action);\n },\n [onModelChange, persistence],\n );\n\n const store = useDashfooStore({\n defaultModel: persistence.initialModel ?? defaultModel,\n model,\n onAction,\n onActiveTabsetChange,\n onMaximizedTabsetChange,\n onModelChange: handleModelChange,\n });\n\n // A host can wrap the layout in DashfooDragProvider to share a manager with\n // external sources; if so, reuse it (the floats join that shared manager too).\n const hasSharedManager = useContext(SharedDragManagerContext) !== null;\n\n useImperativeHandle(\n ref,\n () => ({\n addTab: (tab, target) =>\n store.dispatch({\n index: target.index,\n location: target.location ?? \"center\",\n tab,\n targetId: target.targetId,\n type: \"addNode\",\n }),\n canRedo: store.canRedo,\n canUndo: store.canUndo,\n closeTab: (tabId) => store.dispatch({ tabId, type: \"deleteTab\" }),\n dispatch: store.dispatch,\n dockFloat: (floatId) => store.dispatch({ floatId, type: \"dockFloat\" }),\n floatTab: (tabId) => store.dispatch({ tabId, type: \"floatTab\" }),\n getModel: () => store.model,\n maximizeTabset: (tabsetId) => store.dispatch({ tabsetId, type: \"setMaximizedTabset\" }),\n redo: store.redo,\n renameTab: (tabId, name) => store.dispatch({ name, tabId, type: \"renameTab\" }),\n resetLayout: () => {\n persistence.clear();\n if (defaultModel !== undefined) {\n store.setModel(defaultModel);\n }\n },\n selectTab: (tabsetId, index) => store.dispatch({ index, tabsetId, type: \"selectTab\" }),\n undo: store.undo,\n }),\n [defaultModel, persistence, store],\n );\n\n const renderTab = useCallback(\n (tab: TabNode): ReactNode => {\n if (factory) {\n return factory(tab);\n }\n const Component = components?.[tab.component];\n if (!Component) {\n if (components && !warnedComponents.has(tab.component)) {\n warnedComponents.add(tab.component);\n // A tab whose component is not registered renders nothing — surface it\n // once so the misconfiguration is not silent.\n // oxlint-disable-next-line no-console\n console.warn(`[dashfoo] no component registered for \"${tab.component}\"`);\n }\n return null;\n }\n return <Component node={tab} />;\n },\n [components, factory],\n );\n\n // While compact, render a stacked projection; the canonical store.model is\n // untouched (ids survive stackModel, so tap-to-select still routes), so widening\n // back is lossless.\n const [containerRef, width] = useContainerWidth();\n const isCompact = responsive !== undefined && width <= responsive.maxWidth;\n const view = useMemo(\n () => (isCompact ? stackModel(store.model, responsive?.orientation) : store.model),\n [isCompact, responsive?.orientation, store.model],\n );\n\n // rrp auto-fires onLayoutChanged as it re-measures the stacked structure, which\n // would commit an adjustSplit and corrupt the canonical model. The lock flags\n // can't gate it — they reach the resize adapter via the layout store one commit\n // late, so resizableSplits is stale-true during the swap. Gate at the dispatch\n // boundary instead: a stable dispatch reads isCompact from a ref written during\n // render (current before rrp's onLayoutChanged, which can fire in a child effect\n // ahead of this component's effects).\n const isCompactRef = useRef(isCompact);\n isCompactRef.current = isCompact;\n const dispatch = useCallback(\n (action: Action): void => {\n if (isCompactRef.current && action.type === \"adjustSplit\") {\n return;\n }\n store.dispatch(action);\n },\n [store],\n );\n\n // A maximized tabset fills the frame on its own; otherwise the row tree renders.\n const maximized = view.maximizedTabsetId ? findTabset(view, view.maximizedTabsetId) : undefined;\n\n // Floating panels overlay the layout and render from the canonical model rather\n // than the (possibly stacked) compact view.\n const tree = (\n <Layout.FloatLayer floats={store.model.floats ?? []} global={store.model.global}>\n <Layout.DragLayer>\n {maximized ? <Layout.Tabset node={maximized} /> : <Layout.Rows node={view.layout} />}\n </Layout.DragLayer>\n </Layout.FloatLayer>\n );\n\n return (\n <Layout.Root\n closableTabs={closableTabs}\n dispatch={dispatch}\n draggableTabs={isCompact ? false : draggableTabs}\n draggableTabsets={isCompact ? false : draggableTabsets}\n editable={editable}\n floatable={isCompact ? false : floatable}\n keepMounted={keepMounted}\n maximizable={maximizable}\n model={view}\n renamableTabs={renamableTabs}\n renderTab={renderTab}\n renderTabLabel={renderTabLabel}\n renderTabsetToolbar={renderTabsetToolbar}\n resizableSplits={isCompact ? false : resizableSplits}\n rootRef={containerRef}\n snap={snap}\n >\n {/* Share one drag manager across the main layout and every float, so a tab\n can be dragged between them — unless a host DashfooDragProvider already\n provides one (which also lets external sources participate). */}\n {hasSharedManager ? tree : <DashfooDragProvider>{tree}</DashfooDragProvider>}\n </Layout.Root>\n );\n});\n\nDashfooLayout.displayName = \"DashfooLayout\";\n\nexport { DashfooLayout };\nexport type { DashfooHandle, DashfooLayoutProps, TabComponent };\n","\"use client\";\n\nimport type { ComponentProps, ReactNode } from \"react\";\n\ntype PanelRootProps = ComponentProps<\"div\">;\ntype PanelHeaderProps = ComponentProps<\"div\">;\ntype PanelBodyProps = ComponentProps<\"div\">;\ntype PanelTitleProps = ComponentProps<\"span\">;\ntype PanelIconProps = ComponentProps<\"span\">;\ntype PanelBadgeProps = ComponentProps<\"span\">;\n\nconst PanelRoot = (props: PanelRootProps): ReactNode => <div {...props} data-dashfoo=\"panel\" />;\nconst PanelHeader = (props: PanelHeaderProps): ReactNode => (\n <div {...props} data-dashfoo=\"panel-header\" />\n);\nconst PanelBody = (props: PanelBodyProps): ReactNode => (\n <div {...props} data-dashfoo=\"panel-body\" />\n);\nconst PanelTitle = (props: PanelTitleProps): ReactNode => (\n <span {...props} data-dashfoo=\"panel-title\" />\n);\nconst PanelIcon = (props: PanelIconProps): ReactNode => (\n <span {...props} data-dashfoo=\"panel-icon\" />\n);\nconst PanelBadge = (props: PanelBadgeProps): ReactNode => (\n <span {...props} data-dashfoo=\"panel-badge\" />\n);\n\nconst Panel = {\n Badge: PanelBadge,\n Body: PanelBody,\n Header: PanelHeader,\n Icon: PanelIcon,\n Root: PanelRoot,\n Title: PanelTitle,\n} as const;\n\nexport { Panel };\nexport type {\n PanelBadgeProps,\n PanelBodyProps,\n PanelHeaderProps,\n PanelIconProps,\n PanelRootProps,\n PanelTitleProps,\n};\n","\"use client\";\n\nimport { TabsetContent } from \"./tabset-content\";\nimport { TabsetOverflowMenu } from \"./tabset-overflow\";\nimport { TabsetRoot } from \"./tabset-root\";\nimport { TabsetTab, TabsetTrigger } from \"./tabset-tab\";\nimport { TabsetCloseButton, TabsetRenameInput } from \"./tabset-tab-controls\";\nimport { TabsetTablist, TabsetTabStrip } from \"./tabset-tablist\";\nimport {\n TabsetFloatButton,\n TabsetGrip,\n TabsetMaximizeButton,\n TabsetToolbar,\n} from \"./tabset-toolbar\";\n\n// Compound namespace, same pattern as Panel: users compose the parts freely and\n// they coordinate through the scoped store Tabset.Root provides.\nconst Tabset = {\n CloseButton: TabsetCloseButton,\n Content: TabsetContent,\n FloatButton: TabsetFloatButton,\n Grip: TabsetGrip,\n MaximizeButton: TabsetMaximizeButton,\n OverflowMenu: TabsetOverflowMenu,\n RenameInput: TabsetRenameInput,\n Root: TabsetRoot,\n Tab: TabsetTab,\n Tablist: TabsetTablist,\n TabStrip: TabsetTabStrip,\n Toolbar: TabsetToolbar,\n Trigger: TabsetTrigger,\n} as const;\n\nexport { Tabset };\nexport type { TabsetContentProps } from \"./tabset-content\";\nexport type { TabsetRootProps } from \"./tabset-root\";\nexport type { TabsetTabProps, TabsetTriggerProps } from \"./tabset-tab\";\nexport type { TabsetCloseButtonProps, TabsetRenameInputProps } from \"./tabset-tab-controls\";\nexport type { TabsetTablistProps, TabsetTabStripProps } from \"./tabset-tablist\";\nexport type {\n TabsetFloatButtonProps,\n TabsetGripProps,\n TabsetMaximizeButtonProps,\n TabsetToolbarProps,\n} from \"./tabset-toolbar\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["Panel"],"sources":["../src/lib/topmost-collision.ts","../src/hooks/drag-hooks.tsx","../src/hooks/persistence.ts","../src/hooks/responsive.ts","../src/hooks/store.ts","../src/lib/tab-insertion.ts","../src/components/drag-overlays.tsx","../src/components/drag-root.tsx","../src/hooks/layout-store.ts","../src/lib/warn-once.ts","../src/components/drag-adapter.tsx","../src/components/float-context.ts","../src/lib/float-geometry.ts","../src/components/float-resize-handles.ts","../src/components/layout-root.tsx","../src/lib/tab-ids.ts","../src/components/tabset/tabset-store.ts","../src/components/tabset/tabset-content.tsx","../src/components/tab-overflow.tsx","../src/components/tabset/tabset-overflow.tsx","../src/hooks/use-tab-overflow.ts","../src/lib/tab-selection.ts","../src/components/tabset/tabset-root.tsx","../src/lib/merge-refs.ts","../src/components/tabset/tabset-tab.tsx","../src/components/tabset-icons.tsx","../src/components/tabset/tabset-tab-controls.tsx","../src/components/tabset/tabset-tablist.tsx","../src/components/tabset/tabset-toolbar.tsx","../src/components/tabset/tabset-view.tsx","../src/components/row-view.tsx","../src/components/float-panel.tsx","../src/components/float-layer.tsx","../src/components/layout.tsx","../src/components/dashfoo-layout.tsx","../src/components/panel.tsx","../src/components/tabset/tabset.ts"],"sourcesContent":["import type { Collision, CollisionDetector, UniqueIdentifier } from \"@dnd-kit/abstract\";\nimport { CollisionPriority, CollisionType } from \"@dnd-kit/abstract\";\n\n// The collision detector behind every tabset droppable. dnd-kit's built-in\n// detectors are pure rect geometry with no notion of paint order, but docked\n// tabsets tile while floats overlay them — a tabset's rect can contain a point\n// that is actually over a float on top of it. elementFromPoint returns the\n// occluding element, so an occluded tabset's detector returns null and it never\n// becomes the drop target or shows a stale indicator. The drag overlays\n// (preview, indicator) are pointer-events:none, so they're ignored.\n//\n// Never reads droppable.shape: shapes ride a throttled PositionObserver, while\n// the live DOM answer is always current (auto-scroll, float moves mid-drag).\n\n// What the detector actually reads — a structural supertype of dnd-kit's\n// CollisionDetectorInput, so the same function serves dnd-kit at runtime and\n// plain objects in unit tests. The abstract Droppable carries no element; a\n// droppable without one can't be hit.\ntype TopmostDetectorInput = {\n dragOperation: { position: { current: { x: number; y: number } } };\n droppable: { element?: Element; id: UniqueIdentifier };\n};\n\ntype TopmostDetector = (input: TopmostDetectorInput) => Collision | null;\n\n// One elementFromPoint per collision pass, not per droppable: a pass runs\n// synchronously over every droppable at one pointer position, so the lookup is\n// cached by exact coordinates and dropped on the next microtask — before any\n// later pass (whose DOM may have scrolled under a stationary pointer) can read\n// a stale answer.\nconst createTopmostPointerIntersection = (\n topElementAt: (x: number, y: number) => Element | null = (x, y) =>\n document.elementFromPoint(x, y),\n): TopmostDetector => {\n let cached: { top: Element | null; x: number; y: number } | null = null;\n const topAt = (x: number, y: number): Element | null => {\n if (cached && cached.x === x && cached.y === y) {\n return cached.top;\n }\n const top = topElementAt(x, y);\n cached = { top, x, y };\n queueMicrotask(() => {\n cached = null;\n });\n return top;\n };\n\n return ({ dragOperation, droppable }) => {\n const { element } = droppable;\n if (!element) {\n return null;\n }\n const point = dragOperation.position.current;\n const top = topAt(point.x, point.y);\n if (!top || !element.contains(top)) {\n return null;\n }\n // At most one non-nested droppable contains the topmost element; when\n // droppables nest (a layout inside a tab), DOM depth makes the innermost\n // win deterministically.\n let depth = 0;\n for (let node: Element | null = element; node; node = node.parentElement) {\n depth += 1;\n }\n return {\n id: droppable.id,\n priority: CollisionPriority.High,\n type: CollisionType.PointerIntersection,\n value: depth,\n };\n };\n};\n\nconst topmostPointerIntersection: CollisionDetector = createTopmostPointerIntersection();\n\nexport { createTopmostPointerIntersection, topmostPointerIntersection };\nexport type { TopmostDetectorInput };\n","\"use client\";\n\nimport type { DragSubject, DropIntent, TabNode } from \"@dashfoo/core\";\nimport {\n Accessibility,\n Draggable,\n DragDropManager,\n Droppable,\n Feedback,\n PointerSensor,\n} from \"@dnd-kit/dom\";\nimport type { Context } from \"react\";\nimport { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef } from \"react\";\nimport type { StoreApi } from \"zustand\";\nimport { createStore, useStore } from \"zustand\";\n\nimport { topmostPointerIntersection } from \"../lib/topmost-collision\";\n\n// Shared drag contexts + the draggable/droppable hooks. Lives apart from\n// drag-adapter.tsx so the contexts can be owned here without a circular import:\n// drag-adapter imports these for DragProvider and re-exports the hooks, and this\n// module never reaches back into drag-adapter.\n\nconst INTERACTIVE_SELECTOR = `\n input:not([disabled]),\n select:not([disabled]),\n textarea:not([disabled]),\n button:not([disabled]),\n a[href],\n [contenteditable]:not([contenteditable=\"false\"])\n`;\n\n// The sensor's default preventActivation vetoes any pointerdown whose target is\n// an element child of the draggable: closest() walks up to the trigger button\n// itself and calls it \"interactive\". Plain-text labels dodge that (text nodes\n// are not elements), but custom labels render elements inside the trigger and\n// would silently lose dragging. Allow the draggable itself as the handle while\n// still refusing genuinely interactive children nested in a label.\nconst preventActivation = (event: PointerEvent, source: Draggable): boolean => {\n const { target } = event;\n if (!(target instanceof Element)) {\n return false;\n }\n const interactive = target.closest(INTERACTIVE_SELECTOR);\n return interactive !== null && interactive !== source.element;\n};\n\n// Plugins drop the screen-reader announcer (it stamps ARIA that is invalid on\n// role=tab) and reconfigure Feedback: it runs in overlay mode only — the chip\n// element is handed to its public `overlay` accessor (see DragPreviewOverlay),\n// so the source element is never promoted or placeholder-cloned — with the drop\n// animation off, since drops must settle immediately and new drags are ignored\n// while one animates. Sensors keep only a configured PointerSensor — the\n// KeyboardSensor's nudge model double-binds the arrow keys the tab strip\n// already uses for roving-tabindex navigation, so keyboard docking needs its\n// own interaction design rather than that sensor.\nconst createDragManager = (): DragDropManager =>\n new DragDropManager({\n plugins: (defaults) => [\n ...defaults.filter((plugin) => plugin !== Accessibility && plugin !== Feedback),\n Feedback.configure({ dropAnimation: null }),\n ],\n sensors: () => [PointerSensor.configure({ preventActivation })],\n });\n\ntype DragContextValue = {\n // Identifies the owning DragProvider: droppables carry it in `data` so each\n // layer can claim only its own targets from the manager-global winner.\n layerId: string;\n manager: DragDropManager;\n};\n\nconst DragContext = createContext<DragContextValue | null>(null);\n\n// A manager owned by DashfooDragProvider, shared between a layout and external\n// tab sources outside it so drags can cross that boundary. The annotation keeps\n// declaration emit from expanding @dnd-kit's non-exported generic defaults.\nconst SharedDragManagerContext: Context<DragDropManager | null> =\n createContext<DragDropManager | null>(null);\n\n// The live drag subject and drop intent ride a scoped zustand store instead of a\n// context value, so a drag start/end re-renders only the parts that select the\n// subject — never the provider subtree. The store is owned by the nearest\n// DashfooDragProvider when one exists (so anything under it, layout or not, can\n// observe drags) and by the DragLayer otherwise; the dragDockMachine\n// subscription feeds it. Intent updates are value-guarded by the adapter\n// (sameDropIntent) so OVER pulses only notify when the resolved drop changes.\n// intentOwner disambiguates layouts sharing one store: each layer claims only\n// its own droppables from the manager-global winner, so a null intent from one\n// layer must not erase the live intent the owning layer resolved — the write\n// order between layers on a winner handoff is unspecified.\ntype DragSubjectState = {\n intent: DropIntent | null;\n intentOwner: string | null;\n subject: DragSubject | null;\n};\n\ntype DragSubjectStore = StoreApi<DragSubjectState>;\n\nconst createDragSubjectStore = (): DragSubjectStore =>\n createStore<DragSubjectState>(() => ({ intent: null, intentOwner: null, subject: null }));\n\n// Whether two intents resolve the same drop. Intents are rebuilt on every\n// pointer move, so identity alone would notify subscribers on each pulse.\nconst sameDropIntent = (a: DropIntent | null, b: DropIntent | null): boolean =>\n a === b ||\n (a !== null &&\n b !== null &&\n a.index === b.index &&\n a.location === b.location &&\n a.targetId === b.targetId);\n\n// Whether two subjects describe the same drag. Layouts sharing a manager each\n// build their own subject object for the same drag, so identity alone would\n// write twice per drag start.\nconst sameDragSubject = (a: DragSubject | null, b: DragSubject | null): boolean =>\n a === b || (a !== null && b !== null && a.id === b.id && a.kind === b.kind);\n\n// Stable empty store so useDragSubject keeps an unconditional hook order (and\n// returns null) outside a DragLayer — parts must keep working drag-free.\nconst nullSubjectStore = createDragSubjectStore();\n\nconst DragSubjectStoreContext: Context<DragSubjectStore | null> =\n createContext<DragSubjectStore | null>(null);\n\n// Tracks a Draggable's element across renders without rebuilding it. Returned by\n// the draggable hooks; their effects own the Draggable's lifecycle.\ntype DraggableHandle = {\n draggableRef: { current: Draggable | null };\n elementRef: { current: Element | null };\n ref: (element: Element | null) => void;\n};\n\nconst useDraggableHandle = (): DraggableHandle => {\n const elementRef = useRef<Element | null>(null);\n const draggableRef = useRef<Draggable | null>(null);\n const ref = useCallback((element: Element | null): void => {\n elementRef.current = element;\n if (draggableRef.current) {\n draggableRef.current.element = element ?? undefined;\n }\n }, []);\n return { draggableRef, elementRef, ref };\n};\n\n// What a draggable carries: the dnd-kit id and the stable data (drag kind +\n// tabset id), both derived from identity. The chip label is passed separately so\n// it never sits in the construction effect's deps. data must be referentially\n// stable (the wrappers memoize it) so the construction effect tracks it without\n// rebuilding on every render.\ntype DraggableDescriptor = { data: Record<string, unknown>; id: string };\n\n// Owns the full Draggable lifecycle shared by the tab and tabset hooks. The\n// construction effect is keyed on identity only (manager, id, disabled, the\n// stable data) — never on the chip label — so a tab click or rename can't tear\n// down and rebuild the live instance. The label is folded into the live data by\n// a separate effect, since data is only read at drag start; both effects fire in\n// the same mount commit, so the label is current well before any pointer drag.\n// `Draggable.data` is a public accessor in @dnd-kit/abstract, so the in-place\n// update is type-safe.\nconst useDraggableEntity = (\n descriptor: DraggableDescriptor,\n disabled: boolean,\n label: string,\n): { ref: (element: Element | null) => void } => {\n const context = useContext(DragContext);\n // Internal draggables (tabs, grips) live under DragProvider; external tab\n // sources sit outside it and reach the manager via DashfooDragProvider.\n const sharedManager = useContext(SharedDragManagerContext);\n const manager = context?.manager ?? sharedManager;\n const { draggableRef, elementRef, ref } = useDraggableHandle();\n const { data, id } = descriptor;\n\n useEffect(() => {\n if (!manager || disabled) {\n return undefined;\n }\n const draggable = new Draggable({ data: { ...data, label: \"\" }, id }, manager);\n draggable.element = elementRef.current ?? undefined;\n draggableRef.current = draggable;\n return () => {\n draggable.destroy();\n draggableRef.current = null;\n };\n }, [data, disabled, draggableRef, elementRef, id, manager]);\n\n useEffect(() => {\n const draggable = draggableRef.current;\n if (draggable) {\n draggable.data = { ...data, label };\n }\n }, [data, draggableRef, label]);\n\n // Memoized so callers can hold the whole handle in hook deps without their\n // memoization dissolving on every render.\n return useMemo(() => ({ ref }), [ref]);\n};\n\nconst useTabDraggable = (\n tabId: string,\n disabled = false,\n label = \"\",\n): { ref: (element: Element | null) => void } => {\n const data = useMemo(() => ({ type: \"tab\" }), []);\n return useDraggableEntity({ data, id: tabId }, disabled, label);\n};\n\n// The whole tabset is draggable from its grip. A distinct dnd-kit id (grip-*)\n// avoids colliding with the tabset's own registered id; the real tabset id rides\n// in `data` and becomes the moveTabset subject. The label feeds the overlay chip.\nconst useTabsetDraggable = (\n tabsetId: string,\n disabled = false,\n label = \"\",\n): { ref: (element: Element | null) => void } => {\n const data = useMemo(() => ({ tabsetId, type: \"tabset\" }), [tabsetId]);\n return useDraggableEntity({ data, id: `grip-${tabsetId}` }, disabled, label);\n};\n\n// Registers the tabset as a dnd-kit Droppable with the occlusion-aware\n// detector, mirroring useDraggableEntity's lifecycle: the effect is keyed on\n// identity, the ref setter keeps `element` current across renders. Droppables\n// register on the manager (shared across layers), so the winning tabset is\n// resolved globally; `data.layerId` lets the owning DragProvider claim it.\nconst useTabsetDroppable = (tabsetId: string): { ref: (element: HTMLElement | null) => void } => {\n const context = useContext(DragContext);\n const elementRef = useRef<HTMLElement | null>(null);\n const droppableRef = useRef<Droppable | null>(null);\n const ref = useCallback((element: HTMLElement | null): void => {\n elementRef.current = element;\n if (droppableRef.current) {\n droppableRef.current.element = element ?? undefined;\n }\n }, []);\n const layerId = context?.layerId;\n const manager = context?.manager;\n\n useEffect(() => {\n if (!manager || layerId === undefined) {\n return undefined;\n }\n // Droppable ids must be manager-unique, but model tabset ids are only\n // unique within one layout — sibling layouts under a shared provider can\n // both have a \"ts1\", and dnd-kit's registry replaces the earlier entry on\n // an id collision. The layer prefix keeps registrations distinct; the\n // model id the adapter and reducer understand rides in data.\n const droppable = new Droppable(\n {\n collisionDetector: topmostPointerIntersection,\n data: { layerId, tabsetId, type: \"tabset\" },\n id: `${layerId}:${tabsetId}`,\n },\n manager,\n );\n droppable.element = elementRef.current ?? undefined;\n droppableRef.current = droppable;\n return () => {\n droppable.destroy();\n droppableRef.current = null;\n };\n }, [layerId, manager, tabsetId]);\n\n // Memoized so callers can hold the whole handle in hook deps without their\n // memoization dissolving on every render.\n return useMemo(() => ({ ref }), [ref]);\n};\n\ntype ExternalTabSourceOptions = {\n // Must return a fresh TabNode (unique id) per call — each drop inserts a new\n // tab, and duplicate ids would fail the model's invariants.\n createTab: () => TabNode;\n disabled?: boolean;\n label?: string;\n};\n\n// Makes any element outside a layout a drag source that inserts a new tab when\n// dropped on a DashfooLayout under the same DashfooDragProvider. The adapter\n// recognizes the { type: \"external\" } payload and commits an addNode instead of\n// a move. The ref-indirection keeps `data` referentially stable (the\n// construction effect tracks it) while drags always call the latest createTab.\nconst useExternalTabSource = ({\n createTab,\n disabled = false,\n label = \"\",\n}: ExternalTabSourceOptions): { ref: (element: Element | null) => void } => {\n const id = useId();\n const createTabRef = useRef(createTab);\n // Dependency-less on purpose: a plain ref sync so drags always call the latest createTab.\n useEffect(() => {\n createTabRef.current = createTab;\n });\n const data = useMemo(\n () => ({ createTab: (): TabNode => createTabRef.current(), type: \"external\" }),\n [],\n );\n return useDraggableEntity({ data, id: `external-${id}` }, disabled, label);\n};\n\nconst useDragSubject = (): DragSubject | null => {\n const store = useContext(DragSubjectStoreContext);\n return useStore(store ?? nullSubjectStore, (state) => state.subject);\n};\n\n// The live drop intent: where the drag would land if dropped right now, null\n// when nothing is dragging or the pointer is over no valid target (a no-op\n// drop, a non-editable layout, or empty space). Lets consumers render their own\n// drop indicators alongside the built-in one.\nconst useDropIntent = (): DropIntent | null => {\n const store = useContext(DragSubjectStoreContext);\n return useStore(store ?? nullSubjectStore, (state) => state.intent);\n};\n\nexport type { DragContextValue, DragSubjectStore, ExternalTabSourceOptions };\nexport {\n createDragManager,\n createDragSubjectStore,\n DragContext,\n DragSubjectStoreContext,\n sameDragSubject,\n sameDropIntent,\n SharedDragManagerContext,\n useDragSubject,\n useDropIntent,\n useExternalTabSource,\n useTabDraggable,\n useTabsetDraggable,\n useTabsetDroppable,\n};\n","\"use client\";\n\nimport type { Dashfoo } from \"@dashfoo/core\";\nimport { fromJSON, toJSON } from \"@dashfoo/core\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\n// A minimal localStorage-shaped backend so layouts can persist to anything: the\n// browser, sessionStorage, an in-memory map, or a custom store.\ntype StorageAdapter = {\n getItem: (key: string) => string | null;\n removeItem: (key: string) => void;\n setItem: (key: string, value: string) => void;\n};\n\nconst memoryStorageAdapter = (): StorageAdapter => {\n const store = new Map<string, string>();\n return {\n getItem: (key) => store.get(key) ?? null,\n removeItem: (key) => {\n store.delete(key);\n },\n setItem: (key, value) => {\n store.set(key, value);\n },\n };\n};\n\n// SSR-safe browser adapter: reads return null and writes are swallowed (with a\n// warning) when storage is unavailable or throws (no window, private mode, quota).\nconst localStorageAdapter: StorageAdapter = {\n getItem: (key) => {\n if (typeof window === \"undefined\") {\n return null;\n }\n try {\n return window.localStorage.getItem(key);\n } catch {\n return null;\n }\n },\n removeItem: (key) => {\n if (typeof window === \"undefined\") {\n return;\n }\n try {\n window.localStorage.removeItem(key);\n } catch {\n // storage unavailable — nothing to remove.\n }\n },\n setItem: (key, value) => {\n if (typeof window === \"undefined\") {\n return;\n }\n try {\n window.localStorage.setItem(key, value);\n } catch (error) {\n // A persistence failure (quota, private mode) must not be silent.\n // oxlint-disable-next-line no-console\n console.warn(\"[dashfoo] failed to persist layout\", error);\n }\n },\n};\n\n// A resolved persistence target: where to save and how often. DashfooLayout's\n// `persist` prop normalizes its input to this.\ntype PersistConfig = {\n debounceMs: number;\n key: string;\n storage: StorageAdapter;\n};\n\ntype Persistence = {\n clear: () => void;\n // undefined only in controlled mode, where no defaultModel seeds the load.\n initialModel: Dashfoo | undefined;\n save: (model: Dashfoo) => void;\n};\n\n// The load/save half of persistence, behind the DashfooLayout `persist` prop.\n// Loads the saved model once (validated via serialize.ts, falling back to\n// `defaultModel` on miss or corruption) and\n// debounce-saves every change. Resetting the live model is the caller's job —\n// this primitive only owns the storage side. A null config makes it a no-op, so\n// callers can run the hook unconditionally.\nconst usePersistence = (\n config: PersistConfig | null,\n defaultModel: Dashfoo | undefined,\n): Persistence => {\n // Refs keep the callbacks stable while always seeing the latest config; synced\n // in an effect (never written during render).\n const configRef = useRef(config);\n useEffect(() => {\n configRef.current = config;\n });\n\n // Load the saved model once. The initializer stays pure (no writes during\n // render); a corrupt stored value is pruned in the mount effect below.\n const [initialModel] = useState<Dashfoo | undefined>(() => {\n if (config === null || defaultModel === undefined) {\n return defaultModel;\n }\n const raw = config.storage.getItem(config.key);\n if (raw === null) {\n return defaultModel;\n }\n try {\n return fromJSON(raw);\n } catch {\n return defaultModel;\n }\n });\n\n useEffect(() => {\n const current = configRef.current;\n if (current === null) {\n return;\n }\n const raw = current.storage.getItem(current.key);\n if (raw === null) {\n return;\n }\n try {\n fromJSON(raw);\n } catch (error) {\n // Mirror the setItem warn: a discarded corrupt layout must not be silent.\n // oxlint-disable-next-line no-console\n console.warn(\"[dashfoo] discarding unreadable persisted layout\", error);\n current.storage.removeItem(current.key);\n }\n }, []);\n\n // We load + prune once, but save/flush/clear target the *current* key. Changing\n // config.key for a mounted layout would save the stale model under the new key\n // and clobber it; warn instead of doing that silently. Remounting is the fix.\n const loadedKey = useRef(config?.key);\n useEffect(() => {\n if (config !== null && config.key !== loadedKey.current) {\n // oxlint-disable-next-line no-console\n console.warn(\n \"[dashfoo] persist key changed for a mounted layout; the displayed layout still reflects the previous key — remount (key={persistKey}) to load the new key\",\n );\n loadedKey.current = config.key;\n }\n }, [config]);\n\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n // The pending write carries the key and storage it was produced for, so a\n // config change while a save is queued cannot write the old value into the\n // new target.\n const pending = useRef<{ key: string; storage: StorageAdapter; value: string } | null>(null);\n\n const flush = useCallback((): void => {\n if (timer.current !== null) {\n clearTimeout(timer.current);\n timer.current = null;\n }\n if (pending.current !== null) {\n pending.current.storage.setItem(pending.current.key, pending.current.value);\n pending.current = null;\n }\n }, []);\n\n const save = useCallback(\n (next: Dashfoo): void => {\n const current = configRef.current;\n if (current === null) {\n return;\n }\n pending.current = { key: current.key, storage: current.storage, value: toJSON(next) };\n if (timer.current !== null) {\n clearTimeout(timer.current);\n }\n timer.current = setTimeout(flush, current.debounceMs);\n },\n [flush],\n );\n\n // Flush a pending save on unmount so the last change is never lost — and on\n // page teardown: a reload or navigation never unmounts React, so the debounced\n // timer dies with the page. pagehide is the teardown signal (bfcache-safe);\n // visibilitychange→hidden covers backgrounded tabs killed without a pagehide\n // (mobile). flush() is idempotent, so overlapping signals are harmless.\n useEffect(() => {\n const handlePageHide = (): void => {\n flush();\n };\n const handleVisibilityChange = (): void => {\n if (document.visibilityState === \"hidden\") {\n flush();\n }\n };\n window.addEventListener(\"pagehide\", handlePageHide);\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n return () => {\n window.removeEventListener(\"pagehide\", handlePageHide);\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n flush();\n };\n }, [flush]);\n\n const clear = useCallback((): void => {\n if (timer.current !== null) {\n clearTimeout(timer.current);\n timer.current = null;\n }\n pending.current = null;\n const current = configRef.current;\n if (current !== null) {\n current.storage.removeItem(current.key);\n }\n }, []);\n\n // Memoized so callers can hold the whole object in hook deps without their\n // memoization dissolving on every render.\n return useMemo(() => ({ clear, initialModel, save }), [clear, initialModel, save]);\n};\n\nexport { localStorageAdapter, memoryStorageAdapter, usePersistence };\nexport type { Persistence, PersistConfig, StorageAdapter };\n","\"use client\";\n\nimport type { Dashfoo } from \"@dashfoo/core\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\ntype Breakpoint = {\n // When true, the active breakpoint locks every structural interaction (tab and\n // tabset drag, split resize) — the lock-on-mobile model. Pair it with a stacked\n // model so the narrow view is read-only and tap-navigable. Defaults to false.\n compact?: boolean;\n id: string;\n model: Dashfoo;\n query?: { maxWidth: number } | { media: string };\n};\n\ntype UseResponsiveModelOptions = { breakpoints: Array<Breakpoint> };\n\ntype ResponsiveModel = {\n breakpoint: string;\n containerRef: (element: HTMLElement | null) => void;\n draggableTabs: boolean;\n draggableTabsets: boolean;\n isCompact: boolean;\n model: Dashfoo;\n resizableSplits: boolean;\n};\n\nconst hasMatchMedia = (): boolean =>\n typeof window !== \"undefined\" && typeof window.matchMedia === \"function\";\n\n// Whether a breakpoint applies at a given container width. No query = catch-all;\n// a maxWidth matches at or below the width; a media query consults matchMedia.\nconst matchBreakpoint = (breakpoint: Breakpoint, width: number): boolean => {\n const { query } = breakpoint;\n if (!query) {\n return true;\n }\n if (\"maxWidth\" in query) {\n return width <= query.maxWidth;\n }\n return hasMatchMedia() && window.matchMedia(query.media).matches;\n};\n\n// The first breakpoint that matches, else the last (the expected catch-all).\nconst activeBreakpoint = (breakpoints: Array<Breakpoint>, width: number): Breakpoint => {\n const fallback = breakpoints.at(-1);\n if (!fallback) {\n throw new Error(\"useResponsiveModel requires at least one breakpoint.\");\n }\n return breakpoints.find((breakpoint) => matchBreakpoint(breakpoint, width)) ?? fallback;\n};\n\n// Tracks a single element's content-box width via ResizeObserver. Seeds\n// POSITIVE_INFINITY so server and first client render agree on the widest\n// breakpoint (no hydration mismatch, no compact flash on desktop); the observer\n// supplies the real width on mount. The returned ref callback is stable.\nconst useContainerWidth = (): [(element: HTMLElement | null) => void, number] => {\n const [width, setWidth] = useState<number>(Number.POSITIVE_INFINITY);\n const observerRef = useRef<ResizeObserver | null>(null);\n\n const containerRef = useCallback((element: HTMLElement | null): void => {\n observerRef.current?.disconnect();\n if (!element) {\n return;\n }\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (entry) {\n setWidth(entry.contentRect.width);\n }\n });\n observer.observe(element);\n observerRef.current = observer;\n }, []);\n\n useEffect(\n () => () => {\n observerRef.current?.disconnect();\n },\n [],\n );\n\n return [containerRef, width];\n};\n\n// Picks a model for the active breakpoint, keyed off the container's own width\n// (ResizeObserver) and/or media queries, and derives the structural-interaction\n// flags from the breakpoint's `compact`. Feed model + flags onto DashfooLayout\n// (or Layout.Root) as reactive props and attach containerRef to the wrapper —\n// no key/remount, so store, history, and tab state survive a breakpoint cross.\nconst useResponsiveModel = ({ breakpoints }: UseResponsiveModelOptions): ResponsiveModel => {\n const [containerRef, width] = useContainerWidth();\n const [, setMediaTick] = useState(0);\n\n useEffect(() => {\n if (!hasMatchMedia()) {\n return;\n }\n const lists = breakpoints.flatMap((breakpoint) =>\n breakpoint.query && \"media\" in breakpoint.query\n ? [window.matchMedia(breakpoint.query.media)]\n : [],\n );\n if (lists.length === 0) {\n return;\n }\n const handleChange = (): void => {\n setMediaTick((tick) => tick + 1);\n };\n for (const list of lists) {\n list.addEventListener(\"change\", handleChange);\n }\n return () => {\n for (const list of lists) {\n list.removeEventListener(\"change\", handleChange);\n }\n };\n }, [breakpoints]);\n\n const active = activeBreakpoint(breakpoints, width);\n // Memoized on the active breakpoint (a stable element of the caller's array),\n // so callers can hold the whole result in hook deps without their memoization\n // dissolving on every width pulse within the same breakpoint.\n return useMemo(() => {\n const isCompact = active.compact === true;\n return {\n breakpoint: active.id,\n containerRef,\n draggableTabs: !isCompact,\n draggableTabsets: !isCompact,\n isCompact,\n model: active.model,\n resizableSplits: !isCompact,\n };\n }, [active, containerRef]);\n};\n\nexport { activeBreakpoint, matchBreakpoint, useContainerWidth, useResponsiveModel };\nexport type { Breakpoint, ResponsiveModel, UseResponsiveModelOptions };\n","\"use client\";\n\nimport type { Action, Dashfoo } from \"@dashfoo/core\";\nimport { canRedo, canUndo, dashfooMachine, normalize, reducer } from \"@dashfoo/core\";\nimport { useActorRef, useSelector } from \"@xstate/react\";\nimport { useCallback, useEffect, useMemo } from \"react\";\n\ntype DashfooStore = {\n canRedo: () => boolean;\n canUndo: () => boolean;\n dispatch: (action: Action) => void;\n model: Dashfoo;\n redo: () => void;\n setModel: (model: Dashfoo) => void;\n undo: () => void;\n};\n\ntype UseDashfooStoreOptions = {\n defaultModel?: Dashfoo;\n model?: Dashfoo;\n onAction?: (action: Action) => Action | null;\n onActiveTabsetChange?: (tabsetId: string | undefined) => void;\n onMaximizedTabsetChange?: (tabsetId: string | undefined) => void;\n onModelChange?: (model: Dashfoo, action?: Action) => void;\n};\n\n// Binds a dashfooMachine actor to React. Uncontrolled (defaultModel) lets the\n// actor own the document with full undo/redo; controlled (model) makes the prop\n// the source of truth and routes every change through onModelChange. The\n// actor/inspector stays in sync once the host round-trips `after` back into the\n// `model` prop (it is not synced synchronously within dispatch).\nconst useDashfooStore = (options: UseDashfooStoreOptions): DashfooStore => {\n const {\n defaultModel,\n model: controlledModel,\n onAction,\n onActiveTabsetChange,\n onMaximizedTabsetChange,\n onModelChange,\n } = options;\n const initialModel = controlledModel ?? defaultModel;\n if (initialModel === undefined) {\n throw new Error(\"useDashfooStore requires either a `model` or a `defaultModel`.\");\n }\n\n // Normalize at the boundary so a host-supplied model satisfies the same\n // invariants (clamped selection, no empty tabsets, live maximizedTabsetId) the\n // reducer guarantees — every entry point holds a canonical model.\n const actorRef = useActorRef(dashfooMachine, { input: { model: normalize(initialModel) } });\n const history = useSelector(actorRef, (snapshot) => snapshot.context.history);\n\n useEffect(() => {\n if (controlledModel !== undefined) {\n actorRef.send({ model: normalize(controlledModel), type: \"SET_MODEL\" });\n }\n }, [actorRef, controlledModel]);\n\n const model = controlledModel ?? history.present;\n\n // Single notification path so dispatch and undo/redo stay in lockstep. The\n // Object.is guard makes a no-op transition (e.g. undo at the bottom of the\n // stack, where the history helper returns the same object) emit nothing, so we\n // never write spurious persistence on a change that did not happen.\n const notify = useCallback(\n (before: Dashfoo, after: Dashfoo, action?: Action) => {\n if (Object.is(before, after)) {\n return;\n }\n onModelChange?.(after, action);\n if (after.activeTabsetId !== before.activeTabsetId) {\n onActiveTabsetChange?.(after.activeTabsetId);\n }\n if (after.maximizedTabsetId !== before.maximizedTabsetId) {\n onMaximizedTabsetChange?.(after.maximizedTabsetId);\n }\n },\n [onModelChange, onActiveTabsetChange, onMaximizedTabsetChange],\n );\n\n const dispatch = useCallback(\n (action: Action) => {\n // onAction may veto (null) or replace the action before it mutates anything.\n const resolved = onAction ? onAction(action) : action;\n if (!resolved) {\n return;\n }\n // Uncontrolled: the actor owns history. Controlled: derive the next model by\n // hand (the host round-trips it through the model prop). normalize the\n // controlled `before` too, else a normalization-only id change fires spuriously.\n const transition = ((): { after: Dashfoo; before: Dashfoo } => {\n if (controlledModel === undefined) {\n const before = actorRef.getSnapshot().context.history.present;\n actorRef.send({ action: resolved, type: \"DISPATCH\" });\n return { after: actorRef.getSnapshot().context.history.present, before };\n }\n return { after: reducer(controlledModel, resolved), before: normalize(controlledModel) };\n })();\n notify(transition.before, transition.after, resolved);\n },\n [actorRef, controlledModel, notify, onAction],\n );\n\n const undo = useCallback(() => {\n // actor history is always empty in controlled mode, so undo would be a dead\n // send that still emitted a spurious onModelChange.\n if (controlledModel !== undefined) {\n return;\n }\n const before = actorRef.getSnapshot().context.history.present;\n actorRef.send({ type: \"UNDO\" });\n const after = actorRef.getSnapshot().context.history.present;\n notify(before, after);\n }, [actorRef, controlledModel, notify]);\n\n const redo = useCallback(() => {\n if (controlledModel !== undefined) {\n return;\n }\n const before = actorRef.getSnapshot().context.history.present;\n actorRef.send({ type: \"REDO\" });\n const after = actorRef.getSnapshot().context.history.present;\n notify(before, after);\n }, [actorRef, controlledModel, notify]);\n\n // Replace the whole document, resetting undo history. Drives an uncontrolled\n // reset (e.g. clearing a persisted layout back to its default) without a\n // remount; normalized at the boundary like every other entry point.\n const setModel = useCallback(\n (next: Dashfoo) => {\n actorRef.send({ model: normalize(next), type: \"SET_MODEL\" });\n },\n [actorRef],\n );\n\n // Functions, not booleans: they read the live actor snapshot so a caller\n // reading them right after undo/redo (e.g. inside onModelChange) sees the fresh\n // value, not the one-render-stale useSelector result. Memoized so callers can\n // hold the whole store in hook deps without their memoization dissolving on\n // every render.\n return useMemo(\n () => ({\n canRedo: () => canRedo(actorRef.getSnapshot().context.history),\n canUndo: () => canUndo(actorRef.getSnapshot().context.history),\n dispatch,\n model,\n redo,\n setModel,\n undo,\n }),\n [actorRef, dispatch, model, redo, setModel, undo],\n );\n};\n\nexport { useDashfooStore };\nexport type { DashfooStore, UseDashfooStoreOptions };\n","import type { Point, Rect } from \"@dashfoo/core\";\n\n// Pure drag math for the tab strip — rects in, geometry out. The drag adapter\n// gathers the rects from the DOM and feeds them here, so this stays unit-testable\n// without a live drag.\n\ntype Zone = { height: number; width: number; x: number; y: number };\n\n// Is the point inside the rect? (Rect is DOMRect-compatible: x/y/width/height.)\nconst pointInRect = (point: Point, rect: Rect): boolean =>\n point.x >= rect.x &&\n point.x <= rect.x + rect.width &&\n point.y >= rect.y &&\n point.y <= rect.y + rect.height;\n\n// Which slot in the strip the pointer is over: the first tab whose midpoint is\n// right of the pointer, else the end.\nconst insertionIndex = (rects: ReadonlyArray<Rect>, pointerX: number): number => {\n const found = rects.findIndex((rect) => pointerX < rect.x + rect.width / 2);\n return found === -1 ? rects.length : found;\n};\n\n// How wide the insertion line is, centered on the slot boundary.\nconst INSERTION_LINE_WIDTH = 4;\n\n// The thin vertical line marking where a tab will be inserted. Measured against\n// whole tab-item rects (label + close), so the \"after the last tab\" position sits\n// past the last close button rather than between the label and the close.\n// Clamped so the line never leaves the strip.\nconst insertionLineRect = (\n stripRect: Rect,\n itemRects: ReadonlyArray<Rect>,\n index: number,\n): Zone => {\n const at = itemRects[index];\n const last = itemRects.at(-1);\n const x = at?.x ?? (last ? last.x + last.width : stripRect.x);\n const left = x - INSERTION_LINE_WIDTH / 2;\n return {\n height: stripRect.height,\n width: INSERTION_LINE_WIDTH,\n x: Math.max(stripRect.x, Math.min(left, stripRect.x + stripRect.width - INSERTION_LINE_WIDTH)),\n y: stripRect.y,\n };\n};\n\n// Whether a drop should commit, or is a no-op to be suppressed: dragging a tabset\n// onto itself (grip id is `grip-${tabsetId}`), or the sole tab of a tabset back\n// onto that same tabset — both change nothing once empties collapse.\nconst shouldAllowDrop = (\n draggedId: string | undefined,\n targetId: string,\n tabIds: ReadonlyArray<string>,\n): boolean => {\n if (draggedId === `grip-${targetId}`) {\n return false;\n }\n if (tabIds.length === 1 && tabIds[0] === draggedId) {\n return false;\n }\n return true;\n};\n\nexport { insertionIndex, insertionLineRect, pointInRect, shouldAllowDrop };\nexport type { Zone };\n","\"use client\";\n\nimport type { dragDockMachine, Point } from \"@dashfoo/core\";\nimport { zoneRect } from \"@dashfoo/core\";\nimport type { DragDropManager } from \"@dnd-kit/dom\";\nimport { Feedback } from \"@dnd-kit/dom\";\nimport { useSelector } from \"@xstate/react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport type { ActorRefFrom } from \"xstate\";\n\nimport type { Zone } from \"../lib/tab-insertion\";\nimport { insertionLineRect } from \"../lib/tab-insertion\";\n\n// The drag adapter's two overlays: the dock indicator (where the drop will\n// land) and the pointer-anchored preview chip. Split from drag-adapter.tsx to\n// keep that module focused on wiring @dnd-kit to the drag machine.\n\ntype DragActor = ActorRefFrom<typeof dragDockMachine>;\n\nconst overlayBase: CSSProperties = {\n boxSizing: \"border-box\",\n pointerEvents: \"none\",\n position: \"fixed\",\n // Overridable so a theme can drop it under prefers-reduced-motion.\n transition: \"var(--dashfoo-dock-transition, left 60ms, top 60ms, width 60ms, height 60ms)\",\n zIndex: 9999,\n};\n\n// Only position/size are fixed inline; every visual property is an overridable\n// CSS var with a neutral fallback, so a consumer's data-dashfoo=\"dock-indicator\"\n// theme fully owns the look.\nconst paneStyle = (zone: Zone): CSSProperties => ({\n ...overlayBase,\n background: \"var(--dashfoo-dock-fill, oklch(0.556 0 0 / 0.18))\",\n border:\n \"var(--dashfoo-dock-border-width, 1px) solid var(--dashfoo-dock-border, oklch(0.708 0 0 / 0.75))\",\n borderRadius: \"var(--dashfoo-dock-radius, 6px)\",\n height: zone.height,\n left: zone.x,\n top: zone.y,\n width: zone.width,\n});\n\n// The insertion line shares the pane's fill and border, shrunk to a thin caret\n// between tabs, so the strip indicator and the dock panes read as one family.\nconst lineStyle = (zone: Zone): CSSProperties => ({\n ...paneStyle(zone),\n borderRadius: \"var(--dashfoo-dock-line-radius, 2px)\",\n});\n\n// Whole-tab-item rects (label + close button), excluding the dragged tab. The\n// insertion line lands on these boundaries so the \"after the last tab\" position\n// sits past the close button, not between the label and the close.\nconst tabItemRects = (strip: Element, excludeId?: string): Array<DOMRect> =>\n [...strip.querySelectorAll<HTMLElement>('[data-dashfoo=\"tab-item\"]')].flatMap((item) =>\n item.querySelector<HTMLElement>('[data-dashfoo=\"tab\"]')?.dataset.tabId === excludeId\n ? []\n : [item.getBoundingClientRect()],\n );\n\n// A \"where it will land\" indicator driven off the machine's live intent: an\n// insertion line in the tab bar for a stack, the matching content half for a\n// split. One unkeyed div, so React reuses the DOM node and the position/size\n// transition morphs between the two shapes instead of remounting.\nconst DockIndicator = ({\n actorRef,\n getTabsetElement,\n}: {\n actorRef: DragActor;\n getTabsetElement: (id: string) => HTMLElement | undefined;\n}): ReactNode => {\n const intent = useSelector(actorRef, (snapshot) => snapshot.context.intent);\n const draggedId = useSelector(actorRef, (snapshot) => snapshot.context.subject?.id);\n if (!intent) {\n return null;\n }\n const element = getTabsetElement(intent.targetId);\n if (!element) {\n return null;\n }\n // A docked target sits beneath the floating-panel layer, so its indicator must\n // too — otherwise the z:9999 overlay paints over a float that occludes the\n // target. A target inside a float stays above that float.\n const zIndex = element.closest('[data-dashfoo=\"float\"]') ? overlayBase.zIndex : \"auto\";\n if (intent.location === \"center\") {\n const strip = element.querySelector('[data-dashfoo=\"tabstrip\"]');\n if (strip) {\n const line = insertionLineRect(\n strip.getBoundingClientRect(),\n tabItemRects(strip, draggedId),\n intent.index ?? 0,\n );\n return <div data-dashfoo=\"dock-indicator\" style={{ ...lineStyle(line), zIndex }} />;\n }\n }\n const zone = zoneRect(element.getBoundingClientRect(), intent.location);\n return <div data-dashfoo=\"dock-indicator\" style={{ ...paneStyle(zone), zIndex }} />;\n};\n\n// The pointer-anchored preview chip keeps the cursor at this offset from its\n// top-left corner, exactly as before the Feedback adoption.\nconst PREVIEW_OFFSET: Point = { x: 12, y: 8 };\n\nconst labelOf = (source: { data?: Record<string, unknown> } | null): string => {\n const raw = source?.data?.label;\n return typeof raw === \"string\" ? raw : \"\";\n};\n\ntype ChipState = { label: string; x: number; y: number };\n\n// The drag-preview chip, positioned by dnd-kit's Feedback plugin. Feedback\n// anchors the wrapper to the source element's rect and drives it with the drag\n// delta; the one-shot inner offset (grab point within the source, plus\n// PREVIEW_OFFSET) re-anchors the chip to the pointer, preserving the\n// pointer-following feel. The wrapper stays mounted for the manager's lifetime:\n// Feedback's render effect runs synchronously at drag start, so `overlay` must\n// already be assigned — set mid-drag, Feedback would first promote the source\n// element itself, placeholder clone and all.\nconst DragPreviewOverlay = ({ manager }: { manager: DragDropManager }): ReactNode => {\n const [chip, setChip] = useState<ChipState | null>(null);\n\n useEffect(() => {\n const offStart = manager.monitor.addEventListener(\"dragstart\", (event) => {\n const source = event.operation.source;\n if (!source) {\n return;\n }\n const rect = source.element?.getBoundingClientRect();\n const point = event.operation.position.current;\n setChip({\n label: labelOf(source),\n x: PREVIEW_OFFSET.x + (rect ? point.x - rect.left : 0),\n y: PREVIEW_OFFSET.y + (rect ? point.y - rect.top : 0),\n });\n });\n const offEnd = manager.monitor.addEventListener(\"dragend\", () => setChip(null));\n return () => {\n offStart();\n offEnd();\n };\n }, [manager]);\n\n const attachOverlay = useCallback(\n (element: HTMLDivElement | null): void => {\n const feedback = manager.registry.plugins.get(Feedback);\n if (feedback) {\n feedback.overlay = element ?? undefined;\n }\n },\n [manager],\n );\n\n // data-dnd-overlay is ours to stamp (dnd-kit only references it, in the\n // injected CSS that hides the wrapper while no drag is live). popover and\n // data-dnd-dragging are Feedback-owned attributes — declaring them here would\n // fight its cleanup, which strips the attributes it added.\n return (\n <div data-dnd-overlay=\"\" ref={attachOverlay}>\n {chip === null ? null : (\n <div\n data-dashfoo=\"drag-preview\"\n style={{\n left: 0,\n position: \"absolute\",\n top: 0,\n transform: `translate(${chip.x}px, ${chip.y}px)`,\n // Absolute children shrink to the containing block, and the wrapper\n // is source-sized (a tabset grip is ~20px) — the chip sizes to its\n // own label instead.\n width: \"max-content\",\n }}\n >\n {chip.label}\n </div>\n )}\n </div>\n );\n};\n\nexport { DockIndicator, DragPreviewOverlay };\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useInsertionEffect, useState } from \"react\";\n\nimport {\n createDragManager,\n createDragSubjectStore,\n DragSubjectStoreContext,\n SharedDragManagerContext,\n} from \"../hooks/drag-hooks\";\n\nimport { DragPreviewOverlay } from \"./drag-overlays\";\n\n// Shares one DragDropManager between a DashfooLayout and external tab sources\n// (useExternalTabSource) rendered outside it, so a drag can start at a widget\n// list and end on the layout. Optional: a standalone DashfooLayout creates its\n// own manager and behaves as before.\nconst DashfooDragProvider = ({ children }: { children: ReactNode }): ReactNode => {\n // useState lazily constructs the manager once; the destroy rides a\n // useInsertionEffect cleanup (not useEffect) so StrictMode's simulated unmount\n // doesn't tear down the live instance — the same pattern DragProvider uses.\n const [manager] = useState(createDragManager);\n useInsertionEffect(() => () => manager.destroy(), [manager]);\n // Hosting the drag store here (the nested DragLayer adopts it instead of\n // creating its own) lets useDragSubject/useDropIntent observe the drag from\n // anywhere under the provider — widget lists, custom drop indicators — not\n // just from inside the layout.\n const [subjectStore] = useState(createDragSubjectStore);\n\n return (\n <SharedDragManagerContext.Provider value={manager}>\n <DragSubjectStoreContext.Provider value={subjectStore}>\n {children}\n {/* The manager owner renders the one chip — nested DragProviders\n sharing this manager render none, so cross-layout drags show a\n single preview instead of one per layer. */}\n <DragPreviewOverlay manager={manager} />\n </DragSubjectStoreContext.Provider>\n </SharedDragManagerContext.Provider>\n );\n};\n\nexport { DashfooDragProvider };\n","\"use client\";\n\nimport type { Action, SnapConfig, TabNode, TabsetNode } from \"@dashfoo/core\";\nimport type { ReactNode } from \"react\";\nimport { createContext, useContext } from \"react\";\nimport type { StoreApi } from \"zustand\";\nimport { createStore, useStore } from \"zustand\";\n\n// The layout-wide configuration every part below <Layout.Root> coordinates\n// through: resolved chrome flags, slot renderers, and the model dispatcher.\n// A scoped zustand store rather than a plain context value so parts subscribe\n// per-field — changing one flag re-renders only the parts that select it.\ntype LayoutState = {\n closableTabs: boolean;\n dispatch: (action: Action) => void;\n draggableTabs: boolean;\n draggableTabsets: boolean;\n editable: boolean;\n // Whether tabsets show a \"float into a movable panel\" control.\n floatable: boolean;\n keepMounted: boolean;\n maximizable: boolean;\n maximizedTabsetId: string | undefined;\n renamableTabs: boolean;\n renderTab: (tab: TabNode) => ReactNode;\n renderTabLabel: ((tab: TabNode) => ReactNode) | undefined;\n renderTabsetToolbar: ((tabset: TabsetNode) => ReactNode) | undefined;\n resizableSplits: boolean;\n // Magnetic snap defaults for split resize; null = no snapping. A row may still\n // override this via its own `snap` attribute (read in row-view).\n snap: SnapConfig | null;\n splitDock: boolean;\n tabLocation: \"bottom\" | \"top\";\n tabsetMinSize: number;\n tabStripEnabled: boolean;\n};\n\ntype LayoutStore = StoreApi<LayoutState>;\n\nconst createLayoutStore = (initial: LayoutState): LayoutStore =>\n createStore<LayoutState>(() => initial);\n\n// Carries only the store instance — state always flows through selectors.\nconst LayoutStoreContext = createContext<LayoutStore | null>(null);\n\nconst useLayout = <T>(selector: (state: LayoutState) => T): T => {\n const store = useContext(LayoutStoreContext);\n if (store === null) {\n throw new Error(\"dashfoo components must be rendered inside <DashfooLayout> or <Layout.Root>.\");\n }\n return useStore(store, selector);\n};\n\nexport { createLayoutStore, LayoutStoreContext, useLayout };\nexport type { LayoutState, LayoutStore };\n","// Dev warnings for soft misuse (duplicate parts, orphan tabs, missing editors)\n// fire once per key so a render loop can't flood the console, mirroring the\n// unregistered-component warning in dashfoo-layout.\nconst warned = new Set<string>();\n\nconst warnOnce = (key: string, message: string): void => {\n if (warned.has(key)) {\n return;\n }\n warned.add(key);\n // oxlint-disable-next-line no-console\n console.warn(`[dashfoo] ${message}`);\n};\n\nexport { warnOnce };\n","\"use client\";\n\nimport type { Action, DockLocation, DragSubject, DropIntent, Point } from \"@dashfoo/core\";\nimport { dragDockMachine, resolveDockTarget, tabNodeSchema } from \"@dashfoo/core\";\nimport type { DragEndEvent, DragStartEvent } from \"@dnd-kit/dom\";\nimport { useActorRef } from \"@xstate/react\";\nimport type { ReactNode } from \"react\";\nimport {\n useCallback,\n useContext,\n useEffect,\n useId,\n useInsertionEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport type { DragContextValue } from \"../hooks/drag-hooks\";\nimport {\n createDragManager,\n createDragSubjectStore,\n DragContext,\n DragSubjectStoreContext,\n sameDragSubject,\n sameDropIntent,\n SharedDragManagerContext,\n} from \"../hooks/drag-hooks\";\nimport { LayoutStoreContext } from \"../hooks/layout-store\";\nimport { insertionIndex, pointInRect, shouldAllowDrop } from \"../lib/tab-insertion\";\nimport { warnOnce } from \"../lib/warn-once\";\n\nimport { DockIndicator, DragPreviewOverlay } from \"./drag-overlays\";\n\n// This module is the drag adapter: it (with ./drag-hooks) is where @dnd-kit is\n// touched. It wires the framework-agnostic @dnd-kit/dom core (no React bindings)\n// to the already unit-tested dragDockMachine — the PointerSensor supplies\n// activation + a live pointer, dnd-kit's collision pass resolves the tabset\n// droppable under it (each with dashfoo's occlusion-aware detector, see\n// ../lib/topmost-collision.ts), the adapter turns that target into a DropIntent,\n// and the machine owns the lifecycle and emits a moveNode COMMIT forwarded via\n// onCommit. The drag-preview chip rides the Feedback plugin's `overlay`\n// accessor (see DragPreviewOverlay): the source element is never promoted or\n// placeholder-cloned, and Feedback owns the chip's per-move positioning.\n\n// The dragged tab is excluded so its own slot never counts toward the order —\n// the insertion index and line are measured against the tabs it will land among.\nconst tabRects = (strip: Element, excludeId?: string): Array<DOMRect> =>\n [...strip.querySelectorAll<HTMLElement>('[data-dashfoo=\"tab\"]')].flatMap((tab) =>\n tab.dataset.tabId === excludeId ? [] : [tab.getBoundingClientRect()],\n );\n\n// The tab strip is always a \"stack as a tab\" target, with an insertion index that\n// places the tab at a specific slot. Only the content area below it resolves to\n// the center/split zones via resolveDockTarget (content center appends). The\n// adapter gathers rects from the DOM; the pure math lives in ./tab-insertion.\nconst intentForTabset = (\n id: string,\n element: HTMLElement,\n point: Point,\n draggedId?: string,\n): DropIntent => {\n const strip = element.querySelector('[data-dashfoo=\"tabstrip\"]');\n if (strip && pointInRect(point, strip.getBoundingClientRect())) {\n return {\n index: insertionIndex(tabRects(strip, draggedId), point.x),\n location: \"center\",\n targetId: id,\n };\n }\n const target = resolveDockTarget(point, element.getBoundingClientRect());\n const location: DockLocation = target.kind === \"tab\" ? \"center\" : `split-${target.edge}`;\n if (location === \"center\" && strip) {\n return { index: tabRects(strip, draggedId).length, location, targetId: id };\n }\n return { location, targetId: id };\n};\n\nconst isTabFactory = (value: unknown): value is () => unknown => typeof value === \"function\";\n\n// A tabset grip carries { tabsetId, type: \"tabset\" }; an external source\n// (useExternalTabSource) carries { createTab, type: \"external\" } and its tab is\n// built and validated at drag start; a plain tab carries its id. null aborts\n// the drag — the machine stays idle, so the following OVER/DROP are ignored.\nconst subjectFor = (source: {\n data?: Record<string, unknown>;\n id: string | number;\n}): DragSubject | null => {\n const data = source.data;\n if (data?.type === \"tabset\") {\n return { id: String(data.tabsetId), kind: \"tabset\" };\n }\n if (data?.type === \"external\") {\n if (!isTabFactory(data.createTab)) {\n // A wired-up source that can't produce a tab must not fail silently.\n // oxlint-disable-next-line no-console\n console.warn(\"[dashfoo] external drag source is missing its createTab function\");\n return null;\n }\n let candidate: unknown;\n try {\n candidate = data.createTab();\n } catch (error) {\n // A consumer callback that throws must abort the drag, not break dragging.\n // oxlint-disable-next-line no-console\n console.warn(\"[dashfoo] external drag source createTab threw\", error);\n return null;\n }\n const parsed = tabNodeSchema.safeParse(candidate);\n if (!parsed.success) {\n // oxlint-disable-next-line no-console\n console.warn(\"[dashfoo] external drag source returned an invalid tab\", parsed.error);\n return null;\n }\n return { id: String(source.id), kind: \"external\", tab: parsed.data };\n }\n return { id: String(source.id), kind: \"tab\" };\n};\n\ntype DragProviderProps = {\n children: ReactNode;\n // Defaults to the layout store's dispatch when rendered under Layout.Root.\n onCommit?: (action: Action) => void;\n // Defaults to the layout store's splitDock (model global), else true.\n splitDock?: boolean;\n};\n\nconst DragProvider = ({ children, onCommit, splitDock }: DragProviderProps): ReactNode => {\n const actorRef = useActorRef(dragDockMachine);\n // Nullable read on purpose (not the throwing useLayout hook): the drag layer\n // also works standalone with an explicit onCommit, e.g. in tests.\n const layoutStore = useContext(LayoutStoreContext);\n\n // One manager for the whole layout — the shared one when a DashfooDragProvider\n // sits above (so external sources participate in this layout's drags), else\n // our own. useState lazily constructs it once; the destroy rides a\n // useInsertionEffect cleanup (not useEffect) so StrictMode's simulated unmount\n // doesn't tear down the live instance — the same pattern @dnd-kit/react uses\n // internally.\n const sharedManager = useContext(SharedDragManagerContext);\n const [ownManager] = useState(() => (sharedManager ? null : createDragManager()));\n useInsertionEffect(() => () => ownManager?.destroy(), [ownManager]);\n const manager = sharedManager ?? ownManager;\n if (manager === null) {\n // Only reachable when a DashfooDragProvider unmounts while its layout stays\n // mounted — surface the misuse instead of dragging against a dead manager.\n throw new Error(\n \"[dashfoo] DashfooDragProvider unmounted while its layout is still mounted; keep the provider above the layout or remount the layout\",\n );\n }\n\n // The drag subject store: fed by the machine subscription, read by parts via\n // useDragSubject/useDropIntent selectors. Inherited from DashfooDragProvider\n // when one sits above (so consumers outside the layout can observe drags),\n // else owned here. Guarded so OVER pulses (every pointer move) don't notify\n // subscribers — only a subject change (drag start/end) or a value-level\n // intent change (the resolved drop moved) does. ownerId scopes intent writes:\n // layers sharing a store each claim only their own droppables from the\n // manager-global winner, so this layer's null must not erase an intent the\n // owning layer resolved.\n const inheritedStore = useContext(DragSubjectStoreContext);\n const [subjectStore] = useState(() => inheritedStore ?? createDragSubjectStore());\n const ownerId = useId();\n useEffect(() => {\n const subscription = actorRef.subscribe((snapshot) => {\n const { intent, subject } = snapshot.context;\n const state = subjectStore.getState();\n if (intent !== null) {\n if (!sameDropIntent(state.intent, intent) || state.intentOwner !== ownerId) {\n subjectStore.setState({ intent, intentOwner: ownerId });\n }\n } else if (state.intent !== null && state.intentOwner === ownerId) {\n subjectStore.setState({ intent: null, intentOwner: null });\n }\n if (!sameDragSubject(subjectStore.getState().subject, subject)) {\n subjectStore.setState({ subject });\n }\n });\n return () => {\n subscription.unsubscribe();\n };\n }, [actorRef, ownerId, subjectStore]);\n\n // Consumer-supplied inputs ride refs (the configRef pattern from\n // usePersistence) so the machine subscriptions below stay attached across\n // re-renders — an inline onCommit or a flipped splitDock must not tear down\n // and re-attach the listeners on a hot path.\n const onCommitRef = useRef(onCommit);\n const splitDockRef = useRef(splitDock);\n useEffect(() => {\n onCommitRef.current = onCommit;\n splitDockRef.current = splitDock;\n });\n\n // The DockIndicator's target lookup, against the manager-global droppable\n // registry (tabsets register there via useTabsetDroppable). The machine only\n // ever holds intents for this layer's own targets, so reconstructing this\n // layer's prefixed droppable id from the model tabset id is always right.\n const getTabsetElement = useCallback(\n (id: string): HTMLElement | undefined => {\n const element = manager.registry.droppables.get(`${ownerId}:${id}`)?.element;\n return element instanceof HTMLElement ? element : undefined;\n },\n [manager, ownerId],\n );\n\n useEffect(() => {\n const subscription = actorRef.on(\"COMMIT\", (emitted) => {\n // Mirrors the resolveIntent gate: even a drag whose `editable` was\n // flipped off mid-flight cannot land a structural action.\n if (layoutStore?.getState().editable === false) {\n return;\n }\n const commit = onCommitRef.current ?? layoutStore?.getState().dispatch;\n if (!commit) {\n warnOnce(\n \"drag-layer-no-commit\",\n \"Layout.DragLayer has neither an onCommit prop nor a <Layout.Root> above it; drops are ignored\",\n );\n return;\n }\n commit(emitted.action);\n });\n return () => {\n subscription.unsubscribe();\n };\n }, [actorRef, layoutStore]);\n\n // The helpers live inside the effect (per the React docs' \"move it into the\n // effect\" guidance) so the monitor listeners attach once per manager instead\n // of re-subscribing whenever a render rebuilds a callback.\n useEffect(() => {\n // The dock intent for a pointer over a tabset, or null when the drop would\n // be a no-op: a tabset dragged onto itself, or the sole tab of a tabset\n // dropped back onto that same tabset. Otherwise the tabset resolves to\n // center/split.\n const resolveIntent = (\n targetId: string,\n element: HTMLElement,\n point: Point,\n draggedId?: string,\n ): DropIntent | null => {\n // A non-editable layout is never a drop target — no indicator, no intent.\n // Read at drag time (getState, not a subscription) like splitDock below,\n // so a runtime flip is honored without re-rendering the layer; this also\n // rejects external-source drops arriving via a shared manager.\n if (layoutStore?.getState().editable === false) {\n return null;\n }\n const tabIds = [...element.querySelectorAll<HTMLElement>('[data-dashfoo=\"tab\"]')].map(\n (tab) => tab.dataset.tabId ?? \"\",\n );\n if (!shouldAllowDrop(draggedId, targetId, tabIds)) {\n return null;\n }\n const intent = intentForTabset(targetId, element, point, draggedId);\n // When splitting is disabled, a drop over the body stacks instead of\n // splits. Resolved at drag time (getState, not a subscription) so a model\n // global flip mid-session is honored without re-rendering the layer.\n const splitDockResolved = splitDockRef.current ?? layoutStore?.getState().splitDock ?? true;\n if (!splitDockResolved && intent.location.startsWith(\"split-\")) {\n return { location: \"center\", targetId };\n }\n return intent;\n };\n\n const handleStart = (event: DragStartEvent): void => {\n const source = event.operation.source;\n if (!source) {\n return;\n }\n const subject = subjectFor(source);\n if (!subject) {\n // Abort the dnd-kit operation too: the machine stays idle either way,\n // but a live Feedback drag would keep promoting the source element for\n // a gesture dashfoo will never commit.\n manager.actions.stop({ canceled: true });\n return;\n }\n actorRef.send({ subject, type: \"START\" });\n };\n\n // Feeds the machine the drop target dnd-kit's collision pass resolved\n // (manager-global, across every layer sharing this manager), claiming it\n // only when this layer owns it — otherwise OVER null, which clears this\n // layer's indicator while the owning layer shows its own.\n const syncIntent = (): void => {\n const operation = manager.dragOperation;\n const point = operation.position.current;\n const target = operation.target;\n // The droppable id is layer-prefixed (model tabset ids are only unique\n // per layout); the model id the machine and reducer understand rides in\n // the droppable's data, alongside the layer claim.\n const data = target?.data as { layerId?: string; tabsetId?: string } | undefined;\n const tabsetId = data?.layerId === ownerId ? data.tabsetId : undefined;\n const element = tabsetId === undefined ? undefined : target?.element;\n const draggedId = operation.source ? String(operation.source.id) : undefined;\n actorRef.send({\n intent:\n tabsetId !== undefined && element instanceof HTMLElement\n ? resolveIntent(tabsetId, element, point, draggedId)\n : null,\n type: \"OVER\",\n });\n };\n\n // Both events on purpose: inside a dragmove listener the target lags one\n // move behind (collisions recompute in a microtask after the dispatch), so\n // the collision event keeps target flips fresh — but it can skip pulses\n // while sliding within one tabset (the detector's value is constant per\n // tabset), so dragmove keeps the insertion index tracking the pointer.\n const handleMove = (): void => syncIntent();\n const handleCollision = (): void => syncIntent();\n\n // Recompute from the final operation state, then set the intent and commit\n // in one synchronous pair — the drop uses the authoritative final target,\n // not whatever the last pulse happened to report.\n const handleEnd = (event: DragEndEvent): void => {\n if (event.canceled) {\n actorRef.send({ type: \"CANCEL\" });\n return;\n }\n syncIntent();\n actorRef.send({ type: \"DROP\" });\n };\n const offStart = manager.monitor.addEventListener(\"dragstart\", handleStart);\n const offMove = manager.monitor.addEventListener(\"dragmove\", handleMove);\n const offCollision = manager.monitor.addEventListener(\"collision\", handleCollision);\n const offEnd = manager.monitor.addEventListener(\"dragend\", handleEnd);\n return () => {\n offStart();\n offMove();\n offCollision();\n offEnd();\n };\n }, [actorRef, layoutStore, manager, ownerId]);\n\n const contextValue = useMemo<DragContextValue>(\n () => ({ layerId: ownerId, manager }),\n [manager, ownerId],\n );\n\n return (\n <DragContext.Provider value={contextValue}>\n <DragSubjectStoreContext.Provider value={subjectStore}>\n {children}\n <DockIndicator actorRef={actorRef} getTabsetElement={getTabsetElement} />\n {/* One chip per manager: under a DashfooDragProvider the provider owns\n it, so N layouts sharing that manager don't stack N chips. */}\n {ownManager === null ? null : <DragPreviewOverlay manager={ownManager} />}\n </DragSubjectStoreContext.Provider>\n </DragContext.Provider>\n );\n};\n\n// The draggable/droppable hooks and the drag contexts live in ./drag-hooks to\n// keep this module under the size cap and avoid a circular import; re-exported\n// here so consumers still import the whole drag surface from \"./drag-adapter\".\nexport {\n useDragSubject,\n useTabDraggable,\n useTabsetDraggable,\n useTabsetDroppable,\n} from \"../hooks/drag-hooks\";\nexport { DragProvider, subjectFor };\nexport type { DragProviderProps };\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\n\n// Standalone (leaf) module so the float control can ask \"is a FloatLayer present?\"\n// without importing float-layer.tsx — which pulls in float-panel → row-view →\n// the tabset tree and would close an import cycle back to the control.\nconst FloatLayerContext = createContext(false);\n\nconst useHasFloatLayer = (): boolean => useContext(FloatLayerContext);\n\nexport { FloatLayerContext, useHasFloatLayer };\n","\"use client\";\n\nimport type { Geometry } from \"@dashfoo/core\";\n\n// Pure rect math for floating panels, plus the one DOM measurement that seeds a\n// float's initial position. A float's `geometry` is in viewport CSS pixels (the\n// overlay is fixed), so a float can be dragged anywhere on the page, not just\n// within the layout container.\n\nconst MIN_WIDTH = 200;\nconst MIN_HEIGHT = 120;\n// A comfortable default window size. Floating a large docked panel opens at this\n// size rather than the panel's full footprint; a smaller source keeps its size.\nconst DEFAULT_WIDTH = 480;\nconst DEFAULT_HEIGHT = 340;\n// Nudge a freshly-floated panel down-right of where it was docked so it reads as\n// lifted rather than pixel-aligned on top of its old slot.\nconst LIFT_OFFSET = 16;\n\ntype Size = { height: number; width: number };\n\n// Keep a rect's origin inside the container. `size` is the footprint kept on\n// screen (defaults to the rect's own size; the minimized chip passes its smaller\n// footprint while the rect still carries the window dimensions). A footprint\n// larger than the bounds pins to 0 on that axis rather than going negative.\nconst clampToBounds = (rect: Geometry, bounds: Size, size: Size = rect): Geometry => ({\n height: rect.height,\n left: Math.max(0, Math.min(rect.left, Math.max(0, bounds.width - size.width))),\n top: Math.max(0, Math.min(rect.top, Math.max(0, bounds.height - size.height))),\n width: rect.width,\n});\n\n// The initial rect for a float: a sane window size (the source panel's footprint,\n// capped to the default so a large panel doesn't open huge), placed over where the\n// panel was docked (viewport coordinates) and lifted slightly, clamped on screen.\nconst measureFloatRect = (element: Element): Geometry => {\n const tabsetElement = element.closest('[data-dashfoo=\"tabset\"]') ?? element;\n const rect = tabsetElement.getBoundingClientRect();\n const seeded: Geometry = {\n height: Math.max(MIN_HEIGHT, Math.min(Math.round(rect.height), DEFAULT_HEIGHT)),\n left: Math.round(rect.left) + LIFT_OFFSET,\n top: Math.round(rect.top) + LIFT_OFFSET,\n width: Math.max(MIN_WIDTH, Math.min(Math.round(rect.width), DEFAULT_WIDTH)),\n };\n return clampToBounds(seeded, { height: window.innerHeight, width: window.innerWidth });\n};\n\n// Which edges a resize handle moves: -1 = the leading edge (left/top), 1 = the\n// trailing edge (right/bottom), 0 = fixed on that axis.\ntype ResizeEdges = { x: -1 | 0 | 1; y: -1 | 0 | 1 };\n\n// Apply a pointer delta to a rect for one resize handle. A leading edge moves the\n// origin and shrinks the size; the minimum size pins the moving edge.\nconst resizeRect = (start: Geometry, edges: ResizeEdges, dx: number, dy: number): Geometry => {\n let { height, left, top, width } = start;\n if (edges.x === 1) {\n width = Math.max(MIN_WIDTH, start.width + dx);\n } else if (edges.x === -1) {\n width = Math.max(MIN_WIDTH, start.width - dx);\n left = Math.max(0, start.left + (start.width - width));\n }\n if (edges.y === 1) {\n height = Math.max(MIN_HEIGHT, start.height + dy);\n } else if (edges.y === -1) {\n height = Math.max(MIN_HEIGHT, start.height - dy);\n top = Math.max(0, start.top + (start.height - height));\n }\n return { height, left, top, width };\n};\n\nexport { clampToBounds, measureFloatRect, resizeRect };\nexport type { ResizeEdges, Size };\n","import type { CSSProperties } from \"react\";\n\nimport type { ResizeEdges } from \"../lib/float-geometry\";\n\n// Edge grab band straddles the frame border evenly (half outside, half inside)\n// so the cursor lands on a real target whether the user aims slightly in or out.\nconst EDGE_THICKNESS = 12;\nconst EDGE_OFFSET = -(EDGE_THICKNESS / 2);\n// Corners sit mostly outside the frame and are larger for a forgiving grab.\nconst CORNER_SIZE = 20;\nconst CORNER_OFFSET = -8;\n// Each edge band starts where the corner handle ends, so the corner (painted\n// later, same zIndex) keeps its zone while the band covers the rest of the side.\nconst EDGE_INSET = CORNER_SIZE + CORNER_OFFSET;\n\n// data-edge encodes which edges the handle moves; style positions it on the frame.\nconst RESIZE_HANDLES: ReadonlyArray<{ edges: ResizeEdges; key: string; style: CSSProperties }> = [\n {\n edges: { x: 0, y: -1 },\n key: \"n\",\n style: {\n cursor: \"ns-resize\",\n height: EDGE_THICKNESS,\n insetInline: EDGE_INSET,\n top: EDGE_OFFSET,\n },\n },\n {\n edges: { x: 0, y: 1 },\n key: \"s\",\n style: {\n bottom: EDGE_OFFSET,\n cursor: \"ns-resize\",\n height: EDGE_THICKNESS,\n insetInline: EDGE_INSET,\n },\n },\n {\n edges: { x: 1, y: 0 },\n key: \"e\",\n style: {\n cursor: \"ew-resize\",\n insetBlock: EDGE_INSET,\n right: EDGE_OFFSET,\n width: EDGE_THICKNESS,\n },\n },\n {\n edges: { x: -1, y: 0 },\n key: \"w\",\n style: {\n cursor: \"ew-resize\",\n insetBlock: EDGE_INSET,\n left: EDGE_OFFSET,\n width: EDGE_THICKNESS,\n },\n },\n {\n edges: { x: 1, y: -1 },\n key: \"ne\",\n style: {\n cursor: \"nesw-resize\",\n height: CORNER_SIZE,\n right: CORNER_OFFSET,\n top: CORNER_OFFSET,\n width: CORNER_SIZE,\n },\n },\n {\n edges: { x: -1, y: -1 },\n key: \"nw\",\n style: {\n cursor: \"nwse-resize\",\n height: CORNER_SIZE,\n left: CORNER_OFFSET,\n top: CORNER_OFFSET,\n width: CORNER_SIZE,\n },\n },\n {\n edges: { x: 1, y: 1 },\n key: \"se\",\n style: {\n bottom: CORNER_OFFSET,\n cursor: \"nwse-resize\",\n height: CORNER_SIZE,\n right: CORNER_OFFSET,\n width: CORNER_SIZE,\n },\n },\n {\n edges: { x: -1, y: 1 },\n key: \"sw\",\n style: {\n bottom: CORNER_OFFSET,\n cursor: \"nesw-resize\",\n height: CORNER_SIZE,\n left: CORNER_OFFSET,\n width: CORNER_SIZE,\n },\n },\n];\n\n// Resolve a resize handle's data-edge back to its edges; a missing key (the title\n// bar or the minimized chip) means a move, not a resize.\nconst EDGE_BY_KEY = new Map<string, ResizeEdges>(RESIZE_HANDLES.map((h) => [h.key, h.edges]));\n\nexport { EDGE_BY_KEY, RESIZE_HANDLES };\n","\"use client\";\n\nimport type { Action, Dashfoo, SnapConfig, TabNode, TabsetNode } from \"@dashfoo/core\";\nimport type { ComponentProps, CSSProperties, ReactNode, Ref } from \"react\";\nimport { useLayoutEffect, useState } from \"react\";\n\nimport type { LayoutState } from \"../hooks/layout-store\";\nimport { createLayoutStore, LayoutStoreContext } from \"../hooks/layout-store\";\n\nconst DEFAULT_TABSET_MIN_SIZE = 320;\n\n// position: relative so the floating-panel overlay (absolute, inset 0) anchors to\n// the layout frame and floats are positioned in layout-container coordinates.\nconst rootStyle = { display: \"flex\", height: \"100%\", position: \"relative\", width: \"100%\" } as const;\n\ntype LayoutRootProps = Omit<ComponentProps<\"div\">, \"children\"> & {\n children: ReactNode;\n closableTabs?: boolean;\n dispatch: (action: Action) => void;\n draggableTabs?: boolean;\n draggableTabsets?: boolean;\n // The umbrella switch: false turns off every structural edit (tab/tabset drag,\n // close, rename, splitter resize, external drops) in one go, leaving view\n // interactions (tab selection, maximize, overflow) and dispatch untouched.\n editable?: boolean;\n // Tabsets show a control that floats the panel into a movable, resizable overlay.\n // Off by default — opt in, since it changes the model's `floats`.\n floatable?: boolean;\n keepMounted?: boolean;\n maximizable?: boolean;\n model: Dashfoo;\n renamableTabs?: boolean;\n renderTab: (tab: TabNode) => ReactNode;\n renderTabLabel?: (tab: TabNode) => ReactNode;\n renderTabsetToolbar?: (tabset: TabsetNode) => ReactNode;\n resizableSplits?: boolean;\n // Forwarded onto the root element so a width observer can measure the actual\n // container — the hook behind responsive lock-on-mobile.\n rootRef?: Ref<HTMLDivElement>;\n // Magnetic snap default for split resize; the prop replaces (not merges with)\n // model.global.snap when both are present.\n snap?: SnapConfig;\n};\n\n// The frame of a hand-built layout: creates the scoped layout store every part\n// below subscribes to. Takes the model and dispatch (the two store fields the\n// parts need) rather than a whole DashfooStore — wire useDashfooStore and pass\n// store.model / store.dispatch.\nconst LayoutRoot = ({\n children,\n closableTabs = true,\n dispatch,\n draggableTabs = true,\n draggableTabsets = true,\n editable = true,\n floatable = false,\n keepMounted = false,\n maximizable = true,\n model,\n renamableTabs = true,\n renderTab,\n renderTabLabel,\n renderTabsetToolbar,\n resizableSplits = true,\n rootRef,\n snap,\n style,\n ...props\n}: LayoutRootProps): ReactNode => {\n // Model-level globals act as a default layer under the component props: a\n // feature is on unless the prop, the global, or the per-node flag turns it off.\n // `editable` is an extra AND-term over every structural capability — but not\n // maximize, which is reversible view state (same class as tab selection) and\n // stays available in a static layout.\n const global = model.global;\n const snapshot: LayoutState = {\n closableTabs: editable && closableTabs && global.tabEnableClose !== false,\n dispatch,\n draggableTabs: editable && draggableTabs && global.tabEnableDrag !== false,\n draggableTabsets: editable && draggableTabsets,\n editable,\n floatable: editable && floatable,\n keepMounted,\n maximizable: maximizable && global.tabSetEnableMaximize !== false,\n maximizedTabsetId: model.maximizedTabsetId,\n renamableTabs: editable && renamableTabs && global.tabEnableRename !== false,\n renderTab,\n renderTabLabel,\n renderTabsetToolbar,\n resizableSplits: editable && resizableSplits && global.enableSplitResize !== false,\n snap: snap ?? global.snap ?? null,\n splitDock: global.enableSplitDock !== false,\n tabLocation: global.tabLocation ?? \"top\",\n tabsetMinSize: global.tabSetMinSize ?? DEFAULT_TABSET_MIN_SIZE,\n tabStripEnabled: global.tabSetEnableTabStrip !== false,\n };\n\n const [store] = useState(() => createLayoutStore(snapshot));\n // Props→store sync. useLayoutEffect so subscribers see fresh state before\n // paint; never during render — setState on an external store mid-render is\n // unsafe.\n useLayoutEffect(() => {\n store.setState(snapshot);\n });\n\n const layoutStyle: CSSProperties =\n global.splitterSize === undefined\n ? { ...rootStyle, ...style }\n : ({\n ...rootStyle,\n \"--dashfoo-splitter-size\": `${global.splitterSize}px`,\n ...style,\n } as CSSProperties);\n\n return (\n <LayoutStoreContext.Provider value={store}>\n <div {...props} data-dashfoo=\"layout\" ref={rootRef} style={layoutStyle}>\n {children}\n </div>\n </LayoutStoreContext.Provider>\n );\n};\n\nexport { LayoutRoot };\nexport type { LayoutRootProps };\n","// Stable ids wiring each tab to its panel (aria-controls / aria-labelledby).\n// Shared by tabset-view and tab-button so the wiring stays in one place with no\n// circular import between those two modules.\nconst tabDomId = (tabsetId: string, tabId: string): string => `dashfoo-tab-${tabsetId}-${tabId}`;\nconst panelDomId = (tabsetId: string): string => `dashfoo-panel-${tabsetId}`;\n\nexport { panelDomId, tabDomId };\n","\"use client\";\n\nimport type { Action, TabNode, TabsetNode } from \"@dashfoo/core\";\nimport { createContext, useContext } from \"react\";\nimport type { StoreApi } from \"zustand\";\nimport { createStore, useStore } from \"zustand\";\n\nimport { tabDomId } from \"../../lib/tab-ids\";\nimport { warnOnce } from \"../../lib/warn-once\";\nimport type { OverflowItem } from \"../tab-overflow\";\n\n// The per-tabset coordination store behind <Tabset.Root>. Model-derived fields\n// (node, visualSelected, flags) are synced in by Root each render; coordination\n// state (editingTabId, overflowItems, tablistElement, restoreFocus) lives here\n// so sibling parts stay in lockstep without prop threading; actions read live\n// state via get(). editingTabId being a single field guarantees at most one open\n// rename editor per tabset. restoreFocus is set by closeTab so Root's post-delete\n// effect knows to move focus to the newly-selected tab instead of leaving it on\n// <body>.\ntype TabsetState = {\n activeTab: TabNode | undefined;\n cancelRename: () => void;\n closeTab: (tabId: string) => void;\n commitRename: (tabId: string, value: string) => void;\n dispatch: (action: Action) => void;\n editingTabId: string | null;\n isMaximized: boolean;\n node: TabsetNode;\n overflowItems: Array<OverflowItem>;\n registerRenameInput: () => () => void;\n registerTablist: (element: HTMLDivElement | null) => void;\n renameInputCount: number;\n renameTab: (tabId: string, name: string) => void;\n restoreFocus: boolean;\n selectOverflowTab: (tabId: string) => void;\n selectTab: (index: number, options?: { focus?: boolean }) => void;\n showMaximize: boolean;\n startEditing: (tabId: string) => void;\n tablistElement: HTMLDivElement | null;\n tabsClosable: boolean;\n tabsRenamable: boolean;\n toggleMaximize: () => void;\n visualSelected: number;\n};\n\ntype TabsetStore = StoreApi<TabsetState>;\n\ntype TabsetSnapshot = Pick<\n TabsetState,\n | \"activeTab\"\n | \"dispatch\"\n | \"isMaximized\"\n | \"node\"\n | \"showMaximize\"\n | \"tabsClosable\"\n | \"tabsRenamable\"\n | \"visualSelected\"\n>;\n\nconst tabButtonIn = (\n scope: HTMLElement | null,\n tabsetId: string,\n tabId: string,\n): HTMLElement | null =>\n scope?.querySelector<HTMLElement>(`#${CSS.escape(tabDomId(tabsetId, tabId))}`) ?? null;\n\nconst createTabsetStore = (initial: TabsetSnapshot): TabsetStore =>\n createStore<TabsetState>((set, get) => ({\n ...initial,\n cancelRename: () => set({ editingTabId: null }),\n closeTab: (tabId) => {\n set({ restoreFocus: true });\n get().dispatch({ tabId, type: \"deleteTab\" });\n },\n commitRename: (tabId, value) => {\n set({ editingTabId: null });\n const { node, renameTab } = get();\n const trimmed = value.trim();\n const current = node.children.find((tab) => tab.id === tabId)?.name;\n if (trimmed && trimmed !== current) {\n renameTab(tabId, trimmed);\n }\n },\n editingTabId: null,\n overflowItems: [],\n registerRenameInput: () => {\n set((state) => ({ renameInputCount: state.renameInputCount + 1 }));\n return () => set((state) => ({ renameInputCount: state.renameInputCount - 1 }));\n },\n registerTablist: (element) => {\n if (element) {\n const current = get().tablistElement;\n if (current && current !== element) {\n warnOnce(\n `duplicate-tablist-${get().node.id}`,\n \"more than one <Tabset.Tablist> under the same <Tabset.Root>; the last one wins for keyboard focus and overflow\",\n );\n }\n set({ tablistElement: element });\n return;\n }\n set({ tablistElement: null });\n },\n renameInputCount: 0,\n renameTab: (tabId, name) => get().dispatch({ name, tabId, type: \"renameTab\" }),\n restoreFocus: false,\n selectOverflowTab: (tabId) => {\n const { dispatch, node, tablistElement } = get();\n const index = node.children.findIndex((tab) => tab.id === tabId);\n if (index === -1) {\n return;\n }\n dispatch({ index, tabsetId: node.id, type: \"selectTab\" });\n tabButtonIn(tablistElement, node.id, tabId)?.scrollIntoView({\n block: \"nearest\",\n inline: \"nearest\",\n });\n },\n selectTab: (index, options) => {\n const { dispatch, node, tablistElement } = get();\n dispatch({ index, tabsetId: node.id, type: \"selectTab\" });\n if (options?.focus) {\n const tabId = node.children[index]?.id;\n if (tabId) {\n tabButtonIn(tablistElement, node.id, tabId)?.focus();\n }\n }\n },\n startEditing: (tabId) => {\n const { node, renameInputCount, tabsRenamable } = get();\n const tab = node.children.find((child) => child.id === tabId);\n if (!tabsRenamable || tab?.enableRename === false) {\n return;\n }\n if (renameInputCount === 0) {\n // The trigger must not vanish into nothing when no editor is composed.\n warnOnce(\n `missing-rename-input-${node.id}`,\n \"startEditing needs a <Tabset.RenameInput> in the composition; ignoring\",\n );\n return;\n }\n set({ editingTabId: tabId });\n },\n tablistElement: null,\n toggleMaximize: () => {\n const { dispatch, isMaximized, node } = get();\n dispatch({ tabsetId: isMaximized ? null : node.id, type: \"setMaximizedTabset\" });\n },\n }));\n\n// Carries only the store instance — state always flows through selectors.\nconst TabsetStoreContext = createContext<TabsetStore | null>(null);\n\nconst useTabset = <T>(selector: (state: TabsetState) => T): T => {\n const store = useContext(TabsetStoreContext);\n if (store === null) {\n throw new Error(\"dashfoo Tabset parts must be rendered inside <Tabset.Root>.\");\n }\n return useStore(store, selector);\n};\n\n// Identity only — which tab a Trigger/CloseButton/RenameInput belongs to.\n// Derived state (selected, editing) comes from useTabset selectors.\ntype TabContextValue = { index: number; tab: TabNode };\n\nconst TabContext = createContext<TabContextValue | null>(null);\n\nconst useTab = (): TabContextValue => {\n const value = useContext(TabContext);\n if (value === null) {\n throw new Error(\"dashfoo tab parts must be rendered inside <Tabset.Tab>.\");\n }\n return value;\n};\n\nexport { createTabsetStore, TabContext, TabsetStoreContext, useTab, useTabset };\nexport type { TabContextValue, TabsetSnapshot, TabsetState, TabsetStore };\n","\"use client\";\n\nimport type { TabNode } from \"@dashfoo/core\";\nimport type { ComponentProps, CSSProperties, ReactNode } from \"react\";\n\nimport { useLayout } from \"../../hooks/layout-store\";\nimport { panelDomId, tabDomId } from \"../../lib/tab-ids\";\n\nimport { useTabset } from \"./tabset-store\";\n\nconst contentStyle: CSSProperties = { flex: 1, minHeight: 0, overflow: \"auto\" };\n\n// Content is resolved through a component (not inline) so the panel has a stable\n// element identity and React keeps its state across re-renders instead of\n// remounting the inline result. Covers both the registry default (renderTab)\n// and a consumer-supplied render prop.\nconst TabPanel = ({\n render,\n tab,\n}: {\n render?: (tab: TabNode) => ReactNode;\n tab: TabNode;\n}): ReactNode => {\n const renderTab = useLayout((state) => state.renderTab);\n return render ? render(tab) : renderTab(tab);\n};\n\ntype TabsetContentProps = Omit<ComponentProps<\"div\">, \"children\"> & {\n // Overrides the layout's renderTab for this tabset's panels.\n children?: (tab: TabNode) => ReactNode;\n};\n\nconst TabsetContent = ({ children, style, ...props }: TabsetContentProps): ReactNode => {\n const node = useTabset((state) => state.node);\n const visualSelected = useTabset((state) => state.visualSelected);\n const keepMounted = useLayout((state) => state.keepMounted);\n\n const mergedStyle = { ...contentStyle, ...style };\n\n // keepMounted renders every panel (inactive ones hidden) so their state\n // survives a tab switch; otherwise only the active panel mounts.\n if (keepMounted && node.children.length > 0) {\n return node.children.map((tab, index) => (\n <div\n {...props}\n aria-labelledby={tabDomId(node.id, tab.id)}\n data-dashfoo=\"tabcontent\"\n hidden={index !== visualSelected || undefined}\n id={index === visualSelected ? panelDomId(node.id) : undefined}\n key={tab.id}\n role={index === visualSelected ? \"tabpanel\" : undefined}\n style={mergedStyle}\n tabIndex={index === visualSelected ? 0 : undefined}\n >\n <TabPanel render={children} tab={tab} />\n </div>\n ));\n }\n\n const active = node.children[visualSelected];\n if (active) {\n return (\n <div\n {...props}\n aria-labelledby={tabDomId(node.id, active.id)}\n data-dashfoo=\"tabcontent\"\n id={panelDomId(node.id)}\n role=\"tabpanel\"\n style={mergedStyle}\n tabIndex={0}\n >\n <TabPanel render={children} tab={active} />\n </div>\n );\n }\n return <div {...props} data-dashfoo=\"tabcontent\" style={mergedStyle} />;\n};\n\nexport { TabsetContent };\nexport type { TabsetContentProps };\n","\"use client\";\n\nimport type { CSSProperties, FocusEvent, KeyboardEvent, ReactNode } from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nconst OverflowIcon = (): ReactNode => (\n <svg aria-hidden=\"true\" fill=\"currentColor\" height=\"10\" viewBox=\"0 0 10 10\" width=\"10\">\n <circle cx=\"2\" cy=\"5\" r=\"1\" />\n <circle cx=\"5\" cy=\"5\" r=\"1\" />\n <circle cx=\"8\" cy=\"5\" r=\"1\" />\n </svg>\n);\n\nconst menuStyle: CSSProperties = {\n position: \"absolute\",\n right: 0,\n top: \"100%\",\n zIndex: 10,\n};\n\ntype OverflowItem = { id: string; name: string };\n\n// A dependency-free overflow control: a button that toggles a menu of the hidden\n// tabs. Implements the WAI-ARIA APG menu-button keyboard model — roving tabindex,\n// arrow/Home/End navigation, Escape-to-close with focus return. Closes on outside\n// pointerdown and focusout.\nconst TabOverflowMenu = ({\n items,\n onSelect,\n}: {\n items: Array<OverflowItem>;\n onSelect: (id: string) => void;\n}): ReactNode => {\n const [open, setOpen] = useState(false);\n const [activeIndex, setActiveIndex] = useState(0);\n const rootRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n useEffect(() => {\n if (!open) {\n return;\n }\n const handlePointerDown = (event: PointerEvent): void => {\n if (event.target instanceof Node && !rootRef.current?.contains(event.target)) {\n setOpen(false);\n }\n };\n document.addEventListener(\"pointerdown\", handlePointerDown);\n return () => {\n document.removeEventListener(\"pointerdown\", handlePointerDown);\n };\n }, [open]);\n\n // moving DOM focus onto the first menuitem is a side effect of the menu becoming\n // visible, so it belongs in an effect rather than the click handler (the items don't\n // exist yet there). activeIndex is reset to 0 on open, so we always land on the first.\n useEffect(() => {\n if (open) {\n itemRefs.current[0]?.focus();\n }\n }, [open]);\n\n const closeAndReturnFocus = (): void => {\n setOpen(false);\n triggerRef.current?.focus();\n };\n\n const focusItem = (index: number): void => {\n setActiveIndex(index);\n itemRefs.current[index]?.focus();\n };\n\n const handleToggle = (): void => {\n setActiveIndex(0);\n setOpen((value) => !value);\n };\n\n const handleSelect = (id: string): void => {\n onSelect(id);\n closeAndReturnFocus();\n };\n\n const handleMenuKeyDown = (event: KeyboardEvent<HTMLDivElement>): void => {\n const last = items.length - 1;\n switch (event.key) {\n case \"ArrowDown\": {\n event.preventDefault();\n focusItem(activeIndex >= last ? 0 : activeIndex + 1);\n break;\n }\n case \"ArrowUp\": {\n event.preventDefault();\n focusItem(activeIndex <= 0 ? last : activeIndex - 1);\n break;\n }\n case \"Home\": {\n event.preventDefault();\n focusItem(0);\n break;\n }\n case \"End\": {\n event.preventDefault();\n focusItem(last);\n break;\n }\n case \"Escape\": {\n event.preventDefault();\n closeAndReturnFocus();\n break;\n }\n default: {\n break;\n }\n }\n };\n\n // Tab out of the menu (or any other focus leaving the root) closes it without\n // stealing focus, complementing the outside-pointerdown handler for keyboard users.\n const handleFocusOut = (event: FocusEvent<HTMLDivElement>): void => {\n if (event.relatedTarget instanceof Node && rootRef.current?.contains(event.relatedTarget)) {\n return;\n }\n setOpen(false);\n };\n\n return (\n <div data-dashfoo=\"tab-overflow-root\" ref={rootRef} style={{ position: \"relative\" }}>\n <button\n aria-expanded={open}\n aria-haspopup=\"menu\"\n aria-label=\"More tabs\"\n data-dashfoo=\"tab-overflow\"\n onClick={handleToggle}\n ref={triggerRef}\n title=\"More tabs\"\n type=\"button\"\n >\n <OverflowIcon />\n </button>\n {open ? (\n <div\n data-dashfoo=\"tab-overflow-menu\"\n onBlur={handleFocusOut}\n onKeyDown={handleMenuKeyDown}\n role=\"menu\"\n style={menuStyle}\n tabIndex={-1}\n >\n {items.map((item, index) => (\n <button\n data-dashfoo=\"tab-overflow-item\"\n key={item.id}\n onClick={() => handleSelect(item.id)}\n ref={(node) => {\n itemRefs.current[index] = node;\n }}\n role=\"menuitem\"\n tabIndex={index === activeIndex ? 0 : -1}\n type=\"button\"\n >\n {item.name}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n );\n};\n\nexport { TabOverflowMenu };\nexport type { OverflowItem };\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport { TabOverflowMenu } from \"../tab-overflow\";\n\nimport { useTabset } from \"./tabset-store\";\n\n// The menu of tabs clipped out of the tablist's visible box. Measurement lives\n// in Tabset.Root (the store's overflowItems); this part only renders the\n// APG menu-button when there is something to show.\nconst TabsetOverflowMenu = (): ReactNode => {\n const overflowItems = useTabset((state) => state.overflowItems);\n const selectOverflowTab = useTabset((state) => state.selectOverflowTab);\n\n if (overflowItems.length === 0) {\n return null;\n }\n return <TabOverflowMenu items={overflowItems} onSelect={selectOverflowTab} />;\n};\n\nexport { TabsetOverflowMenu };\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\n// The ids of the tabs clipped by the tablist's visible box — past the right edge\n// OR scrolled off before the left edge. +/-1 absorbs sub-pixel rounding. One\n// pass: keep the id only when the tab is both overflowing and identifiable.\nconst overflowingIds = (tablist: Element): Array<string> => {\n const box = tablist.getBoundingClientRect();\n return [...tablist.querySelectorAll<HTMLElement>('[data-dashfoo=\"tab\"]')].flatMap((tab) => {\n const rect = tab.getBoundingClientRect();\n const clipped = rect.right > box.right + 1 || rect.left < box.left - 1;\n return clipped && tab.dataset.tabId ? [tab.dataset.tabId] : [];\n });\n};\n\n// Recomputes the overflowing ids when the tablist resizes, scrolls, or its tab\n// labels/widths change. Takes the element (not a ref) so a tablist that mounts\n// late — or is swapped by a custom composition — re-arms the observers.\n// `signature` folds tab id+name so renames recompute even when the count is\n// unchanged. Returns [] until measured (and in jsdom, where rects are 0).\nconst useTabOverflow = (tablist: HTMLElement | null, signature: string): Array<string> => {\n const [overflow, setOverflow] = useState<Array<string>>([]);\n\n useEffect(() => {\n // No tablist (e.g. the strip is disabled) means nothing can overflow.\n const recompute = (): void => {\n setOverflow((previous) => {\n const next = tablist ? overflowingIds(tablist) : [];\n return next.length === 0 && previous.length === 0 ? previous : next;\n });\n };\n recompute();\n if (!tablist) {\n return;\n }\n const observer = new ResizeObserver(recompute);\n observer.observe(tablist);\n // Scrolling the strip changes which tabs are clipped on the left/right without\n // resizing it, so listen for scroll too.\n tablist.addEventListener(\"scroll\", recompute, { passive: true });\n return () => {\n observer.disconnect();\n tablist.removeEventListener(\"scroll\", recompute);\n };\n }, [tablist, signature]);\n\n return overflow;\n};\n\nexport { overflowingIds, useTabOverflow };\n","// The neighbour to show as active when the selected tab is dragged out: the next\n// tab if there is one, else the previous, else -1 (the tabset is emptying).\nconst fallbackSelectedIndex = (count: number, removedIndex: number): number =>\n removedIndex + 1 < count ? removedIndex + 1 : removedIndex - 1;\n\nexport { fallbackSelectedIndex };\n","\"use client\";\n\nimport type { TabsetNode } from \"@dashfoo/core\";\nimport type { ComponentProps, CSSProperties, ReactNode } from \"react\";\nimport { useEffect, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport { useStore } from \"zustand\";\n\nimport { useLayout } from \"../../hooks/layout-store\";\nimport { useTabOverflow } from \"../../hooks/use-tab-overflow\";\nimport { tabDomId } from \"../../lib/tab-ids\";\nimport { fallbackSelectedIndex } from \"../../lib/tab-selection\";\nimport { useDragSubject, useTabsetDroppable } from \"../drag-adapter\";\n\nimport type { TabsetSnapshot } from \"./tabset-store\";\nimport { createTabsetStore, TabsetStoreContext } from \"./tabset-store\";\n\n// height/width 100% (not flex:1) so the tabset fills its parent whether that\n// parent is a flex item or a plain block — rrp wraps panel content in a block\n// div, where flex:1 would collapse to content height.\nconst tabsetStyle: CSSProperties = {\n display: \"flex\",\n flexDirection: \"column\",\n height: \"100%\",\n minHeight: 0,\n minWidth: 0,\n width: \"100%\",\n};\n\ntype TabsetRootProps = ComponentProps<\"div\"> & { node: TabsetNode };\n\n// Creates the per-tabset store and owns everything that needs the whole tabset:\n// the droppable registration, the drag-out selection fallback, overflow\n// measurement, and focus restore after a close.\nconst TabsetRoot = ({\n children,\n node,\n ref: userRef,\n style,\n ...props\n}: TabsetRootProps): ReactNode => {\n const closableTabs = useLayout((state) => state.closableTabs);\n const dispatch = useLayout((state) => state.dispatch);\n const maximizable = useLayout((state) => state.maximizable);\n const maximizedTabsetId = useLayout((state) => state.maximizedTabsetId);\n const renamableTabs = useLayout((state) => state.renamableTabs);\n const tabLocation = useLayout((state) => state.tabLocation);\n\n const { ref } = useTabsetDroppable(node.id);\n const dragSubject = useDragSubject();\n const tabsetRef = useRef<HTMLDivElement | null>(null);\n\n const isMaximized = maximizedTabsetId === node.id;\n const showMaximize = maximizable && node.enableMaximize !== false;\n const tabsClosable = closableTabs && node.enableClose !== false;\n // Renaming has no tabset-level flag — only the layout flag and per-tab opt-out.\n const tabsRenamable = renamableTabs;\n\n // While the selected tab is being dragged out of THIS tabset, show a neighbour\n // as active so the strip + content preview \"as if that tab were already gone\".\n // Purely visual — the model selection is untouched and resumes on drop/cancel.\n const draggingTabIndex =\n dragSubject?.kind === \"tab\" ? node.children.findIndex((tab) => tab.id === dragSubject.id) : -1;\n const visualSelected =\n draggingTabIndex !== -1 && draggingTabIndex === node.selected\n ? fallbackSelectedIndex(node.children.length, draggingTabIndex)\n : node.selected;\n const activeTab = node.children[visualSelected];\n const isDragSource = dragSubject?.kind === \"tabset\" && dragSubject.id === node.id;\n\n const snapshot: TabsetSnapshot = {\n activeTab,\n dispatch,\n isMaximized,\n node,\n showMaximize,\n tabsClosable,\n tabsRenamable,\n visualSelected,\n };\n const [store] = useState(() => createTabsetStore(snapshot));\n\n // Props→store sync. useLayoutEffect (not useEffect) so subscribers re-render\n // before paint and DOM-focus effects below see fresh state; never during\n // render — setState on an external store mid-render is unsafe.\n useLayoutEffect(() => {\n store.setState(snapshot);\n });\n\n // Overflow measurement runs here (not in the menu part) because the default\n // composition's toolbar-visibility condition needs the count, and the tablist\n // element registration already lives in the store.\n const tablistElement = useStore(store, (state) => state.tablistElement);\n // A rename or scroll changes clipping without changing the count, so the\n // signature folds each tab's id+name into the deps the hook watches.\n const overflowSignature = node.children.map((tab) => `${tab.id}:${tab.name}`).join(\"|\");\n const overflow = useTabOverflow(tablistElement, overflowSignature);\n // Resolve overflowing ids to names once per change instead of a find() per item.\n const overflowItems = useMemo(() => {\n const names = new Map(node.children.map((tab) => [tab.id, tab.name]));\n return overflow.map((id) => ({ id, name: names.get(id) ?? id }));\n }, [overflow, node.children]);\n useLayoutEffect(() => {\n store.setState({ overflowItems });\n }, [overflowItems, store]);\n\n // Runs after a closeTab commits. Focus the now-active tab's button, or fall\n // back to the tabset container if the tabset emptied so focus never lands on\n // <body>. Scoped to the root (not the tablist) so tabs rendered outside a\n // tablist still get focus restore.\n useEffect(() => {\n if (!store.getState().restoreFocus) {\n return;\n }\n store.setState({ restoreFocus: false });\n const activeTabId = node.children[node.selected]?.id;\n if (activeTabId) {\n tabsetRef.current\n ?.querySelector<HTMLElement>(`#${CSS.escape(tabDomId(node.id, activeTabId))}`)\n ?.focus();\n } else {\n tabsetRef.current?.focus();\n }\n }, [node.children, node.selected, node.id, store]);\n\n return (\n <TabsetStoreContext.Provider value={store}>\n <div\n {...props}\n data-dashfoo=\"tabset\"\n data-dragging-source={isDragSource || undefined}\n data-tab-location={tabLocation}\n ref={(element) => {\n ref(element);\n tabsetRef.current = element;\n if (typeof userRef === \"function\") {\n userRef(element);\n } else if (userRef) {\n userRef.current = element;\n }\n }}\n style={{ ...tabsetStyle, ...style }}\n // -1 so an emptied tabset can receive focus on close without entering the\n // Tab order.\n tabIndex={-1}\n >\n {children}\n </div>\n </TabsetStoreContext.Provider>\n );\n};\n\nexport { TabsetRoot };\nexport type { TabsetRootProps };\n","import type { Ref } from \"react\";\n\nconst applyRef = <T>(ref: Ref<T> | undefined, value: T | null): void => {\n if (typeof ref === \"function\") {\n ref(value);\n } else if (ref) {\n ref.current = value;\n }\n};\n\n// Fans one element out to several refs so a part can keep its internal ref\n// (draggable wiring, focus lookups) while still honoring a consumer-supplied one.\nconst mergeRefs =\n <T>(...refs: Array<Ref<T> | undefined>) =>\n (value: T | null): void => {\n for (const ref of refs) {\n applyRef(ref, value);\n }\n };\n\nexport { mergeRefs };\n","\"use client\";\n\nimport type { TabNode } from \"@dashfoo/core\";\nimport type { ComponentProps, MouseEvent, ReactNode } from \"react\";\nimport { useContext, useEffect, useMemo, useRef } from \"react\";\n\nimport { useLayout } from \"../../hooks/layout-store\";\nimport { mergeRefs } from \"../../lib/merge-refs\";\nimport { panelDomId, tabDomId } from \"../../lib/tab-ids\";\nimport { warnOnce } from \"../../lib/warn-once\";\nimport { useDragSubject, useTabDraggable } from \"../drag-adapter\";\n\nimport { TabContext, TabsetStoreContext, useTab, useTabset } from \"./tabset-store\";\n\ntype TabsetTabProps = ComponentProps<\"span\"> & { tab: TabNode };\n\n// The per-tab wrapper: provides identity (which tab, which index) to Trigger,\n// CloseButton, and RenameInput, and owns the focus-return-after-rename effect.\nconst TabsetTab = ({ children, ref: userRef, tab, ...props }: TabsetTabProps): ReactNode => {\n const store = useContext(TabsetStoreContext);\n const node = useTabset((state) => state.node);\n const editing = useTabset((state) => state.editingTabId === tab.id);\n // `data-dragging` is driven off the drag machine's subject, which is\n // authoritative for the whole drag — the source tab stays in the strip (dimmed)\n // while the overlay chip follows the pointer.\n const dragSubject = useDragSubject();\n const isDragging = dragSubject?.kind === \"tab\" && dragSubject.id === tab.id;\n const itemRef = useRef<HTMLSpanElement | null>(null);\n const wasEditing = useRef(false);\n\n const index = node.children.findIndex((child) => child.id === tab.id);\n\n // The orphan check must not run at render time: right after a tab moves\n // between tabsets, this render sees the new `tab` prop against the store's\n // not-yet-synced node, so a legitimately moved tab transiently looks\n // orphaned (the index self-corrects before paint). The effect reads the live\n // store instead — Root's layout-effect sync always lands before any passive\n // effect flushes, so only a genuinely missing tab warns.\n const orphanAtRender = index === -1;\n useEffect(() => {\n const settled = store?.getState().node.children.some((child) => child.id === tab.id);\n if (settled === false) {\n warnOnce(\n `orphan-tab-${tab.id}`,\n `<Tabset.Tab> for \"${tab.id}\" is not a child of its Tabset.Root's node; it renders but can never be selected`,\n );\n }\n }, [orphanAtRender, store, tab.id]);\n\n // Return focus to the tab button once the inline editor closes.\n useEffect(() => {\n if (wasEditing.current && !editing) {\n itemRef.current?.querySelector<HTMLElement>('[data-dashfoo=\"tab\"]')?.focus();\n }\n wasEditing.current = editing;\n }, [editing]);\n\n const contextValue = useMemo(() => ({ index, tab }), [index, tab]);\n const refCallback = useMemo(() => mergeRefs<HTMLSpanElement>(itemRef, userRef), [userRef]);\n\n return (\n <TabContext.Provider value={contextValue}>\n <span\n {...props}\n data-dashfoo=\"tab-item\"\n data-dragging={isDragging || undefined}\n ref={refCallback}\n >\n {children}\n </span>\n </TabContext.Provider>\n );\n};\n\ntype TabsetTriggerProps = ComponentProps<\"button\">;\n\n// The tab button itself — a sibling of the close control (not its parent, which\n// would be invalid markup and would pollute the tab's accessible name). Hidden\n// while the rename editor is open; the draggable hook stays mounted so the\n// Draggable instance survives the swap.\nconst TabsetTrigger = ({\n children,\n onClick,\n onDoubleClick,\n ref: userRef,\n ...props\n}: TabsetTriggerProps): ReactNode => {\n const { index, tab } = useTab();\n const node = useTabset((state) => state.node);\n const editing = useTabset((state) => state.editingTabId === tab.id);\n const selectTab = useTabset((state) => state.selectTab);\n const startEditing = useTabset((state) => state.startEditing);\n const tabsRenamable = useTabset((state) => state.tabsRenamable);\n const visualSelected = useTabset((state) => state.visualSelected);\n const draggableTabs = useLayout((state) => state.draggableTabs);\n const renderTabLabel = useLayout((state) => state.renderTabLabel);\n const { ref } = useTabDraggable(tab.id, !draggableTabs || tab.enableDrag === false, tab.name);\n const refCallback = useMemo(() => mergeRefs<HTMLButtonElement>(ref, userRef), [ref, userRef]);\n\n if (editing) {\n return null;\n }\n\n const selected = index === visualSelected;\n const renamable = tabsRenamable && tab.enableRename !== false;\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>): void => {\n onClick?.(event);\n selectTab(index);\n };\n\n const handleDoubleClick = (event: MouseEvent<HTMLButtonElement>): void => {\n onDoubleClick?.(event);\n if (renamable) {\n startEditing(tab.id);\n }\n };\n\n return (\n <button\n aria-label={renderTabLabel ? tab.name : undefined}\n {...props}\n aria-controls={panelDomId(node.id)}\n aria-selected={selected}\n data-dashfoo=\"tab\"\n data-tab-id={tab.id}\n id={tabDomId(node.id, tab.id)}\n onClick={handleClick}\n onDoubleClick={handleDoubleClick}\n ref={refCallback}\n role=\"tab\"\n tabIndex={selected ? 0 : -1}\n type=\"button\"\n >\n {children ?? (renderTabLabel ? renderTabLabel(tab) : tab.name)}\n </button>\n );\n};\n\nexport { TabsetTab, TabsetTrigger };\nexport type { TabsetTabProps, TabsetTriggerProps };\n","import type { CSSProperties, ReactNode } from \"react\";\n\nconst iconStyle: CSSProperties = { pointerEvents: \"none\" };\n\n// Shared lucide-style icon frame (24-unit grid, currentColor stroke). iconStyle\n// sets pointer-events:none so a pointerdown on a grip lands on the button (the\n// draggable), not the svg path — otherwise the drag sensor never activates.\nconst Icon = ({ children }: { children: ReactNode }): ReactNode => (\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n height=\"12\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n style={iconStyle}\n viewBox=\"0 0 24 24\"\n width=\"12\"\n >\n {children}\n </svg>\n);\n\nconst CloseIcon = (): ReactNode => (\n <Icon>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </Icon>\n);\n\nconst GripIcon = (): ReactNode => (\n <Icon>\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"19\" cy=\"5\" r=\"1\" />\n <circle cx=\"5\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"19\" cy=\"12\" r=\"1\" />\n <circle cx=\"5\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n <circle cx=\"19\" cy=\"19\" r=\"1\" />\n <circle cx=\"5\" cy=\"19\" r=\"1\" />\n </Icon>\n);\n\nconst MaximizeIcon = ({ maximized }: { maximized: boolean }): ReactNode =>\n maximized ? (\n <Icon>\n <path d=\"m14 10 7-7\" />\n <path d=\"M20 10h-6V4\" />\n <path d=\"m3 21 7-7\" />\n <path d=\"M4 14h6v6\" />\n </Icon>\n ) : (\n <Icon>\n <path d=\"M15 3h6v6\" />\n <path d=\"m21 3-7 7\" />\n <path d=\"m3 21 7-7\" />\n <path d=\"M9 21H3v-6\" />\n </Icon>\n );\n\n// \"Float\" — a small panel lifted off the surface (a framed rect with a header).\nconst FloatIcon = (): ReactNode => (\n <Icon>\n <rect height=\"14\" rx=\"2\" width=\"18\" x=\"3\" y=\"6\" />\n <path d=\"M3 10h18\" />\n </Icon>\n);\n\n// \"Minimize\" — collapse to a chip.\nconst MinimizeIcon = (): ReactNode => (\n <Icon>\n <path d=\"M5 12h14\" />\n </Icon>\n);\n\n// \"Dock back\" — an arrow returning into a frame.\nconst DockIcon = (): ReactNode => (\n <Icon>\n <path d=\"M3 7V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-2\" />\n <path d=\"M11 8 7 12l4 4\" />\n <path d=\"M7 12h10\" />\n </Icon>\n);\n\nexport { CloseIcon, DockIcon, FloatIcon, GripIcon, MaximizeIcon, MinimizeIcon };\n","\"use client\";\n\nimport type { ComponentProps, FocusEvent, KeyboardEvent, MouseEvent, ReactNode } from \"react\";\nimport { useEffect, useMemo, useRef } from \"react\";\n\nimport { mergeRefs } from \"../../lib/merge-refs\";\nimport { CloseIcon } from \"../tabset-icons\";\n\nimport { useTab, useTabset } from \"./tabset-store\";\n\ntype TabsetRenameInputProps = ComponentProps<\"input\">;\n\n// Inline rename editor. Enter/Escape set `done` so the unmount blur does not\n// re-commit after a deliberate commit or cancel. A separate inner component so\n// each editing session mounts fresh (autofocus + select, reset `done`).\nconst RenameEditor = ({\n defaultValue,\n onBlur,\n onKeyDown,\n ref: userRef,\n ...props\n}: TabsetRenameInputProps): ReactNode => {\n const { tab } = useTab();\n const cancelRename = useTabset((state) => state.cancelRename);\n const commitRename = useTabset((state) => state.commitRename);\n const ref = useRef<HTMLInputElement | null>(null);\n const done = useRef(false);\n const refCallback = useMemo(() => mergeRefs<HTMLInputElement>(ref, userRef), [userRef]);\n\n useEffect(() => {\n ref.current?.focus();\n ref.current?.select();\n }, []);\n\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>): void => {\n onKeyDown?.(event);\n if (event.key === \"Enter\") {\n done.current = true;\n commitRename(tab.id, event.currentTarget.value);\n } else if (event.key === \"Escape\") {\n done.current = true;\n cancelRename();\n }\n };\n\n const handleCommitOnBlur = (event: FocusEvent<HTMLInputElement>): void => {\n onBlur?.(event);\n if (done.current) {\n return;\n }\n done.current = true;\n commitRename(tab.id, event.currentTarget.value);\n };\n\n return (\n <input\n aria-label={`Rename ${tab.name}`}\n {...props}\n data-dashfoo=\"tab-rename\"\n defaultValue={defaultValue ?? tab.name}\n onBlur={handleCommitOnBlur}\n onKeyDown={handleKeyDown}\n ref={refCallback}\n type=\"text\"\n />\n );\n};\n\n// Renders only while its tab is being renamed. Always composed (it registers its\n// presence on mount so startEditing can warn when no editor exists), but inert\n// until the trigger's double-click flips editingTabId.\nconst TabsetRenameInput = (props: TabsetRenameInputProps): ReactNode => {\n const { tab } = useTab();\n const editing = useTabset((state) => state.editingTabId === tab.id);\n const registerRenameInput = useTabset((state) => state.registerRenameInput);\n\n useEffect(() => registerRenameInput(), [registerRenameInput]);\n\n if (!editing) {\n return null;\n }\n return <RenameEditor {...props} />;\n};\n\ntype TabsetCloseButtonProps = ComponentProps<\"button\">;\n\nconst TabsetCloseButton = ({ children, onClick, ...props }: TabsetCloseButtonProps): ReactNode => {\n const { index, tab } = useTab();\n const closeTab = useTabset((state) => state.closeTab);\n const editing = useTabset((state) => state.editingTabId === tab.id);\n const tabsClosable = useTabset((state) => state.tabsClosable);\n const visualSelected = useTabset((state) => state.visualSelected);\n\n const closable = tabsClosable && tab.enableClose !== false;\n if (!closable || editing) {\n return null;\n }\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>): void => {\n onClick?.(event);\n // Closing must not bubble into the trigger and select the closing tab.\n event.stopPropagation();\n closeTab(tab.id);\n };\n\n return (\n <button\n aria-label={`Close ${tab.name}`}\n title={`Close ${tab.name}`}\n {...props}\n data-dashfoo=\"tab-close\"\n onClick={handleClick}\n // Roving tabindex: only the active tab's close button is tabbable, so\n // Tab does not stop on a close button inside every tab in the tablist.\n tabIndex={index === visualSelected ? 0 : -1}\n type=\"button\"\n >\n {children ?? <CloseIcon />}\n </button>\n );\n};\n\nexport { TabsetCloseButton, TabsetRenameInput };\nexport type { TabsetCloseButtonProps, TabsetRenameInputProps };\n","\"use client\";\n\nimport type { ComponentProps, CSSProperties, KeyboardEvent, ReactNode } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { mergeRefs } from \"../../lib/merge-refs\";\n\nimport { useTabset } from \"./tabset-store\";\n\n// The strip is a presentational row: the tablist (the actual tabs) plus room for\n// a trailing toolbar. role=\"tablist\" lives on the inner tablist so the toolbar is\n// not announced as a tab. The drag adapter hit-tests [data-dashfoo=\"tabstrip\"],\n// so the attribute is applied after the spread — it is structural, not theming.\nconst stripStyle: CSSProperties = { display: \"flex\", flexShrink: 0 };\n\nconst tablistStyle: CSSProperties = { display: \"flex\", minWidth: 0, overflowX: \"auto\" };\n\ntype TabsetTabStripProps = ComponentProps<\"div\">;\n\nconst TabsetTabStrip = ({ style, ...props }: TabsetTabStripProps): ReactNode => (\n <div {...props} data-dashfoo=\"tabstrip\" style={{ ...stripStyle, ...style }} />\n);\n\ntype TabsetTablistProps = ComponentProps<\"div\">;\n\n// Owns the roving-tabindex keyboard model (WAI-ARIA APG Tabs): arrows move and\n// select, Home/End jump to the ends, and focus follows the new selection.\nconst TabsetTablist = ({\n onKeyDown,\n ref: userRef,\n style,\n ...props\n}: TabsetTablistProps): ReactNode => {\n const node = useTabset((state) => state.node);\n const registerTablist = useTabset((state) => state.registerTablist);\n const selectTab = useTabset((state) => state.selectTab);\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>): void => {\n onKeyDown?.(event);\n if (event.defaultPrevented) {\n return;\n }\n // Only act when the key comes from a tab — otherwise a focused close button\n // (a tablist child) would have its arrows/Home/End hijacked.\n if (!(event.target instanceof HTMLElement) || !event.target.closest('[role=\"tab\"]')) {\n return;\n }\n const count = node.children.length;\n if (count === 0) {\n return;\n }\n const targets: Record<string, number> = {\n ArrowLeft: (node.selected - 1 + count) % count,\n ArrowRight: (node.selected + 1) % count,\n End: count - 1,\n Home: 0,\n };\n const next = targets[event.key];\n if (next === undefined) {\n return;\n }\n event.preventDefault();\n selectTab(next, { focus: true });\n };\n\n // Stable callback ref so React doesn't detach/re-register the tablist on every\n // render (a fresh inline ref identity would churn the store registration).\n const refCallback = useMemo(\n () => mergeRefs<HTMLDivElement>(registerTablist, userRef),\n [registerTablist, userRef],\n );\n\n return (\n <div\n aria-label={node.name ?? \"Tabs\"}\n {...props}\n aria-orientation=\"horizontal\"\n data-dashfoo=\"tablist\"\n onKeyDown={handleKeyDown}\n ref={refCallback}\n role=\"tablist\"\n style={{ ...tablistStyle, ...style }}\n tabIndex={-1}\n />\n );\n};\n\nexport { TabsetTablist, TabsetTabStrip };\nexport type { TabsetTablistProps, TabsetTabStripProps };\n","\"use client\";\n\nimport type { ComponentProps, CSSProperties, MouseEvent, ReactNode } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { useLayout } from \"../../hooks/layout-store\";\nimport { measureFloatRect } from \"../../lib/float-geometry\";\nimport { mergeRefs } from \"../../lib/merge-refs\";\nimport { warnOnce } from \"../../lib/warn-once\";\nimport { useTabsetDraggable } from \"../drag-adapter\";\nimport { useHasFloatLayer } from \"../float-context\";\nimport { FloatIcon, GripIcon, MaximizeIcon } from \"../tabset-icons\";\n\nimport { useTabset } from \"./tabset-store\";\n\nconst toolbarStyle: CSSProperties = {\n alignItems: \"center\",\n display: \"flex\",\n flexShrink: 0,\n marginInlineStart: \"auto\",\n};\n\ntype TabsetToolbarProps = ComponentProps<\"div\">;\n\nconst TabsetToolbar = ({ style, ...props }: TabsetToolbarProps): ReactNode => (\n <div {...props} data-dashfoo=\"tabset-toolbar\" style={{ ...toolbarStyle, ...style }} />\n);\n\ntype TabsetGripProps = ComponentProps<\"button\">;\n\n// The whole tabset is draggable from its grip. It carries the active tab's name\n// so the drag overlay can label the chip. Self-hides when tabset dragging is off\n// or the tabset is maximized (nowhere to dock).\nconst TabsetGrip = ({ children, ref: userRef, ...props }: TabsetGripProps): ReactNode => {\n const activeTabName = useTabset((state) => state.activeTab?.name ?? \"\");\n const isMaximized = useTabset((state) => state.isMaximized);\n const node = useTabset((state) => state.node);\n const draggableTabsets = useLayout((state) => state.draggableTabsets);\n const hidden = !draggableTabsets || isMaximized;\n const { ref } = useTabsetDraggable(node.id, hidden, activeTabName);\n const refCallback = useMemo(() => mergeRefs<HTMLButtonElement>(ref, userRef), [ref, userRef]);\n\n if (hidden) {\n return null;\n }\n\n return (\n <button\n aria-label=\"Move tabset\"\n title=\"Move tabset\"\n {...props}\n data-dashfoo=\"tabset-grip\"\n ref={refCallback}\n type=\"button\"\n >\n {children ?? <GripIcon />}\n </button>\n );\n};\n\ntype TabsetMaximizeButtonProps = ComponentProps<\"button\">;\n\nconst TabsetMaximizeButton = ({\n children,\n onClick,\n ...props\n}: TabsetMaximizeButtonProps): ReactNode => {\n const isMaximized = useTabset((state) => state.isMaximized);\n const showMaximize = useTabset((state) => state.showMaximize);\n const toggleMaximize = useTabset((state) => state.toggleMaximize);\n\n if (!showMaximize) {\n return null;\n }\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>): void => {\n onClick?.(event);\n toggleMaximize();\n };\n\n return (\n <button\n aria-label={isMaximized ? \"Restore\" : \"Maximize\"}\n title={isMaximized ? \"Restore tabset\" : \"Maximize tabset\"}\n {...props}\n aria-pressed={isMaximized}\n data-dashfoo=\"tabset-maximize\"\n onClick={handleClick}\n type=\"button\"\n >\n {children ?? <MaximizeIcon maximized={isMaximized} />}\n </button>\n );\n};\n\ntype TabsetFloatButtonProps = ComponentProps<\"button\">;\n\n// Floats the whole tabset out into a draggable, resizable overlay (dispatches\n// `floatTabset` with a rect measured over the panel). Self-hides when floating is\n// off or the tabset is maximized (a maximized panel already owns the frame).\nconst TabsetFloatButton = ({ children, onClick, ...props }: TabsetFloatButtonProps): ReactNode => {\n const floatable = useLayout((state) => state.floatable);\n const dispatch = useLayout((state) => state.dispatch);\n const isMaximized = useTabset((state) => state.isMaximized);\n const node = useTabset((state) => state.node);\n const hasFloatLayer = useHasFloatLayer();\n\n if (!floatable || isMaximized) {\n return null;\n }\n\n // `floatable` is on but there is no <Layout.FloatLayer> to render the float (a\n // hand-built layout that forgot it — DashfooLayout always adds one). Hide the\n // control and warn rather than render a button that would float a panel into\n // nowhere.\n if (!hasFloatLayer) {\n warnOnce(\n \"float-no-layer\",\n \"Tabset.FloatButton needs a <Layout.FloatLayer> around the layout (DashfooLayout adds one); the float control is hidden\",\n );\n return null;\n }\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>): void => {\n onClick?.(event);\n const geometry = measureFloatRect(event.currentTarget);\n dispatch({ geometry, tabsetId: node.id, type: \"floatTabset\" });\n };\n\n return (\n <button\n aria-label=\"Float panel\"\n title=\"Float panel\"\n {...props}\n data-dashfoo=\"tabset-float\"\n onClick={handleClick}\n type=\"button\"\n >\n {children ?? <FloatIcon />}\n </button>\n );\n};\n\nexport { TabsetFloatButton, TabsetGrip, TabsetMaximizeButton, TabsetToolbar };\nexport type {\n TabsetFloatButtonProps,\n TabsetGripProps,\n TabsetMaximizeButtonProps,\n TabsetToolbarProps,\n};\n","\"use client\";\n\nimport type { TabsetNode } from \"@dashfoo/core\";\nimport type { ReactNode } from \"react\";\n\nimport { useLayout } from \"../../hooks/layout-store\";\n\nimport { TabsetContent } from \"./tabset-content\";\nimport { TabsetOverflowMenu } from \"./tabset-overflow\";\nimport { TabsetRoot } from \"./tabset-root\";\nimport { useTabset } from \"./tabset-store\";\nimport { TabsetTab, TabsetTrigger } from \"./tabset-tab\";\nimport { TabsetCloseButton, TabsetRenameInput } from \"./tabset-tab-controls\";\nimport { TabsetTablist, TabsetTabStrip } from \"./tabset-tablist\";\nimport {\n TabsetFloatButton,\n TabsetGrip,\n TabsetMaximizeButton,\n TabsetToolbar,\n} from \"./tabset-toolbar\";\n\n// Static JSX hoisted to module scope (elements are immutable, so one instance\n// is safely shared) — DefaultTabsetLayout re-renders on every selection change\n// and must not rebuild it each time.\nconst tabsetContent = <TabsetContent />;\n\n// The canonical composition of the Tabset parts — what DashfooLayout and\n// Layout.Rows render by default, and the reference for anyone composing the\n// parts by hand. Lives inside Tabset.Root because the toolbar-visibility\n// condition needs the store's overflow count.\nconst DefaultTabsetLayout = (): ReactNode => {\n const draggableTabsets = useLayout((state) => state.draggableTabsets);\n const floatable = useLayout((state) => state.floatable);\n const renderTabsetToolbar = useLayout((state) => state.renderTabsetToolbar);\n const tabLocation = useLayout((state) => state.tabLocation);\n const tabStripEnabled = useLayout((state) => state.tabStripEnabled);\n const isMaximized = useTabset((state) => state.isMaximized);\n const node = useTabset((state) => state.node);\n const overflowCount = useTabset((state) => state.overflowItems.length);\n const showMaximize = useTabset((state) => state.showMaximize);\n\n // The toolbar exists only when it has content; each part also self-hides so\n // the condition and the parts can never disagree.\n const showToolbar =\n showMaximize ||\n renderTabsetToolbar !== undefined ||\n overflowCount > 0 ||\n (floatable && !isMaximized) ||\n (draggableTabsets && !isMaximized);\n\n const strip = tabStripEnabled ? (\n <TabsetTabStrip>\n <TabsetTablist>\n {node.children.map((tab) => (\n <TabsetTab key={tab.id} tab={tab}>\n <TabsetTrigger />\n <TabsetRenameInput />\n <TabsetCloseButton />\n </TabsetTab>\n ))}\n </TabsetTablist>\n {showToolbar ? (\n <TabsetToolbar>\n <TabsetOverflowMenu />\n <TabsetGrip />\n {renderTabsetToolbar?.(node)}\n <TabsetFloatButton />\n <TabsetMaximizeButton />\n </TabsetToolbar>\n ) : null}\n </TabsetTabStrip>\n ) : null;\n\n return tabLocation === \"bottom\" ? (\n <>\n {tabsetContent}\n {strip}\n </>\n ) : (\n <>\n {strip}\n {tabsetContent}\n </>\n );\n};\n\ntype TabsetViewProps = { node: TabsetNode };\n\nconst TabsetView = ({ node }: TabsetViewProps): ReactNode => (\n <TabsetRoot node={node}>\n <DefaultTabsetLayout />\n </TabsetRoot>\n);\n\nexport { TabsetView };\nexport type { TabsetViewProps };\n","\"use client\";\n\nimport type { Dimension, RowNode, SnapConfig, TabsetNode } from \"@dashfoo/core\";\nimport { snapEnabled, snapSizes } from \"@dashfoo/core\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { Fragment, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport type { GroupImperativeHandle, Layout, Orientation } from \"react-resizable-panels\";\nimport { Group, Panel, Separator } from \"react-resizable-panels\";\n\nimport { useLayout } from \"../hooks/layout-store\";\n\nimport { TabsetView } from \"./tabset/tabset-view\";\n\n// This module is the resize adapter: the only place that imports\n// react-resizable-panels. It maps the model's responsive weights to rrp's\n// percentage layout and unit-typed min/max constraints to rrp sizes, and commits\n// a drag (on release) back to the document as an adjustSplit action.\n//\n// Magnetic snapping is layered on top: rrp's continuous onLayoutChange pulls the\n// dragged boundary onto a grid (groupRef.setLayout), and onLayoutChanged commits\n// the already-snapped weights as a single undo step on release.\n\nconst dimensionToSize = (dimension: Dimension): string => `${dimension.value}${dimension.unit}`;\nconst dimensionToPixels = (dimension: Dimension | undefined): number | undefined =>\n dimension?.unit === \"px\" ? dimension.value : undefined;\n\nconst groupStyle: CSSProperties = { display: \"flex\", flex: 1, minHeight: 0, minWidth: 0 };\nconst WEIGHT_EPSILON = 0.01;\n\ntype LayoutChild = RowNode[\"children\"][number];\n\nconst layoutFromWeights = (children: RowNode[\"children\"], total: number): Layout =>\n children.reduce<Layout>((layout, child) => {\n layout[child.id] = ((child.weight ?? 1) / total) * 100;\n return layout;\n }, {});\n\n// rrp's id-keyed Layout <-> the ordered percentage array the pure snap math wants.\nconst orderedFromLayout = (layout: Layout, children: RowNode[\"children\"]): Array<number> =>\n children.map((child) => layout[child.id] ?? 0);\n\nconst layoutFromOrdered = (sizes: Array<number>, children: RowNode[\"children\"]): Layout =>\n children.reduce<Layout>((layout, child, index) => {\n layout[child.id] = sizes[index] ?? 0;\n return layout;\n }, {});\n\nconst layoutsMatch = (current: Layout, expected: Layout): boolean => {\n const currentIds = Object.keys(current);\n const expectedIds = Object.keys(expected);\n if (currentIds.length !== expectedIds.length) {\n return false;\n }\n return expectedIds.every(\n (id) => Math.abs((current[id] ?? Number.NaN) - expected[id]) <= WEIGHT_EPSILON,\n );\n};\n\nconst descendantMinSize = (\n child: LayoutChild,\n axis: RowNode[\"orientation\"],\n tabsetMinSize: number,\n): number | undefined => {\n const explicit = dimensionToPixels(child.min);\n if (explicit !== undefined) {\n return explicit;\n }\n if (child.min !== undefined) {\n return undefined;\n }\n if (child.type === \"tabset\") {\n return tabsetMinSize;\n }\n\n const childMinimums: Array<number> = [];\n for (const grandchild of child.children) {\n const minimum = descendantMinSize(grandchild, axis, tabsetMinSize);\n if (minimum === undefined) {\n return undefined;\n }\n childMinimums.push(minimum);\n }\n if (childMinimums.length === 0) {\n return undefined;\n }\n\n return child.orientation === axis\n ? childMinimums.reduce((sum, value) => sum + value, 0)\n : Math.max(...childMinimums);\n};\n\ntype RowViewProps = {\n node: RowNode;\n // Substitutes a custom tabset composition at every leaf of the split tree;\n // defaults to the stock TabsetView.\n renderTabset?: (node: TabsetNode) => ReactNode;\n};\n\nconst RowView = ({ node, renderTabset }: RowViewProps): ReactNode => {\n const dispatch = useLayout((state) => state.dispatch);\n const resizableSplits = useLayout((state) => state.resizableSplits);\n const tabsetMinSize = useLayout((state) => state.tabsetMinSize);\n const globalSnap = useLayout((state) => state.snap);\n // A row's own snap attribute overrides the layout-wide default; an empty config\n // (or step 0 with no divisions) means this row does not snap.\n const effectiveSnap: SnapConfig | null = node.snap ?? globalSnap;\n const snapActive = snapEnabled(effectiveSnap);\n const orientation: Orientation = node.orientation === \"row\" ? \"horizontal\" : \"vertical\";\n const total = node.children.reduce((sum, child) => sum + (child.weight ?? 1), 0);\n const desiredLayout = useMemo(\n () => layoutFromWeights(node.children, total),\n [node.children, total],\n );\n\n // rrp fires onLayoutChanged once on mount with its measured layout. That is not\n // a user resize — committing it would rewrite the authored weights and push a\n // spurious undo entry — so the first call (per mount) is ignored.\n const measured = useRef(false);\n const groupRef = useRef<GroupImperativeHandle | null>(null);\n const groupElement = useRef<HTMLDivElement | null>(null);\n const syncing = useRef(false);\n // Which boundary the pointer grabbed (captured on the separator's pointerdown),\n // a re-entrancy guard for our own setLayout, and the snapped boundary mirrored\n // into state only on engage/disengage so the highlight re-renders ~twice a drag.\n const activeBoundary = useRef<number | null>(null);\n const snapping = useRef(false);\n const snappedBoundaryRef = useRef<number | null>(null);\n const [snappedBoundary, setSnappedBoundary] = useState<number | null>(null);\n\n const setHighlight = (boundary: number | null): void => {\n if (boundary !== snappedBoundaryRef.current) {\n snappedBoundaryRef.current = boundary;\n setSnappedBoundary(boundary);\n }\n };\n\n // Toggle the flex transition on the group imperatively (not via React state):\n // it must be live in the DOM before the snapping setLayout writes flex this same\n // frame, so the panels glide onto the grid line. Cleared on free-tracking frames\n // so dragging stays 1:1 with the pointer (snap-out is instant).\n const setSnapTransition = (active: boolean): void => {\n const element = groupElement.current;\n if (!element) {\n return;\n }\n if (active) {\n element.dataset.dashfooSnapping = \"true\";\n } else {\n delete element.dataset.dashfooSnapping;\n }\n };\n\n useLayoutEffect(() => {\n const group = groupRef.current;\n if (!group) {\n return;\n }\n const current = group.getLayout();\n const samePanelSet =\n Object.keys(current).length === Object.keys(desiredLayout).length &&\n Object.keys(desiredLayout).every((id) => id in current);\n if (!samePanelSet || layoutsMatch(current, desiredLayout)) {\n return;\n }\n\n syncing.current = true;\n group.setLayout(desiredLayout);\n const frame = requestAnimationFrame(() => {\n syncing.current = false;\n });\n return () => {\n cancelAnimationFrame(frame);\n syncing.current = false;\n };\n }, [desiredLayout]);\n\n // Fires on every pointer move during a drag. Pull the grabbed boundary onto the\n // nearest grid target and push it back into rrp so the panel visibly sticks. The\n // `snapping` guard plus the idempotence check keep our own setLayout from\n // re-triggering this and prevent jitter at the threshold edge, whatever rrp's\n // re-fire timing.\n const handleLayoutChange = (layout: Layout): void => {\n if (snapping.current || syncing.current || !resizableSplits) {\n return;\n }\n if (effectiveSnap === null || !snapActive) {\n return;\n }\n const boundary = activeBoundary.current;\n if (boundary === null) {\n return;\n }\n\n const { sizes, snapped } = snapSizes(\n orderedFromLayout(layout, node.children),\n boundary,\n effectiveSnap,\n );\n setHighlight(snapped ? boundary : null);\n if (!snapped) {\n // Pointer tracking resumes 1:1 — drop the transition so it never lags.\n setSnapTransition(false);\n return;\n }\n\n // Arm the glide before writing the snapped layout this frame.\n setSnapTransition(true);\n const group = groupRef.current;\n const target = layoutFromOrdered(sizes, node.children);\n if (!group || layoutsMatch(layout, target)) {\n return;\n }\n snapping.current = true;\n group.setLayout(target);\n snapping.current = false;\n };\n\n const handleLayoutChanged = (layout: Layout): void => {\n if (!measured.current) {\n measured.current = true;\n return;\n }\n if (syncing.current) {\n return;\n }\n const boundary = activeBoundary.current;\n activeBoundary.current = null;\n setHighlight(null);\n setSnapTransition(false);\n // Belt over the disabled Group/Separator: a non-resizable row never commits\n // an adjustSplit, even if rrp reports a layout change for another reason.\n if (!resizableSplits) {\n return;\n }\n let weights = node.children.map((child) => layout[child.id] ?? child.weight ?? 1);\n // Re-snap the committed value so the model lands exactly on the grid (one undo\n // step), regardless of where the final frame left rrp.\n if (boundary !== null && effectiveSnap !== null && snapActive) {\n weights = snapSizes(weights, boundary, effectiveSnap).sizes;\n }\n const weightsChanged = weights.some(\n (weight, index) => Math.abs(weight - (node.children[index]?.weight ?? 1)) > WEIGHT_EPSILON,\n );\n\n if (!weightsChanged) {\n return;\n }\n\n dispatch({\n rowId: node.id,\n type: \"adjustSplit\",\n weights,\n });\n };\n\n return (\n <Group\n data-dashfoo=\"row\"\n disabled={!resizableSplits}\n elementRef={groupElement}\n groupRef={groupRef}\n key={node.id}\n onLayoutChange={snapActive ? handleLayoutChange : undefined}\n onLayoutChanged={handleLayoutChanged}\n orientation={orientation}\n style={groupStyle}\n >\n {node.children.map((child, index) => {\n const percent = ((child.weight ?? 1) / total) * 100;\n let min = child.min ? dimensionToSize(child.min) : undefined;\n if (min === undefined) {\n const minimum = descendantMinSize(child, node.orientation, tabsetMinSize);\n min = minimum === undefined ? undefined : `${minimum}px`;\n }\n const max = child.max ? dimensionToSize(child.max) : undefined;\n\n return (\n <Fragment key={child.id}>\n {/* The separator stays mounted when resizing is off — removing it\n would collapse the theme-sized gutter and reflow every panel. */}\n {index > 0 ? (\n <Separator\n data-dashfoo=\"splitter\"\n data-dashfoo-snapped={snappedBoundary === index - 1 ? \"true\" : undefined}\n disabled={!resizableSplits}\n onPointerDown={\n snapActive && resizableSplits\n ? () => {\n activeBoundary.current = index - 1;\n }\n : undefined\n }\n />\n ) : null}\n <Panel defaultSize={`${percent}%`} id={child.id} maxSize={max} minSize={min}>\n {child.type === \"row\" ? (\n <RowView node={child} renderTabset={renderTabset} />\n ) : (\n (renderTabset?.(child) ?? <TabsetView node={child} />)\n )}\n </Panel>\n </Fragment>\n );\n })}\n </Group>\n );\n};\n\nexport { RowView };\nexport type { RowViewProps };\n","\"use client\";\n\nimport type { Action, Dashfoo, FloatNode, Geometry, GlobalAttributes } from \"@dashfoo/core\";\nimport type {\n CSSProperties,\n FocusEvent as ReactFocusEvent,\n KeyboardEvent as ReactKeyboardEvent,\n PointerEvent as ReactPointerEvent,\n ReactNode,\n} from \"react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport { useLayout } from \"../hooks/layout-store\";\nimport type { ResizeEdges, Size } from \"../lib/float-geometry\";\nimport { clampToBounds, resizeRect } from \"../lib/float-geometry\";\n\nimport { DragProvider } from \"./drag-adapter\";\nimport { EDGE_BY_KEY, RESIZE_HANDLES } from \"./float-resize-handles\";\nimport { LayoutRoot } from \"./layout-root\";\nimport { RowView } from \"./row-view\";\nimport { DockIcon, FloatIcon, GripIcon, MinimizeIcon } from \"./tabset-icons\";\n\n// One floating panel: an absolutely-positioned overlay over the layout, dragged by\n// its title bar and resized by edge/corner handles, with the panel itself rendered\n// through a nested Layout.Root (drag-dock, float, and maximize switched off — a\n// float is select/close/rename plus the title-bar \"Dock back\" control). Drag and\n// resize update the DOM imperatively during the gesture and commit one `moveFloat`\n// on release, so a drag is a single undo step and never re-renders per pointer move.\n\n// The window title is the float's own name (\"Panel\", \"Panel 1\", …), set when it is\n// floated and editable via the title bar — never the active tab's name.\nconst floatTitle = (node: FloatNode): string => node.name ?? \"Panel\";\n\nconst titleBarStyle: CSSProperties = {\n alignItems: \"center\",\n display: \"flex\",\n flexShrink: 0,\n gap: \"0.375rem\",\n touchAction: \"none\",\n};\n\nconst titleStyle: CSSProperties = {\n flex: 1,\n minWidth: 0,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n};\n\nconst dockButtonStyle: CSSProperties = {\n alignItems: \"center\",\n cursor: \"pointer\",\n display: \"inline-flex\",\n flexShrink: 0,\n};\n\nconst bodyStyle: CSSProperties = { flex: 1, minHeight: 0, position: \"relative\" };\n\n// Approximate footprint of the minimized chip, used to keep it on screen while it\n// is dragged (its window rect is preserved in geometry for restore).\nconst CHIP_SIZE: Size = { height: 34, width: 168 };\n// Pointer travel (px) past which a press counts as a drag, not a tap.\nconst TAP_SLOP = 4;\n\ntype Gesture = {\n bounds: Size;\n edges: ResizeEdges | null; // null = move (no edges), else resize\n pointerId: number;\n start: Geometry;\n startX: number;\n startY: number;\n};\n\ntype TitleProps = { dispatch: (action: Action) => void; node: FloatNode };\n\n// Inline title editor — mirrors the tab-rename pattern: focus + select on mount,\n// a `done` ref so the unmount blur doesn't re-commit after a deliberate\n// Enter/Escape, and stopPropagation so clicking into it doesn't start a drag.\nconst FloatTitleEditor = ({\n dispatch,\n node,\n onDone,\n}: TitleProps & { onDone: () => void }): ReactNode => {\n const ref = useRef<HTMLInputElement | null>(null);\n const done = useRef(false);\n useEffect(() => {\n ref.current?.focus();\n ref.current?.select();\n }, []);\n\n const commit = (value: string): void => {\n const trimmed = value.trim();\n if (trimmed && trimmed !== floatTitle(node)) {\n dispatch({ floatId: node.id, name: trimmed, type: \"renameFloat\" });\n }\n onDone();\n };\n\n const handleKeyDown = (event: ReactKeyboardEvent<HTMLInputElement>): void => {\n if (event.key === \"Enter\") {\n done.current = true;\n commit(event.currentTarget.value);\n } else if (event.key === \"Escape\") {\n done.current = true;\n onDone();\n }\n };\n\n const handleBlur = (event: ReactFocusEvent<HTMLInputElement>): void => {\n if (done.current) {\n return;\n }\n done.current = true;\n commit(event.currentTarget.value);\n };\n\n return (\n <input\n aria-label={`Rename ${floatTitle(node)}`}\n data-dashfoo=\"float-rename\"\n defaultValue={floatTitle(node)}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n onPointerDown={(event) => event.stopPropagation()}\n ref={ref}\n style={titleStyle}\n type=\"text\"\n />\n );\n};\n\n// The window title: the float's name, double-click to rename. A static layout\n// (renamable=false) shows the name as plain, non-editable text.\nconst FloatTitle = ({\n dispatch,\n node,\n renamable,\n}: TitleProps & { renamable: boolean }): ReactNode => {\n const [editing, setEditing] = useState(false);\n if (renamable && editing) {\n return <FloatTitleEditor dispatch={dispatch} node={node} onDone={() => setEditing(false)} />;\n }\n return (\n <span\n data-dashfoo=\"float-title\"\n onDoubleClick={renamable ? () => setEditing(true) : undefined}\n style={titleStyle}\n title={renamable ? \"Double-click to rename\" : undefined}\n >\n {floatTitle(node)}\n </span>\n );\n};\n\ntype FloatPanelProps = {\n global: GlobalAttributes;\n node: FloatNode;\n onFocus: () => void;\n zIndex: number;\n};\n\nconst FloatPanel = ({ global, node, onFocus, zIndex }: FloatPanelProps): ReactNode => {\n const dispatch = useLayout((state) => state.dispatch);\n const closableTabs = useLayout((state) => state.closableTabs);\n const draggableTabs = useLayout((state) => state.draggableTabs);\n const editable = useLayout((state) => state.editable);\n const renamableTabs = useLayout((state) => state.renamableTabs);\n const resizableSplits = useLayout((state) => state.resizableSplits);\n const keepMounted = useLayout((state) => state.keepMounted);\n const renderTab = useLayout((state) => state.renderTab);\n const renderTabLabel = useLayout((state) => state.renderTabLabel);\n const renderTabsetToolbar = useLayout((state) => state.renderTabsetToolbar);\n const snap = useLayout((state) => state.snap);\n\n const panelRef = useRef<HTMLElement | null>(null);\n const gestureRef = useRef<Gesture | null>(null);\n const latestRef = useRef<Geometry>(node.geometry);\n const movedRef = useRef(false);\n const setPanel = (element: HTMLElement | null): void => {\n panelRef.current = element;\n };\n\n // Restore (un-minimize) is a structural edit, so a static layout cannot do it.\n const restore = (): void => {\n if (!editable) {\n return;\n }\n dispatch({ floatId: node.id, minimized: false, type: \"setFloatMinimized\" });\n };\n\n // One pointerdown handler for the title bar / chip (move) and the resize handles;\n // the moving edges ride the target's data-edge, so it can be assigned directly to\n // onPointerDown (no per-render closure that reads refs). Raise-to-front is wired\n // separately (onPointerDownCapture on the frame), so it still works for body and\n // tab clicks — and even while a static layout has move/resize switched off.\n const handlePointerDown = (event: ReactPointerEvent<HTMLElement>): void => {\n const panel = panelRef.current;\n // A static layout never moves or resizes a float — no gesture, no moveFloat.\n if (!panel || !editable) {\n return;\n }\n // A new press supersedes any prior gesture. Release a capture the prior one\n // may still hold (a gesture whose pointerup/cancel was missed) so it neither\n // strands its pointer nor blocks this press — without this, a stale gesture\n // from a different pointerId would make the float permanently unmovable\n // (each touch has its own pointerId; the move handler ignores the mismatch).\n const prior = gestureRef.current;\n if (prior && panel.hasPointerCapture?.(prior.pointerId)) {\n panel.releasePointerCapture(prior.pointerId);\n }\n movedRef.current = false;\n const edgeKey = event.currentTarget.dataset.edge;\n // While minimized the chip keeps its small footprint on screen; otherwise the\n // whole window rect is clamped against the viewport (the overlay).\n const parent = panel.offsetParent as HTMLElement | null;\n const gesture: Gesture = {\n bounds: { height: parent?.clientHeight ?? 0, width: parent?.clientWidth ?? 0 },\n edges: edgeKey ? (EDGE_BY_KEY.get(edgeKey) ?? null) : null,\n pointerId: event.pointerId,\n start: node.geometry,\n startX: event.clientX,\n startY: event.clientY,\n };\n gestureRef.current = gesture;\n latestRef.current = node.geometry;\n // A resize has no tap/double-click meaning, so capture the pointer up front: a\n // fast drag that outruns the small handle must keep routing move/up events to\n // this panel. Without capture the first move lands on the layout beneath, its\n // pointerup never reaches us, and the orphaned gesture resumed when the cursor\n // came back over the float. The title bar and chip instead defer capture to\n // the first real move so a tap or double-click can still reach the rename /\n // restore handlers.\n if (gesture.edges) {\n panel.setPointerCapture(event.pointerId);\n }\n };\n\n const handlePointerUp = (event: ReactPointerEvent): void => {\n const gesture = gestureRef.current;\n if (!gesture || event.pointerId !== gesture.pointerId) {\n return;\n }\n gestureRef.current = null;\n // Resize captures eagerly (even a no-move click holds it), so always release.\n // Optional call: jsdom (and other non-DOM hosts) may not implement the API.\n const panel = panelRef.current;\n if (panel?.hasPointerCapture?.(event.pointerId)) {\n panel.releasePointerCapture(event.pointerId);\n }\n // A tap (never moved past the slop) restores the chip, or is a no-op on the\n // title bar — leaving the click/double-click to reach the title. Only a real\n // drag commits the new rect.\n if (!movedRef.current) {\n if (node.minimized) {\n restore();\n }\n return;\n }\n dispatch({ floatId: node.id, geometry: latestRef.current, type: \"moveFloat\" });\n };\n\n const handlePointerMove = (event: ReactPointerEvent): void => {\n const gesture = gestureRef.current;\n const panel = panelRef.current;\n if (!gesture || !panel || event.pointerId !== gesture.pointerId) {\n return;\n }\n // No button down means the pointerup was missed (it landed on a non-capturing\n // element mid-drag); end the gesture instead of chasing the released cursor.\n if (event.buttons === 0) {\n handlePointerUp(event);\n return;\n }\n const dx = event.clientX - gesture.startX;\n const dy = event.clientY - gesture.startY;\n if (!movedRef.current) {\n // Below the slop it is still a (possible) tap — don't move or capture yet.\n if (Math.hypot(dx, dy) <= TAP_SLOP) {\n return;\n }\n movedRef.current = true;\n // Resize already captured at pointerdown; the move gesture captures here.\n if (!gesture.edges) {\n panel.setPointerCapture(gesture.pointerId);\n }\n }\n const next = gesture.edges\n ? resizeRect(gesture.start, gesture.edges, dx, dy)\n : clampToBounds(\n { ...gesture.start, left: gesture.start.left + dx, top: gesture.start.top + dy },\n gesture.bounds,\n node.minimized ? CHIP_SIZE : undefined,\n );\n // next always carries the window's own width/height (the chip's footprint is\n // only used to clamp position), so restore reopens at the saved size.\n latestRef.current = next;\n panel.style.left = `${next.left}px`;\n panel.style.top = `${next.top}px`;\n // The chip's size is CSS-driven; only the window writes its own dimensions.\n if (!node.minimized) {\n panel.style.width = `${next.width}px`;\n panel.style.height = `${next.height}px`;\n }\n };\n\n // pointercancel means the OS took the pointer (a system gesture, a scroll that\n // won the touch). That is an abort, not a release: revert the imperative DOM to\n // where the drag started and never commit a half-finished rect. handlePointerUp\n // (a real release) is what commits.\n const handlePointerCancel = (event: ReactPointerEvent): void => {\n const gesture = gestureRef.current;\n const panel = panelRef.current;\n if (!gesture || !panel || event.pointerId !== gesture.pointerId) {\n return;\n }\n gestureRef.current = null;\n if (panel.hasPointerCapture?.(event.pointerId)) {\n panel.releasePointerCapture(event.pointerId);\n }\n if (!movedRef.current) {\n return;\n }\n panel.style.left = `${gesture.start.left}px`;\n panel.style.top = `${gesture.start.top}px`;\n if (!node.minimized) {\n panel.style.width = `${gesture.start.width}px`;\n panel.style.height = `${gesture.start.height}px`;\n }\n };\n\n if (node.minimized) {\n return (\n <button\n aria-label={`Restore ${floatTitle(node)} panel`}\n data-dashfoo=\"float-chip\"\n onKeyDown={(event) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n restore();\n }\n }}\n onPointerCancel={handlePointerCancel}\n onPointerDown={handlePointerDown}\n onPointerDownCapture={onFocus}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n ref={setPanel}\n style={{\n left: node.geometry.left,\n pointerEvents: \"auto\",\n position: \"absolute\",\n top: node.geometry.top,\n zIndex,\n }}\n title={floatTitle(node)}\n type=\"button\"\n >\n <FloatIcon />\n <span data-dashfoo=\"float-chip-label\">{floatTitle(node)}</span>\n </button>\n );\n }\n\n const floatModel: Dashfoo = { global, layout: node.layout, version: 1 };\n\n return (\n <div\n data-dashfoo=\"float\"\n // Capture so a click anywhere in the float — body, tab, or chrome — raises it\n // above the others before any child handler runs, even when a static layout\n // has move/resize off.\n onPointerCancel={handlePointerCancel}\n onPointerDownCapture={onFocus}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n ref={setPanel}\n style={{\n height: node.geometry.height,\n left: node.geometry.left,\n // The overlay is pointer-events:none so it never blocks the docked layout;\n // each float opts back in.\n pointerEvents: \"auto\",\n position: \"absolute\",\n top: node.geometry.top,\n width: node.geometry.width,\n zIndex,\n }}\n >\n <div\n data-dashfoo=\"float-titlebar\"\n onPointerDown={handlePointerDown}\n // A static layout's title bar doesn't drag, so don't dangle a grab cursor.\n style={editable ? titleBarStyle : { ...titleBarStyle, cursor: \"default\" }}\n >\n <span aria-hidden=\"true\" data-dashfoo=\"float-grip\">\n <GripIcon />\n </span>\n <FloatTitle dispatch={dispatch} node={node} renamable={editable} />\n {editable && (\n <>\n <button\n aria-label=\"Minimize panel\"\n data-dashfoo=\"float-minimize\"\n onClick={() =>\n dispatch({ floatId: node.id, minimized: true, type: \"setFloatMinimized\" })\n }\n onPointerDown={(event) => event.stopPropagation()}\n style={dockButtonStyle}\n title=\"Minimize panel\"\n type=\"button\"\n >\n <MinimizeIcon />\n </button>\n <button\n aria-label=\"Dock panel back into the main layout\"\n data-dashfoo=\"float-dock\"\n onClick={() => dispatch({ floatId: node.id, type: \"dockFloat\" })}\n onPointerDown={(event) => event.stopPropagation()}\n style={dockButtonStyle}\n title=\"Dock panel back\"\n type=\"button\"\n >\n <DockIcon />\n </button>\n </>\n )}\n </div>\n <div data-dashfoo=\"float-body\" style={bodyStyle}>\n <LayoutRoot\n closableTabs={closableTabs}\n dispatch={dispatch}\n draggableTabs={draggableTabs}\n draggableTabsets={false}\n editable={editable}\n floatable={false}\n keepMounted={keepMounted}\n maximizable={false}\n model={floatModel}\n renamableTabs={renamableTabs}\n renderTab={renderTab}\n renderTabLabel={renderTabLabel}\n renderTabsetToolbar={renderTabsetToolbar}\n resizableSplits={resizableSplits}\n snap={snap ?? undefined}\n >\n {/* Its own drag layer, joined to the shared manager above, so tabs drag\n between this float and the main layout (and other floats). */}\n <DragProvider>\n <RowView node={node.layout} />\n </DragProvider>\n </LayoutRoot>\n </div>\n {editable &&\n RESIZE_HANDLES.map((handle) => (\n <div\n data-dashfoo=\"float-resize\"\n data-edge={handle.key}\n key={handle.key}\n onPointerDown={handlePointerDown}\n style={{ position: \"absolute\", touchAction: \"none\", zIndex: 1, ...handle.style }}\n />\n ))}\n </div>\n );\n};\n\nexport { FloatPanel };\nexport type { FloatPanelProps };\n","\"use client\";\n\nimport type { FloatNode, GlobalAttributes } from \"@dashfoo/core\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { useState } from \"react\";\n\nimport { FloatLayerContext } from \"./float-context\";\nimport { FloatPanel } from \"./float-panel\";\n\n// The floating-panel layer: the in-app counterpart of the drag layer. It renders\n// `model.floats` as draggable, resizable overlays over the docked layout, in the\n// SAME React tree — so context, events, and styling just work (no separate window,\n// no portal). Wrap the layout's content with <Layout.FloatLayer> and it drops an\n// absolutely-positioned overlay alongside the rows.\n\nconst overlayStyle: CSSProperties = {\n inset: 0,\n // Never block the docked layout underneath; each float opts pointer events back\n // in, so empty overlay space stays click-through. Fixed to the viewport so a\n // float can be dragged anywhere on the page, not just within the layout box.\n pointerEvents: \"none\",\n position: \"fixed\",\n // An explicit layer so a drop indicator aimed at a docked tabset (rendered at\n // z:auto) stays *behind* the floats that overlap it; a float's own indicator\n // opts back above this layer. See DockIndicator in drag-overlays.tsx.\n zIndex: 1,\n};\n\nconst FloatOverlay = ({\n floats,\n global,\n}: {\n floats: Array<FloatNode>;\n global: GlobalAttributes;\n}): ReactNode => {\n // The clicked float comes to the front; the rest share the lower band, stacking\n // by DOM (model) order.\n const [topId, setTopId] = useState<string | null>(null);\n if (floats.length === 0) {\n return null;\n }\n return (\n <div data-dashfoo=\"float-overlay\" style={overlayStyle}>\n {floats.map((node) => (\n <FloatPanel\n global={global}\n key={node.id}\n node={node}\n onFocus={() => setTopId(node.id)}\n zIndex={node.id === topId ? 2 : 1}\n />\n ))}\n </div>\n );\n};\n\ntype FloatLayerProps = {\n children: ReactNode;\n floats: Array<FloatNode>;\n global: GlobalAttributes;\n};\n\nconst FloatLayer = ({ children, floats, global }: FloatLayerProps): ReactNode => (\n <FloatLayerContext.Provider value>\n {children}\n <FloatOverlay floats={floats} global={global} />\n </FloatLayerContext.Provider>\n);\n\nexport { FloatLayer };\nexport type { FloatLayerProps };\n","\"use client\";\n\nimport { DragProvider } from \"./drag-adapter\";\nimport { FloatLayer } from \"./float-layer\";\nimport { LayoutRoot } from \"./layout-root\";\nimport { RowView } from \"./row-view\";\nimport { TabsetView } from \"./tabset/tabset-view\";\n\n// Compound namespace for hand-built layouts, same pattern as Panel/Tabset:\n// Root provides the layout store, DragLayer opts the tree into drag-dock,\n// Rows renders the split tree, and Tabset is the stock tabset composition for\n// leaves that don't need custom chrome. FloatLayer opts the layout into floating\n// panels: wrap the tree's content with it (passing `floats` + `global`) and it\n// renders each floated panel as a draggable, resizable overlay over the rows.\nconst Layout = {\n DragLayer: DragProvider,\n FloatLayer,\n Root: LayoutRoot,\n Rows: RowView,\n Tabset: TabsetView,\n} as const;\n\nexport { Layout };\nexport type { DragProviderProps as LayoutDragLayerProps } from \"./drag-adapter\";\nexport type { FloatLayerProps as LayoutFloatLayerProps } from \"./float-layer\";\nexport type { LayoutRootProps } from \"./layout-root\";\nexport type { RowViewProps as LayoutRowsProps } from \"./row-view\";\nexport type { TabsetViewProps as LayoutTabsetProps } from \"./tabset/tabset-view\";\n","\"use client\";\n\nimport type {\n Action,\n Dashfoo,\n DockLocation,\n Orientation,\n SnapConfig,\n TabNode,\n TabsetNode,\n} from \"@dashfoo/core\";\nimport { findTabset, stackModel } from \"@dashfoo/core\";\nimport type { ComponentType, ReactNode } from \"react\";\nimport { forwardRef, useCallback, useContext, useImperativeHandle, useMemo, useRef } from \"react\";\n\nimport { SharedDragManagerContext } from \"../hooks/drag-hooks\";\nimport type { PersistConfig, StorageAdapter } from \"../hooks/persistence\";\nimport { localStorageAdapter, usePersistence } from \"../hooks/persistence\";\nimport { useContainerWidth } from \"../hooks/responsive\";\nimport { useDashfooStore } from \"../hooks/store\";\n\nimport { DashfooDragProvider } from \"./drag-root\";\nimport { Layout } from \"./layout\";\n\nconst DEFAULT_PERSIST_DEBOUNCE_MS = 300;\n\n// `persist` accepts a bare localStorage key or a full target (custom storage,\n// debounce). Controlled mode (a `model` prop, no `defaultModel`) skips it —\n// persistence implies the library owns the state.\ntype PersistInput = string | { debounceMs?: number; key: string; storage?: StorageAdapter };\n\nconst resolvePersist = (\n persist: PersistInput | undefined,\n hasDefaultModel: boolean,\n): PersistConfig | null => {\n if (persist === undefined || !hasDefaultModel) {\n return null;\n }\n if (typeof persist === \"string\") {\n return { debounceMs: DEFAULT_PERSIST_DEBOUNCE_MS, key: persist, storage: localStorageAdapter };\n }\n return {\n debounceMs: persist.debounceMs ?? DEFAULT_PERSIST_DEBOUNCE_MS,\n key: persist.key,\n storage: persist.storage ?? localStorageAdapter,\n };\n};\n\ntype TabComponent = ComponentType<{ node: TabNode }>;\n\n// Component names already warned about, so the dev warning fires at most once each.\nconst warnedComponents = new Set<string>();\n\n// Imperative API exposed via ref — lets a host drive the layout from a toolbar,\n// command palette, or keyboard shortcuts without rebuilding the store's plumbing.\ntype DashfooHandle = {\n addTab: (\n tab: TabNode,\n target: { index?: number; location?: DockLocation; targetId: string },\n ) => void;\n canRedo: () => boolean;\n canUndo: () => boolean;\n closeTab: (tabId: string) => void;\n dispatch: (action: Action) => void;\n // Dock a floating panel back into the main layout.\n dockFloat: (floatId: string) => void;\n // Float a tab out into a movable, resizable panel.\n floatTab: (tabId: string) => void;\n getModel: () => Dashfoo;\n maximizeTabset: (tabsetId: string | null) => void;\n redo: () => void;\n renameTab: (tabId: string, name: string) => void;\n // Reset to the original defaultModel, clearing undo history and any persisted\n // copy. No-op in controlled mode (the host owns the model).\n resetLayout: () => void;\n selectTab: (tabsetId: string, index: number) => void;\n undo: () => void;\n};\n\ntype DashfooLayoutProps = {\n closableTabs?: boolean;\n components?: Record<string, TabComponent>;\n defaultModel?: Dashfoo;\n draggableTabs?: boolean;\n draggableTabsets?: boolean;\n // false renders a static dashboard: no drag, close, rename, or resize. Tab\n // selection, maximize, and the imperative ref API keep working.\n editable?: boolean;\n factory?: (tab: TabNode) => ReactNode;\n // Show a per-tabset control that floats the panel into a movable, resizable\n // overlay (and render any floating panels). Off by default — opt in. Floating\n // adds the panel to the model's `floats`.\n floatable?: boolean;\n keepMounted?: boolean;\n maximizable?: boolean;\n model?: Dashfoo;\n onAction?: (action: Action) => Action | null;\n onActiveTabsetChange?: (tabsetId: string | undefined) => void;\n onMaximizedTabsetChange?: (tabsetId: string | undefined) => void;\n onModelChange?: (model: Dashfoo, action?: Action) => void;\n persist?: PersistInput;\n renamableTabs?: boolean;\n renderTabLabel?: (tab: TabNode) => ReactNode;\n renderTabsetToolbar?: (tabset: TabsetNode) => ReactNode;\n // At or below `maxWidth` (the layout's own container width, not the viewport)\n // the layout renders one stacked column and locks drag and resize. The stack is\n // a view-only projection, so widening back is lossless and never remounts.\n // `orientation` defaults to \"column\".\n resizableSplits?: boolean;\n responsive?: { maxWidth: number; orientation?: Orientation };\n // Magnetic snap for split resize: the dragged boundary pulls to multiples of\n // `step` (percent of the group) within `threshold`. A row may override this via\n // its own `snap` attribute. Off when omitted; locked off in compact mode.\n snap?: SnapConfig;\n};\n\n// The batteries-included component: owns the store (controlled or uncontrolled),\n// resolves tab content via a components registry or a factory, and assembles the\n// same Layout/Tabset primitives a hand-built layout would use.\n// forwardRef (not the React 19 ref-as-prop) keeps the React 18 peer working.\nconst DashfooLayout = forwardRef<DashfooHandle, DashfooLayoutProps>((props, ref): ReactNode => {\n const {\n closableTabs = true,\n components,\n defaultModel,\n draggableTabs = true,\n draggableTabsets = true,\n editable = true,\n factory,\n floatable = false,\n keepMounted = false,\n maximizable = true,\n model,\n onAction,\n onActiveTabsetChange,\n onMaximizedTabsetChange,\n onModelChange,\n persist,\n renamableTabs = true,\n renderTabLabel,\n renderTabsetToolbar,\n resizableSplits = true,\n responsive,\n snap,\n } = props;\n\n const persistConfig = useMemo(\n () => resolvePersist(persist, defaultModel !== undefined),\n [persist, defaultModel],\n );\n const persistence = usePersistence(persistConfig, defaultModel);\n\n // The save side of persistence rides onModelChange; the consumer's own handler\n // still fires after it.\n const handleModelChange = useCallback(\n (next: Dashfoo, action?: Action): void => {\n persistence.save(next);\n onModelChange?.(next, action);\n },\n [onModelChange, persistence],\n );\n\n const store = useDashfooStore({\n defaultModel: persistence.initialModel ?? defaultModel,\n model,\n onAction,\n onActiveTabsetChange,\n onMaximizedTabsetChange,\n onModelChange: handleModelChange,\n });\n\n // A host can wrap the layout in DashfooDragProvider to share a manager with\n // external sources; if so, reuse it (the floats join that shared manager too).\n const hasSharedManager = useContext(SharedDragManagerContext) !== null;\n\n useImperativeHandle(\n ref,\n () => ({\n addTab: (tab, target) =>\n store.dispatch({\n index: target.index,\n location: target.location ?? \"center\",\n tab,\n targetId: target.targetId,\n type: \"addNode\",\n }),\n canRedo: store.canRedo,\n canUndo: store.canUndo,\n closeTab: (tabId) => store.dispatch({ tabId, type: \"deleteTab\" }),\n dispatch: store.dispatch,\n dockFloat: (floatId) => store.dispatch({ floatId, type: \"dockFloat\" }),\n floatTab: (tabId) => store.dispatch({ tabId, type: \"floatTab\" }),\n getModel: () => store.model,\n maximizeTabset: (tabsetId) => store.dispatch({ tabsetId, type: \"setMaximizedTabset\" }),\n redo: store.redo,\n renameTab: (tabId, name) => store.dispatch({ name, tabId, type: \"renameTab\" }),\n resetLayout: () => {\n persistence.clear();\n if (defaultModel !== undefined) {\n store.setModel(defaultModel);\n }\n },\n selectTab: (tabsetId, index) => store.dispatch({ index, tabsetId, type: \"selectTab\" }),\n undo: store.undo,\n }),\n [defaultModel, persistence, store],\n );\n\n const renderTab = useCallback(\n (tab: TabNode): ReactNode => {\n if (factory) {\n return factory(tab);\n }\n const Component = components?.[tab.component];\n if (!Component) {\n if (components && !warnedComponents.has(tab.component)) {\n warnedComponents.add(tab.component);\n // A tab whose component is not registered renders nothing — surface it\n // once so the misconfiguration is not silent.\n // oxlint-disable-next-line no-console\n console.warn(`[dashfoo] no component registered for \"${tab.component}\"`);\n }\n return null;\n }\n return <Component node={tab} />;\n },\n [components, factory],\n );\n\n // While compact, render a stacked projection; the canonical store.model is\n // untouched (ids survive stackModel, so tap-to-select still routes), so widening\n // back is lossless.\n const [containerRef, width] = useContainerWidth();\n const isCompact = responsive !== undefined && width <= responsive.maxWidth;\n const view = useMemo(\n () => (isCompact ? stackModel(store.model, responsive?.orientation) : store.model),\n [isCompact, responsive?.orientation, store.model],\n );\n\n // rrp auto-fires onLayoutChanged as it re-measures the stacked structure, which\n // would commit an adjustSplit and corrupt the canonical model. The lock flags\n // can't gate it — they reach the resize adapter via the layout store one commit\n // late, so resizableSplits is stale-true during the swap. Gate at the dispatch\n // boundary instead: a stable dispatch reads isCompact from a ref written during\n // render (current before rrp's onLayoutChanged, which can fire in a child effect\n // ahead of this component's effects).\n const isCompactRef = useRef(isCompact);\n isCompactRef.current = isCompact;\n const dispatch = useCallback(\n (action: Action): void => {\n if (isCompactRef.current && action.type === \"adjustSplit\") {\n return;\n }\n store.dispatch(action);\n },\n [store],\n );\n\n // A maximized tabset fills the frame on its own; otherwise the row tree renders.\n const maximized = view.maximizedTabsetId ? findTabset(view, view.maximizedTabsetId) : undefined;\n\n // Floating panels overlay the layout and render from the canonical model rather\n // than the (possibly stacked) compact view.\n const tree = (\n <Layout.FloatLayer floats={store.model.floats ?? []} global={store.model.global}>\n <Layout.DragLayer>\n {maximized ? <Layout.Tabset node={maximized} /> : <Layout.Rows node={view.layout} />}\n </Layout.DragLayer>\n </Layout.FloatLayer>\n );\n\n return (\n <Layout.Root\n closableTabs={closableTabs}\n dispatch={dispatch}\n draggableTabs={isCompact ? false : draggableTabs}\n draggableTabsets={isCompact ? false : draggableTabsets}\n editable={editable}\n floatable={isCompact ? false : floatable}\n keepMounted={keepMounted}\n maximizable={maximizable}\n model={view}\n renamableTabs={renamableTabs}\n renderTab={renderTab}\n renderTabLabel={renderTabLabel}\n renderTabsetToolbar={renderTabsetToolbar}\n resizableSplits={isCompact ? false : resizableSplits}\n rootRef={containerRef}\n snap={snap}\n >\n {/* Share one drag manager across the main layout and every float, so a tab\n can be dragged between them — unless a host DashfooDragProvider already\n provides one (which also lets external sources participate). */}\n {hasSharedManager ? tree : <DashfooDragProvider>{tree}</DashfooDragProvider>}\n </Layout.Root>\n );\n});\n\nDashfooLayout.displayName = \"DashfooLayout\";\n\nexport { DashfooLayout };\nexport type { DashfooHandle, DashfooLayoutProps, TabComponent };\n","\"use client\";\n\nimport type { ComponentProps, ReactNode } from \"react\";\n\ntype PanelRootProps = ComponentProps<\"div\">;\ntype PanelHeaderProps = ComponentProps<\"div\">;\ntype PanelBodyProps = ComponentProps<\"div\">;\ntype PanelTitleProps = ComponentProps<\"span\">;\ntype PanelIconProps = ComponentProps<\"span\">;\ntype PanelBadgeProps = ComponentProps<\"span\">;\n\nconst PanelRoot = (props: PanelRootProps): ReactNode => <div {...props} data-dashfoo=\"panel\" />;\nconst PanelHeader = (props: PanelHeaderProps): ReactNode => (\n <div {...props} data-dashfoo=\"panel-header\" />\n);\nconst PanelBody = (props: PanelBodyProps): ReactNode => (\n <div {...props} data-dashfoo=\"panel-body\" />\n);\nconst PanelTitle = (props: PanelTitleProps): ReactNode => (\n <span {...props} data-dashfoo=\"panel-title\" />\n);\nconst PanelIcon = (props: PanelIconProps): ReactNode => (\n <span {...props} data-dashfoo=\"panel-icon\" />\n);\nconst PanelBadge = (props: PanelBadgeProps): ReactNode => (\n <span {...props} data-dashfoo=\"panel-badge\" />\n);\n\nconst Panel = {\n Badge: PanelBadge,\n Body: PanelBody,\n Header: PanelHeader,\n Icon: PanelIcon,\n Root: PanelRoot,\n Title: PanelTitle,\n} as const;\n\nexport { Panel };\nexport type {\n PanelBadgeProps,\n PanelBodyProps,\n PanelHeaderProps,\n PanelIconProps,\n PanelRootProps,\n PanelTitleProps,\n};\n","\"use client\";\n\nimport { TabsetContent } from \"./tabset-content\";\nimport { TabsetOverflowMenu } from \"./tabset-overflow\";\nimport { TabsetRoot } from \"./tabset-root\";\nimport { TabsetTab, TabsetTrigger } from \"./tabset-tab\";\nimport { TabsetCloseButton, TabsetRenameInput } from \"./tabset-tab-controls\";\nimport { TabsetTablist, TabsetTabStrip } from \"./tabset-tablist\";\nimport {\n TabsetFloatButton,\n TabsetGrip,\n TabsetMaximizeButton,\n TabsetToolbar,\n} from \"./tabset-toolbar\";\n\n// Compound namespace, same pattern as Panel: users compose the parts freely and\n// they coordinate through the scoped store Tabset.Root provides.\nconst Tabset = {\n CloseButton: TabsetCloseButton,\n Content: TabsetContent,\n FloatButton: TabsetFloatButton,\n Grip: TabsetGrip,\n MaximizeButton: TabsetMaximizeButton,\n OverflowMenu: TabsetOverflowMenu,\n RenameInput: TabsetRenameInput,\n Root: TabsetRoot,\n Tab: TabsetTab,\n Tablist: TabsetTablist,\n TabStrip: TabsetTabStrip,\n Toolbar: TabsetToolbar,\n Trigger: TabsetTrigger,\n} as const;\n\nexport { Tabset };\nexport type { TabsetContentProps } from \"./tabset-content\";\nexport type { TabsetRootProps } from \"./tabset-root\";\nexport type { TabsetTabProps, TabsetTriggerProps } from \"./tabset-tab\";\nexport type { TabsetCloseButtonProps, TabsetRenameInputProps } from \"./tabset-tab-controls\";\nexport type { TabsetTablistProps, TabsetTabStripProps } from \"./tabset-tablist\";\nexport type {\n TabsetFloatButtonProps,\n TabsetGripProps,\n TabsetMaximizeButtonProps,\n TabsetToolbarProps,\n} from \"./tabset-toolbar\";\n"],"mappings":"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"}