@jmruthers/pace-core 0.6.6 → 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.
Files changed (246) hide show
  1. package/{scripts/audit/audit-dependencies.cjs → audit-tool/00-dependencies.cjs} +12 -13
  2. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  3. package/audit-tool/audits/02-project-structure.cjs +255 -0
  4. package/audit-tool/audits/03-architecture.cjs +196 -0
  5. package/audit-tool/audits/04-code-quality.cjs +149 -0
  6. package/audit-tool/audits/05-styling.cjs +224 -0
  7. package/audit-tool/audits/06-security-rbac.cjs +544 -0
  8. package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
  9. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  10. package/audit-tool/audits/09-operations.cjs +208 -0
  11. package/audit-tool/index.cjs +291 -0
  12. package/audit-tool/utils/code-utils.cjs +218 -0
  13. package/audit-tool/utils/file-utils.cjs +230 -0
  14. package/audit-tool/utils/report-utils.cjs +241 -0
  15. package/cursor-rules/00-standards-overview.mdc +156 -0
  16. package/cursor-rules/{00-pace-core-compliance.mdc → 01-pace-core-compliance.mdc} +187 -34
  17. package/cursor-rules/02-project-structure.mdc +37 -5
  18. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +125 -11
  19. package/cursor-rules/04-code-quality.mdc +419 -0
  20. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +55 -10
  21. package/cursor-rules/{09-rbac-compliance.mdc → 06-security-rbac.mdc} +62 -6
  22. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  23. package/cursor-rules/08-testing-documentation.mdc +324 -0
  24. package/cursor-rules/09-operations.mdc +365 -0
  25. package/dist/DataTable-7PMH7XN7.js +15 -0
  26. package/dist/{DataTable-2N_tqbfq.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  27. package/dist/{PublicPageProvider-BBH6Vqg7.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +26 -16
  28. package/dist/{chunk-FENMYN2U.js → chunk-5X4QLXRG.js} +1 -3
  29. package/dist/{chunk-4T7OBVTU.js → chunk-6F3IILHI.js} +1 -1
  30. package/dist/{chunk-SD6WQY43.js → chunk-7ILTDCL2.js} +9 -1
  31. package/dist/{chunk-3QC3KRHK.js → chunk-A3W6LW53.js} +16 -1
  32. package/dist/{chunk-7TYHROIV.js → chunk-BM4CQ5P3.js} +50 -8
  33. package/dist/{chunk-2HGJFNAH.js → chunk-FEJLJNWA.js} +1 -15
  34. package/dist/{chunk-OHIK3MIO.js → chunk-GHYHJTYV.js} +2 -2
  35. package/dist/{chunk-UIYSCEV7.js → chunk-IUBRCBSY.js} +1 -1
  36. package/dist/{chunk-LAZMKTTF.js → chunk-JGWDVX64.js} +281 -347
  37. package/dist/{chunk-MAGBIDNS.js → chunk-L4XMVJKY.js} +2 -2
  38. package/dist/{chunk-A55DK444.js → chunk-OJ4SKRSV.js} +1 -7
  39. package/dist/{chunk-ZS5VO5JB.js → chunk-Q7Q7V5NV.js} +406 -451
  40. package/dist/{chunk-3O3WHILE.js → chunk-VBCS3DUA.js} +236 -60
  41. package/dist/{chunk-BVP2BCJF.js → chunk-ZKAWKYT4.js} +8 -8
  42. package/dist/components.d.ts +5 -4
  43. package/dist/components.js +27 -32
  44. package/dist/eslint-rules/index.cjs +22 -9
  45. package/{src/eslint-rules/rules/compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +184 -23
  46. package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
  47. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  48. package/dist/eslint-rules/rules/{rbac.cjs → 06-security-rbac.cjs} +26 -10
  49. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
  50. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  51. package/dist/hooks.d.ts +5 -5
  52. package/dist/hooks.js +6 -6
  53. package/dist/index.d.ts +6 -6
  54. package/dist/index.js +18 -17
  55. package/dist/rbac/index.js +6 -6
  56. package/dist/theming/runtime.d.ts +14 -1
  57. package/dist/theming/runtime.js +1 -1
  58. package/dist/{types-B-K_5VnO.d.ts → types-DXstZpNI.d.ts} +0 -17
  59. package/dist/{usePublicRouteParams-COZ28Mvq.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +19 -19
  60. package/dist/utils.d.ts +2 -2
  61. package/dist/utils.js +8 -8
  62. package/docs/README.md +1 -1
  63. package/docs/api/modules.md +47 -31
  64. package/docs/api-reference/components.md +18 -20
  65. package/docs/api-reference/hooks.md +80 -80
  66. package/docs/api-reference/types.md +1 -1
  67. package/docs/api-reference/utilities.md +1 -1
  68. package/docs/architecture/README.md +1 -1
  69. package/docs/core-concepts/events.md +3 -3
  70. package/docs/core-concepts/organisations.md +6 -6
  71. package/docs/core-concepts/permissions.md +6 -6
  72. package/docs/documentation-index.md +12 -18
  73. package/docs/getting-started/documentation-index.md +1 -1
  74. package/docs/getting-started/examples/README.md +4 -4
  75. package/docs/getting-started/examples/full-featured-app.md +1 -1
  76. package/docs/getting-started/faq.md +2 -2
  77. package/docs/getting-started/quick-reference.md +4 -4
  78. package/docs/implementation-guides/authentication.md +15 -15
  79. package/docs/implementation-guides/component-styling.md +1 -1
  80. package/docs/implementation-guides/data-tables.md +126 -33
  81. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  82. package/docs/implementation-guides/dynamic-colors.md +3 -3
  83. package/docs/implementation-guides/file-upload-storage.md +2 -2
  84. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  85. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  86. package/docs/implementation-guides/large-datasets.md +3 -2
  87. package/docs/implementation-guides/organisation-security.md +2 -2
  88. package/docs/implementation-guides/performance.md +2 -2
  89. package/docs/implementation-guides/permission-enforcement.md +1 -1
  90. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  91. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  92. package/docs/rbac/README.md +5 -5
  93. package/docs/rbac/advanced-patterns.md +6 -6
  94. package/docs/rbac/api-reference.md +20 -20
  95. package/docs/rbac/event-based-apps.md +3 -3
  96. package/docs/rbac/examples.md +41 -41
  97. package/docs/rbac/getting-started.md +37 -37
  98. package/docs/rbac/performance.md +1 -1
  99. package/docs/rbac/quick-start.md +52 -52
  100. package/docs/rbac/secure-client-protection.md +1 -1
  101. package/docs/rbac/troubleshooting.md +1 -1
  102. package/docs/security/README.md +5 -5
  103. package/docs/standards/0-standards-overview.md +220 -0
  104. package/docs/standards/{00-pace-core-compliance.md → 1-pace-core-compliance-standards.md} +204 -185
  105. package/docs/standards/{02-project-structure.md → 2-project-structure-standards.md} +11 -47
  106. package/docs/standards/3-architecture-standards.md +606 -0
  107. package/docs/standards/4-code-quality-standards.md +728 -0
  108. package/docs/standards/{08-markup-quality.md → 5-styling-standards.md} +12 -9
  109. package/docs/standards/{09-rbac-compliance.md → 6-security-rbac-standards.md} +126 -18
  110. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  111. package/docs/standards/8-testing-documentation-standards.md +401 -0
  112. package/docs/standards/9-operations-standards.md +1102 -0
  113. package/docs/standards/README.md +203 -104
  114. package/docs/troubleshooting/README.md +4 -4
  115. package/docs/troubleshooting/common-issues.md +2 -2
  116. package/docs/troubleshooting/debugging.md +9 -9
  117. package/docs/troubleshooting/migration.md +4 -4
  118. package/eslint-config-pace-core.cjs +21 -10
  119. package/package.json +6 -5
  120. package/scripts/install-cursor-rules.cjs +11 -243
  121. package/scripts/install-eslint-config.cjs +284 -0
  122. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +2 -2
  123. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  124. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +10 -10
  125. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  126. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  127. package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
  128. package/src/__tests__/templates/component.test.template.tsx +18 -15
  129. package/src/components/Calendar/Calendar.tsx +201 -47
  130. package/src/components/ContextSelector/ContextSelector.tsx +137 -153
  131. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  132. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
  133. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
  134. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  135. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  136. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  137. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  138. package/src/components/DataTable/components/DataTableLayout.tsx +5 -16
  139. package/src/components/DataTable/components/EditableRow.tsx +5 -7
  140. package/src/components/DataTable/components/EmptyState.tsx +10 -9
  141. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  142. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  143. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  144. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  145. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  146. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  147. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  148. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  149. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  150. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
  151. package/src/components/DataTable/components/index.ts +2 -1
  152. package/src/components/DataTable/types.ts +0 -18
  153. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  154. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
  155. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  156. package/src/components/DateTimeField/DateTimeField.tsx +7 -8
  157. package/src/components/Dialog/Dialog.test.tsx +1 -0
  158. package/src/components/Dialog/Dialog.tsx +25 -8
  159. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  160. package/src/components/FileUpload/FileUpload.test.tsx +52 -14
  161. package/src/components/FileUpload/FileUpload.tsx +112 -130
  162. package/src/components/Progress/Progress.tsx +2 -4
  163. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  164. package/src/components/Select/Select.tsx +86 -77
  165. package/src/components/Select/types.ts +3 -0
  166. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  167. package/src/hooks/__tests__/hooks.integration.test.tsx +49 -49
  168. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
  169. package/src/hooks/public/usePublicEvent.ts +5 -5
  170. package/src/hooks/public/usePublicEventLogo.ts +5 -5
  171. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  172. package/src/hooks/public/usePublicRouteParams.ts +5 -5
  173. package/src/hooks/useAppConfig.ts +2 -2
  174. package/src/hooks/useEventTheme.test.ts +7 -7
  175. package/src/hooks/useEventTheme.ts +1 -4
  176. package/src/hooks/useFileDisplay.ts +2 -2
  177. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  178. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  179. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  180. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  181. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  182. package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
  183. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  184. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  185. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +10 -10
  186. package/src/styles/core.css +7 -0
  187. package/src/theming/__tests__/parseEventColours.test.ts +9 -3
  188. package/src/theming/parseEventColours.ts +22 -10
  189. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  190. package/src/utils/storage/README.md +1 -1
  191. package/cursor-rules/01-standards-compliance.mdc +0 -285
  192. package/cursor-rules/04-testing-standards.mdc +0 -270
  193. package/cursor-rules/05-bug-reports-and-features.mdc +0 -248
  194. package/cursor-rules/06-code-quality.mdc +0 -311
  195. package/cursor-rules/07-tech-stack-compliance.mdc +0 -216
  196. package/cursor-rules/10-error-handling-patterns.mdc +0 -179
  197. package/cursor-rules/11-performance-optimization.mdc +0 -169
  198. package/cursor-rules/12-ci-cd-integration.mdc +0 -150
  199. package/dist/DataTable-LRJL4IRV.js +0 -15
  200. package/dist/eslint-rules/rules/compliance.cjs +0 -348
  201. package/dist/eslint-rules/rules/components.cjs +0 -113
  202. package/dist/eslint-rules/rules/imports.cjs +0 -102
  203. package/docs/best-practices/README.md +0 -472
  204. package/docs/best-practices/accessibility.md +0 -604
  205. package/docs/best-practices/common-patterns.md +0 -516
  206. package/docs/best-practices/deployment.md +0 -1103
  207. package/docs/best-practices/performance.md +0 -1328
  208. package/docs/best-practices/security.md +0 -940
  209. package/docs/best-practices/testing.md +0 -1034
  210. package/docs/rbac/compliance/compliance-guide.md +0 -544
  211. package/docs/standards/01-standards-compliance.md +0 -188
  212. package/docs/standards/03-solid-principles.md +0 -39
  213. package/docs/standards/04-testing-standards.md +0 -36
  214. package/docs/standards/05-bug-reports-and-features.md +0 -27
  215. package/docs/standards/06-code-quality.md +0 -34
  216. package/docs/standards/07-tech-stack-compliance.md +0 -30
  217. package/docs/standards/10-error-handling-patterns.md +0 -401
  218. package/docs/standards/11-performance-optimization.md +0 -348
  219. package/docs/standards/12-ci-cd-integration.md +0 -370
  220. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +0 -192
  221. package/scripts/audit/audit-compliance.cjs +0 -1295
  222. package/scripts/audit/audit-components.cjs +0 -260
  223. package/scripts/audit/audit-rbac.cjs +0 -954
  224. package/scripts/audit/audit-standards.cjs +0 -1268
  225. package/scripts/audit/index.cjs +0 -1927
  226. package/src/components/DataTable/components/DataTableBody.tsx +0 -478
  227. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  228. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  229. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  230. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  231. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  232. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  233. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  234. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  235. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  236. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  237. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  238. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  239. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  240. package/src/components/DataTable/utils/debugTools.ts +0 -514
  241. package/src/eslint-rules/index.cjs +0 -22
  242. package/src/eslint-rules/rules/components.cjs +0 -113
  243. package/src/eslint-rules/rules/imports.cjs +0 -102
  244. package/src/eslint-rules/rules/rbac.cjs +0 -790
  245. package/src/eslint-rules/utils/helpers.cjs +0 -42
  246. package/src/eslint-rules/utils/manifest-loader.cjs +0 -75
@@ -44,10 +44,11 @@ import { getTextContent } from "./utils/text";
44
44
  * @returns The rendered select component
45
45
  */
46
46
  export const Select = React.forwardRef<HTMLFieldSetElement, SelectProps & UseSelectStateProps>(
47
- ({
47
+ ({
48
48
  children,
49
49
  className,
50
50
  direction = 'down',
51
+ showCheckmark = true,
51
52
  ...selectProps
52
53
  }, ref) => {
53
54
  const internalRef = React.useRef<HTMLFieldSetElement>(null);
@@ -108,7 +109,7 @@ export const Select = React.forwardRef<HTMLFieldSetElement, SelectProps & UseSel
108
109
  // Query the DOM for the SelectItem (li element) with matching value
109
110
  // Must be a select-item, not the trigger which also has data-value
110
111
  let selectItem = selectElement.querySelector(`[data-testid="select-item"][data-value="${state.value}"]`) as HTMLElement;
111
-
112
+
112
113
  // If not found, try querying within content containers
113
114
  if (!selectItem) {
114
115
  const hiddenContent = selectElement.querySelector('[data-testid="select-content-hidden"]');
@@ -116,7 +117,7 @@ export const Select = React.forwardRef<HTMLFieldSetElement, SelectProps & UseSel
116
117
  selectItem = hiddenContent.querySelector(`[data-testid="select-item"][data-value="${state.value}"]`) as HTMLElement;
117
118
  }
118
119
  }
119
-
120
+
120
121
  // Try visible content as fallback
121
122
  if (!selectItem) {
122
123
  const visibleContent = selectElement.querySelector('[data-testid="select-content"]');
@@ -130,7 +131,7 @@ export const Select = React.forwardRef<HTMLFieldSetElement, SelectProps & UseSel
130
131
  let textContent = selectItem.textContent?.trim() || '';
131
132
  // Remove any check mark icons or other decorators (basic cleanup)
132
133
  textContent = textContent.split('\n').map(line => line.trim()).filter(line => line).join(' ');
133
-
134
+
134
135
  if (textContent) {
135
136
  actions.setSelectedText(textContent);
136
137
  // Also register it for future use
@@ -138,11 +139,11 @@ export const Select = React.forwardRef<HTMLFieldSetElement, SelectProps & UseSel
138
139
  return;
139
140
  }
140
141
  }
141
-
142
+
142
143
  // If not found and we have a content container, items might still be rendering
143
144
  // Don't clear selectedText in this case - let the MutationObserver or retry effect handle it
144
- const hasContentContainer = selectElement.querySelector('[data-testid="select-content-hidden"]') ||
145
- selectElement.querySelector('[data-testid="select-content"]');
145
+ const hasContentContainer = selectElement.querySelector('[data-testid="select-content-hidden"]') ||
146
+ selectElement.querySelector('[data-testid="select-content"]');
146
147
  if (!hasContentContainer) {
147
148
  // No content container means no items exist - clear selectedText
148
149
  actions.setSelectedText('');
@@ -198,7 +199,8 @@ export const Select = React.forwardRef<HTMLFieldSetElement, SelectProps & UseSel
198
199
  registerItem,
199
200
  unregisterItem,
200
201
  direction,
201
- }), [state, actions, registerItem, unregisterItem, direction]);
202
+ showCheckmark,
203
+ }), [state, actions, registerItem, unregisterItem, direction, showCheckmark]);
202
204
 
203
205
  return (
204
206
  <fieldset
@@ -235,14 +237,14 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
235
237
 
236
238
  // Use ref to store the latest handleClick to avoid re-creating the effect
237
239
  const handleClickRef = React.useRef<(e: React.MouseEvent) => void>(undefined);
238
-
240
+
239
241
  const handleClick = React.useCallback((e: React.MouseEvent) => {
240
242
  if (disabled) {
241
243
  e.preventDefault();
242
244
  e.stopPropagation();
243
245
  return;
244
246
  }
245
-
247
+
246
248
  e.preventDefault();
247
249
  e.stopPropagation();
248
250
  actions.setOpen(!open);
@@ -313,14 +315,14 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
313
315
 
314
316
  // Early return after all hooks have been called
315
317
  if (asChild) {
316
- const childElement = children as React.ReactElement<{ children?: React.ReactNode; [key: string]: unknown }>;
318
+ const childElement = children as React.ReactElement<{ children?: React.ReactNode;[key: string]: unknown }>;
317
319
  const childChildren = React.Children.toArray(childElement.props.children);
318
320
  const hasChevron = childChildren.some(child => {
319
321
  if (React.isValidElement(child)) {
320
- const childProps = child.props as { 'data-testid'?: string; [key: string]: unknown };
321
- return child.type === ChevronDown ||
322
- (child.type === 'svg' && childProps['data-testid'] === 'chevron-down') ||
323
- (typeof child === 'object' && 'type' in child && typeof child.type === 'function' && child.type.name === 'ChevronDown');
322
+ const childProps = child.props as { 'data-testid'?: string;[key: string]: unknown };
323
+ return child.type === ChevronDown ||
324
+ (child.type === 'svg' && childProps['data-testid'] === 'chevron-down') ||
325
+ (typeof child === 'object' && 'type' in child && typeof child.type === 'function' && child.type.name === 'ChevronDown');
324
326
  }
325
327
  return false;
326
328
  });
@@ -337,12 +339,12 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
337
339
  className: mergedClassName,
338
340
  children: hasChevron ? childChildren : [
339
341
  ...childChildren,
340
- <ChevronDown
342
+ <ChevronDown
341
343
  key="chevron-down"
342
344
  className={cn(
343
345
  "size-4 opacity-50 transition-transform pointer-events-none float-right",
344
346
  open && "rotate-180"
345
- )}
347
+ )}
346
348
  />
347
349
  ]
348
350
  });
@@ -380,11 +382,11 @@ export const SelectTrigger = React.forwardRef<HTMLButtonElement, SelectTriggerPr
380
382
  {...props}
381
383
  >
382
384
  {children}
383
- <ChevronDown
385
+ <ChevronDown
384
386
  className={cn(
385
387
  "size-4 opacity-50 transition-transform pointer-events-none float-right",
386
388
  open && "rotate-180"
387
- )}
389
+ )}
388
390
  />
389
391
  </Button>
390
392
  );
@@ -409,8 +411,8 @@ export const SelectValue = React.forwardRef<HTMLSpanElement, SelectValueProps>(
409
411
  const { selectedText } = useSelectContext();
410
412
 
411
413
  return (
412
- <span
413
- ref={ref}
414
+ <span
415
+ ref={ref}
414
416
  data-testid="select-value"
415
417
  style={{ pointerEvents: 'none' }}
416
418
  className="pointer-events-none"
@@ -435,9 +437,9 @@ SelectValue.displayName = "SelectValue";
435
437
  * @returns The rendered select content
436
438
  */
437
439
  export const SelectContent = React.forwardRef<HTMLUListElement, SelectContentProps>(
438
- ({
439
- children,
440
- className,
440
+ ({
441
+ children,
442
+ className,
441
443
  searchable = false,
442
444
  searchPlaceholder = "Search...",
443
445
  maxHeight = "max(20rem, 50vh)",
@@ -473,19 +475,19 @@ export const SelectContent = React.forwardRef<HTMLUListElement, SelectContentPro
473
475
  }
474
476
 
475
477
  const opensUpward = direction === 'up';
476
-
478
+
477
479
  return (
478
480
  <ul
479
481
  ref={ref}
480
482
  className={cn(
481
483
  "absolute z-[99999] w-full overflow-y-auto border border-main-300 bg-main-50 shadow-lg",
482
484
  "list-none p-0 m-0",
483
- opensUpward
484
- ? "rounded-t-md border-b-0"
485
+ opensUpward
486
+ ? "rounded-t-md border-b-0"
485
487
  : "rounded-b-md border-t-0",
486
488
  className
487
489
  )}
488
- style={{
490
+ style={{
489
491
  [opensUpward ? 'bottom' : 'top']: '100%',
490
492
  left: 0,
491
493
  right: 0,
@@ -498,38 +500,36 @@ export const SelectContent = React.forwardRef<HTMLUListElement, SelectContentPro
498
500
  role="listbox"
499
501
  >
500
502
  {searchable && (
501
- <div className="p-2 border-b border-main-200">
502
- <div className="relative">
503
- <Search className="absolute left-2 top-1/2 transform -translate-y-1/2 size-4 text-main-400" />
504
- <input
505
- ref={searchInputRef}
506
- type="text"
507
- placeholder={searchPlaceholder}
508
- value={searchTerm}
509
- onChange={(e) => setSearchTerm(e.target.value)}
510
- onKeyDown={(e) => {
511
- if (e.key === 'Escape') {
512
- e.preventDefault();
513
- setSearchTerm('');
514
- }
515
- }}
516
- className="w-full pl-8 pr-8 py-1 text-sm border border-main-200 rounded focus:outline-none focus:ring-2 focus:ring-main-500"
517
- data-testid="select-search-input"
518
- aria-label="Search options"
519
- />
520
- {searchTerm && (
521
- <button
522
- type="button"
523
- onClick={() => setSearchTerm('')}
524
- className="absolute right-2 top-1/2 transform -translate-y-1/2 text-main-400 hover:text-main-600"
525
- data-testid="select-clear-search"
526
- aria-label="Clear search"
527
- >
528
- <X className="size-4" />
529
- </button>
530
- )}
531
- </div>
532
- </div>
503
+ <li className="relative p-2 border-b border-main-200 sticky top-0 bg-main-50 z-10" data-testid="select-search-item">
504
+ <Search className="absolute left-2 top-1/2 transform -translate-y-1/2 size-4 text-main-400" />
505
+ <input
506
+ ref={searchInputRef}
507
+ type="text"
508
+ placeholder={searchPlaceholder}
509
+ value={searchTerm}
510
+ onChange={(e) => setSearchTerm(e.target.value)}
511
+ onKeyDown={(e) => {
512
+ if (e.key === 'Escape') {
513
+ e.preventDefault();
514
+ setSearchTerm('');
515
+ }
516
+ }}
517
+ className="w-full pl-8 pr-8 py-1 text-sm border border-main-200 rounded focus:outline-none focus:ring-2 focus:ring-main-500"
518
+ data-testid="select-search-input"
519
+ aria-label="Search options"
520
+ />
521
+ {searchTerm && (
522
+ <button
523
+ type="button"
524
+ onClick={() => setSearchTerm('')}
525
+ className="absolute right-2 top-1/2 transform -translate-y-1/2 text-main-400 hover:text-main-600"
526
+ data-testid="select-clear-search"
527
+ aria-label="Clear search"
528
+ >
529
+ <X className="size-4" />
530
+ </button>
531
+ )}
532
+ </li>
533
533
  )}
534
534
  {filteredChildren}
535
535
  </ul>
@@ -551,9 +551,12 @@ SelectContent.displayName = "SelectContent";
551
551
  * @returns The rendered select item
552
552
  */
553
553
  export const SelectItem = React.forwardRef<HTMLLIElement, SelectItemProps>(
554
- ({ value, children, disabled = false, className, onClick }, ref) => {
555
- const { value: selectedValue, actions, registerItem, unregisterItem } = useSelectContext();
554
+ ({ value, children, disabled = false, className, onClick, showCheckmark: propShowCheckmark }, ref) => {
555
+ const { value: selectedValue, actions, registerItem, unregisterItem, showCheckmark: contextShowCheckmark = true } = useSelectContext();
556
556
  const isSelected = selectedValue === value;
557
+
558
+ // Use prop if provided, otherwise use context value, default to true
559
+ const showCheckmark = propShowCheckmark ?? contextShowCheckmark;
557
560
 
558
561
  const itemText = getTextContent(children);
559
562
 
@@ -569,7 +572,7 @@ export const SelectItem = React.forwardRef<HTMLLIElement, SelectItemProps>(
569
572
  }
570
573
  };
571
574
  }, [value, itemText, registerItem, unregisterItem]);
572
-
575
+
573
576
  const handleMouseDown = (e: React.MouseEvent) => {
574
577
  if (!disabled) {
575
578
  // CRITICAL FIX: Prevent event from bubbling to avoid interference with table row interactions
@@ -636,7 +639,7 @@ export const SelectItem = React.forwardRef<HTMLLIElement, SelectItemProps>(
636
639
  tabIndex={disabled ? -1 : 0}
637
640
  >
638
641
  {children}
639
- {isSelected && (
642
+ {isSelected && showCheckmark && (
640
643
  <Check className="absolute right-2 size-4 flex-shrink-0 mt-0.5" />
641
644
  )}
642
645
  </li>
@@ -651,18 +654,24 @@ SelectItem.displayName = "SelectItem";
651
654
 
652
655
  /**
653
656
  * Select group component.
654
- * Groups related select items together.
657
+ * Groups related select items together using a nested list structure.
655
658
  *
656
659
  * @param props - Select group configuration
657
- * @param ref - Forwarded ref to the div element
660
+ * @param ref - Forwarded ref to the ul element
658
661
  * @returns The rendered select group
659
662
  */
660
- export const SelectGroup = React.forwardRef<HTMLDivElement, { children: React.ReactNode; className?: string }>(
663
+ export const SelectGroup = React.forwardRef<HTMLUListElement, { children: React.ReactNode; className?: string }>(
661
664
  ({ children, className }, ref) => {
662
665
  return (
663
- <div ref={ref} className={cn("p-1", className)} data-testid="select-group">
664
- {children}
665
- </div>
666
+ <li className="list-none" data-testid="select-group-wrapper">
667
+ <ul
668
+ ref={ref}
669
+ className={cn("p-1 list-none m-0", className)}
670
+ data-testid="select-group"
671
+ >
672
+ {children}
673
+ </ul>
674
+ </li>
666
675
  );
667
676
  }
668
677
  );
@@ -673,15 +682,15 @@ SelectGroup.displayName = "SelectGroup";
673
682
  * Provides a label for a group of select items.
674
683
  *
675
684
  * @param props - Select label configuration
676
- * @param ref - Forwarded ref to the div element
685
+ * @param ref - Forwarded ref to the li element
677
686
  * @returns The rendered select label
678
687
  */
679
- export const SelectLabel = React.forwardRef<HTMLDivElement, { children: React.ReactNode; className?: string }>(
688
+ export const SelectLabel = React.forwardRef<HTMLLIElement, { children: React.ReactNode; className?: string }>(
680
689
  ({ children, className }, ref) => {
681
690
  return (
682
- <div ref={ref} className={cn("px-2 py-1.5 text-sm font-semibold", className)} data-testid="select-label">
691
+ <li ref={ref} className={cn("px-2 py-1.5 text-sm font-semibold", className)} data-testid="select-label">
683
692
  {children}
684
- </div>
693
+ </li>
685
694
  );
686
695
  }
687
696
  );
@@ -692,13 +701,13 @@ SelectLabel.displayName = "SelectLabel";
692
701
  * Provides visual separation between groups of select items.
693
702
  *
694
703
  * @param props - Select separator configuration
695
- * @param ref - Forwarded ref to the div element
704
+ * @param ref - Forwarded ref to the hr element
696
705
  * @returns The rendered select separator
697
706
  */
698
- export const SelectSeparator = React.forwardRef<HTMLDivElement, { className?: string }>(
707
+ export const SelectSeparator = React.forwardRef<HTMLHRElement, { className?: string }>(
699
708
  ({ className }, ref) => {
700
709
  return (
701
- <div
710
+ <hr
702
711
  ref={ref}
703
712
  className={cn("my-1 h-px bg-sec-200", className)}
704
713
  data-testid="select-separator"
@@ -67,6 +67,7 @@ export interface SelectContextValue extends SelectState {
67
67
  registerItem?: (value: string, text: string) => void;
68
68
  unregisterItem?: (value: string) => void;
69
69
  direction?: SelectDirection;
70
+ showCheckmark?: boolean;
70
71
  }
71
72
 
72
73
  /**
@@ -80,6 +81,7 @@ export interface SelectProps
80
81
  children: React.ReactNode;
81
82
  className?: string;
82
83
  direction?: SelectDirection;
84
+ showCheckmark?: boolean;
83
85
  }
84
86
 
85
87
  /**
@@ -120,4 +122,5 @@ export interface SelectItemProps {
120
122
  disabled?: boolean;
121
123
  className?: string;
122
124
  onClick?: (e: React.MouseEvent) => void;
125
+ showCheckmark?: boolean;
123
126
  }
@@ -137,7 +137,7 @@ describe('Service Hooks', () => {
137
137
  it('should return AuthService from context', () => {
138
138
  const mockService = createMockService('auth');
139
139
  const wrapper = ({ children }: { children: React.ReactNode }) => (
140
- <div>{children}</div>
140
+ <section>{children}</section>
141
141
  );
142
142
 
143
143
  // Mock the context with proper structure
@@ -150,7 +150,7 @@ describe('Service Hooks', () => {
150
150
 
151
151
  it('should throw error when used outside provider', () => {
152
152
  const wrapper = ({ children }: { children: React.ReactNode }) => (
153
- <div>{children}</div>
153
+ <section>{children}</section>
154
154
  );
155
155
 
156
156
  // Mock the context to return null
@@ -164,7 +164,7 @@ describe('Service Hooks', () => {
164
164
  it('should subscribe to service changes', () => {
165
165
  const mockService = createMockService('auth');
166
166
  const wrapper = ({ children }: { children: React.ReactNode }) => (
167
- <div>{children}</div>
167
+ <section>{children}</section>
168
168
  );
169
169
 
170
170
  mockUseContext.mockReturnValue({ authService: mockService });
@@ -179,7 +179,7 @@ describe('Service Hooks', () => {
179
179
  it('should return OrganisationService from context', () => {
180
180
  const mockService = createMockService('organisation');
181
181
  const wrapper = ({ children }: { children: React.ReactNode }) => (
182
- <div>{children}</div>
182
+ <section>{children}</section>
183
183
  );
184
184
 
185
185
  mockUseContext.mockReturnValue({ organisationService: mockService });
@@ -191,7 +191,7 @@ describe('Service Hooks', () => {
191
191
 
192
192
  it('should throw error when used outside provider', () => {
193
193
  const wrapper = ({ children }: { children: React.ReactNode }) => (
194
- <div>{children}</div>
194
+ <section>{children}</section>
195
195
  );
196
196
 
197
197
  mockUseContext.mockReturnValue(null);
@@ -206,7 +206,7 @@ describe('Service Hooks', () => {
206
206
  it('should return EventService from context', () => {
207
207
  const mockService = createMockService('event');
208
208
  const wrapper = ({ children }: { children: React.ReactNode }) => (
209
- <div>{children}</div>
209
+ <section>{children}</section>
210
210
  );
211
211
 
212
212
  mockUseContext.mockReturnValue({ eventService: mockService });
@@ -218,7 +218,7 @@ describe('Service Hooks', () => {
218
218
 
219
219
  it('should throw error when used outside provider', () => {
220
220
  const wrapper = ({ children }: { children: React.ReactNode }) => (
221
- <div>{children}</div>
221
+ <section>{children}</section>
222
222
  );
223
223
 
224
224
  mockUseContext.mockReturnValue(null);
@@ -233,7 +233,7 @@ describe('Service Hooks', () => {
233
233
  it('should return InactivityService from context', () => {
234
234
  const mockService = createMockService('inactivity');
235
235
  const wrapper = ({ children }: { children: React.ReactNode }) => (
236
- <div>{children}</div>
236
+ <section>{children}</section>
237
237
  );
238
238
 
239
239
  vi.spyOn(React, 'useContext').mockReturnValue({ inactivityService: mockService });
@@ -245,7 +245,7 @@ describe('Service Hooks', () => {
245
245
 
246
246
  it('should throw error when used outside provider', () => {
247
247
  const wrapper = ({ children }: { children: React.ReactNode }) => (
248
- <div>{children}</div>
248
+ <section>{children}</section>
249
249
  );
250
250
 
251
251
  mockUseContext.mockReturnValue(null);
@@ -276,7 +276,7 @@ describe('Service Hooks', () => {
276
276
  };
277
277
 
278
278
  const wrapper = ({ children }: { children: React.ReactNode }) => (
279
- <div>{children}</div>
279
+ <section>{children}</section>
280
280
  );
281
281
 
282
282
  mockUseContext.mockReturnValue({ authService: mockService });
@@ -327,7 +327,7 @@ describe('Service Hooks', () => {
327
327
  };
328
328
 
329
329
  const wrapper = ({ children }: { children: React.ReactNode }) => (
330
- <div>{children}</div>
330
+ <section>{children}</section>
331
331
  );
332
332
 
333
333
  mockUseContext.mockReturnValue({ rbacService: mockService });
@@ -382,7 +382,7 @@ describe('Service Hooks', () => {
382
382
  };
383
383
 
384
384
  const wrapper = ({ children }: { children: React.ReactNode }) => (
385
- <div>{children}</div>
385
+ <section>{children}</section>
386
386
  );
387
387
 
388
388
  mockUseContext.mockReturnValue({ organisationService: mockService });
@@ -434,7 +434,7 @@ describe('Service Hooks', () => {
434
434
  };
435
435
 
436
436
  const wrapper = ({ children }: { children: React.ReactNode }) => (
437
- <div>{children}</div>
437
+ <section>{children}</section>
438
438
  );
439
439
 
440
440
  mockUseContext.mockReturnValue({ eventService: mockService });
@@ -527,7 +527,7 @@ describe('Service Hooks', () => {
527
527
  };
528
528
 
529
529
  const wrapper = ({ children }: { children: React.ReactNode }) => (
530
- <div>{children}</div>
530
+ <section>{children}</section>
531
531
  );
532
532
 
533
533
  // Test individual hooks
@@ -570,7 +570,7 @@ describe('Service Hooks', () => {
570
570
  };
571
571
 
572
572
  const wrapper = ({ children }: { children: React.ReactNode }) => (
573
- <div>{children}</div>
573
+ <section>{children}</section>
574
574
  );
575
575
 
576
576
  mockUseContext.mockReturnValue({ authService: mockService });
@@ -600,7 +600,7 @@ describe('Service Hooks', () => {
600
600
  };
601
601
 
602
602
  const wrapper = ({ children }: { children: React.ReactNode }) => (
603
- <div>{children}</div>
603
+ <section>{children}</section>
604
604
  );
605
605
 
606
606
  mockUseContext.mockReturnValue({ authService: mockService });