@semiont/react-ui 0.5.5 → 0.5.6

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 (87) hide show
  1. package/README.md +59 -55
  2. package/dist/{PdfAnnotationCanvas.client-CN3C3S55.js → PdfAnnotationCanvas.client-NIMALXNZ.js} +7 -27
  3. package/dist/PdfAnnotationCanvas.client-NIMALXNZ.js.map +1 -0
  4. package/dist/index.css +6 -0
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.d.ts +243 -99
  7. package/dist/index.js +539 -405
  8. package/dist/index.js.map +1 -1
  9. package/package.json +16 -12
  10. package/src/components/Button/__tests__/Button.test.tsx +0 -2
  11. package/src/components/CodeMirrorRenderer.tsx +2 -0
  12. package/src/components/ErrorBoundary.tsx +0 -9
  13. package/src/components/ProtectedErrorBoundary.tsx +6 -2
  14. package/src/components/__tests__/AnnotateReferencesProgressWidget.test.tsx +0 -1
  15. package/src/components/__tests__/ErrorBoundary.test.tsx +20 -13
  16. package/src/components/__tests__/LiveRegion.hooks.test.tsx +1 -1
  17. package/src/components/__tests__/ProtectedErrorBoundary.test.tsx +2 -1
  18. package/src/components/__tests__/ResizeHandle.test.tsx +0 -1
  19. package/src/components/__tests__/SessionExpiryBanner.test.tsx +0 -1
  20. package/src/components/__tests__/StatusDisplay.test.tsx +0 -1
  21. package/src/components/__tests__/Toast.test.tsx +2 -3
  22. package/src/components/__tests__/Toolbar.test.tsx +0 -1
  23. package/src/components/annotation/annotations.css +14 -0
  24. package/src/components/annotation-popups/__tests__/JsonLdView.test.tsx +3 -5
  25. package/src/components/annotation-popups/__tests__/SharedPopupElements.test.tsx +0 -1
  26. package/src/components/branding/__tests__/SemiontBranding.test.tsx +1 -2
  27. package/src/components/layout/__tests__/LeftSidebar.test.tsx +5 -6
  28. package/src/components/layout/__tests__/PageLayout.test.tsx +1 -3
  29. package/src/components/layout/__tests__/SkipLinks.a11y.test.tsx +8 -8
  30. package/src/components/layout/__tests__/UnifiedHeader.test.tsx +12 -1
  31. package/src/components/modals/__tests__/KeyboardShortcutsHelpModal.test.tsx +0 -1
  32. package/src/components/modals/__tests__/PermissionDeniedModal.test.tsx +3 -4
  33. package/src/components/modals/__tests__/ResourceSearchModal.test.tsx +0 -1
  34. package/src/components/modals/__tests__/SearchModal.basic.test.tsx +1 -1
  35. package/src/components/modals/__tests__/SearchModal.keyboard.test.tsx +0 -5
  36. package/src/components/modals/__tests__/SearchModal.search-wiring.test.tsx +0 -1
  37. package/src/components/modals/__tests__/SearchModal.visual.test.tsx +2 -2
  38. package/src/components/modals/__tests__/SessionExpiredModal.test.tsx +0 -1
  39. package/src/components/navigation/NavigationMenu.tsx +1 -1
  40. package/src/components/navigation/__tests__/Footer.a11y.test.tsx +4 -0
  41. package/src/components/navigation/__tests__/Footer.test.tsx +3 -6
  42. package/src/components/navigation/__tests__/NavigationMenu.a11y.test.tsx +1 -1
  43. package/src/components/navigation/__tests__/NavigationMenu.test.tsx +7 -9
  44. package/src/components/navigation/__tests__/ObservableLink.test.tsx +0 -1
  45. package/src/components/navigation/__tests__/SimpleNavigation.test.tsx +1 -2
  46. package/src/components/navigation/__tests__/SortableResourceTab.test.tsx +0 -1
  47. package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +6 -4
  48. package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +10 -19
  49. package/src/components/resource/__tests__/BrowseView.test.tsx +8 -6
  50. package/src/components/resource/__tests__/HistoryEvent.test.tsx +0 -4
  51. package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +4 -6
  52. package/src/components/resource/panels/ReferencesPanel.tsx +1 -1
  53. package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +3 -4
  54. package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +7 -6
  55. package/src/components/resource/panels/__tests__/AssistSection.test.tsx +14 -10
  56. package/src/components/resource/panels/__tests__/CollaborationPanel.test.tsx +0 -1
  57. package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +30 -17
  58. package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +6 -5
  59. package/src/components/resource/panels/__tests__/HighlightEntry.test.tsx +4 -5
  60. package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +19 -13
  61. package/src/components/resource/panels/__tests__/JsonLdPanel.test.tsx +1 -3
  62. package/src/components/resource/panels/__tests__/PanelHeader.test.tsx +0 -1
  63. package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +5 -5
  64. package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +40 -7
  65. package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +3 -3
  66. package/src/components/resource/panels/__tests__/StatisticsPanel.test.tsx +30 -32
  67. package/src/components/resource/panels/__tests__/TagEntry.test.tsx +5 -5
  68. package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +6 -5
  69. package/src/components/settings/__tests__/SettingsPanel.test.tsx +0 -1
  70. package/src/components/viewers/__tests__/ImageViewer.test.tsx +0 -1
  71. package/src/features/auth/__tests__/SignInForm.a11y.test.tsx +2 -0
  72. package/src/features/auth/__tests__/SignUpForm.a11y.test.tsx +11 -12
  73. package/src/features/auth/__tests__/SignUpForm.test.tsx +3 -3
  74. package/src/features/moderate-tag-schemas/components/TagSchemasPage.tsx +1 -0
  75. package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +2 -1
  76. package/src/features/resource-discovery/__tests__/ResourceCard.test.tsx +0 -1
  77. package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +33 -35
  78. package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +12 -11
  79. package/src/features/resource-discovery/state/__tests__/discover-state-unit.test.ts +204 -11
  80. package/src/features/resource-discovery/state/discover-state-unit.ts +70 -11
  81. package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +2 -2
  82. package/src/features/resource-viewer/components/ResourceViewerPage.tsx +3 -2
  83. package/src/features/resource-viewer/state/__tests__/resource-viewer-page-state-unit.test.ts +0 -1
  84. package/src/features/resource-viewer/state/resource-viewer-page-state-unit.ts +5 -2
  85. package/src/integrations/__tests__/css-modules-helper.test.tsx +2 -3
  86. package/src/integrations/__tests__/styled-components-theme.test.ts +1 -3
  87. package/dist/PdfAnnotationCanvas.client-CN3C3S55.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "name": "@semiont/react-ui",
3
- "version": "0.5.5",
3
+ "version": "0.5.6",
4
+ "engines": {
5
+ "node": ">=24.0.0"
6
+ },
4
7
  "description": "React components and hooks for Semiont",
5
8
  "type": "module",
6
9
  "main": "./dist/index.js",
@@ -74,25 +77,26 @@
74
77
  "test:split:coverage": "npm run test:coverage"
75
78
  },
76
79
  "peerDependencies": {
77
- "react": "^18.0.0 || ^19.0.0",
78
- "react-dom": "^18.0.0 || ^19.0.0"
80
+ "react": "^19.0.0",
81
+ "react-dom": "^19.0.0"
79
82
  },
80
83
  "devDependencies": {
81
84
  "@testing-library/jest-dom": "^6.1.5",
82
85
  "@testing-library/react": "^16.1.0",
83
- "@types/react": "^19",
86
+ "@types/react": "^19.2.16",
84
87
  "@types/react-dom": "^19",
85
- "@vitest/coverage-v8": "^4.1.0",
86
- "autoprefixer": "^10.4.23",
87
- "axe-core": "^4.11.0",
88
- "cssnano": "^7.1.2",
88
+ "@vitest/coverage-v8": "^4.1.8",
89
+ "autoprefixer": "^10.5.0",
90
+ "axe-core": "^4.11.4",
91
+ "cssnano": "^8.0.1",
89
92
  "jest-axe": "^10.0.0",
90
- "jsdom": "^28.0.0",
93
+ "jsdom": "^29.1.1",
91
94
  "postcss-import": "^16.1.1",
92
- "rollup": "^4.60.3",
95
+ "rollup": "^4.61.0",
93
96
  "rollup-plugin-dts": "^6.4.1",
94
97
  "tsup": "^8.0.1",
95
- "typescript": "^6.0.2"
98
+ "typescript": "^6.0.2",
99
+ "vitest": "^4.1.8"
96
100
  },
97
101
  "publishConfig": {
98
102
  "access": "public"
@@ -108,6 +112,6 @@
108
112
  "@semiont/api-client": "*",
109
113
  "@semiont/core": "*",
110
114
  "@semiont/sdk": "*",
111
- "react-error-boundary": "^4.1.2"
115
+ "react-error-boundary": "^6.1.2"
112
116
  }
113
117
  }
@@ -157,7 +157,6 @@ describe('Button Component', () => {
157
157
  const icon = <span data-testid="left-icon">←</span>;
158
158
  render(<Button leftIcon={icon}>Button</Button>);
159
159
 
160
- const button = screen.getByRole('button');
161
160
  const leftIcon = screen.getByTestId('left-icon');
162
161
  const iconWrapper = leftIcon.parentElement;
163
162
 
@@ -169,7 +168,6 @@ describe('Button Component', () => {
169
168
  const icon = <span data-testid="right-icon">→</span>;
170
169
  render(<Button rightIcon={icon}>Button</Button>);
171
170
 
172
- const button = screen.getByRole('button');
173
171
  const rightIcon = screen.getByTestId('right-icon');
174
172
  const iconWrapper = rightIcon.parentElement;
175
173
 
@@ -81,6 +81,8 @@ function buildAnnotationDecorations(
81
81
  attributes: {
82
82
  'data-annotation-id': meta.annotationId,
83
83
  'data-annotation-type': meta.annotationType,
84
+ ...(meta.strategy ? { 'data-anchor-strategy': meta.strategy } : {}),
85
+ ...(meta.confidence ? { 'data-anchor-confidence': meta.confidence } : {}),
84
86
  title: meta.tooltip,
85
87
  },
86
88
  });
@@ -11,7 +11,6 @@ interface Props {
11
11
  interface State {
12
12
  hasError: boolean;
13
13
  error: Error | null;
14
- errorInfo: ErrorInfo | null;
15
14
  }
16
15
 
17
16
  /**
@@ -24,7 +23,6 @@ export class ErrorBoundary extends Component<Props, State> {
24
23
  this.state = {
25
24
  hasError: false,
26
25
  error: null,
27
- errorInfo: null,
28
26
  };
29
27
  }
30
28
 
@@ -33,7 +31,6 @@ export class ErrorBoundary extends Component<Props, State> {
33
31
  return {
34
32
  hasError: true,
35
33
  error,
36
- errorInfo: null,
37
34
  };
38
35
  }
39
36
 
@@ -48,11 +45,6 @@ export class ErrorBoundary extends Component<Props, State> {
48
45
  this.props.onError(error, errorInfo);
49
46
  }
50
47
 
51
- // Update state with error info
52
- this.setState({
53
- errorInfo,
54
- });
55
-
56
48
  // In production, you might want to log to an error reporting service
57
49
  // Example: logErrorToService(error, errorInfo);
58
50
  }
@@ -61,7 +53,6 @@ export class ErrorBoundary extends Component<Props, State> {
61
53
  this.setState({
62
54
  hasError: false,
63
55
  error: null,
64
- errorInfo: null,
65
56
  });
66
57
  };
67
58
 
@@ -45,6 +45,10 @@ export function ProtectedErrorBoundary({
45
45
  }
46
46
 
47
47
  function ProtectedErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
48
+ // react-error-boundary v6 types `error` as `unknown` — a thrown value can be
49
+ // anything, so narrow before reading Error fields.
50
+ const message = error instanceof Error ? error.message : String(error);
51
+ const stack = error instanceof Error ? error.stack : undefined;
48
52
  return (
49
53
  <div className="min-h-[400px] flex items-center justify-center p-4">
50
54
  <div className="max-w-md w-full bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6">
@@ -69,8 +73,8 @@ function ProtectedErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
69
73
  Error details (development only)
70
74
  </summary>
71
75
  <pre className="mt-2 text-xs bg-gray-100 dark:bg-gray-900 p-2 rounded-sm overflow-auto">
72
- {error.message}
73
- {error.stack}
76
+ {message}
77
+ {stack}
74
78
  </pre>
75
79
  </details>
76
80
  )}
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, vi } from 'vitest';
2
- import React from 'react';
3
2
  import { screen, fireEvent } from '@testing-library/react';
4
3
  import '@testing-library/jest-dom';
5
4
  import { renderWithProviders } from '../../test-utils';
@@ -1,5 +1,5 @@
1
1
  import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import React from 'react';
2
+ import type { ReactNode } from 'react';
3
3
  import { render, screen, fireEvent } from '@testing-library/react';
4
4
  import '@testing-library/jest-dom';
5
5
  import { ErrorBoundary, AsyncErrorBoundary } from '../ErrorBoundary';
@@ -146,7 +146,7 @@ describe('ErrorBoundary Component', () => {
146
146
  });
147
147
 
148
148
  it('should not render default fallback when custom fallback is provided', () => {
149
- const customFallback = (error: Error) => <div>Custom Fallback</div>;
149
+ const customFallback = () => <div>Custom Fallback</div>;
150
150
 
151
151
  render(
152
152
  <ErrorBoundary fallback={customFallback}>
@@ -223,7 +223,7 @@ describe('ErrorBoundary Component', () => {
223
223
 
224
224
  it('should call custom reset handler in custom fallback', () => {
225
225
  const resetHandler = vi.fn();
226
- const customFallback = (error: Error, reset: () => void) => (
226
+ const customFallback = (_error: Error, reset: () => void) => (
227
227
  <div>
228
228
  <button onClick={() => { resetHandler(); reset(); }}>Reset</button>
229
229
  </div>
@@ -242,9 +242,9 @@ describe('ErrorBoundary Component', () => {
242
242
  });
243
243
 
244
244
  it('should clear error state when reset is called', () => {
245
- let resetFn: (() => void) | null = null;
245
+ const resetRef: { current: (() => void) | null } = { current: null };
246
246
  const customFallback = (error: Error, reset: () => void) => {
247
- resetFn = reset;
247
+ resetRef.current = reset;
248
248
  return <div>Error: {error.message}</div>;
249
249
  };
250
250
 
@@ -255,11 +255,11 @@ describe('ErrorBoundary Component', () => {
255
255
  );
256
256
 
257
257
  expect(screen.getByText('Error: Initial error')).toBeInTheDocument();
258
- expect(resetFn).not.toBeNull();
258
+ expect(resetRef.current).not.toBeNull();
259
259
 
260
260
  // Call reset
261
- if (resetFn) {
262
- resetFn();
261
+ if (resetRef.current) {
262
+ resetRef.current();
263
263
  }
264
264
 
265
265
  // Rerender with non-throwing component after reset
@@ -286,8 +286,11 @@ describe('ErrorBoundary Component', () => {
286
286
 
287
287
  it('should navigate to home when Go Home button clicked', () => {
288
288
  const originalLocation = window.location;
289
- delete (window as any).location;
290
- window.location = { href: '' } as any;
289
+ Object.defineProperty(window, 'location', {
290
+ value: { href: '' },
291
+ writable: true,
292
+ configurable: true,
293
+ });
291
294
 
292
295
  render(
293
296
  <ErrorBoundary>
@@ -300,7 +303,11 @@ describe('ErrorBoundary Component', () => {
300
303
 
301
304
  expect(window.location.href).toBe('/');
302
305
 
303
- window.location = originalLocation;
306
+ Object.defineProperty(window, 'location', {
307
+ value: originalLocation,
308
+ writable: true,
309
+ configurable: true,
310
+ });
304
311
  });
305
312
  });
306
313
 
@@ -336,7 +343,7 @@ describe('ErrorBoundary Component', () => {
336
343
 
337
344
  describe('Edge Cases', () => {
338
345
  it('should handle error with no message', () => {
339
- function ThrowEmptyError() {
346
+ function ThrowEmptyError(): ReactNode {
340
347
  throw new Error();
341
348
  }
342
349
 
@@ -433,7 +440,7 @@ describe('AsyncErrorBoundary Component', () => {
433
440
  });
434
441
 
435
442
  it('should handle error with no message', () => {
436
- function ThrowEmptyError() {
443
+ function ThrowEmptyError(): ReactNode {
437
444
  throw new Error();
438
445
  }
439
446
 
@@ -1,7 +1,7 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import React from 'react';
3
3
  import { renderHook, act } from '@testing-library/react';
4
- import { render, screen } from '@testing-library/react';
4
+ import { render } from '@testing-library/react';
5
5
  import '@testing-library/jest-dom';
6
6
  import {
7
7
  LiveRegionProvider,
@@ -186,7 +186,8 @@ describe('ProtectedErrorBoundary', () => {
186
186
  // Multiple console.error calls happen (React's own logs, plus ours).
187
187
  // Look for the boundary's prefix specifically.
188
188
  const ourCall = consoleErrorSpy.mock.calls.find(
189
- call => typeof call[0] === 'string' && call[0].includes('ProtectedErrorBoundary caught:')
189
+ (call: Parameters<typeof console.error>) =>
190
+ typeof call[0] === 'string' && call[0].includes('ProtectedErrorBoundary caught:')
190
191
  );
191
192
  expect(ourCall).toBeDefined();
192
193
  } finally {
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, vi } from 'vitest';
2
- import React from 'react';
3
2
  import { render, screen, fireEvent } from '@testing-library/react';
4
3
  import '@testing-library/jest-dom';
5
4
  import { ResizeHandle } from '../ResizeHandle';
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import React from 'react';
3
2
  import { screen, fireEvent } from '@testing-library/react';
4
3
  import '@testing-library/jest-dom';
5
4
  import { renderWithProviders } from '../../test-utils';
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import React from 'react';
3
2
  import { screen, waitFor } from '@testing-library/react';
4
3
  import { BehaviorSubject } from 'rxjs';
5
4
  import '@testing-library/jest-dom';
@@ -1,7 +1,6 @@
1
1
  import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { render, screen, waitFor, act } from '@testing-library/react';
3
- import userEvent from '@testing-library/user-event';
4
- import { ToastProvider, useToast, ToastContainer, type ToastMessage } from '../Toast';
2
+ import { render, screen } from '@testing-library/react';
3
+ import { ToastProvider, useToast } from '../Toast';
5
4
 
6
5
  describe('Toast System', () => {
7
6
  beforeEach(() => {
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, vi } from 'vitest';
2
- import React from 'react';
3
2
  import { screen, fireEvent } from '@testing-library/react';
4
3
  import '@testing-library/jest-dom';
5
4
  import { renderWithProviders } from '../../test-utils';
@@ -36,6 +36,20 @@
36
36
  position: relative;
37
37
  }
38
38
 
39
+ /* Low-confidence anchor affordance.
40
+ *
41
+ * Annotations whose anchor was resolved by something other than a clean
42
+ * fast-path or unique-occurrence match (i.e. `confidence !== 'high'`)
43
+ * get a dotted underline so operators can see at a glance which
44
+ * highlights were rescued by score-resolved tiebreaking, fuzzy matching,
45
+ * or a position-fallback. The hover tooltip (added by
46
+ * `getAnnotationDecorationMeta`) names the strategy. */
47
+ .annotation-low-confidence {
48
+ text-decoration: underline dotted var(--semiont-color-warning-500, #d97706);
49
+ text-decoration-thickness: 2px;
50
+ text-underline-offset: 2px;
51
+ }
52
+
39
53
  /* Print styles */
40
54
  @media print {
41
55
  .annotation-highlight,
@@ -1,11 +1,9 @@
1
1
  import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import React from 'react';
3
2
  import { screen, fireEvent, waitFor } from '@testing-library/react';
4
3
  import userEvent from '@testing-library/user-event';
5
4
  import '@testing-library/jest-dom';
6
- import type { components } from '@semiont/core';
7
5
 
8
- import type { Annotation } from '@semiont/core';
6
+ import type { Annotation, AnnotationId } from '@semiont/core';
9
7
 
10
8
  // Mock CodeMirror modules
11
9
  vi.mock('@codemirror/view', () => {
@@ -57,10 +55,10 @@ import { JsonLdView } from '../JsonLdView';
57
55
 
58
56
  const createMockAnnotation = (overrides?: Partial<Annotation>): Annotation => ({
59
57
  '@context': 'http://www.w3.org/ns/anno.jsonld',
60
- id: 'anno-1',
58
+ id: 'anno-1' as AnnotationId,
61
59
  type: 'Annotation',
62
60
  motivation: 'highlighting',
63
- creator: { name: 'user@example.com' },
61
+ creator: { '@type': 'Person', name: 'user@example.com' },
64
62
  created: '2024-01-01T10:00:00Z',
65
63
  target: {
66
64
  source: 'resource-1',
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, vi } from 'vitest';
2
- import React from 'react';
3
2
  import { screen, fireEvent } from '@testing-library/react';
4
3
  import '@testing-library/jest-dom';
5
4
  import { renderWithProviders } from '../../../test-utils';
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import React from 'react';
3
2
  import { render, screen } from '@testing-library/react';
4
3
  import '@testing-library/jest-dom';
5
4
  import { SemiontBranding } from '../SemiontBranding';
@@ -305,7 +304,7 @@ describe('SemiontBranding Component', () => {
305
304
 
306
305
  describe('Edge Cases', () => {
307
306
  it('should handle missing translation gracefully', () => {
308
- const emptyTranslate = vi.fn((key: string) => '');
307
+ const emptyTranslate = vi.fn(() => '');
309
308
 
310
309
  render(<SemiontBranding t={emptyTranslate} />);
311
310
 
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import React from 'react';
3
2
  import { render, screen, fireEvent } from '@testing-library/react';
4
3
  import '@testing-library/jest-dom';
5
4
  import { LeftSidebar } from '../LeftSidebar';
@@ -159,7 +158,7 @@ describe('LeftSidebar Component', () => {
159
158
  });
160
159
 
161
160
  it('should save collapsed state to localStorage', () => {
162
- const mockChildren = vi.fn((isCollapsed, toggleCollapsed) => (
161
+ const mockChildren = vi.fn((_isCollapsed, toggleCollapsed) => (
163
162
  <button onClick={toggleCollapsed} data-testid="toggle-btn">Toggle</button>
164
163
  ));
165
164
 
@@ -183,7 +182,7 @@ describe('LeftSidebar Component', () => {
183
182
  });
184
183
 
185
184
  it('should not collapse when collapsible is false', () => {
186
- const mockChildren = vi.fn((isCollapsed, toggleCollapsed) => (
185
+ const mockChildren = vi.fn((_isCollapsed, toggleCollapsed) => (
187
186
  <button onClick={toggleCollapsed} data-testid="toggle-btn">Toggle</button>
188
187
  ));
189
188
 
@@ -208,7 +207,7 @@ describe('LeftSidebar Component', () => {
208
207
  });
209
208
 
210
209
  it('should use default storage key', () => {
211
- const mockChildren = vi.fn((isCollapsed, toggleCollapsed) => (
210
+ const mockChildren = vi.fn((_isCollapsed, toggleCollapsed) => (
212
211
  <button onClick={toggleCollapsed} data-testid="toggle-btn">Toggle</button>
213
212
  ));
214
213
 
@@ -233,7 +232,7 @@ describe('LeftSidebar Component', () => {
233
232
 
234
233
  describe('Navigation Menu Helper', () => {
235
234
  it('should provide navigationMenu helper to function children', () => {
236
- const mockChildren = vi.fn((isCollapsed, toggleCollapsed, navigationMenu) => {
235
+ const mockChildren = vi.fn((_isCollapsed, _toggleCollapsed, navigationMenu) => {
237
236
  // Test that navigationMenu helper returns NavigationMenu component
238
237
  const menuElement = navigationMenu(() => {});
239
238
  return <div data-testid="children-content">{menuElement}</div>;
@@ -259,7 +258,7 @@ describe('LeftSidebar Component', () => {
259
258
 
260
259
  it('should pass onClose callback to NavigationMenu', () => {
261
260
  const mockOnClose = vi.fn();
262
- const mockChildren = vi.fn((isCollapsed, toggleCollapsed, navigationMenu) => {
261
+ const mockChildren = vi.fn((_isCollapsed, _toggleCollapsed, navigationMenu) => {
263
262
  const menuElement = navigationMenu(mockOnClose);
264
263
  return <div>{menuElement}</div>;
265
264
  });
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, vi } from 'vitest';
2
- import React from 'react';
3
2
  import { render, screen } from '@testing-library/react';
4
3
  import '@testing-library/jest-dom';
5
4
  import { PageLayout } from '../PageLayout';
@@ -247,7 +246,6 @@ describe('PageLayout Component', () => {
247
246
  );
248
247
 
249
248
  // Real Footer renders copyright with dynamic year
250
- const currentYear = new Date().getFullYear();
251
249
  expect(screen.getByText(`translated.copyright`)).toBeInTheDocument();
252
250
  });
253
251
  });
@@ -270,7 +268,7 @@ describe('PageLayout Component', () => {
270
268
  });
271
269
 
272
270
  it('should render with CookiePreferences component', () => {
273
- const MockCookiePreferences = ({ isOpen, onClose }: any) => (
271
+ const MockCookiePreferences = ({ }: any) => (
274
272
  <div data-testid="cookie-prefs">Cookie Preferences</div>
275
273
  );
276
274
 
@@ -63,7 +63,7 @@ describe('SkipLinks - Accessibility', () => {
63
63
 
64
64
  it('should become visible on focus', async () => {
65
65
  const user = userEvent.setup();
66
- const { container } = render(<SkipLinks />);
66
+ render(<SkipLinks />);
67
67
 
68
68
  const firstLink = screen.getAllByRole('link')[0];
69
69
 
@@ -76,12 +76,12 @@ describe('SkipLinks - Accessibility', () => {
76
76
 
77
77
  it('should hide when focus leaves', async () => {
78
78
  const user = userEvent.setup();
79
- const { container } = render(
80
- <div>
81
- <SkipLinks />
82
- <button>Next focusable element</button>
83
- </div>
84
- );
79
+ render(
80
+ <div>
81
+ <SkipLinks />
82
+ <button>Next focusable element</button>
83
+ </div>
84
+ );
85
85
 
86
86
  // Tab to first skip link
87
87
  await user.tab();
@@ -239,7 +239,7 @@ describe('SkipLinks - Accessibility', () => {
239
239
 
240
240
  it('should maintain focus management with multiple links', async () => {
241
241
  const user = userEvent.setup();
242
- const { container } = render(<SkipLinks />);
242
+ render(<SkipLinks />);
243
243
 
244
244
  // Tab to first link
245
245
  await user.tab();
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import React from 'react';
3
2
  import { render, screen, fireEvent } from '@testing-library/react';
4
3
  import '@testing-library/jest-dom';
5
4
  import { UnifiedHeader } from '../UnifiedHeader';
@@ -9,6 +8,7 @@ vi.mock('@/hooks/useUI', () => ({
9
8
  useDropdown: vi.fn(() => ({
10
9
  isOpen: false,
11
10
  toggle: vi.fn(),
11
+ open: vi.fn(),
12
12
  close: vi.fn(),
13
13
  dropdownRef: { current: null },
14
14
  })),
@@ -37,6 +37,7 @@ describe('UnifiedHeader Component', () => {
37
37
  vi.mocked(useDropdown).mockReturnValue({
38
38
  isOpen: false,
39
39
  toggle: vi.fn(),
40
+ open: vi.fn(),
40
41
  close: vi.fn(),
41
42
  dropdownRef: { current: null },
42
43
  });
@@ -216,6 +217,7 @@ describe('UnifiedHeader Component', () => {
216
217
  vi.mocked(useDropdown).mockReturnValue({
217
218
  isOpen: false,
218
219
  toggle: mockToggle,
220
+ open: vi.fn(),
219
221
  close: vi.fn(),
220
222
  dropdownRef: { current: null },
221
223
  });
@@ -239,6 +241,7 @@ describe('UnifiedHeader Component', () => {
239
241
  vi.mocked(useDropdown).mockReturnValue({
240
242
  isOpen: true,
241
243
  toggle: vi.fn(),
244
+ open: vi.fn(),
242
245
  close: vi.fn(),
243
246
  dropdownRef: { current: null },
244
247
  });
@@ -261,6 +264,7 @@ describe('UnifiedHeader Component', () => {
261
264
  vi.mocked(useDropdown).mockReturnValue({
262
265
  isOpen: true,
263
266
  toggle: vi.fn(),
267
+ open: vi.fn(),
264
268
  close: vi.fn(),
265
269
  dropdownRef: { current: null },
266
270
  });
@@ -282,6 +286,7 @@ describe('UnifiedHeader Component', () => {
282
286
  vi.mocked(useDropdown).mockReturnValue({
283
287
  isOpen: false,
284
288
  toggle: vi.fn(),
289
+ open: vi.fn(),
285
290
  close: vi.fn(),
286
291
  dropdownRef: { current: null },
287
292
  });
@@ -304,6 +309,7 @@ describe('UnifiedHeader Component', () => {
304
309
  vi.mocked(useDropdown).mockReturnValue({
305
310
  isOpen: true,
306
311
  toggle: vi.fn(),
312
+ open: vi.fn(),
307
313
  close: mockClose,
308
314
  dropdownRef: { current: null },
309
315
  });
@@ -331,6 +337,7 @@ describe('UnifiedHeader Component', () => {
331
337
  vi.mocked(useDropdown).mockReturnValue({
332
338
  isOpen: false,
333
339
  toggle: vi.fn(),
340
+ open: vi.fn(),
334
341
  close: vi.fn(),
335
342
  dropdownRef: { current: null },
336
343
  });
@@ -366,6 +373,7 @@ describe('UnifiedHeader Component', () => {
366
373
  vi.mocked(useDropdown).mockReturnValue({
367
374
  isOpen: true,
368
375
  toggle: vi.fn(),
376
+ open: vi.fn(),
369
377
  close: vi.fn(),
370
378
  dropdownRef: { current: null },
371
379
  });
@@ -389,6 +397,7 @@ describe('UnifiedHeader Component', () => {
389
397
  vi.mocked(useDropdown).mockReturnValue({
390
398
  isOpen: true,
391
399
  toggle: vi.fn(),
400
+ open: vi.fn(),
392
401
  close: vi.fn(),
393
402
  dropdownRef: { current: null },
394
403
  });
@@ -450,6 +459,7 @@ describe('UnifiedHeader Component', () => {
450
459
  vi.mocked(useDropdown).mockReturnValue({
451
460
  isOpen: true,
452
461
  toggle: vi.fn(),
462
+ open: vi.fn(),
453
463
  close: vi.fn(),
454
464
  dropdownRef: { current: null },
455
465
  });
@@ -471,6 +481,7 @@ describe('UnifiedHeader Component', () => {
471
481
  vi.mocked(useDropdown).mockReturnValue({
472
482
  isOpen: true,
473
483
  toggle: vi.fn(),
484
+ open: vi.fn(),
474
485
  close: vi.fn(),
475
486
  dropdownRef: { current: null },
476
487
  });
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, vi } from 'vitest';
2
- import React from 'react';
3
2
  import { screen, fireEvent } from '@testing-library/react';
4
3
  import { renderWithProviders } from '../../../test-utils';
5
4
  import '@testing-library/jest-dom';
@@ -6,8 +6,7 @@
6
6
  * `acknowledgePermissionDenied()` and navigate the window or history.
7
7
  */
8
8
 
9
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
10
- import React from 'react';
9
+ import { describe, it, expect, beforeEach, afterEach, vi, type Mock } from 'vitest';
11
10
  import { screen, fireEvent } from '@testing-library/react';
12
11
  import '@testing-library/jest-dom';
13
12
  import {
@@ -27,7 +26,7 @@ vi.mock('@headlessui/react', () => ({
27
26
  const originalLocation = window.location;
28
27
  const originalHistoryBack = window.history.back;
29
28
  let mockLocation: { href: string; pathname: string };
30
- let mockHistoryBack: ReturnType<typeof vi.fn>;
29
+ let mockHistoryBack: Mock<() => void>;
31
30
 
32
31
  beforeEach(() => {
33
32
  mockLocation = { href: '', pathname: '/admin/users' };
@@ -36,7 +35,7 @@ beforeEach(() => {
36
35
  writable: true,
37
36
  configurable: true,
38
37
  });
39
- mockHistoryBack = vi.fn();
38
+ mockHistoryBack = vi.fn<() => void>();
40
39
  window.history.back = mockHistoryBack;
41
40
  });
42
41
 
@@ -1,5 +1,4 @@
1
1
  import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import React from 'react';
3
2
  import { screen, fireEvent, waitFor } from '@testing-library/react';
4
3
  import { BehaviorSubject } from 'rxjs';
5
4
  import { renderWithProviders } from '../../../test-utils';
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import { describe, it, expect, vi, beforeEach } from 'vitest';
6
- import { render, screen, fireEvent, waitFor } from '@testing-library/react';
6
+ import { render, screen, fireEvent } from '@testing-library/react';
7
7
  import userEvent from '@testing-library/user-event';
8
8
  import { SearchModal } from '../SearchModal';
9
9
 
@@ -52,11 +52,6 @@ describe.skip('SearchModal Component - Keyboard Navigation', () => {
52
52
  });
53
53
 
54
54
  it('should handle Arrow Down key to navigate results', async () => {
55
- const mockResults = [
56
- { type: 'resource' as const, id: '1', name: 'Resource 1', content: 'Content 1' },
57
- { type: 'resource' as const, id: '2', name: 'Resource 2', content: 'Content 2' },
58
- { type: 'entity' as const, id: '3', name: 'Entity 1', entityType: 'Person' }
59
- ];
60
55
 
61
56
  // TODO: Mock search results when API is integrated
62
57
  render(<SearchModal {...defaultProps} />);