@jmruthers/pace-core 0.5.136 → 0.5.139
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DataTable-CYOHOX3O.js → DataTable-JXFCA2BJ.js} +10 -9
- package/dist/{EventLogo-801uofbR.d.ts → EventLogo-rFL_kRjk.d.ts} +73 -1
- package/dist/{UnifiedAuthProvider-5E5TUNMS.js → UnifiedAuthProvider-XIQQ7LVU.js} +4 -5
- package/dist/{chunk-YLKIDTUK.js → chunk-22WKWKRX.js} +4 -4
- package/dist/{chunk-TVYPTYOY.js → chunk-4C7EXCAR.js} +60 -24
- package/dist/chunk-4C7EXCAR.js.map +1 -0
- package/dist/{chunk-NOHEVYVX.js → chunk-5JMOHWDI.js} +417 -319
- package/dist/chunk-5JMOHWDI.js.map +1 -0
- package/dist/{chunk-FHWWBIHA.js → chunk-6DXZ6V5Q.js} +5 -5
- package/dist/{chunk-2TWNJ46Y.js → chunk-6LAAY47Q.js} +2 -2
- package/dist/{chunk-444EZN6N.js → chunk-7QCC6MCP.js} +88 -1
- package/dist/chunk-7QCC6MCP.js.map +1 -0
- package/dist/chunk-BJPBT3CU.js +21 -0
- package/dist/chunk-BJPBT3CU.js.map +1 -0
- package/dist/{chunk-L6PGMCMD.js → chunk-BOOI7GK2.js} +38 -12
- package/dist/chunk-BOOI7GK2.js.map +1 -0
- package/dist/{chunk-XARJS7CD.js → chunk-INQLMHPF.js} +2 -2
- package/dist/chunk-JISYG63F.js +70 -0
- package/dist/chunk-JISYG63F.js.map +1 -0
- package/dist/{chunk-SL2YQDR6.js → chunk-MA6EPSGZ.js} +2 -2
- package/dist/{chunk-5DPZ5EAT.js → chunk-OWAG3GSU.js} +1 -3
- package/dist/{chunk-LTV3XIJJ.js → chunk-T6JN6LH6.js} +4 -4
- package/dist/{chunk-HJGGOMQ6.js → chunk-TLT2ZR3L.js} +147 -103
- package/dist/chunk-TLT2ZR3L.js.map +1 -0
- package/dist/{chunk-4MT5BGGL.js → chunk-YCWDTTUK.js} +4 -6
- package/dist/{chunk-4MT5BGGL.js.map → chunk-YCWDTTUK.js.map} +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/components.js +12 -11
- package/dist/components.js.map +1 -1
- package/dist/hooks.js +8 -9
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +15 -14
- package/dist/index.js.map +1 -1
- package/dist/providers.js +3 -4
- package/dist/rbac/index.js +8 -9
- package/dist/schema-DTDZQe2u.d.ts +28 -0
- package/dist/types.d.ts +152 -3
- package/dist/types.js +51 -16
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +89 -4
- package/dist/utils.js +214 -96
- package/dist/utils.js.map +1 -1
- package/dist/validation.d.ts +1 -343
- package/dist/validation.js +3 -100
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +27 -0
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +1 -1
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +84 -15
- package/docs/architecture/README.md +0 -1
- package/docs/styles/README.md +0 -2
- package/examples/RBAC/CompleteRBACExample.tsx +324 -0
- package/examples/RBAC/EventBasedApp.tsx +239 -0
- package/examples/RBAC/PermissionExample.tsx +151 -0
- package/examples/RBAC/index.ts +13 -0
- package/examples/public-pages/CorrectPublicPageImplementation.tsx +301 -0
- package/examples/public-pages/PublicEventPage.tsx +274 -0
- package/examples/public-pages/PublicPageApp.tsx +308 -0
- package/examples/public-pages/PublicPageUsageExample.tsx +216 -0
- package/examples/public-pages/index.ts +14 -0
- package/package.json +1 -10
- package/src/__tests__/TEST_STANDARD.md +92 -0
- package/src/components/Badge/Badge.test.tsx +314 -0
- package/src/components/Badge/Badge.tsx +304 -0
- package/src/components/Badge/index.ts +3 -0
- package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +217 -0
- package/src/components/DataTable/__tests__/styles.test.ts +1 -1
- package/src/components/DataTable/components/ColumnFilter.tsx +8 -4
- package/src/components/DataTable/components/DataTableBody.tsx +461 -0
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +144 -0
- package/src/components/DataTable/components/FilterRow.tsx +9 -3
- package/src/components/DataTable/components/PaginationControls.tsx +1 -0
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +513 -0
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +14 -68
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +62 -0
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +43 -0
- package/src/components/DataTable/core/ActionManager.ts +235 -0
- package/src/components/DataTable/core/ColumnManager.ts +205 -0
- package/src/components/DataTable/core/DataManager.ts +188 -0
- package/src/components/DataTable/core/DataTableContext.tsx +181 -0
- package/src/components/DataTable/core/LocalDataAdapter.ts +273 -0
- package/src/components/DataTable/core/PluginRegistry.ts +229 -0
- package/src/components/DataTable/core/StateManager.ts +311 -0
- package/src/components/DataTable/core/interfaces.ts +338 -0
- package/src/components/DataTable/styles.ts +27 -6
- package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +94 -0
- package/src/components/DataTable/utils/columnUtils.ts +40 -0
- package/src/components/DataTable/utils/debugTools.ts +609 -0
- package/src/components/DataTable/utils/index.ts +1 -0
- package/src/components/Dialog/README.md +804 -0
- package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +611 -0
- package/src/components/Dialog/utils/safeHtml.ts +185 -0
- package/src/components/Footer/Footer.test.tsx +1 -1
- package/src/components/Form/Form.test.tsx +1 -1
- package/src/components/Form/FormErrorSummary.tsx +113 -0
- package/src/components/Form/FormFieldset.tsx +127 -0
- package/src/components/Form/FormLiveRegion.tsx +198 -0
- package/src/components/LoginForm/LoginForm.test.tsx +1 -1
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +76 -10
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +1 -1
- package/src/components/PasswordReset/PasswordResetForm.test.tsx +597 -0
- package/src/components/PasswordReset/PasswordResetForm.tsx +201 -0
- package/src/components/PublicLayout/PublicPageDebugger.tsx +104 -0
- package/src/components/PublicLayout/PublicPageDiagnostic.tsx +162 -0
- package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +1 -1
- package/src/components/Select/Select.test.tsx +1 -1
- package/src/components/Select/Select.tsx +20 -8
- package/src/components/Table/__tests__/Table.test.tsx +1 -1
- package/src/components/index.ts +3 -0
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +83 -85
- package/src/index.ts +4 -0
- package/src/rbac/hooks/useCan.test.ts +24 -0
- package/src/rbac/hooks/usePermissions.ts +49 -12
- package/src/styles/core.css +3 -0
- package/src/utils/appConfig.ts +47 -0
- package/src/utils/appIdResolver.test.ts +499 -0
- package/src/utils/appIdResolver.ts +130 -0
- package/src/utils/appNameResolver.simple.test.ts +212 -0
- package/src/utils/appNameResolver.test.ts +121 -0
- package/src/utils/appNameResolver.ts +191 -0
- package/src/utils/audit.ts +127 -0
- package/src/utils/auth-utils.ts +96 -0
- package/src/utils/bundleAnalysis.ts +129 -0
- package/src/utils/cn.ts +7 -0
- package/src/utils/debugLogger.ts +67 -0
- package/src/utils/deviceFingerprint.ts +215 -0
- package/src/utils/dynamicUtils.ts +105 -0
- package/src/utils/file-reference.test.ts +788 -0
- package/src/utils/file-reference.ts +519 -0
- package/src/utils/formatDate.test.ts +237 -0
- package/src/utils/formatting.ts +133 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/lazyLoad.tsx +44 -0
- package/src/utils/logger.ts +179 -0
- package/src/utils/organisationContext.test.ts +322 -0
- package/src/utils/organisationContext.ts +153 -0
- package/src/utils/performanceBenchmark.ts +64 -0
- package/src/utils/performanceBudgets.ts +110 -0
- package/src/utils/permissionTypes.ts +37 -0
- package/src/utils/permissionUtils.test.ts +393 -0
- package/src/utils/permissionUtils.ts +34 -0
- package/src/utils/sanitization.ts +264 -0
- package/src/utils/schemaUtils.ts +37 -0
- package/src/utils/secureDataAccess.test.ts +711 -0
- package/src/utils/secureDataAccess.ts +377 -0
- package/src/utils/secureErrors.ts +79 -0
- package/src/utils/secureStorage.ts +244 -0
- package/src/utils/security.ts +156 -0
- package/src/utils/securityMonitor.ts +45 -0
- package/src/utils/sessionTracking.ts +126 -0
- package/src/utils/validation.ts +111 -0
- package/src/utils/validationUtils.ts +120 -0
- package/src/validation/index.ts +2 -2
- package/dist/chunk-444EZN6N.js.map +0 -1
- package/dist/chunk-APIBCTL2.js +0 -670
- package/dist/chunk-APIBCTL2.js.map +0 -1
- package/dist/chunk-HJGGOMQ6.js.map +0 -1
- package/dist/chunk-K2WWTH7O.js +0 -94
- package/dist/chunk-K2WWTH7O.js.map +0 -1
- package/dist/chunk-L6PGMCMD.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-NOHEVYVX.js.map +0 -1
- package/dist/chunk-TVYPTYOY.js.map +0 -1
- package/dist/validation-8npbysjg.d.ts +0 -177
- /package/dist/{DataTable-CYOHOX3O.js.map → DataTable-JXFCA2BJ.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-5E5TUNMS.js.map → UnifiedAuthProvider-XIQQ7LVU.js.map} +0 -0
- /package/dist/{chunk-YLKIDTUK.js.map → chunk-22WKWKRX.js.map} +0 -0
- /package/dist/{chunk-FHWWBIHA.js.map → chunk-6DXZ6V5Q.js.map} +0 -0
- /package/dist/{chunk-2TWNJ46Y.js.map → chunk-6LAAY47Q.js.map} +0 -0
- /package/dist/{chunk-XARJS7CD.js.map → chunk-INQLMHPF.js.map} +0 -0
- /package/dist/{chunk-SL2YQDR6.js.map → chunk-MA6EPSGZ.js.map} +0 -0
- /package/dist/{chunk-5DPZ5EAT.js.map → chunk-OWAG3GSU.js.map} +0 -0
- /package/dist/{chunk-LTV3XIJJ.js.map → chunk-T6JN6LH6.js.map} +0 -0
- /package/examples/{components → components 2}/DataTable/HierarchicalActionsExample.tsx +0 -0
- /package/examples/{components → components 2}/DataTable/HierarchicalExample.tsx +0 -0
- /package/examples/{components → components 2}/DataTable/InitialPageSizeExample.tsx +0 -0
- /package/examples/{components → components 2}/DataTable/PerformanceExample.tsx +0 -0
- /package/examples/{components → components 2}/DataTable/index.ts +0 -0
- /package/examples/{components → components 2}/Dialog/BasicHtmlTest.tsx +0 -0
- /package/examples/{components → components 2}/Dialog/DebugHtmlExample.tsx +0 -0
- /package/examples/{components → components 2}/Dialog/HtmlDialogExample.tsx +0 -0
- /package/examples/{components → components 2}/Dialog/ScrollableDialogExample.tsx +0 -0
- /package/examples/{components → components 2}/Dialog/SimpleHtmlTest.tsx +0 -0
- /package/examples/{components → components 2}/Dialog/SmartDialogExample.tsx +0 -0
- /package/examples/{components → components 2}/Dialog/index.ts +0 -0
- /package/examples/{components → components 2}/index.ts +0 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Badge Component
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components
|
|
5
|
+
* @since 0.1.0
|
|
6
|
+
*
|
|
7
|
+
* A small, non-interactive visual label component for displaying concise information
|
|
8
|
+
* such as status indicators, tags, or labels. Acts as a visual alternative to buttons
|
|
9
|
+
* for non-interactive content.
|
|
10
|
+
*
|
|
11
|
+
* Features:
|
|
12
|
+
* - 27 combined variants (3 styles × 3 colors × 3 shades)
|
|
13
|
+
* - Non-interactive by default (renders as <span>)
|
|
14
|
+
* - Supports all pace-core color palettes (main, sec, acc)
|
|
15
|
+
* - Customizable styling via className prop
|
|
16
|
+
* - Accessible and screen reader friendly
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* // Basic badge with default variant
|
|
21
|
+
* <Badge>New</Badge>
|
|
22
|
+
*
|
|
23
|
+
* // Badge with specific variant
|
|
24
|
+
* <Badge variant="solid-main-normal">Active</Badge>
|
|
25
|
+
*
|
|
26
|
+
* // Outline variant
|
|
27
|
+
* <Badge variant="outline-sec-muted">Pending</Badge>
|
|
28
|
+
*
|
|
29
|
+
* // Soft variant with accent color
|
|
30
|
+
* <Badge variant="soft-acc-strong">Featured</Badge>
|
|
31
|
+
*
|
|
32
|
+
* // Custom styling
|
|
33
|
+
* <Badge variant="solid-main-normal" className="px-4">
|
|
34
|
+
* Custom Badge
|
|
35
|
+
* </Badge>
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @accessibility
|
|
39
|
+
* - Renders as semantic <span> element
|
|
40
|
+
* - No focus styles (non-interactive by default)
|
|
41
|
+
* - Screen reader friendly through semantic HTML
|
|
42
|
+
* - Can be wrapped in interactive elements if needed
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
import * as React from 'react';
|
|
46
|
+
import { cn } from '../../utils/core/cn';
|
|
47
|
+
|
|
48
|
+
// ============================================================================
|
|
49
|
+
// TYPE DEFINITIONS
|
|
50
|
+
// ============================================================================
|
|
51
|
+
|
|
52
|
+
export type BadgeVariant =
|
|
53
|
+
| 'solid-main-muted' | 'solid-main-normal' | 'solid-main-strong'
|
|
54
|
+
| 'solid-sec-muted' | 'solid-sec-normal' | 'solid-sec-strong'
|
|
55
|
+
| 'solid-acc-muted' | 'solid-acc-normal' | 'solid-acc-strong'
|
|
56
|
+
| 'outline-main-muted' | 'outline-main-normal' | 'outline-main-strong'
|
|
57
|
+
| 'outline-sec-muted' | 'outline-sec-normal' | 'outline-sec-strong'
|
|
58
|
+
| 'outline-acc-muted' | 'outline-acc-normal' | 'outline-acc-strong'
|
|
59
|
+
| 'soft-main-muted' | 'soft-main-normal' | 'soft-main-strong'
|
|
60
|
+
| 'soft-sec-muted' | 'soft-sec-normal' | 'soft-sec-strong'
|
|
61
|
+
| 'soft-acc-muted' | 'soft-acc-normal' | 'soft-acc-strong';
|
|
62
|
+
|
|
63
|
+
export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
64
|
+
/** Visual variant of the badge (style-color-shade) */
|
|
65
|
+
variant?: BadgeVariant;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// VARIANT CONFIGURATION
|
|
70
|
+
// ============================================================================
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Shade configuration mapping
|
|
74
|
+
* Maps shade names to background, text, border, and outline text color shades
|
|
75
|
+
*/
|
|
76
|
+
const shadeConfig = {
|
|
77
|
+
muted: {
|
|
78
|
+
bg: 200,
|
|
79
|
+
text: 600,
|
|
80
|
+
border: 400,
|
|
81
|
+
outlineText: 600,
|
|
82
|
+
outlineBg: 100,
|
|
83
|
+
},
|
|
84
|
+
normal: {
|
|
85
|
+
bg: 500,
|
|
86
|
+
text: 50,
|
|
87
|
+
border: 700,
|
|
88
|
+
outlineText: 700,
|
|
89
|
+
outlineBg: 200,
|
|
90
|
+
},
|
|
91
|
+
strong: {
|
|
92
|
+
bg: 700,
|
|
93
|
+
text: 50,
|
|
94
|
+
border: 800,
|
|
95
|
+
outlineText: 900,
|
|
96
|
+
outlineBg: 400,
|
|
97
|
+
},
|
|
98
|
+
} as const;
|
|
99
|
+
|
|
100
|
+
type Shade = keyof typeof shadeConfig;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Color palette options
|
|
104
|
+
*/
|
|
105
|
+
const colors = ['main', 'sec', 'acc'] as const;
|
|
106
|
+
type Color = typeof colors[number];
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Style options
|
|
110
|
+
*/
|
|
111
|
+
const styles = ['solid', 'outline', 'soft'] as const;
|
|
112
|
+
type Style = typeof styles[number];
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Build variant class string for a given style, color, and shade
|
|
116
|
+
* Generates classes programmatically from configuration
|
|
117
|
+
*/
|
|
118
|
+
function buildVariantClasses(style: Style, color: Color, shade: Shade): string {
|
|
119
|
+
const cfg = shadeConfig[shade];
|
|
120
|
+
const parts: string[] = [];
|
|
121
|
+
|
|
122
|
+
if (style === 'solid') {
|
|
123
|
+
// Solid: flat background colors
|
|
124
|
+
parts.push(`bg-${color}-${cfg.bg}`, `text-${color}-${cfg.text}`);
|
|
125
|
+
} else if (style === 'outline') {
|
|
126
|
+
// Outline: outlined with light background
|
|
127
|
+
parts.push('outline outline-1 -outline-offset-1', `outline-${color}-${cfg.border}`, `bg-${color}-${cfg.outlineBg}`, `text-${color}-${cfg.outlineText}`);
|
|
128
|
+
} else if (style === 'soft') {
|
|
129
|
+
// Soft: uses shadow-badge-soft utility with colored shadows
|
|
130
|
+
parts.push(
|
|
131
|
+
`bg-${color}-${cfg.bg}`,
|
|
132
|
+
'shadow-badge-soft',
|
|
133
|
+
`shadow-${color}-${cfg.bg}`,
|
|
134
|
+
`text-${color}-${cfg.text}`,
|
|
135
|
+
'my-1', 'mx-1', 'py-0', 'px-2'
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return parts.join(' ');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Generate all class name patterns for Tailwind scanning
|
|
144
|
+
* This ensures Tailwind can detect all dynamically generated classes
|
|
145
|
+
*
|
|
146
|
+
* Tailwind v4 content scanning: These classes are listed here so Tailwind
|
|
147
|
+
* can detect them during content scanning, even when built dynamically.
|
|
148
|
+
*
|
|
149
|
+
* Classes used: shadow-badge-soft shadow-main-200 shadow-main-500 shadow-main-700
|
|
150
|
+
* shadow-sec-200 shadow-sec-500 shadow-sec-700 shadow-acc-200 shadow-acc-500 shadow-acc-700
|
|
151
|
+
*/
|
|
152
|
+
const tailwindClassScan = [
|
|
153
|
+
// Solid background classes
|
|
154
|
+
'bg-main-100', 'bg-main-600', 'bg-main-900',
|
|
155
|
+
'bg-sec-100', 'bg-sec-600', 'bg-sec-900',
|
|
156
|
+
'bg-acc-100', 'bg-acc-600', 'bg-acc-900',
|
|
157
|
+
// Solid text classes
|
|
158
|
+
'text-main-50', 'text-main-900',
|
|
159
|
+
'text-sec-50', 'text-sec-900',
|
|
160
|
+
'text-acc-50', 'text-acc-900',
|
|
161
|
+
// Outline classes
|
|
162
|
+
'outline outline-1',
|
|
163
|
+
'outline-main-400', 'outline-main-700', 'outline-main-800',
|
|
164
|
+
'outline-sec-400', 'outline-sec-700', 'outline-sec-800',
|
|
165
|
+
'outline-acc-400', 'outline-acc-700', 'outline-acc-800',
|
|
166
|
+
// Outline background classes
|
|
167
|
+
'bg-main-100', 'bg-main-200', 'bg-main-300',
|
|
168
|
+
'bg-sec-100', 'bg-sec-200', 'bg-sec-300',
|
|
169
|
+
'bg-acc-100', 'bg-acc-200', 'bg-acc-300',
|
|
170
|
+
// Outline text classes
|
|
171
|
+
'text-main-500', 'text-main-600', 'text-main-800',
|
|
172
|
+
'text-sec-500', 'text-sec-600', 'text-sec-800',
|
|
173
|
+
'text-acc-500', 'text-acc-600', 'text-acc-800',
|
|
174
|
+
// Soft background classes (solid, no opacity)
|
|
175
|
+
'bg-main-200', 'bg-main-500', 'bg-main-700',
|
|
176
|
+
'bg-sec-200', 'bg-sec-500', 'bg-sec-700',
|
|
177
|
+
'bg-acc-200', 'bg-acc-500', 'bg-acc-700',
|
|
178
|
+
// Soft shadow utility classes - CRITICAL: These must be detected by Tailwind
|
|
179
|
+
'shadow-badge-soft',
|
|
180
|
+
'shadow-main-200', 'shadow-main-500', 'shadow-main-700',
|
|
181
|
+
'shadow-sec-200', 'shadow-sec-500', 'shadow-sec-700',
|
|
182
|
+
'shadow-acc-200', 'shadow-acc-500', 'shadow-acc-700',
|
|
183
|
+
// Soft margin/padding classes
|
|
184
|
+
'my-3', 'mx-3', 'py-0', 'px-2',
|
|
185
|
+
] as const;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Generate all variant class combinations programmatically
|
|
189
|
+
* Uses the configuration to build the lookup map dynamically
|
|
190
|
+
*/
|
|
191
|
+
function generateVariantClasses(): Record<BadgeVariant, string> {
|
|
192
|
+
const variantClasses = {} as Record<BadgeVariant, string>;
|
|
193
|
+
|
|
194
|
+
for (const style of styles) {
|
|
195
|
+
for (const color of colors) {
|
|
196
|
+
for (const shade of Object.keys(shadeConfig) as Shade[]) {
|
|
197
|
+
const variant = `${style}-${color}-${shade}` as BadgeVariant;
|
|
198
|
+
variantClasses[variant] = buildVariantClasses(style, color, shade);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return variantClasses;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Pre-generate all variant classes
|
|
207
|
+
const variantClassesMap = generateVariantClasses();
|
|
208
|
+
|
|
209
|
+
// Ensure Tailwind detects shadow-badge-soft class
|
|
210
|
+
// This string literal ensures Tailwind v4 content scanning includes the class
|
|
211
|
+
const _tailwindShadowDetection = 'shadow-badge-soft';
|
|
212
|
+
|
|
213
|
+
// ============================================================================
|
|
214
|
+
// CLASS GENERATION FUNCTION
|
|
215
|
+
// ============================================================================
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Get badge classes based on variant
|
|
219
|
+
*
|
|
220
|
+
* Variant format: {style}-{color}-{shade}
|
|
221
|
+
* - style: solid (flat), outline (bordered), soft (blurred)
|
|
222
|
+
* - color: main, sec, acc
|
|
223
|
+
* - shade: muted (dark on light), normal (light on medium), strong (light on dark)
|
|
224
|
+
*/
|
|
225
|
+
function getBadgeClasses(variant: BadgeVariant = 'solid-main-normal'): string {
|
|
226
|
+
const baseClasses = 'inline-flex text-balance items-center rounded-2xl px-3 py-1 text-xs font-medium transition-colors box-border';
|
|
227
|
+
return `${baseClasses} ${variantClassesMap[variant]}`;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// ============================================================================
|
|
231
|
+
// BADGE COMPONENT
|
|
232
|
+
// ============================================================================
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Badge Component
|
|
236
|
+
* A small, non-interactive visual label for displaying concise information.
|
|
237
|
+
*
|
|
238
|
+
* @component
|
|
239
|
+
* @example
|
|
240
|
+
* ```tsx
|
|
241
|
+
* // Default variant
|
|
242
|
+
* <Badge>New</Badge>
|
|
243
|
+
*
|
|
244
|
+
* // Specific variant
|
|
245
|
+
* <Badge variant="solid-main-normal">Active</Badge>
|
|
246
|
+
*
|
|
247
|
+
* // Outline variant
|
|
248
|
+
* <Badge variant="outline-sec-muted">Pending</Badge>
|
|
249
|
+
*
|
|
250
|
+
* // Soft variant
|
|
251
|
+
* <Badge variant="soft-acc-strong">Featured</Badge>
|
|
252
|
+
* ```
|
|
253
|
+
*/
|
|
254
|
+
const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
|
|
255
|
+
({ className, variant = 'solid-main-normal', ...props }, ref) => {
|
|
256
|
+
const isSoftVariant = variant.startsWith('soft-');
|
|
257
|
+
|
|
258
|
+
if (isSoftVariant) {
|
|
259
|
+
// For soft variants, we need both shadow-badge-soft and shadow color class
|
|
260
|
+
// twMerge treats all shadow-* classes as conflicting, so we need to add them after merging
|
|
261
|
+
const variantClasses = getBadgeClasses(variant);
|
|
262
|
+
// Extract the shadow color class from variantClasses (e.g., shadow-main-200)
|
|
263
|
+
const shadowColorMatch = variantClasses.match(/\bshadow-(\w+)-(\d+)\b/);
|
|
264
|
+
const shadowColorClass = shadowColorMatch ? shadowColorMatch[0] : '';
|
|
265
|
+
|
|
266
|
+
// Remove shadow classes from variantClasses to avoid twMerge conflicts
|
|
267
|
+
const classesWithoutShadows = variantClasses
|
|
268
|
+
.replace(/\bshadow-badge-soft\b/g, '')
|
|
269
|
+
.replace(/\bshadow-\w+-\d+\b/g, '')
|
|
270
|
+
.replace(/\s+/g, ' ')
|
|
271
|
+
.trim();
|
|
272
|
+
|
|
273
|
+
// Merge non-shadow classes first, then append shadow classes to ensure both are present
|
|
274
|
+
// shadow-badge-soft first (defines shape), then shadow color (defines color)
|
|
275
|
+
const mergedClasses = cn(classesWithoutShadows, className);
|
|
276
|
+
const finalClasses = `${mergedClasses} shadow-badge-soft ${shadowColorClass}`.trim();
|
|
277
|
+
|
|
278
|
+
return (
|
|
279
|
+
<span
|
|
280
|
+
ref={ref}
|
|
281
|
+
className={finalClasses}
|
|
282
|
+
{...props}
|
|
283
|
+
/>
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
<span
|
|
289
|
+
ref={ref}
|
|
290
|
+
className={cn(getBadgeClasses(variant), className)}
|
|
291
|
+
{...props}
|
|
292
|
+
/>
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
Badge.displayName = 'Badge';
|
|
298
|
+
|
|
299
|
+
// ============================================================================
|
|
300
|
+
// EXPORTS
|
|
301
|
+
// ============================================================================
|
|
302
|
+
|
|
303
|
+
export { Badge };
|
|
304
|
+
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file DataTableCore Test Setup
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Components/DataTable/__tests__
|
|
5
|
+
* @since 0.4.0
|
|
6
|
+
*
|
|
7
|
+
* Shared test setup and mocks for DataTableCore component tests.
|
|
8
|
+
* This file is imported by all DataTableCore test files to ensure consistent mocking.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { vi } from 'vitest';
|
|
12
|
+
import React from 'react';
|
|
13
|
+
|
|
14
|
+
// Mock the RBAC hooks
|
|
15
|
+
vi.mock('../../../rbac/hooks', () => ({
|
|
16
|
+
useCan: vi.fn(),
|
|
17
|
+
useResolvedScope: vi.fn(() => ({
|
|
18
|
+
resolvedScope: {
|
|
19
|
+
organisationId: 'test-org-id',
|
|
20
|
+
eventId: 'test-event-id',
|
|
21
|
+
appId: 'test-app-id'
|
|
22
|
+
}
|
|
23
|
+
}))
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
// Mock the auth provider
|
|
27
|
+
vi.mock('../../../providers/UnifiedAuthProvider', () => ({
|
|
28
|
+
useUnifiedAuth: vi.fn(() => ({
|
|
29
|
+
user: { id: 'test-user', email: 'test@example.com' },
|
|
30
|
+
isAuthenticated: true,
|
|
31
|
+
isLoading: false,
|
|
32
|
+
error: null,
|
|
33
|
+
selectedOrganisationId: 'test-org-id',
|
|
34
|
+
selectedEventId: 'test-event-id',
|
|
35
|
+
supabase: null,
|
|
36
|
+
})),
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
// Mock the performance hook
|
|
40
|
+
vi.mock('../../../hooks/useDataTablePerformance', () => ({
|
|
41
|
+
useDataTablePerformance: vi.fn(() => ({
|
|
42
|
+
paginationMode: 'client',
|
|
43
|
+
isVirtualized: false,
|
|
44
|
+
pageSizeOptions: [10, 25, 50],
|
|
45
|
+
processedData: [],
|
|
46
|
+
totalCount: 0,
|
|
47
|
+
isLoading: false,
|
|
48
|
+
searchQuery: '',
|
|
49
|
+
setSearchQuery: vi.fn(),
|
|
50
|
+
searchResults: [],
|
|
51
|
+
fetchServerData: vi.fn(),
|
|
52
|
+
serverData: null,
|
|
53
|
+
memoryUsage: 0,
|
|
54
|
+
errorState: {
|
|
55
|
+
hasErrors: false,
|
|
56
|
+
errorCount: 0,
|
|
57
|
+
lastError: null,
|
|
58
|
+
fallbacksActive: [],
|
|
59
|
+
},
|
|
60
|
+
retryLastOperation: vi.fn(),
|
|
61
|
+
clearErrors: vi.fn(),
|
|
62
|
+
cleanup: vi.fn(),
|
|
63
|
+
shouldUseVirtualization: false,
|
|
64
|
+
performanceMetrics: {},
|
|
65
|
+
})),
|
|
66
|
+
}));
|
|
67
|
+
|
|
68
|
+
// Mock the data table state hook
|
|
69
|
+
vi.mock('../hooks/useDataTableState', () => ({
|
|
70
|
+
useDataTableState: vi.fn(() => ({
|
|
71
|
+
state: {
|
|
72
|
+
sorting: [],
|
|
73
|
+
columnFilters: [],
|
|
74
|
+
columnVisibility: {},
|
|
75
|
+
grouping: [],
|
|
76
|
+
expanded: {},
|
|
77
|
+
pagination: { pageIndex: 0, pageSize: 10 },
|
|
78
|
+
columnOrder: [],
|
|
79
|
+
rowSelection: {},
|
|
80
|
+
isCreating: false,
|
|
81
|
+
creationData: {},
|
|
82
|
+
editingRowId: null,
|
|
83
|
+
editingData: {},
|
|
84
|
+
showImportModal: false,
|
|
85
|
+
showFilterRow: false,
|
|
86
|
+
searchQuery: '',
|
|
87
|
+
},
|
|
88
|
+
actions: {
|
|
89
|
+
setSorting: vi.fn(),
|
|
90
|
+
setColumnFilters: vi.fn(),
|
|
91
|
+
setColumnVisibility: vi.fn(),
|
|
92
|
+
setGrouping: vi.fn(),
|
|
93
|
+
setExpanded: vi.fn(),
|
|
94
|
+
setPagination: vi.fn(),
|
|
95
|
+
setColumnOrder: vi.fn(),
|
|
96
|
+
setRowSelection: vi.fn(),
|
|
97
|
+
setCreating: vi.fn(),
|
|
98
|
+
setCreationData: vi.fn(),
|
|
99
|
+
clearCreationData: vi.fn(),
|
|
100
|
+
setEditingRow: vi.fn(),
|
|
101
|
+
clearEditing: vi.fn(),
|
|
102
|
+
setImportModal: vi.fn(),
|
|
103
|
+
setFilterRow: vi.fn(),
|
|
104
|
+
setSearchQuery: vi.fn(),
|
|
105
|
+
resetState: vi.fn(),
|
|
106
|
+
},
|
|
107
|
+
})),
|
|
108
|
+
}));
|
|
109
|
+
|
|
110
|
+
// Mock the hierarchical state hook
|
|
111
|
+
vi.mock('../hooks/useHierarchicalState', () => ({
|
|
112
|
+
useHierarchicalState: vi.fn(() => ({
|
|
113
|
+
hierarchicalData: [],
|
|
114
|
+
setHierarchicalData: vi.fn(),
|
|
115
|
+
expandedRows: {},
|
|
116
|
+
setExpandedRows: vi.fn(),
|
|
117
|
+
})),
|
|
118
|
+
}));
|
|
119
|
+
|
|
120
|
+
// Mock the column order persistence hook
|
|
121
|
+
vi.mock('../hooks/useColumnOrderPersistence', () => ({
|
|
122
|
+
useColumnOrderPersistence: vi.fn(() => ({
|
|
123
|
+
columnOrder: [],
|
|
124
|
+
setColumnOrder: vi.fn(),
|
|
125
|
+
})),
|
|
126
|
+
}));
|
|
127
|
+
|
|
128
|
+
// Mock the column factory
|
|
129
|
+
vi.mock('../core/ColumnFactory', () => ({
|
|
130
|
+
ColumnFactory: {
|
|
131
|
+
createColumns: vi.fn((columns) => columns),
|
|
132
|
+
createActionColumn: vi.fn(() => ({
|
|
133
|
+
id: 'actions',
|
|
134
|
+
header: 'Actions',
|
|
135
|
+
cell: () => React.createElement('div', { 'data-testid': 'action-cell' }, 'Actions'),
|
|
136
|
+
})),
|
|
137
|
+
},
|
|
138
|
+
}));
|
|
139
|
+
|
|
140
|
+
// Mock the hierarchical utilities
|
|
141
|
+
vi.mock('../utils/hierarchicalUtils', () => ({
|
|
142
|
+
validateHierarchicalData: vi.fn(() => true),
|
|
143
|
+
sortHierarchicalData: vi.fn((data) => data),
|
|
144
|
+
}));
|
|
145
|
+
|
|
146
|
+
vi.mock('../utils/hierarchicalSorting', () => ({
|
|
147
|
+
sortHierarchicalData: vi.fn((data) => data),
|
|
148
|
+
}));
|
|
149
|
+
|
|
150
|
+
// Create a mock implementation that can be overridden
|
|
151
|
+
const mockUseDataTablePermissions = vi.hoisted(() => vi.fn(() => ({
|
|
152
|
+
permissions: {
|
|
153
|
+
canRead: { can: true },
|
|
154
|
+
canCreate: { can: true },
|
|
155
|
+
canUpdate: { can: true },
|
|
156
|
+
canDelete: { can: true },
|
|
157
|
+
canExport: { can: true },
|
|
158
|
+
canImport: { can: true },
|
|
159
|
+
},
|
|
160
|
+
secureFeatures: {
|
|
161
|
+
search: true,
|
|
162
|
+
sorting: true,
|
|
163
|
+
pagination: true,
|
|
164
|
+
selection: true,
|
|
165
|
+
creation: true,
|
|
166
|
+
editing: true,
|
|
167
|
+
deletion: true,
|
|
168
|
+
deleteSelected: true,
|
|
169
|
+
export: true,
|
|
170
|
+
import: true,
|
|
171
|
+
columnVisibility: true,
|
|
172
|
+
filtering: true,
|
|
173
|
+
grouping: true,
|
|
174
|
+
},
|
|
175
|
+
effectivePageId: 'test-page',
|
|
176
|
+
})));
|
|
177
|
+
|
|
178
|
+
vi.mock('../hooks/useDataTablePermissions', () => ({
|
|
179
|
+
useDataTablePermissions: mockUseDataTablePermissions
|
|
180
|
+
}));
|
|
181
|
+
|
|
182
|
+
vi.mock('../hooks/useTableColumns', () => ({
|
|
183
|
+
useTableColumns: vi.fn(({ columns }) => ({
|
|
184
|
+
enhancedColumns: columns || []
|
|
185
|
+
}))
|
|
186
|
+
}));
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Shared test data and utilities
|
|
190
|
+
*/
|
|
191
|
+
export const createTestSetup = () => {
|
|
192
|
+
const mockData = require('./test-utils/dataFactories').createTestData(5);
|
|
193
|
+
const mockColumns = require('./test-utils/dataFactories').createTestColumns();
|
|
194
|
+
const mockRBAC = { pageId: 'test-page' };
|
|
195
|
+
const mockPerformance = { serverSideThreshold: 10000 };
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
mockData,
|
|
199
|
+
mockColumns,
|
|
200
|
+
mockRBAC,
|
|
201
|
+
mockPerformance,
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Setup function to be called in beforeEach
|
|
207
|
+
*/
|
|
208
|
+
export const setupTestMocks = async () => {
|
|
209
|
+
vi.clearAllMocks();
|
|
210
|
+
const { useCan } = await import('../../../rbac/hooks');
|
|
211
|
+
(useCan as any).mockReturnValue({
|
|
212
|
+
can: true,
|
|
213
|
+
isLoading: false,
|
|
214
|
+
error: null,
|
|
215
|
+
});
|
|
216
|
+
};
|
|
217
|
+
|
|
@@ -4,6 +4,7 @@ import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '.
|
|
|
4
4
|
import { Button } from '../../Button/Button';
|
|
5
5
|
import { X, Filter } from 'lucide-react';
|
|
6
6
|
import type { Column } from '@tanstack/react-table';
|
|
7
|
+
import { getColumnHeaderText } from '../utils/columnUtils';
|
|
7
8
|
|
|
8
9
|
interface ColumnFilterProps {
|
|
9
10
|
column: Column<any, unknown>;
|
|
@@ -38,6 +39,9 @@ export function ColumnFilter({
|
|
|
38
39
|
};
|
|
39
40
|
|
|
40
41
|
const hasFilter = columnFilterValue !== undefined && columnFilterValue !== '';
|
|
42
|
+
|
|
43
|
+
// Get the default placeholder using column header text
|
|
44
|
+
const defaultPlaceholder = `Filter ${getColumnHeaderText(column)}...`;
|
|
41
45
|
|
|
42
46
|
const renderFilterInput = () => {
|
|
43
47
|
switch (filterType) {
|
|
@@ -48,7 +52,7 @@ export function ColumnFilter({
|
|
|
48
52
|
onValueChange={handleFilterChange}
|
|
49
53
|
>
|
|
50
54
|
<SelectTrigger className="h-8">
|
|
51
|
-
<SelectValue placeholder={placeholder ||
|
|
55
|
+
<SelectValue placeholder={placeholder || defaultPlaceholder} />
|
|
52
56
|
</SelectTrigger>
|
|
53
57
|
<SelectContent>
|
|
54
58
|
<SelectItem value="">All</SelectItem>
|
|
@@ -68,7 +72,7 @@ export function ColumnFilter({
|
|
|
68
72
|
type="number"
|
|
69
73
|
value={columnFilterValue as string || ''}
|
|
70
74
|
onChange={(e) => handleFilterChange(e.target.value ? Number(e.target.value) : undefined)}
|
|
71
|
-
placeholder={placeholder ||
|
|
75
|
+
placeholder={placeholder || defaultPlaceholder}
|
|
72
76
|
className="h-8 datatable-number-no-spinners"
|
|
73
77
|
/>
|
|
74
78
|
);
|
|
@@ -79,7 +83,7 @@ export function ColumnFilter({
|
|
|
79
83
|
type="date"
|
|
80
84
|
value={columnFilterValue as string || ''}
|
|
81
85
|
onChange={(e) => handleFilterChange(e.target.value || undefined)}
|
|
82
|
-
placeholder={placeholder ||
|
|
86
|
+
placeholder={placeholder || defaultPlaceholder}
|
|
83
87
|
className="h-8"
|
|
84
88
|
/>
|
|
85
89
|
);
|
|
@@ -89,7 +93,7 @@ export function ColumnFilter({
|
|
|
89
93
|
<Input
|
|
90
94
|
value={columnFilterValue as string || ''}
|
|
91
95
|
onChange={(e) => handleFilterChange(e.target.value || undefined)}
|
|
92
|
-
placeholder={placeholder ||
|
|
96
|
+
placeholder={placeholder || defaultPlaceholder}
|
|
93
97
|
className="h-8"
|
|
94
98
|
/>
|
|
95
99
|
);
|