@gcsa/console-react 0.1.0
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.
- package/dist/ConsoleHeader.d.ts +9 -0
- package/dist/ConsoleHeader.js +21 -0
- package/dist/ConsoleHeader.js.map +1 -0
- package/dist/ConsolePage.d.ts +8 -0
- package/dist/ConsolePage.js +14 -0
- package/dist/ConsolePage.js.map +1 -0
- package/dist/ConsoleShell.d.ts +23 -0
- package/dist/ConsoleShell.js +133 -0
- package/dist/ConsoleShell.js.map +1 -0
- package/dist/ConsoleSidebar.d.ts +11 -0
- package/dist/ConsoleSidebar.js +52 -0
- package/dist/ConsoleSidebar.js.map +1 -0
- package/dist/GcsaAlert.d.ts +9 -0
- package/dist/GcsaAlert.js +24 -0
- package/dist/GcsaAlert.js.map +1 -0
- package/dist/GcsaAutoComplete.d.ts +15 -0
- package/dist/GcsaAutoComplete.js +106 -0
- package/dist/GcsaAutoComplete.js.map +1 -0
- package/dist/GcsaAvatar.d.ts +8 -0
- package/dist/GcsaAvatar.js +13 -0
- package/dist/GcsaAvatar.js.map +1 -0
- package/dist/GcsaBadge.d.ts +7 -0
- package/dist/GcsaBadge.js +8 -0
- package/dist/GcsaBadge.js.map +1 -0
- package/dist/GcsaBrandMark.d.ts +4 -0
- package/dist/GcsaBrandMark.js +21 -0
- package/dist/GcsaBrandMark.js.map +1 -0
- package/dist/GcsaBreadcrumb.d.ts +9 -0
- package/dist/GcsaBreadcrumb.js +20 -0
- package/dist/GcsaBreadcrumb.js.map +1 -0
- package/dist/GcsaButton.d.ts +8 -0
- package/dist/GcsaButton.js +38 -0
- package/dist/GcsaButton.js.map +1 -0
- package/dist/GcsaCalendar.d.ts +11 -0
- package/dist/GcsaCalendar.js +35 -0
- package/dist/GcsaCalendar.js.map +1 -0
- package/dist/GcsaCard.d.ts +8 -0
- package/dist/GcsaCard.js +11 -0
- package/dist/GcsaCard.js.map +1 -0
- package/dist/GcsaCascader.d.ts +14 -0
- package/dist/GcsaCascader.js +91 -0
- package/dist/GcsaCascader.js.map +1 -0
- package/dist/GcsaChatPanel.d.ts +43 -0
- package/dist/GcsaChatPanel.js +180 -0
- package/dist/GcsaChatPanel.js.map +1 -0
- package/dist/GcsaCheckbox.d.ts +11 -0
- package/dist/GcsaCheckbox.js +45 -0
- package/dist/GcsaCheckbox.js.map +1 -0
- package/dist/GcsaCollapse.d.ts +16 -0
- package/dist/GcsaCollapse.js +20 -0
- package/dist/GcsaCollapse.js.map +1 -0
- package/dist/GcsaConfigProvider.d.ts +13 -0
- package/dist/GcsaConfigProvider.js +68 -0
- package/dist/GcsaConfigProvider.js.map +1 -0
- package/dist/GcsaDataTable.d.ts +119 -0
- package/dist/GcsaDataTable.js +508 -0
- package/dist/GcsaDataTable.js.map +1 -0
- package/dist/GcsaDatePicker.d.ts +16 -0
- package/dist/GcsaDatePicker.js +211 -0
- package/dist/GcsaDatePicker.js.map +1 -0
- package/dist/GcsaDateRangePicker.d.ts +17 -0
- package/dist/GcsaDateRangePicker.js +222 -0
- package/dist/GcsaDateRangePicker.js.map +1 -0
- package/dist/GcsaDateTimePicker.d.ts +13 -0
- package/dist/GcsaDateTimePicker.js +300 -0
- package/dist/GcsaDateTimePicker.js.map +1 -0
- package/dist/GcsaDescriptions.d.ts +9 -0
- package/dist/GcsaDescriptions.js +11 -0
- package/dist/GcsaDescriptions.js.map +1 -0
- package/dist/GcsaDivider.d.ts +4 -0
- package/dist/GcsaDivider.js +8 -0
- package/dist/GcsaDivider.js.map +1 -0
- package/dist/GcsaDrawer.d.ts +15 -0
- package/dist/GcsaDrawer.js +68 -0
- package/dist/GcsaDrawer.js.map +1 -0
- package/dist/GcsaDropdown.d.ts +20 -0
- package/dist/GcsaDropdown.js +46 -0
- package/dist/GcsaDropdown.js.map +1 -0
- package/dist/GcsaEmpty.d.ts +9 -0
- package/dist/GcsaEmpty.js +16 -0
- package/dist/GcsaEmpty.js.map +1 -0
- package/dist/GcsaField.d.ts +11 -0
- package/dist/GcsaField.js +26 -0
- package/dist/GcsaField.js.map +1 -0
- package/dist/GcsaForm.d.ts +13 -0
- package/dist/GcsaForm.js +60 -0
- package/dist/GcsaForm.js.map +1 -0
- package/dist/GcsaFormField.d.ts +16 -0
- package/dist/GcsaFormField.js +39 -0
- package/dist/GcsaFormField.js.map +1 -0
- package/dist/GcsaIcon.d.ts +7 -0
- package/dist/GcsaIcon.js +17 -0
- package/dist/GcsaIcon.js.map +1 -0
- package/dist/GcsaImagePreview.d.ts +8 -0
- package/dist/GcsaImagePreview.js +18 -0
- package/dist/GcsaImagePreview.js.map +1 -0
- package/dist/GcsaInput.d.ts +13 -0
- package/dist/GcsaInput.js +76 -0
- package/dist/GcsaInput.js.map +1 -0
- package/dist/GcsaInputGroup.d.ts +11 -0
- package/dist/GcsaInputGroup.js +27 -0
- package/dist/GcsaInputGroup.js.map +1 -0
- package/dist/GcsaInputNumber.d.ts +18 -0
- package/dist/GcsaInputNumber.js +108 -0
- package/dist/GcsaInputNumber.js.map +1 -0
- package/dist/GcsaLoading.d.ts +24 -0
- package/dist/GcsaLoading.js +101 -0
- package/dist/GcsaLoading.js.map +1 -0
- package/dist/GcsaLoadingMask.d.ts +8 -0
- package/dist/GcsaLoadingMask.js +39 -0
- package/dist/GcsaLoadingMask.js.map +1 -0
- package/dist/GcsaMarkdownRenderer.d.ts +6 -0
- package/dist/GcsaMarkdownRenderer.js +32 -0
- package/dist/GcsaMarkdownRenderer.js.map +1 -0
- package/dist/GcsaMenu.d.ts +16 -0
- package/dist/GcsaMenu.js +241 -0
- package/dist/GcsaMenu.js.map +1 -0
- package/dist/GcsaModal.d.ts +10 -0
- package/dist/GcsaModal.js +45 -0
- package/dist/GcsaModal.js.map +1 -0
- package/dist/GcsaMultiSelect.d.ts +23 -0
- package/dist/GcsaMultiSelect.js +149 -0
- package/dist/GcsaMultiSelect.js.map +1 -0
- package/dist/GcsaPagination.d.ts +17 -0
- package/dist/GcsaPagination.js +108 -0
- package/dist/GcsaPagination.js.map +1 -0
- package/dist/GcsaPopconfirm.d.ts +18 -0
- package/dist/GcsaPopconfirm.js +68 -0
- package/dist/GcsaPopconfirm.js.map +1 -0
- package/dist/GcsaPopover.d.ts +30 -0
- package/dist/GcsaPopover.js +65 -0
- package/dist/GcsaPopover.js.map +1 -0
- package/dist/GcsaPopoverClose.d.ts +6 -0
- package/dist/GcsaPopoverClose.js +9 -0
- package/dist/GcsaPopoverClose.js.map +1 -0
- package/dist/GcsaProgress.d.ts +5 -0
- package/dist/GcsaProgress.js +18 -0
- package/dist/GcsaProgress.js.map +1 -0
- package/dist/GcsaRadioGroup.d.ts +9 -0
- package/dist/GcsaRadioGroup.js +37 -0
- package/dist/GcsaRadioGroup.js.map +1 -0
- package/dist/GcsaResult.d.ts +9 -0
- package/dist/GcsaResult.js +14 -0
- package/dist/GcsaResult.js.map +1 -0
- package/dist/GcsaRow.d.ts +7 -0
- package/dist/GcsaRow.js +8 -0
- package/dist/GcsaRow.js.map +1 -0
- package/dist/GcsaSelect.d.ts +20 -0
- package/dist/GcsaSelect.js +117 -0
- package/dist/GcsaSelect.js.map +1 -0
- package/dist/GcsaSkeleton.d.ts +6 -0
- package/dist/GcsaSkeleton.js +19 -0
- package/dist/GcsaSkeleton.js.map +1 -0
- package/dist/GcsaSpace.d.ts +7 -0
- package/dist/GcsaSpace.js +14 -0
- package/dist/GcsaSpace.js.map +1 -0
- package/dist/GcsaSpin.d.ts +7 -0
- package/dist/GcsaSpin.js +16 -0
- package/dist/GcsaSpin.js.map +1 -0
- package/dist/GcsaStatistic.d.ts +8 -0
- package/dist/GcsaStatistic.js +11 -0
- package/dist/GcsaStatistic.js.map +1 -0
- package/dist/GcsaSteps.d.ts +10 -0
- package/dist/GcsaSteps.js +54 -0
- package/dist/GcsaSteps.js.map +1 -0
- package/dist/GcsaSwitch.d.ts +11 -0
- package/dist/GcsaSwitch.js +36 -0
- package/dist/GcsaSwitch.js.map +1 -0
- package/dist/GcsaTabs.d.ts +15 -0
- package/dist/GcsaTabs.js +39 -0
- package/dist/GcsaTabs.js.map +1 -0
- package/dist/GcsaTag.d.ts +7 -0
- package/dist/GcsaTag.js +9 -0
- package/dist/GcsaTag.js.map +1 -0
- package/dist/GcsaTextarea.d.ts +13 -0
- package/dist/GcsaTextarea.js +76 -0
- package/dist/GcsaTextarea.js.map +1 -0
- package/dist/GcsaTimePicker.d.ts +12 -0
- package/dist/GcsaTimePicker.js +221 -0
- package/dist/GcsaTimePicker.js.map +1 -0
- package/dist/GcsaTimeline.d.ts +5 -0
- package/dist/GcsaTimeline.js +19 -0
- package/dist/GcsaTimeline.js.map +1 -0
- package/dist/GcsaToastStack.d.ts +11 -0
- package/dist/GcsaToastStack.js +45 -0
- package/dist/GcsaToastStack.js.map +1 -0
- package/dist/GcsaTooltip.d.ts +17 -0
- package/dist/GcsaTooltip.js +43 -0
- package/dist/GcsaTooltip.js.map +1 -0
- package/dist/GcsaTransfer.d.ts +11 -0
- package/dist/GcsaTransfer.js +95 -0
- package/dist/GcsaTransfer.js.map +1 -0
- package/dist/GcsaTree.d.ts +17 -0
- package/dist/GcsaTree.js +38 -0
- package/dist/GcsaTree.js.map +1 -0
- package/dist/GcsaTypography.d.ts +8 -0
- package/dist/GcsaTypography.js +14 -0
- package/dist/GcsaTypography.js.map +1 -0
- package/dist/GcsaUpload.d.ts +24 -0
- package/dist/GcsaUpload.js +146 -0
- package/dist/GcsaUpload.js.map +1 -0
- package/dist/hooks/gcsaFormTypes.d.ts +7 -0
- package/dist/hooks/useDocumentThemeSync.d.ts +3 -0
- package/dist/hooks/useDocumentThemeSync.js +7 -0
- package/dist/hooks/useDocumentThemeSync.js.map +1 -0
- package/dist/hooks/useGcsaComponentSize.d.ts +5 -0
- package/dist/hooks/useGcsaComponentSize.js +21 -0
- package/dist/hooks/useGcsaComponentSize.js.map +1 -0
- package/dist/hooks/useGcsaFormField.d.ts +26 -0
- package/dist/hooks/useGcsaFormField.js +47 -0
- package/dist/hooks/useGcsaFormField.js.map +1 -0
- package/dist/hooks/useGcsaFormSchema.d.ts +7 -0
- package/dist/hooks/useGcsaFormSchema.js +6 -0
- package/dist/hooks/useGcsaFormSchema.js.map +1 -0
- package/dist/hooks/useGcsaLocale.d.ts +4 -0
- package/dist/hooks/useGcsaLocale.js +15 -0
- package/dist/hooks/useGcsaLocale.js.map +1 -0
- package/dist/hooks/useGcsaPopupZIndex.d.ts +6 -0
- package/dist/hooks/useGcsaPopupZIndex.js +18 -0
- package/dist/hooks/useGcsaPopupZIndex.js.map +1 -0
- package/dist/hooks/useGcsaTextCount.d.ts +16 -0
- package/dist/hooks/useGcsaTextCount.js +16 -0
- package/dist/hooks/useGcsaTextCount.js.map +1 -0
- package/dist/hooks/useGcsaTheme.d.ts +7 -0
- package/dist/hooks/useGcsaTheme.js +19 -0
- package/dist/hooks/useGcsaTheme.js.map +1 -0
- package/dist/hooks/useGcsaZIndex.d.ts +13 -0
- package/dist/hooks/useGcsaZIndex.js +37 -0
- package/dist/hooks/useGcsaZIndex.js.map +1 -0
- package/dist/hooks/useMessage.d.ts +6 -0
- package/dist/hooks/useOverlayZIndex.d.ts +8 -0
- package/dist/hooks/useOverlayZIndex.js +14 -0
- package/dist/hooks/useOverlayZIndex.js.map +1 -0
- package/dist/hooks/usePreventHiddenInputScroll.d.ts +13 -0
- package/dist/hooks/usePreventHiddenInputScroll.js +124 -0
- package/dist/hooks/usePreventHiddenInputScroll.js.map +1 -0
- package/dist/icons/iconNames.d.ts +7 -0
- package/dist/icons/iconNames.js +24 -0
- package/dist/icons/iconNames.js.map +1 -0
- package/dist/icons/index.d.ts +2 -0
- package/dist/icons/registry.d.ts +3 -0
- package/dist/icons/registry.js +58 -0
- package/dist/icons/registry.js.map +1 -0
- package/dist/icons/svg/alert.svg.js +9 -0
- package/dist/icons/svg/alert.svg.js.map +1 -0
- package/dist/icons/svg/assets.svg.js +9 -0
- package/dist/icons/svg/assets.svg.js.map +1 -0
- package/dist/icons/svg/chat.svg.js +8 -0
- package/dist/icons/svg/chat.svg.js.map +1 -0
- package/dist/icons/svg/check.svg.js +8 -0
- package/dist/icons/svg/check.svg.js.map +1 -0
- package/dist/icons/svg/chevron-down.svg.js +8 -0
- package/dist/icons/svg/chevron-down.svg.js.map +1 -0
- package/dist/icons/svg/chevron-left.svg.js +8 -0
- package/dist/icons/svg/chevron-left.svg.js.map +1 -0
- package/dist/icons/svg/chevron-right.svg.js +8 -0
- package/dist/icons/svg/chevron-right.svg.js.map +1 -0
- package/dist/icons/svg/chevron-up.svg.js +8 -0
- package/dist/icons/svg/chevron-up.svg.js.map +1 -0
- package/dist/icons/svg/close.svg.js +6 -0
- package/dist/icons/svg/close.svg.js.map +1 -0
- package/dist/icons/svg/dashboard.svg.js +8 -0
- package/dist/icons/svg/dashboard.svg.js.map +1 -0
- package/dist/icons/svg/menu.svg.js +8 -0
- package/dist/icons/svg/menu.svg.js.map +1 -0
- package/dist/icons/svg/plus.svg.js +6 -0
- package/dist/icons/svg/plus.svg.js.map +1 -0
- package/dist/icons/svg/result-empty.svg.js +6 -0
- package/dist/icons/svg/result-empty.svg.js.map +1 -0
- package/dist/icons/svg/settings.svg.js +8 -0
- package/dist/icons/svg/settings.svg.js.map +1 -0
- package/dist/icons/svg/users.svg.js +11 -0
- package/dist/icons/svg/users.svg.js.map +1 -0
- package/dist/index.d.ts +151 -0
- package/dist/index.js +166 -0
- package/dist/index.js.map +1 -0
- package/dist/style.css +8028 -0
- package/dist/utils/gcsaDateValue.d.ts +25 -0
- package/dist/utils/gcsaDateValue.js +60 -0
- package/dist/utils/gcsaDateValue.js.map +1 -0
- package/dist/utils/gcsaTableColumns.d.ts +19 -0
- package/dist/utils/gcsaTableColumns.js +43 -0
- package/dist/utils/gcsaTableColumns.js.map +1 -0
- package/dist/utils/preserveDrawerScroll.d.ts +2 -0
- package/dist/utils/preserveDrawerScroll.js +13 -0
- package/dist/utils/preserveDrawerScroll.js.map +1 -0
- package/dist/utils/zodValidators.d.ts +21 -0
- package/dist/utils/zodValidators.js +35 -0
- package/dist/utils/zodValidators.js.map +1 -0
- package/package.json +58 -0
- package/src/ConsoleHeader.tsx +24 -0
- package/src/ConsolePage.tsx +22 -0
- package/src/ConsoleShell.tsx +248 -0
- package/src/ConsoleSidebar.tsx +61 -0
- package/src/GcsaAlert.tsx +29 -0
- package/src/GcsaAutoComplete.tsx +163 -0
- package/src/GcsaAvatar.tsx +21 -0
- package/src/GcsaBadge.tsx +15 -0
- package/src/GcsaBrandMark.tsx +18 -0
- package/src/GcsaBreadcrumb.tsx +35 -0
- package/src/GcsaButton.tsx +44 -0
- package/src/GcsaCalendar.tsx +14 -0
- package/src/GcsaCard.tsx +21 -0
- package/src/GcsaCascader.tsx +121 -0
- package/src/GcsaChatPanel.tsx +320 -0
- package/src/GcsaCheckbox.tsx +55 -0
- package/src/GcsaCollapse.tsx +23 -0
- package/src/GcsaConfigProvider.tsx +121 -0
- package/src/GcsaDataTable.tsx +779 -0
- package/src/GcsaDatePicker.tsx +284 -0
- package/src/GcsaDateRangePicker.tsx +310 -0
- package/src/GcsaDateTimePicker.tsx +407 -0
- package/src/GcsaDescriptions.tsx +22 -0
- package/src/GcsaDivider.tsx +7 -0
- package/src/GcsaDrawer.tsx +87 -0
- package/src/GcsaDropdown.tsx +84 -0
- package/src/GcsaEmpty.tsx +27 -0
- package/src/GcsaField.tsx +50 -0
- package/src/GcsaForm.tsx +82 -0
- package/src/GcsaFormField.tsx +67 -0
- package/src/GcsaIcon.tsx +21 -0
- package/src/GcsaImagePreview.tsx +30 -0
- package/src/GcsaInput.tsx +87 -0
- package/src/GcsaInputGroup.tsx +32 -0
- package/src/GcsaInputNumber.tsx +155 -0
- package/src/GcsaLoading.ts +206 -0
- package/src/GcsaLoadingMask.tsx +53 -0
- package/src/GcsaMarkdownRenderer.tsx +40 -0
- package/src/GcsaMenu.tsx +340 -0
- package/src/GcsaModal.tsx +68 -0
- package/src/GcsaMultiSelect.tsx +246 -0
- package/src/GcsaPagination.tsx +194 -0
- package/src/GcsaPopconfirm.tsx +104 -0
- package/src/GcsaPopover.tsx +131 -0
- package/src/GcsaPopoverClose.tsx +11 -0
- package/src/GcsaProgress.tsx +18 -0
- package/src/GcsaRadioGroup.tsx +42 -0
- package/src/GcsaResult.tsx +23 -0
- package/src/GcsaRow.tsx +13 -0
- package/src/GcsaSelect.tsx +186 -0
- package/src/GcsaSkeleton.tsx +19 -0
- package/src/GcsaSpace.tsx +17 -0
- package/src/GcsaSpin.tsx +25 -0
- package/src/GcsaStatistic.tsx +17 -0
- package/src/GcsaSteps.tsx +73 -0
- package/src/GcsaSwitch.tsx +45 -0
- package/src/GcsaTabs.tsx +53 -0
- package/src/GcsaTag.tsx +16 -0
- package/src/GcsaTextarea.tsx +87 -0
- package/src/GcsaTimePicker.tsx +298 -0
- package/src/GcsaTimeline.tsx +27 -0
- package/src/GcsaToastStack.tsx +67 -0
- package/src/GcsaTooltip.tsx +75 -0
- package/src/GcsaTransfer.tsx +129 -0
- package/src/GcsaTree.tsx +43 -0
- package/src/GcsaTypography.tsx +24 -0
- package/src/GcsaUpload.tsx +206 -0
- package/src/hooks/gcsaFormTypes.ts +23 -0
- package/src/hooks/useDocumentThemeSync.ts +6 -0
- package/src/hooks/useGcsaComponentSize.ts +24 -0
- package/src/hooks/useGcsaFormField.ts +49 -0
- package/src/hooks/useGcsaFormSchema.ts +6 -0
- package/src/hooks/useGcsaLocale.ts +16 -0
- package/src/hooks/useGcsaPopupZIndex.ts +23 -0
- package/src/hooks/useGcsaTextCount.ts +44 -0
- package/src/hooks/useGcsaTheme.ts +19 -0
- package/src/hooks/useGcsaZIndex.ts +60 -0
- package/src/hooks/useMessage.ts +7 -0
- package/src/hooks/useOverlayZIndex.ts +23 -0
- package/src/hooks/usePreventHiddenInputScroll.ts +233 -0
- package/src/icons/iconNames.ts +27 -0
- package/src/icons/index.ts +8 -0
- package/src/icons/registry.ts +38 -0
- package/src/icons/svg/alert.svg +4 -0
- package/src/icons/svg/assets.svg +4 -0
- package/src/icons/svg/chat.svg +3 -0
- package/src/icons/svg/check.svg +3 -0
- package/src/icons/svg/chevron-down.svg +3 -0
- package/src/icons/svg/chevron-left.svg +3 -0
- package/src/icons/svg/chevron-right.svg +3 -0
- package/src/icons/svg/chevron-up.svg +3 -0
- package/src/icons/svg/close.svg +1 -0
- package/src/icons/svg/dashboard.svg +3 -0
- package/src/icons/svg/menu.svg +3 -0
- package/src/icons/svg/plus.svg +1 -0
- package/src/icons/svg/result-empty.svg +1 -0
- package/src/icons/svg/settings.svg +3 -0
- package/src/icons/svg/users.svg +6 -0
- package/src/index.ts +166 -0
- package/src/utils/gcsaDateValue.ts +99 -0
- package/src/utils/gcsaTableColumns.ts +97 -0
- package/src/utils/preserveDrawerScroll.ts +20 -0
- package/src/utils/zodValidators.ts +45 -0
- package/src/vite-env.d.ts +6 -0
|
@@ -0,0 +1,779 @@
|
|
|
1
|
+
import { Fragment, useEffect, useMemo, useRef, useState, type CSSProperties, type MouseEvent as ReactMouseEvent, type MutableRefObject, type PointerEvent as ReactPointerEvent, type ReactNode } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
flexRender,
|
|
4
|
+
getCoreRowModel,
|
|
5
|
+
getFilteredRowModel,
|
|
6
|
+
getExpandedRowModel,
|
|
7
|
+
getPaginationRowModel,
|
|
8
|
+
getSortedRowModel,
|
|
9
|
+
useReactTable,
|
|
10
|
+
type ColumnDef,
|
|
11
|
+
type ColumnFiltersState,
|
|
12
|
+
type ExpandedState,
|
|
13
|
+
type Row,
|
|
14
|
+
type SortingState
|
|
15
|
+
} from '@tanstack/react-table';
|
|
16
|
+
import type {
|
|
17
|
+
GcsaLegacyTableColumn,
|
|
18
|
+
GcsaPaginationAlign,
|
|
19
|
+
GcsaPaginationLayoutPart,
|
|
20
|
+
GcsaTableColumn,
|
|
21
|
+
GcsaTableColumnFixed,
|
|
22
|
+
GcsaTableColumnInfo
|
|
23
|
+
} from '@gcsa/console-core';
|
|
24
|
+
import {
|
|
25
|
+
GCSA_TABLE_DEFAULT_COLUMN_MIN_WIDTH,
|
|
26
|
+
GCSA_TABLE_EXPAND_COLUMN_WIDTH,
|
|
27
|
+
GCSA_TABLE_SELECTION_COLUMN_WIDTH,
|
|
28
|
+
formatGcsaLocaleMessage,
|
|
29
|
+
getGcsaTableFixedOffset,
|
|
30
|
+
getGcsaTableDefaultExpandedKeys,
|
|
31
|
+
getGcsaTableMinWidth,
|
|
32
|
+
getGcsaTableRowId,
|
|
33
|
+
getGcsaTableSortChange,
|
|
34
|
+
getGcsaTableSorting,
|
|
35
|
+
normalizeGcsaTableColumns
|
|
36
|
+
} from '@gcsa/console-core';
|
|
37
|
+
import { GcsaCheckbox } from './GcsaCheckbox';
|
|
38
|
+
import { GcsaEmpty } from './GcsaEmpty';
|
|
39
|
+
import { GcsaIcon } from './GcsaIcon';
|
|
40
|
+
import { GcsaInput } from './GcsaInput';
|
|
41
|
+
import { GcsaPagination } from './GcsaPagination';
|
|
42
|
+
import { GcsaSelect } from './GcsaSelect';
|
|
43
|
+
import { GcsaSpin } from './GcsaSpin';
|
|
44
|
+
import { formatGcsaTableCellValue, resolveGcsaTableColumns } from './utils/gcsaTableColumns';
|
|
45
|
+
import { useGcsaLocaleMessages } from './hooks/useGcsaLocale';
|
|
46
|
+
import { useGcsaComponentSize } from './hooks/useGcsaComponentSize';
|
|
47
|
+
|
|
48
|
+
type TableMeta = {
|
|
49
|
+
width?: string;
|
|
50
|
+
minWidth?: string;
|
|
51
|
+
align?: 'left' | 'center' | 'right';
|
|
52
|
+
slotKey?: string;
|
|
53
|
+
fixed?: GcsaTableColumnFixed;
|
|
54
|
+
hidden?: boolean;
|
|
55
|
+
showOverflowTooltip?: boolean;
|
|
56
|
+
filter?: { type: 'text' | 'select'; placeholder?: string; options?: Array<{ label: string; value: string; disabled?: boolean }> };
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function childColumns<T extends Record<string, unknown>>(column: ColumnDef<T, unknown>): ColumnDef<T, unknown>[] {
|
|
60
|
+
return 'columns' in column && Array.isArray(column.columns)
|
|
61
|
+
? column.columns as ColumnDef<T, unknown>[]
|
|
62
|
+
: [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function flattenColumns<T extends Record<string, unknown>>(columns: ColumnDef<T, unknown>[]): ColumnDef<T, unknown>[] {
|
|
66
|
+
return columns.flatMap(column => {
|
|
67
|
+
const children = childColumns(column);
|
|
68
|
+
return children.length ? flattenColumns(children) : [column];
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function filterColumnTree<T extends Record<string, unknown>>(columns: ColumnDef<T, unknown>[], visibility: Record<string, boolean>): ColumnDef<T, unknown>[] {
|
|
73
|
+
return columns.flatMap(column => {
|
|
74
|
+
const meta = metaOf(column);
|
|
75
|
+
if (meta.hidden || visibility[column.id ?? ''] === false) return [];
|
|
76
|
+
const columnChildren = childColumns(column);
|
|
77
|
+
if (!columnChildren.length) return [column];
|
|
78
|
+
const children = filterColumnTree(columnChildren, visibility);
|
|
79
|
+
return children.length ? [{ ...column, columns: children }] : [];
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function TableLoadingState({ label }: { label: string }) {
|
|
84
|
+
return (
|
|
85
|
+
<div className="gcsa-data-table__state gcsa-data-table__state--loading" role="status" aria-live="polite">
|
|
86
|
+
<div className="gcsa-data-table__loading-label">
|
|
87
|
+
<GcsaSpin spinning />
|
|
88
|
+
<span>{label}</span>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export type GcsaDataTableProps<T extends Record<string, unknown>> = {
|
|
95
|
+
data: T[];
|
|
96
|
+
columns?: Array<GcsaTableColumn<T> | ColumnDef<T, unknown>>;
|
|
97
|
+
legacyColumns?: GcsaLegacyTableColumn<T>[];
|
|
98
|
+
total?: number;
|
|
99
|
+
pageSize?: number;
|
|
100
|
+
pageSizeOptions?: number[];
|
|
101
|
+
showPageSize?: boolean;
|
|
102
|
+
showJumper?: boolean;
|
|
103
|
+
pageSizeLabel?: string;
|
|
104
|
+
jumperLabel?: string;
|
|
105
|
+
paginationLayout?: string | GcsaPaginationLayoutPart[];
|
|
106
|
+
paginationAlign?: GcsaPaginationAlign;
|
|
107
|
+
showTotal?: boolean;
|
|
108
|
+
page?: number;
|
|
109
|
+
pagination?: boolean;
|
|
110
|
+
showToolbar?: boolean;
|
|
111
|
+
/** 工具栏是否显示总条数 */
|
|
112
|
+
showCount?: boolean;
|
|
113
|
+
size?: 'sm' | 'md';
|
|
114
|
+
serverSide?: boolean;
|
|
115
|
+
sorting?: SortingState;
|
|
116
|
+
filters?: Record<string, string>;
|
|
117
|
+
defaultSorting?: SortingState;
|
|
118
|
+
defaultFilters?: Record<string, string>;
|
|
119
|
+
loading?: boolean;
|
|
120
|
+
error?: string;
|
|
121
|
+
retryLabel?: string;
|
|
122
|
+
selectable?: boolean | ((row: T, index: number) => boolean);
|
|
123
|
+
selectedRowKeys?: string[];
|
|
124
|
+
columnVisibility?: Record<string, boolean>;
|
|
125
|
+
resizable?: boolean;
|
|
126
|
+
columnWidths?: Record<string, number>;
|
|
127
|
+
treeData?: boolean;
|
|
128
|
+
childrenKey?: keyof T & string;
|
|
129
|
+
treeLazy?: boolean;
|
|
130
|
+
treeHasChildrenKey?: keyof T & string;
|
|
131
|
+
treeHasChildren?: (row: T, index: number) => boolean;
|
|
132
|
+
loadChildren?: (row: T, index: number) => Promise<T[]> | T[];
|
|
133
|
+
treeLoadingText?: string;
|
|
134
|
+
treeLoadErrorText?: string;
|
|
135
|
+
expandedRowKeys?: string[];
|
|
136
|
+
mobileMode?: 'scroll' | 'cards';
|
|
137
|
+
stripe?: boolean;
|
|
138
|
+
bordered?: boolean;
|
|
139
|
+
highlightCurrentRow?: boolean;
|
|
140
|
+
currentRowKey?: string;
|
|
141
|
+
rowClassName?: string | ((row: T, index: number) => string | undefined);
|
|
142
|
+
summary?: (rows: T[]) => Record<string, string | number | null | undefined>;
|
|
143
|
+
summaryLabel?: string;
|
|
144
|
+
apiRef?: MutableRefObject<GcsaDataTableApi<T> | null>;
|
|
145
|
+
rowKey?: keyof T & string | ((row: T, index: number) => string);
|
|
146
|
+
height?: string | number;
|
|
147
|
+
maxHeight?: string | number;
|
|
148
|
+
expandable?: boolean;
|
|
149
|
+
defaultExpandAll?: boolean;
|
|
150
|
+
fixedSelection?: boolean;
|
|
151
|
+
selectionColumnWidth?: number;
|
|
152
|
+
expandColumnWidth?: number;
|
|
153
|
+
renderExpandedRow?: (row: T, index: number) => ReactNode;
|
|
154
|
+
toolbar?: ReactNode;
|
|
155
|
+
onPageChange?: (page: number) => void;
|
|
156
|
+
onPageSizeChange?: (pageSize: number) => void;
|
|
157
|
+
onSortingChange?: (sorting: SortingState) => void;
|
|
158
|
+
/** Element-style sort event payload for migration from el-table. */
|
|
159
|
+
onSortChange?: (change: ReturnType<typeof getGcsaTableSortChange>) => void;
|
|
160
|
+
onFiltersChange?: (filters: Record<string, string>) => void;
|
|
161
|
+
onFilterChange?: (filters: Record<string, string>) => void;
|
|
162
|
+
onSelectionChange?: (rows: T[]) => void;
|
|
163
|
+
onSelect?: (rows: T[], row: T) => void;
|
|
164
|
+
onSelectAll?: (rows: T[]) => void;
|
|
165
|
+
onSelectedRowKeysChange?: (keys: string[]) => void;
|
|
166
|
+
onColumnVisibilityChange?: (visibility: Record<string, boolean>) => void;
|
|
167
|
+
onColumnWidthsChange?: (widths: Record<string, number>) => void;
|
|
168
|
+
onExpandedRowKeysChange?: (keys: string[]) => void;
|
|
169
|
+
onCurrentRowKeyChange?: (key: string | undefined) => void;
|
|
170
|
+
onRowClick?: (row: T, index: number, event: ReactMouseEvent<HTMLTableRowElement>) => void;
|
|
171
|
+
onRowDoubleClick?: (row: T, index: number, event: ReactMouseEvent<HTMLTableRowElement>) => void;
|
|
172
|
+
onCellClick?: (row: T, column: string, value: unknown, index: number, event: ReactMouseEvent<HTMLTableCellElement>) => void;
|
|
173
|
+
onCellDoubleClick?: (row: T, column: string, value: unknown, index: number, event: ReactMouseEvent<HTMLTableCellElement>) => void;
|
|
174
|
+
onHeaderClick?: (column: GcsaTableColumnInfo, event: ReactMouseEvent<HTMLTableCellElement>) => void;
|
|
175
|
+
onRowContextMenu?: (row: T, index: number, event: ReactMouseEvent<HTMLTableRowElement>) => void;
|
|
176
|
+
onCellContextMenu?: (row: T, column: string, value: unknown, index: number, event: ReactMouseEvent<HTMLTableCellElement>) => void;
|
|
177
|
+
onLegacyRowClick?: (row: T, column: GcsaTableColumnInfo, event: ReactMouseEvent<HTMLTableRowElement>) => void;
|
|
178
|
+
onLegacyCellClick?: (row: T, column: GcsaTableColumnInfo, cell: HTMLTableCellElement, event: ReactMouseEvent<HTMLTableCellElement>) => void;
|
|
179
|
+
onLegacyRowContextMenu?: (row: T, column: GcsaTableColumnInfo, event: ReactMouseEvent<HTMLTableRowElement>) => void;
|
|
180
|
+
onLegacyCellContextMenu?: (row: T, column: GcsaTableColumnInfo, cell: HTMLTableCellElement, event: ReactMouseEvent<HTMLTableCellElement>) => void;
|
|
181
|
+
onCurrentChange?: (current: T | undefined, previous: T | undefined) => void;
|
|
182
|
+
onExpandChange?: (row: T, expanded: boolean, expandedRows: T[]) => void;
|
|
183
|
+
columnSelector?: (columns: Array<{ id: string; title: string; visible: boolean }>, toggle: (id: string) => void) => ReactNode;
|
|
184
|
+
onRetry?: () => void;
|
|
185
|
+
onTreeLoadError?: (error: unknown, row: T, index: number) => void;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export type GcsaDataTableApi<T extends Record<string, unknown>> = {
|
|
189
|
+
clearSorting: () => void;
|
|
190
|
+
clearFilters: () => void;
|
|
191
|
+
clearSelection: () => void;
|
|
192
|
+
clearExpanded: () => void;
|
|
193
|
+
setRowSelected: (key: string, selected?: boolean) => void;
|
|
194
|
+
setRowExpanded: (key: string, expanded?: boolean) => Promise<void>;
|
|
195
|
+
clearSort: () => void;
|
|
196
|
+
clearFilter: (columnKeys?: string | string[]) => void;
|
|
197
|
+
sort: (prop: string, order: 'ascending' | 'descending' | null) => void;
|
|
198
|
+
toggleRowSelection: (row: T, selected?: boolean) => void;
|
|
199
|
+
toggleAllSelection: () => void;
|
|
200
|
+
toggleRowExpansion: (row: T, expanded?: boolean) => Promise<void>;
|
|
201
|
+
setCurrentRow: (row?: T) => void;
|
|
202
|
+
getSelectionRows: () => T[];
|
|
203
|
+
setScrollTop: (top: number) => void;
|
|
204
|
+
scrollTo: (options: ScrollToOptions | number, y?: number) => void;
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
function metaOf<T>(column: ColumnDef<T, unknown>): TableMeta {
|
|
208
|
+
return (column.meta ?? {}) as TableMeta;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function toColumnFilters(filters?: Record<string, string>): ColumnFiltersState {
|
|
212
|
+
return Object.entries(filters ?? {}).filter(([, value]) => value !== '').map(([id, value]) => ({ id, value }));
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function filterRecord(filters: ColumnFiltersState) {
|
|
216
|
+
return Object.fromEntries(filters.map(filter => [filter.id, String(filter.value)]));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function fixedStyle<T extends Record<string, unknown>>(
|
|
220
|
+
columns: ColumnDef<T, unknown>[],
|
|
221
|
+
id: string,
|
|
222
|
+
meta: TableMeta,
|
|
223
|
+
widths: Record<string, number> = {},
|
|
224
|
+
controls: { expandable: boolean; selectable: boolean; fixedSelection: boolean; expandColumnWidth?: number; selectionColumnWidth?: number }
|
|
225
|
+
): CSSProperties | undefined {
|
|
226
|
+
const override = widths[id];
|
|
227
|
+
const sizing = override
|
|
228
|
+
? { width: `${override}px`, minWidth: `${override}px` }
|
|
229
|
+
: meta.width || meta.minWidth
|
|
230
|
+
? { width: meta.width, minWidth: meta.minWidth ?? meta.width }
|
|
231
|
+
: { minWidth: `${GCSA_TABLE_DEFAULT_COLUMN_MIN_WIDTH}px` };
|
|
232
|
+
if (!meta.fixed) return Object.keys(sizing).length ? sizing : undefined;
|
|
233
|
+
const fixedDirection = meta.fixed === true ? 'left' : meta.fixed;
|
|
234
|
+
const offset = getGcsaTableFixedOffset(
|
|
235
|
+
columns.map(column => ({ id: column.id ?? '', ...metaOf(column) })),
|
|
236
|
+
id,
|
|
237
|
+
fixedDirection,
|
|
238
|
+
{ ...controls, columnWidths: widths }
|
|
239
|
+
);
|
|
240
|
+
return { ...sizing, position: 'sticky', [fixedDirection]: offset } as CSSProperties;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function collectExpandedRows<T extends Record<string, unknown>>(
|
|
244
|
+
rows: T[],
|
|
245
|
+
expanded: ExpandedState,
|
|
246
|
+
getRowId: (row: T, index: number, parent?: Row<T>) => string,
|
|
247
|
+
treeData: boolean,
|
|
248
|
+
childrenKey: keyof T & string
|
|
249
|
+
) {
|
|
250
|
+
const expandedKeys = expanded === true ? undefined : new Set(Object.keys(expanded).filter(key => expanded[key]));
|
|
251
|
+
const result: T[] = [];
|
|
252
|
+
const visit = (items: T[], parent?: Row<T>) => items.forEach((row, index) => {
|
|
253
|
+
const key = getRowId(row, index, parent);
|
|
254
|
+
if (!expandedKeys || expandedKeys.has(key)) result.push(row);
|
|
255
|
+
if (treeData) {
|
|
256
|
+
const children = (row as Record<string, unknown>)[childrenKey];
|
|
257
|
+
if (Array.isArray(children)) visit(children as T[], { id: key } as Row<T>);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
visit(rows);
|
|
261
|
+
return result;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function GcsaDataTable<T extends Record<string, unknown>>({
|
|
265
|
+
data,
|
|
266
|
+
columns,
|
|
267
|
+
legacyColumns,
|
|
268
|
+
total = data.length,
|
|
269
|
+
pageSize: pageSizeProp = 10,
|
|
270
|
+
pageSizeOptions = [10, 20, 50, 100],
|
|
271
|
+
showPageSize = false,
|
|
272
|
+
showJumper = false,
|
|
273
|
+
pageSizeLabel,
|
|
274
|
+
jumperLabel,
|
|
275
|
+
paginationLayout,
|
|
276
|
+
paginationAlign,
|
|
277
|
+
showTotal = true,
|
|
278
|
+
page = 1,
|
|
279
|
+
pagination = true,
|
|
280
|
+
showToolbar = true,
|
|
281
|
+
showCount = true,
|
|
282
|
+
size,
|
|
283
|
+
serverSide = false,
|
|
284
|
+
sorting: controlledSorting,
|
|
285
|
+
filters: controlledFilters,
|
|
286
|
+
defaultSorting = [],
|
|
287
|
+
defaultFilters = {},
|
|
288
|
+
loading = false,
|
|
289
|
+
error,
|
|
290
|
+
retryLabel,
|
|
291
|
+
selectable,
|
|
292
|
+
selectedRowKeys,
|
|
293
|
+
columnVisibility: controlledColumnVisibility,
|
|
294
|
+
resizable = false,
|
|
295
|
+
columnWidths: controlledColumnWidths,
|
|
296
|
+
treeData = false,
|
|
297
|
+
childrenKey = 'children' as keyof T & string,
|
|
298
|
+
treeLazy = false,
|
|
299
|
+
treeHasChildrenKey = 'hasChildren' as keyof T & string,
|
|
300
|
+
treeHasChildren,
|
|
301
|
+
loadChildren,
|
|
302
|
+
treeLoadingText,
|
|
303
|
+
treeLoadErrorText,
|
|
304
|
+
expandedRowKeys,
|
|
305
|
+
mobileMode = 'scroll',
|
|
306
|
+
stripe = false,
|
|
307
|
+
bordered = false,
|
|
308
|
+
highlightCurrentRow = false,
|
|
309
|
+
currentRowKey: controlledCurrentRowKey,
|
|
310
|
+
rowClassName,
|
|
311
|
+
summary,
|
|
312
|
+
summaryLabel,
|
|
313
|
+
apiRef,
|
|
314
|
+
rowKey,
|
|
315
|
+
expandable,
|
|
316
|
+
height,
|
|
317
|
+
maxHeight,
|
|
318
|
+
defaultExpandAll = false,
|
|
319
|
+
fixedSelection,
|
|
320
|
+
selectionColumnWidth,
|
|
321
|
+
expandColumnWidth,
|
|
322
|
+
renderExpandedRow,
|
|
323
|
+
toolbar,
|
|
324
|
+
onPageChange,
|
|
325
|
+
onPageSizeChange,
|
|
326
|
+
onSortingChange,
|
|
327
|
+
onSortChange,
|
|
328
|
+
onFiltersChange,
|
|
329
|
+
onFilterChange,
|
|
330
|
+
onSelectionChange,
|
|
331
|
+
onSelect,
|
|
332
|
+
onSelectAll,
|
|
333
|
+
onSelectedRowKeysChange,
|
|
334
|
+
onColumnVisibilityChange,
|
|
335
|
+
onColumnWidthsChange,
|
|
336
|
+
onExpandedRowKeysChange,
|
|
337
|
+
onCurrentRowKeyChange,
|
|
338
|
+
onRowClick,
|
|
339
|
+
onRowDoubleClick,
|
|
340
|
+
onCellClick,
|
|
341
|
+
onCellDoubleClick,
|
|
342
|
+
onHeaderClick,
|
|
343
|
+
onRowContextMenu,
|
|
344
|
+
onCellContextMenu,
|
|
345
|
+
onLegacyRowClick,
|
|
346
|
+
onLegacyCellClick,
|
|
347
|
+
onLegacyRowContextMenu,
|
|
348
|
+
onLegacyCellContextMenu,
|
|
349
|
+
onCurrentChange,
|
|
350
|
+
onExpandChange,
|
|
351
|
+
columnSelector,
|
|
352
|
+
onRetry,
|
|
353
|
+
onTreeLoadError
|
|
354
|
+
}: GcsaDataTableProps<T>) {
|
|
355
|
+
const messages = useGcsaLocaleMessages();
|
|
356
|
+
const resolvedPageSizeLabel = pageSizeLabel ?? messages.paginationPageSize;
|
|
357
|
+
const resolvedJumperLabel = jumperLabel ?? messages.paginationJumper;
|
|
358
|
+
const resolvedRetryLabel = retryLabel ?? messages.retry;
|
|
359
|
+
const resolvedTreeLoadingText = treeLoadingText ?? messages.dataTableTreeLoading;
|
|
360
|
+
const resolvedTreeLoadErrorText = treeLoadErrorText ?? messages.dataTableTreeLoadError;
|
|
361
|
+
const resolvedSummaryLabel = summaryLabel ?? messages.dataTableSummary;
|
|
362
|
+
const resolvedSize = useGcsaComponentSize(size);
|
|
363
|
+
const getRowId = (row: T, index: number, parent?: Row<T>) => getGcsaTableRowId(row, index, rowKey, parent?.id);
|
|
364
|
+
const [pageSize, setPageSize] = useState(pageSizeProp);
|
|
365
|
+
const [sorting, setSorting] = useState<SortingState>(() => [...(controlledSorting ?? defaultSorting)]);
|
|
366
|
+
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>(() => toColumnFilters(controlledFilters ?? defaultFilters));
|
|
367
|
+
const [rowSelection, setRowSelection] = useState<Record<string, boolean>>(() => Object.fromEntries((selectedRowKeys ?? []).map(key => [key, true])));
|
|
368
|
+
const [columnVisibility, setColumnVisibility] = useState<Record<string, boolean>>(controlledColumnVisibility ?? {});
|
|
369
|
+
const [columnWidths, setColumnWidths] = useState<Record<string, number>>(controlledColumnWidths ?? {});
|
|
370
|
+
const [expandedKeys, setExpandedKeys] = useState<ExpandedState>(() => Object.fromEntries((expandedRowKeys ?? (defaultExpandAll ? getGcsaTableDefaultExpandedKeys(data, treeData, childrenKey, rowKey) : [])).map(key => [key, true])));
|
|
371
|
+
const [currentRowKey, setCurrentRowKey] = useState(controlledCurrentRowKey);
|
|
372
|
+
const [treeChildren, setTreeChildren] = useState<Record<string, T[]>>({});
|
|
373
|
+
const [treeLoadingKeys, setTreeLoadingKeys] = useState<Record<string, boolean>>({});
|
|
374
|
+
const [treeErrors, setTreeErrors] = useState<Record<string, unknown>>({});
|
|
375
|
+
const tableWrapRef = useRef<HTMLDivElement>(null);
|
|
376
|
+
useEffect(() => {
|
|
377
|
+
setPageSize(pageSizeProp);
|
|
378
|
+
}, [pageSizeProp]);
|
|
379
|
+
const treeObjectIds = useMemo(() => new WeakMap<object, string>(), []);
|
|
380
|
+
const treeObjectSequence = useRef(0);
|
|
381
|
+
const legacyMigration = useMemo(() => legacyColumns?.length
|
|
382
|
+
? normalizeGcsaTableColumns(legacyColumns, { page, pageSize })
|
|
383
|
+
: undefined, [legacyColumns, page, pageSize]);
|
|
384
|
+
const effectiveSelectable = legacyMigration?.selectable ?? selectable ?? false;
|
|
385
|
+
const effectiveExpandable = legacyMigration?.expandable ?? expandable ?? false;
|
|
386
|
+
const effectiveFixedSelection = fixedSelection ?? legacyMigration?.fixedSelection ?? false;
|
|
387
|
+
const effectiveSelectionColumnWidth = selectionColumnWidth ?? legacyMigration?.selectionColumnWidth ?? GCSA_TABLE_SELECTION_COLUMN_WIDTH;
|
|
388
|
+
const effectiveExpandColumnWidth = expandColumnWidth ?? legacyMigration?.expandColumnWidth ?? GCSA_TABLE_EXPAND_COLUMN_WIDTH;
|
|
389
|
+
const allColumns = useMemo(() => resolveGcsaTableColumns(legacyMigration?.columns ?? columns ?? []), [legacyMigration, columns]);
|
|
390
|
+
const resolvedColumns = useMemo(() => filterColumnTree(allColumns, columnVisibility), [allColumns, columnVisibility]);
|
|
391
|
+
const leafColumns = useMemo(() => flattenColumns(resolvedColumns), [resolvedColumns]);
|
|
392
|
+
const columnOptions = useMemo(() => flattenColumns(allColumns).filter(column => !metaOf(column).hidden).map(column => ({ id: column.id ?? '', title: typeof column.header === 'string' ? column.header : column.id ?? '', visible: columnVisibility[column.id ?? ''] !== false })), [allColumns, columnVisibility]);
|
|
393
|
+
const treeNodeKey = (row: T, index: number) => {
|
|
394
|
+
const objectRow = row as object;
|
|
395
|
+
const existing = treeObjectIds.get(objectRow);
|
|
396
|
+
if (existing) return existing;
|
|
397
|
+
const key = rowKey ? getRowId(row, index) : `tree-${treeObjectSequence.current++}`;
|
|
398
|
+
treeObjectIds.set(objectRow, key);
|
|
399
|
+
return key;
|
|
400
|
+
};
|
|
401
|
+
const canExpandTreeRow = (row: T, index: number) => {
|
|
402
|
+
const key = treeNodeKey(row, index);
|
|
403
|
+
if (Object.prototype.hasOwnProperty.call(treeChildren, key)) return treeChildren[key].length > 0;
|
|
404
|
+
const children = (row as Record<string, unknown>)[childrenKey as string];
|
|
405
|
+
if (Array.isArray(children) && children.length) return true;
|
|
406
|
+
if (!treeLazy) return false;
|
|
407
|
+
return treeHasChildren ? treeHasChildren(row, index) : (row as Record<string, unknown>)[treeHasChildrenKey as string] === true;
|
|
408
|
+
};
|
|
409
|
+
const tableData = useMemo(() => {
|
|
410
|
+
if (!treeData || !Object.keys(treeChildren).length) return data;
|
|
411
|
+
const merge = (rows: T[]): T[] => rows.map((row, index) => {
|
|
412
|
+
const key = treeNodeKey(row, index);
|
|
413
|
+
const loaded = treeChildren[key];
|
|
414
|
+
const inline = (row as Record<string, unknown>)[childrenKey as string] as T[] | undefined;
|
|
415
|
+
const children = loaded ?? inline;
|
|
416
|
+
if (!children) return row;
|
|
417
|
+
const clone = { ...row, [childrenKey]: merge(children) } as T;
|
|
418
|
+
treeObjectIds.set(clone as object, key);
|
|
419
|
+
return clone;
|
|
420
|
+
});
|
|
421
|
+
return merge(data);
|
|
422
|
+
}, [data, treeChildren, treeData, childrenKey]);
|
|
423
|
+
const getSubRows = (row: T) => treeData ? (((row as Record<string, unknown>)[childrenKey as string] as T[] | undefined) ?? []) : undefined;
|
|
424
|
+
const table = useReactTable({
|
|
425
|
+
data: tableData,
|
|
426
|
+
columns: resolvedColumns,
|
|
427
|
+
state: { pagination: { pageIndex: page - 1, pageSize }, sorting, columnFilters, rowSelection, columnVisibility, expanded: expandedKeys },
|
|
428
|
+
getRowId,
|
|
429
|
+
getSubRows,
|
|
430
|
+
getRowCanExpand: row => treeData ? canExpandTreeRow(row.original, row.index) : false,
|
|
431
|
+
enableRowSelection: row => typeof effectiveSelectable === 'function' ? effectiveSelectable(row.original, row.index) : effectiveSelectable,
|
|
432
|
+
manualPagination: serverSide,
|
|
433
|
+
manualSorting: serverSide,
|
|
434
|
+
manualFiltering: serverSide,
|
|
435
|
+
pageCount: serverSide ? Math.ceil(total / pageSize) : undefined,
|
|
436
|
+
onPaginationChange: updater => { const next = typeof updater === 'function' ? updater({ pageIndex: page - 1, pageSize }) : updater; onPageChange?.(next.pageIndex + 1); },
|
|
437
|
+
onSortingChange: updater => { const next = typeof updater === 'function' ? updater(sorting) : updater; setSorting(next); onSortingChange?.(next); onSortChange?.(getGcsaTableSortChange(next)); },
|
|
438
|
+
onColumnFiltersChange: updater => { const next = typeof updater === 'function' ? updater(columnFilters) : updater; setColumnFilters(next); onFiltersChange?.(filterRecord(next)); },
|
|
439
|
+
onColumnVisibilityChange: updater => { const next = typeof updater === 'function' ? updater(columnVisibility) : updater; setColumnVisibility(next); onColumnVisibilityChange?.(next); },
|
|
440
|
+
onRowSelectionChange: updater => {
|
|
441
|
+
const next = typeof updater === 'function' ? updater(rowSelection) : updater;
|
|
442
|
+
setRowSelection(next);
|
|
443
|
+
onSelectedRowKeysChange?.(Object.keys(next).filter(key => next[key]));
|
|
444
|
+
onSelectionChange?.(selectedRowsForState(next));
|
|
445
|
+
},
|
|
446
|
+
onExpandedChange: updater => {
|
|
447
|
+
const next = typeof updater === 'function' ? updater(expandedKeys) : updater;
|
|
448
|
+
setExpandedKeys(next);
|
|
449
|
+
onExpandedRowKeysChange?.(next === true ? table.getRowModel().flatRows.map(row => row.id) : Object.keys(next).filter(key => next[key]));
|
|
450
|
+
},
|
|
451
|
+
getCoreRowModel: getCoreRowModel(),
|
|
452
|
+
getFilteredRowModel: serverSide ? undefined : getFilteredRowModel(),
|
|
453
|
+
getSortedRowModel: serverSide ? undefined : getSortedRowModel(),
|
|
454
|
+
getPaginationRowModel: serverSide ? undefined : getPaginationRowModel(),
|
|
455
|
+
getExpandedRowModel: treeData ? getExpandedRowModel() : undefined
|
|
456
|
+
});
|
|
457
|
+
useEffect(() => {
|
|
458
|
+
if (controlledSorting) setSorting([...controlledSorting]);
|
|
459
|
+
}, [controlledSorting]);
|
|
460
|
+
useEffect(() => {
|
|
461
|
+
if (defaultExpandAll && !expandedRowKeys) {
|
|
462
|
+
setExpandedKeys(Object.fromEntries(getGcsaTableDefaultExpandedKeys(data, treeData, childrenKey, rowKey).map(key => [key, true])));
|
|
463
|
+
}
|
|
464
|
+
}, [data, treeData, defaultExpandAll, expandedRowKeys, childrenKey, rowKey]);
|
|
465
|
+
useEffect(() => {
|
|
466
|
+
if (controlledFilters) setColumnFilters(toColumnFilters(controlledFilters));
|
|
467
|
+
}, [controlledFilters]);
|
|
468
|
+
useEffect(() => {
|
|
469
|
+
if (selectedRowKeys) setRowSelection(Object.fromEntries(selectedRowKeys.map(key => [key, true])));
|
|
470
|
+
}, [selectedRowKeys]);
|
|
471
|
+
useEffect(() => {
|
|
472
|
+
if (controlledColumnVisibility) setColumnVisibility(controlledColumnVisibility);
|
|
473
|
+
}, [controlledColumnVisibility]);
|
|
474
|
+
useEffect(() => {
|
|
475
|
+
if (controlledColumnWidths) setColumnWidths(controlledColumnWidths);
|
|
476
|
+
}, [controlledColumnWidths]);
|
|
477
|
+
useEffect(() => {
|
|
478
|
+
if (expandedRowKeys) setExpandedKeys(Object.fromEntries(expandedRowKeys.map(key => [key, true])));
|
|
479
|
+
}, [expandedRowKeys]);
|
|
480
|
+
useEffect(() => {
|
|
481
|
+
setCurrentRowKey(controlledCurrentRowKey);
|
|
482
|
+
}, [controlledCurrentRowKey]);
|
|
483
|
+
const selectedCount = table.getSelectedRowModel().rows.length;
|
|
484
|
+
const totalCountText = formatGcsaLocaleMessage(messages.dataTableTotal, { count: total });
|
|
485
|
+
const selectedCountText = formatGcsaLocaleMessage(messages.dataTableSelected, { count: selectedCount });
|
|
486
|
+
const selectableRows = table.getRowModel().rows.filter(row => row.getCanSelect());
|
|
487
|
+
const visibleColumnCount = leafColumns.length + (effectiveSelectable ? 1 : 0) + (effectiveExpandable || treeData ? 1 : 0);
|
|
488
|
+
const fixedControls = Boolean(effectiveSelectable && effectiveFixedSelection);
|
|
489
|
+
const fixedLayout = { expandable: effectiveExpandable || treeData, selectable: Boolean(effectiveSelectable), fixedSelection: effectiveFixedSelection, expandColumnWidth: effectiveExpandColumnWidth, selectionColumnWidth: effectiveSelectionColumnWidth };
|
|
490
|
+
const tableMinWidth = useMemo(
|
|
491
|
+
() => getGcsaTableMinWidth(
|
|
492
|
+
leafColumns.map(column => ({ id: column.id ?? '', ...metaOf(column) })),
|
|
493
|
+
{
|
|
494
|
+
expandable: effectiveExpandable || treeData,
|
|
495
|
+
selectable: Boolean(effectiveSelectable),
|
|
496
|
+
expandColumnWidth: effectiveExpandColumnWidth,
|
|
497
|
+
selectionColumnWidth: effectiveSelectionColumnWidth,
|
|
498
|
+
columnWidths
|
|
499
|
+
}
|
|
500
|
+
),
|
|
501
|
+
[
|
|
502
|
+
columnWidths,
|
|
503
|
+
effectiveExpandColumnWidth,
|
|
504
|
+
effectiveExpandable,
|
|
505
|
+
effectiveSelectionColumnWidth,
|
|
506
|
+
effectiveSelectable,
|
|
507
|
+
leafColumns,
|
|
508
|
+
treeData
|
|
509
|
+
]
|
|
510
|
+
);
|
|
511
|
+
const expandColumnStyle: CSSProperties = {
|
|
512
|
+
width: effectiveExpandColumnWidth,
|
|
513
|
+
minWidth: effectiveExpandColumnWidth,
|
|
514
|
+
maxWidth: effectiveExpandColumnWidth,
|
|
515
|
+
...(fixedControls ? { position: 'sticky', left: 0 } : {})
|
|
516
|
+
};
|
|
517
|
+
const selectionColumnStyle: CSSProperties = {
|
|
518
|
+
width: effectiveSelectionColumnWidth,
|
|
519
|
+
minWidth: effectiveSelectionColumnWidth,
|
|
520
|
+
maxWidth: effectiveSelectionColumnWidth,
|
|
521
|
+
...(fixedControls ? { position: 'sticky', left: effectiveExpandable || treeData ? effectiveExpandColumnWidth : 0 } : {})
|
|
522
|
+
};
|
|
523
|
+
const filterValue = (id: string) => String(columnFilters.find(filter => filter.id === id)?.value ?? '');
|
|
524
|
+
const updateFilter = (id: string, value: string) => {
|
|
525
|
+
const next = columnFilters.filter(filter => filter.id !== id);
|
|
526
|
+
if (value) next.push({ id, value });
|
|
527
|
+
setColumnFilters(next);
|
|
528
|
+
const filters = filterRecord(next);
|
|
529
|
+
onFiltersChange?.(filters);
|
|
530
|
+
onFilterChange?.(filters);
|
|
531
|
+
};
|
|
532
|
+
const rangeStart = total ? (page - 1) * pageSize + 1 : 0;
|
|
533
|
+
const rangeEnd = Math.min(page * pageSize, total);
|
|
534
|
+
const rangeText = formatGcsaLocaleMessage(messages.dataTableRange, {
|
|
535
|
+
start: rangeStart,
|
|
536
|
+
end: rangeEnd,
|
|
537
|
+
total
|
|
538
|
+
});
|
|
539
|
+
const toggleColumn = (id: string) => {
|
|
540
|
+
const visibleCount = leafColumns.length;
|
|
541
|
+
const next = { ...columnVisibility, [id]: columnVisibility[id] === false };
|
|
542
|
+
if (!next[id] && visibleCount <= 1) return;
|
|
543
|
+
setColumnVisibility(next);
|
|
544
|
+
onColumnVisibilityChange?.(next);
|
|
545
|
+
};
|
|
546
|
+
const startColumnResize = (event: ReactPointerEvent<HTMLSpanElement>, id: string) => {
|
|
547
|
+
const cell = event.currentTarget.parentElement;
|
|
548
|
+
const sourceColumn = leafColumns.find(column => column.id === id) as ColumnDef<T, unknown> | undefined;
|
|
549
|
+
const sourceMeta = sourceColumn ? metaOf(sourceColumn) : {};
|
|
550
|
+
const initialWidth = cell?.getBoundingClientRect().width ?? Number.parseFloat(String(sourceMeta.width ?? '0'));
|
|
551
|
+
const minWidth = Math.max(64, Number.parseFloat(String(sourceMeta.minWidth ?? sourceMeta.width ?? '64')) || 64);
|
|
552
|
+
const startX = event.clientX;
|
|
553
|
+
const move = (moveEvent: PointerEvent) => {
|
|
554
|
+
const next = Math.max(minWidth, Math.round(initialWidth + moveEvent.clientX - startX));
|
|
555
|
+
setColumnWidths(current => ({ ...current, [id]: next }));
|
|
556
|
+
};
|
|
557
|
+
const up = () => {
|
|
558
|
+
setColumnWidths(current => { onColumnWidthsChange?.(current); return current; });
|
|
559
|
+
document.removeEventListener('pointermove', move);
|
|
560
|
+
document.removeEventListener('pointerup', up);
|
|
561
|
+
};
|
|
562
|
+
document.addEventListener('pointermove', move);
|
|
563
|
+
document.addEventListener('pointerup', up, { once: true });
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
const tableRows = table.getRowModel().rows;
|
|
567
|
+
const expandedRowsFor = (expanded: ExpandedState) => collectExpandedRows(tableData, expanded, (row, index, parent) => getRowId(row, index, parent), treeData, childrenKey);
|
|
568
|
+
const summaryValues = summary?.(data);
|
|
569
|
+
const isRowExpanded = (rowIdValue: string) => expandedKeys === true ? true : expandedKeys[rowIdValue] === true;
|
|
570
|
+
const treeLoading = (row: Row<T>) => Boolean(treeLoadingKeys[treeNodeKey(row.original, row.index)]);
|
|
571
|
+
const treeError = (row: Row<T>) => Boolean(treeErrors[treeNodeKey(row.original, row.index)]);
|
|
572
|
+
const applyExpanded = (row: Row<T>, expanded: boolean) => {
|
|
573
|
+
const nextExpanded = { ...(expandedKeys === true ? {} : expandedKeys), [row.id]: expanded };
|
|
574
|
+
setExpandedKeys(nextExpanded);
|
|
575
|
+
onExpandedRowKeysChange?.(Object.keys(nextExpanded).filter(key => nextExpanded[key]));
|
|
576
|
+
onExpandChange?.(row.original, expanded, expandedRowsFor(nextExpanded));
|
|
577
|
+
};
|
|
578
|
+
const toggleExpanded = async (row: Row<T>) => {
|
|
579
|
+
if (treeData && treeLazy && !isRowExpanded(row.id)) {
|
|
580
|
+
const key = treeNodeKey(row.original, row.index);
|
|
581
|
+
if (!Object.prototype.hasOwnProperty.call(treeChildren, key) && loadChildren && canExpandTreeRow(row.original, row.index)) {
|
|
582
|
+
setTreeLoadingKeys(current => ({ ...current, [key]: true }));
|
|
583
|
+
setTreeErrors(current => { const next = { ...current }; delete next[key]; return next; });
|
|
584
|
+
try {
|
|
585
|
+
const children = await loadChildren(row.original, row.index);
|
|
586
|
+
setTreeChildren(current => ({ ...current, [key]: children ?? [] }));
|
|
587
|
+
if (children?.length) {
|
|
588
|
+
applyExpanded(row, true);
|
|
589
|
+
}
|
|
590
|
+
} catch (error) {
|
|
591
|
+
setTreeErrors(current => ({ ...current, [key]: error }));
|
|
592
|
+
onTreeLoadError?.(error, row.original, row.index);
|
|
593
|
+
} finally {
|
|
594
|
+
setTreeLoadingKeys(current => { const next = { ...current }; delete next[key]; return next; });
|
|
595
|
+
}
|
|
596
|
+
} else if (Object.prototype.hasOwnProperty.call(treeChildren, key)) {
|
|
597
|
+
applyExpanded(row, !isRowExpanded(row.id));
|
|
598
|
+
}
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
if (treeData) {
|
|
602
|
+
applyExpanded(row, !isRowExpanded(row.id));
|
|
603
|
+
} else {
|
|
604
|
+
const expanded = !isRowExpanded(row.id);
|
|
605
|
+
applyExpanded(row, expanded);
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
const tableClassName = ['gcsa-table', resolvedSize === 'sm' ? 'gcsa-table--sm' : undefined, stripe ? 'gcsa-table--striped' : undefined, bordered ? 'gcsa-table--bordered' : undefined].filter(Boolean).join(' ');
|
|
609
|
+
const getRowClassName = (row: T, index: number) => typeof rowClassName === 'function' ? rowClassName(row, index) : rowClassName;
|
|
610
|
+
const getColumnInfo = (id: string): GcsaTableColumnInfo => {
|
|
611
|
+
const column = leafColumns.find(candidate => candidate.id === id);
|
|
612
|
+
const meta = column ? metaOf(column) : {};
|
|
613
|
+
return { id, prop: id, label: typeof column?.header === 'string' ? column.header : id, width: meta.width, minWidth: meta.minWidth, fixed: meta.fixed };
|
|
614
|
+
};
|
|
615
|
+
const selectCurrentRow = (row: T, index: number) => {
|
|
616
|
+
if (!highlightCurrentRow) return;
|
|
617
|
+
const key = getRowId(row, index);
|
|
618
|
+
setCurrentRowKey(key);
|
|
619
|
+
onCurrentRowKeyChange?.(key);
|
|
620
|
+
};
|
|
621
|
+
const emitSelection = (next: Record<string, boolean>) => {
|
|
622
|
+
setRowSelection(next);
|
|
623
|
+
const keys = Object.keys(next).filter(key => next[key]);
|
|
624
|
+
onSelectedRowKeysChange?.(keys);
|
|
625
|
+
onSelectionChange?.(selectedRowsForState(next));
|
|
626
|
+
};
|
|
627
|
+
const clearSorting = () => { setSorting([]); onSortingChange?.([]); onSortChange?.(getGcsaTableSortChange([])); };
|
|
628
|
+
const clearFilters = () => { setColumnFilters([]); onFiltersChange?.({}); onFilterChange?.({}); };
|
|
629
|
+
const clearFilter = (columnKeys?: string | string[]) => {
|
|
630
|
+
if (columnKeys === undefined) {
|
|
631
|
+
clearFilters();
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
const keys = new Set(Array.isArray(columnKeys) ? columnKeys : [columnKeys]);
|
|
635
|
+
const next = columnFilters.filter(filter => !keys.has(filter.id));
|
|
636
|
+
setColumnFilters(next);
|
|
637
|
+
const filters = filterRecord(next);
|
|
638
|
+
onFiltersChange?.(filters);
|
|
639
|
+
onFilterChange?.(filters);
|
|
640
|
+
};
|
|
641
|
+
const sort = (prop: string, order: 'ascending' | 'descending' | null) => {
|
|
642
|
+
const next = getGcsaTableSorting(prop, order);
|
|
643
|
+
setSorting(next);
|
|
644
|
+
onSortingChange?.(next);
|
|
645
|
+
onSortChange?.(getGcsaTableSortChange(next));
|
|
646
|
+
};
|
|
647
|
+
const clearSelection = () => emitSelection({});
|
|
648
|
+
const clearExpanded = () => { setExpandedKeys({}); onExpandedRowKeysChange?.([]); };
|
|
649
|
+
const setRowSelected = (key: string, selected = true) => {
|
|
650
|
+
const row = table.getCoreRowModel().flatRows.find(candidate => candidate.id === key);
|
|
651
|
+
if (!row || !row.getCanSelect()) return;
|
|
652
|
+
emitSelection({ ...rowSelection, [key]: selected });
|
|
653
|
+
};
|
|
654
|
+
const toggleRowSelection = (row: T, selected?: boolean) => {
|
|
655
|
+
const tableRow = findTableRow(row);
|
|
656
|
+
if (!tableRow || !tableRow.getCanSelect()) return;
|
|
657
|
+
setRowSelected(tableRow.id, selected ?? !tableRow.getIsSelected());
|
|
658
|
+
};
|
|
659
|
+
const rowsForSelection = (selection: Record<string, boolean>) => table.getCoreRowModel().flatRows
|
|
660
|
+
.filter(row => selection[row.id] && row.getCanSelect())
|
|
661
|
+
.map(row => row.original);
|
|
662
|
+
const selectedRowsForState = rowsForSelection;
|
|
663
|
+
const toggleRowSelectionValue = (row: Row<T>, selected: boolean) => {
|
|
664
|
+
const next = { ...rowSelection, [row.id]: selected };
|
|
665
|
+
row.toggleSelected(selected);
|
|
666
|
+
onSelect?.(rowsForSelection(next), row.original);
|
|
667
|
+
};
|
|
668
|
+
const toggleAllSelection = (checked?: boolean) => {
|
|
669
|
+
const allSelected = selectableRows.length > 0 && selectableRows.every(row => row.getIsSelected());
|
|
670
|
+
const nextChecked = checked ?? !allSelected;
|
|
671
|
+
table.toggleAllPageRowsSelected(nextChecked);
|
|
672
|
+
const next = { ...rowSelection };
|
|
673
|
+
selectableRows.forEach(row => { next[row.id] = nextChecked; });
|
|
674
|
+
onSelectAll?.(rowsForSelection(next));
|
|
675
|
+
};
|
|
676
|
+
const setRowExpanded = async (key: string, expanded = true) => {
|
|
677
|
+
const row = table.getCoreRowModel().flatRows.find(candidate => candidate.id === key);
|
|
678
|
+
if (!row) return;
|
|
679
|
+
if (treeData) {
|
|
680
|
+
if (isRowExpanded(key) === expanded) return;
|
|
681
|
+
if (expanded) await toggleExpanded(row);
|
|
682
|
+
else applyExpanded(row, false);
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
const next = { ...(expandedKeys === true ? {} : expandedKeys), [key]: expanded };
|
|
686
|
+
setExpandedKeys(next);
|
|
687
|
+
onExpandedRowKeysChange?.(Object.keys(next).filter(value => next[value]));
|
|
688
|
+
};
|
|
689
|
+
const toggleRowExpansion = async (row: T, expanded?: boolean) => {
|
|
690
|
+
const tableRow = findTableRow(row);
|
|
691
|
+
if (!tableRow) return;
|
|
692
|
+
await setRowExpanded(tableRow.id, expanded ?? !isRowExpanded(tableRow.id));
|
|
693
|
+
};
|
|
694
|
+
const setCurrentRow = (row?: T) => {
|
|
695
|
+
const tableRow = row ? findTableRow(row) : undefined;
|
|
696
|
+
setCurrentRowKey(tableRow?.id);
|
|
697
|
+
onCurrentRowKeyChange?.(tableRow?.id);
|
|
698
|
+
};
|
|
699
|
+
const findTableRow = (row: T) => {
|
|
700
|
+
const rows = table.getCoreRowModel().flatRows;
|
|
701
|
+
const byReference = rows.find(candidate => candidate.original === row);
|
|
702
|
+
if (byReference) return byReference;
|
|
703
|
+
if (rowKey) {
|
|
704
|
+
const key = getRowId(row, 0);
|
|
705
|
+
return rows.find(candidate => candidate.id === key);
|
|
706
|
+
}
|
|
707
|
+
return undefined;
|
|
708
|
+
};
|
|
709
|
+
const getSelectionRows = () => table.getCoreRowModel().flatRows.filter(row => row.getIsSelected()).map(row => row.original);
|
|
710
|
+
const setScrollTop = (top: number) => tableWrapRef.current?.scrollTo({ top });
|
|
711
|
+
const scrollTo = (options: ScrollToOptions | number, y?: number) => {
|
|
712
|
+
if (typeof options === 'number') tableWrapRef.current?.scrollTo(options, y ?? 0);
|
|
713
|
+
else tableWrapRef.current?.scrollTo(options);
|
|
714
|
+
};
|
|
715
|
+
if (apiRef) {
|
|
716
|
+
apiRef.current = {
|
|
717
|
+
clearSorting,
|
|
718
|
+
clearFilters,
|
|
719
|
+
clearSelection,
|
|
720
|
+
clearExpanded,
|
|
721
|
+
setRowSelected,
|
|
722
|
+
setRowExpanded,
|
|
723
|
+
clearSort: clearSorting,
|
|
724
|
+
clearFilter,
|
|
725
|
+
sort,
|
|
726
|
+
toggleRowSelection,
|
|
727
|
+
toggleAllSelection,
|
|
728
|
+
toggleRowExpansion,
|
|
729
|
+
setCurrentRow,
|
|
730
|
+
getSelectionRows,
|
|
731
|
+
setScrollTop,
|
|
732
|
+
scrollTo
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
return <div className={`gcsa-data-table${mobileMode === 'cards' ? ' gcsa-data-table--cards' : ''}`}>
|
|
736
|
+
{showToolbar && (toolbar || columnSelector) ? <div className="gcsa-data-table__toolbar"><div className="gcsa-data-table__toolbar-meta">{showCount && !loading ? <span className="gcsa-data-table__count">{totalCountText}</span> : null}{selectedCount ? <span className="gcsa-data-table__selected">{selectedCountText}</span> : null}</div><div className="gcsa-data-table__toolbar-actions">{toolbar}{columnSelector ? <div className="gcsa-data-table__columns-control">{columnSelector(columnOptions, toggleColumn)}</div> : null}</div></div> : null}
|
|
737
|
+
<div ref={tableWrapRef} className="gcsa-table-wrap gcsa-ui-surface" style={{ height: height === undefined ? undefined : typeof height === 'number' ? `${height}px` : height, maxHeight: maxHeight === undefined ? undefined : typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight }}>
|
|
738
|
+
{loading ? <TableLoadingState label={messages.dataTableLoading} /> : null}
|
|
739
|
+
{error ? <div className="gcsa-data-table__state gcsa-data-table__state--error" role="alert"><span>{error}</span><button type="button" className="gcsa-btn gcsa-btn--sm gcsa-btn--secondary" onClick={onRetry}>{resolvedRetryLabel}</button></div> : null}
|
|
740
|
+
{!loading && !error ? <table className={tableClassName} style={{ minWidth: tableMinWidth }}>
|
|
741
|
+
<thead className="gcsa-table__head">
|
|
742
|
+
{table.getHeaderGroups().map((headerGroup, groupIndex) => <tr key={headerGroup.id}>
|
|
743
|
+
{groupIndex === 0 && (effectiveExpandable || treeData) ? <th className="gcsa-table__col-expand" style={expandColumnStyle} rowSpan={table.getHeaderGroups().length} /> : null}
|
|
744
|
+
{groupIndex === 0 && effectiveSelectable ? <th className="gcsa-table__col-check" style={selectionColumnStyle} rowSpan={table.getHeaderGroups().length}><GcsaCheckbox checked={selectableRows.length > 0 && selectableRows.every(row => row.getIsSelected())} disabled={!selectableRows.length} label="" ariaLabel={messages.dataTableSelectAll} onCheckedChange={checked => toggleAllSelection(checked)} /></th> : null}
|
|
745
|
+
{headerGroup.headers.map(header => {
|
|
746
|
+
const meta = metaOf(header.column.columnDef);
|
|
747
|
+
const isLeaf = !header.column.columns.length;
|
|
748
|
+
return <th key={header.id} colSpan={header.colSpan} rowSpan={header.rowSpan > 1 ? header.rowSpan : undefined} style={fixedStyle(leafColumns, header.column.id, meta, columnWidths, fixedLayout)} className={meta.align === 'center' ? 'gcsa-table__align-center' : meta.align === 'right' ? 'gcsa-table__align-right' : undefined} onClick={event => onHeaderClick?.(getColumnInfo(header.column.id), event)}>
|
|
749
|
+
{header.isPlaceholder ? null : isLeaf && header.column.getCanSort() ? <button type="button" className={`gcsa-table__sort${header.column.getIsSorted() ? ' gcsa-table__sort--active' : ''}`} onClick={header.column.getToggleSortingHandler()}><span className="gcsa-table__sort-label">{flexRender(header.column.columnDef.header, header.getContext())}</span><span className="gcsa-table__sort-icon" aria-hidden="true"><GcsaIcon name="chevronUp" size="sm" /><GcsaIcon name="chevronDown" size="sm" /></span></button> : isLeaf ? <span className="gcsa-table__head-text">{flexRender(header.column.columnDef.header, header.getContext())}</span> : <span className="gcsa-table__head-text">{flexRender(header.column.columnDef.header, header.getContext())}</span>}
|
|
750
|
+
{isLeaf && meta.filter ? <div className="gcsa-table__filter">{meta.filter.type === 'text' ? <GcsaInput value={filterValue(header.column.id)} placeholder={meta.filter.placeholder ?? messages.dataTableFilter} onValueChange={value => updateFilter(header.column.id, value)} /> : <GcsaSelect value={filterValue(header.column.id)} options={meta.filter.options ?? []} placeholder={meta.filter.placeholder ?? messages.dataTableFilter} onValueChange={value => updateFilter(header.column.id, value)} />}</div> : null}
|
|
751
|
+
{resizable && isLeaf ? <span className="gcsa-table__resize-handle" role="separator" aria-label={messages.dataTableResizeColumn} onPointerDown={event => { event.stopPropagation(); event.preventDefault(); startColumnResize(event, header.column.id); }} /> : null}
|
|
752
|
+
</th>;
|
|
753
|
+
})}
|
|
754
|
+
</tr>)}
|
|
755
|
+
</thead>
|
|
756
|
+
<tbody className="gcsa-table__body">
|
|
757
|
+
{table.getRowModel().rows.map(row => { const rowExpanded = isRowExpanded(row.id); return <Fragment key={row.id}>
|
|
758
|
+
<tr key={row.id} className={`gcsa-table__row${row.index % 2 === 1 ? ' gcsa-table__row--striped' : ''}${getRowClassName(row.original, row.index) ? ` ${getRowClassName(row.original, row.index)}` : ''}`} data-selected={row.getIsSelected() || undefined} data-current={highlightCurrentRow && currentRowKey === getRowId(row.original, row.index) ? true : undefined} onClick={event => { const previous = highlightCurrentRow ? table.getCoreRowModel().flatRows.find(candidate => candidate.id === currentRowKey)?.original : undefined; selectCurrentRow(row.original, row.index); if (highlightCurrentRow) onCurrentChange?.(row.original, previous); onRowClick?.(row.original, row.index, event); onLegacyRowClick?.(row.original, getColumnInfo(row.getVisibleCells()[0]?.column.id ?? ''), event); }} onDoubleClick={event => onRowDoubleClick?.(row.original, row.index, event)} onContextMenu={event => { event.preventDefault(); onRowContextMenu?.(row.original, row.index, event); onLegacyRowContextMenu?.(row.original, getColumnInfo(row.getVisibleCells()[0]?.column.id ?? ''), event); }}>
|
|
759
|
+
{effectiveExpandable || treeData ? <td className="gcsa-table__col-expand" style={expandColumnStyle} onClick={event => event.stopPropagation()}>{(!treeData || row.getCanExpand()) ? <><button type="button" className="gcsa-table__expand gcsa-focus-ring" disabled={treeLoading(row)} aria-label={treeLoading(row) ? messages.dataTableLoadChildren : treeError(row) ? messages.dataTableRetryChildren : rowExpanded ? messages.dataTableCollapseRow : messages.dataTableExpandRow} aria-expanded={rowExpanded} onClick={() => toggleExpanded(row)}><GcsaIcon name="chevronDown" size="sm" className={rowExpanded ? 'gcsa-table__expand-icon--open' : undefined} /></button>{treeLoading(row) ? <span className="gcsa-table__tree-state" role="status">{resolvedTreeLoadingText}</span> : treeError(row) ? <button type="button" className="gcsa-table__tree-retry" onClick={() => toggleExpanded(row)}>{resolvedTreeLoadErrorText}</button> : null}</> : null}</td> : null}
|
|
760
|
+
{effectiveSelectable ? <td className="gcsa-table__col-check" onClick={event => event.stopPropagation()} style={selectionColumnStyle}><GcsaCheckbox checked={row.getIsSelected()} disabled={!row.getCanSelect()} label="" ariaLabel={messages.dataTableSelectRow} onCheckedChange={checked => toggleRowSelectionValue(row, checked)} /></td> : null}
|
|
761
|
+
{row.getVisibleCells().map((cell, cellIndex) => { const cellMeta = metaOf(cell.column.columnDef); const cellValue = cell.getValue(); return <td key={cell.id} data-label={typeof cell.column.columnDef.header === 'string' ? cell.column.columnDef.header : cell.column.id} title={cellMeta.showOverflowTooltip ? formatGcsaTableCellValue(cellValue) : undefined} className={`${cellMeta.align === 'center' ? 'gcsa-table__align-center' : cellMeta.align === 'right' ? 'gcsa-table__align-right' : ''}${cellMeta.showOverflowTooltip ? ' gcsa-table__cell--overflow' : ''}`} style={fixedStyle(leafColumns, cell.column.id, cellMeta, columnWidths, fixedLayout)} onClick={event => { event.stopPropagation(); selectCurrentRow(row.original, row.index); onCellClick?.(row.original, cell.column.id, cellValue, row.index, event); onLegacyCellClick?.(row.original, getColumnInfo(cell.column.id), event.currentTarget, event); }} onDoubleClick={event => { event.stopPropagation(); onCellDoubleClick?.(row.original, cell.column.id, cellValue, row.index, event); }} onContextMenu={event => { event.stopPropagation(); event.preventDefault(); onCellContextMenu?.(row.original, cell.column.id, cellValue, row.index, event); onLegacyCellContextMenu?.(row.original, getColumnInfo(cell.column.id), event.currentTarget, event); }}><div className="gcsa-table__cell" style={treeData && cellIndex === 0 ? { paddingInlineStart: `${row.depth * 18}px` } : undefined}>{cell.column.columnDef.cell ? flexRender(cell.column.columnDef.cell, cell.getContext()) : formatGcsaTableCellValue(cellValue)}</div></td>; })}
|
|
762
|
+
</tr>
|
|
763
|
+
{!treeData && rowExpanded && renderExpandedRow ? <tr key={`${row.id}-expanded`} className="gcsa-table__expanded-row"><td colSpan={visibleColumnCount}>{renderExpandedRow(row.original, row.index)}</td></tr> : null}
|
|
764
|
+
</Fragment>; })}
|
|
765
|
+
</tbody>
|
|
766
|
+
{summaryValues ? <tfoot className="gcsa-table__foot"><tr className="gcsa-table__summary-row">
|
|
767
|
+
{effectiveExpandable || treeData ? <th className="gcsa-table__col-expand" scope="row" style={expandColumnStyle} /> : null}
|
|
768
|
+
{effectiveSelectable ? <th className="gcsa-table__col-check" scope="row" style={selectionColumnStyle} /> : null}
|
|
769
|
+
{leafColumns.map((column, summaryIndex) => {
|
|
770
|
+
const columnMeta = metaOf(column);
|
|
771
|
+
return <td key={column.id} className={columnMeta.align === 'center' ? 'gcsa-table__align-center' : columnMeta.align === 'right' ? 'gcsa-table__align-right' : undefined} style={fixedStyle(leafColumns, column.id ?? '', columnMeta, columnWidths, fixedLayout)}>{summaryValues[column.id ?? ''] ?? (summaryIndex === 0 ? resolvedSummaryLabel : '')}</td>;
|
|
772
|
+
})}
|
|
773
|
+
</tr></tfoot> : null}
|
|
774
|
+
</table> : null}
|
|
775
|
+
{!loading && !error && tableRows.length === 0 ? <div className="gcsa-data-table__empty"><GcsaEmpty title={messages.dataTableEmpty} /></div> : null}
|
|
776
|
+
</div>
|
|
777
|
+
{pagination && total > 0 && !loading && !error ? <div className="gcsa-data-table__footer">{showTotal ? <div className="gcsa-data-table__footer-meta">{rangeText}</div> : null}<GcsaPagination page={page} total={total} pageSize={pageSize} pageSizeOptions={pageSizeOptions} showPageSize={showPageSize} showJumper={showJumper} pageSizeLabel={resolvedPageSizeLabel} jumperLabel={resolvedJumperLabel} layout={paginationLayout} align={paginationAlign} onPageChange={onPageChange} onPageSizeChange={next => { setPageSize(next); onPageSizeChange?.(next); }} /></div> : null}
|
|
778
|
+
</div>;
|
|
779
|
+
}
|