import { Dispatch, SetStateAction } from 'react'; import { RowHeight } from './row-height.js'; import { DataListDisplayOptions } from './data-list-display-options.js'; import { SortRule, ActiveFilter, ConditionalRule } from './table-properties-types.js'; import { ViewTab } from '../components/templates/list-page.js'; import 'react/jsx-runtime'; import './data-list-view.js'; import './list-page-table-properties.js'; import '../data-list-view-registry-BBKzJxGS.js'; /** Public so hubs that want to clear or namespace-scan storage can. */ declare function lifecycleStorageKey(namespace: string, tabId: string): string; declare function pageStorageKey(namespace: string): string; /** * Versioned snapshot of a single table's lifecycle state. The fields under * `extras` are entity-specific (e.g. placements stuff `conditionalRules` and * pagination there) and opaque to this module. Older v1 records (pre-extras * rollout) may have those entity-specific fields at the top level — the * parser accepts both shapes for back-compat. */ interface PersistedLifecycleV1 { v: 1; sortRules: SortRule[]; search: string; activeFilters: ActiveFilter[]; filterConnectors: Record; groupBy: string | null; colOrder: string[]; hiddenCols: string[]; colWidths: Record; colPins: Record; colWrap: Record; colMenuSearch: Record; rowHeight: RowHeight; showGridlines: boolean; filterBarVisible: boolean; searchOpen: boolean; /** Generic hub-defined extras. Persisted as JSON. */ extras?: Record; /** * @deprecated Legacy top-level fields (used by placements pre-extras * rollout). New code SHOULD live under `extras`. Kept here so existing * placements `localStorage` payloads still parse. */ conditionalRules?: ConditionalRule[]; pagination?: boolean; paginationPage?: number; paginationPageSize?: number; } interface PersistedPageV1 { v: 1; displayOptions: DataListDisplayOptions; showMetrics: boolean; tabs: ViewTab[]; activeTabId: string; } /** * Narrow surface the lifecycle hook needs from `useTableState` — getters + * setters for every persisted slice. Defined as a structural type so * callers can pass `tableState` directly (it satisfies this shape). */ interface TableStatePersistSlice { sortRules: SortRule[]; search: string; activeFilters: ActiveFilter[]; filterConnectors: Record; groupBy: string | null; colOrder: string[]; hiddenCols: Set; colWidths: Record; colPins: Record; colWrap: Record; colMenuSearch: Record; rowHeight: RowHeight; showGridlines: boolean; filterBarVisible: boolean; searchOpen: boolean; setSortRules: Dispatch>; setSearch: Dispatch>; setActiveFilters: Dispatch>; setFilterConnectors: Dispatch>>; setGroupBy: Dispatch>; setColOrder: Dispatch>; setHiddenCols: Dispatch>>; setColWidths: Dispatch>>; setColPins: Dispatch>>; setColWrap: Dispatch>>; setColMenuSearch: Dispatch>>; setRowHeight: Dispatch>; setShowGridlines: Dispatch>; setFilterBarVisible: Dispatch>; setSearchOpen: Dispatch>; } declare function parsePersistedPage(raw: string | null): PersistedPageV1 | null; declare function parsePersistedLifecycle(raw: string | null): PersistedLifecycleV1 | null; /** Column layout only — keeps in-memory search / filters when the column set changes. */ declare function applyLifecycleColumnLayout(ts: TableStatePersistSlice, p: PersistedLifecycleV1, columnKeys: Set): void; declare function applyLifecyclePersisted(ts: TableStatePersistSlice, p: PersistedLifecycleV1, columnKeys: Set): void; declare function serializeLifecycle(ts: TableStatePersistSlice, extras?: Record): PersistedLifecycleV1; /** * Read merged extras from a payload, falling back to the legacy top-level * placements fields when `extras` isn't set yet. Generic so hubs can cast to * their own extras shape. */ declare function readLifecycleExtras>(p: PersistedLifecycleV1): TExtras | undefined; declare function loadLifecycleFromStorage(namespace: string, tabId: string): PersistedLifecycleV1 | null; declare function scheduleLifecycleSave(namespace: string, tabId: string, payload: PersistedLifecycleV1): void; /** * Pre-populate the localStorage lifecycle record for a new `(namespace, tabId)` * scope so the next mount of `useTableStateLifecycle` reads back the seeded * values on first render. * * Used by the centralized "Add view" creation flow in `HubTable` — when the * user commits a new tab from the creation drawer, the hub client emits a * `CreatedViewSpec` describing the filters / sort / columns / etc. that were * configured in the ephemeral creation state buffer. Calling this helper with * the new `tabId` and the spec's writable slices ensures those values stick * when the new tab activates and `useTableStateLifecycle` mounts against that * tabId for the first time. * * Any field omitted falls back to the same defaults `useTableStateLifecycle` * uses when reading an empty record (so partial seeding is safe). * * SSR-safe: no-op on the server (`typeof window === "undefined"`). * * @example * seedTableStateLifecycle("library", "table-abc123", { * activeFilters: spec.filters, * sortRules: spec.sortRules, * colOrder: spec.colOrder, * hiddenCols: spec.hiddenCols, * groupBy: spec.groupBy, * conditionalRules: spec.conditionalRules, * displayOptions: spec.displayOptions, * }) */ interface SeedTableStateLifecyclePartial { activeFilters?: ActiveFilter[]; sortRules?: SortRule[]; colOrder?: string[]; /** Pass as an array (the persisted shape). Internal `hiddenCols` is a `Set` but the JSON record stores an array. */ hiddenCols?: string[]; groupBy?: string | null; conditionalRules?: ConditionalRule[]; /** * Seeded `displayOptions` go into `extras.displayOptions`. `HubTable` reads * `extras` via `onLoadExtras` and applies the seeded display options once * the new tab mounts. */ displayOptions?: DataListDisplayOptions; } declare function seedTableStateLifecycle(namespace: string, tabId: string, partial: SeedTableStateLifecyclePartial): void; declare function loadPageFromStorage(namespace: string): PersistedPageV1 | null; declare function schedulePageSave(namespace: string, payload: PersistedPageV1): void; interface UseTableStateLifecycleOptions | void = void> { /** Storage namespace, e.g. `"placements"`, `"team"`, `"library"`. */ namespace: string; /** * Sub-key per lifecycle tab. A hub with only one lifecycle should pass a * stable constant like `"main"`. A hub with multiple lifecycle scopes * (e.g. placements' "all / mine / shared" tabs) passes the active scope id. */ tabId: string; /** `useTableState(...)` return value. Satisfies `TableStatePersistSlice`. */ tableState: TableStatePersistSlice; /** * Valid column keys for the active table. Persisted column references that * are no longer present (e.g. column was renamed / removed) are dropped on * load. */ columnKeys: Set; /** * Current value of extra state to persist alongside the table (optional). * Pass `undefined` / omit entirely if the hub only persists the table. */ extras?: TExtras; /** * Called once when the persisted record is loaded, with whatever `extras` * it contained (or legacy top-level fields). Use this to rehydrate the * matching React state in the consumer. */ onLoadExtras?: (extras: TExtras | Record | undefined) => void; } /** * Opt-in lifecycle persistence for a `DataTable`. Wires up: * * 1. **Load** (`useLayoutEffect`, once per `tabId` / `columnKeys` change) — * reads from `localStorage` and pushes the persisted state back into * `tableState` setters; then calls `onLoadExtras` so the consumer can * restore hub-specific state too. * 2. **Save** (`useEffect`, debounced ~400ms) — re-serializes whenever any * persisted slice changes and writes to `localStorage`. * * Behaviour: * * - SSR-safe (`localStorage` reads are guarded; the layout effect only runs * on the client). * - No render hits: setters are called inside the effect, not during render. * - Doesn't depend on the full `tableState` object — it depends on each * persisted slice individually so the table object identity (which is fresh * every render) doesn't force re-saves. */ declare function useTableStateLifecycle | void = void>(opts: UseTableStateLifecycleOptions): void; export { type PersistedLifecycleV1, type PersistedPageV1, type SeedTableStateLifecyclePartial, type TableStatePersistSlice, type UseTableStateLifecycleOptions, applyLifecycleColumnLayout, applyLifecyclePersisted, lifecycleStorageKey, loadLifecycleFromStorage, loadPageFromStorage, pageStorageKey, parsePersistedLifecycle, parsePersistedPage, readLifecycleExtras, scheduleLifecycleSave, schedulePageSave, seedTableStateLifecycle, serializeLifecycle, useTableStateLifecycle };