@semiont/react-ui 0.2.45 → 0.3.0
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/dist/{PdfAnnotationCanvas.client-COQREPXU.mjs → PdfAnnotationCanvas.client-PVTVPDBQ.mjs} +3 -4
- package/dist/PdfAnnotationCanvas.client-PVTVPDBQ.mjs.map +1 -0
- package/dist/{ar-7SUXNE34.mjs → ar-APUOG2AP.mjs} +46 -6
- package/dist/ar-APUOG2AP.mjs.map +1 -0
- package/dist/{bn-XOET3DOI.mjs → bn-EFK2LJGK.mjs} +46 -6
- package/dist/bn-EFK2LJGK.mjs.map +1 -0
- package/dist/{chunk-JH7BXE2P.mjs → chunk-7DW2P4UE.mjs} +45 -5
- package/dist/chunk-7DW2P4UE.mjs.map +1 -0
- package/dist/{chunk-Q2KV6Y2J.mjs → chunk-7GEYABC6.mjs} +32 -32
- package/dist/{chunk-3JTO27MH.mjs → chunk-D4GAAQMM.mjs} +2 -9
- package/dist/{cs-X63DXX7L.mjs → cs-A26MEEQE.mjs} +46 -6
- package/dist/cs-A26MEEQE.mjs.map +1 -0
- package/dist/{da-OWTCV57A.mjs → da-U3L2FHSZ.mjs} +46 -6
- package/dist/da-U3L2FHSZ.mjs.map +1 -0
- package/dist/{de-77BMFDVF.mjs → de-Y5BHEBT7.mjs} +46 -6
- package/dist/de-Y5BHEBT7.mjs.map +1 -0
- package/dist/dist-YLEIY3JJ.mjs +547 -0
- package/dist/dist-YLEIY3JJ.mjs.map +1 -0
- package/dist/{el-FIBNLH2V.mjs → el-HU7LAWQY.mjs} +46 -6
- package/dist/el-HU7LAWQY.mjs.map +1 -0
- package/dist/{en-XWEPVTB4.mjs → en-HAKDCFKL.mjs} +5 -3
- package/dist/{es-726NTS53.mjs → es-4BN64QH5.mjs} +46 -6
- package/dist/es-4BN64QH5.mjs.map +1 -0
- package/dist/{fa-3N4CIWE6.mjs → fa-6ELTBARU.mjs} +46 -6
- package/dist/fa-6ELTBARU.mjs.map +1 -0
- package/dist/{fi-JOM3M7Z4.mjs → fi-DJ4WGIFW.mjs} +46 -6
- package/dist/fi-DJ4WGIFW.mjs.map +1 -0
- package/dist/{fr-56QSXS7E.mjs → fr-23XM6H6H.mjs} +46 -6
- package/dist/fr-23XM6H6H.mjs.map +1 -0
- package/dist/{he-SNAXPJEK.mjs → he-JSWJC2XU.mjs} +46 -6
- package/dist/he-JSWJC2XU.mjs.map +1 -0
- package/dist/{hi-CRBRD5TB.mjs → hi-BENHG3OJ.mjs} +46 -6
- package/dist/hi-BENHG3OJ.mjs.map +1 -0
- package/dist/{id-BRCVLICF.mjs → id-4HHQJQNF.mjs} +46 -6
- package/dist/id-4HHQJQNF.mjs.map +1 -0
- package/dist/index.css +108 -12
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +399 -147
- package/dist/index.mjs +3573 -2226
- package/dist/index.mjs.map +1 -1
- package/dist/{it-M2Z27BNB.mjs → it-U6I5PDKU.mjs} +46 -6
- package/dist/it-U6I5PDKU.mjs.map +1 -0
- package/dist/{ja-TZUKW7HD.mjs → ja-K3YBDWDP.mjs} +46 -6
- package/dist/ja-K3YBDWDP.mjs.map +1 -0
- package/dist/{ko-NKBGGOL6.mjs → ko-KC2HXRXG.mjs} +46 -6
- package/dist/ko-KC2HXRXG.mjs.map +1 -0
- package/dist/{magic-string.es-7FJ3LUGB.mjs → magic-string.es-K77I4ZQN.mjs} +2 -2
- package/dist/{ms-XFXPN6RX.mjs → ms-KY5QGBNN.mjs} +46 -6
- package/dist/ms-KY5QGBNN.mjs.map +1 -0
- package/dist/{nl-MVYXAS5C.mjs → nl-6PZFLGY2.mjs} +46 -6
- package/dist/nl-6PZFLGY2.mjs.map +1 -0
- package/dist/{no-XOLO4JPV.mjs → no-5QR7PLVJ.mjs} +46 -6
- package/dist/no-5QR7PLVJ.mjs.map +1 -0
- package/dist/{pl-TRWLMMC4.mjs → pl-4GV2NQXE.mjs} +46 -6
- package/dist/pl-4GV2NQXE.mjs.map +1 -0
- package/dist/{pt-M3TE24UI.mjs → pt-F3F5QD2P.mjs} +46 -6
- package/dist/pt-F3F5QD2P.mjs.map +1 -0
- package/dist/{ro-QBFG2T64.mjs → ro-TFYL2IQB.mjs} +46 -6
- package/dist/ro-TFYL2IQB.mjs.map +1 -0
- package/dist/{sv-IUECBXWX.mjs → sv-PRVF2QLR.mjs} +46 -6
- package/dist/sv-PRVF2QLR.mjs.map +1 -0
- package/dist/test-utils.mjs +16994 -22140
- package/dist/test-utils.mjs.map +1 -1
- package/dist/{th-US7KIN5Q.mjs → th-SUQOQFUZ.mjs} +46 -6
- package/dist/th-SUQOQFUZ.mjs.map +1 -0
- package/dist/{tr-DWJ2FFUK.mjs → tr-AYUJZOFJ.mjs} +46 -6
- package/dist/tr-AYUJZOFJ.mjs.map +1 -0
- package/dist/{uk-M4ZE4DPZ.mjs → uk-YY5WGLBM.mjs} +46 -6
- package/dist/uk-YY5WGLBM.mjs.map +1 -0
- package/dist/{vi-FERZNPSH.mjs → vi-6RO77ITD.mjs} +46 -6
- package/dist/{vi-FERZNPSH.mjs.map → vi-6RO77ITD.mjs.map} +1 -1
- package/dist/{zh-3J2I3WYK.mjs → zh-L6GA65H6.mjs} +46 -6
- package/dist/zh-L6GA65H6.mjs.map +1 -0
- package/package.json +18 -14
- package/src/components/Button/Button.tsx +23 -25
- package/src/components/annotation/AnnotateToolbar.tsx +1 -1
- package/src/components/annotation-popups/SharedPopupElements.tsx +5 -7
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +3 -4
- package/src/components/modals/ConfigureGenerationStep.tsx +190 -0
- package/src/components/modals/ConfigureSearchStep.tsx +105 -0
- package/src/components/modals/ContextSummary.tsx +183 -0
- package/src/components/modals/GatherContextStep.tsx +89 -0
- package/src/components/modals/KeyboardShortcutsHelpModal.tsx +4 -6
- package/src/components/modals/ProposeEntitiesModal.tsx +4 -6
- package/src/components/modals/ReferenceWizardModal.tsx +326 -0
- package/src/components/modals/ResourceSearchModal.tsx +4 -6
- package/src/components/modals/SearchModal.css +43 -0
- package/src/components/modals/SearchModal.tsx +4 -6
- package/src/components/modals/SearchResultsStep.tsx +126 -0
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +3 -4
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +36 -14
- package/src/components/resource/AnnotateView.tsx +4 -4
- package/src/components/resource/AnnotationHistory.tsx +2 -2
- package/src/components/resource/BrowseView.tsx +4 -4
- package/src/components/resource/ResourceViewer.tsx +5 -8
- package/src/components/resource/__tests__/AnnotationHistory.test.tsx +16 -16
- package/src/components/resource/__tests__/BrowseView.test.tsx +2 -2
- package/src/components/resource/__tests__/HistoryEvent.test.tsx +1 -1
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +1 -1
- package/src/components/resource/panels/AssessmentEntry.tsx +9 -11
- package/src/components/resource/panels/AssessmentPanel.tsx +1 -1
- package/src/components/resource/panels/CommentEntry.tsx +10 -12
- package/src/components/resource/panels/CommentsPanel.tsx +1 -1
- package/src/components/resource/panels/HighlightEntry.tsx +9 -11
- package/src/components/resource/panels/HighlightPanel.tsx +2 -2
- package/src/components/resource/panels/ReferenceEntry.tsx +57 -104
- package/src/components/resource/panels/ReferencesPanel.css +85 -13
- package/src/components/resource/panels/ReferencesPanel.tsx +2 -3
- package/src/components/resource/panels/TagEntry.tsx +9 -11
- package/src/components/resource/panels/TaggingPanel.tsx +1 -1
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/AssistSection.test.tsx +7 -7
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +3 -3
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +2 -2
- package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +64 -101
- package/src/components/resource/panels/__tests__/StatisticsPanel.test.tsx +1 -1
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +7 -7
- package/src/components/viewers/ImageViewer.tsx +3 -6
- package/src/components/viewers/__tests__/ImageViewer.test.tsx +3 -3
- package/src/features/admin-devops/__tests__/AdminDevOpsPage.test.tsx +5 -5
- package/src/features/admin-exchange/__tests__/AdminExchangePage.test.tsx +141 -0
- package/src/features/admin-exchange/__tests__/ExportCard.test.tsx +41 -0
- package/src/features/admin-exchange/__tests__/ImportCard.test.tsx +148 -0
- package/src/features/admin-exchange/__tests__/ImportProgress.test.tsx +106 -0
- package/src/features/admin-exchange/components/AdminExchangePage.tsx +120 -0
- package/src/features/admin-exchange/components/ExportCard.tsx +35 -0
- package/src/features/admin-exchange/components/ImportCard.tsx +188 -0
- package/src/features/admin-exchange/components/ImportProgress.tsx +86 -0
- package/src/features/admin-security/__tests__/AdminSecurityPage.test.tsx +3 -3
- package/src/features/moderate-entity-tags/__tests__/EntityTagsPage.test.tsx +2 -2
- package/src/features/moderate-recent/__tests__/RecentDocumentsPage.test.tsx +4 -4
- package/src/features/moderate-tag-schemas/__tests__/TagSchemasPage.test.tsx +3 -3
- package/src/features/moderation-linked-data/__tests__/LinkedDataPage.test.tsx +117 -0
- package/src/features/moderation-linked-data/components/LinkedDataPage.tsx +121 -0
- package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +5 -5
- package/src/features/resource-compose/components/ResourceComposePage.tsx +56 -1
- package/src/features/resource-discovery/__tests__/ResourceCard.test.tsx +1 -1
- package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +2 -2
- package/src/features/resource-viewer/__tests__/AnnotationCreationPending.test.tsx +14 -14
- package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +12 -11
- package/src/features/resource-viewer/__tests__/AnnotationProgressDismissal.test.tsx +2 -2
- package/src/features/resource-viewer/__tests__/BindFlowIntegration.test.tsx +22 -115
- package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +3 -3
- package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +20 -20
- package/src/features/resource-viewer/__tests__/ResourceMutations.test.tsx +7 -7
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +43 -20
- package/src/features/resource-viewer/__tests__/ToastNotifications.test.tsx +2 -2
- package/src/features/resource-viewer/__tests__/YieldFlowIntegration.test.tsx +45 -82
- package/src/features/resource-viewer/__tests__/annotation-progress-flow.test.tsx +4 -4
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +151 -74
- package/src/integrations/tailwind-plugin.js +3 -3
- package/src/styles/core/buttons.css +31 -0
- package/src/styles/features/exchange.css +404 -0
- package/src/styles/index.css +1 -0
- package/translations/ar.json +42 -4
- package/translations/bn.json +42 -4
- package/translations/cs.json +42 -4
- package/translations/da.json +128 -90
- package/translations/de.json +122 -84
- package/translations/el.json +42 -4
- package/translations/en.json +42 -4
- package/translations/es.json +42 -4
- package/translations/fa.json +42 -4
- package/translations/fi.json +68 -30
- package/translations/fr.json +42 -4
- package/translations/he.json +42 -4
- package/translations/hi.json +42 -4
- package/translations/id.json +43 -5
- package/translations/it.json +62 -24
- package/translations/ja.json +43 -5
- package/translations/ko.json +42 -4
- package/translations/ms.json +43 -5
- package/translations/nl.json +41 -3
- package/translations/no.json +104 -66
- package/translations/pl.json +42 -4
- package/translations/pt.json +43 -5
- package/translations/ro.json +42 -4
- package/translations/sv.json +42 -4
- package/translations/th.json +42 -4
- package/translations/tr.json +42 -4
- package/translations/uk.json +42 -4
- package/translations/vi.json +42 -4
- package/translations/zh.json +42 -4
- package/dist/PdfAnnotationCanvas.client-COQREPXU.mjs.map +0 -1
- package/dist/ar-7SUXNE34.mjs.map +0 -1
- package/dist/bn-XOET3DOI.mjs.map +0 -1
- package/dist/chunk-JH7BXE2P.mjs.map +0 -1
- package/dist/cs-X63DXX7L.mjs.map +0 -1
- package/dist/da-OWTCV57A.mjs.map +0 -1
- package/dist/de-77BMFDVF.mjs.map +0 -1
- package/dist/el-FIBNLH2V.mjs.map +0 -1
- package/dist/es-726NTS53.mjs.map +0 -1
- package/dist/fa-3N4CIWE6.mjs.map +0 -1
- package/dist/fi-JOM3M7Z4.mjs.map +0 -1
- package/dist/fr-56QSXS7E.mjs.map +0 -1
- package/dist/he-SNAXPJEK.mjs.map +0 -1
- package/dist/hi-CRBRD5TB.mjs.map +0 -1
- package/dist/id-BRCVLICF.mjs.map +0 -1
- package/dist/it-M2Z27BNB.mjs.map +0 -1
- package/dist/ja-TZUKW7HD.mjs.map +0 -1
- package/dist/ko-NKBGGOL6.mjs.map +0 -1
- package/dist/ms-XFXPN6RX.mjs.map +0 -1
- package/dist/nl-MVYXAS5C.mjs.map +0 -1
- package/dist/no-XOLO4JPV.mjs.map +0 -1
- package/dist/pl-TRWLMMC4.mjs.map +0 -1
- package/dist/pt-M3TE24UI.mjs.map +0 -1
- package/dist/ro-QBFG2T64.mjs.map +0 -1
- package/dist/sv-IUECBXWX.mjs.map +0 -1
- package/dist/th-US7KIN5Q.mjs.map +0 -1
- package/dist/tr-DWJ2FFUK.mjs.map +0 -1
- package/dist/uk-M4ZE4DPZ.mjs.map +0 -1
- package/dist/zh-3J2I3WYK.mjs.map +0 -1
- package/src/examples/ButtonUsageExample.tsx +0 -242
- package/src/examples/button-css-modules.module.css +0 -164
- package/src/examples/button-styled-components.tsx +0 -215
- package/src/examples/button-tailwind.css +0 -51
- /package/dist/{chunk-Q2KV6Y2J.mjs.map → chunk-7GEYABC6.mjs.map} +0 -0
- /package/dist/{chunk-3JTO27MH.mjs.map → chunk-D4GAAQMM.mjs.map} +0 -0
- /package/dist/{en-XWEPVTB4.mjs.map → en-HAKDCFKL.mjs.map} +0 -0
- /package/dist/{magic-string.es-7FJ3LUGB.mjs.map → magic-string.es-K77I4ZQN.mjs.map} +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import type { Ref } from 'react';
|
|
4
4
|
import type { RouteBuilder } from '../../../contexts/RoutingContext';
|
|
5
5
|
import { useTranslations } from '../../../contexts/TranslationContext';
|
|
6
6
|
import type { components } from '@semiont/core';
|
|
7
|
+
import { annotationId, resourceId } from '@semiont/core';
|
|
7
8
|
import { getAnnotationExactText, isBodyResolved, getBodySource, getFragmentSelector, getSvgSelector, getTargetSelector } from '@semiont/api-client';
|
|
8
9
|
import { getEntityTypes } from '@semiont/ontology';
|
|
9
10
|
import { getResourceIcon } from '../../../lib/resource-utils';
|
|
@@ -26,20 +27,18 @@ interface ReferenceEntryProps {
|
|
|
26
27
|
routes: RouteBuilder;
|
|
27
28
|
annotateMode?: boolean;
|
|
28
29
|
isGenerating?: boolean;
|
|
30
|
+
ref?: Ref<HTMLDivElement>;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
export
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
},
|
|
41
|
-
ref
|
|
42
|
-
) {
|
|
33
|
+
export function ReferenceEntry({
|
|
34
|
+
reference,
|
|
35
|
+
isFocused,
|
|
36
|
+
isHovered = false,
|
|
37
|
+
routes,
|
|
38
|
+
annotateMode = true,
|
|
39
|
+
isGenerating = false,
|
|
40
|
+
ref,
|
|
41
|
+
}: ReferenceEntryProps) {
|
|
43
42
|
const t = useTranslations('ReferencesPanel');
|
|
44
43
|
const eventBus = useEventBus();
|
|
45
44
|
const navigate = useObservableExternalNavigation();
|
|
@@ -64,56 +63,46 @@ export const ReferenceEntry = forwardRef<HTMLDivElement, ReferenceEntryProps>(
|
|
|
64
63
|
|
|
65
64
|
const handleOpen = () => {
|
|
66
65
|
if (resolvedResourceUri) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// Use observable navigation - emits 'browse:external-navigate' event
|
|
70
|
-
navigate(routes.resourceDetail(resourceId), { resourceId });
|
|
71
|
-
}
|
|
66
|
+
// resolvedResourceUri is already a bare resource ID
|
|
67
|
+
navigate(routes.resourceDetail(resolvedResourceUri), { resourceId: resolvedResourceUri });
|
|
72
68
|
}
|
|
73
69
|
};
|
|
74
70
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
title: selectedText,
|
|
79
|
-
entityTypes,
|
|
80
|
-
});
|
|
81
|
-
};
|
|
71
|
+
const source = typeof reference.target === 'object' && 'source' in reference.target
|
|
72
|
+
? reference.target.source
|
|
73
|
+
: '';
|
|
82
74
|
|
|
83
75
|
const handleUnlink = () => {
|
|
84
|
-
|
|
85
|
-
const sourceUri = typeof reference.target === 'object' && 'source' in reference.target
|
|
86
|
-
? reference.target.source
|
|
87
|
-
: '';
|
|
88
|
-
if (sourceUri) {
|
|
76
|
+
if (source) {
|
|
89
77
|
eventBus.get('bind:update-body').next({
|
|
90
|
-
|
|
91
|
-
resourceId:
|
|
92
|
-
operations: [{ op: 'remove' }],
|
|
78
|
+
annotationId: annotationId(reference.id),
|
|
79
|
+
resourceId: resourceId(source),
|
|
80
|
+
operations: [{ op: 'remove' }],
|
|
93
81
|
});
|
|
94
82
|
}
|
|
95
83
|
};
|
|
96
84
|
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
:
|
|
101
|
-
|
|
102
|
-
// Emit request to open generation modal
|
|
103
|
-
eventBus.get('yield:modal-open').next({
|
|
104
|
-
annotationUri: reference.id,
|
|
105
|
-
resourceUri,
|
|
85
|
+
const handleInitiateWizard = () => {
|
|
86
|
+
eventBus.get('bind:initiate').next({
|
|
87
|
+
annotationId: annotationId(reference.id),
|
|
88
|
+
resourceId: resourceId(source),
|
|
106
89
|
defaultTitle: selectedText,
|
|
90
|
+
entityTypes,
|
|
107
91
|
});
|
|
108
92
|
};
|
|
109
93
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
94
|
+
// Status icon click handler depends on state and mode
|
|
95
|
+
const handleIconClick = (e: React.MouseEvent) => {
|
|
96
|
+
e.stopPropagation();
|
|
97
|
+
if (isResolved) {
|
|
98
|
+
handleOpen();
|
|
99
|
+
} else if (annotateMode) {
|
|
100
|
+
handleInitiateWizard();
|
|
101
|
+
}
|
|
115
102
|
};
|
|
116
103
|
|
|
104
|
+
const iconIsClickable = isResolved || annotateMode;
|
|
105
|
+
|
|
117
106
|
return (
|
|
118
107
|
<div
|
|
119
108
|
ref={ref}
|
|
@@ -127,9 +116,26 @@ export const ReferenceEntry = forwardRef<HTMLDivElement, ReferenceEntryProps>(
|
|
|
127
116
|
>
|
|
128
117
|
{/* Status indicator and text quote */}
|
|
129
118
|
<div className="semiont-annotation-entry__header">
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
|
|
119
|
+
<div className="semiont-reference-icon-group">
|
|
120
|
+
<button
|
|
121
|
+
className={`semiont-reference-icon${iconIsClickable ? ' semiont-reference-icon--clickable' : ''}`}
|
|
122
|
+
title={isResolved ? t('open') : annotateMode ? t('resolve') : t('stub')}
|
|
123
|
+
onClick={iconIsClickable ? handleIconClick : undefined}
|
|
124
|
+
data-generating={!isResolved && isGenerating ? 'true' : 'false'}
|
|
125
|
+
tabIndex={iconIsClickable ? 0 : -1}
|
|
126
|
+
>
|
|
127
|
+
{isResolved ? '🔗' : '❓'}
|
|
128
|
+
</button>
|
|
129
|
+
{annotateMode && isResolved && (
|
|
130
|
+
<button
|
|
131
|
+
className="semiont-reference-unlink"
|
|
132
|
+
title={t('unlink')}
|
|
133
|
+
onClick={(e) => { e.stopPropagation(); handleUnlink(); }}
|
|
134
|
+
>
|
|
135
|
+
⛓️💥
|
|
136
|
+
</button>
|
|
137
|
+
)}
|
|
138
|
+
</div>
|
|
133
139
|
<div className="semiont-annotation-entry__content">
|
|
134
140
|
{selectedText && (
|
|
135
141
|
<div className="semiont-annotation-entry__quote" data-type="reference">
|
|
@@ -163,59 +169,6 @@ export const ReferenceEntry = forwardRef<HTMLDivElement, ReferenceEntryProps>(
|
|
|
163
169
|
))}
|
|
164
170
|
</div>
|
|
165
171
|
)}
|
|
166
|
-
|
|
167
|
-
{/* Actions based on state - only show curation actions in Annotate mode */}
|
|
168
|
-
<div className="semiont-annotation-entry__actions" onClick={(e) => e.stopPropagation()}>
|
|
169
|
-
{isResolved ? (
|
|
170
|
-
// Resolved reference actions
|
|
171
|
-
<div className="semiont-annotation-entry__action-row">
|
|
172
|
-
<button
|
|
173
|
-
onClick={handleOpen}
|
|
174
|
-
className={`semiont-reference-button semiont-reference-button--primary ${annotateMode ? 'semiont-reference-button--full' : 'semiont-reference-button--wide'}`}
|
|
175
|
-
title={t('open')}
|
|
176
|
-
>
|
|
177
|
-
🔗
|
|
178
|
-
</button>
|
|
179
|
-
{annotateMode && (
|
|
180
|
-
<button
|
|
181
|
-
onClick={handleUnlink}
|
|
182
|
-
className="semiont-reference-button semiont-reference-button--primary"
|
|
183
|
-
title={t('unlink')}
|
|
184
|
-
>
|
|
185
|
-
⛓️💥
|
|
186
|
-
</button>
|
|
187
|
-
)}
|
|
188
|
-
</div>
|
|
189
|
-
) : (
|
|
190
|
-
// Stub reference actions - only in Annotate mode
|
|
191
|
-
annotateMode && (
|
|
192
|
-
<div className="semiont-annotation-entry__action-row">
|
|
193
|
-
<button
|
|
194
|
-
onClick={handleGenerate}
|
|
195
|
-
className="semiont-reference-button semiont-reference-button--primary semiont-reference-button--full"
|
|
196
|
-
title={t('generate')}
|
|
197
|
-
data-generating={isGenerating ? 'true' : 'false'}
|
|
198
|
-
>
|
|
199
|
-
✨
|
|
200
|
-
</button>
|
|
201
|
-
<button
|
|
202
|
-
onClick={handleSearch}
|
|
203
|
-
className="semiont-reference-button semiont-reference-button--primary semiont-reference-button--full"
|
|
204
|
-
title={t('find')}
|
|
205
|
-
>
|
|
206
|
-
🔍
|
|
207
|
-
</button>
|
|
208
|
-
<button
|
|
209
|
-
onClick={handleComposeDocument}
|
|
210
|
-
className="semiont-reference-button semiont-reference-button--primary semiont-reference-button--full"
|
|
211
|
-
title={t('create')}
|
|
212
|
-
>
|
|
213
|
-
✏️
|
|
214
|
-
</button>
|
|
215
|
-
</div>
|
|
216
|
-
)
|
|
217
|
-
)}
|
|
218
|
-
</div>
|
|
219
172
|
</div>
|
|
220
173
|
);
|
|
221
|
-
}
|
|
174
|
+
}
|
|
@@ -61,25 +61,97 @@
|
|
|
61
61
|
color: var(--semiont-text-tertiary);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
/* Reference
|
|
65
|
-
.semiont-reference-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
/* Reference Icon Group — status icon + hover-reveal unlink */
|
|
65
|
+
.semiont-reference-icon-group {
|
|
66
|
+
position: relative;
|
|
67
|
+
display: inline-flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
flex-shrink: 0;
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
.semiont-reference-
|
|
72
|
-
display: flex;
|
|
72
|
+
.semiont-reference-icon {
|
|
73
|
+
display: inline-flex;
|
|
73
74
|
align-items: center;
|
|
74
75
|
justify-content: center;
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
width: 1.75rem;
|
|
77
|
+
height: 1.75rem;
|
|
78
|
+
font-size: 0.875rem;
|
|
79
|
+
line-height: 1;
|
|
80
|
+
border-radius: var(--semiont-radius-md);
|
|
81
|
+
border: 1px solid var(--semiont-color-gray-300);
|
|
82
|
+
background: var(--semiont-bg-secondary);
|
|
83
|
+
color: var(--semiont-text-secondary);
|
|
84
|
+
transition: all 0.15s ease;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
[data-theme="dark"] .semiont-reference-icon {
|
|
88
|
+
border-color: var(--semiont-color-gray-600);
|
|
89
|
+
background: var(--semiont-color-gray-700);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.semiont-reference-icon--clickable {
|
|
93
|
+
cursor: pointer;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.semiont-reference-icon--clickable:hover {
|
|
97
|
+
background: var(--semiont-gradient-primary);
|
|
98
|
+
border-color: var(--semiont-color-primary-300);
|
|
99
|
+
transform: scale(1.1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
[data-theme="dark"] .semiont-reference-icon--clickable:hover {
|
|
103
|
+
background: var(--semiont-gradient-primary-dark);
|
|
104
|
+
border-color: var(--semiont-color-primary-500);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.semiont-reference-icon--clickable:focus-visible {
|
|
108
|
+
outline: 2px solid var(--semiont-color-primary-500);
|
|
109
|
+
outline-offset: 2px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
[data-theme="dark"] .semiont-reference-icon--clickable:focus-visible {
|
|
113
|
+
outline-color: var(--semiont-color-primary-400);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Generating state pulse on stub icon */
|
|
117
|
+
.semiont-reference-icon[data-generating="true"] {
|
|
118
|
+
animation: semiont-icon-pulse 1.5s ease-in-out infinite;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@keyframes semiont-icon-pulse {
|
|
122
|
+
0%, 100% { transform: scale(1); }
|
|
123
|
+
50% { transform: scale(1.2); }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* Hover-reveal unlink button */
|
|
127
|
+
.semiont-reference-unlink {
|
|
128
|
+
position: absolute;
|
|
129
|
+
right: -1.25rem;
|
|
130
|
+
top: 50%;
|
|
131
|
+
transform: translateY(-50%);
|
|
132
|
+
background: none;
|
|
133
|
+
border: none;
|
|
134
|
+
padding: 0;
|
|
135
|
+
font-size: 0.75rem;
|
|
136
|
+
cursor: pointer;
|
|
137
|
+
opacity: 0;
|
|
138
|
+
pointer-events: none;
|
|
139
|
+
transition: opacity 0.15s ease;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.semiont-annotation-entry:hover .semiont-reference-unlink {
|
|
143
|
+
opacity: 1;
|
|
144
|
+
pointer-events: auto;
|
|
77
145
|
}
|
|
78
146
|
|
|
79
|
-
.semiont-reference-
|
|
80
|
-
|
|
147
|
+
.semiont-reference-unlink:hover {
|
|
148
|
+
transform: translateY(-50%) scale(1.2);
|
|
81
149
|
}
|
|
82
150
|
|
|
83
|
-
.semiont-reference-
|
|
84
|
-
|
|
151
|
+
.semiont-reference-unlink:focus-visible {
|
|
152
|
+
opacity: 1;
|
|
153
|
+
pointer-events: auto;
|
|
154
|
+
outline: 2px solid var(--semiont-color-primary-500);
|
|
155
|
+
outline-offset: 2px;
|
|
156
|
+
border-radius: 2px;
|
|
85
157
|
}
|
|
@@ -245,7 +245,7 @@ export function ReferencesPanel({
|
|
|
245
245
|
const handleCreateReference = () => {
|
|
246
246
|
if (pendingAnnotation) {
|
|
247
247
|
const entityType = pendingEntityTypes.join(',') || undefined;
|
|
248
|
-
eventBus.get('mark:
|
|
248
|
+
eventBus.get('mark:submit').next({
|
|
249
249
|
motivation: 'linking',
|
|
250
250
|
selector: pendingAnnotation.selector,
|
|
251
251
|
body: entityType ? [{ type: 'TextualBody', value: entityType, purpose: 'tagging' }] : [],
|
|
@@ -497,8 +497,7 @@ export function ReferencesPanel({
|
|
|
497
497
|
{referencedBy.length > 0 ? (
|
|
498
498
|
<div className="semiont-panel__list">
|
|
499
499
|
{referencedBy.map((ref) => {
|
|
500
|
-
|
|
501
|
-
const resourceId = ref.target.source.split('/').pop() || '';
|
|
500
|
+
const resourceId = ref.target.source;
|
|
502
501
|
|
|
503
502
|
return (
|
|
504
503
|
<div key={ref.id} className="semiont-reference-item semiont-reference-item--incoming">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import type { Ref } from 'react';
|
|
4
4
|
import type { components } from '@semiont/core';
|
|
5
5
|
import { getAnnotationExactText } from '@semiont/api-client';
|
|
6
6
|
import { getTagCategory, getTagSchemaId } from '@semiont/ontology';
|
|
@@ -14,17 +14,15 @@ interface TagEntryProps {
|
|
|
14
14
|
tag: Annotation;
|
|
15
15
|
isFocused: boolean;
|
|
16
16
|
isHovered?: boolean;
|
|
17
|
+
ref?: Ref<HTMLDivElement>;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
},
|
|
26
|
-
ref
|
|
27
|
-
) {
|
|
20
|
+
export function TagEntry({
|
|
21
|
+
tag,
|
|
22
|
+
isFocused,
|
|
23
|
+
isHovered = false,
|
|
24
|
+
ref,
|
|
25
|
+
}: TagEntryProps) {
|
|
28
26
|
const eventBus = useEventBus();
|
|
29
27
|
const hoverProps = useHoverEmitter(tag.id);
|
|
30
28
|
|
|
@@ -62,4 +60,4 @@ export const TagEntry = forwardRef<HTMLDivElement, TagEntryProps>(
|
|
|
62
60
|
</div>
|
|
63
61
|
</div>
|
|
64
62
|
);
|
|
65
|
-
}
|
|
63
|
+
}
|
|
@@ -274,7 +274,7 @@ export function TaggingPanel({
|
|
|
274
274
|
className="semiont-select"
|
|
275
275
|
onChange={(e) => {
|
|
276
276
|
if (e.target.value && pendingAnnotation) {
|
|
277
|
-
eventBus.get('mark:
|
|
277
|
+
eventBus.get('mark:submit').next({
|
|
278
278
|
motivation: 'tagging',
|
|
279
279
|
selector: pendingAnnotation.selector,
|
|
280
280
|
body: [
|
|
@@ -29,7 +29,7 @@ function createEventTracker() {
|
|
|
29
29
|
events.push({ event: eventName, payload });
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
const panelEvents = ['mark:
|
|
32
|
+
const panelEvents = ['mark:submit'] as const;
|
|
33
33
|
|
|
34
34
|
panelEvents.forEach(eventName => {
|
|
35
35
|
const handler = trackEvent(eventName);
|
|
@@ -359,7 +359,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
359
359
|
expect(textarea).toHaveFocus();
|
|
360
360
|
});
|
|
361
361
|
|
|
362
|
-
it('should emit mark:
|
|
362
|
+
it('should emit mark:submitevent when save is clicked', async () => {
|
|
363
363
|
const tracker = createEventTracker();
|
|
364
364
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
365
365
|
|
|
@@ -379,7 +379,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
379
379
|
|
|
380
380
|
await waitFor(() => {
|
|
381
381
|
expect(tracker.events.some(e =>
|
|
382
|
-
e.event === 'mark:
|
|
382
|
+
e.event === 'mark:submit' &&
|
|
383
383
|
e.payload?.motivation === 'assessing' &&
|
|
384
384
|
e.payload?.body?.[0]?.value === 'My assessment'
|
|
385
385
|
)).toBe(true);
|
|
@@ -420,7 +420,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
420
420
|
|
|
421
421
|
await waitFor(() => {
|
|
422
422
|
expect(tracker.events.some(e =>
|
|
423
|
-
e.event === 'mark:
|
|
423
|
+
e.event === 'mark:submit' &&
|
|
424
424
|
e.payload?.motivation === 'assessing' &&
|
|
425
425
|
Array.isArray(e.payload?.body) &&
|
|
426
426
|
e.payload.body.length === 0
|
|
@@ -135,7 +135,7 @@ describe('AssistSection', () => {
|
|
|
135
135
|
|
|
136
136
|
// Form should not be visible
|
|
137
137
|
expect(screen.queryByPlaceholderText('Enter custom instructions...')).not.toBeInTheDocument();
|
|
138
|
-
expect(screen.queryByRole('button', { name:
|
|
138
|
+
expect(screen.queryByRole('button', { name: /✨\s*Annotate/ })).not.toBeInTheDocument();
|
|
139
139
|
});
|
|
140
140
|
|
|
141
141
|
it('should show form when progress is null', () => {
|
|
@@ -149,7 +149,7 @@ describe('AssistSection', () => {
|
|
|
149
149
|
|
|
150
150
|
// Form should be visible
|
|
151
151
|
expect(screen.getByPlaceholderText('Enter custom instructions...')).toBeInTheDocument();
|
|
152
|
-
expect(screen.getByRole('button', { name:
|
|
152
|
+
expect(screen.getByRole('button', { name: /✨\s*Annotate/ })).toBeInTheDocument();
|
|
153
153
|
});
|
|
154
154
|
|
|
155
155
|
it('should show form when progress is undefined', () => {
|
|
@@ -163,7 +163,7 @@ describe('AssistSection', () => {
|
|
|
163
163
|
|
|
164
164
|
// Form should be visible
|
|
165
165
|
expect(screen.getByPlaceholderText('Enter custom instructions...')).toBeInTheDocument();
|
|
166
|
-
expect(screen.getByRole('button', { name:
|
|
166
|
+
expect(screen.getByRole('button', { name: /✨\s*Annotate/ })).toBeInTheDocument();
|
|
167
167
|
});
|
|
168
168
|
|
|
169
169
|
it('should keep progress visible after detection completes (isAssisting=false but progress exists)', () => {
|
|
@@ -279,7 +279,7 @@ describe('AssistSection', () => {
|
|
|
279
279
|
|
|
280
280
|
const subscription = eventBus!.get('mark:assist-request').subscribe(detectionHandler);
|
|
281
281
|
|
|
282
|
-
const annotateButton = screen.getByRole('button', { name:
|
|
282
|
+
const annotateButton = screen.getByRole('button', { name: /✨\s*Annotate/ });
|
|
283
283
|
await user.click(annotateButton);
|
|
284
284
|
|
|
285
285
|
expect(detectionHandler).toHaveBeenCalledWith({
|
|
@@ -305,7 +305,7 @@ describe('AssistSection', () => {
|
|
|
305
305
|
|
|
306
306
|
const subscription = eventBus!.get('mark:assist-request').subscribe(detectionHandler);
|
|
307
307
|
|
|
308
|
-
const annotateButton = screen.getByRole('button', { name:
|
|
308
|
+
const annotateButton = screen.getByRole('button', { name: /✨\s*Annotate/ });
|
|
309
309
|
await user.click(annotateButton);
|
|
310
310
|
|
|
311
311
|
expect(detectionHandler).toHaveBeenCalledWith({
|
|
@@ -331,7 +331,7 @@ describe('AssistSection', () => {
|
|
|
331
331
|
|
|
332
332
|
const subscription = eventBus!.get('mark:assist-request').subscribe(detectionHandler);
|
|
333
333
|
|
|
334
|
-
const annotateButton = screen.getByRole('button', { name:
|
|
334
|
+
const annotateButton = screen.getByRole('button', { name: /✨\s*Annotate/ });
|
|
335
335
|
await user.click(annotateButton);
|
|
336
336
|
|
|
337
337
|
expect(detectionHandler).toHaveBeenCalledWith({
|
|
@@ -360,7 +360,7 @@ describe('AssistSection', () => {
|
|
|
360
360
|
const textarea = screen.getByPlaceholderText('Enter custom instructions...');
|
|
361
361
|
await user.type(textarea, 'Find key concepts');
|
|
362
362
|
|
|
363
|
-
const annotateButton = screen.getByRole('button', { name:
|
|
363
|
+
const annotateButton = screen.getByRole('button', { name: /✨\s*Annotate/ });
|
|
364
364
|
await user.click(annotateButton);
|
|
365
365
|
|
|
366
366
|
expect(detectionHandler).toHaveBeenCalledWith({
|
|
@@ -29,7 +29,7 @@ function createEventTracker() {
|
|
|
29
29
|
events.push({ event: eventName, payload });
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
const panelEvents = ['mark:
|
|
32
|
+
const panelEvents = ['mark:submit'] as const;
|
|
33
33
|
|
|
34
34
|
panelEvents.forEach(eventName => {
|
|
35
35
|
const handler = trackEvent(eventName);
|
|
@@ -396,7 +396,7 @@ describe('CommentsPanel Component', () => {
|
|
|
396
396
|
expect(textarea).toHaveFocus();
|
|
397
397
|
});
|
|
398
398
|
|
|
399
|
-
it('should emit mark:
|
|
399
|
+
it('should emit mark:submitevent when save is clicked', async () => {
|
|
400
400
|
const tracker = createEventTracker();
|
|
401
401
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
402
402
|
|
|
@@ -416,7 +416,7 @@ describe('CommentsPanel Component', () => {
|
|
|
416
416
|
|
|
417
417
|
await waitFor(() => {
|
|
418
418
|
expect(tracker.events.some(e =>
|
|
419
|
-
e.event === 'mark:
|
|
419
|
+
e.event === 'mark:submit' &&
|
|
420
420
|
e.payload?.motivation === 'commenting' &&
|
|
421
421
|
e.payload?.body?.[0]?.value === 'My new comment'
|
|
422
422
|
)).toBe(true);
|
|
@@ -106,7 +106,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
106
106
|
|
|
107
107
|
// Form should be visible (meaning progress was null)
|
|
108
108
|
expect(screen.getByPlaceholderText('Enter custom instructions...')).toBeInTheDocument();
|
|
109
|
-
expect(screen.getByRole('button', { name:
|
|
109
|
+
expect(screen.getByRole('button', { name: /✨\s*Annotate/ })).toBeInTheDocument();
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
it('should pass undefined progress to AssistSection', () => {
|
|
@@ -122,7 +122,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
122
122
|
|
|
123
123
|
// Form should be visible (meaning progress was undefined)
|
|
124
124
|
expect(screen.getByPlaceholderText('Enter custom instructions...')).toBeInTheDocument();
|
|
125
|
-
expect(screen.getByRole('button', { name:
|
|
125
|
+
expect(screen.getByRole('button', { name: /✨\s*Annotate/ })).toBeInTheDocument();
|
|
126
126
|
});
|
|
127
127
|
|
|
128
128
|
it('should keep progress visible after detection completes (isAssisting=false)', () => {
|