@jmruthers/pace-core 0.6.10 → 0.6.11
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 +21 -0
- package/audit-tool/00-dependencies.cjs +46 -13
- package/audit-tool/audits/01-pace-core-compliance.cjs +96 -21
- package/audit-tool/audits/02-project-structure.cjs +13 -3
- package/audit-tool/audits/03-architecture.cjs +78 -4
- package/audit-tool/audits/04-code-quality.cjs +9 -2
- package/audit-tool/audits/05-styling.cjs +19 -7
- package/audit-tool/audits/06-security-rbac.cjs +105 -14
- package/audit-tool/audits/07-api-tech-stack.cjs +31 -15
- package/audit-tool/audits/08-testing-documentation.cjs +11 -3
- package/audit-tool/audits/09-operations.cjs +19 -7
- package/audit-tool/index.cjs +22 -11
- package/audit-tool/utils/report-utils.cjs +4 -0
- package/cursor-rules/01-pace-core-compliance.mdc +1 -0
- package/cursor-rules/02-project-structure.mdc +1 -0
- package/cursor-rules/03-architecture.mdc +3 -1
- package/cursor-rules/04-code-quality.mdc +1 -0
- package/cursor-rules/05-styling.mdc +41 -7
- package/cursor-rules/06-security-rbac.mdc +2 -1
- package/cursor-rules/07-api-tech-stack.mdc +1 -0
- package/cursor-rules/08-testing-documentation.mdc +1 -0
- package/cursor-rules/09-operations.mdc +1 -0
- package/dist/{DataTable-SAXFG4XI.js → DataTable-EFYP2QLE.js} +10 -7
- package/dist/{InactivityServiceProvider-DHryoh6K.d.ts → InactivityServiceProvider-BbxwwDz1.d.ts} +10 -1
- package/dist/{UnifiedAuthProvider-CiBAl9-s.d.ts → UnifiedAuthProvider-Bkt_tzdS.d.ts} +56 -24
- package/dist/{api-F47QJ7FX.js → api-BZR2CYXL.js} +3 -2
- package/dist/api-result-USV1Czr-.d.ts +51 -0
- package/dist/{audit-Z6ZZBWLU.js → audit-HI2DHUVU.js} +2 -1
- package/dist/{auth-BZOJqrdd.d.ts → auth-JvdRVaud.d.ts} +1 -1
- package/dist/{chunk-KSNLMI7N.js → chunk-2DL2WSOE.js} +1 -155
- package/dist/{chunk-MPY44PWB.js → chunk-2OEVOGGR.js} +4648 -3560
- package/dist/chunk-44CNXN4P.js +15 -0
- package/dist/{chunk-Y4PF6HIM.js → chunk-4R3T5ENU.js} +867 -786
- package/dist/{chunk-LNHFAF4X.js → chunk-7A6IMHH2.js} +289 -247
- package/dist/chunk-CU2BU2MQ.js +2 -0
- package/dist/{chunk-JJEYZ3DX.js → chunk-D6BMFMQZ.js} +37 -2
- package/dist/{chunk-BCTXBU6U.js → chunk-ENLXB7GP.js} +88 -71
- package/dist/{chunk-FBZ7U3ID.js → chunk-J2KQK6DG.js} +937 -987
- package/dist/{chunk-TFIPNIPE.js → chunk-KJXRL3XE.js} +3300 -2245
- package/dist/{chunk-3GWSPISD.js → chunk-L5LFKKLJ.js} +1 -1
- package/dist/{chunk-X5EAU5G7.js → chunk-PCSHBLPB.js} +132 -114
- package/dist/{chunk-NIU6DPQV.js → chunk-QRYSEPHB.js} +2 -0
- package/dist/{chunk-KYURMOQM.js → chunk-V7FTM2LU.js} +423 -320
- package/dist/chunk-WY6Y7KC3.js +264 -0
- package/dist/{chunk-FN52B75D.js → chunk-XOJME5T7.js} +176 -15
- package/dist/{chunk-7YDC7LMU.js → chunk-XPFVT3GN.js} +71 -66
- package/dist/{chunk-66R6RLUZ.js → chunk-YFTFFJIV.js} +3 -3
- package/dist/{chunk-W46INAVW.js → chunk-YYTWKVHO.js} +688 -570
- package/dist/components.d.ts +8 -7
- package/dist/components.js +17 -15
- package/dist/{database.generated-DT8JTZiP.d.ts → database.generated-qkdoiVrJ.d.ts} +45 -10
- package/dist/eslint-rules/index.cjs +3 -0
- package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +74 -0
- package/dist/{event-WTAQuGcq.d.ts → event-BfCox3N2.d.ts} +36 -10
- package/dist/{file-reference-BavO2eQj.d.ts → file-reference-DU1hcawx.d.ts} +29 -13
- package/dist/hooks.d.ts +22 -9
- package/dist/hooks.js +34 -25
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +66 -177
- package/dist/index.js +316 -340
- package/dist/pagination-BW1mqywp.d.ts +201 -0
- package/dist/providers.d.ts +6 -5
- package/dist/providers.js +5 -3
- package/dist/rbac/index.d.ts +123 -138
- package/dist/rbac/index.js +10 -8
- package/dist/theming/runtime.d.ts +19 -2
- package/dist/theming/runtime.js +1 -1
- package/dist/{timezone-K-ptz3HO.d.ts → timezone-BTWWXKVY.d.ts} +1 -1
- package/dist/types.d.ts +17 -10
- package/dist/types.js +1 -0
- package/dist/{usePublicPageContext-vxBlEHO9.d.ts → usePublicPageContext-B91dGYW1.d.ts} +433 -356
- package/dist/{usePublicRouteParams-G3Ks53mk.d.ts → usePublicRouteParams-BgV6VhMi.d.ts} +73 -4
- package/dist/utils.d.ts +163 -145
- package/dist/utils.js +42 -25
- package/docs/api/modules.md +782 -643
- package/docs/api-reference/rpc-functions.md +12 -3
- package/docs/core-concepts/rbac-system.md +8 -0
- package/docs/getting-started/cursor-rules.md +17 -20
- package/docs/getting-started/dependencies.md +1 -1
- package/docs/getting-started/setup.md +235 -0
- package/docs/implementation-guides/authentication.md +27 -0
- package/docs/implementation-guides/data-tables.md +176 -3
- package/docs/migration/ApiResult-migration.md +25 -0
- package/docs/rbac/api-reference.md +33 -31
- package/docs/standards/0-standards-overview.md +50 -15
- package/docs/standards/1-pace-core-compliance-standards.md +62 -57
- package/docs/standards/2-project-structure-standards.md +33 -16
- package/docs/standards/3-architecture-standards.md +41 -1
- package/docs/standards/4-code-quality-standards.md +26 -6
- package/docs/standards/5-styling-standards.md +35 -1
- package/docs/standards/6-security-rbac-standards.md +66 -0
- package/docs/standards/7-api-tech-stack-standards.md +25 -14
- package/docs/standards/8-testing-documentation-standards.md +31 -0
- package/docs/standards/9-operations-standards.md +19 -0
- package/docs/standards/README.md +20 -201
- package/docs/testing/test-setup-for-consumers.md +2 -0
- package/docs/troubleshooting/common-issues.md +17 -1
- package/docs/troubleshooting/organisation-context-setup.md +8 -0
- package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
- package/eslint-config-pace-core.cjs +20 -0
- package/package.json +14 -20
- package/scripts/{build-docs-incremental.js → build-docs.js} +3 -2
- package/scripts/setup.cjs +536 -0
- package/scripts/validate.cjs +480 -0
- package/src/__tests__/helpers/{__tests__/component-test-utils.test.tsx → component-test-utils.test.tsx} +3 -3
- package/src/__tests__/helpers/{__tests__/optimized-test-setup.test.ts → optimized-test-setup.test.ts} +2 -2
- package/src/__tests__/helpers/{__tests__/supabaseMock.test.ts → supabaseMock.test.ts} +2 -2
- package/src/__tests__/helpers/{__tests__/test-providers.test.tsx → test-providers.test.tsx} +1 -1
- package/src/__tests__/helpers/test-providers.tsx +37 -39
- package/src/__tests__/helpers/{__tests__/test-utils.test.tsx → test-utils.test.tsx} +4 -3
- package/src/__tests__/helpers/{__tests__/timer-utils.test.ts → timer-utils.test.ts} +2 -2
- package/src/assets/app-icons/index.test.ts +304 -0
- package/src/components/AddressField/AddressField.test.tsx +1 -1
- package/src/components/AddressField/AddressField.tsx +238 -212
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Card/Card.test.tsx +172 -17
- package/src/components/Card/Card.tsx +19 -10
- package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
- package/src/components/ContextSelector/{__tests__/ContextSelector.test.tsx → ContextSelector.test.tsx} +6 -6
- package/src/components/ContextSelector/ContextSelector.tsx +66 -280
- package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
- package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
- package/src/components/DataTable/AUDIT_REPORT.md +59 -44
- package/src/components/DataTable/{__tests__/DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/DataTable.default-state.test.tsx → DataTable.default-state.test.tsx} +5 -5
- package/src/components/DataTable/{__tests__/DataTable.export.test.tsx → DataTable.export.test.tsx} +10 -10
- package/src/components/DataTable/{__tests__/DataTable.grouping-aggregation.test.tsx → DataTable.grouping-aggregation.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/DataTable.hooks.test.tsx → DataTable.hooks.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/DataTable.select-label-display.test.tsx → DataTable.select-label-display.test.tsx} +6 -6
- package/src/components/DataTable/DataTable.test.tsx +787 -416
- package/src/components/DataTable/DataTable.tsx +12 -12
- package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
- package/src/components/DataTable/{__tests__/DataTableCore.test-setup.ts → DataTableCore.test-setup.ts} +10 -9
- package/src/components/DataTable/{__tests__/DataTableCore.test.tsx → DataTableCore.test.tsx} +8 -8
- package/src/components/DataTable/{__tests__/README.md → README.md} +17 -7
- package/src/components/DataTable/TESTING.md +101 -0
- package/src/components/DataTable/{__tests__/a11y.basic.test.tsx → a11y.basic.test.tsx} +34 -34
- package/src/components/DataTable/components/DataTableCore.tsx +104 -864
- package/src/components/DataTable/components/{__tests__/GroupingDropdown.test.tsx → GroupingDropdown.test.tsx} +17 -8
- package/src/components/DataTable/components/GroupingDropdown.tsx +2 -2
- package/src/components/DataTable/components/ImportModal.tsx +61 -559
- package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
- package/src/components/DataTable/context/{__tests__/DataTableContext.test.tsx → DataTableContext.test.tsx} +2 -2
- package/src/components/DataTable/context/DataTableContext.tsx +7 -6
- package/src/components/DataTable/core/{__tests__/ColumnFactory.test.ts → ColumnFactory.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useColumnOrderPersistence.test.ts → useColumnOrderPersistence.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useColumnVisibilityPersistence.test.ts → useColumnVisibilityPersistence.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useDataTableConfiguration.test.ts → useDataTableConfiguration.test.ts} +3 -3
- package/src/components/DataTable/hooks/useDataTableConfiguration.ts +14 -2
- package/src/components/DataTable/hooks/{__tests__/useDataTableDataPipeline.test.ts → useDataTableDataPipeline.test.ts} +6 -6
- package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
- package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
- package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
- package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
- package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
- package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
- package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
- package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
- package/src/components/DataTable/hooks/{__tests__/useDataTablePermissions.test.ts → useDataTablePermissions.test.ts} +11 -11
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +79 -247
- package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
- package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
- package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
- package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
- package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
- package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
- package/src/components/DataTable/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +47 -5
- package/src/components/DataTable/hooks/useDataTableState.ts +145 -94
- package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
- package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
- package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
- package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
- package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
- package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
- package/src/components/DataTable/hooks/{__tests__/useEffectiveColumnOrder.test.ts → useEffectiveColumnOrder.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useHierarchicalState.test.ts → useHierarchicalState.test.ts} +2 -2
- package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.test.ts +3 -3
- package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.ts +2 -2
- package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
- package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
- package/src/components/DataTable/hooks/{__tests__/useKeyboardNavigation.test.ts → useKeyboardNavigation.test.ts} +3 -3
- package/src/components/DataTable/hooks/useKeyboardNavigation.ts +309 -269
- package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.test.ts +3 -3
- package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.ts +3 -3
- package/src/components/DataTable/hooks/{__tests__/useServerSideDataEffect.test.ts → useServerSideDataEffect.test.ts} +2 -2
- package/src/components/DataTable/hooks/useServerSideDataEffect.ts +14 -3
- package/src/components/DataTable/hooks/{__tests__/useTableColumns.test.ts → useTableColumns.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useTableHandlers.test.ts → useTableHandlers.test.ts} +25 -4
- package/src/components/DataTable/hooks/useTableHandlers.ts +5 -2
- package/src/components/DataTable/index.ts +18 -17
- package/src/components/DataTable/{__tests__/keyboard.test.tsx → keyboard.test.tsx} +41 -63
- package/src/components/DataTable/{__tests__/mocks → mocks}/MockRBACProvider.tsx +1 -1
- package/src/components/DataTable/{__tests__/pagination.modes.test.tsx → pagination.modes.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/ssr.strict-mode.test.tsx → ssr.strict-mode.test.tsx} +2 -2
- package/src/components/DataTable/{__tests__/styles.test.ts → styles.test.ts} +1 -4
- package/src/components/DataTable/styles.ts +0 -1
- package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
- package/src/components/DataTable/{__tests__/test-utils → test-utils}/dataFactories.ts +2 -2
- package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
- package/src/components/DataTable/{__tests__/test-utils/sharedTestUtils.tsx → test-utils/sharedTestUtils.ts} +97 -66
- package/src/components/DataTable/{__tests__/test-utils.ts → test-utils.ts} +1 -1
- package/src/components/DataTable/types/actions.ts +71 -0
- package/src/components/DataTable/types/base.ts +39 -0
- package/src/components/DataTable/types/columns.ts +125 -0
- package/src/components/DataTable/types/export.ts +32 -0
- package/src/components/DataTable/types/features.ts +81 -0
- package/src/components/DataTable/types/hierarchical.ts +44 -0
- package/src/components/DataTable/types/index.ts +43 -0
- package/src/components/DataTable/types/pagination.ts +85 -0
- package/src/components/DataTable/types/performance.ts +47 -0
- package/src/components/DataTable/types/props.ts +62 -0
- package/src/components/DataTable/types/rbac.ts +45 -0
- package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableCore.test.tsx +430 -28
- package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
- package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableErrorBoundary.test.tsx +4 -4
- package/src/components/DataTable/{components → ui/layout}/DataTableErrorBoundary.tsx +7 -7
- package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
- package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
- package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
- package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
- package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
- package/src/components/DataTable/{components → ui/modals}/DataTableModals.tsx +36 -28
- package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
- package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
- package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
- package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
- package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
- package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
- package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
- package/src/components/DataTable/{components/__tests__ → ui/shared}/AccessDeniedPage.test.tsx +2 -2
- package/src/components/DataTable/{components → ui/shared}/AccessDeniedPage.tsx +2 -2
- package/src/components/DataTable/{components/__tests__ → ui/shared}/ActionButtons.test.tsx +6 -4
- package/src/components/DataTable/{components → ui/shared}/ActionButtons.tsx +4 -4
- package/src/components/DataTable/{components/__tests__ → ui/shared}/ColumnFilter.test.tsx +29 -16
- package/src/components/DataTable/{components → ui/shared}/ColumnFilter.tsx +4 -4
- package/src/components/DataTable/{components/__tests__ → ui/shared}/PaginationControls.test.tsx +38 -16
- package/src/components/DataTable/{components → ui/shared}/PaginationControls.tsx +21 -15
- package/src/components/DataTable/{components/__tests__ → ui/shared}/SortIndicator.test.tsx +2 -2
- package/src/components/DataTable/{components → ui/shared}/SortIndicator.tsx +1 -1
- package/src/components/DataTable/{components/__tests__ → ui/table}/EditFields.test.tsx +3 -3
- package/src/components/DataTable/{components → ui/table}/EditFields.tsx +138 -69
- package/src/components/DataTable/{components/__tests__ → ui/table}/EditableRow.test.tsx +36 -27
- package/src/components/DataTable/{components → ui/table}/EditableRow.tsx +86 -104
- package/src/components/DataTable/{components/__tests__ → ui/table}/EmptyState.test.tsx +2 -62
- package/src/components/DataTable/{components → ui/table}/EmptyState.tsx +7 -15
- package/src/components/DataTable/{components/__tests__ → ui/table}/FilterRow.test.tsx +5 -4
- package/src/components/DataTable/{components → ui/table}/FilterRow.tsx +3 -3
- package/src/components/DataTable/{components/__tests__ → ui/table}/LoadingState.test.tsx +6 -10
- package/src/components/DataTable/{components → ui/table}/LoadingState.tsx +4 -4
- package/src/components/DataTable/{components/__tests__ → ui/table}/RowComponent.test.tsx +412 -17
- package/src/components/DataTable/{components → ui/table}/RowComponent.tsx +183 -177
- package/src/components/DataTable/{components/__tests__ → ui/table}/UnifiedTableBody.test.tsx +425 -16
- package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
- package/src/components/DataTable/{components/__tests__ → ui/table}/cellValueUtils.test.ts +2 -2
- package/src/components/DataTable/{components → ui/table}/cellValueUtils.ts +1 -1
- package/src/components/DataTable/{components/__tests__ → ui/toolbar}/BulkOperationsDropdown.test.tsx +12 -5
- package/src/components/DataTable/{components → ui/toolbar}/BulkOperationsDropdown.tsx +3 -3
- package/src/components/DataTable/{components/__tests__ → ui/toolbar}/ColumnVisibilityDropdown.test.tsx +7 -4
- package/src/components/DataTable/{components → ui/toolbar}/ColumnVisibilityDropdown.tsx +7 -7
- package/src/components/DataTable/{components/__tests__ → ui/toolbar}/DataTableToolbar.test.tsx +4 -4
- package/src/components/DataTable/{components → ui/toolbar}/DataTableToolbar.tsx +4 -4
- package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
- package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
- package/src/components/DataTable/utils/{__tests__/a11yUtils.test.ts → a11yUtils.test.ts} +2 -2
- package/src/components/DataTable/utils/{__tests__/aggregationUtils.test.ts → aggregationUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/columnUtils.test.ts → columnUtils.test.ts} +2 -2
- package/src/components/DataTable/utils/csvParse.test.ts +74 -0
- package/src/components/DataTable/utils/csvParse.ts +65 -0
- package/src/components/DataTable/utils/{__tests__/errorHandling.test.ts → errorHandling.test.ts} +2 -2
- package/src/components/DataTable/utils/{__tests__/exportUtils.test.ts → exportUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/flexibleImport.test.ts → flexibleImport.test.ts} +2 -2
- package/src/components/DataTable/utils/flexibleImport.ts +3 -186
- package/src/components/DataTable/utils/{__tests__/hierarchicalSorting.test.ts → hierarchicalSorting.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/hierarchicalUtils.test.ts → hierarchicalUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
- package/src/components/DataTable/utils/importDateParser.ts +114 -0
- package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
- package/src/components/DataTable/utils/importValueParser.ts +91 -0
- package/src/components/DataTable/utils/{__tests__/paginationUtils.test.ts → paginationUtils.test.ts} +2 -2
- package/src/components/DataTable/utils/paginationUtils.ts +6 -3
- package/src/components/DataTable/utils/{__tests__/performanceUtils.test.ts → performanceUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/rowUtils.test.ts → rowUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/selectFieldUtils.test.ts → selectFieldUtils.test.ts} +66 -3
- package/src/components/DataTable/utils/selectFieldUtils.ts +97 -60
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
- package/src/components/DateTimeField/DateTimeField.test.tsx +1 -1
- package/src/components/Dialog/Dialog.test-utils.ts +49 -0
- package/src/components/Dialog/Dialog.test.tsx +896 -89
- package/src/components/Dialog/Dialog.tsx +174 -882
- package/src/components/Dialog/dialogLock.test.ts +238 -0
- package/src/components/Dialog/dialogLock.ts +98 -0
- package/src/components/Dialog/index.ts +2 -0
- package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
- package/src/components/Dialog/useDialogDimensions.ts +140 -0
- package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
- package/src/components/Dialog/useDialogLifecycle.ts +135 -0
- package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
- package/src/components/Dialog/useDialogPersistence.ts +357 -0
- package/src/components/FileDisplay/FileDisplay.test.tsx +40 -40
- package/src/components/FileDisplay/FileDisplay.tsx +24 -656
- package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
- package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
- package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
- package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
- package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
- package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
- package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
- package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
- package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
- package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
- package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
- package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
- package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
- package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
- package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
- package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
- package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
- package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
- package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
- package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
- package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
- package/src/components/FileDisplay/fallbackUtils.ts +44 -0
- package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
- package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
- package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
- package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
- package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.test.ts +40 -42
- package/src/components/FileDisplay/useFileDisplay.ts +515 -0
- package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.unit.test.ts +406 -77
- package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
- package/src/{hooks/public → components/FileDisplay}/usePublicFileDisplay.test.ts +94 -88
- package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
- package/src/components/FileUpload/FileUpload.test.tsx +16 -10
- package/src/components/FileUpload/FileUpload.tsx +107 -525
- package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
- package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
- package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
- package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
- package/src/components/FileUpload/useFileUploadManager.ts +454 -0
- package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
- package/src/components/FileUpload/useResolvedAppId.ts +77 -0
- package/src/components/Footer/Footer.test.tsx +6 -292
- package/src/components/Footer/Footer.tsx +8 -125
- package/src/components/Form/Form.test.tsx +44 -27
- package/src/components/Form/Form.tsx +64 -287
- package/src/components/Form/useFormPersistence.ts +257 -0
- package/src/components/Header/Header.test.tsx +17 -18
- package/src/components/Header/Header.tsx +10 -1
- package/src/components/Input/Input.tsx +1 -1
- package/src/components/Label/Label.test.tsx +1 -1
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +1 -1
- package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +1029 -26
- package/src/components/NavigationMenu/NavigationMenu.tsx +61 -361
- package/src/components/NavigationMenu/index.ts +6 -1
- package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
- package/src/components/NavigationMenu/{__tests__/useNavigationFiltering.test.ts → useNavigationFiltering.test.ts} +68 -53
- package/src/components/NavigationMenu/useNavigationFiltering.ts +197 -296
- package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
- package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +77 -62
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +3 -3
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +16 -19
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +529 -5
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +280 -756
- package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
- package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
- package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +31 -25
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +31 -122
- package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
- package/src/components/Progress/Progress.tsx +1 -2
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -235
- package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
- package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
- package/src/components/PublicLayout/PublicLayout.test.tsx +217 -36
- package/src/components/PublicLayout/PublicPageLayout.tsx +132 -73
- package/src/components/PublicLayout/PublicPageProvider.tsx +5 -1
- package/src/components/Select/Select.test.tsx +1 -1
- package/src/components/Select/Select.tsx +28 -18
- package/src/components/Select/{__tests__/context.test.tsx → context.test.tsx} +3 -3
- package/src/components/Select/{utils/__tests__/text.test.tsx → text.test.tsx} +2 -2
- package/src/components/Select/{utils/text.ts → text.ts} +1 -1
- package/src/components/Select/{hooks/__tests__/useSelectEvents.test.ts → useSelectEvents.test.ts} +5 -5
- package/src/components/Select/{hooks/useSelectEvents.ts → useSelectEvents.ts} +2 -2
- package/src/components/Select/{hooks/__tests__/useSelectSearch.test.tsx → useSelectSearch.test.tsx} +7 -7
- package/src/components/Select/{hooks/useSelectSearch.ts → useSelectSearch.ts} +2 -2
- package/src/components/Select/{hooks/__tests__/useSelectState.test.ts → useSelectState.test.ts} +16 -2
- package/src/components/Select/{hooks/useSelectState.ts → useSelectState.ts} +3 -3
- package/src/components/Table/Table.test.tsx +348 -0
- package/src/components/Tabs/Tabs.test.tsx +270 -0
- package/src/components/Tabs/Tabs.tsx +1 -1
- package/src/components/Toast/Toast.test.tsx +420 -0
- package/src/components/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/constants/{__tests__/performance.test.ts → performance.test.ts} +2 -2
- package/src/hooks/{__tests__/ServiceHooks.test.tsx → ServiceHooks.test.tsx} +8 -8
- package/src/hooks/{__tests__/hooks.integration.test.tsx → hooks.integration.test.tsx} +11 -11
- package/src/hooks/index.ts +7 -4
- package/src/hooks/{__tests__/index.unit.test.ts → index.unit.test.ts} +2 -2
- package/src/hooks/public/usePublicEvent.test.ts +1 -1
- package/src/hooks/public/usePublicEventLogo.test.ts +1 -1
- package/src/hooks/public/usePublicRouteParams.test.ts +1 -1
- package/src/hooks/services/useAuth.ts +9 -7
- package/src/hooks/useAddressAutocomplete.test.ts +22 -22
- package/src/hooks/useAddressAutocomplete.ts +90 -75
- package/src/hooks/{__tests__/useAppConfig.unit.test.ts → useAppConfig.unit.test.ts} +328 -22
- package/src/hooks/{__tests__/useComponentPerformance.unit.test.tsx → useComponentPerformance.unit.test.tsx} +27 -41
- package/src/hooks/useDataTablePerformance.ts +100 -120
- package/src/hooks/{__tests__/useDataTablePerformance.unit.test.ts → useDataTablePerformance.unit.test.ts} +5 -5
- package/src/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +2 -2
- package/src/hooks/{__tests__/useDebounce.unit.test.ts → useDebounce.unit.test.ts} +2 -2
- package/src/hooks/useEventTheme.test.ts +4 -1
- package/src/hooks/useEventTheme.ts +49 -21
- package/src/hooks/useEvents.ts +41 -1
- package/src/hooks/{__tests__/useEvents.unit.test.ts → useEvents.unit.test.ts} +5 -5
- package/src/hooks/useFileReference.test.ts +44 -41
- package/src/hooks/useFileReference.ts +182 -173
- package/src/hooks/useFileUrl.ts +1 -1
- package/src/hooks/{__tests__/useFileUrl.unit.test.ts → useFileUrl.unit.test.ts} +26 -36
- package/src/hooks/{__tests__/useFileUrlCache.test.ts → useFileUrlCache.test.ts} +8 -8
- package/src/hooks/useFileUrlCache.ts +1 -1
- package/src/hooks/{__tests__/useFocusManagement.unit.test.ts → useFocusManagement.unit.test.ts} +2 -2
- package/src/hooks/{__tests__/useFocusTrap.unit.test.tsx → useFocusTrap.unit.test.tsx} +2 -2
- package/src/hooks/{__tests__/useFormDialog.test.ts → useFormDialog.test.ts} +2 -2
- package/src/hooks/useInactivityTracker.ts +138 -131
- package/src/hooks/{__tests__/useInactivityTracker.unit.test.ts → useInactivityTracker.unit.test.ts} +3 -3
- package/src/hooks/{__tests__/useIsMobile.unit.test.ts → useIsMobile.unit.test.ts} +2 -2
- package/src/hooks/useIsPrint.ts +62 -0
- package/src/hooks/useIsPrint.unit.test.ts +545 -0
- package/src/hooks/{__tests__/useKeyboardShortcuts.unit.test.ts → useKeyboardShortcuts.unit.test.ts} +2 -2
- package/src/hooks/{__tests__/useOrganisationPermissions.unit.test.tsx → useOrganisationPermissions.unit.test.tsx} +4 -4
- package/src/hooks/useOrganisationSecurity.test.ts +3 -3
- package/src/hooks/useOrganisationSecurity.ts +190 -201
- package/src/hooks/{__tests__/useOrganisationSecurity.unit.test.tsx → useOrganisationSecurity.unit.test.tsx} +61 -63
- package/src/hooks/{__tests__/useOrganisations.unit.test.ts → useOrganisations.unit.test.ts} +5 -5
- package/src/hooks/{__tests__/usePerformanceMonitor.unit.test.ts → usePerformanceMonitor.unit.test.ts} +13 -14
- package/src/hooks/{__tests__/usePermissionCache.test.ts → usePermissionCache.test.ts} +26 -27
- package/src/hooks/usePermissionCache.ts +276 -271
- package/src/hooks/{__tests__/usePreventTabReload.test.ts → usePreventTabReload.test.ts} +2 -2
- package/src/hooks/{__tests__/usePublicEvent.simple.test.ts → usePublicEvent.simple.test.ts} +4 -4
- package/src/hooks/{__tests__/usePublicEvent.test.ts → usePublicEvent.test.ts} +4 -4
- package/src/hooks/{__tests__/usePublicEvent.unit.test.ts → usePublicEvent.unit.test.ts} +4 -4
- package/src/hooks/{__tests__/usePublicFileDisplay.test.ts → usePublicFileDisplay.test.ts} +12 -12
- package/src/hooks/{__tests__/usePublicRouteParams.unit.test.ts → usePublicRouteParams.unit.test.ts} +3 -3
- package/src/hooks/{__tests__/useQueryCache.test.ts → useQueryCache.test.ts} +2 -2
- package/src/hooks/useQueryCache.ts +0 -2
- package/src/hooks/{__tests__/useRBAC.unit.test.ts → useRBAC.unit.test.ts} +55 -38
- package/src/hooks/{__tests__/useSessionDraft.test.ts → useSessionDraft.test.ts} +2 -2
- package/src/hooks/{__tests__/useSessionRestoration.unit.test.tsx → useSessionRestoration.unit.test.tsx} +10 -19
- package/src/hooks/useStorage.ts +21 -16
- package/src/hooks/{__tests__/useStorage.unit.test.ts → useStorage.unit.test.ts} +38 -75
- package/src/hooks/{__tests__/useToast.test.ts → useToast.test.ts} +2 -2
- package/src/hooks/{__tests__/useToast.unit.test.tsx → useToast.unit.test.tsx} +2 -2
- package/src/hooks/{__tests__/useZodForm.unit.test.tsx → useZodForm.unit.test.tsx} +2 -2
- package/src/icons/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/icons/index.ts +2 -0
- package/src/{__tests__/index.test.ts → index.test.ts} +3 -7
- package/src/index.ts +15 -7
- package/src/providers/{__tests__/AuthProvider.test.tsx → AuthProvider.test.tsx} +3 -3
- package/src/providers/{__tests__/EventProvider.test.tsx → EventProvider.test.tsx} +3 -3
- package/src/providers/InactivityProvider.test-helper.tsx +40 -0
- package/src/providers/{__tests__/InactivityProvider.test.tsx → InactivityProvider.test.tsx} +14 -21
- package/src/providers/{__tests__/ProviderLifecycle.test.tsx → ProviderLifecycle.test.tsx} +4 -4
- package/src/providers/{__tests__/UnifiedAuthProvider.test.tsx → UnifiedAuthProvider.test.tsx} +1 -1
- package/src/providers/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/providers/services/{__tests__/AuthServiceProvider.integration.test.tsx → AuthServiceProvider.integration.test.tsx} +4 -4
- package/src/providers/services/{__tests__/AuthServiceProvider.test.tsx → AuthServiceProvider.test.tsx} +7 -7
- package/src/providers/services/{__tests__/EventServiceProvider.test.tsx → EventServiceProvider.test.tsx} +7 -7
- package/src/providers/services/{__tests__/InactivityServiceProvider.test.tsx → InactivityServiceProvider.test.tsx} +5 -5
- package/src/providers/services/{__tests__/OrganisationServiceProvider.test.tsx → OrganisationServiceProvider.test.tsx} +6 -6
- package/src/providers/services/UnifiedAuthContext.ts +30 -27
- package/src/providers/services/{__tests__/UnifiedAuthProvider.advanced.test.tsx → UnifiedAuthProvider.advanced.test.tsx} +8 -9
- package/src/providers/services/{__tests__/UnifiedAuthProvider.appId.test.tsx → UnifiedAuthProvider.appId.test.tsx} +25 -25
- package/src/providers/services/{__tests__/UnifiedAuthProvider.integration.test.tsx → UnifiedAuthProvider.integration.test.tsx} +14 -11
- package/src/providers/services/UnifiedAuthProvider.tsx +115 -360
- package/src/providers/services/{__tests__/contexts.test.tsx → contexts.test.tsx} +6 -6
- package/src/providers/services/{__tests__/useUnifiedAuth.test.tsx → useUnifiedAuth.test.tsx} +6 -6
- package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
- package/src/providers/useInactivity.test-helper.ts +27 -0
- package/src/rbac/{__tests__/adapters.comprehensive.test.tsx → adapters.comprehensive.test.tsx} +24 -24
- package/src/rbac/adapters.test.tsx +22 -22
- package/src/rbac/adapters.tsx +29 -29
- package/src/rbac/api.test.ts +973 -42
- package/src/rbac/api.ts +228 -253
- package/src/rbac/{__tests__/audit-batched.test.ts → audit-batched.test.ts} +6 -6
- package/src/rbac/audit.ts +4 -1
- package/src/rbac/{__tests__/auth-rbac-security.integration.test.tsx → auth-rbac-security.integration.test.tsx} +1 -1
- package/src/rbac/{__tests__/auth-rbac.e2e.test.tsx → auth-rbac.e2e.test.tsx} +27 -34
- package/src/rbac/cache-invalidation.test.ts +715 -0
- package/src/rbac/components/{__tests__/AccessDenied.test.tsx → AccessDenied.test.tsx} +3 -3
- package/src/rbac/components/{__tests__/NavigationGuard.test.tsx → NavigationGuard.test.tsx} +13 -11
- package/src/{__tests__/rbac/PagePermissionGuard.test.tsx → rbac/components/PagePermissionGuard.guard.test.tsx} +33 -19
- package/src/rbac/components/{__tests__/PagePermissionGuard.performance.test.tsx → PagePermissionGuard.performance.test.tsx} +30 -9
- package/src/rbac/components/{__tests__/PagePermissionGuard.race-condition.test.tsx → PagePermissionGuard.race-condition.test.tsx} +7 -7
- package/src/rbac/components/{__tests__/PagePermissionGuard.test.tsx → PagePermissionGuard.test.tsx} +10 -10
- package/src/rbac/components/PagePermissionGuard.tsx +177 -372
- package/src/rbac/components/{__tests__/PagePermissionGuard.verification.test.tsx → PagePermissionGuard.verification.test.tsx} +7 -7
- package/src/rbac/config.ts +58 -18
- package/src/rbac/{__tests__/engine.comprehensive.test.ts → engine.comprehensive.test.ts} +3 -3
- package/src/rbac/engine.test.ts +494 -0
- package/src/rbac/errors.ts +89 -55
- package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
- package/src/rbac/hooks/permissions/{__tests__/useAccessLevel.test.ts → useAccessLevel.test.ts} +40 -40
- package/src/rbac/hooks/permissions/useAccessLevel.ts +16 -6
- package/src/rbac/hooks/permissions/{__tests__/useCan.test.ts → useCan.test.ts} +41 -41
- package/src/rbac/hooks/permissions/useCan.ts +170 -252
- package/src/rbac/hooks/permissions/{__tests__/useMultiplePermissions.test.ts → useMultiplePermissions.test.ts} +49 -49
- package/src/rbac/hooks/permissions/useMultiplePermissions.ts +6 -2
- package/src/rbac/hooks/permissions/{__tests__/usePermissions.test.ts → usePermissions.test.ts} +10 -12
- package/src/rbac/hooks/permissions/usePermissions.ts +36 -65
- package/src/rbac/hooks/useCan.test.ts +42 -42
- package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
- package/src/rbac/hooks/usePageGuardScope.ts +117 -0
- package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
- package/src/rbac/hooks/{__tests__/usePermissions.integration.test.ts → usePermissions.integration.test.ts} +9 -9
- package/src/{__tests__/hooks/usePermissions.test.ts → rbac/hooks/usePermissions.stability.test.ts} +18 -18
- package/src/rbac/hooks/usePermissions.test.ts +54 -54
- package/src/rbac/hooks/useRBAC.test.ts +313 -217
- package/src/rbac/hooks/useRBAC.ts +145 -81
- package/src/rbac/hooks/useResourcePermissions.test.ts +25 -25
- package/src/rbac/hooks/useResourcePermissions.ts +68 -134
- package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
- package/src/rbac/hooks/useRoleManagement.test.ts +27 -112
- package/src/rbac/hooks/useRoleManagement.ts +153 -585
- package/src/rbac/hooks/{__tests__/useSecureSupabase.test.ts → useSecureSupabase.test.ts} +17 -17
- package/src/rbac/hooks/useSecureSupabase.ts +10 -2
- package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
- package/src/rbac/{__tests__/performance.test.ts → performance.test.ts} +1 -1
- package/src/rbac/{__tests__/rbac-core.test.tsx → rbac-core.test.tsx} +3 -3
- package/src/rbac/{__tests__/rbac-engine-core-logic.test.ts → rbac-engine-core-logic.test.ts} +2 -2
- package/src/rbac/{__tests__/rbac-engine-simplified.test.ts → rbac-engine-simplified.test.ts} +3 -3
- package/src/rbac/{__tests__/rbac-functions.test.ts → rbac-functions.test.ts} +57 -0
- package/src/rbac/{__tests__/rbac-role-isolation.test.ts → rbac-role-isolation.test.ts} +2 -2
- package/src/rbac/request-deduplication.test.ts +14 -9
- package/src/rbac/request-deduplication.ts +5 -4
- package/src/rbac/{__tests__/scenarios.user-role.test.tsx → scenarios.user-role.test.tsx} +23 -23
- package/src/rbac/secureClient.test.ts +514 -83
- package/src/rbac/secureClient.ts +8 -2
- package/src/rbac/security.test.ts +323 -0
- package/src/rbac/types/roleManagement.ts +66 -0
- package/src/rbac/utils/{__tests__/clientSecurity.test.ts → clientSecurity.test.ts} +4 -4
- package/src/rbac/utils/{__tests__/contextValidator.test.ts → contextValidator.test.ts} +4 -4
- package/src/rbac/utils/contextValidator.ts +5 -1
- package/src/rbac/utils/{__tests__/deep-equal.test.ts → deep-equal.test.ts} +1 -1
- package/src/rbac/utils/{__tests__/eventContext.test.ts → eventContext.test.ts} +36 -21
- package/src/rbac/utils/eventContext.ts +37 -33
- package/src/rbac/utils/fetchPermissionMap.ts +13 -0
- package/src/rbac/utils/permissionMapHelpers.ts +34 -0
- package/src/rbac/utils/roleManagementRpc.ts +303 -0
- package/src/services/{__tests__/AuthService.edge-cases.test.ts → AuthService.edge-cases.test.ts} +19 -19
- package/src/services/{__tests__/AuthService.restoreSession.test.ts → AuthService.restoreSession.test.ts} +2 -2
- package/src/services/{__tests__/AuthService.test.ts → AuthService.test.ts} +89 -55
- package/src/services/AuthService.ts +184 -205
- package/src/services/{__tests__/BaseService.edge-cases.test.ts → BaseService.edge-cases.test.ts} +3 -3
- package/src/services/{__tests__/BaseService.test.ts → BaseService.test.ts} +2 -2
- package/src/services/{__tests__/EventService.edge-cases.test.ts → EventService.edge-cases.test.ts} +27 -24
- package/src/services/{__tests__/EventService.eventColours.test.ts → EventService.eventColours.test.ts} +1 -1
- package/src/services/{__tests__/EventService.test.ts → EventService.test.ts} +256 -24
- package/src/services/EventService.ts +242 -312
- package/src/services/{__tests__/InactivityService.edge-cases.test.ts → InactivityService.edge-cases.test.ts} +3 -3
- package/src/services/{__tests__/InactivityService.lifecycle.test.ts → InactivityService.lifecycle.test.ts} +2 -2
- package/src/services/{__tests__/InactivityService.test.ts → InactivityService.test.ts} +179 -4
- package/src/services/InactivityService.ts +172 -213
- package/src/services/{__tests__/OrganisationService.edge-cases.test.ts → OrganisationService.edge-cases.test.ts} +5 -5
- package/src/services/{__tests__/OrganisationService.pagination.test.ts → OrganisationService.pagination.test.ts} +4 -4
- package/src/services/{__tests__/OrganisationService.test.ts → OrganisationService.test.ts} +410 -7
- package/src/services/OrganisationService.ts +184 -238
- package/src/services/base/BaseService.test.ts +1 -1
- package/src/services/interfaces/{__tests__/IAuthService.test.ts → IAuthService.test.ts} +21 -27
- package/src/services/interfaces/IAuthService.ts +10 -9
- package/src/services/interfaces/{__tests__/IEventService.test.ts → IEventService.test.ts} +4 -4
- package/src/services/interfaces/{__tests__/IInactivityService.test.ts → IInactivityService.test.ts} +3 -3
- package/src/services/interfaces/{__tests__/IOrganisationService.test.ts → IOrganisationService.test.ts} +3 -3
- package/src/styles/core.css +243 -12
- package/src/theming/{__tests__/parseEventColours.test.ts → parseEventColours.test.ts} +1 -1
- package/src/theming/{__tests__/runtime.test.ts → runtime.test.ts} +8 -17
- package/src/theming/runtime.ts +71 -2
- package/src/types/api-result.ts +53 -0
- package/src/types/{__tests__/core.test.ts → core.test.ts} +2 -2
- package/src/types/{__tests__/database-generated.test.ts → database-generated.test.ts} +3 -3
- package/src/types/database.generated.ts +45 -10
- package/src/types/event.ts +38 -18
- package/src/types/{__tests__/file-reference.test.ts → file-reference.test.ts} +13 -13
- package/src/types/file-reference.ts +37 -12
- package/src/types/{__tests__/guards.test.ts → guards.test.ts} +2 -2
- package/src/types/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/types/index.ts +3 -0
- package/src/types/{__tests__/organisation.roles.test.ts → organisation.roles.test.ts} +1 -1
- package/src/types/{__tests__/organisation.test.ts → organisation.test.ts} +3 -31
- package/src/types/organisation.ts +15 -15
- package/src/types/supabase.ts +13 -4
- package/src/types/{__tests__/theme.test.ts → theme.test.ts} +1 -1
- package/src/types/{__tests__/type-validation.test.ts → type-validation.test.ts} +1 -1
- package/src/types/{__tests__/validation.test.ts → validation.test.ts} +2 -2
- package/src/utils/app/appIdResolver.test.ts +98 -71
- package/src/utils/app/appIdResolver.ts +31 -20
- package/src/utils/{__tests__/appConfig.unit.test.ts → appConfig.unit.test.ts} +1 -1
- package/src/utils/{__tests__/audit.unit.test.ts → audit.unit.test.ts} +1 -1
- package/src/utils/{__tests__/auth-utils.unit.test.ts → auth-utils.unit.test.ts} +16 -17
- package/src/utils/{__tests__/bundleAnalysis.unit.test.ts → bundleAnalysis.unit.test.ts} +35 -35
- package/src/utils/{__tests__/cn.unit.test.ts → cn.unit.test.ts} +1 -1
- package/src/utils/context/organisationContext.test.ts +105 -91
- package/src/utils/context/organisationContext.ts +29 -40
- package/src/utils/core/{__tests__/cn.test.ts → cn.test.ts} +3 -3
- package/src/utils/core/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +2 -2
- package/src/utils/core/{__tests__/logger.test.ts → logger.test.ts} +2 -2
- package/src/utils/core/mergeRefs.ts +24 -0
- package/src/utils/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +1 -1
- package/src/utils/{__tests__/deviceFingerprint.unit.test.ts → deviceFingerprint.unit.test.ts} +1 -1
- package/src/utils/dynamic/createLazyComponent.tsx +9 -1
- package/src/utils/dynamic/{__tests__/dynamicUtils.test.ts → dynamicUtils.test.ts} +2 -2
- package/src/utils/dynamic/{__tests__/lazyLoad.test.tsx → lazyLoad.test.tsx} +2 -2
- package/src/utils/{__tests__/dynamicUtils.unit.test.ts → dynamicUtils.unit.test.ts} +1 -1
- package/src/utils/file-reference/{__tests__/file-reference.test.ts → file-reference.test.ts} +214 -289
- package/src/utils/file-reference/index.ts +330 -347
- package/src/utils/{__tests__/formatDate.unit.test.ts → formatDate.unit.test.ts} +2 -2
- package/src/utils/formatting/formatDateTimeTimezone.test.ts +1 -1
- package/src/utils/formatting/formatNumber.test.ts +1 -1
- package/src/utils/{__tests__/formatting.unit.test.ts → formatting.unit.test.ts} +1 -1
- package/src/utils/google-places/googlePlacesUtils.test.ts +70 -48
- package/src/utils/google-places/googlePlacesUtils.ts +67 -99
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +25 -22
- package/src/utils/google-places/loadGoogleMapsScript.ts +138 -117
- package/src/utils/{__tests__/index.unit.test.ts → index.unit.test.ts} +1 -1
- package/src/utils/{__tests__/lazyLoad.unit.test.tsx → lazyLoad.unit.test.tsx} +13 -14
- package/src/utils/location/location.test.ts +1 -1
- package/src/utils/{__tests__/logger.unit.test.ts → logger.unit.test.ts} +1 -1
- package/src/utils/{__tests__/organisationContext.unit.test.ts → organisationContext.unit.test.ts} +37 -48
- package/src/utils/performance/{__tests__/bundleAnalysis.test.ts → bundleAnalysis.test.ts} +2 -2
- package/src/utils/performance/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
- package/src/utils/performance/{__tests__/performanceBudgets.test.ts → performanceBudgets.test.ts} +2 -2
- package/src/utils/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
- package/src/utils/{__tests__/performanceBudgets.unit.test.ts → performanceBudgets.unit.test.ts} +2 -2
- package/src/utils/{__tests__/permissionTypes.unit.test.ts → permissionTypes.unit.test.ts} +1 -1
- package/src/utils/{__tests__/permissionUtils.unit.test.ts → permissionUtils.unit.test.ts} +1 -1
- package/src/utils/permissions/{__tests__/permissionTypes.test.ts → permissionTypes.test.ts} +2 -2
- package/src/utils/persistence/{__tests__/keyDerivation.test.ts → keyDerivation.test.ts} +2 -2
- package/src/utils/persistence/{__tests__/sensitiveFieldDetection.test.ts → sensitiveFieldDetection.test.ts} +2 -2
- package/src/utils/{__tests__/request-deduplication.test.ts → request-deduplication.test.ts} +2 -2
- package/src/utils/{__tests__/sanitization.unit.test.ts → sanitization.unit.test.ts} +1 -1
- package/src/utils/{__tests__/schemaUtils.unit.test.ts → schemaUtils.unit.test.ts} +1 -1
- package/src/utils/{__tests__/secureDataAccess.unit.test.ts → secureDataAccess.unit.test.ts} +2 -2
- package/src/utils/{__tests__/secureErrors.unit.test.ts → secureErrors.unit.test.ts} +4 -4
- package/src/utils/{__tests__/secureStorage.unit.test.ts → secureStorage.unit.test.ts} +1 -1
- package/src/utils/security/auth-utils.ts +34 -23
- package/src/utils/security/secureDataAccess.ts +241 -281
- package/src/utils/security/secureErrors.test.ts +1 -1
- package/src/utils/security/secureStorage.test.ts +1 -1
- package/src/utils/security/security.test.ts +25 -17
- package/src/utils/security/security.ts +15 -18
- package/src/utils/security/securityMonitor.test.ts +1 -1
- package/src/utils/{__tests__/security.unit.test.ts → security.unit.test.ts} +21 -15
- package/src/utils/{__tests__/securityMonitor.unit.test.ts → securityMonitor.unit.test.ts} +1 -1
- package/src/utils/{__tests__/sessionTracking.unit.test.ts → sessionTracking.unit.test.ts} +12 -12
- package/src/utils/storage/{__tests__/config.unit.test.ts → config.unit.test.ts} +2 -2
- package/src/utils/storage/helpers.test.ts +88 -102
- package/src/utils/storage/helpers.ts +173 -251
- package/src/utils/storage/{__tests__/index.unit.test.ts → index.unit.test.ts} +3 -3
- package/src/utils/storage/types.ts +7 -0
- package/src/utils/supabase/createBaseClient.test.ts +1 -1
- package/src/utils/timezone/timezone.test.ts +1 -1
- package/src/utils/{__tests__/timezone.test.ts → timezone.test.ts} +2 -2
- package/src/utils/validation/{__tests__/common.test.ts → common.test.ts} +2 -2
- package/src/utils/validation/{__tests__/csrf.test.ts → csrf.test.ts} +56 -28
- package/src/utils/validation/csrf.ts +42 -41
- package/src/utils/validation/{__tests__/htmlSanitization.unit.test.ts → htmlSanitization.unit.test.ts} +2 -2
- package/src/utils/validation/{__tests__/passwordSchema.test.ts → passwordSchema.test.ts} +2 -2
- package/src/utils/validation/{__tests__/schema.test.ts → schema.test.ts} +2 -2
- package/src/utils/validation/{__tests__/sqlInjectionProtection.test.ts → sqlInjectionProtection.test.ts} +2 -2
- package/src/utils/validation/{__tests__/user.test.ts → user.test.ts} +2 -2
- package/src/utils/validation/{__tests__/validation.test.ts → validation.test.ts} +2 -2
- package/src/utils/validation/{__tests__/validationUtils.test.ts → validationUtils.test.ts} +2 -2
- package/src/utils/{__tests__/validation.unit.test.ts → validation.unit.test.ts} +1 -1
- package/src/utils/{__tests__/validationUtils.unit.test.ts → validationUtils.unit.test.ts} +5 -2
- package/dist/UnifiedAuthProvider-BBD2PS3Q.js +0 -7
- package/dist/chunk-KPYQWGFQ.js +0 -183
- package/dist/types-D05dCGma.d.ts +0 -521
- package/scripts/eslint-audit.cjs +0 -222
- package/scripts/generate-docs.js +0 -157
- package/scripts/install-cursor-rules.cjs +0 -255
- package/scripts/install-eslint-config.cjs +0 -349
- package/scripts/setup-build-cache.js +0 -73
- package/scripts/validate-pre-publish.js +0 -145
- package/src/__tests__/integration/UserProfile.test.tsx +0 -124
- package/src/__tests__/public-recipe-view.test.ts +0 -228
- package/src/__tests__/rls-policies.test.ts +0 -472
- package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
- package/src/components/DataTable/components/DataTableLayout.tsx +0 -584
- package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -395
- package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +0 -467
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -358
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -957
- package/src/components/DataTable/core/ActionManager.ts +0 -235
- package/src/components/DataTable/core/ColumnManager.ts +0 -204
- package/src/components/DataTable/core/DataManager.ts +0 -190
- package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
- package/src/components/DataTable/core/PluginRegistry.ts +0 -229
- package/src/components/DataTable/core/StateManager.ts +0 -312
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -235
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -141
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -178
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -133
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -142
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -158
- package/src/components/DataTable/core/interfaces.ts +0 -338
- package/src/components/DataTable/types.ts +0 -764
- package/src/hooks/public/usePublicFileDisplay.ts +0 -534
- package/src/hooks/useFileDisplay.ts +0 -748
- package/src/providers/OrganisationProvider.test.tsx +0 -40
- package/src/providers/OrganisationProvider.tsx +0 -92
- package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
- package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -616
- package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +0 -591
- package/src/rbac/__tests__/cache-invalidation.test.ts +0 -393
- /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
- /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
- /package/src/hooks/{__tests__/useApiFetch.unit.test.ts → useApiFetch.unit.test.ts} +0 -0
- /package/src/providers/{__tests__/README.md → README.md} +0 -0
- /package/src/rbac/{__tests__/index.test.ts → index.test.ts} +0 -0
- /package/src/rbac/{__tests__/rbac-integration.test.ts → rbac-integration.test.ts} +0 -0
- /package/src/types/{__tests__/README.md → README.md} +0 -0
|
@@ -14,20 +14,20 @@ import { screen, waitFor, within } from '@testing-library/react';
|
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
16
16
|
import '@testing-library/jest-dom/vitest';
|
|
17
|
-
import {
|
|
18
|
-
Dialog,
|
|
19
|
-
DialogTrigger,
|
|
20
|
-
DialogContent,
|
|
21
|
-
DialogHeader,
|
|
22
|
-
DialogBody,
|
|
23
|
-
DialogFooter,
|
|
17
|
+
import {
|
|
18
|
+
Dialog,
|
|
19
|
+
DialogTrigger,
|
|
20
|
+
DialogContent,
|
|
21
|
+
DialogHeader,
|
|
22
|
+
DialogBody,
|
|
23
|
+
DialogFooter,
|
|
24
24
|
DialogClose,
|
|
25
25
|
DialogTitle,
|
|
26
|
-
DialogDescription
|
|
26
|
+
DialogDescription,
|
|
27
27
|
} from './Dialog';
|
|
28
28
|
import { renderWithProviders } from '../../__tests__/helpers/test-utils';
|
|
29
|
+
import { waitForDialog, setupDialogEnv } from './Dialog.test-utils';
|
|
29
30
|
|
|
30
|
-
// Mock logger - must define before other mocks
|
|
31
31
|
const mockLogger = {
|
|
32
32
|
debug: vi.fn(),
|
|
33
33
|
info: vi.fn(),
|
|
@@ -39,33 +39,6 @@ vi.mock('../../utils/core/logger', () => ({
|
|
|
39
39
|
createLogger: () => mockLogger,
|
|
40
40
|
}));
|
|
41
41
|
|
|
42
|
-
// Helper function to wait for dialog to be accessible
|
|
43
|
-
// Native dialog elements are only accessible after showModal() completes
|
|
44
|
-
// In test environments, we use querySelector as fallback since getByRole may not work
|
|
45
|
-
// Note: In test environments (jsdom), dialog.open may not be set even when dialog is rendered
|
|
46
|
-
const waitForDialog = async (): Promise<HTMLElement> => {
|
|
47
|
-
return await waitFor(
|
|
48
|
-
() => {
|
|
49
|
-
// Try getByRole first (works in browsers with full dialog support)
|
|
50
|
-
try {
|
|
51
|
-
const dialog = screen.getByRole('dialog');
|
|
52
|
-
expect(dialog).toBeInTheDocument();
|
|
53
|
-
return dialog;
|
|
54
|
-
} catch (_e) {
|
|
55
|
-
// Fallback: use querySelector for test environments that don't fully support dialog accessibility
|
|
56
|
-
const dialog = document.querySelector('dialog[role="dialog"]') as HTMLDialogElement;
|
|
57
|
-
if (!dialog) {
|
|
58
|
-
throw new Error('Dialog not found in DOM');
|
|
59
|
-
}
|
|
60
|
-
// In test environments, dialog.open may not be set even when dialog is rendered
|
|
61
|
-
// Just check that dialog exists in DOM - that's sufficient for testing
|
|
62
|
-
return dialog;
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
{ timeout: 3000 }
|
|
66
|
-
);
|
|
67
|
-
};
|
|
68
|
-
|
|
69
42
|
// Mock lodash debounce to avoid timing issues in tests
|
|
70
43
|
vi.mock('lodash', () => ({
|
|
71
44
|
debounce: (fn: Function) => fn
|
|
@@ -106,24 +79,7 @@ vi.mock('../../hooks/useFocusTrap', () => ({
|
|
|
106
79
|
describe('Dialog Component System', () => {
|
|
107
80
|
beforeEach(() => {
|
|
108
81
|
vi.clearAllMocks();
|
|
109
|
-
|
|
110
|
-
vi.spyOn(console, 'log').mockImplementation(() => {});
|
|
111
|
-
vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
112
|
-
|
|
113
|
-
// Mock showModal for dialog elements (needed for test environments)
|
|
114
|
-
// Override the prototype methods to ensure they're always available
|
|
115
|
-
if (typeof HTMLDialogElement !== 'undefined') {
|
|
116
|
-
HTMLDialogElement.prototype.showModal = vi.fn(function(this: HTMLDialogElement) {
|
|
117
|
-
this.setAttribute('open', '');
|
|
118
|
-
this.open = true;
|
|
119
|
-
this.dispatchEvent(new Event('show', { bubbles: true }));
|
|
120
|
-
});
|
|
121
|
-
HTMLDialogElement.prototype.close = vi.fn(function(this: HTMLDialogElement) {
|
|
122
|
-
this.removeAttribute('open');
|
|
123
|
-
this.open = false;
|
|
124
|
-
this.dispatchEvent(new Event('close', { bubbles: true }));
|
|
125
|
-
});
|
|
126
|
-
}
|
|
82
|
+
setupDialogEnv();
|
|
127
83
|
});
|
|
128
84
|
|
|
129
85
|
describe('Dialog Root Component', () => {
|
|
@@ -1048,7 +1004,7 @@ describe('Dialog Component System', () => {
|
|
|
1048
1004
|
|
|
1049
1005
|
it('renders multiple dialog triggers independently', () => {
|
|
1050
1006
|
renderWithProviders(
|
|
1051
|
-
|
|
1007
|
+
<>
|
|
1052
1008
|
<Dialog>
|
|
1053
1009
|
<DialogTrigger asChild>
|
|
1054
1010
|
<button>Open Dialog 1</button>
|
|
@@ -1069,7 +1025,7 @@ describe('Dialog Component System', () => {
|
|
|
1069
1025
|
</DialogHeader>
|
|
1070
1026
|
</DialogContent>
|
|
1071
1027
|
</Dialog>
|
|
1072
|
-
|
|
1028
|
+
</>
|
|
1073
1029
|
);
|
|
1074
1030
|
|
|
1075
1031
|
expect(screen.getByRole('button', { name: 'Open Dialog 1' })).toBeInTheDocument();
|
|
@@ -1750,36 +1706,6 @@ describe('Dialog Component System', () => {
|
|
|
1750
1706
|
});
|
|
1751
1707
|
});
|
|
1752
1708
|
|
|
1753
|
-
describe('DialogOverlay Component', () => {
|
|
1754
|
-
it('does not render (native dialog provides backdrop automatically)', async () => {
|
|
1755
|
-
// DialogOverlay component returns null because native <dialog> element
|
|
1756
|
-
// provides ::backdrop automatically via CSS
|
|
1757
|
-
// This test verifies that dialogs work correctly without DialogOverlay
|
|
1758
|
-
const user = userEvent.setup();
|
|
1759
|
-
|
|
1760
|
-
renderWithProviders(
|
|
1761
|
-
<Dialog>
|
|
1762
|
-
<DialogTrigger asChild>
|
|
1763
|
-
<button>Open Dialog</button>
|
|
1764
|
-
</DialogTrigger>
|
|
1765
|
-
<DialogContent title="Test Dialog">
|
|
1766
|
-
<DialogHeader>
|
|
1767
|
-
<h2>Test Dialog</h2>
|
|
1768
|
-
</DialogHeader>
|
|
1769
|
-
</DialogContent>
|
|
1770
|
-
</Dialog>
|
|
1771
|
-
);
|
|
1772
|
-
|
|
1773
|
-
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
1774
|
-
await waitForDialog();
|
|
1775
|
-
|
|
1776
|
-
// Dialog should render and function correctly without DialogOverlay
|
|
1777
|
-
// (backdrop is provided by native dialog element)
|
|
1778
|
-
const dialog = document.querySelector('dialog[role="dialog"]');
|
|
1779
|
-
expect(dialog).toBeInTheDocument();
|
|
1780
|
-
});
|
|
1781
|
-
});
|
|
1782
|
-
|
|
1783
1709
|
describe('Context Error Handling', () => {
|
|
1784
1710
|
it('throws error when DialogTrigger is used outside Dialog', () => {
|
|
1785
1711
|
// Suppress console.error for this test
|
|
@@ -2585,11 +2511,11 @@ describe('Dialog Component System', () => {
|
|
|
2585
2511
|
});
|
|
2586
2512
|
|
|
2587
2513
|
describe('DialogTrigger Edge Cases', () => {
|
|
2588
|
-
it('handles asChild with non-
|
|
2514
|
+
it('handles asChild with non-button element gracefully', () => {
|
|
2589
2515
|
renderWithProviders(
|
|
2590
2516
|
<Dialog>
|
|
2591
2517
|
<DialogTrigger asChild>
|
|
2592
|
-
<
|
|
2518
|
+
<span>Not a button</span>
|
|
2593
2519
|
</DialogTrigger>
|
|
2594
2520
|
<DialogContent title="Test Dialog">
|
|
2595
2521
|
<DialogHeader>
|
|
@@ -2599,7 +2525,6 @@ describe('Dialog Component System', () => {
|
|
|
2599
2525
|
</Dialog>
|
|
2600
2526
|
);
|
|
2601
2527
|
|
|
2602
|
-
// Should render the div
|
|
2603
2528
|
expect(screen.getByText('Not a button')).toBeInTheDocument();
|
|
2604
2529
|
});
|
|
2605
2530
|
|
|
@@ -2813,4 +2738,886 @@ describe('Dialog Component System', () => {
|
|
|
2813
2738
|
unmountFirst();
|
|
2814
2739
|
});
|
|
2815
2740
|
});
|
|
2741
|
+
|
|
2742
|
+
describe('Ref Forwarding', () => {
|
|
2743
|
+
it('forwards ref correctly to dialog element', async () => {
|
|
2744
|
+
const user = userEvent.setup();
|
|
2745
|
+
const ref = React.createRef<HTMLDialogElement>();
|
|
2746
|
+
|
|
2747
|
+
renderWithProviders(
|
|
2748
|
+
<Dialog>
|
|
2749
|
+
<DialogTrigger asChild>
|
|
2750
|
+
<button>Open Dialog</button>
|
|
2751
|
+
</DialogTrigger>
|
|
2752
|
+
<DialogContent ref={ref} title="Test Dialog">
|
|
2753
|
+
<DialogHeader>
|
|
2754
|
+
<h2>Test Dialog</h2>
|
|
2755
|
+
</DialogHeader>
|
|
2756
|
+
</DialogContent>
|
|
2757
|
+
</Dialog>
|
|
2758
|
+
);
|
|
2759
|
+
|
|
2760
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
2761
|
+
const dialog = await waitForDialog();
|
|
2762
|
+
|
|
2763
|
+
expect(ref.current).toBeInstanceOf(HTMLDialogElement);
|
|
2764
|
+
expect(ref.current).toBe(dialog);
|
|
2765
|
+
});
|
|
2766
|
+
|
|
2767
|
+
it('ref persists when dialog is closed', async () => {
|
|
2768
|
+
const user = userEvent.setup();
|
|
2769
|
+
const ref = React.createRef<HTMLDialogElement>();
|
|
2770
|
+
|
|
2771
|
+
const { rerender } = renderWithProviders(
|
|
2772
|
+
<Dialog open={true}>
|
|
2773
|
+
<DialogContent ref={ref} title="Test Dialog">
|
|
2774
|
+
<DialogHeader>
|
|
2775
|
+
<h2>Test Dialog</h2>
|
|
2776
|
+
</DialogHeader>
|
|
2777
|
+
</DialogContent>
|
|
2778
|
+
</Dialog>
|
|
2779
|
+
);
|
|
2780
|
+
|
|
2781
|
+
await waitForDialog();
|
|
2782
|
+
expect(ref.current).toBeInstanceOf(HTMLDialogElement);
|
|
2783
|
+
|
|
2784
|
+
// Close dialog
|
|
2785
|
+
rerender(
|
|
2786
|
+
<Dialog open={false}>
|
|
2787
|
+
<DialogContent ref={ref} title="Test Dialog">
|
|
2788
|
+
<DialogHeader>
|
|
2789
|
+
<h2>Test Dialog</h2>
|
|
2790
|
+
</DialogHeader>
|
|
2791
|
+
</DialogContent>
|
|
2792
|
+
</Dialog>
|
|
2793
|
+
);
|
|
2794
|
+
|
|
2795
|
+
await waitFor(() => {
|
|
2796
|
+
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
2797
|
+
});
|
|
2798
|
+
|
|
2799
|
+
// React refs persist even when element is removed from DOM
|
|
2800
|
+
// The ref.current will still point to the element until component unmounts
|
|
2801
|
+
// This is expected React behavior
|
|
2802
|
+
if (ref.current) {
|
|
2803
|
+
expect(ref.current).toBeInstanceOf(HTMLDialogElement);
|
|
2804
|
+
}
|
|
2805
|
+
});
|
|
2806
|
+
|
|
2807
|
+
it('handles ref callback function', async () => {
|
|
2808
|
+
const user = userEvent.setup();
|
|
2809
|
+
let refElement: HTMLDialogElement | null = null;
|
|
2810
|
+
const refCallback = (node: HTMLDialogElement | null) => {
|
|
2811
|
+
refElement = node;
|
|
2812
|
+
};
|
|
2813
|
+
|
|
2814
|
+
renderWithProviders(
|
|
2815
|
+
<Dialog>
|
|
2816
|
+
<DialogTrigger asChild>
|
|
2817
|
+
<button>Open Dialog</button>
|
|
2818
|
+
</DialogTrigger>
|
|
2819
|
+
<DialogContent ref={refCallback} title="Test Dialog">
|
|
2820
|
+
<DialogHeader>
|
|
2821
|
+
<h2>Test Dialog</h2>
|
|
2822
|
+
</DialogHeader>
|
|
2823
|
+
</DialogContent>
|
|
2824
|
+
</Dialog>
|
|
2825
|
+
);
|
|
2826
|
+
|
|
2827
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
2828
|
+
await waitForDialog();
|
|
2829
|
+
|
|
2830
|
+
expect(refElement).toBeInstanceOf(HTMLDialogElement);
|
|
2831
|
+
});
|
|
2832
|
+
});
|
|
2833
|
+
|
|
2834
|
+
describe('DialogContent Props Spreading', () => {
|
|
2835
|
+
it('spreads additional props to dialog element', async () => {
|
|
2836
|
+
const user = userEvent.setup();
|
|
2837
|
+
|
|
2838
|
+
renderWithProviders(
|
|
2839
|
+
<Dialog>
|
|
2840
|
+
<DialogTrigger asChild>
|
|
2841
|
+
<button>Open Dialog</button>
|
|
2842
|
+
</DialogTrigger>
|
|
2843
|
+
<DialogContent
|
|
2844
|
+
title="Test Dialog"
|
|
2845
|
+
data-testid="custom-dialog"
|
|
2846
|
+
data-custom-attr="custom-value"
|
|
2847
|
+
>
|
|
2848
|
+
<DialogHeader>
|
|
2849
|
+
<h2>Test Dialog</h2>
|
|
2850
|
+
</DialogHeader>
|
|
2851
|
+
</DialogContent>
|
|
2852
|
+
</Dialog>
|
|
2853
|
+
);
|
|
2854
|
+
|
|
2855
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
2856
|
+
const dialog = await waitForDialog();
|
|
2857
|
+
|
|
2858
|
+
expect(dialog).toHaveAttribute('data-testid', 'custom-dialog');
|
|
2859
|
+
expect(dialog).toHaveAttribute('data-custom-attr', 'custom-value');
|
|
2860
|
+
});
|
|
2861
|
+
|
|
2862
|
+
it('merges custom style with smart dimensions', async () => {
|
|
2863
|
+
const user = userEvent.setup();
|
|
2864
|
+
|
|
2865
|
+
renderWithProviders(
|
|
2866
|
+
<Dialog>
|
|
2867
|
+
<DialogTrigger asChild>
|
|
2868
|
+
<button>Open Dialog</button>
|
|
2869
|
+
</DialogTrigger>
|
|
2870
|
+
<DialogContent
|
|
2871
|
+
title="Test Dialog"
|
|
2872
|
+
maxHeightPercent={80}
|
|
2873
|
+
>
|
|
2874
|
+
<DialogHeader>
|
|
2875
|
+
<h2>Test Dialog</h2>
|
|
2876
|
+
</DialogHeader>
|
|
2877
|
+
</DialogContent>
|
|
2878
|
+
</Dialog>
|
|
2879
|
+
);
|
|
2880
|
+
|
|
2881
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
2882
|
+
const dialog = await waitForDialog();
|
|
2883
|
+
|
|
2884
|
+
expect(dialog).toHaveStyle({ maxHeight: '80vh' });
|
|
2885
|
+
const style = dialog.getAttribute('style');
|
|
2886
|
+
expect(style).toBeTruthy();
|
|
2887
|
+
expect(style).toContain('max-height');
|
|
2888
|
+
});
|
|
2889
|
+
});
|
|
2890
|
+
|
|
2891
|
+
describe('DialogBody Flex Container Detection Edge Cases', () => {
|
|
2892
|
+
it('handles flex container detection when dialog is closed', () => {
|
|
2893
|
+
renderWithProviders(
|
|
2894
|
+
<Dialog open={false}>
|
|
2895
|
+
<DialogContent title="Test Dialog" maxHeightPercent={80}>
|
|
2896
|
+
<DialogHeader>
|
|
2897
|
+
<h2>Test Dialog</h2>
|
|
2898
|
+
</DialogHeader>
|
|
2899
|
+
<DialogBody>
|
|
2900
|
+
<p>Content</p>
|
|
2901
|
+
</DialogBody>
|
|
2902
|
+
</DialogContent>
|
|
2903
|
+
</Dialog>
|
|
2904
|
+
);
|
|
2905
|
+
|
|
2906
|
+
// Should not crash when dialog is closed
|
|
2907
|
+
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
2908
|
+
});
|
|
2909
|
+
|
|
2910
|
+
it('handles flex container detection timeout cleanup', async () => {
|
|
2911
|
+
const user = userEvent.setup();
|
|
2912
|
+
const { unmount } = renderWithProviders(
|
|
2913
|
+
<Dialog>
|
|
2914
|
+
<DialogTrigger asChild>
|
|
2915
|
+
<button>Open Dialog</button>
|
|
2916
|
+
</DialogTrigger>
|
|
2917
|
+
<DialogContent title="Test Dialog" maxHeightPercent={80}>
|
|
2918
|
+
<DialogHeader>
|
|
2919
|
+
<h2>Test Dialog</h2>
|
|
2920
|
+
</DialogHeader>
|
|
2921
|
+
<DialogBody>
|
|
2922
|
+
<p>Content</p>
|
|
2923
|
+
</DialogBody>
|
|
2924
|
+
</DialogContent>
|
|
2925
|
+
</Dialog>
|
|
2926
|
+
);
|
|
2927
|
+
|
|
2928
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
2929
|
+
await waitForDialog();
|
|
2930
|
+
|
|
2931
|
+
// Unmount should clean up timeouts
|
|
2932
|
+
unmount();
|
|
2933
|
+
|
|
2934
|
+
// Should not crash
|
|
2935
|
+
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
2936
|
+
});
|
|
2937
|
+
});
|
|
2938
|
+
|
|
2939
|
+
describe('DialogTitle and DialogDescription Ref Forwarding', () => {
|
|
2940
|
+
it('forwards ref correctly to DialogTitle', async () => {
|
|
2941
|
+
const user = userEvent.setup();
|
|
2942
|
+
const ref = React.createRef<HTMLHeadingElement>();
|
|
2943
|
+
|
|
2944
|
+
renderWithProviders(
|
|
2945
|
+
<Dialog>
|
|
2946
|
+
<DialogTrigger asChild>
|
|
2947
|
+
<button>Open Dialog</button>
|
|
2948
|
+
</DialogTrigger>
|
|
2949
|
+
<DialogContent title="Test Dialog">
|
|
2950
|
+
<DialogHeader>
|
|
2951
|
+
<DialogTitle ref={ref}>Custom Title</DialogTitle>
|
|
2952
|
+
</DialogHeader>
|
|
2953
|
+
</DialogContent>
|
|
2954
|
+
</Dialog>
|
|
2955
|
+
);
|
|
2956
|
+
|
|
2957
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
2958
|
+
await waitForDialog();
|
|
2959
|
+
|
|
2960
|
+
expect(ref.current).toBeInstanceOf(HTMLHeadingElement);
|
|
2961
|
+
expect(ref.current?.tagName).toBe('H2');
|
|
2962
|
+
});
|
|
2963
|
+
|
|
2964
|
+
it('forwards ref correctly to DialogDescription', async () => {
|
|
2965
|
+
const user = userEvent.setup();
|
|
2966
|
+
const ref = React.createRef<HTMLParagraphElement>();
|
|
2967
|
+
|
|
2968
|
+
renderWithProviders(
|
|
2969
|
+
<Dialog>
|
|
2970
|
+
<DialogTrigger asChild>
|
|
2971
|
+
<button>Open Dialog</button>
|
|
2972
|
+
</DialogTrigger>
|
|
2973
|
+
<DialogContent title="Test Dialog">
|
|
2974
|
+
<DialogHeader>
|
|
2975
|
+
<DialogTitle>Test Dialog</DialogTitle>
|
|
2976
|
+
<DialogDescription ref={ref}>Custom Description</DialogDescription>
|
|
2977
|
+
</DialogHeader>
|
|
2978
|
+
</DialogContent>
|
|
2979
|
+
</Dialog>
|
|
2980
|
+
);
|
|
2981
|
+
|
|
2982
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
2983
|
+
await waitForDialog();
|
|
2984
|
+
|
|
2985
|
+
expect(ref.current).toBeInstanceOf(HTMLParagraphElement);
|
|
2986
|
+
expect(ref.current?.tagName).toBe('P');
|
|
2987
|
+
});
|
|
2988
|
+
});
|
|
2989
|
+
|
|
2990
|
+
describe('DialogHeader and DialogFooter Sticky Behavior', () => {
|
|
2991
|
+
it('applies sticky styles correctly when enableScrolling is true', async () => {
|
|
2992
|
+
const user = userEvent.setup();
|
|
2993
|
+
|
|
2994
|
+
renderWithProviders(
|
|
2995
|
+
<Dialog>
|
|
2996
|
+
<DialogTrigger asChild>
|
|
2997
|
+
<button>Open Dialog</button>
|
|
2998
|
+
</DialogTrigger>
|
|
2999
|
+
<DialogContent title="Test Dialog" enableScrolling>
|
|
3000
|
+
<DialogHeader sticky>
|
|
3001
|
+
<h2>Sticky Header</h2>
|
|
3002
|
+
</DialogHeader>
|
|
3003
|
+
<DialogBody>
|
|
3004
|
+
<p>Content</p>
|
|
3005
|
+
</DialogBody>
|
|
3006
|
+
<DialogFooter sticky>
|
|
3007
|
+
<button>Save</button>
|
|
3008
|
+
</DialogFooter>
|
|
3009
|
+
</DialogContent>
|
|
3010
|
+
</Dialog>
|
|
3011
|
+
);
|
|
3012
|
+
|
|
3013
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3014
|
+
await waitForDialog();
|
|
3015
|
+
|
|
3016
|
+
const header = document.querySelector('dialog header');
|
|
3017
|
+
const footer = document.querySelector('dialog footer');
|
|
3018
|
+
|
|
3019
|
+
expect(header).toHaveClass('sticky', 'top-0');
|
|
3020
|
+
expect(footer).toHaveClass('sticky', 'bottom-0');
|
|
3021
|
+
});
|
|
3022
|
+
|
|
3023
|
+
it('does not apply sticky styles when sticky prop is false', async () => {
|
|
3024
|
+
const user = userEvent.setup();
|
|
3025
|
+
|
|
3026
|
+
renderWithProviders(
|
|
3027
|
+
<Dialog>
|
|
3028
|
+
<DialogTrigger asChild>
|
|
3029
|
+
<button>Open Dialog</button>
|
|
3030
|
+
</DialogTrigger>
|
|
3031
|
+
<DialogContent title="Test Dialog" enableScrolling>
|
|
3032
|
+
<DialogHeader sticky={false}>
|
|
3033
|
+
<h2>Non-Sticky Header</h2>
|
|
3034
|
+
</DialogHeader>
|
|
3035
|
+
<DialogBody>
|
|
3036
|
+
<p>Content</p>
|
|
3037
|
+
</DialogBody>
|
|
3038
|
+
<DialogFooter sticky={false}>
|
|
3039
|
+
<button>Save</button>
|
|
3040
|
+
</DialogFooter>
|
|
3041
|
+
</DialogContent>
|
|
3042
|
+
</Dialog>
|
|
3043
|
+
);
|
|
3044
|
+
|
|
3045
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3046
|
+
await waitForDialog();
|
|
3047
|
+
|
|
3048
|
+
const header = document.querySelector('dialog header');
|
|
3049
|
+
const footer = document.querySelector('dialog footer');
|
|
3050
|
+
|
|
3051
|
+
expect(header).not.toHaveClass('sticky');
|
|
3052
|
+
expect(footer).not.toHaveClass('sticky');
|
|
3053
|
+
});
|
|
3054
|
+
});
|
|
3055
|
+
|
|
3056
|
+
describe('DialogContent Size Variants - Extended', () => {
|
|
3057
|
+
it('applies correct classes for full size variant', async () => {
|
|
3058
|
+
const user = userEvent.setup();
|
|
3059
|
+
|
|
3060
|
+
renderWithProviders(
|
|
3061
|
+
<Dialog>
|
|
3062
|
+
<DialogTrigger asChild>
|
|
3063
|
+
<button>Open Dialog</button>
|
|
3064
|
+
</DialogTrigger>
|
|
3065
|
+
<DialogContent size="full" title="Full Dialog">
|
|
3066
|
+
<DialogHeader>
|
|
3067
|
+
<h2>Full Dialog</h2>
|
|
3068
|
+
</DialogHeader>
|
|
3069
|
+
</DialogContent>
|
|
3070
|
+
</Dialog>
|
|
3071
|
+
);
|
|
3072
|
+
|
|
3073
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3074
|
+
const dialog = await waitForDialog();
|
|
3075
|
+
|
|
3076
|
+
expect(dialog).toHaveClass('max-w-full', 'size-full');
|
|
3077
|
+
});
|
|
3078
|
+
|
|
3079
|
+
it('applies correct classes for auto size variant', async () => {
|
|
3080
|
+
const user = userEvent.setup();
|
|
3081
|
+
|
|
3082
|
+
renderWithProviders(
|
|
3083
|
+
<Dialog>
|
|
3084
|
+
<DialogTrigger asChild>
|
|
3085
|
+
<button>Open Dialog</button>
|
|
3086
|
+
</DialogTrigger>
|
|
3087
|
+
<DialogContent size="auto" title="Auto Dialog">
|
|
3088
|
+
<DialogHeader>
|
|
3089
|
+
<h2>Auto Dialog</h2>
|
|
3090
|
+
</DialogHeader>
|
|
3091
|
+
</DialogContent>
|
|
3092
|
+
</Dialog>
|
|
3093
|
+
);
|
|
3094
|
+
|
|
3095
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3096
|
+
const dialog = await waitForDialog();
|
|
3097
|
+
|
|
3098
|
+
// Auto size applies w-fit and max-w-[90vw] sm:max-w-[80vw] classes
|
|
3099
|
+
expect(dialog).toHaveClass('w-fit');
|
|
3100
|
+
expect(dialog).toHaveClass('min-w-0');
|
|
3101
|
+
});
|
|
3102
|
+
});
|
|
3103
|
+
|
|
3104
|
+
describe('Dialog Persistence - Extended Scenarios', () => {
|
|
3105
|
+
beforeEach(() => {
|
|
3106
|
+
sessionStorage.clear();
|
|
3107
|
+
});
|
|
3108
|
+
|
|
3109
|
+
it('handles persistence when title changes', async () => {
|
|
3110
|
+
const user = userEvent.setup();
|
|
3111
|
+
const { useSessionDraft } = await import('../../hooks/useSessionDraft');
|
|
3112
|
+
const mockSetState = vi.fn();
|
|
3113
|
+
|
|
3114
|
+
vi.mocked(useSessionDraft).mockReturnValue({
|
|
3115
|
+
state: false,
|
|
3116
|
+
setState: mockSetState,
|
|
3117
|
+
clearDraft: vi.fn(),
|
|
3118
|
+
wasRestored: false,
|
|
3119
|
+
saveImmediately: vi.fn(),
|
|
3120
|
+
});
|
|
3121
|
+
|
|
3122
|
+
const { rerender } = renderWithProviders(
|
|
3123
|
+
<Dialog>
|
|
3124
|
+
<DialogTrigger asChild>
|
|
3125
|
+
<button>Open Dialog</button>
|
|
3126
|
+
</DialogTrigger>
|
|
3127
|
+
<DialogContent title="Original Title" persistOpenState={true}>
|
|
3128
|
+
<DialogHeader>
|
|
3129
|
+
<h2>Original Title</h2>
|
|
3130
|
+
</DialogHeader>
|
|
3131
|
+
</DialogContent>
|
|
3132
|
+
</Dialog>
|
|
3133
|
+
);
|
|
3134
|
+
|
|
3135
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3136
|
+
await waitForDialog();
|
|
3137
|
+
|
|
3138
|
+
// Change title
|
|
3139
|
+
rerender(
|
|
3140
|
+
<Dialog>
|
|
3141
|
+
<DialogTrigger asChild>
|
|
3142
|
+
<button>Open Dialog</button>
|
|
3143
|
+
</DialogTrigger>
|
|
3144
|
+
<DialogContent title="New Title" persistOpenState={true}>
|
|
3145
|
+
<DialogHeader>
|
|
3146
|
+
<h2>New Title</h2>
|
|
3147
|
+
</DialogHeader>
|
|
3148
|
+
</DialogContent>
|
|
3149
|
+
</Dialog>
|
|
3150
|
+
);
|
|
3151
|
+
|
|
3152
|
+
// Dialog should handle title change gracefully
|
|
3153
|
+
await waitFor(() => {
|
|
3154
|
+
const dialog = document.querySelector('dialog[role="dialog"]');
|
|
3155
|
+
expect(dialog).toHaveAttribute('title', 'New Title');
|
|
3156
|
+
});
|
|
3157
|
+
});
|
|
3158
|
+
|
|
3159
|
+
it('handles persistence when description changes', async () => {
|
|
3160
|
+
const user = userEvent.setup();
|
|
3161
|
+
const { useSessionDraft } = await import('../../hooks/useSessionDraft');
|
|
3162
|
+
|
|
3163
|
+
vi.mocked(useSessionDraft).mockReturnValue({
|
|
3164
|
+
state: false,
|
|
3165
|
+
setState: vi.fn(),
|
|
3166
|
+
clearDraft: vi.fn(),
|
|
3167
|
+
wasRestored: false,
|
|
3168
|
+
saveImmediately: vi.fn(),
|
|
3169
|
+
});
|
|
3170
|
+
|
|
3171
|
+
const { rerender } = renderWithProviders(
|
|
3172
|
+
<Dialog>
|
|
3173
|
+
<DialogTrigger asChild>
|
|
3174
|
+
<button>Open Dialog</button>
|
|
3175
|
+
</DialogTrigger>
|
|
3176
|
+
<DialogContent title="Test Dialog" description="Original Description" persistOpenState={true}>
|
|
3177
|
+
<DialogHeader>
|
|
3178
|
+
<h2>Test Dialog</h2>
|
|
3179
|
+
</DialogHeader>
|
|
3180
|
+
</DialogContent>
|
|
3181
|
+
</Dialog>
|
|
3182
|
+
);
|
|
3183
|
+
|
|
3184
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3185
|
+
await waitForDialog();
|
|
3186
|
+
|
|
3187
|
+
// Change description
|
|
3188
|
+
rerender(
|
|
3189
|
+
<Dialog>
|
|
3190
|
+
<DialogTrigger asChild>
|
|
3191
|
+
<button>Open Dialog</button>
|
|
3192
|
+
</DialogTrigger>
|
|
3193
|
+
<DialogContent title="Test Dialog" description="New Description" persistOpenState={true}>
|
|
3194
|
+
<DialogHeader>
|
|
3195
|
+
<h2>Test Dialog</h2>
|
|
3196
|
+
</DialogHeader>
|
|
3197
|
+
</DialogContent>
|
|
3198
|
+
</Dialog>
|
|
3199
|
+
);
|
|
3200
|
+
|
|
3201
|
+
// Dialog should handle description change gracefully
|
|
3202
|
+
await waitFor(() => {
|
|
3203
|
+
const dialog = document.querySelector('dialog[role="dialog"]');
|
|
3204
|
+
expect(dialog).toHaveAttribute('aria-description', 'New Description');
|
|
3205
|
+
});
|
|
3206
|
+
});
|
|
3207
|
+
});
|
|
3208
|
+
|
|
3209
|
+
describe('Dialog Lock Mechanism - Extended', () => {
|
|
3210
|
+
beforeEach(() => {
|
|
3211
|
+
sessionStorage.clear();
|
|
3212
|
+
});
|
|
3213
|
+
|
|
3214
|
+
it('handles lock acquisition when another dialog is closing', async () => {
|
|
3215
|
+
const user = userEvent.setup();
|
|
3216
|
+
|
|
3217
|
+
// First dialog
|
|
3218
|
+
const { unmount: unmountFirst } = renderWithProviders(
|
|
3219
|
+
<Dialog>
|
|
3220
|
+
<DialogTrigger asChild>
|
|
3221
|
+
<button>Open Dialog 1</button>
|
|
3222
|
+
</DialogTrigger>
|
|
3223
|
+
<DialogContent title="Dialog 1" persistOpenState={true}>
|
|
3224
|
+
<DialogHeader>
|
|
3225
|
+
<h2>Dialog 1</h2>
|
|
3226
|
+
</DialogHeader>
|
|
3227
|
+
</DialogContent>
|
|
3228
|
+
</Dialog>
|
|
3229
|
+
);
|
|
3230
|
+
|
|
3231
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog 1' }));
|
|
3232
|
+
await waitForDialog();
|
|
3233
|
+
|
|
3234
|
+
// Close first dialog
|
|
3235
|
+
const dialog1 = document.querySelector('dialog[role="dialog"]');
|
|
3236
|
+
const closeIcon1 = dialog1?.querySelector('[data-testid="lucide-x"]');
|
|
3237
|
+
const closeButton1 = closeIcon1?.closest('button') as HTMLButtonElement;
|
|
3238
|
+
await user.click(closeButton1);
|
|
3239
|
+
|
|
3240
|
+
await waitFor(() => {
|
|
3241
|
+
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
3242
|
+
});
|
|
3243
|
+
|
|
3244
|
+
unmountFirst();
|
|
3245
|
+
|
|
3246
|
+
// Second dialog should be able to acquire lock
|
|
3247
|
+
renderWithProviders(
|
|
3248
|
+
<Dialog>
|
|
3249
|
+
<DialogTrigger asChild>
|
|
3250
|
+
<button>Open Dialog 2</button>
|
|
3251
|
+
</DialogTrigger>
|
|
3252
|
+
<DialogContent title="Dialog 2" persistOpenState={true}>
|
|
3253
|
+
<DialogHeader>
|
|
3254
|
+
<h2>Dialog 2</h2>
|
|
3255
|
+
</DialogHeader>
|
|
3256
|
+
</DialogContent>
|
|
3257
|
+
</Dialog>
|
|
3258
|
+
);
|
|
3259
|
+
|
|
3260
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog 2' }));
|
|
3261
|
+
await waitForDialog();
|
|
3262
|
+
|
|
3263
|
+
// Second dialog should open successfully
|
|
3264
|
+
const dialog2 = document.querySelector('dialog[role="dialog"]');
|
|
3265
|
+
expect(dialog2).toBeInTheDocument();
|
|
3266
|
+
});
|
|
3267
|
+
});
|
|
3268
|
+
|
|
3269
|
+
describe('DialogContent Conditional Rendering', () => {
|
|
3270
|
+
it('does not render when open is false', () => {
|
|
3271
|
+
renderWithProviders(
|
|
3272
|
+
<Dialog open={false}>
|
|
3273
|
+
<DialogContent title="Test Dialog">
|
|
3274
|
+
<DialogHeader>
|
|
3275
|
+
<h2>Test Dialog</h2>
|
|
3276
|
+
</DialogHeader>
|
|
3277
|
+
</DialogContent>
|
|
3278
|
+
</Dialog>
|
|
3279
|
+
);
|
|
3280
|
+
|
|
3281
|
+
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
3282
|
+
});
|
|
3283
|
+
|
|
3284
|
+
it('does not render when lock is not acquired', async () => {
|
|
3285
|
+
const user = userEvent.setup();
|
|
3286
|
+
|
|
3287
|
+
// Set a lock for another dialog
|
|
3288
|
+
sessionStorage.setItem('pace-core:dialog:lock', JSON.stringify({
|
|
3289
|
+
key: 'other-dialog-key',
|
|
3290
|
+
timestamp: Date.now(),
|
|
3291
|
+
}));
|
|
3292
|
+
|
|
3293
|
+
// Create a fake dialog in DOM to simulate another dialog being open
|
|
3294
|
+
const fakeDialog = document.createElement('dialog');
|
|
3295
|
+
fakeDialog.setAttribute('data-persistence-key', 'other-dialog-key');
|
|
3296
|
+
fakeDialog.setAttribute('open', '');
|
|
3297
|
+
document.body.appendChild(fakeDialog);
|
|
3298
|
+
|
|
3299
|
+
renderWithProviders(
|
|
3300
|
+
<Dialog>
|
|
3301
|
+
<DialogTrigger asChild>
|
|
3302
|
+
<button>Open Dialog</button>
|
|
3303
|
+
</DialogTrigger>
|
|
3304
|
+
<DialogContent title="Test Dialog" persistOpenState={true}>
|
|
3305
|
+
<DialogHeader>
|
|
3306
|
+
<h2>Test Dialog</h2>
|
|
3307
|
+
</DialogHeader>
|
|
3308
|
+
</DialogContent>
|
|
3309
|
+
</Dialog>
|
|
3310
|
+
);
|
|
3311
|
+
|
|
3312
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3313
|
+
|
|
3314
|
+
// Dialog should not render (lock not acquired)
|
|
3315
|
+
await waitFor(() => {
|
|
3316
|
+
const dialogs = document.querySelectorAll('dialog[role="dialog"]');
|
|
3317
|
+
// Should only have the fake dialog, not the new one
|
|
3318
|
+
expect(dialogs.length).toBeLessThanOrEqual(1);
|
|
3319
|
+
}, { timeout: 1000 });
|
|
3320
|
+
|
|
3321
|
+
// Cleanup
|
|
3322
|
+
document.body.removeChild(fakeDialog);
|
|
3323
|
+
});
|
|
3324
|
+
});
|
|
3325
|
+
|
|
3326
|
+
describe('DialogClose Context Integration', () => {
|
|
3327
|
+
it('uses markClosedByUser from DialogContext when available', async () => {
|
|
3328
|
+
const user = userEvent.setup();
|
|
3329
|
+
const { useSessionDraft } = await import('../../hooks/useSessionDraft');
|
|
3330
|
+
const mockClearDraft = vi.fn();
|
|
3331
|
+
|
|
3332
|
+
vi.mocked(useSessionDraft).mockReturnValue({
|
|
3333
|
+
state: false,
|
|
3334
|
+
setState: vi.fn(),
|
|
3335
|
+
clearDraft: mockClearDraft,
|
|
3336
|
+
wasRestored: false,
|
|
3337
|
+
saveImmediately: vi.fn(),
|
|
3338
|
+
});
|
|
3339
|
+
|
|
3340
|
+
renderWithProviders(
|
|
3341
|
+
<Dialog defaultOpen={true}>
|
|
3342
|
+
<DialogContent title="Test Dialog" persistOpenState={true}>
|
|
3343
|
+
<DialogHeader>
|
|
3344
|
+
<h2>Test Dialog</h2>
|
|
3345
|
+
</DialogHeader>
|
|
3346
|
+
<DialogFooter>
|
|
3347
|
+
<DialogClose />
|
|
3348
|
+
</DialogFooter>
|
|
3349
|
+
</DialogContent>
|
|
3350
|
+
</Dialog>
|
|
3351
|
+
);
|
|
3352
|
+
|
|
3353
|
+
await waitForDialog();
|
|
3354
|
+
|
|
3355
|
+
// Close via DialogClose button
|
|
3356
|
+
const dialog = document.querySelector('dialog[role="dialog"]');
|
|
3357
|
+
const closeIcon = dialog?.querySelector('[data-testid="lucide-x"]');
|
|
3358
|
+
const closeButton = closeIcon?.closest('button') as HTMLButtonElement;
|
|
3359
|
+
await user.click(closeButton);
|
|
3360
|
+
|
|
3361
|
+
await waitFor(() => {
|
|
3362
|
+
expect(mockClearDraft).toHaveBeenCalled();
|
|
3363
|
+
});
|
|
3364
|
+
});
|
|
3365
|
+
});
|
|
3366
|
+
|
|
3367
|
+
describe('DialogBody HTML Content Edge Cases', () => {
|
|
3368
|
+
it('handles HTML content that becomes empty after sanitization', async () => {
|
|
3369
|
+
const user = userEvent.setup();
|
|
3370
|
+
|
|
3371
|
+
renderWithProviders(
|
|
3372
|
+
<Dialog>
|
|
3373
|
+
<DialogTrigger asChild>
|
|
3374
|
+
<button>Open Dialog</button>
|
|
3375
|
+
</DialogTrigger>
|
|
3376
|
+
<DialogContent title="Test Dialog">
|
|
3377
|
+
<DialogHeader>
|
|
3378
|
+
<h2>Test Dialog</h2>
|
|
3379
|
+
</DialogHeader>
|
|
3380
|
+
<DialogBody
|
|
3381
|
+
htmlContent="<script>alert('xss')</script>"
|
|
3382
|
+
allowHtml={true}
|
|
3383
|
+
>
|
|
3384
|
+
<p>Fallback Content</p>
|
|
3385
|
+
</DialogBody>
|
|
3386
|
+
</DialogContent>
|
|
3387
|
+
</Dialog>
|
|
3388
|
+
);
|
|
3389
|
+
|
|
3390
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3391
|
+
await waitForDialog();
|
|
3392
|
+
|
|
3393
|
+
// Should show fallback message or children
|
|
3394
|
+
const body = document.querySelector('dialog main');
|
|
3395
|
+
expect(body).toBeInTheDocument();
|
|
3396
|
+
});
|
|
3397
|
+
|
|
3398
|
+
it('handles HTML content with only unsafe elements', async () => {
|
|
3399
|
+
const user = userEvent.setup();
|
|
3400
|
+
|
|
3401
|
+
renderWithProviders(
|
|
3402
|
+
<Dialog>
|
|
3403
|
+
<DialogTrigger asChild>
|
|
3404
|
+
<button>Open Dialog</button>
|
|
3405
|
+
</DialogTrigger>
|
|
3406
|
+
<DialogContent title="Test Dialog">
|
|
3407
|
+
<DialogHeader>
|
|
3408
|
+
<h2>Test Dialog</h2>
|
|
3409
|
+
</DialogHeader>
|
|
3410
|
+
<DialogBody
|
|
3411
|
+
htmlContent="<script>alert('xss')</script><iframe src='evil.com'></iframe>"
|
|
3412
|
+
allowHtml={true}
|
|
3413
|
+
>
|
|
3414
|
+
<p>Fallback Content</p>
|
|
3415
|
+
</DialogBody>
|
|
3416
|
+
</DialogContent>
|
|
3417
|
+
</Dialog>
|
|
3418
|
+
);
|
|
3419
|
+
|
|
3420
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3421
|
+
await waitForDialog();
|
|
3422
|
+
|
|
3423
|
+
// Should show fallback message
|
|
3424
|
+
const body = document.querySelector('dialog main');
|
|
3425
|
+
expect(body).toBeInTheDocument();
|
|
3426
|
+
});
|
|
3427
|
+
});
|
|
3428
|
+
|
|
3429
|
+
describe('DialogPortal Mount State', () => {
|
|
3430
|
+
it('handles portal mount state correctly', async () => {
|
|
3431
|
+
const user = userEvent.setup();
|
|
3432
|
+
|
|
3433
|
+
renderWithProviders(
|
|
3434
|
+
<Dialog>
|
|
3435
|
+
<DialogTrigger asChild>
|
|
3436
|
+
<button>Open Dialog</button>
|
|
3437
|
+
</DialogTrigger>
|
|
3438
|
+
<DialogContent title="Test Dialog">
|
|
3439
|
+
<DialogHeader>
|
|
3440
|
+
<h2>Test Dialog</h2>
|
|
3441
|
+
</DialogHeader>
|
|
3442
|
+
</DialogContent>
|
|
3443
|
+
</Dialog>
|
|
3444
|
+
);
|
|
3445
|
+
|
|
3446
|
+
// Portal should mount after initial render
|
|
3447
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3448
|
+
await waitForDialog();
|
|
3449
|
+
|
|
3450
|
+
// Dialog should be portaled to document.body
|
|
3451
|
+
const dialog = document.querySelector('dialog[role="dialog"]');
|
|
3452
|
+
expect(dialog?.parentElement).toBe(document.body);
|
|
3453
|
+
});
|
|
3454
|
+
});
|
|
3455
|
+
|
|
3456
|
+
describe('DialogContent Title and Description Updates', () => {
|
|
3457
|
+
it('updates title attribute when title prop changes', async () => {
|
|
3458
|
+
const user = userEvent.setup();
|
|
3459
|
+
const { rerender } = renderWithProviders(
|
|
3460
|
+
<Dialog open={true}>
|
|
3461
|
+
<DialogContent title="Original Title">
|
|
3462
|
+
<DialogHeader>
|
|
3463
|
+
<h2>Original Title</h2>
|
|
3464
|
+
</DialogHeader>
|
|
3465
|
+
</DialogContent>
|
|
3466
|
+
</Dialog>
|
|
3467
|
+
);
|
|
3468
|
+
|
|
3469
|
+
await waitForDialog();
|
|
3470
|
+
let dialog = document.querySelector('dialog[role="dialog"]');
|
|
3471
|
+
expect(dialog).toHaveAttribute('title', 'Original Title');
|
|
3472
|
+
|
|
3473
|
+
// Update title
|
|
3474
|
+
rerender(
|
|
3475
|
+
<Dialog open={true}>
|
|
3476
|
+
<DialogContent title="Updated Title">
|
|
3477
|
+
<DialogHeader>
|
|
3478
|
+
<h2>Updated Title</h2>
|
|
3479
|
+
</DialogHeader>
|
|
3480
|
+
</DialogContent>
|
|
3481
|
+
</Dialog>
|
|
3482
|
+
);
|
|
3483
|
+
|
|
3484
|
+
await waitFor(() => {
|
|
3485
|
+
dialog = document.querySelector('dialog[role="dialog"]');
|
|
3486
|
+
expect(dialog).toHaveAttribute('title', 'Updated Title');
|
|
3487
|
+
});
|
|
3488
|
+
});
|
|
3489
|
+
|
|
3490
|
+
it('updates aria-description when description prop changes', async () => {
|
|
3491
|
+
const user = userEvent.setup();
|
|
3492
|
+
const { rerender } = renderWithProviders(
|
|
3493
|
+
<Dialog open={true}>
|
|
3494
|
+
<DialogContent title="Test Dialog" description="Original Description">
|
|
3495
|
+
<DialogHeader>
|
|
3496
|
+
<h2>Test Dialog</h2>
|
|
3497
|
+
</DialogHeader>
|
|
3498
|
+
</DialogContent>
|
|
3499
|
+
</Dialog>
|
|
3500
|
+
);
|
|
3501
|
+
|
|
3502
|
+
await waitForDialog();
|
|
3503
|
+
let dialog = document.querySelector('dialog[role="dialog"]');
|
|
3504
|
+
expect(dialog).toHaveAttribute('aria-description', 'Original Description');
|
|
3505
|
+
|
|
3506
|
+
// Update description
|
|
3507
|
+
rerender(
|
|
3508
|
+
<Dialog open={true}>
|
|
3509
|
+
<DialogContent title="Test Dialog" description="Updated Description">
|
|
3510
|
+
<DialogHeader>
|
|
3511
|
+
<h2>Test Dialog</h2>
|
|
3512
|
+
</DialogHeader>
|
|
3513
|
+
</DialogContent>
|
|
3514
|
+
</Dialog>
|
|
3515
|
+
);
|
|
3516
|
+
|
|
3517
|
+
await waitFor(() => {
|
|
3518
|
+
dialog = document.querySelector('dialog[role="dialog"]');
|
|
3519
|
+
expect(dialog).toHaveAttribute('aria-description', 'Updated Description');
|
|
3520
|
+
});
|
|
3521
|
+
});
|
|
3522
|
+
});
|
|
3523
|
+
|
|
3524
|
+
describe('DialogContent Size and Dimension Combinations', () => {
|
|
3525
|
+
it('handles size with custom maxWidth override', async () => {
|
|
3526
|
+
const user = userEvent.setup();
|
|
3527
|
+
|
|
3528
|
+
renderWithProviders(
|
|
3529
|
+
<Dialog>
|
|
3530
|
+
<DialogTrigger asChild>
|
|
3531
|
+
<button>Open Dialog</button>
|
|
3532
|
+
</DialogTrigger>
|
|
3533
|
+
<DialogContent size="md" maxWidth="1200px" title="Test Dialog">
|
|
3534
|
+
<DialogHeader>
|
|
3535
|
+
<h2>Test Dialog</h2>
|
|
3536
|
+
</DialogHeader>
|
|
3537
|
+
</DialogContent>
|
|
3538
|
+
</Dialog>
|
|
3539
|
+
);
|
|
3540
|
+
|
|
3541
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3542
|
+
const dialog = await waitForDialog();
|
|
3543
|
+
|
|
3544
|
+
// Custom maxWidth should override size class
|
|
3545
|
+
expect(dialog).toHaveStyle({ maxWidth: '1200px' });
|
|
3546
|
+
});
|
|
3547
|
+
|
|
3548
|
+
it('handles size with custom maxHeight override', async () => {
|
|
3549
|
+
const user = userEvent.setup();
|
|
3550
|
+
|
|
3551
|
+
renderWithProviders(
|
|
3552
|
+
<Dialog>
|
|
3553
|
+
<DialogTrigger asChild>
|
|
3554
|
+
<button>Open Dialog</button>
|
|
3555
|
+
</DialogTrigger>
|
|
3556
|
+
<DialogContent size="lg" maxHeight="600px" title="Test Dialog">
|
|
3557
|
+
<DialogHeader>
|
|
3558
|
+
<h2>Test Dialog</h2>
|
|
3559
|
+
</DialogHeader>
|
|
3560
|
+
</DialogContent>
|
|
3561
|
+
</Dialog>
|
|
3562
|
+
);
|
|
3563
|
+
|
|
3564
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3565
|
+
const dialog = await waitForDialog();
|
|
3566
|
+
|
|
3567
|
+
expect(dialog).toHaveStyle({ maxHeight: '600px' });
|
|
3568
|
+
});
|
|
3569
|
+
});
|
|
3570
|
+
|
|
3571
|
+
describe('DialogContent enableScrolling Behavior', () => {
|
|
3572
|
+
it('applies flex layout when enableScrolling is true', async () => {
|
|
3573
|
+
const user = userEvent.setup();
|
|
3574
|
+
|
|
3575
|
+
renderWithProviders(
|
|
3576
|
+
<Dialog>
|
|
3577
|
+
<DialogTrigger asChild>
|
|
3578
|
+
<button>Open Dialog</button>
|
|
3579
|
+
</DialogTrigger>
|
|
3580
|
+
<DialogContent title="Test Dialog" enableScrolling>
|
|
3581
|
+
<DialogHeader>
|
|
3582
|
+
<h2>Test Dialog</h2>
|
|
3583
|
+
</DialogHeader>
|
|
3584
|
+
<DialogBody>
|
|
3585
|
+
<p>Content</p>
|
|
3586
|
+
</DialogBody>
|
|
3587
|
+
</DialogContent>
|
|
3588
|
+
</Dialog>
|
|
3589
|
+
);
|
|
3590
|
+
|
|
3591
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3592
|
+
const dialog = await waitForDialog();
|
|
3593
|
+
|
|
3594
|
+
expect(dialog).toHaveClass('flex', 'flex-col');
|
|
3595
|
+
});
|
|
3596
|
+
|
|
3597
|
+
it('applies default maxHeightPercent when enableScrolling is true', async () => {
|
|
3598
|
+
const user = userEvent.setup();
|
|
3599
|
+
|
|
3600
|
+
renderWithProviders(
|
|
3601
|
+
<Dialog>
|
|
3602
|
+
<DialogTrigger asChild>
|
|
3603
|
+
<button>Open Dialog</button>
|
|
3604
|
+
</DialogTrigger>
|
|
3605
|
+
<DialogContent title="Test Dialog" enableScrolling>
|
|
3606
|
+
<DialogHeader>
|
|
3607
|
+
<h2>Test Dialog</h2>
|
|
3608
|
+
</DialogHeader>
|
|
3609
|
+
<DialogBody>
|
|
3610
|
+
<p>Content</p>
|
|
3611
|
+
</DialogBody>
|
|
3612
|
+
</DialogContent>
|
|
3613
|
+
</Dialog>
|
|
3614
|
+
);
|
|
3615
|
+
|
|
3616
|
+
await user.click(screen.getByRole('button', { name: 'Open Dialog' }));
|
|
3617
|
+
const dialog = await waitForDialog();
|
|
3618
|
+
|
|
3619
|
+
// Should have default 80vh maxHeight when enableScrolling is true
|
|
3620
|
+
expect(dialog).toHaveStyle({ maxHeight: '80vh' });
|
|
3621
|
+
});
|
|
3622
|
+
});
|
|
2816
3623
|
});
|