{"version":3,"file":"useColumns.mjs","names":[],"sources":["../../../../package/common/virtualList/useColumns.ts"],"sourcesContent":["import React, { useState, useRef, useEffect, useLayoutEffect, useCallback } from 'react';\n\nimport {\n  buildColumnTemplate,\n  buildFrozenTemplate,\n  columnWidthVar,\n  DEFAULT_FROZEN_WIDTH,\n  measureCellWidth,\n  loadPersistedColumns,\n  isColumnInitiallyVisible,\n  COLUMN_STORAGE_PREFIX,\n  type PersistedColumns,\n} from './virtualList.utils';\nimport type { VirtualListColumn } from './virtualList.types';\n\ninterface UseColumnsArgs<T> {\n  columns?: VirtualListColumn<T>[];\n  items: T[];\n  multiSelect: boolean;\n  visibleColumnKeys?: string[];\n  onVisibleColumnsChange?: (keys: string[]) => void;\n  persistColumnsKey?: string;\n  showColumnToggle?: boolean;\n  /** User-set column widths, from `useColumnResize`. */\n  userWidths: Record<string, number>;\n  /** Whether those widths have taken over the layout. */\n  isFrozen: boolean;\n  rootRef: React.RefObject<HTMLDivElement | null>;\n  /** Visible-window bounds — re-measure `fit` columns as new cells scroll in. */\n  startIndex: number;\n  endIndex: number;\n  containerHeight: number;\n  /** Re-measure `fit` columns when the container width settles (e.g. after a route transition). */\n  containerWidth: number;\n  /** Re-measure `fit` columns when rows replace the spinner under the same `items`. */\n  isLoading: boolean;\n}\n\nexport interface UseColumnsResult<T> {\n  hasColumns: boolean;\n  visibleColumns: VirtualListColumn<T>[];\n  columnTemplate: string | undefined;\n  /**\n   * Custom properties for the list element: the total width of a frozen layout,\n   * as a `calc()` over the per-column properties so that rewriting one width\n   * during a drag updates the total without any bookkeeping.\n   */\n  widthVars: React.CSSProperties;\n  shouldShowToggle: boolean;\n  effectiveVisible: Set<string>;\n  /** How many default-visible columns the user has hidden (excludes defaultHidden). */\n  manuallyHiddenCount: number;\n  toggleOpen: boolean;\n  setToggleOpen: React.Dispatch<React.SetStateAction<boolean>>;\n  handleToggleColumn: (key: string) => void;\n  /** Imperative escape hatch: drop fit-column pins so they re-measure on the\n   *  next layout. For out-of-band content changes that don't flow through a new\n   *  `items` array or `columns` set (which reset automatically). */\n  recalculateColumns: () => void;\n}\n\n/**\n * Table-mode column logic: visibility (controlled or uncontrolled, with\n * localStorage persistence and runtime reconciliation), the toggle popover, and\n * `fit`-column width measurement that pins one shared px track across the header\n * and every row grid so they stay aligned.\n */\nexport function useColumns<T>({\n  columns,\n  items,\n  multiSelect,\n  visibleColumnKeys,\n  onVisibleColumnsChange,\n  persistColumnsKey,\n  showColumnToggle,\n  userWidths,\n  isFrozen,\n  rootRef,\n  startIndex,\n  endIndex,\n  containerHeight,\n  containerWidth,\n  isLoading,\n}: UseColumnsArgs<T>): UseColumnsResult<T> {\n  const isControlled = visibleColumnKeys !== undefined;\n  const [toggleOpen, setToggleOpen] = useState(false);\n  // Measured px widths for `fit` columns, keyed by column key. Pinning these\n  // into the shared column template keeps the header and rows aligned (a raw\n  // `fit-content` track resolves per-grid and drifts). See the effects below.\n  const [fitWidths, setFitWidths] = useState<Record<string, number>>({});\n\n  const [internalVisibleKeys, setInternalVisibleKeys] = useState<Set<string>>(() => {\n    const persisted = loadPersistedColumns(persistColumnsKey);\n    return new Set((columns ?? []).filter((c) => isColumnInitiallyVisible(c, persisted)).map((c) => c.key));\n  });\n  // The set of column keys the internal visibility state was last reconciled\n  // against. The lazy initializer above only runs at mount, so without this a\n  // list that mounts in list mode (no columns) and later switches to table mode\n  // would keep an empty visible set and render no columns.\n  const knownColumnKeysRef = useRef<Set<string>>(new Set((columns ?? []).map((c) => c.key)));\n\n  // Re-derive internal visibility when the column set changes at runtime: new\n  // columns get their saved/default visibility, removed columns drop out, and\n  // existing columns keep whatever the user toggled them to. This is also what\n  // applies persisted settings when a list switches from list mode to table\n  // mode (columns absent at mount, supplied later).\n  useEffect(() => {\n    if (isControlled) return;\n    const cols = columns ?? [];\n    const currentKeys = new Set(cols.map((c) => c.key));\n    const known = knownColumnKeysRef.current;\n    let identical = currentKeys.size === known.size;\n    if (identical)\n      for (const k of currentKeys)\n        if (!known.has(k)) {\n          identical = false;\n          break;\n        }\n    if (identical) return;\n    knownColumnKeysRef.current = currentKeys;\n    const persisted = loadPersistedColumns(persistColumnsKey);\n    setInternalVisibleKeys((prev) => {\n      const next = new Set<string>();\n      for (const c of cols) {\n        if (known.has(c.key)) {\n          if (prev.has(c.key)) next.add(c.key); // preserve the current-session choice\n        } else if (isColumnInitiallyVisible(c, persisted)) {\n          next.add(c.key); // newly-added column: saved setting, else defaultHidden\n        }\n      }\n      return next;\n    });\n  }, [columns, isControlled, persistColumnsKey]);\n\n  // Persist visibility whenever it changes (uncontrolled mode only). Skip while\n  // there are no columns, or the transient empty state during a list→table\n  // switch before the reconcile effect above has filled in the visible set —\n  // writing then would clobber the saved config with an empty set.\n  useEffect(() => {\n    if (isControlled || !persistColumnsKey || typeof window === 'undefined') return;\n    const cols = columns ?? [];\n    if (cols.length === 0 || internalVisibleKeys.size === 0) return;\n    try {\n      window.localStorage.setItem(\n        COLUMN_STORAGE_PREFIX + persistColumnsKey,\n        JSON.stringify({\n          visible: [...internalVisibleKeys],\n          known: cols.map((c) => c.key),\n          widths: userWidths,\n        } satisfies PersistedColumns),\n      );\n    } catch {\n      // Storage full or unavailable — non-fatal, just don't persist.\n    }\n  }, [internalVisibleKeys, columns, isControlled, persistColumnsKey, userWidths]);\n\n  // Locked columns can never be hidden — force them into the visible set even if\n  // a controlled `visibleColumnKeys` or persisted state omits them. Only clone\n  // (rather than mutate the state Set) when a locked key is actually missing;\n  // in uncontrolled mode they're already present via isColumnInitiallyVisible.\n  const baseVisible: Set<string> = isControlled ? new Set(visibleColumnKeys) : internalVisibleKeys;\n  const lockedKeys = (columns ?? []).filter((c) => c.lockVisible).map((c) => c.key);\n  const effectiveVisible: Set<string> = lockedKeys.some((k) => !baseVisible.has(k))\n    ? new Set([...baseVisible, ...lockedKeys])\n    : baseVisible;\n\n  const hasColumns = !!columns?.length;\n  const visibleColumns = hasColumns ? columns!.filter((c) => effectiveVisible.has(c.key)) : [];\n  // A column counts as \"manually hidden\" only if it's default-visible yet\n  // currently hidden — a defaultHidden column being hidden is its default\n  // state, not a user choice, so it never contributes to the chip.\n  const manuallyHiddenCount = hasColumns\n    ? columns!.filter((c) => !c.defaultHidden && !effectiveVisible.has(c.key)).length\n    : 0;\n  const selectPrefix = multiSelect && hasColumns ? '40px ' : '';\n  const columnTemplate = hasColumns\n    ? `${selectPrefix}${isFrozen ? buildFrozenTemplate(visibleColumns) : buildColumnTemplate(visibleColumns, fitWidths)}`\n    : undefined;\n  // Hide the gear entirely when nothing is left to toggle (every column opts out).\n  const shouldShowToggle = showColumnToggle !== false && hasColumns && columns!.some((c) => !c.hideFromToggle);\n\n  // Sum of the tracks, so the header and body can stretch past the viewport and\n  // the list scrolls horizontally instead of clipping. Kept as a `calc()` over\n  // the same custom properties the tracks read, so a drag rewriting one of them\n  // resizes the row canvas in the same layout pass.\n  const widthVars: React.CSSProperties = {};\n  if (isFrozen && hasColumns) {\n    const parts = visibleColumns.map((c) => `var(${columnWidthVar(c.key)}, ${DEFAULT_FROZEN_WIDTH}px)`);\n    if (multiSelect) parts.unshift('40px');\n    if (shouldShowToggle) parts.push('32px');\n    (widthVars as Record<string, string>)['--vl-total'] = `calc(${parts.join(' + ')})`;\n  }\n\n  // ── `fit` column width measurement ──────────────────────────────────────────\n  const fitColumns = visibleColumns.filter((c) => c.width.type === 'fit');\n  // A frozen layout is exact px and ignores the pins, so measuring would only\n  // fight the user: `measureFitWidths` never shrinks a column, and every drag\n  // narrower than the content would be undone on the next scroll frame.\n  const hasFit = !isFrozen && fitColumns.length > 0;\n  const fitColKey = fitColumns.map((c) => c.key).join('|');\n\n  // Drop the measured pins when the data or the fit-column set changes, so the\n  // measure effect below re-reads the true intrinsic width on the next pass —\n  // this is what lets a column shrink (during scroll the effect only grows it,\n  // to avoid jitter). Resetting state during render is React's recommended\n  // pattern for \"reset on prop change\" and avoids a cascading effect render.\n  const [fitReset, setFitReset] = useState<{ key: string; items: T[] }>({ key: fitColKey, items });\n  if (fitReset.key !== fitColKey || fitReset.items !== items) {\n    setFitReset({ key: fitColKey, items });\n    if (Object.keys(fitWidths).length > 0) setFitWidths({});\n  }\n\n  // Measure every fit cell currently in the DOM (header + visible rows), keyed\n  // by its `data-fit-key`, and grow each column's pin to the widest. Reading the\n  // key off the DOM (rather than closing over `fitColumns`) keeps this a stable\n  // callback the ResizeObserver below can reuse. `measureCellWidth` reports the\n  // true content width even when the cell is pinned narrower, so a later pass\n  // always recovers a column first measured while it was still empty.\n  const measureFitWidths = useCallback(() => {\n    const root = rootRef.current;\n    if (!root) return;\n    const maxByKey = new Map<string, number>();\n    root.querySelectorAll('[data-fit-key]').forEach((node) => {\n      const el = node as HTMLElement;\n      const key = el.getAttribute('data-fit-key');\n      if (!key) return;\n      const w = measureCellWidth(el);\n      if (w > (maxByKey.get(key) ?? 0)) maxByKey.set(key, w);\n    });\n    if (maxByKey.size === 0) return;\n    setFitWidths((prev) => {\n      let changed = false;\n      const next = { ...prev };\n      for (const [key, max] of maxByKey) {\n        if (max <= 0) continue;\n        // Cap at the viewport width so one oversized cell can't blow out layout.\n        const pinned = Math.min(Math.ceil(max), root.clientWidth);\n        if (pinned > (prev[key] ?? 0)) {\n          next[key] = pinned;\n          changed = true;\n        }\n      }\n      return changed ? next : prev;\n    });\n  }, [rootRef]);\n\n  // One ResizeObserver shared across all fit cells. It re-measures whenever a\n  // cell's box changes — crucially when content first appears after mount (which\n  // changes the cell's height even while its width is pinned), so a too-early or\n  // empty-cell measure self-corrects instead of sticking. Its initial callback\n  // also fires once after layout settles, covering route transitions and other\n  // post-mount layout shifts without depending on font/rAF timing.\n  const [fitObserver] = useState<ResizeObserver | null>(() =>\n    typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(() => measureFitWidths()),\n  );\n  const observedRef = useRef<Set<Element>>(new Set());\n  useEffect(\n    () => () => {\n      fitObserver?.disconnect();\n      observedRef.current.clear();\n    },\n    [fitObserver],\n  );\n\n  // Measure synchronously (before paint, so a wider row scrolling in never shows\n  // a clipped frame), then *diff* the observed set rather than re-observing every\n  // cell. Re-observing fires a redundant ResizeObserver callback per node, and\n  // `startIndex`/`endIndex` change every scroll frame — so observing only the\n  // cells that entered (and dropping the ones that left) keeps stable, already\n  // pinned cells from generating any observer traffic while scrolling. A newly\n  // entered cell still fires exactly once, which is when we want to measure it.\n  useLayoutEffect(() => {\n    if (!hasFit) return;\n    const root = rootRef.current;\n    if (!root) return;\n    measureFitWidths();\n    if (!fitObserver) return;\n    const current = new Set<Element>(root.querySelectorAll('[data-fit-key]'));\n    const observed = observedRef.current;\n    for (const el of observed)\n      if (!current.has(el)) {\n        fitObserver.unobserve(el);\n        observed.delete(el);\n      }\n    for (const el of current)\n      if (!observed.has(el)) {\n        fitObserver.observe(el);\n        observed.add(el);\n      }\n  }, [\n    rootRef,\n    hasFit,\n    fitColKey,\n    fitWidths,\n    startIndex,\n    endIndex,\n    containerHeight,\n    containerWidth,\n    items,\n    isLoading,\n    measureFitWidths,\n    fitObserver,\n  ]);\n\n  // Cheap insurance: re-measure on the next two frames after mount / data /\n  // fit-column changes, in case the icons (or the injected FontAwesome sizing\n  // CSS) resolve a frame after the first synchronous pass. Safe and scoped —\n  // measureFitWidths only ever grows a pin, and this runs on mount / data change\n  // (not every scroll frame), so it keeps the diff-observe perf win.\n  useEffect(() => {\n    if (!hasFit) return;\n    let raf2 = 0;\n    const raf1 = requestAnimationFrame(() => {\n      measureFitWidths();\n      raf2 = requestAnimationFrame(() => measureFitWidths());\n    });\n    return () => {\n      cancelAnimationFrame(raf1);\n      cancelAnimationFrame(raf2);\n    };\n  }, [hasFit, fitColKey, items, isLoading, measureFitWidths]);\n\n  // Force a fresh fit-column measure regardless of current pins. Always installs\n  // a new empty object so the measure layout effect re-runs even when nothing\n  // was pinned (e.g. content changed while the column was still fit-content).\n  const recalculateColumns = useCallback(() => setFitWidths({}), []);\n\n  function handleToggleColumn(key: string) {\n    // Locked columns can't be toggled off.\n    if (columns?.find((c) => c.key === key)?.lockVisible) return;\n    const next = new Set(effectiveVisible);\n    if (next.has(key)) {\n      if (next.size <= 1) return;\n      next.delete(key);\n    } else {\n      next.add(key);\n    }\n    const nextArray = [...next];\n    if (!isControlled) setInternalVisibleKeys(next);\n    onVisibleColumnsChange?.(nextArray);\n  }\n\n  return {\n    hasColumns,\n    visibleColumns,\n    columnTemplate,\n    widthVars,\n    shouldShowToggle,\n    effectiveVisible,\n    manuallyHiddenCount,\n    toggleOpen,\n    setToggleOpen,\n    handleToggleColumn,\n    recalculateColumns,\n  };\n}\n"],"mappings":"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"}