@jmruthers/pace-core 0.4.1 → 0.5.1
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/CHANGELOG.md +26 -1
- package/README.md +231 -229
- package/dist/{DataTable-2LB6HI6V.js → DataTable-GX3XERFJ.js} +14 -17
- package/dist/{DataTable-BDBqkU-i.d.ts → DataTable-ltTFXHS3.d.ts} +25 -51
- package/dist/{Table-CIm9IWqk.d.ts → PublicLoadingSpinner-DztrzuJr.d.ts} +635 -122
- package/dist/UnifiedAuthProvider-w66zSCUf.d.ts +160 -0
- package/dist/{api-AIJ3IJX3.js → api-ETQ6YJ3C.js} +6 -4
- package/dist/{appConfig-fB1pP_v3.d.ts → appConfig-BVGyuvI7.d.ts} +1 -1
- package/dist/appNameResolver-7GHF5ED2.js +22 -0
- package/dist/{audit-PD5L5ZSC.js → audit-BUW3LMJB.js} +3 -3
- package/dist/chunk-5EL3KHOQ.js +388 -0
- package/dist/chunk-5EL3KHOQ.js.map +1 -0
- package/dist/{chunk-4MCJAK7J.js → chunk-6CR3MRZN.js} +1827 -4886
- package/dist/chunk-6CR3MRZN.js.map +1 -0
- package/dist/{chunk-YNU5QJ4S.js → chunk-7BNPOCLL.js} +22 -5
- package/dist/chunk-7BNPOCLL.js.map +1 -0
- package/dist/chunk-AUE24LVR.js +268 -0
- package/dist/chunk-AUE24LVR.js.map +1 -0
- package/dist/chunk-C5G2A4PO.js +1349 -0
- package/dist/chunk-C5G2A4PO.js.map +1 -0
- package/dist/{chunk-4ZTIEYU2.js → chunk-CDQ3PX7L.js} +1 -1
- package/dist/chunk-CDQ3PX7L.js.map +1 -0
- package/dist/chunk-COBPIXXQ.js +379 -0
- package/dist/chunk-COBPIXXQ.js.map +1 -0
- package/dist/chunk-GSNM5D6H.js +5441 -0
- package/dist/chunk-GSNM5D6H.js.map +1 -0
- package/dist/chunk-MZBUOP4P.js +119 -0
- package/dist/chunk-MZBUOP4P.js.map +1 -0
- package/dist/chunk-N2EUGZRW.js +98 -0
- package/dist/chunk-N2EUGZRW.js.map +1 -0
- package/dist/chunk-NQ4TOOO6.js +20 -0
- package/dist/chunk-NQ4TOOO6.js.map +1 -0
- package/dist/{chunk-KK6WIDK6.js → chunk-OEGRKULD.js} +12 -2
- package/dist/{chunk-KK6WIDK6.js.map → chunk-OEGRKULD.js.map} +1 -1
- package/dist/chunk-OYRY44Q2.js +62 -0
- package/dist/chunk-OYRY44Q2.js.map +1 -0
- package/dist/{chunk-DC5AMYBS.js → chunk-PLDDJCW6.js} +15 -5
- package/dist/chunk-PLDDJCW6.js.map +1 -0
- package/dist/{chunk-WHLSWC6W.js → chunk-SS3E6QLB.js} +16 -61
- package/dist/chunk-SS3E6QLB.js.map +1 -0
- package/dist/chunk-T3XIA4AJ.js +3295 -0
- package/dist/chunk-T3XIA4AJ.js.map +1 -0
- package/dist/{chunk-H4PZ4B3Y.js → chunk-TGDCLPP2.js} +129 -28
- package/dist/chunk-TGDCLPP2.js.map +1 -0
- package/dist/{chunk-IOX76PSM.js → chunk-U6JDHVC2.js} +273 -29
- package/dist/chunk-U6JDHVC2.js.map +1 -0
- package/dist/{chunk-JUUNUW3O.js → chunk-XJK2J4N6.js} +17 -6
- package/dist/chunk-XJK2J4N6.js.map +1 -0
- package/dist/chunk-YDJW5XTN.js +84 -0
- package/dist/chunk-YDJW5XTN.js.map +1 -0
- package/dist/components.d.ts +906 -10
- package/dist/components.js +3263 -84
- package/dist/components.js.map +1 -1
- package/dist/{database-CAMsquLm.d.ts → database-C3Szpi5J.d.ts} +28 -11
- package/dist/hooks.d.ts +7 -6
- package/dist/hooks.js +35 -11
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +245 -111
- package/dist/index.js +195 -185
- package/dist/index.js.map +1 -1
- package/dist/{organisation-DLNNQhPB.d.ts → organisation-CO3Sh3_D.d.ts} +1 -1
- package/dist/providers.d.ts +4 -4
- package/dist/providers.js +21 -6
- package/dist/rbac/index.d.ts +862 -806
- package/dist/rbac/index.js +953 -1032
- package/dist/rbac/index.js.map +1 -1
- package/dist/styles/core.css +422 -0
- package/dist/styles/fonts/georama-italic.woff2 +0 -0
- package/dist/styles/fonts/georama.woff2 +0 -0
- package/dist/styles/fonts/open-sans-italic.woff2 +0 -0
- package/dist/styles/fonts/open-sans.woff2 +0 -0
- package/dist/styles/fonts/reddit-mono.woff2 +0 -0
- package/dist/styles/index.d.ts +36 -0
- package/dist/styles/index.js +24 -0
- package/dist/styles/index.js.map +1 -0
- package/dist/theming/runtime.d.ts +73 -0
- package/dist/theming/runtime.js +16 -0
- package/dist/theming/runtime.js.map +1 -0
- package/dist/{types-Bavn44NW.d.ts → types-BRDU7N6w.d.ts} +79 -33
- package/dist/types.d.ts +5 -5
- package/dist/types.js +7 -2
- package/dist/types.js.map +1 -1
- package/dist/{unified-BtRpPbmp.d.ts → unified-CM7T0aTK.d.ts} +1 -2
- package/dist/usePublicRouteParams-B6i0KtXW.d.ts +477 -0
- package/dist/utils.d.ts +83 -60
- package/dist/utils.js +301 -55657
- package/dist/utils.js.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.js +1 -1
- package/docs/INDEX.md +192 -0
- package/docs/README.md +46 -32
- package/docs/api/README.md +231 -229
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +132 -0
- package/docs/api/interfaces/AggregateConfig.md +4 -4
- package/docs/api/interfaces/ButtonProps.md +2 -2
- package/docs/api/interfaces/CardProps.md +2 -2
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +98 -7
- package/docs/api/interfaces/DataTableColumn.md +131 -12
- package/docs/api/interfaces/DataTableProps.md +77 -274
- package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
- package/docs/api/interfaces/EmptyStateConfig.md +5 -5
- package/docs/api/interfaces/EventContextType.md +7 -7
- package/docs/api/interfaces/EventLogoProps.md +152 -0
- package/docs/api/interfaces/EventProviderProps.md +2 -2
- package/docs/api/interfaces/FileSizeLimits.md +7 -0
- package/docs/api/interfaces/FileUploadProps.md +154 -0
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +115 -0
- package/docs/api/interfaces/InputProps.md +2 -2
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +2 -2
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +26 -26
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +94 -0
- package/docs/api/interfaces/PublicErrorBoundaryState.md +68 -0
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +86 -0
- package/docs/api/interfaces/PublicPageFooterProps.md +112 -0
- package/docs/api/interfaces/PublicPageHeaderProps.md +138 -0
- package/docs/api/interfaces/PublicPageLayoutProps.md +138 -0
- package/docs/api/interfaces/StorageConfig.md +41 -0
- package/docs/api/interfaces/StorageFileInfo.md +74 -0
- package/docs/api/interfaces/StorageFileMetadata.md +140 -0
- package/docs/api/interfaces/StorageListOptions.md +86 -0
- package/docs/api/interfaces/StorageListResult.md +41 -0
- package/docs/api/interfaces/StorageUploadOptions.md +88 -0
- package/docs/api/interfaces/StorageUploadResult.md +63 -0
- package/docs/api/interfaces/StorageUrlOptions.md +47 -0
- package/docs/api/interfaces/StyleImport.md +2 -2
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +447 -46
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +95 -9
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +136 -0
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +123 -0
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +87 -0
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +81 -0
- package/docs/api/interfaces/UsePublicEventOptions.md +34 -0
- package/docs/api/interfaces/UsePublicEventReturn.md +68 -0
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +94 -0
- package/docs/api/interfaces/UserEventAccess.md +14 -14
- package/docs/api/interfaces/UserMenuProps.md +6 -6
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +1626 -768
- package/docs/api-reference/components.md +761 -43
- package/docs/api-reference/hooks.md +126 -0
- package/docs/api-reference/providers.md +141 -65
- package/docs/api-reference/types.md +66 -36
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -2
- package/docs/best-practices/README.md +400 -0
- package/docs/consuming-app-example.md +42 -96
- package/docs/consuming-app-vite-config.md +233 -0
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +0 -1
- package/docs/core-concepts/rbac-system.md +23 -10
- package/docs/documentation-style-checklist.md +8 -2
- package/docs/examples/navigation-menu-auth-fix.md +344 -0
- package/docs/getting-started/examples/README.md +15 -1
- package/docs/getting-started/examples/basic-auth-app.md +444 -119
- package/docs/getting-started/examples/full-featured-app.md +6 -6
- package/docs/getting-started/installation.md +231 -52
- package/docs/getting-started/quick-start.md +121 -24
- package/docs/implementation-guides/app-layout.md +133 -108
- package/docs/implementation-guides/data-tables.md +1011 -29
- package/docs/implementation-guides/forms.md +3 -3
- package/docs/implementation-guides/hierarchical-datatable.md +850 -0
- package/docs/implementation-guides/large-datasets.md +2 -2
- package/docs/implementation-guides/navigation.md +1 -1
- package/docs/implementation-guides/permission-enforcement.md +4 -4
- package/docs/implementation-guides/public-pages.md +752 -0
- package/docs/migration/README.md +18 -8
- package/docs/migration/quick-migration-guide.md +320 -0
- package/docs/migration/rbac-migration.md +50 -0
- package/docs/migration/v0.4.15-tailwind-scanning.md +272 -0
- package/docs/migration/v0.4.16-css-first-approach.md +306 -0
- package/docs/migration/v0.4.17-source-path-fix.md +229 -0
- package/docs/migration-guide.md +51 -104
- package/docs/performance/README.md +1 -4
- package/docs/print-components/README.md +258 -0
- package/docs/print-components/api-reference.md +636 -0
- package/docs/print-components/examples/README.md +204 -0
- package/docs/print-components/examples/basic-report.tsx +92 -0
- package/docs/print-components/examples/card-catalog.tsx +149 -0
- package/docs/print-components/examples/cover-page-report.tsx +163 -0
- package/docs/print-components/quick-start.md +363 -0
- package/docs/quick-reference.md +53 -36
- package/docs/rbac/README.md +136 -69
- package/docs/rbac/api-reference.md +39 -8
- package/docs/rbac/examples.md +237 -66
- package/docs/rbac/getting-started.md +131 -16
- package/docs/rbac/quick-start.md +499 -323
- package/docs/rbac/troubleshooting.md +240 -262
- package/docs/security/README.md +50 -1
- package/docs/styles/README.md +143 -117
- package/docs/testing/README.md +6 -10
- package/docs/troubleshooting/README.md +497 -0
- package/docs/troubleshooting/common-issues.md +604 -14
- package/docs/troubleshooting/styling-issues.md +219 -0
- package/docs/troubleshooting/tailwind-content-scanning.md +213 -0
- package/docs/usage.md +28 -90
- package/docs/visual-testing.md +0 -7
- package/package.json +46 -24
- package/src/__mocks__/lucide-react.ts +181 -0
- package/src/__tests__/REBUILD_PLAN.md +223 -0
- package/src/__tests__/TESTING_GUIDELINES.md +341 -0
- package/src/__tests__/fixtures/mocks.ts +93 -0
- package/src/__tests__/helpers/component-test-utils.tsx +145 -0
- package/src/__tests__/helpers/test-utils.tsx +117 -0
- package/src/__tests__/integration/UserProfile.test.tsx +128 -0
- package/src/__tests__/setup.ts +71 -0
- package/src/__tests__/templates/accessibility.test.template.tsx +279 -0
- package/src/__tests__/templates/component.test.template.tsx +144 -0
- package/src/__tests__/templates/hook.test.template.ts +173 -0
- package/src/__tests__/templates/integration.test.template.tsx +199 -0
- package/src/__tests__/types/test.types.ts +106 -0
- package/src/components/Alert/Alert.test.tsx +496 -0
- package/src/components/Alert/Alert.tsx +134 -0
- package/src/components/Alert/index.ts +2 -0
- package/src/components/Avatar/Avatar.test.tsx +484 -0
- package/src/components/Avatar/Avatar.tsx +84 -0
- package/src/components/Avatar/index.ts +2 -0
- package/src/components/Button/Button.test.tsx +662 -0
- package/src/components/Button/Button.tsx +270 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/Card/Card.test.tsx +593 -0
- package/src/components/Card/Card.tsx +271 -0
- package/src/components/Card/index.ts +1 -0
- package/src/components/Checkbox/Checkbox.test.tsx +461 -0
- package/src/components/Checkbox/Checkbox.tsx +75 -0
- package/src/components/Checkbox/__mocks__/Checkbox.tsx +2 -0
- package/src/components/Checkbox/index.ts +2 -0
- package/src/components/DataTable/DataTable.tsx +446 -0
- package/src/components/DataTable/__tests__/README.md +145 -0
- package/src/components/DataTable/__tests__/mocks/MockRBACProvider.tsx +66 -0
- package/src/components/DataTable/__tests__/test-utils/dataFactories.ts +103 -0
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +381 -0
- package/src/components/DataTable/__tests__/test-utils.ts +94 -0
- package/src/components/DataTable/components/AccessDeniedPage.tsx +168 -0
- package/src/components/DataTable/components/ActionButtons.tsx +194 -0
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +160 -0
- package/src/components/DataTable/components/ColumnFilter.tsx +114 -0
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +100 -0
- package/src/components/DataTable/components/DataTableBody.tsx +461 -0
- package/src/components/DataTable/components/DataTableCore.tsx +1027 -0
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +214 -0
- package/src/components/DataTable/components/DataTableModals.tsx +87 -0
- package/src/components/DataTable/components/DataTableToolbar.tsx +262 -0
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +144 -0
- package/src/components/DataTable/components/EditableRow.tsx +159 -0
- package/src/components/DataTable/components/EmptyState.tsx +64 -0
- package/src/components/DataTable/components/ExpandButton.tsx +113 -0
- package/src/components/DataTable/components/FilterRow.tsx +100 -0
- package/src/components/DataTable/components/GroupHeader.tsx +42 -0
- package/src/components/DataTable/components/GroupingDropdown.tsx +96 -0
- package/src/components/DataTable/components/ImportModal.tsx +345 -0
- package/src/components/DataTable/components/LoadingState.tsx +12 -0
- package/src/components/DataTable/components/PaginationControls.tsx +332 -0
- package/src/components/DataTable/components/UnifiedTableBody.tsx +742 -0
- package/src/components/DataTable/components/ViewRowModal.tsx +68 -0
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +513 -0
- package/src/components/DataTable/components/index.ts +16 -0
- package/src/components/DataTable/context/DataTableContext.tsx +97 -0
- package/src/components/DataTable/core/ActionManager.ts +235 -0
- package/src/components/DataTable/core/ColumnFactory.ts +268 -0
- package/src/components/DataTable/core/ColumnManager.ts +205 -0
- package/src/components/DataTable/core/DataManager.ts +188 -0
- package/src/components/DataTable/core/DataTableContext.tsx +181 -0
- package/src/components/DataTable/core/LocalDataAdapter.ts +264 -0
- package/src/components/DataTable/core/PluginRegistry.ts +229 -0
- package/src/components/DataTable/core/StateManager.ts +311 -0
- package/src/components/DataTable/core/index.ts +8 -0
- package/src/components/DataTable/core/interfaces.ts +338 -0
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +419 -0
- package/src/components/DataTable/examples/HierarchicalExample.tsx +475 -0
- package/src/components/DataTable/examples/InitialPageSizeExample.tsx +176 -0
- package/src/components/DataTable/examples/PerformanceExample.tsx +505 -0
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +95 -0
- package/src/components/DataTable/hooks/useColumnReordering.ts +110 -0
- package/src/components/DataTable/hooks/useDataTableState.ts +325 -0
- package/src/components/DataTable/hooks/useHierarchicalState.ts +174 -0
- package/src/components/DataTable/index.ts +68 -0
- package/src/components/DataTable/styles.ts +171 -0
- package/src/components/DataTable/types.ts +511 -0
- package/src/components/DataTable/utils/debugTools.ts +583 -0
- package/src/components/DataTable/utils/errorHandling.ts +494 -0
- package/src/components/DataTable/utils/exportUtils.ts +126 -0
- package/src/components/DataTable/utils/flexibleImport.ts +510 -0
- package/src/components/DataTable/utils/hierarchicalSorting.ts +151 -0
- package/src/components/DataTable/utils/hierarchicalUtils.ts +218 -0
- package/src/components/DataTable/utils/index.ts +1 -0
- package/src/components/DataTable/utils/performanceUtils.ts +351 -0
- package/src/components/Dialog/Dialog.test.tsx +1139 -0
- package/src/components/Dialog/Dialog.tsx +782 -0
- package/src/components/Dialog/README.md +804 -0
- package/src/components/Dialog/examples/BasicHtmlTest.tsx +55 -0
- package/src/components/Dialog/examples/DebugHtmlExample.tsx +68 -0
- package/src/components/Dialog/examples/HtmlDialogExample.tsx +202 -0
- package/src/components/Dialog/examples/SimpleHtmlTest.tsx +61 -0
- package/src/components/Dialog/examples/SmartDialogExample.tsx +322 -0
- package/src/components/Dialog/index.ts +12 -0
- package/src/components/Dialog/utils/safeHtml.ts +185 -0
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +752 -0
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +312 -0
- package/src/components/ErrorBoundary/index.ts +8 -0
- package/src/components/EventSelector/EventSelector.tsx +360 -0
- package/src/components/EventSelector/index.ts +3 -0
- package/src/components/EventSelector/types.ts +79 -0
- package/src/components/FileUpload/FileUpload.example.tsx +218 -0
- package/src/components/FileUpload/FileUpload.test.tsx +665 -0
- package/src/components/FileUpload/FileUpload.tsx +237 -0
- package/src/components/FileUpload/index.ts +6 -0
- package/src/components/Footer/Footer.tsx +197 -0
- package/src/components/Footer/index.ts +17 -0
- package/src/components/Form/Form.tsx +166 -0
- package/src/components/Form/FormErrorSummary.tsx +113 -0
- package/src/components/Form/FormField.tsx +249 -0
- package/src/components/Form/FormFieldset.tsx +127 -0
- package/src/components/Form/FormLiveRegion.tsx +198 -0
- package/src/components/Form/index.ts +26 -0
- package/src/components/Header/Header.tsx +301 -0
- package/src/components/Header/index.ts +4 -0
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +164 -0
- package/src/components/InactivityWarningModal/index.ts +9 -0
- package/src/components/Input/Input.tsx +201 -0
- package/src/components/Input/__mocks__/Input.tsx +2 -0
- package/src/components/Input/index.ts +9 -0
- package/src/components/Label/Label.tsx +186 -0
- package/src/components/Label/index.ts +2 -0
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +98 -0
- package/src/components/LoadingSpinner/index.ts +3 -0
- package/src/components/LoginForm/LoginForm.tsx +273 -0
- package/src/components/LoginForm/index.ts +3 -0
- package/src/components/NavigationMenu/NavigationMenu.tsx +698 -0
- package/src/components/NavigationMenu/index.ts +10 -0
- package/src/components/NavigationMenu/types.ts +85 -0
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +304 -0
- package/src/components/OrganisationSelector/index.ts +9 -0
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +699 -0
- package/src/components/PaceAppLayout/README.md +278 -0
- package/src/components/PaceAppLayout/index.ts +1 -0
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +221 -0
- package/src/components/PaceLoginPage/index.ts +1 -0
- package/src/components/PasswordReset/PasswordChangeForm.tsx +186 -0
- package/src/components/PasswordReset/PasswordResetForm.tsx +201 -0
- package/src/components/PasswordReset/index.ts +4 -0
- package/src/components/PrintButton/PrintButton.tsx +321 -0
- package/src/components/PrintButton/PrintButtonGroup.tsx +84 -0
- package/src/components/PrintButton/PrintToolbar.tsx +94 -0
- package/src/components/PrintButton/examples/PrintButtonShowcase.tsx +438 -0
- package/src/components/PrintButton/index.ts +33 -0
- package/src/components/PrintButton/types.ts +173 -0
- package/src/components/PrintCard/PrintCard.tsx +154 -0
- package/src/components/PrintCard/PrintCardContent.tsx +57 -0
- package/src/components/PrintCard/PrintCardFooter.tsx +60 -0
- package/src/components/PrintCard/PrintCardGrid.tsx +91 -0
- package/src/components/PrintCard/PrintCardHeader.tsx +78 -0
- package/src/components/PrintCard/PrintCardImage.tsx +81 -0
- package/src/components/PrintCard/examples/PrintCardShowcase.tsx +239 -0
- package/src/components/PrintCard/index.ts +34 -0
- package/src/components/PrintCard/types.ts +171 -0
- package/src/components/PrintDataTable/PrintDataTable.tsx +215 -0
- package/src/components/PrintDataTable/PrintTableGroup.tsx +90 -0
- package/src/components/PrintDataTable/PrintTableRow.tsx +76 -0
- package/src/components/PrintDataTable/index.ts +25 -0
- package/src/components/PrintDataTable/types.ts +67 -0
- package/src/components/PrintFooter/PrintFooter.tsx +183 -0
- package/src/components/PrintFooter/PrintFooterContent.tsx +71 -0
- package/src/components/PrintFooter/PrintFooterInfo.tsx +86 -0
- package/src/components/PrintFooter/PrintPageNumber.tsx +90 -0
- package/src/components/PrintFooter/examples/PrintFooterShowcase.tsx +390 -0
- package/src/components/PrintFooter/index.ts +30 -0
- package/src/components/PrintFooter/types.ts +149 -0
- package/src/components/PrintGrid/PrintGrid.tsx +180 -0
- package/src/components/PrintGrid/PrintGridBreakpoint.tsx +109 -0
- package/src/components/PrintGrid/PrintGridContainer.tsx +128 -0
- package/src/components/PrintGrid/PrintGridItem.tsx +220 -0
- package/src/components/PrintGrid/examples/PrintGridShowcase.tsx +359 -0
- package/src/components/PrintGrid/index.ts +31 -0
- package/src/components/PrintGrid/types.ts +159 -0
- package/src/components/PrintHeader/PrintCoverHeader.tsx +230 -0
- package/src/components/PrintHeader/PrintHeader.tsx +150 -0
- package/src/components/PrintHeader/index.ts +17 -0
- package/src/components/PrintHeader/types.ts +42 -0
- package/src/components/PrintLayout/PrintLayout.tsx +122 -0
- package/src/components/PrintLayout/PrintLayoutContext.tsx +66 -0
- package/src/components/PrintLayout/PrintPageBreak.tsx +52 -0
- package/src/components/PrintLayout/examples/PrintShowcase.tsx +230 -0
- package/src/components/PrintLayout/index.ts +19 -0
- package/src/components/PrintLayout/types.ts +37 -0
- package/src/components/PrintPageBreak/PrintPageBreak.tsx +120 -0
- package/src/components/PrintPageBreak/PrintPageBreakGroup.tsx +90 -0
- package/src/components/PrintPageBreak/PrintPageBreakIndicator.tsx +112 -0
- package/src/components/PrintPageBreak/examples/PrintPageBreakShowcase.tsx +279 -0
- package/src/components/PrintPageBreak/index.ts +23 -0
- package/src/components/PrintPageBreak/types.ts +94 -0
- package/src/components/PrintSection/PrintColumn.tsx +104 -0
- package/src/components/PrintSection/PrintDivider.tsx +101 -0
- package/src/components/PrintSection/PrintSection.tsx +129 -0
- package/src/components/PrintSection/PrintSectionContent.tsx +75 -0
- package/src/components/PrintSection/PrintSectionHeader.tsx +97 -0
- package/src/components/PrintSection/examples/PrintSectionShowcase.tsx +258 -0
- package/src/components/PrintSection/index.ts +33 -0
- package/src/components/PrintSection/types.ts +155 -0
- package/src/components/PrintText/PrintText.tsx +116 -0
- package/src/components/PrintText/index.ts +16 -0
- package/src/components/PrintText/types.ts +24 -0
- package/src/components/Progress/Progress.tsx +116 -0
- package/src/components/Progress/index.ts +3 -0
- package/src/components/PublicLayout/EventLogo.tsx +287 -0
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +279 -0
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +208 -0
- package/src/components/PublicLayout/PublicPageContextChecker.tsx +130 -0
- package/src/components/PublicLayout/PublicPageDebugger.tsx +104 -0
- package/src/components/PublicLayout/PublicPageDiagnostic.tsx +162 -0
- package/src/components/PublicLayout/PublicPageFooter.tsx +124 -0
- package/src/components/PublicLayout/PublicPageHeader.tsx +178 -0
- package/src/components/PublicLayout/PublicPageLayout.tsx +232 -0
- package/src/components/PublicLayout/PublicPageProvider.tsx +137 -0
- package/src/components/PublicLayout/index.ts +51 -0
- package/src/components/RBAC/PagePermissionGuard.tsx +287 -0
- package/src/components/RBAC/RBACGuard.tsx +143 -0
- package/src/components/RBAC/RBACProvider.tsx +186 -0
- package/src/components/RBAC/RoleBasedContent.tsx +129 -0
- package/src/components/RBAC/index.ts +23 -0
- package/src/components/Select/Select.tsx +660 -0
- package/src/components/Select/index.ts +1 -0
- package/src/components/SuperAdminGuard.tsx +116 -0
- package/src/components/Table/Table.tsx +222 -0
- package/src/components/Table/index.ts +11 -0
- package/src/components/Toast/Toast.tsx +339 -0
- package/src/components/Toast/index.ts +14 -0
- package/src/components/Tooltip/Tooltip.tsx +167 -0
- package/src/components/Tooltip/index.ts +7 -0
- package/src/components/UserMenu/UserMenu.tsx +243 -0
- package/src/components/UserMenu/index.ts +3 -0
- package/src/components/examples/PermissionExample.tsx +150 -0
- package/src/components/index.ts +434 -0
- package/src/components.ts +19 -0
- package/src/constants/performance.ts +14 -0
- package/src/examples/CorrectPublicPageImplementation.tsx +301 -0
- package/src/examples/PublicEventPage.tsx +274 -0
- package/src/examples/PublicPageApp.tsx +308 -0
- package/src/examples/PublicPageUsageExample.tsx +216 -0
- package/src/hooks/index.ts +56 -0
- package/src/hooks/public/index.ts +34 -0
- package/src/hooks/public/usePublicEvent.ts +261 -0
- package/src/hooks/public/usePublicEventLogo.ts +285 -0
- package/src/hooks/public/usePublicRouteParams.ts +259 -0
- package/src/hooks/useAppConfig.ts +94 -0
- package/src/hooks/useComponentPerformance.ts +39 -0
- package/src/hooks/useCounter.test.ts +135 -0
- package/src/hooks/useDataTablePerformance.ts +387 -0
- package/src/hooks/useDataTableState.ts +110 -0
- package/src/hooks/useDebounce.ts +18 -0
- package/src/hooks/useFocusManagement.ts +161 -0
- package/src/hooks/useFocusTrap.ts +155 -0
- package/src/hooks/useInactivityTracker.ts +372 -0
- package/src/hooks/useIsMobile.ts +42 -0
- package/src/hooks/useKeyboardShortcuts.ts +237 -0
- package/src/hooks/useOrganisationPermissions.ts +208 -0
- package/src/hooks/useOrganisationSecurity.ts +262 -0
- package/src/hooks/usePerformanceMonitor.ts +128 -0
- package/src/hooks/usePermissionCache.ts +455 -0
- package/src/hooks/useRBAC.ts +262 -0
- package/src/hooks/useSecureDataAccess.ts +586 -0
- package/src/hooks/useStorage.ts +274 -0
- package/src/hooks/useToast.ts +242 -0
- package/src/hooks/useZodForm.ts +28 -0
- package/src/index.ts +200 -0
- package/src/providers/AuthProvider.tsx +369 -0
- package/src/providers/EventProvider.tsx +324 -0
- package/src/providers/InactivityProvider.tsx +238 -0
- package/src/providers/OrganisationProvider.tsx +588 -0
- package/src/providers/RBACProvider.tsx +634 -0
- package/src/providers/UnifiedAuthProvider.tsx +327 -0
- package/src/providers/index.ts +15 -0
- package/src/rbac/README.md +885 -0
- package/src/rbac/adapters.tsx +726 -0
- package/src/rbac/api.ts +339 -0
- package/src/rbac/audit-enhanced.ts +339 -0
- package/src/rbac/audit.ts +338 -0
- package/src/rbac/cache.ts +215 -0
- package/src/rbac/components/EnhancedNavigationMenu.tsx +294 -0
- package/src/rbac/components/NavigationGuard.tsx +294 -0
- package/src/rbac/components/NavigationProvider.tsx +314 -0
- package/src/rbac/components/PagePermissionGuard.tsx +430 -0
- package/src/rbac/components/PagePermissionProvider.tsx +274 -0
- package/src/rbac/components/PermissionEnforcer.tsx +307 -0
- package/src/rbac/components/RoleBasedRouter.tsx +425 -0
- package/src/rbac/components/SecureDataProvider.tsx +319 -0
- package/src/rbac/components/index.ts +64 -0
- package/src/rbac/config.ts +133 -0
- package/src/rbac/docs/event-based-apps.md +285 -0
- package/src/rbac/engine.ts +1026 -0
- package/src/rbac/eslint-rules.js +285 -0
- package/src/rbac/examples/CompleteRBACExample.tsx +323 -0
- package/src/rbac/examples/EventBasedApp.tsx +238 -0
- package/src/rbac/hooks.ts +570 -0
- package/src/rbac/index.ts +114 -0
- package/src/rbac/permissions.ts +293 -0
- package/src/rbac/secureClient.ts +244 -0
- package/src/rbac/security.ts +346 -0
- package/src/rbac/testing/index.tsx +340 -0
- package/src/rbac/types.ts +343 -0
- package/src/rbac/utils/eventContext.ts +83 -0
- package/src/styles/core.css +422 -0
- package/src/styles/index.ts +51 -0
- package/src/theming/runtime.ts +187 -0
- package/src/types/database.ts +472 -0
- package/src/types/guards.ts +30 -0
- package/src/types/index.ts +25 -0
- package/src/types/organisation.ts +184 -0
- package/src/types/security.ts +70 -0
- package/src/types/supabase.ts +166 -0
- package/src/types/theme.ts +6 -0
- package/src/types/unified.ts +262 -0
- package/src/types/validation.ts +164 -0
- package/src/types/vitest-globals.d.ts +43 -0
- package/src/utils/__mocks__/supabaseMock.ts +75 -0
- package/src/utils/__mocks__/supabaseMock.tsx +198 -0
- package/src/utils/appConfig.ts +47 -0
- package/src/utils/appIdResolver.ts +130 -0
- package/src/utils/appNameResolver.ts +190 -0
- package/src/utils/audit.ts +127 -0
- package/src/utils/auth-utils.ts +96 -0
- package/src/utils/bundleAnalysis.ts +129 -0
- package/src/utils/cn.ts +7 -0
- package/src/utils/debugLogger.ts +46 -0
- package/src/utils/deviceFingerprint.ts +215 -0
- package/src/utils/dynamicUtils.ts +105 -0
- package/src/utils/formatting.ts +77 -0
- package/src/utils/index.ts +145 -0
- package/src/utils/lazyLoad.tsx +44 -0
- package/src/utils/organisationContext.ts +135 -0
- package/src/utils/performanceBenchmark.ts +64 -0
- package/src/utils/performanceBudgets.ts +111 -0
- package/src/utils/permissionTypes.ts +37 -0
- package/src/utils/permissionUtils.ts +31 -0
- package/src/utils/print/PrintDataProcessor.ts +390 -0
- package/src/utils/print/examples/PrintUtilitiesShowcase.tsx +397 -0
- package/src/utils/print/index.ts +29 -0
- package/src/utils/print/types.ts +196 -0
- package/src/utils/print/usePrintOptimization.ts +272 -0
- package/src/utils/sanitization.ts +264 -0
- package/src/utils/schemaUtils.ts +37 -0
- package/src/utils/secureDataAccess.ts +361 -0
- package/src/utils/secureErrors.ts +79 -0
- package/src/utils/secureStorage.ts +244 -0
- package/src/utils/security.ts +156 -0
- package/src/utils/securityMonitor.ts +45 -0
- package/src/utils/sessionTracking.ts +170 -0
- package/src/utils/storage/README.md +348 -0
- package/src/utils/storage/config.ts +100 -0
- package/src/utils/storage/helpers.ts +359 -0
- package/src/utils/storage/index.ts +36 -0
- package/src/utils/storage/types.ts +90 -0
- package/src/utils/validation.ts +111 -0
- package/src/utils/validationUtils.ts +120 -0
- package/src/validation/common.ts +53 -0
- package/src/validation/csrf.ts +214 -0
- package/src/validation/index.ts +43 -0
- package/src/validation/passwordSchema.ts +125 -0
- package/src/validation/sanitization.ts +96 -0
- package/src/validation/schemaUtils.ts +42 -0
- package/src/validation/sqlInjectionProtection.ts +242 -0
- package/src/validation/user.ts +34 -0
- package/dist/UnifiedAuthProvider-V7y63NjT.d.ts +0 -88
- package/dist/chunk-4MCJAK7J.js.map +0 -1
- package/dist/chunk-4ZTIEYU2.js.map +0 -1
- package/dist/chunk-H4PZ4B3Y.js.map +0 -1
- package/dist/chunk-IOX76PSM.js.map +0 -1
- package/dist/chunk-JUUNUW3O.js.map +0 -1
- package/dist/chunk-U7DY5T33.js +0 -11
- package/dist/chunk-U7DY5T33.js.map +0 -1
- package/dist/chunk-WHLSWC6W.js.map +0 -1
- package/dist/chunk-XI7QFSSC.js +0 -790
- package/dist/chunk-XI7QFSSC.js.map +0 -1
- package/dist/chunk-XIJMMBDD.js +0 -73
- package/dist/chunk-XIJMMBDD.js.map +0 -1
- package/dist/chunk-YNU5QJ4S.js.map +0 -1
- package/dist/chunk-YWYCNGWH.js +0 -2070
- package/dist/chunk-YWYCNGWH.js.map +0 -1
- package/dist/chunk-ZJ3UKPIW.js +0 -952
- package/dist/chunk-ZJ3UKPIW.js.map +0 -1
- package/dist/useAppConfig-CZNJJsT_.d.ts +0 -148
- package/dist/{DataTable-2LB6HI6V.js.map → DataTable-GX3XERFJ.js.map} +0 -0
- package/dist/{api-AIJ3IJX3.js.map → api-ETQ6YJ3C.js.map} +0 -0
- package/dist/{audit-PD5L5ZSC.js.map → appNameResolver-7GHF5ED2.js.map} +0 -0
- package/dist/{chunk-DC5AMYBS.js.map → audit-BUW3LMJB.js.map} +0 -0
- package/dist/{validation-D2-NNCCE.d.ts → validation-PM_iOaTI.d.ts} +6 -6
|
@@ -8,9 +8,11 @@ The PACE Core DataTable is an enterprise-grade data table component built on Tan
|
|
|
8
8
|
|
|
9
9
|
- **🚀 Performance Optimized** - Virtual scrolling, intelligent chunking, and automatic mode detection
|
|
10
10
|
- **📊 Data Management** - Sorting, filtering, pagination, search, export/import
|
|
11
|
+
- **🌳 Hierarchical Rows** - Parent/child row relationships with expand/collapse all and smart sorting ([Detailed Guide](./hierarchical-datatable.md))
|
|
11
12
|
- **✏️ Inline Editing** - Row editing, creation, and deletion
|
|
12
13
|
- **🎯 Actions** - Custom row actions and toolbar buttons
|
|
13
14
|
- **📈 Grouping** - Data grouping with aggregation functions
|
|
15
|
+
- **📏 Auto Column Sizing** - Automatic column width adjustment based on content
|
|
14
16
|
- **🎨 Customizable** - Column visibility, responsive design, accessibility
|
|
15
17
|
- **🔧 TypeScript** - Full TypeScript support with strict typing
|
|
16
18
|
|
|
@@ -55,8 +57,8 @@ const columns: DataTableColumn<User>[] = [
|
|
|
55
57
|
cell: ({ row }) => (
|
|
56
58
|
<span className={`px-2 py-1 rounded text-xs ${
|
|
57
59
|
row.original.status === 'active'
|
|
58
|
-
? 'bg-
|
|
59
|
-
: 'bg-
|
|
60
|
+
? 'bg-main-100 text-main-800'
|
|
61
|
+
: 'bg-acc-100 text-acc-800'
|
|
60
62
|
}`}>
|
|
61
63
|
{row.original.status}
|
|
62
64
|
</span>
|
|
@@ -82,6 +84,7 @@ function UserTable() {
|
|
|
82
84
|
sorting: true,
|
|
83
85
|
filtering: true,
|
|
84
86
|
}}
|
|
87
|
+
columnOrder={['name', 'email', 'role', 'status']} // Control column order
|
|
85
88
|
// Performance and other settings can be configured via performance prop
|
|
86
89
|
/>
|
|
87
90
|
);
|
|
@@ -141,19 +144,22 @@ The DataTable component has a comprehensive prop interface. Here are the key pro
|
|
|
141
144
|
- `description?: string` - Table description
|
|
142
145
|
- `variant?: 'default' | 'compact' | 'spacious'` - Visual variant
|
|
143
146
|
- `className?: string` - Additional CSS classes
|
|
147
|
+
- `columnOrder?: string[]` - **Column ordering** - Array of column IDs in desired order
|
|
144
148
|
|
|
145
149
|
### Event Handlers
|
|
146
150
|
- `onEditRow?: (row: TData, data: Partial<TData>) => void` - Row edit handler
|
|
147
|
-
- `onDeleteRow?: (row: TData) => void` - Row deletion handler
|
|
151
|
+
- `onDeleteRow?: (row: TData) => void` - Row deletion handler (also used as fallback for bulk delete)
|
|
148
152
|
- `onCreateRow?: (data: Partial<TData>) => void` - Row creation handler
|
|
149
153
|
- `onImport?: (data: TData[]) => void | Promise<void>` - Import handler
|
|
150
|
-
- `
|
|
154
|
+
- `onRowSelectionChange?: (selection: Record<string, boolean>) => void` - Row selection change handler
|
|
155
|
+
- `onDeleteSelected?: (selectedRows: Record<string, boolean>) => void` - **Bulk delete handler** - Called when delete selected button is clicked
|
|
151
156
|
|
|
152
157
|
### Performance Props
|
|
153
158
|
- `performance?: PerformanceConfig` - Performance optimization settings
|
|
154
159
|
- `serverSide?: ServerSideConfig<TData>` - Server-side data fetching
|
|
155
160
|
- `virtualHeight?: number` - Virtual scrolling height (default: 600)
|
|
156
161
|
- `showPerformanceMetrics?: boolean` - Show performance metrics
|
|
162
|
+
- `initialPageSize?: number` - Initial page size for pagination (default: 10)
|
|
157
163
|
|
|
158
164
|
### Feature-Specific Configuration
|
|
159
165
|
- `bulkOperationsConfig?: BulkOperationsConfig` - Bulk operations config
|
|
@@ -165,6 +171,30 @@ The DataTable component has a comprehensive prop interface. Here are the key pro
|
|
|
165
171
|
|
|
166
172
|
The DataTable component uses a unified `features` prop to control all table functionality. This provides a consistent and intuitive way to enable or disable features.
|
|
167
173
|
|
|
174
|
+
### DataTableFeatureConfig Properties
|
|
175
|
+
|
|
176
|
+
| Property | Type | Default | Description |
|
|
177
|
+
|----------|------|---------|-------------|
|
|
178
|
+
| **Core Features** |
|
|
179
|
+
| `search` | `boolean` | `false` | Enable global search functionality |
|
|
180
|
+
| `pagination` | `boolean` | `false` | Enable pagination controls |
|
|
181
|
+
| `sorting` | `boolean` | `false` | Enable column sorting |
|
|
182
|
+
| `filtering` | `boolean` | `false` | Enable column filtering |
|
|
183
|
+
| **Data Management** |
|
|
184
|
+
| `import` | `boolean` | `false` | Enable data import functionality |
|
|
185
|
+
| `export` | `boolean` | `false` | Enable data export functionality |
|
|
186
|
+
| **Row Operations** |
|
|
187
|
+
| `selection` | `boolean` | `false` | Enable row selection for bulk operations |
|
|
188
|
+
| `creation` | `boolean` | `false` | Enable row creation |
|
|
189
|
+
| `editing` | `boolean` | `false` | Enable row editing |
|
|
190
|
+
| `deletion` | `boolean` | `false` | Enable row deletion |
|
|
191
|
+
| `deleteSelected` | `boolean` | `false` | Enable bulk deletion of selected rows |
|
|
192
|
+
| **Table Customization** |
|
|
193
|
+
| `grouping` | `boolean` | `false` | Enable data grouping |
|
|
194
|
+
| `columnVisibility` | `boolean` | `false` | Enable column visibility controls |
|
|
195
|
+
| `columnReordering` | `boolean` | `false` | Enable column reordering |
|
|
196
|
+
| `autoColumnSizing` | `boolean` | `false` | Enable automatic column width adjustment based on content |
|
|
197
|
+
|
|
168
198
|
### Basic Feature Configuration
|
|
169
199
|
|
|
170
200
|
```tsx
|
|
@@ -183,25 +213,17 @@ The DataTable component uses a unified `features` prop to control all table func
|
|
|
183
213
|
export: true,
|
|
184
214
|
|
|
185
215
|
// Row Operations
|
|
186
|
-
selection: true,
|
|
216
|
+
selection: true, // Required for row selection
|
|
187
217
|
creation: true,
|
|
188
218
|
editing: true,
|
|
189
|
-
deletion: true,
|
|
190
|
-
deleteSelected: true,
|
|
219
|
+
deletion: true, // Required for delete functionality
|
|
220
|
+
deleteSelected: true, // Required for delete selected button
|
|
191
221
|
|
|
192
222
|
// Table Customization
|
|
193
223
|
grouping: true,
|
|
194
224
|
columnVisibility: true,
|
|
195
225
|
columnReordering: true,
|
|
196
|
-
|
|
197
|
-
// Performance
|
|
198
|
-
virtualization: true,
|
|
199
|
-
performanceMetrics: true,
|
|
200
|
-
|
|
201
|
-
// Advanced Features
|
|
202
|
-
inlineEditing: true,
|
|
203
|
-
bulkOperations: true,
|
|
204
|
-
rowActions: true,
|
|
226
|
+
autoColumnSizing: true, // Enable automatic column width adjustment
|
|
205
227
|
}}
|
|
206
228
|
/>
|
|
207
229
|
```
|
|
@@ -239,17 +261,93 @@ For a full-featured data management table:
|
|
|
239
261
|
creation: true,
|
|
240
262
|
editing: true,
|
|
241
263
|
deletion: true,
|
|
264
|
+
deleteSelected: true, // Enable delete selected functionality
|
|
242
265
|
export: true,
|
|
243
266
|
import: true,
|
|
244
267
|
grouping: true,
|
|
245
268
|
columnVisibility: true,
|
|
246
269
|
bulkOperations: true,
|
|
247
270
|
}}
|
|
271
|
+
columnOrder={['select', 'name', 'email', 'role', 'status', 'actions']} // Custom column order
|
|
248
272
|
onEditRow={handleEdit}
|
|
249
273
|
onDeleteRow={handleDelete}
|
|
250
274
|
onCreateRow={handleCreate}
|
|
251
275
|
onImport={handleImport}
|
|
276
|
+
onRowSelectionChange={handleSelectionChange}
|
|
252
277
|
onDeleteSelected={handleBulkDelete}
|
|
278
|
+
getRowId={(row) => row.id} // Important: Required for selection and delete operations
|
|
279
|
+
/>
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Auto Column Sizing
|
|
283
|
+
|
|
284
|
+
The DataTable component includes automatic column width adjustment based on content, which helps optimize space usage and improve readability.
|
|
285
|
+
|
|
286
|
+
### How Auto-Sizing Works
|
|
287
|
+
|
|
288
|
+
When `autoColumnSizing: true` is enabled:
|
|
289
|
+
|
|
290
|
+
1. **Content Analysis**: Analyzes both header text and data content to determine optimal widths
|
|
291
|
+
2. **Smart Calculation**: Uses character count estimation (8px per character + padding)
|
|
292
|
+
3. **Constraints**: Respects min-width (80px) and max-width (400px) limits
|
|
293
|
+
4. **Performance**: Only samples first 100 rows for large datasets
|
|
294
|
+
5. **Table Layout**: Switches from `tableLayout: 'fixed'` to `tableLayout: 'auto'`
|
|
295
|
+
|
|
296
|
+
### Benefits
|
|
297
|
+
|
|
298
|
+
- **Better Space Utilization**: Columns automatically adjust to content width
|
|
299
|
+
- **Improved Readability**: Long text gets more space, short text takes less space
|
|
300
|
+
- **No Text Wrapping**: Prevents unnecessary text wrapping in narrow columns
|
|
301
|
+
- **Consistent Layout**: Maintains proper spacing and alignment
|
|
302
|
+
|
|
303
|
+
### Enabling Auto-Sizing
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
<DataTable
|
|
307
|
+
data={data}
|
|
308
|
+
columns={columns}
|
|
309
|
+
features={{
|
|
310
|
+
search: true,
|
|
311
|
+
pagination: true,
|
|
312
|
+
sorting: true,
|
|
313
|
+
autoColumnSizing: true, // Enable automatic column width adjustment
|
|
314
|
+
}}
|
|
315
|
+
/>
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Auto-Sizing vs Fixed Widths
|
|
319
|
+
|
|
320
|
+
**With Auto-Sizing (Recommended):**
|
|
321
|
+
- Columns automatically adjust to content width
|
|
322
|
+
- Long text gets more space, short text takes less space
|
|
323
|
+
- Better space utilization
|
|
324
|
+
- Improved readability
|
|
325
|
+
|
|
326
|
+
**Without Auto-Sizing:**
|
|
327
|
+
- All columns have equal width
|
|
328
|
+
- Long text may wrap unnecessarily
|
|
329
|
+
- Short columns have wasted space
|
|
330
|
+
- Consistent but potentially inefficient layout
|
|
331
|
+
|
|
332
|
+
### Example: Content-Based Sizing
|
|
333
|
+
|
|
334
|
+
```tsx
|
|
335
|
+
const data = [
|
|
336
|
+
{ id: '1', name: 'John', description: 'A short description' },
|
|
337
|
+
{ id: '2', name: 'Jane', description: 'A very long description that should make this column wider' },
|
|
338
|
+
{ id: '3', name: 'Bob', description: 'Medium length description' }
|
|
339
|
+
];
|
|
340
|
+
|
|
341
|
+
const columns = [
|
|
342
|
+
{ accessorKey: 'name', header: 'Name' },
|
|
343
|
+
{ accessorKey: 'description', header: 'Description' }
|
|
344
|
+
];
|
|
345
|
+
|
|
346
|
+
// With auto-sizing: Description column will be wider than Name column
|
|
347
|
+
<DataTable
|
|
348
|
+
data={data}
|
|
349
|
+
columns={columns}
|
|
350
|
+
features={{ autoColumnSizing: true }}
|
|
253
351
|
/>
|
|
254
352
|
```
|
|
255
353
|
|
|
@@ -361,6 +459,275 @@ const columns: DataTableColumn<User>[] = [
|
|
|
361
459
|
];
|
|
362
460
|
```
|
|
363
461
|
|
|
462
|
+
## Column Ordering
|
|
463
|
+
|
|
464
|
+
The DataTable component supports custom column ordering through the `columnOrder` prop, allowing you to control the exact position of columns including selection and actions columns.
|
|
465
|
+
|
|
466
|
+
### Basic Column Ordering
|
|
467
|
+
|
|
468
|
+
```tsx
|
|
469
|
+
<DataTable
|
|
470
|
+
data={data}
|
|
471
|
+
columns={columns}
|
|
472
|
+
features={{
|
|
473
|
+
selection: true,
|
|
474
|
+
sorting: true,
|
|
475
|
+
filtering: true,
|
|
476
|
+
}}
|
|
477
|
+
columnOrder={['select', 'name', 'email', 'role', 'status']}
|
|
478
|
+
/>
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Column Order Behavior
|
|
482
|
+
|
|
483
|
+
#### When `columnOrder` is provided:
|
|
484
|
+
- **Exact positioning**: Columns appear in the exact order specified
|
|
485
|
+
- **Selection column**: Include `'select'` in the array to position the selection column
|
|
486
|
+
- **Actions column**: Include `'actions'` in the array to position the actions column
|
|
487
|
+
- **Data columns**: Use the column's `accessorKey` or `id` to reference data columns
|
|
488
|
+
|
|
489
|
+
#### When `columnOrder` is not provided:
|
|
490
|
+
- **Default behavior**: Selection column first (if enabled), then data columns, then actions column
|
|
491
|
+
- **Automatic ordering**: Columns appear in the order they're defined in the `columns` array
|
|
492
|
+
|
|
493
|
+
### Selection Column Positioning
|
|
494
|
+
|
|
495
|
+
The selection column can be positioned anywhere in the column order:
|
|
496
|
+
|
|
497
|
+
```tsx
|
|
498
|
+
// Selection column first (default when not in columnOrder)
|
|
499
|
+
<DataTable
|
|
500
|
+
data={data}
|
|
501
|
+
columns={columns}
|
|
502
|
+
features={{ selection: true }}
|
|
503
|
+
columnOrder={['select', 'name', 'email', 'role']}
|
|
504
|
+
/>
|
|
505
|
+
|
|
506
|
+
// Selection column in the middle
|
|
507
|
+
<DataTable
|
|
508
|
+
data={data}
|
|
509
|
+
columns={columns}
|
|
510
|
+
features={{ selection: true }}
|
|
511
|
+
columnOrder={['name', 'select', 'email', 'role']}
|
|
512
|
+
/>
|
|
513
|
+
|
|
514
|
+
// Selection column last
|
|
515
|
+
<DataTable
|
|
516
|
+
data={data}
|
|
517
|
+
columns={columns}
|
|
518
|
+
features={{ selection: true }}
|
|
519
|
+
columnOrder={['name', 'email', 'role', 'select']}
|
|
520
|
+
/>
|
|
521
|
+
|
|
522
|
+
// Selection column not in columnOrder - defaults to first position
|
|
523
|
+
<DataTable
|
|
524
|
+
data={data}
|
|
525
|
+
columns={columns}
|
|
526
|
+
features={{ selection: true }}
|
|
527
|
+
columnOrder={['name', 'email', 'role']} // selection will be first
|
|
528
|
+
/>
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### Actions Column Positioning
|
|
532
|
+
|
|
533
|
+
The actions column can also be positioned anywhere:
|
|
534
|
+
|
|
535
|
+
```tsx
|
|
536
|
+
// Actions column last (default when not in columnOrder)
|
|
537
|
+
<DataTable
|
|
538
|
+
data={data}
|
|
539
|
+
columns={columns}
|
|
540
|
+
features={{ editing: true, deletion: true }}
|
|
541
|
+
columnOrder={['name', 'email', 'role', 'actions']}
|
|
542
|
+
/>
|
|
543
|
+
|
|
544
|
+
// Actions column first
|
|
545
|
+
<DataTable
|
|
546
|
+
data={data}
|
|
547
|
+
columns={columns}
|
|
548
|
+
features={{ editing: true, deletion: true }}
|
|
549
|
+
columnOrder={['actions', 'name', 'email', 'role']}
|
|
550
|
+
/>
|
|
551
|
+
|
|
552
|
+
// Actions column in the middle
|
|
553
|
+
<DataTable
|
|
554
|
+
data={data}
|
|
555
|
+
columns={columns}
|
|
556
|
+
features={{ editing: true, deletion: true }}
|
|
557
|
+
columnOrder={['name', 'actions', 'email', 'role']}
|
|
558
|
+
/>
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Complete Column Ordering Example
|
|
562
|
+
|
|
563
|
+
```tsx
|
|
564
|
+
interface User {
|
|
565
|
+
id: string;
|
|
566
|
+
name: string;
|
|
567
|
+
email: string;
|
|
568
|
+
role: string;
|
|
569
|
+
status: 'active' | 'inactive';
|
|
570
|
+
createdAt: Date;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const columns: DataTableColumn<User>[] = [
|
|
574
|
+
{
|
|
575
|
+
accessorKey: 'name',
|
|
576
|
+
header: 'Name',
|
|
577
|
+
sortable: true,
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
accessorKey: 'email',
|
|
581
|
+
header: 'Email',
|
|
582
|
+
sortable: true,
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
accessorKey: 'role',
|
|
586
|
+
header: 'Role',
|
|
587
|
+
sortable: true,
|
|
588
|
+
enableGrouping: true,
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
accessorKey: 'status',
|
|
592
|
+
header: 'Status',
|
|
593
|
+
sortable: true,
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
accessorKey: 'createdAt',
|
|
597
|
+
header: 'Created',
|
|
598
|
+
sortable: true,
|
|
599
|
+
},
|
|
600
|
+
];
|
|
601
|
+
|
|
602
|
+
function UserTable() {
|
|
603
|
+
return (
|
|
604
|
+
<DataTable
|
|
605
|
+
data={users}
|
|
606
|
+
columns={columns}
|
|
607
|
+
title="User Management"
|
|
608
|
+
features={{
|
|
609
|
+
selection: true,
|
|
610
|
+
sorting: true,
|
|
611
|
+
filtering: true,
|
|
612
|
+
editing: true,
|
|
613
|
+
deletion: true,
|
|
614
|
+
}}
|
|
615
|
+
// Custom column order: selection first, then name, email, role, status, actions, created last
|
|
616
|
+
columnOrder={['select', 'name', 'email', 'role', 'status', 'actions', 'createdAt']}
|
|
617
|
+
onEditRow={handleEdit}
|
|
618
|
+
onDeleteRow={handleDelete}
|
|
619
|
+
/>
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### Column Ordering with Hierarchical Data
|
|
625
|
+
|
|
626
|
+
When using hierarchical data, column ordering works the same way:
|
|
627
|
+
|
|
628
|
+
```tsx
|
|
629
|
+
<DataTable
|
|
630
|
+
data={hierarchicalData}
|
|
631
|
+
columns={columns}
|
|
632
|
+
features={{
|
|
633
|
+
hierarchical: true,
|
|
634
|
+
selection: true,
|
|
635
|
+
editing: true,
|
|
636
|
+
deletion: true,
|
|
637
|
+
}}
|
|
638
|
+
hierarchical={{
|
|
639
|
+
enabled: true,
|
|
640
|
+
defaultExpanded: false,
|
|
641
|
+
}}
|
|
642
|
+
// Custom order for hierarchical table
|
|
643
|
+
columnOrder={['select', 'name', 'ingredient', 'quantity', 'actions']}
|
|
644
|
+
/>
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### Dynamic Column Ordering
|
|
648
|
+
|
|
649
|
+
You can dynamically change column order based on user preferences or application state:
|
|
650
|
+
|
|
651
|
+
```tsx
|
|
652
|
+
function DynamicUserTable() {
|
|
653
|
+
const [columnOrder, setColumnOrder] = useState(['select', 'name', 'email', 'role', 'status']);
|
|
654
|
+
|
|
655
|
+
const handleColumnReorder = (newOrder: string[]) => {
|
|
656
|
+
setColumnOrder(newOrder);
|
|
657
|
+
// Save to localStorage or user preferences
|
|
658
|
+
localStorage.setItem('userTableColumnOrder', JSON.stringify(newOrder));
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
return (
|
|
662
|
+
<DataTable
|
|
663
|
+
data={users}
|
|
664
|
+
columns={columns}
|
|
665
|
+
features={{
|
|
666
|
+
selection: true,
|
|
667
|
+
sorting: true,
|
|
668
|
+
columnReordering: true, // Enable drag-and-drop reordering
|
|
669
|
+
}}
|
|
670
|
+
columnOrder={columnOrder}
|
|
671
|
+
onColumnOrderChange={handleColumnReorder}
|
|
672
|
+
/>
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
### Column Ordering Best Practices
|
|
678
|
+
|
|
679
|
+
#### 1. **Consistent Ordering**
|
|
680
|
+
```tsx
|
|
681
|
+
// ✅ Good - Consistent ordering across similar tables
|
|
682
|
+
const userTableOrder = ['select', 'name', 'email', 'role', 'status', 'actions'];
|
|
683
|
+
const productTableOrder = ['select', 'name', 'sku', 'price', 'status', 'actions'];
|
|
684
|
+
|
|
685
|
+
// ❌ Avoid - Inconsistent ordering
|
|
686
|
+
const userTableOrder = ['select', 'name', 'email', 'role', 'status', 'actions'];
|
|
687
|
+
const productTableOrder = ['name', 'select', 'sku', 'actions', 'price', 'status'];
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
#### 2. **Logical Grouping**
|
|
691
|
+
```tsx
|
|
692
|
+
// ✅ Good - Logical grouping of related columns
|
|
693
|
+
columnOrder={[
|
|
694
|
+
'select', // Selection controls
|
|
695
|
+
'name', 'email', // Identity information
|
|
696
|
+
'role', 'status', // Access and state
|
|
697
|
+
'createdAt', // Metadata
|
|
698
|
+
'actions' // Actions
|
|
699
|
+
]}
|
|
700
|
+
|
|
701
|
+
// ❌ Avoid - Random column order
|
|
702
|
+
columnOrder={['email', 'actions', 'name', 'select', 'status', 'role', 'createdAt']}
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
#### 3. **User Experience Considerations**
|
|
706
|
+
```tsx
|
|
707
|
+
// ✅ Good - Most important columns first
|
|
708
|
+
columnOrder={['select', 'name', 'email', 'role', 'status', 'actions']}
|
|
709
|
+
|
|
710
|
+
// ✅ Good - Actions column last (standard pattern)
|
|
711
|
+
columnOrder={['select', 'name', 'email', 'role', 'status', 'actions']}
|
|
712
|
+
|
|
713
|
+
// ❌ Avoid - Actions column in the middle (confusing)
|
|
714
|
+
columnOrder={['select', 'name', 'actions', 'email', 'role', 'status']}
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
#### 4. **Responsive Considerations**
|
|
718
|
+
```tsx
|
|
719
|
+
// For mobile-first design, put most important columns first
|
|
720
|
+
const mobileColumnOrder = ['select', 'name', 'status', 'actions'];
|
|
721
|
+
const desktopColumnOrder = ['select', 'name', 'email', 'role', 'status', 'createdAt', 'actions'];
|
|
722
|
+
|
|
723
|
+
<DataTable
|
|
724
|
+
data={users}
|
|
725
|
+
columns={columns}
|
|
726
|
+
features={{ selection: true, sorting: true }}
|
|
727
|
+
columnOrder={isMobile ? mobileColumnOrder : desktopColumnOrder}
|
|
728
|
+
/>
|
|
729
|
+
```
|
|
730
|
+
|
|
364
731
|
## Data Management
|
|
365
732
|
|
|
366
733
|
### Sorting
|
|
@@ -402,6 +769,35 @@ const columns: DataTableColumn<User>[] = [
|
|
|
402
769
|
/>
|
|
403
770
|
```
|
|
404
771
|
|
|
772
|
+
#### Custom Initial Page Size
|
|
773
|
+
|
|
774
|
+
```tsx
|
|
775
|
+
<DataTable
|
|
776
|
+
data={data}
|
|
777
|
+
columns={columns}
|
|
778
|
+
features={{ pagination: true }}
|
|
779
|
+
initialPageSize={25} // Start with 25 items per page instead of default 10
|
|
780
|
+
/>
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
#### Page Size Validation
|
|
784
|
+
|
|
785
|
+
The DataTable automatically validates the `initialPageSize` against available page size options:
|
|
786
|
+
|
|
787
|
+
```tsx
|
|
788
|
+
<DataTable
|
|
789
|
+
data={data}
|
|
790
|
+
columns={columns}
|
|
791
|
+
features={{ pagination: true }}
|
|
792
|
+
initialPageSize={15} // Will fallback to closest valid option (10) with console warning
|
|
793
|
+
/>
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
**Available page size options by mode:**
|
|
797
|
+
- **Client mode**: `[10, 25, 50]` or `[10, 25, 50, 100]` (depending on data size)
|
|
798
|
+
- **Hybrid mode**: `[50, 100, 250, 500]`
|
|
799
|
+
- **Server mode**: `[25, 50, 100, 250]`
|
|
800
|
+
|
|
405
801
|
### Search
|
|
406
802
|
|
|
407
803
|
```tsx
|
|
@@ -439,6 +835,24 @@ Row actions are handled through the `actions` prop, which provides full flexibil
|
|
|
439
835
|
icon: EyeIcon,
|
|
440
836
|
variant: 'default',
|
|
441
837
|
},
|
|
838
|
+
{
|
|
839
|
+
label: 'Edit',
|
|
840
|
+
onClick: (row) => editUser(row.original.id),
|
|
841
|
+
icon: EditIcon,
|
|
842
|
+
variant: 'outline',
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
label: 'Share',
|
|
846
|
+
onClick: (row) => shareUser(row.original.id),
|
|
847
|
+
icon: ShareIcon,
|
|
848
|
+
variant: 'secondary',
|
|
849
|
+
},
|
|
850
|
+
{
|
|
851
|
+
label: 'More Options',
|
|
852
|
+
onClick: (row) => showMoreOptions(row.original.id),
|
|
853
|
+
icon: MoreHorizontalIcon,
|
|
854
|
+
variant: 'ghost',
|
|
855
|
+
},
|
|
442
856
|
{
|
|
443
857
|
label: 'Archive',
|
|
444
858
|
onClick: (row) => archiveUser(row.original.id),
|
|
@@ -464,6 +878,155 @@ Each action supports the following properties:
|
|
|
464
878
|
- `showInEditMode?: boolean` - Show in edit mode (default: true)
|
|
465
879
|
- `hideInViewMode?: boolean` - Hide in view mode (default: false)
|
|
466
880
|
|
|
881
|
+
#### Action Variants Guide
|
|
882
|
+
|
|
883
|
+
The DataTable supports 5 action variants, each designed for specific use cases:
|
|
884
|
+
|
|
885
|
+
```tsx
|
|
886
|
+
const actions = [
|
|
887
|
+
// DEFAULT - Primary actions (most important)
|
|
888
|
+
{
|
|
889
|
+
label: 'View Details',
|
|
890
|
+
onClick: (row) => viewDetails(row.original.id),
|
|
891
|
+
icon: EyeIcon,
|
|
892
|
+
variant: 'default', // Solid background, primary color
|
|
893
|
+
},
|
|
894
|
+
|
|
895
|
+
// OUTLINE - Secondary actions (important but not primary)
|
|
896
|
+
{
|
|
897
|
+
label: 'Edit',
|
|
898
|
+
onClick: (row) => editItem(row.original.id),
|
|
899
|
+
icon: EditIcon,
|
|
900
|
+
variant: 'outline', // Bordered, transparent background
|
|
901
|
+
},
|
|
902
|
+
|
|
903
|
+
// SECONDARY - Supporting actions (less prominent)
|
|
904
|
+
{
|
|
905
|
+
label: 'Share',
|
|
906
|
+
onClick: (row) => shareItem(row.original.id),
|
|
907
|
+
icon: ShareIcon,
|
|
908
|
+
variant: 'secondary', // Muted background, subtle styling
|
|
909
|
+
},
|
|
910
|
+
|
|
911
|
+
// GHOST - Subtle actions (minimal visual impact)
|
|
912
|
+
{
|
|
913
|
+
label: 'More Options',
|
|
914
|
+
onClick: (row) => showMoreOptions(row.original.id),
|
|
915
|
+
icon: MoreHorizontalIcon,
|
|
916
|
+
variant: 'ghost', // No background, minimal styling
|
|
917
|
+
},
|
|
918
|
+
|
|
919
|
+
// DESTRUCTIVE - Dangerous actions (require caution)
|
|
920
|
+
{
|
|
921
|
+
label: 'Delete',
|
|
922
|
+
onClick: (row) => deleteItem(row.original.id),
|
|
923
|
+
icon: TrashIcon,
|
|
924
|
+
variant: 'destructive', // Red styling to indicate danger
|
|
925
|
+
disabled: (row) => row.original.status === 'locked',
|
|
926
|
+
},
|
|
927
|
+
];
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
**Variant Usage Guidelines:**
|
|
931
|
+
|
|
932
|
+
- **`default`**: Use for the most important action (e.g., "View Details", "Open")
|
|
933
|
+
- **`outline`**: Use for important secondary actions (e.g., "Edit", "Download")
|
|
934
|
+
- **`secondary`**: Use for supporting actions (e.g., "Share", "Copy", "Export")
|
|
935
|
+
- **`ghost`**: Use for subtle actions (e.g., "More Options", "Settings")
|
|
936
|
+
- **`destructive`**: Use for dangerous actions (e.g., "Delete", "Archive", "Remove")
|
|
937
|
+
|
|
938
|
+
#### Hierarchical Actions
|
|
939
|
+
|
|
940
|
+
When using hierarchical rows, you can define different action icons and labels for parent vs child rows:
|
|
941
|
+
|
|
942
|
+
```tsx
|
|
943
|
+
<DataTable
|
|
944
|
+
data={hierarchicalData}
|
|
945
|
+
columns={columns}
|
|
946
|
+
features={{
|
|
947
|
+
hierarchical: true,
|
|
948
|
+
editing: true,
|
|
949
|
+
deletion: true,
|
|
950
|
+
}}
|
|
951
|
+
hierarchical={{
|
|
952
|
+
enabled: true,
|
|
953
|
+
defaultExpanded: false,
|
|
954
|
+
}}
|
|
955
|
+
actions={[
|
|
956
|
+
{
|
|
957
|
+
label: 'View Details',
|
|
958
|
+
icon: EyeIcon,
|
|
959
|
+
// Different icons for parent vs child rows
|
|
960
|
+
parentIcon: EyeIcon,
|
|
961
|
+
childIcon: InfoIcon,
|
|
962
|
+
// Different labels for parent vs child rows
|
|
963
|
+
parentLabel: 'View Recipe',
|
|
964
|
+
childLabel: 'View Ingredient',
|
|
965
|
+
onClick: (row) => {
|
|
966
|
+
console.log('Viewing:', row.isParent ? 'Recipe' : 'Ingredient', row.name);
|
|
967
|
+
},
|
|
968
|
+
variant: 'default',
|
|
969
|
+
},
|
|
970
|
+
{
|
|
971
|
+
label: 'Edit',
|
|
972
|
+
icon: PencilIcon,
|
|
973
|
+
parentIcon: SettingsIcon,
|
|
974
|
+
childIcon: PencilIcon,
|
|
975
|
+
parentLabel: 'Edit Recipe',
|
|
976
|
+
childLabel: 'Edit Ingredient',
|
|
977
|
+
onClick: (row) => {
|
|
978
|
+
console.log('Editing:', row.isParent ? 'Recipe' : 'Ingredient', row.name);
|
|
979
|
+
},
|
|
980
|
+
variant: 'default',
|
|
981
|
+
},
|
|
982
|
+
{
|
|
983
|
+
label: 'Copy Recipe',
|
|
984
|
+
icon: CopyIcon,
|
|
985
|
+
parentIcon: CopyIcon,
|
|
986
|
+
parentLabel: 'Duplicate Recipe',
|
|
987
|
+
onClick: (row) => {
|
|
988
|
+
console.log('Copying recipe:', row.name);
|
|
989
|
+
},
|
|
990
|
+
variant: 'outline',
|
|
991
|
+
// Only show for parent rows
|
|
992
|
+
showForParent: true,
|
|
993
|
+
},
|
|
994
|
+
{
|
|
995
|
+
label: 'Export',
|
|
996
|
+
icon: DownloadIcon,
|
|
997
|
+
childIcon: DownloadIcon,
|
|
998
|
+
childLabel: 'Export Ingredient',
|
|
999
|
+
onClick: (row) => {
|
|
1000
|
+
console.log('Exporting ingredient:', row.item);
|
|
1001
|
+
},
|
|
1002
|
+
variant: 'ghost',
|
|
1003
|
+
// Only show for child rows
|
|
1004
|
+
showForChild: true,
|
|
1005
|
+
},
|
|
1006
|
+
]}
|
|
1007
|
+
/>
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
##### Hierarchical Action Properties
|
|
1011
|
+
|
|
1012
|
+
When using hierarchical rows, actions support additional properties:
|
|
1013
|
+
|
|
1014
|
+
- `showForParent?: boolean` - Only show this action for parent rows
|
|
1015
|
+
- `showForChild?: boolean` - Only show this action for child rows
|
|
1016
|
+
- `parentIcon?: ComponentType` - Icon to use for parent rows (overrides `icon`)
|
|
1017
|
+
- `childIcon?: ComponentType` - Icon to use for child rows (overrides `icon`)
|
|
1018
|
+
- `parentLabel?: string` - Label to use for parent rows (overrides `label`)
|
|
1019
|
+
- `childLabel?: string` - Label to use for child rows (overrides `label`)
|
|
1020
|
+
|
|
1021
|
+
##### Action Visibility Logic
|
|
1022
|
+
|
|
1023
|
+
The action visibility is determined by the following logic:
|
|
1024
|
+
|
|
1025
|
+
1. **Hierarchical filtering**: If `showForParent` is true, action only shows for parent rows
|
|
1026
|
+
2. **Hierarchical filtering**: If `showForChild` is true, action only shows for child rows
|
|
1027
|
+
3. **Standard filtering**: Uses `visible`, `showInEditMode`, `hideInViewMode` properties
|
|
1028
|
+
4. **Disabled state**: Uses `disabled` function to determine if action is disabled
|
|
1029
|
+
|
|
467
1030
|
### Toolbar Actions
|
|
468
1031
|
|
|
469
1032
|
Toolbar actions are automatically generated based on the enabled features. Custom toolbar buttons are not directly supported in the current interface, but you can implement them outside the DataTable component:
|
|
@@ -496,11 +1059,218 @@ Toolbar actions are automatically generated based on the enabled features. Custo
|
|
|
496
1059
|
</div>
|
|
497
1060
|
```
|
|
498
1061
|
|
|
1062
|
+
### Hierarchical Parent/Child Rows
|
|
1063
|
+
|
|
1064
|
+
The DataTable supports hierarchical parent/child row relationships with built-in expand/collapse functionality, expand/collapse all controls, and proper column rendering for different row types.
|
|
1065
|
+
|
|
1066
|
+
#### Data Structure
|
|
1067
|
+
|
|
1068
|
+
Your data must conform to the `HierarchicalDataRow` interface:
|
|
1069
|
+
|
|
1070
|
+
```typescript
|
|
1071
|
+
interface HierarchicalDataRow extends DataRecord {
|
|
1072
|
+
/** Whether this row is a parent row */
|
|
1073
|
+
isParent: boolean;
|
|
1074
|
+
/** For child rows, references the parent row ID */
|
|
1075
|
+
parentId?: string;
|
|
1076
|
+
/** Unique identifier for this row */
|
|
1077
|
+
id: string;
|
|
1078
|
+
// ... your actual data properties
|
|
1079
|
+
}
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
#### Configuration
|
|
1083
|
+
|
|
1084
|
+
Enable hierarchical functionality through the `features` prop and configure it with the `hierarchical` prop:
|
|
1085
|
+
|
|
1086
|
+
```tsx
|
|
1087
|
+
<DataTable
|
|
1088
|
+
data={hierarchicalData}
|
|
1089
|
+
columns={columns}
|
|
1090
|
+
features={{
|
|
1091
|
+
// ... other features
|
|
1092
|
+
hierarchical: true, // Enable hierarchical functionality
|
|
1093
|
+
}}
|
|
1094
|
+
hierarchical={{
|
|
1095
|
+
enabled: true,
|
|
1096
|
+
defaultExpanded: false, // true = all expanded, false = all collapsed, array = specific IDs
|
|
1097
|
+
onExpandedChange: (expandedIds) => console.log('Expanded:', expandedIds),
|
|
1098
|
+
expandButton: CustomExpandButton, // Optional custom expand button
|
|
1099
|
+
indentSize: 24, // Indentation for child rows in pixels
|
|
1100
|
+
parentRowClassName: 'bg-main-50 font-medium', // Custom styling for parent rows
|
|
1101
|
+
childRowClassName: 'bg-sec-25', // Custom styling for child rows
|
|
1102
|
+
}}
|
|
1103
|
+
```
|
|
1104
|
+
|
|
1105
|
+
**Default Collapsed State:**
|
|
1106
|
+
To make parent rows collapsed by default (recommended for better UX), set `defaultExpanded: false`. This ensures users see only parent rows initially and must click to expand and view child rows.
|
|
1107
|
+
|
|
1108
|
+
#### Column Configuration
|
|
1109
|
+
|
|
1110
|
+
Configure how columns render for different row types:
|
|
1111
|
+
|
|
1112
|
+
```tsx
|
|
1113
|
+
const columns: DataTableColumn<YourDataType>[] = [
|
|
1114
|
+
{
|
|
1115
|
+
accessorKey: 'code',
|
|
1116
|
+
header: 'Code',
|
|
1117
|
+
// Render differently for parent vs child rows
|
|
1118
|
+
renderForParent: (row) => (
|
|
1119
|
+
<div className="flex items-center gap-2">
|
|
1120
|
+
<strong>{row.code}</strong>
|
|
1121
|
+
</div>
|
|
1122
|
+
),
|
|
1123
|
+
renderForChild: () => '', // Blank for child rows
|
|
1124
|
+
hideForChild: true, // Hide this column for child rows
|
|
1125
|
+
},
|
|
1126
|
+
{
|
|
1127
|
+
accessorKey: 'name',
|
|
1128
|
+
header: 'Name',
|
|
1129
|
+
renderForParent: (row) => <strong>{row.name}</strong>,
|
|
1130
|
+
renderForChild: () => '', // Blank for child rows
|
|
1131
|
+
hideForChild: true,
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
accessorKey: 'ingredient',
|
|
1135
|
+
header: 'Ingredient',
|
|
1136
|
+
renderForParent: () => '', // Blank for parent rows
|
|
1137
|
+
renderForChild: (row) => <span className="ml-4">{row.ingredient}</span>,
|
|
1138
|
+
hideForParent: true, // Hide this column for parent rows
|
|
1139
|
+
},
|
|
1140
|
+
];
|
|
1141
|
+
```
|
|
1142
|
+
|
|
1143
|
+
#### Column Properties
|
|
1144
|
+
|
|
1145
|
+
- `renderForParent?: (row: TData) => React.ReactNode` - Custom renderer for parent rows
|
|
1146
|
+
- `renderForChild?: (row: TData) => React.ReactNode` - Custom renderer for child rows
|
|
1147
|
+
- `hideForParent?: boolean` - Hide this column for parent rows
|
|
1148
|
+
- `hideForChild?: boolean` - Hide this column for child rows
|
|
1149
|
+
|
|
1150
|
+
#### Expand/Collapse All Controls
|
|
1151
|
+
|
|
1152
|
+
The DataTable automatically adds an expand/collapse all button in the header when hierarchical mode is enabled:
|
|
1153
|
+
|
|
1154
|
+
**Features:**
|
|
1155
|
+
- **Expand All Button (▶️)**: Expands all parent rows to show their children
|
|
1156
|
+
- **Collapse All Button (🔽)**: Collapses all parent rows to hide their children
|
|
1157
|
+
- **Smart State Detection**: Button automatically updates based on current expansion state
|
|
1158
|
+
- **Accessibility**: Proper ARIA labels and keyboard navigation support
|
|
1159
|
+
|
|
1160
|
+
**Usage:**
|
|
1161
|
+
```tsx
|
|
1162
|
+
<DataTable
|
|
1163
|
+
data={hierarchicalData}
|
|
1164
|
+
columns={columns}
|
|
1165
|
+
features={{ hierarchical: true }}
|
|
1166
|
+
hierarchical={{
|
|
1167
|
+
enabled: true,
|
|
1168
|
+
defaultExpanded: false, // Start with all collapsed
|
|
1169
|
+
onExpandedChange: (expandedIds) => {
|
|
1170
|
+
console.log('Expanded rows:', expandedIds);
|
|
1171
|
+
},
|
|
1172
|
+
}}
|
|
1173
|
+
/>
|
|
1174
|
+
```
|
|
1175
|
+
|
|
1176
|
+
**Button Behavior:**
|
|
1177
|
+
- Shows ▶️ when some or all parent rows are collapsed
|
|
1178
|
+
- Shows 🔽 when all parent rows are expanded
|
|
1179
|
+
- Only appears when there are parent rows with children
|
|
1180
|
+
- Positioned in the first column of the table header
|
|
1181
|
+
|
|
1182
|
+
#### Hierarchical Sorting
|
|
1183
|
+
|
|
1184
|
+
When hierarchical mode is enabled, sorting behavior is optimized to preserve the parent-child relationship structure:
|
|
1185
|
+
|
|
1186
|
+
**Parent Row Sorting:**
|
|
1187
|
+
- Parent rows maintain their original order and are not affected by sorting
|
|
1188
|
+
- Only child rows within each parent group are sorted
|
|
1189
|
+
- This prevents parent rows from being moved to unexpected positions
|
|
1190
|
+
|
|
1191
|
+
**Child Row Sorting:**
|
|
1192
|
+
- Child rows are sorted within their parent group only
|
|
1193
|
+
- Sorting by a child-specific column (e.g., "Diet", "Ingredient") will sort children within each parent
|
|
1194
|
+
- The parent row remains at the top of its group
|
|
1195
|
+
|
|
1196
|
+
**Example:**
|
|
1197
|
+
```tsx
|
|
1198
|
+
// When sorting by "Diet" column:
|
|
1199
|
+
// ✅ Correct behavior:
|
|
1200
|
+
// Parent: Caesar Salad
|
|
1201
|
+
// ├─ Child: Dairy Free (Sour cream)
|
|
1202
|
+
// ├─ Child: Egg Free (Mayonnaise)
|
|
1203
|
+
// └─ Child: GF & Vegan (Lettuce)
|
|
1204
|
+
// Parent: Beef Stir Fry
|
|
1205
|
+
// ├─ Child: GF & Vegan (Vegetables)
|
|
1206
|
+
// └─ Child: Halal (Beef)
|
|
1207
|
+
|
|
1208
|
+
// ❌ Incorrect behavior (what we prevent):
|
|
1209
|
+
// Child: Dairy Free (Sour cream)
|
|
1210
|
+
// Child: Egg Free (Mayonnaise)
|
|
1211
|
+
// Child: GF & Vegan (Lettuce)
|
|
1212
|
+
// Child: GF & Vegan (Vegetables)
|
|
1213
|
+
// Child: Halal (Beef)
|
|
1214
|
+
// Parent: Caesar Salad (moved to end)
|
|
1215
|
+
// Parent: Beef Stir Fry (moved to end)
|
|
1216
|
+
```
|
|
1217
|
+
|
|
1218
|
+
**Sorting Configuration:**
|
|
1219
|
+
- All existing sorting features work with hierarchical data
|
|
1220
|
+
- Multi-column sorting is supported
|
|
1221
|
+
- Server-side sorting is compatible
|
|
1222
|
+
- Column-specific sorting behavior is preserved
|
|
1223
|
+
|
|
1224
|
+
#### Example Use Case
|
|
1225
|
+
|
|
1226
|
+
```tsx
|
|
1227
|
+
// Dishes and ingredients example
|
|
1228
|
+
const dishData = [
|
|
1229
|
+
// Parent rows (dishes)
|
|
1230
|
+
{ id: 'dish-1', isParent: true, code: 'D001', name: 'Caesar Salad', type: 'Salad' },
|
|
1231
|
+
{ id: 'dish-2', isParent: true, code: 'D002', name: 'Beef Stir Fry', type: 'Main Course' },
|
|
1232
|
+
|
|
1233
|
+
// Child rows (ingredients) for Caesar Salad
|
|
1234
|
+
{ id: 'ing-1-1', isParent: false, parentId: 'dish-1', ingredient: 'Lettuce', quantity: '200g' },
|
|
1235
|
+
{ id: 'ing-1-2', isParent: false, parentId: 'dish-1', ingredient: 'Chicken', quantity: '150g' },
|
|
1236
|
+
|
|
1237
|
+
// Child rows (ingredients) for Beef Stir Fry
|
|
1238
|
+
{ id: 'ing-2-1', isParent: false, parentId: 'dish-2', ingredient: 'Beef Strips', quantity: '250g' },
|
|
1239
|
+
{ id: 'ing-2-2', isParent: false, parentId: 'dish-2', ingredient: 'Mixed Vegetables', quantity: '200g' },
|
|
1240
|
+
];
|
|
1241
|
+
```
|
|
1242
|
+
|
|
499
1243
|
### Row Selection and Bulk Operations
|
|
500
1244
|
|
|
501
1245
|
```tsx
|
|
502
1246
|
function SelectableUserTable() {
|
|
503
|
-
const [selectedRows, setSelectedRows] = useState<
|
|
1247
|
+
const [selectedRows, setSelectedRows] = useState<Record<string, boolean>>({});
|
|
1248
|
+
const [data, setData] = useState<User[]>(initialData);
|
|
1249
|
+
|
|
1250
|
+
const handleBulkDelete = (selectedRows: Record<string, boolean>) => {
|
|
1251
|
+
// Get the selected row IDs
|
|
1252
|
+
const selectedRowIds = Object.keys(selectedRows).filter(id => selectedRows[id]);
|
|
1253
|
+
|
|
1254
|
+
// Get the actual data for selected rows
|
|
1255
|
+
const selectedData = data.filter(row => {
|
|
1256
|
+
const rowId = getRowId ? getRowId(row, data.indexOf(row)) : row.id;
|
|
1257
|
+
return selectedRowIds.includes(rowId);
|
|
1258
|
+
});
|
|
1259
|
+
|
|
1260
|
+
// Perform your deletion logic
|
|
1261
|
+
console.log('Deleting selected rows:', selectedData);
|
|
1262
|
+
|
|
1263
|
+
// Update your data state
|
|
1264
|
+
setData(prevData =>
|
|
1265
|
+
prevData.filter(row => {
|
|
1266
|
+
const rowId = getRowId ? getRowId(row, prevData.indexOf(row)) : row.id;
|
|
1267
|
+
return !selectedRowIds.includes(rowId);
|
|
1268
|
+
})
|
|
1269
|
+
);
|
|
1270
|
+
|
|
1271
|
+
// Clear selection after deletion
|
|
1272
|
+
setSelectedRows({});
|
|
1273
|
+
};
|
|
504
1274
|
|
|
505
1275
|
return (
|
|
506
1276
|
<DataTable
|
|
@@ -508,23 +1278,44 @@ function SelectableUserTable() {
|
|
|
508
1278
|
columns={columns}
|
|
509
1279
|
features={{
|
|
510
1280
|
selection: true,
|
|
1281
|
+
deletion: true, // Required for delete functionality
|
|
1282
|
+
deleteSelected: true, // Enables the delete selected button
|
|
511
1283
|
bulkOperations: true,
|
|
512
|
-
deleteSelected: true,
|
|
513
1284
|
}}
|
|
514
|
-
rowSelection={selectedRows}
|
|
515
1285
|
onRowSelectionChange={setSelectedRows}
|
|
516
1286
|
onDeleteSelected={handleBulkDelete}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
1287
|
+
getRowId={(row) => row.id} // Important: provide getRowId for proper row identification
|
|
1288
|
+
/>
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
```
|
|
1292
|
+
|
|
1293
|
+
#### Alternative: Using Individual onDeleteRow (Fallback)
|
|
1294
|
+
|
|
1295
|
+
If you don't provide `onDeleteSelected`, the DataTable will automatically fall back to calling `onDeleteRow` for each selected row:
|
|
1296
|
+
|
|
1297
|
+
```tsx
|
|
1298
|
+
function SelectableUserTable() {
|
|
1299
|
+
const [data, setData] = useState<User[]>(initialData);
|
|
1300
|
+
|
|
1301
|
+
const handleDeleteRow = (row: User) => {
|
|
1302
|
+
console.log('Deleting row:', row);
|
|
1303
|
+
|
|
1304
|
+
// Update your data state
|
|
1305
|
+
setData(prevData => prevData.filter(item => item.id !== row.id));
|
|
1306
|
+
};
|
|
1307
|
+
|
|
1308
|
+
return (
|
|
1309
|
+
<DataTable
|
|
1310
|
+
data={data}
|
|
1311
|
+
columns={columns}
|
|
1312
|
+
features={{
|
|
1313
|
+
selection: true,
|
|
1314
|
+
deletion: true,
|
|
1315
|
+
deleteSelected: true,
|
|
527
1316
|
}}
|
|
1317
|
+
onDeleteRow={handleDeleteRow} // This will be called for each selected row
|
|
1318
|
+
getRowId={(row) => row.id}
|
|
528
1319
|
/>
|
|
529
1320
|
);
|
|
530
1321
|
}
|
|
@@ -680,8 +1471,191 @@ function SecureUserTable() {
|
|
|
680
1471
|
}
|
|
681
1472
|
```
|
|
682
1473
|
|
|
1474
|
+
## Practical Examples
|
|
1475
|
+
|
|
1476
|
+
### Custom Page Size Configuration
|
|
1477
|
+
|
|
1478
|
+
Here's a complete example showing how to configure a DataTable with custom initial page size:
|
|
1479
|
+
|
|
1480
|
+
```tsx
|
|
1481
|
+
import { DataTable, type DataTableColumn } from '@jmruthers/pace-core';
|
|
1482
|
+
|
|
1483
|
+
interface User {
|
|
1484
|
+
id: string;
|
|
1485
|
+
name: string;
|
|
1486
|
+
email: string;
|
|
1487
|
+
role: string;
|
|
1488
|
+
status: 'active' | 'inactive';
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
const columns: DataTableColumn<User>[] = [
|
|
1492
|
+
{
|
|
1493
|
+
accessorKey: 'name',
|
|
1494
|
+
header: 'Name',
|
|
1495
|
+
sortable: true,
|
|
1496
|
+
searchable: true,
|
|
1497
|
+
},
|
|
1498
|
+
{
|
|
1499
|
+
accessorKey: 'email',
|
|
1500
|
+
header: 'Email',
|
|
1501
|
+
sortable: true,
|
|
1502
|
+
searchable: true,
|
|
1503
|
+
},
|
|
1504
|
+
{
|
|
1505
|
+
accessorKey: 'role',
|
|
1506
|
+
header: 'Role',
|
|
1507
|
+
sortable: true,
|
|
1508
|
+
enableGrouping: true,
|
|
1509
|
+
},
|
|
1510
|
+
{
|
|
1511
|
+
accessorKey: 'status',
|
|
1512
|
+
header: 'Status',
|
|
1513
|
+
sortable: true,
|
|
1514
|
+
cell: ({ row }) => (
|
|
1515
|
+
<span className={`px-2 py-1 rounded text-xs ${
|
|
1516
|
+
row.original.status === 'active'
|
|
1517
|
+
? 'bg-main-100 text-main-800'
|
|
1518
|
+
: 'bg-acc-100 text-acc-800'
|
|
1519
|
+
}`}>
|
|
1520
|
+
{row.original.status}
|
|
1521
|
+
</span>
|
|
1522
|
+
),
|
|
1523
|
+
},
|
|
1524
|
+
];
|
|
1525
|
+
|
|
1526
|
+
function UserManagementTable() {
|
|
1527
|
+
const [users, setUsers] = useState<User[]>([]);
|
|
1528
|
+
const [loading, setLoading] = useState(true);
|
|
1529
|
+
|
|
1530
|
+
useEffect(() => {
|
|
1531
|
+
// Load users data
|
|
1532
|
+
loadUsers().then(setUsers).finally(() => setLoading(false));
|
|
1533
|
+
}, []);
|
|
1534
|
+
|
|
1535
|
+
return (
|
|
1536
|
+
<DataTable
|
|
1537
|
+
data={users}
|
|
1538
|
+
columns={columns}
|
|
1539
|
+
title="User Management"
|
|
1540
|
+
description="Manage system users with custom page size"
|
|
1541
|
+
features={{
|
|
1542
|
+
search: true,
|
|
1543
|
+
pagination: true,
|
|
1544
|
+
sorting: true,
|
|
1545
|
+
filtering: true,
|
|
1546
|
+
selection: true,
|
|
1547
|
+
creation: true,
|
|
1548
|
+
editing: true,
|
|
1549
|
+
deletion: true,
|
|
1550
|
+
deleteSelected: true,
|
|
1551
|
+
export: true,
|
|
1552
|
+
import: true,
|
|
1553
|
+
grouping: true,
|
|
1554
|
+
columnVisibility: true,
|
|
1555
|
+
columnReordering: true,
|
|
1556
|
+
autoColumnSizing: true,
|
|
1557
|
+
}}
|
|
1558
|
+
initialPageSize={25} // Start with 25 users per page
|
|
1559
|
+
isLoading={loading}
|
|
1560
|
+
onEditRow={(row, data) => {
|
|
1561
|
+
console.log('Editing user:', row.id, data);
|
|
1562
|
+
// Handle user edit
|
|
1563
|
+
}}
|
|
1564
|
+
onDeleteRow={(row) => {
|
|
1565
|
+
console.log('Deleting user:', row.id);
|
|
1566
|
+
// Handle user deletion
|
|
1567
|
+
}}
|
|
1568
|
+
onCreateRow={(data) => {
|
|
1569
|
+
console.log('Creating user:', data);
|
|
1570
|
+
// Handle user creation
|
|
1571
|
+
}}
|
|
1572
|
+
onImport={(data) => {
|
|
1573
|
+
console.log('Importing users:', data);
|
|
1574
|
+
// Handle user import
|
|
1575
|
+
}}
|
|
1576
|
+
onRowSelectionChange={(selection) => {
|
|
1577
|
+
console.log('Selection changed:', selection);
|
|
1578
|
+
// Handle selection changes
|
|
1579
|
+
}}
|
|
1580
|
+
onDeleteSelected={(selectedRows) => {
|
|
1581
|
+
console.log('Bulk deleting users:', selectedRows);
|
|
1582
|
+
// Handle bulk deletion
|
|
1583
|
+
}}
|
|
1584
|
+
/>
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1587
|
+
```
|
|
1588
|
+
|
|
1589
|
+
### Page Size Validation Example
|
|
1590
|
+
|
|
1591
|
+
```tsx
|
|
1592
|
+
// This will show a console warning and use the closest valid option
|
|
1593
|
+
<DataTable
|
|
1594
|
+
data={largeDataset}
|
|
1595
|
+
columns={columns}
|
|
1596
|
+
features={{ pagination: true }}
|
|
1597
|
+
initialPageSize={15} // Invalid - will fallback to 10 with warning
|
|
1598
|
+
paginationMode="client" // Uses [10, 25, 50] options
|
|
1599
|
+
/>
|
|
1600
|
+
|
|
1601
|
+
// This will work correctly
|
|
1602
|
+
<DataTable
|
|
1603
|
+
data={largeDataset}
|
|
1604
|
+
columns={columns}
|
|
1605
|
+
features={{ pagination: true }}
|
|
1606
|
+
initialPageSize={25} // Valid option
|
|
1607
|
+
paginationMode="client"
|
|
1608
|
+
/>
|
|
1609
|
+
```
|
|
1610
|
+
|
|
683
1611
|
## Best Practices
|
|
684
1612
|
|
|
1613
|
+
### Data Processing Best Practices
|
|
1614
|
+
- **Stable Data References**: Ensure your data processing doesn't create new object references on every render
|
|
1615
|
+
- **Memoization**: Use `useMemo` with proper dependency arrays to prevent unnecessary re-computations
|
|
1616
|
+
- **Avoid Complex Transformations in useMemo**: Move complex data transformations to the backend or data fetching layer when possible
|
|
1617
|
+
- **Data Comparison**: Use shallow comparison to detect actual data changes before updating state
|
|
1618
|
+
|
|
1619
|
+
#### ✅ Good Data Processing Patterns
|
|
1620
|
+
```tsx
|
|
1621
|
+
// Simple, stable data processing
|
|
1622
|
+
const processedData = useMemo(() => {
|
|
1623
|
+
if (!data || data.length === 0) return [];
|
|
1624
|
+
return data; // Direct usage, no transformations
|
|
1625
|
+
}, [data]);
|
|
1626
|
+
|
|
1627
|
+
// Complex processing with stable references
|
|
1628
|
+
const processedData = useMemo(() => {
|
|
1629
|
+
if (!data || data.length === 0) return [];
|
|
1630
|
+
|
|
1631
|
+
// Use stable references and avoid creating new objects unnecessarily
|
|
1632
|
+
return data.map(item => ({
|
|
1633
|
+
...item,
|
|
1634
|
+
// Simple transformations only
|
|
1635
|
+
displayName: item.firstName + ' ' + item.lastName,
|
|
1636
|
+
}));
|
|
1637
|
+
}, [data]); // Single dependency
|
|
1638
|
+
```
|
|
1639
|
+
|
|
1640
|
+
#### ❌ Avoid These Patterns
|
|
1641
|
+
```tsx
|
|
1642
|
+
// This can cause infinite loops
|
|
1643
|
+
const processedData = useMemo(() => {
|
|
1644
|
+
return data.map(item => ({
|
|
1645
|
+
...item,
|
|
1646
|
+
// Complex transformations that create new objects
|
|
1647
|
+
computed_field: relatedData?.find(rel => rel.id === item.relation_id)?.name || 'Unknown',
|
|
1648
|
+
formatted_date: item.date ? format(new Date(item.date), 'MMM dd, yyyy') : 'No date',
|
|
1649
|
+
}));
|
|
1650
|
+
}, [data, relatedData]); // Multiple dependencies with complex processing
|
|
1651
|
+
```
|
|
1652
|
+
|
|
1653
|
+
#### 🔧 Recommended Solutions for Complex Data
|
|
1654
|
+
1. **Backend Processing**: Move complex transformations to your API layer
|
|
1655
|
+
2. **Supabase Relations**: Use database relations instead of client-side lookups
|
|
1656
|
+
3. **Separate Hooks**: Create dedicated hooks for data processing
|
|
1657
|
+
4. **Stable References**: Use `useCallback` and `useMemo` with proper dependencies
|
|
1658
|
+
|
|
685
1659
|
### 1. Use the Features Configuration Properly
|
|
686
1660
|
|
|
687
1661
|
```tsx
|
|
@@ -897,6 +1871,14 @@ const columns: DataTableColumn<User>[] = [
|
|
|
897
1871
|
- Check that required event handlers are provided (e.g., `onEditRow` for editing)
|
|
898
1872
|
- Verify that the feature configuration matches your use case
|
|
899
1873
|
|
|
1874
|
+
#### 7. Delete selected rows not working
|
|
1875
|
+
- **Check feature configuration**: Ensure `features={{ selection: true, deletion: true, deleteSelected: true }}`
|
|
1876
|
+
- **Provide onDeleteSelected callback**: Implement the callback to handle bulk deletion
|
|
1877
|
+
- **Verify getRowId function**: Ensure you provide a `getRowId` function that returns unique IDs
|
|
1878
|
+
- **Check button visibility**: The delete button only appears when all three features are enabled and rows are selected
|
|
1879
|
+
- **Debug selection state**: Add console logs to verify `onRowSelectionChange` is being called with correct data
|
|
1880
|
+
- **Fallback option**: If you don't provide `onDeleteSelected`, the table will fall back to calling `onDeleteRow` for each selected row
|
|
1881
|
+
|
|
900
1882
|
### Debug Mode
|
|
901
1883
|
|
|
902
1884
|
Enable debug logging for DataTable issues:
|