@semiont/react-ui 0.5.5 → 0.5.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 (218) 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/{ar-U2EXWUMQ.js → ar-SONK6MON.js} +3 -7
  5. package/dist/ar-SONK6MON.js.map +1 -0
  6. package/dist/{bn-DRJGV772.js → bn-ZKPRITNG.js} +3 -7
  7. package/dist/bn-ZKPRITNG.js.map +1 -0
  8. package/dist/{chunk-3Q3TUKWP.js → chunk-Y2EEAOMZ.js} +29 -29
  9. package/dist/{cs-PTWDM23V.js → cs-LPXQ7NHQ.js} +3 -7
  10. package/dist/cs-LPXQ7NHQ.js.map +1 -0
  11. package/dist/{da-KSNIKYSS.js → da-6TKY7MCY.js} +6 -10
  12. package/dist/da-6TKY7MCY.js.map +1 -0
  13. package/dist/{de-F2XBEWFY.js → de-C3GNII74.js} +3 -7
  14. package/dist/de-C3GNII74.js.map +1 -0
  15. package/dist/{el-DLD2GWAP.js → el-UBCXQDJ7.js} +3 -7
  16. package/dist/el-UBCXQDJ7.js.map +1 -0
  17. package/dist/{es-WLPYWGB5.js → es-BQ23TRI7.js} +11 -15
  18. package/dist/es-BQ23TRI7.js.map +1 -0
  19. package/dist/{fa-BAXHSDZG.js → fa-AFTBZB77.js} +3 -7
  20. package/dist/fa-AFTBZB77.js.map +1 -0
  21. package/dist/{fi-FCHSYVOT.js → fi-WOYNLZC2.js} +3 -7
  22. package/dist/fi-WOYNLZC2.js.map +1 -0
  23. package/dist/{fr-3UERBSL6.js → fr-NDSMIFJM.js} +3 -7
  24. package/dist/fr-NDSMIFJM.js.map +1 -0
  25. package/dist/{he-F6F3FV2K.js → he-VJXVRDOY.js} +3 -7
  26. package/dist/he-VJXVRDOY.js.map +1 -0
  27. package/dist/{hi-4BK6IK7Q.js → hi-BF6PHIE2.js} +3 -7
  28. package/dist/hi-BF6PHIE2.js.map +1 -0
  29. package/dist/{id-7ECCWP3J.js → id-GXG5QCZY.js} +3 -7
  30. package/dist/id-GXG5QCZY.js.map +1 -0
  31. package/dist/index.css +103 -0
  32. package/dist/index.css.map +1 -1
  33. package/dist/index.d.ts +271 -120
  34. package/dist/index.js +877 -698
  35. package/dist/index.js.map +1 -1
  36. package/dist/{it-234Z6XK6.js → it-XKHHCBAF.js} +3 -7
  37. package/dist/it-XKHHCBAF.js.map +1 -0
  38. package/dist/{ja-PJWQI4OQ.js → ja-TX7VM4XD.js} +3 -7
  39. package/dist/ja-TX7VM4XD.js.map +1 -0
  40. package/dist/{ko-APUEW2RS.js → ko-DNC7EQ7J.js} +3 -7
  41. package/dist/ko-DNC7EQ7J.js.map +1 -0
  42. package/dist/{ms-PJBZWZWD.js → ms-POZGBKPH.js} +3 -7
  43. package/dist/ms-POZGBKPH.js.map +1 -0
  44. package/dist/{nl-L4C3ZBCU.js → nl-IRMTKI7Z.js} +4 -11
  45. package/dist/nl-IRMTKI7Z.js.map +1 -0
  46. package/dist/{no-QE5N5KNG.js → no-ZUDJA4S6.js} +20 -24
  47. package/dist/no-ZUDJA4S6.js.map +1 -0
  48. package/dist/{pl-5Q2D23PD.js → pl-2NGAXL5U.js} +3 -7
  49. package/dist/pl-2NGAXL5U.js.map +1 -0
  50. package/dist/{pt-AIGUOIOC.js → pt-ABMCXZUM.js} +118 -122
  51. package/dist/pt-ABMCXZUM.js.map +1 -0
  52. package/dist/{ro-T56CSHTY.js → ro-VOJP6O5X.js} +3 -7
  53. package/dist/ro-VOJP6O5X.js.map +1 -0
  54. package/dist/{sv-L4TJQ2UH.js → sv-4HVFIIE5.js} +43 -47
  55. package/dist/sv-4HVFIIE5.js.map +1 -0
  56. package/dist/test-utils.js +2 -2
  57. package/dist/test-utils.js.map +1 -1
  58. package/dist/{th-6O7Y6O2Q.js → th-IFPZP3HQ.js} +3 -7
  59. package/dist/th-IFPZP3HQ.js.map +1 -0
  60. package/dist/{tr-D4CQCSNO.js → tr-2GYEAMJ4.js} +3 -7
  61. package/dist/tr-2GYEAMJ4.js.map +1 -0
  62. package/dist/{uk-2HMQG6ND.js → uk-XCJBVLLD.js} +3 -7
  63. package/dist/uk-XCJBVLLD.js.map +1 -0
  64. package/dist/{vi-XVJ4RUEJ.js → vi-4FR7CB2F.js} +3 -7
  65. package/dist/vi-4FR7CB2F.js.map +1 -0
  66. package/dist/{zh-K2KDPGHK.js → zh-NSKFOINB.js} +3 -7
  67. package/dist/zh-NSKFOINB.js.map +1 -0
  68. package/package.json +17 -13
  69. package/src/components/Button/__tests__/Button.test.tsx +0 -2
  70. package/src/components/CodeMirrorRenderer.tsx +2 -0
  71. package/src/components/ErrorBoundary.tsx +0 -9
  72. package/src/components/ProtectedErrorBoundary.css +119 -0
  73. package/src/components/ProtectedErrorBoundary.tsx +24 -15
  74. package/src/components/__tests__/AnnotateReferencesProgressWidget.test.tsx +0 -1
  75. package/src/components/__tests__/ErrorBoundary.test.tsx +20 -13
  76. package/src/components/__tests__/LiveRegion.hooks.test.tsx +1 -1
  77. package/src/components/__tests__/ProtectedErrorBoundary.test.tsx +2 -1
  78. package/src/components/__tests__/ResizeHandle.test.tsx +0 -1
  79. package/src/components/__tests__/SessionExpiryBanner.test.tsx +0 -1
  80. package/src/components/__tests__/StatusDisplay.test.tsx +0 -1
  81. package/src/components/__tests__/Toast.test.tsx +2 -3
  82. package/src/components/__tests__/Toolbar.test.tsx +0 -1
  83. package/src/components/annotation/annotations.css +14 -0
  84. package/src/components/annotation-popups/__tests__/JsonLdView.test.tsx +3 -5
  85. package/src/components/annotation-popups/__tests__/SharedPopupElements.test.tsx +0 -1
  86. package/src/components/branding/__tests__/SemiontBranding.test.tsx +1 -2
  87. package/src/components/layout/__tests__/LeftSidebar.test.tsx +5 -6
  88. package/src/components/layout/__tests__/PageLayout.test.tsx +1 -3
  89. package/src/components/layout/__tests__/SkipLinks.a11y.test.tsx +8 -8
  90. package/src/components/layout/__tests__/UnifiedHeader.test.tsx +12 -1
  91. package/src/components/modals/__tests__/KeyboardShortcutsHelpModal.test.tsx +0 -1
  92. package/src/components/modals/__tests__/PermissionDeniedModal.test.tsx +3 -4
  93. package/src/components/modals/__tests__/ResourceSearchModal.test.tsx +1 -2
  94. package/src/components/modals/__tests__/SearchModal.basic.test.tsx +1 -1
  95. package/src/components/modals/__tests__/SearchModal.keyboard.test.tsx +0 -5
  96. package/src/components/modals/__tests__/SearchModal.search-wiring.test.tsx +1 -2
  97. package/src/components/modals/__tests__/SearchModal.visual.test.tsx +2 -2
  98. package/src/components/modals/__tests__/SessionExpiredModal.test.tsx +0 -1
  99. package/src/components/navigation/NavigationMenu.tsx +1 -1
  100. package/src/components/navigation/__tests__/Footer.a11y.test.tsx +4 -0
  101. package/src/components/navigation/__tests__/Footer.test.tsx +3 -6
  102. package/src/components/navigation/__tests__/NavigationMenu.a11y.test.tsx +1 -1
  103. package/src/components/navigation/__tests__/NavigationMenu.test.tsx +7 -9
  104. package/src/components/navigation/__tests__/ObservableLink.test.tsx +0 -1
  105. package/src/components/navigation/__tests__/SimpleNavigation.test.tsx +1 -2
  106. package/src/components/navigation/__tests__/SortableResourceTab.test.tsx +0 -1
  107. package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +6 -4
  108. package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +10 -19
  109. package/src/components/resource/AnnotateView.tsx +35 -37
  110. package/src/components/resource/BrowseView.tsx +31 -31
  111. package/src/components/resource/__tests__/AnnotationHistory.test.tsx +0 -1
  112. package/src/components/resource/__tests__/BrowseView.test.tsx +12 -14
  113. package/src/components/resource/__tests__/HistoryEvent.test.tsx +0 -5
  114. package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +4 -6
  115. package/src/components/resource/__tests__/event-formatting.test.ts +1 -1
  116. package/src/components/resource/panels/CollaborationPanel.tsx +1 -1
  117. package/src/components/resource/panels/JsonLdPanel.tsx +33 -16
  118. package/src/components/resource/panels/ReferencesPanel.tsx +1 -1
  119. package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +4 -5
  120. package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +8 -7
  121. package/src/components/resource/panels/__tests__/AssistSection.test.tsx +14 -10
  122. package/src/components/resource/panels/__tests__/CollaborationPanel.test.tsx +0 -1
  123. package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +31 -18
  124. package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +7 -6
  125. package/src/components/resource/panels/__tests__/HighlightEntry.test.tsx +5 -6
  126. package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +19 -13
  127. package/src/components/resource/panels/__tests__/JsonLdPanel.test.tsx +95 -426
  128. package/src/components/resource/panels/__tests__/PanelHeader.test.tsx +0 -1
  129. package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +5 -5
  130. package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +40 -7
  131. package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +4 -4
  132. package/src/components/resource/panels/__tests__/StatisticsPanel.test.tsx +30 -32
  133. package/src/components/resource/panels/__tests__/TagEntry.test.tsx +6 -6
  134. package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +7 -6
  135. package/src/components/settings/__tests__/SettingsPanel.test.tsx +0 -1
  136. package/src/components/viewers/__tests__/ImageViewer.test.tsx +0 -1
  137. package/src/features/admin-exchange/__tests__/AdminExchangePage.test.tsx +7 -10
  138. package/src/features/admin-exchange/__tests__/ImportProgress.test.tsx +38 -27
  139. package/src/features/admin-exchange/components/ImportProgress.tsx +28 -34
  140. package/src/features/auth/__tests__/SignInForm.a11y.test.tsx +2 -0
  141. package/src/features/auth/__tests__/SignUpForm.a11y.test.tsx +11 -12
  142. package/src/features/auth/__tests__/SignUpForm.test.tsx +3 -3
  143. package/src/features/moderate-tag-schemas/components/TagSchemasPage.tsx +1 -0
  144. package/src/features/moderation-linked-data/__tests__/LinkedDataPage.test.tsx +11 -9
  145. package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +2 -1
  146. package/src/features/resource-compose/components/ResourceComposePage.tsx +36 -9
  147. package/src/features/resource-compose/state/compose-page-state-unit.ts +5 -8
  148. package/src/features/resource-discovery/__tests__/ResourceCard.test.tsx +0 -1
  149. package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +33 -35
  150. package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +12 -11
  151. package/src/features/resource-discovery/state/__tests__/discover-state-unit.test.ts +204 -11
  152. package/src/features/resource-discovery/state/discover-state-unit.ts +70 -11
  153. package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +2 -2
  154. package/src/features/resource-viewer/components/ResourceViewerPage.tsx +10 -7
  155. package/src/features/resource-viewer/state/__tests__/resource-viewer-page-state-unit.test.ts +37 -1
  156. package/src/features/resource-viewer/state/resource-viewer-page-state-unit.ts +14 -7
  157. package/src/integrations/__tests__/css-modules-helper.test.tsx +2 -3
  158. package/src/integrations/__tests__/styled-components-theme.test.ts +1 -3
  159. package/src/styles/features/exchange.css +0 -30
  160. package/src/styles/index.css +1 -0
  161. package/translations/ar.json +1 -3
  162. package/translations/bn.json +1 -3
  163. package/translations/cs.json +1 -3
  164. package/translations/da.json +4 -6
  165. package/translations/de.json +1 -3
  166. package/translations/el.json +1 -3
  167. package/translations/es.json +9 -11
  168. package/translations/fa.json +1 -3
  169. package/translations/fi.json +1 -3
  170. package/translations/fr.json +1 -3
  171. package/translations/he.json +1 -3
  172. package/translations/hi.json +1 -3
  173. package/translations/id.json +1 -3
  174. package/translations/it.json +1 -3
  175. package/translations/ja.json +1 -3
  176. package/translations/ko.json +1 -3
  177. package/translations/ms.json +1 -3
  178. package/translations/nl.json +2 -7
  179. package/translations/no.json +18 -20
  180. package/translations/pl.json +1 -3
  181. package/translations/pt.json +116 -118
  182. package/translations/ro.json +1 -3
  183. package/translations/sv.json +41 -43
  184. package/translations/th.json +1 -3
  185. package/translations/tr.json +1 -3
  186. package/translations/uk.json +1 -3
  187. package/translations/vi.json +1 -3
  188. package/translations/zh.json +1 -3
  189. package/dist/PdfAnnotationCanvas.client-CN3C3S55.js.map +0 -1
  190. package/dist/ar-U2EXWUMQ.js.map +0 -1
  191. package/dist/bn-DRJGV772.js.map +0 -1
  192. package/dist/cs-PTWDM23V.js.map +0 -1
  193. package/dist/da-KSNIKYSS.js.map +0 -1
  194. package/dist/de-F2XBEWFY.js.map +0 -1
  195. package/dist/el-DLD2GWAP.js.map +0 -1
  196. package/dist/es-WLPYWGB5.js.map +0 -1
  197. package/dist/fa-BAXHSDZG.js.map +0 -1
  198. package/dist/fi-FCHSYVOT.js.map +0 -1
  199. package/dist/fr-3UERBSL6.js.map +0 -1
  200. package/dist/he-F6F3FV2K.js.map +0 -1
  201. package/dist/hi-4BK6IK7Q.js.map +0 -1
  202. package/dist/id-7ECCWP3J.js.map +0 -1
  203. package/dist/it-234Z6XK6.js.map +0 -1
  204. package/dist/ja-PJWQI4OQ.js.map +0 -1
  205. package/dist/ko-APUEW2RS.js.map +0 -1
  206. package/dist/ms-PJBZWZWD.js.map +0 -1
  207. package/dist/nl-L4C3ZBCU.js.map +0 -1
  208. package/dist/no-QE5N5KNG.js.map +0 -1
  209. package/dist/pl-5Q2D23PD.js.map +0 -1
  210. package/dist/pt-AIGUOIOC.js.map +0 -1
  211. package/dist/ro-T56CSHTY.js.map +0 -1
  212. package/dist/sv-L4TJQ2UH.js.map +0 -1
  213. package/dist/th-6O7Y6O2Q.js.map +0 -1
  214. package/dist/tr-D4CQCSNO.js.map +0 -1
  215. package/dist/uk-2HMQG6ND.js.map +0 -1
  216. package/dist/vi-XVJ4RUEJ.js.map +0 -1
  217. package/dist/zh-K2KDPGHK.js.map +0 -1
  218. /package/dist/{chunk-3Q3TUKWP.js.map → chunk-Y2EEAOMZ.js.map} +0 -0
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.7",
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"
@@ -105,9 +109,9 @@
105
109
  "directory": "packages/react-ui"
106
110
  },
107
111
  "dependencies": {
108
- "@semiont/api-client": "*",
112
+ "@semiont/http-transport": "*",
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
 
@@ -0,0 +1,119 @@
1
+ /* ============================================
2
+ ProtectedErrorBoundary Component Styles
3
+ ============================================ */
4
+
5
+ .semiont-protected-error-boundary-container {
6
+ min-height: 400px;
7
+ display: flex;
8
+ align-items: center;
9
+ justify-content: center;
10
+ padding: var(--semiont-spacing-md);
11
+ }
12
+
13
+ .semiont-protected-error-boundary-card {
14
+ max-width: 28rem;
15
+ width: 100%;
16
+ background-color: var(--semiont-color-white);
17
+ border-radius: var(--semiont-radius-lg);
18
+ box-shadow: var(--semiont-shadow-lg);
19
+ padding: var(--semiont-spacing-lg);
20
+ }
21
+
22
+ [data-theme="dark"] .semiont-protected-error-boundary-card {
23
+ background-color: var(--semiont-color-gray-800);
24
+ }
25
+
26
+ .semiont-protected-error-boundary-header {
27
+ display: flex;
28
+ align-items: center;
29
+ gap: 0.75rem;
30
+ margin-bottom: var(--semiont-spacing-md);
31
+ }
32
+
33
+ .semiont-protected-error-boundary-icon-wrapper {
34
+ flex-shrink: 0;
35
+ display: flex;
36
+ align-items: center;
37
+ justify-content: center;
38
+ width: 2.5rem;
39
+ height: 2.5rem;
40
+ border-radius: var(--semiont-radius-full);
41
+ background-color: var(--semiont-color-red-100);
42
+ }
43
+
44
+ [data-theme="dark"] .semiont-protected-error-boundary-icon-wrapper {
45
+ background-color: rgba(127, 29, 29, 0.3);
46
+ }
47
+
48
+ .semiont-protected-error-boundary-icon {
49
+ width: 1.5rem;
50
+ height: 1.5rem;
51
+ color: var(--semiont-color-red-600);
52
+ }
53
+
54
+ [data-theme="dark"] .semiont-protected-error-boundary-icon {
55
+ color: var(--semiont-color-red-400);
56
+ }
57
+
58
+ .semiont-protected-error-boundary-title {
59
+ font-size: var(--semiont-text-xl);
60
+ font-weight: var(--semiont-font-semibold);
61
+ color: var(--semiont-color-gray-900);
62
+ }
63
+
64
+ [data-theme="dark"] .semiont-protected-error-boundary-title {
65
+ color: var(--semiont-color-white);
66
+ }
67
+
68
+ .semiont-protected-error-boundary-message {
69
+ color: var(--semiont-color-gray-600);
70
+ margin-bottom: var(--semiont-spacing-lg);
71
+ }
72
+
73
+ [data-theme="dark"] .semiont-protected-error-boundary-message {
74
+ color: var(--semiont-color-gray-300);
75
+ }
76
+
77
+ .semiont-protected-error-boundary-details {
78
+ margin-bottom: var(--semiont-spacing-md);
79
+ }
80
+
81
+ .semiont-protected-error-boundary-summary {
82
+ font-size: var(--semiont-text-sm);
83
+ color: var(--semiont-color-gray-500);
84
+ cursor: pointer;
85
+ }
86
+
87
+ .semiont-protected-error-boundary-summary:hover {
88
+ color: var(--semiont-color-gray-700);
89
+ }
90
+
91
+ [data-theme="dark"] .semiont-protected-error-boundary-summary {
92
+ color: var(--semiont-color-gray-500);
93
+ }
94
+
95
+ [data-theme="dark"] .semiont-protected-error-boundary-summary:hover {
96
+ color: var(--semiont-color-gray-300);
97
+ }
98
+
99
+ .semiont-protected-error-boundary-stack {
100
+ margin-top: var(--semiont-spacing-sm);
101
+ font-size: var(--semiont-text-xs);
102
+ background-color: var(--semiont-color-gray-100);
103
+ padding: var(--semiont-spacing-sm);
104
+ border-radius: var(--semiont-radius-sm);
105
+ overflow: auto;
106
+ }
107
+
108
+ [data-theme="dark"] .semiont-protected-error-boundary-stack {
109
+ background-color: var(--semiont-color-gray-900);
110
+ }
111
+
112
+ .semiont-protected-error-boundary-actions {
113
+ display: flex;
114
+ gap: 0.75rem;
115
+ }
116
+
117
+ .semiont-protected-error-boundary-actions .semiont-button {
118
+ flex: 1 1 0;
119
+ }
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { ErrorBoundary, type FallbackProps } from 'react-error-boundary';
3
+ import './ProtectedErrorBoundary.css';
3
4
 
4
5
  interface ProtectedErrorBoundaryProps {
5
6
  children: React.ReactNode;
@@ -45,46 +46,54 @@ export function ProtectedErrorBoundary({
45
46
  }
46
47
 
47
48
  function ProtectedErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
49
+ // react-error-boundary v6 types `error` as `unknown` — a thrown value can be
50
+ // anything, so narrow before reading Error fields.
51
+ const message = error instanceof Error ? error.message : String(error);
52
+ const stack = error instanceof Error ? error.stack : undefined;
48
53
  return (
49
- <div className="min-h-[400px] flex items-center justify-center p-4">
50
- <div className="max-w-md w-full bg-white dark:bg-gray-800 rounded-lg shadow-lg p-6">
51
- <div className="flex items-center gap-3 mb-4">
52
- <div className="flex-shrink-0 w-10 h-10 bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center">
53
- <svg className="w-6 h-6 text-red-600 dark:text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
54
+ <div className="semiont-protected-error-boundary-container">
55
+ <div className="semiont-protected-error-boundary-card">
56
+ <div className="semiont-protected-error-boundary-header">
57
+ <div className="semiont-protected-error-boundary-icon-wrapper">
58
+ <svg className="semiont-protected-error-boundary-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
54
59
  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
55
60
  </svg>
56
61
  </div>
57
- <h2 className="text-xl font-semibold text-gray-900 dark:text-white">
62
+ <h2 className="semiont-protected-error-boundary-title">
58
63
  Something went wrong
59
64
  </h2>
60
65
  </div>
61
66
 
62
- <p className="text-gray-600 dark:text-gray-300 mb-6">
67
+ <p className="semiont-protected-error-boundary-message">
63
68
  An unexpected error occurred. Try again, or refresh the page.
64
69
  </p>
65
70
 
66
71
  {process.env.NODE_ENV === 'development' && (
67
- <details className="mb-4">
68
- <summary className="text-sm text-gray-500 cursor-pointer hover:text-gray-700 dark:hover:text-gray-300">
72
+ <details className="semiont-protected-error-boundary-details">
73
+ <summary className="semiont-protected-error-boundary-summary">
69
74
  Error details (development only)
70
75
  </summary>
71
- <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
+ <pre className="semiont-protected-error-boundary-stack">
77
+ {message}
78
+ {stack}
74
79
  </pre>
75
80
  </details>
76
81
  )}
77
82
 
78
- <div className="flex gap-3">
83
+ <div className="semiont-protected-error-boundary-actions">
79
84
  <button
80
85
  onClick={resetErrorBoundary}
81
- className="flex-1 px-4 py-2 text-gray-700 dark:text-gray-200 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
86
+ className="semiont-button"
87
+ data-variant="secondary"
88
+ data-size="md"
82
89
  >
83
90
  Try Again
84
91
  </button>
85
92
  <button
86
93
  onClick={() => window.location.reload()}
87
- className="flex-1 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
94
+ className="semiont-button"
95
+ data-variant="primary"
96
+ data-size="md"
88
97
  >
89
98
  Refresh Page
90
99
  </button>
@@ -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