{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "table", "title": "Table", "dependencies": [ "@rc-component/util", "@tanstack/react-table", "ahooks", "lodash", "ts-xor", "zustand" ], "registryDependencies": [ "table-tree-support", "table-shared-core", "table-tooltip-support", "table-spin-support", "table-checkbox-support", "table-pagination-support", "table-empty-support" ], "files": [ { "path": "components/table/index.tsx", "content": "import type { XOR } from \"ts-xor\";\n\nimport type { AnyObject } from \"../_util/type\";\nimport type { OwnTableProps, RecordWithCustomRow } from \"./table\";\nimport type { Key } from \"./types\";\nimport { TableRoot } from \"./_components/base\";\nimport { OwnTable } from \"./table\";\n\ntype ShadcnTableProps = React.ComponentProps;\n\ntype XORTableProps<\n TRecord extends RecordWithCustomRow = AnyObject,\n TKey extends Key = Key,\n> = XOR>;\n\nconst Table = <\n TRecord extends RecordWithCustomRow = AnyObject,\n TKey extends Key = Key,\n>(\n props: XORTableProps,\n) => {\n const isShadcnTable = !props.columns;\n if (isShadcnTable) {\n return ;\n }\n return ;\n};\n\nexport type { XORTableProps as TableProps };\nexport type {\n ColumnGroupType as TableColumnGroupType,\n ColumnsType as TableColumnsType,\n ColumnType as TableColumnType,\n TablePaginationConfig,\n} from \"./types\";\nexport { Table };\n\nexport {\n TableBody,\n TableCaption,\n TableCell,\n TableFooter,\n TableHead,\n TableHeader,\n TableRow,\n} from \"./_components/base\";\nexport {\n DragHandle,\n TableRowSortable,\n TableSummary,\n TableSummaryCell,\n TableSummaryRow,\n TableToolbarLeft,\n TableToolbarRight,\n TableToolbarRoot,\n TableViewOptions,\n} from \"./_components\";\n", "type": "registry:file", "target": "components/table/index.tsx" }, { "path": "components/table/table.tsx", "content": "\"use client\";\n\nimport type {\n ExpandedState,\n OnChangeFn,\n Row,\n Table as TableDef,\n} from \"@tanstack/react-table\";\nimport React, { Fragment, useRef } from \"react\";\nimport {\n flexRender,\n getCoreRowModel,\n getExpandedRowModel,\n getSortedRowModel,\n useReactTable,\n} from \"@tanstack/react-table\";\nimport { useScroll, useSize } from \"ahooks\";\nimport _ from \"lodash\";\n\nimport type { AnyObject } from \"../_util/type\";\nimport type { ConfigConsumerProps } from \"../config-provider/context\";\nimport type { SizeType } from \"../config-provider/size-context\";\nimport type { FilterState } from \"./hooks/use-filter\";\nimport type { SortState } from \"./hooks/use-sorter\";\nimport type {\n ColumnsType,\n ExpandableConfig,\n FilterValue,\n GetComponentProps,\n GetPopupContainer,\n GetRowKey,\n Key,\n LegacyExpandableProps,\n RcTableProps,\n RowSelectMethod,\n SorterResult,\n SorterTooltipProps,\n SortOrder,\n TableAction,\n TableComponents,\n TableCurrentDataSource,\n TableLocale,\n TablePaginationConfig,\n TableRowSelection,\n} from \"./types\";\nimport scrollTo from \"../_util/scroll-to\";\nimport { devUseWarning } from \"../_util/warning\";\nimport { cn } from \"../../lib/utils\";\nimport { Checkbox } from \"../checkbox\";\nimport { ConfigContext, useComponentConfig } from \"../config-provider/context\";\nimport { Empty } from \"../empty\";\nimport defaultLocale from \"../locale/en-us\";\nimport { Pagination } from \"../pagination\";\nimport { Skeleton } from \"../skeleton\";\nimport { Spin } from \"../spin\";\nimport {\n TableBody,\n TableCell,\n TableFooter,\n TableHeader,\n TableRoot,\n TableRow,\n TableWrapperFooter,\n TableWrapperHeader,\n} from \"./_components/base\";\nimport { ColGroup } from \"./_components/col-group\";\nimport { TableHeadAdvanced } from \"./_components/table-head-advanced\";\nimport { useColumns } from \"./hooks/use-columns\";\nimport useExpand from \"./hooks/use-expand\";\nimport { getFilterData } from \"./hooks/use-filter\";\nimport useLazyKVMap from \"./hooks/use-lazy-kv-map\";\nimport usePagination, { getPaginationParam } from \"./hooks/use-pagination\";\nimport useSorter from \"./hooks/use-sorter\";\nimport { TableStoreProvider } from \"./hooks/use-table\";\nimport { getCommonPinningClassName, getCommonPinningStyles } from \"./styles\";\n\nconst EMPTY_LIST: AnyObject[] = [];\n\nfunction normalizeSelectionKeys(keys?: readonly Key[]) {\n return (keys ?? []).map(String);\n}\n\nfunction flattenSelectionData(\n data: readonly RecordType[],\n childrenColumnName: string,\n): RecordType[] {\n let list: RecordType[] = [];\n\n for (const record of data) {\n list.push(record);\n\n if (\n record &&\n typeof record === \"object\" &&\n childrenColumnName in record &&\n Array.isArray(record[childrenColumnName])\n ) {\n list = [\n ...list,\n ...flattenSelectionData(\n record[childrenColumnName] as readonly RecordType[],\n childrenColumnName,\n ),\n ];\n }\n }\n\n return list;\n}\n\nfunction SelectionControl({\n type,\n checked,\n indeterminate = false,\n disabled = false,\n ariaLabel,\n className,\n onClick,\n onToggle,\n}: {\n type: \"checkbox\" | \"radio\";\n checked: boolean;\n indeterminate?: boolean;\n disabled?: boolean;\n ariaLabel: string;\n className?: string;\n onClick?: (event: React.MouseEvent) => void;\n onToggle: () => void;\n}) {\n if (type === \"radio\") {\n return (\n \n {\n event.stopPropagation();\n onClick?.(event);\n onToggle();\n }}\n >\n \n \n \n );\n }\n\n return (\n \n ) => {\n event.stopPropagation();\n onClick?.(event);\n }}\n onCheckedChange={() => {\n if (disabled) {\n return;\n }\n\n onToggle();\n }}\n />\n \n );\n}\n\ninterface ChangeEventInfo {\n pagination: {\n current?: number;\n pageSize?: number;\n total?: number;\n };\n filters: Record;\n sorter: SorterResult | SorterResult[];\n\n filterStates: FilterState[];\n sorterStates: SortState[];\n\n resetPagination: (current?: number, pageSize?: number) => void;\n}\n\ntype RecordWithCustomRow =\n | (Omit & {\n _customRow?: undefined;\n _customRowClassName?: undefined;\n })\n | (Partial & {\n _customRow: React.ReactNode;\n _customRowClassName?: string;\n _customCellClassName?: string;\n _customRowStyle?: React.CSSProperties;\n });\ntype TableProps<\n TRecord extends RecordWithCustomRow = AnyObject,\n TKey extends Key = Key,\n> = Omit<\n React.ComponentProps<\"table\">,\n \"title\" | \"onChange\" | \"summary\"\n> &\n Omit, \"showExpandColumn\"> & {\n columns?: ColumnsType;\n dataSource?: TRecord[] | undefined;\n\n extra?: React.ReactNode;\n alertRender?:\n | React.ReactNode\n | ((args?: {\n selectedRowKeys: Key[];\n selectedRows: TRecord[];\n }) => React.ReactNode);\n\n bordered?: boolean | \"around\";\n classNames?: {\n root?: string;\n title?: string;\n table?: string;\n body?: string;\n footer?: string;\n row?: string | ((record: TRecord, index: number) => string);\n head?: string;\n cell?: string;\n empty?: string;\n };\n\n sortDirections?: SortOrder[];\n showSorterTooltip?: boolean | SorterTooltipProps;\n\n // emptyRender?: EmptyProps;\n /** Config expand rows */\n expandable?: ExpandableConfig;\n indentSize?: number;\n\n // {\n // expandedRowKeys?: string[];\n // expandedRowRender?: (record: TRecord) => React.ReactNode;\n // rowExpandable?: (record: TRecord) => boolean;\n // onExpand?: (expanded: boolean, record: TRecord) => void;\n // expandRowByClick?: boolean;\n // columnWidth?: number;\n // };\n\n /** Row's className */\n rowClassName?: string | ((record: TRecord, index: number) => string);\n /** Row key config */\n rowKey?: (string & {}) | keyof TRecord | GetRowKey;\n /** Row selection config */\n rowSelection?: TableRowSelection;\n\n pagination?: false | TablePaginationConfig;\n loading?: boolean;\n skeleton?: boolean;\n /** Set sticky header and scroll bar */\n sticky?:\n | boolean\n | {\n offsetHeader?: number;\n offsetScroll?: number;\n getContainer?: () => HTMLElement;\n };\n size?: SizeType;\n /** Whether the table can be scrollable */\n scroll?: {\n x?: number;\n y?: number;\n scrollToFirstRowOnChange?: boolean;\n };\n /** Translation */\n locale?: TableLocale;\n /** Override default table elements */\n components?: TableComponents;\n\n getPopupContainer?: GetPopupContainer;\n\n /** Toolbar */\n toolbar?: (table: TableDef) => React.JSX.Element;\n /** Summary content */\n summary?: (currentData: TRecord[]) => React.ReactNode;\n /** Footer content */\n footer?: (currentData: TRecord[]) => React.ReactNode;\n\n onChange?: (\n pagination: TablePaginationConfig,\n filters: Record,\n sorter: SorterResult[],\n extra: TableCurrentDataSource,\n ) => void;\n\n onRow?: GetComponentProps;\n\n // Customize\n showHeader?: boolean;\n\n // =================================== Internal ===================================\n /**\n * @private Internal usage, may remove by refactor. Should always use `columns` instead.\n *\n * !!! DO NOT USE IN PRODUCTION ENVIRONMENT !!!\n */\n internalHooks?: string;\n };\n\nfunction OwnTable(\n props: TableProps,\n) {\n \"use no memo\";\n\n const tableConfig = useComponentConfig(\"table\");\n const {\n ref,\n style,\n className,\n classNames,\n bordered: borderedProp = tableConfig.bordered,\n size,\n\n loading = false,\n skeleton = false,\n\n columns: _columns,\n children: _children,\n childrenColumnName: _legacyChildrenColumnName,\n dataSource,\n pagination,\n\n rowClassName,\n rowKey = \"key\",\n rowSelection,\n\n sticky,\n scroll,\n locale,\n\n // Additional Part\n title,\n summary,\n toolbar,\n extra,\n alertRender,\n footer,\n\n // Customize\n showHeader,\n components,\n\n onChange,\n onRow,\n\n sortDirections,\n showSorterTooltip,\n\n expandable: _expandable,\n expandIcon: _expandIcon,\n expandedRowRender: _expandedRowRender,\n expandIconColumnIndex: _expandIconColumnIndex,\n indentSize: _indentSize,\n\n // getPopupContainer,\n\n // Internal\n // internalHooks,\n\n ...restProps\n } = props;\n\n const warning = devUseWarning(\"Table\");\n\n if (process.env.NODE_ENV !== \"production\") {\n warning(\n !(typeof rowKey === \"function\" && rowKey.length > 1),\n \"usage\",\n \"`index` parameter of `rowKey` function is deprecated. There is no guarantee that it will work as expected.\",\n );\n }\n\n const { locale: contextLocale = defaultLocale } =\n React.useContext(ConfigContext);\n\n // const mergedData = dataSource ?? EMPTY_DATA;\n const rawData: readonly TRecord[] = dataSource ?? EMPTY_LIST;\n\n const tableLocale: TableLocale = { ...contextLocale.Table, ...locale };\n\n // =======================\n const internalRefs: NonNullable = {\n body: React.useRef(null),\n } as NonNullable;\n\n // const data = React.useMemo(() => dataSource, [dataSource]);\n\n // ==================== Customize =====================\n // const getComponent = React.useCallback(\n // (path, defaultComponent) => getValue(components, path) || defaultComponent,\n // [components],\n // );\n\n // ============================ RowKey ============================\n const getRowKey = React.useMemo>(() => {\n if (typeof rowKey === \"function\") {\n return rowKey;\n }\n return (record: TRecord, index: number) => {\n const key = record[rowKey];\n\n return key ?? index;\n };\n }, [rowKey]);\n\n // ============================ Events =============================\n const changeEventInfo: Partial> = {};\n\n const triggerOnChange = (\n info: Partial>,\n action: TableAction,\n reset = false,\n ) => {\n const changeInfo = {\n ...changeEventInfo,\n ...info,\n };\n\n if (reset) {\n changeEventInfo.resetPagination?.();\n\n // Reset event param\n if (changeInfo.pagination?.current) {\n changeInfo.pagination.current = 1;\n }\n\n // Trigger pagination events\n const changedPageSize = changeInfo.pagination?.pageSize;\n if (pagination && changedPageSize !== undefined) {\n pagination.onChange?.(1, changedPageSize);\n }\n }\n\n if (\n scroll &&\n scroll.scrollToFirstRowOnChange !== false &&\n internalRefs.body.current\n ) {\n scrollTo(0, {\n getContainer: () => internalRefs.body.current,\n });\n }\n\n const paginationInfo = changeInfo.pagination ?? {};\n const filterInfo = changeInfo.filters ?? {};\n const sorterInfo = Array.isArray(changeInfo.sorter)\n ? changeInfo.sorter\n : changeInfo.sorter\n ? [changeInfo.sorter]\n : [];\n\n onChange?.(paginationInfo, filterInfo, sorterInfo, {\n // currentDataSource: getFilterData(\n // getSortData(rawData, changeInfo.sorterStates!, childrenColumnName),\n // changeInfo.filterStates!,\n // childrenColumnName,\n // ),\n currentDataSource: [],\n action,\n });\n };\n\n // ========================== Expandable ==========================\n const [\n expandedState,\n setExpandedState,\n\n expandableConfig,\n expandType,\n mergedExpandedKeys,\n mergedExpandIcon,\n childrenColumnName,\n onTriggerExpand,\n ] = useExpand(\n // {\n // ...props,\n // expandable: {\n // ...props.expandable,\n // expandedRowKeys:\n // typeof expanded === \"boolean\"\n // ? findAllChildrenKeys(\n // rawData,\n // getRowKey,\n // props.expandable?.childrenColumnName ?? \"children\",\n // )\n // : expandedStateToExpandedRowKeys(expanded),\n // },\n // },\n props,\n rawData,\n getRowKey,\n );\n\n const [getRecordByKey] = useLazyKVMap(rawData, childrenColumnName, getRowKey);\n\n // useEffect(() => {\n // const expandedRowKeys = expandable?.expandedRowKeys ?? [];\n // setExpanded((prev) => {\n // if (typeof prev === \"boolean\") return prev;\n // const newExpanded = { ...prev };\n // for (const key of expandedRowKeys) {\n // newExpanded[key.toString()] = true;\n // }\n // return newExpanded;\n // });\n // }, [expandable?.expandedRowKeys]);\n // const [expanded, setExpanded] = useMergedState(\n // {},\n // {\n // value: expandable?.expandedRowKeys\n // ? expandable.expandedRowKeys.reduce((acc, key) => {\n // acc[key.toString()] = true;\n // return acc;\n // }, {} as ExpandedStateList)\n // : undefined,\n // onChange: () => {\n // // if (typeof value === \"boolean\") return;\n // // const expandedRowKeys = Object.keys(value).filter((key) => value[key]);\n // // expandable?.onExpand?.(expandedRowKeys, {});\n // },\n // },\n // );\n\n /**\n * Controlled state in `columns` is not a good idea that makes too many code (1000+ line?) to read\n * state out and then put it back to title render. Move these code into `hooks` but still too\n * complex. We should provides Table props like `sorter` & `filter` to handle control in next big\n * version.\n */\n\n // ============================ Filter/Sort Data ============================\n // const sortedData = React.useMemo(\n // () => getSortData(rawData, sortStates, childrenColumnName),\n // [rawData, sortStates],\n // );\n const sortedData = React.useMemo(() => [...rawData], [rawData]);\n\n const mergedData = React.useMemo(\n () =>\n getFilterData(\n sortedData,\n [], // filterStates,\n childrenColumnName,\n ),\n [sortedData, childrenColumnName],\n );\n\n // ====================== Column ======================\n const flattenedSelectionData = React.useMemo(\n () => flattenSelectionData(mergedData, childrenColumnName),\n [mergedData, childrenColumnName],\n );\n\n const [internalSelectedRowKeys, setInternalSelectedRowKeys] = React.useState<\n string[]\n >(() => normalizeSelectionKeys(rowSelection?.defaultSelectedRowKeys));\n\n const controlledSelectedRowKeys = React.useMemo(\n () => normalizeSelectionKeys(rowSelection?.selectedRowKeys),\n [rowSelection?.selectedRowKeys],\n );\n\n const selectedRowKeys =\n rowSelection?.selectedRowKeys === undefined\n ? internalSelectedRowKeys\n : controlledSelectedRowKeys;\n const selectedKeySet = React.useMemo(\n () => new Set(selectedRowKeys),\n [selectedRowKeys],\n );\n\n const selectionType = rowSelection?.type ?? \"checkbox\";\n // Maps the normalized (string) selection key back to its ORIGINAL typed key.\n // Seeded from the controlled `selectedRowKeys`/`defaultSelectedRowKeys` first\n // so rows that are currently filtered out of view still resolve to their real\n // key — without this, off-view selected rows fell back to a string key and a\n // numeric `onChange` consumer received a string. Visible rows are layered on\n // top (covers freshly toggled rows not yet in `selectedRowKeys`).\n const recordKeyBySelectionKey = React.useMemo(() => {\n const map = new Map();\n for (const key of rowSelection?.selectedRowKeys ?? []) {\n map.set(String(key), key);\n }\n for (const key of rowSelection?.defaultSelectedRowKeys ?? []) {\n map.set(String(key), key);\n }\n for (const [index, record] of flattenedSelectionData.entries()) {\n const recordKey = getRowKey(record, index);\n map.set(String(recordKey), recordKey);\n }\n return map;\n }, [\n flattenedSelectionData,\n getRowKey,\n rowSelection?.selectedRowKeys,\n rowSelection?.defaultSelectedRowKeys,\n ]);\n const selectedRows = React.useMemo(\n () =>\n selectedRowKeys\n .map((key) => getRecordByKey(key))\n .filter((record): record is TRecord => record !== undefined),\n [getRecordByKey, selectedRowKeys],\n );\n\n const setSelectedRows = React.useCallback(\n (nextKeys: string[], method: RowSelectMethod) => {\n if (rowSelection?.selectedRowKeys === undefined) {\n setInternalSelectedRowKeys(nextKeys);\n }\n\n const nextRows = nextKeys\n .map((key) => getRecordByKey(key))\n .filter((record): record is TRecord => record !== undefined);\n // Resolved back to the original typed keys via recordKeyBySelectionKey\n // (seeded from selectedRowKeys, so this holds even for off-view rows).\n // A miss means the key was never seen in the data nor in\n // selectedRowKeys/defaultSelectedRowKeys: we pass the raw string through\n // and warn, since a non-string `TKey` consumer would otherwise silently\n // receive a string it cannot match against its own keys.\n const nextRecordKeys = nextKeys.map((key) => {\n const recordKey = recordKeyBySelectionKey.get(key);\n warning(\n recordKey !== undefined,\n \"usage\",\n `Selected key \\`${key}\\` could not be resolved to an original row key, so the raw string is passed to \\`rowSelection.onChange\\`. Add it to \\`selectedRowKeys\\`/\\`defaultSelectedRowKeys\\` so keys with a non-string type keep their type.`,\n );\n return recordKey ?? key;\n }) as TKey[];\n\n rowSelection?.onChange?.(nextRecordKeys, nextRows, { type: method });\n },\n [getRecordByKey, recordKeyBySelectionKey, rowSelection],\n );\n\n const transformSelectionColumns = React.useCallback(\n (columns: ColumnsType) => {\n if (!rowSelection) {\n return columns;\n }\n\n const selectionColumnWidth = rowSelection.columnWidth ?? 48;\n const visibleSelectionKeys = flattenedSelectionData\n .map((record, index) => ({\n key: String(getRowKey(record, index)),\n record,\n disabled: rowSelection.getCheckboxProps?.(record)?.disabled ?? false,\n }))\n .filter((item) => !item.disabled);\n\n const allChecked =\n visibleSelectionKeys.length > 0 &&\n visibleSelectionKeys.every((item) => selectedKeySet.has(item.key));\n const someChecked = visibleSelectionKeys.some((item) =>\n selectedKeySet.has(item.key),\n );\n\n const toggleAll = () => {\n const nextKeys = allChecked\n ? selectedRowKeys.filter(\n (key) => !visibleSelectionKeys.some((item) => item.key === key),\n )\n : [\n ...new Set([\n ...selectedRowKeys,\n ...visibleSelectionKeys.map((item) => item.key),\n ]),\n ];\n\n setSelectedRows(nextKeys, \"all\");\n };\n\n const selectionColumn = {\n key: \"__select__\",\n width: selectionColumnWidth,\n minWidth:\n typeof selectionColumnWidth === \"number\" ? selectionColumnWidth : 48,\n title:\n selectionType === \"radio\"\n ? null\n : rowSelection.columnTitle\n ? typeof rowSelection.columnTitle === \"function\"\n ? rowSelection.columnTitle(\n ,\n )\n : rowSelection.columnTitle\n : !rowSelection.hideSelectAll && (\n \n ),\n render: (_: unknown, record: TRecord, index: number) => {\n const key = String(getRowKey(record, index));\n const checkboxProps = rowSelection.getCheckboxProps?.(record);\n const checked = selectedKeySet.has(key);\n const originNode = (\n {\n checkboxProps?.onClick?.(event);\n }}\n onToggle={() => {\n if (checkboxProps?.disabled) {\n return;\n }\n\n const nextKeys =\n selectionType === \"radio\"\n ? [key]\n : checked\n ? selectedRowKeys.filter(\n (selectedKey) => selectedKey !== key,\n )\n : [...selectedRowKeys, key];\n\n const method: RowSelectMethod =\n selectionType === \"radio\" ? \"single\" : \"all\";\n setSelectedRows([...new Set(nextKeys)], method);\n }}\n />\n );\n\n return rowSelection.renderCell\n ? rowSelection.renderCell(checked, record, index, originNode)\n : originNode;\n },\n align: rowSelection.align ?? \"center\",\n onCell: rowSelection.onCell,\n } satisfies ColumnsType[0];\n\n return [selectionColumn, ...columns];\n },\n [\n flattenedSelectionData,\n getRowKey,\n rowSelection,\n selectedKeySet,\n selectedRowKeys,\n selectionType,\n setSelectedRows,\n ],\n );\n\n const [mergedColumns, columnsForTTTable, _flattenColumns] =\n useColumns(\n {\n ...props,\n ...expandableConfig,\n expandable: !!expandableConfig.expandedRowRender,\n expandColumnTitle: expandableConfig.columnTitle,\n expandedKeys: mergedExpandedKeys,\n getRowKey,\n onTriggerExpand,\n expandIcon: mergedExpandIcon,\n expandIconColumnIndex: expandableConfig.expandIconColumnIndex,\n expandedRowRender: expandableConfig.expandedRowRender,\n },\n transformSelectionColumns,\n );\n\n const columnPinning = React.useMemo(() => {\n const left: string[] = [];\n const right: string[] = [];\n for (const col of columnsForTTTable) {\n const fixed = col.meta?.fixed;\n if (col.id === undefined) {\n continue;\n }\n if (fixed === \"left\" || fixed === \"start\" || fixed === true) {\n left.push(col.id);\n } else if (fixed === \"right\" || fixed === \"end\") {\n right.push(col.id);\n }\n }\n return { left, right };\n }, [columnsForTTTable]);\n\n // ============================ Sorter =============================\n const onSorterChange = (\n sorter: SorterResult | SorterResult[],\n sorterStates: SortState[],\n ) => {\n triggerOnChange(\n {\n sorter,\n sorterStates,\n },\n \"sort\",\n false,\n );\n };\n\n const [\n sortingState,\n setSortingState,\n _transformSorterColumns,\n sortStates,\n _sorterTitleProps,\n getSorters,\n ] = useSorter({\n mergedColumns,\n onSorterChange,\n sortDirections: sortDirections ?? [\"ascend\", \"descend\"],\n tableLocale,\n showSorterTooltip,\n });\n\n changeEventInfo.sorter = getSorters();\n changeEventInfo.sorterStates = sortStates;\n\n // ====================== Pinnings ======================\n\n // ========================== Pagination ==========================\n const onPaginationChange = (current: number, pageSize: number) => {\n triggerOnChange(\n {\n pagination: { ...changeEventInfo.pagination, current, pageSize },\n },\n \"paginate\",\n );\n };\n\n const [mergedPagination, resetPagination] = usePagination(\n rawData.length,\n onPaginationChange,\n pagination,\n );\n\n changeEventInfo.pagination =\n pagination === false\n ? {}\n : getPaginationParam(mergedPagination, pagination);\n\n changeEventInfo.resetPagination = resetPagination;\n\n // ============================= Data =============================\n // const pageData = React.useMemo(() => {\n // if (pagination === false || !mergedPagination.pageSize) {\n // return mergedData;\n // }\n\n // const {\n // current = 1,\n // total,\n // pageSize = DEFAULT_PAGE_SIZE,\n // } = mergedPagination;\n // warning(current > 0, \"usage\", \"`current` should be positive number.\");\n\n // // Dynamic table data\n // if (mergedData.length < total!) {\n // if (mergedData.length > pageSize) {\n // warning(\n // false,\n // \"usage\",\n // \"`dataSource` length is less than `pagination.total` but large than `pagination.pageSize`. Please make sure your config correct data with async mode.\",\n // );\n // return mergedData.slice((current - 1) * pageSize, current * pageSize);\n // }\n // return mergedData;\n // }\n\n // return mergedData.slice((current - 1) * pageSize, current * pageSize);\n // }, [\n // !!pagination,\n // mergedData,\n // mergedPagination?.current,\n // mergedPagination?.pageSize,\n // mergedPagination?.total,\n // ]);\n\n // ====================== Table Instance ======================\n // Memoize columns to prevent unnecessary re-renders\n // const memoizedColumns = React.useMemo(\n // () => columnsForTTTable,\n // [columnsForTTTable],\n // );\n\n // Memoize table state to prevent unnecessary re-renders\n // const tableState = React.useMemo(\n // () => ({\n // // columnPinning,\n // // expanded,\n // // rowSelection,\n // // sorting: collectedSorting,\n // }),\n // [columnPinning, expanded, rowSelection, collectedSorting],\n // );\n\n // Memoize handlers to prevent unnecessary re-renders\n const handleExpandedChange: OnChangeFn = React.useCallback(\n (updaterOrValue) => {\n setExpandedState(updaterOrValue);\n },\n [setExpandedState],\n );\n\n // ============================ Render ============================\n // const transformColumns = React.useCallback(\n // (innerColumns: ColumnsType): ColumnsType =>\n // transformTitleColumns(\n // transformSelectionColumns(\n // transformFilterColumns(transformSorterColumns(innerColumns)),\n // ),\n // ),\n // [transformSorterColumns, transformFilterColumns, transformSelectionColumns],\n // );\n\n // Create table instance with memoized values and required properties\n\n // eslint-disable-next-line react-hooks/incompatible-library\n const table = useReactTable({\n data: mergedData,\n columns: columnsForTTTable,\n state: {\n sorting: sortingState,\n expanded: expandedState,\n columnPinning,\n },\n // Core functionality\n getCoreRowModel: getCoreRowModel(),\n getRowId: (originalRow, index) => getRowKey(originalRow, index).toString(),\n // Expandable rows\n getExpandedRowModel: getExpandedRowModel(),\n getSubRows: (row) => row[childrenColumnName] ?? [],\n // For tree data (nest): only expand if row has children\n // For custom expandedRowRender: always allow expand\n getRowCanExpand: (row) => {\n if (expandableConfig.expandedRowRender) {\n return true; // Allow expanding for custom detail rows\n }\n // For tree data, check if row has children\n const children = row.original[childrenColumnName];\n return Array.isArray(children) && children.length > 0;\n },\n onExpandedChange: handleExpandedChange,\n // Row selection\n enableRowSelection: false,\n enableSubRowSelection: false,\n // Sorting\n getSortedRowModel: getSortedRowModel(),\n onSortingChange: setSortingState,\n isMultiSortEvent: mergedColumns.some(\n (col) => typeof col.sorter === \"object\",\n )\n ? () => true\n : undefined, // Enable multi-sort if any column has sorter object\n // Column resizing\n columnResizeMode: \"onChange\",\n // Enable manual row model if you're handling pagination server-side\n // manualPagination: true,\n // pageCount: dataQuery.data?.totalPages ?? -1,\n });\n\n // ====================== Scroll ======================\n // const [colsWidths, _updateColsWidths] = useLayoutState(\n // new Map(),\n // );\n\n // Convert map to number width\n\n // const colWidths = React.useMemo(\n // () => pureColWidths,\n // // eslint-disable-next-line react-compiler/react-compiler\n // [pureColWidths.join(\"_\")],\n // );\n // const stickyOffsets = useStickyOffsets(colWidths, flattenColumns, direction);\n\n // ---- scroll X ----//\n // ---- to show or disable box-shadow ----//\n const wrapperRef = useRef(null);\n const wrapperSize = useSize(wrapperRef);\n const wrapperWidth = wrapperSize?.width ?? scroll?.x ?? 0;\n const wrapperScroll = useScroll(wrapperRef);\n const wrapperScrollLeft = wrapperScroll?.left ?? 0;\n const wrapperScrollRight =\n (scroll?.x ?? 0) - (wrapperWidth + wrapperScrollLeft);\n\n const TableHeaderComp =\n components?.header &&\n \"wrapper\" in components.header &&\n components.header.wrapper\n ? components.header.wrapper\n : TableHeader;\n const TableBodyComp =\n components?.body && \"wrapper\" in components.body && components.body.wrapper\n ? components.body.wrapper\n : TableBody;\n const TableRowComp =\n components?.body && \"row\" in components.body && components.body.row\n ? components.body.row\n : TableRow;\n\n const TableToolbarSection = toolbar ? <>{toolbar(table)} : undefined;\n const TableAlertSection = alertRender ? (\n typeof alertRender === \"function\" ? (\n alertRender({\n selectedRowKeys,\n selectedRows,\n })\n ) : (\n
{alertRender}
\n )\n ) : (\n <>\n );\n\n // ====================== UI ======================\n const bordered = borderedProp ?? tableConfig?.bordered ?? false;\n // ---- classes ----//\n const getRowClassName = (row: Row, index: number) => {\n const classFromClassNames = classNames?.row\n ? typeof classNames.row === \"string\"\n ? classNames.row\n : classNames.row(row.original, index)\n : \"\";\n\n const classFromRowClassName = rowClassName\n ? typeof rowClassName === \"string\"\n ? rowClassName\n : rowClassName(row.original, index)\n : \"\";\n\n return cn(classFromClassNames, classFromRowClassName);\n };\n\n // ========================================================================\n // == Render ==\n // ========================================================================\n // =================== Render: Node ===================\n // // Header props\n // const headerProps = {\n // colWidths,\n // columCount: flattenColumns.length,\n // // stickyOffsets,\n // // onHeaderRow,\n // // fixHeader,\n // scroll,\n // };\n\n // Use table.getAllLeafColumns() to include dynamically added columns (selection, etc.)\n const allLeafColumns = table.getAllLeafColumns();\n\n const bodyColGroup = (\n {\n // Only return size if explicitly set (not TanStack Table's default 150)\n const colDef = col.columnDef;\n // Check if size/minSize was explicitly set or if meta has width\n const hasExplicitSize =\n colDef.size !== undefined ||\n colDef.minSize !== undefined ||\n (colDef.meta &&\n typeof colDef.meta === \"object\" &&\n \"width\" in colDef.meta);\n\n return hasExplicitSize ? col.getSize() : undefined;\n })}\n columCount={allLeafColumns.length}\n />\n );\n\n return (\n \n \n table]:border-spacing-0 [&>table]:rounded-md [&>table]:border\",\n typeof bordered === \"boolean\" &&\n \"[&_th]:border-e [&_th:last-child]:border-e-0\",\n typeof bordered === \"boolean\" &&\n \"[&_td]:border-e [&_td:last-child]:border-e-0\",\n !summary && \"[&_tbody_tr:last-child>td]:border-b-0\",\n summary && \"[&_tfoot_tr:last-child>td]:border-b-0\",\n ],\n (!bordered || bordered === \"around\") && [\n \"[&_th]:before:bg-accent [&_th]:before:absolute [&_th]:before:top-1/2 [&_th]:before:right-0 [&_th]:before:h-[1.6em] [&_th]:before:w-px [&_th]:before:-translate-y-1/2 [&_th]:before:content-[''] [&_th:last-child]:before:bg-transparent\",\n ],\n // bordered === \"around\" && [\n // \"[&_table]:border-separate [&_table]:border-spacing-0 [&_table]:rounded-md\",\n // ],\n classNames?.root,\n className,\n )}\n style={style}\n >\n {TableToolbarSection}\n\n {TableAlertSection}\n \n {(title || extra) && (\n \n
{title?.(mergedData)}
\n {extra &&
{extra}
}\n \n )}\n \n {bodyColGroup}\n {showHeader !== false && (\n \n {table.getHeaderGroups().map((headerGroup) => (\n \n {headerGroup.headers.map((header) => {\n return (\n \n {header.isPlaceholder\n ? undefined\n : flexRender(\n header.column.columnDef.header,\n header.getContext(),\n )}\n \n );\n })}\n \n ))}\n \n )}\n {/* padding with header [disable if bordered]*/}\n {/* {!bordered && } */}\n {skeleton ? (\n \n {Array.from({ length: mergedPagination?.pageSize ?? 5 })\n .fill(0)\n .map((_, index) => {\n return (\n \n {table.getVisibleFlatColumns().map((x) => {\n return (\n \n \n \n );\n })}\n \n );\n })}\n \n ) : (\n \n {table.getRowModel().rows.length > 0 ? (\n table.getRowModel().rows.map((row, rowIndex) =>\n \"_customRow\" in row.original ? (\n \n \n {row.original._customRow}\n \n \n ) : (\n \n {\n onRow?.(row.original).onClick?.(e);\n // onRow?.({\n // record: row.original,\n // row,\n // table,\n // event: e,\n // });\n\n if (expandableConfig.expandRowByClick) {\n const selection = globalThis.getSelection();\n if (selection?.type === \"Range\") {\n return;\n }\n row.getToggleExpandedHandler()();\n // row.getToggleExpandedHandler()();\n }\n // e.preventDefault();\n // e.stopPropagation();\n }}\n >\n {row.getVisibleCells().map((cell) => {\n return (\n \n {flexRender(\n cell.column.columnDef.cell,\n cell.getContext(),\n )}\n \n );\n })}\n \n {row.getIsExpanded() &&\n expandableConfig.expandedRowRender && (\n \n {/* 2nd row is a custom 1 cell row */}\n \n {expandableConfig.expandedRowRender(\n row.original,\n row.index,\n row.index,\n row.getIsExpanded(),\n )}\n \n \n )}\n \n ),\n )\n ) : (\n \n \n {!loading &&\n (tableLocale.emptyText == null ? (\n \n ) : typeof tableLocale.emptyText === \"function\" ? (\n tableLocale.emptyText()\n ) : (\n tableLocale.emptyText\n ))}\n \n \n )}\n \n )}\n {summary && (\n \n {summary(mergedData)}\n \n )}\n
\n {footer && (\n \n {footer(mergedData)}\n \n )}\n \n {pagination && (\n \n )}\n \n \n \n );\n}\nexport { OwnTable };\n\nexport type { TableProps as OwnTableProps, RecordWithCustomRow };\n", "type": "registry:file", "target": "components/table/table.tsx" }, { "path": "components/table/types.ts", "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-function-type */\nimport type {\n BuiltInSortingFn,\n Column,\n Row,\n RowData,\n Table,\n} from \"@tanstack/react-table\";\nimport type { DropdownMenu } from \"radix-ui\";\n\nimport type { Breakpoint } from \"../_util/responsive-observer\";\nimport type { AnyObject } from \"../_util/type\";\nimport type { Placement } from \"../../types\";\nimport type { CheckboxProps } from \"../checkbox\";\nimport type { PaginationProps } from \"../pagination\";\nimport type { TooltipProps } from \"../tooltip\";\n\ndeclare module \"@tanstack/react-table\" {\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n interface ColumnMeta<\n TData extends RowData,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n TValue,\n > extends ColumnType {}\n}\n\nexport type SelectionItemSelectFn = (currentRowKeys: Key[]) => void;\n\nexport type ExpandType = null | \"row\" | \"nest\";\n\nexport interface TableLocale {\n filterTitle?: string;\n filterConfirm?: React.ReactNode;\n filterReset?: React.ReactNode;\n filterEmptyText?: React.ReactNode;\n /**\n * @deprecated Please use `filterCheckAll` instead.\n */\n filterCheckall?: React.ReactNode;\n filterCheckAll?: React.ReactNode;\n filterSearchPlaceholder?: string;\n emptyText?: React.ReactNode | (() => React.ReactNode);\n selectAll?: React.ReactNode;\n selectNone?: React.ReactNode;\n selectInvert?: React.ReactNode;\n selectionAll?: React.ReactNode;\n sortTitle?: string;\n expand?: string;\n collapse?: string;\n triggerDesc?: string;\n triggerAsc?: string;\n cancelSort?: string;\n}\n\nexport type SorterTooltipTarget = \"full-header\" | \"sorter-icon\";\n\nexport type SorterTooltipProps = TooltipProps & {\n target?: SorterTooltipTarget;\n};\n\nexport interface CellType {\n key?: Key;\n className?: string;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n column?: ColumnType;\n colSpan?: number;\n rowSpan?: number;\n\n /** Only used for table header */\n hasSubColumns?: boolean;\n colStart?: number;\n colEnd?: number;\n}\nexport interface RenderedCell {\n props?: CellType;\n children?: React.ReactNode;\n}\n\n// SpecialString will be removed in antd@6\n// export type SpecialString = T | (string & {});\n\nexport type DataIndex = DeepNamePath;\n\nexport type CellEllipsisType =\n | {\n showTitle?: boolean;\n }\n | boolean;\ntype ColumnSharedType = {\n title?:\n | React.ReactNode\n | ((ctx: { table: Table }) => React.ReactNode);\n key?: string;\n className?: string;\n hidden?: boolean;\n fixed?: FixedType;\n align?: AlignType;\n\n // own\n classNames?: {\n head?: string;\n cell?: string;\n };\n\n // width?: number;\n minWidth?: number;\n\n enableResizing?: boolean;\n enableHiding?: boolean;\n\n responsive?: Breakpoint[];\n\n styles?: {\n head?: React.CSSProperties;\n cell?:\n | React.CSSProperties\n | ((ctx: {\n record: TRecord;\n index: number;\n row: Row;\n column: Column;\n }) => React.CSSProperties);\n };\n attributes?: Record;\n headAttributes?: Record;\n // rowName?: string | ((record: TRecord, index: number) => string);\n\n onHeaderCell?: GetComponentProps[number]>;\n ellipsis?: CellEllipsisType;\n};\n\nexport interface ColumnGroupType extends Omit<\n ColumnType,\n \"dataIndex\"\n> {\n children: ColumnsType;\n}\n\nexport type AlignType =\n | \"start\"\n | \"end\"\n | \"left\"\n | \"right\"\n | \"center\"\n | \"justify\"\n | \"match-parent\";\n\nexport interface ColumnFilterItem {\n text: React.ReactNode;\n value: React.Key | boolean;\n children?: ColumnFilterItem[];\n}\n\nexport interface ColumnTitleProps {\n /** @deprecated Please use `sorterColumns` instead. */\n sortOrder?: SortOrder;\n /** @deprecated Please use `sorterColumns` instead. */\n sortColumn?: ColumnType;\n sortColumns?: { column: ColumnType; order: SortOrder }[];\n\n filters?: Record;\n}\n\nexport type ColumnTitle =\n | React.ReactNode\n | ((props: ColumnTitleProps) => React.ReactNode);\n\nexport type FilterValue = (Key | boolean)[];\nexport type FilterKey = (string | number)[] | null;\nexport type FilterSearchType =\n | boolean\n | ((input: string, record: RecordType) => boolean);\nexport interface FilterConfirmProps {\n closeDropdown: boolean;\n}\n\nexport interface FilterRestProps {\n confirm?: boolean;\n closeDropdown?: boolean;\n}\n\nexport interface FilterDropdownProps {\n prefixCls: string;\n setSelectedKeys: (selectedKeys: React.Key[]) => void;\n selectedKeys: React.Key[];\n /**\n * Confirm filter value, if you want to close dropdown before commit, you can call with\n * {closeDropdown: true}\n */\n confirm: (param?: FilterConfirmProps) => void;\n clearFilters?: (param?: FilterRestProps) => void;\n filters?: ColumnFilterItem[];\n /** Only close filterDropdown */\n close: () => void;\n visible: boolean;\n}\n\ntype RenderCellContext = {\n table: Table;\n row: Row;\n column: Column;\n};\n\n// XOR<\n// {\n// dataIndex?: never;\n// render?: (\n// value: null,\n// record: TRecord,\n// index: number,\n// // cellContext: RenderCellContext,\n// ) => React.ReactNode;\n// },\n// {\n// [K in keyof TRecord]-?: {\n// dataIndex: K;\n// render?: (\n// value: TRecord[K],\n// record: TRecord,\n// index: number,\n// // cellContext: RenderCellContext,\n// ) => React.ReactNode;\n// };\n// }[keyof TRecord]\n// >\ninterface CoverableDropdownProps extends DropdownMenu.DropdownMenuTriggerProps {\n children?: React.ReactNode;\n className?: string;\n disabled?: boolean;\n menu?: {\n getPopupContainer?: GetPopupContainer;\n items?: Array<{\n key?: Key;\n label?: React.ReactNode;\n onClick?: () => void;\n }>;\n };\n open?: boolean;\n placement?: Placement;\n trigger?: (\"click\" | \"hover\" | \"contextMenu\")[];\n getPopupContainer?: GetPopupContainer;\n onOpenChange?: (open: boolean) => void;\n}\nexport type ColumnType = ColumnSharedType & {\n title?: ColumnTitle;\n // RC\n dataIndex?: DataIndex;\n render?: (\n value: any,\n record: TRecord,\n index: number,\n cellContext: RenderCellContext,\n ) => React.ReactNode | RenderedCell;\n shouldCellUpdate?: (record: TRecord, prevRecord: TRecord) => boolean;\n colSpan?: number;\n rowSpan?: number;\n width?: number | string;\n /** Min width of this column, only works when `tableLayout=\"auto\"` */\n minWidth?: number;\n onCell?: GetComponentProps;\n\n /** Sort function for local sort, see Array.sort's compareFunction. If it is server-side sorting, set to true, but if you want to support multi-column sorting, you can set it to { multiple: number }\n * boolean\n * function\n * Build-in sorting function: 'alphanumeric', 'alphanumericCaseSensitive', 'text', 'textCaseSensitive', 'datetime', 'basic'.\n * */\n // Sorter\n sorter?:\n | boolean\n | BuiltInSortingFn\n | CompareFn\n | {\n compare?: CompareFn;\n /** Config multiple sorter order priority */\n multiple?: number;\n };\n sortOrder?: SortOrder;\n defaultSortOrder?: SortOrder;\n sortDirections?: SortOrder[];\n sortIcon?: (props: { sortOrder: SortOrder }) => React.ReactNode;\n showSorterTooltip?: boolean | SorterTooltipProps;\n\n // filter\n filtered?: boolean;\n filters?: ColumnFilterItem[];\n filterDropdown?:\n | React.ReactNode\n | ((props: FilterDropdownProps) => React.ReactNode);\n filterOnClose?: boolean;\n filterMultiple?: boolean;\n filteredValue?: FilterValue | null;\n defaultFilteredValue?: FilterValue | null;\n filterIcon?: React.ReactNode | ((filtered: boolean) => React.ReactNode);\n filterMode?: \"menu\" | \"tree\";\n filterSearch?: FilterSearchType;\n onFilter?: (value: React.Key | boolean, record: TRecord) => boolean;\n /**\n * Can cover `` props\n * @since 5.22.0\n */\n filterDropdownProps?: CoverableDropdownProps;\n filterResetToDefaultFilteredValue?: boolean;\n\n // Deprecated\n /**\n * @deprecated Please use `filterDropdownProps.open` instead.\n * @since 4.23.0\n */\n filterDropdownOpen?: boolean;\n /**\n * @deprecated Please use `filterDropdownProps.onOpenChange` instead.\n * @since 4.23.0\n */\n onFilterDropdownOpenChange?: (visible: boolean) => void;\n /** @deprecated Please use `filterDropdownProps.open` instead. */\n filterDropdownVisible?: boolean;\n /** @deprecated Please use `filterDropdownProps.onOpenChange` instead */\n onFilterDropdownVisibleChange?: (visible: boolean) => void;\n};\n\nexport type ColumnsType = (\n | ColumnGroupType\n | ColumnType\n)[];\n\nexport interface SelectionItem {\n key: string;\n text: React.ReactNode;\n onSelect?: SelectionItemSelectFn;\n}\n\nexport type INTERNAL_SELECTION_ITEM =\n | SelectionItem\n | \"SELECT_ALL\"\n | \"SELECT_INVERT\"\n | \"SELECT_NONE\";\n\nexport type SelectionSelectFn = (\n record: T,\n selected: boolean,\n selectedRows: T[],\n nativeEvent: Event,\n) => void;\n\nexport type GetRowKey = (record: RecordType, index: number) => Key;\n\n// type DefWithOutDataIndex = ColumnSharedDef & {\n// dataIndex?: never;\n// render?: (context: RenderContext) => React.ReactNode;\n// };\n// /**\n// * TRecord[K] inherit from https://stackoverflow.com/a/56837244\n// */\n// export type ColumnDef = ExtraColumnDef &\n// (\n// | DefWithOutDataIndex\n// | (ColumnSharedDef &\n// {\n// [K in keyof TRecord]-?: {\n// dataIndex: K;\n// render?: (\n// context: RenderContext & {\n// value: TRecord[K];\n// },\n// ) => React.ReactNode;\n// };\n// }[keyof TRecord])\n// );\n\nexport type RowSelectionType = \"checkbox\" | \"radio\";\n\nexport type RowSelectMethod = \"all\" | \"none\" | \"invert\" | \"single\" | \"multiple\";\n\nexport type TableRowSelection = {\n /** Keep the selection keys in list even the key not exist in `dataSource` anymore */\n preserveSelectedRowKeys?: boolean;\n type?: RowSelectionType;\n /**\n * Controlled selected row keys.\n *\n * `TKey` defaults to `Key` (string | number). Narrow it — e.g.\n * `TableRowSelection` — when your `rowKey` resolves to a single\n * type, so `onChange` hands back that type instead of `Key[]`. The Table\n * resolves every key (incl. rows filtered out of view) back to its original\n * `selectedRowKeys` value, so this narrowing is sound, not a cast.\n */\n selectedRowKeys?: TKey[];\n defaultSelectedRowKeys?: TKey[];\n /** Callback executed when selected rows change */\n onChange?: (\n selectedRowKeys: TKey[],\n selectedRows: TRecord[],\n info: { type: RowSelectMethod },\n ) => void;\n getCheckboxProps?: (\n record: TRecord,\n ) => Partial>;\n onSelect?: SelectionSelectFn;\n /** @deprecated This function is deprecated and should use `onChange` instead */\n onSelectMultiple?: (\n selected: boolean,\n selectedRows: TRecord[],\n changeRows: TRecord[],\n ) => void;\n /** @deprecated This function is deprecated and should use `onChange` instead */\n onSelectAll?: (\n selected: boolean,\n selectedRows: TRecord[],\n changeRows: TRecord[],\n ) => void;\n /** @deprecated This function is deprecated and should use `onChange` instead */\n onSelectInvert?: (selectedRowKeys: Key[]) => void;\n /** @deprecated This function is deprecated and should use `onChange` instead */\n onSelectNone?: () => void;\n selections?: INTERNAL_SELECTION_ITEM[] | boolean;\n /** Hide the selectAll checkbox and custom selection */\n hideSelectAll?: boolean;\n fixed?: FixedType;\n columnWidth?: string | number;\n columnTitle?:\n | React.ReactNode\n | ((checkboxNode: React.ReactNode) => React.ReactNode);\n checkStrictly?: boolean;\n /** Set the alignment of the selection column */\n align?: \"left\" | \"center\" | \"right\";\n /** Renderer of the `table` cell. Same as render in column */\n renderCell?: (\n value: boolean,\n record: TRecord,\n index: number,\n originNode: React.ReactNode,\n ) => React.ReactNode;\n onCell?: GetComponentProps;\n\n // Own extensions\n /** Renderer of the `table` header */\n renderHeader?: (args: {\n checked: boolean;\n originNode: React.ReactNode;\n }) => React.ReactNode;\n};\n\nexport type TransformColumns = (\n columns: ColumnsType,\n) => ColumnsType;\n\nexport type Key = React.Key;\n\n/**\n * Use `start` or `end` instead. `left` or `right` is deprecated.\n */\nexport type FixedType = \"start\" | \"end\" | \"left\" | \"right\" | boolean;\n\nexport type ScrollConfig = {\n index?: number;\n key?: Key;\n top?: number;\n};\n\n// ==================== Row =====================\nexport type RowClassName = (\n record: RecordType,\n index: number,\n indent: number,\n) => string;\n\n// ================= Fix Column =================\nexport interface StickyOffsets {\n start: readonly number[];\n end: readonly number[];\n widths: readonly number[];\n isSticky?: boolean;\n}\n\n// ================= Customized =================\ntype Component

=\n | React.ComponentType

\n | React.ForwardRefExoticComponent

\n | React.FC

\n | React.HTMLElementType;\n\nexport type CustomizeComponent = Component;\n\nexport type OnCustomizeScroll = (info: {\n currentTarget?: HTMLElement;\n scrollLeft?: number;\n}) => void;\n\nexport type CustomizeScrollBody = (\n data: readonly RecordType[],\n info: {\n scrollbarSize: number;\n ref: React.Ref<{\n scrollLeft: number;\n scrollTo?: (scrollConfig: ScrollConfig) => void;\n }>;\n onScroll: OnCustomizeScroll;\n },\n) => React.ReactNode;\n\nexport interface TableComponents {\n table?: CustomizeComponent;\n header?: {\n table?: CustomizeComponent;\n wrapper?: CustomizeComponent;\n row?: CustomizeComponent;\n cell?: CustomizeComponent;\n };\n body?:\n | CustomizeScrollBody\n | {\n wrapper?: CustomizeComponent;\n row?: CustomizeComponent;\n cell?: CustomizeComponent;\n };\n}\n\ntype TablePaginationPosition =\n | \"topLeft\"\n | \"topCenter\"\n | \"topRight\"\n | \"bottomLeft\"\n | \"bottomCenter\"\n | \"bottomRight\"\n | \"none\";\nexport interface TablePaginationConfig extends PaginationProps {\n position?: TablePaginationPosition[];\n}\n\nexport type SortOrder = \"descend\" | \"ascend\" | null;\n\nexport type CompareFn = (\n a: T,\n b: T,\n sortOrder?: SortOrder,\n) => number;\n\ndeclare const _TableActions: readonly [\"paginate\", \"sort\", \"filter\"];\nexport type TableAction = (typeof _TableActions)[number];\nexport interface TableCurrentDataSource {\n currentDataSource: RecordType[];\n action: TableAction;\n}\n\n// =================== Expand ===================\n\nexport type ExpandableType = false | \"row\" | \"nest\";\nexport interface LegacyExpandableProps {\n /** @deprecated Use `expandable.expandedRowKeys` instead */\n expandedRowKeys?: Key[];\n /** @deprecated Use `expandable.defaultExpandedRowKeys` instead */\n defaultExpandedRowKeys?: Key[];\n /** @deprecated Use `expandable.expandedRowRender` instead */\n expandedRowRender?: ExpandedRowRender;\n /** @deprecated Use `expandable.expandRowByClick` instead */\n expandRowByClick?: boolean;\n /** @deprecated Use `expandable.expandIcon` instead */\n expandIcon?: RenderExpandIcon;\n /** @deprecated Use `expandable.onExpand` instead */\n onExpand?: (expanded: boolean, record: RecordType) => void;\n /** @deprecated Use `expandable.onExpandedRowsChange` instead */\n onExpandedRowsChange?: (expandedKeys: Key[]) => void;\n /** @deprecated Use `expandable.defaultExpandAllRows` instead */\n defaultExpandAllRows?: boolean;\n /** @deprecated Use `expandable.indentSize` instead */\n indentSize?: number;\n /** @deprecated Use `expandable.expandIconColumnIndex` instead */\n expandIconColumnIndex?: number;\n /** @deprecated Use `expandable.expandedRowClassName` instead */\n expandedRowClassName?: RowClassName;\n /** @deprecated Use `expandable.childrenColumnName` instead */\n childrenColumnName?: string;\n title?: PanelRender;\n}\n\nexport type ExpandedRowRender = (\n record: TRcord,\n index: number,\n indent: number,\n expanded: boolean,\n) => React.ReactNode;\n\nexport interface RenderExpandIconProps {\n // prefixCls: string;\n expanded: boolean;\n record: TRecord;\n expandable: boolean;\n onExpand: TriggerEventHandler;\n className?: string;\n}\n\nexport type RenderExpandIcon = (\n props: RenderExpandIconProps,\n) => React.ReactNode;\n\nexport interface ExpandableConfig {\n expandedRowKeys?: readonly Key[];\n defaultExpandedRowKeys?: readonly Key[];\n expandedRowRender?: ExpandedRowRender;\n columnTitle?: React.ReactNode;\n expandRowByClick?: boolean;\n expandIcon?: RenderExpandIcon;\n onExpand?: (expanded: boolean, record: TRecord) => void;\n onExpandedRowsChange?: (expandedKeys: readonly Key[]) => void;\n defaultExpandAllRows?: boolean;\n indentSize?: number;\n /** @deprecated Please use `EXPAND_COLUMN` in `columns` directly */\n expandIconColumnIndex?: number;\n showExpandColumn?: boolean;\n expandedRowClassName?: string | RowClassName;\n /**\n * The property name for tree data children. Defaults to 'children'.\n * Set this to match your nested data property (e.g., 'tasks').\n */\n childrenColumnName?: string;\n rowExpandable?: (record: TRecord) => boolean;\n columnWidth?: number | string;\n fixed?: FixedType;\n}\nexport type PanelRender = (\n data: readonly RecordType[],\n) => React.ReactNode;\n\n// =================== Events ===================\nexport type TriggerEventHandler = (\n record: RecordType,\n event: React.MouseEvent,\n) => void;\n\n// =================== Sticky ===================\nexport interface TableSticky {\n offsetHeader?: number;\n offsetSummary?: number;\n offsetScroll?: number;\n getContainer?: () => Window | HTMLElement;\n}\n\n// ================= Customized =================\nexport type GetComponentProps = (\n data: DataType,\n index?: number,\n) => React.HTMLAttributes & React.TdHTMLAttributes;\n\nexport type GetComponent = (\n path: readonly string[],\n defaultComponent?: CustomizeComponent,\n) => CustomizeComponent;\n\n// ================= NamePath =================\n// source https://github.com/crazyair/field-form/blob/master/src/namePathType.ts\n\ntype BaseNamePath = string | number | boolean | (string | number | boolean)[];\n/**\n * Store: The store type from `FormInstance`\n * ParentNamePath: Auto generate by nest logic. Do not fill manually.\n */\nexport type DeepNamePath<\n Store = any,\n ParentNamePath extends any[] = [],\n> = ParentNamePath[\"length\"] extends 3\n ? never\n : // Follow code is batch check if `Store` is base type\n true extends (Store extends BaseNamePath ? true : false)\n ? ParentNamePath[\"length\"] extends 0\n ? Store | BaseNamePath // Return `BaseNamePath` instead of array if `ParentNamePath` is empty\n : Store extends any[]\n ? [...ParentNamePath, number] // Connect path\n : never\n : Store extends any[] // Check if `Store` is `any[]`\n ? // Connect path. e.g. { a: { b: string }[] }\n // Get: [a] | [ a,number] | [ a ,number , b]\n | [...ParentNamePath, number]\n | DeepNamePath\n : keyof Store extends never // unknown\n ? Store\n : {\n // Convert `Store` to . We mark key a `FieldKey`\n [FieldKey in keyof Store]: Store[FieldKey] extends Function\n ? never\n :\n | (ParentNamePath[\"length\"] extends 0 ? FieldKey : never) // If `ParentNamePath` is empty, it can use `FieldKey` without array path\n | [...ParentNamePath, FieldKey] // Exist `ParentNamePath`, connect it\n | DeepNamePath<\n Required[FieldKey],\n [...ParentNamePath, FieldKey]\n >; // If `Store[FieldKey]` is object\n }[keyof Store];\n\nexport interface SorterResult {\n column?: ColumnType;\n order?: SortOrder;\n field?: Key | readonly Key[];\n columnKey?: Key;\n}\n\nexport type GetPopupContainer = (triggerNode: HTMLElement) => HTMLElement;\n\nexport interface RcTableProps {\n // =================================== Internal ===================================\n /**\n * @private Internal usage, may remove by refactor.\n *\n * !!! DO NOT USE IN PRODUCTION ENVIRONMENT !!!\n */\n internalRefs?: {\n body: React.MutableRefObject;\n };\n}\n", "type": "registry:file", "target": "components/table/types.ts" }, { "path": "components/table/util.tsx", "content": "import type { Row, ColumnDef as TTColumnDef } from \"@tanstack/react-table\";\nimport type { ReactNode } from \"react\";\n\nimport type { AnyObject } from \"../_util/type\";\nimport type { OwnTableProps } from \"./table\";\nimport type {\n ColumnsType,\n ColumnTitle,\n ColumnTitleProps,\n ColumnType,\n Key,\n} from \"./types\";\n\nexport const transformColumnDefs = (\n columns: ColumnsType,\n props: Pick, \"rowKey\" | \"rowSelection\" | \"expandable\">,\n _isNotFirstDeepColumn = true,\n): TTColumnDef[] => {\n const columnsDef: TTColumnDef[] = columns.map(\n (columnProp, columnIndex) => {\n const column = columnProp as ColumnType & {\n children?: ColumnsType;\n };\n const {\n key,\n children,\n dataIndex,\n enableResizing,\n enableHiding,\n title,\n width,\n minWidth,\n render,\n\n // meta props\n // align,\n fixed,\n // className,\n // classNames,\n // styles,\n // defaultSortOrder,\n sorter,\n // attributes,\n // headAttributes,\n // onHeaderCell,\n\n ...restProps\n } = column;\n const columnDefMerged: TTColumnDef = {\n // accessorKey: dataIndex,\n ...(typeof dataIndex === \"string\"\n ? { id: key ?? dataIndex, accessorKey: dataIndex }\n : {\n id: key ?? columnIndex.toString(),\n accessorFn: () => key ?? columnIndex.toString(),\n }),\n header: ({ table }) =>\n typeof title === \"function\" ? title({ table }) : title,\n ...(children\n ? {\n columns: transformColumnDefs(\n // add fixed to children\n children.map((x) => ({ ...x, fixed })),\n props,\n columnIndex === 0 || false,\n ),\n // for use in Gantt\n children: transformColumnDefs(\n // add fixed to children\n children.map((x) => ({ ...x, fixed })),\n props,\n ),\n }\n : {}),\n enableResizing,\n enableHiding,\n size: typeof width === \"number\" ? width : undefined,\n minSize: minWidth,\n meta: column,\n // sorting\n ...(sorter\n ? {\n enableSorting: true,\n sortingFn:\n typeof sorter === \"string\"\n ? sorter\n : typeof sorter === \"function\"\n ? (rowA, rowB) => sorter(rowA.original, rowB.original)\n : // object\n typeof sorter === \"object\"\n ? \"compare\" in sorter\n ? typeof sorter.compare === \"boolean\"\n ? () => 0\n : (rowA, rowB) =>\n (\n sorter.compare as (\n a: TRecord,\n b: TRecord,\n ) => number\n )(rowA.original, rowB.original)\n : \"auto\"\n : // boolean\n \"auto\",\n }\n : { enableSorting: false }),\n ...restProps,\n cell: ({ column, row, getValue, table }) => {\n // First data column should have expand icon + indent\n const isFirstDataColumn = columnIndex === 0;\n const hasTreeData =\n props.expandable &&\n !props.expandable.expandedRowRender &&\n (row.depth > 0 || row.getCanExpand());\n\n // Cell Content - render function can return ReactNode or RenderedCell\n const cellContent = (\n render\n ? typeof dataIndex === \"string\"\n ? render(getValue() as never, row.original, row.index, {\n table,\n column,\n row,\n })\n : render(undefined as never, row.original, row.index, {\n table,\n column,\n row,\n })\n : (getValue() as ReactNode)\n ) as React.ReactNode;\n\n // Only wrap with flex container if first column has tree data\n if (isFirstDataColumn && hasTreeData) {\n return (\n \n {/* Tree Data: Indent (only on first column, only children) */}\n {row.depth > 0 && (\n \n )}\n {/* Tree Data: Expand Icon (only on first column) */}\n \n {row.getCanExpand() && props.expandable?.expandIcon\n ? props.expandable.expandIcon({\n record: row.original,\n expanded: row.getIsExpanded(),\n expandable: row.getCanExpand(),\n onExpand: row.getToggleExpandedHandler(),\n })\n : null}\n \n {cellContent}\n \n );\n }\n\n // Regular cell without wrapper\n return cellContent;\n },\n };\n\n return columnDefMerged;\n },\n );\n\n // if (props.rowSelection) {\n // let lastSelectedId = \"\";\n\n // const selectionColumn: TTColumnDef = {\n // id: \"selection\",\n // header: ({ table }) => {\n // const originNode = (\n // \n // );\n // return props.rowSelection?.renderHeader\n // ? props.rowSelection.renderHeader({\n // checked: table.getIsAllPageRowsSelected(),\n // originNode,\n // })\n // : originNode;\n // },\n // cell: ({ row, table }) => {\n // const originNode = (\n // {\n // if (event.shiftKey) {\n // const { rows, rowsById } = table.getRowModel();\n // const rowsToToggle = getRowRange(rows, row.id, lastSelectedId);\n // const isLastSelected =\n // rowsById[lastSelectedId]?.getIsSelected();\n // for (const row of rowsToToggle)\n // row.toggleSelected(isLastSelected);\n // }\n\n // lastSelectedId = row.id;\n // }}\n // />\n // );\n // return props.rowSelection?.renderCell\n // ? props.rowSelection.renderCell({\n // checked: row.getIsSelected(),\n // record: row.original,\n // index: row.index,\n // originNode,\n // })\n // : originNode;\n // },\n // size: 32,\n // minSize: 32,\n // meta: {\n // align: \"center\",\n // },\n // enableSorting: false,\n // enableHiding: false,\n // };\n // columnsDef.unshift(selectionColumn);\n // }\n\n // if (props.expandable) {\n // const expandColumn: TTColumnDef = {\n // id: \"expander\",\n // size: 50,\n // meta: {\n // align: \"center\",\n // },\n // cell: ({ row }) => {\n // return row.getCanExpand() ? (\n // {\n // if (!props.expandable?.expandRowByClick) {\n // row.getToggleExpandedHandler()();\n // }\n // },\n // }}\n // className=\"flex w-full cursor-pointer items-center justify-center\"\n // >\n // {row.getIsExpanded() ? (\n // \n // ) : (\n // \n // )}\n // \n // ) : undefined;\n // },\n // };\n // columnsDef.unshift(expandColumn);\n // }\n\n return columnsDef;\n};\n\nexport function getRowRange(rows: Array>, idA: string, idB: string) {\n const range: Array> = [];\n let foundStart = false;\n let foundEnd = false;\n // for (let index = 0; index < rows.length; index += 1) {\n for (const row of rows) {\n if (row.id === idA || row.id === idB) {\n if (foundStart) {\n foundEnd = true;\n }\n if (!foundStart) {\n foundStart = true;\n }\n }\n\n if (foundStart) {\n range.push(row);\n }\n\n if (foundEnd) {\n break;\n }\n }\n\n return range;\n}\n\nexport const transformedTanstackTableRowSelection = (\n selectedRowKeys: string[],\n) => {\n const rowSelectionTst: Record = {};\n for (const x of selectedRowKeys) {\n rowSelectionTst[x] = true;\n }\n return rowSelectionTst;\n};\n\nexport const getColumnKey = (\n column: ColumnType,\n defaultKey: string,\n): Key => {\n if (\"key\" in column && column.key !== undefined && column.key !== null) {\n return column.key;\n }\n if (column.dataIndex) {\n return Array.isArray(column.dataIndex)\n ? column.dataIndex.join(\".\")\n : (column.dataIndex as Key);\n }\n return defaultKey;\n};\n\nexport function getColumnPos(index: number, pos?: string) {\n return pos ? `${pos}-${index}` : `${index}`;\n}\n\nexport const renderColumnTitle = (\n title: ColumnTitle,\n props: ColumnTitleProps,\n) => {\n if (typeof title === \"function\") {\n return title(props);\n }\n return title;\n};\n\n/**\n * Safe get column title\n *\n * Should filter [object Object]\n *\n * @param title\n */\nexport const safeColumnTitle = (\n title: ColumnTitle,\n props: ColumnTitleProps,\n) => {\n const res = renderColumnTitle(title, props);\n if (Object.prototype.toString.call(res) === \"[object Object]\") {\n return \"\";\n }\n return res;\n};\n", "type": "registry:file", "target": "components/table/util.tsx" }, { "path": "components/table/styles.ts", "content": "import type { Column } from \"@tanstack/react-table\";\nimport type { CSSProperties } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\n// export const tableStyles = {\n// row: {\n// classNames: cn(\"bg-background\"),\n// hoverClassNames: cn(\"bg-gray-100 dark:bg-gray-800\"),\n// hoverByCssClassNames: \"hover:bg-gray-100 dark:hover:bg-gray-800\",\n// },\n// };\n\n//These are the important styles to make sticky column pinning work!\n//Apply styles like this using your CSS strategy of choice with this kind of logic to head cells, data cells, footer cells, etc.\n//View the index.css file for more needed styles such as border-collapse: separate\nexport const getCommonPinningStyles = (column: Column): CSSProperties => {\n const isPinned = column.getIsPinned();\n return {\n left: isPinned === \"left\" ? `${column.getStart(\"left\")}px` : undefined,\n right: isPinned === \"right\" ? `${column.getAfter(\"right\")}px` : undefined,\n };\n};\nexport const getCommonPinningClassName = (\n column: Column,\n { scrollLeft, scrollRight }: { scrollLeft: number; scrollRight: number },\n _isHeader?: boolean,\n): string => {\n const isPinned = column.getIsPinned();\n const isLastLeftPinnedColumn =\n isPinned === \"left\" && column.getIsLastColumn(\"left\");\n const isFirstRightPinnedColumn =\n isPinned === \"right\" && column.getIsFirstColumn(\"right\");\n return cn(\n // isPinned && !isHeader && \"bg-surface\",\n isPinned ? \"sticky z-10 bg-background\" : \"relative\",\n isLastLeftPinnedColumn && [\n \"after:absolute after:inset-y-0 after:right-0 after:w-[30px] after:translate-x-full\",\n scrollLeft !== 0 &&\n \"after:shadow-[inset_10px_0_8px_-8px_rgba(5,5,5,.06)]\",\n ],\n\n isFirstRightPinnedColumn && [\n \"after:absolute after:inset-y-0 after:left-0 after:w-[30px] after:-translate-x-full\",\n scrollRight > 0 &&\n \"after:shadow-[inset_-10px_0_8px_-8px_rgba(5,5,5,.06)]\",\n ],\n );\n};\n", "type": "registry:file", "target": "components/table/styles.ts" }, { "path": "components/table/constant.ts", "content": "export const EXPAND_COLUMN = {} as const;\n\nexport const INTERNAL_HOOKS = \"table-internal-hook\";\n", "type": "registry:file", "target": "components/table/constant.ts" }, { "path": "components/table/_components/base.tsx", "content": "import type * as React from \"react\";\n\nimport type { SizeType } from \"../../config-provider/size-context\";\nimport type { OwnTableProps } from \"../table\";\nimport { cn } from \"../../../lib/utils\";\nimport {\n Table as ShadcnTable,\n TableBody as ShadcnTableBody,\n TableCell as ShadcnTableCell,\n TableFooter as ShadcnTableFooter,\n TableHead as ShadcnTableHead,\n TableHeader as ShadcnTableHeader,\n TableRow as ShadcnTableRow,\n} from \"../../../shadcn/table\";\n\nfunction TableRoot({\n className,\n bordered,\n ...props\n}: React.ComponentProps<\"table\"> & { bordered?: OwnTableProps[\"bordered\"] }) {\n return (\n

\n \n
\n );\n}\n\ntype TableHeaderProps = React.ComponentProps<\"thead\"> & {\n /** Set sticky header and scroll bar */\n sticky?:\n | boolean\n | {\n offsetHeader?: number;\n offsetScroll?: number;\n getContainer?: () => HTMLElement;\n };\n};\nfunction TableHeader({ className, sticky, ...props }: TableHeaderProps) {\n return (\n \n );\n}\n\ntype TableBodyProps = React.ComponentProps<\"tbody\">;\nfunction TableBody({ className, ...props }: TableBodyProps) {\n return (\n td]:border-b-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction TableFooter({ className, ...props }: React.ComponentProps<\"tfoot\">) {\n return (\n td]:border-b-0\",\n // \"bg-muted/50 border-t font-medium [&>tr]:last:border-b-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\ntype TableRowProps = React.ComponentProps<\"tr\">;\nfunction TableRow({ className, ...props }: TableRowProps) {\n return (\n \n );\n}\n\ntype TableWrapperHeaderProps = React.ComponentProps<\"div\"> & {\n bordered?: OwnTableProps[\"bordered\"];\n size?: SizeType;\n};\nconst TableWrapperHeader = ({\n className,\n bordered,\n size,\n ...props\n}: TableWrapperHeaderProps) => {\n return (\n \n );\n};\n\ntype TableWrapperFooterProps = React.ComponentProps<\"div\"> & {\n bordered?: OwnTableProps[\"bordered\"];\n size?: SizeType;\n};\nconst TableWrapperFooter = ({\n className,\n bordered,\n size,\n ...props\n}: TableWrapperFooterProps) => {\n return (\n \n );\n};\n\ntype TableHeadProps = React.ComponentProps<\"th\"> & {\n size?: SizeType;\n};\nfunction TableHead({ className, size, ...props }: TableHeadProps) {\n return (\n \n );\n}\n\ntype TableCellProps = React.ComponentProps<\"td\"> & {\n size?: SizeType;\n};\nfunction TableCell({ className, size, ...props }: TableCellProps) {\n return (\n \n );\n}\n\nexport type { TableHeaderProps, TableBodyProps, TableRowProps, TableHeadProps };\n\nexport {\n TableWrapperHeader,\n TableWrapperFooter,\n TableRoot,\n TableHeader,\n TableBody,\n TableFooter,\n TableHead,\n TableRow,\n TableCell,\n};\n\nexport { TableCaption } from \"../../../shadcn/table\";\n", "type": "registry:file", "target": "components/table/_components/base.tsx" }, { "path": "components/table/_components/col-group.tsx", "content": "// Jun 6, 2024\n\nimport type { AnyObject } from \"../../_util/type\";\nimport type { ColumnType } from \"../types\";\nimport { useTableStore } from \"../hooks/use-table\";\n\ninterface ColGroupProps {\n colWidths: readonly (number | string | undefined)[];\n columns?: readonly ColumnType[];\n columCount?: number;\n}\nconst ColGroup = ({\n colWidths,\n columns,\n columCount,\n}: ColGroupProps) => {\n const { tableLayout } = useTableStore((s) => s);\n\n const cols: React.ReactElement[] = [];\n const len = columCount ?? columns?.length ?? 0;\n\n // Only insert col with width & additional props\n // Skip if rest col do not have any useful info\n let mustInsert = false;\n for (let i = len - 1; i >= 0; i -= 1) {\n const width = colWidths[i];\n const column = columns?.[i];\n // let additionalProps;\n let minWidth: number | undefined;\n if (column) {\n // additionalProps = column[INTERNAL_COL_DEFINE];\n\n // fixed will cause layout problems\n if (tableLayout === \"auto\") {\n minWidth = column.minWidth;\n }\n }\n\n if (\n width ||\n minWidth ||\n // additionalProps ||\n mustInsert\n ) {\n // const { columnType, ...restAdditionalProps } = additionalProps || {};\n cols.unshift(\n ,\n );\n mustInsert = true;\n }\n }\n\n return {cols};\n};\n\nexport type { ColGroupProps };\nexport { ColGroup };\n", "type": "registry:file", "target": "components/table/_components/col-group.tsx" }, { "path": "components/table/_components/table-head-advanced.tsx", "content": "\"use client\";\n\nimport type { Column } from \"@tanstack/react-table\";\n\nimport type { TableLocale } from \"../types\";\nimport type { TableHeadProps } from \"./base\";\nimport { Icon } from \"../../../icons\";\nimport { cn } from \"../../../lib/utils\";\nimport { Tooltip } from \"../../tooltip\";\nimport { TableHead } from \"./base\";\n\ninterface TableHeadAdvancedProps extends TableHeadProps {\n column: Column;\n locale: TableLocale;\n}\n\nexport function TableHeadAdvanced({\n column,\n children,\n\n align,\n size,\n className,\n\n locale,\n\n onClick: originOnClick,\n ...props\n}: TableHeadAdvancedProps) {\n if (!column.getCanSort()) {\n return (\n \n {children}\n \n );\n }\n // const originOnClick = cell.onClick;\n\n const onClick = (event: React.MouseEvent) => {\n column.columnDef.meta?.onHeaderCell?.(column.columnDef.meta);\n originOnClick?.(event);\n };\n\n const nextSortOrder = column.getNextSortingOrder();\n const ariaLabel = column.getIsSorted()\n ? `Sorted ${column.getIsSorted() === \"asc\" ? \"ascending\" : \"descending\"}. Click to ${\n nextSortOrder === \"asc\"\n ? \"sort ascending\"\n : nextSortOrder === \"desc\"\n ? \"sort descending\"\n : \"cancel sort\"\n }.`\n : `Not sorted. Click to sort ${nextSortOrder === \"asc\" ? \"ascending\" : \"descending\"}.`;\n\n return (\n \n \n \n {align === \"center\" && }\n {children}\n {column.getCanSort() && column.getIsSorted() === \"desc\" ? (\n \n ) : column.getIsSorted() === \"asc\" ? (\n \n ) : (\n \n )}\n \n \n \n );\n}\n", "type": "registry:file", "target": "components/table/_components/table-head-advanced.tsx" }, { "path": "components/table/_components/index.tsx", "content": "export * from \"./base\";\nexport * from \"./view-options\";\nexport * from \"./table-summary\";\nexport * from \"./table-summary-row\";\nexport * from \"./table-summary-cell\";\nexport * from \"./table-toolbar-root\";\nexport * from \"./table-toolbar-left\";\nexport * from \"./table-toolbar-right\";\nexport * from \"./table-sortable-row\";\n", "type": "registry:file", "target": "components/table/_components/index.tsx" }, { "path": "components/table/_components/view-options.tsx", "content": "// https://github.com/sadmann7/shadcn-table/blob/main/src/components/data-table/data-table-view-options.tsx\n// Nov 14, 2024\n\"use client\";\n\nimport type { Table } from \"@tanstack/react-table\";\nimport React from \"react\";\n\nimport { Button } from \"@acme/ui/components/button\";\nimport { Icon } from \"@acme/ui/icons\";\nimport { cn } from \"@acme/ui/lib/utils\";\n\nimport type { PopoverProps } from \"../../popover\";\nimport { Command } from \"../../command\";\nimport { PopoverContent, PopoverTrigger } from \"../../popover\";\nimport { Popover } from \"../../popover/_component\";\n\ntype TableViewOptionsProps = PopoverProps & {\n table: Table;\n};\n\nexport function TableViewOptions({\n table,\n className,\n}: TableViewOptionsProps) {\n const triggerRef = React.useRef(null);\n\n return (\n \n \n \n triggerRef.current?.focus()}\n >\n \n column.accessorFn !== undefined && column.getCanHide(),\n )\n .map((column) => ({\n label: column.columnDef.meta?.title\n ? typeof column.columnDef.meta.title === \"function\"\n ? column.columnDef.meta.title({ table })\n : column.columnDef.meta.title\n : column.id,\n value: column.id,\n checked: column.getIsVisible(),\n className: \"truncate\",\n onSelect: () => column.toggleVisibility(!column.getIsVisible()),\n }))}\n />\n \n \n );\n}\n", "type": "registry:file", "target": "components/table/_components/view-options.tsx" }, { "path": "components/table/_components/table-summary.tsx", "content": "import type React from \"react\";\n\nexport interface SummaryProps {\n fixed?: boolean | \"top\" | \"bottom\";\n children?: React.ReactNode;\n}\n\n/**\n * Syntactic sugar. Do not support HOC.\n */\nexport function TableSummary({ children }: SummaryProps) {\n return children as React.ReactElement;\n}\n", "type": "registry:file", "target": "components/table/_components/table-summary.tsx" }, { "path": "components/table/_components/table-summary-row.tsx", "content": "import { TableRow } from \".\";\n\ntype SummaryRowProps = {\n children?: React.ReactNode;\n};\nexport const TableSummaryRow = ({ children }: SummaryRowProps) => {\n return {children};\n};\n", "type": "registry:file", "target": "components/table/_components/table-summary-row.tsx" }, { "path": "components/table/_components/table-summary-cell.tsx", "content": "import type React from \"react\";\n\nimport { TableCell } from \".\";\n\n// import { getCellFixedInfo } from \"../utils/fixUtil\";\n// import SummaryContext from \"./table-summary-context\";\n\ntype SummaryCellProps = {\n index: number;\n children?: React.ReactNode;\n colSpan?: number;\n rowSpan?: number;\n className?: string;\n};\nexport const TableSummaryCell = ({\n // index,\n children,\n colSpan = 1,\n rowSpan,\n className,\n}: SummaryCellProps) => {\n // const { scrollColumnIndex, stickyOffsets, flattenColumns } =\n // React.useContext(SummaryContext);\n // const lastIndex = index + colSpan - 1;\n // const mergedColSpan =\n // lastIndex + 1 === scrollColumnIndex ? colSpan + 1 : colSpan;\n\n // const direction = \"rtl\";\n // const fixedInfo = getCellFixedInfo(\n // index,\n // index + mergedColSpan - 1,\n // flattenColumns,\n // stickyOffsets,\n // direction,\n // );\n\n return (\n \n {children}\n \n );\n};\n", "type": "registry:file", "target": "components/table/_components/table-summary-cell.tsx" }, { "path": "components/table/_components/table-toolbar-root.tsx", "content": "import { cn } from \"@acme/ui/lib/utils\";\n\ntype TableToolbarRootProps = React.DetailedHTMLProps<\n React.HTMLAttributes,\n HTMLDivElement\n>;\nexport const TableToolbarRoot = ({\n className,\n ...props\n}: TableToolbarRootProps) => {\n return (\n \n );\n};\n", "type": "registry:file", "target": "components/table/_components/table-toolbar-root.tsx" }, { "path": "components/table/_components/table-toolbar-left.tsx", "content": "import { cn } from \"@acme/ui/lib/utils\";\n\ntype TableToolbarLeftProps = React.DetailedHTMLProps<\n React.HTMLAttributes,\n HTMLDivElement\n>;\nexport const TableToolbarLeft = ({\n className,\n ...props\n}: TableToolbarLeftProps) => {\n return (\n \n );\n};\n", "type": "registry:file", "target": "components/table/_components/table-toolbar-left.tsx" }, { "path": "components/table/_components/table-toolbar-right.tsx", "content": "import { cn } from \"@acme/ui/lib/utils\";\n\ntype TableToolbarRightProps = React.DetailedHTMLProps<\n React.HTMLAttributes,\n HTMLDivElement\n>;\nexport const TableToolbarRight = ({\n className,\n ...props\n}: TableToolbarRightProps) => {\n return (\n
\n );\n};\n", "type": "registry:file", "target": "components/table/_components/table-toolbar-right.tsx" }, { "path": "components/table/_components/table-sortable-row.tsx", "content": "\"use client\";\n\nimport type { SyntheticListenerMap } from \"@dnd-kit/core/dist/hooks/utilities\";\nimport React, { useContext, useMemo } from \"react\";\nimport { useSortable } from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\n\nimport type { ButtonProps } from \"@acme/ui/components/button\";\nimport { Button } from \"@acme/ui/components/button\";\nimport { Icon } from \"@acme/ui/icons\";\n\nimport { TableRow } from \".\";\n\ninterface RowContextProps {\n setActivatorNodeRef?: (element: HTMLElement | null) => void;\n listeners?: SyntheticListenerMap;\n}\n\nconst RowContext = React.createContext({});\ntype DragHandleProps = ButtonProps & {\n readOnly?: boolean;\n};\nconst DragHandle = ({ readOnly, ...props }: DragHandleProps) => {\n const { setActivatorNodeRef, listeners } = useContext(RowContext);\n return (\n }\n {...(readOnly ? {} : listeners)}\n ref={readOnly ? undefined : setActivatorNodeRef}\n {...props}\n />\n );\n};\n\ninterface TableRowSortableProps extends React.HTMLAttributes {\n \"data-row-key\": string;\n asHandle?: boolean;\n}\nconst TableSortableRow: React.FC = ({\n asHandle = true,\n ...props\n}) => {\n const {\n attributes,\n listeners,\n setNodeRef,\n setActivatorNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id: props[\"data-row-key\"] });\n\n const style: React.CSSProperties = {\n ...props.style,\n transform: CSS.Translate.toString(transform),\n transition,\n ...(asHandle\n ? {\n cursor: \"move\",\n userSelect: \"none\",\n WebkitUserSelect: \"none\",\n }\n : { cursor: \"auto\" }),\n ...(isDragging ? { position: \"relative\", zIndex: 9999 } : {}),\n };\n\n const contextValue = useMemo(\n () => ({ setActivatorNodeRef, listeners }),\n [setActivatorNodeRef, listeners],\n );\n\n return (\n \n \n \n );\n};\n\nexport { TableSortableRow as TableRowSortable, DragHandle };\n", "type": "registry:file", "target": "components/table/_components/table-sortable-row.tsx" }, { "path": "components/command/index.ts", "content": "export * from \"./command\";\nexport * from \"./_components\";\n", "type": "registry:file", "target": "components/command/index.ts" }, { "path": "components/command/command.tsx", "content": "import type { XOR } from \"ts-xor\";\nimport { useMergedState } from \"@rc-component/util\";\n\nimport { tagColors } from \"@acme/ui/components/tag\";\nimport { cn } from \"@acme/ui/lib/utils\";\n\nimport type { OptionType } from \"../select/types\";\nimport type { CommandRootProps as CommandRootProperties } from \"./_components\";\nimport { Icon } from \"../../icons\";\nimport {\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList,\n CommandRoot,\n} from \"./_components\";\nimport { defaultEmpty, defaultPlaceholder } from \"./config\";\n\ntype ShadcnCommandProperties = React.ComponentProps;\n\ntype CommandValueType = string | number;\n\ntype CommandSingleValue = {\n mode?: \"default\";\n value?: TValue;\n defaultValue?: TValue;\n onChange?: (value?: TValue, option?: OptionType) => void;\n};\ntype CommandMultipleValue = {\n mode: \"multiple\" | \"tags\";\n value?: TValue[];\n defaultValue?: TValue[];\n onChange?: (value: TValue[], options?: OptionType[]) => void;\n};\n\nexport type OwnCommandProps = Omit<\n CommandRootProperties,\n \"defaultValue\" | \"value\" | \"onChange\"\n> &\n (CommandSingleValue | CommandMultipleValue) & {\n options: OptionType[];\n\n empty?: React.ReactNode;\n placeholder?: string;\n\n onSearchChange?: (search: string) => void;\n /**\n * Control the search input value programmatically.\n * Useful when you want to render your own external input but still leverage cmdk filtering.\n */\n searchValue?: string;\n /**\n * Hide the internal CommandInput UI while keeping it in the DOM to drive filtering.\n */\n hideSearchInput?: boolean;\n\n groupClassName?: string;\n optionRender?: {\n checked?: boolean;\n icon?: (option: OptionType) => React.ReactNode;\n label?: (option: OptionType) => React.ReactNode;\n };\n optionsRender?: (options: OptionType[]) => React.ReactNode;\n\n dropdownRender?: (originalNode: React.ReactNode) => React.ReactNode;\n dropdownFooter?: React.ReactNode;\n };\n\ntype CommandProperties = XOR<\n OwnCommandProps,\n ShadcnCommandProperties\n>;\n\nconst Command = (\n properties: CommandProperties,\n) => {\n const [value, setValue] = useMergedState(properties.defaultValue, {\n value: properties.value,\n onChange: (value) => {\n if ((mode === undefined || mode === \"default\") && !Array.isArray(value)) {\n const option = options.find((o) => o.value === value);\n onChange?.(option?.value, option);\n return;\n } else if (mode === \"multiple\" && Array.isArray(value)) {\n onChange?.(\n value,\n options.filter((o) => value.includes(o.value)),\n );\n return;\n }\n },\n });\n\n const isShadcnCommand = !properties.options;\n if (isShadcnCommand) {\n return (\n \n );\n }\n const {\n mode,\n options,\n defaultValue: _defaultValue,\n value: _value,\n empty,\n placeholder,\n onSearchChange,\n searchValue,\n hideSearchInput,\n\n groupClassName,\n optionRender,\n optionsRender,\n dropdownRender,\n onChange,\n\n filter,\n\n dropdownFooter,\n } = properties;\n // ======================= TAGS/MULTIPLE MODE =======================\n // const isDefault = !mode || mode === \"default\";\n // const isTags = mode === \"tags\";\n // const isMultiple = mode === \"multiple\" || isTags;\n\n const panel = (\n \n {empty ?? defaultEmpty}\n \n {/* to allow user set value that not in options - update 20250224 should not show - same antd */}\n {/* {!Array.isArray(value) &&\n !!value &&\n !options.some((o) => o.value === value) &&\n value !== \"\" && (\n \n {value}\n \n )} */}\n {options.length > 0 ? (\n optionsRender ? (\n optionsRender(options)\n ) : (\n options.map((o) => (\n {\n if (mode === \"multiple\" && Array.isArray(value)) {\n if (value.includes(o.value)) {\n setValue(value.filter((x) => x !== o.value));\n } else {\n setValue([...value, o.value]);\n }\n } else {\n setValue(o.value);\n }\n o.onSelect?.();\n }}\n checked={\n o.checked ??\n (Array.isArray(value)\n ? value.includes(o.value)\n : value === o.value)\n }\n className={cn(\n o.color ? tagColors[o.color] : \"\",\n o.color ? \"hover:bg-current/10\" : \"\",\n o.className,\n )}\n >\n {optionRender?.icon ? (\n {optionRender.icon(o)}\n ) : (\n o.icon && \n )}\n {optionRender?.label ? optionRender.label(o) : o.label}\n \n ))\n )\n ) : (\n <>{/* {empty ?? defaultEmpty} */}\n )}\n \n \n );\n\n const PanelComp = dropdownRender ? dropdownRender(panel) : panel;\n\n return (\n \n {/* When hidden, wrap the whole input chrome (search icon + border) in\n sr-only so the row disappears but the input stays mounted to drive\n filtering. Applying sr-only to CommandInput's className only hides the\n inner , leaving the icon/border row visible. */}\n {hideSearchInput ? (\n
\n \n
\n ) : (\n \n )}\n {PanelComp}\n {dropdownFooter && (\n
\n {dropdownFooter}\n
\n )}\n
\n );\n};\n\nexport type { CommandProperties as CommandProps };\n\nexport { Command };\n", "type": "registry:file", "target": "components/command/command.tsx" }, { "path": "components/command/_components.tsx", "content": "\"use client\";\n\nimport type * as React from \"react\";\n\nimport type { Command as CommandRoot } from \"@acme/ui/shadcn/command\";\nimport { cn } from \"@acme/ui/lib/utils\";\nimport { CommandItem as ShadcnCommandItem } from \"@acme/ui/shadcn/command\";\n\nimport { Icon } from \"../../icons\";\n\ntype CommandRootProperties = React.ComponentProps;\n\n// Local wrapper to support a `checked` prop for items\ntype WrappedCommandItemProperties = React.ComponentProps<\n typeof ShadcnCommandItem\n> & {\n checked?: boolean;\n};\n\nfunction CommandItem({\n className,\n children,\n checked,\n ...properties\n}: WrappedCommandItemProperties) {\n return (\n \n {children}\n \n \n );\n}\n\nexport type { CommandRootProperties as CommandRootProps };\nexport { CommandItem };\n\nexport {\n Command as CommandRoot,\n CommandDialog,\n CommandInput,\n CommandList,\n CommandEmpty,\n CommandGroup,\n CommandSeparator,\n CommandShortcut,\n} from \"@acme/ui/shadcn/command\";\n", "type": "registry:file", "target": "components/command/_components.tsx" }, { "path": "components/command/config.ts", "content": "export const defaultPlaceholder = \"Search...\";\nexport const defaultEmpty = \"No data\";\n", "type": "registry:file", "target": "components/command/config.ts" }, { "path": "components/popover/index.tsx", "content": "export * from \"./popover\";\nexport {\n PopoverAnchor,\n PopoverClose,\n PopoverContent,\n PopoverDescription,\n PopoverHeader,\n PopoverTitle,\n PopoverTrigger,\n} from \"./_component\";\nexport type { PopoverContentProps } from \"./_component\";\n", "type": "registry:file", "target": "components/popover/index.tsx" }, { "path": "components/popover/popover.tsx", "content": "import React from \"react\";\nimport { useMergedState } from \"@rc-component/util\";\nimport { useDebounce } from \"ahooks\";\nimport { Popover as PopoverPrimitive } from \"radix-ui\";\n\nimport { cn } from \"@acme/ui/lib/utils\";\n\nimport type { AlignType } from \"../../types\";\nimport type { AbstractTooltipProps } from \"../tooltip\";\nimport type { PopoverContentProps, PopoverRootProps } from \"./_component\";\nimport {\n PopoverAnchor,\n Popover as InternalPopover,\n PopoverContent,\n PopoverDescription,\n PopoverHeader,\n PopoverTitle,\n PopoverTrigger,\n} from \"./_component\";\n\nexport type PopoverProps = AbstractTooltipProps &\n PopoverRootProps &\n Omit & {\n trigger?: \"click\" | \"hover\" | \"focus\";\n content?: React.ReactNode;\n\n align?: AlignType;\n title?: React.ReactNode;\n description?: React.ReactNode;\n\n arrow?: boolean;\n };\nexport const Popover = (props: PopoverProps) => {\n const [open, setOpen] = useMergedState(false, {\n value: props.open,\n onChange: (value) => props.onOpenChange?.(value),\n });\n const debouncedOpen = useDebounce(open, {\n wait: 100,\n });\n\n const isShadcnPopover = React.Children.toArray(props.children).some(\n (child) =>\n React.isValidElement(child) &&\n (child.type === PopoverContent || child.type === PopoverTrigger),\n );\n\n if (isShadcnPopover) {\n return ;\n }\n\n const {\n children,\n trigger = \"hover\",\n content,\n title,\n description,\n open: _open,\n onOpenChange: _onOpenChange,\n\n align: domAlign,\n placement,\n className,\n arrow = true,\n ...restProps\n } = props;\n\n let side: \"top\" | \"right\" | \"bottom\" | \"left\" = \"bottom\";\n if (placement?.includes(\"top\")) {\n side = \"top\";\n } else if (placement?.includes(\"right\")) {\n side = \"right\";\n } else if (placement?.includes(\"left\")) {\n side = \"left\";\n }\n\n let align: \"start\" | \"center\" | \"end\" = \"center\";\n if (placement?.includes(\"Top\")) {\n align = \"start\";\n } else if (placement?.includes(\"Left\")) {\n align = \"start\";\n } else if (placement?.includes(\"Right\")) {\n align = \"end\";\n }\n\n const alignOffset = domAlign?.offset?.[0];\n const sideOffset = domAlign?.offset?.[1];\n\n // In \"focus\" mode use an Anchor instead of a Trigger: the Anchor only\n // positions the panel and never toggles `open` on click. Opening is driven by\n // focus (below) and closing by the consumer (outside/escape/selection). This\n // avoids the click-toggle fighting a consumer-driven focus-open, which causes\n // the panel to flicker open/closed on the first focus.\n const TriggerComp = trigger === \"focus\" ? PopoverAnchor : PopoverTrigger;\n\n return (\n \n {\n if (!open) setOpen(true);\n },\n onMouseLeave: () => {\n if (open) setOpen(false);\n },\n }\n : {})}\n {...(trigger === \"focus\"\n ? {\n onFocus: () => {\n if (!open) setOpen(true);\n },\n }\n : {})}\n >\n {children}\n \n\n {\n if (!open) setOpen(true);\n },\n onMouseLeave: () => {\n if (open) setOpen(false);\n },\n }\n : {})}\n {...restProps}\n >\n {arrow && }\n {(title || description) && (\n \n {title && {title}}\n {description && (\n {description}\n )}\n \n )}\n {content}\n \n \n );\n};\n\nexport { PopoverHeader, PopoverTitle, PopoverDescription } from \"./_component\";\n", "type": "registry:file", "target": "components/popover/popover.tsx" }, { "path": "components/popover/_component.tsx", "content": "import { Popover as PopoverPrimitive } from \"radix-ui\";\n\nimport type {\n Popover as ShadcnPopover,\n PopoverContent as ShadcnPopoverContent,\n} from \"@acme/ui/shadcn/popover\";\nimport { cn } from \"@acme/ui/lib/utils\";\n\ntype PopoverRootProps = React.ComponentProps;\n\ntype PopoverContentProps = React.ComponentProps & {\n container?: HTMLElement | null;\n};\nconst PopoverContent = ({\n container,\n\n style,\n className,\n align = \"center\",\n sideOffset = 4,\n\n onFocusOutside,\n onWheel,\n onTouchMove,\n forceMount,\n ...props\n}: PopoverContentProps) => {\n return (\n \n while\n // a modal layer (e.g. a vaul Drawer / Radix Dialog) has locked the\n // page with `body { pointer-events: none }`, pointer-events would\n // otherwise be inherited as `none` and the popover becomes\n // click-through (clicks fall to the layer behind, dismissing it).\n // Forcing `auto` here keeps the popover interactive in that case and\n // is a no-op when the body is not locked.\n // `select-text`: guarantee the popover text stays selectable/copyable\n // inside modal contexts that otherwise disable selection.\n \"pointer-events-auto select-text\",\n \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden max-sm:p-2\",\n className,\n )}\n // prevent close panel if open any modal\n onFocusOutside={(e) => {\n e.preventDefault();\n e.stopPropagation();\n onFocusOutside?.(e);\n }}\n // Fix scrollable https://github.com/shadcn-ui/ui/issues/542#issuecomment-3077844347\n onWheel={(e) => {\n e.stopPropagation();\n onWheel?.(e);\n }}\n onTouchMove={(e) => {\n e.stopPropagation();\n onTouchMove?.(e);\n }}\n {...props}\n />\n \n );\n};\n\nconst PopoverClose = PopoverPrimitive.Close;\n\nexport type { PopoverRootProps, PopoverContentProps };\nexport {\n Popover,\n PopoverTrigger,\n PopoverAnchor,\n PopoverHeader,\n PopoverTitle,\n PopoverDescription,\n} from \"@acme/ui/shadcn/popover\";\nexport { PopoverContent, PopoverClose };\n", "type": "registry:file", "target": "components/popover/_component.tsx" }, { "path": "components/select/types.ts", "content": "import type { AnyObject } from \"../_util/type\";\n\nexport type OptionType<\n TValue extends SelectValueType = SelectValueType,\n TRecord extends AnyObject = AnyObject,\n> = {\n label?: React.ReactNode;\n value: TValue;\n icon?: string;\n color?: string;\n checked?: boolean;\n className?: string;\n onSelect?: () => void;\n} & TRecord;\n\nexport type GroupOptionType =\n {\n label: React.ReactNode;\n title?: string;\n options: OptionType[];\n };\n\n/** A single option or a group of options */\nexport type SelectOption<\n TValue extends SelectValueType = SelectValueType,\n TRecord extends AnyObject = AnyObject,\n> = OptionType | GroupOptionType;\n\nexport type SelectValueType = string | number;\n\nexport interface FlattenOptionData {\n label?: React.ReactNode;\n data: TOption;\n key: React.Key;\n value?: SelectValueType;\n groupOption?: boolean;\n group?: boolean;\n}\n\nexport type RenderNode =\n | React.ReactNode\n | ((properties?: Record) => React.ReactNode);\n", "type": "registry:file", "target": "components/select/types.ts" }, { "path": "shadcn/command.tsx", "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Command as CommandPrimitive } from \"cmdk\"\nimport { SearchIcon } from \"lucide-react\"\n\nimport { cn } from \"@acme/ui/lib/utils\"\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from \"@acme/ui/shadcn/dialog\"\n\nfunction Command({\n className,\n ...props\n}: React.ComponentProps) {\n return (\n \n )\n}\n\nfunction CommandDialog({\n title = \"Command Palette\",\n description = \"Search for a command to run...\",\n children,\n className,\n showCloseButton = true,\n ...props\n}: React.ComponentProps & {\n title?: string\n description?: string\n className?: string\n showCloseButton?: boolean\n}) {\n return (\n \n \n {title}\n {description}\n \n \n \n {children}\n \n \n \n )\n}\n\nfunction CommandInput({\n className,\n ...props\n}: React.ComponentProps) {\n return (\n \n \n \n
\n )\n}\n\nfunction CommandList({\n className,\n ...props\n}: React.ComponentProps) {\n return (\n \n )\n}\n\nfunction CommandEmpty({\n ...props\n}: React.ComponentProps) {\n return (\n \n )\n}\n\nfunction CommandGroup({\n className,\n ...props\n}: React.ComponentProps) {\n return (\n \n )\n}\n\nfunction CommandSeparator({\n className,\n ...props\n}: React.ComponentProps) {\n return (\n \n )\n}\n\nfunction CommandItem({\n className,\n ...props\n}: React.ComponentProps) {\n return (\n \n )\n}\n\nfunction CommandShortcut({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n \n )\n}\n\nexport {\n Command,\n CommandDialog,\n CommandInput,\n CommandList,\n CommandEmpty,\n CommandGroup,\n CommandItem,\n CommandShortcut,\n CommandSeparator,\n}\n", "type": "registry:file", "target": "shadcn/command.tsx" }, { "path": "shadcn/popover.tsx", "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Popover as PopoverPrimitive } from \"radix-ui\"\n\nimport { cn } from \"@acme/ui/lib/utils\"\n\nfunction Popover({\n ...props\n}: React.ComponentProps) {\n return \n}\n\nfunction PopoverTrigger({\n ...props\n}: React.ComponentProps) {\n return \n}\n\nfunction PopoverContent({\n className,\n align = \"center\",\n sideOffset = 4,\n ...props\n}: React.ComponentProps) {\n return (\n \n \n \n )\n}\n\nfunction PopoverAnchor({\n ...props\n}: React.ComponentProps) {\n return \n}\n\nfunction PopoverHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n \n )\n}\n\nfunction PopoverTitle({ className, ...props }: React.ComponentProps<\"h2\">) {\n return (\n \n )\n}\n\nfunction PopoverDescription({\n className,\n ...props\n}: React.ComponentProps<\"p\">) {\n return (\n \n )\n}\n\nexport {\n Popover,\n PopoverTrigger,\n PopoverContent,\n PopoverAnchor,\n PopoverHeader,\n PopoverTitle,\n PopoverDescription,\n}\n", "type": "registry:file", "target": "shadcn/popover.tsx" }, { "path": "components/table/hooks/use-columns.tsx", "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { ColumnDef as TTColumnDef } from \"@tanstack/react-table\";\nimport React, { useMemo } from \"react\";\nimport toArray from \"@rc-component/util/es/Children/toArray\";\nimport warning from \"@rc-component/util/es/warning\";\n\nimport type { Breakpoint } from \"../../_util/responsive-observer\";\nimport type { AnyObject } from \"../../_util/type\";\nimport type { Direction } from \"../../../types\";\nimport type {\n ColumnGroupType,\n ColumnsType,\n ColumnType,\n ExpandableConfig,\n FixedType,\n GetRowKey,\n Key,\n RenderExpandIcon,\n TriggerEventHandler,\n // Key,\n // RenderExpandIcon,\n} from \"../types\";\nimport useBreakpoint from \"../../grid/hooks/use-breakpoint\";\nimport { EXPAND_COLUMN } from \"../constant\";\nimport { getColumnKey, transformColumnDefs } from \"../util\";\nimport { INTERNAL_COL_DEFINE } from \"../utils/legacy-util\";\n\nexport function convertChildrenToColumns(\n children: React.ReactNode,\n): ColumnsType {\n return toArray(children)\n .filter((node) => React.isValidElement(node))\n .map(({ key, props }: React.ReactElement) => {\n const { children: nodeChildren, ...restProps } = props as any;\n const column = {\n key,\n ...restProps,\n };\n\n if (nodeChildren) {\n column.children = convertChildrenToColumns(nodeChildren);\n }\n\n return column;\n });\n}\n\nfunction filterHiddenColumns(\n columns: ColumnsType,\n): ColumnsType {\n return columns\n .filter((column) => column && typeof column === \"object\" && !column.hidden)\n .map((column) => {\n const subColumns = (column as ColumnGroupType).children;\n\n if (subColumns && subColumns.length > 0) {\n return {\n ...column,\n children: filterHiddenColumns(subColumns),\n };\n }\n\n return column;\n });\n}\n\nfunction flatColumns(\n columns: ColumnsType,\n parentKey = \"key\",\n): {\n flattenColumns: ColumnType[];\n // flattenColumnsForTTTable: TTColumnDef[];\n} {\n const flattenColumns: ColumnType[] = [];\n // const flattenColumnsForTTTable: TTColumnDef[] = [];\n for (const [index, column] of columns.entries()) {\n const { fixed } = column;\n const parsedFixed =\n fixed === true || fixed === \"left\"\n ? \"start\"\n : fixed === \"right\"\n ? \"end\"\n : fixed;\n const mergedKey = `${parentKey}-${index}`;\n\n if (\"children\" in column) {\n flattenColumns.push(\n ...flatColumns(column.children, mergedKey).flattenColumns.map(\n (subColum) => ({\n fixed: parsedFixed,\n ...subColum,\n }),\n ),\n );\n } else {\n flattenColumns.push({\n key: mergedKey,\n ...column,\n fixed: parsedFixed,\n });\n }\n }\n return {\n flattenColumns,\n // flattenColumnsForTTTable\n };\n}\n\n/**\n * Parse `columns` & `children` into `columns`.\n */\nexport const useColumns = (\n {\n columns,\n // rowSelection,\n\n children,\n\n // columnWidth,\n // rowKey,\n // rowSelection: rowSelectionProp,\n // rowSelection,\n childrenColumnName,\n\n expandable,\n expandedKeys,\n expandColumnTitle,\n expandColumnWidth,\n expandIcon,\n expandIconColumnIndex,\n expandedRowOffset = 0,\n expandRowByClick,\n expandedRowRender,\n rowExpandable,\n onTriggerExpand,\n\n direction,\n fixed,\n getRowKey,\n scrollWidth,\n }: {\n columns?: ColumnsType;\n children?: React.ReactNode;\n\n expandable: boolean;\n expandedKeys: Set;\n expandColumnTitle?: React.ReactNode;\n expandColumnWidth?: number | string;\n expandIcon?: RenderExpandIcon;\n expandIconColumnIndex?: number;\n expandRowByClick?: boolean;\n expandedRowRender: ExpandableConfig[\"expandedRowRender\"];\n rowExpandable?: (record: TRecord) => boolean;\n onTriggerExpand: TriggerEventHandler;\n\n direction?: Direction;\n fixed?: FixedType;\n getRowKey: GetRowKey;\n scrollWidth?: number;\n expandedRowOffset?: number;\n\n childrenColumnName?: string;\n },\n transformColumns:\n | null\n | ((columns: ColumnsType) => ColumnsType),\n): [\n columns: ColumnsType,\n columnsForTTTable: TTColumnDef[],\n flattenColumns: readonly ColumnType[],\n] => {\n const baseColumns = React.useMemo>(() => {\n const newColumns = columns || convertChildrenToColumns(children) || [];\n\n return filterHiddenColumns(newColumns.slice());\n }, [columns, children]);\n\n // ========================== Responsive ==========================\n const needResponsive = React.useMemo(\n () => baseColumns.some((col) => col.responsive),\n [baseColumns],\n );\n const screens = useBreakpoint(needResponsive);\n\n const responsiveColumns = React.useMemo(() => {\n const matched = new Set(\n Object.keys(screens).filter((m) => screens[m as Breakpoint]),\n );\n\n return baseColumns.filter(\n (c) => !c.responsive || c.responsive.some((r) => matched.has(r)),\n );\n }, [baseColumns, screens]);\n\n // ========================== Expand ==========================\n const withExpandColumns = React.useMemo>(() => {\n if (expandable) {\n let cloneColumns = responsiveColumns.slice();\n\n // >>> Warning if use `expandIconColumnIndex`\n if (\n process.env.NODE_ENV !== \"production\" &&\n expandIconColumnIndex !== undefined &&\n expandIconColumnIndex >= 0\n ) {\n warning(\n false,\n \"`expandIconColumnIndex` is deprecated. Please use `Table.EXPAND_COLUMN` in `columns` instead.\",\n );\n }\n\n // >>> Insert expand column if not exist\n if (!cloneColumns.includes(EXPAND_COLUMN)) {\n const expandColIndex = expandIconColumnIndex || 0;\n if (\n expandColIndex >= 0 &&\n (expandColIndex || fixed === \"left\" || fixed === \"start\" || !fixed)\n ) {\n cloneColumns.splice(expandColIndex, 0, EXPAND_COLUMN);\n }\n if (fixed === \"right\" || fixed === \"end\") {\n cloneColumns.splice(baseColumns.length, 0, EXPAND_COLUMN);\n }\n }\n\n // >>> Deduplicate additional expand column\n if (\n process.env.NODE_ENV !== \"production\" &&\n cloneColumns.filter((c) => c === EXPAND_COLUMN).length > 1\n ) {\n warning(\n false,\n \"There exist more than one `EXPAND_COLUMN` in `columns`.\",\n );\n }\n const expandColumnIndex = cloneColumns.indexOf(EXPAND_COLUMN);\n cloneColumns = cloneColumns.filter(\n (column, index) =>\n column !== EXPAND_COLUMN || index === expandColumnIndex,\n );\n\n // >>> Check if expand column need to fixed\n const prevColumn = baseColumns[expandColumnIndex];\n\n let fixedColumn: FixedType | null;\n if (fixed) {\n fixedColumn = fixed;\n } else {\n fixedColumn = prevColumn?.fixed ? prevColumn.fixed : null;\n }\n\n // >>> Create expandable column\n const expandColumn: ColumnType & {\n [INTERNAL_COL_DEFINE]: { columnType: \"EXPAND_COLUMN\" };\n } = {\n [INTERNAL_COL_DEFINE]: {\n columnType: \"EXPAND_COLUMN\",\n },\n title: expandColumnTitle,\n fixed: fixedColumn ?? undefined,\n width: expandColumnWidth ?? 50,\n minWidth:\n typeof expandColumnWidth === \"number\" ? expandColumnWidth : 50,\n align: \"center\",\n enableResizing: false,\n render: (_, record, index, { row }) => {\n const rowKey = getRowKey(record, index);\n const expanded = expandedKeys.has(rowKey);\n\n // Check if row can expand using TanStack Table's logic\n const recordExpandable = rowExpandable\n ? rowExpandable(record)\n : row.getCanExpand();\n\n const icon = expandIcon?.({\n expanded,\n expandable: recordExpandable,\n record,\n onExpand: (record, event) => {\n onTriggerExpand(record, event);\n row.getToggleExpandedHandler()();\n },\n });\n\n if (expandRowByClick) {\n return e.stopPropagation()}>{icon};\n }\n return icon;\n },\n };\n\n return cloneColumns.map((col, index) => {\n const column = col === EXPAND_COLUMN ? expandColumn : col;\n if (index < expandedRowOffset) {\n return {\n ...column,\n fixed: column.fixed || \"start\",\n };\n }\n return column;\n });\n }\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n baseColumns.includes(EXPAND_COLUMN)\n ) {\n warning(\n false,\n \"`expandable` is not config but there exist `EXPAND_COLUMN` in `columns`.\",\n );\n }\n\n return baseColumns.filter((col) => col !== EXPAND_COLUMN);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n expandable,\n baseColumns,\n getRowKey,\n expandedKeys,\n expandIcon,\n direction,\n expandedRowOffset,\n\n // expandColumnTitle,\n // expandColumnWidth,\n // expandRowByClick,\n // fixed,\n // mergedChildrenColumnName,\n // onTriggerExpand,\n // rowExpandable,\n // direction,\n ]);\n\n // ========================= Transform ========================\n const mergedColumns = React.useMemo(() => {\n let finalColumns = withExpandColumns;\n if (transformColumns) {\n finalColumns = transformColumns(finalColumns);\n }\n\n // Always provides at least one column for table display\n if (finalColumns.length === 0) {\n finalColumns = [\n {\n render: () => null,\n },\n ];\n }\n\n // Set key for tanstaack table id\n return finalColumns.map((col, colIndex) => {\n return {\n ...col,\n key: getColumnKey(col, colIndex.toString()).toString(),\n };\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [transformColumns, withExpandColumns, direction]);\n\n // ========================== Flatten =========================\n const { flattenColumns } = React.useMemo(\n () => flatColumns(mergedColumns),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [mergedColumns, direction, scrollWidth],\n );\n\n // ========================== For TT Table =========================\n // const columnsForTTTable = transformColumnDefs(mergedColumns, {\n // // rowKey,\n // // rowSelection: rowSelectionProp,\n // expandable: childrenColumnName\n // ? {\n // childrenColumnName,\n // expandIcon,\n // }\n // : undefined,\n // });\n\n const columnsForTTTable = useMemo(() => {\n return transformColumnDefs(mergedColumns, {\n // rowKey,\n // rowSelection: rowSelectionProp,\n expandable: {\n childrenColumnName,\n expandIcon,\n expandedRowRender, // true when there's expandedRowRender (separate expand column)\n },\n });\n }, [childrenColumnName, expandIcon, expandedRowRender, mergedColumns]);\n\n return [mergedColumns, columnsForTTTable, flattenColumns];\n};\n", "type": "registry:file", "target": "components/table/hooks/use-columns.tsx" }, { "path": "components/table/hooks/use-expand.tsx", "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { ExpandedState, OnChangeFn } from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { useMergedState } from \"@rc-component/util\";\nimport warning from \"@rc-component/util/es/warning\";\n\nimport type { AnyObject } from \"../../_util/type\";\nimport type { OwnTableProps } from \"../table\";\nimport type {\n ExpandableConfig,\n ExpandableType,\n GetRowKey,\n Key,\n RenderExpandIcon,\n TriggerEventHandler,\n} from \"../types\";\nimport { INTERNAL_HOOKS } from \"../constant\";\nimport {\n findAllChildrenKeys,\n // mergedExpandedKeysToExpandedState,\n renderExpandIcon,\n} from \"../utils/expand-util\";\n\nexport default function useExpand<\n TRecord extends AnyObject,\n TKey extends Key = Key,\n>(\n props: OwnTableProps,\n mergedData: readonly TRecord[],\n getRowKey: GetRowKey,\n): [\n ExpandedState,\n OnChangeFn,\n\n ExpandableConfig,\n expandableType: ExpandableType,\n expandedKeys: Set,\n expandIcon: RenderExpandIcon,\n childrenColumnName: string,\n onTriggerExpand: TriggerEventHandler,\n] {\n const expandableConfig = props.expandable ?? {};\n\n const {\n expandIcon,\n expandedRowKeys,\n defaultExpandedRowKeys,\n defaultExpandAllRows,\n expandedRowRender,\n onExpand,\n onExpandedRowsChange,\n childrenColumnName,\n } = expandableConfig;\n\n // ========================= Tanstack Table State =========================\n // Convert expandedRowKeys to TanStack Table's ExpandedState format\n const getExpandedStateFromKeys = React.useCallback(\n (keys: readonly Key[] | undefined): ExpandedState => {\n if (!keys || keys.length === 0) {\n return defaultExpandAllRows ? true : {};\n }\n const expandedState: Record = {};\n for (const key of keys) {\n expandedState[key.toString()] = true;\n }\n return expandedState;\n },\n [defaultExpandAllRows],\n );\n\n const [expandedState, setExpandedStateInternal] =\n useMergedState(\n () => getExpandedStateFromKeys(defaultExpandedRowKeys),\n {\n value: expandedRowKeys\n ? getExpandedStateFromKeys(expandedRowKeys)\n : undefined,\n },\n );\n\n // Wrap setExpandedState to also notify parent via onExpandedRowsChange\n const setExpandedState: React.Dispatch> =\n React.useCallback(\n (updaterOrValue) => {\n setExpandedStateInternal((prev) => {\n const newState =\n typeof updaterOrValue === \"function\"\n ? updaterOrValue(prev)\n : updaterOrValue;\n\n // Convert ExpandedState back to key array and notify parent\n if (onExpandedRowsChange && typeof newState === \"object\") {\n const keys = Object.entries(newState)\n .filter(([, isExpanded]) => isExpanded)\n .map(([key]) => key);\n // Use setTimeout to avoid calling during render\n setTimeout(() => onExpandedRowsChange(keys), 0);\n }\n\n return newState;\n });\n },\n [setExpandedStateInternal, onExpandedRowsChange],\n );\n\n const mergedExpandIcon = expandIcon || renderExpandIcon;\n const mergedChildrenColumnName = childrenColumnName || \"children\";\n const hasExpandedRowRender = !!expandedRowRender;\n const defaultExpandedAllKeys = React.useMemo(\n () =>\n defaultExpandAllRows\n ? findAllChildrenKeys(\n mergedData,\n getRowKey,\n mergedChildrenColumnName,\n )\n : [],\n [defaultExpandAllRows, mergedData, getRowKey, mergedChildrenColumnName],\n );\n const expandableType = React.useMemo(() => {\n if (hasExpandedRowRender) {\n return \"row\";\n }\n\n /**\n * Fix https://github.com/ant-design/ant-design/issues/21154\n * This is a workaround to not to break current behavior.\n * We can remove follow code after final release.\n *\n * To other developer:\n * Do not use `__PARENT_RENDER_ICON__` in prod since we will remove this when refactor\n */\n if (\n (props.expandable &&\n props.internalHooks === INTERNAL_HOOKS &&\n (props.expandable as any).__PARENT_RENDER_ICON__) ||\n mergedData.some(\n (record) =>\n record &&\n typeof record === \"object\" &&\n record[mergedChildrenColumnName],\n )\n ) {\n return \"nest\";\n }\n\n return false;\n }, [\n hasExpandedRowRender,\n props.expandable,\n props.internalHooks,\n mergedData,\n mergedChildrenColumnName,\n ]);\n\n const [innerExpandedKeys, setInnerExpandedKeys] = React.useState<\n readonly Key[]\n >(() => defaultExpandedRowKeys ?? []);\n const mergedInnerExpandedKeys = defaultExpandAllRows\n ? defaultExpandedAllKeys\n : innerExpandedKeys;\n const mergedExpandedKeys = React.useMemo>(\n () => new Set(expandedRowKeys || mergedInnerExpandedKeys || []),\n [expandedRowKeys, mergedInnerExpandedKeys],\n );\n\n const onTriggerExpand: TriggerEventHandler = React.useCallback(\n (record: TRecord) => {\n const key = getRowKey(record, mergedData.indexOf(record));\n\n const currentExpandedKeys = [...mergedExpandedKeys];\n const hasKey = mergedExpandedKeys.has(key);\n const newExpandedKeys: Key[] = hasKey\n ? currentExpandedKeys.filter((expandedKey) => expandedKey !== key)\n : [...currentExpandedKeys, key];\n\n setInnerExpandedKeys(newExpandedKeys);\n if (onExpand) {\n onExpand(!hasKey, record);\n }\n if (onExpandedRowsChange) {\n onExpandedRowsChange(newExpandedKeys);\n }\n },\n [getRowKey, mergedExpandedKeys, mergedData, onExpand, onExpandedRowsChange],\n );\n\n // Warning if use `expandedRowRender` and nest children in the same time\n if (\n process.env.NODE_ENV !== \"production\" &&\n expandedRowRender &&\n mergedData.some((record: TRecord) => {\n return Array.isArray(record?.[mergedChildrenColumnName]);\n })\n ) {\n warning(false, \"`expandedRowRender` should not use with nested Table\");\n }\n\n return [\n expandedState,\n setExpandedState,\n\n expandableConfig,\n expandableType,\n mergedExpandedKeys,\n mergedExpandIcon,\n mergedChildrenColumnName,\n onTriggerExpand,\n\n // expanded,\n // setExpanded,\n ];\n}\n", "type": "registry:file", "target": "components/table/hooks/use-expand.tsx" }, { "path": "components/table/hooks/use-filter/index.tsx", "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport React from \"react\";\n\nimport type { AnyObject } from \"../../../_util/type\";\nimport type { SafeKey } from \"../../../tree/types\";\nimport type {\n ColumnsType,\n ColumnTitleProps,\n ColumnType,\n FilterKey,\n FilterValue,\n GetPopupContainer,\n Key,\n TableLocale,\n TransformColumns,\n} from \"../../types\";\nimport { devUseWarning } from \"../../../_util/warning\";\nimport { getColumnKey, getColumnPos, renderColumnTitle } from \"../../util\";\nimport FilterDropdown, { flattenKeys } from \"./filter-dropdown\";\n\nexport interface FilterState {\n column: ColumnType;\n key: Key;\n filteredKeys?: FilterKey;\n forceFiltered?: boolean;\n}\n\nconst collectFilterStates = (\n columns: ColumnsType,\n init: boolean,\n pos?: string,\n): FilterState[] => {\n let filterStates: FilterState[] = [];\n\n (columns || []).forEach((column, index) => {\n const columnPos = getColumnPos(index, pos);\n const filterDropdownIsDefined = column.filterDropdown !== undefined;\n\n if (column.filters || filterDropdownIsDefined || \"onFilter\" in column) {\n if (\"filteredValue\" in column) {\n // Controlled\n let filteredValues = column.filteredValue;\n if (!filterDropdownIsDefined) {\n filteredValues = filteredValues?.map(String) ?? filteredValues;\n }\n filterStates.push({\n column,\n key: getColumnKey(column, columnPos),\n filteredKeys: filteredValues as FilterKey,\n forceFiltered: column.filtered,\n });\n } else {\n // Uncontrolled\n filterStates.push({\n column,\n key: getColumnKey(column, columnPos),\n filteredKeys: (init && column.defaultFilteredValue\n ? column.defaultFilteredValue!\n : undefined) as FilterKey,\n forceFiltered: column.filtered,\n });\n }\n }\n\n if (\"children\" in column) {\n filterStates = [\n ...filterStates,\n ...collectFilterStates(column.children, init, columnPos),\n ];\n }\n });\n\n return filterStates;\n};\n\nfunction injectFilter(\n columns: ColumnsType,\n filterStates: FilterState[],\n locale: TableLocale,\n triggerFilter: (filterState: FilterState) => void,\n getPopupContainer?: GetPopupContainer,\n pos?: string,\n rootClassName?: string,\n): ColumnsType {\n return columns.map((column, index) => {\n const columnPos = getColumnPos(index, pos);\n const {\n filterOnClose = true,\n filterMultiple = true,\n filterMode,\n filterSearch,\n } = column as ColumnType;\n\n let newColumn: ColumnsType[number] = column;\n\n if (newColumn.filters || newColumn.filterDropdown) {\n const columnKey = getColumnKey(newColumn, columnPos);\n const filterState = filterStates.find(({ key }) => columnKey === key);\n\n newColumn = {\n ...newColumn,\n title: (renderProps: ColumnTitleProps) => (\n \n {renderColumnTitle(column.title, renderProps)}\n \n ),\n };\n }\n\n if (\"children\" in newColumn) {\n newColumn = {\n ...newColumn,\n children: injectFilter(\n newColumn.children,\n filterStates,\n locale,\n triggerFilter,\n getPopupContainer,\n columnPos,\n rootClassName,\n ),\n };\n }\n\n return newColumn;\n });\n}\n\nconst generateFilterInfo = (\n filterStates: FilterState[],\n) => {\n const currentFilters: Record = {};\n\n filterStates.forEach(({ key, filteredKeys, column }) => {\n const keyAsString = key as SafeKey;\n const { filters, filterDropdown } = column;\n if (filterDropdown) {\n currentFilters[String(keyAsString)] = filteredKeys ?? null;\n } else if (Array.isArray(filteredKeys)) {\n const keys = flattenKeys(filters);\n currentFilters[String(keyAsString)] = keys.filter((originKey) =>\n filteredKeys.includes(String(originKey)),\n );\n } else {\n currentFilters[String(keyAsString)] = null;\n }\n });\n\n return currentFilters;\n};\n\nexport const getFilterData = (\n data: RecordType[],\n filterStates: FilterState[],\n childrenColumnName: string,\n) => {\n const filterDatas = filterStates.reduce(\n (currentData, filterState) => {\n const {\n column: { onFilter, filters },\n filteredKeys,\n } = filterState;\n if (onFilter && filteredKeys && filteredKeys.length) {\n return (\n currentData\n // shallow copy\n .map((record) => ({ ...record }))\n .filter((record: any) =>\n filteredKeys.some((key) => {\n const keys = flattenKeys(filters);\n const keyIndex = keys.findIndex(\n (k) => String(k) === String(key),\n );\n const realKey = keyIndex !== -1 ? keys[keyIndex]! : key;\n\n // filter children\n if (record[childrenColumnName]) {\n record[childrenColumnName] = getFilterData(\n record[childrenColumnName],\n filterStates,\n childrenColumnName,\n );\n }\n\n return onFilter(realKey, record);\n }),\n )\n );\n }\n return currentData;\n },\n data,\n );\n return filterDatas;\n};\n\nexport interface FilterConfig {\n mergedColumns: ColumnsType;\n locale: TableLocale;\n onFilterChange: (\n filters: Record,\n filterStates: FilterState[],\n ) => void;\n getPopupContainer?: GetPopupContainer;\n rootClassName?: string;\n}\n\nconst getMergedColumns = (\n rawMergedColumns: ColumnsType,\n): ColumnsType =>\n rawMergedColumns.flatMap((column) => {\n if (\"children\" in column) {\n return [column, ...getMergedColumns(column.children || [])];\n }\n return [column];\n });\n\nconst useFilter = (\n props: FilterConfig,\n): [\n TransformColumns,\n FilterState[],\n Record,\n] => {\n const {\n mergedColumns: rawMergedColumns,\n onFilterChange,\n getPopupContainer,\n locale: tableLocale,\n rootClassName,\n } = props;\n const warning = devUseWarning(\"Table\");\n\n const mergedColumns = React.useMemo(\n () => getMergedColumns(rawMergedColumns || []),\n [rawMergedColumns],\n );\n\n const [filterStates, setFilterStates] = React.useState<\n FilterState[]\n >(() => collectFilterStates(mergedColumns, true));\n\n const mergedFilterStates = React.useMemo(() => {\n const collectedStates = collectFilterStates(mergedColumns, false);\n if (collectedStates.length === 0) {\n return collectedStates;\n }\n let filteredKeysIsAllNotControlled = true;\n let filteredKeysIsAllControlled = true;\n for (const { filteredKeys } of collectedStates) {\n if (filteredKeys !== undefined) {\n filteredKeysIsAllNotControlled = false;\n } else {\n filteredKeysIsAllControlled = false;\n }\n }\n\n // Return if not controlled\n if (filteredKeysIsAllNotControlled) {\n // Filter column may have been removed\n const keyList = (mergedColumns || []).map((column, index) =>\n getColumnKey(column, getColumnPos(index)),\n );\n return filterStates\n .filter(({ key }) => keyList.includes(key))\n .map((item) => {\n const col = mergedColumns[keyList.indexOf(item.key)]!;\n return {\n ...item,\n column: {\n ...item.column,\n ...col,\n },\n forceFiltered: col.filtered,\n };\n });\n }\n\n warning(\n filteredKeysIsAllControlled,\n \"usage\",\n \"Columns should all contain `filteredValue` or not contain `filteredValue`.\",\n );\n\n return collectedStates;\n }, [mergedColumns, filterStates, warning]);\n\n const filters = React.useMemo(\n () => generateFilterInfo(mergedFilterStates),\n [mergedFilterStates],\n );\n\n const triggerFilter = (filterState: FilterState) => {\n const newFilterStates = mergedFilterStates.filter(\n ({ key }) => key !== filterState.key,\n );\n newFilterStates.push(filterState);\n setFilterStates(newFilterStates);\n onFilterChange(\n generateFilterInfo(newFilterStates),\n newFilterStates,\n );\n };\n\n const transformColumns = (innerColumns: ColumnsType) =>\n injectFilter(\n innerColumns,\n mergedFilterStates,\n tableLocale,\n triggerFilter,\n getPopupContainer,\n undefined,\n rootClassName,\n );\n\n return [transformColumns, mergedFilterStates, filters] as const;\n};\n\nexport default useFilter;\nexport { flattenKeys } from \"./filter-dropdown\";\n", "type": "registry:file", "target": "components/table/hooks/use-filter/index.tsx" }, { "path": "components/table/hooks/use-filter/filter-dropdown.tsx", "content": "import type * as React from \"react\";\n\nimport type { FilterState } from \".\";\nimport type { AnyObject } from \"../../../_util/type\";\nimport type { FieldDataNode } from \"../../../tree/types\";\nimport type {\n ColumnFilterItem,\n ColumnType,\n FilterSearchType,\n FilterValue,\n GetPopupContainer,\n Key,\n TableLocale,\n} from \"../../types\";\n\ntype FilterTreeDataNode = FieldDataNode<{\n title: React.ReactNode;\n key: string;\n}>;\n\nexport function flattenKeys(filters?: ColumnFilterItem[]) {\n let keys: FilterValue = [];\n (filters || []).forEach(({ value, children }) => {\n keys.push(value);\n if (children) {\n keys = [...keys, ...flattenKeys(children)];\n }\n });\n return keys;\n}\n\nexport type TreeColumnFilterItem = ColumnFilterItem & FilterTreeDataNode;\n\nexport interface FilterDropdownProps {\n column: ColumnType;\n filterState?: FilterState;\n filterOnClose: boolean;\n filterMultiple: boolean;\n filterMode?: \"menu\" | \"tree\";\n filterSearch?: FilterSearchType;\n columnKey: Key;\n children: React.ReactNode;\n triggerFilter: (filterState: FilterState) => void;\n locale: TableLocale;\n getPopupContainer?: GetPopupContainer;\n filterResetToDefaultFilteredValue?: boolean;\n rootClassName?: string;\n}\n\nconst FilterDropdown = (\n _props: FilterDropdownProps,\n) => {\n return <>Filter Dropdown;\n};\n\nexport default FilterDropdown;\n", "type": "registry:file", "target": "components/table/hooks/use-filter/filter-dropdown.tsx" }, { "path": "components/table/hooks/use-lazy-kv-map.ts", "content": "/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */\n\nimport * as React from \"react\";\n\nimport type { AnyObject } from \"../../_util/type\";\nimport type { GetRowKey, Key } from \"../types\";\n\ninterface MapCache {\n data?: readonly RecordType[];\n childrenColumnName?: string;\n kvMap?: Map;\n getRowKey?: (record: RecordType, index: number) => Key;\n}\n\nconst useLazyKVMap = (\n data: readonly RecordType[],\n childrenColumnName: string,\n getRowKey: GetRowKey,\n) => {\n const mapCacheRef = React.useRef>({});\n\n const getRecordByKey = React.useCallback(\n (key: Key): RecordType => {\n if (\n mapCacheRef.current?.data !== data ||\n mapCacheRef.current.childrenColumnName !== childrenColumnName ||\n mapCacheRef.current.getRowKey !== getRowKey\n ) {\n const kvMap = new Map();\n\n function dig(records: readonly RecordType[]) {\n records.forEach((record, index) => {\n const rowKey = getRowKey(record, index);\n kvMap.set(rowKey.toString(), record);\n\n if (\n record &&\n typeof record === \"object\" &&\n childrenColumnName in record\n ) {\n dig(record[childrenColumnName] || []);\n }\n });\n }\n\n dig(data);\n\n mapCacheRef.current = {\n data,\n childrenColumnName,\n kvMap,\n getRowKey,\n };\n }\n\n return mapCacheRef.current.kvMap?.get(key)!;\n },\n [data, childrenColumnName, getRowKey],\n );\n\n return [getRecordByKey] as const;\n};\n\nexport default useLazyKVMap;\n", "type": "registry:file", "target": "components/table/hooks/use-lazy-kv-map.ts" }, { "path": "components/table/hooks/use-pagination.ts", "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */\n/* eslint-disable @typescript-eslint/no-empty-function */\nimport { useState } from \"react\";\n\nimport type { PaginationProps } from \"../../pagination\";\nimport type { TablePaginationConfig } from \"../types\";\nimport extendsObject from \"../../_util/extends-object\";\n\nexport const DEFAULT_PAGE_SIZE = 10;\n\nexport function getPaginationParam(\n mergedPagination: TablePaginationConfig,\n pagination?: TablePaginationConfig | boolean,\n) {\n const param: any = {\n current: mergedPagination.current,\n pageSize: mergedPagination.pageSize,\n };\n\n const paginationObj =\n pagination && typeof pagination === \"object\" ? pagination : {};\n\n Object.keys(paginationObj).forEach((pageProp) => {\n const value = mergedPagination[pageProp as keyof typeof paginationObj];\n\n if (typeof value !== \"function\") {\n param[pageProp] = value;\n }\n });\n\n return param;\n}\n\nfunction usePagination(\n total: number,\n onChange: (current: number, pageSize: number) => void,\n pagination?: TablePaginationConfig | false,\n): readonly [\n TablePaginationConfig,\n (current?: number, pageSize?: number) => void,\n] {\n const { total: paginationTotal = 0, ...paginationObj } =\n pagination && typeof pagination === \"object\" ? pagination : {};\n\n const [innerPagination, setInnerPagination] = useState<{\n current?: number;\n pageSize?: number;\n }>(() => ({\n current:\n \"defaultCurrent\" in paginationObj ? paginationObj.defaultCurrent : 1,\n pageSize:\n \"defaultPageSize\" in paginationObj\n ? paginationObj.defaultPageSize\n : DEFAULT_PAGE_SIZE,\n }));\n\n // ============ Basic Pagination Config ============\n const mergedPagination = extendsObject(innerPagination, paginationObj, {\n total: paginationTotal > 0 ? paginationTotal : total,\n });\n\n // Reset `current` if data length or pageSize changed\n const maxPage = Math.ceil(\n (paginationTotal || total) / mergedPagination.pageSize!,\n );\n if (mergedPagination.current! > maxPage) {\n // Prevent a maximum page count of 0\n mergedPagination.current = maxPage || 1;\n }\n\n const refreshPagination = (current?: number, pageSize?: number) => {\n setInnerPagination({\n current: current ?? 1,\n pageSize: pageSize || mergedPagination.pageSize,\n });\n };\n\n const onInternalChange: PaginationProps[\"onChange\"] = (current, pageSize) => {\n if (pagination) {\n pagination.onChange?.(current, pageSize);\n }\n refreshPagination(current, pageSize);\n onChange(current, pageSize || mergedPagination?.pageSize!);\n };\n\n if (pagination === false) {\n return [{}, () => {}] as const;\n }\n\n return [\n {\n ...mergedPagination,\n onChange: onInternalChange,\n },\n refreshPagination,\n ] as const;\n}\n\nexport default usePagination;\n", "type": "registry:file", "target": "components/table/hooks/use-pagination.ts" }, { "path": "components/table/hooks/use-sorter.tsx", "content": "/* eslint-disable react-hooks/exhaustive-deps */\n\nimport type { OnChangeFn, SortingState } from \"@tanstack/react-table\";\nimport React from \"react\";\nimport KeyCode from \"@rc-component/util/es/KeyCode\";\n\nimport type { AnyObject } from \"../../_util/type\";\nimport type { TooltipProps } from \"../../tooltip\";\nimport type {\n ColumnGroupType,\n ColumnsType,\n ColumnTitleProps,\n ColumnType,\n Key,\n SorterResult,\n SorterTooltipProps,\n SortOrder,\n TableLocale,\n TransformColumns,\n} from \"../types\";\nimport { Icon } from \"../../../icons\";\nimport { cn } from \"../../../lib/utils\";\nimport { Tooltip } from \"../../tooltip\";\nimport {\n getColumnKey,\n getColumnPos,\n renderColumnTitle,\n safeColumnTitle,\n} from \"../util\";\n\nconst ASCEND = \"ascend\";\nconst DESCEND = \"descend\";\n\nconst getMultiplePriority = (\n column: ColumnType,\n): number | false => {\n if (\n typeof column.sorter === \"object\" &&\n typeof column.sorter.multiple === \"number\"\n ) {\n return column.sorter.multiple;\n }\n return false;\n};\n\nconst nextSortDirection = (\n sortDirections: SortOrder[],\n current: SortOrder | null,\n) => {\n if (!current) {\n return sortDirections[0]!;\n }\n return sortDirections[sortDirections.indexOf(current) + 1]!;\n};\n\nexport interface SortState {\n column: ColumnType;\n key: Key;\n sortOrder: SortOrder | null;\n multiplePriority: number | false;\n}\n\nconst collectSortStates = (\n columns: ColumnsType,\n init: boolean,\n pos?: string,\n): SortState[] => {\n let sortStates: SortState[] = [];\n\n const pushState = (\n column: ColumnsType[number],\n columnPos: string,\n ) => {\n sortStates.push({\n column: column as ColumnType,\n key: getColumnKey(\n column as ColumnType,\n columnPos,\n ),\n multiplePriority: getMultiplePriority(\n column as ColumnType,\n ),\n sortOrder: (column as ColumnType).sortOrder!,\n });\n };\n\n for (const [index, column] of (columns || []).entries()) {\n const columnPos = getColumnPos(index, pos);\n if ((column as ColumnGroupType).children) {\n if (\"sortOrder\" in column) {\n // Controlled\n pushState(column, columnPos);\n }\n sortStates = [\n ...sortStates,\n ...collectSortStates(\n (column as ColumnGroupType).children,\n init,\n columnPos,\n ),\n ];\n } else if (column.sorter) {\n if (\"sortOrder\" in column) {\n // Controlled\n pushState(column, columnPos);\n } else if (init && column.defaultSortOrder) {\n // Default sorter\n sortStates.push({\n column,\n key: getColumnKey(column, columnPos),\n multiplePriority: getMultiplePriority(column),\n sortOrder: column.defaultSortOrder,\n });\n }\n }\n }\n\n return sortStates;\n};\n\nconst injectSorter = (\n columns: ColumnsType,\n sorterStates: SortState[],\n triggerSorter: (sorterSates: SortState) => void,\n defaultSortDirections: SortOrder[],\n tableLocale?: TableLocale,\n tableShowSorterTooltip?: boolean | SorterTooltipProps,\n pos?: string,\n): ColumnsType => {\n return (columns || []).map((column, index) => {\n const columnPos = getColumnPos(index, pos);\n let newColumn: ColumnsType[number] = column;\n if (newColumn.sorter) {\n const sortDirections: SortOrder[] =\n newColumn.sortDirections || defaultSortDirections;\n const showSorterTooltip =\n newColumn.showSorterTooltip === undefined\n ? tableShowSorterTooltip\n : newColumn.showSorterTooltip;\n\n const columnKey = getColumnKey(newColumn, columnPos);\n const sorterState = sorterStates.find(({ key }) => key === columnKey);\n const sortOrder = sorterState ? sorterState.sortOrder : null;\n const nextSortOrder = nextSortDirection(sortDirections, sortOrder);\n\n let sorter: React.ReactNode;\n if (column.sortIcon) {\n sorter = column.sortIcon({ sortOrder });\n } else {\n const upNode: React.ReactNode = sortDirections.includes(ASCEND) && (\n \n );\n const downNode: React.ReactNode = sortDirections.includes(DESCEND) && (\n \n );\n sorter = (\n \n \n {upNode}\n {downNode}\n \n \n );\n }\n\n const { cancelSort, triggerAsc, triggerDesc } = tableLocale || {};\n let sortTip: string | undefined = cancelSort;\n if (nextSortOrder === DESCEND) {\n sortTip = triggerDesc;\n } else if (nextSortOrder === ASCEND) {\n sortTip = triggerAsc;\n }\n const tooltipProps: TooltipProps =\n typeof showSorterTooltip === \"object\"\n ? {\n title: sortTip,\n ...showSorterTooltip,\n }\n : { title: sortTip };\n newColumn = {\n ...newColumn,\n className: cn(newColumn.className, { \"column-sort\": sortOrder }),\n title: (renderProps: ColumnTitleProps) => {\n const columnSortersClass = \"column-sorters\";\n const renderColumnTitleWrapper = (\n \n {renderColumnTitle(column.title, renderProps)}\n \n );\n const renderSortTitle = (\n
\n {renderColumnTitleWrapper}\n {sorter}\n
\n );\n if (showSorterTooltip) {\n if (\n typeof showSorterTooltip !== \"boolean\" &&\n showSorterTooltip?.target === \"sorter-icon\"\n ) {\n return (\n \n {renderColumnTitleWrapper}\n {sorter}\n \n );\n }\n return {renderSortTitle};\n }\n return renderSortTitle;\n },\n onHeaderCell: (col) => {\n const cell: React.HTMLAttributes =\n column.onHeaderCell?.(col) || {};\n const originOnClick = cell.onClick;\n const originOKeyDown = cell.onKeyDown;\n cell.onClick = (event: React.MouseEvent) => {\n triggerSorter({\n column,\n key: columnKey,\n sortOrder: nextSortOrder,\n multiplePriority: getMultiplePriority(column),\n });\n originOnClick?.(event);\n };\n cell.onKeyDown = (event: React.KeyboardEvent) => {\n if (event.keyCode === KeyCode.ENTER) {\n triggerSorter({\n column,\n key: columnKey,\n sortOrder: nextSortOrder,\n multiplePriority: getMultiplePriority(column),\n });\n originOKeyDown?.(event);\n }\n };\n\n const renderTitle = safeColumnTitle(column.title, {});\n const displayTitle = renderTitle?.toString();\n\n // Inform the screen-reader so it can tell the visually impaired user which column is sorted\n if (sortOrder) {\n cell[\"aria-sort\"] =\n sortOrder === \"ascend\" ? \"ascending\" : \"descending\";\n }\n cell[\"aria-label\"] = displayTitle || \"\";\n cell.className = cn(cell.className, \"column-has-sorters\");\n cell.tabIndex = 0;\n if (column.ellipsis) {\n cell.title = (renderTitle ?? \"\").toString();\n }\n return cell;\n },\n };\n }\n\n if (\"children\" in newColumn) {\n newColumn = {\n ...newColumn,\n children: injectSorter(\n newColumn.children,\n sorterStates,\n triggerSorter,\n defaultSortDirections,\n tableLocale,\n tableShowSorterTooltip,\n columnPos,\n ),\n };\n }\n\n return newColumn;\n });\n};\n\nconst stateToInfo = (\n sorterState: SortState,\n): SorterResult => {\n const { column, sortOrder } = sorterState;\n return {\n column,\n order: sortOrder,\n field: column.dataIndex as SorterResult[\"field\"],\n columnKey: column.key,\n };\n};\nconst generateSorterInfo = (\n sorterStates: SortState[],\n): SorterResult | SorterResult[] => {\n const activeSorters = sorterStates\n .filter(({ sortOrder }) => sortOrder)\n .map>(stateToInfo);\n\n // =========== Legacy compatible support ===========\n // https://github.com/ant-design/ant-design/pull/19226\n if (activeSorters.length === 0 && sorterStates.length > 0) {\n const lastIndex = sorterStates.length - 1;\n return {\n ...stateToInfo(sorterStates[lastIndex]!),\n column: undefined,\n order: undefined,\n field: undefined,\n columnKey: undefined,\n };\n }\n\n if (activeSorters.length <= 1) {\n return activeSorters[0] || {};\n }\n\n return activeSorters;\n};\n\ninterface SorterConfig {\n mergedColumns: ColumnsType;\n onSorterChange: (\n sorterResult: SorterResult | SorterResult[],\n sortStates: SortState[],\n ) => void;\n sortDirections: SortOrder[];\n tableLocale?: TableLocale;\n showSorterTooltip?: boolean | SorterTooltipProps;\n}\n\nexport const useFilterSorter = (\n props: SorterConfig,\n): [\n SortingState,\n OnChangeFn,\n TransformColumns,\n SortState[],\n ColumnTitleProps,\n () => SorterResult | SorterResult[],\n] => {\n const {\n mergedColumns,\n sortDirections,\n tableLocale,\n showSorterTooltip,\n onSorterChange,\n } = props;\n\n const [sortStates, setSortStates] = React.useState[]>(\n () => collectSortStates(mergedColumns, true),\n );\n\n const sortingState: SortingState = React.useMemo(\n () =>\n sortStates\n .filter((sortState) => sortState.sortOrder)\n .map((sortState) => ({\n id: sortState.key as string,\n desc: sortState.sortOrder === \"descend\",\n })),\n [sortStates],\n );\n\n const handleSortingChange: OnChangeFn = React.useCallback(\n (updaterOrValue) => {\n const newSorting =\n typeof updaterOrValue === \"function\"\n ? updaterOrValue(sortingState)\n : updaterOrValue;\n\n const updatedSortStates: SortState[] = [];\n const sorterResults: SorterResult[] = [];\n\n for (const [_index, sort] of newSorting.entries()) {\n const column = mergedColumns.find((col) => col.key === sort.id);\n if (!column) continue;\n const order = sort.desc ? \"descend\" : \"ascend\";\n const sorterResult: SorterResult = {\n column,\n columnKey: column.key as Key,\n field: (column as ColumnType).dataIndex as Key,\n order,\n };\n\n updatedSortStates.push({\n column,\n key: sort.id,\n sortOrder: order,\n multiplePriority:\n typeof column.sorter === \"object\"\n ? (column.sorter.multiple ?? false)\n : false,\n });\n sorterResults.push(sorterResult);\n }\n\n setSortStates(updatedSortStates);\n\n if (sorterResults.length <= 1) {\n onSorterChange(sorterResults[0]!, updatedSortStates);\n } else {\n onSorterChange(sorterResults, updatedSortStates);\n }\n },\n [mergedColumns, sortingState, onSorterChange],\n );\n\n const triggerSorter = React.useCallback(\n (sortState: SortState) => {\n let newSorterStates: SortState[];\n if (\n sortState.multiplePriority === false ||\n !sortStates.length ||\n sortStates[0]?.multiplePriority === false\n ) {\n newSorterStates = [sortState];\n } else {\n newSorterStates = [\n ...sortStates.filter(({ key }) => key !== sortState.key),\n sortState,\n ];\n }\n setSortStates(newSorterStates);\n onSorterChange(generateSorterInfo(newSorterStates), newSorterStates);\n },\n [sortStates, onSorterChange],\n );\n\n const columnTitleSorterProps = React.useMemo<\n ColumnTitleProps\n >(() => {\n const sortColumns = sortStates.map(({ column, sortOrder }) => ({\n column,\n order: sortOrder,\n }));\n\n return {\n sortColumns,\n // Legacy\n sortColumn: sortColumns[0]?.column,\n sortOrder: sortColumns[0]?.order,\n };\n }, [sortStates]);\n\n const transformColumns = React.useCallback(\n (innerColumns: ColumnsType) =>\n injectSorter(\n innerColumns,\n sortStates,\n triggerSorter,\n sortDirections,\n tableLocale,\n showSorterTooltip,\n ),\n [sortStates, sortDirections, tableLocale, showSorterTooltip],\n );\n\n const getSorters = React.useCallback(\n () => generateSorterInfo(sortStates),\n [sortStates],\n );\n\n return [\n sortingState,\n handleSortingChange,\n transformColumns,\n sortStates,\n columnTitleSorterProps,\n getSorters,\n ];\n};\n\nexport default useFilterSorter;\n", "type": "registry:file", "target": "components/table/hooks/use-sorter.tsx" }, { "path": "components/table/hooks/use-table.tsx", "content": "\"use client\";\n\nimport React from \"react\";\nimport { useStore } from \"zustand\";\nimport { createStore } from \"zustand/vanilla\";\n\nimport type { GetComponent } from \"../types\";\n\ntype TableState = {\n getComponent: GetComponent;\n isSticky: boolean;\n scrollbarSize: number;\n tableLayout?: \"auto\" | \"fixed\";\n};\ntype TableStore = TableState;\n\nconst defaultInitState: TableState = {\n scrollbarSize: 0,\n isSticky: false,\n getComponent: () => () => <>,\n tableLayout: \"auto\",\n};\n\nconst createTableStore = (initState: TableState = defaultInitState) => {\n return createStore()(() => ({\n ...initState,\n }));\n};\n\ntype TableStoreApi = ReturnType;\n\nconst TableStoreContext = React.createContext(\n undefined,\n);\n\ntype TableStoreProviderProps = {\n children: React.ReactNode;\n};\nexport const TableStoreProvider = ({ children }: TableStoreProviderProps) => {\n const [store] = React.useState(() =>\n createTableStore({\n ...defaultInitState,\n }),\n );\n\n return (\n \n {children}\n \n );\n};\n\nexport function useTableStore(): TableStore;\nexport function useTableStore(selector: (store: TableStore) => T): T;\nexport function useTableStore(selector?: (store: TableStore) => T): T {\n const appStoreContext = React.useContext(TableStoreContext);\n\n if (!appStoreContext) {\n throw new Error(`useTableStore must be used within TableStoreProvider`);\n }\n\n return useStore(\n appStoreContext,\n selector ?? ((store: TableStore) => store as T),\n );\n}\n", "type": "registry:file", "target": "components/table/hooks/use-table.tsx" }, { "path": "components/table/utils/expand-util.tsx", "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { GetRowKey, Key, RenderExpandIconProps } from \"../types\";\nimport { Icon } from \"../../../icons\";\nimport { cn } from \"../../../lib/utils\";\n\nexport function renderExpandIcon({\n record,\n onExpand,\n expanded,\n expandable,\n className,\n}: RenderExpandIconProps & {\n className?: string;\n}): React.ReactNode {\n if (!expandable) {\n return ;\n }\n\n const onClick: React.MouseEventHandler = (event) => {\n onExpand(record, event);\n event.stopPropagation();\n };\n\n return (\n \n {expanded ? (\n \n ) : (\n \n )}\n \n );\n\n // return (\n // \n // );\n}\n\nexport function findAllChildrenKeys(\n data: readonly RecordType[],\n getRowKey: GetRowKey,\n childrenColumnName: string,\n): Key[] {\n const keys: Key[] = [];\n\n function dig(list: readonly RecordType[]) {\n for (const [index, item] of (list || []).entries()) {\n keys.push(getRowKey(item, index));\n\n dig((item as any)[childrenColumnName]);\n }\n }\n\n dig(data);\n\n return keys;\n}\n\nexport function expandedStateToExpandedRowKeys(\n expandedState: Record,\n): string[] {\n return Object.keys(expandedState).filter((key) => expandedState[key]);\n}\n\n// export function mergedExpandedKeysToExpandedState(\n// mergedExpandedKeys: Set | readonly Key[],\n// ): Record {\n// const arr = Array.isArray(mergedExpandedKeys)\n// ? mergedExpandedKeys\n// : [...mergedExpandedKeys];\n// const result: Record = {};\n// for (const key of arr) {\n// result[String(key)] = true; // Use String(key) to handle symbol, bigint, etc.\n// }\n// return result;\n// }\n", "type": "registry:file", "target": "components/table/utils/expand-util.tsx" }, { "path": "components/table/utils/legacy-util.ts", "content": "export const INTERNAL_COL_DEFINE = \"RC_TABLE_INTERNAL_COL_DEFINE\";\n", "type": "registry:file", "target": "components/table/utils/legacy-util.ts" } ], "type": "registry:component" }