@jini-ai/ui 0.6.15-rc.2 → 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/providers/shadcn/data-table.js +10 -5
- 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/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
|
@@ -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']
|
|
@@ -36,21 +36,24 @@ const xcodePath = 'M19.06 5.3327c.4517-.1936.7744-.2581 1.097-.1936.5163.1291.77
|
|
|
36
36
|
const webstormPath = 'M0 0v24h24V0H0zm17.889 2.889c1.444 0 2.667.444 3.667 1.278l-1.111 1.667c-.889-.611-1.722-1-2.556-1s-1.278.389-1.278.889v.056c0 .667.444.889 2.111 1.333 2 .556 3.111 1.278 3.111 3v.056c0 2-1.5 3.111-3.611 3.111-1.5-.056-3-.611-4.167-1.667l1.278-1.556c.889.722 1.833 1.222 2.944 1.222.889 0 1.389-.333 1.389-.944v-.056c0-.556-.333-.833-2-1.278-2-.5-3.222-1.056-3.222-3.056v-.056c0-1.833 1.444-3 3.444-3zm-16.111.222h2.278l1.5 5.778 1.722-5.778h1.667l1.667 5.778 1.5-5.778h2.333l-2.833 9.944H9.723L8.112 7.277l-1.667 5.778H4.612L1.779 3.111zm.5 16.389h9V21h-9v-1.5z';
|
|
37
37
|
const ideaPath = 'M0 0v24h24V0zm3.723 3.111h5v1.834h-1.39v6.277h1.39v1.834h-5v-1.834h1.444V4.945H3.723zm11.055 0H17v6.5c0 .612-.055 1.111-.222 1.556-.167.444-.39.777-.723 1.11-.277.279-.666.557-1.11.668a3.933 3.933 0 0 1-1.445.278c-.778 0-1.444-.167-1.944-.445a4.81 4.81 0 0 1-1.279-1.056l1.39-1.555c.277.334.555.555.833.722.277.167.611.278.945.278.389 0 .721-.111 1-.389.221-.278.333-.667.333-1.278zM2.222 19.5h9V21h-9z';
|
|
38
38
|
const warpPath = 'M12.035 2.723h9.253A2.712 2.712 0 0 1 24 5.435v10.529a2.712 2.712 0 0 1-2.712 2.713H8.047Zm-1.681 2.6L6.766 19.677h5.598l-.399 1.6H2.712A2.712 2.712 0 0 1 0 18.565V8.036a2.712 2.712 0 0 1 2.712-2.712Z';
|
|
39
|
+
const PRIMARY = 'var(--jini-primary)';
|
|
40
|
+
const BG = 'var(--jini-bg)';
|
|
41
|
+
const TEXT = 'var(--jini-text)';
|
|
39
42
|
const EDITORS = {
|
|
40
|
-
vscode: { bg:
|
|
41
|
-
cursor: { bg:
|
|
42
|
-
windsurf: { bg:
|
|
43
|
-
zed: { bg:
|
|
44
|
-
qoder: { bg: 'var(--jini-warning)', fg:
|
|
45
|
-
antigravity: { bg:
|
|
46
|
-
webstorm: { bg:
|
|
47
|
-
idea: { bg:
|
|
48
|
-
xcode: { bg:
|
|
49
|
-
finder: { bg:
|
|
50
|
-
explorer: { bg: 'var(--jini-warning)', fg:
|
|
51
|
-
'file-manager': { bg: 'var(--jini-muted)', fg:
|
|
52
|
-
terminal: { bg:
|
|
53
|
-
warp: { bg:
|
|
43
|
+
vscode: { bg: PRIMARY, fg: BG, glyph: vscodeLogo },
|
|
44
|
+
cursor: { bg: TEXT, fg: BG, glyph: simplePath(cursorPath) },
|
|
45
|
+
windsurf: { bg: BG, fg: TEXT, glyph: simplePath(windsurfPath) },
|
|
46
|
+
zed: { bg: PRIMARY, fg: BG, glyph: simplePath(zedPath) },
|
|
47
|
+
qoder: { bg: 'var(--jini-warning)', fg: TEXT, glyph: qoderLogo },
|
|
48
|
+
antigravity: { bg: BG, fg: TEXT, glyph: antigravityLogo },
|
|
49
|
+
webstorm: { bg: TEXT, fg: BG, glyph: simplePath(webstormPath) },
|
|
50
|
+
idea: { bg: TEXT, fg: BG, glyph: simplePath(ideaPath) },
|
|
51
|
+
xcode: { bg: PRIMARY, fg: BG, glyph: simplePath(xcodePath) },
|
|
52
|
+
finder: { bg: PRIMARY, fg: BG, glyph: finderLogo },
|
|
53
|
+
explorer: { bg: 'var(--jini-warning)', fg: TEXT, glyph: folderLogo },
|
|
54
|
+
'file-manager': { bg: 'var(--jini-muted)', fg: BG, glyph: folderLogo },
|
|
55
|
+
terminal: { bg: TEXT, fg: 'var(--jini-success)', glyph: terminalLogo },
|
|
56
|
+
warp: { bg: PRIMARY, fg: BG, glyph: simplePath(warpPath) },
|
|
54
57
|
};
|
|
55
58
|
/**
|
|
56
59
|
* Renders an editor/target glyph by string key using the host's theme, with a
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Icon } from './Icon.js';
|
|
3
|
+
import { withClassName } from '../../utils/class-names.js';
|
|
3
4
|
export function Spinner({ size = 14, label }) {
|
|
4
5
|
return (_jsxs("span", { className: "loading-spinner", role: "status", "aria-live": "polite", children: [_jsx(Icon, { name: "spinner", size: size }), label ? _jsx("span", { className: "loading-spinner-label", children: label }) : null] }));
|
|
5
6
|
}
|
|
6
7
|
export function Skeleton({ width, height = 14, radius = 6, className }) {
|
|
7
|
-
return (_jsx("span", { className:
|
|
8
|
+
return (_jsx("span", { className: withClassName('skeleton-block', className), style: { width, height, borderRadius: radius }, "aria-hidden": true }));
|
|
8
9
|
}
|
|
9
10
|
/**
|
|
10
11
|
* Card-shaped skeleton for grid layouts (thumbnail area over a row of meta
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/** A single-select value as a selection list; an empty string selects nothing. */
|
|
3
|
+
function singleSelection(value) {
|
|
4
|
+
return value ? [value] : [];
|
|
5
|
+
}
|
|
2
6
|
export function OnboardingChipField(props) {
|
|
3
7
|
const { label, options, className } = props;
|
|
4
|
-
const selected = props.multiple ? props.value : props.value
|
|
8
|
+
const selected = props.multiple ? props.value : singleSelection(props.value);
|
|
5
9
|
return (_jsxs("div", { className: ['onboarding-chip-field', className].filter(Boolean).join(' '), children: [_jsx("span", { className: "onboarding-chip-field__label", children: label }), _jsx("div", { className: "onboarding-chip-field__chips", children: options.map((option) => {
|
|
6
10
|
const active = selected.includes(option.value);
|
|
7
11
|
return (_jsx("button", { type: "button", className: `onboarding-chip${active ? ' is-selected' : ''}`, "aria-pressed": active, onClick: () => {
|
|
@@ -51,7 +51,9 @@ export const ONBOARDING_MENU_FALLBACK_VIEWPORT = 720;
|
|
|
51
51
|
* string (or otherwise falsy value) becomes an empty selection.
|
|
52
52
|
*/
|
|
53
53
|
export function resolveOnboardingSelectedValues(value) {
|
|
54
|
-
|
|
54
|
+
if (Array.isArray(value))
|
|
55
|
+
return value;
|
|
56
|
+
return value ? [value] : [];
|
|
55
57
|
}
|
|
56
58
|
/**
|
|
57
59
|
* Compute the trigger's visible label. In multiple mode it joins every
|
|
@@ -121,7 +123,7 @@ export function useOnboardingDropdownPlacement(rootRef, open, placement, optionC
|
|
|
121
123
|
});
|
|
122
124
|
useLayoutEffect(() => {
|
|
123
125
|
if (!open)
|
|
124
|
-
return;
|
|
126
|
+
return undefined;
|
|
125
127
|
function measureMenu() {
|
|
126
128
|
const node = rootRef.current;
|
|
127
129
|
if (!node)
|
|
@@ -153,11 +155,11 @@ export function useOnboardingDropdown(props) {
|
|
|
153
155
|
const [open, setOpen] = useState(false);
|
|
154
156
|
const [query, setQuery] = useState('');
|
|
155
157
|
const rootRef = useRef(null);
|
|
156
|
-
const dropdownIdRef = useRef(`onboarding-dropdown-${
|
|
158
|
+
const dropdownIdRef = useRef(`onboarding-dropdown-${globalThis.crypto.getRandomValues(new Uint32Array(1))[0].toString(36)}`);
|
|
157
159
|
const { placement: resolvedPlacement, maxHeight: menuMaxHeight } = useOnboardingDropdownPlacement(rootRef, open, placement, options.length);
|
|
158
160
|
useEffect(() => {
|
|
159
161
|
if (!open)
|
|
160
|
-
return;
|
|
162
|
+
return undefined;
|
|
161
163
|
function handlePointerDown(event) {
|
|
162
164
|
if (!rootRef.current?.contains(event.target)) {
|
|
163
165
|
setOpen(false);
|
|
@@ -10,12 +10,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
10
10
|
// hook-testable in isolation.
|
|
11
11
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
12
12
|
import { Icon } from './Icon.js';
|
|
13
|
+
const PRIMARY = 'var(--jini-primary)';
|
|
13
14
|
export const PALETTE_TWEAKS_SWATCHES = [
|
|
14
|
-
{ id: 'coral', label: 'Coral - default', stripe: [
|
|
15
|
-
{ id: 'electric', label: 'Electric', stripe: [
|
|
16
|
-
{ id: 'acid-forest', label: 'Acid forest', stripe: [
|
|
17
|
-
{ id: 'risograph', label: 'Risograph', stripe: [
|
|
18
|
-
{ id: 'mono-noir', label: 'Mono noir', stripe: ['var(--jini-text)',
|
|
15
|
+
{ id: 'coral', label: 'Coral - default', stripe: [PRIMARY, PRIMARY, PRIMARY, PRIMARY] },
|
|
16
|
+
{ id: 'electric', label: 'Electric', stripe: [PRIMARY, PRIMARY, PRIMARY, PRIMARY] },
|
|
17
|
+
{ id: 'acid-forest', label: 'Acid forest', stripe: [PRIMARY, PRIMARY, PRIMARY, PRIMARY] },
|
|
18
|
+
{ id: 'risograph', label: 'Risograph', stripe: [PRIMARY, PRIMARY, PRIMARY, PRIMARY] },
|
|
19
|
+
{ id: 'mono-noir', label: 'Mono noir', stripe: ['var(--jini-text)', PRIMARY, PRIMARY, PRIMARY] },
|
|
19
20
|
];
|
|
20
21
|
// --- Pure derivations (module-level, directly unit-testable) --------------
|
|
21
22
|
/**
|
|
@@ -71,7 +72,7 @@ export function usePaletteDismiss(options) {
|
|
|
71
72
|
const rootRef = useRef(null);
|
|
72
73
|
useEffect(() => {
|
|
73
74
|
if (!open)
|
|
74
|
-
return;
|
|
75
|
+
return undefined;
|
|
75
76
|
function onDoc(ev) {
|
|
76
77
|
if (!rootRef.current)
|
|
77
78
|
return;
|
|
@@ -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
|
* Generic labeled trigger pill: icon + label (+ optional trailing icon),
|
|
4
5
|
* togglable `active` state, and an optional anchored children slot for a
|
|
@@ -9,6 +10,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
9
10
|
* (recon r6 §1.19) — generic popover-trigger chrome, no product types.
|
|
10
11
|
*/
|
|
11
12
|
export function PillButton({ icon, label, active = false, 'aria-label': ariaLabel, trailingIcon, onClick, disabled = false, className, children, }) {
|
|
12
|
-
return (_jsxs("div", { className:
|
|
13
|
+
return (_jsxs("div", { className: withClassName('jini-pill-wrap', className), children: [_jsxs("button", { type: "button", className: `jini-pill${active ? ' is-active' : ''}`, "aria-label": ariaLabel, "aria-expanded": children ? active : undefined, onClick: onClick, disabled: disabled, children: [icon, _jsx("span", { className: "jini-pill__label", children: label }), trailingIcon] }), children] }));
|
|
13
14
|
}
|
|
14
15
|
//# sourceMappingURL=PillButton.js.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { withClassName } from '../../utils/class-names.js';
|
|
2
3
|
/**
|
|
3
4
|
* Generic popover panel shell: a plain positioned wrapper around a list of
|
|
4
5
|
* `PopoverItem`s (or any other content). No open/closed state of its own —
|
|
@@ -8,6 +9,6 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
8
9
|
* (recon r6 §1.19) — generic, no product types.
|
|
9
10
|
*/
|
|
10
11
|
export function PopoverMenu({ children, className }) {
|
|
11
|
-
return _jsx("div", { className:
|
|
12
|
+
return _jsx("div", { className: withClassName('jini-popover', className), children: children });
|
|
12
13
|
}
|
|
13
14
|
//# sourceMappingURL=PopoverMenu.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect } from 'react';
|
|
3
3
|
import { ensureRemixIconStylesheet } from './RemixIcon.stylesheet.js';
|
|
4
|
+
import { withClassName } from '../../utils/class-names.js';
|
|
4
5
|
export { installRemixIconStylesheet, REMIXICON_STYLESHEET_MARKER } from './RemixIcon.stylesheet.js';
|
|
5
6
|
/**
|
|
6
7
|
* Thin wrapper around a RemixIcon webfont glyph (`ri-<name>`). Loads this package's own default
|
|
@@ -12,7 +13,7 @@ export function RemixIcon({ name, size = 14, className, style }) {
|
|
|
12
13
|
useEffect(() => {
|
|
13
14
|
ensureRemixIconStylesheet({});
|
|
14
15
|
}, []);
|
|
15
|
-
return (_jsx("i", { className: `ri-${name}
|
|
16
|
+
return (_jsx("i", { className: withClassName(`ri-${name}`, className), "aria-hidden": "true", style: {
|
|
16
17
|
fontSize: size,
|
|
17
18
|
lineHeight: 1,
|
|
18
19
|
width: size,
|
|
@@ -1,26 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
readonly value: unknown;
|
|
4
|
-
/** The toggle's full accessible names, translated ("Show API key" / "Hide API key"). */
|
|
5
|
-
readonly labels: {
|
|
6
|
-
readonly show: string;
|
|
7
|
-
readonly hide: string;
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
export interface SecretRevealOptional {
|
|
11
|
-
/** Controlled mode: the host owns the shown/hidden state (e.g. to reset it per provider). */
|
|
12
|
-
readonly revealed?: boolean;
|
|
13
|
-
readonly onRevealedChange?: (revealed: boolean) => void;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* The show/hide state behind `SecretInput`'s eye toggle. Starts hidden. Uncontrolled, it re-hides on
|
|
17
|
-
* the value's transition to empty only — an empty field may still be revealed before pasting.
|
|
18
|
-
* @complexity O(1).
|
|
19
|
-
*/
|
|
20
|
-
export declare function useSecretReveal(required: SecretRevealRequired, optional?: SecretRevealOptional): {
|
|
21
|
-
readonly revealed: boolean;
|
|
22
|
-
readonly inputType: "text" | "password";
|
|
23
|
-
readonly toggleLabel: string;
|
|
24
|
-
readonly toggle: () => void;
|
|
25
|
-
};
|
|
1
|
+
/** Compatibility entry; ui-kit owns the shared secret reveal lifecycle. */
|
|
2
|
+
export { useSecretReveal, type SecretRevealRequired, type SecretRevealOptional } from "@jini-ai/ui-kit/react";
|
|
26
3
|
//# sourceMappingURL=SecretInput.hooks.d.ts.map
|
|
@@ -1,25 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* The show/hide state behind `SecretInput`'s eye toggle. Starts hidden. Uncontrolled, it re-hides on
|
|
4
|
-
* the value's transition to empty only — an empty field may still be revealed before pasting.
|
|
5
|
-
* @complexity O(1).
|
|
6
|
-
*/
|
|
7
|
-
export function useSecretReveal(required, optional = {}) {
|
|
8
|
-
const [ownRevealed, setOwnRevealed] = useState(false);
|
|
9
|
-
const [lastValue, setLastValue] = useState(required.value);
|
|
10
|
-
if (required.value !== lastValue) {
|
|
11
|
-
setLastValue(required.value);
|
|
12
|
-
if (required.value === '')
|
|
13
|
-
setOwnRevealed(false);
|
|
14
|
-
}
|
|
15
|
-
const revealed = optional.revealed ?? ownRevealed;
|
|
16
|
-
const toggleLabel = revealed ? required.labels.hide : required.labels.show;
|
|
17
|
-
const toggle = () => {
|
|
18
|
-
if (optional.onRevealedChange)
|
|
19
|
-
optional.onRevealedChange(!revealed);
|
|
20
|
-
else
|
|
21
|
-
setOwnRevealed(!revealed);
|
|
22
|
-
};
|
|
23
|
-
return { revealed, inputType: revealed ? 'text' : 'password', toggleLabel, toggle };
|
|
24
|
-
}
|
|
1
|
+
/** Compatibility entry; ui-kit owns the shared secret reveal lifecycle. */
|
|
2
|
+
export { useSecretReveal } from "@jini-ai/ui-kit/react";
|
|
25
3
|
//# sourceMappingURL=SecretInput.hooks.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef } from 'react';
|
|
3
|
+
import { SecretInput as KitSecretInput } from '@jini-ai/ui-kit/react';
|
|
3
4
|
import { useT } from '../../features/i18n/index.js';
|
|
4
5
|
import { Icon } from './Icon.js';
|
|
5
6
|
import { useSecretReveal } from './SecretInput.hooks.js';
|
|
@@ -13,10 +14,10 @@ function useSecretToggle({ label, toggleLabels, toggleAttrs, revealed, onReveale
|
|
|
13
14
|
return { reveal, button };
|
|
14
15
|
}
|
|
15
16
|
export const SecretInput = forwardRef(function SecretInput(props, ref) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
const t = useT();
|
|
18
|
+
return _jsx(KitSecretInput, { ...props, ref: ref, toggleLabels: props.toggleLabels ?? {
|
|
19
|
+
show: `${t('Show')} ${props.label}`, hide: `${t('Hide')} ${props.label}`,
|
|
20
|
+
} });
|
|
20
21
|
});
|
|
21
22
|
export const SecretTextarea = forwardRef(function SecretTextarea(props, ref) {
|
|
22
23
|
const { label, toggleLabels, toggleAttrs, revealed, onRevealedChange, style, maskedValue, ...textareaProps } = props;
|
|
@@ -15,6 +15,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
15
15
|
// hook-testable in isolation.
|
|
16
16
|
import { useCallback, useEffect, useRef, useState, } from 'react';
|
|
17
17
|
import { Icon } from './Icon.js';
|
|
18
|
+
import { withClassName } from '../../utils/class-names.js';
|
|
18
19
|
export const TOAST_DEFAULT_TTL = 4000;
|
|
19
20
|
// Exit fade duration — kept in sync with the `.jini-toast.leaving` CSS
|
|
20
21
|
// animation the host supplies. The fade plays inside the TTL window (it
|
|
@@ -65,7 +66,8 @@ export function toastFadeDelay(effectiveTtl) {
|
|
|
65
66
|
/** The root `className` string, composed from tone/placement/extra/leaving. */
|
|
66
67
|
export function toastClassName(options) {
|
|
67
68
|
const { tone, placement, className, leaving } = options;
|
|
68
|
-
|
|
69
|
+
const base = withClassName(`jini-toast tone-${tone} placement-${placement}`, className);
|
|
70
|
+
return leaving ? `${base} leaving` : base;
|
|
69
71
|
}
|
|
70
72
|
// --- Hooks (co-located, exported) -----------------------------------------
|
|
71
73
|
/**
|
|
@@ -105,7 +107,7 @@ export function useToastAutoDismiss(options) {
|
|
|
105
107
|
// prior leaving state before re-arming the timers.
|
|
106
108
|
setLeaving(false);
|
|
107
109
|
if (!toastShouldAutoDismiss(hasDismiss, effectiveTtl))
|
|
108
|
-
return;
|
|
110
|
+
return undefined;
|
|
109
111
|
const fadeId = window.setTimeout(() => setLeaving(true), toastFadeDelay(effectiveTtl));
|
|
110
112
|
const dismissId = window.setTimeout(fireDismiss, effectiveTtl);
|
|
111
113
|
return () => {
|
|
@@ -46,6 +46,9 @@ export function positionTooltip(target, tooltip, placement) {
|
|
|
46
46
|
left = rect.right + TOOLTIP_GAP;
|
|
47
47
|
top = rect.top + rect.height / 2 - tip.height / 2;
|
|
48
48
|
}
|
|
49
|
+
else {
|
|
50
|
+
// 'top': the centred-above position computed above already applies.
|
|
51
|
+
}
|
|
49
52
|
return {
|
|
50
53
|
x: Math.round(clamp(left, TOOLTIP_MARGIN, maxLeft)),
|
|
51
54
|
y: Math.round(clamp(top, TOOLTIP_MARGIN, maxTop)),
|
|
@@ -180,7 +183,7 @@ export function useTooltipLayer() {
|
|
|
180
183
|
}, [restoreNativeTitle]);
|
|
181
184
|
useEffect(() => {
|
|
182
185
|
if (!state?.target || typeof MutationObserver === 'undefined')
|
|
183
|
-
return;
|
|
186
|
+
return undefined;
|
|
184
187
|
const target = state.target;
|
|
185
188
|
const observer = new MutationObserver(() => {
|
|
186
189
|
if (!isTooltipTarget(target)) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useId, useRef, useState, } from 'react';
|
|
3
3
|
import { Icon } from './Icon.js';
|
|
4
|
+
import { withClassName } from '../../utils/class-names.js';
|
|
4
5
|
export const DEFAULT_WORKING_DIR_LABELS = {
|
|
5
6
|
missing: 'Directory no longer exists',
|
|
6
7
|
hint: 'Select a working directory',
|
|
@@ -45,7 +46,7 @@ export function useDismissablePanel(onOpen) {
|
|
|
45
46
|
}, [open, onOpen]);
|
|
46
47
|
useEffect(() => {
|
|
47
48
|
if (!open)
|
|
48
|
-
return;
|
|
49
|
+
return undefined;
|
|
49
50
|
function onPointer(event) {
|
|
50
51
|
if (wrapRef.current?.contains(event.target))
|
|
51
52
|
return;
|
|
@@ -175,10 +176,10 @@ function useWorkingDirFocusHandoff({ open, triggerRef, panelRef }) {
|
|
|
175
176
|
if (open) {
|
|
176
177
|
wasOpenRef.current = true;
|
|
177
178
|
panelRef.current?.querySelector(MENU_ITEM_SELECTOR)?.focus();
|
|
178
|
-
return;
|
|
179
|
+
return undefined;
|
|
179
180
|
}
|
|
180
181
|
if (!wasOpenRef.current)
|
|
181
|
-
return;
|
|
182
|
+
return undefined;
|
|
182
183
|
wasOpenRef.current = false;
|
|
183
184
|
const timeout = window.setTimeout(() => triggerRef.current?.focus(), 0);
|
|
184
185
|
return () => window.clearTimeout(timeout);
|
|
@@ -212,6 +213,6 @@ export function WorkingDirPicker({ workingDir, recentDirs, onPickDirectory, onSe
|
|
|
212
213
|
return;
|
|
213
214
|
handleRecentFlyoutKey({ event, showRecent, hideRecent });
|
|
214
215
|
}, [hideRecent, showRecent]);
|
|
215
|
-
return (_jsxs("div", { ref: wrapRef, className:
|
|
216
|
+
return (_jsxs("div", { ref: wrapRef, className: withClassName('jini-working-dir-picker', className), "data-testid": "working-dir-picker", children: [_jsx(WorkingDirTrigger, { triggerRef: triggerRef, workingDir: workingDir, invalid: invalid, open: open, panelId: panelId, t: t, toggle: toggle }), open ? (_jsx(WorkingDirPanel, { panelRef: panelRef, panelId: panelId, placement: placement, workingDir: workingDir, recentDirs: recentDirs, canClear: Boolean(workingDir && onClear), t: t, picker: picker, onKeyDown: handlePanelKeyDown })) : null] }));
|
|
216
217
|
}
|
|
217
218
|
//# sourceMappingURL=WorkingDirPicker.js.map
|
|
@@ -85,7 +85,15 @@ function isRemixIconFaceRule(rule) {
|
|
|
85
85
|
function findRemixIconFontSource({ rules }) {
|
|
86
86
|
const face = Array.from(rules).find(isRemixIconFaceRule);
|
|
87
87
|
// This package owns one url(...) WOFF2 source, not a general CSS font-source parser.
|
|
88
|
-
|
|
88
|
+
const source = face?.style.getPropertyValue('src');
|
|
89
|
+
if (!source)
|
|
90
|
+
return undefined;
|
|
91
|
+
const open = source.indexOf('url(');
|
|
92
|
+
const close = source.indexOf(')', open + 4);
|
|
93
|
+
if (open < 0 || close < 0)
|
|
94
|
+
return undefined;
|
|
95
|
+
// URL construction below already discards surrounding whitespace. Keep quotes outside the URL.
|
|
96
|
+
return /^["']?([^"']+)["']?$/.exec(source.slice(open + 4, close).trim())?.[1];
|
|
89
97
|
}
|
|
90
98
|
/** The source URL tagged with the attempt number; only http(s) URLs accept a query parameter. */
|
|
91
99
|
function retryFontUrl({ url, attempt }) {
|
|
@@ -103,7 +103,7 @@ export function useSelectPopoverPosition(required, optional = {}) {
|
|
|
103
103
|
// biome-ignore lint/correctness/useExhaustiveDependencies: scroll/resize listener wiring — see comment above; onOutOfView is read through latest; only lifecycle/ref changes re-arm it.
|
|
104
104
|
useEffect(() => {
|
|
105
105
|
if (!open || !portal)
|
|
106
|
-
return;
|
|
106
|
+
return undefined;
|
|
107
107
|
function reposition() {
|
|
108
108
|
const trigger = triggerRef.current;
|
|
109
109
|
if (!trigger)
|
|
@@ -146,7 +146,7 @@ export function useSelectPopover(required, optional = {}) {
|
|
|
146
146
|
}
|
|
147
147
|
useEffect(() => {
|
|
148
148
|
if (!open)
|
|
149
|
-
return;
|
|
149
|
+
return undefined;
|
|
150
150
|
function onOutside(event) {
|
|
151
151
|
if (isSelectEventInside({ target: event.target, trigger: triggerRef.current, panel: panelRef.current }))
|
|
152
152
|
return;
|
|
@@ -10,21 +10,21 @@ export function useInView(options = {}) {
|
|
|
10
10
|
useEffect(() => {
|
|
11
11
|
const node = ref.current;
|
|
12
12
|
if (!node)
|
|
13
|
-
return;
|
|
13
|
+
return undefined;
|
|
14
14
|
if (typeof IntersectionObserver === 'undefined') {
|
|
15
15
|
setInView(true);
|
|
16
|
-
return;
|
|
16
|
+
return undefined;
|
|
17
17
|
}
|
|
18
18
|
const observer = new IntersectionObserver((entries) => {
|
|
19
19
|
for (const entry of entries) {
|
|
20
|
-
if (entry.isIntersecting) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
20
|
+
if (!entry.isIntersecting) {
|
|
21
|
+
if (options.once === false)
|
|
22
|
+
setInView(false);
|
|
23
|
+
continue;
|
|
25
24
|
}
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
setInView(true);
|
|
26
|
+
if (options.once !== false) {
|
|
27
|
+
observer.disconnect();
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
}, {
|
|
@@ -114,12 +114,9 @@ export function useResizableSplitPane(options = {}) {
|
|
|
114
114
|
return undefined;
|
|
115
115
|
const updateAllowedWidth = () => {
|
|
116
116
|
const containerWidth = container.clientWidth;
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
? 0
|
|
121
|
-
: minSecondaryWidth;
|
|
122
|
-
const nextMax = !Number.isFinite(containerWidth) || containerWidth <= 0
|
|
117
|
+
const unmeasured = !Number.isFinite(containerWidth) || containerWidth <= 0;
|
|
118
|
+
const nextSecondaryMin = !unmeasured && containerWidth < minNormalContainerWidth ? 0 : minSecondaryWidth;
|
|
119
|
+
const nextMax = unmeasured
|
|
123
120
|
? maxWidthOption
|
|
124
121
|
: Math.max(0, Math.min(maxWidthOption, Math.floor(containerWidth - handleWidth - nextSecondaryMin)));
|
|
125
122
|
maxWidthRef.current = nextMax;
|
|
@@ -219,22 +216,17 @@ export function useResizableSplitPane(options = {}) {
|
|
|
219
216
|
finishResize(false);
|
|
220
217
|
}, [finishResize, renderPreferredWidth]);
|
|
221
218
|
const onHandleKeyDown = useCallback((event) => {
|
|
222
|
-
let nextWidth = null;
|
|
223
219
|
const container = containerRef.current;
|
|
224
220
|
const isRtl = container ? window.getComputedStyle(container).direction === 'rtl' : false;
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
else if (event.key === 'End') {
|
|
235
|
-
nextWidth = maxWidthRef.current;
|
|
236
|
-
}
|
|
237
|
-
if (nextWidth === null)
|
|
221
|
+
// ArrowRight grows the pane in LTR and shrinks it in RTL; ArrowLeft is the mirror.
|
|
222
|
+
const rightStep = (isRtl ? -1 : 1) * keyboardStep;
|
|
223
|
+
const nextWidth = new Map([
|
|
224
|
+
['ArrowLeft', widthRef.current - rightStep],
|
|
225
|
+
['ArrowRight', widthRef.current + rightStep],
|
|
226
|
+
['Home', minWidth],
|
|
227
|
+
['End', maxWidthRef.current],
|
|
228
|
+
]).get(event.key);
|
|
229
|
+
if (nextWidth === undefined)
|
|
238
230
|
return;
|
|
239
231
|
event.preventDefault();
|
|
240
232
|
const next = applyWidth(nextWidth);
|