@jini-ai/ui 0.6.15-rc.1 → 0.6.15
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/browser/useDismissOnOutsideOrEscape.js +1 -1
- package/dist/browser/useGlobalKeydown.js +2 -2
- package/dist/browser/useModalWindowDragGuard.js +1 -1
- package/dist/core/theme/css-name.d.ts +3 -0
- package/dist/core/theme/css-name.js +5 -0
- package/dist/core/theme/stylesheet.js +2 -1
- package/dist/core/theme/validation.js +15 -4
- package/dist/features/about/rules.js +2 -1
- package/dist/features/admin-widgets/components/InfoTip.hooks.js +22 -12
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +1 -1
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +1 -1
- package/dist/features/admin-widgets/components/SeeMore/SeeMore.hooks.js +2 -2
- package/dist/features/admin-widgets/components/SeeMore/SeeMore.js +4 -2
- package/dist/features/admin-widgets/components/Select/Select.hooks.js +2 -1
- package/dist/features/admin-widgets/components/Select/Select.js +2 -1
- package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.js +4 -2
- package/dist/features/admin-widgets/components/useDebouncedHtmlPreview.hooks.js +3 -2
- package/dist/features/asset-grid/react/components/AssetGrid.js +8 -3
- package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +7 -6
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +8 -10
- package/dist/features/asset-grid/react/hooks/useRubberBandDrag.js +1 -1
- package/dist/features/asset-tree-browser/react/components/AssetTreeFileRow.js +6 -8
- package/dist/features/asset-tree-browser/react/hooks/useAssetTreeRowMenu.js +1 -1
- package/dist/features/asset-tree-browser/rules.js +1 -3
- package/dist/features/browser-chrome/rules.js +10 -8
- package/dist/features/charts/browser.js +2 -1
- package/dist/features/charts/react.js +3 -1
- package/dist/features/connectors/ConnectorsBrowser.js +3 -1
- package/dist/features/connectors/hooks/useConnectorAuthorization.js +1 -1
- package/dist/features/connectors/hooks/useConnectorCatalog.js +2 -2
- package/dist/features/connectors/rules.js +10 -14
- package/dist/features/execution/react/components/AgentDiagnosticRow.js +2 -0
- package/dist/features/execution/react/components/ByokProviderForm.js +1 -3
- package/dist/features/execution/react/components/LocalCliAgentSettings.js +2 -1
- package/dist/features/execution/react/hooks/use-byok-field-validation.hooks.js +6 -2
- package/dist/features/execution/react/hooks/useExecutionTab.js +9 -5
- package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +3 -6
- package/dist/features/execution/react/hooks/useReasoningControl.js +3 -3
- package/dist/features/execution/rules.js +23 -18
- package/dist/features/external-mcp/react/components/ExternalMcpTab.js +10 -1
- package/dist/features/file-dropzone/rules.js +3 -2
- package/dist/features/html-editor/canvas-embed-placeholders.js +2 -3
- package/dist/features/html-editor/css.js +7 -5
- package/dist/features/html-editor/editor-blocks.js +60 -6
- package/dist/features/html-editor/protected-elements.js +5 -3
- package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +3 -3
- package/dist/features/html-editor/source-splice.js +6 -4
- package/dist/features/iframe-pool/react/components/IframeKeepAliveProvider.js +5 -5
- package/dist/features/iframe-pool/react/dom-sync.js +2 -2
- package/dist/features/integrations/react/components/IntegrationsTab.js +3 -1
- package/dist/features/integrations/rules.js +6 -4
- package/dist/features/interactive-ui/interactive-ui.css +1 -1
- package/dist/features/interactive-ui/providers/shadcn/button.d.ts +8 -6
- package/dist/features/interactive-ui/providers/shadcn/button.js +5 -6
- package/dist/features/interactive-ui/providers/shadcn/card.d.ts +3 -3
- package/dist/features/interactive-ui/providers/shadcn/card.js +3 -4
- package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -5
- package/dist/features/interactive-ui/providers/shadcn/select.d.ts +3 -5
- package/dist/features/interactive-ui/providers/shadcn/select.js +3 -7
- package/dist/features/interactive-ui/providers/shadcn/table.d.ts +4 -5
- package/dist/features/interactive-ui/providers/shadcn/table.js +4 -9
- package/dist/features/interactive-ui/table-data.js +1 -1
- package/dist/features/lexical-rich-text-editor/deserialize.js +2 -2
- package/dist/features/lexical-rich-text-editor/mention-parser.js +4 -4
- package/dist/features/lexical-rich-text-editor/react/components/RichTextInput.js +2 -1
- package/dist/features/lexical-rich-text-editor/react/hooks/useCaretFloatingLayerPosition.js +1 -1
- package/dist/features/lexical-rich-text-editor/react/hooks/useMentionColorStamping.js +1 -1
- package/dist/features/lexical-rich-text-editor/serialize.js +13 -10
- package/dist/features/list-detail-panel/react/components/ListDetailPanel.js +1 -1
- package/dist/features/mcp-ui/confirmation-store.js +3 -6
- package/dist/features/mcp-ui/surfaces/confirmation.d.ts +5 -0
- package/dist/features/mcp-ui/surfaces/confirmation.js +1 -0
- package/dist/features/mcp-ui/surfaces/document.d.ts +3 -15
- package/dist/features/mcp-ui/surfaces/document.js +37 -6
- package/dist/features/mcp-ui/surfaces/fields.js +2 -0
- package/dist/features/mcp-ui/surfaces/host-theme.js +2 -1
- package/dist/features/mcp-ui/surfaces/index.d.ts +1 -0
- package/dist/features/mcp-ui/surfaces/index.js +1 -0
- package/dist/features/mcp-ui/surfaces/outcome.js +1 -1
- package/dist/features/mcp-ui/surfaces/select.js +2 -1
- package/dist/features/mcp-ui/surfaces/structured-details.d.ts +40 -0
- package/dist/features/mcp-ui/surfaces/structured-details.js +159 -0
- package/dist/features/mcp-ui/surfaces/text-input.js +1 -1
- package/dist/features/mcp-ui/surfaces/tool-approval.d.ts +21 -0
- package/dist/features/mcp-ui/surfaces/tool-approval.js +41 -0
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +2 -1
- package/dist/features/memory/async-commit-guard.js +4 -1
- package/dist/features/memory/formatters.js +5 -1
- package/dist/features/memory/react/components/MemoryConnectedPanel.js +3 -1
- package/dist/features/memory/react/components/MemoryEntryCard.js +1 -1
- package/dist/features/memory/react/components/MemorySettingsPanel.js +3 -1
- package/dist/features/memory/react/hooks/useMemoryConfig.hooks.js +12 -10
- package/dist/features/memory/react/hooks/useMemoryConnectors.hooks.js +2 -5
- package/dist/features/memory/react/hooks/useMemoryConnectors.rules.js +10 -9
- package/dist/features/memory/react/hooks/useMemoryEntries.hooks.js +4 -2
- package/dist/features/memory/react/hooks/useMemoryFlash.hooks.js +1 -1
- package/dist/features/memory/rules.js +2 -1
- package/dist/features/panel-kit/fetch-query/adapter.react.js +3 -2
- package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +3 -2
- package/dist/features/panel-kit/fetch-query/binding.react.js +2 -1
- package/dist/features/panel-kit/helpers/standing-draft-recovery-message.js +13 -4
- package/dist/features/panel-kit/hooks/use-dirty-guard.hooks.js +1 -1
- package/dist/features/panel-kit/hooks/use-focus-trap.hooks.js +1 -1
- package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +14 -10
- package/dist/features/panel-kit/hooks/use-standing-draft-autosave.hooks.js +2 -2
- package/dist/features/progress-card/components/ProgressCard.d.ts +1 -1
- package/dist/features/progress-card/reference-adapters.js +23 -13
- package/dist/features/progress-card/rules.d.ts +0 -1
- package/dist/features/progress-card/rules.js +14 -20
- package/dist/features/progress-card/types.d.ts +1 -1
- package/dist/features/project-locations/dependencies.js +6 -1
- package/dist/features/project-locations/react/components/ProjectLocationsTab.js +2 -1
- package/dist/features/project-locations/rules.js +2 -1
- package/dist/features/resource-dashboard/react/components/ResourceBoardToolbar.js +8 -1
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.js +3 -2
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.d.ts +0 -2
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.js +0 -6
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +2 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +3 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +2 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +1 -1
- package/dist/features/resource-dashboard/react/hooks/useResourceBoard.js +1 -1
- package/dist/features/schedule-picker/rules.js +13 -7
- package/dist/features/sketch-editor/constants.d.ts +0 -6
- package/dist/features/sketch-editor/constants.js +17 -15
- package/dist/features/sketch-editor/dom.js +4 -7
- package/dist/features/sketch-editor/react/components/SketchMainMenu.js +2 -1
- package/dist/features/sketch-editor/react/components/SketchSaveStateBadge.js +2 -1
- package/dist/features/sketch-editor/react/hooks/useSketchDomEnhancements.js +1 -1
- package/dist/features/sketch-editor/rules.js +13 -12
- package/dist/features/skills/dependencies.js +9 -4
- package/dist/features/skills/react/components/SkillRow.js +2 -1
- package/dist/features/skills/react/components/SkillsTab.js +2 -1
- package/dist/features/skills/rules.js +3 -3
- package/dist/features/source-config-list/agent-handles.js +4 -3
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +3 -1
- package/dist/features/tab-strip/react/components/TabBar.hooks.js +4 -2
- package/dist/features/version-manager/react/components/VersionPreviewFrame.js +4 -1
- package/dist/features/version-manager/react/components/VersionSidebar.js +8 -6
- package/dist/features/version-manager/react/hooks/usePreviewCanvasSize.js +1 -1
- package/dist/features/version-manager/react/hooks/useVersionManager.js +5 -7
- package/dist/features/version-manager/rules.js +3 -5
- package/dist/features/viewer-shell/react/components/CommentSidePanel.js +2 -1
- package/dist/features/viewer-shell/react/components/SegmentedToggle.js +2 -1
- package/dist/features/viewer-shell/react/components/ViewerShell.js +2 -1
- package/dist/features/viewer-shell/rules.js +8 -7
- package/dist/react/components/BrandLogo.js +10 -2
- package/dist/react/components/CustomSelect.js +1 -1
- package/dist/react/components/EditorIcon.js +17 -14
- package/dist/react/components/Loading.js +2 -1
- package/dist/react/components/OnboardingChipField.js +5 -1
- package/dist/react/components/OnboardingDropdown.js +6 -4
- package/dist/react/components/PaletteTweaks.js +7 -6
- package/dist/react/components/PillButton.js +2 -1
- package/dist/react/components/PopoverMenu.js +2 -1
- package/dist/react/components/RemixIcon.js +2 -1
- package/dist/react/components/SecretInput.hooks.d.ts +2 -25
- package/dist/react/components/SecretInput.hooks.js +2 -24
- package/dist/react/components/SecretInput.js +5 -4
- package/dist/react/components/Toast.js +4 -2
- package/dist/react/components/TooltipLayer.js +4 -1
- package/dist/react/components/WorkingDirPicker.js +5 -4
- package/dist/react/components/remixicon-font-recovery.js +9 -1
- package/dist/react/components/select-popover.js +2 -2
- package/dist/react/hooks/useBrandFonts.js +1 -1
- package/dist/react/hooks/useEdgeAutoScroll.js +1 -1
- package/dist/react/hooks/useInView.js +9 -9
- package/dist/react/hooks/useResizableSplitPane.js +12 -20
- package/dist/react/mcp-ui/useHostSurfaceTokens.js +1 -1
- package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +7 -1
- package/dist/renderers/annotation-canvas/react/hooks/useAnnotationCanvas.controller.js +4 -2
- package/dist/renderers/annotation-canvas/react/hooks/useAnnotationCanvas.js +9 -5
- package/dist/renderers/annotation-canvas/rules.js +9 -13
- package/dist/renderers/annotation-canvas/theme.js +5 -2
- package/dist/renderers/renderers/index.js +1 -1
- package/dist/renderers/renderers/markdown.js +4 -6
- package/dist/theme/apply.js +7 -3
- package/dist/utils/class-names.d.ts +3 -0
- package/dist/utils/class-names.js +5 -0
- package/dist/utils/design-md.js +3 -3
- package/dist/utils/ime-composing.d.ts +1 -1
- package/dist/utils/ime-composing.js +1 -2
- package/dist/utils/localized-url.js +2 -11
- package/dist/utils/markdown-scroll-sync.js +1 -1
- package/dist/utils/omit-keys.d.ts +3 -0
- package/dist/utils/omit-keys.js +8 -0
- package/dist/utils/polygon-selection.js +1 -1
- package/dist/utils/sse.js +3 -0
- package/dist/utils/trim-chars.d.ts +13 -0
- package/dist/utils/trim-chars.js +30 -0
- package/dist/utils/unhandled-case.d.ts +10 -0
- package/dist/utils/unhandled-case.js +12 -0
- package/dist/utils/unit-bezier.js +1 -3
- package/dist/utils/zip.js +6 -10
- package/package.json +10 -9
|
@@ -23,8 +23,12 @@ export function formatTime12h(time) {
|
|
|
23
23
|
const h = Number(m[1]);
|
|
24
24
|
const mm = m[2];
|
|
25
25
|
const suffix = h >= 12 ? 'PM' : 'AM';
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
return `${to12Hour(h)}:${mm} ${suffix}`;
|
|
27
|
+
}
|
|
28
|
+
function to12Hour(h) {
|
|
29
|
+
if (h === 0)
|
|
30
|
+
return 12;
|
|
31
|
+
return h > 12 ? h - 12 : h;
|
|
28
32
|
}
|
|
29
33
|
function weekdayLongName(weekday, weekdays) {
|
|
30
34
|
return weekdays.find((w) => w.value === weekday)?.long ?? weekdays[0]?.long ?? 'Sunday';
|
|
@@ -39,11 +43,13 @@ export function decomposeSchedule(schedule, weekdays = DEFAULT_WEEKDAYS) {
|
|
|
39
43
|
if (schedule.kind === 'hourly') {
|
|
40
44
|
return { kind: 'hourly', minute: String(schedule.minute).padStart(2, '0') };
|
|
41
45
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
let freq;
|
|
47
|
+
if (schedule.kind === 'daily')
|
|
48
|
+
freq = 'Daily';
|
|
49
|
+
else if (schedule.kind === 'weekdays')
|
|
50
|
+
freq = 'Weekdays';
|
|
51
|
+
else
|
|
52
|
+
freq = weekdayLongName(schedule.weekday, weekdays);
|
|
47
53
|
return { kind: 'timed', freq, time: formatTime12h(schedule.time), tz: schedule.timezone };
|
|
48
54
|
}
|
|
49
55
|
/** Plain-English one-line summary, e.g. `'Hourly at :05'` or
|
|
@@ -2,12 +2,6 @@ import type { SketchTooltipTarget } from './types.js';
|
|
|
2
2
|
export declare const SAVED_VISIBLE_MS = 2000;
|
|
3
3
|
export declare const EXPORTED_IMAGE_MIME_TYPE = "image/png";
|
|
4
4
|
export declare const SKETCH_CONTEXT_MENU_MARGIN = 8;
|
|
5
|
-
/**
|
|
6
|
-
* Default tool/menu tooltip targets — these selectors and `data-testid`
|
|
7
|
-
* values are Excalidraw's own toolbar markup, not host-product content.
|
|
8
|
-
* Host-overridable via `SketchEditorProps.tooltipTargets` for a forked or
|
|
9
|
-
* newer Excalidraw build with different markup.
|
|
10
|
-
*/
|
|
11
5
|
export declare const DEFAULT_SKETCH_TOOLTIP_TARGETS: readonly SketchTooltipTarget[];
|
|
12
6
|
/**
|
|
13
7
|
* Default context-menu action allow-list + order. These are Excalidraw's
|
|
@@ -7,23 +7,25 @@ export const SKETCH_CONTEXT_MENU_MARGIN = 8;
|
|
|
7
7
|
* Host-overridable via `SketchEditorProps.tooltipTargets` for a forked or
|
|
8
8
|
* newer Excalidraw build with different markup.
|
|
9
9
|
*/
|
|
10
|
+
/** Anchor the tooltip on the toolbar button's wrapping `<label>`. */
|
|
11
|
+
const CLOSEST_LABEL = 'closest-label';
|
|
10
12
|
export const DEFAULT_SKETCH_TOOLTIP_TARGETS = [
|
|
11
13
|
{ selector: '[data-testid="main-menu-trigger"]', label: 'mainMenu', placement: 'bottom' },
|
|
12
|
-
{ selector: '[data-testid="toolbar-lock"]', target:
|
|
13
|
-
{ selector: '[data-testid="toolbar-hand"]', target:
|
|
14
|
-
{ selector: '[data-testid="toolbar-selection"]', target:
|
|
15
|
-
{ selector: '[data-testid="toolbar-rectangle"]', target:
|
|
16
|
-
{ selector: '[data-testid="toolbar-diamond"]', target:
|
|
17
|
-
{ selector: '[data-testid="toolbar-ellipse"]', target:
|
|
18
|
-
{ selector: '[data-testid="toolbar-arrow"]', target:
|
|
19
|
-
{ selector: '[data-testid="toolbar-line"]', target:
|
|
20
|
-
{ selector: '[data-testid="toolbar-freedraw"]', target:
|
|
21
|
-
{ selector: '[data-testid="toolbar-text"]', target:
|
|
22
|
-
{ selector: '[data-testid="toolbar-image"]', target:
|
|
23
|
-
{ selector: '[data-testid="toolbar-eraser"]', target:
|
|
24
|
-
{ selector: '[data-testid="toolbar-frame"]', target:
|
|
25
|
-
{ selector: '[data-testid="toolbar-embeddable"]', target:
|
|
26
|
-
{ selector: '[data-testid="toolbar-laser"]', target:
|
|
14
|
+
{ selector: '[data-testid="toolbar-lock"]', target: CLOSEST_LABEL, label: 'lock', placement: 'bottom' },
|
|
15
|
+
{ selector: '[data-testid="toolbar-hand"]', target: CLOSEST_LABEL, label: 'hand', placement: 'bottom' },
|
|
16
|
+
{ selector: '[data-testid="toolbar-selection"]', target: CLOSEST_LABEL, label: 'selection', placement: 'bottom' },
|
|
17
|
+
{ selector: '[data-testid="toolbar-rectangle"]', target: CLOSEST_LABEL, label: 'rectangle', placement: 'bottom' },
|
|
18
|
+
{ selector: '[data-testid="toolbar-diamond"]', target: CLOSEST_LABEL, label: 'diamond', placement: 'bottom' },
|
|
19
|
+
{ selector: '[data-testid="toolbar-ellipse"]', target: CLOSEST_LABEL, label: 'ellipse', placement: 'bottom' },
|
|
20
|
+
{ selector: '[data-testid="toolbar-arrow"]', target: CLOSEST_LABEL, label: 'arrow', placement: 'bottom' },
|
|
21
|
+
{ selector: '[data-testid="toolbar-line"]', target: CLOSEST_LABEL, label: 'line', placement: 'bottom' },
|
|
22
|
+
{ selector: '[data-testid="toolbar-freedraw"]', target: CLOSEST_LABEL, label: 'freedraw', placement: 'bottom' },
|
|
23
|
+
{ selector: '[data-testid="toolbar-text"]', target: CLOSEST_LABEL, label: 'text', placement: 'bottom' },
|
|
24
|
+
{ selector: '[data-testid="toolbar-image"]', target: CLOSEST_LABEL, label: 'image', placement: 'bottom' },
|
|
25
|
+
{ selector: '[data-testid="toolbar-eraser"]', target: CLOSEST_LABEL, label: 'eraser', placement: 'bottom' },
|
|
26
|
+
{ selector: '[data-testid="toolbar-frame"]', target: CLOSEST_LABEL, label: 'frame', placement: 'bottom' },
|
|
27
|
+
{ selector: '[data-testid="toolbar-embeddable"]', target: CLOSEST_LABEL, label: 'embeddable', placement: 'bottom' },
|
|
28
|
+
{ selector: '[data-testid="toolbar-laser"]', target: CLOSEST_LABEL, label: 'laser', placement: 'bottom' },
|
|
27
29
|
{ selector: '.App-toolbar__extra-tools-trigger', label: 'moreTools', placement: 'bottom' },
|
|
28
30
|
];
|
|
29
31
|
/**
|
|
@@ -109,18 +109,15 @@ function hasRecognizedContextMenuAction(menu, recognized) {
|
|
|
109
109
|
function pruneContextMenuItems(menu, allowed) {
|
|
110
110
|
const byAction = new Map();
|
|
111
111
|
for (const child of Array.from(menu.children)) {
|
|
112
|
-
if (child instanceof HTMLHRElement)
|
|
112
|
+
if (child instanceof HTMLHRElement)
|
|
113
113
|
child.remove();
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
114
|
if (!(child instanceof HTMLLIElement))
|
|
117
115
|
continue;
|
|
118
116
|
const actionName = child.getAttribute('data-testid') ?? '';
|
|
119
|
-
if (
|
|
117
|
+
if (allowed.has(actionName))
|
|
118
|
+
byAction.set(actionName, child);
|
|
119
|
+
else
|
|
120
120
|
child.remove();
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
byAction.set(actionName, child);
|
|
124
121
|
}
|
|
125
122
|
return byAction;
|
|
126
123
|
}
|
|
@@ -2,7 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Icon } from '../../../../react/components/Icon.js';
|
|
3
3
|
/** The composed `<MainMenu>` Excalidraw renders inside its own menu popover. */
|
|
4
4
|
export function SketchMainMenu({ MainMenu, t, saving, showSaved, canSave, onSave, exportAvailable, exporting, canExport, onExportImage, canClear, onClear, }) {
|
|
5
|
-
const
|
|
5
|
+
const idleSaveLabel = showSaved ? t('Saved') : t('Save');
|
|
6
|
+
const saveLabel = saving ? t('Saving…') : idleSaveLabel;
|
|
6
7
|
const exportLabel = exporting ? t('Exporting image…') : t('Export image');
|
|
7
8
|
return (_jsxs(MainMenu, { children: [_jsx(MainMenu.Item, { "data-testid": "sketch-menu-save", icon: showSaved ? _jsx(Icon, { name: "check", size: 16 }) : undefined, onClick: onSave, disabled: saving || !canSave, "aria-label": saveLabel, children: saveLabel }), exportAvailable ? (_jsx(MainMenu.Item, { "data-testid": "sketch-menu-export-image", icon: _jsx(Icon, { name: "download", size: 16 }), onClick: onExportImage, disabled: exporting || !canExport, "aria-label": exportLabel, children: exportLabel })) : null, _jsx(MainMenu.Separator, {}), _jsx(MainMenu.DefaultItems.SearchMenu, {}), _jsx(MainMenu.DefaultItems.Help, {}), _jsx(MainMenu.Item, { "data-testid": "sketch-menu-clear", icon: _jsx(Icon, { name: "trash", size: 16 }), onClick: onClear, disabled: !canClear, children: t('Clear canvas') }), _jsx(MainMenu.Separator, {}), _jsx(MainMenu.DefaultItems.ChangeCanvasBackground, {})] }));
|
|
8
9
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Icon } from '../../../../react/components/Icon.js';
|
|
3
|
+
const STATE_ICONS = { saving: 'spinner', dirty: 'alert-triangle' };
|
|
3
4
|
/** The small save-state indicator rendered in Excalidraw's own top-right UI slot. */
|
|
4
5
|
export function SketchSaveStateBadge({ state, label }) {
|
|
5
|
-
return (_jsx("div", { className: "sketch-excalidraw-actions", "data-testid": "sketch-save-state", children: _jsxs("span", { className: `sketch-save-state is-${state}`, role: "status", "aria-live": "polite", children: [_jsx(Icon, { name: state
|
|
6
|
+
return (_jsx("div", { className: "sketch-excalidraw-actions", "data-testid": "sketch-save-state", children: _jsxs("span", { className: `sketch-save-state is-${state}`, role: "status", "aria-live": "polite", children: [_jsx(Icon, { name: STATE_ICONS[state] ?? 'check', size: 12, className: state === 'saving' ? 'icon-spin' : undefined }), _jsx("span", { children: label })] }) }));
|
|
6
7
|
}
|
|
7
8
|
//# sourceMappingURL=SketchSaveStateBadge.js.map
|
|
@@ -16,7 +16,7 @@ export function useSketchDomEnhancements({ containerRef, t, domTextOverrides, to
|
|
|
16
16
|
useEffect(() => {
|
|
17
17
|
const root = containerRef.current;
|
|
18
18
|
if (!root)
|
|
19
|
-
return;
|
|
19
|
+
return undefined;
|
|
20
20
|
let frame = null;
|
|
21
21
|
const applyEnhancements = () => {
|
|
22
22
|
frame = null;
|
|
@@ -136,12 +136,15 @@ export function exportedImageFileName(fileName, sourceExtension) {
|
|
|
136
136
|
const slash = fileName.lastIndexOf('/');
|
|
137
137
|
const baseName = slash >= 0 ? fileName.slice(slash + 1) : fileName;
|
|
138
138
|
const stem = typeof sourceExtension === 'string'
|
|
139
|
-
? baseName
|
|
140
|
-
? baseName.slice(0, baseName.length - sourceExtension.length)
|
|
141
|
-
: baseName
|
|
139
|
+
? stripKnownExtension(baseName, sourceExtension)
|
|
142
140
|
: baseName.replace(/\.[^./]+$/, '');
|
|
143
141
|
return `${stem || 'sketch'}.png`;
|
|
144
142
|
}
|
|
143
|
+
function stripKnownExtension(baseName, extension) {
|
|
144
|
+
return baseName.toLowerCase().endsWith(extension.toLowerCase())
|
|
145
|
+
? baseName.slice(0, baseName.length - extension.length)
|
|
146
|
+
: baseName;
|
|
147
|
+
}
|
|
145
148
|
export function exportedImageResultFileName(result, fallback) {
|
|
146
149
|
if (result && typeof result === 'object' && typeof result.fileName === 'string') {
|
|
147
150
|
return result.fileName;
|
|
@@ -197,15 +200,13 @@ export function buildSketchTooltipLabels(t) {
|
|
|
197
200
|
* in `overrides` matches (caller should leave the node untouched).
|
|
198
201
|
*/
|
|
199
202
|
export function translateDomTextValue(value, overrides) {
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const
|
|
206
|
-
const
|
|
207
|
-
const core = match[2];
|
|
208
|
-
const trailing = match[3];
|
|
203
|
+
// Split into leading whitespace, core, trailing whitespace (an all-whitespace
|
|
204
|
+
// value is all leading). `trimStart`/`trimEnd` strip exactly regex `\s`.
|
|
205
|
+
const coreStart = value.length - value.trimStart().length;
|
|
206
|
+
const leading = value.slice(0, coreStart);
|
|
207
|
+
const rest = value.slice(coreStart);
|
|
208
|
+
const core = rest.trimEnd();
|
|
209
|
+
const trailing = rest.slice(core.length);
|
|
209
210
|
const normalized = core.replace(/\s+/g, ' ').trim();
|
|
210
211
|
if (!normalized)
|
|
211
212
|
return null;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { omitKeys } from '../../utils/omit-keys.js';
|
|
1
2
|
const DEFAULT_FAKE_SKILLS = [
|
|
2
3
|
{
|
|
3
4
|
id: 'skill-summarize',
|
|
@@ -10,9 +11,13 @@ const DEFAULT_FAKE_SKILLS = [
|
|
|
10
11
|
},
|
|
11
12
|
];
|
|
12
13
|
let nextFakeId = 1;
|
|
14
|
+
function takeFakeSkillId() {
|
|
15
|
+
const id = `fake-skill-${nextFakeId}`;
|
|
16
|
+
nextFakeId += 1;
|
|
17
|
+
return id;
|
|
18
|
+
}
|
|
13
19
|
function toSummary(detail) {
|
|
14
|
-
|
|
15
|
-
return summary;
|
|
20
|
+
return omitKeys(detail, ['body']);
|
|
16
21
|
}
|
|
17
22
|
/**
|
|
18
23
|
* An in-memory test/demo double. Per this package's established convention
|
|
@@ -39,7 +44,7 @@ export function createFakeSkillsPort(options = {}) {
|
|
|
39
44
|
return delay([...(files.get(id) ?? [])]);
|
|
40
45
|
},
|
|
41
46
|
createSkill(payload) {
|
|
42
|
-
const id =
|
|
47
|
+
const id = takeFakeSkillId();
|
|
43
48
|
const detail = {
|
|
44
49
|
id,
|
|
45
50
|
name: payload.name,
|
|
@@ -58,7 +63,7 @@ export function createFakeSkillsPort(options = {}) {
|
|
|
58
63
|
return Promise.reject(new Error(`Unknown skill: ${id}`));
|
|
59
64
|
// A built-in edit writes a NEW user-owned shadow copy, same as the
|
|
60
65
|
// origin — the requested id is never mutated in place.
|
|
61
|
-
const targetId = existing.source === 'user' ? id :
|
|
66
|
+
const targetId = existing.source === 'user' ? id : takeFakeSkillId();
|
|
62
67
|
const detail = {
|
|
63
68
|
...existing,
|
|
64
69
|
id: targetId,
|
|
@@ -18,7 +18,8 @@ export function SkillRow({ skill, locale, enabled, expanded, editing, body, body
|
|
|
18
18
|
// Built-in skills are never edited in place — "editing" one creates a
|
|
19
19
|
// user-owned override, so every edit affordance says so.
|
|
20
20
|
const editActionLabel = builtIn ? l.overrideCreateLabel : l.editLabel;
|
|
21
|
-
|
|
21
|
+
const editFormHandleProps = agentHandle ? { agentHandle: agentSubHandle({ base: agentHandle, action: 'edit-form' }) } : {};
|
|
22
|
+
return (_jsxs("div", { className: skillRowClassName({ enabled, expanded }), "data-testid": `skill-row-${skill.id}`, children: [_jsxs("div", { className: "jini-skills-row-head", children: [_jsx(SkillRowSummaryButton, { skill: skill, locale: locale, expanded: expanded, onToggleExpanded: onToggleExpanded, labels: l, agentHandle: agentHandle }), _jsxs("div", { className: "jini-skills-row-actions", children: [isDeletableSkill(skill) && confirmDelete ? (_jsx(SkillRowDeleteConfirm, { onCommitDelete: onCommitDelete, onCancelDelete: onCancelDelete, labels: l, agentHandle: agentHandle })) : (_jsx(SkillRowEditDeleteActions, { skill: skill, editActionLabel: editActionLabel, onStartEdit: onStartEdit, onArmDelete: onArmDelete, labels: l, agentHandle: agentHandle })), _jsxs("label", { className: "toggle-switch toggle-switch-sm jini-skills-row-enable", title: l.enableToggleLabel, children: [_jsx("input", { type: "checkbox", checked: enabled, onChange: (event) => onToggleEnabled(event.target.checked), "aria-label": l.enableToggleLabel, ...agentHandleProps({}, { base: agentHandle, action: 'enabled', role: 'checkbox', label: l.enableToggleLabel }) }), _jsx("span", { className: "toggle-slider" })] })] })] }), confirmBuiltInEdit ? (_jsx(SkillRowBuiltInEditWarning, { onCancelBuiltInEdit: onCancelBuiltInEdit, onConfirmBuiltInEdit: onConfirmBuiltInEdit, labels: l, agentHandle: agentHandle })) : null, expanded && !editing ? (_jsx(SkillRowDetail, { body: body, bodyLoading: bodyLoading, files: files, filesLoading: filesLoading, labels: l })) : null, editing && draft ? (_jsx(SkillDraftForm, { heading: editActionLabel, subheading: skill.id, draft: draft, onDraftChange: onDraftChange, error: draftError, saving: draftSaving, isEdit: true, isBuiltInOverride: builtIn, onCancel: onCancelEdit, onSubmit: onSubmitEdit, labels: labels, ...editFormHandleProps })) : null] }));
|
|
22
23
|
}
|
|
23
24
|
function skillRowClassName({ enabled, expanded }) {
|
|
24
25
|
return `jini-skills-row${enabled ? '' : ' jini-skills-row-disabled'}${expanded ? ' jini-skills-row-expanded' : ''}`;
|
|
@@ -21,7 +21,8 @@ export function SkillsTab({ port, disabledSkillIds, onToggleEnabled, locale = 'e
|
|
|
21
21
|
const tab = useSkillsTab({ port, locale });
|
|
22
22
|
const l = resolveLabels({ defaults: DEFAULT_SKILLS_TAB_LABELS, t }, { labels });
|
|
23
23
|
const loadErrorLabel = labels?.loadErrorLabel ?? t('Could not load skills: {error}', { error: tab.loadError ?? '' });
|
|
24
|
-
|
|
24
|
+
const createFormHandleProps = agentHandle ? { agentHandle: agentSubHandle({ base: agentHandle, action: 'create-form' }) } : {};
|
|
25
|
+
return (_jsxs("section", { className: "jini-settings-section jini-settings-skills", children: [_jsx(SkillsTabToolbar, { tab: tab, labels: l, agentHandle: agentHandle }), tab.loadError ? (_jsx("div", { className: "jini-empty-card jini-empty-card-error", children: _jsx("strong", { children: loadErrorLabel }) })) : null, tab.creating ? (_jsx(SkillDraftForm, { heading: l.newSkillLabel, draft: tab.draft, onDraftChange: tab.setDraft, error: tab.draftError, saving: tab.draftSaving, isEdit: false, onCancel: tab.cancelDraft, onSubmit: tab.submitDraft, labels: labels, ...createFormHandleProps })) : null, !tab.loading && tab.filteredSkills.length === 0 ? (_jsx("div", { className: "jini-empty-card", children: _jsx("strong", { children: l.noResultsLabel }) })) : (_jsx(SkillsTabRows, { tab: tab, disabledSkillIds: disabledSkillIds, onToggleEnabled: onToggleEnabled, locale: locale, labels: labels, agentHandle: agentHandle }))] }));
|
|
25
26
|
}
|
|
26
27
|
/** Search box, "New skill" button, and the source/mode/(category) selects. */
|
|
27
28
|
function SkillsTabToolbar({ tab, labels: l, agentHandle, }) {
|
|
@@ -146,16 +146,16 @@ const modeValue = (skill) => skill.mode;
|
|
|
146
146
|
const categoryValue = (skill) => typeof skill.category === 'string' && skill.category ? skill.category : null;
|
|
147
147
|
/** The data-derived pills (`mode`, `category`): option SET from every skill,
|
|
148
148
|
* COUNTS from `matching` — see `skillFilterOptions`. */
|
|
149
|
-
function valueFilterOptions({ skills, matching, valueOf, }) {
|
|
149
|
+
function valueFilterOptions({ skills, matching, valueOf: valueFor, }) {
|
|
150
150
|
const values = new Set();
|
|
151
151
|
for (const skill of skills) {
|
|
152
|
-
const value =
|
|
152
|
+
const value = valueFor(skill);
|
|
153
153
|
if (value !== null)
|
|
154
154
|
values.add(value);
|
|
155
155
|
}
|
|
156
156
|
const counts = new Map();
|
|
157
157
|
for (const skill of matching) {
|
|
158
|
-
const value =
|
|
158
|
+
const value = valueFor(skill);
|
|
159
159
|
if (value === null)
|
|
160
160
|
continue;
|
|
161
161
|
counts.set(value, (counts.get(value) ?? 0) + 1);
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
* why cards are keyed by id rather than list position.
|
|
40
40
|
*/
|
|
41
41
|
import { agentHandle, buildAgentListHandles } from '@jini-ai/agentic';
|
|
42
|
+
import { trimChars } from '../../utils/trim-chars.js';
|
|
42
43
|
/** Segments of a derived handle: `<base>-field-<key>` and `<base>-<action>` share one joiner. */
|
|
43
44
|
const HANDLE_SEPARATOR = '-';
|
|
44
45
|
/** The namespace every host-described field sits under — see this module's doc for why. */
|
|
@@ -65,11 +66,11 @@ const LIST_ITEM_NAMESPACE = 'item';
|
|
|
65
66
|
* @complexity O(n) in `segment.length`.
|
|
66
67
|
*/
|
|
67
68
|
function sanitizeHandleSegment(segment) {
|
|
68
|
-
|
|
69
|
+
const separated = segment
|
|
69
70
|
.replace(/([a-z0-9])([A-Z])/g, `$1${HANDLE_SEPARATOR}$2`)
|
|
70
71
|
.toLowerCase()
|
|
71
|
-
.replace(/[^a-z0-9]+/g, HANDLE_SEPARATOR)
|
|
72
|
-
|
|
72
|
+
.replace(/[^a-z0-9]+/g, HANDLE_SEPARATOR);
|
|
73
|
+
return trimChars(separated, '-');
|
|
73
74
|
}
|
|
74
75
|
/**
|
|
75
76
|
* The handle for one action or sub-control published under `base`.
|
|
@@ -122,7 +122,9 @@ function useItemCardEdit({ source, fieldSpecs, onUpdate }) {
|
|
|
122
122
|
/** The expanded body: the Edit/Save/Cancel toggle, the editable or read-only fields, and the test control. */
|
|
123
123
|
function ItemCardBody(props) {
|
|
124
124
|
const { capabilities, testing, testResult, onTest, agentHandle, edit } = props;
|
|
125
|
-
|
|
125
|
+
const testResultProps = testResult ? { result: testResult } : {};
|
|
126
|
+
const testHandleProps = agentHandle ? { agentHandle: sourceConfigActionHandle(agentHandle, 'test') } : {};
|
|
127
|
+
return (_jsxs("div", { className: "source-config-item-card-body", children: [capabilities.canUpdate ? _jsx(ItemCardEditToggle, { ...props, edit: edit }) : null, edit.editing ? _jsx(ItemCardEditFields, { ...props, edit: edit }) : _jsx(ItemCardReadOnlyFields, { ...props }), capabilities.canTest ? (_jsx(SourceConfigTestControl, { running: testing, disabled: isAnyActionPending(props), onTest: onTest, ...testResultProps, ...testHandleProps })) : null] }));
|
|
126
128
|
}
|
|
127
129
|
function ItemCardEditToggle(props) {
|
|
128
130
|
const { updating, agentHandle, edit } = props;
|
|
@@ -138,9 +138,11 @@ export function useActiveTabInView({ activeId }, _optional = {}) {
|
|
|
138
138
|
const tabBox = tab.getBoundingClientRect();
|
|
139
139
|
// A host's end padding (e.g. room for an edge fade) counts as off-screen.
|
|
140
140
|
const visibleRight = stripBox.right - (parseFloat(getComputedStyle(strip).paddingRight) || 0);
|
|
141
|
-
if (tabBox.left < stripBox.left)
|
|
141
|
+
if (tabBox.left < stripBox.left) {
|
|
142
142
|
strip.scrollLeft += tabBox.left - stripBox.left;
|
|
143
|
-
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (tabBox.right > visibleRight)
|
|
144
146
|
strip.scrollLeft += tabBox.right - visibleRight;
|
|
145
147
|
}
|
|
146
148
|
scrollActiveTabIntoView();
|
|
@@ -11,6 +11,9 @@ export function VersionPreviewFrame({ previewDocument, frameReady, onFrameLoad,
|
|
|
11
11
|
const [frameRef, canvasSize] = usePreviewCanvasSize();
|
|
12
12
|
const preset = findViewportPreset(viewportPresets, viewport);
|
|
13
13
|
const scale = effectivePreviewScale(preset, 1, canvasSize, DEFAULT_PREVIEW_CANVAS_PADDING);
|
|
14
|
-
|
|
14
|
+
const showEmpty = !previewDocument && !loading && !loadingContent;
|
|
15
|
+
const showLoading = loading || loadingContent || (previewDocument && !frameReady);
|
|
16
|
+
const emptyState = showEmpty ? _jsx("div", { className: "jini-viewer-empty", children: t('No preview available.') }) : null;
|
|
17
|
+
return (_jsx("div", { className: "jini-version-preview", ref: frameRef, children: error ? (_jsx("div", { className: "jini-viewer-empty", role: "alert", children: error })) : (_jsxs(_Fragment, { children: [previewDocument ? (_jsx("div", { className: "jini-preview-viewport", style: previewViewportStyle(preset, scale, 1), children: _jsx("div", { className: "jini-preview-frame-clip", children: _jsx("div", { style: previewScaleShellStyle(preset, 1), children: _jsx("iframe", { title: title, sandbox: "allow-scripts allow-downloads", srcDoc: previewDocument, onLoad: onFrameLoad }) }) }) })) : null, emptyState, showLoading ? (_jsx("div", { className: "jini-version-preview-overlay", role: "status", "aria-label": t('Loading preview…'), children: _jsx("span", { className: "jini-version-preview-spinner", "aria-hidden": "true" }) })) : null] })) }));
|
|
15
18
|
}
|
|
16
19
|
//# sourceMappingURL=VersionPreviewFrame.js.map
|
|
@@ -4,11 +4,13 @@ import { useT } from '../../../i18n/index.js';
|
|
|
4
4
|
* independent of whatever the preview pane is doing. */
|
|
5
5
|
export function VersionSidebar({ countLabel, search, onSearchChange, showSearch, loading, versions, visibleVersions, selectedVersionId, onSelect, onPrefetch, formatDate, sourceLabel, sourceClassName, restoredFrom, }) {
|
|
6
6
|
const t = useT();
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
const noResultsMessage = visibleVersions.length === 0 ? t('No results for “{query}”.', { query: search.trim() }) : null;
|
|
8
|
+
const emptyMessage = versions.length === 0 ? t('No versions yet.') : noResultsMessage;
|
|
9
|
+
return (_jsxs("div", { className: "jini-version-sidebar", children: [_jsx("div", { className: "jini-version-sidebar-head", children: _jsx("span", { className: "jini-version-count", children: countLabel }) }), showSearch ? (_jsxs("div", { className: "jini-version-search", children: [_jsx("input", { type: "search", value: search, onChange: (event) => onSearchChange(event.target.value), placeholder: t('Search…'), "aria-label": t('Search…') }), search ? (_jsx("button", { type: "button", className: "jini-version-search-clear", "aria-label": t('Clear'), onClick: () => onSearchChange(''), children: t('Clear') })) : null] })) : null, _jsxs("div", { className: "jini-version-list", role: "listbox", "aria-label": t('Version history'), children: [loading ? (_jsx("div", { className: "jini-version-skeleton-list", role: "status", "aria-label": t('Loading versions…'), children: [0, 1, 2, 3].map((row) => (_jsx("div", { className: "jini-version-skeleton-item", "aria-hidden": "true" }, row))) })) : null, !loading && emptyMessage ? _jsx("div", { className: "jini-version-empty", children: emptyMessage }) : null, !loading && !emptyMessage ? (visibleVersions.map((version) => {
|
|
10
|
+
const selected = version.id === selectedVersionId;
|
|
11
|
+
const itemRestoredFrom = restoredFrom(version);
|
|
12
|
+
const prefetch = () => onPrefetch(version.id);
|
|
13
|
+
return (_jsxs("button", { type: "button", className: `jini-version-item${selected ? ' active' : ''}`, role: "option", "aria-selected": selected, onClick: () => onSelect(version.id), onMouseEnter: prefetch, onFocus: prefetch, children: [_jsxs("span", { className: "jini-version-item-top", children: [version.current ? _jsx("span", { className: "jini-version-current-badge", children: t('Current') }) : null, _jsx("span", { className: `jini-version-source-badge ${sourceClassName(version)}`, children: sourceLabel(version) }), _jsx("span", { className: "jini-version-time", children: formatDate(version) })] }), _jsx("span", { className: "jini-version-item-title", children: version.prompt || version.label || t('Version {version}', { version: version.version }) }), _jsxs("span", { className: "jini-version-item-meta", children: [t('Version {version}', { version: version.version }), itemRestoredFrom ? (_jsx("span", { className: "jini-version-item-restored", children: t('Restored from v{version}', { version: itemRestoredFrom.version }) })) : null] })] }, version.id));
|
|
14
|
+
})) : null] })] }));
|
|
13
15
|
}
|
|
14
16
|
//# sourceMappingURL=VersionSidebar.js.map
|
|
@@ -16,7 +16,7 @@ export function usePreviewCanvasSize() {
|
|
|
16
16
|
// dead-branch-gets-refactored-away rule.
|
|
17
17
|
const el = ref.current;
|
|
18
18
|
if (!el)
|
|
19
|
-
return;
|
|
19
|
+
return undefined;
|
|
20
20
|
const measure = () => {
|
|
21
21
|
const rect = el.getBoundingClientRect();
|
|
22
22
|
setSize({ width: rect.width, height: rect.height });
|
|
@@ -108,10 +108,8 @@ export function useVersionManager(dependencies, options) {
|
|
|
108
108
|
setVersions(nextVersions);
|
|
109
109
|
const currentVersion = nextVersions.find((version) => version.current);
|
|
110
110
|
seedCurrentVersionContent({ currentVersion, currentContent, contentCache: contentCacheRef.current });
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
nextVersions[0] ??
|
|
114
|
-
null;
|
|
111
|
+
const preferredVersion = preferredId ? nextVersions.find((version) => version.id === preferredId) : null;
|
|
112
|
+
const nextSelected = preferredVersion ?? currentVersion ?? nextVersions[0] ?? null;
|
|
115
113
|
setSelectedId(nextSelected?.id ?? null);
|
|
116
114
|
setLoading(false);
|
|
117
115
|
}, [port, fileRef, currentContent]);
|
|
@@ -125,7 +123,7 @@ export function useVersionManager(dependencies, options) {
|
|
|
125
123
|
if (!selectedId) {
|
|
126
124
|
setSelectedContent(null);
|
|
127
125
|
setSelectedContentVersionId(null);
|
|
128
|
-
return;
|
|
126
|
+
return undefined;
|
|
129
127
|
}
|
|
130
128
|
const cached = contentCacheRef.current.get(selectedId);
|
|
131
129
|
if (cached !== undefined) {
|
|
@@ -138,7 +136,7 @@ export function useVersionManager(dependencies, options) {
|
|
|
138
136
|
else {
|
|
139
137
|
setError(null);
|
|
140
138
|
}
|
|
141
|
-
return;
|
|
139
|
+
return undefined;
|
|
142
140
|
}
|
|
143
141
|
// Cache miss: keep the previous preview mounted (don't clear
|
|
144
142
|
// `selectedContent`) so switching versions never blanks to empty while
|
|
@@ -177,7 +175,7 @@ export function useVersionManager(dependencies, options) {
|
|
|
177
175
|
// is ever missed.
|
|
178
176
|
useEffect(() => {
|
|
179
177
|
if (!previewDocument || loadedPreviewDocument === previewDocument)
|
|
180
|
-
return;
|
|
178
|
+
return undefined;
|
|
181
179
|
const fallback = setTimeout(() => setLoadedPreviewDocument(previewDocument), PREVIEW_LOAD_FALLBACK_MS);
|
|
182
180
|
return () => clearTimeout(fallback);
|
|
183
181
|
}, [previewDocument, loadedPreviewDocument]);
|
|
@@ -89,11 +89,9 @@ export function filterVersionsBySearch(versions, search, describe) {
|
|
|
89
89
|
* current, no restoring mid-fetch, no restoring stale/mismatched content). */
|
|
90
90
|
export function isRestoreDisabled(input) {
|
|
91
91
|
const { selectedVersion, restoring, loadingContent, selectedContentMatchesVersion } = input;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
loadingContent ||
|
|
96
|
-
!selectedContentMatchesVersion);
|
|
92
|
+
if (!selectedVersion || selectedVersion.current)
|
|
93
|
+
return true;
|
|
94
|
+
return restoring || loadingContent || !selectedContentMatchesVersion;
|
|
97
95
|
}
|
|
98
96
|
/** Whether the currently-loaded preview content actually corresponds to the
|
|
99
97
|
* currently-selected version (guards against acting on stale content
|
|
@@ -113,7 +113,8 @@ function CommentSideSelectBar({ selectedCount, sending, sendDisabled, queueOnSen
|
|
|
113
113
|
const t = useT();
|
|
114
114
|
if (selectedCount === 0)
|
|
115
115
|
return null;
|
|
116
|
-
|
|
116
|
+
const idleSendLabel = queueOnSend ? t('Queue') : t('Send to chat');
|
|
117
|
+
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…') : idleSendLabel })] }));
|
|
117
118
|
}
|
|
118
119
|
function CommentSideCreateForm({ renderCreateForm, draft, onDraftChange, onCreateComment, sending, sendDisabled, }) {
|
|
119
120
|
const t = useT();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { RemixIcon } from '../../../../react/components/RemixIcon.js';
|
|
3
|
+
import { withClassName } from '../../../../utils/class-names.js';
|
|
3
4
|
/**
|
|
4
5
|
* A small, always-visible group of toggle buttons, one active at a time.
|
|
5
6
|
* This is the shared primitive behind two call sites that turned out to be
|
|
@@ -14,7 +15,7 @@ import { RemixIcon } from '../../../../react/components/RemixIcon.js';
|
|
|
14
15
|
* primitives for a minor ARIA-pattern difference.
|
|
15
16
|
*/
|
|
16
17
|
export function SegmentedToggle({ options, value, onChange, ariaLabel, className, }) {
|
|
17
|
-
return (_jsx("div", { className:
|
|
18
|
+
return (_jsx("div", { className: withClassName('viewer-segmented-toggle', className), role: "group", "aria-label": ariaLabel, children: options.map((option) => {
|
|
18
19
|
const selected = option.value === value;
|
|
19
20
|
const label = option.title ?? option.label;
|
|
20
21
|
return (_jsxs("button", { type: "button", className: `viewer-segmented-toggle-button${selected ? ' active' : ''}`, "aria-pressed": selected, "aria-label": label, title: label, onClick: () => onChange(option.value), children: [option.icon ? _jsx(RemixIcon, { name: option.icon, size: 14 }) : null, _jsx("span", { children: option.label })] }, option.value));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { withClassName } from '../../../../utils/class-names.js';
|
|
2
3
|
/**
|
|
3
4
|
* The "viewer-toolbar + viewer-body" chrome independently repeated across
|
|
4
5
|
* 8 media-viewer components in the source file (`BinaryViewer`,
|
|
@@ -9,7 +10,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
9
10
|
* layout wrapper.
|
|
10
11
|
*/
|
|
11
12
|
export function ViewerShell({ kindClassName, toolbarLeft, toolbarActions, bodyClassName, children }) {
|
|
12
|
-
return (_jsxs("div", { className:
|
|
13
|
+
return (_jsxs("div", { className: withClassName('viewer', kindClassName), children: [_jsxs("div", { className: "viewer-toolbar", children: [_jsx("div", { className: "viewer-toolbar-left", children: toolbarLeft }), toolbarActions ? _jsx("div", { className: "viewer-toolbar-actions", children: toolbarActions }) : null] }), _jsx("div", { className: withClassName('viewer-body', bodyClassName), children: children })] }));
|
|
13
14
|
}
|
|
14
15
|
/** Trivial "nothing to show" placeholder shared by every viewer body. */
|
|
15
16
|
export function ViewerEmptyState({ children }) {
|
|
@@ -97,13 +97,14 @@ export function hasPrecisionSensitiveJsonNumberText(text) {
|
|
|
97
97
|
}
|
|
98
98
|
numberTokenPattern.lastIndex = i;
|
|
99
99
|
const match = numberTokenPattern.exec(text);
|
|
100
|
-
if (
|
|
100
|
+
if (match) {
|
|
101
|
+
if (isPrecisionSensitiveNumberLiteral(match[0]))
|
|
102
|
+
return true;
|
|
103
|
+
i = numberTokenPattern.lastIndex;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
101
106
|
i += 1;
|
|
102
|
-
continue;
|
|
103
107
|
}
|
|
104
|
-
if (isPrecisionSensitiveNumberLiteral(match[0]))
|
|
105
|
-
return true;
|
|
106
|
-
i = numberTokenPattern.lastIndex;
|
|
107
108
|
}
|
|
108
109
|
return false;
|
|
109
110
|
}
|
|
@@ -111,10 +112,10 @@ export function hasPrecisionSensitiveJsonNumberText(text) {
|
|
|
111
112
|
* `start` (honouring `\` escapes), or `text.length` when it is unterminated. */
|
|
112
113
|
function indexAfterJsonString(text, start) {
|
|
113
114
|
for (let i = start; i < text.length; i += 1) {
|
|
115
|
+
if (text[i] === '"')
|
|
116
|
+
return i + 1;
|
|
114
117
|
if (text[i] === '\\')
|
|
115
118
|
i += 1;
|
|
116
|
-
else if (text[i] === '"')
|
|
117
|
-
return i + 1;
|
|
118
119
|
}
|
|
119
120
|
return text.length;
|
|
120
121
|
}
|
|
@@ -18,12 +18,20 @@ export function brandMonogram(name) {
|
|
|
18
18
|
}
|
|
19
19
|
/** The stage to start at, given which sources are available. */
|
|
20
20
|
export function firstLogoStage(opts) {
|
|
21
|
-
|
|
21
|
+
if (opts.canUseBrandStage)
|
|
22
|
+
return 'brand';
|
|
23
|
+
return fallbackLogoStage(opts);
|
|
24
|
+
}
|
|
25
|
+
/** The first non-brand stage whose source is available. */
|
|
26
|
+
function fallbackLogoStage(opts) {
|
|
27
|
+
if (opts.logoSrc)
|
|
28
|
+
return 'custom';
|
|
29
|
+
return opts.host ? 'favicon' : 'letter';
|
|
22
30
|
}
|
|
23
31
|
/** The next stage to try after the current one fails to load. */
|
|
24
32
|
export function advanceLogoStage(stage, opts) {
|
|
25
33
|
if (stage === 'brand')
|
|
26
|
-
return opts
|
|
34
|
+
return fallbackLogoStage(opts);
|
|
27
35
|
if (stage === 'custom')
|
|
28
36
|
return 'favicon';
|
|
29
37
|
return 'letter';
|
|
@@ -233,7 +233,7 @@ export function useCustomSelectOriginTheme({ buttonRef, open, portal }, _optiona
|
|
|
233
233
|
const [attributes, setAttributes] = useState({});
|
|
234
234
|
useLayoutEffect(() => {
|
|
235
235
|
if (!open || !portal)
|
|
236
|
-
return;
|
|
236
|
+
return undefined;
|
|
237
237
|
const update = () => {
|
|
238
238
|
const next = resolveCustomSelectOriginTheme({ trigger: buttonRef.current });
|
|
239
239
|
setAttributes((current) => current['data-admin-theme'] === next['data-admin-theme']
|