@jini-ai/ui 0.4.7 → 0.4.8

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 (125) hide show
  1. package/README.md +2 -0
  2. package/dist/features/admin-widgets/components/InfoTip.d.ts +23 -2
  3. package/dist/features/admin-widgets/components/InfoTip.hooks.d.ts +22 -2
  4. package/dist/features/admin-widgets/components/InfoTip.hooks.js +75 -28
  5. package/dist/features/admin-widgets/components/InfoTip.js +12 -4
  6. package/dist/features/admin-widgets/components/InfoTip.rules.d.ts +72 -0
  7. package/dist/features/admin-widgets/components/InfoTip.rules.js +68 -0
  8. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.d.ts +36 -0
  9. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.d.ts +58 -0
  10. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.js +66 -0
  11. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.js +24 -0
  12. package/dist/features/admin-widgets/components/useDebouncedHtmlPreview.hooks.d.ts +23 -0
  13. package/dist/features/admin-widgets/components/useDebouncedHtmlPreview.hooks.js +28 -0
  14. package/dist/features/admin-widgets/index.d.ts +9 -0
  15. package/dist/features/admin-widgets/index.js +5 -0
  16. package/dist/features/execution/constants.js +11 -10
  17. package/dist/features/execution/http-adapter.d.ts +3 -1
  18. package/dist/features/execution/http-adapter.js +9 -4
  19. package/dist/features/execution/index.d.ts +1 -1
  20. package/dist/features/execution/index.js +1 -1
  21. package/dist/features/execution/react/components/ByokProviderForm.d.ts +18 -1
  22. package/dist/features/execution/react/components/ByokProviderForm.js +14 -16
  23. package/dist/features/execution/react/components/LocalCliAgentCard.d.ts +5 -1
  24. package/dist/features/execution/react/components/LocalCliAgentCard.js +12 -87
  25. package/dist/features/execution/react/components/LocalCliAgentList.d.ts +4 -1
  26. package/dist/features/execution/react/components/LocalCliAgentList.js +13 -4
  27. package/dist/features/execution/react/components/LocalCliAgentSettings.d.ts +20 -0
  28. package/dist/features/execution/react/components/LocalCliAgentSettings.js +20 -0
  29. package/dist/features/execution/react/hooks/use-byok-field-validation.hooks.d.ts +24 -0
  30. package/dist/features/execution/react/hooks/use-byok-field-validation.hooks.js +27 -0
  31. package/dist/features/execution/react/hooks/useExecutionTab.js +10 -1
  32. package/dist/features/execution/react/hooks/useLocalCliAgentCard.d.ts +48 -0
  33. package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +110 -0
  34. package/dist/features/execution/react/hooks/useLocalCliAgentList.d.ts +19 -0
  35. package/dist/features/execution/react/hooks/useLocalCliAgentList.js +13 -0
  36. package/dist/features/execution/rules.d.ts +13 -0
  37. package/dist/features/execution/rules.js +14 -0
  38. package/dist/features/execution/types.d.ts +2 -0
  39. package/dist/features/html-editor/canvas-embed-placeholders.d.ts +13 -1
  40. package/dist/features/html-editor/canvas-embed-placeholders.js +61 -12
  41. package/dist/features/html-editor/dom.d.ts +5 -0
  42. package/dist/features/html-editor/dom.js +10 -0
  43. package/dist/features/html-editor/editor-blocks.d.ts +71 -0
  44. package/dist/features/html-editor/editor-blocks.js +185 -0
  45. package/dist/features/html-editor/editor-serialization.d.ts +24 -0
  46. package/dist/features/html-editor/editor-serialization.js +110 -0
  47. package/dist/features/html-editor/index.d.ts +5 -0
  48. package/dist/features/html-editor/index.js +3 -0
  49. package/dist/features/html-editor/protected-elements.d.ts +64 -0
  50. package/dist/features/html-editor/protected-elements.js +189 -0
  51. package/dist/features/html-editor/react/components/InteractiveHtmlEditor.d.ts +6 -4
  52. package/dist/features/html-editor/react/components/InteractiveHtmlEditor.js +3 -3
  53. package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.d.ts +9 -1
  54. package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +107 -196
  55. package/dist/features/html-editor/source-splice.d.ts +23 -0
  56. package/dist/features/html-editor/source-splice.js +45 -0
  57. package/dist/features/i18n/dictionaries/settings-dialog.ar.js +4 -0
  58. package/dist/features/i18n/dictionaries/settings-dialog.bn.js +4 -0
  59. package/dist/features/i18n/dictionaries/settings-dialog.de.js +4 -0
  60. package/dist/features/i18n/dictionaries/settings-dialog.en.js +4 -0
  61. package/dist/features/i18n/dictionaries/settings-dialog.es.js +4 -0
  62. package/dist/features/i18n/dictionaries/settings-dialog.fa.js +4 -0
  63. package/dist/features/i18n/dictionaries/settings-dialog.fr.js +4 -0
  64. package/dist/features/i18n/dictionaries/settings-dialog.hi.js +4 -0
  65. package/dist/features/i18n/dictionaries/settings-dialog.hu.js +4 -0
  66. package/dist/features/i18n/dictionaries/settings-dialog.id.js +4 -0
  67. package/dist/features/i18n/dictionaries/settings-dialog.it.js +4 -0
  68. package/dist/features/i18n/dictionaries/settings-dialog.ja.js +4 -0
  69. package/dist/features/i18n/dictionaries/settings-dialog.ko.js +4 -0
  70. package/dist/features/i18n/dictionaries/settings-dialog.pl.js +4 -0
  71. package/dist/features/i18n/dictionaries/settings-dialog.pt-BR.js +4 -0
  72. package/dist/features/i18n/dictionaries/settings-dialog.ru.js +4 -0
  73. package/dist/features/i18n/dictionaries/settings-dialog.th.js +4 -0
  74. package/dist/features/i18n/dictionaries/settings-dialog.tr.js +4 -0
  75. package/dist/features/i18n/dictionaries/settings-dialog.uk.js +4 -0
  76. package/dist/features/i18n/dictionaries/settings-dialog.ur.js +4 -0
  77. package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +4 -0
  78. package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +4 -0
  79. package/dist/features/interactive-ui/providers/shadcn/button.d.ts +1 -1
  80. package/dist/features/mcp-ui/escape.js +2 -6
  81. package/dist/features/mcp-ui/surfaces/bridge.js +4 -2
  82. package/dist/features/mcp-ui/surfaces/document.d.ts +11 -4
  83. package/dist/features/mcp-ui/surfaces/document.js +25 -3
  84. package/dist/features/mcp-ui/surfaces/outcome.js +1 -1
  85. package/dist/features/media-providers/constants.d.ts +0 -7
  86. package/dist/features/media-providers/constants.js +7 -15
  87. package/dist/features/media-providers/react/components/MediaProvidersTab.js +3 -2
  88. package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +6 -3
  89. package/dist/features/memory/dependencies.d.ts +2 -0
  90. package/dist/features/memory/dependencies.js +9 -25
  91. package/dist/features/memory/index.d.ts +1 -0
  92. package/dist/features/memory/index.js +1 -0
  93. package/dist/features/memory/react/MemoryPorts.d.ts +17 -0
  94. package/dist/features/memory/react/MemoryPorts.js +15 -0
  95. package/dist/features/memory/react/hooks/useMemoryConfig.hooks.d.ts +2 -2
  96. package/dist/features/memory/react/hooks/useMemoryConfig.hooks.js +7 -7
  97. package/dist/features/memory/react/hooks/useMemoryConnectors.hooks.d.ts +2 -3
  98. package/dist/features/memory/react/hooks/useMemoryConnectors.hooks.js +4 -5
  99. package/dist/features/memory/react/hooks/useMemoryEntries.hooks.d.ts +2 -3
  100. package/dist/features/memory/react/hooks/useMemoryEntries.hooks.js +4 -5
  101. package/dist/features/memory/react/hooks/useMemoryExtractions.hooks.js +2 -2
  102. package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +2 -2
  103. package/dist/features/panel-kit/fetch-query/adapter.react.js +2 -2
  104. package/dist/features/panel-kit/fetch-query/adapter.tanstack.d.ts +1 -1
  105. package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +35 -13
  106. package/dist/features/panel-kit/fetch-query/binding.react.d.ts +1 -1
  107. package/dist/features/panel-kit/fetch-query/environment.browser.d.ts +1 -1
  108. package/dist/features/panel-kit/fetch-query/index.d.ts +4 -2
  109. package/dist/features/panel-kit/fetch-query/tanstack.d.ts +4 -2
  110. package/dist/features/panel-kit/helpers/standing-draft-recovery-message.d.ts +3 -1
  111. package/dist/features/panel-kit/helpers/standing-draft-recovery-message.js +9 -2
  112. package/dist/features/settings/dialog/styles/settings-dialog.css +169 -21
  113. package/dist/features/tabbed-dialog/styles/tabbed-dialog.css +91 -0
  114. package/dist/react/components/RemixIcon.d.ts +1 -41
  115. package/dist/react/components/RemixIcon.js +3 -176
  116. package/dist/react/components/RemixIcon.stylesheet.d.ts +84 -0
  117. package/dist/react/components/RemixIcon.stylesheet.js +208 -0
  118. package/dist/react/components/remixicon-font-recovery.d.ts +55 -0
  119. package/dist/react/components/remixicon-font-recovery.js +110 -0
  120. package/dist/styles/admin.css +8 -2
  121. package/package.json +12 -7
  122. package/dist/features/panel-kit/fetch-query/cache.d.ts +0 -125
  123. package/dist/features/panel-kit/fetch-query/cache.js +0 -232
  124. package/dist/features/panel-kit/fetch-query/types.d.ts +0 -93
  125. package/dist/features/panel-kit/fetch-query/types.js +0 -2
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Marks whichever stylesheet is currently serving `.ri-*` glyphs — this package's own default, or
3
+ * a host override that got inserted first. `ensureRemixIconStylesheet` checks for this attribute
4
+ * (not a specific `href`) before injecting, so a host that wants its own icon set/font just needs
5
+ * to add a `<link data-jini-remixicon rel="stylesheet" href="...">` (or an equivalent `<style
6
+ * data-jini-remixicon>`) anywhere in `<head>` before the first `RemixIcon` mounts, and this
7
+ * package's default never loads.
8
+ *
9
+ * Exported because every host that has needed the override so far re-declared this string
10
+ * literally rather than importing it -- three copies outside this file, across two apps of the
11
+ * one downstream checkout inspected (2026-09-06), and they do not agree on element type: one
12
+ * installs a `<style>`, the other a `<link>`. A copied magic string is a rename away from
13
+ * silently double-loading the font; importing the constant is not.
14
+ */
15
+ export declare const REMIXICON_STYLESHEET_MARKER = "data-jini-remixicon";
16
+ /**
17
+ * Installs a caller-supplied stylesheet as the one serving `.ri-*` glyphs, claiming
18
+ * {@link REMIXICON_STYLESHEET_MARKER} so this package's own default never loads.
19
+ *
20
+ * This is the supported opt-in for any host whose bundler defeats the default's `import.meta.url`
21
+ * resolution (see {@link ensureRemixIconStylesheet}) — point it at
22
+ * `@jini-ai/ui/remixicon.css`, which is a normal subpath export a bundler resolves and rewrites
23
+ * like any other asset. Call it before the first `RemixIcon` mounts; module top level in the
24
+ * host's entry file is the usual place, since the default injection runs from a `useEffect` and
25
+ * therefore only has to lose a race against React's commit phase.
26
+ *
27
+ * Idempotent and safe to call unconditionally: it no-ops if any marked stylesheet is already
28
+ * present (including one a previous call installed), and no-ops outside a DOM.
29
+ *
30
+ * @param options.href URL of a stylesheet defining the `.ri-*` classes and its own `@font-face`.
31
+ * Resolved by the browser against the document, so relative values follow the page's base URL —
32
+ * pass a bundler-produced URL rather than a hand-written relative path.
33
+ * @returns `true` if this call inserted the stylesheet, `false` if it no-opped.
34
+ * @sideEffects Appends one `<link>` to `document.head`; probes and retries its icon font.
35
+ * @complexity O(n + r) including recovery, for n stylesheet rules and r bounded retries.
36
+ * @overallScore 100
37
+ */
38
+ export declare function installRemixIconStylesheet(options: {
39
+ href: string;
40
+ }, _optional?: object): boolean;
41
+ /**
42
+ * Idempotently loads this package's default RemixIcon webfont/CSS on first use, so a host gets
43
+ * working icons out of the box with zero setup — see {@link REMIXICON_STYLESHEET_MARKER} for how a
44
+ * host overrides this and {@link installRemixIconStylesheet} for the supported way to do it.
45
+ *
46
+ * **This default only survives unbundled ESM, and that is not a fixable property of this
47
+ * function.** It resolves the CSS with `new URL('./remixicon-font/remixicon.css',
48
+ * import.meta.url)`, which is correct exactly while this module is still a real ES module sitting
49
+ * next to its own `remixicon-font/` directory. Three bundler transformations break it three
50
+ * different ways. The first two were confirmed live against this component; the third was
51
+ * confirmed live against its sibling, and is listed because nothing exempts this file from it:
52
+ *
53
+ * - **`iife`/`umd` output** cannot express the reference at all and degrades it to an inlined
54
+ * `data:` URL whose own relative `@font-face` src can never resolve. Confirmed live in a
55
+ * downstream `lib`/`iife` widget bundle, where `document.fonts` reported the `remixicon` face
56
+ * as `status: "error"` with no matching resource entry at all — an unattempted fetch, not a
57
+ * 404. Detected and refused by {@link resolveDefaultStylesheetHref}.
58
+ * - **Production ESM builds** may copy the CSS as an opaque asset without descending into its
59
+ * `url(./remixicon.woff2)`, emitting the stylesheet without the font beside it. Confirmed live
60
+ * in a downstream admin SPA build, which is why that host imports the CSS through its
61
+ * bundler's real CSS pipeline instead of letting this default run.
62
+ * - **Vite dev-server dependency pre-bundling** flattens a package module into a `.vite/deps/`
63
+ * chunk, so an `import.meta.url`-relative URL resolves against the chunk's location instead.
64
+ * Observed live for this package's `AgentIcon` (fixed in 58bf42fa by inlining those assets as
65
+ * `data:` URIs — not an option here, see {@link installRemixIconStylesheet}), *not* observed
66
+ * for this component, whose two known hosts both claim the marker before this default ever
67
+ * runs. Worth knowing how it presented there: not as a 404, but as the dev server's SPA
68
+ * history fallback answering `200 text/html`.
69
+ *
70
+ * A previous version of this comment claimed "Vite/Rollup/webpack all rewrite this correctly at
71
+ * build time". They do not, and each downstream host that hit it rediscovered a different half
72
+ * of the above independently. There is no runtime-resolvable URL that survives all of it — the
73
+ * cannot know where, or whether, its sibling asset was emitted — so the honest contract is: the
74
+ * default is a convenience for unbundled ESM, and any bundled host should call
75
+ * {@link installRemixIconStylesheet} instead. This function's job is to make that failure *loud*
76
+ * rather than silent, since tofu glyphs give no clue where to look.
77
+ *
78
+ * @sideEffects Appends at most one `<link>` to `document.head`; may emit one `console.warn`.
79
+ * Probes and retries the installed font, including a host-provided marked override.
80
+ * @complexity O(n + r) including recovery, for n stylesheet rules and r bounded retries.
81
+ * @overallScore 100
82
+ */
83
+ export declare function ensureRemixIconStylesheet(_input: object, _optional?: object): void;
84
+ //# sourceMappingURL=RemixIcon.stylesheet.d.ts.map
@@ -0,0 +1,208 @@
1
+ import { startRemixIconStylesheetRecovery } from './remixicon-font-recovery.js';
2
+ /** Start once per installed sheet, waiting for linked CSS before inspecting its font source. */
3
+ function recoverFont({ stylesheet }) {
4
+ if (!document.fonts || typeof FontFace === 'undefined')
5
+ return;
6
+ if (stylesheet.tagName !== 'STYLE' && stylesheet.tagName !== 'LINK')
7
+ return;
8
+ const sheet = stylesheet;
9
+ const start = () => startRemixIconStylesheetRecovery({
10
+ stylesheet: sheet,
11
+ fonts: document.fonts,
12
+ baseUrl: document.baseURI,
13
+ createFontFace: ({ family, source, descriptors }) => new FontFace(family, source, descriptors),
14
+ timers: {
15
+ setTimeout: (run, delay) => globalThis.setTimeout(run, delay),
16
+ clearTimeout: (handle) => globalThis.clearTimeout(handle),
17
+ },
18
+ });
19
+ if (sheet.sheet) {
20
+ start();
21
+ return;
22
+ }
23
+ sheet.addEventListener('load', start, { once: true });
24
+ }
25
+ /**
26
+ * Marks whichever stylesheet is currently serving `.ri-*` glyphs — this package's own default, or
27
+ * a host override that got inserted first. `ensureRemixIconStylesheet` checks for this attribute
28
+ * (not a specific `href`) before injecting, so a host that wants its own icon set/font just needs
29
+ * to add a `<link data-jini-remixicon rel="stylesheet" href="...">` (or an equivalent `<style
30
+ * data-jini-remixicon>`) anywhere in `<head>` before the first `RemixIcon` mounts, and this
31
+ * package's default never loads.
32
+ *
33
+ * Exported because every host that has needed the override so far re-declared this string
34
+ * literally rather than importing it -- three copies outside this file, across two apps of the
35
+ * one downstream checkout inspected (2026-09-06), and they do not agree on element type: one
36
+ * installs a `<style>`, the other a `<link>`. A copied magic string is a rename away from
37
+ * silently double-loading the font; importing the constant is not.
38
+ */
39
+ export const REMIXICON_STYLESHEET_MARKER = 'data-jini-remixicon';
40
+ let injected = false;
41
+ let warned = false;
42
+ /**
43
+ * One diagnostic per page load, not one per `RemixIcon` mount — the failure this reports is a
44
+ * build/bundler property, so it is the same failure every time and a per-mount warning would bury
45
+ * the rest of the console under it.
46
+ *
47
+ * @complexity O(1) time, O(1) space.
48
+ * @overallScore 100
49
+ */
50
+ function warnOnce(message) {
51
+ if (warned)
52
+ return;
53
+ warned = true;
54
+ console.warn(`[@jini-ai/ui] RemixIcon: ${message}`);
55
+ }
56
+ const OPT_IN_HINT = 'Import the stylesheet yourself and install it via ' +
57
+ "`installRemixIconStylesheet({ href })` — the subpath export `@jini-ai/ui/remixicon.css` " +
58
+ 'resolves through your bundler normally, unlike this runtime default.';
59
+ /**
60
+ * Installs a caller-supplied stylesheet as the one serving `.ri-*` glyphs, claiming
61
+ * {@link REMIXICON_STYLESHEET_MARKER} so this package's own default never loads.
62
+ *
63
+ * This is the supported opt-in for any host whose bundler defeats the default's `import.meta.url`
64
+ * resolution (see {@link ensureRemixIconStylesheet}) — point it at
65
+ * `@jini-ai/ui/remixicon.css`, which is a normal subpath export a bundler resolves and rewrites
66
+ * like any other asset. Call it before the first `RemixIcon` mounts; module top level in the
67
+ * host's entry file is the usual place, since the default injection runs from a `useEffect` and
68
+ * therefore only has to lose a race against React's commit phase.
69
+ *
70
+ * Idempotent and safe to call unconditionally: it no-ops if any marked stylesheet is already
71
+ * present (including one a previous call installed), and no-ops outside a DOM.
72
+ *
73
+ * @param options.href URL of a stylesheet defining the `.ri-*` classes and its own `@font-face`.
74
+ * Resolved by the browser against the document, so relative values follow the page's base URL —
75
+ * pass a bundler-produced URL rather than a hand-written relative path.
76
+ * @returns `true` if this call inserted the stylesheet, `false` if it no-opped.
77
+ * @sideEffects Appends one `<link>` to `document.head`; probes and retries its icon font.
78
+ * @complexity O(n + r) including recovery, for n stylesheet rules and r bounded retries.
79
+ * @overallScore 100
80
+ */
81
+ export function installRemixIconStylesheet(options, _optional = {}) {
82
+ if (typeof document === 'undefined')
83
+ return false;
84
+ const existing = document.querySelector(`[${REMIXICON_STYLESHEET_MARKER}]`);
85
+ if (existing) {
86
+ if (!injected)
87
+ recoverFont({ stylesheet: existing });
88
+ injected = true;
89
+ return false;
90
+ }
91
+ const link = document.createElement('link');
92
+ link.rel = 'stylesheet';
93
+ link.setAttribute(REMIXICON_STYLESHEET_MARKER, '');
94
+ link.href = options.href;
95
+ recoverFont({ stylesheet: link });
96
+ document.head.appendChild(link);
97
+ injected = true;
98
+ return true;
99
+ }
100
+ /**
101
+ * Resolves this package's bundled RemixIcon CSS relative to its own module URL, or `null` when
102
+ * that resolution has provably produced something unusable.
103
+ *
104
+ * The `null` case is not hypothetical. Bundling a `new URL(..., import.meta.url)` asset reference
105
+ * into a non-ESM output (Vite/Rollup `iife`, for one) makes Rollup inline the referenced file as a
106
+ * `data:text/css;base64,...` href instead. That stylesheet then loads, but its own
107
+ * `@font-face { src: url("./remixicon.woff2") }` is relative and a `data:` URL has no location to
108
+ * be relative *to*, so the font request is never even attempted and every glyph renders as tofu.
109
+ * Injecting it is strictly worse than injecting nothing, because it also claims
110
+ * {@link REMIXICON_STYLESHEET_MARKER} and so suppresses any override installed later.
111
+ *
112
+ * @returns An absolute URL string, or `null` if resolution failed or yielded a `data:`/`blob:` URL.
113
+ * @complexity O(1) time, O(1) space.
114
+ * @overallScore 100
115
+ */
116
+ function resolveDefaultStylesheetHref() {
117
+ let resolved;
118
+ try {
119
+ resolved = new URL('./remixicon-font/remixicon.css', import.meta.url);
120
+ }
121
+ catch {
122
+ return null;
123
+ }
124
+ if (resolved.protocol === 'data:' || resolved.protocol === 'blob:')
125
+ return null;
126
+ return resolved.href;
127
+ }
128
+ /**
129
+ * Idempotently loads this package's default RemixIcon webfont/CSS on first use, so a host gets
130
+ * working icons out of the box with zero setup — see {@link REMIXICON_STYLESHEET_MARKER} for how a
131
+ * host overrides this and {@link installRemixIconStylesheet} for the supported way to do it.
132
+ *
133
+ * **This default only survives unbundled ESM, and that is not a fixable property of this
134
+ * function.** It resolves the CSS with `new URL('./remixicon-font/remixicon.css',
135
+ * import.meta.url)`, which is correct exactly while this module is still a real ES module sitting
136
+ * next to its own `remixicon-font/` directory. Three bundler transformations break it three
137
+ * different ways. The first two were confirmed live against this component; the third was
138
+ * confirmed live against its sibling, and is listed because nothing exempts this file from it:
139
+ *
140
+ * - **`iife`/`umd` output** cannot express the reference at all and degrades it to an inlined
141
+ * `data:` URL whose own relative `@font-face` src can never resolve. Confirmed live in a
142
+ * downstream `lib`/`iife` widget bundle, where `document.fonts` reported the `remixicon` face
143
+ * as `status: "error"` with no matching resource entry at all — an unattempted fetch, not a
144
+ * 404. Detected and refused by {@link resolveDefaultStylesheetHref}.
145
+ * - **Production ESM builds** may copy the CSS as an opaque asset without descending into its
146
+ * `url(./remixicon.woff2)`, emitting the stylesheet without the font beside it. Confirmed live
147
+ * in a downstream admin SPA build, which is why that host imports the CSS through its
148
+ * bundler's real CSS pipeline instead of letting this default run.
149
+ * - **Vite dev-server dependency pre-bundling** flattens a package module into a `.vite/deps/`
150
+ * chunk, so an `import.meta.url`-relative URL resolves against the chunk's location instead.
151
+ * Observed live for this package's `AgentIcon` (fixed in 58bf42fa by inlining those assets as
152
+ * `data:` URIs — not an option here, see {@link installRemixIconStylesheet}), *not* observed
153
+ * for this component, whose two known hosts both claim the marker before this default ever
154
+ * runs. Worth knowing how it presented there: not as a 404, but as the dev server's SPA
155
+ * history fallback answering `200 text/html`.
156
+ *
157
+ * A previous version of this comment claimed "Vite/Rollup/webpack all rewrite this correctly at
158
+ * build time". They do not, and each downstream host that hit it rediscovered a different half
159
+ * of the above independently. There is no runtime-resolvable URL that survives all of it — the
160
+ * cannot know where, or whether, its sibling asset was emitted — so the honest contract is: the
161
+ * default is a convenience for unbundled ESM, and any bundled host should call
162
+ * {@link installRemixIconStylesheet} instead. This function's job is to make that failure *loud*
163
+ * rather than silent, since tofu glyphs give no clue where to look.
164
+ *
165
+ * @sideEffects Appends at most one `<link>` to `document.head`; may emit one `console.warn`.
166
+ * Probes and retries the installed font, including a host-provided marked override.
167
+ * @complexity O(n + r) including recovery, for n stylesheet rules and r bounded retries.
168
+ * @overallScore 100
169
+ */
170
+ export function ensureRemixIconStylesheet(_input, _optional = {}) {
171
+ if (injected || typeof document === 'undefined')
172
+ return;
173
+ const existing = document.querySelector(`[${REMIXICON_STYLESHEET_MARKER}]`);
174
+ if (existing) {
175
+ recoverFont({ stylesheet: existing });
176
+ injected = true;
177
+ return;
178
+ }
179
+ const href = resolveDefaultStylesheetHref();
180
+ if (href === null) {
181
+ // Claiming the marker with a stylesheet that cannot work would block a later override, so
182
+ // stay out of the way entirely and let the host know why its icons are blank.
183
+ injected = true;
184
+ warnOnce(`this bundle defeated the default stylesheet's own URL resolution. ${OPT_IN_HINT}`);
185
+ return;
186
+ }
187
+ const link = document.createElement('link');
188
+ link.rel = 'stylesheet';
189
+ link.setAttribute(REMIXICON_STYLESHEET_MARKER, '');
190
+ link.href = href;
191
+ link.addEventListener('error', () => {
192
+ // The pre-bundling case above: undetectable synchronously, because the href looked perfectly
193
+ // well formed. Drop the dead <link> so it stops holding the marker hostage — a host can
194
+ // still recover by calling installRemixIconStylesheet — but leave `injected` set so a later
195
+ // mount does not re-request the same missing file.
196
+ //
197
+ // UNVERIFIED, and deliberately not relied on: whether this also fires for the `200 text/html`
198
+ // SPA-fallback shape that case actually takes. A stylesheet served as `text/html` is refused
199
+ // under strict MIME checking, which is specified to fire `error` — but that has not been
200
+ // exercised here, so treat the warning as a bonus in that shape, not a guarantee.
201
+ link.remove();
202
+ warnOnce(`the default stylesheet failed to load from ${href}. ${OPT_IN_HINT}`);
203
+ });
204
+ recoverFont({ stylesheet: link });
205
+ document.head.appendChild(link);
206
+ injected = true;
207
+ }
208
+ //# sourceMappingURL=RemixIcon.stylesheet.js.map
@@ -0,0 +1,55 @@
1
+ /** Native font/timer ports keep retries testable without module mocks or a real clock. */
2
+ export interface RemixIconFontSet {
3
+ load(font: string, text?: string): Promise<FontFace[]>;
4
+ check(font: string, text?: string): boolean;
5
+ add(face: FontFace): void;
6
+ }
7
+ export interface FontRetryTimers {
8
+ setTimeout(run: () => void, delay: number): unknown;
9
+ clearTimeout(handle: unknown): void;
10
+ }
11
+ interface RecoveryInput {
12
+ fonts: RemixIconFontSet;
13
+ timers: FontRetryTimers;
14
+ createFace(input: {
15
+ attempt: number;
16
+ }): Pick<FontFace, 'load'>;
17
+ }
18
+ /**
19
+ * Probe the existing icon face once, then retry with fresh faces after bounded backoff.
20
+ * A failed FontFace retains its rejected load promise, so loading that same face again cannot
21
+ * recover. Adding the loaded replacement to the set makes existing icons repaint automatically.
22
+ * Network/parse failures are consumed; exhaustion leaves the existing fallback in place.
23
+ * @param input Explicit font set, fresh-face factory, and timer ports.
24
+ * @param options Backoff delays in milliseconds, defaulting to 1s, 3s, 10s.
25
+ * @returns Dispose function cancelling pending work and suppressing late font registration.
26
+ * @complexity O(r) attempts and O(1) working space, where r is the supplied retry count.
27
+ * @example startRemixIconFontRecovery({ fonts, timers, createFace });
28
+ */
29
+ export declare function startRemixIconFontRecovery({ fonts, timers, createFace }: RecoveryInput, { retryDelays }?: {
30
+ retryDelays?: readonly number[];
31
+ }): () => void;
32
+ interface StylesheetRecoveryInput {
33
+ stylesheet: HTMLStyleElement | HTMLLinkElement;
34
+ fonts: RemixIconFontSet;
35
+ timers: FontRetryTimers;
36
+ baseUrl: string;
37
+ createFontFace(input: {
38
+ family: string;
39
+ source: string;
40
+ descriptors: FontFaceDescriptors;
41
+ }): FontFace;
42
+ }
43
+ /**
44
+ * Recover this package's single WOFF2 face using the owning stylesheet's resolved URL.
45
+ * CSSOM, rather than a bundled-module URL, preserves host asset rewriting and linked CSS bases.
46
+ * Cross-origin inaccessible sheets and overrides without our face are left to their owner.
47
+ * @returns Retry disposer, or a no-op when this sheet does not expose the RemixIcon face.
48
+ * @complexity O(n + r), where n is the owning sheet's rule count and r is the retry count.
49
+ * @example startRemixIconStylesheetRecovery({ stylesheet, fonts, timers, baseUrl, createFontFace });
50
+ */
51
+ export declare function startRemixIconStylesheetRecovery({ stylesheet, fonts, timers, baseUrl, createFontFace }: StylesheetRecoveryInput, options?: {
52
+ retryDelays?: readonly number[];
53
+ }): () => void;
54
+ export {};
55
+ //# sourceMappingURL=remixicon-font-recovery.d.ts.map
@@ -0,0 +1,110 @@
1
+ const FONT = '16px "remixicon"';
2
+ // Use a real private-use glyph: FontFaceSet.check alone also returns true for absent fonts.
3
+ const GLYPH = '\uea01';
4
+ /**
5
+ * Probe the existing icon face once, then retry with fresh faces after bounded backoff.
6
+ * A failed FontFace retains its rejected load promise, so loading that same face again cannot
7
+ * recover. Adding the loaded replacement to the set makes existing icons repaint automatically.
8
+ * Network/parse failures are consumed; exhaustion leaves the existing fallback in place.
9
+ * @param input Explicit font set, fresh-face factory, and timer ports.
10
+ * @param options Backoff delays in milliseconds, defaulting to 1s, 3s, 10s.
11
+ * @returns Dispose function cancelling pending work and suppressing late font registration.
12
+ * @complexity O(r) attempts and O(1) working space, where r is the supplied retry count.
13
+ * @example startRemixIconFontRecovery({ fonts, timers, createFace });
14
+ */
15
+ export function startRemixIconFontRecovery({ fonts, timers, createFace }, { retryDelays = [1000, 3000, 10000] } = {}) {
16
+ let stopped = false;
17
+ let attempt = 0;
18
+ let pending;
19
+ function scheduleRetry() {
20
+ if (stopped)
21
+ return;
22
+ const delay = retryDelays[attempt];
23
+ if (delay === undefined) {
24
+ stopped = true;
25
+ return;
26
+ }
27
+ pending = timers.setTimeout(() => {
28
+ pending = undefined;
29
+ void retry();
30
+ }, delay);
31
+ }
32
+ async function retry() {
33
+ if (stopped)
34
+ return;
35
+ attempt++;
36
+ try {
37
+ const face = await createFace({ attempt }).load();
38
+ if (stopped)
39
+ return;
40
+ fonts.add(face);
41
+ stopped = true;
42
+ }
43
+ catch {
44
+ scheduleRetry();
45
+ }
46
+ }
47
+ async function probe() {
48
+ try {
49
+ const faces = await fonts.load(FONT, GLYPH);
50
+ if (stopped)
51
+ return;
52
+ if (faces.length > 0 && fonts.check(FONT, GLYPH)) {
53
+ stopped = true;
54
+ return;
55
+ }
56
+ scheduleRetry();
57
+ }
58
+ catch {
59
+ scheduleRetry();
60
+ }
61
+ }
62
+ void probe();
63
+ return () => {
64
+ stopped = true;
65
+ if (pending !== undefined)
66
+ timers.clearTimeout(pending);
67
+ };
68
+ }
69
+ /**
70
+ * Recover this package's single WOFF2 face using the owning stylesheet's resolved URL.
71
+ * CSSOM, rather than a bundled-module URL, preserves host asset rewriting and linked CSS bases.
72
+ * Cross-origin inaccessible sheets and overrides without our face are left to their owner.
73
+ * @returns Retry disposer, or a no-op when this sheet does not expose the RemixIcon face.
74
+ * @complexity O(n + r), where n is the owning sheet's rule count and r is the retry count.
75
+ * @example startRemixIconStylesheetRecovery({ stylesheet, fonts, timers, baseUrl, createFontFace });
76
+ */
77
+ export function startRemixIconStylesheetRecovery({ stylesheet, fonts, timers, baseUrl, createFontFace }, options = {}) {
78
+ let rules;
79
+ try {
80
+ rules = stylesheet.sheet?.cssRules;
81
+ }
82
+ catch {
83
+ return () => { };
84
+ }
85
+ if (!rules)
86
+ return () => { };
87
+ for (const rule of Array.from(rules)) {
88
+ if (rule.type !== 5)
89
+ continue; // CSSRule.FONT_FACE_RULE (no global constructor in SSR/fakes).
90
+ const style = rule.style;
91
+ const family = style.getPropertyValue('font-family').replace(/["']/g, '').trim();
92
+ if (family !== 'remixicon')
93
+ continue;
94
+ // This package owns one url(...) WOFF2 source, not a general CSS font-source parser.
95
+ const source = style.getPropertyValue('src').match(/url\(\s*["']?([^"')]+)["']?\s*\)/)?.[1];
96
+ if (!source)
97
+ return () => { };
98
+ const url = new URL(source.trim(), stylesheet.sheet?.href ?? baseUrl);
99
+ return startRemixIconFontRecovery({ fonts, timers, createFace({ attempt }) {
100
+ // A distinct URL also bypasses the browser's cached failed font resource after a restart.
101
+ const freshUrl = new URL(url.href);
102
+ if (freshUrl.protocol === 'http:' || freshUrl.protocol === 'https:') {
103
+ freshUrl.searchParams.set('jini-font-retry', String(attempt));
104
+ }
105
+ return createFontFace({ family: 'remixicon', source: `url("${freshUrl.href}") format("woff2")`, descriptors: { display: 'swap' } });
106
+ } }, options);
107
+ }
108
+ return () => { };
109
+ }
110
+ //# sourceMappingURL=remixicon-font-recovery.js.map
@@ -188,6 +188,12 @@
188
188
  }
189
189
 
190
190
  .info-tip { position: relative; display: inline-flex; margin-left: 0.35rem; vertical-align: middle; }
191
+ /* In a wrapping label row, inline help takes a full row and pushes fields down safely. */
192
+ .info-tip.info-tip--inline { display: contents; }
193
+ .info-tip-inline-copy {
194
+ flex-basis: 100%; font-size: var(--jini-font-size-xs, 12px); font-weight: 400;
195
+ line-height: 1.5; color: var(--jini-text-muted); overflow-wrap: anywhere;
196
+ }
191
197
  .info-tip-icon {
192
198
  display: inline-flex; align-items: center; justify-content: center;
193
199
  width: 1.1rem; height: 1.1rem; border-radius: 50%; color: var(--jini-text-disabled);
@@ -197,14 +203,14 @@
197
203
  .info-tip-icon:focus-visible { outline: 2px solid var(--jini-accent); outline-offset: 2px; border-radius: 50%; }
198
204
  .info-tip-bubble {
199
205
  position: fixed; transform: translate(-50%, calc(-100% - 8px));
200
- width: max-content; max-width: 18rem; padding: 0.55rem 0.75rem; border-radius: var(--jini-radius-sm);
206
+ width: max-content; max-width: min(18rem, calc(100vw - 16px)); padding: 0.55rem 0.75rem; border-radius: var(--jini-radius-sm);
201
207
  background: var(--jini-bg-panel); color: var(--jini-text); font-size: 0.78rem; font-weight: 400;
202
208
  line-height: 1.4; letter-spacing: normal; text-transform: none;
203
209
  box-shadow: 0 4px 16px var(--jini-backdrop); border: 1px solid var(--jini-border);
204
210
  pointer-events: none; z-index: 1000;
205
211
  }
206
212
  .info-tip-bubble::after {
207
- content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
213
+ content: ""; position: absolute; top: 100%; left: var(--info-tip-arrow-left, 50%); transform: translateX(-50%);
208
214
  border: 5px solid transparent; border-top-color: var(--jini-bg-panel);
209
215
  }
210
216
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jini-ai/ui",
3
- "version": "0.4.7",
3
+ "version": "0.4.8",
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": {
@@ -210,14 +210,16 @@
210
210
  "shiki": "^1.24.4",
211
211
  "tailwind-merge": "^2.6.0",
212
212
  "zod": "^3.25.76",
213
- "@jini-ai/platform": "^0.5.2",
214
- "@jini-ai/core": "^0.4.2",
215
- "@jini-ai/agentic": "^0.4.3"
213
+ "@jini-ai/integrations": "^0.4.2",
214
+ "@jini-ai/platform": "^0.5.3",
215
+ "@jini-ai/core": "^0.4.3",
216
+ "@jini-ai/agentic": "^0.4.4"
216
217
  },
217
218
  "dependencies": {
218
- "@jini-ai/core": "^0.4.2"
219
+ "@jini-ai/core": "^0.4.3"
219
220
  },
220
221
  "peerDependencies": {
222
+ "@jini-ai/integrations": "^0.4.2",
221
223
  "@tanstack/react-query": "^5.0.0",
222
224
  "@excalidraw/excalidraw": "0.18.1",
223
225
  "@lexical/react": "0.36.2",
@@ -233,8 +235,8 @@
233
235
  "react": "^18.3.0 || ^19.0.0",
234
236
  "react-dom": "^18.3.0 || ^19.0.0",
235
237
  "recharts": "^3.10.1",
236
- "@jini-ai/platform": "^0.5.1",
237
- "@jini-ai/agentic": "^0.4.2",
238
+ "@jini-ai/platform": "^0.5.3",
239
+ "@jini-ai/agentic": "^0.4.4",
238
240
  "class-variance-authority": "^0.7.1",
239
241
  "clsx": "^2.1.1",
240
242
  "micromark": "^4.0.0",
@@ -245,6 +247,9 @@
245
247
  "zod": "^3.25.76"
246
248
  },
247
249
  "peerDependenciesMeta": {
250
+ "@jini-ai/integrations": {
251
+ "optional": true
252
+ },
248
253
  "@tanstack/react-query": {
249
254
  "optional": true
250
255
  },
@@ -1,125 +0,0 @@
1
- import type { Clock } from '@jini-ai/core/primitives';
2
- import type { QueryKey } from './types.js';
3
- /**
4
- * Ten seconds covers reading, closing and reopening a record or bouncing between screens
5
- * without paying for another identical request. Five seconds was too short for that read
6
- * cycle; thirty seconds exposed more other-operator staleness than the conservative initial
7
- * shared default should allow. There is no default polling/focus refresh, so this bounds
8
- * the extra exposure on a quick revisit. Write invalidation bypasses freshness; reads that
9
- * must be fresh on every mount can choose staleTime: 0 without lowering every query default.
10
- */
11
- export declare const DEFAULT_STALE_TIME = 10000;
12
- /** Minimum time an unobserved entry is kept; both adapters retain max(this, staleTime). */
13
- export declare const IDLE_RETENTION: number;
14
- export interface QueryCacheSchedulerPort {
15
- schedule(required: {
16
- callback: () => void;
17
- delayMs: number;
18
- }): unknown;
19
- cancel(required: {
20
- handle: unknown;
21
- }): void;
22
- }
23
- /** Host connectivity and focus signals; the cache itself has no DOM dependency. */
24
- export interface FetchQueryEnvironmentPort {
25
- isOnline(): boolean;
26
- subscribeOnline(required: {
27
- listener: (online: boolean) => void;
28
- }): () => void;
29
- subscribeFocus(required: {
30
- listener: () => void;
31
- }): () => void;
32
- }
33
- export interface FetchQueryCacheOptions {
34
- clock?: Clock;
35
- scheduler?: QueryCacheSchedulerPort;
36
- environment?: FetchQueryEnvironmentPort;
37
- }
38
- export interface QueryState {
39
- data: unknown;
40
- error: Error | null;
41
- status: 'pending' | 'success' | 'error';
42
- isFetching: boolean;
43
- }
44
- export interface QueryObserver {
45
- fetch: () => Promise<unknown>;
46
- staleTime: number;
47
- focus: boolean;
48
- }
49
- export interface CacheEntry {
50
- key: QueryKey;
51
- state: QueryState;
52
- updatedAt: number;
53
- invalidated: boolean;
54
- replacement: number;
55
- pending: Promise<unknown> | undefined;
56
- refreshAfterPending: boolean;
57
- listeners: Set<() => void>;
58
- observers: Set<QueryObserver>;
59
- retention: number;
60
- eviction: unknown;
61
- }
62
- export declare function toQueryError(value: unknown): Error;
63
- /** One provider-owned cache. Requests are shared by structural primitive keys.
64
- * Failed reads retain earlier data; replacement writes supersede older requests.
65
- * Idle entries live for at least five minutes or their declared freshness period. */
66
- export declare class FetchQueryCache {
67
- private readonly entries;
68
- private disposed;
69
- private readonly clock;
70
- private readonly scheduler;
71
- private readonly environment;
72
- private online;
73
- private readonly onlineWaiters;
74
- private releaseEnvironment;
75
- constructor(_required?: Record<string, never>, { clock, scheduler, environment }?: FetchQueryCacheOptions);
76
- entry({ key }: {
77
- key: QueryKey;
78
- }, { staleTime }?: {
79
- staleTime?: number;
80
- }): CacheEntry;
81
- fresh({ entry, staleTime }: {
82
- entry: CacheEntry;
83
- staleTime: number;
84
- }): boolean;
85
- subscribe({ entry, listener }: {
86
- entry: CacheEntry;
87
- listener: () => void;
88
- }): () => void;
89
- observe({ entry, observer }: {
90
- entry: CacheEntry;
91
- observer: QueryObserver;
92
- }): () => void;
93
- /** Cache hits respect freshness; explicit refreshes restart background reads.
94
- * Initial reads still deduplicate because no earlier successful data exists to refresh. */
95
- load<T>({ entry, fetch, staleTime }: {
96
- entry: CacheEntry;
97
- fetch: () => Promise<T>;
98
- staleTime: number;
99
- }, { force }?: {
100
- force?: boolean;
101
- }): Promise<T>;
102
- replace({ entry, data }: {
103
- entry: CacheEntry;
104
- data: unknown;
105
- }): void;
106
- invalidate({ prefix }: {
107
- prefix: QueryKey;
108
- }): void;
109
- onFocus(): void;
110
- /** Execute a read/write once connectivity returns; failures are not retried.
111
- * @param required.run Operation to invoke online.
112
- * @returns The operation's original result or rejection. */
113
- runOnline<T>({ run }: {
114
- run: () => Promise<T>;
115
- }): Promise<T>;
116
- /** Stop timers on provider disposal; reactivate for React's effect replay. */
117
- activate(): void;
118
- dispose(): void;
119
- private onOnline;
120
- private refresh;
121
- private publish;
122
- private cancelEviction;
123
- private scheduleEviction;
124
- }
125
- //# sourceMappingURL=cache.d.ts.map