@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.
Files changed (183) hide show
  1. package/dist/browser/useDismissOnOutsideOrEscape.js +1 -1
  2. package/dist/browser/useGlobalKeydown.js +2 -2
  3. package/dist/browser/useModalWindowDragGuard.js +1 -1
  4. package/dist/core/theme/css-name.d.ts +3 -0
  5. package/dist/core/theme/css-name.js +5 -0
  6. package/dist/core/theme/stylesheet.js +2 -1
  7. package/dist/core/theme/validation.js +15 -4
  8. package/dist/features/about/rules.js +2 -1
  9. package/dist/features/admin-widgets/components/InfoTip.hooks.js +22 -12
  10. package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +1 -1
  11. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +1 -1
  12. package/dist/features/admin-widgets/components/SeeMore/SeeMore.hooks.js +2 -2
  13. package/dist/features/admin-widgets/components/SeeMore/SeeMore.js +4 -2
  14. package/dist/features/admin-widgets/components/Select/Select.hooks.js +2 -1
  15. package/dist/features/admin-widgets/components/Select/Select.js +2 -1
  16. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.js +4 -2
  17. package/dist/features/admin-widgets/components/useDebouncedHtmlPreview.hooks.js +3 -2
  18. package/dist/features/asset-grid/react/components/AssetGrid.js +8 -3
  19. package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +7 -6
  20. package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +8 -10
  21. package/dist/features/asset-grid/react/hooks/useRubberBandDrag.js +1 -1
  22. package/dist/features/asset-tree-browser/react/components/AssetTreeFileRow.js +6 -8
  23. package/dist/features/asset-tree-browser/react/hooks/useAssetTreeRowMenu.js +1 -1
  24. package/dist/features/asset-tree-browser/rules.js +1 -3
  25. package/dist/features/browser-chrome/rules.js +10 -8
  26. package/dist/features/charts/browser.js +2 -1
  27. package/dist/features/charts/react.js +3 -1
  28. package/dist/features/connectors/ConnectorsBrowser.js +3 -1
  29. package/dist/features/connectors/hooks/useConnectorAuthorization.js +1 -1
  30. package/dist/features/connectors/hooks/useConnectorCatalog.js +2 -2
  31. package/dist/features/connectors/rules.js +10 -14
  32. package/dist/features/execution/react/components/AgentDiagnosticRow.js +2 -0
  33. package/dist/features/execution/react/components/ByokProviderForm.js +1 -3
  34. package/dist/features/execution/react/components/LocalCliAgentSettings.js +2 -1
  35. package/dist/features/execution/react/hooks/use-byok-field-validation.hooks.js +6 -2
  36. package/dist/features/execution/react/hooks/useExecutionTab.js +9 -5
  37. package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +3 -6
  38. package/dist/features/execution/react/hooks/useReasoningControl.js +3 -3
  39. package/dist/features/execution/rules.js +23 -18
  40. package/dist/features/external-mcp/react/components/ExternalMcpTab.js +10 -1
  41. package/dist/features/file-dropzone/rules.js +3 -2
  42. package/dist/features/html-editor/canvas-embed-placeholders.js +2 -3
  43. package/dist/features/html-editor/css.js +7 -5
  44. package/dist/features/html-editor/editor-blocks.js +60 -6
  45. package/dist/features/html-editor/protected-elements.js +5 -3
  46. package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +3 -3
  47. package/dist/features/html-editor/source-splice.js +6 -4
  48. package/dist/features/iframe-pool/react/components/IframeKeepAliveProvider.js +5 -5
  49. package/dist/features/iframe-pool/react/dom-sync.js +2 -2
  50. package/dist/features/integrations/react/components/IntegrationsTab.js +3 -1
  51. package/dist/features/integrations/rules.js +6 -4
  52. package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -5
  53. package/dist/features/interactive-ui/table-data.js +1 -1
  54. package/dist/features/lexical-rich-text-editor/deserialize.js +2 -2
  55. package/dist/features/lexical-rich-text-editor/mention-parser.js +4 -4
  56. package/dist/features/lexical-rich-text-editor/react/components/RichTextInput.js +2 -1
  57. package/dist/features/lexical-rich-text-editor/react/hooks/useCaretFloatingLayerPosition.js +1 -1
  58. package/dist/features/lexical-rich-text-editor/react/hooks/useMentionColorStamping.js +1 -1
  59. package/dist/features/lexical-rich-text-editor/serialize.js +13 -10
  60. package/dist/features/list-detail-panel/react/components/ListDetailPanel.js +1 -1
  61. package/dist/features/mcp-ui/confirmation-store.js +3 -6
  62. package/dist/features/mcp-ui/surfaces/confirmation.d.ts +5 -0
  63. package/dist/features/mcp-ui/surfaces/confirmation.js +1 -0
  64. package/dist/features/mcp-ui/surfaces/document.d.ts +3 -15
  65. package/dist/features/mcp-ui/surfaces/document.js +37 -6
  66. package/dist/features/mcp-ui/surfaces/fields.js +2 -0
  67. package/dist/features/mcp-ui/surfaces/host-theme.js +2 -1
  68. package/dist/features/mcp-ui/surfaces/index.d.ts +1 -0
  69. package/dist/features/mcp-ui/surfaces/index.js +1 -0
  70. package/dist/features/mcp-ui/surfaces/outcome.js +1 -1
  71. package/dist/features/mcp-ui/surfaces/select.js +2 -1
  72. package/dist/features/mcp-ui/surfaces/structured-details.d.ts +40 -0
  73. package/dist/features/mcp-ui/surfaces/structured-details.js +159 -0
  74. package/dist/features/mcp-ui/surfaces/text-input.js +1 -1
  75. package/dist/features/mcp-ui/surfaces/tool-approval.d.ts +21 -0
  76. package/dist/features/mcp-ui/surfaces/tool-approval.js +41 -0
  77. package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +2 -1
  78. package/dist/features/memory/async-commit-guard.js +4 -1
  79. package/dist/features/memory/formatters.js +5 -1
  80. package/dist/features/memory/react/components/MemoryConnectedPanel.js +3 -1
  81. package/dist/features/memory/react/components/MemoryEntryCard.js +1 -1
  82. package/dist/features/memory/react/components/MemorySettingsPanel.js +3 -1
  83. package/dist/features/memory/react/hooks/useMemoryConfig.hooks.js +12 -10
  84. package/dist/features/memory/react/hooks/useMemoryConnectors.hooks.js +2 -5
  85. package/dist/features/memory/react/hooks/useMemoryConnectors.rules.js +10 -9
  86. package/dist/features/memory/react/hooks/useMemoryEntries.hooks.js +4 -2
  87. package/dist/features/memory/react/hooks/useMemoryFlash.hooks.js +1 -1
  88. package/dist/features/memory/rules.js +2 -1
  89. package/dist/features/panel-kit/fetch-query/adapter.react.js +3 -2
  90. package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +3 -2
  91. package/dist/features/panel-kit/fetch-query/binding.react.js +2 -1
  92. package/dist/features/panel-kit/helpers/standing-draft-recovery-message.js +13 -4
  93. package/dist/features/panel-kit/hooks/use-dirty-guard.hooks.js +1 -1
  94. package/dist/features/panel-kit/hooks/use-focus-trap.hooks.js +1 -1
  95. package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +14 -10
  96. package/dist/features/panel-kit/hooks/use-standing-draft-autosave.hooks.js +2 -2
  97. package/dist/features/progress-card/components/ProgressCard.d.ts +1 -1
  98. package/dist/features/progress-card/reference-adapters.js +23 -13
  99. package/dist/features/progress-card/rules.d.ts +0 -1
  100. package/dist/features/progress-card/rules.js +14 -20
  101. package/dist/features/progress-card/types.d.ts +1 -1
  102. package/dist/features/project-locations/dependencies.js +6 -1
  103. package/dist/features/project-locations/react/components/ProjectLocationsTab.js +2 -1
  104. package/dist/features/project-locations/rules.js +2 -1
  105. package/dist/features/resource-dashboard/react/components/ResourceBoardToolbar.js +8 -1
  106. package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +2 -1
  107. package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +3 -1
  108. package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +2 -1
  109. package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +1 -1
  110. package/dist/features/resource-dashboard/react/hooks/useResourceBoard.js +1 -1
  111. package/dist/features/schedule-picker/rules.js +13 -7
  112. package/dist/features/sketch-editor/constants.d.ts +0 -6
  113. package/dist/features/sketch-editor/constants.js +17 -15
  114. package/dist/features/sketch-editor/dom.js +4 -7
  115. package/dist/features/sketch-editor/react/components/SketchMainMenu.js +2 -1
  116. package/dist/features/sketch-editor/react/components/SketchSaveStateBadge.js +2 -1
  117. package/dist/features/sketch-editor/react/hooks/useSketchDomEnhancements.js +1 -1
  118. package/dist/features/sketch-editor/rules.js +13 -12
  119. package/dist/features/skills/dependencies.js +9 -4
  120. package/dist/features/skills/react/components/SkillRow.js +2 -1
  121. package/dist/features/skills/react/components/SkillsTab.js +2 -1
  122. package/dist/features/skills/rules.js +3 -3
  123. package/dist/features/source-config-list/agent-handles.js +4 -3
  124. package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +3 -1
  125. package/dist/features/tab-strip/react/components/TabBar.hooks.js +4 -2
  126. package/dist/features/version-manager/react/components/VersionPreviewFrame.js +4 -1
  127. package/dist/features/version-manager/react/components/VersionSidebar.js +8 -6
  128. package/dist/features/version-manager/react/hooks/usePreviewCanvasSize.js +1 -1
  129. package/dist/features/version-manager/react/hooks/useVersionManager.js +5 -7
  130. package/dist/features/version-manager/rules.js +3 -5
  131. package/dist/features/viewer-shell/react/components/CommentSidePanel.js +2 -1
  132. package/dist/features/viewer-shell/react/components/SegmentedToggle.js +2 -1
  133. package/dist/features/viewer-shell/react/components/ViewerShell.js +2 -1
  134. package/dist/features/viewer-shell/rules.js +8 -7
  135. package/dist/react/components/BrandLogo.js +10 -2
  136. package/dist/react/components/CustomSelect.js +1 -1
  137. package/dist/react/components/EditorIcon.js +17 -14
  138. package/dist/react/components/Loading.js +2 -1
  139. package/dist/react/components/OnboardingChipField.js +5 -1
  140. package/dist/react/components/OnboardingDropdown.js +6 -4
  141. package/dist/react/components/PaletteTweaks.js +7 -6
  142. package/dist/react/components/PillButton.js +2 -1
  143. package/dist/react/components/PopoverMenu.js +2 -1
  144. package/dist/react/components/RemixIcon.js +2 -1
  145. package/dist/react/components/SecretInput.hooks.d.ts +2 -25
  146. package/dist/react/components/SecretInput.hooks.js +2 -24
  147. package/dist/react/components/SecretInput.js +5 -4
  148. package/dist/react/components/Toast.js +4 -2
  149. package/dist/react/components/TooltipLayer.js +4 -1
  150. package/dist/react/components/WorkingDirPicker.js +5 -4
  151. package/dist/react/components/remixicon-font-recovery.js +9 -1
  152. package/dist/react/components/select-popover.js +2 -2
  153. package/dist/react/hooks/useBrandFonts.js +1 -1
  154. package/dist/react/hooks/useEdgeAutoScroll.js +1 -1
  155. package/dist/react/hooks/useInView.js +9 -9
  156. package/dist/react/hooks/useResizableSplitPane.js +12 -20
  157. package/dist/react/mcp-ui/useHostSurfaceTokens.js +1 -1
  158. package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +7 -1
  159. package/dist/renderers/annotation-canvas/react/hooks/useAnnotationCanvas.controller.js +4 -2
  160. package/dist/renderers/annotation-canvas/react/hooks/useAnnotationCanvas.js +9 -5
  161. package/dist/renderers/annotation-canvas/rules.js +9 -13
  162. package/dist/renderers/annotation-canvas/theme.js +5 -2
  163. package/dist/renderers/renderers/index.js +1 -1
  164. package/dist/renderers/renderers/markdown.js +4 -6
  165. package/dist/theme/apply.js +7 -3
  166. package/dist/utils/class-names.d.ts +3 -0
  167. package/dist/utils/class-names.js +5 -0
  168. package/dist/utils/design-md.js +3 -3
  169. package/dist/utils/ime-composing.d.ts +1 -1
  170. package/dist/utils/ime-composing.js +1 -2
  171. package/dist/utils/localized-url.js +2 -11
  172. package/dist/utils/markdown-scroll-sync.js +1 -1
  173. package/dist/utils/omit-keys.d.ts +3 -0
  174. package/dist/utils/omit-keys.js +8 -0
  175. package/dist/utils/polygon-selection.js +1 -1
  176. package/dist/utils/sse.js +3 -0
  177. package/dist/utils/trim-chars.d.ts +13 -0
  178. package/dist/utils/trim-chars.js +30 -0
  179. package/dist/utils/unhandled-case.d.ts +10 -0
  180. package/dist/utils/unhandled-case.js +12 -0
  181. package/dist/utils/unit-bezier.js +1 -3
  182. package/dist/utils/zip.js +6 -10
  183. package/package.json +10 -9
@@ -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,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
@@ -10,8 +10,7 @@
10
10
  *
11
11
  * @overallScore 100
12
12
  */
13
- export function isImeComposing(event, composing) {
14
- void event;
13
+ export function isImeComposing(_event, composing) {
15
14
  return composing;
16
15
  }
17
16
  //# sourceMappingURL=ime-composing.js.map
@@ -1,15 +1,6 @@
1
- // Build a locale-segmented URL against a host-supplied base and locale-map,
2
- // e.g. for linking out to a marketing/docs site in the reader's language.
3
- //
4
- // Ported from an origin helper that hardcoded one product's own marketing
5
- // domain and locale table inline — that's product identity, not reusable
6
- // logic, so it's dropped here. What's actually generic and worth keeping is
7
- // the resolution algorithm: map the active locale to a URL segment (falling
8
- // back to no segment — i.e. the base's default language — for locales the
9
- // target site doesn't support), then join it onto the base. `baseUrl` and
10
- // `localeSegments` are supplied by the caller.
1
+ import { trimTrailingChars } from './trim-chars.js';
11
2
  export function buildLocalizedUrl(locale, options) {
12
- const base = options.baseUrl.replace(/\/+$/, '');
3
+ const base = trimTrailingChars(options.baseUrl, '/');
13
4
  const segment = options.localeSegments?.[locale];
14
5
  return segment ? `${base}/${segment}/` : `${base}/`;
15
6
  }
@@ -160,7 +160,7 @@ function buildMirrorMarkup({ blockLines, text }) {
160
160
  // is escaped, so it cannot inject one), so each index is a valid block index.
161
161
  function readMarkerOffsets({ mirror, blockCount }) {
162
162
  document.body.appendChild(mirror);
163
- const offsets = new Array(blockCount).fill(0);
163
+ const offsets = Array.from({ length: blockCount }, () => 0);
164
164
  try {
165
165
  for (const marker of Array.from(mirror.querySelectorAll('span[data-md-block]'))) {
166
166
  offsets[Number(marker.getAttribute('data-md-block'))] = marker.offsetTop;
@@ -0,0 +1,3 @@
1
+ /** A shallow copy of `value` without `keys` — the rest-destructuring "omit" idiom, minus the unused bindings. */
2
+ export declare function omitKeys<T extends object, K extends keyof T>(value: T, keys: readonly K[]): Omit<T, K>;
3
+ //# sourceMappingURL=omit-keys.d.ts.map
@@ -0,0 +1,8 @@
1
+ /** A shallow copy of `value` without `keys` — the rest-destructuring "omit" idiom, minus the unused bindings. */
2
+ export function omitKeys(value, keys) {
3
+ const copy = { ...value };
4
+ for (const key of keys)
5
+ Reflect.deleteProperty(copy, key);
6
+ return copy;
7
+ }
8
+ //# sourceMappingURL=omit-keys.js.map
@@ -55,7 +55,7 @@ export function lineIntersectsLine(a1, a2, b1, b2) {
55
55
  /** Standard even-odd-rule ray-casting point-in-polygon test. */
56
56
  export function pointInPolygon(point, polygon) {
57
57
  let inside = false;
58
- for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
58
+ for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i, i += 1) {
59
59
  const pi = polygon[i];
60
60
  const pj = polygon[j];
61
61
  // No `|| Number.EPSILON` divide-by-zero guard on `(pj.y - pi.y)`: the
package/dist/utils/sse.js CHANGED
@@ -15,6 +15,9 @@ function applySseLine({ fields, line }) {
15
15
  else if (line.startsWith('data: ')) {
16
16
  fields.dataLines.push(line.slice(6));
17
17
  }
18
+ else {
19
+ // Any other field (e.g. `retry:`) or a malformed line is ignored.
20
+ }
18
21
  }
19
22
  /** Build the result for a frame that carried no `data:` lines. */
20
23
  function dataLessFrame({ comments }) {
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Linear-time trimming of a set of characters, in place of `value.replace(/[…]+$/, '')`-style
3
+ * regexes whose engine retries the run from every start position (quadratic on long runs).
4
+ * `chars` is a set of single UTF-16 code units, matched exactly like a non-`u` regex class.
5
+ */
6
+ export declare function trimTrailingChars(value: string, chars: string): string;
7
+ /** Leading counterpart of {@link trimTrailingChars}. */
8
+ export declare function trimLeadingChars(value: string, chars: string): string;
9
+ /** Both ends — the linear form of `value.replace(/^[…]+|[…]+$/g, '')`. */
10
+ export declare function trimChars(value: string, chars: string): string;
11
+ /** {@link trimTrailingChars} for a character class a plain list cannot spell (e.g. one including `\s`). */
12
+ export declare function trimTrailingWhere(value: string, isTrimmed: (char: string) => boolean): string;
13
+ //# sourceMappingURL=trim-chars.d.ts.map
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Linear-time trimming of a set of characters, in place of `value.replace(/[…]+$/, '')`-style
3
+ * regexes whose engine retries the run from every start position (quadratic on long runs).
4
+ * `chars` is a set of single UTF-16 code units, matched exactly like a non-`u` regex class.
5
+ */
6
+ export function trimTrailingChars(value, chars) {
7
+ let end = value.length;
8
+ while (end > 0 && chars.includes(value[end - 1]))
9
+ end -= 1;
10
+ return value.slice(0, end);
11
+ }
12
+ /** Leading counterpart of {@link trimTrailingChars}. */
13
+ export function trimLeadingChars(value, chars) {
14
+ let start = 0;
15
+ while (start < value.length && chars.includes(value[start]))
16
+ start += 1;
17
+ return value.slice(start);
18
+ }
19
+ /** Both ends — the linear form of `value.replace(/^[…]+|[…]+$/g, '')`. */
20
+ export function trimChars(value, chars) {
21
+ return trimLeadingChars(trimTrailingChars(value, chars), chars);
22
+ }
23
+ /** {@link trimTrailingChars} for a character class a plain list cannot spell (e.g. one including `\s`). */
24
+ export function trimTrailingWhere(value, isTrimmed) {
25
+ let end = value.length;
26
+ while (end > 0 && isTrimmed(value[end - 1]))
27
+ end -= 1;
28
+ return value.slice(0, end);
29
+ }
30
+ //# sourceMappingURL=trim-chars.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Closes an exhaustive `switch` over a closed union.
3
+ *
4
+ * `value` is typed `never`, so the compiler still flags any union member the
5
+ * switch forgot. At runtime a value outside the declared union yields
6
+ * `undefined` — exactly what falling off the end of the switch did before — so
7
+ * ending a switch with `return unhandledCase(x)` changes no behaviour.
8
+ */
9
+ export declare function unhandledCase(_value: never): never;
10
+ //# sourceMappingURL=unhandled-case.d.ts.map
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Closes an exhaustive `switch` over a closed union.
3
+ *
4
+ * `value` is typed `never`, so the compiler still flags any union member the
5
+ * switch forgot. At runtime a value outside the declared union yields
6
+ * `undefined` — exactly what falling off the end of the switch did before — so
7
+ * ending a switch with `return unhandledCase(x)` changes no behaviour.
8
+ */
9
+ export function unhandledCase(_value) {
10
+ return undefined;
11
+ }
12
+ //# sourceMappingURL=unhandled-case.js.map
@@ -21,14 +21,12 @@ export function unitBezier(x1, y1, x2, y2) {
21
21
  let t = x;
22
22
  for (let i = 0; i < 8; i += 1) {
23
23
  const err = sampleX(t) - x;
24
- if (Math.abs(err) < 1e-6)
25
- break;
26
24
  const d = sampleDX(t);
27
25
  // A flat x-derivative would make the Newton step divide by ~0. For smooth-scroll-to-top's
28
26
  // fixed ease-out curve sampleDX stays at least about 0.6095 over [0, 1], so it never fires
29
27
  // there; it does for degenerate control points (e.g. x1 = x2 = 0 near x = 0), where the
30
28
  // current estimate is kept rather than stepping to Infinity/NaN.
31
- if (Math.abs(d) < 1e-6)
29
+ if (Math.abs(err) < 1e-6 || Math.abs(d) < 1e-6)
32
30
  break;
33
31
  t -= err / d;
34
32
  }
package/dist/utils/zip.js CHANGED
@@ -3,17 +3,13 @@
3
3
  // few MB — skipping deflate keeps the implementation small and
4
4
  // dependency-free, which matters for a package meant to run in any host
5
5
  // (browser or Node) without pulling in a compression library.
6
- const CRC_TABLE = (() => {
7
- const t = new Array(256);
8
- for (let n = 0; n < 256; n++) {
9
- let c = n;
10
- for (let k = 0; k < 8; k++) {
11
- c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
12
- }
13
- t[n] = c >>> 0;
6
+ const CRC_TABLE = Array.from({ length: 256 }, (_, n) => {
7
+ let c = n;
8
+ for (let k = 0; k < 8; k++) {
9
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
14
10
  }
15
- return t;
16
- })();
11
+ return c >>> 0;
12
+ });
17
13
  function crc32(bytes) {
18
14
  let c = 0xffffffff;
19
15
  for (let i = 0; i < bytes.length; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jini-ai/ui",
3
- "version": "0.6.15-rc.2",
3
+ "version": "0.6.15",
4
4
  "description": "Generic, product-neutral React UI primitives and feature domains. Framework-free types, decision rules, catalogs, and host port contracts live behind ./core (no React, no DOM). The Excalidraw and Lexical editors live behind ./sketch-editor and ./lexical-rich-text-editor; the GrapesJS-backed inline HTML editor lives behind ./html-editor.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -243,14 +243,15 @@
243
243
  "shiki": "^1.24.4",
244
244
  "tailwind-merge": "^2.6.0",
245
245
  "zod": "^3.25.76",
246
- "@jini-ai/agent-runtime": "^0.6.15-rc.2",
247
- "@jini-ai/integrations": "^0.6.15-rc.2",
248
- "@jini-ai/platform": "^0.6.15-rc.2",
249
- "@jini-ai/core": "^0.6.15-rc.2",
250
- "@jini-ai/agentic": "^0.6.15-rc.2"
246
+ "@jini-ai/agent-runtime": "^0.6.15",
247
+ "@jini-ai/integrations": "^0.6.15",
248
+ "@jini-ai/agentic": "^0.6.15",
249
+ "@jini-ai/core": "^0.6.15",
250
+ "@jini-ai/platform": "^0.6.15"
251
251
  },
252
252
  "dependencies": {
253
- "@jini-ai/core": "^0.6.15-rc.2"
253
+ "@jini-ai/ui-kit": "^0.6.15",
254
+ "@jini-ai/core": "^0.6.15"
254
255
  },
255
256
  "peerDependencies": {
256
257
  "@tanstack/react-query": "^5.0.0",
@@ -267,8 +268,8 @@
267
268
  "lexical": "0.36.2",
268
269
  "react": "^18.3.0 || ^19.0.0",
269
270
  "react-dom": "^18.3.0 || ^19.0.0",
270
- "@jini-ai/platform": "^0.6.15-rc.2",
271
- "@jini-ai/agentic": "^0.6.15-rc.2",
271
+ "@jini-ai/platform": "^0.6.10",
272
+ "@jini-ai/agentic": "^0.6.10",
272
273
  "class-variance-authority": "^0.7.1",
273
274
  "clsx": "^2.1.1",
274
275
  "micromark": "^4.0.0",