@semiont/react-ui 0.5.26 → 0.5.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -4
- package/dist/{PdfAnnotationCanvas.client-6ZSF6ZTJ.js → PdfAnnotationCanvas.client-EVUPTUWZ.js} +5 -5
- package/dist/PdfAnnotationCanvas.client-EVUPTUWZ.js.map +1 -0
- package/dist/{PdfAnnotationCanvas.client-JCJMXWWJ.css → PdfAnnotationCanvas.client-TGDPPGXJ.css} +6 -1
- package/dist/PdfAnnotationCanvas.client-TGDPPGXJ.css.map +1 -0
- package/dist/{ar-YTUUGK2O.js → ar-OU3DQGC6.js} +53 -7
- package/dist/ar-OU3DQGC6.js.map +1 -0
- package/dist/{bn-ASGNGPMD.js → bn-PHWCR6AZ.js} +53 -7
- package/dist/bn-PHWCR6AZ.js.map +1 -0
- package/dist/{chunk-OBQOZCJE.js → chunk-5VDTWRXJ.js} +31 -31
- package/dist/{chunk-L3WKRWP3.js → chunk-PCRRBU7H.js} +53 -7
- package/dist/chunk-PCRRBU7H.js.map +1 -0
- package/dist/{cs-WMYVAOZY.js → cs-NEXYZ62I.js} +53 -7
- package/dist/cs-NEXYZ62I.js.map +1 -0
- package/dist/{da-FSHHN4D6.js → da-FAT43YCU.js} +53 -7
- package/dist/da-FAT43YCU.js.map +1 -0
- package/dist/{de-FJFO3TPT.js → de-KRQ3WBCU.js} +53 -7
- package/dist/de-KRQ3WBCU.js.map +1 -0
- package/dist/{el-XOH4QIAG.js → el-Q4IU3EKC.js} +53 -7
- package/dist/el-Q4IU3EKC.js.map +1 -0
- package/dist/{en-3FCBW3YD.js → en-2KADE7N4.js} +4 -2
- package/dist/{es-HDX4QI7E.js → es-2IO3R2MK.js} +53 -7
- package/dist/es-2IO3R2MK.js.map +1 -0
- package/dist/{fa-DJ6WTFTJ.js → fa-Q5GOQFXX.js} +53 -7
- package/dist/fa-Q5GOQFXX.js.map +1 -0
- package/dist/{fi-4S7H7W7U.js → fi-R6NMRWBE.js} +53 -7
- package/dist/fi-R6NMRWBE.js.map +1 -0
- package/dist/{fr-6UJSYHXC.js → fr-QY4D5E6J.js} +53 -7
- package/dist/fr-QY4D5E6J.js.map +1 -0
- package/dist/{he-ZZJOHJX2.js → he-X6Y77XHY.js} +53 -7
- package/dist/he-X6Y77XHY.js.map +1 -0
- package/dist/{hi-HZJTAW7U.js → hi-XL7IOEQM.js} +53 -7
- package/dist/hi-XL7IOEQM.js.map +1 -0
- package/dist/{id-E3I6ILEM.js → id-QZ4ZZS67.js} +53 -7
- package/dist/id-QZ4ZZS67.js.map +1 -0
- package/dist/index.css +105 -454
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +155 -54
- package/dist/index.js +1798 -1637
- package/dist/index.js.map +1 -1
- package/dist/integrations/css-modules-helper.js +1 -3
- package/dist/integrations/css-modules-helper.js.map +1 -1
- package/dist/{it-ULAPAD7U.js → it-ME2Q7OB6.js} +53 -7
- package/dist/it-ME2Q7OB6.js.map +1 -0
- package/dist/{ja-SAHZQ4CZ.js → ja-HX7QASRI.js} +53 -7
- package/dist/ja-HX7QASRI.js.map +1 -0
- package/dist/{ko-DFU2ADQ4.js → ko-EQO5AHAV.js} +53 -7
- package/dist/ko-EQO5AHAV.js.map +1 -0
- package/dist/{ms-NWL76XNT.js → ms-UILFSF3I.js} +53 -7
- package/dist/ms-UILFSF3I.js.map +1 -0
- package/dist/{nl-ATCM76WN.js → nl-NNI45PMK.js} +53 -7
- package/dist/nl-NNI45PMK.js.map +1 -0
- package/dist/{no-UIAQ5RJF.js → no-MAL5F6P6.js} +53 -7
- package/dist/no-MAL5F6P6.js.map +1 -0
- package/dist/{pl-NOECQDXD.js → pl-4RMY6JAJ.js} +53 -7
- package/dist/pl-4RMY6JAJ.js.map +1 -0
- package/dist/{pt-SVWIIUPC.js → pt-VQH2X3QQ.js} +53 -7
- package/dist/pt-VQH2X3QQ.js.map +1 -0
- package/dist/{ro-NR2DRTZG.js → ro-XXCQO2OG.js} +53 -7
- package/dist/ro-XXCQO2OG.js.map +1 -0
- package/dist/{sv-STVJ37JP.js → sv-7Z6EJ6U4.js} +53 -7
- package/dist/sv-7Z6EJ6U4.js.map +1 -0
- package/dist/test-utils.css +1 -1
- package/dist/test-utils.css.map +1 -1
- package/dist/test-utils.d.ts +1 -1
- package/dist/test-utils.js +2 -2
- package/dist/test-utils.js.map +1 -1
- package/dist/{th-UWQR4K54.js → th-L3DXXYVQ.js} +53 -7
- package/dist/th-L3DXXYVQ.js.map +1 -0
- package/dist/{tr-WNXZSD27.js → tr-P3DFVLFJ.js} +53 -7
- package/dist/tr-P3DFVLFJ.js.map +1 -0
- package/dist/{uk-SJRMB47Y.js → uk-7C5D3PXS.js} +53 -7
- package/dist/uk-7C5D3PXS.js.map +1 -0
- package/dist/{vi-TMRQFES2.js → vi-ZLTLEO7P.js} +53 -7
- package/dist/vi-ZLTLEO7P.js.map +1 -0
- package/dist/{zh-QOL3LYEM.js → zh-5FHVWDIN.js} +53 -7
- package/dist/zh-5FHVWDIN.js.map +1 -0
- package/package.json +7 -7
- package/src/components/AssistProgress.tsx +144 -134
- package/src/components/{EntityFoundLog.tsx → ItemFoundLog.tsx} +12 -7
- package/src/components/ProtectedErrorBoundary.css +3 -1
- package/src/components/StatusDisplay.css +1 -1
- package/src/components/Toast.css +3 -1
- package/src/components/__tests__/AssistProgress.test.tsx +216 -148
- package/src/components/annotation/annotation-entries.css +0 -4
- package/src/components/annotation/references.css +0 -4
- package/src/components/image-annotation/AnnotationOverlay.tsx +6 -6
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +1 -1
- package/src/components/image-annotation/__tests__/AnnotationOverlay.click.test.tsx +7 -9
- package/src/components/image-annotation/__tests__/SvgDrawingCanvas.click.test.tsx +1 -2
- package/src/components/layout/Header.css +0 -4
- package/src/components/layout/LeftSidebar.css +0 -4
- package/src/components/modals/ConfigureGenerationStep.tsx +109 -48
- package/src/components/modals/ConfigureSearchStep.tsx +23 -40
- package/src/components/modals/ReferenceWizardModal.tsx +55 -16
- package/src/components/modals/ResourceGenerateModal.tsx +24 -8
- package/src/components/modals/ResourceSearchModal.tsx +1 -1
- package/src/components/modals/SearchModal.css +0 -12
- package/src/components/modals/SearchModal.tsx +1 -1
- package/src/components/modals/SearchResultsStep.tsx +2 -20
- package/src/components/modals/WizardFooter.tsx +63 -0
- package/src/components/modals/__tests__/ConfigureGenerationStep.test.tsx +255 -0
- package/src/components/modals/__tests__/ConfigureSearchStep.test.tsx +72 -0
- package/src/components/modals/__tests__/ReferenceWizardModal.test.tsx +256 -0
- package/src/components/modals/__tests__/ResourceGenerateModal.test.tsx +1 -0
- package/src/components/modals/__tests__/ResourceSearchModal.test.tsx +6 -2
- package/src/components/modals/__tests__/SearchModal.search-wiring.test.tsx +6 -2
- package/src/components/modals/__tests__/WizardFooter.test.tsx +235 -0
- package/src/components/modals/modals.css +16 -42
- package/src/components/navigation/NavigationTabs.css +0 -20
- package/src/components/pdf-annotation/PdfAnnotationCanvas.css +21 -2
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +2 -2
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +3 -5
- package/src/components/resource/AnnotateView.tsx +16 -5
- package/src/components/resource/AnnotationHistory.tsx +2 -0
- package/src/components/resource/BrowseView.tsx +15 -4
- package/src/components/resource/ResourceViewer.tsx +23 -24
- package/src/components/resource/__tests__/AnnotateView.focus.test.tsx +50 -0
- package/src/components/resource/__tests__/AnnotationHistory.test.tsx +2 -0
- package/src/components/resource/__tests__/BrowseView.test.tsx +29 -3
- package/src/components/resource/__tests__/ResourceViewer.embeddable.test.tsx +47 -3
- package/src/components/resource/event-formatting.ts +0 -3
- package/src/components/resource/panels/AssessmentEntry.tsx +1 -1
- package/src/components/resource/panels/AssessmentPanel.css +5 -6
- package/src/components/resource/panels/AssistSection.css +68 -271
- package/src/components/resource/panels/AssistSection.tsx +4 -4
- package/src/components/resource/panels/AssistShell.tsx +12 -4
- package/src/components/resource/panels/CollaborationPanel.css +47 -22
- package/src/components/resource/panels/CollaborationPanel.tsx +93 -2
- package/src/components/resource/panels/CommentEntry.tsx +1 -1
- package/src/components/resource/panels/CommentsPanel.css +0 -16
- package/src/components/resource/panels/HighlightEntry.tsx +1 -1
- package/src/components/resource/panels/HighlightPanel.css +0 -7
- package/src/components/resource/panels/JsonLdPanel.css +0 -4
- package/src/components/resource/panels/ReferenceEntry.tsx +1 -1
- package/src/components/resource/panels/ReferencesPanel.css +0 -12
- package/src/components/resource/panels/ReferencesPanel.tsx +12 -20
- package/src/components/resource/panels/ResourceInfoPanel.css +0 -32
- package/src/components/resource/panels/ResourceInfoPanel.tsx +1 -1
- package/src/components/resource/panels/StatisticsPanel.css +0 -20
- package/src/components/resource/panels/TagEntry.tsx +1 -1
- package/src/components/resource/panels/TaggingPanel.css +0 -4
- package/src/components/resource/panels/TaggingPanel.tsx +2 -10
- package/src/components/resource/panels/UnifiedAnnotationsPanel.css +0 -4
- package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +0 -1
- package/src/components/resource/panels/__tests__/AssistSection.test.tsx +48 -50
- package/src/components/resource/panels/__tests__/AssistShell.test.tsx +11 -6
- package/src/components/resource/panels/__tests__/CollaborationPanel.test.tsx +89 -0
- package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/HighlightEntry.test.tsx +0 -1
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +44 -36
- package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +0 -1
- package/src/components/resource/panels/__tests__/ReferencesPanel.headless.test.tsx +1 -1
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +34 -53
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +37 -1
- package/src/components/resource/panels/__tests__/TagEntry.test.tsx +0 -1
- package/src/components/settings/SettingsPanel.css +0 -4
- package/src/features/auth/auth.css +2 -26
- package/src/features/resource-compose/state/__tests__/compose-page-state-unit.test.ts +25 -1
- package/src/features/resource-compose/state/compose-page-state-unit.ts +11 -2
- package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +55 -0
- package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +29 -0
- package/src/features/resource-discovery/state/__tests__/discover-state-unit.test.ts +53 -3
- package/src/features/resource-discovery/state/discover-state-unit.ts +29 -8
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +41 -20
- package/src/features/resource-viewer/hooks/__tests__/useResourceViewedReport.test.tsx +63 -0
- package/src/features/resource-viewer/hooks/useResourceViewedReport.ts +33 -0
- package/src/features/resource-viewer/state/__tests__/resource-viewer-page-state-unit.test.ts +2 -2
- package/src/features/resource-viewer/state/resource-viewer-page-state-unit.ts +1 -1
- package/src/styles/core/buttons.css +3 -1
- package/src/styles/core/forms.css +0 -21
- package/src/styles/core/indicators.css +0 -4
- package/src/styles/core/inputs.css +0 -4
- package/src/styles/core/progress.css +2 -34
- package/src/styles/core/sliders.css +0 -4
- package/src/styles/core/toggles.css +0 -4
- package/src/styles/features/resource-discovery.css +13 -0
- package/src/styles/features/resource-viewer.css +0 -20
- package/src/styles/motivations/motivation-assessment.css +2 -2
- package/src/styles/panels/history-panel.css +0 -40
- package/src/styles/panels/user-panel.css +0 -3
- package/src/styles/patterns/panel-helpers.css +0 -27
- package/src/styles/patterns/panel-sections.css +0 -59
- package/src/styles/patterns/panels-base.css +0 -32
- package/translations/ar.json +49 -5
- package/translations/bn.json +49 -5
- package/translations/cs.json +49 -5
- package/translations/da.json +49 -5
- package/translations/de.json +49 -5
- package/translations/el.json +49 -5
- package/translations/en.json +49 -5
- package/translations/es.json +49 -5
- package/translations/fa.json +49 -5
- package/translations/fi.json +49 -5
- package/translations/fr.json +49 -5
- package/translations/he.json +49 -5
- package/translations/hi.json +49 -5
- package/translations/id.json +49 -5
- package/translations/it.json +49 -5
- package/translations/ja.json +49 -5
- package/translations/ko.json +49 -5
- package/translations/ms.json +49 -5
- package/translations/nl.json +49 -5
- package/translations/no.json +49 -5
- package/translations/pl.json +49 -5
- package/translations/pt.json +49 -5
- package/translations/ro.json +49 -5
- package/translations/sv.json +49 -5
- package/translations/th.json +49 -5
- package/translations/tr.json +49 -5
- package/translations/uk.json +49 -5
- package/translations/vi.json +49 -5
- package/translations/zh.json +49 -5
- package/dist/PdfAnnotationCanvas.client-6ZSF6ZTJ.js.map +0 -1
- package/dist/PdfAnnotationCanvas.client-JCJMXWWJ.css.map +0 -1
- package/dist/ar-YTUUGK2O.js.map +0 -1
- package/dist/bn-ASGNGPMD.js.map +0 -1
- package/dist/chunk-L3WKRWP3.js.map +0 -1
- package/dist/chunk-XUDKYAVC.js +0 -21
- package/dist/chunk-XUDKYAVC.js.map +0 -1
- package/dist/cs-WMYVAOZY.js.map +0 -1
- package/dist/da-FSHHN4D6.js.map +0 -1
- package/dist/de-FJFO3TPT.js.map +0 -1
- package/dist/el-XOH4QIAG.js.map +0 -1
- package/dist/es-HDX4QI7E.js.map +0 -1
- package/dist/fa-DJ6WTFTJ.js.map +0 -1
- package/dist/fi-4S7H7W7U.js.map +0 -1
- package/dist/fr-6UJSYHXC.js.map +0 -1
- package/dist/he-ZZJOHJX2.js.map +0 -1
- package/dist/hi-HZJTAW7U.js.map +0 -1
- package/dist/id-E3I6ILEM.js.map +0 -1
- package/dist/it-ULAPAD7U.js.map +0 -1
- package/dist/ja-SAHZQ4CZ.js.map +0 -1
- package/dist/ko-DFU2ADQ4.js.map +0 -1
- package/dist/ms-NWL76XNT.js.map +0 -1
- package/dist/nl-ATCM76WN.js.map +0 -1
- package/dist/no-UIAQ5RJF.js.map +0 -1
- package/dist/pl-NOECQDXD.js.map +0 -1
- package/dist/pt-SVWIIUPC.js.map +0 -1
- package/dist/ro-NR2DRTZG.js.map +0 -1
- package/dist/sv-STVJ37JP.js.map +0 -1
- package/dist/th-UWQR4K54.js.map +0 -1
- package/dist/tr-WNXZSD27.js.map +0 -1
- package/dist/uk-SJRMB47Y.js.map +0 -1
- package/dist/vi-TMRQFES2.js.map +0 -1
- package/dist/zh-QOL3LYEM.js.map +0 -1
- package/src/integrations/tailwind-plugin.cjs +0 -224
- /package/dist/{chunk-OBQOZCJE.js.map → chunk-5VDTWRXJ.js.map} +0 -0
- /package/dist/{en-3FCBW3YD.js.map → en-2KADE7N4.js.map} +0 -0
|
@@ -36,10 +36,6 @@
|
|
|
36
36
|
align-items: center;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
[data-theme="dark"] .semiont-nav-section__header-button {
|
|
40
|
-
color: inherit;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
39
|
.semiont-nav-section__header-button:hover {
|
|
44
40
|
opacity: 0.8;
|
|
45
41
|
}
|
|
@@ -68,10 +64,6 @@
|
|
|
68
64
|
text-align: left;
|
|
69
65
|
}
|
|
70
66
|
|
|
71
|
-
[data-theme="dark"] .semiont-nav-section__header-text {
|
|
72
|
-
color: inherit;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
67
|
.semiont-nav-section__header-icon {
|
|
76
68
|
display: flex;
|
|
77
69
|
align-items: center;
|
|
@@ -99,14 +91,6 @@
|
|
|
99
91
|
outline-offset: 2px;
|
|
100
92
|
}
|
|
101
93
|
|
|
102
|
-
[data-theme="dark"] .semiont-nav-section__header-icon {
|
|
103
|
-
color: var(--semiont-text-secondary);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
[data-theme="dark"] .semiont-nav-section__header-icon:hover {
|
|
107
|
-
background: var(--semiont-bg-tertiary);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
94
|
[data-theme="dark"] .semiont-nav-section__header-icon:focus-visible {
|
|
111
95
|
outline-color: var(--semiont-color-primary-400);
|
|
112
96
|
}
|
|
@@ -361,10 +345,6 @@
|
|
|
361
345
|
outline-color: var(--semiont-color-primary-400);
|
|
362
346
|
}
|
|
363
347
|
|
|
364
|
-
[data-theme="dark"] .semiont-resource-tab__link:visited {
|
|
365
|
-
color: inherit !important;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
348
|
/* Resource tab icon (emoji) */
|
|
369
349
|
.semiont-resource-tab__icon {
|
|
370
350
|
flex-shrink: 0;
|
|
@@ -101,9 +101,16 @@
|
|
|
101
101
|
scrollbar-width: none; /* standard; Firefox + recent Chromium */
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
/*
|
|
104
|
+
/*
|
|
105
|
+
* WebKit/Safari, which has no `scrollbar-width` support to rely on.
|
|
106
|
+
*
|
|
107
|
+
* This hides a SCROLLBAR, not content: `scrollbar-width: none` above already
|
|
108
|
+
* does the same for every other engine, the rail still scrolls by wheel and
|
|
109
|
+
* drag, and each page is a focusable button — so tabbing through the rail
|
|
110
|
+
* scrolls it, which is the keyboard path the rule is protecting.
|
|
111
|
+
*/
|
|
105
112
|
.semiont-pdf-annotation-canvas__strip::-webkit-scrollbar {
|
|
106
|
-
display: none;
|
|
113
|
+
display: none; /* stylelint-disable-line semiont/accessibility */
|
|
107
114
|
}
|
|
108
115
|
|
|
109
116
|
/*
|
|
@@ -160,6 +167,18 @@
|
|
|
160
167
|
font-weight: var(--semiont-font-semibold);
|
|
161
168
|
}
|
|
162
169
|
|
|
170
|
+
/*
|
|
171
|
+
* Palette tokens are one fixed hue in both themes, so this marker needs a real
|
|
172
|
+
* variant — the accent steps lighter against a dark surface (the treatment
|
|
173
|
+
* `.semiont-checkbox:checked` uses), and the number flips to dark type, which
|
|
174
|
+
* at this size reads far better on that lighter blue than white does.
|
|
175
|
+
*/
|
|
176
|
+
[data-theme="dark"] .semiont-pdf-annotation-canvas__strip-page[aria-current="page"] {
|
|
177
|
+
border-color: var(--semiont-color-primary-400);
|
|
178
|
+
background: var(--semiont-color-primary-400);
|
|
179
|
+
color: var(--semiont-color-neutral-900);
|
|
180
|
+
}
|
|
181
|
+
|
|
163
182
|
.semiont-pdf-annotation-canvas__strip-page:focus-visible {
|
|
164
183
|
outline: 2px solid var(--semiont-focus-ring);
|
|
165
184
|
outline-offset: 1px;
|
|
@@ -353,7 +353,7 @@ function PdfPageView({
|
|
|
353
353
|
});
|
|
354
354
|
|
|
355
355
|
if (hit) {
|
|
356
|
-
session?.client.browse.click(hit.annId,
|
|
356
|
+
session?.client.browse.click(hit.annId, hitRect);
|
|
357
357
|
setIsDrawing(false);
|
|
358
358
|
setSelection(null);
|
|
359
359
|
return;
|
|
@@ -515,7 +515,7 @@ function PdfPageView({
|
|
|
515
515
|
cursor: 'pointer',
|
|
516
516
|
opacity: isSelected ? 1 : isHovered ? 0.9 : 0.7
|
|
517
517
|
}}
|
|
518
|
-
onClick={(e) => session?.client.browse.click(r.annId,
|
|
518
|
+
onClick={(e) => session?.client.browse.click(r.annId, e.currentTarget.getBoundingClientRect())}
|
|
519
519
|
onMouseEnter={() => handleMouseEnter(r.annId)}
|
|
520
520
|
onMouseLeave={handleMouseLeave}
|
|
521
521
|
/>
|
|
@@ -275,7 +275,7 @@ describe('PdfAnnotationCanvas', () => {
|
|
|
275
275
|
});
|
|
276
276
|
});
|
|
277
277
|
|
|
278
|
-
test('passes the annotation rect as browse.click
|
|
278
|
+
test('passes the annotation rect as browse.click second argument (A1 anchor)', async () => {
|
|
279
279
|
const click = vi.fn();
|
|
280
280
|
const session = {
|
|
281
281
|
client: { browse: { click }, beckon: { hover: vi.fn() } },
|
|
@@ -328,8 +328,7 @@ describe('PdfAnnotationCanvas', () => {
|
|
|
328
328
|
|
|
329
329
|
expect(click).toHaveBeenCalledTimes(1);
|
|
330
330
|
expect(click.mock.calls[0]?.[0]).toBe('ann-1');
|
|
331
|
-
|
|
332
|
-
const anchorRect = click.mock.calls[0]?.[2];
|
|
331
|
+
const anchorRect = click.mock.calls[0]?.[1];
|
|
333
332
|
expect(anchorRect).toBeDefined();
|
|
334
333
|
expect(typeof anchorRect.width).toBe('number');
|
|
335
334
|
});
|
|
@@ -401,8 +400,7 @@ describe('PdfAnnotationCanvas', () => {
|
|
|
401
400
|
|
|
402
401
|
expect(click).toHaveBeenCalledTimes(1);
|
|
403
402
|
expect(click.mock.calls[0]?.[0]).toBe('ann-hit-1');
|
|
404
|
-
expect(click.mock.calls[0]?.[1]).
|
|
405
|
-
expect(click.mock.calls[0]?.[2]).toMatchObject({
|
|
403
|
+
expect(click.mock.calls[0]?.[1]).toMatchObject({
|
|
406
404
|
left: displayRect.x,
|
|
407
405
|
top: displayRect.y,
|
|
408
406
|
width: displayRect.width,
|
|
@@ -53,7 +53,7 @@ interface Props {
|
|
|
53
53
|
*
|
|
54
54
|
* @emits mark:requested - User requested to create annotation. Payload: { selector: Selector | Selector[], motivation: SelectionMotivation }
|
|
55
55
|
* @subscribes beckon:hover - Annotation hovered. Payload: { annotationId: string | null }
|
|
56
|
-
* @subscribes beckon:focus - Scroll to and highlight annotation. Payload: { annotationId: string }
|
|
56
|
+
* @subscribes beckon:focus - Scroll to and highlight annotation, unless `resourceId` names a different resource (D7). Payload: { annotationId: string, resourceId?: string }
|
|
57
57
|
*/
|
|
58
58
|
export function AnnotateView({
|
|
59
59
|
content,
|
|
@@ -111,10 +111,21 @@ export function AnnotateView({
|
|
|
111
111
|
// serves, so the behaviour no longer depends on which view mode is active.
|
|
112
112
|
// The `scrollToAnnotationId` prop path (uiState → renderer) stays as the
|
|
113
113
|
// host-facing capability it is; this is the in-app producer's route.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
// `resourceId` is a GUARD, not navigation (GUIDED-TOUR D7): it names the
|
|
115
|
+
// resource this focus applies to, and a viewer showing a different one
|
|
116
|
+
// ignores it. Absent means unscoped — the in-app emitters (history panel,
|
|
117
|
+
// annotation list) omit it because they are already scoped to the open
|
|
118
|
+
// resource, so treating absence as "not mine" would silence all of them.
|
|
119
|
+
// Focus never navigates; driving the Browser to a resource is
|
|
120
|
+
// `browse:resource-open`'s job.
|
|
121
|
+
const handleAnnotationFocus = useCallback(
|
|
122
|
+
({ annotationId, resourceId }: { annotationId?: string | null; resourceId?: string }) => {
|
|
123
|
+
if (resourceId && resourceId !== resourceUri) return;
|
|
124
|
+
if (!containerRef.current) return;
|
|
125
|
+
scrollAnnotationIntoView(annotationId ?? null, containerRef.current, { pulse: true });
|
|
126
|
+
},
|
|
127
|
+
[resourceUri],
|
|
128
|
+
);
|
|
118
129
|
|
|
119
130
|
// Annotation hover (session-scoped). Toolbar preference changes flow through
|
|
120
131
|
// props/callbacks, not the bus (TOOLBAR-PREFS-AS-PROPS).
|
|
@@ -51,6 +51,8 @@ export function AnnotationHistory({
|
|
|
51
51
|
|
|
52
52
|
// Sort events by oldest first (most recent at bottom)
|
|
53
53
|
// Filter out job events - they're represented by mark:body-updated events instead
|
|
54
|
+
// `job:progress` is no longer a persisted event type, but logs written before it
|
|
55
|
+
// was retired still hold them; naming it here keeps those out of the history.
|
|
54
56
|
const events: StoredEventLike[] = eventsData
|
|
55
57
|
.filter((e) => {
|
|
56
58
|
return e.type !== 'job:started' && e.type !== 'job:progress' && e.type !== 'job:completed';
|
|
@@ -155,7 +155,7 @@ export const BrowseView = memo(function BrowseView({
|
|
|
155
155
|
if (annotation) {
|
|
156
156
|
// The emission site owns the geometry: the clicked span's viewport
|
|
157
157
|
// rect rides the event so hosts can anchor popovers (A1).
|
|
158
|
-
session.client.browse.click(annotation.id,
|
|
158
|
+
session.client.browse.click(annotation.id, annotationElement.getBoundingClientRect());
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
};
|
|
@@ -263,9 +263,20 @@ export const BrowseView = memo(function BrowseView({
|
|
|
263
263
|
scrollToAnnotation(annotationId);
|
|
264
264
|
}, [scrollToAnnotation]);
|
|
265
265
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
266
|
+
// `resourceId` is a GUARD, not navigation (GUIDED-TOUR D7): it names the
|
|
267
|
+
// resource this focus applies to, and a viewer showing a different one
|
|
268
|
+
// ignores it. Absent means unscoped — the in-app emitters (history panel,
|
|
269
|
+
// annotation list) omit it because they are already scoped to the open
|
|
270
|
+
// resource, so treating absence as "not mine" would silence all of them.
|
|
271
|
+
// Focus never navigates; driving the Browser to a resource is
|
|
272
|
+
// `browse:resource-open`'s job.
|
|
273
|
+
const handleAnnotationFocus = useCallback(
|
|
274
|
+
({ annotationId, resourceId }: { annotationId?: string | null; resourceId?: string }) => {
|
|
275
|
+
if (resourceId && resourceId !== resourceUri) return;
|
|
276
|
+
scrollToAnnotation(annotationId ?? null, true);
|
|
277
|
+
},
|
|
278
|
+
[scrollToAnnotation, resourceUri],
|
|
279
|
+
);
|
|
269
280
|
|
|
270
281
|
useSessionEventSubscriptions(session, {
|
|
271
282
|
'beckon:hover': handleAnnotationHover,
|
|
@@ -8,7 +8,7 @@ import { BrowseView, type ReferenceHover } from './BrowseView';
|
|
|
8
8
|
import type { BrowseMediaRenderers } from './browse-renderers';
|
|
9
9
|
import { PopupContainer } from '../annotation-popups/SharedPopupElements';
|
|
10
10
|
import { JsonLdView } from '../annotation-popups/JsonLdView';
|
|
11
|
-
import type { Annotation, AnnotationId, ResourceDescriptor as SemiontResource,
|
|
11
|
+
import type { Annotation, AnnotationId, ResourceDescriptor as SemiontResource, EventMap, AnchorRect } from '@semiont/core';
|
|
12
12
|
import { getExactText, getTargetSelector, getPrimaryMediaType, isHighlight, isAssessment, isReference, isComment, isTag, getBodySource } from '@semiont/core';
|
|
13
13
|
import type { SemiontSession } from '@semiont/sdk';
|
|
14
14
|
import { useSessionEventSubscriptions } from '../../hooks/useSessionEventSubscriptions';
|
|
@@ -102,7 +102,10 @@ interface Props {
|
|
|
102
102
|
* panel opening invokes the host's `onOpenPanel` callback — the host owns
|
|
103
103
|
* the panel and any `panel:open` emission.
|
|
104
104
|
*
|
|
105
|
-
* @subscribes browse:click -
|
|
105
|
+
* @subscribes browse:click - An annotation was clicked — locally, or driven over
|
|
106
|
+
* the wire by another participant. Payload: { annotationId: string, anchorRect? };
|
|
107
|
+
* the motivation is derived from the annotation the id names, and an id this
|
|
108
|
+
* viewer has not loaded is a no-op.
|
|
106
109
|
*/
|
|
107
110
|
export function ResourceViewer({
|
|
108
111
|
resource,
|
|
@@ -270,38 +273,34 @@ export function ResourceViewer({
|
|
|
270
273
|
}, [annotateMode, selectedClick, onOpenResource]);
|
|
271
274
|
|
|
272
275
|
// Annotation click coordinator - handles panel opening and scrolling
|
|
273
|
-
const handleAnnotationClickEvent = useCallback(({ annotationId,
|
|
276
|
+
const handleAnnotationClickEvent = useCallback(({ annotationId, anchorRect }: {
|
|
274
277
|
annotationId: string;
|
|
275
|
-
motivation: components['schemas']['Motivation'];
|
|
276
278
|
anchorRect?: AnchorRect;
|
|
277
279
|
}) => {
|
|
278
|
-
//
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
280
|
+
// Resolve the annotation FIRST. The id is the whole address, and the
|
|
281
|
+
// motivation is derived from the annotation it names rather than carried
|
|
282
|
+
// beside it (TOUR-CLICK D2) — one fact, one encoding. Resolving first also
|
|
283
|
+
// means a click naming an annotation this viewer has not loaded (a remote
|
|
284
|
+
// drive that arrived while the participant was elsewhere) finds nothing
|
|
285
|
+
// and does nothing, which is why the channel needs no resourceId guard.
|
|
286
|
+
const allAnnotations = [...highlights, ...references, ...assessments, ...comments, ...tags];
|
|
287
|
+
const annotation = allAnnotations.find(a => a.id === annotationId);
|
|
288
|
+
if (!annotation) return;
|
|
289
|
+
|
|
290
|
+
// The real annotation, not a `{ motivation } as Annotation` stand-in.
|
|
291
|
+
const metadata = Object.values(ANNOTATORS).find(a => a.matchesAnnotation(annotation));
|
|
290
292
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
if (annotation) {
|
|
296
|
-
handleAnnotationClick(annotation);
|
|
297
|
-
}
|
|
293
|
+
// No side panel, or a click mode other than detail: this is a plain
|
|
294
|
+
// annotation click, not a panel-opening one.
|
|
295
|
+
if (!metadata?.hasSidePanel || selectedClick !== 'detail') {
|
|
296
|
+
handleAnnotationClick(annotation);
|
|
298
297
|
return;
|
|
299
298
|
}
|
|
300
299
|
|
|
301
300
|
// All annotations open the unified annotations panel — the host owns the panel.
|
|
302
301
|
// The panel internally switches tabs based on the motivation → tab mapping in UnifiedAnnotationsPanel.
|
|
303
302
|
// View geometry passes through untouched: the emitter owned it, the host anchors with it.
|
|
304
|
-
onOpenPanel?.({ panel: 'annotations', scrollToAnnotationId: annotationId, motivation, ...(anchorRect ? { anchorRect } : {}) });
|
|
303
|
+
onOpenPanel?.({ panel: 'annotations', scrollToAnnotationId: annotationId, motivation: annotation.motivation, ...(anchorRect ? { anchorRect } : {}) });
|
|
305
304
|
}, [highlights, references, assessments, comments, tags, handleAnnotationClick, selectedClick, onOpenPanel]);
|
|
306
305
|
|
|
307
306
|
// Single subscription call per file (see scripts/compliance/audit-hooks-ordering.ts).
|
|
@@ -56,3 +56,53 @@ describe('AnnotateView — beckon:focus scrolls the content', () => {
|
|
|
56
56
|
expect(scrollSpy.mock.calls[0]?.[0]).toBe('ann-7');
|
|
57
57
|
});
|
|
58
58
|
});
|
|
59
|
+
|
|
60
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
61
|
+
// GUIDED-TOUR P6 (D7) — `resourceId` is a GUARD, not navigation.
|
|
62
|
+
//
|
|
63
|
+
// The schema now says so out loud: "it names the resource this focus applies
|
|
64
|
+
// to, and a viewer currently showing a different resource ignores the event".
|
|
65
|
+
// Without the comparison the field was decorative — a guide beckoning a
|
|
66
|
+
// reference in doc B scrolled every participant's doc A.
|
|
67
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
68
|
+
describe('AnnotateView — beckon:focus is guarded by resourceId (P6/D7)', () => {
|
|
69
|
+
beforeEach(() => { scrollSpy.mockClear(); });
|
|
70
|
+
|
|
71
|
+
const renderAt = (resourceUri: string) => {
|
|
72
|
+
const { session, client } = createTestSemiontWrapper();
|
|
73
|
+
render(
|
|
74
|
+
<AnnotateView
|
|
75
|
+
content="hello world"
|
|
76
|
+
mimeType="text/plain"
|
|
77
|
+
resourceUri={resourceUri}
|
|
78
|
+
annotations={emptyAnnotations}
|
|
79
|
+
uiState={uiState}
|
|
80
|
+
session={session}
|
|
81
|
+
annotateMode
|
|
82
|
+
/>,
|
|
83
|
+
);
|
|
84
|
+
return client;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
it('ignores a focus aimed at a DIFFERENT resource', () => {
|
|
88
|
+
const client = renderAt('res-1');
|
|
89
|
+
client.bus.get('beckon:focus').next({ annotationId: 'ann-7', resourceId: 'res-2' });
|
|
90
|
+
expect(scrollSpy).not.toHaveBeenCalled();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('still scrolls when the resource matches', () => {
|
|
94
|
+
const client = renderAt('res-1');
|
|
95
|
+
client.bus.get('beckon:focus').next({ annotationId: 'ann-7', resourceId: 'res-1' });
|
|
96
|
+
expect(scrollSpy).toHaveBeenCalledTimes(1);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('still scrolls when the event names no resource at all', () => {
|
|
100
|
+
// `resourceId` is optional in the schema (`required: []`), and the in-app
|
|
101
|
+
// emitters — the history panel, the annotation list — omit it because they
|
|
102
|
+
// are already scoped to the open resource. A guard that treated absence as
|
|
103
|
+
// "not mine" would break every one of them.
|
|
104
|
+
const client = renderAt('res-1');
|
|
105
|
+
client.bus.get('beckon:focus').next({ annotationId: 'ann-7' });
|
|
106
|
+
expect(scrollSpy).toHaveBeenCalledTimes(1);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -173,6 +173,8 @@ describe('AnnotationHistory', () => {
|
|
|
173
173
|
});
|
|
174
174
|
|
|
175
175
|
it('filters out job events', () => {
|
|
176
|
+
// e3 is `job:progress`, a retired event type. Logs written before it was
|
|
177
|
+
// retired still hold them, so the filter must keep excluding it.
|
|
176
178
|
const events = [
|
|
177
179
|
makeStoredEvent('e1', 'mark:added', 1),
|
|
178
180
|
makeStoredEvent('e2', 'job:started', 2),
|
|
@@ -427,7 +427,7 @@ describe('BrowseView Component', () => {
|
|
|
427
427
|
{ id: 'comment-1', type: 'comment', motivation: 'commenting' },
|
|
428
428
|
] as const;
|
|
429
429
|
|
|
430
|
-
for (const { id, type
|
|
430
|
+
for (const { id, type } of clickCases) {
|
|
431
431
|
const el = document.createElement('span');
|
|
432
432
|
el.setAttribute('data-annotation-id', id);
|
|
433
433
|
el.setAttribute('data-annotation-type', type);
|
|
@@ -439,8 +439,7 @@ describe('BrowseView Component', () => {
|
|
|
439
439
|
await waitFor(() => {
|
|
440
440
|
expect(tracker.events.some(e =>
|
|
441
441
|
e.event === 'browse:click' &&
|
|
442
|
-
e.payload?.annotationId === id
|
|
443
|
-
e.payload?.motivation === motivation
|
|
442
|
+
e.payload?.annotationId === id
|
|
444
443
|
)).toBe(true);
|
|
445
444
|
});
|
|
446
445
|
}
|
|
@@ -653,3 +652,30 @@ describe('BrowseView Component', () => {
|
|
|
653
652
|
});
|
|
654
653
|
});
|
|
655
654
|
});
|
|
655
|
+
|
|
656
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
657
|
+
// GUIDED-TOUR P6 (D7) — the same guard BrowseView's sibling carries.
|
|
658
|
+
// BrowseView subscribed to `beckon:focus` first, so it is the one that has
|
|
659
|
+
// been scrolling on other people's resources the longest.
|
|
660
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
661
|
+
describe('BrowseView — beckon:focus is guarded by resourceId (P6/D7)', () => {
|
|
662
|
+
it('ignores a focus aimed at a different resource, honours one that matches', () => {
|
|
663
|
+
const { session, client } = createTestSemiontWrapper();
|
|
664
|
+
const { container } = render(
|
|
665
|
+
<BrowseView
|
|
666
|
+
content="hello world"
|
|
667
|
+
mimeType="text/plain"
|
|
668
|
+
resourceUri="res-1"
|
|
669
|
+
annotations={{ highlights: [], references: [], assessments: [], comments: [], tags: [] }}
|
|
670
|
+
session={session}
|
|
671
|
+
annotateMode={false}
|
|
672
|
+
/>,
|
|
673
|
+
);
|
|
674
|
+
expect(container).toBeTruthy();
|
|
675
|
+
|
|
676
|
+
// Neither call may throw; the assertion that matters is the guard's
|
|
677
|
+
// existence, pinned in AnnotateView where the scroll helper is mockable.
|
|
678
|
+
client.bus.get('beckon:focus').next({ annotationId: 'ann-7', resourceId: 'res-2' });
|
|
679
|
+
client.bus.get('beckon:focus').next({ annotationId: 'ann-7', resourceId: 'res-1' });
|
|
680
|
+
});
|
|
681
|
+
});
|
|
@@ -15,7 +15,8 @@ import { describe, it, expect, vi } from 'vitest';
|
|
|
15
15
|
import { render, screen, act, waitFor } from '@testing-library/react';
|
|
16
16
|
import '@testing-library/jest-dom';
|
|
17
17
|
import type { SemiontSession } from '@semiont/sdk';
|
|
18
|
-
import type { ResourceDescriptor as SemiontResource, ResourceId } from '@semiont/core';
|
|
18
|
+
import type { Annotation, ResourceDescriptor as SemiontResource, ResourceId } from '@semiont/core';
|
|
19
|
+
import { annotationId } from '@semiont/core';
|
|
19
20
|
import { createTestSemiontWrapper } from '../../../test-utils';
|
|
20
21
|
import { ResourceViewer } from '../ResourceViewer';
|
|
21
22
|
|
|
@@ -46,6 +47,23 @@ const resource: SemiontResource & { content: string } = {
|
|
|
46
47
|
|
|
47
48
|
const annotations = { highlights: [], references: [], assessments: [], comments: [], tags: [] };
|
|
48
49
|
|
|
50
|
+
/**
|
|
51
|
+
* A highlight the viewer has actually loaded. Required since TOUR-CLICK D2: the
|
|
52
|
+
* click handler resolves the annotation by id and derives the motivation from
|
|
53
|
+
* it, so a click for an id absent from this collection is a no-op. Before that,
|
|
54
|
+
* the wire carried the motivation and the viewer never looked — which is why
|
|
55
|
+
* the anchorRect test below used to pass against an empty collection.
|
|
56
|
+
*/
|
|
57
|
+
const loadedHighlight: Annotation = {
|
|
58
|
+
'@context': 'http://www.w3.org/ns/anno.jsonld',
|
|
59
|
+
type: 'Annotation',
|
|
60
|
+
id: annotationId('ann-1'),
|
|
61
|
+
motivation: 'highlighting',
|
|
62
|
+
target: { source: 'res-1', selector: { type: 'TextPositionSelector', start: 0, end: 10 } },
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const annotationsWithHighlight = { ...annotations, highlights: [loadedHighlight] };
|
|
66
|
+
|
|
49
67
|
describe('ResourceViewer — embeddable (bring-your-own-session, no providers)', () => {
|
|
50
68
|
// GREEN: the whole browse-mode subtree (ResourceViewer → BrowseView →
|
|
51
69
|
// AnnotateToolbar) renders provider-free from a bare session.
|
|
@@ -73,7 +91,7 @@ describe('ResourceViewer — embeddable (bring-your-own-session, no providers)',
|
|
|
73
91
|
<ResourceViewer
|
|
74
92
|
session={session}
|
|
75
93
|
resource={resource}
|
|
76
|
-
annotations={
|
|
94
|
+
annotations={annotationsWithHighlight}
|
|
77
95
|
onOpenResource={vi.fn()}
|
|
78
96
|
onOpenPanel={onOpenPanel}
|
|
79
97
|
/>,
|
|
@@ -86,7 +104,6 @@ describe('ResourceViewer — embeddable (bring-your-own-session, no providers)',
|
|
|
86
104
|
act(() => {
|
|
87
105
|
eventBus.get('browse:click').next({
|
|
88
106
|
annotationId: 'ann-1',
|
|
89
|
-
motivation: 'highlighting',
|
|
90
107
|
anchorRect,
|
|
91
108
|
});
|
|
92
109
|
});
|
|
@@ -95,8 +112,35 @@ describe('ResourceViewer — embeddable (bring-your-own-session, no providers)',
|
|
|
95
112
|
expect(onOpenPanel).toHaveBeenCalledWith(expect.objectContaining({
|
|
96
113
|
panel: 'annotations',
|
|
97
114
|
scrollToAnnotationId: 'ann-1',
|
|
115
|
+
// Derived from the annotation the id names, never carried on the wire.
|
|
116
|
+
motivation: 'highlighting',
|
|
98
117
|
anchorRect: expect.objectContaining({ left: 5, width: 7 }),
|
|
99
118
|
}));
|
|
100
119
|
});
|
|
101
120
|
});
|
|
121
|
+
|
|
122
|
+
it('ignores a browse:click naming an annotation this viewer has not loaded', async () => {
|
|
123
|
+
// A remote drive can arrive while the participant is looking at something
|
|
124
|
+
// else. Resolving the annotation FIRST makes that a no-op by construction,
|
|
125
|
+
// which is why the channel carries no resourceId guard (TOUR-CLICK D3).
|
|
126
|
+
const { session, eventBus } = createTestSemiontWrapper();
|
|
127
|
+
const onOpenPanel = vi.fn();
|
|
128
|
+
|
|
129
|
+
render(
|
|
130
|
+
<ResourceViewer
|
|
131
|
+
session={session}
|
|
132
|
+
resource={resource}
|
|
133
|
+
annotations={annotationsWithHighlight}
|
|
134
|
+
onOpenResource={vi.fn()}
|
|
135
|
+
onOpenPanel={onOpenPanel}
|
|
136
|
+
/>,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
act(() => {
|
|
140
|
+
eventBus.get('browse:click').next({ annotationId: 'ann-not-here' });
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
144
|
+
expect(onOpenPanel).not.toHaveBeenCalled();
|
|
145
|
+
});
|
|
102
146
|
});
|
|
@@ -81,7 +81,6 @@ export function formatEventType(type: PersistedEventType, t: TranslateFn, payloa
|
|
|
81
81
|
|
|
82
82
|
case 'job:completed':
|
|
83
83
|
case 'job:started':
|
|
84
|
-
case 'job:progress':
|
|
85
84
|
case 'job:failed':
|
|
86
85
|
return t('jobEvent');
|
|
87
86
|
|
|
@@ -128,7 +127,6 @@ export function getEventEmoji(type: PersistedEventType, payload?: any): string {
|
|
|
128
127
|
case 'job:completed':
|
|
129
128
|
return '🔗'; // Link emoji for linked document creation
|
|
130
129
|
case 'job:started':
|
|
131
|
-
case 'job:progress':
|
|
132
130
|
return '⚙️'; // Gear for job processing
|
|
133
131
|
case 'job:failed':
|
|
134
132
|
return '❌'; // X mark for failed jobs
|
|
@@ -276,7 +274,6 @@ export function getEventDisplayContent(
|
|
|
276
274
|
}
|
|
277
275
|
|
|
278
276
|
case 'job:started':
|
|
279
|
-
case 'job:progress':
|
|
280
277
|
case 'job:failed':
|
|
281
278
|
case 'yield:representation-added':
|
|
282
279
|
case 'yield:representation-removed':
|
|
@@ -88,7 +88,7 @@ export function AssessmentEntry({
|
|
|
88
88
|
data-type="assessment"
|
|
89
89
|
data-focused={isFocused ? 'true' : 'false'}
|
|
90
90
|
onClick={() => {
|
|
91
|
-
session?.client.browse.click(assessment.id
|
|
91
|
+
session?.client.browse.click(assessment.id);
|
|
92
92
|
}}
|
|
93
93
|
{...hoverProps}
|
|
94
94
|
>
|
|
@@ -30,10 +30,6 @@
|
|
|
30
30
|
letter-spacing: 0.05em;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
[data-theme="dark"] .semiont-assessment-panel__label {
|
|
34
|
-
color: var(--semiont-text-secondary);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
33
|
.semiont-assessment-panel__rating {
|
|
38
34
|
display: flex;
|
|
39
35
|
gap: var(--semiont-panel-padding-xs);
|
|
@@ -46,8 +42,11 @@
|
|
|
46
42
|
transition: color 0.2s ease;
|
|
47
43
|
}
|
|
48
44
|
|
|
45
|
+
/* An UNRATED star must recede. gray-300 is near-white: on a dark panel the
|
|
46
|
+
empty stars outshone the filled ones, inverting the reading. Dark takes a
|
|
47
|
+
dim grey; the filled star keeps the warning hue. */
|
|
49
48
|
[data-theme="dark"] .semiont-assessment-panel__star {
|
|
50
|
-
color: var(--semiont-color-gray-
|
|
49
|
+
color: var(--semiont-color-gray-600);
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
.semiont-assessment-panel__star:hover {
|
|
@@ -59,7 +58,7 @@
|
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
[data-theme="dark"] .semiont-assessment-panel__star--filled {
|
|
62
|
-
color: var(--semiont-color-warning);
|
|
61
|
+
color: var(--semiont-color-warning-light);
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
.semiont-assessment-panel__textarea {
|