@vertesia/ui 1.4.0-dev.20260629.130134Z → 1.4.1
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/lib/core/components/SidePanel.js +1 -1
- package/lib/core/components/SidePanel.js.map +1 -1
- package/lib/core/components/shadcn/button.d.ts +10 -3
- package/lib/core/components/shadcn/button.d.ts.map +1 -1
- package/lib/core/components/shadcn/button.js +41 -9
- package/lib/core/components/shadcn/button.js.map +1 -1
- package/lib/core/components/shadcn/modal/dialog.js +1 -1
- package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
- package/lib/core/components/shadcn/resizeable.d.ts +1 -1
- package/lib/core/components/shadcn/resizeable.d.ts.map +1 -1
- package/lib/core/components/shadcn/resizeable.js +12 -2
- package/lib/core/components/shadcn/resizeable.js.map +1 -1
- package/lib/core/components/shadcn/tabs.d.ts +12 -1
- package/lib/core/components/shadcn/tabs.d.ts.map +1 -1
- package/lib/core/components/shadcn/tabs.js +12 -4
- package/lib/core/components/shadcn/tabs.js.map +1 -1
- package/lib/core/components/shadcn/theme/ThemeSwitcher.js +1 -1
- package/lib/core/components/shadcn/theme/ThemeSwitcher.js.map +1 -1
- package/lib/core/hooks/useIntersectionObserver.d.ts.map +1 -1
- package/lib/core/hooks/useIntersectionObserver.js +3 -1
- package/lib/core/hooks/useIntersectionObserver.js.map +1 -1
- package/lib/features/agent/chat/AgentChatPlaybackControls.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentChatPlaybackControls.js +2 -2
- package/lib/features/agent/chat/AgentChatPlaybackControls.js.map +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts.map +1 -1
- package/lib/features/agent/chat/AgentRequestInputOverlay.js +2 -2
- package/lib/features/agent/chat/AgentRequestInputOverlay.js.map +1 -1
- package/lib/features/agent/chat/AgentRightPanel.js +1 -1
- package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
- package/lib/features/agent/chat/AskUserWidget.js +4 -3
- package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
- package/lib/features/agent/chat/ImageLightbox.d.ts.map +1 -1
- package/lib/features/agent/chat/ImageLightbox.js +1 -1
- package/lib/features/agent/chat/ImageLightbox.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentConversation.js +57 -12
- package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +8 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +45 -36
- package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/Header.js +4 -2
- package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +7 -3
- package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +2 -1
- package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js +158 -8
- package/lib/features/agent/chat/ModernAgentOutput/WorkstreamTabs.js.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts +6 -0
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +15 -1
- package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js.map +1 -1
- package/lib/features/agent/chat/hooks/useFileProcessing.d.ts +1 -0
- package/lib/features/agent/chat/hooks/useFileProcessing.d.ts.map +1 -1
- package/lib/features/agent/chat/hooks/useFileProcessing.js +37 -3
- package/lib/features/agent/chat/hooks/useFileProcessing.js.map +1 -1
- package/lib/features/magic-pdf/AnnotatedImageSlider.js +13 -13
- package/lib/features/magic-pdf/AnnotatedImageSlider.js.map +1 -1
- package/lib/features/magic-pdf/DownloadPopover.js +2 -2
- package/lib/features/magic-pdf/DownloadPopover.js.map +1 -1
- package/lib/features/magic-pdf/MagicPdfView.js +3 -3
- package/lib/features/magic-pdf/MagicPdfView.js.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -1
- package/lib/features/oauth/McpConnectionsButton.js +2 -2
- package/lib/features/oauth/McpConnectionsButton.js.map +1 -1
- package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -1
- package/lib/features/oauth/McpConnectionsDialog.js +1 -1
- package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
- package/lib/features/oauth/RemoteMcpConnectionButton.d.ts.map +1 -1
- package/lib/features/oauth/RemoteMcpConnectionButton.js +1 -1
- package/lib/features/oauth/RemoteMcpConnectionButton.js.map +1 -1
- package/lib/features/pdf-viewer/PdfPageSlider.js +2 -2
- package/lib/features/pdf-viewer/PdfPageSlider.js.map +1 -1
- package/lib/features/pdf-viewer/SimplePdfViewer.d.ts.map +1 -1
- package/lib/features/pdf-viewer/SimplePdfViewer.js +3 -3
- package/lib/features/pdf-viewer/SimplePdfViewer.js.map +1 -1
- package/lib/features/store/objects/DocumentQuickFilter.d.ts.map +1 -1
- package/lib/features/store/objects/DocumentQuickFilter.js +5 -5
- package/lib/features/store/objects/DocumentQuickFilter.js.map +1 -1
- package/lib/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
- package/lib/features/store/objects/DocumentSearchResults.js +2 -2
- package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
- package/lib/features/store/objects/components/ContentDispositionButton.d.ts.map +1 -1
- package/lib/features/store/objects/components/ContentDispositionButton.js +1 -1
- package/lib/features/store/objects/components/ContentDispositionButton.js.map +1 -1
- package/lib/features/store/objects/components/ContentOverview.js +3 -3
- package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
- package/lib/features/store/objects/components/DocumentIcon.js +1 -1
- package/lib/features/store/objects/components/VectorSearchWidget.js +1 -1
- package/lib/features/store/objects/components/VectorSearchWidget.js.map +1 -1
- package/lib/features/store/objects/layout/renderers.d.ts.map +1 -1
- package/lib/features/store/objects/layout/renderers.js +2 -2
- package/lib/features/store/objects/layout/renderers.js.map +1 -1
- package/lib/features/store/objects/selection/SelectionActions.js +1 -1
- package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
- package/lib/features/store/objects/selection/actions/StartWorkflowComponent.js +4 -4
- package/lib/features/store/objects/selection/actions/StartWorkflowComponent.js.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.d.ts.map +1 -1
- package/lib/features/store/types/ContentObjectTypesTable.js +4 -4
- package/lib/features/store/types/ContentObjectTypesTable.js.map +1 -1
- package/lib/features/store/types/SelectContentTypeModal.js +1 -1
- package/lib/features/store/types/SelectContentTypeModal.js.map +1 -1
- package/lib/features/user/UserInfo.js +7 -3
- package/lib/features/user/UserInfo.js.map +1 -1
- package/lib/router/HistoryNavigator.d.ts.map +1 -1
- package/lib/router/HistoryNavigator.js +5 -0
- package/lib/router/HistoryNavigator.js.map +1 -1
- package/lib/router/Nav.d.ts.map +1 -1
- package/lib/router/Nav.js +9 -1
- package/lib/router/Nav.js.map +1 -1
- package/lib/vertesia-ui-core.js +1 -1
- package/lib/vertesia-ui-core.js.map +1 -1
- package/lib/vertesia-ui-features.js +1 -1
- package/lib/vertesia-ui-features.js.map +1 -1
- package/lib/vertesia-ui-router.js +1 -1
- package/lib/vertesia-ui-router.js.map +1 -1
- package/lib/vertesia-ui-widgets.js +1 -1
- package/lib/vertesia-ui-widgets.js.map +1 -1
- package/lib/widgets/form/Form.js +1 -1
- package/lib/widgets/form/Form.js.map +1 -1
- package/lib/widgets/json-view/JSONSwitcher.js +1 -1
- package/lib/widgets/json-view/JSONSwitcher.js.map +1 -1
- package/lib/widgets/json-view/JSONView.js +6 -6
- package/lib/widgets/json-view/JSONView.js.map +1 -1
- package/lib/widgets/monacoEditor/MonacoEditor.d.ts.map +1 -1
- package/lib/widgets/monacoEditor/MonacoEditor.js +29 -0
- package/lib/widgets/monacoEditor/MonacoEditor.js.map +1 -1
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts +9 -0
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts.map +1 -1
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.js +20 -17
- package/lib/widgets/xml-viewer/hooks/useXMLViewer.js.map +1 -1
- package/package.json +29 -30
- package/src/__tests__/a11y.test.tsx +73 -0
- package/src/core/components/SidePanel.tsx +1 -1
- package/src/core/components/shadcn/button.tsx +67 -12
- package/src/core/components/shadcn/modal/dialog.tsx +1 -1
- package/src/core/components/shadcn/resizeable.test.tsx +77 -0
- package/src/core/components/shadcn/resizeable.tsx +28 -2
- package/src/core/components/shadcn/tabs.test.tsx +65 -0
- package/src/core/components/shadcn/tabs.tsx +25 -3
- package/src/core/components/shadcn/theme/ThemeSwitcher.tsx +1 -1
- package/src/core/hooks/useIntersectionObserver.tsx +3 -1
- package/src/features/agent/chat/AgentChatPlaybackControls.tsx +0 -5
- package/src/features/agent/chat/AgentRequestInputOverlay.test.tsx +31 -0
- package/src/features/agent/chat/AgentRequestInputOverlay.tsx +6 -2
- package/src/features/agent/chat/AgentRightPanel.tsx +1 -1
- package/src/features/agent/chat/AskUserWidget.test.tsx +49 -0
- package/src/features/agent/chat/AskUserWidget.tsx +32 -22
- package/src/features/agent/chat/ImageLightbox.tsx +0 -1
- package/src/features/agent/chat/ModernAgentConversation.test.tsx +246 -1
- package/src/features/agent/chat/ModernAgentConversation.tsx +62 -17
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +6 -1
- package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +81 -49
- package/src/features/agent/chat/ModernAgentOutput/Header.tsx +3 -3
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.test.tsx +25 -0
- package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +5 -3
- package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +4 -1
- package/src/features/agent/chat/ModernAgentOutput/WorkstreamTabs.tsx +328 -42
- package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.test.ts +80 -0
- package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +21 -1
- package/src/features/agent/chat/hooks/useFileProcessing.test.tsx +70 -0
- package/src/features/agent/chat/hooks/useFileProcessing.ts +37 -6
- package/src/features/magic-pdf/AnnotatedImageSlider.tsx +62 -66
- package/src/features/magic-pdf/DownloadPopover.tsx +2 -2
- package/src/features/magic-pdf/MagicPdfView.tsx +3 -3
- package/src/features/oauth/McpConnectionsButton.tsx +0 -2
- package/src/features/oauth/McpConnectionsDialog.tsx +0 -1
- package/src/features/oauth/RemoteMcpConnectionButton.tsx +0 -1
- package/src/features/pdf-viewer/PdfPageSlider.tsx +5 -5
- package/src/features/pdf-viewer/SimplePdfViewer.tsx +11 -12
- package/src/features/store/objects/DocumentQuickFilter.tsx +13 -15
- package/src/features/store/objects/DocumentSearchResults.tsx +3 -6
- package/src/features/store/objects/components/ContentDispositionButton.tsx +5 -1
- package/src/features/store/objects/components/ContentOverview.tsx +11 -11
- package/src/features/store/objects/components/DocumentIcon.tsx +1 -1
- package/src/features/store/objects/components/VectorSearchWidget.tsx +2 -2
- package/src/features/store/objects/layout/renderers.tsx +1 -2
- package/src/features/store/objects/selection/SelectionActions.tsx +1 -1
- package/src/features/store/objects/selection/actions/StartWorkflowComponent.tsx +6 -5
- package/src/features/store/types/ContentObjectTypesTable.tsx +12 -14
- package/src/features/store/types/SelectContentTypeModal.tsx +2 -2
- package/src/features/user/UserInfo.tsx +7 -7
- package/src/router/HistoryNavigator.ts +5 -0
- package/src/router/Nav.tsx +12 -3
- package/src/widgets/form/Form.tsx +1 -1
- package/src/widgets/json-view/JSONSwitcher.tsx +2 -2
- package/src/widgets/json-view/JSONView.tsx +7 -7
- package/src/widgets/monacoEditor/MonacoEditor.tsx +29 -0
- package/src/widgets/xml-viewer/hooks/useXMLViewer.test.ts +26 -0
- package/src/widgets/xml-viewer/hooks/useXMLViewer.ts +23 -18
|
@@ -110,10 +110,10 @@ export function SelectContentTypeModal({
|
|
|
110
110
|
)}
|
|
111
111
|
</ModalBody>
|
|
112
112
|
<ModalFooter>
|
|
113
|
-
<Button variant="ghost" onClick={handleClose}
|
|
113
|
+
<Button variant="ghost" onClick={handleClose} title={t('modal.cancel')}>
|
|
114
114
|
{t('modal.cancel')}
|
|
115
115
|
</Button>
|
|
116
|
-
<Button onClick={handleConfirm}
|
|
116
|
+
<Button onClick={handleConfirm} title={t('store.confirmSelection')}>
|
|
117
117
|
{t('modal.confirm')}
|
|
118
118
|
</Button>
|
|
119
119
|
</ModalFooter>
|
|
@@ -140,7 +140,7 @@ function EmailAgentAvatar({ email, showTitle = false, size = 'md' }: EmailAgentA
|
|
|
140
140
|
|
|
141
141
|
const description = (
|
|
142
142
|
<>
|
|
143
|
-
<div>{t('user.
|
|
143
|
+
<div>{t('user.agentOnBehalfOf')}</div>
|
|
144
144
|
<div className="text-muted text-sm">
|
|
145
145
|
<span className="font-semibold">Email:</span> {email}
|
|
146
146
|
</div>
|
|
@@ -158,11 +158,7 @@ function EmailAgentAvatar({ email, showTitle = false, size = 'md' }: EmailAgentA
|
|
|
158
158
|
/>
|
|
159
159
|
<Avatar name={email} size={size} className="border-2 border-white dark:border-gray-800" />
|
|
160
160
|
</div>
|
|
161
|
-
{showTitle && (
|
|
162
|
-
<div className="text-sm font-semibold truncate">
|
|
163
|
-
{t('user.agentOnBehalfOf')} : {email}
|
|
164
|
-
</div>
|
|
165
|
-
)}
|
|
161
|
+
{showTitle && <div className="text-sm font-semibold truncate">Agent ({email})</div>}
|
|
166
162
|
</div>
|
|
167
163
|
</UserPopoverPanel>
|
|
168
164
|
);
|
|
@@ -260,7 +256,11 @@ function AgentAvatar({
|
|
|
260
256
|
</div>
|
|
261
257
|
{showTitle && (
|
|
262
258
|
<div className="text-sm font-semibold truncate">
|
|
263
|
-
{user
|
|
259
|
+
{user
|
|
260
|
+
? `Agent${'\u2003'}(${user.name || user.email})`
|
|
261
|
+
: apiKey
|
|
262
|
+
? `Agent (${apiKey.name})`
|
|
263
|
+
: title}
|
|
264
264
|
</div>
|
|
265
265
|
)}
|
|
266
266
|
</div>
|
|
@@ -233,6 +233,11 @@ export class HistoryNavigator {
|
|
|
233
233
|
this.fireLocationChange(new AfterLocationChangeEvent(type, to, state));
|
|
234
234
|
};
|
|
235
235
|
const _linkNavListener = (ev: MouseEvent) => {
|
|
236
|
+
// Let the browser handle modifier / non-primary clicks natively (open in new tab/window,
|
|
237
|
+
// download). Intercepting them here would preventDefault those affordances.
|
|
238
|
+
if (ev.defaultPrevented || ev.metaKey || ev.altKey || ev.ctrlKey || ev.shiftKey || ev.button !== 0) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
236
241
|
const target = ev.target as HTMLElement;
|
|
237
242
|
// Skip anchors with download attribute or blob: URLs - they are file downloads, not navigation
|
|
238
243
|
if (
|
package/src/router/Nav.tsx
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import type { SyntheticEvent } from 'react';
|
|
1
|
+
import type { MouseEvent, SyntheticEvent } from 'react';
|
|
2
2
|
import { useNavigate, useRouterContext } from './Router';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* True when the click carries a modifier the browser uses for alternate link behavior
|
|
6
|
+
* (open in new tab/window, download) or is not a primary-button click. Such clicks must fall
|
|
7
|
+
* through to the native anchor so the browser can handle them instead of the SPA router.
|
|
8
|
+
*/
|
|
9
|
+
function isModifiedClick(ev: MouseEvent): boolean {
|
|
10
|
+
return ev.metaKey || ev.altKey || ev.ctrlKey || ev.shiftKey || ev.button !== 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
4
13
|
/**
|
|
5
14
|
* Wraps a <a href="..."> and perform the navigation to href through the router.
|
|
6
15
|
*/
|
|
@@ -76,8 +85,8 @@ export function NavLink({
|
|
|
76
85
|
const isExternal = /^[a-z][a-z0-9+.-]*:/i.test(href) || href.startsWith('//') || (!!target && target !== '_self');
|
|
77
86
|
const isInternal = !isAnchorOrEmpty && !isExternal;
|
|
78
87
|
const resolvedHref = !skipStickyParams && isInternal ? router.getTopRouter().navigator.addStickyParams(href) : href;
|
|
79
|
-
const _onClick = (ev:
|
|
80
|
-
if (ev.defaultPrevented || !isInternal) {
|
|
88
|
+
const _onClick = (ev: MouseEvent) => {
|
|
89
|
+
if (ev.defaultPrevented || !isInternal || isModifiedClick(ev)) {
|
|
81
90
|
return;
|
|
82
91
|
}
|
|
83
92
|
ev.stopPropagation();
|
|
@@ -184,7 +184,7 @@ function ListItem({ list, object, onDelete, disabled }: ListItemProps) {
|
|
|
184
184
|
return (
|
|
185
185
|
<div className="flex gap-2 w-full">
|
|
186
186
|
<div className="flex-1">{renderItemProperty(object, editor)}</div>
|
|
187
|
-
<Button variant="ghost" onClick={onDelete} disabled={disabled}
|
|
187
|
+
<Button variant="ghost" onClick={onDelete} disabled={disabled} title="Delete">
|
|
188
188
|
<Trash2 className="size-4 text-destructive" />
|
|
189
189
|
</Button>
|
|
190
190
|
</div>
|
|
@@ -14,7 +14,7 @@ export function JSONSwitcher({
|
|
|
14
14
|
<Button
|
|
15
15
|
variant={viewCode ? 'ghost' : 'primary'}
|
|
16
16
|
size="sm"
|
|
17
|
-
|
|
17
|
+
title="Preview properties"
|
|
18
18
|
onClick={() => setViewCode(false)}
|
|
19
19
|
>
|
|
20
20
|
{title}
|
|
@@ -22,7 +22,7 @@ export function JSONSwitcher({
|
|
|
22
22
|
<Button
|
|
23
23
|
variant={viewCode ? 'primary' : 'ghost'}
|
|
24
24
|
size="sm"
|
|
25
|
-
|
|
25
|
+
title="View in JSON format"
|
|
26
26
|
onClick={() => setViewCode(true)}
|
|
27
27
|
>
|
|
28
28
|
JSON
|
|
@@ -35,7 +35,7 @@ interface PropertyTitleProps {
|
|
|
35
35
|
name: string;
|
|
36
36
|
}
|
|
37
37
|
function PropertyTitle({ name }: PropertyTitleProps) {
|
|
38
|
-
return <div className="text-
|
|
38
|
+
return <div className="text-sm font-semibold">{computeTitleFromName(name)}</div>;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
interface BlockElementProps {
|
|
@@ -64,14 +64,14 @@ function PropertyElement({ name, value }: PropertyElementProps) {
|
|
|
64
64
|
switch (info.type) {
|
|
65
65
|
case ValueType.Inline:
|
|
66
66
|
return (
|
|
67
|
-
<div className="w-full flex gap-2">
|
|
67
|
+
<div className="w-full flex gap-2 text-sm">
|
|
68
68
|
<PropertyTitle name={`${name}:`} />
|
|
69
69
|
<p>{info.value}</p>
|
|
70
70
|
</div>
|
|
71
71
|
);
|
|
72
72
|
case ValueType.Paragraph:
|
|
73
73
|
return (
|
|
74
|
-
<div>
|
|
74
|
+
<div className="w-full flex flex-col gap-2 text-sm">
|
|
75
75
|
<PropertyTitle name={name} />
|
|
76
76
|
<p>{info.value}</p>
|
|
77
77
|
</div>
|
|
@@ -80,14 +80,14 @@ function PropertyElement({ name, value }: PropertyElementProps) {
|
|
|
80
80
|
return (
|
|
81
81
|
<div className="prose dark:prose-invert">
|
|
82
82
|
<PropertyTitle name={name} />
|
|
83
|
-
<div className="vprose dark:prose-invert">{info.value}</div>
|
|
83
|
+
<div className="vprose prose-sm dark:prose-invert">{info.value}</div>
|
|
84
84
|
</div>
|
|
85
85
|
);
|
|
86
86
|
case ValueType.Array:
|
|
87
87
|
return <ArrayProperty name={name} value={value as JSONArray} />;
|
|
88
88
|
case ValueType.Object:
|
|
89
89
|
return (
|
|
90
|
-
<div>
|
|
90
|
+
<div className="w-full flex flex-col gap-2 text-sm">
|
|
91
91
|
<PropertyTitle name={name} />
|
|
92
92
|
<BlockElement className="mt-2">
|
|
93
93
|
{Object.entries(value as JSONObject).map(([key, value]) => (
|
|
@@ -164,8 +164,8 @@ function ItemProperty({ index, value, useBullet }: ItemPropertyProps) {
|
|
|
164
164
|
break;
|
|
165
165
|
}
|
|
166
166
|
return (
|
|
167
|
-
<div className="flex gap-4 hover:bg-
|
|
168
|
-
<div className="font-semibold text-
|
|
167
|
+
<div className="flex gap-4 hover:bg-muted py-2 pe-2 ps-4">
|
|
168
|
+
<div className="font-semibold text-muted">{bullet}</div>
|
|
169
169
|
<div>{content}</div>
|
|
170
170
|
</div>
|
|
171
171
|
);
|
|
@@ -8,6 +8,33 @@ import { registerCustomFoldingProviders } from './foldingProviders.js';
|
|
|
8
8
|
|
|
9
9
|
export type Monaco = typeof monaco;
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Shared, body-level host for Monaco "overflow widgets" — the suggestion, hover, and
|
|
13
|
+
* parameter-hint popups. With `fixedOverflowWidgets` enabled these are `position: fixed`; a CSS
|
|
14
|
+
* `transform` on any ancestor (e.g. a modal centered with `translate(-50%, -50%)`) becomes their
|
|
15
|
+
* containing block and drags the popups away from the cursor, sometimes off-screen. Hosting them in
|
|
16
|
+
* an untransformed node appended to `document.body` keeps them anchored to the caret. The node
|
|
17
|
+
* carries the `monaco-editor` class so Monaco's (global) theme styles apply, and a high z-index so
|
|
18
|
+
* the popups render above modals/overlays. One shared node is reused by every editor instance.
|
|
19
|
+
*/
|
|
20
|
+
let overflowWidgetsNode: HTMLElement | undefined;
|
|
21
|
+
function getOverflowWidgetsNode(): HTMLElement | undefined {
|
|
22
|
+
if (typeof document === 'undefined') return undefined;
|
|
23
|
+
if (!overflowWidgetsNode) {
|
|
24
|
+
const node = document.createElement('div');
|
|
25
|
+
node.className = 'monaco-editor';
|
|
26
|
+
// `absolute` + z-index establishes a stacking context above modals without creating a
|
|
27
|
+
// containing block for the fixed-positioned popups (only transform/filter/etc. would).
|
|
28
|
+
node.style.position = 'absolute';
|
|
29
|
+
node.style.top = '0';
|
|
30
|
+
node.style.left = '0';
|
|
31
|
+
node.style.zIndex = '10000';
|
|
32
|
+
document.body.appendChild(node);
|
|
33
|
+
overflowWidgetsNode = node;
|
|
34
|
+
}
|
|
35
|
+
return overflowWidgetsNode;
|
|
36
|
+
}
|
|
37
|
+
|
|
11
38
|
export interface IEditorApi {
|
|
12
39
|
getValue(): string;
|
|
13
40
|
setValue(value?: string): void;
|
|
@@ -226,6 +253,8 @@ export function MonacoEditor({
|
|
|
226
253
|
tabSize: 2,
|
|
227
254
|
insertSpaces: true,
|
|
228
255
|
fixedOverflowWidgets: true, // Hover/diagnostic popovers float outside the editor bounds
|
|
256
|
+
// Host the fixed popups in a body-level node so a modal's CSS transform doesn't offset them.
|
|
257
|
+
overflowWidgetsDomNode: getOverflowWidgetsNode(),
|
|
229
258
|
glyphMargin: true, // Enable better error reporting
|
|
230
259
|
renderValidationDecorations: 'on', // Show error squiggles
|
|
231
260
|
renderLineHighlight: 'line', // Highlight entire line for errors
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { parseXML } from './useXMLViewer';
|
|
3
|
+
|
|
4
|
+
describe('parseXML', () => {
|
|
5
|
+
it('parses valid XML', () => {
|
|
6
|
+
const result = parseXML('<root><item id="1">value</item></root>');
|
|
7
|
+
|
|
8
|
+
expect(result.valid).toBe(true);
|
|
9
|
+
expect(result.json).not.toBeNull();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('allows parsererror elements in valid XML content', () => {
|
|
13
|
+
const result = parseXML('<root><parsererror>expected content</parsererror></root>');
|
|
14
|
+
|
|
15
|
+
expect(result.valid).toBe(true);
|
|
16
|
+
expect(result.json).not.toBeNull();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('rejects invalid XML', () => {
|
|
20
|
+
const result = parseXML('<root><item></root>');
|
|
21
|
+
|
|
22
|
+
expect(result.valid).toBe(false);
|
|
23
|
+
expect(result.json).toBeNull();
|
|
24
|
+
expect(result.errorMessage).toContain('Fail to parse:');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { XMLParser } from 'fast-xml-parser';
|
|
2
|
-
import { SyntaxValidator } from 'fast-xml-validator';
|
|
3
2
|
import { useMemo } from 'react';
|
|
4
3
|
import { ATTRIBUTE_CDATA, ATTRIBUTE_COMMENT } from '../constants';
|
|
5
4
|
|
|
@@ -13,24 +12,30 @@ const parser = new XMLParser({
|
|
|
13
12
|
parseTagValue: false,
|
|
14
13
|
});
|
|
15
14
|
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
export function parseXML(xml: string) {
|
|
16
|
+
try {
|
|
17
|
+
const validationDocument = new DOMParser().parseFromString(xml, 'application/xml');
|
|
18
|
+
const parserError =
|
|
19
|
+
validationDocument.documentElement.localName === 'parsererror'
|
|
20
|
+
? validationDocument.documentElement
|
|
21
|
+
: undefined;
|
|
22
|
+
if (parserError) {
|
|
23
|
+
throw new Error(parserError.textContent?.trim() || 'Invalid XML!');
|
|
24
|
+
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
throw new Error('Invalid XML!');
|
|
28
|
-
}
|
|
26
|
+
const json = parser.parse(xml);
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const error = e as Error;
|
|
33
|
-
return { json: null, valid: false, errorMessage: `Fail to parse: ${error.message}` };
|
|
28
|
+
if (xml.trim().length > 0 && json.length === 0) {
|
|
29
|
+
throw new Error('Invalid XML!');
|
|
34
30
|
}
|
|
35
|
-
|
|
31
|
+
|
|
32
|
+
return { json, valid: true };
|
|
33
|
+
} catch (error: unknown) {
|
|
34
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
35
|
+
return { json: null, valid: false, errorMessage: `Fail to parse: ${message}` };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export default function useXMLViewer(xml: string) {
|
|
40
|
+
return useMemo(() => parseXML(xml), [xml]);
|
|
36
41
|
}
|