{"version":3,"file":"index.cjs","names":["depsMatch","a","b","length","every","value","index","Object","is","computed","spec","memos","WeakMap","valueOf","row","deps","memo","get","set","column","key","header","accessor","format","asText","sortValue","exportValue","String","Date","toISOString","useCallback","useEffect","useId","useState","defaultFilterRegistry","RANGE_SUFFIXES","scalarFilterText","filterWidgetKind","filterOpKey","isValuelessFilterOp","readRangeWidget","SESSION_ATTR","headerFilterFieldIsComplete","def","extra","registry","kind","type","key","stored","suffixes","dateRange","widget","start","end","op","bindHeaderFilterDismiss","source","options","closeOnSelect","afterWrite","queueMicrotask","dismiss","setExtra","value","setExtras","patch","usePointerDismiss","open","insideSelector","$","_c","t0","t1","isInside","target","Element","closest","active","document","activeElement","HTMLSelectElement","onPointer","event","armed","onKey","event_0","arm","addEventListener","removeEventListener","useHeaderFilterOverlay","props","rawId","replaceAll","id","setOpen","resetKey","setResetKey","Symbol","for","_temp","t2","t3","session","selector","nestedSelector","pointerDismiss","t4","t5","sessionProps","useCallback","useEffect","useRef","useState","usePrefersReducedMotion","FADE_MS","STEADY_MS","cellKey","rowId","columnKey","useHighlight","enabled","$","_c","reduced","rows","setRows","_temp","cells","setCells","_temp2","t0","Symbol","for","Map","timers","duration","t1","t2","timer","current","values","clearTimeout","clear","t3","key","drop","existing","get","set","setTimeout","delete","schedule","t4","Set","add","current_0","next","flashRow","t5","t6","rowId_0","key_0","current_1","current_2","next_0","flashCell","timer_0","t7","rowId_1","has","t8","rowId_2","columnKey_0","t9","t10","isRowHighlighted","isCellHighlighted","animated","stableKey","POSITION_FIELDS","Set","identityOf","query","Object","fromEntries","entries","filter","field","has","tableQueryKey","options","tableQueryBaseKey","page","cursor","scope","useCallback","useEffect","useMemo","useRef","useState","useSyncExternalStore","useResolvedAdapter","PARAM_DENSITY","DENSITY_URL_WRITE_DEBOUNCE_MS","readDensity","params","ns","raw","get","undefined","useDensityUrlState","options","urlAdapter","urlSync","urlKey","defaultDensity","resolved","search","onChange","subscribe","getSearch","pending","setPending","flushTimer","density","URLSearchParams","persist","next","delete","set","setSearch","toString","onDensityChange","current","clearTimeout","setTimeout","latestRef","last","write","routerUrlAdapter","search","navigate","getSearch","startsWith","slice","setSearch","next","options","push","subscribe","undefined","useCallback","useEffect","useMemo","useRef","useState","useSyncExternalStore","EMPTY_COLUMN_LAYOUT","stableKey","useResolvedAdapter","PARAM_COL_HIDDEN","readColumnLayout","writeColumnLayout","LAYOUT_URL_WRITE_DEBOUNCE_MS","useColumnLayoutUrlState","options","urlAdapter","urlSync","defaultColumnLayout","urlKey","baseLayout","backend","syncToUrl","ns","resolved","search","onChange","subscribe","getSearch","params","URLSearchParams","fallback","pending","setPending","flushTimer","layout","persist","next","p","isDefault","isEmpty","set","setSearch","toString","onLayoutChange","current","clearTimeout","setTimeout","latestRef","last","write","useCallback","useEffect","useMemo","useRef","useState","safeLocalStorage","useResolvedAdapter","FILTER_PREFIX","PARAM_COL_GROUPS","PARAM_COL_HIDDEN","PARAM_COL_ORDER","PARAM_COL_PINNED","PARAM_COL_WIDTHS","PARAM_DENSITY","PARAM_FILTER_TREE","PARAM_FORMULA","PARAM_GROUP_BY","PARAM_GROUP_CLOSED","PARAM_LIMIT","PARAM_PAGE","PARAM_PIVOT","PARAM_ROW_PIN","PARAM_SEARCH","PARAM_SORT","PARAM_SORT_BY","PARAM_SORT_DIR","SAVED_VIEW_VERSION","BARE_PARAMS","migrateView","view","migrate","from","version","upgraded","migrateAll","views","out","push","swallow","undefined","omitDefault","isDefault","next","ownsParam","key","ns","some","p","startsWith","captureTableParams","search","all","URLSearchParams","own","forEach","value","set","toString","readStored","storage","raw","getItem","parsed","JSON","parse","Array","isArray","filter","v","name","useSavedViews","storageKey","store","visibility","urlAdapter","urlKey","urlSync","resolved","backend","setViews","latest","current","reloads","setReloads","reload","n","s","m","b","k","list","then","remote","persist","writes","written","removed","remove","catch","saved","save","reordered","reorder","order","map","Promise","setItem","stringify","getSearch","rename","to","trimmed","trim","target","find","readOnly","move","delta","index","findIndex","moved","length","splice","setDefault","already","apply","stale","_","delete","setSearch","defaultView","useCallback","useEffect","useMemo","useRef","useState","parseGroupBy","resolvePaginationMode","useIsMobile","useTableUrlState","applyQuerySupport","defaultSelectPage","page","rows","total","facets","useQuerySource","options","usePaginatedQuery","selectPage","baseParams","paginationMode","sanitizeParams","forceMobile","supports","aggregates","expandedIds","nextCursor","facetKeys","urlOptions","mediaMobile","isMobile","resolvedMode","paged","state","limit","search","sortBy","sortDir","groupBy","extra","cursorMode","cursor","cursors","setCursors","undefined","params","merged","filters","Object","assign","filterTree","next","query","lastPage","data","pages","at","token","prev","trailKey","JSON","stringify","previousTrailKey","current","selector","selectorRef","length","project","projected","acc","lastTotal","lastFacets","pg","push","isLoading","isFetching","Math","max","ceil","setPage","queryRef","fetchNextPage","live","hasNextPage","isFetchingNextPage","refetch","setLimit","setSort","setGroupBy","sortLevels","toggleSortLevel","setSearch","setExtra","setExtras","setFilterTree","clearExtras","clearAll","error","defaultLimit","COUNT_OPERATORS","COUNT_OPERATOR_SYMBOL","eq","gte","lte","gt","lt","between","OP_SUFFIX","VALUE_SUFFIX","FROM_SUFFIX","TO_SUFFIX","opKey","bucket","valueKey","fromKey","toKey","isNumber","value","Number","isFinite","toNumber","undefined","trim","parsed","toOperator","includes","isCountFilterComplete","state","op","from","to","countFilterExtra","clearCountFilterExtra","countFilterStateFromExtra","extra","sanitizeCountFilterParams","params","buckets","out","countFilterChipLabel","label","useCallback","useEffect","useMemo","useState","devWarn","safeLocalStorage","stableKey","EMPTY_COLUMN_LAYOUT","stringEntries","value","Array","isArray","filter","entry","isPlainRecord","sanitizePinned","pinned","key","side","Object","entries","sanitizeWidths","widths","px","Number","isFinite","sanitizeStoredLayout","parsed","hidden","order","readStored","storage","storageKey","raw","getItem","sanitized","JSON","parse","useColumnLayoutStorageState","options","defaultColumnLayout","baseLayout","fallback","layout","setLayout","stored","onLayoutChange","next","removeItem","setItem","stringify","useMediaQuery","DARK_SCHEME_QUERY","useColorScheme","t0","preference","undefined","prefersDark","visibleRowActions","actions","row","filter","action","isHidden","formatMultiDraft","readMultiDraft","editorValidationProps","MultiSelectEditorChrome","t0","$","_c","ctrl","label","onKeyDown","slots","t1","Checkbox","selected","draft","toggle","value","next","includes","filter","item","setDraft","selectOptions","map","_temp","option_0","option","t2","t3","Symbol","for","display","flexWrap","alignItems","gap","minWidth","t4","event","currentTarget","contains","relatedTarget","commitOnBlur","option_1","index","focusRef","undefined","groupRowLayout","columns","aggregateCells","has","column","key","undefined","firstAggregate","findIndex","labelColumns","labelAggregates","cells","split","Math","max","slice","filter","map","node","groupAggregateEntries","flatMap","groupLeafCount","entry","serverCount","leafIds","length","useCallback","useMemo","useState","useSyncExternalStore","useResolvedAdapter","readCollapsedGroups","writeCollapsedGroups","useGroupCollapseUrlState","t0","$","_c","t1","undefined","options","urlAdapter","urlSync","urlKey","defaultCollapsedGroupIds","ns","resolved","t2","t3","onChange","subscribe","getSearch","t4","search","pending","setPending","t5","bb0","t6","URLSearchParams","fromUrl","t7","collapsedGroupIds","length","ids","params","set","setSearch","toString","onCollapsedGroupIdsChange"],"sources":["../src/columns/computed.ts","../src/filters/headerFilterOverlay.ts","../src/rows/useHighlight.ts","../src/source/queryKey.ts","../src/url/useDensityUrlState.ts","../src/url/routerAdapter.ts","../src/url/useColumnLayoutUrlState.ts","../src/url/useSavedViews.ts","../src/source/useQuerySource.ts","../src/filters/countFilters.ts","../src/columns/useColumnLayoutStorageState.ts","../src/hooks/useColorScheme.ts","../src/rows/rowActions.ts","../src/editing/MultiSelectEditorChrome.tsx","../src/grouping/groupRowLayout.ts","../src/url/useGroupCollapseUrlState.ts"],"sourcesContent":["/**\n * Computed columns — a column whose value is derived rather than stored.\n *\n * A total, a margin, a full name, days-until-due: all of them are functions of\n * other fields, and all of them are usually written straight into `accessor`.\n * That works until the column has to do anything else. Sorting compares the\n * formatted string, so \"$1,240.00\" sorts before \"$90.00\". Filtering has\n * nothing to match against. Exporting writes the formatting. And the function\n * runs again for every cell on every render.\n *\n * {@link computed} declares the derivation once and wires all four surfaces\n * from it:\n *\n * ```ts\n * computed<Order>({\n *   key: \"total\",\n *   header: \"Total\",\n *   deps: (row) => [row.quantity, row.unitPrice],\n *   value: (row) => row.quantity * row.unitPrice,\n *   format: (total) => money.format(total),\n * })\n * ```\n *\n * The screen shows the formatted string; sorting, filtering and export all see\n * the number. The result is cached per row and recomputed only when a declared\n * dependency changes — which is what `deps` is for, and why it is not\n * optional: a cache with no invalidation rule is a bug waiting to be filed.\n */\nimport type { ReactNode } from \"react\";\n\nimport type { ColumnDef, SortableValue } from \"../types\";\n\n/** How a computed column is declared. */\nexport interface ComputedColumnSpec<TRow, TValue> {\n  /** Column key — also the filter/sort key, as with any column. */\n  key: string;\n  /** Header content. Defaults to the humanized key, like any column. */\n  header?: ReactNode;\n  /**\n   * The inputs this column reads. The value is recomputed when any of them\n   * changes and reused when none do.\n   *\n   * List every field `value` touches. Anything left out is a stale cell that\n   * only appears once the data changes underneath it.\n   */\n  deps: (row: TRow) => readonly unknown[];\n  /** The derivation itself. Runs once per row per distinct set of deps. */\n  value: (row: TRow) => TValue;\n  /**\n   * How the value is displayed. Without one, primitives and dates render as\n   * text and anything else renders as empty — an object has no useful reading,\n   * so a value that is not a primitive wants a formatter.\n   *\n   * Formatting lives here rather than in `accessor` so that sorting,\n   * filtering and export keep seeing the underlying value.\n   */\n  format?: (value: TValue, row: TRow) => ReactNode;\n  /**\n   * Anything else a column can be — `sortable`, `align`, `width`, `filter`,\n   * `hideOnMobile`, and the rest. `accessor`, `sortValue` and `exportValue`\n   * are derived and cannot be overridden here.\n   */\n  column?: Omit<\n    ColumnDef<TRow>,\n    \"key\" | \"header\" | \"accessor\" | \"sortValue\" | \"exportValue\"\n  >;\n}\n\n/** One row's memo: the deps it was computed from, and what came out. */\ninterface Memo<TValue> {\n  deps: readonly unknown[];\n  value: TValue;\n}\n\n/** Same-length, same-members-by-`Object.is` — the React dependency rule. */\nfunction depsMatch(a: readonly unknown[], b: readonly unknown[]): boolean {\n  if (a.length !== b.length) return false;\n  return a.every((value, index) => Object.is(value, b[index]));\n}\n\n/**\n * Build a derived column: computed once per row, cached until its declared\n * dependencies change, and consistent across display, sorting, filtering and\n * export.\n *\n * Define columns at module level, or memoise them. The cache lives inside the\n * column this returns, so rebuilding the column on every render throws the\n * cache away with it — the values stay correct, but nothing is ever reused.\n * This is the same rule {@link ColumnDef.Cell} already asks for.\n *\n * @typeParam TRow - The row type.\n * @typeParam TValue - What the derivation produces.\n */\nexport function computed<TRow extends object, TValue = SortableValue>(\n  spec: ComputedColumnSpec<TRow, TValue>\n): ColumnDef<TRow> {\n  // Keyed by the row object, so a row that leaves the page takes its memo with\n  // it and a long-lived table cannot grow a cache it never releases.\n  const memos = new WeakMap<TRow, Memo<TValue>>();\n\n  const valueOf = (row: TRow): TValue => {\n    const deps = spec.deps(row);\n    const memo = memos.get(row);\n    if (memo && depsMatch(memo.deps, deps)) return memo.value;\n    const value = spec.value(row);\n    memos.set(row, { deps, value });\n    return value;\n  };\n\n  return {\n    ...spec.column,\n    key: spec.key,\n    header: spec.header,\n    accessor: (row) => {\n      const value = valueOf(row);\n      return spec.format ? spec.format(value, row) : asText(value);\n    },\n    // Sorting and filtering compare the value, never the formatting.\n    sortValue: (row) => valueOf(row) as SortableValue,\n    // And a spreadsheet gets the same value the table sorted by.\n    exportValue: (row) => valueOf(row),\n  };\n}\n\n/**\n * Text for a value with no formatter.\n *\n * Primitives and dates have an obvious reading. Anything else does not —\n * `\"[object Object]\"` is noise in a cell, never information — so it renders as\n * empty, and `format` is how such a value is meant to be shown.\n */\nfunction asText(value: unknown): string {\n  if (typeof value === \"string\") return value;\n  if (typeof value === \"number\" || typeof value === \"boolean\") {\n    return String(value);\n  }\n  if (value instanceof Date) return value.toISOString();\n  return \"\";\n}\n","/**\n * Header-filter overlay session: stay open while the field is incomplete,\n * ignore nested kit dropdowns as \"outside\", and optionally dismiss once\n * a complete value is written (`closeOnSelect`).\n */\nimport { useCallback, useEffect, useId, useState } from \"react\";\n\nimport type { ExtraFilters } from \"../types\";\nimport { defaultFilterRegistry } from \"./filterBuiltins\";\nimport { type FilterDef, RANGE_SUFFIXES } from \"./filterDefs\";\nimport { type FilterFormSource, scalarFilterText } from \"./filterForm\";\nimport { type FilterTypeRegistry, filterWidgetKind } from \"./filterRegistry\";\nimport { filterOpKey, isValuelessFilterOp } from \"./operators\";\nimport { readRangeWidget } from \"./rangeWidget\";\n\nconst SESSION_ATTR = \"data-adapttable-header-filter\";\n\nexport interface HeaderFilterSessionProps {\n  readonly [SESSION_ATTR]: string;\n}\n\n/**\n * Whether this write is a finished, single-control value — the only case\n * {@link bindHeaderFilterDismiss} will close the overlay when `closeOnSelect`\n * is on. Operator-only writes, typed terms, and multi-select toggles are\n * incomplete: another control is still waiting.\n */\nexport function headerFilterFieldIsComplete<TRow>(\n  def: FilterDef<TRow>,\n  extra: ExtraFilters,\n  registry: FilterTypeRegistry = defaultFilterRegistry\n): boolean {\n  const kind = filterWidgetKind(def, registry) ?? def.type;\n  if (kind === \"select\" || kind === \"boolean\") {\n    return scalarFilterText(extra[def.key]) !== \"\";\n  }\n  if (kind === \"text\") {\n    const stored = extra[filterOpKey(def.key)];\n    return typeof stored === \"string\" && isValuelessFilterOp(stored);\n  }\n  if (kind === \"dateRange\") {\n    const suffixes = RANGE_SUFFIXES.dateRange;\n    const widget = readRangeWidget(\n      extra,\n      def.key + suffixes.start,\n      def.key + suffixes.end,\n      filterOpKey(def.key),\n      def.key,\n      \"date\"\n    );\n    return widget.op != null && isValuelessFilterOp(widget.op);\n  }\n  return false;\n}\n\n/**\n * Wrap a filter source so a complete write can dismiss the overlay.\n * Off unless `closeOnSelect` is true — the default is stay open.\n */\nexport function bindHeaderFilterDismiss<TRow>(\n  source: FilterFormSource<TRow>,\n  options: {\n    def: FilterDef<TRow>;\n    closeOnSelect?: boolean;\n    dismiss: () => void;\n    registry?: FilterTypeRegistry;\n  }\n): FilterFormSource<TRow> {\n  if (options.closeOnSelect !== true) return source;\n  const afterWrite = (extra: ExtraFilters): void => {\n    if (headerFilterFieldIsComplete(options.def, extra, options.registry)) {\n      queueMicrotask(options.dismiss);\n    }\n  };\n  return {\n    ...source,\n    setExtra: (key, value) => {\n      source.setExtra(key, value);\n      afterWrite({ ...source.extra, [key]: value });\n    },\n    setExtras: (patch) => {\n      source.setExtras(patch);\n      afterWrite({ ...source.extra, ...patch });\n    },\n  };\n}\n\n/**\n * Dismiss on a true outside press or Escape. Nested kit dropdowns (and a\n * focused native `<select>` whose OS list is open) are not outside.\n */\nexport function usePointerDismiss(\n  open: boolean,\n  dismiss: () => void,\n  insideSelector: string\n): void {\n  useEffect(() => {\n    if (!open) return;\n    const isInside = (target: EventTarget | null): boolean => {\n      if (target instanceof Element && target.closest(insideSelector)) {\n        return true;\n      }\n      // Native <select> lists live outside the DOM. While that list is\n      // open the select stays focused inside the overlay — a click that\n      // lands on `document` after picking an option is not an outside click.\n      const active = document.activeElement;\n      return (\n        active instanceof HTMLSelectElement &&\n        active.closest(insideSelector) !== null\n      );\n    };\n    const onPointer = (event: Event): void => {\n      if (!armed) return;\n      if (isInside(event.target)) return;\n      dismiss();\n    };\n    const onKey = (event: KeyboardEvent): void => {\n      if (event.key === \"Escape\") dismiss();\n    };\n    let armed = false;\n    const arm = (): void => {\n      armed = true;\n    };\n    document.addEventListener(\"mousedown\", onPointer);\n    document.addEventListener(\"touchstart\", onPointer);\n    document.addEventListener(\"keydown\", onKey);\n    queueMicrotask(arm);\n    return () => {\n      document.removeEventListener(\"mousedown\", onPointer);\n      document.removeEventListener(\"touchstart\", onPointer);\n      document.removeEventListener(\"keydown\", onKey);\n    };\n  }, [open, dismiss, insideSelector]);\n}\n\n/** Open state + a source that honours {@link bindHeaderFilterDismiss}. */\nexport function useHeaderFilterOverlay<TRow>(\n  props: {\n    source: FilterFormSource<TRow>;\n    def: FilterDef<TRow>;\n    closeOnSelect?: boolean;\n    registry?: FilterTypeRegistry;\n  },\n  options?: {\n    nestedSelector?: string;\n    pointerDismiss?: boolean;\n  }\n): {\n  open: boolean;\n  setOpen: (open: boolean) => void;\n  source: FilterFormSource<TRow>;\n  sessionProps: HeaderFilterSessionProps;\n  resetKey: number;\n} {\n  const rawId = useId();\n  const id = rawId.replaceAll(\":\", \"\");\n  const [open, setOpen] = useState(false);\n  const [resetKey, setResetKey] = useState(0);\n  const dismiss = useCallback(() => {\n    setOpen(false);\n    setResetKey((key) => key + 1);\n  }, []);\n  const source = bindHeaderFilterDismiss(props.source, {\n    def: props.def,\n    closeOnSelect: props.closeOnSelect === true,\n    dismiss,\n    registry: props.registry,\n  });\n  const session = `[${SESSION_ATTR}=\"${id}\"]`;\n  const selector = options?.nestedSelector\n    ? `${session},${options.nestedSelector}`\n    : session;\n  usePointerDismiss(\n    open && options?.pointerDismiss !== false,\n    dismiss,\n    selector\n  );\n  return {\n    open,\n    setOpen,\n    source,\n    sessionProps: { [SESSION_ATTR]: id },\n    resetKey,\n  };\n}\n","/**\n * \"Flash the row I just created.\"\n *\n * After a save, an import or a paste, the thing that changed is somewhere in\n * a list of a thousand rows and the user has no way to find it. A brief\n * highlight answers that — and it is the kind of feature that gets built as\n * a `setTimeout` in the host, three times, slightly differently.\n *\n * Two things make it worth owning here.\n *\n * The first is that reduced motion does not mean no feedback. A user who\n * asked for less motion still needs to know which row changed; what they\n * asked to be spared is the movement. So the highlight still appears and\n * still clears — it holds steady instead of fading, and holds longer to make\n * up for the missing transition. Dropping it entirely would read the\n * preference as \"tell me less\", which it is not.\n *\n * The second is that a highlight has to survive the row moving. Sorting,\n * filtering and paging all reorder rows, and a mark keyed to a position\n * would light up whatever landed there. These are keyed by row id and cell\n * address, so the mark travels with the data.\n */\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { usePrefersReducedMotion } from \"../hooks/usePrefersReducedMotion\";\n\n/** How long an animated highlight lasts, in milliseconds. */\nconst FADE_MS = 1500;\n\n/**\n * Longer without motion: a steady mark needs more time to be noticed than\n * one that animates, because nothing about it catches the eye.\n */\nconst STEADY_MS = 2500;\n\n/** One highlighted cell. */\nexport interface HighlightedCell {\n  rowId: string;\n  columnKey: string;\n}\n\n/** What {@link useHighlight} returns. */\nexport interface HighlightState {\n  /** Mark a row. Repeating it restarts the clock rather than stacking. */\n  flashRow: (rowId: string) => void;\n  /** Mark one cell. */\n  flashCell: (cell: HighlightedCell) => void;\n  /** Drop every mark now. */\n  clear: () => void;\n  /** Whether this row is marked. */\n  isRowHighlighted: (rowId: string) => boolean;\n  /** Whether this cell is marked. */\n  isCellHighlighted: (rowId: string, columnKey: string) => boolean;\n  /**\n   * Whether the mark should animate. False when the user asked for reduced\n   * motion — the mark still appears, it simply does not move.\n   */\n  animated: boolean;\n}\n\nconst cellKey = (rowId: string, columnKey: string) => `${rowId} ${columnKey}`;\n\n/**\n * Highlight rows and cells for a moment.\n *\n * @param enabled - Off unless the host asked; every call is then inert.\n * @returns The controls and the current marks.\n */\nexport function useHighlight(enabled: boolean): HighlightState {\n  const reduced = usePrefersReducedMotion();\n  const [rows, setRows] = useState<ReadonlySet<string>>(() => new Set());\n  const [cells, setCells] = useState<ReadonlySet<string>>(() => new Set());\n  // One timer per mark, so a second flash restarts that mark's clock\n  // without disturbing any other.\n  const timers = useRef(new Map<string, ReturnType<typeof setTimeout>>());\n  const duration = reduced ? STEADY_MS : FADE_MS;\n\n  useEffect(\n    () => () => {\n      for (const timer of timers.current.values()) clearTimeout(timer);\n      timers.current.clear();\n    },\n    []\n  );\n\n  const schedule = useCallback(\n    (key: string, drop: () => void) => {\n      const existing = timers.current.get(key);\n      if (existing) clearTimeout(existing);\n      timers.current.set(\n        key,\n        setTimeout(() => {\n          timers.current.delete(key);\n          drop();\n        }, duration)\n      );\n    },\n    [duration]\n  );\n\n  const flashRow = useCallback(\n    (rowId: string) => {\n      if (!enabled) return;\n      setRows((current) => new Set(current).add(rowId));\n      schedule(`row:${rowId}`, () => {\n        setRows((current) => {\n          const next = new Set(current);\n          next.delete(rowId);\n          return next;\n        });\n      });\n    },\n    [enabled, schedule]\n  );\n\n  const flashCell = useCallback(\n    ({ rowId, columnKey }: HighlightedCell) => {\n      if (!enabled) return;\n      const key = cellKey(rowId, columnKey);\n      setCells((current) => new Set(current).add(key));\n      schedule(`cell:${key}`, () => {\n        setCells((current) => {\n          const next = new Set(current);\n          next.delete(key);\n          return next;\n        });\n      });\n    },\n    [enabled, schedule]\n  );\n\n  const clear = useCallback(() => {\n    for (const timer of timers.current.values()) clearTimeout(timer);\n    timers.current.clear();\n    setRows(new Set());\n    setCells(new Set());\n  }, []);\n\n  return {\n    flashRow,\n    flashCell,\n    clear,\n    isRowHighlighted: (rowId) => rows.has(rowId),\n    isCellHighlighted: (rowId, columnKey) =>\n      cells.has(cellKey(rowId, columnKey)),\n    animated: enabled && !reduced,\n  };\n}\n","/**\n * Cache keys for a table query.\n *\n * Wiring the table to TanStack Query or SWR means turning the emitted\n * {@link TableQuery} into a cache key, and hand-rolling that goes wrong in two\n * ways that are hard to see:\n *\n * - **The key changes when nothing did.** A key built from an object literal\n *   depends on property order and on `filters` being a new object each render,\n *   so the cache misses and the table refetches on every keystroke.\n * - **Invalidation hits too much or too little.** Refetching after a save\n *   should refresh every page of the current view, not the whole endpoint and\n *   not only the page on screen.\n *\n * {@link tableQueryKey} and {@link tableQueryBaseKey} answer both. The base key\n * covers everything that defines *which* rows — search, filters, sort,\n * grouping, page size — and the full key appends *where* in them the table is\n * — page and cursor. Since the full key starts with the base key, a library\n * that matches by prefix invalidates every page of a view with the base key\n * alone:\n *\n * ```ts\n * useInfiniteQuery({\n *   queryKey: tableQueryKey(query),\n *   queryFn: ({ signal }) => fetchPeople(query, signal),\n * });\n *\n * // after a save — every page of this view, nothing else\n * queryClient.invalidateQueries({ queryKey: tableQueryBaseKey(query) });\n * ```\n *\n * SWR takes a single string; join the key or pass it straight to `useSWR`,\n * which serialises arrays itself.\n *\n * Both are pure functions of the query. Neither library is imported here and\n * neither is a dependency — these are plain arrays that happen to be exactly\n * what both expect.\n */\nimport { stableKey } from \"../utils/stableKey\";\nimport type { TableQuery } from \"./useServerData\";\n\n/** Options for {@link tableQueryKey} and {@link tableQueryBaseKey}. */\nexport interface TableQueryKeyOptions {\n  /**\n   * Namespace for this table, so two tables on one page never share a cache\n   * entry. Defaults to `\"table\"` — name it when there is more than one.\n   */\n  scope?: string;\n}\n\n/**\n * Position rather than identity. These belong to the full key only, so that\n * the base key can stand for every page of a view at once.\n */\nconst POSITION_FIELDS = new Set([\"page\", \"cursor\"]);\n\n/** The fields that decide WHICH rows, as opposed to where in them. */\nfunction identityOf(query: TableQuery): Record<string, unknown> {\n  return Object.fromEntries(\n    Object.entries(query).filter(([field]) => !POSITION_FIELDS.has(field))\n  );\n}\n\n/**\n * The key for one page of a view: stable across renders, distinct per page.\n *\n * @param query - The query the table emitted.\n * @param options - See {@link TableQueryKeyOptions}.\n */\nexport function tableQueryKey(\n  query: TableQuery,\n  options: TableQueryKeyOptions = {}\n): readonly unknown[] {\n  return [\n    ...tableQueryBaseKey(query, options),\n    // A cursor identifies the page on its own; page number does when there is\n    // no cursor. Both are included so neither mode has to be special-cased.\n    stableKey({ page: query.page, cursor: query.cursor }),\n  ];\n}\n\n/**\n * The key shared by every page of a view — what to invalidate after a write.\n *\n * @param query - The query the table emitted.\n * @param options - See {@link TableQueryKeyOptions}.\n */\nexport function tableQueryBaseKey(\n  query: TableQuery,\n  options: TableQueryKeyOptions = {}\n): readonly unknown[] {\n  return [\"adapttable\", options.scope ?? \"table\", stableKey(identityOf(query))];\n}\n","/**\n * Density in the URL, so a chosen layout survives a reload and a shared\n * link.\n *\n * Density is a display preference, and display preferences that live only\n * in memory are the ones people re-set every morning. It sits in the URL\n * with sort, filters and column layout for the same reason those do: the\n * table's visible state should be reproducible by sending someone a link.\n *\n * The host stays in control. Pass `density` and this hook is inert — a\n * controlled table's density is the host's business, and a URL that\n * silently overrode it would be a second source of truth.\n */\nimport {\n  useCallback,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n  useSyncExternalStore,\n} from \"react\";\n\nimport { type UrlStateAdapter, useResolvedAdapter } from \"./adapter\";\nimport { PARAM_DENSITY } from \"./serialize\";\n\n/** The two layouts a table has. */\nexport type Density = \"comfortable\" | \"compact\";\n\n/**\n * Trailing debounce for URL persistence, as the column-layout and formula hooks\n * use. Reads stay instant through the optimistic overlay below; the write waits,\n * which is what lets the overlay bridge a router whose navigation lands a tick\n * later — clearing it in the same batch as the write leaves one render with the\n * overlay gone and the URL not yet updated, so the table flicks back to the\n * density the reader just left.\n */\nexport const DENSITY_URL_WRITE_DEBOUNCE_MS = 150;\n\n/** What {@link useDensityUrlState} needs. */\nexport interface UseDensityUrlStateOptions {\n  urlAdapter?: UrlStateAdapter;\n  urlSync?: boolean;\n  urlKey?: string;\n  /** The density before anyone has chosen one. Defaults to comfortable. */\n  defaultDensity?: Density;\n}\n\n/** The controlled pair to spread onto the table. */\nexport interface UseDensityUrlStateResult {\n  density: Density;\n  onDensityChange: (next: Density) => void;\n}\n\nfunction readDensity(params: URLSearchParams, ns: string): Density | undefined {\n  const raw = params.get(`${ns}${PARAM_DENSITY}`);\n  return raw === \"compact\" || raw === \"comfortable\" ? raw : undefined;\n}\n\n/**\n * Keep the table's density in the URL.\n *\n * @param options - See {@link UseDensityUrlStateOptions}.\n * @returns The controlled pair to spread onto the table.\n */\nexport function useDensityUrlState(\n  options: UseDensityUrlStateOptions = {}\n): UseDensityUrlStateResult {\n  const { urlAdapter, urlSync, urlKey, defaultDensity } = options;\n  const ns = urlKey ? `${urlKey}.` : \"\";\n  const resolved = useResolvedAdapter(urlAdapter, urlSync ?? true);\n  // Same SSR rule as the other URL hooks: only an explicit adapter is\n  // trusted to be hydration-consistent.\n  const search = useSyncExternalStore(\n    (onChange) => resolved.subscribe(onChange),\n    () => resolved.getSearch(),\n    () => (urlAdapter ? urlAdapter.getSearch() : \"\")\n  );\n  // Optimistic overlay: the click that has not reached the URL yet.\n  const [pending, setPending] = useState<Density | null>(null);\n  const flushTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n  const density = useMemo(() => {\n    if (pending) return pending;\n    return (\n      readDensity(new URLSearchParams(search), ns) ??\n      defaultDensity ??\n      \"comfortable\"\n    );\n  }, [pending, search, ns, defaultDensity]);\n\n  const persist = useCallback(\n    (next: Density) => {\n      const params = new URLSearchParams(resolved.getSearch());\n      // The default writes no parameter: a URL should carry what someone\n      // chose, not restate what the table would have done anyway.\n      if (next === (defaultDensity ?? \"comfortable\")) {\n        params.delete(`${ns}${PARAM_DENSITY}`);\n      } else {\n        params.set(`${ns}${PARAM_DENSITY}`, next);\n      }\n      resolved.setSearch(params.toString());\n    },\n    [resolved, ns, defaultDensity]\n  );\n\n  const onDensityChange = useCallback(\n    (next: Density) => {\n      setPending(next);\n      if (flushTimer.current) clearTimeout(flushTimer.current);\n      flushTimer.current = setTimeout(() => {\n        flushTimer.current = null;\n        persist(next);\n        setPending(null);\n      }, DENSITY_URL_WRITE_DEBOUNCE_MS);\n    },\n    [persist]\n  );\n\n  // Flush a pending choice on unmount, so a density chosen and navigated away\n  // from is not lost.\n  const latestRef = useRef<{\n    pending: Density | null;\n    persist: typeof persist;\n  }>({ pending, persist });\n  latestRef.current = { pending, persist };\n  useEffect(\n    () => () => {\n      if (flushTimer.current) {\n        clearTimeout(flushTimer.current);\n        // Invariant: a live timer implies a pending choice — the timeout clears\n        // the timer BEFORE it clears `pending`.\n        const { pending: last, persist: write } = latestRef.current;\n        write(last!);\n      }\n    },\n    []\n  );\n\n  return { density, onDensityChange };\n}\n","/**\n * The table's URL adapter, for whatever router the app already has.\n *\n * Every router recipe — React Router, TanStack Router, Next.js App Router —\n * was the same twelve lines with two names changed, copied into each app's\n * codebase where nobody could fix it centrally. They are the same because the\n * question is the same: given a way to READ the current query string and a\n * way to NAVIGATE to a new one, what does a correct adapter look like?\n *\n * So that is the function. It takes no dependency on any router, which is the\n * point: a package that imported `next/navigation` would work for one\n * framework and break the build of every other.\n *\n * The subtle part it gets right is `subscribe`. A router re-renders its tree\n * on navigation, which means the hook holding this adapter runs again and\n * reads the new search itself — so subscribing to anything would be a second\n * notification for a change already delivered, and a second render for free.\n * The adapter therefore reports no external changes and relies on the caller\n * rebuilding it when `search` changes. Hand it a `search` that does not\n * update and the table will look frozen; that is the one way to hold it\n * wrong, and it is why `search` is a value rather than a getter.\n */\nimport type { UrlStateAdapter } from \"./adapter\";\n\n/** What {@link routerUrlAdapter} needs from the router. */\nexport interface RouterUrlAdapterOptions {\n  /**\n   * The current query string, WITHOUT the leading `\"?\"`. Must come from the\n   * router's own reactive source — `useSearchParams().toString()`,\n   * `location.search.slice(1)` — so it changes when the route does.\n   */\n  search: string;\n  /**\n   * Go to a new query string. `push` adds a history entry; the default is a\n   * replace, because a table's every keystroke is not a page a user wants to\n   * walk back through.\n   */\n  navigate: (search: string, options: { push: boolean }) => void;\n}\n\n/**\n * Build a `UrlStateAdapter` from a router's search string and navigate.\n *\n * Memoize it on `search` — the adapter is a value, and rebuilding it is how\n * the table learns the route changed.\n *\n * @example React Router\n * ```tsx\n * const [params] = useSearchParams();\n * const navigate = useNavigate();\n * const adapter = useMemo(\n *   () =>\n *     routerUrlAdapter({\n *       search: params.toString(),\n *       navigate: (search, { push }) =>\n *         navigate({ search }, { replace: !push }),\n *     }),\n *   [params, navigate]\n * );\n * ```\n *\n * @example Next.js App Router\n * ```tsx\n * const searchParams = useSearchParams();\n * const pathname = usePathname();\n * const router = useRouter();\n * const adapter = useMemo(\n *   () =>\n *     routerUrlAdapter({\n *       search: searchParams.toString(),\n *       navigate: (search, { push }) => {\n *         const url = search ? `${pathname}?${search}` : pathname;\n *         (push ? router.push : router.replace)(url, { scroll: false });\n *       },\n *     }),\n *   [searchParams, pathname, router]\n * );\n * ```\n *\n * @param options - The router's current search, and how to navigate.\n * @returns An adapter to hand the table as `urlAdapter`.\n */\nexport function routerUrlAdapter({\n  search,\n  navigate,\n}: RouterUrlAdapterOptions): UrlStateAdapter {\n  return {\n    // Tolerate a caller who passed the string with its \"?\" — every router\n    // spells this differently and none of them are wrong.\n    getSearch: () => (search.startsWith(\"?\") ? search.slice(1) : search),\n    setSearch: (next, options) => {\n      navigate(next, { push: options?.push === true });\n    },\n    // See the note at the top of the file: the router's own re-render is the\n    // notification, and subscribing would double it.\n    subscribe: () => () => undefined,\n  };\n}\n","import {\n  useCallback,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n  useSyncExternalStore,\n} from \"react\";\n\nimport {\n  type ColumnLayoutState,\n  EMPTY_COLUMN_LAYOUT,\n} from \"../columns/useColumnLayout\";\nimport { stableKey } from \"../utils/stableKey\";\nimport { type UrlStateAdapter, useResolvedAdapter } from \"./adapter\";\nimport {\n  PARAM_COL_HIDDEN,\n  readColumnLayout,\n  writeColumnLayout,\n} from \"./serialize\";\n\n/** Options for {@link useColumnLayoutUrlState}. */\nexport interface UseColumnLayoutUrlStateOptions {\n  /** URL-state backend. Defaults to the browser History API. */\n  urlAdapter?: UrlStateAdapter;\n  /** When `false`, keep the layout in a local memory store. Defaults `true`. */\n  urlSync?: boolean;\n  /** Layout applied when the URL carries no column layout yet. */\n  defaultColumnLayout?: Partial<ColumnLayoutState>;\n  /**\n   * Namespace for this table's params, so multiple tables can share one URL\n   * (`left.colHide`, `right.colPin`, …). Omit for the bare keys.\n   */\n  urlKey?: string;\n}\n\n/**\n * Trailing debounce for URL persistence. A column-resize drag commits one\n * layout per animation frame; writing `history.replaceState` that often\n * trips Safari's rate limit (~100 calls per 30s, then it throws). Reads stay\n * instant via an optimistic overlay — only the URL write is deferred.\n */\nexport const LAYOUT_URL_WRITE_DEBOUNCE_MS = 150;\n\n/** State + change handler returned by {@link useColumnLayoutUrlState}. */\nexport interface UseColumnLayoutUrlStateResult {\n  /** Current layout — from the URL, or the default when the URL is empty. */\n  layout: ColumnLayoutState;\n  /** Persist a new layout into the URL. Wire to `onColumnLayoutChange`. */\n  onLayoutChange: (next: ColumnLayoutState) => void;\n}\n\n/**\n * Headless URL-synced column layout. Mirrors {@link useTableUrlState} for the\n * column dimension: which columns are hidden, pinned, reordered, or resized is\n * kept in the query string (or a local store when disabled), so reloads,\n * shared links, and re-mounts restore the exact layout. Feed the result into\n * a table's `columnLayout` / `onColumnLayoutChange`.\n *\n * `defaultColumnLayout` applies only while the URL carries no layout. When the user\n * explicitly empties the layout (e.g. unhides the last default-hidden\n * column), an empty `colHide=` marker records that emptiness — deleting every\n * param would resurrect the default on the next read. A change back to the\n * exact default clears the params instead, keeping shared URLs clean.\n *\n * @param options - See {@link UseColumnLayoutUrlStateOptions}.\n * @returns The current layout and a change handler that persists it.\n */\nexport function useColumnLayoutUrlState(\n  options: UseColumnLayoutUrlStateOptions = {}\n): UseColumnLayoutUrlStateResult {\n  const { urlAdapter, urlSync, defaultColumnLayout, urlKey } = options;\n  const baseLayout = defaultColumnLayout;\n  const backend = urlAdapter;\n  const syncToUrl = urlSync ?? true;\n  const ns = urlKey ? `${urlKey}.` : \"\";\n\n  const resolved = useResolvedAdapter(backend, syncToUrl);\n  // Same SSR rule as useTableUrlState: only an explicit adapter is trusted\n  // to be hydration-consistent; the default history adapter hydrates from \"\".\n  const search = useSyncExternalStore(\n    (onChange) => resolved.subscribe(onChange),\n    () => resolved.getSearch(),\n    () => (backend ? backend.getSearch() : \"\")\n  );\n  const params = useMemo(() => new URLSearchParams(search), [search]);\n\n  const fallback = useMemo<ColumnLayoutState>(\n    () => ({ ...EMPTY_COLUMN_LAYOUT, ...baseLayout }),\n    [baseLayout]\n  );\n  // Optimistic overlay: the most recent layout not yet flushed to the URL.\n  const [pending, setPending] = useState<ColumnLayoutState | null>(null);\n  const flushTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n  const layout = useMemo<ColumnLayoutState>(\n    () => pending ?? readColumnLayout(params, ns) ?? fallback,\n    [pending, params, ns, fallback]\n  );\n\n  const persist = useCallback(\n    (next: ColumnLayoutState) => {\n      const p = new URLSearchParams(resolved.getSearch());\n      const isDefault = stableKey(next) === stableKey(fallback);\n      const isEmpty = stableKey(next) === stableKey(EMPTY_COLUMN_LAYOUT);\n      // Back to the exact default → drop the params; the default re-applies\n      // and shared URLs stay clean.\n      writeColumnLayout(p, isDefault ? EMPTY_COLUMN_LAYOUT : next, ns);\n      // An all-empty layout writes no params, which reads back as \"use the\n      // default\" — stamp a marker so an explicitly emptied layout sticks.\n      if (isEmpty && !isDefault) p.set(ns + PARAM_COL_HIDDEN, \"\");\n      resolved.setSearch(p.toString());\n    },\n    [resolved, ns, fallback]\n  );\n\n  const onLayoutChange = useCallback(\n    (next: ColumnLayoutState) => {\n      setPending(next);\n      if (flushTimer.current) clearTimeout(flushTimer.current);\n      flushTimer.current = setTimeout(() => {\n        flushTimer.current = null;\n        persist(next);\n        setPending(null);\n      }, LAYOUT_URL_WRITE_DEBOUNCE_MS);\n    },\n    [persist]\n  );\n\n  // Flush a pending layout on unmount so the last drag frame is never lost.\n  const latestRef = useRef<{\n    pending: ColumnLayoutState | null;\n    persist: typeof persist;\n  }>({ pending, persist });\n  latestRef.current = { pending, persist };\n  useEffect(\n    () => () => {\n      if (flushTimer.current) {\n        clearTimeout(flushTimer.current);\n        // Invariant: a live timer implies a pending layout — the timeout\n        // clears the timer BEFORE it clears `pending`.\n        const { pending: last, persist: write } = latestRef.current;\n        write(last!);\n      }\n    },\n    []\n  );\n\n  return { layout, onLayoutChange };\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type { LayoutStorage } from \"../columns/useColumnLayoutStorageState\";\nimport { safeLocalStorage } from \"../utils/env\";\nimport { type UrlStateAdapter, useResolvedAdapter } from \"./adapter\";\nimport {\n  FILTER_PREFIX,\n  PARAM_COL_GROUPS,\n  PARAM_COL_HIDDEN,\n  PARAM_COL_ORDER,\n  PARAM_COL_PINNED,\n  PARAM_COL_WIDTHS,\n  PARAM_DENSITY,\n  PARAM_FILTER_TREE,\n  PARAM_FORMULA,\n  PARAM_GROUP_BY,\n  PARAM_GROUP_CLOSED,\n  PARAM_LIMIT,\n  PARAM_PAGE,\n  PARAM_PIVOT,\n  PARAM_ROW_PIN,\n  PARAM_SEARCH,\n  PARAM_SORT,\n  PARAM_SORT_BY,\n  PARAM_SORT_DIR,\n} from \"./serialize\";\n\n/** One captured view: a name plus the table's own URL params. */\nexport interface SavedView {\n  name: string;\n  /** The table-scoped query string (only this table's params). */\n  search: string;\n  /**\n   * Whether this is the view the table opens with. At most one view carries\n   * it — setting it on another clears the first, because \"default\" that can\n   * be true twice is not a default.\n   */\n  isDefault?: boolean;\n  /**\n   * Who the view is for. `\"private\"` is the default and needs no storage\n   * beyond this browser; `\"team\"` is one a store shares with other people.\n   */\n  visibility?: SavedViewVisibility;\n  /**\n   * The schema this view was written at. Absent means version 1 — the shape\n   * that predates versioning.\n   */\n  version?: number;\n  /**\n   * Whether this reader may change it. A team view someone else owns arrives\n   * read-only, and the panel must show it as such rather than offering\n   * controls that will fail — a disabled control is information; a control\n   * that silently does nothing is a bug the user is blamed for.\n   */\n  readOnly?: boolean;\n}\n\n/** Who a saved view is for. */\nexport type SavedViewVisibility = \"private\" | \"team\";\n\n/**\n * The schema a view is written at today.\n *\n * A saved view outlives the code that saved it — that is the whole point of\n * saving one — so it carries the version it was written at and the table\n * upgrades what it reads. Views stored before versioning existed have no\n * number and are treated as version 1, which is what they are.\n */\nexport const SAVED_VIEW_VERSION = 2;\n\n/**\n * Bring one stored view up to date, or return `null` to drop it.\n *\n * Called for every view whose `version` is behind {@link SAVED_VIEW_VERSION},\n * oldest first, after the built-in migration has run. Dropping is a real\n * answer: a view whose columns no longer exist restores a table nobody asked\n * for, and silently applying it is worse than losing it.\n */\nexport type SavedViewMigration = (\n  view: SavedView,\n  from: number\n) => SavedView | null;\n\n/**\n * Somewhere to keep views other than this browser.\n *\n * Async on purpose: the whole point is a server, and a synchronous interface\n * would have to be faked by every implementation. `localStorage` remains the\n * zero-config default, so a table that never passes a store keeps working\n * offline with no server at all.\n */\nexport interface SavedViewsStore {\n  /** Every view this reader can see, in the order to show them. */\n  list: () => Promise<readonly SavedView[]>;\n  /** Create or replace one. */\n  save: (view: SavedView) => Promise<void>;\n  /** Delete one by name. */\n  remove: (name: string) => Promise<void>;\n  /**\n   * Persist the ORDER of the list — names only, in the order a later\n   * {@link SavedViewsStore.list} should answer with.\n   *\n   * Order belongs to the list, not to any one view, so it has nowhere to go\n   * through `save`. It travels as names rather than views for the same reason\n   * `save` takes one view at a time: a whole-list write would carry every\n   * view's contents with it and overwrite whatever someone else changed\n   * meanwhile. Names carry the ordering and nothing else.\n   *\n   * Optional, so a store written before this existed keeps compiling and\n   * keeps working — saving, renaming, removing and switching the default all\n   * go through `save` and `remove` as before. What such a store cannot do is\n   * remember an order: `move` reorders the list on screen for the session,\n   * and the next `list()` decides the order again. Implement this when\n   * reordering has to survive a reload.\n   *\n   * Called after the `save` and `remove` writes of the same operation have\n   * settled, so a rename's new name is already known by the time its place in\n   * the list arrives.\n   */\n  reorder?: (names: readonly string[]) => Promise<void>;\n}\n\n/** Options for {@link useSavedViews}. */\nexport interface UseSavedViewsOptions {\n  /** Storage key for the view list, e.g. `\"people-table-views\"`. */\n  storageKey: string;\n  /** Storage backend. Defaults to `localStorage`; memory-only under SSR. */\n  storage?: LayoutStorage;\n  /**\n   * Keep views somewhere other than this browser — a server, usually. Given\n   * one, it replaces `storage` entirely: two sources of truth for the same\n   * list is how a view comes back after being deleted.\n   */\n  store?: SavedViewsStore;\n  /** What `save` marks a new view as. Defaults to `\"private\"`. */\n  visibility?: SavedViewVisibility;\n  /**\n   * Upgrade views saved by an older version of your table — renamed columns,\n   * retired filters. Runs after the built-in migration; return `null` to drop\n   * a view rather than restore a table nobody asked for.\n   */\n  migrate?: SavedViewMigration;\n  /** The table's URL-state backend (same one the table uses). */\n  urlAdapter?: UrlStateAdapter;\n  /** The table's URL namespace — must match the table's `urlKey`. */\n  urlKey?: string;\n  /**\n   * Mirror of the table's URL-sync switch. When `false` (and no explicit\n   * `urlAdapter` is given) views capture and apply against an in-memory\n   * backend instead of the address bar — matching a table mounted with\n   * URL sync off.\n   * @defaultValue true\n   */\n  urlSync?: boolean;\n}\n\n/** Result of {@link useSavedViews}. */\nexport interface UseSavedViewsResult {\n  /** The saved views, in save order. */\n  views: readonly SavedView[];\n  /** Capture the table's CURRENT state under a name (replaces same-name). */\n  save: (name: string) => void;\n  /** Apply a saved view to the table (other tables' params untouched). */\n  apply: (name: string) => void;\n  /** Remove a saved view. */\n  remove: (name: string) => void;\n  /**\n   * Rename a view, keeping its place in the list. A no-op when the name is\n   * unknown or the new name is taken — silently merging two views is how a\n   * rename loses one.\n   */\n  rename: (from: string, to: string) => void;\n  /**\n   * Move a view one step through the list. Past either end does nothing\n   * rather than wrapping, and a view this reader may not change does not move\n   * at all. With a `store`, the new order reaches it through\n   * {@link SavedViewsStore.reorder}; a store without that member reorders for\n   * the session only.\n   */\n  move: (name: string, delta: -1 | 1) => void;\n  /**\n   * Make a view the default, or clear the default by passing its own name\n   * again. Only one view can hold it.\n   */\n  setDefault: (name: string) => void;\n  /** The default view, when one is set. */\n  defaultView: SavedView | undefined;\n  /**\n   * Read the list again — after someone else has changed a shared view, say.\n   * Loading happens on mount and when `storageKey` changes; a `store` or a\n   * `migrate` written inline changes identity on every render, so neither can\n   * be allowed to trigger it. Refreshing is therefore something the host asks\n   * for rather than something identity accidentally causes.\n   */\n  reload: () => void;\n}\n\nconst BARE_PARAMS = [\n  PARAM_PAGE,\n  PARAM_LIMIT,\n  PARAM_SEARCH,\n  PARAM_SORT_BY,\n  PARAM_SORT_DIR,\n  // The multi-sort chain — it supersedes sortBy/sortDir, so a view that\n  // missed it could neither capture nor displace an active chain.\n  PARAM_SORT,\n  PARAM_GROUP_BY,\n  PARAM_COL_HIDDEN,\n  PARAM_COL_PINNED,\n  PARAM_COL_ORDER,\n  PARAM_COL_WIDTHS,\n  PARAM_COL_GROUPS,\n  PARAM_ROW_PIN,\n  // The advanced filter tree, collapsed groups, density, the pivot and the\n  // typed formula columns. A view that captured everything EXCEPT these looked\n  // like it worked and then quietly dropped the most laboriously built parts of\n  // the state — and a formula is the one part nobody can rebuild from memory,\n  // because the table never offered it: someone wrote it.\n  PARAM_FILTER_TREE,\n  PARAM_GROUP_CLOSED,\n  PARAM_DENSITY,\n  PARAM_PIVOT,\n  PARAM_FORMULA,\n];\n\n/**\n * Bring a view up to today's schema.\n *\n * Version 1 is everything saved before versioning existed. Its `search` is\n * already the shape the table reads, so the built-in step is only the stamp —\n * but the step exists so the NEXT change has somewhere to go, and so a host's\n * `migrate` is handed a view whose version it can trust.\n *\n * @param view - The stored view, as it came off the wire or out of storage.\n * @param migrate - The host's own upgrade, run after the built-in one.\n * @returns The upgraded view, or `null` when it should be dropped.\n */\nfunction migrateView(\n  view: SavedView,\n  migrate: SavedViewMigration | undefined\n): SavedView | null {\n  const from = view.version ?? 1;\n  if (from >= SAVED_VIEW_VERSION) return view;\n  const upgraded: SavedView = { ...view, version: SAVED_VIEW_VERSION };\n  if (!migrate) return upgraded;\n  return migrate(upgraded, from);\n}\n\n/**\n * Every stored view, upgraded, with the ones the host dropped removed.\n *\n * A view that throws during migration is dropped rather than allowed to take\n * the list down with it: one bad view in storage should cost that view, not\n * every view.\n */\nfunction migrateAll(\n  views: readonly SavedView[],\n  migrate: SavedViewMigration | undefined\n): SavedView[] {\n  const out: SavedView[] = [];\n  for (const view of views) {\n    try {\n      const upgraded = migrateView(view, migrate);\n      if (upgraded) out.push(upgraded);\n    } catch {\n      // Dropped: see above.\n    }\n  }\n  return out;\n}\n\n/**\n * A store that rejects leaves the list as the user last saw it rather than\n * throwing into a render. The alternative — an unhandled rejection — takes\n * the page down over a failed view save.\n */\nfunction swallow(): void {\n  return undefined;\n}\n\n/**\n * What one operation changed, in a store's terms.\n *\n * `localStorage` takes the whole array in a single write and needs none of\n * this. A store owns one view at a time, so an operation has to name every\n * view whose stored copy is stale — and a default switch makes TWO stale: the\n * view that gains the flag and the view that loses it. A cleared flag that\n * never reaches the store comes back set at the next `list()`, and then two\n * views claim a field that allows one.\n */\ninterface StoreWrites {\n  /** Views whose stored copy is stale, each written through `save`. */\n  readonly saved?: readonly SavedView[];\n  /** A name whose stored copy must go. */\n  readonly removed?: string;\n  /** Whether the list order changed, which `reorder` persists. */\n  readonly reordered?: boolean;\n}\n\n/** A view without its default flag, so the stored shape stays minimal. */\nfunction omitDefault(view: SavedView): SavedView {\n  if (view.isDefault === undefined) return view;\n  const next = { ...view };\n  delete next.isDefault;\n  return next;\n}\n\n/** Whether a param key belongs to the table at namespace `ns`. */\nfunction ownsParam(key: string, ns: string): boolean {\n  return (\n    BARE_PARAMS.some((p) => key === ns + p) ||\n    key.startsWith(ns + FILTER_PREFIX)\n  );\n}\n\n/** The table-scoped subset of a full query string. */\nfunction captureTableParams(search: string, ns: string): string {\n  const all = new URLSearchParams(search);\n  const own = new URLSearchParams();\n  all.forEach((value, key) => {\n    if (ownsParam(key, ns)) own.set(key, value);\n  });\n  return own.toString();\n}\n\nfunction readStored(\n  storage: LayoutStorage | undefined,\n  key: string\n): SavedView[] {\n  if (!storage) return [];\n  try {\n    const raw = storage.getItem(key);\n    if (!raw) return [];\n    const parsed: unknown = JSON.parse(raw);\n    if (!Array.isArray(parsed)) return [];\n    return parsed.filter(\n      (v): v is SavedView =>\n        typeof v === \"object\" &&\n        v !== null &&\n        typeof (v as SavedView).name === \"string\" &&\n        typeof (v as SavedView).search === \"string\"\n    );\n  } catch {\n    return [];\n  }\n}\n\n/**\n * Headless saved views: capture the table's current URL state (search,\n * sort, page, filters, column layout — ONLY this table's params) under a\n * name, persist the list, and re-apply on demand without touching other\n * tables sharing the URL. Wire it to any menu in the `toolbar` slot.\n */\nexport function useSavedViews({\n  storageKey,\n  storage,\n  store,\n  visibility = \"private\",\n  migrate,\n  urlAdapter,\n  urlKey,\n  urlSync = true,\n}: UseSavedViewsOptions): UseSavedViewsResult {\n  const resolved = useResolvedAdapter(urlAdapter, urlSync);\n  const ns = urlKey ? `${urlKey}.` : \"\";\n  const backend = useMemo<LayoutStorage | undefined>(() => {\n    if (storage) return storage;\n    return safeLocalStorage();\n  }, [storage]);\n\n  // Start empty and hydrate from storage AFTER mount: reading storage in\n  // the initializer made the client's first render differ from the\n  // server's whenever views were saved (hydration mismatch).\n  const [views, setViews] = useState<SavedView[]>([]);\n  // The store and the migration are held rather than depended on: both are\n  // routinely written inline, and an effect keyed on their identity would\n  // re-run every render — a load loop the host has no way to see coming.\n  const latest = useRef({ store, migrate, backend, storageKey });\n  latest.current = { store, migrate, backend, storageKey };\n  const [reloads, setReloads] = useState(0);\n  const reload = useCallback(() => {\n    setReloads((n) => n + 1);\n  }, []);\n\n  useEffect(() => {\n    const { store: s, migrate: m, backend: b, storageKey: k } = latest.current;\n    if (s) return undefined;\n    setViews(migrateAll(readStored(b, k), m));\n    return undefined;\n  }, [storageKey, reloads]);\n\n  useEffect(() => {\n    const { store, migrate } = latest.current;\n    if (!store) return undefined;\n    // A store's answer can arrive after the table has moved on; ignore a\n    // reply that is no longer the one being waited for.\n    let current = true;\n    void store.list().then(\n      (remote) => {\n        if (current) setViews(migrateAll(remote, migrate));\n      },\n      () => {\n        // A store that cannot be reached leaves the list empty rather than\n        // throwing into a render. The table still works; the views do not.\n        if (current) setViews([]);\n      }\n    );\n    return () => {\n      current = false;\n    };\n  }, [storageKey, reloads]);\n\n  const persist = useCallback(\n    (next: SavedView[], writes: StoreWrites = {}) => {\n      setViews(next);\n      if (store) {\n        // The store owns one view at a time, not the list: sending the whole\n        // list back would overwrite what other people changed meanwhile. So\n        // every stale view is written on its own, and the list's own property\n        // — its order — goes through `reorder` as names, carrying no view\n        // contents with it.\n        const written: Promise<void>[] = [];\n        if (writes.removed !== undefined) {\n          written.push(store.remove(writes.removed).catch(swallow));\n        }\n        for (const view of writes.saved ?? []) {\n          written.push(store.save(view).catch(swallow));\n        }\n        if (writes.reordered && store.reorder) {\n          const order = next.map((view) => view.name);\n          // Order goes last, once the writes it describes have settled: a\n          // rename reaches a store as a delete plus a save, and a store hearing\n          // the new name first in a reorder has nothing to order yet.\n          void Promise.all(written)\n            .then(() => store.reorder?.(order))\n            .catch(swallow);\n        }\n        return;\n      }\n      try {\n        backend?.setItem(storageKey, JSON.stringify(next));\n      } catch {\n        // Storage may be full or denied — the in-memory list still works.\n      }\n    },\n    [backend, storageKey, store]\n  );\n\n  const save = useCallback(\n    (name: string) => {\n      const view: SavedView = {\n        name,\n        search: captureTableParams(resolved.getSearch(), ns),\n        version: SAVED_VIEW_VERSION,\n        ...(visibility === \"private\" ? {} : { visibility }),\n      };\n      persist([...views.filter((v) => v.name !== name), view], {\n        saved: [view],\n      });\n    },\n    [views, persist, resolved, ns, visibility]\n  );\n\n  const rename = useCallback(\n    (from: string, to: string) => {\n      const trimmed = to.trim();\n      if (trimmed === \"\" || from === trimmed) return;\n      // Renaming onto an existing name would merge two views into one and\n      // lose whichever lost the race. Refuse instead.\n      if (views.some((view) => view.name === trimmed)) return;\n      const target = views.find((view) => view.name === from);\n      // A read-only view belongs to someone else. Refusing here means the\n      // panel's disabled controls and the hook agree, rather than the hook\n      // quietly accepting what the UI said was impossible.\n      if (!target || target.readOnly === true) return;\n      persist(\n        views.map((view) =>\n          view.name === from ? { ...view, name: trimmed } : view\n        ),\n        {\n          saved: [{ ...target, name: trimmed }],\n          removed: from,\n          // A rename keeps the view's place, and to a store that place is new\n          // information: the view arrives there as a delete plus a save under\n          // a name the store has never seen, which it would otherwise file\n          // wherever new views go.\n          reordered: true,\n        }\n      );\n    },\n    [views, persist]\n  );\n\n  const move = useCallback(\n    (name: string, delta: -1 | 1) => {\n      const index = views.findIndex((view) => view.name === name);\n      const moved = views[index];\n      // Read-only is refused here for the same reason rename, setDefault and\n      // remove refuse it: the panel disables a read-only row's move controls,\n      // and a hook that accepted the move anyway would let code do what the\n      // UI said was impossible.\n      if (!moved || moved.readOnly === true) return;\n      const target = index + delta;\n      if (target < 0 || target >= views.length) return;\n      const next = [...views];\n      next.splice(index, 1);\n      next.splice(target, 0, moved);\n      // Nothing about either view changed — only where they sit — so this is\n      // the one operation with no per-view write at all.\n      persist(next, { reordered: true });\n    },\n    [views, persist]\n  );\n\n  const setDefault = useCallback(\n    (name: string) => {\n      const target = views.find((view) => view.name === name);\n      if (!target || target.readOnly === true) return;\n      // Toggling: naming the current default again clears it.\n      const already = views.find((view) => view.isDefault)?.name === name;\n      const next: SavedView[] = views.map((view) => {\n        const isDefault = !already && view.name === name;\n        return isDefault ? { ...view, isDefault } : omitDefault(view);\n      });\n      // Every view the switch touches has to reach the store, not only the one\n      // that gains the flag: a cleared flag that never gets written comes back\n      // set at the next `list()`, and then two views claim to be the default.\n      // `omitDefault` hands back the very same object when there is nothing to\n      // clear, so a changed identity is exactly the set of stale views — which\n      // also settles a store already holding more than one default.\n      persist(next, {\n        saved: next.filter((view, index) => view !== views[index]),\n      });\n    },\n    [views, persist]\n  );\n\n  const apply = useCallback(\n    (name: string) => {\n      const view = views.find((v) => v.name === name);\n      if (!view) return;\n      const next = new URLSearchParams(resolved.getSearch());\n      // Drop this table's current params, then lay the view's over.\n      const stale: string[] = [];\n      next.forEach((_, key) => {\n        if (ownsParam(key, ns)) stale.push(key);\n      });\n      for (const key of stale) next.delete(key);\n      // Write owned params ONLY — a stored view is external input (old\n      // versions, hand-edited storage) and must never touch params that\n      // belong to other tables or the surrounding app.\n      new URLSearchParams(view.search).forEach((value, key) => {\n        if (ownsParam(key, ns)) next.set(key, value);\n      });\n      resolved.setSearch(next.toString());\n    },\n    [views, resolved, ns]\n  );\n\n  const remove = useCallback(\n    (name: string) => {\n      const target = views.find((view) => view.name === name);\n      if (!target || target.readOnly === true) return;\n      persist(\n        views.filter((v) => v.name !== name),\n        { removed: name }\n      );\n    },\n    [views, persist]\n  );\n\n  return {\n    views,\n    save,\n    apply,\n    remove,\n    rename,\n    move,\n    setDefault,\n    defaultView: views.find((view) => view.isDefault),\n    reload,\n  };\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type { FacetMap } from \"../filters/facets\";\nimport { parseGroupBy } from \"../grouping/groupKeys\";\nimport { resolvePaginationMode, useIsMobile } from \"../hooks/useIsMobile\";\nimport type {\n  PaginatedResponse,\n  PaginationMode,\n  TableQueryParams,\n} from \"../types\";\nimport {\n  useTableUrlState,\n  type UseTableUrlStateOptions,\n} from \"../url/useTableUrlState\";\nimport {\n  applyQuerySupport,\n  type QueryAggregate,\n  type QuerySupport,\n} from \"./queryContract\";\nimport type { TableSource } from \"./TableSource\";\n\n/**\n * The minimal shape `useQuerySource` reads from a `useInfiniteQuery`\n * result. Declared structurally so `@tanstack/react-query` stays an\n * optional, type-only peer dependency (no runtime import).\n *\n * @typeParam TPage - The page type returned by each fetch.\n */\nexport interface InfiniteQueryLike<TPage> {\n  data: { pages: TPage[]; pageParams: unknown[] } | undefined;\n  isLoading: boolean;\n  isFetching: boolean;\n  isFetchingNextPage: boolean;\n  hasNextPage: boolean;\n  fetchNextPage: () => Promise<unknown> | void;\n  refetch: () => Promise<unknown> | void;\n  error: Error | null;\n}\n\n/** Project a fetched page to its rows (and optional total). */\nexport type PageSelector<TRow, TPage> = (page: TPage) => {\n  rows: readonly TRow[];\n  total?: number;\n  facets?: FacetMap;\n};\n\n/** Options for {@link useQuerySource}. */\nexport interface UseQuerySourceOptions<\n  TRow,\n  TParams extends TableQueryParams,\n  TPage,\n> extends Pick<\n  UseTableUrlStateOptions,\n  | \"urlAdapter\"\n  | \"urlSync\"\n  | \"defaults\"\n  | \"numberExtraKeys\"\n  | \"arrayExtraKeys\"\n  | \"urlKey\"\n> {\n  /**\n   * The caller's paginated-query hook, built on `useInfiniteQuery`. It\n   * receives the merged params and must return an {@link InfiniteQueryLike}.\n   */\n  usePaginatedQuery: (params: Partial<TParams>) => InfiniteQueryLike<TPage>;\n  /** Page → `{ items, total }` selector. Defaults to reading {@link PaginatedResponse}. */\n  selectPage?: PageSelector<TRow, TPage>;\n  /**\n   * Static params merged into every query call (e.g. a parent scope id).\n   * The live table state always wins on collision: `page`, `limit`,\n   * `search`, `sortBy`, `sortDir`, `groupBy` and `filters` come from the\n   * table itself and can never be overridden here — seed state through\n   * `defaults` instead.\n   */\n  baseParams?: Partial<TParams>;\n  /** Pagination mode. Defaults to `\"auto\"` (mobile → infinite). */\n  paginationMode?: PaginationMode;\n  /** Final scrubber on the merged params before they reach the query. */\n  sanitizeParams?: (params: Partial<TParams>) => Partial<TParams>;\n  /** Force the resolved mobile state instead of a media query (test/SSR seam). */\n  forceMobile?: boolean;\n  /**\n   * What the endpoint can answer, exactly as {@link useServerData} takes it.\n   * Only a declared capability is ever sent; an undeclared one is dropped\n   * before the request rather than sent and ignored.\n   */\n  supports?: QuerySupport;\n  /**\n   * Aggregates to ask the server for — `[{ key: \"budget\", fn: \"sum\" }]`.\n   *\n   * Sent only when the source declares `supports.aggregates`. With grouping\n   * armed the server computes them per group; without it, over the whole\n   * result set.\n   */\n  aggregates?: readonly QueryAggregate[];\n  /**\n   * The tree nodes the reader has open, when the hierarchy lives on the server.\n   * Sent as `expandedIds` only if the source declares\n   * `supports: { tree: true }`, so the response can carry the children of every\n   * open branch alongside the page. Hold the same array in the table's\n   * `expandedIds` and one piece of state drives both.\n   */\n  expandedIds?: readonly string[];\n  /**\n   * The token that opens the NEXT page, read from the page the query just\n   * returned — pass it and declare `supports: { cursor: true }` to page by\n   * cursor instead of by offset.\n   *\n   * Rows inserted or deleted mid-read shift every offset after them, which is\n   * how an offset pager duplicates or skips rows; a cursor names a position in\n   * the result rather than a distance into it.\n   */\n  nextCursor?: (page: TPage) => string | null | undefined;\n  /**\n   * Filter keys to ask the server for distinct-value counts. Sent as\n   * `query.facets` only when `supports.facets` is set.\n   */\n  facetKeys?: readonly string[];\n}\n\nconst defaultSelectPage: PageSelector<unknown, PaginatedResponse<unknown>> = (\n  page\n) => ({ rows: page.rows ?? [], total: page.total, facets: page.facets });\n\n/**\n * Server-paginated {@link TableSource}. Wraps a caller's\n * `useInfiniteQuery` hook and exposes the uniform contract: flattening\n * pages in infinite mode, returning the latest page in paged mode, and\n * keeping query params in sync with URL state.\n *\n * @returns A {@link TableSource} backed by the server query.\n */\nexport function useQuerySource<\n  TRow,\n  TParams extends TableQueryParams = TableQueryParams,\n  TPage = PaginatedResponse<TRow>,\n>(options: UseQuerySourceOptions<TRow, TParams, TPage>): TableSource<TRow> {\n  const {\n    usePaginatedQuery,\n    selectPage,\n    baseParams,\n    paginationMode = \"auto\",\n    sanitizeParams,\n    forceMobile,\n    supports,\n    aggregates,\n    expandedIds,\n    nextCursor,\n    facetKeys,\n    ...urlOptions\n  } = options;\n\n  const mediaMobile = useIsMobile();\n  const isMobile = forceMobile ?? mediaMobile;\n  const resolvedMode = resolvePaginationMode(paginationMode, isMobile);\n  const paged = resolvedMode === \"paged\";\n\n  const state = useTableUrlState(urlOptions);\n  const { page, limit, search, sortBy, sortDir, groupBy, extra } = state;\n\n  // Cursor mode keeps every token the server has handed out, indexed by the\n  // page it opens: `cursors[0]` is always `undefined` (page 1 needs no token)\n  // and `cursors[n]` opens page n+1. The trail is what lets the user page BACK\n  // through what they have already seen — a single \"next cursor\" cannot.\n  const cursorMode = supports?.cursor === true;\n  const [cursors, setCursors] = useState<readonly (string | undefined)[]>([\n    undefined,\n  ]);\n  const cursor = cursorMode ? cursors[page - 1] : undefined;\n\n  const params = useMemo(() => {\n    // baseParams are DEFAULTS: everything live is written after them, so a\n    // static param can never beat the user's current state. Filter values\n    // travel under their own `filters` key — a user filter named `sortBy`,\n    // `search` or `groupBy` can never collide with a state param.\n    const merged: Record<string, unknown> = { ...baseParams };\n    merged.page = page;\n    merged.limit = limit;\n    merged.search = search || undefined;\n    merged.sortBy = sortBy;\n    merged.sortDir = sortDir;\n    merged.groupBy = groupBy;\n    merged.filters = extra;\n    // Everything past the baseline is gated on what the source declared. The\n    // grouping keys travel as a LIST even when there is one — the contract has\n    // always been an array, so nesting needed no new field.\n    Object.assign(\n      merged,\n      applyQuerySupport(\n        {\n          cursor,\n          groupBy: parseGroupBy(groupBy),\n          aggregates,\n          expandedIds,\n          filterTree: state.filterTree,\n          facets: facetKeys,\n        },\n        supports\n      )\n    );\n    const next = merged as Partial<TParams>;\n    return sanitizeParams ? sanitizeParams(next) : next;\n  }, [\n    extra,\n    baseParams,\n    page,\n    limit,\n    search,\n    sortBy,\n    sortDir,\n    groupBy,\n    sanitizeParams,\n    cursor,\n    aggregates,\n    expandedIds,\n    supports,\n    state.filterTree,\n    facetKeys,\n  ]);\n\n  const query = usePaginatedQuery(params);\n\n  // Record the token the CURRENT page handed back, so \"next\" has something to\n  // send and a later \"back\" can retrace the trail. Read from the last page the\n  // infinite query holds, which is the one the table is showing.\n  const lastPage = query.data?.pages.at(-1);\n  const token = cursorMode && lastPage ? nextCursor?.(lastPage) : undefined;\n  useEffect(() => {\n    if (!cursorMode || token === undefined || token === null) return;\n    setCursors((prev) => {\n      if (prev[page] === token) return prev;\n      const next = [...prev];\n      next[page] = token;\n      return next;\n    });\n  }, [cursorMode, token, page]);\n\n  // A query whose cursor trail is stale must start over rather than page into\n  // a position that no longer exists: any change to what the query MEANS\n  // (search, sort, filters, page size) invalidates every token already held.\n  const trailKey = `${limit}|${search}|${sortBy ?? \"\"}|${sortDir ?? \"\"}|${groupBy ?? \"\"}|${JSON.stringify(extra)}`;\n  const previousTrailKey = useRef(trailKey);\n  useEffect(() => {\n    if (!cursorMode || previousTrailKey.current === trailKey) return;\n    previousTrailKey.current = trailKey;\n    setCursors([undefined]);\n  }, [cursorMode, trailKey]);\n\n  // Route the selector through a ref so the rows memo only refires when\n  // upstream data changes, not on every parent render (inline selectors\n  // are a fresh reference each render).\n  const selector = (selectPage ?? defaultSelectPage) as PageSelector<\n    TRow,\n    TPage\n  >;\n  const selectorRef = useRef(selector);\n  selectorRef.current = selector;\n\n  const { rows, total, facets } = useMemo(() => {\n    const pages = query.data?.pages;\n    if (!pages?.length) {\n      return { rows: [] as readonly TRow[], total: 0, facets: undefined };\n    }\n    const project = selectorRef.current;\n    if (paged) {\n      const lastPage = pages.at(-1)!;\n      const projected = project(lastPage);\n      return {\n        rows: projected.rows,\n        total: projected.total ?? projected.rows.length,\n        facets: projected.facets,\n      };\n    }\n    const acc: TRow[] = [];\n    let lastTotal: number | undefined;\n    let lastFacets: FacetMap | undefined;\n    for (const pg of pages) {\n      const projected = project(pg);\n      acc.push(...projected.rows);\n      if (projected.total !== undefined) lastTotal = projected.total;\n      if (projected.facets) lastFacets = projected.facets;\n    }\n    // Mirror the paged branch / useFrontendData: when the source reports no\n    // grand total, fall back to the accumulated row count rather than 0.\n    return { rows: acc, total: lastTotal ?? acc.length, facets: lastFacets };\n  }, [query.data, paged]);\n\n  // Clamp out-of-range pages (hand-edited / stale shared links) once the\n  // total is known and nothing is in flight.\n  useEffect(() => {\n    if (!paged || query.isLoading || query.isFetching || total <= 0) return;\n    const lastPage = Math.max(1, Math.ceil(total / Math.max(limit, 1)));\n    if (page > lastPage) state.setPage(lastPage);\n  }, [paged, query.isLoading, query.isFetching, total, limit, page, state]);\n\n  // Query libraries hand back a FRESH result object every render — latch\n  // it so these two keep stable identity (they gate the source memo).\n  // Shared contract: append semantics exist only in infinite mode — paged\n  // navigation is `setPage`, so in paged mode `fetchNextPage` no-ops and\n  // the append flags below read false instead of leaking TanStack's values.\n  const queryRef = useRef(query);\n  queryRef.current = query;\n  const fetchNextPage = useCallback(() => {\n    if (paged) return;\n    const live = queryRef.current;\n    if (live.hasNextPage && !live.isFetchingNextPage) void live.fetchNextPage();\n  }, [paged]);\n\n  const refetch = useCallback(() => queryRef.current.refetch(), []);\n\n  // Memoised so the returned source keeps its identity across unrelated\n  // renders — a fresh object every render defeated downstream memoization\n  // (and the React Compiler bails on this hook, unlike useFrontendData).\n  // The mutators are destructured because the url-state RESULT object is\n  // itself fresh every render; its members are the stable parts.\n  const {\n    setPage,\n    setLimit,\n    setSort,\n    setGroupBy,\n    sortLevels,\n    toggleSortLevel,\n    setSearch,\n    setExtra,\n    setExtras,\n    setFilterTree,\n    clearExtras,\n    clearAll,\n  } = state;\n  return useMemo(\n    () => ({\n      rows,\n      total,\n      isLoading: query.isLoading,\n      isFetching: query.isFetching,\n      isFetchingNextPage: paged ? false : query.isFetchingNextPage,\n      hasNextPage: paged ? false : query.hasNextPage,\n      fetchNextPage,\n      error: query.error,\n      refetch,\n      paginationMode: resolvedMode,\n      page,\n      limit,\n      defaultLimit: state.defaultLimit,\n      search,\n      sortBy,\n      sortDir,\n      groupBy,\n      extra,\n      facets,\n      filterTree: state.filterTree,\n      setPage,\n      setLimit,\n      setSort,\n      setGroupBy,\n      sortLevels,\n      toggleSortLevel,\n      setSearch,\n      setExtra,\n      setExtras,\n      setFilterTree,\n      clearExtras,\n      clearAll,\n    }),\n    [\n      rows,\n      total,\n      paged,\n      query.isLoading,\n      query.isFetching,\n      query.isFetchingNextPage,\n      query.hasNextPage,\n      fetchNextPage,\n      query.error,\n      refetch,\n      resolvedMode,\n      page,\n      limit,\n      state.defaultLimit,\n      search,\n      sortBy,\n      sortDir,\n      groupBy,\n      extra,\n      facets,\n      state.filterTree,\n      setPage,\n      setLimit,\n      setSort,\n      setGroupBy,\n      sortLevels,\n      toggleSortLevel,\n      setSearch,\n      setExtra,\n      setExtras,\n      setFilterTree,\n      clearExtras,\n      clearAll,\n    ]\n  );\n}\n","import type { ExtraFilters, FilterValue } from \"../types\";\n\n/** Numeric comparison operators for count/usage filters. */\nexport const COUNT_OPERATORS = [\n  \"eq\",\n  \"gte\",\n  \"lte\",\n  \"gt\",\n  \"lt\",\n  \"between\",\n] as const;\n\n/** Numeric comparison operator. */\nexport type CountOperator = (typeof COUNT_OPERATORS)[number];\n\n/** State for one operator-driven count filter. */\nexport interface CountFilterState {\n  op?: CountOperator;\n  value?: number;\n  from?: number;\n  to?: number;\n}\n\n/** Symbols used in compact chip labels. */\nexport const COUNT_OPERATOR_SYMBOL: Record<CountOperator, string> = {\n  eq: \"=\",\n  gte: \"≥\",\n  lte: \"≤\",\n  gt: \">\",\n  lt: \"<\",\n  between: \"↔\",\n};\n\nconst OP_SUFFIX = \"Op\";\nconst VALUE_SUFFIX = \"Value\";\nconst FROM_SUFFIX = \"From\";\nconst TO_SUFFIX = \"To\";\n\nconst opKey = (bucket: string) => `${bucket}${OP_SUFFIX}`;\nconst valueKey = (bucket: string) => `${bucket}${VALUE_SUFFIX}`;\nconst fromKey = (bucket: string) => `${bucket}${FROM_SUFFIX}`;\nconst toKey = (bucket: string) => `${bucket}${TO_SUFFIX}`;\n\nfunction isNumber(value: unknown): value is number {\n  return typeof value === \"number\" && Number.isFinite(value);\n}\n\n/**\n * Coerce a raw extra/param value to a finite number. URL state arrives as\n * strings (e.g. `\"5\"`), so a bare `as number` cast would leave numeric\n * filters looking incomplete and silently drop them. Returns undefined for\n * anything that is not a finite number or numeric string.\n */\nfunction toNumber(value: unknown): number | undefined {\n  if (typeof value === \"number\")\n    return Number.isFinite(value) ? value : undefined;\n  if (typeof value === \"string\" && value.trim() !== \"\") {\n    const parsed = Number(value);\n    return Number.isFinite(parsed) ? parsed : undefined;\n  }\n  return undefined;\n}\n\n/** Coerce a raw value to a known {@link CountOperator}, else undefined. */\nfunction toOperator(value: unknown): CountOperator | undefined {\n  return COUNT_OPERATORS.includes(value as CountOperator)\n    ? (value as CountOperator)\n    : undefined;\n}\n\n/** Whether a count-filter state is complete enough to affect a query. */\nexport function isCountFilterComplete(state: CountFilterState): boolean {\n  if (!state.op) return false;\n  if (state.op === \"between\") {\n    return isNumber(state.from) && isNumber(state.to);\n  }\n  return isNumber(state.value);\n}\n\n/** Convert a state update to URL-extra values for one bucket. */\nexport function countFilterExtra(\n  bucket: string,\n  state: CountFilterState\n): ExtraFilters {\n  return {\n    [opKey(bucket)]: state.op,\n    [valueKey(bucket)]: state.op === \"between\" ? undefined : state.value,\n    [fromKey(bucket)]: state.op === \"between\" ? state.from : undefined,\n    [toKey(bucket)]: state.op === \"between\" ? state.to : undefined,\n  };\n}\n\n/** URL-extra update that clears every value for one bucket. */\nexport function clearCountFilterExtra(bucket: string): ExtraFilters {\n  return {\n    [opKey(bucket)]: undefined,\n    [valueKey(bucket)]: undefined,\n    [fromKey(bucket)]: undefined,\n    [toKey(bucket)]: undefined,\n  };\n}\n\n/** Rehydrate one bucket's count-filter state from an extra-filter bag. */\nexport function countFilterStateFromExtra(\n  bucket: string,\n  extra: Readonly<Record<string, FilterValue>>\n): CountFilterState {\n  return {\n    op: toOperator(extra[opKey(bucket)]),\n    value: toNumber(extra[valueKey(bucket)]),\n    from: toNumber(extra[fromKey(bucket)]),\n    to: toNumber(extra[toKey(bucket)]),\n  };\n}\n\n/**\n * Remove incomplete count filters from backend params while preserving any\n * unrelated params. This lets a UI keep partial state in the URL without\n * sending invalid operator/value pairs to an API.\n */\nexport function sanitizeCountFilterParams<P extends Record<string, unknown>>(\n  params: P,\n  buckets: readonly string[]\n): P {\n  const out: Record<string, unknown> = { ...params };\n  for (const bucket of buckets) {\n    const state: CountFilterState = {\n      op: toOperator(out[opKey(bucket)]),\n      value: toNumber(out[valueKey(bucket)]),\n      from: toNumber(out[fromKey(bucket)]),\n      to: toNumber(out[toKey(bucket)]),\n    };\n    if (isCountFilterComplete(state)) continue;\n    delete out[opKey(bucket)];\n    delete out[valueKey(bucket)];\n    delete out[fromKey(bucket)];\n    delete out[toKey(bucket)];\n  }\n  return out as P;\n}\n\n/** Build a compact chip label for a complete count filter. */\nexport function countFilterChipLabel(\n  label: string,\n  state: CountFilterState\n): string | undefined {\n  if (!isCountFilterComplete(state) || !state.op) return undefined;\n  if (state.op === \"between\") {\n    return `${label}: ${state.from}-${state.to}`;\n  }\n  return `${label} ${COUNT_OPERATOR_SYMBOL[state.op]} ${state.value}`;\n}\n","import { useCallback, useEffect, useMemo, useState } from \"react\";\n\nimport { devWarn } from \"../utils/devWarn\";\nimport { safeLocalStorage } from \"../utils/env\";\nimport { stableKey } from \"../utils/stableKey\";\nimport { type ColumnLayoutState, EMPTY_COLUMN_LAYOUT } from \"./useColumnLayout\";\n\n/** The subset of the Web `Storage` API the hook needs (injectable for tests). */\nexport type LayoutStorage = Pick<Storage, \"getItem\" | \"setItem\" | \"removeItem\">;\n\n/** Options for {@link useColumnLayoutStorageState}. */\nexport interface UseColumnLayoutStorageStateOptions {\n  /** Storage key for this table's layout, e.g. `\"people-table-columns\"`. */\n  storageKey: string;\n  /** Storage backend. Defaults to `localStorage`; memory-only under SSR. */\n  storage?: LayoutStorage;\n  /** Layout applied when storage carries no saved layout yet. */\n  defaultColumnLayout?: Partial<ColumnLayoutState>;\n}\n\n/** State + change handler returned by {@link useColumnLayoutStorageState}. */\nexport interface UseColumnLayoutStorageStateResult {\n  /** Current layout — from storage, or the default when storage is empty. */\n  layout: ColumnLayoutState;\n  /** Persist a new layout. Wire to `onColumnLayoutChange`. */\n  onLayoutChange: (next: ColumnLayoutState) => void;\n}\n\n/** Keep only string entries of a (possibly hostile) stored array. */\nfunction stringEntries(value: unknown): string[] {\n  if (!Array.isArray(value)) return [];\n  return value.filter((entry): entry is string => typeof entry === \"string\");\n}\n\n/** A non-null, non-array object — the only shape worth field-scanning. */\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Keep only valid pin sides of a (possibly hostile) stored record. */\nfunction sanitizePinned(value: unknown): Record<string, \"start\" | \"end\"> {\n  const pinned: Record<string, \"start\" | \"end\"> = {};\n  if (!isPlainRecord(value)) return pinned;\n  for (const [key, side] of Object.entries(value)) {\n    if (side === \"start\" || side === \"end\") pinned[key] = side;\n  }\n  return pinned;\n}\n\n/** Keep only finite positive widths of a (possibly hostile) stored record. */\nfunction sanitizeWidths(value: unknown): Record<string, number> {\n  const widths: Record<string, number> = {};\n  if (!isPlainRecord(value)) return widths;\n  for (const [key, px] of Object.entries(value)) {\n    if (typeof px === \"number\" && Number.isFinite(px) && px > 0) {\n      widths[key] = px;\n    }\n  }\n  return widths;\n}\n\n/**\n * Validate a parsed storage payload into a {@link ColumnLayoutState}.\n * Persisted data is external input — hand-edited or written by another\n * app version — so every field is checked; anything malformed is dropped\n * rather than crashing the table. Returns `null` when the payload is not\n * even an object.\n */\nfunction sanitizeStoredLayout(parsed: unknown): ColumnLayoutState | null {\n  if (!isPlainRecord(parsed)) return null;\n  return {\n    hidden: stringEntries(parsed.hidden),\n    order: stringEntries(parsed.order),\n    pinned: sanitizePinned(parsed.pinned),\n    widths: sanitizeWidths(parsed.widths),\n  };\n}\n\nfunction readStored(\n  storage: LayoutStorage | undefined,\n  storageKey: string\n): ColumnLayoutState | null {\n  try {\n    const raw = storage?.getItem(storageKey);\n    if (!raw) return null;\n    const sanitized = sanitizeStoredLayout(JSON.parse(raw));\n    if (sanitized === null) {\n      devWarn(\n        `stored column layout under \"${storageKey}\" is not a layout object — ignoring it.`\n      );\n    }\n    return sanitized;\n  } catch {\n    // Corrupted/inaccessible storage (private mode, quota) → just fall back.\n    return null;\n  }\n}\n\n/**\n * Column layout persisted to `localStorage` (or any injected storage) — the\n * \"user preference\" counterpart to {@link useColumnLayoutUrlState}'s\n * shareable links. A layout set back to the exact default removes the stored\n * entry, so defaults can evolve in later releases. SSR-safe: without a\n * browser the layout stays in memory for that render.\n *\n * ```tsx\n * const { layout, onLayoutChange } = useColumnLayoutStorageState({\n *   storageKey: \"people-table-columns\",\n * });\n * <DataTable columnLayout={layout} onColumnLayoutChange={onLayoutChange} … />\n * ```\n *\n * @param options - See {@link UseColumnLayoutStorageStateOptions}.\n * @returns The current layout and a change handler that persists it.\n */\nexport function useColumnLayoutStorageState(\n  options: UseColumnLayoutStorageStateOptions\n): UseColumnLayoutStorageStateResult {\n  const { storageKey, defaultColumnLayout } = options;\n  const baseLayout = defaultColumnLayout;\n  const storage = options.storage ?? safeLocalStorage();\n\n  const fallback = useMemo<ColumnLayoutState>(\n    () => ({ ...EMPTY_COLUMN_LAYOUT, ...baseLayout }),\n    [baseLayout]\n  );\n  // Start from the default and hydrate from storage AFTER mount: reading\n  // storage in the initializer made the client's first render differ from\n  // the server's whenever a layout was saved (hydration mismatch).\n  const [layout, setLayout] = useState<ColumnLayoutState>(fallback);\n  useEffect(() => {\n    const stored = readStored(storage, storageKey);\n    if (stored !== null) setLayout(stored);\n    // `storage` is module-stable (localStorage) or caller-provided.\n  }, [storage, storageKey]);\n\n  const onLayoutChange = useCallback(\n    (next: ColumnLayoutState) => {\n      setLayout(next);\n      try {\n        if (stableKey(next) === stableKey(fallback)) {\n          storage?.removeItem(storageKey);\n        } else {\n          storage?.setItem(storageKey, JSON.stringify(next));\n        }\n      } catch {\n        // Storage write failed (quota/private mode) — state still updates.\n      }\n    },\n    [storage, storageKey, fallback]\n  );\n\n  return { layout, onLayoutChange };\n}\n","import type { ColorScheme } from \"../types\";\nimport { useMediaQuery } from \"./useMediaQuery\";\n\n/** The media query that matches when the OS prefers a dark color scheme. */\nexport const DARK_SCHEME_QUERY = \"(prefers-color-scheme: dark)\";\n\n/**\n * Resolve a color-scheme preference to a concrete `\"light\"` or `\"dark\"`.\n * `\"auto\"` follows the OS via `prefers-color-scheme`; an explicit\n * preference is returned unchanged. Adapters map the result to their\n * theming (Mantine/MUI/Chakra color schemes, or a `data-theme` attribute\n * + CSS variables for the unstyled adapter).\n *\n * @param preference - `\"light\" | \"dark\" | \"auto\"`. Defaults to `\"auto\"`.\n * @returns The resolved scheme, `\"light\"` or `\"dark\"`.\n */\nexport function useColorScheme(\n  preference: ColorScheme = \"auto\"\n): \"light\" | \"dark\" {\n  const prefersDark = useMediaQuery(DARK_SCHEME_QUERY);\n  if (preference === \"auto\") return prefersDark ? \"dark\" : \"light\";\n  return preference;\n}\n","/**\n * Trailing row-action cell: the resolved list, the opt-in layout, and the\n * host override that replaces the cell entirely.\n *\n * Adapters own the pixels (a kit Menu, native `<details>`, a host render).\n * This file is the shared model: which actions are visible, and the context\n * a custom renderer receives.\n */\nimport type { ReactNode } from \"react\";\n\nimport type { ConfirmHandler } from \"../actions/confirm\";\nimport type { RowAction, TableLabels } from \"../types\";\n\n/** How the trailing actions column renders. Omit / `\"buttons\"` is today's strip. */\nexport type RowActionsLayout = \"buttons\" | \"menu\";\n\n/**\n * Inputs a host `renderRowActions` receives. `actions` is the resolved list\n * (host entries plus built-in duplicate / delete / pin) — hidden ones are\n * still present so a custom cell can decide; the default layouts skip them.\n */\nexport interface RowActionsRenderContext<TRow> {\n  row: TRow;\n  actions: readonly RowAction<TRow>[];\n  confirm: ConfirmHandler;\n  labels: Required<TableLabels>;\n}\n\n/** Host override for the trailing actions cell (desktop and mobile cards). */\nexport type RowActionsRenderer<TRow> = (\n  ctx: RowActionsRenderContext<TRow>\n) => ReactNode;\n\n/**\n * Actions that should render for this row. `isHidden` returning true drops\n * the entry; everything else stays, including disabled ones.\n *\n * @typeParam TRow - The row type.\n */\nexport function visibleRowActions<TRow>(\n  actions: readonly RowAction<TRow>[],\n  row: TRow\n): RowAction<TRow>[] {\n  return actions.filter((action) => action.isHidden?.(row) !== true);\n}\n","/**\n * Multi-select cell editor, for kits whose select holds one value.\n *\n * A native `<select multiple>` is the compact answer, and the kits that wrap\n * one — MUI, Ant Design, Mantine, Chakra — use theirs. Radix Themes and Base UI\n * build their select out of a button and a popup, which by construction picks a\n * single item, so those kits express \"several of these\" as a list of their own\n * checkboxes instead.\n *\n * That list is structure — the group, its accessible name, which option takes\n * focus, when a blur means \"done\" — so it lives here, and each kit supplies the\n * checkbox. Three adapters rendering three copies of the same `<div role=\n * \"group\">` is the defect this exists to avoid.\n */\nimport type { KeyboardEvent, ReactNode } from \"react\";\n\nimport { formatMultiDraft, readMultiDraft } from \"./cellEditing\";\nimport {\n  type EditableCellEditorCtrl,\n  editorValidationProps,\n} from \"./EditableCellGate\";\n\n/** One option's checkbox, rendered by the adapter with its kit's control. */\nexport interface MultiSelectEditorCheckboxProps {\n  /** The option's visible text. */\n  readonly label: ReactNode;\n  /** The option's value — unique within the editor. */\n  readonly value: string;\n  /** Whether the draft currently holds this value. */\n  readonly checked: boolean;\n  /** Add or remove this value from the draft. */\n  readonly onToggle: () => void;\n  /**\n   * Present on the FIRST option only. Attach it to the kit's control so the\n   * editor takes focus when the cell opens, exactly as a single-control editor\n   * does through {@link EditableCellEditorCtrl.focusRef}.\n   */\n  readonly focusRef?: (node: { focus: () => void } | null) => void;\n  /**\n   * The editor's key handling — Enter commits, Escape cancels. It belongs on\n   * the controls themselves rather than the group: a group is not an\n   * interactive element, and keys arrive at whichever option has focus.\n   */\n  readonly onKeyDown: (event: KeyboardEvent) => void;\n}\n\n/** Adapter-supplied controls for {@link MultiSelectEditorChrome}. */\nexport interface MultiSelectEditorSlots {\n  readonly Checkbox: (props: MultiSelectEditorCheckboxProps) => ReactNode;\n}\n\n/** Props for {@link MultiSelectEditorChrome}. */\nexport interface MultiSelectEditorChromeProps {\n  /** The active cell's editor controller. */\n  readonly ctrl: EditableCellEditorCtrl;\n  /** Accessible name for the group — the table's edit label. */\n  readonly label: string;\n  /** The adapter's key handling, already wired to `ctrl.onEditorKeyDown`. */\n  readonly onKeyDown: (event: KeyboardEvent) => void;\n  readonly slots: MultiSelectEditorSlots;\n}\n\n/**\n * A group of kit checkboxes standing in for `<select multiple>`.\n *\n * @param props - See {@link MultiSelectEditorChromeProps}.\n * @returns The editor, named and focusable as one control.\n */\nexport function MultiSelectEditorChrome({\n  ctrl,\n  label,\n  onKeyDown,\n  slots,\n}: Readonly<MultiSelectEditorChromeProps>): ReactNode {\n  const selected = readMultiDraft(ctrl.draft);\n  const Checkbox = slots.Checkbox;\n\n  const toggle = (value: string) => {\n    const next = selected.includes(value)\n      ? selected.filter((item) => item !== value)\n      : [...selected, value];\n    // Written in the editor's own option order, so a round-trip through the\n    // draft never reshuffles what the reader ticked.\n    ctrl.setDraft(\n      formatMultiDraft(\n        ctrl.selectOptions\n          .map((option) => option.value)\n          .filter((option) => next.includes(option))\n      )\n    );\n  };\n\n  return (\n    <div\n      role=\"group\"\n      aria-label={label}\n      data-adapttable-part=\"edit-cell-editor\"\n      {...editorValidationProps(ctrl)}\n      style={{\n        display: \"flex\",\n        flexWrap: \"wrap\",\n        alignItems: \"center\",\n        gap: 8,\n        minWidth: 0,\n      }}\n      onBlur={(event) => {\n        // Moving between this group's own checkboxes is not leaving the\n        // editor — committing there would close the cell on the first Tab.\n        if (event.currentTarget.contains(event.relatedTarget)) return;\n        ctrl.commitOnBlur();\n      }}\n    >\n      {ctrl.selectOptions.map((option, index) => (\n        <Checkbox\n          key={option.value}\n          label={option.label}\n          value={option.value}\n          checked={selected.includes(option.value)}\n          onToggle={() => toggle(option.value)}\n          onKeyDown={onKeyDown}\n          focusRef={index === 0 ? ctrl.focusRef : undefined}\n        />\n      ))}\n    </div>\n  );\n}\n","/**\n * Where a group header row's cells go.\n *\n * A group header is not free text: it is a row of the same table, and a subtotal\n * only reads as a subtotal when it sits **under the column it totals**. Rendering\n * the row as one spanning cell with the numbers pushed to its end puts them\n * wherever the row happens to finish — which, on a table wide enough to scroll,\n * is off the right edge of the visible area entirely. Measured on the grouping\n * demo at a 1600px viewport: the Budget column at x=1150, its subtotal at\n * x=1448, and the scroll container ending at x=1316.\n *\n * So the row is built like the summary row already was: a leading cell carrying\n * the toggle, the label and the count, then one cell per column, each holding\n * that column's aggregate or nothing at all. The label cell spans the columns\n * before the first aggregate, which keeps the label's roomy look without\n * displacing a single number.\n */\nimport type { ReactNode } from \"react\";\n\nimport type { ColumnDef } from \"../types\";\n\n/** One cell of a group header row, after the leading label cell. */\nexport interface GroupRowCell<TRow> {\n  /** The column this cell sits under. */\n  column: ColumnDef<TRow>;\n  /** That column's aggregate, or `undefined` for an empty cell. */\n  node: ReactNode;\n}\n\n/** How to build a group header row. */\nexport interface GroupRowLayout<TRow> {\n  /**\n   * Columns the leading label cell covers. Its `colSpan` is this length plus\n   * however many edge cells (expand chevron, selection checkbox) precede it.\n   */\n  labelColumns: readonly ColumnDef<TRow>[];\n  /**\n   * Aggregates belonging to a column inside the label cell — only possible when\n   * the very first column carries one, since the label has to live somewhere.\n   * Rendered after the count.\n   */\n  labelAggregates: readonly GroupRowCell<TRow>[];\n  /** One cell per remaining column, in render order. */\n  cells: readonly GroupRowCell<TRow>[];\n}\n\n/**\n * Plan a group header row.\n *\n * With no aggregates the row stays a single spanning cell — nothing to align, and\n * a full-width label is what a plain group header should look like.\n *\n * @typeParam TRow - The row type.\n * @param columns - The columns as rendered, in order.\n * @param aggregateCells - Per-column aggregate nodes, keyed by column key.\n * @returns The row's shape.\n */\nexport function groupRowLayout<TRow>(\n  columns: readonly ColumnDef<TRow>[],\n  aggregateCells: Readonly<Partial<Record<string, ReactNode>>> | undefined\n): GroupRowLayout<TRow> {\n  const has = (column: ColumnDef<TRow>) =>\n    aggregateCells?.[column.key] !== undefined;\n  const firstAggregate = columns.findIndex(has);\n  if (firstAggregate === -1) {\n    return { labelColumns: columns, labelAggregates: [], cells: [] };\n  }\n\n  // The label needs at least one column to sit in. When the first column is\n  // also the one carrying a number, they share the cell rather than the number\n  // being dropped or the label being squeezed into an edge cell.\n  const split = Math.max(firstAggregate, 1);\n  const labelColumns = columns.slice(0, split);\n  return {\n    labelColumns,\n    labelAggregates: labelColumns\n      .filter(has)\n      .map((column) => ({ column, node: aggregateCells?.[column.key] })),\n    cells: columns.slice(split).map((column) => ({\n      column,\n      node: aggregateCells?.[column.key],\n    })),\n  };\n}\n\n/**\n * Just the columns that carry an aggregate, in column order.\n *\n * A mobile card is a list of label/value pairs rather than a row of columns, so\n * alignment means nothing there and the empty cells are noise. A card shows only\n * the numbers that exist, each captioned by its column.\n *\n * @typeParam TRow - The row type.\n * @param columns - The columns as rendered, in order.\n * @param aggregateCells - Per-column aggregate nodes, keyed by column key.\n * @returns One entry per column that has an aggregate.\n */\nexport function groupAggregateEntries<TRow>(\n  columns: readonly ColumnDef<TRow>[],\n  aggregateCells: Readonly<Partial<Record<string, ReactNode>>> | undefined\n): GroupRowCell<TRow>[] {\n  if (!aggregateCells) return [];\n  return columns.flatMap((column) => {\n    const node = aggregateCells[column.key];\n    return node === undefined ? [] : [{ column, node }];\n  });\n}\n\n/**\n * How many leaves a group header should report.\n *\n * The server's count when the grouping was computed there — a page of a group\n * of 4,000 still says 4,000 — and the rows in hand otherwise.\n *\n * @param entry - The group entry.\n * @returns The count to display.\n */\nexport function groupLeafCount(entry: {\n  leafIds: readonly string[];\n  serverCount?: number;\n}): number {\n  return entry.serverCount ?? entry.leafIds.length;\n}\n","/**\n * Collapsed groups, in the URL.\n *\n * Which groups are folded is part of what someone means when they send a link\n * to a table: \"look at this, the other regions are in the way\". So it belongs\n * in the address bar for the same reason sorting and filtering do — and it is\n * opt-in for the same reason column layout is, because a table with twenty\n * collapsed groups would otherwise write a long URL nobody asked for.\n *\n * Pair it with `<DataTable collapsedGroupIds onCollapsedGroupIdsChange>` and\n * grouping's state travels with the link.\n */\nimport { useCallback, useMemo, useState, useSyncExternalStore } from \"react\";\n\nimport { type UrlStateAdapter, useResolvedAdapter } from \"./adapter\";\nimport { readCollapsedGroups, writeCollapsedGroups } from \"./serialize\";\n\n/** What {@link useGroupCollapseUrlState} needs. */\nexport interface UseGroupCollapseUrlStateOptions {\n  /** URL backend; defaults to the History API. */\n  urlAdapter?: UrlStateAdapter;\n  /** Sync to the URL at all. Defaults to `true`. */\n  urlSync?: boolean;\n  /** Namespace, when several tables share a page. */\n  urlKey?: string;\n  /** Groups collapsed before the URL says otherwise. */\n  defaultCollapsedGroupIds?: readonly string[];\n}\n\n/** The controlled pair `<DataTable>` takes. */\nexport interface UseGroupCollapseUrlStateResult {\n  /** The collapsed group keys. */\n  collapsedGroupIds: string[];\n  /** Hand this to `onCollapsedGroupIdsChange`. */\n  onCollapsedGroupIdsChange: (ids: string[]) => void;\n}\n\n/**\n * Keep collapsed groups in the URL.\n *\n * @param options - See {@link UseGroupCollapseUrlStateOptions}.\n * @returns The controlled pair to spread onto the table.\n */\nexport function useGroupCollapseUrlState(\n  options: UseGroupCollapseUrlStateOptions = {}\n): UseGroupCollapseUrlStateResult {\n  const { urlAdapter, urlSync, urlKey, defaultCollapsedGroupIds } = options;\n  const ns = urlKey ? `${urlKey}.` : \"\";\n  const resolved = useResolvedAdapter(urlAdapter, urlSync ?? true);\n  // Same SSR rule as the other URL hooks: only an explicit adapter is trusted\n  // to be hydration-consistent; the default history adapter hydrates from \"\".\n  const search = useSyncExternalStore(\n    (onChange) => resolved.subscribe(onChange),\n    () => resolved.getSearch(),\n    () => (urlAdapter ? urlAdapter.getSearch() : \"\")\n  );\n  // Optimistic overlay: the click that has not reached the URL yet.\n  const [pending, setPending] = useState<string[] | null>(null);\n\n  const collapsedGroupIds = useMemo(() => {\n    if (pending) return pending;\n    const fromUrl = readCollapsedGroups(new URLSearchParams(search), ns);\n    return fromUrl ?? [...(defaultCollapsedGroupIds ?? [])];\n  }, [pending, search, ns, defaultCollapsedGroupIds]);\n\n  const onCollapsedGroupIdsChange = useCallback(\n    (ids: string[]) => {\n      setPending(ids);\n      const params = new URLSearchParams(resolved.getSearch());\n      writeCollapsedGroups(params, ids, ns);\n      // An emptied set writes no parameter, which reads back as \"nothing has\n      // been said\" — so the default would re-apply. Stamp it empty instead.\n      if (ids.length === 0 && (defaultCollapsedGroupIds?.length ?? 0) > 0) {\n        params.set(`${ns}groupClosed`, \"\");\n      }\n      resolved.setSearch(params.toString());\n      setPending(null);\n    },\n    [resolved, ns, defaultCollapsedGroupIds]\n  );\n\n  return { collapsedGroupIds, onCollapsedGroupIdsChange };\n}\n"],"mappings":"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"}