@umodeapporg/ui 0.22.1 → 0.22.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -137,10 +137,10 @@ const useDataTableInstance = ({
|
|
|
137
137
|
const getSearchableText = config.getSearchableText;
|
|
138
138
|
const globalFilterFn = useMemo(
|
|
139
139
|
() => (row, _columnId, filterValue) => {
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
142
|
-
const haystack = getSearchableText ? getSearchableText(row.original) : "";
|
|
143
|
-
return
|
|
140
|
+
const searchWords = normalizeText(String(filterValue ?? "")).split(/\s+/).filter(Boolean);
|
|
141
|
+
if (searchWords.length === 0) return true;
|
|
142
|
+
const haystack = normalizeText(getSearchableText ? getSearchableText(row.original) : "");
|
|
143
|
+
return searchWords.every((searchWord) => haystack.includes(searchWord));
|
|
144
144
|
},
|
|
145
145
|
[getSearchableText]
|
|
146
146
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDataTableInstance.js","sources":["../../../../src/components/UI/DataTable/useDataTableInstance.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { normalizeText } from '@/helpers/stringHelpers';\nimport {\n type ColumnSizingState,\n createColumnHelper,\n type ExpandedState,\n type FilterFn,\n getCoreRowModel,\n getExpandedRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type PaginationState,\n type SortingState,\n type Updater,\n useReactTable,\n type VisibilityState,\n} from '@tanstack/react-table';\n\nimport DataTableActionsCell from './cells/DataTableActionsCell';\nimport DataTableCell from './cells/DataTableCell';\nimport { computeColumnContentWidths, resolveColumnMinWidthPx } from './dataTableColumnWidths';\nimport {\n DATA_TABLE_CROSSFADE_DIP_OPACITY,\n DATA_TABLE_OPACITY_TRANSITION_MS,\n DATA_TABLE_UPDATING_BAR_DELAY_MS,\n DATA_TABLE_UPDATING_OPACITY,\n dataTableOpacityTransitionClass,\n prefersReducedMotion,\n} from './dataTableMotion';\nimport {\n type IDataTableColumnConfig,\n type IDataTableConfig,\n type IDataTableRow,\n type IDataTableSortState,\n isDataTableDetailTableExpansion,\n isDataTablePanelExpansion,\n isDataTableSubRowsExpansion,\n isDataTableTableExpansion,\n type TDataTableSortDirection,\n} from './types';\nimport { useFlipRows } from './useFlipRows';\n\nconst CLIENT_SEARCH_DEBOUNCE_MS = 150;\n\nexport interface IDataTableClientPaginationState {\n page: number;\n pageSize: number;\n}\n\nexport interface IDataTablePagination {\n pageSize: number;\n numberOfPages: number;\n currentPage: number;\n setCurrentPage: (page: number) => void;\n onPageSizeChange?: (pageSize: number) => void;\n /** Total de registros. Presente, a barra mostra o intervalo em vez do número da página. */\n totalItems?: number;\n}\n\ninterface IUseDataTableInstanceParams<T extends IDataTableRow, C extends IDataTableRow = IDataTableRow> {\n config: IDataTableConfig<T, C>;\n rows: Array<T>;\n loading: boolean;\n sort?: IDataTableSortState | null;\n onSortChange?: (sort: IDataTableSortState | null) => void;\n onSearch?: (value: string) => void;\n initialSearch?: string;\n onSearchTermChange?: (value: string) => void;\n pagination?: IDataTablePagination;\n /** Client mode: seeds the internal page/pageSize (1-based page), e.g. from the URL. */\n initialClientPagination?: IDataTableClientPaginationState;\n /** Client mode: reports every page/pageSize change so the host can persist it (URL, storage). */\n onClientPaginationChange?: (pagination: IDataTableClientPaginationState) => void;\n columnVisibility: VisibilityState;\n onColumnVisibilityChange: (updater: Updater<VisibilityState>) => void;\n columnOrder: Array<string>;\n onColumnOrderChange: (updater: Updater<Array<string>>) => void;\n columnSizing: ColumnSizingState;\n onColumnSizingChange: (updater: Updater<ColumnSizingState>) => void;\n onFilteredCountChange?: (count: number) => void;\n}\n\nexport const useDataTableInstance = <T extends IDataTableRow, C extends IDataTableRow = IDataTableRow>({\n config,\n rows,\n loading,\n sort,\n onSortChange,\n onSearch,\n initialSearch = '',\n onSearchTermChange,\n pagination,\n initialClientPagination,\n onClientPaginationChange,\n columnVisibility,\n onColumnVisibilityChange,\n columnOrder,\n onColumnOrderChange,\n columnSizing,\n onColumnSizingChange,\n onFilteredCountChange,\n}: IUseDataTableInstanceParams<T, C>) => {\n const isClientMode = config.dataMode === 'client';\n\n const tabs = config.tabs;\n const [activeTab, setActiveTab] = useState(() => tabs?.[0]?.value ?? '');\n\n // Active tab predicate filters rows BEFORE search/sort/pagination (client mode).\n const tabFilteredRows = useMemo(() => {\n if (!isClientMode || !tabs?.length) return rows;\n const predicate = tabs.find((tab) => tab.value === activeTab)?.clientPredicate;\n if (!predicate) return rows;\n\n return rows.filter(predicate);\n }, [isClientMode, tabs, activeTab, rows]);\n\n const columnHelper = useMemo(() => createColumnHelper<T>(), []);\n\n // Actions and badge columns are sized from the current rows (visible action\n // count / widest chip) so the actions column scales with its buttons and badge\n // labels are never clipped. Other columns fall back to the config-only seed.\n // Both are derived in one memo so the hook signature stays unchanged.\n // Row-derived widths (actions/badge columns) kept in their own memo and read by the\n // column defs through a ref, so editing a cell (which changes the rows) does NOT\n // rebuild the column defs. Rebuilding them hands TanStack a new columns array every\n // keystroke and tears down / remounts every cell, dropping input focus.\n const columnContentWidths = useMemo(\n () => computeColumnContentWidths(config.columns, tabFilteredRows),\n [config.columns, tabFilteredRows],\n );\n const columnContentWidthsRef = useRef(columnContentWidths);\n columnContentWidthsRef.current = columnContentWidths;\n\n const columns = useMemo(() => {\n const contentWidths = columnContentWidthsRef.current;\n\n const columnDefs = config.columns.map((columnConfig, columnIndex) => {\n const accessorFn = (row: T): string | number | boolean => {\n if (columnConfig.sortAccessor) return columnConfig.sortAccessor(row);\n\n const value = columnConfig.accessor?.(row);\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return value;\n }\n\n return '';\n };\n\n const isFirstColumn = columnIndex === 0;\n const columnWidth =\n contentWidths.get(columnConfig.id) ??\n resolveColumnMinWidthPx(columnConfig, {\n isFirstColumn,\n hasColumnToggle: isFirstColumn,\n });\n\n return columnHelper.accessor(accessorFn, {\n id: columnConfig.id,\n header: columnConfig.header,\n enableSorting: !!columnConfig.sortable,\n size: columnWidth,\n minSize: columnWidth,\n enableResizing: columnConfig.type !== 'actions' && columnConfig.resizable !== false,\n cell: ({ row }) =>\n columnConfig.type === 'actions' && columnConfig.actions ? (\n <DataTableActionsCell row={row.original} actions={columnConfig.actions} />\n ) : (\n <DataTableCell\n column={columnConfig}\n row={row.original}\n gridRowId={row.id}\n onCellChange={config.editing?.onCellChange}\n keyboardNav={config.editing?.keyboardNav}\n clickToEdit={config.editing?.clickToEdit}\n />\n ),\n });\n });\n\n return columnDefs;\n }, [config.columns, config.editing, columnHelper]);\n\n // ----- Client-mode internal state -----\n const [clientSorting, setClientSorting] = useState<SortingState>([]);\n const [globalFilter, setGlobalFilter] = useState(initialSearch);\n const [clientPagination, setClientPagination] = useState<PaginationState>(() => ({\n pageIndex: Math.max(0, (initialClientPagination?.page ?? 1) - 1),\n pageSize: initialClientPagination?.pageSize ?? 20,\n }));\n\n const onClientPaginationChangeRef = useRef(onClientPaginationChange);\n onClientPaginationChangeRef.current = onClientPaginationChange;\n\n useEffect(() => {\n onClientPaginationChangeRef.current?.({\n page: clientPagination.pageIndex + 1,\n pageSize: clientPagination.pageSize,\n });\n }, [clientPagination.pageIndex, clientPagination.pageSize]);\n const [expanded, setExpanded] = useState<ExpandedState>({});\n\n const expansion = config.expansion;\n const hasExpansion = !!expansion;\n const defaultExpanded = expansion?.defaultExpanded;\n\n // Rows the user opened or closed by hand keep that choice; `defaultExpanded` only drives the\n // rest, so a default that resolves later (a count that arrives async) never undoes a click.\n const userToggledRowIdsRef = useRef<Set<string>>(new Set());\n\n const handleExpandedChange = useCallback((updater: Updater<ExpandedState>) => {\n setExpanded((previous) => {\n const next = typeof updater === 'function' ? updater(previous) : updater;\n\n if (previous !== true && next !== true) {\n for (const rowId of new Set([...Object.keys(previous), ...Object.keys(next)])) {\n if (Boolean(previous[rowId]) !== Boolean(next[rowId])) userToggledRowIdsRef.current.add(rowId);\n }\n }\n\n return next;\n });\n }, []);\n\n useEffect(() => {\n if (!hasExpansion || defaultExpanded === undefined) return;\n\n setExpanded((previous) => {\n if (previous === true) return previous;\n\n let next: Record<string, boolean> | null = null;\n\n for (const row of tabFilteredRows) {\n const rowId = row.id;\n if (!rowId || userToggledRowIdsRef.current.has(rowId)) continue;\n\n const shouldExpand = typeof defaultExpanded === 'function' ? defaultExpanded(row) : defaultExpanded;\n if (Boolean(previous[rowId]) === shouldExpand) continue;\n\n next = next ?? { ...previous };\n if (shouldExpand) next[rowId] = true;\n else delete next[rowId];\n }\n\n return next ?? previous;\n });\n }, [hasExpansion, defaultExpanded, tabFilteredRows]);\n\n const isPanelExpansion = !!expansion && isDataTablePanelExpansion(expansion);\n const isDetailTableExpansion = !!expansion && isDataTableDetailTableExpansion(expansion);\n const isTableExpansion = !!expansion && isDataTableTableExpansion(expansion);\n const subRowsExpansion = expansion && isDataTableSubRowsExpansion(expansion) ? expansion : null;\n\n const getSearchableText = config.getSearchableText;\n\n const globalFilterFn: FilterFn<T> = useMemo(\n () => (row, _columnId, filterValue) => {\n const term = normalizeText(String(filterValue ?? '')).trim();\n if (!term) return true;\n\n const haystack = getSearchableText ? getSearchableText(row.original) : '';\n\n return normalizeText(haystack).includes(term);\n },\n [getSearchableText],\n );\n\n // ----- Server-mode external sort mapping -----\n const serverSortingState: SortingState = useMemo(() => {\n if (!sort) return [];\n const columnForField = config.columns.find((column) => column.sortField === sort.sortBy);\n if (!columnForField) return [];\n\n return [{ id: columnForField.id, desc: sort.sortDir === 'desc' }];\n }, [sort, config.columns]);\n\n const table = useReactTable({\n data: tabFilteredRows,\n columns,\n // The row id IS the entity id (prefixed by the parent for nested rows), not the\n // default positional index: the spreadsheet layer and the commit queue address\n // cells by it, so it has to survive sorting, filtering and pagination.\n getRowId: (row, index, parent) => {\n const ownId = row.id ?? String(index);\n return parent ? `${parent.id}.${ownId}` : ownId;\n },\n state: isClientMode\n ? {\n sorting: clientSorting,\n globalFilter,\n pagination: clientPagination,\n columnVisibility,\n columnOrder,\n columnSizing,\n expanded,\n }\n : { sorting: serverSortingState, columnVisibility, columnOrder, columnSizing, expanded },\n manualSorting: !isClientMode,\n manualFiltering: !isClientMode,\n manualPagination: !isClientMode,\n // A host that persists the page (URL) expects an in-place row update to keep it;\n // TanStack would otherwise jump back to page 1 whenever `rows` changes reference.\n autoResetPageIndex: onClientPaginationChange ? false : undefined,\n enableColumnResizing: true,\n // `onChange`: columns follow the cursor live during the drag (fluid, ag-grid\n // style) rather than snapping only on release.\n columnResizeMode: 'onChange',\n onColumnVisibilityChange,\n onColumnOrderChange,\n onColumnSizingChange,\n onSortingChange: isClientMode ? setClientSorting : undefined,\n onGlobalFilterChange: isClientMode ? setGlobalFilter : undefined,\n onPaginationChange: isClientMode ? setClientPagination : undefined,\n onExpandedChange: hasExpansion ? handleExpandedChange : undefined,\n globalFilterFn: isClientMode ? globalFilterFn : undefined,\n // Panel and detailTable modes have no nested rows in the row model. Omit\n // getSubRows so TanStack never looks for children. SubRows mode keeps the\n // existing lazy-children path.\n getSubRows: subRowsExpansion?.getSubRows,\n getRowCanExpand: expansion\n ? (row) => {\n if (expansion.canExpand) return expansion.canExpand(row.original);\n // Panel/detailTable/table: every row is expandable unless canExpand says otherwise.\n if (isPanelExpansion || isDetailTableExpansion || isTableExpansion) return true;\n return row.subRows.length > 0;\n }\n : undefined,\n // Client mode keeps children glued to their parent (not counted toward the\n // page size). The pagination row model re-inserts them. Server mode has NO\n // pagination row model, so `false` would leave `getExpandedRowModel` without\n // anything to flatten the children and they would never render; `true` makes\n // the expanded model flatten them itself (server already paginates parents).\n // Panel and detailTable modes have no child rows, so the flag is irrelevant.\n paginateExpandedRows: !isClientMode,\n getCoreRowModel: getCoreRowModel(),\n getFilteredRowModel: isClientMode ? getFilteredRowModel() : undefined,\n getSortedRowModel: isClientMode ? getSortedRowModel() : undefined,\n getPaginationRowModel: isClientMode ? getPaginationRowModel() : undefined,\n getExpandedRowModel: hasExpansion ? getExpandedRowModel() : undefined,\n });\n\n const visibleRows = table.getRowModel().rows;\n const orderedRowIds = useMemo(() => visibleRows.map((row) => row.id).join('|'), [visibleRows]);\n // SubRows expansion uses a slower slide so the subgroup open/close reads clearly.\n // Panel and detailTable expansion only toggle a content row. Keep the default\n // FLIP timing for those.\n const flipDurationMs = subRowsExpansion ? 420 : undefined;\n const { registerRow, beginExit: beginRowsExit } = useFlipRows(\n useMemo(() => orderedRowIds.split('|'), [orderedRowIds]),\n flipDurationMs,\n );\n\n const filteredCount = isClientMode ? table.getFilteredRowModel().rows.length : rows.length;\n\n useEffect(() => {\n onFilteredCountChange?.(filteredCount);\n }, [filteredCount, onFilteredCountChange]);\n\n // In server mode, header click round-trips through the host. In client mode\n // TanStack drives the sorting state directly (cycle: asc -> desc -> none).\n const handleHeaderSortClick = (columnConfig: IDataTableColumnConfig<T>) => {\n if (!columnConfig.sortable) return;\n\n if (isClientMode) {\n table.getColumn(columnConfig.id)?.toggleSorting(undefined, false);\n return;\n }\n\n if (!columnConfig.sortField || !onSortChange) return;\n\n const isActive = sort?.sortBy === columnConfig.sortField;\n let nextDir: TDataTableSortDirection = 'asc';\n\n if (isActive && sort?.sortDir === 'asc') nextDir = 'desc';\n else if (isActive && sort?.sortDir === 'desc') {\n onSortChange(null);\n return;\n }\n\n onSortChange({ sortBy: columnConfig.sortField, sortDir: nextDir });\n };\n\n const resolveSortDirection = (columnConfig: IDataTableColumnConfig<T>): false | 'asc' | 'desc' => {\n if (isClientMode) {\n const direction = table.getColumn(columnConfig.id)?.getIsSorted();\n return direction ?? false;\n }\n\n if (sort?.sortBy !== columnConfig.sortField) return false;\n return sort?.sortDir ?? 'asc';\n };\n\n const handleSearchInput = (value: string) => {\n onSearchTermChange?.(value);\n\n if (isClientMode) {\n setGlobalFilter(value);\n table.setPageIndex(0);\n return;\n }\n\n onSearch?.(value);\n };\n\n const handleTabChange = (value: string) => {\n setActiveTab(value);\n if (isClientMode) table.setPageIndex(0);\n };\n\n // Skeleton is shown ONLY on the very first load (no rows yet). Filter/sort/\n // pagination never swap the loaded table for skeletons. That is the \"blink\".\n const showSkeleton = loading && rows.length === 0;\n // Server mode keeps rows visible during a refetch with a subtle updating state.\n const isUpdating = !isClientMode && loading && rows.length > 0;\n\n const [showUpdatingBar, setShowUpdatingBar] = useState(false);\n const [contentOpacity, setContentOpacity] = useState(1);\n const wasUpdatingRef = useRef(false);\n\n useEffect(() => {\n if (!isUpdating) {\n setShowUpdatingBar(false);\n return;\n }\n\n if (prefersReducedMotion()) return;\n\n const timer = window.setTimeout(() => setShowUpdatingBar(true), DATA_TABLE_UPDATING_BAR_DELAY_MS);\n return () => window.clearTimeout(timer);\n }, [isUpdating]);\n\n useEffect(() => {\n const reducedMotion = prefersReducedMotion();\n\n if (wasUpdatingRef.current && !isUpdating && !isClientMode) {\n if (reducedMotion) {\n setContentOpacity(1);\n } else {\n setContentOpacity(DATA_TABLE_CROSSFADE_DIP_OPACITY);\n const frame = window.requestAnimationFrame(() => setContentOpacity(1));\n wasUpdatingRef.current = isUpdating;\n return () => window.cancelAnimationFrame(frame);\n }\n }\n\n wasUpdatingRef.current = isUpdating;\n }, [isUpdating, isClientMode]);\n\n const contentOpacityStyle = useMemo(() => {\n if (prefersReducedMotion()) return undefined;\n\n const opacity = isUpdating ? DATA_TABLE_UPDATING_OPACITY : contentOpacity;\n\n return {\n opacity,\n transition: `opacity ${DATA_TABLE_OPACITY_TRANSITION_MS}ms ease-enter`,\n };\n }, [isUpdating, contentOpacity]);\n\n const clientPaginationProps: IDataTablePagination | undefined = isClientMode\n ? {\n pageSize: clientPagination.pageSize,\n numberOfPages: table.getPageCount(),\n currentPage: clientPagination.pageIndex + 1,\n totalItems: table.getFilteredRowModel().rows.length,\n setCurrentPage: (page: number) => table.setPageIndex(page - 1),\n onPageSizeChange: (size: number) => {\n table.setPageSize(size);\n table.setPageIndex(0);\n },\n }\n : pagination;\n\n const hasRows = visibleRows.length > 0;\n\n return {\n table,\n isClientMode,\n columnContentWidths,\n registerRow,\n beginRowsExit,\n visibleRows,\n orderedRowIds,\n filteredCount,\n activeTab,\n tabs,\n handleTabChange,\n handleSearchInput,\n handleHeaderSortClick,\n resolveSortDirection,\n clientPaginationProps,\n isUpdating,\n showUpdatingBar,\n contentOpacityStyle,\n dataTableOpacityTransitionClass,\n showSkeleton,\n hasRows,\n clientSearchDebounceMs: CLIENT_SEARCH_DEBOUNCE_MS,\n };\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useDataTableInstance.js","sources":["../../../../src/components/UI/DataTable/useDataTableInstance.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { normalizeText } from '@/helpers/stringHelpers';\nimport {\n type ColumnSizingState,\n createColumnHelper,\n type ExpandedState,\n type FilterFn,\n getCoreRowModel,\n getExpandedRowModel,\n getFilteredRowModel,\n getPaginationRowModel,\n getSortedRowModel,\n type PaginationState,\n type SortingState,\n type Updater,\n useReactTable,\n type VisibilityState,\n} from '@tanstack/react-table';\n\nimport DataTableActionsCell from './cells/DataTableActionsCell';\nimport DataTableCell from './cells/DataTableCell';\nimport { computeColumnContentWidths, resolveColumnMinWidthPx } from './dataTableColumnWidths';\nimport {\n DATA_TABLE_CROSSFADE_DIP_OPACITY,\n DATA_TABLE_OPACITY_TRANSITION_MS,\n DATA_TABLE_UPDATING_BAR_DELAY_MS,\n DATA_TABLE_UPDATING_OPACITY,\n dataTableOpacityTransitionClass,\n prefersReducedMotion,\n} from './dataTableMotion';\nimport {\n type IDataTableColumnConfig,\n type IDataTableConfig,\n type IDataTableRow,\n type IDataTableSortState,\n isDataTableDetailTableExpansion,\n isDataTablePanelExpansion,\n isDataTableSubRowsExpansion,\n isDataTableTableExpansion,\n type TDataTableSortDirection,\n} from './types';\nimport { useFlipRows } from './useFlipRows';\n\nconst CLIENT_SEARCH_DEBOUNCE_MS = 150;\n\nexport interface IDataTableClientPaginationState {\n page: number;\n pageSize: number;\n}\n\nexport interface IDataTablePagination {\n pageSize: number;\n numberOfPages: number;\n currentPage: number;\n setCurrentPage: (page: number) => void;\n onPageSizeChange?: (pageSize: number) => void;\n /** Total de registros. Presente, a barra mostra o intervalo em vez do número da página. */\n totalItems?: number;\n}\n\ninterface IUseDataTableInstanceParams<T extends IDataTableRow, C extends IDataTableRow = IDataTableRow> {\n config: IDataTableConfig<T, C>;\n rows: Array<T>;\n loading: boolean;\n sort?: IDataTableSortState | null;\n onSortChange?: (sort: IDataTableSortState | null) => void;\n onSearch?: (value: string) => void;\n initialSearch?: string;\n onSearchTermChange?: (value: string) => void;\n pagination?: IDataTablePagination;\n /** Client mode: seeds the internal page/pageSize (1-based page), e.g. from the URL. */\n initialClientPagination?: IDataTableClientPaginationState;\n /** Client mode: reports every page/pageSize change so the host can persist it (URL, storage). */\n onClientPaginationChange?: (pagination: IDataTableClientPaginationState) => void;\n columnVisibility: VisibilityState;\n onColumnVisibilityChange: (updater: Updater<VisibilityState>) => void;\n columnOrder: Array<string>;\n onColumnOrderChange: (updater: Updater<Array<string>>) => void;\n columnSizing: ColumnSizingState;\n onColumnSizingChange: (updater: Updater<ColumnSizingState>) => void;\n onFilteredCountChange?: (count: number) => void;\n}\n\nexport const useDataTableInstance = <T extends IDataTableRow, C extends IDataTableRow = IDataTableRow>({\n config,\n rows,\n loading,\n sort,\n onSortChange,\n onSearch,\n initialSearch = '',\n onSearchTermChange,\n pagination,\n initialClientPagination,\n onClientPaginationChange,\n columnVisibility,\n onColumnVisibilityChange,\n columnOrder,\n onColumnOrderChange,\n columnSizing,\n onColumnSizingChange,\n onFilteredCountChange,\n}: IUseDataTableInstanceParams<T, C>) => {\n const isClientMode = config.dataMode === 'client';\n\n const tabs = config.tabs;\n const [activeTab, setActiveTab] = useState(() => tabs?.[0]?.value ?? '');\n\n // Active tab predicate filters rows BEFORE search/sort/pagination (client mode).\n const tabFilteredRows = useMemo(() => {\n if (!isClientMode || !tabs?.length) return rows;\n const predicate = tabs.find((tab) => tab.value === activeTab)?.clientPredicate;\n if (!predicate) return rows;\n\n return rows.filter(predicate);\n }, [isClientMode, tabs, activeTab, rows]);\n\n const columnHelper = useMemo(() => createColumnHelper<T>(), []);\n\n // Actions and badge columns are sized from the current rows (visible action\n // count / widest chip) so the actions column scales with its buttons and badge\n // labels are never clipped. Other columns fall back to the config-only seed.\n // Both are derived in one memo so the hook signature stays unchanged.\n // Row-derived widths (actions/badge columns) kept in their own memo and read by the\n // column defs through a ref, so editing a cell (which changes the rows) does NOT\n // rebuild the column defs. Rebuilding them hands TanStack a new columns array every\n // keystroke and tears down / remounts every cell, dropping input focus.\n const columnContentWidths = useMemo(\n () => computeColumnContentWidths(config.columns, tabFilteredRows),\n [config.columns, tabFilteredRows],\n );\n const columnContentWidthsRef = useRef(columnContentWidths);\n columnContentWidthsRef.current = columnContentWidths;\n\n const columns = useMemo(() => {\n const contentWidths = columnContentWidthsRef.current;\n\n const columnDefs = config.columns.map((columnConfig, columnIndex) => {\n const accessorFn = (row: T): string | number | boolean => {\n if (columnConfig.sortAccessor) return columnConfig.sortAccessor(row);\n\n const value = columnConfig.accessor?.(row);\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return value;\n }\n\n return '';\n };\n\n const isFirstColumn = columnIndex === 0;\n const columnWidth =\n contentWidths.get(columnConfig.id) ??\n resolveColumnMinWidthPx(columnConfig, {\n isFirstColumn,\n hasColumnToggle: isFirstColumn,\n });\n\n return columnHelper.accessor(accessorFn, {\n id: columnConfig.id,\n header: columnConfig.header,\n enableSorting: !!columnConfig.sortable,\n size: columnWidth,\n minSize: columnWidth,\n enableResizing: columnConfig.type !== 'actions' && columnConfig.resizable !== false,\n cell: ({ row }) =>\n columnConfig.type === 'actions' && columnConfig.actions ? (\n <DataTableActionsCell row={row.original} actions={columnConfig.actions} />\n ) : (\n <DataTableCell\n column={columnConfig}\n row={row.original}\n gridRowId={row.id}\n onCellChange={config.editing?.onCellChange}\n keyboardNav={config.editing?.keyboardNav}\n clickToEdit={config.editing?.clickToEdit}\n />\n ),\n });\n });\n\n return columnDefs;\n }, [config.columns, config.editing, columnHelper]);\n\n // ----- Client-mode internal state -----\n const [clientSorting, setClientSorting] = useState<SortingState>([]);\n const [globalFilter, setGlobalFilter] = useState(initialSearch);\n const [clientPagination, setClientPagination] = useState<PaginationState>(() => ({\n pageIndex: Math.max(0, (initialClientPagination?.page ?? 1) - 1),\n pageSize: initialClientPagination?.pageSize ?? 20,\n }));\n\n const onClientPaginationChangeRef = useRef(onClientPaginationChange);\n onClientPaginationChangeRef.current = onClientPaginationChange;\n\n useEffect(() => {\n onClientPaginationChangeRef.current?.({\n page: clientPagination.pageIndex + 1,\n pageSize: clientPagination.pageSize,\n });\n }, [clientPagination.pageIndex, clientPagination.pageSize]);\n const [expanded, setExpanded] = useState<ExpandedState>({});\n\n const expansion = config.expansion;\n const hasExpansion = !!expansion;\n const defaultExpanded = expansion?.defaultExpanded;\n\n // Rows the user opened or closed by hand keep that choice; `defaultExpanded` only drives the\n // rest, so a default that resolves later (a count that arrives async) never undoes a click.\n const userToggledRowIdsRef = useRef<Set<string>>(new Set());\n\n const handleExpandedChange = useCallback((updater: Updater<ExpandedState>) => {\n setExpanded((previous) => {\n const next = typeof updater === 'function' ? updater(previous) : updater;\n\n if (previous !== true && next !== true) {\n for (const rowId of new Set([...Object.keys(previous), ...Object.keys(next)])) {\n if (Boolean(previous[rowId]) !== Boolean(next[rowId])) userToggledRowIdsRef.current.add(rowId);\n }\n }\n\n return next;\n });\n }, []);\n\n useEffect(() => {\n if (!hasExpansion || defaultExpanded === undefined) return;\n\n setExpanded((previous) => {\n if (previous === true) return previous;\n\n let next: Record<string, boolean> | null = null;\n\n for (const row of tabFilteredRows) {\n const rowId = row.id;\n if (!rowId || userToggledRowIdsRef.current.has(rowId)) continue;\n\n const shouldExpand = typeof defaultExpanded === 'function' ? defaultExpanded(row) : defaultExpanded;\n if (Boolean(previous[rowId]) === shouldExpand) continue;\n\n next = next ?? { ...previous };\n if (shouldExpand) next[rowId] = true;\n else delete next[rowId];\n }\n\n return next ?? previous;\n });\n }, [hasExpansion, defaultExpanded, tabFilteredRows]);\n\n const isPanelExpansion = !!expansion && isDataTablePanelExpansion(expansion);\n const isDetailTableExpansion = !!expansion && isDataTableDetailTableExpansion(expansion);\n const isTableExpansion = !!expansion && isDataTableTableExpansion(expansion);\n const subRowsExpansion = expansion && isDataTableSubRowsExpansion(expansion) ? expansion : null;\n\n const getSearchableText = config.getSearchableText;\n\n const globalFilterFn: FilterFn<T> = useMemo(\n () => (row, _columnId, filterValue) => {\n const searchWords = normalizeText(String(filterValue ?? ''))\n .split(/\\s+/)\n .filter(Boolean);\n if (searchWords.length === 0) return true;\n\n const haystack = normalizeText(getSearchableText ? getSearchableText(row.original) : '');\n\n return searchWords.every((searchWord) => haystack.includes(searchWord));\n },\n [getSearchableText],\n );\n\n // ----- Server-mode external sort mapping -----\n const serverSortingState: SortingState = useMemo(() => {\n if (!sort) return [];\n const columnForField = config.columns.find((column) => column.sortField === sort.sortBy);\n if (!columnForField) return [];\n\n return [{ id: columnForField.id, desc: sort.sortDir === 'desc' }];\n }, [sort, config.columns]);\n\n const table = useReactTable({\n data: tabFilteredRows,\n columns,\n // The row id IS the entity id (prefixed by the parent for nested rows), not the\n // default positional index: the spreadsheet layer and the commit queue address\n // cells by it, so it has to survive sorting, filtering and pagination.\n getRowId: (row, index, parent) => {\n const ownId = row.id ?? String(index);\n return parent ? `${parent.id}.${ownId}` : ownId;\n },\n state: isClientMode\n ? {\n sorting: clientSorting,\n globalFilter,\n pagination: clientPagination,\n columnVisibility,\n columnOrder,\n columnSizing,\n expanded,\n }\n : { sorting: serverSortingState, columnVisibility, columnOrder, columnSizing, expanded },\n manualSorting: !isClientMode,\n manualFiltering: !isClientMode,\n manualPagination: !isClientMode,\n // A host that persists the page (URL) expects an in-place row update to keep it;\n // TanStack would otherwise jump back to page 1 whenever `rows` changes reference.\n autoResetPageIndex: onClientPaginationChange ? false : undefined,\n enableColumnResizing: true,\n // `onChange`: columns follow the cursor live during the drag (fluid, ag-grid\n // style) rather than snapping only on release.\n columnResizeMode: 'onChange',\n onColumnVisibilityChange,\n onColumnOrderChange,\n onColumnSizingChange,\n onSortingChange: isClientMode ? setClientSorting : undefined,\n onGlobalFilterChange: isClientMode ? setGlobalFilter : undefined,\n onPaginationChange: isClientMode ? setClientPagination : undefined,\n onExpandedChange: hasExpansion ? handleExpandedChange : undefined,\n globalFilterFn: isClientMode ? globalFilterFn : undefined,\n // Panel and detailTable modes have no nested rows in the row model. Omit\n // getSubRows so TanStack never looks for children. SubRows mode keeps the\n // existing lazy-children path.\n getSubRows: subRowsExpansion?.getSubRows,\n getRowCanExpand: expansion\n ? (row) => {\n if (expansion.canExpand) return expansion.canExpand(row.original);\n // Panel/detailTable/table: every row is expandable unless canExpand says otherwise.\n if (isPanelExpansion || isDetailTableExpansion || isTableExpansion) return true;\n return row.subRows.length > 0;\n }\n : undefined,\n // Client mode keeps children glued to their parent (not counted toward the\n // page size). The pagination row model re-inserts them. Server mode has NO\n // pagination row model, so `false` would leave `getExpandedRowModel` without\n // anything to flatten the children and they would never render; `true` makes\n // the expanded model flatten them itself (server already paginates parents).\n // Panel and detailTable modes have no child rows, so the flag is irrelevant.\n paginateExpandedRows: !isClientMode,\n getCoreRowModel: getCoreRowModel(),\n getFilteredRowModel: isClientMode ? getFilteredRowModel() : undefined,\n getSortedRowModel: isClientMode ? getSortedRowModel() : undefined,\n getPaginationRowModel: isClientMode ? getPaginationRowModel() : undefined,\n getExpandedRowModel: hasExpansion ? getExpandedRowModel() : undefined,\n });\n\n const visibleRows = table.getRowModel().rows;\n const orderedRowIds = useMemo(() => visibleRows.map((row) => row.id).join('|'), [visibleRows]);\n // SubRows expansion uses a slower slide so the subgroup open/close reads clearly.\n // Panel and detailTable expansion only toggle a content row. Keep the default\n // FLIP timing for those.\n const flipDurationMs = subRowsExpansion ? 420 : undefined;\n const { registerRow, beginExit: beginRowsExit } = useFlipRows(\n useMemo(() => orderedRowIds.split('|'), [orderedRowIds]),\n flipDurationMs,\n );\n\n const filteredCount = isClientMode ? table.getFilteredRowModel().rows.length : rows.length;\n\n useEffect(() => {\n onFilteredCountChange?.(filteredCount);\n }, [filteredCount, onFilteredCountChange]);\n\n // In server mode, header click round-trips through the host. In client mode\n // TanStack drives the sorting state directly (cycle: asc -> desc -> none).\n const handleHeaderSortClick = (columnConfig: IDataTableColumnConfig<T>) => {\n if (!columnConfig.sortable) return;\n\n if (isClientMode) {\n table.getColumn(columnConfig.id)?.toggleSorting(undefined, false);\n return;\n }\n\n if (!columnConfig.sortField || !onSortChange) return;\n\n const isActive = sort?.sortBy === columnConfig.sortField;\n let nextDir: TDataTableSortDirection = 'asc';\n\n if (isActive && sort?.sortDir === 'asc') nextDir = 'desc';\n else if (isActive && sort?.sortDir === 'desc') {\n onSortChange(null);\n return;\n }\n\n onSortChange({ sortBy: columnConfig.sortField, sortDir: nextDir });\n };\n\n const resolveSortDirection = (columnConfig: IDataTableColumnConfig<T>): false | 'asc' | 'desc' => {\n if (isClientMode) {\n const direction = table.getColumn(columnConfig.id)?.getIsSorted();\n return direction ?? false;\n }\n\n if (sort?.sortBy !== columnConfig.sortField) return false;\n return sort?.sortDir ?? 'asc';\n };\n\n const handleSearchInput = (value: string) => {\n onSearchTermChange?.(value);\n\n if (isClientMode) {\n setGlobalFilter(value);\n table.setPageIndex(0);\n return;\n }\n\n onSearch?.(value);\n };\n\n const handleTabChange = (value: string) => {\n setActiveTab(value);\n if (isClientMode) table.setPageIndex(0);\n };\n\n // Skeleton is shown ONLY on the very first load (no rows yet). Filter/sort/\n // pagination never swap the loaded table for skeletons. That is the \"blink\".\n const showSkeleton = loading && rows.length === 0;\n // Server mode keeps rows visible during a refetch with a subtle updating state.\n const isUpdating = !isClientMode && loading && rows.length > 0;\n\n const [showUpdatingBar, setShowUpdatingBar] = useState(false);\n const [contentOpacity, setContentOpacity] = useState(1);\n const wasUpdatingRef = useRef(false);\n\n useEffect(() => {\n if (!isUpdating) {\n setShowUpdatingBar(false);\n return;\n }\n\n if (prefersReducedMotion()) return;\n\n const timer = window.setTimeout(() => setShowUpdatingBar(true), DATA_TABLE_UPDATING_BAR_DELAY_MS);\n return () => window.clearTimeout(timer);\n }, [isUpdating]);\n\n useEffect(() => {\n const reducedMotion = prefersReducedMotion();\n\n if (wasUpdatingRef.current && !isUpdating && !isClientMode) {\n if (reducedMotion) {\n setContentOpacity(1);\n } else {\n setContentOpacity(DATA_TABLE_CROSSFADE_DIP_OPACITY);\n const frame = window.requestAnimationFrame(() => setContentOpacity(1));\n wasUpdatingRef.current = isUpdating;\n return () => window.cancelAnimationFrame(frame);\n }\n }\n\n wasUpdatingRef.current = isUpdating;\n }, [isUpdating, isClientMode]);\n\n const contentOpacityStyle = useMemo(() => {\n if (prefersReducedMotion()) return undefined;\n\n const opacity = isUpdating ? DATA_TABLE_UPDATING_OPACITY : contentOpacity;\n\n return {\n opacity,\n transition: `opacity ${DATA_TABLE_OPACITY_TRANSITION_MS}ms ease-enter`,\n };\n }, [isUpdating, contentOpacity]);\n\n const clientPaginationProps: IDataTablePagination | undefined = isClientMode\n ? {\n pageSize: clientPagination.pageSize,\n numberOfPages: table.getPageCount(),\n currentPage: clientPagination.pageIndex + 1,\n totalItems: table.getFilteredRowModel().rows.length,\n setCurrentPage: (page: number) => table.setPageIndex(page - 1),\n onPageSizeChange: (size: number) => {\n table.setPageSize(size);\n table.setPageIndex(0);\n },\n }\n : pagination;\n\n const hasRows = visibleRows.length > 0;\n\n return {\n table,\n isClientMode,\n columnContentWidths,\n registerRow,\n beginRowsExit,\n visibleRows,\n orderedRowIds,\n filteredCount,\n activeTab,\n tabs,\n handleTabChange,\n handleSearchInput,\n handleHeaderSortClick,\n resolveSortDirection,\n clientPaginationProps,\n isUpdating,\n showUpdatingBar,\n contentOpacityStyle,\n dataTableOpacityTransitionClass,\n showSkeleton,\n hasRows,\n clientSearchDebounceMs: CLIENT_SEARCH_DEBOUNCE_MS,\n };\n};\n"],"names":[],"mappings":"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"}
|