@jini-ai/ui 0.5.5 → 0.6.10
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/CHANGELOG.md +91 -2
- package/dist/core/theme/validation.js +40 -38
- package/dist/features/a2ui/renderer.js +15 -13
- package/dist/features/about/react/components/AboutTab.js +64 -34
- package/dist/features/about/rules.d.ts +2 -2
- package/dist/features/about/rules.js +156 -129
- package/dist/features/admin-widgets/components/ImagePreviewModal.d.ts +4 -3
- package/dist/features/admin-widgets/components/ImagePreviewModal.js +6 -10
- package/dist/features/admin-widgets/components/InfoTip.d.ts +3 -2
- package/dist/features/admin-widgets/components/InfoTip.hooks.js +2 -0
- package/dist/features/admin-widgets/components/InfoTip.js +34 -7
- package/dist/features/admin-widgets/components/InfoTip.rules.d.ts +13 -0
- package/dist/features/admin-widgets/components/InfoTip.rules.js +43 -10
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.d.ts +30 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.d.ts +40 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +128 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.js +18 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.d.ts +14 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.js +12 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.rules.d.ts +20 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.rules.js +21 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.d.ts +18 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.d.ts +16 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +45 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.js +18 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.d.ts +32 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.js +26 -0
- package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.js +29 -14
- package/dist/features/admin-widgets/index.d.ts +14 -2
- package/dist/features/admin-widgets/index.js +7 -1
- package/dist/features/admin-widgets/styles/admin-widgets.css +1 -0
- package/dist/features/asset-grid/react/components/AssetCard.js +7 -1
- package/dist/features/asset-grid/react/components/AssetGrid.d.ts +1 -1
- package/dist/features/asset-grid/react/components/AssetGrid.js +38 -18
- package/dist/features/asset-grid/react/components/useAssetGridFilters.d.ts +21 -0
- package/dist/features/asset-grid/react/components/useAssetGridFilters.js +19 -0
- package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +16 -11
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.d.ts +2 -0
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +35 -11
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.d.ts +6 -6
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.js +10 -129
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.d.ts +50 -0
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.js +95 -0
- package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.d.ts +56 -0
- package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.js +80 -0
- package/dist/features/asset-tree-browser/rules.js +40 -22
- package/dist/features/browser-chrome/rules.js +74 -70
- package/dist/features/charts/browser.js +11 -5
- package/dist/features/charts/react.js +2 -2
- package/dist/features/charts/table.js +2 -2
- package/dist/features/command-palette/react/hooks/useCommandPalette.js +3 -9
- package/dist/features/connectors/ConnectorsBrowser.d.ts +4 -4
- package/dist/features/connectors/ConnectorsBrowser.js +26 -14
- package/dist/features/connectors/components/ConnectorCard.js +67 -38
- package/dist/features/connectors/components/ConnectorDetailDrawer.js +62 -31
- package/dist/features/connectors/components/ConnectorGrid.js +11 -6
- package/dist/features/connectors/hooks/useConnectorAuthorization.js +6 -0
- package/dist/features/connectors/hooks/useConnectorCatalog.d.ts +2 -0
- package/dist/features/connectors/hooks/useConnectorCatalog.js +32 -13
- package/dist/features/connectors/hooks/useWiredConnectorsBrowser.d.ts +3 -3
- package/dist/features/connectors/rules.d.ts +8 -1
- package/dist/features/connectors/rules.js +42 -20
- package/dist/features/connectors/types.d.ts +11 -0
- package/dist/features/execution/constants.d.ts +4 -10
- package/dist/features/execution/constants.js +9 -94
- package/dist/features/execution/react/components/ByokProviderForm.d.ts +2 -4
- package/dist/features/execution/react/components/ByokProviderForm.js +140 -43
- package/dist/features/execution/react/components/ExecutionTab.d.ts +1 -2
- package/dist/features/execution/react/components/ExecutionTab.js +52 -30
- package/dist/features/execution/react/components/LocalCliAgentCard.js +12 -3
- package/dist/features/execution/react/components/LocalCliAgentList.js +14 -3
- package/dist/features/execution/react/components/LocalCliAgentSettings.js +14 -3
- package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +54 -36
- package/dist/features/execution/react/hooks/useReasoningControl.js +114 -78
- package/dist/features/execution/rules.d.ts +2 -2
- package/dist/features/execution/rules.js +31 -15
- package/dist/features/execution/types.d.ts +4 -42
- package/dist/features/execution/types.js +0 -17
- package/dist/features/external-mcp/react/components/ExternalMcpTab.d.ts +6 -2
- package/dist/features/external-mcp/react/components/ExternalMcpTab.js +9 -2
- package/dist/features/file-dropzone/react/components/FileDropzone.js +24 -25
- package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.d.ts +2 -2
- package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.js +35 -30
- package/dist/features/file-dropzone/react/components/FileDropzoneThumbnailGrid.js +30 -24
- package/dist/features/file-dropzone/react/components/FileDropzoneZone.d.ts +14 -0
- package/dist/features/file-dropzone/react/components/FileDropzoneZone.js +26 -0
- package/dist/features/html-editor/canvas-content-wrapper.js +13 -13
- package/dist/features/html-editor/canvas-embed-placeholders.js +46 -37
- package/dist/features/html-editor/css.js +76 -69
- package/dist/features/html-editor/editor-blocks.js +47 -33
- package/dist/features/html-editor/editor-serialization.js +6 -5
- package/dist/features/html-editor/protected-elements.js +39 -28
- package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +4 -4
- package/dist/features/html-editor/source-splice.js +51 -30
- package/dist/features/i18n/dictionaries/settings-dialog.ja.js +1 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +1 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +1 -0
- package/dist/features/i18n/locale.js +20 -16
- package/dist/features/iframe-pool/react/dom-sync.js +8 -6
- package/dist/features/integrations/react/components/CodexInstallToggleButton.js +19 -4
- package/dist/features/integrations/react/components/IntegrationsTab.js +60 -14
- package/dist/features/interactive-ui/interactive-ui.css +1 -1
- package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -7
- package/dist/features/lexical-rich-text-editor/mention-parser.js +60 -57
- package/dist/features/lexical-rich-text-editor/react/hooks/useKeyboardCommands.js +33 -38
- package/dist/features/lexical-rich-text-editor/rules.js +87 -74
- package/dist/features/lexical-rich-text-editor/serialize.js +27 -25
- package/dist/features/mcp-ui/secret-card.js +111 -61
- package/dist/features/mcp-ui/surfaces/confirmation.js +39 -21
- package/dist/features/mcp-ui/surfaces/document.d.ts +1 -1
- package/dist/features/mcp-ui/surfaces/document.js +10 -2
- package/dist/features/mcp-ui/surfaces/fields.js +30 -50
- package/dist/features/mcp-ui/surfaces/form.d.ts +6 -0
- package/dist/features/mcp-ui/surfaces/form.js +43 -21
- package/dist/features/mcp-ui/surfaces/outcome.js +30 -20
- package/dist/features/mcp-ui/surfaces/text-input.js +33 -21
- package/dist/features/mcp-ui/surfaces/tokens.d.ts +6 -1
- package/dist/features/mcp-ui/surfaces/tokens.js +5 -2
- package/dist/features/media-providers/constants.d.ts +1 -0
- package/dist/features/media-providers/constants.js +2 -81
- package/dist/features/media-providers/index.d.ts +1 -1
- package/dist/features/media-providers/ports.d.ts +2 -0
- package/dist/features/media-providers/react/components/MediaProviderCard.d.ts +22 -0
- package/dist/features/media-providers/react/components/MediaProviderCard.js +50 -0
- package/dist/features/media-providers/react/components/MediaProvidersTab.d.ts +5 -6
- package/dist/features/media-providers/react/components/MediaProvidersTab.js +40 -72
- package/dist/features/media-providers/react/components/media-providers-tab-labels.d.ts +11 -0
- package/dist/features/media-providers/react/components/media-providers-tab-labels.js +57 -0
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.d.ts +4 -2
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +37 -23
- package/dist/features/media-providers/rules.js +17 -10
- package/dist/features/media-providers/types.d.ts +4 -22
- package/dist/features/media-providers/types.js +3 -8
- package/dist/features/memory/formatters.js +127 -92
- package/dist/features/memory/react/components/MemoryConnectedPanel.js +92 -36
- package/dist/features/memory/react/components/MemoryList.js +37 -18
- package/dist/features/memory/react/hooks/useMemoryExtractions.store.js +42 -36
- package/dist/features/notifications/react/components/NotificationsTab.js +28 -28
- package/dist/features/observability/long-task.d.ts +0 -12
- package/dist/features/observability/long-task.js +15 -19
- package/dist/features/observability/resource-error.d.ts +0 -10
- package/dist/features/observability/resource-error.js +18 -13
- package/dist/features/observability/stuck-run.js +10 -6
- package/dist/features/observability/telemetry-url.d.ts +6 -0
- package/dist/features/observability/telemetry-url.js +16 -0
- package/dist/features/observability/white-screen.js +12 -24
- package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +2 -2
- package/dist/features/panel-kit/fetch-query/adapter.react.js +4 -2
- package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +46 -33
- package/dist/features/panel-kit/helpers/standing-draft-local-backup.js +3 -1
- package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +3 -1
- package/dist/features/privacy/react/components/PrivacyTab.js +24 -13
- package/dist/features/progress-card/components/ProgressCard.js +7 -3
- package/dist/features/progress-card/reference-adapters.js +59 -54
- package/dist/features/project-locations/react/components/ProjectLocationsTab.js +24 -15
- package/dist/features/project-locations/react/hooks/useProjectLocationsTab.d.ts +8 -0
- package/dist/features/project-locations/react/hooks/useProjectLocationsTab.js +31 -23
- package/dist/features/resource-dashboard/react/components/ResourceBoard.js +6 -47
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.d.ts +2 -2
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.js +3 -6
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.d.ts +15 -0
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.js +35 -0
- package/dist/features/resource-dashboard/react/components/ResourceCard.js +5 -16
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.d.ts +34 -0
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +34 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowList.js +3 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +2 -2
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.d.ts +19 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +11 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.d.ts +1 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +4 -4
- package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.d.ts +10 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.js +20 -0
- package/dist/features/resource-dashboard/react/components/resourceBoardProps.d.ts +48 -0
- package/dist/features/resource-dashboard/react/components/resourceBoardProps.js +70 -0
- package/dist/features/resource-dashboard/react/components/resourceRowListProps.d.ts +19 -0
- package/dist/features/resource-dashboard/react/components/resourceRowListProps.js +14 -0
- package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.d.ts +16 -0
- package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.js +13 -0
- package/dist/features/resource-dashboard/rules.js +2 -8
- package/dist/features/sketch-editor/dom.js +150 -99
- package/dist/features/sketch-editor/react/components/SketchEditor.js +26 -15
- package/dist/features/skills/react/components/SkillDraftForm.js +13 -19
- package/dist/features/skills/react/components/SkillDraftForm.labels.d.ts +31 -0
- package/dist/features/skills/react/components/SkillDraftForm.labels.js +54 -0
- package/dist/features/skills/react/components/SkillRow.js +38 -18
- package/dist/features/skills/react/components/SkillRow.labels.d.ts +7 -0
- package/dist/features/skills/react/components/SkillRow.labels.js +18 -0
- package/dist/features/skills/react/components/SkillsTab.js +24 -14
- package/dist/features/skills/react/components/SkillsTab.labels.d.ts +7 -0
- package/dist/features/skills/react/components/SkillsTab.labels.js +11 -0
- package/dist/features/skills/rules.js +32 -23
- package/dist/features/source-config-list/agent-handles.js +2 -1
- package/dist/features/source-config-list/dependencies.js +53 -49
- package/dist/features/source-config-list/index.d.ts +3 -3
- package/dist/features/source-config-list/react/components/SourceConfigAddForm.d.ts +6 -5
- package/dist/features/source-config-list/react/components/SourceConfigAddForm.js +38 -7
- package/dist/features/source-config-list/react/components/SourceConfigField.js +69 -25
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.d.ts +6 -5
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +76 -20
- package/dist/features/source-config-list/react/components/SourceConfigListView.d.ts +5 -3
- package/dist/features/source-config-list/react/components/SourceConfigListView.js +33 -3
- package/dist/features/source-config-list/react/components/SourceConfigTestControl.js +17 -1
- package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.d.ts +11 -0
- package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.js +12 -0
- package/dist/features/source-config-list/types.d.ts +14 -0
- package/dist/features/tab-launcher-menu/react/components/TabLauncherMenu.js +25 -1
- package/dist/features/tab-launcher-menu/react/hooks/useTabLauncherMenu.js +15 -16
- package/dist/features/tab-strip/react/components/TabBar.js +8 -1
- package/dist/features/tabbed-dialog/react/components/TabbedDialog.js +8 -30
- package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.d.ts +15 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.js +8 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.d.ts +12 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.js +6 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.d.ts +27 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.js +12 -0
- package/dist/features/tabbed-dialog/react/components/tabbedDialogView.d.ts +43 -0
- package/dist/features/tabbed-dialog/react/components/tabbedDialogView.js +59 -0
- package/dist/features/version-manager/dependencies.d.ts +3 -1
- package/dist/features/version-manager/dependencies.js +3 -2
- package/dist/features/version-manager/react/components/VersionManagerModal.js +10 -6
- package/dist/features/version-manager/react/hooks/useVersionManager.js +7 -4
- package/dist/features/viewer-shell/react/components/CommentSidePanel.js +103 -50
- package/dist/features/viewer-shell/react/components/MarkdownSplitPane.js +28 -8
- package/dist/features/viewer-shell/react/hooks/useCommentReorder.js +22 -16
- package/dist/features/viewer-shell/rules.js +19 -23
- package/dist/react/components/CustomSelect.d.ts +38 -1
- package/dist/react/components/CustomSelect.js +94 -38
- package/dist/react/components/OnboardingDropdown.js +20 -8
- package/dist/react/components/RemixIcon.stylesheet.js +3 -1
- package/dist/react/components/Toast.js +13 -2
- package/dist/react/components/TooltipLayer.js +5 -14
- package/dist/react/components/WorkingDirPicker.js +78 -50
- package/dist/react/components/remixicon-font-recovery.js +38 -30
- package/dist/react/components/select-popover.d.ts +8 -6
- package/dist/react/components/select-popover.js +33 -29
- package/dist/react/mcp-ui/McpUiHost.d.ts +1 -1
- package/dist/react/mcp-ui/McpUiHost.js +10 -11
- package/dist/react/mcp-ui/host-message-source.d.ts +14 -2
- package/dist/react/mcp-ui/host-message-source.js +15 -5
- package/dist/react/mcp-ui/mcp-ui-host-frame.d.ts +41 -0
- package/dist/react/mcp-ui/mcp-ui-host-frame.js +39 -0
- package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +97 -69
- package/dist/renderers/preview-modal-shell/react/components/PreviewModalShell.js +59 -30
- package/dist/renderers/react/components/ArtifactView.js +9 -6
- package/dist/renderers/srcdoc/build.d.ts +4 -1
- package/dist/renderers/srcdoc/build.js +62 -48
- package/dist/styles/admin.css +29 -14
- package/dist/styles/lightbox.css +142 -0
- package/dist/styles/variables.css +128 -0
- package/dist/theme/apply.js +9 -5
- package/dist/utils/auto-open-file.d.ts +2 -1
- package/dist/utils/auto-open-file.js +69 -85
- package/dist/utils/markdown-scroll-sync.js +108 -87
- package/dist/utils/polygon-selection.js +25 -26
- package/dist/utils/smooth-scroll-to-top.d.ts +1 -1
- package/dist/utils/smooth-scroll-to-top.js +2 -32
- package/dist/utils/sse.js +26 -26
- package/dist/utils/unit-bezier.d.ts +7 -0
- package/dist/utils/unit-bezier.js +38 -0
- package/package.json +9 -12
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.d.ts +0 -13
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.js +0 -46
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Icon } from '../../../../react/components/Icon.js';
|
|
3
|
+
/** One sidebar nav button. */
|
|
4
|
+
export function TabbedDialogNavItem({ tab, active, isModal, onSelect }) {
|
|
5
|
+
return (_jsxs("button", { type: "button", className: `jini-tabbed-dialog-nav-item${active ? ' active' : ''}`, "aria-pressed": active, onClick: () => onSelect(tab.id), "data-testid": `settings-dialog-nav-${tab.id}`, "data-agent-element": isModal ? undefined : `tab-${tab.id}`, "data-agent-role": isModal ? undefined : 'button', "data-agent-label": isModal ? undefined : tab.label, children: [_jsx("span", { className: "jini-tabbed-dialog-nav-icon", "aria-hidden": "true", children: tab.icon }), _jsxs("span", { className: "jini-tabbed-dialog-nav-text", children: [_jsx("strong", { children: tab.label }), tab.navHint ? _jsx("small", { children: tab.navHint }) : null] })] }));
|
|
6
|
+
}
|
|
7
|
+
/** The collapse toggle plus the sidebar nav it controls. */
|
|
8
|
+
export function TabbedDialogSidebar({ tabs, activeTabId, isModal, collapsed, onToggleCollapsed, onSelect, labels, }) {
|
|
9
|
+
const sidebarToggleLabel = collapsed ? labels.expandSidebarLabel : labels.collapseSidebarLabel;
|
|
10
|
+
return (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "jini-tabbed-dialog-sidebar-toggle", onClick: onToggleCollapsed, "aria-label": sidebarToggleLabel, "aria-pressed": collapsed, "aria-controls": "jini-tabbed-dialog-sidebar", title: sidebarToggleLabel, children: _jsx(Icon, { name: collapsed ? 'chevron-right' : 'chevron-left', size: 15, strokeWidth: 2 }) }), _jsx("aside", { id: "jini-tabbed-dialog-sidebar", className: "jini-tabbed-dialog-sidebar", "aria-label": labels.sidebarAriaLabel, "aria-hidden": collapsed ? true : undefined, children: tabs.map((tab) => (_jsx(TabbedDialogNavItem, { tab: tab, active: tab.id === activeTabId, isModal: isModal, onSelect: onSelect }, tab.id))) })] }));
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=TabbedDialogSidebar.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { MouseEvent } from 'react';
|
|
2
|
+
import type { I18nContextValue } from '../../../i18n/index.js';
|
|
3
|
+
import type { TabbedDialogChromeLabels } from '../../types.js';
|
|
4
|
+
/** Every chrome label resolved to a concrete string. */
|
|
5
|
+
export type ResolvedTabbedDialogLabels = Required<TabbedDialogChromeLabels>;
|
|
6
|
+
/**
|
|
7
|
+
* Fills each chrome label the host left unset (absent or `undefined`) with its
|
|
8
|
+
* product-neutral default, translated through `t`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveTabbedDialogLabels({ t }: {
|
|
11
|
+
t: I18nContextValue['t'];
|
|
12
|
+
}, { labels }?: {
|
|
13
|
+
labels?: TabbedDialogChromeLabels | undefined;
|
|
14
|
+
}): ResolvedTabbedDialogLabels;
|
|
15
|
+
/**
|
|
16
|
+
* `presentation` wins when set; otherwise a dialog with a close handler is a
|
|
17
|
+
* modal and one without is inline (see `TabbedDialogProps.presentation`).
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveIsModal({ hasOnClose }: {
|
|
20
|
+
hasOnClose: boolean;
|
|
21
|
+
}, { presentation }?: {
|
|
22
|
+
presentation?: 'modal' | 'inline' | undefined;
|
|
23
|
+
}): boolean;
|
|
24
|
+
/** The dialog root's class list: base class plus state modifiers plus the host's own. */
|
|
25
|
+
export declare function buildTabbedDialogClassName({ sidebarCollapsed, fullscreen }: {
|
|
26
|
+
sidebarCollapsed: boolean;
|
|
27
|
+
fullscreen: boolean;
|
|
28
|
+
}, { className }?: {
|
|
29
|
+
className?: string | undefined;
|
|
30
|
+
}): string;
|
|
31
|
+
/**
|
|
32
|
+
* The dialog root's role/modality props. A modal is a `dialog` with
|
|
33
|
+
* `aria-modal` that swallows its own clicks (so only a backdrop click closes
|
|
34
|
+
* it); inline is a plain `region` with neither.
|
|
35
|
+
*/
|
|
36
|
+
export declare function dialogRootRoleProps({ isModal }: {
|
|
37
|
+
isModal: boolean;
|
|
38
|
+
}): {
|
|
39
|
+
role: 'dialog' | 'region';
|
|
40
|
+
'aria-modal': true | undefined;
|
|
41
|
+
onClick: ((event: Pick<MouseEvent, 'stopPropagation'>) => void) | undefined;
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=tabbedDialogView.d.ts.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fills each chrome label the host left unset (absent or `undefined`) with its
|
|
3
|
+
* product-neutral default, translated through `t`.
|
|
4
|
+
*/
|
|
5
|
+
export function resolveTabbedDialogLabels({ t }, { labels } = {}) {
|
|
6
|
+
const defaults = {
|
|
7
|
+
// No brand/product word defaults to a bare `''` here on purpose — this component has no
|
|
8
|
+
// opinion about what it's a dialog FOR. A host that wants a kicker (as `SettingsDialogShell`
|
|
9
|
+
// does, with `t('Settings')`) supplies one via `labels.kicker`.
|
|
10
|
+
kicker: '',
|
|
11
|
+
welcomeKicker: t('Welcome'),
|
|
12
|
+
welcomeTitle: t('Get started'),
|
|
13
|
+
welcomeSubtitle: t('Set up your preferences before you begin.'),
|
|
14
|
+
closeLabel: t('Close'),
|
|
15
|
+
fullscreenLabel: t('Fullscreen'),
|
|
16
|
+
exitFullscreenLabel: t('Exit fullscreen'),
|
|
17
|
+
collapseSidebarLabel: t('Collapse sidebar'),
|
|
18
|
+
expandSidebarLabel: t('Expand sidebar'),
|
|
19
|
+
sidebarAriaLabel: t('Sections'),
|
|
20
|
+
};
|
|
21
|
+
const resolved = { ...defaults };
|
|
22
|
+
for (const key of Object.keys(defaults)) {
|
|
23
|
+
resolved[key] = labels?.[key] ?? defaults[key];
|
|
24
|
+
}
|
|
25
|
+
return resolved;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* `presentation` wins when set; otherwise a dialog with a close handler is a
|
|
29
|
+
* modal and one without is inline (see `TabbedDialogProps.presentation`).
|
|
30
|
+
*/
|
|
31
|
+
export function resolveIsModal({ hasOnClose }, { presentation } = {}) {
|
|
32
|
+
return (presentation ?? (hasOnClose ? 'modal' : 'inline')) === 'modal';
|
|
33
|
+
}
|
|
34
|
+
/** The dialog root's class list: base class plus state modifiers plus the host's own. */
|
|
35
|
+
export function buildTabbedDialogClassName({ sidebarCollapsed, fullscreen }, { className } = {}) {
|
|
36
|
+
return [
|
|
37
|
+
'jini-tabbed-dialog',
|
|
38
|
+
sidebarCollapsed ? 'jini-tabbed-dialog-sidebar-collapsed' : '',
|
|
39
|
+
fullscreen ? 'jini-tabbed-dialog-fullscreen' : '',
|
|
40
|
+
className,
|
|
41
|
+
]
|
|
42
|
+
.filter(Boolean)
|
|
43
|
+
.join(' ');
|
|
44
|
+
}
|
|
45
|
+
/** Keeps a click inside the modal dialog from reaching the backdrop's close handler. */
|
|
46
|
+
function stopPropagation(event) {
|
|
47
|
+
event.stopPropagation();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The dialog root's role/modality props. A modal is a `dialog` with
|
|
51
|
+
* `aria-modal` that swallows its own clicks (so only a backdrop click closes
|
|
52
|
+
* it); inline is a plain `region` with neither.
|
|
53
|
+
*/
|
|
54
|
+
export function dialogRootRoleProps({ isModal }) {
|
|
55
|
+
if (!isModal)
|
|
56
|
+
return { role: 'region', 'aria-modal': undefined, onClick: undefined };
|
|
57
|
+
return { role: 'dialog', 'aria-modal': true, onClick: stopPropagation };
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=tabbedDialogView.js.map
|
|
@@ -7,7 +7,9 @@ import type { VersionManagerClipboardPort, VersionManagerDependencies, VersionMa
|
|
|
7
7
|
* transport call") — a real host binds its own REST/daemon calls to
|
|
8
8
|
* `VersionManagerPort` instead.
|
|
9
9
|
*/
|
|
10
|
-
export declare function createFakeVersionManagerPort<TVersion extends VersionRecord = VersionRecord>(seed?: ReadonlyMap<string, TVersion[]
|
|
10
|
+
export declare function createFakeVersionManagerPort<TVersion extends VersionRecord = VersionRecord>(seed?: ReadonlyMap<string, TVersion[]>, { content: seedContent }?: {
|
|
11
|
+
content?: ReadonlyMap<string, string>;
|
|
12
|
+
}): VersionManagerPort<TVersion>;
|
|
11
13
|
/** Reuses `features/viewer-shell/`'s real browser clipboard implementation
|
|
12
14
|
* — clipboard access is a generic browser API with no backend shape to
|
|
13
15
|
* fake, same reasoning that feature's own `dependencies.ts` documents. */
|
|
@@ -6,9 +6,10 @@ import { createBrowserViewerClipboard } from '../viewer-shell/index.js';
|
|
|
6
6
|
* transport call") — a real host binds its own REST/daemon calls to
|
|
7
7
|
* `VersionManagerPort` instead.
|
|
8
8
|
*/
|
|
9
|
-
export function createFakeVersionManagerPort(seed) {
|
|
9
|
+
export function createFakeVersionManagerPort(seed, { content: seedContent } = {}) {
|
|
10
10
|
const store = new Map(seed ? [...seed.entries()].map(([k, v]) => [k, [...v]]) : []);
|
|
11
|
-
|
|
11
|
+
// Content uses the same scope/name key as metadata, followed by the version id.
|
|
12
|
+
const content = new Map(seedContent);
|
|
12
13
|
const key = (fileRef) => `${fileRef.scopeId}:${fileRef.name}`;
|
|
13
14
|
return {
|
|
14
15
|
async listVersions(fileRef) {
|
|
@@ -30,9 +30,6 @@ export function VersionManagerModal({ fileRef, currentContent, onClose, onRestor
|
|
|
30
30
|
const { copied, copy } = useCopyToClipboard(dependencies.clipboard);
|
|
31
31
|
const { versions, visibleVersions, versionById, selectedVersion, search, setSearch, showSearch, loading, loadingContent, error, previewDocument, frameReady, markFrameLoaded, restoring, restoreDisabled, restore, openInNewTab, viewportPresets: presets, viewport, setViewport, selectVersion, prefetchVersion, } = controller;
|
|
32
32
|
const versionCountLabel = versions.length === 1 ? t('1 version') : t('{count} versions', { count: versions.length });
|
|
33
|
-
const selectedPrompt = selectedVersion?.prompt?.trim() ?? '';
|
|
34
|
-
const selectedDate = selectedVersion ? formatVersionDateTime(selectedVersion.createdAt, locale) : fileRef.name;
|
|
35
|
-
const selectedRestoredFrom = selectedVersion ? restoredFromVersion(selectedVersion, versionById) : null;
|
|
36
33
|
// Layered Escape handling: close the modal only when neither popover is
|
|
37
34
|
// consuming the keystroke — each popover owns its own Escape dismissal
|
|
38
35
|
// via `useDismissOnOutsideOrEscape`, so this only needs to know whether
|
|
@@ -62,8 +59,15 @@ export function VersionManagerModal({ fileRef, currentContent, onClose, onRestor
|
|
|
62
59
|
return createPortal(_jsx("div", { className: "jini-modal-backdrop jini-version-modal-backdrop", role: "presentation", onMouseDown: (event) => {
|
|
63
60
|
if (event.target === event.currentTarget)
|
|
64
61
|
onClose();
|
|
65
|
-
}, children: _jsxs("div", { className: "jini-version-modal", role: "dialog", "aria-modal": "true", "aria-label": t('Version history'), children: [_jsx(VersionSidebar, { countLabel: versionCountLabel, search: search, onSearchChange: setSearch, showSearch: showSearch, loading: loading, versions: versions, visibleVersions: visibleVersions, selectedVersionId: selectedVersion
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
}, children: _jsxs("div", { className: "jini-version-modal", role: "dialog", "aria-modal": "true", "aria-label": t('Version history'), children: [_jsx(VersionSidebar, { countLabel: versionCountLabel, search: search, onSearchChange: setSearch, showSearch: showSearch, loading: loading, versions: versions, visibleVersions: visibleVersions, selectedVersionId: selectedVersion ? selectedVersion.id : null, onSelect: selectVersion, onPrefetch: prefetchVersion, formatDate: (version) => formatVersionDateTime(version.createdAt, locale), sourceLabel: (version) => t(versionSourceLabel(version.source)), sourceClassName: (version) => versionSourceClassName(version.source), restoredFrom: (version) => restoredFromVersion(version, versionById) }), _jsxs("div", { className: "jini-version-main", children: [_jsxs("header", { className: "jini-version-head", children: [_jsx(VersionMetadata, { selectedVersion: selectedVersion, versionById: versionById, fileName: fileRef.name, copied: copied, onCopy: (text) => void copy(text), onOpenChange: (open) => {
|
|
63
|
+
promptOpenRef.current = open;
|
|
64
|
+
} }), _jsxs("div", { className: "jini-version-actions", children: [selectedVersion && !selectedVersion.current ? (_jsx(VersionRestoreControl, { disabled: restoreDisabled, restoring: restoring, onRestore: () => void restore() })) : null, _jsx(ViewportToggleGroup, { presets: presets, viewport: viewport, onViewport: setViewport, ariaLabel: t('Preview viewport') }), openInNewTab ? (_jsx("button", { type: "button", className: "jini-viewer-action jini-viewer-action-icon", "aria-label": t('Open in new tab'), title: t('Open in new tab'), disabled: loadingContent, onClick: openInNewTab, children: t('Open') })) : null, _jsx("button", { type: "button", className: "jini-viewer-action jini-viewer-action-icon", "aria-label": t('Close'), title: t('Close'), onClick: onClose, children: t('Close') })] })] }), _jsx(VersionPreviewFrame, { previewDocument: previewDocument, frameReady: frameReady, onFrameLoad: () => markFrameLoaded(previewDocument), viewport: viewport, viewportPresets: presets, title: selectedVersion ? `${fileRef.name} · v${selectedVersion.version}` : fileRef.name, error: error, loading: loading, loadingContent: loadingContent })] })] }) }), document.body);
|
|
65
|
+
}
|
|
66
|
+
function VersionMetadata({ selectedVersion, versionById, fileName, copied, onCopy, onOpenChange, }) {
|
|
67
|
+
const { t, locale } = useI18n();
|
|
68
|
+
const selectedPrompt = selectedVersion?.prompt?.trim() ?? '';
|
|
69
|
+
const selectedDate = selectedVersion ? formatVersionDateTime(selectedVersion.createdAt, locale) : fileName;
|
|
70
|
+
const selectedRestoredFrom = selectedVersion ? restoredFromVersion(selectedVersion, versionById) : null;
|
|
71
|
+
return (_jsx("div", { className: "jini-version-meta", children: _jsxs("div", { className: "jini-version-meta-row", children: [selectedVersion?.current ? (_jsx("span", { className: "jini-version-current-badge", children: t('Current') })) : null, selectedVersion ? (_jsx("span", { className: `jini-version-source-badge ${versionSourceClassName(selectedVersion.source)}`, children: t(versionSourceLabel(selectedVersion.source)) })) : null, _jsx("span", { className: "jini-version-selected-date", children: selectedDate }), selectedRestoredFrom ? (_jsx("span", { className: "jini-version-restored-from", children: t('Restored from v{version}', { version: selectedRestoredFrom.version }) })) : null, _jsx(VersionPromptPopover, { prompt: selectedPrompt, disabled: !selectedVersion, copied: copied, onCopy: onCopy, onOpenChange: onOpenChange })] }) }));
|
|
68
72
|
}
|
|
69
73
|
//# sourceMappingURL=VersionManagerModal.js.map
|
|
@@ -4,6 +4,11 @@ import { DEFAULT_VIEWPORT_PRESETS } from '../../../viewer-shell/index.js';
|
|
|
4
4
|
import { PREVIEW_LOAD_FALLBACK_MS, SEARCH_VISIBLE_THRESHOLD, } from '../../constants.js';
|
|
5
5
|
import { defaultVersionManagerDependencies } from '../../dependencies.js';
|
|
6
6
|
import { buildVersionIndex, contentMatchesSelection, filterVersionsBySearch, formatVersionDateTime, isRestoreDisabled, restoredFromVersion, resolveSelectedVersion, shouldShowVersionSearch, sortVersionsDescending, versionSourceLabel, } from '../../rules.js';
|
|
7
|
+
function seedCurrentVersionContent({ currentVersion, currentContent, contentCache, }) {
|
|
8
|
+
if (currentVersion && currentContent != null && !contentCache.has(currentVersion.id)) {
|
|
9
|
+
contentCache.set(currentVersion.id, currentContent);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
7
12
|
/**
|
|
8
13
|
* Owns the whole version-manager state machine: list fetch, selection,
|
|
9
14
|
* content cache/prefetch, search, restore, and viewport choice. Kept as one
|
|
@@ -102,9 +107,7 @@ export function useVersionManager(dependencies, options) {
|
|
|
102
107
|
const nextVersions = sortVersionsDescending(result);
|
|
103
108
|
setVersions(nextVersions);
|
|
104
109
|
const currentVersion = nextVersions.find((version) => version.current);
|
|
105
|
-
|
|
106
|
-
contentCacheRef.current.set(currentVersion.id, currentContent);
|
|
107
|
-
}
|
|
110
|
+
seedCurrentVersionContent({ currentVersion, currentContent, contentCache: contentCacheRef.current });
|
|
108
111
|
const nextSelected = (preferredId ? nextVersions.find((version) => version.id === preferredId) : null) ??
|
|
109
112
|
currentVersion ??
|
|
110
113
|
nextVersions[0] ??
|
|
@@ -207,7 +210,7 @@ export function useVersionManager(dependencies, options) {
|
|
|
207
210
|
// this hook already has.
|
|
208
211
|
contentCacheRef.current.set(restoredVersion.id, selectedContent);
|
|
209
212
|
preserveErrorOnNextSelectionRef.current = true;
|
|
210
|
-
await loadVersions(
|
|
213
|
+
await loadVersions(restoredVersion.id);
|
|
211
214
|
setError(result.warning.message);
|
|
212
215
|
return;
|
|
213
216
|
}
|
|
@@ -22,30 +22,28 @@ export function CommentSidePanel({ comments, selectedIds, activeCommentId, colla
|
|
|
22
22
|
const reorder = useCommentReorderHook(orderedIds, onReorder);
|
|
23
23
|
const visibleSelectedIds = visibleSelectedCommentIds(comments, selectedIds);
|
|
24
24
|
const selectedCount = visibleSelectedIds.size;
|
|
25
|
-
const allSelected = comments.length > 0 && selectedCount === comments.length;
|
|
26
25
|
const commentsLabel = t('Comments');
|
|
27
|
-
const canCreateComment = Boolean(onCreateComment) && newCommentDraft.trim().length > 0 && !sending && !sendDisabled;
|
|
28
|
-
const collapsedRailRef = useRef(null);
|
|
29
|
-
const expandedToggleRef = useRef(null);
|
|
30
|
-
const pendingToggleFocusRef = useRef(null);
|
|
31
26
|
const panelId = useId();
|
|
32
|
-
const formatTs = formatTimestamp
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
const formatTs = useCommentTimestampFormatter(formatTimestamp);
|
|
28
|
+
const { collapsedRailRef, expandedToggleRef, handleCollapsedChange } = useCollapseToggleFocus({
|
|
29
|
+
collapsed,
|
|
30
|
+
onCollapsedChange,
|
|
35
31
|
});
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return;
|
|
39
|
-
const saved = await onCreateComment(newCommentDraft.trim());
|
|
40
|
-
if (saved)
|
|
41
|
-
setNewCommentDraft('');
|
|
32
|
+
if (collapsed) {
|
|
33
|
+
return (_jsx(CommentSideRail, { railRef: collapsedRailRef, commentsLabel: commentsLabel, commentCount: comments.length, onExpand: () => handleCollapsedChange(false, 'expanded') }));
|
|
42
34
|
}
|
|
35
|
+
return (_jsxs("aside", { id: panelId, className: "comment-side-panel", "data-testid": "comment-side-panel", "aria-label": commentsLabel, children: [_jsx(CommentSideHeader, { toggleRef: expandedToggleRef, panelId: panelId, commentsLabel: commentsLabel, commentCount: comments.length, selectedCount: selectedCount, onSelectAll: onSelectAll, onCollapse: () => handleCollapsedChange(true, 'collapsed') }), _jsx("div", { className: "comment-side-list", onDragLeave: reorder.onDragLeaveContainer, children: comments.length === 0 ? (_jsx("div", { className: "comment-side-empty", children: t('No comments yet') })) : (comments.map((comment, index) => (_jsx(CommentSideItem, { comment: comment, index: index, selected: visibleSelectedIds.has(comment.id), active: comment.id === activeCommentId, reorder: reorder, onReply: onReply, onToggleSelect: onToggleSelect, getCommentLabel: getCommentLabel, getCommentTimestamp: getCommentTimestamp, getCommentBody: getCommentBody, getCommentAttachments: getCommentAttachments, resolveAttachmentUrl: resolveAttachmentUrl, formatTs: formatTs }, comment.id)))) }), _jsx(CommentSideSelectBar, { selectedCount: selectedCount, sending: sending, sendDisabled: sendDisabled, queueOnSend: queueOnSend, onClearSelection: onClearSelection, onSendSelected: onSendSelected }), composer ? _jsx("div", { className: "comment-side-composer", children: composer }) : null, _jsx(CommentSideCreateForm, { renderCreateForm: renderCreateForm, draft: newCommentDraft, onDraftChange: setNewCommentDraft, onCreateComment: onCreateComment, sending: sending, sendDisabled: sendDisabled })] }));
|
|
36
|
+
}
|
|
37
|
+
/** Moves focus onto whichever collapse/expand control replaced the one the
|
|
38
|
+
* user just clicked, once the `collapsed` change has re-rendered. */
|
|
39
|
+
function useCollapseToggleFocus({ collapsed, onCollapsedChange, }) {
|
|
40
|
+
const collapsedRailRef = useRef(null);
|
|
41
|
+
const expandedToggleRef = useRef(null);
|
|
42
|
+
const pendingToggleFocusRef = useRef(null);
|
|
43
43
|
useEffect(() => {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
? expandedToggleRef.current
|
|
48
|
-
: null;
|
|
44
|
+
const targets = { collapsed: collapsedRailRef.current, expanded: expandedToggleRef.current };
|
|
45
|
+
const pending = pendingToggleFocusRef.current;
|
|
46
|
+
const target = pending ? targets[pending] : null;
|
|
49
47
|
if (!target)
|
|
50
48
|
return;
|
|
51
49
|
pendingToggleFocusRef.current = null;
|
|
@@ -55,37 +53,92 @@ export function CommentSidePanel({ comments, selectedIds, activeCommentId, colla
|
|
|
55
53
|
pendingToggleFocusRef.current = nextFocusTarget;
|
|
56
54
|
onCollapsedChange(nextCollapsed);
|
|
57
55
|
}
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
return { collapsedRailRef, expandedToggleRef, handleCollapsedChange };
|
|
57
|
+
}
|
|
58
|
+
function useCommentTimestampFormatter(formatTimestamp) {
|
|
59
|
+
const t = useT();
|
|
60
|
+
return (formatTimestamp ??
|
|
61
|
+
((ts) => {
|
|
62
|
+
const translation = relativeCommentTimeTranslation(ts);
|
|
63
|
+
return t(translation.key, translation.vars);
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
function CommentSideRail({ railRef, commentsLabel, commentCount, onExpand, }) {
|
|
67
|
+
const t = useT();
|
|
68
|
+
const showLabel = t('Show {label}', { label: commentsLabel });
|
|
69
|
+
return (_jsxs("button", { ref: railRef, type: "button", className: "comment-side-rail", "data-testid": "comment-side-collapsed-rail", "aria-label": showLabel, "aria-expanded": false, title: showLabel, onClick: onExpand, children: [_jsx(RemixIcon, { name: "message-3-line", size: 15 }), _jsx("span", { children: commentsLabel }), commentCount > 0 ? _jsx("strong", { children: commentCount }) : null] }));
|
|
70
|
+
}
|
|
71
|
+
function CommentSideHeader({ toggleRef, panelId, commentsLabel, commentCount, selectedCount, onSelectAll, onCollapse, }) {
|
|
72
|
+
const t = useT();
|
|
73
|
+
const hideLabel = t('Hide {label}', { label: commentsLabel });
|
|
74
|
+
const allSelected = commentCount > 0 && selectedCount === commentCount;
|
|
75
|
+
return (_jsxs("div", { className: "comment-side-header", children: [_jsxs("div", { className: "comment-side-title", children: [_jsx(RemixIcon, { name: "message-3-line", size: 15 }), _jsx("span", { children: commentsLabel })] }), _jsxs("div", { className: "comment-side-header-actions", children: [commentCount > 0 ? (_jsx("button", { type: "button", className: "comment-side-select-all", disabled: allSelected, onClick: onSelectAll, children: t('Select all') })) : null, _jsx("button", { ref: toggleRef, type: "button", className: "comment-side-collapse", "aria-label": hideLabel, "aria-controls": panelId, "aria-expanded": true, title: hideLabel, onClick: onCollapse, children: _jsx(Icon, { name: "chevron-right", size: 14 }) })] })] }));
|
|
76
|
+
}
|
|
77
|
+
/** ` comment-side-item-drop-<edge>` while another comment is dragged over
|
|
78
|
+
* `commentId` with a known edge, else `''`. */
|
|
79
|
+
function dropEdgeClassName(dragState, commentId) {
|
|
80
|
+
const showsDropEdge = dragState?.overId === commentId && dragState.draggingId !== commentId && dragState.edge;
|
|
81
|
+
return showsDropEdge ? ` comment-side-item-drop-${dragState.edge}` : '';
|
|
82
|
+
}
|
|
83
|
+
function commentItemClassName({ selected, active, isDragging, dropClass, }) {
|
|
84
|
+
return `comment-side-item${selected ? ' selected' : ''}${active ? ' active' : ''}${isDragging ? ' dragging' : ''}${dropClass}`;
|
|
85
|
+
}
|
|
86
|
+
function CommentSideItem({ comment, index, selected, active, reorder, onReply, onToggleSelect, getCommentLabel, getCommentTimestamp, getCommentBody, getCommentAttachments, resolveAttachmentUrl, formatTs, }) {
|
|
87
|
+
const t = useT();
|
|
88
|
+
const className = commentItemClassName({
|
|
89
|
+
selected,
|
|
90
|
+
active,
|
|
91
|
+
isDragging: reorder.dragState?.draggingId === comment.id,
|
|
92
|
+
dropClass: dropEdgeClassName(reorder.dragState, comment.id),
|
|
93
|
+
});
|
|
94
|
+
const attachments = getCommentAttachments?.(comment) ?? [];
|
|
95
|
+
const dragLabel = t('Drag to reorder');
|
|
96
|
+
return (_jsxs("div", { className: className, "data-testid": "comment-side-item", "data-comment-id": comment.id, "aria-current": active ? 'true' : undefined, role: "button", tabIndex: 0, onDragOver: (event) => reorder.onDragOver(event, comment.id), onDrop: (event) => reorder.onDrop(event, comment.id), onClick: () => onReply(comment), onKeyDown: (event) => {
|
|
97
|
+
if (event.key !== 'Enter' && event.key !== ' ')
|
|
98
|
+
return;
|
|
99
|
+
event.preventDefault();
|
|
100
|
+
onReply(comment);
|
|
101
|
+
}, children: [_jsxs("div", { className: "comment-side-item-head", children: [_jsx("button", { type: "button", className: "comment-side-drag-handle", title: dragLabel, "aria-label": dragLabel, draggable: reorder.canReorder, disabled: !reorder.canReorder, onClick: (event) => event.stopPropagation(), onDragStart: (event) => reorder.onDragStart(event, comment.id), onDragEnd: reorder.clear, children: _jsx(Icon, { name: "grip-vertical", size: 13 }) }), _jsx("span", { className: "comment-side-author", children: _jsx("strong", { children: `${index + 1}. ${getCommentLabel(comment, index)}` }) }), _jsx("span", { className: "comment-side-time", children: formatTs(getCommentTimestamp(comment)) }), _jsx("button", { type: "button", className: `comment-side-check${selected ? ' checked' : ''}`, "aria-label": selected ? t('Deselect') : t('Select'), "aria-pressed": selected, onClick: (event) => {
|
|
102
|
+
event.stopPropagation();
|
|
103
|
+
onToggleSelect(comment.id);
|
|
104
|
+
}, children: selected ? _jsx(Icon, { name: "check", size: 11 }) : null })] }), _jsx("div", { className: "comment-side-body", children: getCommentBody(comment) }), resolveAttachmentUrl && attachments.length > 0 ? (_jsx(CommentSideAttachments, { attachments: attachments, resolveAttachmentUrl: resolveAttachmentUrl })) : null] }));
|
|
105
|
+
}
|
|
106
|
+
function CommentSideAttachments({ attachments, resolveAttachmentUrl, }) {
|
|
107
|
+
return (_jsx("div", { className: "comment-side-attachments", children: attachments.map((attachment) => {
|
|
108
|
+
const url = resolveAttachmentUrl(attachment);
|
|
109
|
+
return (_jsx("a", { className: "comment-side-attachment", "data-testid": "comment-side-attachment", href: url, target: "_blank", rel: "noopener noreferrer", "aria-label": attachment.name, title: attachment.name, onClick: (event) => event.stopPropagation(), children: _jsx("img", { src: url, alt: attachment.name }) }, attachment.path));
|
|
110
|
+
}) }));
|
|
111
|
+
}
|
|
112
|
+
function CommentSideSelectBar({ selectedCount, sending, sendDisabled, queueOnSend, onClearSelection, onSendSelected, }) {
|
|
113
|
+
const t = useT();
|
|
114
|
+
if (selectedCount === 0)
|
|
115
|
+
return null;
|
|
116
|
+
return (_jsxs("div", { className: "comment-side-selectbar", "data-testid": "comment-side-selectbar", children: [_jsx("span", { className: "comment-side-selectcount", children: t('{n} selected', { n: selectedCount }) }), _jsx("button", { type: "button", className: "comment-side-clear", onClick: onClearSelection, children: t('Clear') }), _jsx("button", { type: "button", className: "comment-side-send", "data-testid": "comment-side-send-claude", disabled: sending || sendDisabled, onClick: () => void onSendSelected(), children: sending ? t('Sending…') : queueOnSend ? t('Queue') : t('Send to chat') })] }));
|
|
117
|
+
}
|
|
118
|
+
function CommentSideCreateForm({ renderCreateForm, draft, onDraftChange, onCreateComment, sending, sendDisabled, }) {
|
|
119
|
+
const t = useT();
|
|
120
|
+
if (!renderCreateForm || !onCreateComment)
|
|
121
|
+
return null;
|
|
122
|
+
// Bind the narrowed callback: TypeScript drops the narrowing inside the
|
|
123
|
+
// nested async `submitNewComment` closure below.
|
|
124
|
+
const createComment = onCreateComment;
|
|
125
|
+
const canCreateComment = draft.trim().length > 0 && !sending && !sendDisabled;
|
|
126
|
+
const addLabel = t('Add a comment…');
|
|
127
|
+
async function submitNewComment() {
|
|
128
|
+
if (!draft.trim())
|
|
129
|
+
return;
|
|
130
|
+
const saved = await createComment(draft.trim());
|
|
131
|
+
if (saved)
|
|
132
|
+
onDraftChange('');
|
|
60
133
|
}
|
|
61
|
-
return (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (event.key !== 'Enter' && event.key !== ' ')
|
|
71
|
-
return;
|
|
72
|
-
event.preventDefault();
|
|
73
|
-
onReply(comment);
|
|
74
|
-
}, children: [_jsxs("div", { className: "comment-side-item-head", children: [_jsx("button", { type: "button", className: "comment-side-drag-handle", title: t('Drag to reorder'), "aria-label": t('Drag to reorder'), draggable: reorder.canReorder, disabled: !reorder.canReorder, onClick: (event) => event.stopPropagation(), onDragStart: (event) => reorder.onDragStart(event, comment.id), onDragEnd: reorder.clear, children: _jsx(Icon, { name: "grip-vertical", size: 13 }) }), _jsx("span", { className: "comment-side-author", children: _jsx("strong", { children: `${index + 1}. ${getCommentLabel(comment, index)}` }) }), _jsx("span", { className: "comment-side-time", children: formatTs(getCommentTimestamp(comment)) }), _jsx("button", { type: "button", className: `comment-side-check${selected ? ' checked' : ''}`, "aria-label": selected ? t('Deselect') : t('Select'), "aria-pressed": selected, onClick: (event) => {
|
|
75
|
-
event.stopPropagation();
|
|
76
|
-
onToggleSelect(comment.id);
|
|
77
|
-
}, children: selected ? _jsx(Icon, { name: "check", size: 11 }) : null })] }), _jsx("div", { className: "comment-side-body", children: getCommentBody(comment) }), resolveAttachmentUrl && attachments.length > 0 ? (_jsx("div", { className: "comment-side-attachments", children: attachments.map((attachment) => {
|
|
78
|
-
const url = resolveAttachmentUrl(attachment);
|
|
79
|
-
return (_jsx("a", { className: "comment-side-attachment", "data-testid": "comment-side-attachment", href: url, target: "_blank", rel: "noopener noreferrer", "aria-label": attachment.name, title: attachment.name, onClick: (event) => event.stopPropagation(), children: _jsx("img", { src: url, alt: attachment.name }) }, attachment.path));
|
|
80
|
-
}) })) : null] }, comment.id));
|
|
81
|
-
})) }), selectedCount > 0 ? (_jsxs("div", { className: "comment-side-selectbar", "data-testid": "comment-side-selectbar", children: [_jsx("span", { className: "comment-side-selectcount", children: t('{n} selected', { n: selectedCount }) }), _jsx("button", { type: "button", className: "comment-side-clear", onClick: onClearSelection, children: t('Clear') }), _jsx("button", { type: "button", className: "comment-side-send", "data-testid": "comment-side-send-claude", disabled: sending || sendDisabled, onClick: () => void onSendSelected(), children: sending ? t('Sending…') : queueOnSend ? t('Queue') : t('Send to chat') })] })) : null, composer ? _jsx("div", { className: "comment-side-composer", children: composer }) : null, renderCreateForm && onCreateComment ? (_jsx("form", { className: "comment-side-new-comment composer", onSubmit: (event) => {
|
|
82
|
-
event.preventDefault();
|
|
83
|
-
void submitNewComment();
|
|
84
|
-
}, children: _jsxs("div", { className: "composer-shell comment-side-new-comment-shell", children: [_jsx("div", { className: "composer-input-wrap", children: _jsx("div", { className: "composer-textarea-layer", children: _jsx("textarea", { value: newCommentDraft, placeholder: t('Add a comment…'), "aria-label": t('Add a comment…'), onChange: (event) => setNewCommentDraft(event.target.value), onKeyDown: (event) => {
|
|
85
|
-
if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {
|
|
86
|
-
event.preventDefault();
|
|
87
|
-
void submitNewComment();
|
|
88
|
-
}
|
|
89
|
-
} }) }) }), _jsxs("div", { className: "composer-row comment-side-new-comment-actions", children: [_jsx("button", { type: "button", className: "icon-btn", title: t('Attach'), "aria-label": t('Attach'), disabled: true, children: _jsx(Icon, { name: "attach", size: 15 }) }), _jsx("span", { className: "composer-spacer" }), _jsxs("button", { type: "submit", className: `composer-send${sending ? ' is-sending' : ''}`, disabled: !canCreateComment, children: [_jsx(Icon, { name: "send", size: 13 }), _jsx("span", { children: sending ? t('Sending…') : t('Send') })] })] })] }) })) : null] }));
|
|
134
|
+
return (_jsx("form", { className: "comment-side-new-comment composer", onSubmit: (event) => {
|
|
135
|
+
event.preventDefault();
|
|
136
|
+
void submitNewComment();
|
|
137
|
+
}, children: _jsxs("div", { className: "composer-shell comment-side-new-comment-shell", children: [_jsx("div", { className: "composer-input-wrap", children: _jsx("div", { className: "composer-textarea-layer", children: _jsx("textarea", { value: draft, placeholder: addLabel, "aria-label": addLabel, onChange: (event) => onDraftChange(event.target.value), onKeyDown: (event) => {
|
|
138
|
+
if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {
|
|
139
|
+
event.preventDefault();
|
|
140
|
+
void submitNewComment();
|
|
141
|
+
}
|
|
142
|
+
} }) }) }), _jsxs("div", { className: "composer-row comment-side-new-comment-actions", children: [_jsx("button", { type: "button", className: "icon-btn", title: t('Attach'), "aria-label": t('Attach'), disabled: true, children: _jsx(Icon, { name: "attach", size: 15 }) }), _jsx("span", { className: "composer-spacer" }), _jsxs("button", { type: "submit", className: `composer-send${sending ? ' is-sending' : ''}`, disabled: !canCreateComment, children: [_jsx(Icon, { name: "send", size: 13 }), _jsx("span", { children: sending ? t('Sending…') : t('Send') })] })] })] }) }));
|
|
90
143
|
}
|
|
91
144
|
//# sourceMappingURL=CommentSidePanel.js.map
|
|
@@ -31,13 +31,33 @@ export function MarkdownSplitPane({ mode, onModeChange, sourceText, onSourceChan
|
|
|
31
31
|
const showEditor = mode === 'source' || mode === 'split';
|
|
32
32
|
const showPreview = mode === 'preview' || mode === 'split';
|
|
33
33
|
const isLoading = loading || previewHtml === null;
|
|
34
|
-
return (_jsx(ViewerShell, { kindClassName: "markdown-split-viewer", bodyClassName: `markdown-workbench markdown-workbench-${mode}`, toolbarLeft: _jsxs(_Fragment, { children: [toolbarLeftExtra, _jsx(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
return (_jsx(ViewerShell, { kindClassName: "markdown-split-viewer", bodyClassName: `markdown-workbench markdown-workbench-${mode}`, toolbarLeft: _jsxs(_Fragment, { children: [toolbarLeftExtra, _jsx(MarkdownModeTabs, { mode: mode, onModeChange: onModeChange, sourceLabel: sourceLabel, splitLabel: splitLabel, previewLabel: previewLabel, modeAriaLabel: modeAriaLabel })] }), toolbarActions: toolbarActions, children: isLoading ? (_jsx("div", { className: "viewer-empty", children: loadingLabel ?? t('Loading…') })) : (_jsxs(_Fragment, { children: [showEditor ? (_jsx(MarkdownEditorPane, { editorRef: editorRef, sourceText: sourceText, onSourceChange: onSourceChange, ariaLabel: editorAriaLabel, onScroll: handleEditorScroll, activatePane: activatePane, textareaProps: editorTextareaProps })) : null, showPreview ? (_jsx(MarkdownPreviewPane, { previewRef: previewRef,
|
|
35
|
+
// Non-null assertion: `isLoading` (above) is true whenever
|
|
36
|
+
// `previewHtml === null`, and this JSX only renders in the
|
|
37
|
+
// `!isLoading` branch — so `previewHtml` is always a string
|
|
38
|
+
// here. TypeScript can't follow that indirect invariant
|
|
39
|
+
// through the derived `isLoading` boolean, hence the `!`.
|
|
40
|
+
html: previewHtml, ariaLabel: previewAriaLabel, onScroll: handlePreviewScroll, activatePane: activatePane, onPreviewClick: onPreviewClick })) : null] })) }));
|
|
41
|
+
}
|
|
42
|
+
function MarkdownModeTabs({ mode, onModeChange, sourceLabel, splitLabel, previewLabel, modeAriaLabel, }) {
|
|
43
|
+
const t = useT();
|
|
44
|
+
return (_jsx(SegmentedToggle, { className: "markdown-mode-tabs", ariaLabel: modeAriaLabel ?? t('Markdown view mode'), value: mode, onChange: onModeChange, options: [
|
|
45
|
+
{ value: 'source', label: sourceLabel ?? t('Source') },
|
|
46
|
+
{ value: 'split', label: splitLabel ?? t('Split') },
|
|
47
|
+
{ value: 'preview', label: previewLabel ?? t('Preview') },
|
|
48
|
+
] }));
|
|
49
|
+
}
|
|
50
|
+
function MarkdownEditorPane({ editorRef, sourceText, onSourceChange, ariaLabel, onScroll, activatePane, textareaProps, }) {
|
|
51
|
+
const t = useT();
|
|
52
|
+
const label = ariaLabel ?? t('Markdown editor');
|
|
53
|
+
return (_jsx("section", { className: "markdown-editor-pane", "aria-label": label, children: _jsx("textarea", { ref: editorRef, className: "markdown-editor", value: sourceText, "aria-label": label, spellCheck: true, onFocus: () => activatePane('editor'), onChange: (event) => {
|
|
54
|
+
activatePane('editor');
|
|
55
|
+
onSourceChange(event.currentTarget.value);
|
|
56
|
+
}, onScroll: onScroll, ...textareaProps }) }));
|
|
57
|
+
}
|
|
58
|
+
function MarkdownPreviewPane({ previewRef, html, ariaLabel, onScroll, activatePane, onPreviewClick, }) {
|
|
59
|
+
const t = useT();
|
|
60
|
+
const activatePreview = () => activatePane('preview');
|
|
61
|
+
return (_jsx("div", { className: "markdown-preview-pane-wrap", children: _jsx("section", { ref: previewRef, className: "markdown-preview-pane", "aria-label": ariaLabel ?? t('Markdown preview'), onPointerDown: activatePreview, onWheel: activatePreview, onTouchStart: activatePreview, onKeyDown: activatePreview, onFocus: activatePreview, onScroll: onScroll, children: _jsx("article", { className: "markdown-rendered", onClick: onPreviewClick, dangerouslySetInnerHTML: { __html: html } }) }) }));
|
|
42
62
|
}
|
|
43
63
|
//# sourceMappingURL=MarkdownSplitPane.js.map
|
|
@@ -26,31 +26,22 @@ export function useCommentReorder(orderedIds, onReorder) {
|
|
|
26
26
|
return;
|
|
27
27
|
event.preventDefault();
|
|
28
28
|
event.dataTransfer.dropEffect = 'move';
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
const edge = dropEdgeForClientY(event.clientY, event.currentTarget.getBoundingClientRect());
|
|
36
|
-
if (dragState?.draggingId !== draggingId || dragState.overId !== targetId || dragState.edge !== edge) {
|
|
37
|
-
setDragState({ draggingId, overId: targetId, edge });
|
|
38
|
-
}
|
|
29
|
+
// Hovering back over the dragged item itself shows no drop edge.
|
|
30
|
+
const edge = draggingId === targetId ? null : pointerDropEdge(event);
|
|
31
|
+
const next = { draggingId, overId: targetId, edge };
|
|
32
|
+
if (!isSameDragState(dragState, next))
|
|
33
|
+
setDragState(next);
|
|
39
34
|
}
|
|
40
35
|
function onDrop(event, targetId) {
|
|
41
36
|
if (!canReorder)
|
|
42
37
|
return;
|
|
43
38
|
event.preventDefault();
|
|
44
|
-
const draggingId = dragState?.draggingId ||
|
|
45
|
-
event.dataTransfer.getData(COMMENT_SIDE_DRAG_MIME) ||
|
|
46
|
-
event.dataTransfer.getData('text/plain');
|
|
39
|
+
const draggingId = dragState?.draggingId || draggingIdFromTransfer(event.dataTransfer);
|
|
47
40
|
if (!draggingId || draggingId === targetId) {
|
|
48
41
|
setDragState(null);
|
|
49
42
|
return;
|
|
50
43
|
}
|
|
51
|
-
const edge = dragState
|
|
52
|
-
? dragState.edge
|
|
53
|
-
: dropEdgeForClientY(event.clientY, event.currentTarget.getBoundingClientRect());
|
|
44
|
+
const edge = cachedDropEdge(dragState, targetId) ?? pointerDropEdge(event);
|
|
54
45
|
const nextIds = reorderCommentIds(orderedIds, draggingId, targetId, edge);
|
|
55
46
|
if (nextIds.join('\0') !== orderedIds.join('\0')) {
|
|
56
47
|
onReorder?.(nextIds);
|
|
@@ -68,4 +59,19 @@ export function useCommentReorder(orderedIds, onReorder) {
|
|
|
68
59
|
}
|
|
69
60
|
return { dragState, canReorder, onDragStart, onDragOver, onDrop, onDragLeaveContainer, clear };
|
|
70
61
|
}
|
|
62
|
+
function pointerDropEdge(event) {
|
|
63
|
+
return dropEdgeForClientY(event.clientY, event.currentTarget.getBoundingClientRect());
|
|
64
|
+
}
|
|
65
|
+
/** Dragging id carried by the DOM payload: the comment mime type, then the
|
|
66
|
+
* `text/plain` copy `onDragStart` also writes. */
|
|
67
|
+
function draggingIdFromTransfer(dataTransfer) {
|
|
68
|
+
return dataTransfer.getData(COMMENT_SIDE_DRAG_MIME) || dataTransfer.getData('text/plain');
|
|
69
|
+
}
|
|
70
|
+
/** The edge already shown while hovering `targetId`, if any. */
|
|
71
|
+
function cachedDropEdge(dragState, targetId) {
|
|
72
|
+
return dragState?.overId === targetId ? dragState.edge : null;
|
|
73
|
+
}
|
|
74
|
+
function isSameDragState(current, next) {
|
|
75
|
+
return current?.draggingId === next.draggingId && current.overId === next.overId && current.edge === next.edge;
|
|
76
|
+
}
|
|
71
77
|
//# sourceMappingURL=useCommentReorder.js.map
|
|
@@ -89,27 +89,10 @@ export function visibleSelectedCommentIds(comments, selectedIds) {
|
|
|
89
89
|
* `number`. When true, callers should display the original text verbatim
|
|
90
90
|
* instead of a "prettified" re-stringify. */
|
|
91
91
|
export function hasPrecisionSensitiveJsonNumberText(text) {
|
|
92
|
-
let inString = false;
|
|
93
|
-
let escaped = false;
|
|
94
92
|
const numberTokenPattern = /-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/y;
|
|
95
93
|
for (let i = 0; i < text.length;) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (escaped) {
|
|
99
|
-
escaped = false;
|
|
100
|
-
}
|
|
101
|
-
else if (char === '\\') {
|
|
102
|
-
escaped = true;
|
|
103
|
-
}
|
|
104
|
-
else if (char === '"') {
|
|
105
|
-
inString = false;
|
|
106
|
-
}
|
|
107
|
-
i += 1;
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
if (char === '"') {
|
|
111
|
-
inString = true;
|
|
112
|
-
i += 1;
|
|
94
|
+
if (text[i] === '"') {
|
|
95
|
+
i = indexAfterJsonString(text, i + 1);
|
|
113
96
|
continue;
|
|
114
97
|
}
|
|
115
98
|
numberTokenPattern.lastIndex = i;
|
|
@@ -118,15 +101,28 @@ export function hasPrecisionSensitiveJsonNumberText(text) {
|
|
|
118
101
|
i += 1;
|
|
119
102
|
continue;
|
|
120
103
|
}
|
|
121
|
-
|
|
122
|
-
if (isSignedNegativeZeroJsonNumberToken(token))
|
|
123
|
-
return true;
|
|
124
|
-
if (/[.eE]/.test(token) && isPrecisionSensitiveJsonNumberToken(token))
|
|
104
|
+
if (isPrecisionSensitiveNumberLiteral(match[0]))
|
|
125
105
|
return true;
|
|
126
106
|
i = numberTokenPattern.lastIndex;
|
|
127
107
|
}
|
|
128
108
|
return false;
|
|
129
109
|
}
|
|
110
|
+
/** Index just past the closing quote of the JSON string whose body starts at
|
|
111
|
+
* `start` (honouring `\` escapes), or `text.length` when it is unterminated. */
|
|
112
|
+
function indexAfterJsonString(text, start) {
|
|
113
|
+
for (let i = start; i < text.length; i += 1) {
|
|
114
|
+
if (text[i] === '\\')
|
|
115
|
+
i += 1;
|
|
116
|
+
else if (text[i] === '"')
|
|
117
|
+
return i + 1;
|
|
118
|
+
}
|
|
119
|
+
return text.length;
|
|
120
|
+
}
|
|
121
|
+
function isPrecisionSensitiveNumberLiteral(token) {
|
|
122
|
+
if (isSignedNegativeZeroJsonNumberToken(token))
|
|
123
|
+
return true;
|
|
124
|
+
return /[.eE]/.test(token) && isPrecisionSensitiveJsonNumberToken(token);
|
|
125
|
+
}
|
|
130
126
|
function isSignedNegativeZeroJsonNumberToken(token) {
|
|
131
127
|
return /^-0(?:\.0+)?(?:[eE][+-]?\d+)?$/.test(token);
|
|
132
128
|
}
|