@jmruthers/pace-core 0.6.5 → 0.6.7
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 +104 -0
- package/README.md +5 -403
- package/audit-tool/00-dependencies.cjs +394 -0
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +255 -0
- package/audit-tool/audits/03-architecture.cjs +196 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +544 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +291 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +241 -0
- package/core-usage-manifest.json +93 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/01-pace-core-compliance.mdc +586 -0
- package/cursor-rules/02-project-structure.mdc +42 -4
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
- package/cursor-rules/06-security-rbac.mdc +518 -0
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
- package/dist/chunk-6F3IILHI.js +62 -0
- package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
- package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
- package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
- package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
- package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/chunk-GHYHJTYV.js +994 -0
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
- package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
- package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
- package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
- package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
- package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
- package/dist/components.d.ts +7 -5
- package/dist/components.js +46 -257
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +35 -0
- package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
- package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/eslint-rules/utils/helpers.cjs +42 -0
- package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.js +62 -172
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +67 -660
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +8 -35
- package/dist/rbac/eslint-rules.d.ts +46 -44
- package/dist/rbac/eslint-rules.js +7 -4
- package/dist/rbac/index.d.ts +109 -586
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +3 -19
- package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
- package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +17 -7
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +301 -871
- package/docs/api-reference/components.md +21 -21
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +126 -33
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +5 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +17 -8
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -35
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/1-pace-core-compliance-standards.md +986 -0
- package/docs/standards/2-project-structure-standards.md +949 -0
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/5-styling-standards.md +348 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +185 -57
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +33 -6
- package/package.json +35 -23
- package/scripts/install-cursor-rules.cjs +25 -6
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +106 -119
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +12 -9
- package/src/components/DataTable/components/EmptyState.tsx +10 -9
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
- package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
- package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
- package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
- package/src/components/DataTable/types.ts +5 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +10 -9
- package/src/components/Dialog/Dialog.test.tsx +128 -104
- package/src/components/Dialog/Dialog.tsx +742 -24
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
- package/src/components/FileDisplay/FileDisplay.tsx +23 -17
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Form/Form.test.tsx +6 -8
- package/src/components/Form/Form.tsx +365 -4
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +109 -98
- package/src/components/Select/types.ts +4 -1
- package/src/components/UserMenu/UserMenu.tsx +9 -6
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
- package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
- package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
- package/src/hooks/public/usePublicEvent.ts +67 -195
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +24 -14
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +28 -26
- package/src/hooks/useEventTheme.test.ts +217 -239
- package/src/hooks/useEventTheme.ts +16 -28
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useOrganisationPermissions.ts +5 -7
- package/src/hooks/useQueryCache.ts +0 -1
- package/src/hooks/useSessionDraft.ts +380 -0
- package/src/hooks/useSessionRestoration.ts +3 -1
- package/src/icons/index.ts +27 -0
- package/src/index.ts +5 -0
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
- package/src/rbac/adapters.tsx +7 -295
- package/src/rbac/api.test.ts +44 -56
- package/src/rbac/api.ts +10 -17
- package/src/rbac/cache-invalidation.ts +0 -1
- package/src/rbac/compliance/index.ts +10 -0
- package/src/rbac/compliance/pattern-detector.ts +553 -0
- package/src/rbac/compliance/runtime-compliance.ts +22 -0
- package/src/rbac/components/AccessDenied.tsx +150 -0
- package/src/rbac/components/NavigationGuard.tsx +12 -20
- package/src/rbac/components/PagePermissionGuard.tsx +4 -24
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
- package/src/rbac/components/index.ts +3 -41
- package/src/rbac/eslint-rules.js +1 -1
- package/src/rbac/hooks/index.ts +0 -3
- package/src/rbac/hooks/permissions/index.ts +0 -3
- package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
- package/src/rbac/hooks/usePermissions.ts +0 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
- package/src/rbac/hooks/useResolvedScope.ts +58 -140
- package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
- package/src/rbac/hooks/useResourcePermissions.ts +139 -48
- package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
- package/src/rbac/hooks/useRoleManagement.ts +147 -19
- package/src/rbac/hooks/useSecureSupabase.ts +4 -8
- package/src/rbac/index.ts +7 -9
- package/src/rbac/utils/contextValidator.ts +9 -7
- package/src/services/AuthService.ts +130 -18
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +16 -0
- package/src/services/OrganisationService.ts +7 -44
- package/src/services/__tests__/OrganisationService.test.ts +26 -8
- package/src/services/base/BaseService.ts +0 -3
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +9 -3
- package/src/theming/parseEventColours.ts +22 -10
- package/src/types/database.generated.ts +4733 -3809
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
- package/src/utils/context/organisationContext.test.ts +13 -28
- package/src/utils/context/organisationContext.ts +21 -52
- package/src/utils/dynamic/dynamicUtils.ts +1 -1
- package/src/utils/file-reference/index.ts +39 -15
- package/src/utils/formatting/formatDateTime.test.ts +3 -2
- package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
- package/src/utils/index.ts +4 -1
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
- package/src/utils/persistence/keyDerivation.ts +304 -0
- package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
- package/src/utils/security/secureStorage.ts +5 -5
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/helpers.ts +3 -3
- package/src/utils/supabase/createBaseClient.ts +147 -0
- package/src/utils/timezone/timezone.test.ts +1 -2
- package/src/utils/timezone/timezone.ts +1 -1
- package/src/utils/validation/csrf.ts +4 -4
- package/cursor-rules/00-pace-core-compliance.mdc +0 -331
- package/cursor-rules/01-standards-compliance.mdc +0 -244
- package/cursor-rules/04-testing-standards.mdc +0 -268
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
- package/cursor-rules/06-code-quality.mdc +0 -309
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
- package/cursor-rules/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-AOVNCPTX.js +0 -175
- package/dist/DataTable-AOVNCPTX.js.map +0 -1
- package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
- package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
- package/dist/api-O6HTBX5Y.js +0 -52
- package/dist/api-O6HTBX5Y.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6COVEUS7.js.map +0 -1
- package/dist/chunk-AFVQODI2.js +0 -263
- package/dist/chunk-AFVQODI2.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.js.map +0 -1
- package/dist/chunk-EFN2EIMK.js.map +0 -1
- package/dist/chunk-FFQEQTNW.js.map +0 -1
- package/dist/chunk-FMUCXFII.js.map +0 -1
- package/dist/chunk-G37KK66H.js.map +0 -1
- package/dist/chunk-G7QEZTYQ.js +0 -2053
- package/dist/chunk-G7QEZTYQ.js.map +0 -1
- package/dist/chunk-HU2C6SSC.js.map +0 -1
- package/dist/chunk-IHB5DR3H.js.map +0 -1
- package/dist/chunk-IVOFDYWT.js.map +0 -1
- package/dist/chunk-J36DSWQK.js.map +0 -1
- package/dist/chunk-JGRYX5UX.js.map +0 -1
- package/dist/chunk-KQCRWDSA.js +0 -1
- package/dist/chunk-KQCRWDSA.js.map +0 -1
- package/dist/chunk-L4OXEN46.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-M43Y4SSO.js.map +0 -1
- package/dist/chunk-M7MPQISP.js.map +0 -1
- package/dist/chunk-NTM7ZSB6.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-RGAWHO7N.js.map +0 -1
- package/dist/chunk-UPPMRMYG.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-5OGXSPKS.js +0 -9
- package/dist/contextValidator-5OGXSPKS.js.map +0 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
- package/dist/hooks.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers.js.map +0 -1
- package/dist/rbac/eslint-rules.js.map +0 -1
- package/dist/rbac/index.js.map +0 -1
- package/dist/styles/index.js.map +0 -1
- package/dist/theming/runtime.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -601
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-architecture-standard.md +0 -44
- package/docs/standards/02-api-and-rpc-standard.md +0 -39
- package/docs/standards/03-component-standard.md +0 -32
- package/docs/standards/04-code-style-standard.md +0 -32
- package/docs/standards/05-security-standard.md +0 -44
- package/docs/standards/06-testing-and-docs-standard.md +0 -29
- package/docs/standards/pace-core-compliance.md +0 -432
- package/scripts/audit/core/checks/accessibility.cjs +0 -197
- package/scripts/audit/core/checks/api-usage.cjs +0 -191
- package/scripts/audit/core/checks/bundle.cjs +0 -142
- package/scripts/audit/core/checks/compliance.cjs +0 -2706
- package/scripts/audit/core/checks/config.cjs +0 -54
- package/scripts/audit/core/checks/coverage.cjs +0 -84
- package/scripts/audit/core/checks/dependencies.cjs +0 -994
- package/scripts/audit/core/checks/documentation.cjs +0 -268
- package/scripts/audit/core/checks/environment.cjs +0 -116
- package/scripts/audit/core/checks/error-handling.cjs +0 -340
- package/scripts/audit/core/checks/forms.cjs +0 -172
- package/scripts/audit/core/checks/heuristics.cjs +0 -68
- package/scripts/audit/core/checks/hooks.cjs +0 -334
- package/scripts/audit/core/checks/imports.cjs +0 -244
- package/scripts/audit/core/checks/performance.cjs +0 -325
- package/scripts/audit/core/checks/routes.cjs +0 -117
- package/scripts/audit/core/checks/state.cjs +0 -130
- package/scripts/audit/core/checks/structure.cjs +0 -65
- package/scripts/audit/core/checks/style.cjs +0 -584
- package/scripts/audit/core/checks/testing.cjs +0 -122
- package/scripts/audit/core/checks/typescript.cjs +0 -61
- package/scripts/audit/core/scanner.cjs +0 -199
- package/scripts/audit/core/utils.cjs +0 -137
- package/scripts/audit/index.cjs +0 -223
- package/scripts/audit/reporters/console.cjs +0 -151
- package/scripts/audit/reporters/json.cjs +0 -54
- package/scripts/audit/reporters/markdown.cjs +0 -124
- package/scripts/audit-consuming-app.cjs +0 -86
- package/src/components/DataTable/components/DataTableBody.tsx +0 -454
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/pace-core-compliance.js +0 -638
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
- package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
- package/src/rbac/components/NavigationProvider.test.tsx +0 -481
- package/src/rbac/components/NavigationProvider.tsx +0 -345
- package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
- package/src/rbac/components/PagePermissionProvider.tsx +0 -279
- package/src/rbac/components/PermissionEnforcer.tsx +0 -312
- package/src/rbac/components/RoleBasedRouter.tsx +0 -440
- package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
- package/src/rbac/components/SecureDataProvider.tsx +0 -339
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
|
@@ -1,516 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
lastUpdated: 2025-11-18T17:00:00+11:00
|
|
3
|
-
version: 0.5.181
|
|
4
|
-
reviewedBy: documentation-standards-audit
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Common Patterns & Best Practices
|
|
8
|
-
|
|
9
|
-
> **📚 Common Patterns** | [← Back to Documentation](./README.md) | [Quick Start](./getting-started/quick-start.md) | [API Reference](./api-reference/components.md)
|
|
10
|
-
|
|
11
|
-
Reusable patterns and best practices for building with PACE Core.
|
|
12
|
-
|
|
13
|
-
## Table of Contents
|
|
14
|
-
|
|
15
|
-
1. [Authentication Patterns](#authentication-patterns)
|
|
16
|
-
2. [Permission Patterns](#permission-patterns)
|
|
17
|
-
3. [Data Fetching Patterns](#data-fetching-patterns)
|
|
18
|
-
4. [Form Handling Patterns](#form-handling-patterns)
|
|
19
|
-
5. [Error Handling Patterns](#error-handling-patterns)
|
|
20
|
-
6. [UI Patterns](#ui-patterns)
|
|
21
|
-
|
|
22
|
-
## Authentication Patterns
|
|
23
|
-
|
|
24
|
-
### Basic Authentication Setup
|
|
25
|
-
|
|
26
|
-
```tsx
|
|
27
|
-
import { UnifiedAuthProvider } from '@jmruthers/pace-core';
|
|
28
|
-
import { supabase } from './lib/supabase';
|
|
29
|
-
|
|
30
|
-
function App() {
|
|
31
|
-
return (
|
|
32
|
-
<UnifiedAuthProvider
|
|
33
|
-
supabaseClient={supabase}
|
|
34
|
-
appName="my-app"
|
|
35
|
-
idleTimeoutMs={30 * 60 * 1000}
|
|
36
|
-
warnBeforeMs={5 * 60 * 1000}
|
|
37
|
-
onIdleLogout={() => window.location.href = '/login'}
|
|
38
|
-
>
|
|
39
|
-
<YourApp />
|
|
40
|
-
</UnifiedAuthProvider>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Protected Routes
|
|
46
|
-
|
|
47
|
-
**✅ Use the standard ProtectedRoute component from pace-core:**
|
|
48
|
-
|
|
49
|
-
```tsx
|
|
50
|
-
import { ProtectedRoute } from '@jmruthers/pace-core';
|
|
51
|
-
import { Routes, Route } from 'react-router-dom';
|
|
52
|
-
|
|
53
|
-
function App() {
|
|
54
|
-
return (
|
|
55
|
-
<Routes>
|
|
56
|
-
<Route path="/login" element={<LoginPage />} />
|
|
57
|
-
{/* Routes requiring authentication and event selection */}
|
|
58
|
-
<Route element={<ProtectedRoute />}>
|
|
59
|
-
<Route path="/dashboard" element={<DashboardPage />} />
|
|
60
|
-
</Route>
|
|
61
|
-
{/* Routes requiring authentication only (no event needed) */}
|
|
62
|
-
<Route element={<ProtectedRoute requireEvent={false} />}>
|
|
63
|
-
<Route path="/settings" element={<SettingsPage />} />
|
|
64
|
-
</Route>
|
|
65
|
-
</Routes>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
**Why use the standard component?**
|
|
71
|
-
- Prevents the chicken-and-egg problem where checking `selectedEvent` blocks the event selector from being visible
|
|
72
|
-
- Handles session restoration automatically
|
|
73
|
-
- Manages loading states properly
|
|
74
|
-
- Provides consistent behavior across all pace apps
|
|
75
|
-
|
|
76
|
-
**❌ Avoid custom ProtectedRoute implementations that block rendering when no event is selected**, as this prevents users from seeing the event selector dropdown in the header.
|
|
77
|
-
|
|
78
|
-
### Session Management
|
|
79
|
-
|
|
80
|
-
```tsx
|
|
81
|
-
import { useUnifiedAuth } from '@jmruthers/pace-core';
|
|
82
|
-
|
|
83
|
-
function UserMenu() {
|
|
84
|
-
const { user, signOut } = useUnifiedAuth();
|
|
85
|
-
|
|
86
|
-
const handleSignOut = async () => {
|
|
87
|
-
await signOut();
|
|
88
|
-
window.location.href = '/login';
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
return (
|
|
92
|
-
<div>
|
|
93
|
-
<p>Welcome, {user?.email}</p>
|
|
94
|
-
<button onClick={handleSignOut}>Sign Out</button>
|
|
95
|
-
</div>
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Permission Patterns
|
|
101
|
-
|
|
102
|
-
### Basic Permission Check
|
|
103
|
-
|
|
104
|
-
```tsx
|
|
105
|
-
import { useCan } from '@jmruthers/pace-core';
|
|
106
|
-
|
|
107
|
-
function UserActions({ userId, organisationId }) {
|
|
108
|
-
const { hasPermission, isLoading } = useCan();
|
|
109
|
-
const [canEdit, setCanEdit] = useState(false);
|
|
110
|
-
|
|
111
|
-
useEffect(() => {
|
|
112
|
-
if (!isLoading) {
|
|
113
|
-
hasPermission('update:users', { userId, organisationId })
|
|
114
|
-
.then(setCanEdit);
|
|
115
|
-
}
|
|
116
|
-
}, [hasPermission, isLoading, userId, organisationId]);
|
|
117
|
-
|
|
118
|
-
return (
|
|
119
|
-
<div>
|
|
120
|
-
{canEdit && <EditButton />}
|
|
121
|
-
<ViewButton />
|
|
122
|
-
</div>
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### Permission-Guided UI
|
|
128
|
-
|
|
129
|
-
```tsx
|
|
130
|
-
import { useCan } from '@jmruthers/pace-core';
|
|
131
|
-
import { Button, Card } from '@jmruthers/pace-core';
|
|
132
|
-
|
|
133
|
-
function UserManagement() {
|
|
134
|
-
const { hasPermission } = useCan();
|
|
135
|
-
const [canCreate, setCanCreate] = useState(false);
|
|
136
|
-
const [canDelete, setCanDelete] = useState(false);
|
|
137
|
-
|
|
138
|
-
useEffect(() => {
|
|
139
|
-
const checkPermissions = async () => {
|
|
140
|
-
setCanCreate(await hasPermission('create:users'));
|
|
141
|
-
setCanDelete(await hasPermission('delete:users'));
|
|
142
|
-
};
|
|
143
|
-
checkPermissions();
|
|
144
|
-
}, [hasPermission]);
|
|
145
|
-
|
|
146
|
-
return (
|
|
147
|
-
<Card>
|
|
148
|
-
{canCreate && (
|
|
149
|
-
<Button onClick={handleCreate}>Create User</Button>
|
|
150
|
-
)}
|
|
151
|
-
{canDelete && (
|
|
152
|
-
<Button variant="destructive" onClick={handleDelete}>
|
|
153
|
-
Delete Selected
|
|
154
|
-
</Button>
|
|
155
|
-
)}
|
|
156
|
-
</Card>
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### Batch Permission Checking
|
|
162
|
-
|
|
163
|
-
```tsx
|
|
164
|
-
import { usePermissions } from '@jmruthers/pace-core';
|
|
165
|
-
|
|
166
|
-
function AdminDashboard() {
|
|
167
|
-
const { permissions, isLoading } = usePermissions({
|
|
168
|
-
userId,
|
|
169
|
-
organisationId
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
const canUpdate = permissions.includes('update:users') ||
|
|
173
|
-
permissions.includes('update:settings');
|
|
174
|
-
|
|
175
|
-
return (
|
|
176
|
-
<div>
|
|
177
|
-
{isLoading && <div>Loading...</div>}
|
|
178
|
-
{canUpdate && <AdminPanel />}
|
|
179
|
-
</div>
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
## Data Fetching Patterns
|
|
185
|
-
|
|
186
|
-
### Fetch with Permissions
|
|
187
|
-
|
|
188
|
-
```tsx
|
|
189
|
-
import { useCan } from '@jmruthers/pace-core';
|
|
190
|
-
|
|
191
|
-
function UserList({ organisationId }) {
|
|
192
|
-
const { hasPermission } = useCan();
|
|
193
|
-
const [data, setData] = useState([]);
|
|
194
|
-
const [loading, setLoading] = useState(true);
|
|
195
|
-
|
|
196
|
-
useEffect(() => {
|
|
197
|
-
const fetchData = async () => {
|
|
198
|
-
const canRead = await hasPermission('read:users', { organisationId });
|
|
199
|
-
if (canRead) {
|
|
200
|
-
const users = await supabase
|
|
201
|
-
.from('users')
|
|
202
|
-
.select('*');
|
|
203
|
-
setData(users.data || []);
|
|
204
|
-
}
|
|
205
|
-
setLoading(false);
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
fetchData();
|
|
209
|
-
}, [hasPermission, organisationId]);
|
|
210
|
-
|
|
211
|
-
if (loading) return <div>Loading...</div>;
|
|
212
|
-
return <DataTable data={data} />;
|
|
213
|
-
}
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### Real-time Data with Permissions
|
|
217
|
-
|
|
218
|
-
```tsx
|
|
219
|
-
import { useEffect, useState } from 'react';
|
|
220
|
-
import { useCan } from '@jmruthers/pace-core';
|
|
221
|
-
|
|
222
|
-
function LiveData({ organisationId }) {
|
|
223
|
-
const { hasPermission } = useCan();
|
|
224
|
-
const [data, setData] = useState([]);
|
|
225
|
-
|
|
226
|
-
useEffect(() => {
|
|
227
|
-
const checkAndSubscribe = async () => {
|
|
228
|
-
const canRead = await hasPermission('read:data', { organisationId });
|
|
229
|
-
|
|
230
|
-
if (canRead) {
|
|
231
|
-
const subscription = supabase
|
|
232
|
-
.channel('data')
|
|
233
|
-
.on('postgres_changes',
|
|
234
|
-
{ event: '*', schema: 'public', table: 'data' },
|
|
235
|
-
(payload) => {
|
|
236
|
-
setData(prev => [...prev, payload.new]);
|
|
237
|
-
}
|
|
238
|
-
)
|
|
239
|
-
.subscribe();
|
|
240
|
-
|
|
241
|
-
return () => {
|
|
242
|
-
supabase.removeChannel(subscription);
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
checkAndSubscribe();
|
|
248
|
-
}, [hasPermission, organisationId]);
|
|
249
|
-
|
|
250
|
-
return <DataTable data={data} />;
|
|
251
|
-
}
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
## Form Handling Patterns
|
|
255
|
-
|
|
256
|
-
### Basic Form with Validation
|
|
257
|
-
|
|
258
|
-
```tsx
|
|
259
|
-
import { Form, Input, Button } from '@jmruthers/pace-core';
|
|
260
|
-
|
|
261
|
-
function UserForm() {
|
|
262
|
-
const [errors, setErrors] = useState({});
|
|
263
|
-
|
|
264
|
-
const validate = (data) => {
|
|
265
|
-
const newErrors = {};
|
|
266
|
-
if (!data.email) newErrors.email = 'Email required';
|
|
267
|
-
if (!data.name) newErrors.name = 'Name required';
|
|
268
|
-
return newErrors;
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
const handleSubmit = async (data) => {
|
|
272
|
-
const newErrors = validate(data);
|
|
273
|
-
if (Object.keys(newErrors).length) {
|
|
274
|
-
setErrors(newErrors);
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
await supabase.from('users').insert(data);
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
return (
|
|
282
|
-
<Form onSubmit={handleSubmit}>
|
|
283
|
-
<Input name="name" error={errors.name} />
|
|
284
|
-
<Input name="email" type="email" error={errors.email} />
|
|
285
|
-
<Button type="submit">Save</Button>
|
|
286
|
-
</Form>
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
### Form with Permission Checks
|
|
292
|
-
|
|
293
|
-
```tsx
|
|
294
|
-
import { useCan } from '@jmruthers/pace-core';
|
|
295
|
-
|
|
296
|
-
function EditableForm({ user, organisationId }) {
|
|
297
|
-
const { hasPermission } = useCan();
|
|
298
|
-
const [canEdit, setCanEdit] = useState(false);
|
|
299
|
-
|
|
300
|
-
useEffect(() => {
|
|
301
|
-
hasPermission('update:users', { organisationId })
|
|
302
|
-
.then(setCanEdit);
|
|
303
|
-
}, [hasPermission, organisationId]);
|
|
304
|
-
|
|
305
|
-
return (
|
|
306
|
-
<Form initialValues={user}>
|
|
307
|
-
<Input name="name" disabled={!canEdit} />
|
|
308
|
-
<Input name="email" disabled={!canEdit} />
|
|
309
|
-
{canEdit && <Button type="submit">Save Changes</Button>}
|
|
310
|
-
</Form>
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
## Error Handling Patterns
|
|
316
|
-
|
|
317
|
-
### Comprehensive Error Handling
|
|
318
|
-
|
|
319
|
-
```tsx
|
|
320
|
-
import { useState } from 'react';
|
|
321
|
-
import { Alert } from '@jmruthers/pace-core';
|
|
322
|
-
|
|
323
|
-
function DataFetcher() {
|
|
324
|
-
const [data, setData] = useState([]);
|
|
325
|
-
const [loading, setLoading] = useState(true);
|
|
326
|
-
const [error, setError] = useState<string | null>(null);
|
|
327
|
-
|
|
328
|
-
useEffect(() => {
|
|
329
|
-
const fetchData = async () => {
|
|
330
|
-
try {
|
|
331
|
-
setLoading(true);
|
|
332
|
-
setError(null);
|
|
333
|
-
|
|
334
|
-
const { data: result, error: fetchError } = await supabase
|
|
335
|
-
.from('users')
|
|
336
|
-
.select('*');
|
|
337
|
-
|
|
338
|
-
if (fetchError) throw fetchError;
|
|
339
|
-
setData(result || []);
|
|
340
|
-
} catch (err) {
|
|
341
|
-
setError(err instanceof Error ? err.message : 'Unknown error');
|
|
342
|
-
} finally {
|
|
343
|
-
setLoading(false);
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
fetchData();
|
|
348
|
-
}, []);
|
|
349
|
-
|
|
350
|
-
if (loading) return <div>Loading...</div>;
|
|
351
|
-
if (error) return <Alert variant="destructive">{error}</Alert>;
|
|
352
|
-
return <DataTable data={data} />;
|
|
353
|
-
}
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
### Loading States
|
|
357
|
-
|
|
358
|
-
```tsx
|
|
359
|
-
import { useState } from 'react';
|
|
360
|
-
|
|
361
|
-
function AsyncComponent() {
|
|
362
|
-
const [loading, setLoading] = useState(true);
|
|
363
|
-
const [error, setError] = useState<string | null>(null);
|
|
364
|
-
const [data, setData] = useState(null);
|
|
365
|
-
|
|
366
|
-
useEffect(() => {
|
|
367
|
-
fetchData().then(setData).catch(setError).finally(() => setLoading(false));
|
|
368
|
-
}, []);
|
|
369
|
-
|
|
370
|
-
if (loading) return <LoadingSpinner />;
|
|
371
|
-
if (error) return <ErrorMessage error={error} />;
|
|
372
|
-
return <DataDisplay data={data} />;
|
|
373
|
-
}
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
## UI Patterns
|
|
377
|
-
|
|
378
|
-
### Conditional Rendering with Permissions
|
|
379
|
-
|
|
380
|
-
```tsx
|
|
381
|
-
import { useCan } from '@jmruthers/pace-core';
|
|
382
|
-
import { Button } from '@jmruthers/pace-core';
|
|
383
|
-
|
|
384
|
-
function ActionButtons() {
|
|
385
|
-
const { hasPermission } = useCan();
|
|
386
|
-
const [canEdit, setCanEdit] = useState(false);
|
|
387
|
-
const [canDelete, setCanDelete] = useState(false);
|
|
388
|
-
|
|
389
|
-
useEffect(() => {
|
|
390
|
-
Promise.all([
|
|
391
|
-
hasPermission('update:users'),
|
|
392
|
-
hasPermission('delete:users')
|
|
393
|
-
]).then(([edit, del]) => {
|
|
394
|
-
setCanEdit(edit);
|
|
395
|
-
setCanDelete(del);
|
|
396
|
-
});
|
|
397
|
-
}, [hasPermission]);
|
|
398
|
-
|
|
399
|
-
return (
|
|
400
|
-
<div className="flex gap-2">
|
|
401
|
-
{canEdit && <Button>Edit</Button>}
|
|
402
|
-
{canDelete && <Button variant="destructive">Delete</Button>}
|
|
403
|
-
<Button>View</Button>
|
|
404
|
-
</div>
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
### Modal with Confirmation
|
|
410
|
-
|
|
411
|
-
```tsx
|
|
412
|
-
import { Dialog, Button } from '@jmruthers/pace-core';
|
|
413
|
-
import { useState } from 'react';
|
|
414
|
-
|
|
415
|
-
function DeleteConfirmation({ item, onConfirm }) {
|
|
416
|
-
const [open, setOpen] = useState(false);
|
|
417
|
-
|
|
418
|
-
return (
|
|
419
|
-
<>
|
|
420
|
-
<Button variant="destructive" onClick={() => setOpen(true)}>
|
|
421
|
-
Delete
|
|
422
|
-
</Button>
|
|
423
|
-
|
|
424
|
-
<Dialog open={open} onOpenChange={setOpen}>
|
|
425
|
-
<Dialog.Header>Confirm Delete</Dialog.Header>
|
|
426
|
-
<Dialog.Content>
|
|
427
|
-
<p>Are you sure you want to delete {item.name}?</p>
|
|
428
|
-
</Dialog.Content>
|
|
429
|
-
<Dialog.Footer>
|
|
430
|
-
<Button variant="ghost" onClick={() => setOpen(false)}>
|
|
431
|
-
Cancel
|
|
432
|
-
</Button>
|
|
433
|
-
<Button variant="destructive" onClick={onConfirm}>
|
|
434
|
-
Delete
|
|
435
|
-
</Button>
|
|
436
|
-
</Dialog.Footer>
|
|
437
|
-
</Dialog>
|
|
438
|
-
</>
|
|
439
|
-
);
|
|
440
|
-
}
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
## Best Practices Summary
|
|
444
|
-
|
|
445
|
-
### Do's ✅
|
|
446
|
-
|
|
447
|
-
- Always check permissions before showing sensitive UI
|
|
448
|
-
- Include loading and error states in async operations
|
|
449
|
-
- Use TypeScript for type safety
|
|
450
|
-
- Handle errors gracefully with user-friendly messages
|
|
451
|
-
- Cache permission checks when possible
|
|
452
|
-
- Use proper loading states for better UX
|
|
453
|
-
|
|
454
|
-
### Don'ts ❌
|
|
455
|
-
|
|
456
|
-
- Don't assume permissions without checking
|
|
457
|
-
- Don't fetch data without permission validation
|
|
458
|
-
- Don't forget to handle loading and error states
|
|
459
|
-
- Don't expose sensitive operations without checks
|
|
460
|
-
- Don't skip TypeScript types in examples
|
|
461
|
-
- Don't forget to import CSS files
|
|
462
|
-
|
|
463
|
-
## Next Steps
|
|
464
|
-
|
|
465
|
-
- **[Installation Guide](./getting-started/installation-guide.md)** - Set up PACE Core
|
|
466
|
-
- **[RBAC Guide](./rbac/README.md)** - Learn about permissions
|
|
467
|
-
- **[Implementation Guides](./implementation-guides/)** - Explore specific features
|
|
468
|
-
- **[API Reference](./api-reference/components.md)** - Component documentation
|
|
469
|
-
|
|
470
|
-
## ♿ Accessibility
|
|
471
|
-
|
|
472
|
-
Common patterns should maintain accessibility:
|
|
473
|
-
|
|
474
|
-
- **Patterns include accessibility features** - All patterns should consider accessibility
|
|
475
|
-
- **Keyboard navigation is supported** - Patterns should support keyboard navigation
|
|
476
|
-
- **Screen reader compatibility** - Patterns should work with screen readers
|
|
477
|
-
- **Focus management** - Patterns should handle focus correctly
|
|
478
|
-
- **ARIA labels are included** - Patterns should include proper ARIA labels
|
|
479
|
-
|
|
480
|
-
### Accessibility Best Practices
|
|
481
|
-
|
|
482
|
-
1. **Test patterns with screen readers** - Verify patterns work with assistive technologies
|
|
483
|
-
2. **Ensure keyboard access** - All patterns should be keyboard accessible
|
|
484
|
-
3. **Include ARIA labels** - Patterns should have proper ARIA attributes
|
|
485
|
-
4. **Test focus management** - Verify focus handling in patterns
|
|
486
|
-
5. **Document accessibility requirements** - Include accessibility in pattern documentation
|
|
487
|
-
|
|
488
|
-
## ⚠️ Edge Cases
|
|
489
|
-
|
|
490
|
-
### Pattern Conflicts
|
|
491
|
-
|
|
492
|
-
When patterns conflict:
|
|
493
|
-
- Document pattern trade-offs
|
|
494
|
-
- Provide guidance on pattern selection
|
|
495
|
-
- Test pattern combinations
|
|
496
|
-
- Verify patterns work together
|
|
497
|
-
- Consider pattern alternatives
|
|
498
|
-
|
|
499
|
-
### Pattern Scalability
|
|
500
|
-
|
|
501
|
-
When patterns don't scale:
|
|
502
|
-
- Test patterns with large datasets
|
|
503
|
-
- Verify patterns work with many components
|
|
504
|
-
- Monitor pattern performance
|
|
505
|
-
- Optimize patterns for scale
|
|
506
|
-
- Document scalability limitations
|
|
507
|
-
|
|
508
|
-
### Pattern Maintenance
|
|
509
|
-
|
|
510
|
-
When patterns need updates:
|
|
511
|
-
- Version pattern documentation
|
|
512
|
-
- Provide migration guides
|
|
513
|
-
- Test pattern updates thoroughly
|
|
514
|
-
- Document breaking changes
|
|
515
|
-
- Maintain backward compatibility when possible
|
|
516
|
-
|