@jini-ai/ui 0.6.15-rc.2 → 0.6.16

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.
Files changed (227) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/browser/useDismissOnOutsideOrEscape.js +1 -1
  3. package/dist/browser/useGlobalKeydown.js +2 -2
  4. package/dist/browser/useModalWindowDragGuard.js +1 -1
  5. package/dist/core/theme/css-name.d.ts +3 -0
  6. package/dist/core/theme/css-name.js +5 -0
  7. package/dist/core/theme/stylesheet.js +2 -1
  8. package/dist/core/theme/validation.js +15 -4
  9. package/dist/core.d.ts +1 -1
  10. package/dist/core.js +1 -1
  11. package/dist/features/about/rules.js +2 -1
  12. package/dist/features/admin-widgets/components/InfoTip.hooks.js +22 -12
  13. package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +1 -1
  14. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +1 -1
  15. package/dist/features/admin-widgets/components/SeeMore/SeeMore.hooks.js +2 -2
  16. package/dist/features/admin-widgets/components/SeeMore/SeeMore.js +4 -2
  17. package/dist/features/admin-widgets/components/Select/Select.hooks.js +2 -1
  18. package/dist/features/admin-widgets/components/Select/Select.js +2 -1
  19. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.js +4 -2
  20. package/dist/features/admin-widgets/components/useDebouncedHtmlPreview.hooks.js +3 -2
  21. package/dist/features/appearance/constants.d.ts +28 -1
  22. package/dist/features/appearance/constants.js +12 -9
  23. package/dist/features/appearance/react/components/AppearanceTab.js +4 -4
  24. package/dist/features/asset-grid/react/components/AssetGrid.js +8 -3
  25. package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +7 -6
  26. package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +8 -10
  27. package/dist/features/asset-grid/react/hooks/useRubberBandDrag.js +1 -1
  28. package/dist/features/asset-tree-browser/react/components/AssetTreeFileRow.js +6 -8
  29. package/dist/features/asset-tree-browser/react/hooks/useAssetTreeRowMenu.js +1 -1
  30. package/dist/features/asset-tree-browser/rules.js +1 -3
  31. package/dist/features/browser-chrome/rules.js +10 -8
  32. package/dist/features/charts/browser.js +2 -1
  33. package/dist/features/charts/contract.d.ts +4 -4
  34. package/dist/features/charts/react.js +5 -3
  35. package/dist/features/charts/wire.d.ts +19 -0
  36. package/dist/features/charts/wire.js +20 -2
  37. package/dist/features/connectors/ConnectorsBrowser.js +3 -1
  38. package/dist/features/connectors/hooks/useConnectorAuthorization.js +1 -1
  39. package/dist/features/connectors/hooks/useConnectorCatalog.js +2 -2
  40. package/dist/features/connectors/rules.js +10 -14
  41. package/dist/features/execution/constants.js +0 -1
  42. package/dist/features/execution/react/components/AgentDiagnosticRow.js +2 -0
  43. package/dist/features/execution/react/components/ByokProviderForm.js +1 -3
  44. package/dist/features/execution/react/components/LocalCliAgentSettings.js +2 -1
  45. package/dist/features/execution/react/hooks/use-byok-field-validation.hooks.js +6 -2
  46. package/dist/features/execution/react/hooks/useExecutionTab.js +9 -5
  47. package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +3 -6
  48. package/dist/features/execution/react/hooks/useReasoningControl.js +3 -3
  49. package/dist/features/execution/rules.js +23 -18
  50. package/dist/features/external-mcp/react/components/ExternalMcpTab.js +10 -1
  51. package/dist/features/file-dropzone/rules.js +3 -2
  52. package/dist/features/folder-path-drop/rules.d.ts +2 -3
  53. package/dist/features/folder-path-drop/rules.js +3 -4
  54. package/dist/features/html-editor/canvas-embed-placeholders.js +2 -3
  55. package/dist/features/html-editor/css.js +7 -5
  56. package/dist/features/html-editor/editor-blocks.js +60 -6
  57. package/dist/features/html-editor/protected-elements.js +5 -3
  58. package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +3 -3
  59. package/dist/features/html-editor/source-splice.js +6 -4
  60. package/dist/features/i18n/dictionaries/settings-dialog.ar.js +8 -0
  61. package/dist/features/i18n/dictionaries/settings-dialog.bn.js +8 -0
  62. package/dist/features/i18n/dictionaries/settings-dialog.de.js +8 -0
  63. package/dist/features/i18n/dictionaries/settings-dialog.en.js +8 -0
  64. package/dist/features/i18n/dictionaries/settings-dialog.es.js +8 -0
  65. package/dist/features/i18n/dictionaries/settings-dialog.fa.js +8 -0
  66. package/dist/features/i18n/dictionaries/settings-dialog.fr.js +8 -0
  67. package/dist/features/i18n/dictionaries/settings-dialog.hi.js +8 -0
  68. package/dist/features/i18n/dictionaries/settings-dialog.hu.js +8 -0
  69. package/dist/features/i18n/dictionaries/settings-dialog.id.js +8 -0
  70. package/dist/features/i18n/dictionaries/settings-dialog.it.js +8 -0
  71. package/dist/features/i18n/dictionaries/settings-dialog.ja.js +8 -0
  72. package/dist/features/i18n/dictionaries/settings-dialog.ko.js +8 -0
  73. package/dist/features/i18n/dictionaries/settings-dialog.pl.js +8 -0
  74. package/dist/features/i18n/dictionaries/settings-dialog.pt-BR.js +8 -0
  75. package/dist/features/i18n/dictionaries/settings-dialog.ru.js +8 -0
  76. package/dist/features/i18n/dictionaries/settings-dialog.th.js +8 -0
  77. package/dist/features/i18n/dictionaries/settings-dialog.tr.js +8 -0
  78. package/dist/features/i18n/dictionaries/settings-dialog.uk.js +8 -0
  79. package/dist/features/i18n/dictionaries/settings-dialog.ur.js +8 -0
  80. package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +8 -0
  81. package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +8 -0
  82. package/dist/features/iframe-pool/react/components/IframeKeepAliveProvider.js +5 -5
  83. package/dist/features/iframe-pool/react/dom-sync.js +2 -2
  84. package/dist/features/integrations/react/components/IntegrationsTab.js +3 -1
  85. package/dist/features/integrations/rules.js +6 -4
  86. package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -5
  87. package/dist/features/interactive-ui/table-data.js +1 -1
  88. package/dist/features/lexical-rich-text-editor/deserialize.js +2 -2
  89. package/dist/features/lexical-rich-text-editor/mention-parser.js +4 -4
  90. package/dist/features/lexical-rich-text-editor/react/components/RichTextInput.js +2 -1
  91. package/dist/features/lexical-rich-text-editor/react/hooks/useCaretFloatingLayerPosition.js +1 -1
  92. package/dist/features/lexical-rich-text-editor/react/hooks/useMentionColorStamping.js +1 -1
  93. package/dist/features/lexical-rich-text-editor/serialize.js +13 -10
  94. package/dist/features/list-detail-panel/react/components/ListDetailPanel.js +1 -1
  95. package/dist/features/mcp-ui/confirmation-store.js +3 -6
  96. package/dist/features/mcp-ui/surfaces/checkbox.d.ts +2 -0
  97. package/dist/features/mcp-ui/surfaces/choice-group.d.ts +2 -0
  98. package/dist/features/mcp-ui/surfaces/choice-group.js +2 -2
  99. package/dist/features/mcp-ui/surfaces/confirmation.d.ts +5 -0
  100. package/dist/features/mcp-ui/surfaces/confirmation.js +1 -0
  101. package/dist/features/mcp-ui/surfaces/document.d.ts +14 -16
  102. package/dist/features/mcp-ui/surfaces/document.js +46 -7
  103. package/dist/features/mcp-ui/surfaces/fields.d.ts +7 -1
  104. package/dist/features/mcp-ui/surfaces/fields.js +14 -11
  105. package/dist/features/mcp-ui/surfaces/form.js +6 -1
  106. package/dist/features/mcp-ui/surfaces/host-theme.js +2 -1
  107. package/dist/features/mcp-ui/surfaces/index.d.ts +1 -0
  108. package/dist/features/mcp-ui/surfaces/index.js +1 -0
  109. package/dist/features/mcp-ui/surfaces/outcome.js +1 -1
  110. package/dist/features/mcp-ui/surfaces/select.d.ts +2 -0
  111. package/dist/features/mcp-ui/surfaces/select.js +2 -1
  112. package/dist/features/mcp-ui/surfaces/structured-details.d.ts +40 -0
  113. package/dist/features/mcp-ui/surfaces/structured-details.js +159 -0
  114. package/dist/features/mcp-ui/surfaces/text-input.d.ts +2 -0
  115. package/dist/features/mcp-ui/surfaces/text-input.js +1 -1
  116. package/dist/features/mcp-ui/surfaces/tool-approval.d.ts +21 -0
  117. package/dist/features/mcp-ui/surfaces/tool-approval.js +42 -0
  118. package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +2 -1
  119. package/dist/features/memory/async-commit-guard.js +4 -1
  120. package/dist/features/memory/formatters.js +5 -1
  121. package/dist/features/memory/react/components/MemoryConnectedPanel.js +3 -1
  122. package/dist/features/memory/react/components/MemoryEntryCard.js +1 -1
  123. package/dist/features/memory/react/components/MemorySettingsPanel.js +3 -1
  124. package/dist/features/memory/react/hooks/useMemoryConfig.hooks.js +12 -10
  125. package/dist/features/memory/react/hooks/useMemoryConnectors.hooks.js +2 -5
  126. package/dist/features/memory/react/hooks/useMemoryConnectors.rules.js +10 -9
  127. package/dist/features/memory/react/hooks/useMemoryEntries.hooks.js +4 -2
  128. package/dist/features/memory/react/hooks/useMemoryFlash.hooks.js +1 -1
  129. package/dist/features/memory/rules.js +2 -1
  130. package/dist/features/panel-kit/fetch-query/adapter.react.js +3 -2
  131. package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +3 -2
  132. package/dist/features/panel-kit/fetch-query/binding.react.js +2 -1
  133. package/dist/features/panel-kit/helpers/standing-draft-recovery-message.js +13 -4
  134. package/dist/features/panel-kit/hooks/use-dirty-guard.hooks.js +1 -1
  135. package/dist/features/panel-kit/hooks/use-focus-trap.hooks.js +1 -1
  136. package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +14 -10
  137. package/dist/features/panel-kit/hooks/use-standing-draft-autosave.hooks.js +2 -2
  138. package/dist/features/progress-card/components/ProgressCard.d.ts +1 -1
  139. package/dist/features/progress-card/reference-adapters.js +23 -13
  140. package/dist/features/progress-card/rules.d.ts +0 -1
  141. package/dist/features/progress-card/rules.js +14 -20
  142. package/dist/features/progress-card/types.d.ts +1 -1
  143. package/dist/features/project-locations/dependencies.js +6 -1
  144. package/dist/features/project-locations/react/components/ProjectLocationsTab.js +2 -1
  145. package/dist/features/project-locations/rules.js +2 -1
  146. package/dist/features/resource-dashboard/react/components/ResourceBoardToolbar.js +8 -1
  147. package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +2 -1
  148. package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +3 -1
  149. package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +2 -1
  150. package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +1 -1
  151. package/dist/features/resource-dashboard/react/hooks/useResourceBoard.js +1 -1
  152. package/dist/features/schedule-picker/rules.js +13 -7
  153. package/dist/features/sketch-editor/constants.d.ts +0 -6
  154. package/dist/features/sketch-editor/constants.js +17 -15
  155. package/dist/features/sketch-editor/dom.js +4 -7
  156. package/dist/features/sketch-editor/react/components/SketchMainMenu.js +2 -1
  157. package/dist/features/sketch-editor/react/components/SketchSaveStateBadge.js +2 -1
  158. package/dist/features/sketch-editor/react/hooks/useSketchDomEnhancements.js +1 -1
  159. package/dist/features/sketch-editor/rules.js +13 -12
  160. package/dist/features/skills/dependencies.js +9 -4
  161. package/dist/features/skills/react/components/SkillRow.js +2 -1
  162. package/dist/features/skills/react/components/SkillsTab.js +2 -1
  163. package/dist/features/skills/rules.js +3 -3
  164. package/dist/features/source-config-list/agent-handles.js +4 -3
  165. package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +3 -1
  166. package/dist/features/tab-strip/react/components/TabBar.hooks.js +4 -2
  167. package/dist/features/version-manager/react/components/VersionPreviewFrame.js +4 -1
  168. package/dist/features/version-manager/react/components/VersionSidebar.js +8 -6
  169. package/dist/features/version-manager/react/hooks/usePreviewCanvasSize.js +1 -1
  170. package/dist/features/version-manager/react/hooks/useVersionManager.js +5 -7
  171. package/dist/features/version-manager/rules.js +3 -5
  172. package/dist/features/viewer-shell/react/components/CommentSidePanel.js +2 -1
  173. package/dist/features/viewer-shell/react/components/SegmentedToggle.js +2 -1
  174. package/dist/features/viewer-shell/react/components/ViewerShell.js +2 -1
  175. package/dist/features/viewer-shell/rules.js +8 -7
  176. package/dist/react/components/AgentIcon.js +0 -1
  177. package/dist/react/components/BrandLogo.js +10 -2
  178. package/dist/react/components/CustomSelect.js +1 -1
  179. package/dist/react/components/EditorIcon.js +17 -14
  180. package/dist/react/components/Loading.js +2 -1
  181. package/dist/react/components/OnboardingChipField.js +5 -1
  182. package/dist/react/components/OnboardingDropdown.js +6 -4
  183. package/dist/react/components/PaletteTweaks.js +7 -6
  184. package/dist/react/components/PillButton.js +2 -1
  185. package/dist/react/components/PopoverMenu.js +2 -1
  186. package/dist/react/components/RemixIcon.js +2 -1
  187. package/dist/react/components/SecretInput.hooks.d.ts +2 -25
  188. package/dist/react/components/SecretInput.hooks.js +2 -24
  189. package/dist/react/components/SecretInput.js +5 -4
  190. package/dist/react/components/Toast.js +4 -2
  191. package/dist/react/components/TooltipLayer.js +4 -1
  192. package/dist/react/components/WorkingDirPicker.js +5 -4
  193. package/dist/react/components/agent-icon-data-uris.generated.js +0 -1
  194. package/dist/react/components/remixicon-font-recovery.js +9 -1
  195. package/dist/react/components/select-popover.js +2 -2
  196. package/dist/react/hooks/useBrandFonts.js +1 -1
  197. package/dist/react/hooks/useEdgeAutoScroll.js +1 -1
  198. package/dist/react/hooks/useInView.js +9 -9
  199. package/dist/react/hooks/useResizableSplitPane.js +12 -20
  200. package/dist/react/mcp-ui/useHostSurfaceTokens.js +1 -1
  201. package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +7 -1
  202. package/dist/renderers/annotation-canvas/react/hooks/useAnnotationCanvas.controller.js +4 -2
  203. package/dist/renderers/annotation-canvas/react/hooks/useAnnotationCanvas.js +9 -5
  204. package/dist/renderers/annotation-canvas/rules.js +9 -13
  205. package/dist/renderers/annotation-canvas/theme.js +5 -2
  206. package/dist/renderers/renderers/index.js +1 -1
  207. package/dist/renderers/renderers/markdown.js +4 -6
  208. package/dist/renderers/shiki.js +7 -1
  209. package/dist/theme/apply.js +7 -3
  210. package/dist/utils/class-names.d.ts +3 -0
  211. package/dist/utils/class-names.js +5 -0
  212. package/dist/utils/design-md.js +3 -3
  213. package/dist/utils/ime-composing.d.ts +1 -1
  214. package/dist/utils/ime-composing.js +1 -2
  215. package/dist/utils/localized-url.js +2 -11
  216. package/dist/utils/markdown-scroll-sync.js +1 -1
  217. package/dist/utils/omit-keys.d.ts +3 -0
  218. package/dist/utils/omit-keys.js +8 -0
  219. package/dist/utils/polygon-selection.js +1 -1
  220. package/dist/utils/sse.js +3 -0
  221. package/dist/utils/trim-chars.d.ts +13 -0
  222. package/dist/utils/trim-chars.js +30 -0
  223. package/dist/utils/unhandled-case.d.ts +10 -0
  224. package/dist/utils/unhandled-case.js +12 -0
  225. package/dist/utils/unit-bezier.js +1 -3
  226. package/dist/utils/zip.js +6 -10
  227. package/package.json +32 -29
@@ -1,26 +1,3 @@
1
- export interface SecretRevealRequired {
2
- /** The input's current value. A transition to `''` re-hides (the usual sign a save succeeded). */
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
- import { useState } from 'react';
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
- // The toggle props are pulled off so they never reach the DOM `<input>`.
17
- const { label, toggleLabels, toggleAttrs, revealed, onRevealedChange, ...inputProps } = props;
18
- const { reveal, button } = useSecretToggle(props, { value: inputProps.value, disabled: inputProps.disabled });
19
- return (_jsxs("span", { className: "jini-secret", children: [_jsx("input", { ...inputProps, spellCheck: false, ref: ref, type: reveal.inputType }), button] }));
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
- return `jini-toast tone-${tone} placement-${placement}${className ? ` ${className}` : ''}${leaving ? ' leaving' : ''}`;
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: `jini-working-dir-picker${className ? ` ${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
+ 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
@@ -7,7 +7,6 @@ export const AGENT_ICON_DATA_URIS = {
7
7
  "antigravity": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0yIC0xIDI4IDI4Ij48cGF0aCBkPSJNMjEuNzUxIDIyLjYwN2MxLjM0IDEuMDA1IDMuMzUuMzM1IDEuNTA4LTEuNTA4QzE3LjczIDE1Ljc0IDE4LjkwNCAxIDEyLjAzNyAxIDUuMTcgMSA2LjM0MiAxNS43NC44MTUgMjEuMWMtMi4wMSAyLjAwOS4xNjcgMi41MTEgMS41MDcgMS41MDYgNS4xOTItMy41MTcgNC44NTctOS43MTQgOS43MTUtOS43MTQgNC44NTcgMCA0LjUyMiA2LjE5NyA5LjcxNCA5LjcxNXoiIGZpbGw9InVybCgjYWcpIi8+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhZyIgeDE9IjIiIHkxPSIxMiIgeDI9IjIyIiB5Mj0iMTIiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBzdG9wLWNvbG9yPSIjNDI4NUY0Ii8+PHN0b3Agb2Zmc2V0PSIuMzMiIHN0b3AtY29sb3I9IiNFQTQzMzUiLz48c3RvcCBvZmZzZXQ9Ii42NiIgc3RvcC1jb2xvcj0iI0ZCQkMwNCIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzM0QTg1MyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjwvc3ZnPgo=",
8
8
  "claude": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iI2Q5Nzc1NyIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMjAuOTk4IDEwLjk0OUgyNHYzLjEwMmgtM3YzLjAyOGgtMS40ODdWMjBIMTh2LTIuOTIxaC0xLjQ4N1YyMEgxNXYtMi45MjFIOVYyMEg3LjQ4OHYtMi45MjFINlYyMEg0LjQ4N3YtMi45MjFIM1YxNC4wNUgwdi0zLjFoM1Y1aDE3Ljk5OHpNNiAxMC45NDloMS40ODhWOC4xMDJINnptMTAuNTEgMEgxOFY4LjEwMmgtMS40OXoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==",
9
9
  "codex": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTE5LjUwMyAwSDQuNDk2QTQuNDk2IDQuNDk2IDAgMCAwIDAgNC40OTZ2MTUuMDA3QTQuNDk2IDQuNDk2IDAgMCAwIDQuNDk2IDI0aDE1LjAwN0E0LjQ5NiA0LjQ5NiAwIDAgMCAyNCAxOS41MDNWNC40OTZBNC40OTYgNC40OTYgMCAwIDAgMTkuNTAzIDAiLz48cGF0aCBmaWxsPSJ1cmwoI2EpIiBkPSJNOS4wNjQgMy4zNDRhNC42IDQuNiAwIDAgMSAyLjI4NS0uMzEycTEuNS4xNzMgMi42NzMgMS4yNzUuMDE2LjAxNS4wMzcuMDIxYS4xLjEgMCAwIDAgLjA0MyAwIDQuNTUgNC41NSAwIDAgMSAzLjA0Ni4yNzVsLjA0Ny4wMjIuMTE2LjA1N2E0LjU4IDQuNTggMCAwIDEgMi4xODggMi4zOTlxLjMxMy43NjUuMzE1IDEuNTk1YTQuMiA0LjIgMCAwIDEtLjEzNCAxLjIyMy4xMi4xMiAwIDAgMCAuMDMuMTE1cS44OS45MSAxLjE4MyAyLjE3LjQzMyAyLjEzOC0uODg3IDMuODU0bC0uMTM2LjE2NmE0LjU1IDQuNTUgMCAwIDEtMi4yMDEgMS4zODguMTIuMTIgMCAwIDAtLjA4MS4wNzZjLS4xOTEuNTUxLS4zODMgMS4wMjMtLjc0IDEuNDk0LS45IDEuMTg3LTIuMjIyIDEuODQ2LTMuNzExIDEuODM4cS0xLjc4LS4wMDktMy4xNTctMS4zMDJhLjExLjExIDAgMCAwLS4xMDUtLjAyNGMtLjM4OC4xMjUtLjc4LjE0My0xLjIwNC4xMzhhNC40NCA0LjQ0IDAgMCAxLTEuOTQ1LS40NjYgNC41NCA0LjU0IDAgMCAxLTEuNjEtMS4zMzVjLS4xNTItLjIwMi0uMzAzLS4zOTItLjQxNC0uNjE3YTYgNiAwIDAgMS0uMzctLjk2MSA0LjYgNC42IDAgMCAxLS4wMTQtMi4yOTguMS4xIDAgMCAwIC4wMDYtLjA1Ni4xLjEgMCAwIDAtLjAyNy0uMDQ4IDQuNSA0LjUgMCAwIDEtMS4wMzQtMS42NTEgMy45IDMuOSAwIDAgMS0uMjUxLTEuMTkyIDUuMiA1LjIgMCAwIDEgLjE0MS0xLjZRMy42NTkgNy45MiA1LjA4NiA2Ljk3cS4zMTgtLjIxMi42MDEtLjMzYTYgNiAwIDAgMSAuNjQ2LS4yMjcuMS4xIDAgMCAwIC4wNjUtLjA2NiA0LjUgNC41IDAgMCAxIC44MjktMS42MTUgNC41NCA0LjU0IDAgMCAxIDEuODM3LTEuMzg4bTMuNDgyIDEwLjU2NWEuNjM3LjYzNyAwIDAgMCAwIDEuMjcyaDMuNjM2YS42MzcuNjM3IDAgMSAwIDAtMS4yNzJ6TTguNDYyIDkuMjNhLjYzNy42MzcgMCAwIDAtMS4xMDYuNjMxbDEuMjcyIDIuMjI0LTEuMjY2IDIuMTM2YS42MzYuNjM2IDAgMSAwIDEuMDk1LjY0OWwxLjQ1NC0yLjQ1NWEuNjQuNjQgMCAwIDAgLjAwNS0uNjR6Ii8+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJhIiB4MT0iMTIiIHgyPSIxMiIgeTE9IjMiIHkyPSIyMSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIHN0b3AtY29sb3I9IiNiMWE3ZmYiLz48c3RvcCBvZmZzZXQ9Ii41IiBzdG9wLWNvbG9yPSIjN2E5ZGZmIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMzk0MWZmIi8+PC9saW5lYXJHcmFkaWVudD48L2RlZnM+PC9zdmc+",
10
- "copilot": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iIzg1MzRGMyIgZD0iTTIzLjkyMiAxNi45OTJjLS44NjEgMS40OTUtNS44NTkgNS4wMjMtMTEuOTIyIDUuMDIzLTYuMDYzIDAtMTEuMDYxLTMuNTI4LTExLjkyMi01LjAyM0EuNjQxLjY0MSAwIDAgMSAwIDE2LjczNnYtMi44NjlhLjg0MS44NDEgMCAwIDEgLjA1My0uMjJjLjM3Mi0uOTM1IDEuMzQ3LTIuMjkyIDIuNjA1LTIuNjU2LjE2Ny0uNDI5LjQxNC0xLjA1NS42NDQtMS41MTdhMTAuMTk1IDEwLjE5NSAwIDAgMS0uMDUyLTEuMDg2YzAtMS4zMzEuMjgyLTIuNDk5IDEuMTMyLTMuMzY4LjM5Ny0uNDA2Ljg5LS43MTcgMS40NzQtLjk1MiAxLjM5OS0xLjEzNiAzLjM5Mi0yLjA5MyA2LjEyMi0yLjA5MyAyLjczMSAwIDQuNzY3Ljk1NyA2LjE2NiAyLjA5My41ODQuMjM1IDEuMDc3LjU0NiAxLjQ3NC45NTIuODUuODY5IDEuMTMyIDIuMDM3IDEuMTMyIDMuMzY4IDAgLjM2OC0uMDE0LjczMy0uMDUyIDEuMDg2LjIzLjQ2Mi40NzcgMS4wODguNjQ0IDEuNTE3IDEuMjU4LjM2NCAyLjIzMyAxLjcyMSAyLjYwNSAyLjY1NmEuODMyLjgzMiAwIDAgMSAuMDUzLjIydjIuODY5YS42NDEuNjQxIDAgMCAxLS4wNzguMjU2Wk0xMi4xNzIgMTFoLS4zNDRhNC4zMjMgNC4zMjMgMCAwIDEtLjM1NS41MDhDMTAuNzAzIDEyLjQ1NSA5LjU1NSAxMyA3Ljk2NSAxM2MtMS43MjUgMC0yLjk4OS0uMzU5LTMuNzgyLTEuMjU5YTIuMDA1IDIuMDA1IDAgMCAxLS4wODUtLjEwNEw0IDExLjc0MXY2LjU4NWMxLjQzNS43NzkgNC41MTQgMi4xNzkgOCAyLjE3OSAzLjQ4NiAwIDYuNTY1LTEuNCA4LTIuMTc5di02LjU4NWwtLjA5OC0uMTA0cy0uMDMzLjA0NS0uMDg1LjEwNGMtLjc5My45LTIuMDU3IDEuMjU5LTMuNzgyIDEuMjU5LTEuNTkgMC0yLjczOC0uNTQ1LTMuNTA4LTEuNDkyYTQuMzIzIDQuMzIzIDAgMCAxLS4zNTUtLjUwOGgtLjAxNi4wMTZabS42NDEtMi45MzVjLjEzNiAxLjA1Ny40MDMgMS45MTMuODc4IDIuNDk3LjQ0Mi41NDQgMS4xMzQuOTM4IDIuMzQ0LjkzOCAxLjU3MyAwIDIuMjkyLS4zMzcgMi42NTctLjc1MS4zODQtLjQzNS41NTgtMS4xNS41NTgtMi4zNjEgMC0xLjE0LS4yNDMtMS44NDctLjcwNS0yLjMxOS0uNDc3LS40ODgtMS4zMTktLjg2Mi0yLjgyNC0xLjAyNS0xLjQ4Ny0uMTYxLTIuMTkyLjEzOC0yLjUzMy41MjktLjI2OS4zMDctLjQzNy44MDgtLjQzOCAxLjU3OHYuMDIxYzAgLjI2NS4wMjEuNTYyLjA2My44OTNabS0xLjYyNiAwYy4wNDItLjMzMS4wNjMtLjYyOC4wNjMtLjg5NHYtLjAyYy0uMDAxLS43Ny0uMTY5LTEuMjcxLS40MzgtMS41NzgtLjM0MS0uMzkxLTEuMDQ2LS42OS0yLjUzMy0uNTI5LTEuNTA1LjE2My0yLjM0Ny41MzctMi44MjQgMS4wMjUtLjQ2Mi40NzItLjcwNSAxLjE3OS0uNzA1IDIuMzE5IDAgMS4yMTEuMTc1IDEuOTI2LjU1OCAyLjM2MS4zNjUuNDE0IDEuMDg0Ljc1MSAyLjY1Ny43NTEgMS4yMSAwIDEuOTAyLS4zOTQgMi4zNDQtLjkzOC40NzUtLjU4NC43NDItMS40NC44NzgtMi40OTdaIi8+PHBhdGggZmlsbD0iIzg1MzRGMyIgZD0iTTE0LjUgMTQuMjVhMSAxIDAgMCAxIDEgMXYyYTEgMSAwIDAgMS0yIDB2LTJhMSAxIDAgMCAxIDEtMVptLTUgMGExIDEgMCAwIDEgMSAxdjJhMSAxIDAgMCAxLTIgMHYtMmExIDEgMCAwIDEgMS0xWiIvPjwvc3ZnPg==",
11
10
  "cursor-agent": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiMxYzFiMWEiIGZpbGwtcnVsZT0iZXZlbm9kZCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMjIuMTA2IDUuNjggMTIuNS4xMzVhMSAxIDAgMCAwLS45OTggMEwxLjg5MyA1LjY4YS44NC44NCAwIDAgMC0uNDE5LjcyNnYxMS4xODZjMCAuMy4xNi41NzcuNDIuNzI3bDkuNjA3IDUuNTQ3YTEgMSAwIDAgMCAuOTk4IDBsOS42MDgtNS41NDdhLjg0Ljg0IDAgMCAwIC40Mi0uNzI3VjYuNDA3YS44NC44NCAwIDAgMC0uNDItLjcyNnptLS42MDMgMS4xNzZMMTIuMjI4IDIyLjkyYy0uMDYzLjEwOC0uMjI4LjA2NC0uMjI4LS4wNjFWMTIuMzRhLjU5LjU5IDAgMCAwLS4yOTUtLjUxbC05LjExLTUuMjZjLS4xMDctLjA2Mi0uMDYzLS4yMjguMDYyLS4yMjhoMTguNTVjLjI2NCAwIC40MjguMjg2LjI5Ni41MTQiLz48L3N2Zz4=",
12
11
  "deepseek": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iIzRkNmJmZSIgZD0iTTIzLjc0OCA0LjQ4MmMtLjI1NC0uMTI0LS4zNjQuMTEzLS41MTIuMjM0LS4wNTEuMDM5LS4wOTQuMDktLjEzNy4xMzYtLjM3Mi4zOTctLjgwNi42NTctMS4zNzMuNjI2LS44MjktLjA0Ni0xLjUzNy4yMTQtMi4xNjMuODQ4LS4xMzMtLjc4Mi0uNTc1LTEuMjQ4LTEuMjQ3LTEuNTQ4LS4zNTItLjE1Ni0uNzA4LS4zMTEtLjk1NS0uNjUtLjE3Mi0uMjQxLS4yMTktLjUxLS4zMDUtLjc3NC0uMDU1LS4xNi0uMTEtLjMyMy0uMjkzLS4zNS0uMi0uMDMxLS4yNzguMTM2LS4zNTYuMjc2LS4zMTMuNTcyLS40MzQgMS4yMDItLjQyMiAxLjg0LjAyNyAxLjQzNi42MzMgMi41OCAxLjgzOCAzLjM5My4xMzcuMDkzLjE3Mi4xODcuMTI5LjMyMy0uMDgyLjI4LS4xOC41NTItLjI2Ni44MzMtLjA1NS4xNzktLjEzNy4yMTctLjMyOS4xNGE1LjUgNS41IDAgMCAxLTEuNzM2LTEuMThjLS44NTctLjgyOC0xLjYzMS0xLjc0Mi0yLjU5Ny0yLjQ1OGExMSAxMSAwIDAgMC0uNjg5LS40NzFjLS45ODUtLjk1Ny4xMy0xLjc0My4zODgtMS44MzYuMjctLjA5OC4wOTMtLjQzMi0uNzc5LS40MjhzLTEuNjcuMjk1LTIuNjg3LjY4NGEzIDMgMCAwIDEtLjQ2NS4xMzcgOS42IDkuNiAwIDAgMC0yLjg4My0uMTAyYy0xLjg4NS4yMS0zLjM5IDEuMTAyLTQuNDk3IDIuNjIzQy4wODIgOC42MDYtLjIzMSAxMC42ODQuMTUyIDEyLjg1Yy40MDMgMi4yODQgMS41NjkgNC4xNzUgMy4zNiA1LjY1MyAxLjg1OCAxLjUzMyAzLjk5NyAyLjI4NCA2LjQzOCAyLjE0IDEuNDgyLS4wODUgMy4xMzMtLjI4NCA0Ljk5NC0xLjg2LjQ3LjIzNC45NjIuMzI3IDEuNzguMzk3LjYzLjA1OSAxLjIzNi0uMDMgMS43MDUtLjEyOC43MzUtLjE1Ni42ODQtLjgzNy40MTktLjk2MS0yLjE1NS0xLjAwNC0xLjY4Mi0uNTk1LTIuMTEzLS45MjYgMS4wOTYtMS4yOTYgMi43NDYtMi42NDIgMy4zOTItNy4wMDMuMDUtLjM0Ny4wMDctLjU2NSAwLS44NDUtLjAwNC0uMTcuMDM1LS4yMzcuMjMtLjI1NmE0LjIgNC4yIDAgMCAwIDEuNTQ1LS40NzVjMS4zOTYtLjc2MyAxLjk2LTIuMDE1IDIuMDkzLTMuNTE3LjAyLS4yMy0uMDA0LS40NjctLjI0Ny0uNTg4ek0xMS41ODEgMThjLTIuMDg5LTEuNjQyLTMuMTAyLTIuMTgzLTMuNTItMi4xNi0uMzkyLjAyNC0uMzIxLjQ3MS0uMjM1Ljc2My4wOS4yODguMjA3LjQ4Ni4zNzEuNzM5LjExNC4xNjcuMTkyLjQxNi0uMTEzLjYwMy0uNjczLjQxNi0xLjg0Mi0uMTQtMS44OTctLjE2Ny0xLjM2MS0uODAyLTIuNS0xLjg2LTMuMzAxLTMuMzA3LS43NzQtMS4zOTMtMS4yMjQtMi44ODctMS4yOTgtNC40ODItLjAyLS4zODYuMDkzLS41MjIuNDc3LS41OTJhNC43IDQuNyAwIDAgMSAxLjUyOS0uMDM5YzIuMTMyLjMxMiAzLjk0NiAxLjI2NSA1LjQ2OCAyLjc3NC44NjguODYgMS41MjUgMS44ODcgMi4yMDIgMi44OTEuNzIgMS4wNjYgMS40OTQgMi4wODIgMi40OCAyLjkxNC4zNDguMjkyLjYyNS41MTQuODkxLjY3Ny0uODAyLjA5LTIuMTQuMTEtMy4wNTQtLjYxNG0xLTYuNDRhLjMwNi4zMDYgMCAwIDEgLjQxNS0uMjg3LjMuMyAwIDAgMSAuMi4yODguMzA2LjMwNiAwIDAgMS0uMzEuMzA3LjMwMy4zMDMgMCAwIDEtLjMwNC0uMzA4em0zLjExIDEuNTk2Yy0uMi4wODEtLjM5OS4xNTEtLjU5LjE2YTEuMjUgMS4yNSAwIDAgMS0uNzk4LS4yNTRjLS4yNzQtLjIzLS40Ny0uMzU4LS41NTItLjc1OGExLjcgMS43IDAgMCAxIC4wMTYtLjU4OGMuMDctLjMyNy0uMDA4LS41MzctLjIzOS0uNzI3LS4xODctLjE1Ni0uNDI2LS4xOTktLjY4OC0uMTk5YS41Ni41NiAwIDAgMS0uMjU0LS4wNzguMjUzLjI1MyAwIDAgMS0uMTE0LS4zNThjLjAyOC0uMDU0LjE2LS4xODYuMTkyLS4yMS4zNTYtLjIwMi43NjctLjEzNiAxLjE0Ni4wMTYuMzUyLjE0NC42MTguNDA4IDEuMDAxLjc4Mi4zOTEuNDUxLjQ2Mi41NzYuNjg1LjkxNC4xNzYuMjY1LjMzNi41MzcuNDQ1Ljg0OC4wNjcuMTk1LS4wMTkuMzU0LS4yNS40NTIiLz48L3N2Zz4=",
13
12
  "gemini": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0idXJsKCNhKSIgZD0iTTAgNC4zOTFBNC4zOSA0LjM5IDAgMCAxIDQuMzkxIDBoMTUuMjE3QTQuMzkgNC4zOSAwIDAgMSAyNCA0LjM5MXYxNS4yMTdBNC4zOSA0LjM5IDAgMCAxIDE5LjYwOCAyNEg0LjM5MUE0LjM5IDQuMzkgMCAwIDEgMCAxOS42MDh6Ii8+PHBhdGggZmlsbD0iIzFlMWUyZSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTkuNzQgMS40NDRhMi44MTYgMi44MTYgMCAwIDEgMi44MTYgMi44MTZ2MTUuNDhhMi44MTYgMi44MTYgMCAwIDEtMi44MTYgMi44MTZINC4yNmEyLjgxNiAyLjgxNiAwIDAgMS0yLjgxNi0yLjgxNlY0LjI2QTIuODE2IDIuODE2IDAgMCAxIDQuMjYgMS40NDR6TTcuMjM2IDguNTY0bDcuNzUyIDMuNzI4LTcuNzUyIDMuNzI3djIuODAybDkuNTU3LTQuNTk2di0zLjg2Nkw3LjIzNiA1Ljc2M3oiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjxkZWZzPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeDE9IjI0IiB4Mj0iMCIgeTE9IjYuNTg3IiB5Mj0iMTYuNDk0IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agc3RvcC1jb2xvcj0iI2VlNGQ1ZCIvPjxzdG9wIG9mZnNldD0iLjMyOCIgc3RvcC1jb2xvcj0iI2IzODFkZCIvPjxzdG9wIG9mZnNldD0iLjQ3NiIgc3RvcC1jb2xvcj0iIzIwN2NmZSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjwvc3ZnPg==",
@@ -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
- return face?.style.getPropertyValue('src').match(/url\(\s*["']?([^"')]+)["']?\s*\)/)?.[1];
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;
@@ -33,7 +33,7 @@ export function useBrandFonts({ fonts }, options = {}) {
33
33
  }, [googleUrls, document]);
34
34
  useEffect(() => {
35
35
  if (!projectId || !resolveProjectAssetUrl)
36
- return;
36
+ return undefined;
37
37
  let cancelled = false;
38
38
  let styleEl = null;
39
39
  void (async () => {
@@ -52,7 +52,7 @@ export function useEdgeAutoScroll(contentKey) {
52
52
  useEffect(() => {
53
53
  const el = scrollRef.current;
54
54
  if (!el)
55
- return;
55
+ return undefined;
56
56
  const updateEdges = () => {
57
57
  const maxScroll = el.scrollWidth - el.clientWidth;
58
58
  setEdges({
@@ -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
- setInView(true);
22
- if (options.once !== false) {
23
- observer.disconnect();
24
- }
20
+ if (!entry.isIntersecting) {
21
+ if (options.once === false)
22
+ setInView(false);
23
+ continue;
25
24
  }
26
- else if (options.once === false) {
27
- setInView(false);
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 nextSecondaryMin = !Number.isFinite(containerWidth) || containerWidth <= 0
118
- ? minSecondaryWidth
119
- : containerWidth < minNormalContainerWidth
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
- if (event.key === 'ArrowLeft') {
226
- nextWidth = widthRef.current + (isRtl ? 1 : -1) * keyboardStep;
227
- }
228
- else if (event.key === 'ArrowRight') {
229
- nextWidth = widthRef.current + (isRtl ? -1 : 1) * keyboardStep;
230
- }
231
- else if (event.key === 'Home') {
232
- nextWidth = minWidth;
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);
@@ -26,7 +26,7 @@ export function useHostSurfaceTokens(ref) {
26
26
  const view = element?.ownerDocument.defaultView;
27
27
  if (element === null || element === undefined || view === null || view === undefined) {
28
28
  setTokens({});
29
- return;
29
+ return undefined;
30
30
  }
31
31
  let last;
32
32
  const read = () => {
@@ -16,6 +16,12 @@ import { useT } from '../../../react/i18n.js';
16
16
  function maybePortal(node, host) {
17
17
  return host ? createPortal(node, host) : node;
18
18
  }
19
+ /** Crosshair for drawing tools, an I-beam for the text tool, the default pointer while inactive. */
20
+ function annotationCursor(active, markTool) {
21
+ if (!active)
22
+ return 'default';
23
+ return markTool === 'text' ? 'text' : 'crosshair';
24
+ }
19
25
  export function AnnotationCanvas(props) {
20
26
  const { children, toolbarHost, icons: iconOverrides, className } = props;
21
27
  const icons = { ...DEFAULT_ANNOTATION_CANVAS_ICONS, ...iconOverrides };
@@ -39,7 +45,7 @@ function DrawingCanvas({ c, active }) {
39
45
  position: 'absolute',
40
46
  inset: 0,
41
47
  pointerEvents: active ? 'auto' : 'none',
42
- cursor: active ? (c.markTool === 'text' ? 'text' : 'crosshair') : 'default',
48
+ cursor: annotationCursor(active, c.markTool),
43
49
  visibility: c.chromeHidden ? 'hidden' : 'visible',
44
50
  touchAction: 'none',
45
51
  userSelect: 'none',
@@ -19,7 +19,8 @@ export function deriveUndoRedoAvailability(input) {
19
19
  /** Shared by the hook's `canSubmit` value and `send()`'s own gate — both computed the identical chain before this extraction. */
20
20
  export function deriveSendGate(input) {
21
21
  const { hasInk, hasBox, hasText, hasCaptureTarget, captureViewport, noteTrimmed, extraFilesCount } = input;
22
- const shouldCapture = hasInk || hasBox || hasText || hasCaptureTarget || captureViewport;
22
+ const hasAnnotation = hasInk || hasBox || hasText;
23
+ const shouldCapture = hasAnnotation || hasCaptureTarget || captureViewport;
23
24
  const canSubmitNow = shouldCapture || Boolean(noteTrimmed) || extraFilesCount > 0;
24
25
  return { shouldCapture, canSubmitNow };
25
26
  }
@@ -35,7 +36,8 @@ export function canAttemptSend(input) {
35
36
  /** Picks which of the two "no screenshot" warnings applies — the whole-viewport-request wording, or the mark-specific one. */
36
37
  export function selectNoScreenshotMessage(input, t) {
37
38
  const { captureViewport, hasInk, hasBox, hasCaptureTarget } = input;
38
- return captureViewport && !hasInk && !hasBox && !hasCaptureTarget
39
+ const hasMark = hasInk || hasBox || hasCaptureTarget;
40
+ return captureViewport && !hasMark
39
41
  ? t('No screenshot was captured for this annotation.')
40
42
  : t('No screenshot was captured for this mark.');
41
43
  }
@@ -25,6 +25,8 @@ const DEFAULT_DOCKED_STYLE = {
25
25
  maxWidth: 'min(760px, calc(100% - 144px))',
26
26
  };
27
27
  const SUBMIT_TIMEOUT_MS = 60_000;
28
+ /** The analytics toolbar element each mark tool reports as. */
29
+ const TOOLBAR_TOOL_FOR_MARK_TOOL = { box: 'rect', text: 'text' };
28
30
  export function useAnnotationCanvas(options) {
29
31
  const { active, onActiveChange, captureViewport = false, captureTarget = null, filePath, sendDisabled = false, hideChrome = false, onToolbarClick, port } = options;
30
32
  const t = useT();
@@ -155,7 +157,7 @@ export function useAnnotationCanvas(options) {
155
157
  }
156
158
  window.addEventListener('keydown', onKey);
157
159
  return () => window.removeEventListener('keydown', onKey);
158
- // eslint-disable-next-line react-hooks/exhaustive-deps
160
+ // Dependency list intentionally follows the lifecycle rationale above.
159
161
  }, [active, onActiveChange, sending]);
160
162
  // Keyboard shortcut #2: Escape closes the staged-image preview modal first (capture phase).
161
163
  useEffect(() => {
@@ -368,7 +370,7 @@ export function useAnnotationCanvas(options) {
368
370
  syncHistoryState();
369
371
  redraw();
370
372
  bumpLayoutRevision();
371
- // eslint-disable-next-line react-hooks/exhaustive-deps
373
+ // Dependency list intentionally follows the lifecycle rationale above.
372
374
  }, [active, redraw]);
373
375
  const autosizeTextArea = useCallback((el) => {
374
376
  if (!el)
@@ -509,7 +511,7 @@ export function useAnnotationCanvas(options) {
509
511
  };
510
512
  }, [extraFiles]);
511
513
  function selectMarkTool(nextTool) {
512
- onToolbarClick?.(nextTool === 'box' ? 'rect' : nextTool === 'text' ? 'text' : 'pen');
514
+ onToolbarClick?.(TOOLBAR_TOOL_FOR_MARK_TOOL[nextTool] ?? 'pen');
513
515
  setMarkTool(nextTool);
514
516
  setMarkToolMenuOpen(false);
515
517
  }
@@ -598,7 +600,9 @@ export function useAnnotationCanvas(options) {
598
600
  }
599
601
  function waitForOverlayHidden() {
600
602
  return new Promise((resolve) => {
601
- requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
603
+ const finish = () => resolve();
604
+ const afterNextFrame = () => requestAnimationFrame(finish);
605
+ requestAnimationFrame(afterNextFrame);
602
606
  });
603
607
  }
604
608
  async function requestSnapshot() {
@@ -735,7 +739,7 @@ export function useAnnotationCanvas(options) {
735
739
  anchor,
736
740
  });
737
741
  setDockPlacement((current) => (dockPlacementEquals(current, next) ? current : next));
738
- // eslint-disable-next-line react-hooks/exhaustive-deps
742
+ // Dependency list intentionally follows the lifecycle rationale above.
739
743
  }, [active, captureTarget, layoutRevision, imagePreviews.length, captureWarning?.message]);
740
744
  useLayoutEffect(() => {
741
745
  if (!active || typeof ResizeObserver === 'undefined')
@@ -22,13 +22,10 @@ export function normalizedRectFromPoints(a, b) {
22
22
  };
23
23
  }
24
24
  export function dockPlacementEquals(a, b) {
25
- return (a.layout === b.layout &&
26
- a.side === b.side &&
27
- a.style.left === b.style.left &&
28
- a.style.top === b.style.top &&
29
- a.style.bottom === b.style.bottom &&
30
- a.style.transform === b.style.transform &&
31
- a.style.maxWidth === b.style.maxWidth);
25
+ if (a.layout !== b.layout || a.side !== b.side)
26
+ return false;
27
+ const samePosition = a.style.left === b.style.left && a.style.top === b.style.top && a.style.bottom === b.style.bottom;
28
+ return samePosition && a.style.transform === b.style.transform && a.style.maxWidth === b.style.maxWidth;
32
29
  }
33
30
  export const DRAW_DOCK_GAP = 12;
34
31
  export const DRAW_DOCK_MARGIN = 16;
@@ -47,12 +44,11 @@ export function computeDockPlacement(input) {
47
44
  const { hostRect, wrapRect, dockRect, anchor } = input;
48
45
  if (!anchor)
49
46
  return docked;
50
- if (hostRect.width <= DRAW_DOCK_MARGIN * 2 ||
51
- hostRect.height <= DRAW_DOCK_MARGIN * 2 ||
52
- dockRect.width <= 0 ||
53
- dockRect.height <= 0 ||
54
- hostRect.width < Math.max(DRAW_DOCK_MIN_WIDTH, dockRect.width) + DRAW_DOCK_MARGIN * 2 ||
55
- hostRect.height < Math.max(DRAW_DOCK_MIN_HEIGHT, dockRect.height) + DRAW_DOCK_MARGIN * 2) {
47
+ const hostTooSmall = hostRect.width <= DRAW_DOCK_MARGIN * 2 || hostRect.height <= DRAW_DOCK_MARGIN * 2;
48
+ const dockEmpty = dockRect.width <= 0 || dockRect.height <= 0;
49
+ const dockDoesNotFit = hostRect.width < Math.max(DRAW_DOCK_MIN_WIDTH, dockRect.width) + DRAW_DOCK_MARGIN * 2
50
+ || hostRect.height < Math.max(DRAW_DOCK_MIN_HEIGHT, dockRect.height) + DRAW_DOCK_MARGIN * 2;
51
+ if (hostTooSmall || dockEmpty || dockDoesNotFit) {
56
52
  return docked;
57
53
  }
58
54
  const anchorInHost = {
@@ -2,8 +2,11 @@ import { defaultAdminTheme } from '../../theme/default.js';
2
2
  /** Canvas requires resolved colors rather than var() strings. Its injected canvas owns the DOM. */
3
3
  export function resolveAnnotationTheme({ canvas }, { getComputedStyle } = {}) {
4
4
  const document = canvas?.ownerDocument;
5
- const readStyle = getComputedStyle ?? (document?.defaultView ? document.defaultView.getComputedStyle.bind(document.defaultView) : undefined);
6
- const style = document && readStyle ? readStyle(canvas?.isConnected ? canvas : document.documentElement) : undefined;
5
+ const view = document?.defaultView;
6
+ const readStyle = getComputedStyle ?? view?.getComputedStyle.bind(view);
7
+ let style;
8
+ if (document && readStyle)
9
+ style = readStyle(canvas?.isConnected ? canvas : document.documentElement);
7
10
  const read = (name, fallback) => style?.getPropertyValue(name).trim() || fallback;
8
11
  return {
9
12
  stroke: read('--jini-danger', defaultAdminTheme.light.danger),
@@ -1,6 +1,6 @@
1
1
  import { RendererRegistry } from '../registry.js';
2
2
  import { HtmlRenderer } from './html.js';
3
- import { MarkdownRenderer, renderMarkdownToSafeHtml } from './markdown.js';
3
+ import { MarkdownRenderer } from './markdown.js';
4
4
  import { SvgRenderer } from './svg.js';
5
5
  import { ReactComponentRenderer } from './react-component.js';
6
6
  export { HtmlRenderer } from './html.js';
@@ -8,6 +8,7 @@
8
8
  import { micromark } from 'micromark';
9
9
  import { gfm, gfmHtml } from 'micromark-extension-gfm';
10
10
  import { resolveArtifactManifest } from '../registry.js';
11
+ import { trimTrailingWhere } from '../../utils/trim-chars.js';
11
12
  export function renderMarkdownToSafeHtml(markdown) {
12
13
  return postProcessMarkdownHtml(micromark(escapeTableCodePipes(markdown), {
13
14
  extensions: [gfm()],
@@ -56,7 +57,7 @@ function isTableDelimiter(line) {
56
57
  function escapeCodeSpanPipes(line) {
57
58
  if (!line.includes('|') || !line.includes('`'))
58
59
  return line;
59
- return line.replace(/`([^`]*\|[^`]*)`/g, (_match, code) => `\`${code.replace(/\|/g, '\\|')}\``);
60
+ return line.replace(/`([^`|]*\|[^`]*)`/g, (_match, code) => `\`${code.replace(/\|/g, '\\|')}\``);
60
61
  }
61
62
  function postProcessMarkdownHtml(html) {
62
63
  let out = html.trim();
@@ -78,11 +79,8 @@ function postProcessMarkdownHtml(html) {
78
79
  }
79
80
  function normalizeSafeHref(href) {
80
81
  const decoded = decodeHref(href);
81
- const stripped = decoded.replace(/[!"')}\],.;:\s]+$/, '');
82
- if (stripped.startsWith('#') ||
83
- stripped.startsWith('/') ||
84
- stripped.startsWith('./') ||
85
- stripped.startsWith('../') ||
82
+ const stripped = trimTrailingWhere(decoded, (char) => /[!"')}\],.;:\s]/.test(char));
83
+ if (['#', '/', './', '../'].some(prefix => stripped.startsWith(prefix)) ||
86
84
  /^https?:\/\//i.test(stripped) ||
87
85
  /^mailto:/i.test(stripped)) {
88
86
  return stripped;
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Syntax-highlighted code fragments for artifact rendering. Verbatim port of
3
+ * `apps/web/src/runtime/shiki.ts` in the origin project — no product-specific
4
+ * logic in the original. See `archived provenance ledger`.
5
+ */
6
+ import { loadOptionalPeer } from '@jini-ai/core/optional-peer';
1
7
  let highlighterPromise = null;
2
8
  const cache = new Map();
3
9
  const CACHE_MAX = 128;
@@ -8,7 +14,7 @@ const CACHE_MAX = 128;
8
14
  // around with a cast that would fail at runtime. See `archived provenance ledger`.
9
15
  function getHighlighter() {
10
16
  if (!highlighterPromise) {
11
- highlighterPromise = import('shiki/bundle/web').then(({ createHighlighter }) => createHighlighter({
17
+ highlighterPromise = loadOptionalPeer({ feature: 'Syntax highlighting', dependency: 'shiki', load: () => import('shiki/bundle/web') }).then(({ createHighlighter }) => createHighlighter({
12
18
  themes: ['github-light-default', 'github-dark-default'],
13
19
  langs: [
14
20
  'javascript', 'typescript', 'tsx', 'jsx', 'html', 'css', 'json',
@@ -1,4 +1,5 @@
1
1
  import { defaultAdminTheme } from '../core/theme/default.js';
2
+ import { kebabThemeKey } from '../core/theme/css-name.js';
2
3
  import { adminThemeColorKeys, validateAdminTheme } from '../core/theme/validation.js';
3
4
  const fontLeases = new WeakMap();
4
5
  function acquireFont(document, href) {
@@ -20,17 +21,20 @@ function acquireFont(document, href) {
20
21
  }
21
22
  const held = lease;
22
23
  held.users++;
23
- return () => { if (--held.users === 0) {
24
+ return () => {
25
+ held.users -= 1;
26
+ if (held.users !== 0)
27
+ return;
24
28
  if (held.owned)
25
29
  held.link.remove();
26
30
  leases.delete(absolute);
27
- } };
31
+ };
28
32
  }
29
33
  function themeValues({ theme }, _options = {}) {
30
34
  const values = {};
31
35
  for (const scheme of ['light', 'dark'])
32
36
  for (const key of adminThemeColorKeys) {
33
- values[`--jini-theme-${scheme}-${key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}`] = theme[scheme][key];
37
+ values[`--jini-theme-${scheme}-${kebabThemeKey(key)}`] = theme[scheme][key];
34
38
  }
35
39
  values['--jini-font-body'] = theme.fonts.body;
36
40
  values['--jini-font-heading'] = theme.fonts.heading;
@@ -0,0 +1,3 @@
1
+ /** `base` plus a caller-supplied extra class, space-separated; an absent or empty extra adds nothing. */
2
+ export declare function withClassName(base: string, extra: string | null | undefined): string;
3
+ //# sourceMappingURL=class-names.d.ts.map
@@ -0,0 +1,5 @@
1
+ /** `base` plus a caller-supplied extra class, space-separated; an absent or empty extra adds nothing. */
2
+ export function withClassName(base, extra) {
3
+ return extra ? `${base} ${extra}` : base;
4
+ }
5
+ //# sourceMappingURL=class-names.js.map
@@ -6,16 +6,16 @@
6
6
  // heading's text — the same fuzzy match a hand-edited doc's headings need to
7
7
  // keep matching after a human renames "Color Palette" to "Palette", etc.
8
8
  export function designMdHeadings(body, startOffset) {
9
- return [...body.slice(startOffset).matchAll(/^##\s+(.+?)\s*$/gm)].map((match) => {
9
+ return [...body.slice(startOffset).matchAll(/^##\s+(\S.*|.)$/gm)].map((match) => {
10
10
  // `RegExpMatchArray.index` and a capture group are typed as possibly
11
11
  // `undefined` because the JS regex API can't express "always set for a
12
12
  // `matchAll` result" / "always set for a mandatory capture group" — for
13
13
  // this specific pattern (an unanchored global match, one non-optional
14
- // `(.+?)` group) both are always defined whenever a match exists.
14
+ // title group) both are always defined whenever a match exists.
15
15
  const start = startOffset + match.index;
16
16
  return {
17
17
  start,
18
- title: match[1],
18
+ title: match[1].trimEnd() || match[1],
19
19
  };
20
20
  });
21
21
  }
@@ -11,5 +11,5 @@ import type { KeyboardEvent as ReactKeyboardEvent } from 'react';
11
11
  *
12
12
  * @overallScore 100
13
13
  */
14
- export declare function isImeComposing(event: ReactKeyboardEvent<HTMLInputElement | HTMLTextAreaElement>, composing: boolean): boolean;
14
+ export declare function isImeComposing(_event: ReactKeyboardEvent<HTMLInputElement | HTMLTextAreaElement>, composing: boolean): boolean;
15
15
  //# sourceMappingURL=ime-composing.d.ts.map