@lablup/ui-common 0.2.0-alpha.16 → 0.2.0-alpha.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +1 -0
  2. package/astryx/components/Board.doc.mjs +122 -0
  3. package/astryx/components/Board.tsx +3 -0
  4. package/astryx/docs/ui-common.doc.mjs +1 -1
  5. package/dist/assets/components/Board/Board.css +2 -0
  6. package/dist/components/Board/Board.d.ts +102 -0
  7. package/dist/components/Board/Board.messages.d.ts +62 -0
  8. package/dist/components/Board/Board.messages.js +68 -0
  9. package/dist/components/Board/Board.messages.js.map +1 -0
  10. package/dist/components/Board/Board2.js +607 -0
  11. package/dist/components/Board/Board2.js.map +1 -0
  12. package/dist/components/Board/engine.d.ts +60 -0
  13. package/dist/components/Board/engine.js +397 -0
  14. package/dist/components/Board/engine.js.map +1 -0
  15. package/dist/components/Board/index.d.ts +4 -0
  16. package/dist/components/Board/index.js +3 -0
  17. package/dist/components/Board/layout.d.ts +81 -0
  18. package/dist/components/Board/layout.js +67 -0
  19. package/dist/components/Board/layout.js.map +1 -0
  20. package/dist/components/Board/scroll.d.ts +38 -0
  21. package/dist/components/Board/scroll.js +42 -0
  22. package/dist/components/Board/scroll.js.map +1 -0
  23. package/dist/components/DataGrid/DataGrid2.js +128 -128
  24. package/dist/components/DataGrid/DataGrid2.js.map +1 -1
  25. package/dist/components/Form/FormItem.d.ts +1 -1
  26. package/dist/components/Modal/modalStack.d.ts +9 -8
  27. package/dist/components/Modal/modalStack.js +29 -26
  28. package/dist/components/Modal/modalStack.js.map +1 -1
  29. package/dist/components/PageHeader/PageHeader2.js +4 -4
  30. package/dist/components/PagedSelector/PagedSelector2.js +37 -37
  31. package/dist/components/PagedSelector/PagedSelector2.js.map +1 -1
  32. package/dist/components/SelectionLabel/SelectionLabel.js +4 -4
  33. package/dist/forks/Drawer/Drawer.js +71 -53
  34. package/dist/forks/Drawer/Drawer.js.map +1 -1
  35. package/dist/forks/Drawer/useDrawerDialogPresence.d.ts +6 -6
  36. package/dist/forks/Drawer/useDrawerDialogPresence.js +19 -31
  37. package/dist/forks/Drawer/useDrawerDialogPresence.js.map +1 -1
  38. package/dist/i18n/catalog.js +27 -25
  39. package/dist/i18n/catalog.js.map +1 -1
  40. package/dist/i18n/locales/de-DE.js +60 -0
  41. package/dist/i18n/locales/de-DE.js.map +1 -1
  42. package/dist/i18n/locales/el-GR.js +60 -0
  43. package/dist/i18n/locales/el-GR.js.map +1 -1
  44. package/dist/i18n/locales/es-ES.js +60 -0
  45. package/dist/i18n/locales/es-ES.js.map +1 -1
  46. package/dist/i18n/locales/fi-FI.js +60 -0
  47. package/dist/i18n/locales/fi-FI.js.map +1 -1
  48. package/dist/i18n/locales/fr-FR.js +60 -0
  49. package/dist/i18n/locales/fr-FR.js.map +1 -1
  50. package/dist/i18n/locales/id-ID.js +60 -0
  51. package/dist/i18n/locales/id-ID.js.map +1 -1
  52. package/dist/i18n/locales/it-IT.js +60 -0
  53. package/dist/i18n/locales/it-IT.js.map +1 -1
  54. package/dist/i18n/locales/ja-JP.js +60 -0
  55. package/dist/i18n/locales/ja-JP.js.map +1 -1
  56. package/dist/i18n/locales/ko-KR.js +60 -0
  57. package/dist/i18n/locales/ko-KR.js.map +1 -1
  58. package/dist/i18n/locales/mn-MN.js +60 -0
  59. package/dist/i18n/locales/mn-MN.js.map +1 -1
  60. package/dist/i18n/locales/ms-MY.js +60 -0
  61. package/dist/i18n/locales/ms-MY.js.map +1 -1
  62. package/dist/i18n/locales/pl-PL.js +60 -0
  63. package/dist/i18n/locales/pl-PL.js.map +1 -1
  64. package/dist/i18n/locales/pt-BR.js +60 -0
  65. package/dist/i18n/locales/pt-BR.js.map +1 -1
  66. package/dist/i18n/locales/pt-PT.js +60 -0
  67. package/dist/i18n/locales/pt-PT.js.map +1 -1
  68. package/dist/i18n/locales/ru-RU.js +60 -0
  69. package/dist/i18n/locales/ru-RU.js.map +1 -1
  70. package/dist/i18n/locales/th-TH.js +60 -0
  71. package/dist/i18n/locales/th-TH.js.map +1 -1
  72. package/dist/i18n/locales/tr-TR.js +60 -0
  73. package/dist/i18n/locales/tr-TR.js.map +1 -1
  74. package/dist/i18n/locales/vi-VN.js +60 -0
  75. package/dist/i18n/locales/vi-VN.js.map +1 -1
  76. package/dist/i18n/locales/zh-CN.js +60 -0
  77. package/dist/i18n/locales/zh-CN.js.map +1 -1
  78. package/dist/i18n/locales/zh-TW.js +60 -0
  79. package/dist/i18n/locales/zh-TW.js.map +1 -1
  80. package/dist/index.d.ts +2 -0
  81. package/dist/index.js +61 -59
  82. package/dist/instance.js +1 -1
  83. package/dist/ui-common-locales/de-DE.json +60 -0
  84. package/dist/ui-common-locales/el-GR.json +60 -0
  85. package/dist/ui-common-locales/en.json +60 -0
  86. package/dist/ui-common-locales/es-ES.json +60 -0
  87. package/dist/ui-common-locales/fi-FI.json +60 -0
  88. package/dist/ui-common-locales/fr-FR.json +60 -0
  89. package/dist/ui-common-locales/id-ID.json +60 -0
  90. package/dist/ui-common-locales/it-IT.json +60 -0
  91. package/dist/ui-common-locales/ja-JP.json +60 -0
  92. package/dist/ui-common-locales/ko-KR.json +60 -0
  93. package/dist/ui-common-locales/mn-MN.json +60 -0
  94. package/dist/ui-common-locales/ms-MY.json +60 -0
  95. package/dist/ui-common-locales/pl-PL.json +60 -0
  96. package/dist/ui-common-locales/pt-BR.json +60 -0
  97. package/dist/ui-common-locales/pt-PT.json +60 -0
  98. package/dist/ui-common-locales/ru-RU.json +60 -0
  99. package/dist/ui-common-locales/th-TH.json +60 -0
  100. package/dist/ui-common-locales/tr-TR.json +60 -0
  101. package/dist/ui-common-locales/vi-VN.json +60 -0
  102. package/dist/ui-common-locales/zh-CN.json +60 -0
  103. package/dist/ui-common-locales/zh-TW.json +60 -0
  104. package/exports.customs.json +1 -0
  105. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"DataGrid2.js","names":[],"sources":["../../../src/components/DataGrid/DataGrid.tsx"],"sourcesContent":["/**\n * DataGrid\n *\n * Astryx `Table` with the pieces a list page needs around it: a page bar with\n * a range line, client or server sorting, row selection by key, resizable\n * and pinnable columns, expandable rows, per-user column settings (visibility,\n * order, width) and a CSV export picker.\n *\n * Rows are sliced to the page unless `pagination.totalItems` says the caller\n * already sliced them. Sorting is client-side for columns with `compare`,\n * otherwise it only reports `onSortChange`. Column settings live in one\n * overrides record (`hidden`, `order`, `width` per column key) that a product\n * persists as it likes.\n *\n * Plugin order matters: Astryx runs columnSettings, sort, selection, then\n * unknown names in insertion order. `resize` / `sticky` / `scrollX` /\n * `scrollY` / `cellRow` / `expansion` read the final column list, and\n * `scrollY` runs before `cellRow` so a column's `getCellProps` wins.\n *\n * @example\n * <DataGrid\n * data={users}\n * idKey=\"id\"\n * columns={[\n * { key: \"name\", header: \"Name\", renderCell: (u) => u.name, sortKey: \"name\" },\n * { key: \"email\", header: \"Email\", renderCell: (u) => u.email },\n * ]}\n * sort={sort}\n * onSortChange={setSort}\n * pagination={{ page, pageSize, totalItems, onChange: setPage }}\n * />\n */\nimport {\n isValidElement,\n type Key,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type ReactElement,\n type ReactNode,\n type TdHTMLAttributes,\n} from \"react\";\nimport { EmptyState } from \"@astryxdesign/core/EmptyState\";\nimport { Button } from \"@astryxdesign/core/Button\";\nimport { Icon } from \"@astryxdesign/core/Icon\";\nimport { IconButton } from \"@astryxdesign/core/IconButton\";\nimport { Pagination, type PaginationProps } from \"@astryxdesign/core/Pagination\";\nimport { HStack, VStack } from \"@astryxdesign/core/Stack\";\nimport {\n Table,\n pixel,\n proportional,\n useTableColumnResize,\n useTableColumnSettings,\n useTableSelection,\n useTableSortable,\n useTableStickyColumns,\n type TableColumn,\n type TablePlugin,\n type TableProps,\n type TableSortState,\n} from \"@astryxdesign/core/Table\";\nimport { Text } from \"@astryxdesign/core/Text\";\nimport { ChevronDown, ChevronRight, FileDown, Inbox, Settings } from \"lucide-react\";\n\nimport { useUicTranslator } from \"../../i18n/useUicTranslator\";\nimport {\n DataGridExportModal,\n type DataGridExportModalProps,\n} from \"./DataGridExportModal\";\nimport {\n DataGridSettingsModal,\n type DataGridSettingsModalProps,\n type DataGridSettingsResult,\n} from \"./DataGridSettingsModal\";\nimport { nodeToPlainText } from \"./nodeToPlainText\";\nimport \"./DataGrid.css\";\n\n/** A row identity, as `idKey` returns it. */\nexport type DataGridKey = Key;\n\nexport type DataGridSortDirection = \"ascending\" | \"descending\";\n\n/** The active sort: one column, by its `sortKey`. */\nexport interface DataGridSort {\n sortKey: string;\n direction: DataGridSortDirection;\n}\n\nexport interface DataGridColumn<T> {\n /** Stable identity: column settings, widths and pinning use it. */\n key: string;\n /** Header content. It is clipped to the column width. */\n header?: ReactNode;\n /** Caption above the header, for a column that belongs to a group. */\n groupHeader?: ReactNode;\n /**\n * Plain-text name in the settings and export dialogs. Default: the text of\n * `groupHeader` and `header` joined with \" / \", else the key.\n */\n label?: string;\n /** Cell content. `index` is the row's position on the current page. */\n renderCell?: (item: T, index: number) => ReactNode;\n /** Width in pixels. A resized width replaces it. Without one the column flexes. */\n width?: number;\n /** Lower bound, in pixels, of a flexing column. */\n minWidth?: number;\n align?: \"start\" | \"center\" | \"end\";\n /** Makes the column sortable. The sort state names it by this key. */\n sortKey?: string;\n /**\n * Sorts the rows on the client when this column is sorted. Compare in\n * ascending order; the grid reverses the result for descending.\n */\n compare?: (a: T, b: T, direction: DataGridSortDirection) => number;\n /**\n * Pins the column to an edge. Only the contiguous run of pinned columns at\n * each edge of the displayed order is pinned.\n */\n pin?: \"start\" | \"end\";\n /** Column settings cannot hide it. */\n isAlwaysVisible?: boolean;\n /** Hidden until the user shows it in the column settings. */\n isHiddenByDefault?: boolean;\n /** Fields this column exports as. Without them it cannot be exported. */\n exportKeys?: ReadonlyArray<string>;\n /** Extra attributes for this column's body cells. */\n getCellProps?: (item: T, index: number) => TdHTMLAttributes<HTMLTableCellElement>;\n}\n\n/** Per-column settings a user changed, keyed by column key. */\nexport interface DataGridColumnOverride {\n hidden?: boolean;\n /** Display position. Lower comes first. Set only after a reorder. */\n order?: number;\n /** Resized width in pixels. */\n width?: number;\n}\n\nexport type DataGridColumnOverrides = Record<string, DataGridColumnOverride>;\n\nexport interface DataGridColumnSettings {\n /** Controlled overrides. */\n overrides?: DataGridColumnOverrides;\n /** Initial overrides when uncontrolled; always merged under `overrides`. */\n defaultOverrides?: DataGridColumnOverrides;\n onOverridesChange?: (overrides: DataGridColumnOverrides) => void;\n /** Whether the settings dialog lets the user reorder columns. Default: true */\n isReorderable?: boolean;\n /** Strings of the settings dialog. */\n modalProps?: Pick<\n DataGridSettingsModalProps,\n \"title\" | \"subtitle\" | \"searchLabel\" | \"noMatchText\" | \"applyLabel\" | \"cancelLabel\"\n >;\n}\n\nexport interface DataGridCsvExport {\n /** Export keys the backend can produce. Columns asking for others are disabled. */\n supportedKeys: ReadonlyArray<string>;\n /** Runs the export with the chosen keys. The dialog closes when it resolves. */\n onExport: (keys: string[]) => Promise<void>;\n /** A warning above the column list, e.g. that the export is truncated. */\n notice?: ReactNode;\n /** Strings of the export dialog. */\n modalProps?: Pick<\n DataGridExportModalProps,\n \"title\" | \"subtitle\" | \"searchLabel\" | \"noMatchText\" | \"exportLabel\" | \"cancelLabel\"\n >;\n}\n\nexport interface DataGridSelection<T> {\n /** The selected row keys. Selection is controlled. */\n selectedKeys?: ReadonlyArray<DataGridKey>;\n onChange?: (keys: string[], items: T[]) => void;\n /** Whether a row's checkbox is enabled. Select-all leaves a disabled row as it is. */\n getIsItemEnabled?: (item: T) => boolean;\n /** Accessible name of a row's checkbox. Default: the row key. */\n getRowLabel?: (item: T) => string;\n /** Select-all keeps keys of rows on other pages. Default: false */\n isPreservingOtherPages?: boolean;\n}\n\nexport interface DataGridExpansion<T> {\n renderExpandedRow: (item: T, index: number) => ReactNode;\n getIsRowExpandable?: (item: T) => boolean;\n /** Controlled expanded row keys. */\n expandedKeys?: ReadonlyArray<DataGridKey>;\n defaultExpandedKeys?: ReadonlyArray<DataGridKey>;\n onExpandedKeysChange?: (keys: ReadonlyArray<DataGridKey>) => void;\n /** Header content of the expand-button column. */\n columnHeader?: ReactNode;\n /** Width in pixels of the expand-button column. */\n columnWidth?: number;\n}\n\nexport interface DataGridPagination extends Omit<\n PaginationProps,\n | \"page\"\n | \"totalItems\"\n | \"onChange\"\n | \"onPageSizeChange\"\n | \"label\"\n | \"ref\"\n | \"totalPages\"\n | \"hasMore\"\n> {\n /** Controlled page, 1-based. */\n page?: number;\n defaultPage?: number;\n defaultPageSize?: number;\n /**\n * Total row count. Without it the grid pages `data` itself; a total larger\n * than `data` declares the rows already sliced to the page.\n */\n totalItems?: number;\n onChange?: (page: number, pageSize: number) => void;\n /** Whether the bar offers a page-size choice. Default: true */\n hasPageSizeSelector?: boolean;\n /** Hides the page bar while every row fits on one page. Default: false */\n isHiddenOnSinglePage?: boolean;\n /** Content at the end of the bar. */\n endContent?: ReactNode;\n}\n\ntype AnyRow = Record<string, unknown>;\n\nexport interface DataGridProps<T extends object = AnyRow> extends Omit<\n TableProps<AnyRow>,\n | \"data\"\n | \"columns\"\n | \"idKey\"\n | \"rowIndexStart\"\n | \"rowCount\"\n | \"children\"\n | \"scrollWrapper\"\n | \"ref\"\n | \"emptyState\"\n | \"className\"\n | \"style\"\n | \"plugins\"\n | \"onChange\"\n> {\n data?: ReadonlyArray<T>;\n columns?: ReadonlyArray<DataGridColumn<T>>;\n /**\n * Row identity: a field name or a function. A missing field falls back to\n * the row's `key`, then its `id`, then its position.\n */\n idKey?: string | ((item: T) => DataGridKey);\n /** Dims the rows and blocks input while data is refetched. */\n isLoading?: boolean;\n /** Drag-to-resize column borders. Default: true */\n isResizable?: boolean;\n /** Controlled sort; `null` for none. */\n sort?: DataGridSort | null;\n defaultSort?: DataGridSort | null;\n onSortChange?: (sort: DataGridSort | null) => void;\n selection?: DataGridSelection<T>;\n /** The page bar. `false` shows every row and no bar. */\n pagination?: false | DataGridPagination;\n /** Enables the column settings button and persists resized widths. */\n columnSettings?: DataGridColumnSettings;\n /** Enables the CSV export button. */\n csvExport?: DataGridCsvExport;\n expansion?: DataGridExpansion<T>;\n /**\n * Shown in place of the rows when there are none. A string gets the default\n * icon and layout, a node is rendered as is, `false` shows nothing. Default:\n * the catalog's `uic.DataGrid.noData`.\n */\n emptyState?: ReactNode | false;\n /** Extra attributes for a body row. */\n getRowProps?: (\n item: T,\n index: number | undefined,\n ) => HTMLAttributes<HTMLTableRowElement>;\n /**\n * Scrolls horizontally with the table at this width (at least the\n * container's). Columns without a width then size to their content.\n */\n scrollWidth?: number | string;\n /** Caps the rows' height and makes the header sticky. */\n maxHeight?: number | string;\n /** Hides the header row, and with it sorting and select-all. */\n isHeaderHidden?: boolean;\n /** Accessible name of the expand buttons. Default: the catalog's `uic.DataGrid.expandRow` */\n expandRowLabel?: string;\n /** Shown when the page lies past the last one. Default: the catalog's `uic.DataGrid.invalidPage` */\n invalidPageText?: string;\n /** Default: the catalog's `uic.DataGrid.goToFirstPage` */\n goToFirstPageLabel?: string;\n /** Accessible name of the page navigation. Default: the catalog's `uic.DataGrid.pagination` */\n paginationLabel?: string;\n /** The range line beside the page navigation. Default: the catalog's `uic.DataGrid.range` */\n renderRange?: (range: { start: number; end: number; total: number }) => ReactNode;\n /** Default: the catalog's `uic.DataGrid.settings` */\n settingsLabel?: string;\n /** Default: the catalog's `uic.DataGrid.exportCsv` */\n exportLabel?: string;\n className?: string;\n style?: CSSProperties;\n}\n\nconst EXPAND_COLUMN_KEY = \"__uic_expand__\";\n/** Key of the checkbox column Astryx's selection plugin injects; not exported by Astryx. */\nconst SELECTION_COLUMN_KEY = \"__xds_selection\";\n/**\n * Measured column widths, in pixels. Selection: Astryx's 24px first-column\n * inset + the 20px checkbox + an 8px trailing pad (the plugin's own 36 lets\n * the checkbox overhang its cell). Expand: the same inset + the 24px button +\n * 8px, or an 8px lead-in instead of the inset behind a selection column.\n */\nconst SELECTION_COLUMN_WIDTH = 52;\nconst EXPAND_COLUMN_WIDTH_FIRST = 56;\nconst EXPAND_COLUMN_WIDTH_AFTER_SELECTION = 40;\nconst MIN_COLUMN_WIDTH = 60;\nconst DETAIL_ROW_MARKER = \"__uic_detail_for__\";\nconst DEFAULT_PAGE_SIZE = 10;\nconst DEFAULT_PAGE_SIZE_OPTIONS = [10, 20, 50];\n\nconst EMPTY_STATE_ICON = <Icon icon={Inbox} size=\"lg\" color=\"secondary\" />;\n\nconst X_HEADER_RELEASE: CSSProperties = { width: \"auto\", maxWidth: \"none\" };\nconst X_BODY_RELEASE: CSSProperties = { maxWidth: \"none\" };\n// Inline beats the sticky-header rule's z 2 for pinned header cells.\nconst Y_PINNED_HEADER_STACK: CSSProperties = { zIndex: 3 };\n\nconst isDetailRow = (item: unknown): item is AnyRow =>\n !!item && typeof item === \"object\" && DETAIL_ROW_MARKER in item;\n\nconst toCssLength = (value: number | string): string =>\n typeof value === \"number\" ? `${value}px` : value;\n\nfunction mergeCellStyle<P extends { htmlProps: { style?: CSSProperties } }>(\n props: P,\n extra: CSSProperties,\n): P {\n return {\n ...props,\n htmlProps: {\n ...props.htmlProps,\n style: props.htmlProps.style ? { ...props.htmlProps.style, ...extra } : extra,\n },\n };\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/** The label a column carries in the settings and export dialogs. */\nexport function dataGridColumnLabel<T>(column: DataGridColumn<T>): string {\n if (column.label) return column.label;\n const own = nodeToPlainText(column.header).trim();\n const group = nodeToPlainText(column.groupHeader).trim();\n const label = group && own ? `${group} / ${own}` : own || group;\n return label || column.key;\n}\n\n/** Whether a column shows, given the user's overrides. */\n/**\n * The overrides record a settings dialog result writes. `defaultOverrides`\n * stays merged under it key by key, and a key it holds replaces the default's\n * entry whole. So a column is left out only while its default (natural, then\n * `defaultOverrides`) already renders what the user chose, and an entry that\n * is written states everything that differs from the natural column:\n * otherwise re-showing a column the defaults hide, or restoring the natural\n * order over a reordering default, would bring the default back.\n *\n * @internal Exported for tests.\n */\nexport function dataGridSettingsToOverrides({\n columns,\n result,\n defaultOverrides = {},\n overrides,\n isReorderable,\n}: {\n columns: ReadonlyArray<Pick<DataGridColumn<never>, \"key\" | \"isHiddenByDefault\">>;\n result: DataGridSettingsResult;\n defaultOverrides?: DataGridColumnOverrides;\n /** The overrides in effect, defaults merged; their widths are kept. */\n overrides: DataGridColumnOverrides;\n isReorderable: boolean;\n}): DataGridColumnOverrides {\n const naturalOrder = columns.map((column) => column.key);\n // A default order is only undone by stating every column's position.\n const writesOrder =\n isReorderable &&\n (result.columnOrder.length !== naturalOrder.length ||\n result.columnOrder.some((key, index) => key !== naturalOrder[index]) ||\n columns.some((column) => defaultOverrides[column.key]?.order !== undefined));\n const next: DataGridColumnOverrides = {};\n for (const column of columns) {\n const fallback = defaultOverrides[column.key];\n const naturalHidden = !!column.isHiddenByDefault;\n const defaultHidden = fallback?.hidden ?? naturalHidden;\n const hidden = !result.selectedColumnKeys.includes(column.key);\n const override: DataGridColumnOverride = {};\n if (hidden !== naturalHidden || hidden !== defaultHidden) override.hidden = hidden;\n if (writesOrder) {\n const orderIndex = result.columnOrder.indexOf(column.key);\n if (orderIndex !== -1) override.order = orderIndex;\n }\n // A settings change must not reset resized widths.\n const width = overrides[column.key]?.width;\n if (typeof width === \"number\") override.width = width;\n const matchesDefault =\n hidden === defaultHidden &&\n override.order === fallback?.order &&\n override.width === fallback?.width;\n if (!matchesDefault && Object.keys(override).length > 0)\n next[column.key] = override;\n }\n return next;\n}\n\nexport function isDataGridColumnVisible<T>(\n column: Pick<DataGridColumn<T>, \"key\" | \"isAlwaysVisible\" | \"isHiddenByDefault\">,\n overrides?: DataGridColumnOverrides,\n): boolean {\n if (column.isAlwaysVisible) return true;\n const hidden = overrides?.[column.key]?.hidden;\n return hidden !== undefined ? !hidden : !column.isHiddenByDefault;\n}\n\n/** Controlled when `value` is not undefined; the setter writes state only when uncontrolled. */\nfunction useControllableState<V>(value: V | undefined, initial: () => V) {\n const [state, setState] = useState<V>(initial);\n const isControlled = value !== undefined;\n const current = isControlled ? value : state;\n const set = (next: V) => {\n if (!isControlled) setState(next);\n };\n return [current, set] as const;\n}\n\nexport function DataGrid<T extends object = AnyRow>({\n data,\n columns = [],\n idKey = \"id\",\n isLoading = false,\n isResizable = true,\n sort: sortProp,\n defaultSort,\n onSortChange,\n selection,\n pagination,\n columnSettings,\n csvExport,\n expansion,\n emptyState,\n getRowProps,\n scrollWidth,\n maxHeight,\n isHeaderHidden = false,\n expandRowLabel,\n invalidPageText,\n goToFirstPageLabel,\n paginationLabel,\n renderRange,\n settingsLabel,\n exportLabel,\n density = \"compact\",\n dividers = \"rows\",\n hasHover = true,\n textOverflow = \"truncate\",\n className,\n style,\n ...tableProps\n}: DataGridProps<T>): ReactElement {\n const t = useUicTranslator();\n\n const isScrollX = scrollWidth !== undefined;\n const isScrollY = maxHeight !== undefined;\n\n const [isSettingsOpen, setIsSettingsOpen] = useState(false);\n const [isExportOpen, setIsExportOpen] = useState(false);\n\n /* ---- column overrides (visibility / order / width) ------------------- */\n\n const [storedOverrides, setStoredOverrides] = useState<DataGridColumnOverrides>(\n () => columnSettings?.defaultOverrides ?? {},\n );\n const isOverridesControlled = columnSettings?.overrides !== undefined;\n const ownOverrides = isOverridesControlled\n ? (columnSettings?.overrides ?? {})\n : storedOverrides;\n const setOverrides = (next: DataGridColumnOverrides) => {\n if (!isOverridesControlled) setStoredOverrides(next);\n columnSettings?.onOverridesChange?.(next);\n };\n const overrides: DataGridColumnOverrides = {\n ...(columnSettings?.defaultOverrides ?? {}),\n ...ownOverrides,\n };\n const isReorderable = !!columnSettings && columnSettings.isReorderable !== false;\n\n /* ---- resized widths ---------------------------------------------------- */\n\n // With columnSettings a width rides in the overrides record, so a resize\n // persists like a visibility change; without it the width is local state.\n const [localWidths, setLocalWidths] = useState<Record<string, number>>({});\n const columnWidths: Record<string, number> = {};\n if (columnSettings) {\n for (const [key, override] of Object.entries(overrides)) {\n if (typeof override?.width === \"number\") columnWidths[key] = override.width;\n }\n } else {\n Object.assign(columnWidths, localWidths);\n }\n\n const handleResizeEnd = (updates: Record<string, number>) => {\n if (!columnSettings) {\n setLocalWidths((prev) => ({ ...prev, ...updates }));\n return;\n }\n const next: DataGridColumnOverrides = { ...ownOverrides };\n for (const [key, width] of Object.entries(updates)) {\n if (key === EXPAND_COLUMN_KEY) continue;\n next[key] = { ...next[key], width };\n }\n setOverrides(next);\n };\n\n /* ---- row keys ---------------------------------------------------------- */\n\n const getRowKey = (item: T): string => {\n if (typeof idKey === \"function\") return String(idKey(item));\n const row = item as AnyRow;\n const direct = row[idKey];\n if (direct != null) return String(direct);\n const fallback = row.key ?? row.id;\n if (fallback != null) return String(fallback);\n return `__row_${data ? data.indexOf(item) : -1}`;\n };\n\n /* ---- sort -------------------------------------------------------------- */\n\n const [activeSort, setActiveSort] = useControllableState<DataGridSort | null>(\n sortProp,\n () => defaultSort ?? null,\n );\n\n const sortedRows = ((): T[] => {\n const source = data ? [...data] : [];\n if (!activeSort) return source;\n const compare = columns.find(\n (column) => column.sortKey === activeSort.sortKey && column.compare,\n )?.compare;\n if (!compare) return source;\n const { direction } = activeSort;\n return source.sort((a, b) =>\n direction === \"descending\" ? -compare(a, b, direction) : compare(a, b, direction),\n );\n })();\n\n /* ---- pagination -------------------------------------------------------- */\n\n const pager = pagination === false ? undefined : (pagination ?? {});\n const [currentPage, setCurrentPage] = useControllableState<number>(\n pager?.page,\n () => pager?.defaultPage ?? 1,\n );\n const [pageSize, setPageSize] = useControllableState<number>(\n pager?.pageSize,\n () => pager?.defaultPageSize ?? DEFAULT_PAGE_SIZE,\n );\n\n // Astryx's Pagination answers a page-size pick with onPageSizeChange(size)\n // and then onChange(1) in the same event, still closing over the old size.\n // Forwarding the second call would undo the pick on a controlled grid, so it\n // is dropped; a microtask clears the flag.\n const isPageSizeChangingRef = useRef(false);\n\n const total = pager?.totalItems ?? sortedRows.length;\n const lastPage = Math.max(1, Math.ceil(total / pageSize));\n const activePage = clamp(currentPage, 1, lastPage);\n const isPageOutOfRange =\n !!pager && total > 0 && (currentPage < 1 || currentPage > lastPage);\n // A total above the rows in hand means they are already one page.\n const isServerSliced = total > sortedRows.length;\n const pagedRows =\n pager && !isServerSliced && sortedRows.length > pageSize\n ? sortedRows.slice((activePage - 1) * pageSize, activePage * pageSize)\n : sortedRows;\n const rows = isPageOutOfRange ? [] : pagedRows;\n\n /* ---- expansion --------------------------------------------------------- */\n\n const [storedExpandedKeys, setStoredExpandedKeys] = useState<DataGridKey[]>(() => [\n ...(expansion?.defaultExpandedKeys ?? []),\n ]);\n const expandedKeys = expansion?.expandedKeys ?? storedExpandedKeys;\n const expandedKeySet = new Set(expandedKeys.map(String));\n const hasExpansion = !!expansion;\n const expandColumnWidth =\n expansion?.columnWidth ??\n (selection ? EXPAND_COLUMN_WIDTH_AFTER_SELECTION : EXPAND_COLUMN_WIDTH_FIRST);\n const detailInsetStart = (selection ? SELECTION_COLUMN_WIDTH : 0) + expandColumnWidth;\n\n const toggleExpanded = (key: string) => {\n const next = expandedKeySet.has(key)\n ? expandedKeys.filter((k) => String(k) !== key)\n : [...expandedKeys, key];\n if (!expansion?.expandedKeys) setStoredExpandedKeys(next);\n expansion?.onExpandedKeysChange?.(next);\n };\n\n const rowIndexByKey = new Map<string, number>();\n rows.forEach((item, index) => rowIndexByKey.set(getRowKey(item), index));\n\n // Each expanded row is followed by a marker row the expansion plugin turns\n // into one full-width cell.\n const tableData: AnyRow[] = [];\n for (const item of rows) {\n tableData.push(item as AnyRow);\n if (!hasExpansion) continue;\n const key = getRowKey(item);\n if (expandedKeySet.has(key) && (expansion?.getIsRowExpandable?.(item) ?? true)) {\n tableData.push({ [DETAIL_ROW_MARKER]: key, id: `${key}__detail` });\n }\n }\n\n // From every row, not the page: selection resolves keys on other pages too.\n const itemByKey = new Map<string, T>();\n sortedRows.forEach((item) => itemByKey.set(getRowKey(item), item));\n\n /* ---- Astryx columns ---------------------------------------------------- */\n\n const tableColumns: TableColumn<AnyRow>[] = [];\n if (hasExpansion) {\n tableColumns.push({\n key: EXPAND_COLUMN_KEY,\n header: expansion?.columnHeader ?? \"\",\n width: pixel(expandColumnWidth),\n resizable: false,\n renderCell: (row) => {\n if (isDetailRow(row)) return null;\n const item = row as T;\n if (!(expansion?.getIsRowExpandable?.(item) ?? true)) return null;\n const key = getRowKey(item);\n return (\n <IconButton\n label={expandRowLabel ?? t(\"uic.DataGrid.expandRow\")}\n icon={expandedKeySet.has(key) ? <ChevronDown /> : <ChevronRight />}\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => toggleExpanded(key)}\n />\n );\n },\n });\n }\n\n for (const column of columns) {\n const width = columnWidths[column.key] ?? column.width;\n const header = (\n <span className=\"uic-data-grid__clip\">\n {column.groupHeader == null ? (\n column.header\n ) : (\n <VStack gap={0} align=\"start\">\n <Text type=\"supporting\" color=\"secondary\">\n {column.groupHeader}\n </Text>\n <span>{column.header}</span>\n </VStack>\n )}\n </span>\n );\n tableColumns.push({\n key: column.key,\n header,\n align: column.align === \"start\" ? undefined : column.align,\n sortable: column.sortKey ? { sortKey: column.sortKey } : false,\n resizable: isResizable,\n // In scroll-x mode a width-less column takes no width, so its content sizes it.\n width:\n width != null\n ? pixel(width)\n : isScrollX\n ? undefined\n : proportional(\n 1,\n typeof column.minWidth === \"number\"\n ? { minWidth: column.minWidth }\n : undefined,\n ),\n renderCell: (row) => {\n if (isDetailRow(row)) return null;\n const item = row as T;\n const content = column.renderCell\n ? column.renderCell(item, rowIndexByKey.get(getRowKey(item)) ?? 0)\n : defaultCell(row[column.key]);\n if (textOverflow !== \"truncate\" || content == null) return content;\n return <span className=\"uic-data-grid__clip\">{content}</span>;\n },\n });\n }\n\n /* ---- visibility + order ------------------------------------------------ */\n\n const visibleColumns = columnSettings\n ? columns.filter((column) => isDataGridColumnVisible(column, overrides))\n : [...columns];\n const orderedColumns = isReorderable\n ? visibleColumns\n .map((column, index) => ({ column, index }))\n .sort(\n (a, b) =>\n (overrides[a.column.key]?.order ?? Number.MAX_SAFE_INTEGER) -\n (overrides[b.column.key]?.order ?? Number.MAX_SAFE_INTEGER) ||\n a.index - b.index,\n )\n .map(({ column }) => column)\n : visibleColumns;\n const activeColumnKeys = [\n ...(hasExpansion ? [EXPAND_COLUMN_KEY] : []),\n ...orderedColumns.map((column) => column.key),\n ];\n\n const columnSettingsPlugin = useTableColumnSettings<AnyRow>({\n columns: [\n ...(hasExpansion\n ? [{ key: EXPAND_COLUMN_KEY, label: \"\", isAlwaysVisible: true }]\n : []),\n ...columns.map((column) => ({\n key: column.key,\n label: dataGridColumnLabel(column),\n isAlwaysVisible: !!column.isAlwaysVisible,\n })),\n ],\n activeColumnKeys,\n // The settings dialog owns the write path (it keeps `order` and `width`).\n onChangeActiveColumnKeys: () => {},\n });\n\n /* ---- pinning ----------------------------------------------------------- */\n\n const startKeys: string[] = [];\n for (const column of orderedColumns) {\n if (column.pin === \"start\") startKeys.push(column.key);\n else break;\n }\n const endKeys: string[] = [];\n for (const column of [...orderedColumns].reverse()) {\n if (column.pin === \"end\") endKeys.unshift(column.key);\n else break;\n }\n const stickyConfig = {\n startKeys:\n startKeys.length === 0\n ? undefined\n : [\n ...(selection ? [SELECTION_COLUMN_KEY] : []),\n ...(hasExpansion ? [EXPAND_COLUMN_KEY] : []),\n ...startKeys,\n ],\n endKeys: endKeys.length === 0 ? undefined : endKeys,\n };\n const stickyPlugin = useTableStickyColumns<AnyRow>(\n stickyConfig.startKeys || stickyConfig.endKeys ? stickyConfig : {},\n );\n\n /* ---- per-cell / per-row attributes -------------------------------------- */\n\n const columnByKey = new Map(columns.map((column) => [column.key, column]));\n\n const cellRowPlugin: TablePlugin<AnyRow> = {\n transformBodyCell: (props, column, row) => {\n if (isDetailRow(row)) return props;\n const item = row as T;\n const extra = columnByKey\n .get(column.key)\n ?.getCellProps?.(item, rowIndexByKey.get(getRowKey(item)) ?? 0);\n if (!extra) return props;\n return {\n ...props,\n htmlProps: {\n ...props.htmlProps,\n ...extra,\n style: { ...props.htmlProps.style, ...extra.style },\n },\n };\n },\n transformBodyRow: (props, row) => {\n if (!getRowProps || isDetailRow(row)) return props;\n const item = row as T;\n const extra = getRowProps(item, rowIndexByKey.get(getRowKey(item)));\n if (!extra) return props;\n return {\n ...props,\n htmlProps: {\n ...props.htmlProps,\n ...extra,\n style: { ...props.htmlProps.style, ...extra.style },\n },\n };\n },\n };\n\n // Astryx clips cells with `max-width: 0`; scroll-x releases width-less columns only.\n const scrollXPlugin: TablePlugin<AnyRow> = {\n transformHeaderCell: (props, column) =>\n column.width != null ? props : mergeCellStyle(props, X_HEADER_RELEASE),\n transformBodyCell: (props, column) =>\n column.width != null ? props : mergeCellStyle(props, X_BODY_RELEASE),\n };\n\n const pinnedKeys = new Set([\n ...(stickyConfig.startKeys ?? []),\n ...(stickyConfig.endKeys ?? []),\n ]);\n const scrollYPlugin: TablePlugin<AnyRow> = {\n transformHeaderCell: (props, column) =>\n pinnedKeys.has(column.key) ? mergeCellStyle(props, Y_PINNED_HEADER_STACK) : props,\n };\n\n /* ---- sorting ----------------------------------------------------------- */\n\n const sortState: TableSortState = activeSort\n ? [{ sortKey: activeSort.sortKey, direction: activeSort.direction }]\n : [];\n\n const sortPlugin = useTableSortable<AnyRow>({\n sort: sortState,\n allowUnsortedState: true,\n onSortChange: (next) => {\n const first = next[0];\n const nextSort: DataGridSort | null = first\n ? { sortKey: first.sortKey, direction: first.direction }\n : null;\n setActiveSort(nextSort);\n onSortChange?.(nextSort);\n },\n });\n\n /* ---- selection --------------------------------------------------------- */\n\n const selectedKeySet = new Set((selection?.selectedKeys ?? []).map(String));\n const emitSelection = (keys: string[]) => {\n const items = keys\n .map((key) => itemByKey.get(key))\n .filter((item) => item !== undefined);\n selection?.onChange?.(keys, items);\n };\n const isRowSelected = (item: T) => selectedKeySet.has(getRowKey(item));\n const isRowEnabled = (item: T) => selection?.getIsItemEnabled?.(item) ?? true;\n // Select-all acts on the enabled rows only; a disabled row keeps its state.\n const enabledRows = rows.filter(isRowEnabled);\n\n const selectionPlugin = useTableSelection<AnyRow>({\n getIsItemSelectable: (row) => !isDetailRow(row),\n getIsItemSelected: (row) => !isDetailRow(row) && isRowSelected(row as T),\n getIsItemEnabled: (row) => !isDetailRow(row) && isRowEnabled(row as T),\n getRowLabel: (row) =>\n isDetailRow(row)\n ? \"\"\n : (selection?.getRowLabel?.(row as T) ?? getRowKey(row as T)),\n getIsAllSelected: () => enabledRows.length > 0 && enabledRows.every(isRowSelected),\n getIsIndeterminate: () =>\n enabledRows.some(isRowSelected) && !enabledRows.every(isRowSelected),\n onSelectItem: ({ item, isSelected }) => {\n if (isDetailRow(item)) return;\n const key = getRowKey(item as T);\n const next = new Set(selectedKeySet);\n if (isSelected) next.add(key);\n else next.delete(key);\n emitSelection([...next]);\n },\n onSelectAll: ({ isAllSelected }) => {\n const next = new Set(selection?.isPreservingOtherPages ? selectedKeySet : []);\n for (const item of rows) {\n const key = getRowKey(item);\n const isSelected = isRowEnabled(item) ? isAllSelected : isRowSelected(item);\n if (isSelected) next.add(key);\n else next.delete(key);\n }\n emitSelection([...next]);\n },\n });\n\n const selectionWidthPlugin: TablePlugin<AnyRow> = {\n transformColumns: (cols) =>\n cols.map((column) =>\n column.key === SELECTION_COLUMN_KEY\n ? { ...column, width: pixel(SELECTION_COLUMN_WIDTH) }\n : column,\n ),\n };\n\n /* ---- resize ------------------------------------------------------------ */\n\n const resizePlugin = useTableColumnResize<AnyRow>({\n columns: tableColumns,\n columnWidths,\n minWidth: MIN_COLUMN_WIDTH,\n onColumnResizeEnd: handleResizeEnd,\n });\n\n /* ---- expansion --------------------------------------------------------- */\n\n const renderedColumnCount = activeColumnKeys.length + (selection ? 1 : 0);\n const expansionPlugin: TablePlugin<AnyRow> = {\n transformBodyRow: (props, row) => {\n if (!isDetailRow(row)) return props;\n const parentKey = String(row[DETAIL_ROW_MARKER]);\n const item = itemByKey.get(parentKey);\n if (!item) return props;\n return {\n ...props,\n children: (\n <td\n colSpan={renderedColumnCount}\n className=\"uic-data-grid__detail\"\n style={{ paddingInlineStart: detailInsetStart }}\n >\n {expansion?.renderExpandedRow(item, rowIndexByKey.get(parentKey) ?? 0)}\n </td>\n ),\n };\n },\n };\n\n const plugins: Record<string, TablePlugin<AnyRow>> = {\n columnSettings: columnSettingsPlugin,\n sort: sortPlugin,\n };\n if (selection) {\n plugins.selection = selectionPlugin;\n plugins.selectionWidth = selectionWidthPlugin;\n }\n if (isResizable) plugins.resize = resizePlugin;\n plugins.sticky = stickyPlugin;\n if (isScrollX) plugins.scrollX = scrollXPlugin;\n // Without pinned columns the sticky header is pure CSS.\n if (isScrollY && pinnedKeys.size > 0) plugins.scrollY = scrollYPlugin;\n plugins.cellRow = cellRowPlugin;\n if (hasExpansion) plugins.expansion = expansionPlugin;\n\n /* ---- bottom bar -------------------------------------------------------- */\n\n const {\n page: _page,\n defaultPage: _defaultPage,\n defaultPageSize: _defaultPageSize,\n totalItems: _totalItems,\n onChange: _onChange,\n hasPageSizeSelector = true,\n isHiddenOnSinglePage = false,\n endContent,\n pageSizeOptions,\n size: pagerSize = \"sm\",\n ...paginationRest\n } = pager ?? {};\n\n const rangeStart = total === 0 ? 0 : (activePage - 1) * pageSize + 1;\n const rangeEnd = Math.min(activePage * pageSize, total);\n const isPagerVisible = !!pager && !(isHiddenOnSinglePage && total <= pageSize);\n const hasBottomBar = isPagerVisible || !!columnSettings || !!csvExport;\n\n const emptyStateNode = isPageOutOfRange ? (\n // The way back outranks any empty state the caller gave.\n <EmptyState\n isCompact\n icon={EMPTY_STATE_ICON}\n title={invalidPageText ?? t(\"uic.DataGrid.invalidPage\")}\n actions={\n <Button\n variant=\"primary\"\n label={goToFirstPageLabel ?? t(\"uic.DataGrid.goToFirstPage\")}\n onClick={() => {\n setCurrentPage(1);\n pager?.onChange?.(1, pageSize);\n }}\n />\n }\n />\n ) : emptyState === false ? (\n false\n ) : emptyState == null || typeof emptyState === \"string\" ? (\n <EmptyState\n isCompact\n icon={EMPTY_STATE_ICON}\n title={emptyState ?? t(\"uic.DataGrid.noData\")}\n />\n ) : (\n emptyState\n );\n\n const applySettings = (result: DataGridSettingsResult) => {\n setIsSettingsOpen(false);\n setOverrides(\n dataGridSettingsToOverrides({\n columns,\n result,\n defaultOverrides: columnSettings?.defaultOverrides,\n overrides,\n isReorderable,\n }),\n );\n };\n\n return (\n <div\n className={[\"uic-data-grid\", className].filter(Boolean).join(\" \")}\n style={style}\n >\n <div\n aria-busy={isLoading || undefined}\n className={[\n \"uic-data-grid__body\",\n isLoading && \"uic-data-grid__body--loading\",\n isHeaderHidden && \"uic-data-grid__body--no-header\",\n dividers !== \"grid\" && \"uic-data-grid__body--header-split\",\n isScrollX && \"uic-data-grid__body--scroll-x\",\n isScrollY && \"uic-data-grid__body--scroll-y\",\n ]\n .filter(Boolean)\n .join(\" \")}\n style={\n {\n ...(isScrollX\n ? { \"--data-grid-scroll-width\": toCssLength(scrollWidth) }\n : null),\n ...(isScrollY\n ? { \"--data-grid-max-height\": toCssLength(maxHeight) }\n : null),\n } as CSSProperties\n }\n >\n <Table<AnyRow>\n {...tableProps}\n data={tableData}\n columns={tableColumns}\n idKey={(row: AnyRow) =>\n isDetailRow(row)\n ? `${String(row[DETAIL_ROW_MARKER])}__detail`\n : getRowKey(row as T)\n }\n density={density}\n dividers={dividers}\n hasHover={hasHover}\n textOverflow={textOverflow}\n emptyState={emptyStateNode}\n rowCount={total || undefined}\n rowIndexStart={pager ? (activePage - 1) * pageSize + 1 : undefined}\n plugins={plugins}\n />\n </div>\n\n {hasBottomBar ? (\n <HStack justify=\"end\" align=\"center\" gap={2} className=\"uic-data-grid__footer\">\n {isPagerVisible ? (\n <>\n <Text type=\"supporting\" color=\"secondary\">\n {renderRange\n ? renderRange({ start: rangeStart, end: rangeEnd, total })\n : t(\"uic.DataGrid.range\", {\n start: rangeStart,\n end: rangeEnd,\n total,\n })}\n </Text>\n <Pagination\n variant=\"pages\"\n {...paginationRest}\n page={activePage}\n pageSize={pageSize}\n totalItems={total}\n // Astryx shows the size choice exactly when options are passed.\n pageSizeOptions={\n hasPageSizeSelector\n ? (pageSizeOptions ?? DEFAULT_PAGE_SIZE_OPTIONS)\n : undefined\n }\n size={pagerSize}\n label={paginationLabel ?? t(\"uic.DataGrid.pagination\")}\n onChange={(page) => {\n if (isPageSizeChangingRef.current) return;\n setCurrentPage(page);\n pager?.onChange?.(page, pageSize);\n }}\n onPageSizeChange={(nextSize) => {\n isPageSizeChangingRef.current = true;\n queueMicrotask(() => {\n isPageSizeChangingRef.current = false;\n });\n setCurrentPage(1);\n setPageSize(nextSize);\n pager?.onChange?.(1, nextSize);\n }}\n />\n </>\n ) : null}\n {columnSettings ? (\n <IconButton\n label={settingsLabel ?? t(\"uic.DataGrid.settings\")}\n icon={<Settings />}\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setIsSettingsOpen(true)}\n />\n ) : null}\n {csvExport ? (\n <IconButton\n label={exportLabel ?? t(\"uic.DataGrid.exportCsv\")}\n icon={<FileDown />}\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setIsExportOpen(true)}\n />\n ) : null}\n {pager ? endContent : null}\n </HStack>\n ) : null}\n\n {columnSettings ? (\n <DataGridSettingsModal\n {...columnSettings.modalProps}\n isOpen={isSettingsOpen}\n onOpenChange={setIsSettingsOpen}\n columns={columns.map((column) => ({\n key: column.key,\n label: dataGridColumnLabel(column),\n isAlwaysVisible: !!column.isAlwaysVisible,\n }))}\n visibleColumnKeys={orderedColumns.map((column) => column.key)}\n isReorderable={isReorderable}\n onApply={applySettings}\n />\n ) : null}\n\n {csvExport ? (\n <DataGridExportModal\n {...csvExport.modalProps}\n isOpen={isExportOpen}\n onOpenChange={setIsExportOpen}\n columns={columns.map((column) => ({\n key: column.key,\n label: dataGridColumnLabel(column),\n exportKeys: column.exportKeys ?? [],\n }))}\n supportedKeys={csvExport.supportedKeys}\n notice={csvExport.notice}\n onExport={async (keys) => {\n await csvExport.onExport(keys);\n setIsExportOpen(false);\n }}\n />\n ) : null}\n </div>\n );\n}\n\nfunction defaultCell(value: unknown): ReactNode {\n if (value == null || value === \"\") return null;\n if (isValidElement(value)) return value;\n return String(value);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DataGrid2.js","names":[],"sources":["../../../src/components/DataGrid/DataGrid.tsx"],"sourcesContent":["/**\n * DataGrid\n *\n * Astryx `Table` with the pieces a list page needs around it: a page bar with\n * a range line, client or server sorting, row selection by key, resizable\n * and pinnable columns, expandable rows, per-user column settings (visibility,\n * order, width) and a CSV export picker.\n *\n * Rows are sliced to the page unless `pagination.totalItems` says the caller\n * already sliced them. Sorting is client-side for columns with `compare`,\n * otherwise it only reports `onSortChange`. Column settings live in one\n * overrides record (`hidden`, `order`, `width` per column key) that a product\n * persists as it likes.\n *\n * Plugin order matters: Astryx runs columnSettings, sort, selection, then\n * unknown names in insertion order. `resize` / `sticky` / `scrollX` /\n * `scrollY` / `cellRow` / `expansion` read the final column list, and\n * `scrollY` runs before `cellRow` so a column's `getCellProps` wins.\n *\n * @example\n * <DataGrid\n * data={users}\n * idKey=\"id\"\n * columns={[\n * { key: \"name\", header: \"Name\", renderCell: (u) => u.name, sortKey: \"name\" },\n * { key: \"email\", header: \"Email\", renderCell: (u) => u.email },\n * ]}\n * sort={sort}\n * onSortChange={setSort}\n * pagination={{ page, pageSize, totalItems, onChange: setPage }}\n * />\n */\nimport {\n isValidElement,\n type Key,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type ReactElement,\n type ReactNode,\n type TdHTMLAttributes,\n} from \"react\";\nimport { EmptyState } from \"@astryxdesign/core/EmptyState\";\nimport { Button } from \"@astryxdesign/core/Button\";\nimport { Icon } from \"@astryxdesign/core/Icon\";\nimport { IconButton } from \"@astryxdesign/core/IconButton\";\nimport { Pagination, type PaginationProps } from \"@astryxdesign/core/Pagination\";\nimport { HStack, VStack } from \"@astryxdesign/core/Stack\";\nimport {\n Table,\n pixel,\n proportional,\n useTableColumnResize,\n useTableColumnSettings,\n useTableSelection,\n useTableSortable,\n useTableStickyColumns,\n type TableColumn,\n type TablePlugin,\n type TableProps,\n type TableSortState,\n} from \"@astryxdesign/core/Table\";\nimport { Text } from \"@astryxdesign/core/Text\";\nimport { ChevronDown, ChevronRight, FileDown, Inbox, Settings } from \"lucide-react\";\n\nimport { useUicTranslator } from \"../../i18n/useUicTranslator\";\nimport {\n DataGridExportModal,\n type DataGridExportModalProps,\n} from \"./DataGridExportModal\";\nimport {\n DataGridSettingsModal,\n type DataGridSettingsModalProps,\n type DataGridSettingsResult,\n} from \"./DataGridSettingsModal\";\nimport { nodeToPlainText } from \"./nodeToPlainText\";\nimport \"./DataGrid.css\";\n\n/** A row identity, as `idKey` returns it. */\nexport type DataGridKey = Key;\n\nexport type DataGridSortDirection = \"ascending\" | \"descending\";\n\n/** The active sort: one column, by its `sortKey`. */\nexport interface DataGridSort {\n sortKey: string;\n direction: DataGridSortDirection;\n}\n\nexport interface DataGridColumn<T> {\n /** Stable identity: column settings, widths and pinning use it. */\n key: string;\n /** Header content. It is clipped to the column width. */\n header?: ReactNode;\n /** Caption above the header, for a column that belongs to a group. */\n groupHeader?: ReactNode;\n /**\n * Plain-text name in the settings and export dialogs. Default: the text of\n * `groupHeader` and `header` joined with \" / \", else the key.\n */\n label?: string;\n /** Cell content. `index` is the row's position on the current page. */\n renderCell?: (item: T, index: number) => ReactNode;\n /** Width in pixels. A resized width replaces it. Without one the column flexes. */\n width?: number;\n /** Lower bound, in pixels, of a flexing column. */\n minWidth?: number;\n align?: \"start\" | \"center\" | \"end\";\n /** Makes the column sortable. The sort state names it by this key. */\n sortKey?: string;\n /**\n * Sorts the rows on the client when this column is sorted. Compare in\n * ascending order; the grid reverses the result for descending.\n */\n compare?: (a: T, b: T, direction: DataGridSortDirection) => number;\n /**\n * Pins the column to an edge. Only the contiguous run of pinned columns at\n * each edge of the displayed order is pinned.\n */\n pin?: \"start\" | \"end\";\n /** Column settings cannot hide it. */\n isAlwaysVisible?: boolean;\n /** Hidden until the user shows it in the column settings. */\n isHiddenByDefault?: boolean;\n /** Fields this column exports as. Without them it cannot be exported. */\n exportKeys?: ReadonlyArray<string>;\n /** Extra attributes for this column's body cells. */\n getCellProps?: (item: T, index: number) => TdHTMLAttributes<HTMLTableCellElement>;\n}\n\n/** Per-column settings a user changed, keyed by column key. */\nexport interface DataGridColumnOverride {\n hidden?: boolean;\n /** Display position. Lower comes first. Set only after a reorder. */\n order?: number;\n /** Resized width in pixels. */\n width?: number;\n}\n\nexport type DataGridColumnOverrides = Record<string, DataGridColumnOverride>;\n\nexport interface DataGridColumnSettings {\n /** Controlled overrides. */\n overrides?: DataGridColumnOverrides;\n /** Initial overrides when uncontrolled; always merged under `overrides`. */\n defaultOverrides?: DataGridColumnOverrides;\n onOverridesChange?: (overrides: DataGridColumnOverrides) => void;\n /** Whether the settings dialog lets the user reorder columns. Default: true */\n isReorderable?: boolean;\n /** Strings of the settings dialog. */\n modalProps?: Pick<\n DataGridSettingsModalProps,\n \"title\" | \"subtitle\" | \"searchLabel\" | \"noMatchText\" | \"applyLabel\" | \"cancelLabel\"\n >;\n}\n\nexport interface DataGridCsvExport {\n /** Export keys the backend can produce. Columns asking for others are disabled. */\n supportedKeys: ReadonlyArray<string>;\n /** Runs the export with the chosen keys. The dialog closes when it resolves. */\n onExport: (keys: string[]) => Promise<void>;\n /** A warning above the column list, e.g. that the export is truncated. */\n notice?: ReactNode;\n /** Strings of the export dialog. */\n modalProps?: Pick<\n DataGridExportModalProps,\n \"title\" | \"subtitle\" | \"searchLabel\" | \"noMatchText\" | \"exportLabel\" | \"cancelLabel\"\n >;\n}\n\nexport interface DataGridSelection<T> {\n /** The selected row keys. Selection is controlled. */\n selectedKeys?: ReadonlyArray<DataGridKey>;\n onChange?: (keys: string[], items: T[]) => void;\n /** Whether a row's checkbox is enabled. Select-all leaves a disabled row as it is. */\n getIsItemEnabled?: (item: T) => boolean;\n /** Accessible name of a row's checkbox. Default: the row key. */\n getRowLabel?: (item: T) => string;\n /** Select-all keeps keys of rows on other pages. Default: false */\n isPreservingOtherPages?: boolean;\n}\n\nexport interface DataGridExpansion<T> {\n renderExpandedRow: (item: T, index: number) => ReactNode;\n getIsRowExpandable?: (item: T) => boolean;\n /** Controlled expanded row keys. */\n expandedKeys?: ReadonlyArray<DataGridKey>;\n defaultExpandedKeys?: ReadonlyArray<DataGridKey>;\n onExpandedKeysChange?: (keys: ReadonlyArray<DataGridKey>) => void;\n /** Header content of the expand-button column. */\n columnHeader?: ReactNode;\n /** Width in pixels of the expand-button column. */\n columnWidth?: number;\n}\n\nexport interface DataGridPagination extends Omit<\n PaginationProps,\n | \"page\"\n | \"totalItems\"\n | \"onChange\"\n | \"onPageSizeChange\"\n | \"label\"\n | \"ref\"\n | \"totalPages\"\n | \"hasMore\"\n> {\n /** Controlled page, 1-based. */\n page?: number;\n defaultPage?: number;\n defaultPageSize?: number;\n /**\n * Total row count. Without it the grid pages `data` itself; a total larger\n * than `data` declares the rows already sliced to the page.\n */\n totalItems?: number;\n onChange?: (page: number, pageSize: number) => void;\n /** Whether the bar offers a page-size choice. Default: true */\n hasPageSizeSelector?: boolean;\n /** Hides the page bar while every row fits on one page. Default: false */\n isHiddenOnSinglePage?: boolean;\n /** Content at the end of the bar. */\n endContent?: ReactNode;\n}\n\ntype AnyRow = Record<string, unknown>;\n\nexport interface DataGridProps<T extends object = AnyRow> extends Omit<\n TableProps<AnyRow>,\n | \"data\"\n | \"columns\"\n | \"idKey\"\n | \"rowIndexStart\"\n | \"rowCount\"\n | \"children\"\n | \"scrollWrapper\"\n | \"ref\"\n | \"emptyState\"\n | \"className\"\n | \"style\"\n | \"plugins\"\n | \"onChange\"\n> {\n data?: ReadonlyArray<T>;\n columns?: ReadonlyArray<DataGridColumn<T>>;\n /**\n * Row identity: a field name or a function. A missing field falls back to\n * the row's `key`, then its `id`, then its position.\n */\n idKey?: string | ((item: T) => DataGridKey);\n /** Dims the rows and blocks input while data is refetched. */\n isLoading?: boolean;\n /** Drag-to-resize column borders. Default: true */\n isResizable?: boolean;\n /** Controlled sort; `null` for none. */\n sort?: DataGridSort | null;\n defaultSort?: DataGridSort | null;\n onSortChange?: (sort: DataGridSort | null) => void;\n selection?: DataGridSelection<T>;\n /** The page bar. `false` shows every row and no bar. */\n pagination?: false | DataGridPagination;\n /** Enables the column settings button and persists resized widths. */\n columnSettings?: DataGridColumnSettings;\n /** Enables the CSV export button. */\n csvExport?: DataGridCsvExport;\n expansion?: DataGridExpansion<T>;\n /**\n * Shown in place of the rows when there are none. A string gets the default\n * icon and layout, a node is rendered as is, `false` shows nothing. Default:\n * the catalog's `uic.DataGrid.noData`.\n */\n emptyState?: ReactNode | false;\n /** Extra attributes for a body row. */\n getRowProps?: (\n item: T,\n index: number | undefined,\n ) => HTMLAttributes<HTMLTableRowElement>;\n /**\n * Scrolls horizontally with the table at this width (at least the\n * container's). Columns without a width then size to their content.\n */\n scrollWidth?: number | string;\n /** Caps the rows' height and makes the header sticky. */\n maxHeight?: number | string;\n /** Hides the header row, and with it sorting and select-all. */\n isHeaderHidden?: boolean;\n /** Accessible name of the expand buttons. Default: the catalog's `uic.DataGrid.expandRow` */\n expandRowLabel?: string;\n /** Shown when the page lies past the last one. Default: the catalog's `uic.DataGrid.invalidPage` */\n invalidPageText?: string;\n /** Default: the catalog's `uic.DataGrid.goToFirstPage` */\n goToFirstPageLabel?: string;\n /** Accessible name of the page navigation. Default: the catalog's `uic.DataGrid.pagination` */\n paginationLabel?: string;\n /** The range line beside the page navigation. Default: the catalog's `uic.DataGrid.range` */\n renderRange?: (range: { start: number; end: number; total: number }) => ReactNode;\n /** Default: the catalog's `uic.DataGrid.settings` */\n settingsLabel?: string;\n /** Default: the catalog's `uic.DataGrid.exportCsv` */\n exportLabel?: string;\n className?: string;\n style?: CSSProperties;\n}\n\nconst EXPAND_COLUMN_KEY = \"__uic_expand__\";\n/** Key of the checkbox column Astryx's selection plugin injects; not exported by Astryx. */\nconst SELECTION_COLUMN_KEY = \"__xds_selection\";\n/**\n * Measured column widths, in pixels. Selection: Astryx's 24px first-column\n * inset + the 20px checkbox + an 8px trailing pad (the plugin's own 36 lets\n * the checkbox overhang its cell). Expand: the same inset + the 24px button +\n * 8px, or an 8px lead-in instead of the inset behind a selection column.\n */\nconst SELECTION_COLUMN_WIDTH = 52;\nconst EXPAND_COLUMN_WIDTH_FIRST = 56;\nconst EXPAND_COLUMN_WIDTH_AFTER_SELECTION = 40;\nconst MIN_COLUMN_WIDTH = 60;\nconst DETAIL_ROW_MARKER = \"__uic_detail_for__\";\nconst DEFAULT_PAGE_SIZE = 10;\nconst DEFAULT_PAGE_SIZE_OPTIONS = [10, 20, 50];\n\nconst EMPTY_STATE_ICON = <Icon icon={Inbox} size=\"lg\" color=\"secondary\" />;\n\nconst X_HEADER_RELEASE: CSSProperties = { width: \"auto\", maxWidth: \"none\" };\nconst X_BODY_RELEASE: CSSProperties = { maxWidth: \"none\" };\n// Inline beats the sticky-header rule's z 2 for pinned header cells.\nconst Y_PINNED_HEADER_STACK: CSSProperties = { zIndex: 3 };\n\nconst isDetailRow = (item: unknown): item is AnyRow =>\n !!item && typeof item === \"object\" && DETAIL_ROW_MARKER in item;\n\nconst toCssLength = (value: number | string): string =>\n typeof value === \"number\" ? `${value}px` : value;\n\nfunction mergeCellStyle<P extends { htmlProps: { style?: CSSProperties } }>(\n props: P,\n extra: CSSProperties,\n): P {\n return {\n ...props,\n htmlProps: {\n ...props.htmlProps,\n style: props.htmlProps.style ? { ...props.htmlProps.style, ...extra } : extra,\n },\n };\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\n/** The label a column carries in the settings and export dialogs. */\nexport function dataGridColumnLabel<T>(column: DataGridColumn<T>): string {\n if (column.label) return column.label;\n const own = nodeToPlainText(column.header).trim();\n const group = nodeToPlainText(column.groupHeader).trim();\n const label = group && own ? `${group} / ${own}` : own || group;\n return label || column.key;\n}\n\n/** Whether a column shows, given the user's overrides. */\n/**\n * The overrides record a settings dialog result writes. `defaultOverrides`\n * stays merged under it key by key, and a key it holds replaces the default's\n * entry whole. So a column is left out only while its default (natural, then\n * `defaultOverrides`) already renders what the user chose, and an entry that\n * is written states everything that differs from the natural column:\n * otherwise re-showing a column the defaults hide, or restoring the natural\n * order over a reordering default, would bring the default back.\n *\n * @internal Exported for tests.\n */\nexport function dataGridSettingsToOverrides({\n columns,\n result,\n defaultOverrides = {},\n overrides,\n isReorderable,\n}: {\n columns: ReadonlyArray<Pick<DataGridColumn<never>, \"key\" | \"isHiddenByDefault\">>;\n result: DataGridSettingsResult;\n defaultOverrides?: DataGridColumnOverrides;\n /** The overrides in effect, defaults merged; their widths are kept. */\n overrides: DataGridColumnOverrides;\n isReorderable: boolean;\n}): DataGridColumnOverrides {\n const naturalOrder = columns.map((column) => column.key);\n // A default order is only undone by stating every column's position.\n const writesOrder =\n isReorderable &&\n (result.columnOrder.length !== naturalOrder.length ||\n result.columnOrder.some((key, index) => key !== naturalOrder[index]) ||\n columns.some((column) => defaultOverrides[column.key]?.order !== undefined));\n const next: DataGridColumnOverrides = {};\n for (const column of columns) {\n const fallback = defaultOverrides[column.key];\n const naturalHidden = !!column.isHiddenByDefault;\n const defaultHidden = fallback?.hidden ?? naturalHidden;\n const hidden = !result.selectedColumnKeys.includes(column.key);\n const override: DataGridColumnOverride = {};\n if (hidden !== naturalHidden || hidden !== defaultHidden) override.hidden = hidden;\n if (writesOrder) {\n const orderIndex = result.columnOrder.indexOf(column.key);\n if (orderIndex !== -1) override.order = orderIndex;\n }\n // A settings change must not reset resized widths.\n const width = overrides[column.key]?.width;\n if (typeof width === \"number\") override.width = width;\n const matchesDefault =\n hidden === defaultHidden &&\n override.order === fallback?.order &&\n override.width === fallback?.width;\n if (!matchesDefault && Object.keys(override).length > 0)\n next[column.key] = override;\n }\n return next;\n}\n\nexport function isDataGridColumnVisible<T>(\n column: Pick<DataGridColumn<T>, \"key\" | \"isAlwaysVisible\" | \"isHiddenByDefault\">,\n overrides?: DataGridColumnOverrides,\n): boolean {\n if (column.isAlwaysVisible) return true;\n const hidden = overrides?.[column.key]?.hidden;\n return hidden !== undefined ? !hidden : !column.isHiddenByDefault;\n}\n\n/** Controlled when `value` is not undefined; the setter writes state only when uncontrolled. */\nfunction useControllableState<V>(value: V | undefined, initial: () => V) {\n const [state, setState] = useState<V>(initial);\n const isControlled = value !== undefined;\n const current = isControlled ? value : state;\n const set = (next: V) => {\n if (!isControlled) setState(next);\n };\n return [current, set] as const;\n}\n\nexport function DataGrid<T extends object = AnyRow>({\n data,\n columns = [],\n idKey = \"id\",\n isLoading = false,\n isResizable = true,\n sort: sortProp,\n defaultSort,\n onSortChange,\n selection,\n pagination,\n columnSettings,\n csvExport,\n expansion,\n emptyState,\n getRowProps,\n scrollWidth,\n maxHeight,\n isHeaderHidden = false,\n expandRowLabel,\n invalidPageText,\n goToFirstPageLabel,\n paginationLabel,\n renderRange,\n settingsLabel,\n exportLabel,\n density = \"compact\",\n dividers = \"rows\",\n hasHover = true,\n textOverflow = \"truncate\",\n className,\n style,\n ...tableProps\n}: DataGridProps<T>): ReactElement {\n const t = useUicTranslator();\n\n const isScrollX = scrollWidth !== undefined;\n const isScrollY = maxHeight !== undefined;\n\n const [isSettingsOpen, setIsSettingsOpen] = useState(false);\n const [isExportOpen, setIsExportOpen] = useState(false);\n\n /* ---- column overrides (visibility / order / width) ------------------- */\n\n const [storedOverrides, setStoredOverrides] = useState<DataGridColumnOverrides>(\n () => columnSettings?.defaultOverrides ?? {},\n );\n const isOverridesControlled = columnSettings?.overrides !== undefined;\n const ownOverrides = isOverridesControlled\n ? (columnSettings?.overrides ?? {})\n : storedOverrides;\n const setOverrides = (next: DataGridColumnOverrides) => {\n if (!isOverridesControlled) setStoredOverrides(next);\n columnSettings?.onOverridesChange?.(next);\n };\n const overrides: DataGridColumnOverrides = {\n ...(columnSettings?.defaultOverrides ?? {}),\n ...ownOverrides,\n };\n const isReorderable = !!columnSettings && columnSettings.isReorderable !== false;\n\n /* ---- resized widths ---------------------------------------------------- */\n\n // With columnSettings a width rides in the overrides record, so a resize\n // persists like a visibility change; without it the width is local state.\n const [localWidths, setLocalWidths] = useState<Record<string, number>>({});\n const columnWidths: Record<string, number> = {};\n if (columnSettings) {\n for (const [key, override] of Object.entries(overrides)) {\n if (typeof override?.width === \"number\") columnWidths[key] = override.width;\n }\n } else {\n Object.assign(columnWidths, localWidths);\n }\n\n const handleResizeEnd = (updates: Record<string, number>) => {\n if (!columnSettings) {\n setLocalWidths((prev) => ({ ...prev, ...updates }));\n return;\n }\n const next: DataGridColumnOverrides = { ...ownOverrides };\n for (const [key, width] of Object.entries(updates)) {\n if (key === EXPAND_COLUMN_KEY) continue;\n next[key] = { ...next[key], width };\n }\n setOverrides(next);\n };\n\n /* ---- row keys ---------------------------------------------------------- */\n\n const getRowKey = (item: T): string => {\n if (typeof idKey === \"function\") return String(idKey(item));\n const row = item as AnyRow;\n const direct = row[idKey];\n if (direct != null) return String(direct);\n const fallback = row.key ?? row.id;\n if (fallback != null) return String(fallback);\n return `__row_${data ? data.indexOf(item) : -1}`;\n };\n\n /* ---- sort -------------------------------------------------------------- */\n\n const [activeSort, setActiveSort] = useControllableState<DataGridSort | null>(\n sortProp,\n () => defaultSort ?? null,\n );\n\n const sortedRows = ((): T[] => {\n const source = data ? [...data] : [];\n if (!activeSort) return source;\n const compare = columns.find(\n (column) => column.sortKey === activeSort.sortKey && column.compare,\n )?.compare;\n if (!compare) return source;\n const { direction } = activeSort;\n return source.sort((a, b) =>\n direction === \"descending\" ? -compare(a, b, direction) : compare(a, b, direction),\n );\n })();\n\n /* ---- pagination -------------------------------------------------------- */\n\n const pager = pagination === false ? undefined : (pagination ?? {});\n const [currentPage, setCurrentPage] = useControllableState<number>(\n pager?.page,\n () => pager?.defaultPage ?? 1,\n );\n const [pageSize, setPageSize] = useControllableState<number>(\n pager?.pageSize,\n () => pager?.defaultPageSize ?? DEFAULT_PAGE_SIZE,\n );\n\n // Astryx's Pagination answers a page-size pick with onPageSizeChange(size)\n // and then onChange(1) in the same event, still closing over the old size.\n // Forwarding the second call would undo the pick on a controlled grid, so it\n // is dropped; a microtask clears the flag.\n const isPageSizeChangingRef = useRef(false);\n\n const total = pager?.totalItems ?? sortedRows.length;\n const lastPage = Math.max(1, Math.ceil(total / pageSize));\n const activePage = clamp(currentPage, 1, lastPage);\n const isPageOutOfRange =\n !!pager && total > 0 && (currentPage < 1 || currentPage > lastPage);\n // A total above the rows in hand means they are already one page.\n const isServerSliced = total > sortedRows.length;\n const pagedRows =\n pager && !isServerSliced && sortedRows.length > pageSize\n ? sortedRows.slice((activePage - 1) * pageSize, activePage * pageSize)\n : sortedRows;\n const rows = isPageOutOfRange ? [] : pagedRows;\n\n /* ---- expansion --------------------------------------------------------- */\n\n const [storedExpandedKeys, setStoredExpandedKeys] = useState<DataGridKey[]>(() => [\n ...(expansion?.defaultExpandedKeys ?? []),\n ]);\n const expandedKeys = expansion?.expandedKeys ?? storedExpandedKeys;\n const expandedKeySet = new Set(expandedKeys.map(String));\n const hasExpansion = !!expansion;\n const expandColumnWidth =\n expansion?.columnWidth ??\n (selection ? EXPAND_COLUMN_WIDTH_AFTER_SELECTION : EXPAND_COLUMN_WIDTH_FIRST);\n const detailInsetStart = (selection ? SELECTION_COLUMN_WIDTH : 0) + expandColumnWidth;\n\n const toggleExpanded = (key: string) => {\n const next = expandedKeySet.has(key)\n ? expandedKeys.filter((k) => String(k) !== key)\n : [...expandedKeys, key];\n if (!expansion?.expandedKeys) setStoredExpandedKeys(next);\n expansion?.onExpandedKeysChange?.(next);\n };\n\n const rowIndexByKey = new Map<string, number>();\n rows.forEach((item, index) => rowIndexByKey.set(getRowKey(item), index));\n\n // Each expanded row is followed by a marker row the expansion plugin turns\n // into one full-width cell.\n const tableData: AnyRow[] = [];\n for (const item of rows) {\n tableData.push(item as AnyRow);\n if (!hasExpansion) continue;\n const key = getRowKey(item);\n if (expandedKeySet.has(key) && (expansion?.getIsRowExpandable?.(item) ?? true)) {\n tableData.push({ [DETAIL_ROW_MARKER]: key, id: `${key}__detail` });\n }\n }\n\n // From every row, not the page: selection resolves keys on other pages too.\n const itemByKey = new Map<string, T>();\n sortedRows.forEach((item) => itemByKey.set(getRowKey(item), item));\n\n /* ---- Astryx columns ---------------------------------------------------- */\n\n const tableColumns: TableColumn<AnyRow>[] = [];\n if (hasExpansion) {\n tableColumns.push({\n key: EXPAND_COLUMN_KEY,\n header: expansion?.columnHeader ?? \"\",\n width: pixel(expandColumnWidth),\n resizable: false,\n renderCell: (row) => {\n if (isDetailRow(row)) return null;\n const item = row as T;\n if (!(expansion?.getIsRowExpandable?.(item) ?? true)) return null;\n const key = getRowKey(item);\n return (\n <IconButton\n label={expandRowLabel ?? t(\"uic.DataGrid.expandRow\")}\n icon={expandedKeySet.has(key) ? <ChevronDown /> : <ChevronRight />}\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => toggleExpanded(key)}\n />\n );\n },\n });\n }\n\n for (const column of columns) {\n const width = columnWidths[column.key] ?? column.width;\n const header = (\n <span className=\"uic-data-grid__clip\">\n {column.groupHeader == null ? (\n column.header\n ) : (\n <VStack gap={0} align=\"start\">\n <Text type=\"supporting\" color=\"secondary\">\n {column.groupHeader}\n </Text>\n <span>{column.header}</span>\n </VStack>\n )}\n </span>\n );\n tableColumns.push({\n key: column.key,\n header,\n align: column.align === \"start\" ? undefined : column.align,\n sortable: column.sortKey ? { sortKey: column.sortKey } : false,\n resizable: isResizable,\n // In scroll-x mode a width-less column takes no width, so its content sizes it.\n width:\n width != null\n ? pixel(width)\n : isScrollX\n ? undefined\n : proportional(\n 1,\n typeof column.minWidth === \"number\"\n ? { minWidth: column.minWidth }\n : undefined,\n ),\n renderCell: (row) => {\n if (isDetailRow(row)) return null;\n const item = row as T;\n const content = column.renderCell\n ? column.renderCell(item, rowIndexByKey.get(getRowKey(item)) ?? 0)\n : defaultCell(row[column.key]);\n if (textOverflow !== \"truncate\" || content == null) return content;\n return <span className=\"uic-data-grid__clip\">{content}</span>;\n },\n });\n }\n\n /* ---- visibility + order ------------------------------------------------ */\n\n const visibleColumns = columnSettings\n ? columns.filter((column) => isDataGridColumnVisible(column, overrides))\n : [...columns];\n const orderedColumns = isReorderable\n ? visibleColumns\n .map((column, index) => ({ column, index }))\n .sort(\n (a, b) =>\n (overrides[a.column.key]?.order ?? Number.MAX_SAFE_INTEGER) -\n (overrides[b.column.key]?.order ?? Number.MAX_SAFE_INTEGER) ||\n a.index - b.index,\n )\n .map(({ column }) => column)\n : visibleColumns;\n const activeColumnKeys = [\n ...(hasExpansion ? [EXPAND_COLUMN_KEY] : []),\n ...orderedColumns.map((column) => column.key),\n ];\n\n const columnSettingsPlugin = useTableColumnSettings<AnyRow>({\n columns: [\n ...(hasExpansion\n ? [{ key: EXPAND_COLUMN_KEY, label: \"\", isAlwaysVisible: true }]\n : []),\n ...columns.map((column) => ({\n key: column.key,\n label: dataGridColumnLabel(column),\n isAlwaysVisible: !!column.isAlwaysVisible,\n })),\n ],\n activeColumnKeys,\n // The settings dialog owns the write path (it keeps `order` and `width`).\n onChangeActiveColumnKeys: () => {},\n });\n\n /* ---- pinning ----------------------------------------------------------- */\n\n const startKeys: string[] = [];\n for (const column of orderedColumns) {\n if (column.pin === \"start\") startKeys.push(column.key);\n else break;\n }\n const endKeys: string[] = [];\n for (const column of [...orderedColumns].reverse()) {\n if (column.pin === \"end\") endKeys.unshift(column.key);\n else break;\n }\n const stickyConfig = {\n startKeys:\n startKeys.length === 0\n ? undefined\n : [\n ...(selection ? [SELECTION_COLUMN_KEY] : []),\n ...(hasExpansion ? [EXPAND_COLUMN_KEY] : []),\n ...startKeys,\n ],\n endKeys: endKeys.length === 0 ? undefined : endKeys,\n };\n const stickyPlugin = useTableStickyColumns<AnyRow>(\n stickyConfig.startKeys || stickyConfig.endKeys ? stickyConfig : {},\n );\n\n /* ---- per-cell / per-row attributes -------------------------------------- */\n\n const columnByKey = new Map(columns.map((column) => [column.key, column]));\n\n const cellRowPlugin: TablePlugin<AnyRow> = {\n transformBodyCell: (props, column, row) => {\n if (isDetailRow(row)) return props;\n const item = row as T;\n const extra = columnByKey\n .get(column.key)\n ?.getCellProps?.(item, rowIndexByKey.get(getRowKey(item)) ?? 0);\n if (!extra) return props;\n return {\n ...props,\n htmlProps: {\n ...props.htmlProps,\n ...extra,\n style: { ...props.htmlProps.style, ...extra.style },\n },\n };\n },\n transformBodyRow: (props, row) => {\n if (!getRowProps || isDetailRow(row)) return props;\n const item = row as T;\n const extra = getRowProps(item, rowIndexByKey.get(getRowKey(item)));\n if (!extra) return props;\n return {\n ...props,\n htmlProps: {\n ...props.htmlProps,\n ...extra,\n style: { ...props.htmlProps.style, ...extra.style },\n },\n };\n },\n };\n\n // Astryx clips cells with `max-width: 0`; scroll-x releases width-less columns only.\n const scrollXPlugin: TablePlugin<AnyRow> = {\n transformHeaderCell: (props, column) =>\n column.width != null ? props : mergeCellStyle(props, X_HEADER_RELEASE),\n transformBodyCell: (props, column) =>\n column.width != null ? props : mergeCellStyle(props, X_BODY_RELEASE),\n };\n\n const pinnedKeys = new Set([\n ...(stickyConfig.startKeys ?? []),\n ...(stickyConfig.endKeys ?? []),\n ]);\n const scrollYPlugin: TablePlugin<AnyRow> = {\n transformHeaderCell: (props, column) =>\n pinnedKeys.has(column.key) ? mergeCellStyle(props, Y_PINNED_HEADER_STACK) : props,\n };\n\n /* ---- sorting ----------------------------------------------------------- */\n\n const sortState: TableSortState = activeSort\n ? [{ sortKey: activeSort.sortKey, direction: activeSort.direction }]\n : [];\n\n const sortPlugin = useTableSortable<AnyRow>({\n sort: sortState,\n allowUnsortedState: true,\n onSortChange: (next) => {\n const first = next[0];\n const nextSort: DataGridSort | null = first\n ? { sortKey: first.sortKey, direction: first.direction }\n : null;\n setActiveSort(nextSort);\n onSortChange?.(nextSort);\n },\n });\n\n /* ---- selection --------------------------------------------------------- */\n\n const selectedKeySet = new Set((selection?.selectedKeys ?? []).map(String));\n const emitSelection = (keys: string[]) => {\n const items = keys\n .map((key) => itemByKey.get(key))\n .filter((item) => item !== undefined);\n selection?.onChange?.(keys, items);\n };\n const isRowSelected = (item: T) => selectedKeySet.has(getRowKey(item));\n const isRowEnabled = (item: T) => selection?.getIsItemEnabled?.(item) ?? true;\n // Select-all acts on the enabled rows only; a disabled row keeps its state.\n const enabledRows = rows.filter(isRowEnabled);\n\n const selectionPlugin = useTableSelection<AnyRow>({\n getIsItemSelectable: (row) => !isDetailRow(row),\n getIsItemSelected: (row) => !isDetailRow(row) && isRowSelected(row as T),\n getIsItemEnabled: (row) => !isDetailRow(row) && isRowEnabled(row as T),\n getRowLabel: (row) =>\n isDetailRow(row)\n ? \"\"\n : (selection?.getRowLabel?.(row as T) ?? getRowKey(row as T)),\n getIsAllSelected: () => enabledRows.length > 0 && enabledRows.every(isRowSelected),\n getIsIndeterminate: () =>\n enabledRows.some(isRowSelected) && !enabledRows.every(isRowSelected),\n onSelectItem: ({ item, isSelected }) => {\n if (isDetailRow(item)) return;\n const key = getRowKey(item as T);\n const next = new Set(selectedKeySet);\n if (isSelected) next.add(key);\n else next.delete(key);\n emitSelection([...next]);\n },\n onSelectAll: ({ isAllSelected }) => {\n const next = new Set(selection?.isPreservingOtherPages ? selectedKeySet : []);\n for (const item of rows) {\n const key = getRowKey(item);\n const isSelected = isRowEnabled(item) ? isAllSelected : isRowSelected(item);\n if (isSelected) next.add(key);\n else next.delete(key);\n }\n emitSelection([...next]);\n },\n });\n\n const selectionWidthPlugin: TablePlugin<AnyRow> = {\n transformColumns: (cols) =>\n cols.map((column) =>\n column.key === SELECTION_COLUMN_KEY\n ? { ...column, width: pixel(SELECTION_COLUMN_WIDTH) }\n : column,\n ),\n };\n\n /* ---- resize ------------------------------------------------------------ */\n\n const resizePlugin = useTableColumnResize<AnyRow>({\n columns: tableColumns,\n columnWidths,\n minWidth: MIN_COLUMN_WIDTH,\n onColumnResizeEnd: handleResizeEnd,\n });\n\n /* ---- expansion --------------------------------------------------------- */\n\n const renderedColumnCount = activeColumnKeys.length + (selection ? 1 : 0);\n const expansionPlugin: TablePlugin<AnyRow> = {\n transformBodyRow: (props, row) => {\n if (!isDetailRow(row)) return props;\n const parentKey = String(row[DETAIL_ROW_MARKER]);\n const item = itemByKey.get(parentKey);\n if (!item) return props;\n return {\n ...props,\n children: (\n <td\n colSpan={renderedColumnCount}\n className=\"uic-data-grid__detail\"\n style={{ paddingInlineStart: detailInsetStart }}\n >\n {expansion?.renderExpandedRow(item, rowIndexByKey.get(parentKey) ?? 0)}\n </td>\n ),\n };\n },\n };\n\n const plugins: Record<string, TablePlugin<AnyRow>> = {\n columnSettings: columnSettingsPlugin,\n sort: sortPlugin,\n };\n if (selection) {\n plugins.selection = selectionPlugin;\n plugins.selectionWidth = selectionWidthPlugin;\n }\n if (isResizable) plugins.resize = resizePlugin;\n plugins.sticky = stickyPlugin;\n if (isScrollX) plugins.scrollX = scrollXPlugin;\n // Without pinned columns the sticky header is pure CSS.\n if (isScrollY && pinnedKeys.size > 0) plugins.scrollY = scrollYPlugin;\n plugins.cellRow = cellRowPlugin;\n if (hasExpansion) plugins.expansion = expansionPlugin;\n\n /* ---- bottom bar -------------------------------------------------------- */\n\n const {\n page: _page,\n defaultPage: _defaultPage,\n defaultPageSize: _defaultPageSize,\n totalItems: _totalItems,\n onChange: _onChange,\n hasPageSizeSelector = true,\n isHiddenOnSinglePage = false,\n endContent,\n pageSizeOptions,\n size: pagerSize = \"sm\",\n ...paginationRest\n } = pager ?? {};\n\n const rangeStart = total === 0 ? 0 : (activePage - 1) * pageSize + 1;\n const rangeEnd = Math.min(activePage * pageSize, total);\n const isPagerVisible = !!pager && !(isHiddenOnSinglePage && total <= pageSize);\n const hasBottomBar = isPagerVisible || !!columnSettings || !!csvExport;\n\n const emptyStateNode = isPageOutOfRange ? (\n // The way back outranks any empty state the caller gave.\n <EmptyState\n isCompact\n icon={EMPTY_STATE_ICON}\n title={invalidPageText ?? t(\"uic.DataGrid.invalidPage\")}\n actions={\n <Button\n variant=\"primary\"\n label={goToFirstPageLabel ?? t(\"uic.DataGrid.goToFirstPage\")}\n onClick={() => {\n setCurrentPage(1);\n pager?.onChange?.(1, pageSize);\n }}\n />\n }\n />\n ) : emptyState === false ? (\n false\n ) : emptyState == null || typeof emptyState === \"string\" ? (\n <EmptyState\n isCompact\n icon={EMPTY_STATE_ICON}\n title={emptyState ?? t(\"uic.DataGrid.noData\")}\n />\n ) : (\n emptyState\n );\n\n const applySettings = (result: DataGridSettingsResult) => {\n setIsSettingsOpen(false);\n setOverrides(\n dataGridSettingsToOverrides({\n columns,\n result,\n defaultOverrides: columnSettings?.defaultOverrides,\n overrides,\n isReorderable,\n }),\n );\n };\n\n return (\n <div\n className={[\"uic-data-grid\", className].filter(Boolean).join(\" \")}\n style={style}\n >\n <div\n aria-busy={isLoading || undefined}\n className={[\n \"uic-data-grid__body\",\n isLoading && \"uic-data-grid__body--loading\",\n isHeaderHidden && \"uic-data-grid__body--no-header\",\n dividers !== \"grid\" && \"uic-data-grid__body--header-split\",\n isScrollX && \"uic-data-grid__body--scroll-x\",\n isScrollY && \"uic-data-grid__body--scroll-y\",\n ]\n .filter(Boolean)\n .join(\" \")}\n style={\n {\n ...(isScrollX\n ? { \"--data-grid-scroll-width\": toCssLength(scrollWidth) }\n : null),\n ...(isScrollY\n ? { \"--data-grid-max-height\": toCssLength(maxHeight) }\n : null),\n } as CSSProperties\n }\n >\n <Table<AnyRow>\n {...tableProps}\n data={tableData}\n columns={tableColumns}\n idKey={(row: AnyRow) =>\n isDetailRow(row)\n ? `${String(row[DETAIL_ROW_MARKER])}__detail`\n : getRowKey(row as T)\n }\n density={density}\n dividers={dividers}\n hasHover={hasHover}\n textOverflow={textOverflow}\n emptyState={emptyStateNode}\n rowCount={total || undefined}\n rowIndexStart={pager ? (activePage - 1) * pageSize + 1 : undefined}\n plugins={plugins}\n />\n </div>\n\n {hasBottomBar ? (\n <HStack justify=\"end\" align=\"center\" gap={2} className=\"uic-data-grid__footer\">\n {isPagerVisible ? (\n <>\n <Text type=\"supporting\" color=\"secondary\">\n {renderRange\n ? renderRange({ start: rangeStart, end: rangeEnd, total })\n : t(\"uic.DataGrid.range\", {\n start: rangeStart,\n end: rangeEnd,\n total,\n })}\n </Text>\n <Pagination\n variant=\"pages\"\n {...paginationRest}\n page={activePage}\n pageSize={pageSize}\n totalItems={total}\n // Astryx shows the size choice exactly when options are passed.\n pageSizeOptions={\n hasPageSizeSelector\n ? (pageSizeOptions ?? DEFAULT_PAGE_SIZE_OPTIONS)\n : undefined\n }\n size={pagerSize}\n label={paginationLabel ?? t(\"uic.DataGrid.pagination\")}\n onChange={(page) => {\n if (isPageSizeChangingRef.current) return;\n setCurrentPage(page);\n pager?.onChange?.(page, pageSize);\n }}\n onPageSizeChange={(nextSize) => {\n isPageSizeChangingRef.current = true;\n queueMicrotask(() => {\n isPageSizeChangingRef.current = false;\n });\n setCurrentPage(1);\n setPageSize(nextSize);\n pager?.onChange?.(1, nextSize);\n }}\n />\n </>\n ) : null}\n {columnSettings ? (\n <IconButton\n label={settingsLabel ?? t(\"uic.DataGrid.settings\")}\n icon={<Settings />}\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setIsSettingsOpen(true)}\n />\n ) : null}\n {csvExport ? (\n <IconButton\n label={exportLabel ?? t(\"uic.DataGrid.exportCsv\")}\n icon={<FileDown />}\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => setIsExportOpen(true)}\n />\n ) : null}\n {pager ? endContent : null}\n </HStack>\n ) : null}\n\n {columnSettings ? (\n <DataGridSettingsModal\n {...columnSettings.modalProps}\n isOpen={isSettingsOpen}\n onOpenChange={setIsSettingsOpen}\n columns={columns.map((column) => ({\n key: column.key,\n label: dataGridColumnLabel(column),\n isAlwaysVisible: !!column.isAlwaysVisible,\n }))}\n visibleColumnKeys={orderedColumns.map((column) => column.key)}\n isReorderable={isReorderable}\n onApply={applySettings}\n />\n ) : null}\n\n {csvExport ? (\n <DataGridExportModal\n {...csvExport.modalProps}\n isOpen={isExportOpen}\n onOpenChange={setIsExportOpen}\n columns={columns.map((column) => ({\n key: column.key,\n label: dataGridColumnLabel(column),\n exportKeys: column.exportKeys ?? [],\n }))}\n supportedKeys={csvExport.supportedKeys}\n notice={csvExport.notice}\n onExport={async (keys) => {\n await csvExport.onExport(keys);\n setIsExportOpen(false);\n }}\n />\n ) : null}\n </div>\n );\n}\n\nfunction defaultCell(value: unknown): ReactNode {\n if (value == null || value === \"\") return null;\n if (isValidElement(value)) return value;\n return String(value);\n}\n"],"mappings":"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"}
@@ -47,7 +47,7 @@ export interface FormItemTooltipConfig {
47
47
  declare const FormItem: <Values>(props: FormItemProps<Values>) => React.JSX.Element;
48
48
  /** Errors/warnings of the nearest enclosing `Form.Item`. */
49
49
  export declare const useFormItemStatus: () => {
50
- status: "" | "success" | "error" | "warning" | "validating" | undefined;
50
+ status: "" | "error" | "success" | "warning" | "validating" | undefined;
51
51
  errors: React.ReactNode[];
52
52
  warnings: React.ReactNode[];
53
53
  };
@@ -5,14 +5,13 @@ import { RefObject } from 'react';
5
5
  */
6
6
  export declare const MODAL_OPEN_ATTRIBUTE = "data-uic-modal-open";
7
7
  /**
8
- * The open `<dialog>` a surface inside it renders into, instead of
9
- * `document.body`. A drawer is top layer whether modal (`showModal()`, which
10
- * also inerts everything outside it) or not (`showPopover()`), so a `Modal`
11
- * portalled to the body from inside one would sit behind the drawer,
12
- * unreachable. `Drawer` (src/forks/Drawer) provides its dialog while it is
13
- * open; `Modal` renders there and enters the top layer itself, as a manual
14
- * popover, so it paints above the drawer and escapes the panel's clipping
15
- * and transform. Internal: not exported from the package.
8
+ * The open modal `<dialog>` a surface inside it renders into, instead of
9
+ * `document.body`. `showModal()` makes everything outside the dialog inert,
10
+ * so a `Modal` portalled to the body from inside a scrimmed drawer would sit
11
+ * behind the drawer, unreachable. `Drawer` (src/forks/Drawer) provides its
12
+ * dialog while it is modal; `Modal` renders there and enters the top layer
13
+ * itself, as a manual popover, so it paints above the drawer and escapes the
14
+ * panel's clipping and transform. Internal: not exported from the package.
16
15
  */
17
16
  export declare const ModalPortalContext: import('react').Context<HTMLElement | null>;
18
17
  /** Nesting depth ceiling. Two surfaces past it share a level. */
@@ -33,6 +32,8 @@ export interface ModalZIndexBand {
33
32
  * `{ base: 1100, step: 10, max: 10999 }`. Pass nothing to restore it.
34
33
  */
35
34
  export declare function configureModalZIndex(next?: Partial<ModalZIndexBand>): void;
35
+ /** The band's first level; a scrimless Drawer (src/forks/Drawer) stays below it. */
36
+ export declare function modalZIndexBase(): number;
36
37
  /** A claim on the stack. Released by reference, never by level. */
37
38
  export interface ModalLevelEntry {
38
39
  level: number;
@@ -13,69 +13,72 @@ function d(e) {
13
13
  ...e
14
14
  };
15
15
  }
16
- var f = "--modal-level", p = "--modal-z", m = [];
17
- function h(e, t) {
16
+ function f() {
17
+ return u.base;
18
+ }
19
+ var p = "--modal-level", m = "--modal-z", h = [];
20
+ function g(e, t) {
18
21
  let n = t;
19
22
  n != null && (n < u.base || n > u.max) && (a("Modal", `zIndex ${n} is outside the modal band (${u.base}..${u.max}); ignoring it. Change the band with configureModalZIndex instead.`), n = void 0);
20
23
  let r = e?.zIndex ?? u.base - u.step;
21
24
  return Math.min(Math.max(r + u.step, n ?? 0), u.max);
22
25
  }
23
- var g = "data-uic-modal-live", _ = /* @__PURE__ */ new Set(), v = /* @__PURE__ */ new Set([
26
+ var _ = "data-uic-modal-live", v = /* @__PURE__ */ new Set(), y = /* @__PURE__ */ new Set([
24
27
  "SCRIPT",
25
28
  "STYLE",
26
29
  "LINK",
27
30
  "TEMPLATE",
28
31
  "NOSCRIPT"
29
32
  ]);
30
- function y(e) {
33
+ function b(e) {
31
34
  let t = new Set(e), n = /* @__PURE__ */ new Set();
32
35
  for (let t of e) for (let e = t.parentElement; e && e !== document.body;) n.add(e), e = e.parentElement;
33
36
  let r = [], i = (e) => {
34
- for (let a of Array.from(e.children)) t.has(a) || v.has(a.tagName) || (n.has(a) ? i(a) : r.push(a));
37
+ for (let a of Array.from(e.children)) t.has(a) || y.has(a.tagName) || (n.has(a) ? i(a) : r.push(a));
35
38
  };
36
39
  return i(document.body), r;
37
40
  }
38
- function b() {
39
- if (typeof document > "u" || !document.body) return;
40
- let e = m.map((e) => e.root).filter((e) => e != null && e.isConnected), t = new Set(m.length === 0 ? [] : y([...e, ...Array.from(document.querySelectorAll(`[${g}]`))]));
41
- for (let e of _) t.has(e) || (e.removeAttribute("inert"), _.delete(e));
42
- for (let e of t) _.has(e) || e.hasAttribute("inert") || (e.setAttribute("inert", ""), _.add(e));
43
- }
44
41
  function x() {
45
- (m.length > 0 || _.size > 0) && b();
42
+ if (typeof document > "u" || !document.body) return;
43
+ let e = h.map((e) => e.root).filter((e) => e != null && e.isConnected), t = new Set(h.length === 0 ? [] : b([...e, ...Array.from(document.querySelectorAll(`[${_}]`))]));
44
+ for (let e of v) t.has(e) || (e.removeAttribute("inert"), v.delete(e));
45
+ for (let e of t) v.has(e) || e.hasAttribute("inert") || (e.setAttribute("inert", ""), v.add(e));
46
46
  }
47
47
  function S() {
48
- b(), m.forEach((e, t) => {
49
- let n = t === m.length - 1;
48
+ (h.length > 0 || v.size > 0) && x();
49
+ }
50
+ function C() {
51
+ x(), h.forEach((e, t) => {
52
+ let n = t === h.length - 1;
50
53
  e.root?.toggleAttribute("inert", !n), e.isTopmost !== n && (e.isTopmost = n, e.setIsTopmost(n));
51
54
  });
52
55
  }
53
- function C(t, n, r) {
56
+ function w(t, n, r) {
54
57
  e();
55
- let i = m.at(-1), a = {
58
+ let i = h.at(-1), a = {
56
59
  level: Math.min((i?.level ?? -1) + 1, 80),
57
- zIndex: h(i, r),
60
+ zIndex: g(i, r),
58
61
  isTopmost: !0,
59
62
  root: t,
60
63
  setIsTopmost: n
61
64
  };
62
- return m.push(a), S(), a;
65
+ return h.push(a), C(), a;
63
66
  }
64
- function w(e) {
65
- let t = m.indexOf(e);
66
- t !== -1 && (e.root?.removeAttribute("inert"), m.splice(t, 1), S());
67
+ function T(e) {
68
+ let t = h.indexOf(e);
69
+ t !== -1 && (e.root?.removeAttribute("inert"), h.splice(t, 1), C());
67
70
  }
68
- function T(e, t, a) {
71
+ function E(e, t, a) {
69
72
  let [o, s] = i(!0), c = n(() => a);
70
73
  return r(() => {
71
74
  if (!t) return;
72
- let n = e.current, r = C(n, s, c());
73
- return n?.style.setProperty(f, String(r.level)), n?.style.setProperty(p, String(r.zIndex)), () => {
74
- w(r), n?.style.removeProperty(f), n?.style.removeProperty(p);
75
+ let n = e.current, r = w(n, s, c());
76
+ return n?.style.setProperty(p, String(r.level)), n?.style.setProperty(m, String(r.zIndex)), () => {
77
+ T(r), n?.style.removeProperty(p), n?.style.removeProperty(m);
75
78
  };
76
79
  }, [t, e]), o;
77
80
  }
78
81
  //#endregion
79
- export { c as MAX_MODAL_LEVEL, g as MODAL_LIVE_ATTRIBUTE, o as MODAL_OPEN_ATTRIBUTE, s as ModalPortalContext, C as claimModalLevel, d as configureModalZIndex, x as refreshModalBackground, w as releaseModalLevel, T as useModalLevel };
82
+ export { c as MAX_MODAL_LEVEL, _ as MODAL_LIVE_ATTRIBUTE, o as MODAL_OPEN_ATTRIBUTE, s as ModalPortalContext, w as claimModalLevel, d as configureModalZIndex, f as modalZIndexBase, S as refreshModalBackground, T as releaseModalLevel, E as useModalLevel };
80
83
 
81
84
  //# sourceMappingURL=modalStack.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"modalStack.js","names":[],"sources":["../../../src/components/Modal/modalStack.ts"],"sourcesContent":["/**\n * The one level stack every portalled modal surface shares.\n *\n * `Modal` renders into a `document.body` portal instead of the browser's top\n * layer (see Modal.tsx for why). Without the top layer, stacking and\n * inertness are this module's job: a surface opened from inside another\n * paints above it, only the topmost one is interactive, and while any is\n * open the page behind them is inert, except what is marked\n * `MODAL_LIVE_ATTRIBUTE`.\n *\n * Other portalled modal surfaces (a scrimmed drawer, say) claim a level with\n * `useModalLevel` so they stack on the same order as `Modal`.\n */\nimport {\n createContext,\n useEffectEvent,\n useLayoutEffect,\n useState,\n type RefObject,\n} from \"react\";\nimport { devWarn } from \"@astryxdesign/core/utils\";\n\nimport { registerInstance } from \"../../instance\";\n\n/**\n * Marks an open modal root. Scope document queries to it through this\n * constant rather than retyping the string.\n */\nexport const MODAL_OPEN_ATTRIBUTE = \"data-uic-modal-open\";\n\n/**\n * The open `<dialog>` a surface inside it renders into, instead of\n * `document.body`. A drawer is top layer whether modal (`showModal()`, which\n * also inerts everything outside it) or not (`showPopover()`), so a `Modal`\n * portalled to the body from inside one would sit behind the drawer,\n * unreachable. `Drawer` (src/forks/Drawer) provides its dialog while it is\n * open; `Modal` renders there and enters the top layer itself, as a manual\n * popover, so it paints above the drawer and escapes the panel's clipping\n * and transform. Internal: not exported from the package.\n */\nexport const ModalPortalContext = createContext<HTMLElement | null>(null);\n\n/** Nesting depth ceiling. Two surfaces past it share a level. */\nexport const MAX_MODAL_LEVEL = 80;\n\n/**\n * The z-index band modal roots paint in. `base` is the first level, each\n * nested level adds `step`, and nothing paints above `max`, so whatever the\n * app layers above the band (a notification stack) stays above every modal.\n */\nexport interface ModalZIndexBand {\n base: number;\n step: number;\n max: number;\n}\n\nconst DEFAULT_BAND: ModalZIndexBand = { base: 1100, step: 10, max: 10999 };\nlet band: ModalZIndexBand = DEFAULT_BAND;\n\n/**\n * Sets the z-index band for every modal opened after the call. Call it once,\n * at startup, to fit the app's own layer ladder. The default is\n * `{ base: 1100, step: 10, max: 10999 }`. Pass nothing to restore it.\n */\nexport function configureModalZIndex(next?: Partial<ModalZIndexBand>): void {\n band = { ...DEFAULT_BAND, ...next };\n}\n\nconst LEVEL_CSS_VAR = \"--modal-level\";\nconst Z_INDEX_CSS_VAR = \"--modal-z\";\n\n/** A claim on the stack. Released by reference, never by level. */\nexport interface ModalLevelEntry {\n level: number;\n zIndex: number;\n isTopmost: boolean;\n root: HTMLElement | null;\n setIsTopmost: (isTopmost: boolean) => void;\n}\n\nconst openModals: ModalLevelEntry[] = [];\n\n/**\n * One step above the topmost surface (or the band's base), raised by an\n * accepted override. Stacking and inertness therefore run on one order: a\n * surface opened later paints above an earlier one, whatever that one asked.\n */\nfunction resolveZIndex(\n topmost: ModalLevelEntry | undefined,\n requested?: number,\n): number {\n let override = requested;\n if (override != null && (override < band.base || override > band.max)) {\n devWarn(\n \"Modal\",\n `zIndex ${override} is outside the modal band (${band.base}..${band.max}); ` +\n \"ignoring it. Change the band with configureModalZIndex instead.\",\n );\n override = undefined;\n }\n const floor = topmost?.zIndex ?? band.base - band.step;\n return Math.min(Math.max(floor + band.step, override ?? 0), band.max);\n}\n\n/**\n * Marks an element that stays reachable while a modal is open: it, and the\n * ancestors it needs, are never made inert. `NotificationStack` sets it on\n * its root, so a notice raised over a modal can still be read and dismissed.\n * The mark is read when a modal opens or closes and on\n * `refreshModalBackground()`; call that after mounting a marked element while\n * a modal is open.\n */\nexport const MODAL_LIVE_ATTRIBUTE = \"data-uic-modal-live\";\n\n/** The background elements this module made inert, and only those. */\nconst inertedBackground = new Set<Element>();\n\nconst NEVER_INERT = new Set([\"SCRIPT\", \"STYLE\", \"LINK\", \"TEMPLATE\", \"NOSCRIPT\"]);\n\n/**\n * The elements to inert while `keep` stays reachable: every child of\n * `document.body` that holds none of them, and, inside a body child that\n * does, every sibling on the way down to them.\n */\nfunction backgroundOf(keep: Element[]): Element[] {\n const kept = new Set(keep);\n const onPath = new Set<Element>();\n for (const el of keep) {\n for (let node = el.parentElement; node && node !== document.body;) {\n onPath.add(node);\n node = node.parentElement;\n }\n }\n const out: Element[] = [];\n const visit = (parent: Element) => {\n for (const child of Array.from(parent.children)) {\n if (kept.has(child) || NEVER_INERT.has(child.tagName)) continue;\n if (onPath.has(child)) visit(child);\n else out.push(child);\n }\n };\n visit(document.body);\n return out;\n}\n\n/**\n * While any modal is open the rest of the page is `inert`, which is what\n * `aria-modal` promises. Modal roots (a drawer's too, when it claims a level\n * through `useModalLevel`) and elements marked `MODAL_LIVE_ATTRIBUTE` are\n * spared. An `inert` the page set itself is left alone, before and after.\n */\nfunction syncBackground(): void {\n if (typeof document === \"undefined\" || !document.body) return;\n const roots = openModals\n .map((entry) => entry.root)\n .filter((root): root is HTMLElement => root != null && root.isConnected);\n const target = new Set(\n openModals.length === 0\n ? []\n : backgroundOf([\n ...roots,\n ...Array.from(document.querySelectorAll(`[${MODAL_LIVE_ATTRIBUTE}]`)),\n ]),\n );\n for (const el of inertedBackground) {\n if (target.has(el)) continue;\n el.removeAttribute(\"inert\");\n inertedBackground.delete(el);\n }\n for (const el of target) {\n if (inertedBackground.has(el) || el.hasAttribute(\"inert\")) continue;\n el.setAttribute(\"inert\", \"\");\n inertedBackground.add(el);\n }\n}\n\n/**\n * Re-reads which elements are marked `MODAL_LIVE_ATTRIBUTE` (and which modal\n * roots are in the document) while a modal is open. A no-op otherwise.\n */\nexport function refreshModalBackground(): void {\n if (openModals.length > 0 || inertedBackground.size > 0) syncBackground();\n}\n\n/**\n * Only the topmost surface stays interactive. A covered one drops its focus\n * trap and goes `inert`: the trap alone lets Tab escape to the parent, and\n * `inert` alone leaves the covered trap swallowing Tab with nothing to focus.\n */\nfunction syncCovered(): void {\n syncBackground();\n openModals.forEach((entry, index) => {\n const isTopmost = index === openModals.length - 1;\n entry.root?.toggleAttribute(\"inert\", !isTopmost);\n if (entry.isTopmost !== isTopmost) {\n entry.isTopmost = isTopmost;\n entry.setIsTopmost(isTopmost);\n }\n });\n}\n\nexport function claimModalLevel(\n root: HTMLElement | null,\n setIsTopmost: (isTopmost: boolean) => void,\n requestedZIndex?: number,\n): ModalLevelEntry {\n registerInstance();\n const topmost = openModals.at(-1);\n const entry: ModalLevelEntry = {\n level: Math.min((topmost?.level ?? -1) + 1, MAX_MODAL_LEVEL),\n zIndex: resolveZIndex(topmost, requestedZIndex),\n isTopmost: true,\n root,\n setIsTopmost,\n };\n openModals.push(entry);\n syncCovered();\n return entry;\n}\n\nexport function releaseModalLevel(entry: ModalLevelEntry): void {\n const index = openModals.indexOf(entry);\n if (index === -1) return;\n entry.root?.removeAttribute(\"inert\");\n openModals.splice(index, 1);\n syncCovered();\n}\n\n/**\n * Claims a level for `rootRef` while `isOpen`, and writes the level and the\n * resolved z-index onto the root as `--modal-level` and `--modal-z`.\n * Returns whether this surface is the topmost one; gate a focus trap on it.\n */\nexport function useModalLevel(\n rootRef: RefObject<HTMLElement | null>,\n isOpen: boolean,\n zIndex?: number,\n): boolean {\n const [isTopmost, setIsTopmost] = useState(true);\n // Read at claim time only: re-claiming would move an open surface to the\n // top of the stack and inert whatever legitimately covered it.\n const readZIndex = useEffectEvent(() => zIndex);\n\n useLayoutEffect(() => {\n if (!isOpen) return;\n const root = rootRef.current;\n const entry = claimModalLevel(root, setIsTopmost, readZIndex());\n root?.style.setProperty(LEVEL_CSS_VAR, String(entry.level));\n root?.style.setProperty(Z_INDEX_CSS_VAR, String(entry.zIndex));\n return () => {\n releaseModalLevel(entry);\n root?.style.removeProperty(LEVEL_CSS_VAR);\n root?.style.removeProperty(Z_INDEX_CSS_VAR);\n };\n // An effect event is not a dependency; this plugin version predates it.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, rootRef]);\n\n return isTopmost;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"modalStack.js","names":[],"sources":["../../../src/components/Modal/modalStack.ts"],"sourcesContent":["/**\n * The one level stack every portalled modal surface shares.\n *\n * `Modal` renders into a `document.body` portal instead of the browser's top\n * layer (see Modal.tsx for why). Without the top layer, stacking and\n * inertness are this module's job: a surface opened from inside another\n * paints above it, only the topmost one is interactive, and while any is\n * open the page behind them is inert, except what is marked\n * `MODAL_LIVE_ATTRIBUTE`.\n *\n * Other portalled modal surfaces (a scrimmed drawer, say) claim a level with\n * `useModalLevel` so they stack on the same order as `Modal`.\n */\nimport {\n createContext,\n useEffectEvent,\n useLayoutEffect,\n useState,\n type RefObject,\n} from \"react\";\nimport { devWarn } from \"@astryxdesign/core/utils\";\n\nimport { registerInstance } from \"../../instance\";\n\n/**\n * Marks an open modal root. Scope document queries to it through this\n * constant rather than retyping the string.\n */\nexport const MODAL_OPEN_ATTRIBUTE = \"data-uic-modal-open\";\n\n/**\n * The open modal `<dialog>` a surface inside it renders into, instead of\n * `document.body`. `showModal()` makes everything outside the dialog inert,\n * so a `Modal` portalled to the body from inside a scrimmed drawer would sit\n * behind the drawer, unreachable. `Drawer` (src/forks/Drawer) provides its\n * dialog while it is modal; `Modal` renders there and enters the top layer\n * itself, as a manual popover, so it paints above the drawer and escapes the\n * panel's clipping and transform. Internal: not exported from the package.\n */\nexport const ModalPortalContext = createContext<HTMLElement | null>(null);\n\n/** Nesting depth ceiling. Two surfaces past it share a level. */\nexport const MAX_MODAL_LEVEL = 80;\n\n/**\n * The z-index band modal roots paint in. `base` is the first level, each\n * nested level adds `step`, and nothing paints above `max`, so whatever the\n * app layers above the band (a notification stack) stays above every modal.\n */\nexport interface ModalZIndexBand {\n base: number;\n step: number;\n max: number;\n}\n\nconst DEFAULT_BAND: ModalZIndexBand = { base: 1100, step: 10, max: 10999 };\nlet band: ModalZIndexBand = DEFAULT_BAND;\n\n/**\n * Sets the z-index band for every modal opened after the call. Call it once,\n * at startup, to fit the app's own layer ladder. The default is\n * `{ base: 1100, step: 10, max: 10999 }`. Pass nothing to restore it.\n */\nexport function configureModalZIndex(next?: Partial<ModalZIndexBand>): void {\n band = { ...DEFAULT_BAND, ...next };\n}\n\n/** The band's first level; a scrimless Drawer (src/forks/Drawer) stays below it. */\nexport function modalZIndexBase(): number {\n return band.base;\n}\n\nconst LEVEL_CSS_VAR = \"--modal-level\";\nconst Z_INDEX_CSS_VAR = \"--modal-z\";\n\n/** A claim on the stack. Released by reference, never by level. */\nexport interface ModalLevelEntry {\n level: number;\n zIndex: number;\n isTopmost: boolean;\n root: HTMLElement | null;\n setIsTopmost: (isTopmost: boolean) => void;\n}\n\nconst openModals: ModalLevelEntry[] = [];\n\n/**\n * One step above the topmost surface (or the band's base), raised by an\n * accepted override. Stacking and inertness therefore run on one order: a\n * surface opened later paints above an earlier one, whatever that one asked.\n */\nfunction resolveZIndex(\n topmost: ModalLevelEntry | undefined,\n requested?: number,\n): number {\n let override = requested;\n if (override != null && (override < band.base || override > band.max)) {\n devWarn(\n \"Modal\",\n `zIndex ${override} is outside the modal band (${band.base}..${band.max}); ` +\n \"ignoring it. Change the band with configureModalZIndex instead.\",\n );\n override = undefined;\n }\n const floor = topmost?.zIndex ?? band.base - band.step;\n return Math.min(Math.max(floor + band.step, override ?? 0), band.max);\n}\n\n/**\n * Marks an element that stays reachable while a modal is open: it, and the\n * ancestors it needs, are never made inert. `NotificationStack` sets it on\n * its root, so a notice raised over a modal can still be read and dismissed.\n * The mark is read when a modal opens or closes and on\n * `refreshModalBackground()`; call that after mounting a marked element while\n * a modal is open.\n */\nexport const MODAL_LIVE_ATTRIBUTE = \"data-uic-modal-live\";\n\n/** The background elements this module made inert, and only those. */\nconst inertedBackground = new Set<Element>();\n\nconst NEVER_INERT = new Set([\"SCRIPT\", \"STYLE\", \"LINK\", \"TEMPLATE\", \"NOSCRIPT\"]);\n\n/**\n * The elements to inert while `keep` stays reachable: every child of\n * `document.body` that holds none of them, and, inside a body child that\n * does, every sibling on the way down to them.\n */\nfunction backgroundOf(keep: Element[]): Element[] {\n const kept = new Set(keep);\n const onPath = new Set<Element>();\n for (const el of keep) {\n for (let node = el.parentElement; node && node !== document.body;) {\n onPath.add(node);\n node = node.parentElement;\n }\n }\n const out: Element[] = [];\n const visit = (parent: Element) => {\n for (const child of Array.from(parent.children)) {\n if (kept.has(child) || NEVER_INERT.has(child.tagName)) continue;\n if (onPath.has(child)) visit(child);\n else out.push(child);\n }\n };\n visit(document.body);\n return out;\n}\n\n/**\n * While any modal is open the rest of the page is `inert`, which is what\n * `aria-modal` promises. Modal roots (a drawer's too, when it claims a level\n * through `useModalLevel`) and elements marked `MODAL_LIVE_ATTRIBUTE` are\n * spared. An `inert` the page set itself is left alone, before and after.\n */\nfunction syncBackground(): void {\n if (typeof document === \"undefined\" || !document.body) return;\n const roots = openModals\n .map((entry) => entry.root)\n .filter((root): root is HTMLElement => root != null && root.isConnected);\n const target = new Set(\n openModals.length === 0\n ? []\n : backgroundOf([\n ...roots,\n ...Array.from(document.querySelectorAll(`[${MODAL_LIVE_ATTRIBUTE}]`)),\n ]),\n );\n for (const el of inertedBackground) {\n if (target.has(el)) continue;\n el.removeAttribute(\"inert\");\n inertedBackground.delete(el);\n }\n for (const el of target) {\n if (inertedBackground.has(el) || el.hasAttribute(\"inert\")) continue;\n el.setAttribute(\"inert\", \"\");\n inertedBackground.add(el);\n }\n}\n\n/**\n * Re-reads which elements are marked `MODAL_LIVE_ATTRIBUTE` (and which modal\n * roots are in the document) while a modal is open. A no-op otherwise.\n */\nexport function refreshModalBackground(): void {\n if (openModals.length > 0 || inertedBackground.size > 0) syncBackground();\n}\n\n/**\n * Only the topmost surface stays interactive. A covered one drops its focus\n * trap and goes `inert`: the trap alone lets Tab escape to the parent, and\n * `inert` alone leaves the covered trap swallowing Tab with nothing to focus.\n */\nfunction syncCovered(): void {\n syncBackground();\n openModals.forEach((entry, index) => {\n const isTopmost = index === openModals.length - 1;\n entry.root?.toggleAttribute(\"inert\", !isTopmost);\n if (entry.isTopmost !== isTopmost) {\n entry.isTopmost = isTopmost;\n entry.setIsTopmost(isTopmost);\n }\n });\n}\n\nexport function claimModalLevel(\n root: HTMLElement | null,\n setIsTopmost: (isTopmost: boolean) => void,\n requestedZIndex?: number,\n): ModalLevelEntry {\n registerInstance();\n const topmost = openModals.at(-1);\n const entry: ModalLevelEntry = {\n level: Math.min((topmost?.level ?? -1) + 1, MAX_MODAL_LEVEL),\n zIndex: resolveZIndex(topmost, requestedZIndex),\n isTopmost: true,\n root,\n setIsTopmost,\n };\n openModals.push(entry);\n syncCovered();\n return entry;\n}\n\nexport function releaseModalLevel(entry: ModalLevelEntry): void {\n const index = openModals.indexOf(entry);\n if (index === -1) return;\n entry.root?.removeAttribute(\"inert\");\n openModals.splice(index, 1);\n syncCovered();\n}\n\n/**\n * Claims a level for `rootRef` while `isOpen`, and writes the level and the\n * resolved z-index onto the root as `--modal-level` and `--modal-z`.\n * Returns whether this surface is the topmost one; gate a focus trap on it.\n */\nexport function useModalLevel(\n rootRef: RefObject<HTMLElement | null>,\n isOpen: boolean,\n zIndex?: number,\n): boolean {\n const [isTopmost, setIsTopmost] = useState(true);\n // Read at claim time only: re-claiming would move an open surface to the\n // top of the stack and inert whatever legitimately covered it.\n const readZIndex = useEffectEvent(() => zIndex);\n\n useLayoutEffect(() => {\n if (!isOpen) return;\n const root = rootRef.current;\n const entry = claimModalLevel(root, setIsTopmost, readZIndex());\n root?.style.setProperty(LEVEL_CSS_VAR, String(entry.level));\n root?.style.setProperty(Z_INDEX_CSS_VAR, String(entry.zIndex));\n return () => {\n releaseModalLevel(entry);\n root?.style.removeProperty(LEVEL_CSS_VAR);\n root?.style.removeProperty(Z_INDEX_CSS_VAR);\n };\n // An effect event is not a dependency; this plugin version predates it.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, rootRef]);\n\n return isTopmost;\n}\n"],"mappings":"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"}
@@ -4,8 +4,8 @@ import { Button as t } from "@astryxdesign/core/Button";
4
4
  import { Heading as n } from "@astryxdesign/core/Heading";
5
5
  import { Text as r } from "@astryxdesign/core/Text";
6
6
  import { jsx as i, jsxs as a } from "react/jsx-runtime";
7
- import { Icon as o } from "@astryxdesign/core/Icon";
8
- import { IconButton as s } from "@astryxdesign/core/IconButton";
7
+ import { IconButton as o } from "@astryxdesign/core/IconButton";
8
+ import { Icon as s } from "@astryxdesign/core/Icon";
9
9
  //#region src/components/PageHeader/PageHeader.tsx
10
10
  function c({ title: c, description: l, actions: u, error: d, onErrorDismiss: f, className: p = "", errorDetail: m, onRetry: h, retryLabel: g, dismissErrorLabel: _ }) {
11
11
  let v = e(), y = ["uic-page-header", p].filter(Boolean).join(" ");
@@ -51,12 +51,12 @@ function c({ title: c, description: l, actions: u, error: d, onErrorDismiss: f,
51
51
  className: "uic-page-header__error-retry",
52
52
  label: g ?? v("uic.common.retry"),
53
53
  onClick: h
54
- }), f && /* @__PURE__ */ i(s, {
54
+ }), f && /* @__PURE__ */ i(o, {
55
55
  variant: "ghost",
56
56
  size: "sm",
57
57
  className: "uic-page-header__error-dismiss",
58
58
  label: _ ?? v("uic.PageHeader.dismissError"),
59
- icon: /* @__PURE__ */ i(o, { icon: "close" }),
59
+ icon: /* @__PURE__ */ i(s, { icon: "close" }),
60
60
  onClick: f
61
61
  })]
62
62
  })]