@jmruthers/pace-core 0.5.95 → 0.5.97

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.
Files changed (121) hide show
  1. package/dist/{DataTable-XENXNMCP.js → DataTable-FB22ES46.js} +2 -2
  2. package/dist/{chunk-EPKHU5SS.js → chunk-QX5I62KP.js} +77 -11
  3. package/dist/chunk-QX5I62KP.js.map +1 -0
  4. package/dist/{chunk-V5CTX4FR.js → chunk-UBPRDNPY.js} +2 -2
  5. package/dist/components.js +2 -2
  6. package/dist/index.js +2 -2
  7. package/dist/utils.js +1 -1
  8. package/docs/api/classes/ColumnFactory.md +1 -1
  9. package/docs/api/classes/ErrorBoundary.md +1 -1
  10. package/docs/api/classes/InvalidScopeError.md +1 -1
  11. package/docs/api/classes/MissingUserContextError.md +1 -1
  12. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  13. package/docs/api/classes/PermissionDeniedError.md +1 -1
  14. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  15. package/docs/api/classes/RBACAuditManager.md +1 -1
  16. package/docs/api/classes/RBACCache.md +1 -1
  17. package/docs/api/classes/RBACEngine.md +1 -1
  18. package/docs/api/classes/RBACError.md +1 -1
  19. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  20. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  21. package/docs/api/classes/StorageUtils.md +1 -1
  22. package/docs/api/enums/FileCategory.md +1 -1
  23. package/docs/api/interfaces/AggregateConfig.md +1 -1
  24. package/docs/api/interfaces/ButtonProps.md +1 -1
  25. package/docs/api/interfaces/CardProps.md +1 -1
  26. package/docs/api/interfaces/ColorPalette.md +1 -1
  27. package/docs/api/interfaces/ColorShade.md +1 -1
  28. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  29. package/docs/api/interfaces/DataRecord.md +1 -1
  30. package/docs/api/interfaces/DataTableAction.md +1 -1
  31. package/docs/api/interfaces/DataTableColumn.md +1 -1
  32. package/docs/api/interfaces/DataTableProps.md +1 -1
  33. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  34. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  35. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  36. package/docs/api/interfaces/EventLogoProps.md +1 -1
  37. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  38. package/docs/api/interfaces/FileMetadata.md +1 -1
  39. package/docs/api/interfaces/FileReference.md +1 -1
  40. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  41. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  42. package/docs/api/interfaces/FileUploadProps.md +1 -1
  43. package/docs/api/interfaces/FooterProps.md +1 -1
  44. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  45. package/docs/api/interfaces/InputProps.md +1 -1
  46. package/docs/api/interfaces/LabelProps.md +1 -1
  47. package/docs/api/interfaces/LoginFormProps.md +1 -1
  48. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  49. package/docs/api/interfaces/NavigationContextType.md +1 -1
  50. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  51. package/docs/api/interfaces/NavigationItem.md +1 -1
  52. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  53. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  54. package/docs/api/interfaces/Organisation.md +1 -1
  55. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  56. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  57. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  58. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  59. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  60. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  61. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  62. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  63. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  64. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  65. package/docs/api/interfaces/PaletteData.md +1 -1
  66. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  67. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  68. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  69. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  70. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  71. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  72. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  73. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  74. package/docs/api/interfaces/RBACConfig.md +1 -1
  75. package/docs/api/interfaces/RBACLogger.md +1 -1
  76. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  77. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  78. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  79. package/docs/api/interfaces/RouteConfig.md +1 -1
  80. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  81. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  82. package/docs/api/interfaces/StorageConfig.md +1 -1
  83. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  84. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  85. package/docs/api/interfaces/StorageListOptions.md +1 -1
  86. package/docs/api/interfaces/StorageListResult.md +1 -1
  87. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  88. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  89. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  90. package/docs/api/interfaces/StyleImport.md +1 -1
  91. package/docs/api/interfaces/SwitchProps.md +1 -1
  92. package/docs/api/interfaces/ToastActionElement.md +1 -1
  93. package/docs/api/interfaces/ToastProps.md +1 -1
  94. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  95. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  96. package/docs/api/interfaces/UseEventLogoOptions.md +1 -1
  97. package/docs/api/interfaces/UseEventLogoReturn.md +1 -1
  98. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  99. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  100. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  101. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  102. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  103. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  104. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  105. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  106. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  107. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  108. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  109. package/docs/api/interfaces/UserEventAccess.md +1 -1
  110. package/docs/api/interfaces/UserMenuProps.md +1 -1
  111. package/docs/api/interfaces/UserProfile.md +1 -1
  112. package/docs/api/modules.md +2 -2
  113. package/docs/implementation-guides/data-tables.md +156 -1
  114. package/package.json +1 -1
  115. package/src/components/DataTable/DataTable.tsx +1 -1
  116. package/src/components/DataTable/components/DataTableCore.tsx +51 -18
  117. package/src/components/DataTable/components/DataTableModals.tsx +76 -5
  118. package/src/components/DataTable/utils/exportUtils.ts +18 -2
  119. package/dist/chunk-EPKHU5SS.js.map +0 -1
  120. /package/dist/{DataTable-XENXNMCP.js.map → DataTable-FB22ES46.js.map} +0 -0
  121. /package/dist/{chunk-V5CTX4FR.js.map → chunk-UBPRDNPY.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / StorageConfig
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / StorageConfig
2
2
 
3
3
  # Interface: StorageConfig
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / StorageFileInfo
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / StorageFileInfo
2
2
 
3
3
  # Interface: StorageFileInfo
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / StorageFileMetadata
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / StorageFileMetadata
2
2
 
3
3
  # Interface: StorageFileMetadata
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / StorageListOptions
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / StorageListOptions
2
2
 
3
3
  # Interface: StorageListOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / StorageListResult
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / StorageListResult
2
2
 
3
3
  # Interface: StorageListResult
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / StorageUploadOptions
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / StorageUploadOptions
2
2
 
3
3
  # Interface: StorageUploadOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / StorageUploadResult
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / StorageUploadResult
2
2
 
3
3
  # Interface: StorageUploadResult
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / StorageUrlOptions
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / StorageUrlOptions
2
2
 
3
3
  # Interface: StorageUrlOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / StyleImport
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / StyleImport
2
2
 
3
3
  # Interface: StyleImport
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / SwitchProps
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / SwitchProps
2
2
 
3
3
  # Interface: SwitchProps
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / ToastActionElement
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / ToastActionElement
2
2
 
3
3
  # Interface: ToastActionElement
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / ToastProps
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / ToastProps
2
2
 
3
3
  # Interface: ToastProps
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UnifiedAuthContextType
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UnifiedAuthContextType
2
2
 
3
3
  # Interface: UnifiedAuthContextType
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UnifiedAuthProviderProps
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UnifiedAuthProviderProps
2
2
 
3
3
  # Interface: UnifiedAuthProviderProps
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UseEventLogoOptions
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UseEventLogoOptions
2
2
 
3
3
  # Interface: UseEventLogoOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UseEventLogoReturn
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UseEventLogoReturn
2
2
 
3
3
  # Interface: UseEventLogoReturn
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UseInactivityTrackerOptions
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UseInactivityTrackerOptions
2
2
 
3
3
  # Interface: UseInactivityTrackerOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UseInactivityTrackerReturn
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UseInactivityTrackerReturn
2
2
 
3
3
  # Interface: UseInactivityTrackerReturn
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UsePublicEventLogoOptions
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UsePublicEventLogoOptions
2
2
 
3
3
  # Interface: UsePublicEventLogoOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UsePublicEventLogoReturn
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UsePublicEventLogoReturn
2
2
 
3
3
  # Interface: UsePublicEventLogoReturn
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UsePublicEventOptions
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UsePublicEventOptions
2
2
 
3
3
  # Interface: UsePublicEventOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UsePublicEventReturn
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UsePublicEventReturn
2
2
 
3
3
  # Interface: UsePublicEventReturn
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UsePublicFileDisplayOptions
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UsePublicFileDisplayOptions
2
2
 
3
3
  # Interface: UsePublicFileDisplayOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UsePublicFileDisplayReturn
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UsePublicFileDisplayReturn
2
2
 
3
3
  # Interface: UsePublicFileDisplayReturn
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UsePublicRouteParamsReturn
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UsePublicRouteParamsReturn
2
2
 
3
3
  # Interface: UsePublicRouteParamsReturn
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UseResolvedScopeOptions
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UseResolvedScopeOptions
2
2
 
3
3
  # Interface: UseResolvedScopeOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UseResolvedScopeReturn
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UseResolvedScopeReturn
2
2
 
3
3
  # Interface: UseResolvedScopeReturn
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UserEventAccess
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UserEventAccess
2
2
 
3
3
  # Interface: UserEventAccess
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UserMenuProps
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UserMenuProps
2
2
 
3
3
  # Interface: UserMenuProps
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.95](../README.md) / [Exports](../modules.md) / UserProfile
1
+ [@jmruthers/pace-core - v0.5.97](../README.md) / [Exports](../modules.md) / UserProfile
2
2
 
3
3
  # Interface: UserProfile
4
4
 
@@ -1,6 +1,6 @@
1
- [@jmruthers/pace-core - v0.5.95](README.md) / Exports
1
+ [@jmruthers/pace-core - v0.5.97](README.md) / Exports
2
2
 
3
- # @jmruthers/pace-core - v0.5.95
3
+ # @jmruthers/pace-core - v0.5.97
4
4
 
5
5
  **`File`**
6
6
 
@@ -694,7 +694,9 @@ function MealsTable() {
694
694
  filtering: true, // Enable filtering
695
695
  search: true,
696
696
  pagination: true,
697
- sorting: true
697
+ sorting: true,
698
+ export: true, // Enable export
699
+ import: true // Enable import
698
700
  }}
699
701
  rbac={{
700
702
  pageName: 'meals'
@@ -1227,6 +1229,159 @@ function UserManagement() {
1227
1229
  }
1228
1230
  ```
1229
1231
 
1232
+ ## Export and Import
1233
+
1234
+ DataTable provides seamless CSV export and import functionality with automatic column mapping and support for reference fields.
1235
+
1236
+ ### Basic Export/Import
1237
+
1238
+ When `export: true` and `import: true` are enabled in features, the DataTable automatically provides export and import buttons in the toolbar.
1239
+
1240
+ **Export**:
1241
+ - Exports all visible columns (respects column visibility settings)
1242
+ - Exports filtered data (respects current filters/search)
1243
+ - Exports all rows across all pages (not just current page)
1244
+ - Filename is automatically generated from table title: `{title}_{date}.csv`
1245
+
1246
+ **Import**:
1247
+ - Automatically maps CSV column headers to table columns
1248
+ - Case-insensitive header matching
1249
+ - Supports both display names and field names
1250
+
1251
+ ### Export/Import with Reference Fields
1252
+
1253
+ For columns that display related data (using `accessorFn` with `editAccessorKey`), the export includes both the display value and the ID value for seamless round-trip import/export.
1254
+
1255
+ #### Example: Reference Field Column
1256
+
1257
+ ```tsx
1258
+ const columns = [
1259
+ {
1260
+ id: "meal_code",
1261
+ accessorKey: "meal_code",
1262
+ header: "Meal Code",
1263
+ },
1264
+ {
1265
+ id: "meal_type",
1266
+ // Display function - shows the related meal type name
1267
+ accessorFn: (row) => row.mealtype?.mealtype_name || 'N/A',
1268
+ header: "Type",
1269
+ // Database field for storing/importing the ID
1270
+ editAccessorKey: 'meal_mealtype_id',
1271
+ fieldType: 'select',
1272
+ fieldOptions: mealTypes.map(mt => ({
1273
+ value: mt.mealtype_id,
1274
+ label: mt.mealtype_name
1275
+ }))
1276
+ },
1277
+ {
1278
+ id: "meal_date",
1279
+ accessorKey: "meal_date",
1280
+ header: "Date",
1281
+ },
1282
+ ];
1283
+ ```
1284
+
1285
+ #### Export Behavior
1286
+
1287
+ When you export this table, you'll get CSV columns like:
1288
+
1289
+ ```csv
1290
+ Meal Code,Type,Type (ID),Date
1291
+ ptry,Pantry,abc-123-uuid,2024-04-11
1292
+ 11bf,Breakfast,def-456-uuid,2024-04-11
1293
+ ```
1294
+
1295
+ **Notice**:
1296
+ - "Type" column contains the display value (e.g., "Pantry", "Breakfast")
1297
+ - "Type (ID)" column contains the actual ID value (e.g., UUID) for importing
1298
+ - Both columns are included automatically
1299
+
1300
+ #### Import Behavior
1301
+
1302
+ The import automatically recognizes and maps:
1303
+
1304
+ | CSV Header | Maps To | Description |
1305
+ |------------|---------|-------------|
1306
+ | `Type` | `meal_mealtype_id` | Display column header |
1307
+ | `Type (ID)` | `meal_mealtype_id` | ID column header |
1308
+ | `meal_mealtype_id` | `meal_mealtype_id` | Direct field name |
1309
+
1310
+ **Round-Trip Support**: You can export data, modify it in Excel/CSV, and re-import it - the IDs will be automatically mapped correctly.
1311
+
1312
+ #### Complete Example
1313
+
1314
+ ```tsx
1315
+ <DataTable
1316
+ data={meals}
1317
+ columns={columns}
1318
+ features={{
1319
+ export: true,
1320
+ import: true,
1321
+ // ... other features
1322
+ }}
1323
+ onImport={async (importedData) => {
1324
+ // Imported data is already mapped to your column structure
1325
+ // Reference fields use the editAccessorKey value
1326
+ for (const meal of importedData) {
1327
+ await createMeal({
1328
+ meal_code: meal.meal_code,
1329
+ meal_mealtype_id: meal.meal_mealtype_id, // Automatically mapped
1330
+ meal_date: meal.meal_date,
1331
+ });
1332
+ }
1333
+ }}
1334
+ rbac={{
1335
+ pageName: 'meals'
1336
+ }}
1337
+ />
1338
+ ```
1339
+
1340
+ ### Custom Export Filename
1341
+
1342
+ The export filename is automatically generated from the table `title` prop:
1343
+
1344
+ - If `title` is provided: `{title}_{date}.csv` (e.g., `meals_2024-04-11.csv`)
1345
+ - If no `title`: `data_export_{date}.csv`
1346
+
1347
+ To customize the filename, you can provide a custom `onExport` handler:
1348
+
1349
+ ```tsx
1350
+ <DataTable
1351
+ title="Meals"
1352
+ columns={columns}
1353
+ features={{ export: true }}
1354
+ onExport={async () => {
1355
+ // Custom export logic
1356
+ const data = getFilteredData();
1357
+ await exportToCSV(data, columns, 'custom-export-name.csv');
1358
+ }}
1359
+ />
1360
+ ```
1361
+
1362
+ ### Export Column Selection
1363
+
1364
+ **Important**: Only **visible columns** are exported. If a column is hidden (via column visibility controls), it will not be included in the export.
1365
+
1366
+ To ensure all columns are exported:
1367
+ - Make sure all desired columns are visible before exporting
1368
+ - Or use a custom `onExport` handler to export specific columns
1369
+
1370
+ ### Import Column Mapping
1371
+
1372
+ The import automatically maps CSV columns using this priority:
1373
+
1374
+ 1. **Column Header Match** (case-insensitive)
1375
+ - CSV header "Type" → maps to column with `header: "Type"`
1376
+
1377
+ 2. **editAccessorKey Match** (for reference fields)
1378
+ - CSV header "Type" or "Type (ID)" → maps to `editAccessorKey` field
1379
+
1380
+ 3. **accessorKey/id Match** (fallback)
1381
+ - CSV header matches column `accessorKey` or `id`
1382
+
1383
+ If no match is found, the CSV column name is used as-is (useful for new fields).
1384
+
1230
1385
  ### Form Integration
1231
1386
 
1232
1387
  ```tsx
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmruthers/pace-core",
3
- "version": "0.5.95",
3
+ "version": "0.5.97",
4
4
  "description": "Clean, modern React component library with Tailwind v4 styling and native utilities",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -25,7 +25,7 @@
25
25
  * - ✅ **Pagination** - Configurable pagination with custom initial page size and page size options
26
26
  * - ✅ **Sorting** - Multi-column sorting with visual indicators (↕️ unsorted, ↑ ascending, ↓ descending)
27
27
  * - ✅ **Filtering** - Column-specific filtering with multiple input types
28
- * - ✅ **Export/Import** - CSV and JSON data export/import
28
+ * - ✅ **Export/Import** - CSV data export/import with automatic column mapping and reference field support
29
29
  * - ✅ **Row Selection** - Single and multi-row selection for bulk operations
30
30
  * - ✅ **Row Creation** - Add new rows with validation
31
31
  * - ✅ **Row Editing** - Inline row editing with input field conversion
@@ -982,24 +982,51 @@ function DataTableInternal<TData extends DataRecord>({
982
982
  });
983
983
 
984
984
  // Map table columns back to original column definitions for export
985
- const visibleColumns = visibleTableColumns
986
- .map(tableCol => {
987
- // Find the original column definition that matches this table column
988
- const originalCol = columns.find(col => {
989
- const colId = col.id || col.accessorKey;
990
- return colId && String(colId) === tableCol.id;
985
+ // Also add ID columns for reference fields (columns with accessorFn + editAccessorKey)
986
+ const visibleColumns: Array<{
987
+ header?: string;
988
+ id?: string;
989
+ accessorKey?: string;
990
+ accessorFn?: (row: any) => any;
991
+ editAccessorKey?: string;
992
+ isIdColumn?: boolean;
993
+ }> = [];
994
+
995
+ visibleTableColumns.forEach(tableCol => {
996
+ // Find the original column definition that matches this table column
997
+ const originalCol = columns.find(col => {
998
+ const colId = col.id || col.accessorKey;
999
+ return colId && String(colId) === tableCol.id;
1000
+ });
1001
+
1002
+ if (!originalCol) return;
1003
+
1004
+ const hasAccessorFn = 'accessorFn' in originalCol && (originalCol as any).accessorFn;
1005
+ const editAccessorKey = originalCol.editAccessorKey;
1006
+
1007
+ // Add the display column (what's shown in the table)
1008
+ visibleColumns.push({
1009
+ ...originalCol,
1010
+ header: typeof originalCol.header === 'string'
1011
+ ? originalCol.header
1012
+ : originalCol.accessorKey || tableCol.id || 'Column',
1013
+ // Preserve accessorFn if present (for computed/reference fields)
1014
+ // accessorFn is part of ColumnDef from TanStack Table
1015
+ accessorFn: hasAccessorFn ? (originalCol as any).accessorFn : undefined,
1016
+ });
1017
+
1018
+ // For reference fields (accessorFn + editAccessorKey), also add ID column
1019
+ // This allows round-trip import/export to work seamlessly
1020
+ if (hasAccessorFn && editAccessorKey) {
1021
+ visibleColumns.push({
1022
+ id: editAccessorKey,
1023
+ accessorKey: editAccessorKey,
1024
+ header: `${originalCol.header || 'ID'} (ID)`,
1025
+ isIdColumn: true,
1026
+ editAccessorKey: editAccessorKey,
991
1027
  });
992
-
993
- if (!originalCol) return null;
994
-
995
- return {
996
- ...originalCol,
997
- header: typeof originalCol.header === 'string'
998
- ? originalCol.header
999
- : originalCol.accessorKey || tableCol.id || 'Column',
1000
- };
1001
- })
1002
- .filter((col): col is NonNullable<typeof col> => col !== null);
1028
+ }
1029
+ });
1003
1030
 
1004
1031
  // Generate filename with timestamp
1005
1032
  const timestamp = new Date().toISOString().split('T')[0];
@@ -1249,7 +1276,7 @@ function DataTableInternal<TData extends DataRecord>({
1249
1276
  <DataTableModals
1250
1277
  showImportModal={state.showImportModal}
1251
1278
  onCloseImportModal={() => stateActions.setImportModal(false)}
1252
- onImport={async (data) => {
1279
+ onImport={async (data: TData[]) => {
1253
1280
  if (onImport) {
1254
1281
  const result = onImport(data);
1255
1282
  if (result && typeof result.then === 'function') {
@@ -1259,6 +1286,12 @@ function DataTableInternal<TData extends DataRecord>({
1259
1286
  stateActions.setImportModal(false);
1260
1287
  }}
1261
1288
  importModalConfig={importModalConfig}
1289
+ columns={columns.map(col => ({
1290
+ id: col.id,
1291
+ accessorKey: col.accessorKey,
1292
+ header: typeof col.header === 'string' ? col.header : undefined,
1293
+ editAccessorKey: col.editAccessorKey,
1294
+ }))}
1262
1295
  />
1263
1296
  </>
1264
1297
  );
@@ -24,20 +24,83 @@
24
24
  import React, { useEffect } from 'react';
25
25
  import { ImportModal, type ImportModalConfig } from './ImportModal';
26
26
 
27
+ /**
28
+ * Maps CSV column data to table column structure
29
+ * Handles reference fields (columns with editAccessorKey) and direct accessorKey columns
30
+ */
31
+ function mapCSVToTableColumns<TData extends Record<string, unknown> = Record<string, unknown>>(
32
+ csvData: Array<Record<string, unknown>>,
33
+ columns: Array<{
34
+ id?: string;
35
+ accessorKey?: string;
36
+ header?: string;
37
+ editAccessorKey?: string;
38
+ }>
39
+ ): TData[] {
40
+ // Create a mapping from CSV headers to table field names
41
+ // Priority: editAccessorKey > accessorKey > id
42
+ const columnMap = new Map<string, string>();
43
+
44
+ columns.forEach(col => {
45
+ const fieldName = col.editAccessorKey || col.accessorKey || col.id;
46
+ const header = typeof col.header === 'string' ? col.header : '';
47
+
48
+ if (fieldName && header) {
49
+ // Map header to field name (case-insensitive)
50
+ columnMap.set(header.toLowerCase(), fieldName);
51
+ // Also map id/accessorKey if different from header
52
+ const colId = col.id || col.accessorKey;
53
+ if (colId && colId !== header && colId !== fieldName) {
54
+ columnMap.set(colId.toLowerCase(), fieldName);
55
+ }
56
+
57
+ // For reference fields with editAccessorKey, also map the ID column header
58
+ // This handles exports that include both "Type" and "Type (ID)" columns
59
+ if (col.editAccessorKey && header) {
60
+ const idColumnHeader = `${header} (ID)`;
61
+ columnMap.set(idColumnHeader.toLowerCase(), col.editAccessorKey);
62
+ // Also map the editAccessorKey directly (in case CSV uses the field name)
63
+ columnMap.set(col.editAccessorKey.toLowerCase(), col.editAccessorKey);
64
+ }
65
+ }
66
+ });
67
+
68
+ // Transform CSV data using the mapping
69
+ return csvData.map(row => {
70
+ const mappedRow: Record<string, unknown> = {};
71
+
72
+ // For each CSV column, find the corresponding table field
73
+ Object.keys(row).forEach(csvHeader => {
74
+ const csvHeaderLower = csvHeader.toLowerCase();
75
+ const fieldName = columnMap.get(csvHeaderLower) || csvHeaderLower;
76
+ mappedRow[fieldName] = row[csvHeader];
77
+ });
78
+
79
+ return mappedRow as TData;
80
+ });
81
+ }
82
+
27
83
  /**
28
84
  * Props interface for the DataTableModals component
29
85
  * @public
30
86
  */
31
- export interface DataTableModalsProps {
87
+ export interface DataTableModalsProps<TData extends Record<string, unknown> = Record<string, unknown>> {
32
88
  // Import modal
33
89
  /** Whether the import modal is visible */
34
90
  showImportModal: boolean;
35
91
  /** Callback function when the import modal is closed */
36
92
  onCloseImportModal: () => void;
37
93
  /** Callback function when data is imported successfully */
38
- onImport: (data: any[]) => void | Promise<void>;
94
+ onImport: (data: TData[]) => void | Promise<void>;
39
95
  /** Configuration object for customizing import modal text content */
40
96
  importModalConfig?: ImportModalConfig;
97
+ /** Column definitions for automatic column mapping during import */
98
+ columns?: Array<{
99
+ id?: string;
100
+ accessorKey?: string;
101
+ header?: string;
102
+ editAccessorKey?: string;
103
+ }>;
41
104
 
42
105
  // Focus management
43
106
  /** Function to store focus before opening modal */
@@ -72,14 +135,15 @@ export interface DataTableModalsProps {
72
135
  * />
73
136
  * ```
74
137
  */
75
- export function DataTableModals({
138
+ export function DataTableModals<TData extends Record<string, unknown> = Record<string, unknown>>({
76
139
  showImportModal,
77
140
  onCloseImportModal,
78
141
  onImport,
79
142
  importModalConfig,
143
+ columns,
80
144
  onStoreFocus,
81
145
  onRestoreFocus,
82
- }: DataTableModalsProps) {
146
+ }: DataTableModalsProps<TData>) {
83
147
  // Handle focus management for import modal
84
148
  useEffect(() => {
85
149
  if (showImportModal) {
@@ -99,7 +163,14 @@ export function DataTableModals({
99
163
  <ImportModal
100
164
  isOpen={showImportModal}
101
165
  onClose={onCloseImportModal}
102
- onImport={onImport}
166
+ onImport={async (rawData: Array<Record<string, unknown>>) => {
167
+ // Automatically map CSV columns to table columns based on column definitions
168
+ const mappedData = columns ? mapCSVToTableColumns<TData>(rawData, columns) : (rawData as TData[]);
169
+ const result = onImport(mappedData);
170
+ if (result && typeof result.then === 'function') {
171
+ await result;
172
+ }
173
+ }}
103
174
  config={importModalConfig}
104
175
  />
105
176