@opengeni/react 7.4.0 → 7.5.0-canary.36919050519001

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 (210) hide show
  1. package/README.md +124 -27
  2. package/dist/artifacts-document.js +3 -2
  3. package/dist/artifacts-presentation.js +3 -2
  4. package/dist/artifacts-spreadsheet.js +2 -2
  5. package/dist/artifacts.d.ts +1 -0
  6. package/dist/artifacts.js +516 -1413
  7. package/dist/artifacts.js.map +1 -1
  8. package/dist/{browser-viewer-2E6R2Y4W.js → browser-viewer-Z7S7QEJL.js} +6 -5
  9. package/dist/chat-interactive-block-UGBTNB3L.js +11 -0
  10. package/dist/{chunk-Y3QTZN2F.js → chunk-2VFNCX4E.js} +6 -6
  11. package/dist/{chunk-UDD6DLLT.js → chunk-3IJJEYW4.js} +15 -3
  12. package/dist/chunk-3IJJEYW4.js.map +1 -0
  13. package/dist/chunk-4RVYOY4O.js +379 -0
  14. package/dist/chunk-4RVYOY4O.js.map +1 -0
  15. package/dist/chunk-5CVXZA3Y.js +292 -0
  16. package/dist/chunk-5CVXZA3Y.js.map +1 -0
  17. package/dist/{chunk-5YK2ZDIG.js → chunk-5J4FOW6Q.js} +2 -10
  18. package/dist/chunk-5J4FOW6Q.js.map +1 -0
  19. package/dist/{chunk-KVERXCFY.js → chunk-5KYZIQFY.js} +40 -3
  20. package/dist/chunk-5KYZIQFY.js.map +1 -0
  21. package/dist/{chunk-KNDIXZN6.js → chunk-7UAMYXJY.js} +25 -18
  22. package/dist/{chunk-KNDIXZN6.js.map → chunk-7UAMYXJY.js.map} +1 -1
  23. package/dist/{chunk-SEEVCT36.js → chunk-A4UJB2MM.js} +2 -2
  24. package/dist/{chunk-X4HIN6TV.js → chunk-AFLPWUQ7.js} +71 -162
  25. package/dist/chunk-AFLPWUQ7.js.map +1 -0
  26. package/dist/chunk-B3V6TG77.js +41 -0
  27. package/dist/chunk-B3V6TG77.js.map +1 -0
  28. package/dist/{chunk-XEJEOAOV.js → chunk-B7WMS3CS.js} +51 -40
  29. package/dist/chunk-B7WMS3CS.js.map +1 -0
  30. package/dist/{chunk-S5JQ4R22.js → chunk-BDKR6BAR.js} +54 -24
  31. package/dist/chunk-BDKR6BAR.js.map +1 -0
  32. package/dist/{chunk-4MDLEHXL.js → chunk-DYWBUX5Q.js} +24 -12
  33. package/dist/chunk-DYWBUX5Q.js.map +1 -0
  34. package/dist/{chunk-YZ3YYMOM.js → chunk-E3G7SAYZ.js} +252 -624
  35. package/dist/chunk-E3G7SAYZ.js.map +1 -0
  36. package/dist/chunk-JT4JW7BC.js +54 -0
  37. package/dist/chunk-JT4JW7BC.js.map +1 -0
  38. package/dist/{chunk-5AZSK6MV.js → chunk-LWNLETQT.js} +5 -5
  39. package/dist/{chunk-USXVQACU.js → chunk-M7LBYP63.js} +5 -4
  40. package/dist/{chunk-USXVQACU.js.map → chunk-M7LBYP63.js.map} +1 -1
  41. package/dist/{chunk-L4OSXQ6H.js → chunk-NBOHNRLJ.js} +1289 -1060
  42. package/dist/chunk-NBOHNRLJ.js.map +1 -0
  43. package/dist/chunk-RHREZ7BO.js +11 -0
  44. package/dist/chunk-RHREZ7BO.js.map +1 -0
  45. package/dist/chunk-SCOTPE2I.js +589 -0
  46. package/dist/chunk-SCOTPE2I.js.map +1 -0
  47. package/dist/chunk-WEHMPOXK.js +39 -0
  48. package/dist/chunk-WEHMPOXK.js.map +1 -0
  49. package/dist/chunk-WRHIZYZF.js +988 -0
  50. package/dist/chunk-WRHIZYZF.js.map +1 -0
  51. package/dist/{chunk-3E2AITTZ.js → chunk-WUISZ3WU.js} +32 -28
  52. package/dist/{chunk-3E2AITTZ.js.map → chunk-WUISZ3WU.js.map} +1 -1
  53. package/dist/chunk-XCHWDJ22.js +107 -0
  54. package/dist/chunk-XCHWDJ22.js.map +1 -0
  55. package/dist/{chunk-DUEBTL3N.js → chunk-Y2PRMYLC.js} +4 -3
  56. package/dist/{chunk-DUEBTL3N.js.map → chunk-Y2PRMYLC.js.map} +1 -1
  57. package/dist/chunk-YBXQDQFX.js +1772 -0
  58. package/dist/chunk-YBXQDQFX.js.map +1 -0
  59. package/dist/chunk-YV4L3ILF.js +9 -0
  60. package/dist/chunk-YV4L3ILF.js.map +1 -0
  61. package/dist/{chunk-V2ABIVYJ.js → chunk-ZXSEDZP7.js} +70 -6
  62. package/dist/chunk-ZXSEDZP7.js.map +1 -0
  63. package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
  64. package/dist/components/artifacts/artifact-sandbox.d.ts +27 -0
  65. package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
  66. package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
  67. package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
  68. package/dist/components/artifacts/editable-artifact-view.d.ts +46 -0
  69. package/dist/components/artifacts/index.d.ts +7 -0
  70. package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
  71. package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
  72. package/dist/components/artifacts/site-view.d.ts +23 -0
  73. package/dist/components/browser-select-control.d.ts +3 -1
  74. package/dist/components/code-editor.d.ts +1 -4
  75. package/dist/components/desktop-viewer.d.ts +1 -1
  76. package/dist/components/message-timeline.d.ts +20 -3
  77. package/dist/components/open-geni-links.d.ts +16 -0
  78. package/dist/components/session-conversation.d.ts +20 -1
  79. package/dist/components/timeline-pill-geometry.d.ts +8 -0
  80. package/dist/components/timeline-pill-placement.d.ts +24 -0
  81. package/dist/components/usage-limit-notice.d.ts +49 -0
  82. package/dist/components/usage-member-list.d.ts +91 -0
  83. package/dist/components/usage-meter.d.ts +73 -0
  84. package/dist/composer.js +5 -5
  85. package/dist/{computer-viewer-WMJE6OA3.js → computer-viewer-KJWLH3GI.js} +7 -5
  86. package/dist/connect.js +7 -6
  87. package/dist/connect.js.map +1 -1
  88. package/dist/conversation-timeline.d.ts +1 -1
  89. package/dist/desktop.d.ts +7 -0
  90. package/dist/desktop.js +26 -0
  91. package/dist/desktop.js.map +1 -0
  92. package/dist/editor.d.ts +7 -0
  93. package/dist/editor.js +21 -0
  94. package/dist/editor.js.map +1 -0
  95. package/dist/hooks/latest-question.d.ts +1 -1
  96. package/dist/hooks/use-composer.d.ts +4 -0
  97. package/dist/hooks/use-desktop-stream.d.ts +1 -1
  98. package/dist/hooks/use-usage.d.ts +40 -0
  99. package/dist/index.d.ts +7 -2
  100. package/dist/index.js +460 -1386
  101. package/dist/index.js.map +1 -1
  102. package/dist/interaction.js +8 -6
  103. package/dist/interaction.js.map +1 -1
  104. package/dist/{latest-question-QB4EUCW5.js → latest-question-IS445HOW.js} +3 -3
  105. package/dist/lib/format.d.ts +6 -1
  106. package/dist/lib/workbench-peers.d.ts +36 -0
  107. package/dist/machines.js +2 -2
  108. package/dist/{markdown-table-layout-PFUEZ2U4.js → markdown-table-layout-QXSLK4BY.js} +37 -5
  109. package/dist/markdown-table-layout-QXSLK4BY.js.map +1 -0
  110. package/dist/{queue-surface-implementation-IM2HD3SK.js → queue-surface-implementation-2CAQAIHM.js} +2 -2
  111. package/dist/realtime.js +3 -3
  112. package/dist/{sandbox-files-PXPIZAFG.js → sandbox-files-AEJTWGT4.js} +8 -5
  113. package/dist/sandbox-files-AEJTWGT4.js.map +1 -0
  114. package/dist/session-ui.d.ts +9 -2
  115. package/dist/session-ui.js +39 -20
  116. package/dist/session-ui.js.map +1 -1
  117. package/dist/session.js +4 -4
  118. package/dist/sites.js +4 -289
  119. package/dist/sites.js.map +1 -1
  120. package/dist/terminal.d.ts +8 -0
  121. package/dist/terminal.js +31 -0
  122. package/dist/terminal.js.map +1 -0
  123. package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
  124. package/dist/timeline/genie-loading.d.ts +3 -1
  125. package/dist/timeline/types.d.ts +8 -1
  126. package/dist/{timeline-annotation-selection-ODLVF4OI.js → timeline-annotation-selection-DMLMM2TX.js} +6 -1
  127. package/dist/timeline-annotation-selection-DMLMM2TX.js.map +1 -0
  128. package/dist/timeline-pill-geometry-Z23V243M.js +110 -0
  129. package/dist/timeline-pill-geometry-Z23V243M.js.map +1 -0
  130. package/dist/usage/allowance-copy.d.ts +25 -0
  131. package/dist/usage/summary.d.ts +35 -0
  132. package/dist/usage.d.ts +13 -0
  133. package/dist/usage.js +1073 -0
  134. package/dist/usage.js.map +1 -0
  135. package/package.json +19 -3
  136. package/src/artifacts.ts +37 -0
  137. package/src/components/artifacts/artifact-chrome.tsx +413 -0
  138. package/src/components/artifacts/artifact-sandbox.tsx +185 -0
  139. package/src/components/artifacts/chat-interactive-block.tsx +260 -0
  140. package/src/components/artifacts/deferred-chat-media.tsx +67 -0
  141. package/src/components/artifacts/editable-artifact-ui.tsx +3 -1
  142. package/src/components/artifacts/editable-artifact-view.tsx +187 -0
  143. package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
  144. package/src/components/artifacts/editable-document.tsx +34 -36
  145. package/src/components/artifacts/editable-presentation.tsx +21 -16
  146. package/src/components/artifacts/index.ts +41 -0
  147. package/src/components/artifacts/latest-task-runner.ts +49 -0
  148. package/src/components/artifacts/session-artifact-viewer.tsx +376 -0
  149. package/src/components/artifacts/site-view.tsx +116 -0
  150. package/src/components/browser-select-control.tsx +4 -1
  151. package/src/components/browser-viewer.tsx +81 -22
  152. package/src/components/code-editor.tsx +13 -16
  153. package/src/components/computer-viewer.tsx +51 -23
  154. package/src/components/desktop-viewer.tsx +1 -1
  155. package/src/components/markdown-table-layout.ts +49 -5
  156. package/src/components/markdown.tsx +5 -2
  157. package/src/components/message-timeline.tsx +557 -516
  158. package/src/components/open-geni-links.tsx +24 -0
  159. package/src/components/sandbox-terminal.tsx +48 -11
  160. package/src/components/session-chrome.tsx +22 -3
  161. package/src/components/session-conversation.tsx +195 -102
  162. package/src/components/timeline-annotation-selection.tsx +7 -0
  163. package/src/components/timeline-pill-geometry.ts +169 -0
  164. package/src/components/timeline-pill-placement.ts +99 -0
  165. package/src/components/usage-limit-notice.tsx +179 -0
  166. package/src/components/usage-member-list.tsx +792 -0
  167. package/src/components/usage-meter.tsx +382 -0
  168. package/src/conversation-timeline.ts +10 -2
  169. package/src/desktop.ts +24 -0
  170. package/src/editor.ts +13 -0
  171. package/src/hooks/use-available-models.ts +1 -1
  172. package/src/hooks/use-composer.ts +57 -2
  173. package/src/hooks/use-desktop-stream.ts +19 -28
  174. package/src/hooks/use-usage.ts +100 -0
  175. package/src/index.ts +22 -0
  176. package/src/lib/format.ts +32 -6
  177. package/src/lib/workbench-peers.ts +62 -0
  178. package/src/session-ui.ts +22 -0
  179. package/src/terminal.ts +26 -0
  180. package/src/timeline/activity-rail.tsx +5 -3
  181. package/src/timeline/allowance-exhausted-row.tsx +86 -0
  182. package/src/timeline/genie-loading.tsx +16 -6
  183. package/src/timeline/projection.ts +78 -4
  184. package/src/timeline/types.ts +8 -0
  185. package/src/usage/allowance-copy.ts +64 -0
  186. package/src/usage/summary.ts +93 -0
  187. package/src/usage.ts +50 -0
  188. package/styles/compiled.css +325 -0
  189. package/dist/chunk-4MDLEHXL.js.map +0 -1
  190. package/dist/chunk-5YK2ZDIG.js.map +0 -1
  191. package/dist/chunk-KVERXCFY.js.map +0 -1
  192. package/dist/chunk-L4OSXQ6H.js.map +0 -1
  193. package/dist/chunk-S5JQ4R22.js.map +0 -1
  194. package/dist/chunk-UDD6DLLT.js.map +0 -1
  195. package/dist/chunk-UGMKPUEM.js +0 -299
  196. package/dist/chunk-UGMKPUEM.js.map +0 -1
  197. package/dist/chunk-V2ABIVYJ.js.map +0 -1
  198. package/dist/chunk-X4HIN6TV.js.map +0 -1
  199. package/dist/chunk-XEJEOAOV.js.map +0 -1
  200. package/dist/chunk-YZ3YYMOM.js.map +0 -1
  201. package/dist/markdown-table-layout-PFUEZ2U4.js.map +0 -1
  202. package/dist/timeline-annotation-selection-ODLVF4OI.js.map +0 -1
  203. /package/dist/{browser-viewer-2E6R2Y4W.js.map → browser-viewer-Z7S7QEJL.js.map} +0 -0
  204. /package/dist/{computer-viewer-WMJE6OA3.js.map → chat-interactive-block-UGBTNB3L.js.map} +0 -0
  205. /package/dist/{chunk-Y3QTZN2F.js.map → chunk-2VFNCX4E.js.map} +0 -0
  206. /package/dist/{chunk-SEEVCT36.js.map → chunk-A4UJB2MM.js.map} +0 -0
  207. /package/dist/{chunk-5AZSK6MV.js.map → chunk-LWNLETQT.js.map} +0 -0
  208. /package/dist/{sandbox-files-PXPIZAFG.js.map → computer-viewer-KJWLH3GI.js.map} +0 -0
  209. /package/dist/{latest-question-QB4EUCW5.js.map → latest-question-IS445HOW.js.map} +0 -0
  210. /package/dist/{queue-surface-implementation-IM2HD3SK.js.map → queue-surface-implementation-2CAQAIHM.js.map} +0 -0
@@ -0,0 +1,1772 @@
1
+ import {
2
+ ArtifactBadge,
3
+ ArtifactButton,
4
+ ArtifactLabelsProvider,
5
+ ArtifactSelect,
6
+ useArtifactLabels
7
+ } from "./chunk-5CVXZA3Y.js";
8
+ import {
9
+ useOpenGeniLinkResolver
10
+ } from "./chunk-XCHWDJ22.js";
11
+ import {
12
+ PublishedHtmlArtifactFrame,
13
+ loadSiteSnapshot
14
+ } from "./chunk-SCOTPE2I.js";
15
+ import {
16
+ cn
17
+ } from "./chunk-22KP6LR5.js";
18
+
19
+ // src/components/artifacts/chat-interactive-block.tsx
20
+ import { useEffect as useEffect2, useMemo, useState as useState3 } from "react";
21
+
22
+ // src/components/artifacts/artifact-sandbox.tsx
23
+ import {
24
+ ArrowLeftIcon,
25
+ Globe2Icon,
26
+ Maximize2Icon,
27
+ PlugZapIcon,
28
+ RefreshCwIcon,
29
+ SparklesIcon
30
+ } from "lucide-react";
31
+ import { useLayoutEffect, useRef, useState } from "react";
32
+ import { jsx, jsxs } from "react/jsx-runtime";
33
+ function ArtifactSandbox(props) {
34
+ const labels = useArtifactLabels();
35
+ const [reloadKey, setReloadKey] = useState(0);
36
+ const [focused, setFocused] = useState(false);
37
+ const frameRef = useRef(null);
38
+ const modalRef = useRef(false);
39
+ useLayoutEffect(() => {
40
+ const frame = frameRef.current;
41
+ if (!frame) return;
42
+ if (focused) {
43
+ frame.close();
44
+ frame.showModal();
45
+ modalRef.current = true;
46
+ } else if (modalRef.current) {
47
+ frame.close();
48
+ frame.show();
49
+ modalRef.current = false;
50
+ }
51
+ }, [focused]);
52
+ const reload = () => {
53
+ setReloadKey((value) => value + 1);
54
+ };
55
+ return /* @__PURE__ */ jsxs(
56
+ "dialog",
57
+ {
58
+ ref: frameRef,
59
+ open: true,
60
+ "aria-label": props.title,
61
+ onCancel: (event) => {
62
+ event.preventDefault();
63
+ setFocused(false);
64
+ },
65
+ className: cn(
66
+ "og-root static m-0 w-full max-h-none max-w-none overflow-hidden rounded-2xl border border-border/80 bg-white p-0 text-left shadow-sm",
67
+ props.className,
68
+ props.fill && "flex min-h-0 flex-col",
69
+ focused && "fixed inset-0 z-50 flex h-dvh w-dvw flex-col rounded-none border-0 bg-surface shadow-none"
70
+ ),
71
+ children: [
72
+ /* @__PURE__ */ jsxs("div", { className: "flex min-h-12 shrink-0 items-center justify-between gap-3 border-b border-border/80 bg-surface/95 px-3 sm:px-4", children: [
73
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [
74
+ focused ? /* @__PURE__ */ jsxs(
75
+ ArtifactButton,
76
+ {
77
+ variant: "ghost",
78
+ size: "sm",
79
+ className: "h-8 shrink-0 px-2",
80
+ onClick: () => setFocused(false),
81
+ children: [
82
+ /* @__PURE__ */ jsx(ArrowLeftIcon, { className: "mr-2 size-3.5" }),
83
+ labels.back
84
+ ]
85
+ }
86
+ ) : null,
87
+ !focused && props.showTitle !== false ? /* @__PURE__ */ jsx("span", { className: "grid size-6 shrink-0 place-items-center rounded-md bg-surface-2 text-fg-muted", children: /* @__PURE__ */ jsx(Globe2Icon, { className: "size-3.5" }) }) : null,
88
+ props.showTitle !== false && /* @__PURE__ */ jsx("span", { className: "truncate text-xs font-semibold text-fg", children: props.title }),
89
+ props.headerControls,
90
+ props.versionLabel ? /* @__PURE__ */ jsx(ArtifactBadge, { className: "hidden h-5 rounded-md border-border/80 px-1.5 text-2xs font-normal text-fg-muted sm:inline-flex", children: props.versionLabel }) : null,
91
+ props.connectedToolCount ? /* @__PURE__ */ jsxs(
92
+ ArtifactBadge,
93
+ {
94
+ className: "hidden h-5 max-w-40 gap-1 rounded-md border-border/80 px-1.5 text-2xs font-normal text-fg-muted sm:inline-flex",
95
+ title: labels.toolsAvailable(props.connectedToolCount),
96
+ children: [
97
+ /* @__PURE__ */ jsx(PlugZapIcon, { className: "size-3" }),
98
+ labels.toolCount(props.connectedToolCount)
99
+ ]
100
+ }
101
+ ) : null,
102
+ props.sourceFileCount ? /* @__PURE__ */ jsx("span", { className: "hidden text-2xs text-fg-subtle xl:inline", children: labels.sourceFileCount(props.sourceFileCount) }) : null
103
+ ] }),
104
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
105
+ focused && props.onEdit ? /* @__PURE__ */ jsxs(
106
+ ArtifactButton,
107
+ {
108
+ variant: "ghost",
109
+ size: "sm",
110
+ className: "h-8 px-2",
111
+ disabled: props.editDisabled,
112
+ onClick: props.onEdit,
113
+ children: [
114
+ /* @__PURE__ */ jsx(SparklesIcon, { className: "mr-2 size-3.5" }),
115
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: labels.editWithAgent }),
116
+ /* @__PURE__ */ jsx("span", { className: "sm:hidden", children: labels.editShort })
117
+ ]
118
+ }
119
+ ) : null,
120
+ props.showLiveStatus !== false && /* @__PURE__ */ jsxs("span", { className: "mr-1 hidden items-center gap-1.5 text-2xs font-medium text-fg-muted sm:inline-flex", children: [
121
+ /* @__PURE__ */ jsx("span", { className: "size-1.5 rounded-full bg-status-success ring-4 ring-status-success/10" }),
122
+ labels.live
123
+ ] }),
124
+ /* @__PURE__ */ jsx(
125
+ ArtifactButton,
126
+ {
127
+ variant: "ghost",
128
+ size: "icon",
129
+ className: "size-8 rounded-md text-fg-muted hover:text-fg",
130
+ "aria-label": labels.reloadSite,
131
+ onClick: reload,
132
+ children: /* @__PURE__ */ jsx(RefreshCwIcon, { className: "size-3.5" })
133
+ }
134
+ ),
135
+ !focused ? /* @__PURE__ */ jsx(
136
+ ArtifactButton,
137
+ {
138
+ variant: "ghost",
139
+ size: "icon",
140
+ className: "size-8 rounded-md text-fg-muted hover:text-fg",
141
+ "aria-label": labels.openFullScreen,
142
+ onClick: () => setFocused(true),
143
+ children: /* @__PURE__ */ jsx(Maximize2Icon, { className: "size-3.5" })
144
+ }
145
+ ) : null
146
+ ] })
147
+ ] }),
148
+ /* @__PURE__ */ jsx(
149
+ PublishedHtmlArtifactFrame,
150
+ {
151
+ title: props.title,
152
+ html: props.html,
153
+ autoHeight: Boolean(props.autoHeight && !focused),
154
+ ...props.theme ? { theme: props.theme } : {},
155
+ ...!focused && props.height ? { style: { height: props.height } } : {},
156
+ ...props.toolBridge ? { toolBridge: props.toolBridge } : {},
157
+ className: cn(
158
+ "block h-[clamp(30rem,62vh,48rem)] w-full border-0 bg-white",
159
+ props.fill && "h-0 min-h-0 flex-1",
160
+ focused && "min-h-0 flex-1"
161
+ )
162
+ },
163
+ reloadKey
164
+ )
165
+ ]
166
+ }
167
+ );
168
+ }
169
+
170
+ // src/components/artifacts/deferred-chat-media.tsx
171
+ import { useEffect, useRef as useRef2, useState as useState2 } from "react";
172
+ import { jsx as jsx2 } from "react/jsx-runtime";
173
+ function DeferredChatMedia({
174
+ children,
175
+ height,
176
+ label,
177
+ actionLabel
178
+ }) {
179
+ const host = useRef2(null);
180
+ const [active, setActive] = useState2(false);
181
+ useEffect(() => {
182
+ const node = host.current;
183
+ if (active || !node) return;
184
+ if (typeof IntersectionObserver === "undefined") {
185
+ setActive(true);
186
+ return;
187
+ }
188
+ let disposed = false;
189
+ const observer = new IntersectionObserver(
190
+ (entries) => {
191
+ if (disposed || !entries.some((entry) => entry.isIntersecting)) return;
192
+ setActive(true);
193
+ observer.disconnect();
194
+ },
195
+ {
196
+ root: node.closest("[data-og-timeline-scroller]"),
197
+ rootMargin: "200px 0px"
198
+ }
199
+ );
200
+ observer.observe(node);
201
+ return () => {
202
+ disposed = true;
203
+ observer.disconnect();
204
+ };
205
+ }, [active]);
206
+ return /* @__PURE__ */ jsx2("div", { ref: host, "data-chat-media": active ? "active" : "deferred", children: active ? children : /* @__PURE__ */ jsx2("div", { className: "flex w-full items-center justify-center", style: { height }, children: /* @__PURE__ */ jsx2(
207
+ "button",
208
+ {
209
+ type: "button",
210
+ className: "rounded-md px-3 py-2 text-sm text-fg-muted hover:text-fg focus-visible:outline-2 focus-visible:outline-ring",
211
+ onClick: () => setActive(true),
212
+ children: actionLabel ?? `Load ${label ?? "media"}`
213
+ }
214
+ ) }) });
215
+ }
216
+
217
+ // src/components/artifacts/visualization-assets.gen.ts
218
+ var VISUALIZATION_CSS = `/* Adapted from Codex visualize 1.0.32; shared with the OpenGeni visualization skill. */
219
+ :root {
220
+ color-scheme: light dark;
221
+ background-color: var(
222
+ --background,
223
+ var(--color-background-primary, light-dark(rgb(255 255 255), rgb(24 24 24)))
224
+ ) !important;
225
+
226
+ /* Agent-facing contract; keep in sync with SKILL.md. */
227
+ --background: var(
228
+ --color-background-primary,
229
+ light-dark(rgb(255 255 255), rgb(24 24 24))
230
+ );
231
+ --foreground: var(
232
+ --color-text-primary,
233
+ light-dark(rgb(26 28 31), rgb(255 255 255))
234
+ );
235
+ --card: color-mix(in oklab, var(--foreground) 5%, var(--background));
236
+ --card-foreground: var(
237
+ --color-text-primary,
238
+ light-dark(rgb(26 28 31), rgb(255 255 255))
239
+ );
240
+ --popover: var(
241
+ --color-background-secondary,
242
+ light-dark(rgb(255 255 255), rgb(45 45 45))
243
+ );
244
+ --popover-foreground: var(
245
+ --color-text-primary,
246
+ light-dark(rgb(26 28 31), rgb(255 255 255))
247
+ );
248
+ --primary: var(
249
+ --color-text-info,
250
+ light-dark(rgb(51 156 255), rgb(131 195 255))
251
+ );
252
+ --primary-foreground: var(
253
+ --color-text-inverse,
254
+ light-dark(rgb(255 255 255), rgb(13 13 13))
255
+ );
256
+ --secondary: var(
257
+ --color-background-secondary,
258
+ light-dark(rgb(255 255 255 / 96%), rgb(54 54 54 / 96%))
259
+ );
260
+ --secondary-foreground: var(
261
+ --color-text-primary,
262
+ light-dark(rgb(26 28 31), rgb(255 255 255))
263
+ );
264
+ --muted: color-mix(in srgb, var(--foreground) 10%, transparent);
265
+ --muted-foreground: var(
266
+ --color-text-secondary,
267
+ light-dark(rgb(26 28 31 / 49.4%), rgb(255 255 255 / 49.8%))
268
+ );
269
+ --accent: var(
270
+ --color-background-info,
271
+ light-dark(rgb(229 242 255), rgb(13 39 63))
272
+ );
273
+ --accent-foreground: var(
274
+ --color-text-info,
275
+ light-dark(rgb(51 156 255), rgb(131 195 255))
276
+ );
277
+ --destructive: var(
278
+ --color-text-warning,
279
+ light-dark(rgb(226 85 7), rgb(255 133 73))
280
+ );
281
+ --border: var(
282
+ --color-border-secondary,
283
+ light-dark(rgb(26 28 31 / 8%), rgb(255 255 255 / 8.2%))
284
+ );
285
+ --input: var(
286
+ --color-border-primary,
287
+ light-dark(
288
+ rgb(26 28 31 / 11.8%),
289
+ color-mix(in oklab, rgb(0 0 0) 10%, transparent)
290
+ )
291
+ );
292
+ --ring: var(
293
+ --color-ring-primary,
294
+ light-dark(rgb(51 156 255), rgb(131 195 255 / 76%))
295
+ );
296
+ --font-size-base: var(--font-text-md-size, 14px);
297
+ --blue: light-dark(rgb(51 156 255), rgb(51 156 255));
298
+ --orange: light-dark(rgb(226 85 7), rgb(251 106 34));
299
+ --green: light-dark(rgb(0 162 64), rgb(64 201 119));
300
+ --red: light-dark(rgb(224 46 42), rgb(255 103 100));
301
+ --purple: light-dark(rgb(146 79 247), rgb(173 123 249));
302
+ --yellow: light-dark(rgb(255 195 0), rgb(255 210 64));
303
+ --viz-series-1: var(--primary);
304
+ --viz-series-2: light-dark(rgb(243 136 59), rgb(245 154 86));
305
+ --viz-series-3: light-dark(rgb(93 201 119), rgb(116 213 139));
306
+ --viz-series-4: light-dark(rgb(235 119 177), rgb(240 143 192));
307
+ --viz-series-5: light-dark(rgb(155 121 236), rgb(170 145 239));
308
+ --viz-series-6: light-dark(rgb(58 185 177), rgb(90 203 194));
309
+
310
+ /* Internal implementation variables; not part of the agent contract. */
311
+ --font-sans: -apple-system, system-ui, "Segoe UI", sans-serif;
312
+ --font-mono:
313
+ ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono",
314
+ monospace;
315
+ --font-size-normal: max(11px, var(--font-size-base));
316
+ --font-size-tooltip: calc(var(--font-size-base) - 1px);
317
+ --font-size-small: max(11px, calc(var(--font-size-base) - 2px));
318
+ --font-size-h1: calc(var(--font-size-normal) * 1.7142857143);
319
+ --font-size-h2: calc(var(--font-size-normal) * 1.4285714286);
320
+ --font-size-h3: calc(var(--font-size-normal) * 1.2857142857);
321
+ --font-weight-normal: 430;
322
+ --font-weight-medium: 500;
323
+ --icon-size: 16px;
324
+ --line-height-normal: calc(var(--font-size-normal) * 1.5);
325
+ --line-height-tooltip: calc(var(--font-size-tooltip) * 1.4285714286);
326
+ --line-height-small: calc(var(--font-size-small) + 4px);
327
+ --corner-shape: round;
328
+ --radius: var(--border-radius-lg, 10px);
329
+ --radius-sm: calc(var(--radius) * 0.6);
330
+ --radius-md: calc(var(--radius) * 0.8);
331
+ --radius-lg: var(--radius);
332
+ --radius-2xl: calc(var(--radius) * 1.6);
333
+ --radius-full: 9999px;
334
+ --shadow-sm: 0 1px 2px -1px rgb(0 0 0 / 8%);
335
+ --checkmark-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 17 17'%3E%3Cpath d='M 12.8961 3.64101C13.1297 3.41418 13.4984 3.37523 13.7779 3.56581C14.0571 3.75635 14.1554 4.11331 14.0299 4.41347L13.9615 4.53847L7.71151 13.7045C7.59411 13.8767 7.4063 13.9877 7.19881 14.0072C6.99136 14.0267 6.78564 13.9533 6.63826 13.806L2.88826 10.056L2.79842 9.9457C2.6192 9.67407 2.64927 9.30496 2.88826 9.06581C3.12738 8.82669 3.49647 8.79676 3.76815 8.97597L3.8785 9.06581L7.03084 12.2182L12.8053 3.74941L12.8961 3.64101Z'/%3E%3C/svg%3E");
336
+
337
+ /* Legacy aliases; not part of the current agent contract. */
338
+ --viz-bg: transparent;
339
+ --viz-panel: var(--card);
340
+ --viz-border: var(--border);
341
+ --viz-text: var(--foreground);
342
+ --viz-muted: var(--muted-foreground);
343
+ --viz-accent: var(--primary);
344
+ --viz-accent-text: var(--primary-foreground);
345
+ --viz-accent-bg: var(--accent);
346
+ --viz-font-size: var(--font-size-base);
347
+ --viz-warning: var(--destructive);
348
+ }
349
+
350
+ :root[data-theme="light"] {
351
+ color-scheme: light;
352
+ }
353
+
354
+ :root[data-theme="dark"] {
355
+ color-scheme: dark;
356
+ }
357
+
358
+ * {
359
+ box-sizing: border-box;
360
+ }
361
+
362
+ html > body {
363
+ /* Preserve MCP aliases for older inline renderers without creating :root cycles. */
364
+ --color-background-primary: var(
365
+ --background,
366
+ light-dark(rgb(255 255 255), rgb(24 24 24))
367
+ );
368
+ --color-text-primary: var(
369
+ --foreground,
370
+ light-dark(rgb(26 28 31), rgb(255 255 255))
371
+ );
372
+ --color-border-secondary: var(
373
+ --border,
374
+ light-dark(rgb(26 28 31 / 8%), rgb(255 255 255 / 8.2%))
375
+ );
376
+
377
+ margin: 0;
378
+ padding: var(--visualize-paint-gutter, 16px);
379
+ color: var(--foreground);
380
+ background: transparent !important;
381
+ font-family: var(--font-sans) !important;
382
+ font-size: var(--font-size-normal);
383
+ font-weight: var(--font-weight-normal);
384
+ line-height: var(--line-height-normal);
385
+ }
386
+
387
+ a {
388
+ color: color-mix(in srgb, var(--viz-accent) 80%, var(--viz-text) 20%);
389
+ cursor: pointer;
390
+ font-weight: var(--font-weight-medium, 500);
391
+ text-decoration: none;
392
+ text-underline-offset: 2px;
393
+ }
394
+
395
+ a:is(:hover, :focus-visible) {
396
+ text-decoration-line: underline;
397
+ text-decoration-style: dashed;
398
+ text-decoration-thickness: 0.5px;
399
+ }
400
+
401
+ h1,
402
+ h2,
403
+ h3,
404
+ h4,
405
+ h5,
406
+ h6,
407
+ p {
408
+ margin-block: 0;
409
+ }
410
+
411
+ h1 {
412
+ font-size: var(--font-size-h1);
413
+ font-weight: var(--font-weight-medium);
414
+ line-height: 1.25;
415
+ }
416
+
417
+ h2 {
418
+ font-size: var(--font-size-h2);
419
+ font-weight: var(--font-weight-medium);
420
+ line-height: 1.25;
421
+ }
422
+
423
+ h3,
424
+ h4,
425
+ h5,
426
+ h6 {
427
+ font-size: var(--font-size-h3);
428
+ font-weight: var(--font-weight-medium);
429
+ line-height: 1.3;
430
+ }
431
+
432
+ b,
433
+ strong,
434
+ th {
435
+ font-weight: var(--font-weight-medium);
436
+ }
437
+
438
+ code:not(pre code) {
439
+ display: inline;
440
+ padding: 1px 6px;
441
+ border-radius: var(--radius-sm);
442
+ corner-shape: var(--corner-shape);
443
+ background: var(--muted);
444
+ font-family: var(--font-mono);
445
+ font-size: 0.92em;
446
+ overflow-wrap: anywhere;
447
+ -webkit-box-decoration-break: clone;
448
+ box-decoration-break: clone;
449
+ word-break: break-word;
450
+ }
451
+
452
+ .table-responsive {
453
+ width: 100%;
454
+ overflow-x: auto;
455
+ scrollbar-width: thin;
456
+ }
457
+
458
+ .table {
459
+ width: 100%;
460
+ border-collapse: collapse;
461
+ color: var(--foreground);
462
+ font: inherit;
463
+ text-align: start;
464
+ }
465
+
466
+ .table :is(th, td) {
467
+ padding-block: 10px;
468
+ padding-inline: 0 24px;
469
+ overflow-wrap: anywhere;
470
+ border-bottom: 1px solid var(--border);
471
+ text-align: start;
472
+ vertical-align: top;
473
+ }
474
+
475
+ .table-responsive > .table :is(th, td) {
476
+ overflow-wrap: break-word;
477
+ }
478
+
479
+ .table :is(th, td):last-child {
480
+ padding-inline-end: 0;
481
+ }
482
+
483
+ .table :is(caption, thead th) {
484
+ font-weight: 600;
485
+ }
486
+
487
+ .table thead th {
488
+ padding-block: 8px;
489
+ border-bottom-color: color-mix(in srgb, var(--foreground) 16%, transparent);
490
+ }
491
+
492
+ .table tbody tr:last-child :is(th, td) {
493
+ border-bottom: 0;
494
+ }
495
+
496
+ .table.table-sm :is(th, td) {
497
+ padding-block: 6px;
498
+ }
499
+
500
+ .table.table-sm :is(th, td):not(:last-child) {
501
+ padding-inline-end: 16px;
502
+ }
503
+
504
+ .table :is(.text-end, [align="right"]) {
505
+ text-align: end;
506
+ font-variant-numeric: tabular-nums;
507
+ }
508
+
509
+ .table :is(.text-center, [align="center"]) {
510
+ text-align: center;
511
+ }
512
+
513
+ .table .text-nowrap {
514
+ white-space: nowrap;
515
+ }
516
+
517
+ #widget {
518
+ display: flex;
519
+ flex-direction: column;
520
+ gap: 12px;
521
+ width: 100%;
522
+ padding: 0;
523
+ background: transparent !important;
524
+ }
525
+
526
+ .card {
527
+ min-width: 0;
528
+ padding: 12px;
529
+ overflow: hidden;
530
+ overflow-wrap: break-word;
531
+ border-radius: var(--radius-2xl);
532
+ corner-shape: var(--corner-shape);
533
+ color: var(--card-foreground);
534
+ background: var(--card);
535
+ }
536
+
537
+ #widget > :not(.card, .progress) {
538
+ width: 100% !important;
539
+ max-width: none !important;
540
+ margin: 0 !important;
541
+ padding: 0 !important;
542
+ border: 0 !important;
543
+ border-radius: 0 !important;
544
+ background: transparent !important;
545
+ box-shadow: none !important;
546
+ }
547
+
548
+ .tooltip {
549
+ position: fixed;
550
+ z-index: 50;
551
+ top: 0;
552
+ left: 0;
553
+ width: max-content;
554
+ max-width: min(
555
+ 20rem,
556
+ var(--tooltip-available-width, calc(100vw - 10px)),
557
+ calc(100vw - 10px)
558
+ );
559
+ max-height: min(
560
+ var(--tooltip-available-height, calc(100vh - 10px)),
561
+ calc(100vh - 10px)
562
+ );
563
+ padding: 4px 8px;
564
+ border: 1px solid var(--border);
565
+ border-radius: var(--radius-lg);
566
+ corner-shape: var(--corner-shape);
567
+ color: var(--popover-foreground);
568
+ background: var(--popover);
569
+ box-shadow: none;
570
+ font-size: var(--font-size-tooltip);
571
+ line-height: var(--line-height-tooltip);
572
+ overflow-wrap: break-word;
573
+ white-space: normal;
574
+ pointer-events: none;
575
+ user-select: none;
576
+ }
577
+
578
+ .viz-grid {
579
+ display: grid;
580
+ grid-template-columns: repeat(auto-fit, minmax(max(180px, 24%), 1fr));
581
+ gap: 10px;
582
+ }
583
+
584
+ .viz-stat {
585
+ display: flex;
586
+ flex-direction: column;
587
+ gap: 2px;
588
+ }
589
+
590
+ .viz-stat-value {
591
+ font-size: var(--font-size-h2);
592
+ font-weight: var(--font-weight-medium);
593
+ line-height: 1.25;
594
+ }
595
+
596
+ .viz-row {
597
+ display: flex;
598
+ flex-wrap: wrap;
599
+ align-items: center;
600
+ gap: 10px;
601
+ }
602
+
603
+ hr {
604
+ width: 100%;
605
+ height: 1px;
606
+ margin-block: 6px;
607
+ border: 0;
608
+ background: var(--border);
609
+ }
610
+
611
+ .nav {
612
+ display: flex;
613
+ min-width: 0;
614
+ align-items: center;
615
+ gap: 4px;
616
+ }
617
+
618
+ .progress {
619
+ display: flex;
620
+ height: 8px;
621
+ margin-block: calc((var(--line-height-normal, 1.5em) - 8px) / 2);
622
+ overflow: hidden;
623
+ border: 0;
624
+ border-radius: var(--radius-full);
625
+ background: var(--muted);
626
+ }
627
+
628
+ .progress-bar:only-child {
629
+ border-radius: var(--radius-full);
630
+ }
631
+
632
+ .progress-bar {
633
+ height: 100%;
634
+ flex-shrink: 0;
635
+ border: 0;
636
+ background: var(--viz-series-1);
637
+ }
638
+
639
+ .viz-badge {
640
+ padding: 3px 8px;
641
+ border-radius: var(--radius-full);
642
+ color: var(--accent-foreground);
643
+ background: var(--accent);
644
+ font-weight: var(--font-weight-medium);
645
+ }
646
+
647
+ small,
648
+ .text-small,
649
+ .viz-badge {
650
+ font-size: var(--font-size-small);
651
+ line-height: var(--line-height-small);
652
+ }
653
+
654
+ .text-muted {
655
+ color: var(--muted-foreground);
656
+ }
657
+
658
+ .tabular-nums {
659
+ font-variant-numeric: tabular-nums;
660
+ }
661
+
662
+ .sr-only {
663
+ position: absolute;
664
+ width: 1px;
665
+ height: 1px;
666
+ padding: 0;
667
+ overflow: hidden;
668
+ clip: rect(0, 0, 0, 0);
669
+ white-space: nowrap;
670
+ border: 0;
671
+ }
672
+
673
+ .viz-controls {
674
+ display: flex;
675
+ flex-wrap: wrap;
676
+ align-items: center;
677
+ gap: 8px;
678
+ }
679
+
680
+ .viz-controls > .form-label {
681
+ display: grid;
682
+ min-width: min(100%, 260px);
683
+ flex: 1 1 280px;
684
+ grid-template-columns: minmax(0, 1fr) auto;
685
+ align-items: baseline;
686
+ gap: 2px 12px;
687
+ margin-bottom: 0;
688
+ }
689
+
690
+ .viz-controls > .form-label > :is(.form-control, .form-range, .form-select) {
691
+ grid-column: 1 / -1;
692
+ }
693
+
694
+ .btn,
695
+ .nav-link,
696
+ .form-check-input,
697
+ .form-control,
698
+ .form-range,
699
+ .form-select {
700
+ font: inherit;
701
+ }
702
+
703
+ .btn,
704
+ .nav-link {
705
+ appearance: button;
706
+ display: inline-flex;
707
+ inline-size: fit-content;
708
+ max-inline-size: 100%;
709
+ min-height: 28px;
710
+ align-items: center;
711
+ justify-content: center;
712
+ gap: 4px;
713
+ margin: 0;
714
+ padding: 0 8px;
715
+ -webkit-app-region: no-drag;
716
+ border: 1px solid var(--input);
717
+ border-radius: var(--radius-lg);
718
+ corner-shape: var(--corner-shape);
719
+ color: var(--secondary-foreground);
720
+ background: var(--secondary);
721
+ cursor: var(--cursor-interaction, pointer);
722
+ text-align: center;
723
+ text-decoration: none;
724
+ white-space: nowrap;
725
+ user-select: none;
726
+ -webkit-font-smoothing: antialiased;
727
+ }
728
+
729
+ .btn:is(.btn-block, .viz-tile) {
730
+ inline-size: 100%;
731
+ }
732
+
733
+ .btn.viz-tile {
734
+ min-width: 0;
735
+ overflow-wrap: anywhere;
736
+ white-space: normal;
737
+ }
738
+
739
+ a.btn {
740
+ cursor: pointer;
741
+ text-decoration: none;
742
+ }
743
+
744
+ .btn:not(:disabled):hover,
745
+ .nav-link:not(:disabled):not([aria-disabled="true"]):hover {
746
+ background: color-mix(in srgb, var(--foreground) 6%, var(--secondary));
747
+ }
748
+
749
+ .btn-primary {
750
+ border-color: transparent;
751
+ color: var(--primary-foreground);
752
+ background: var(--foreground);
753
+ background-clip: padding-box;
754
+ }
755
+
756
+ .btn-primary .text-muted {
757
+ color: color-mix(in srgb, var(--primary-foreground) 50%, transparent);
758
+ }
759
+
760
+ .btn-primary:not(:disabled):hover {
761
+ background: color-mix(in srgb, var(--foreground) 80%, transparent);
762
+ background-clip: padding-box;
763
+ }
764
+
765
+ .btn-ghost {
766
+ border-color: transparent;
767
+ color: var(--muted-foreground);
768
+ background: transparent;
769
+ }
770
+
771
+ .btn-ghost:not(:disabled):hover {
772
+ color: var(--foreground);
773
+ background: color-mix(in srgb, var(--foreground) 6%, var(--secondary));
774
+ }
775
+
776
+ .nav-pills .nav-link {
777
+ min-width: 0;
778
+ border-color: transparent;
779
+ color: var(--muted-foreground);
780
+ background: transparent;
781
+ }
782
+
783
+ .nav-justified .nav-link {
784
+ flex: 1 1 0;
785
+ overflow-wrap: anywhere;
786
+ white-space: normal;
787
+ }
788
+
789
+ .nav-pills .nav-link.active {
790
+ color: var(--foreground);
791
+ background: var(--muted);
792
+ }
793
+
794
+ .btn:disabled,
795
+ .nav-link:disabled,
796
+ .nav-link[aria-disabled="true"] {
797
+ cursor: not-allowed;
798
+ opacity: 0.4;
799
+ }
800
+
801
+ [data-lucide] {
802
+ stroke-width: 1.6;
803
+ }
804
+
805
+ .form-label {
806
+ display: block;
807
+ margin-bottom: 6px;
808
+ color: var(--foreground);
809
+ }
810
+
811
+ .form-control {
812
+ display: block;
813
+ width: 100%;
814
+ min-height: 28px;
815
+ padding: 0 8px;
816
+ outline: none;
817
+ border: 1px solid var(--input);
818
+ border-radius: var(--radius-lg);
819
+ corner-shape: var(--corner-shape);
820
+ color: var(--foreground);
821
+ background: var(--secondary);
822
+ }
823
+
824
+ .form-control::placeholder {
825
+ color: var(--muted-foreground);
826
+ }
827
+
828
+ .form-control[type="file"] {
829
+ padding: 0;
830
+ overflow: hidden;
831
+ cursor: var(--cursor-interaction, pointer);
832
+ }
833
+
834
+ .form-control[type="file"]::file-selector-button {
835
+ min-height: 26px;
836
+ margin-right: 8px;
837
+ padding: 0 8px;
838
+ border: 0;
839
+ border-right: 1px solid var(--input);
840
+ color: var(--secondary-foreground);
841
+ background: var(--secondary);
842
+ cursor: inherit;
843
+ font: inherit;
844
+ }
845
+
846
+ .form-control[type="file"]:not(:disabled):hover::file-selector-button {
847
+ background: color-mix(in srgb, var(--foreground) 6%, var(--secondary));
848
+ }
849
+
850
+ .form-control-color[type="color"] {
851
+ width: 40px;
852
+ height: 28px;
853
+ padding: 3px;
854
+ cursor: var(--cursor-interaction, pointer);
855
+ }
856
+
857
+ .form-control-color[type="color"]::-webkit-color-swatch-wrapper {
858
+ padding: 0;
859
+ }
860
+
861
+ .form-control-color[type="color"]::-webkit-color-swatch {
862
+ border: 0;
863
+ border-radius: calc(var(--radius-lg) - 4px);
864
+ corner-shape: var(--corner-shape);
865
+ }
866
+
867
+ textarea.form-control {
868
+ height: auto;
869
+ min-height: 72px;
870
+ padding: 8px 10px;
871
+ resize: vertical;
872
+ }
873
+
874
+ .form-control:focus-visible {
875
+ border-color: var(--ring);
876
+ box-shadow: inset 0 0 0 1px var(--ring);
877
+ }
878
+
879
+ .form-control:disabled,
880
+ .form-select:disabled {
881
+ cursor: not-allowed;
882
+ opacity: 0.4;
883
+ }
884
+
885
+ .form-select {
886
+ appearance: none;
887
+ display: block;
888
+ width: 100%;
889
+ min-height: 28px;
890
+ margin: 0;
891
+ padding: 0 32px 0 8px;
892
+ outline: none;
893
+ border: 1px solid var(--input);
894
+ border-radius: var(--radius-lg);
895
+ corner-shape: var(--corner-shape);
896
+ color: var(--foreground);
897
+ background-color: var(--secondary);
898
+ background-image:
899
+ linear-gradient(45deg, transparent 50%, var(--muted-foreground) 50%),
900
+ linear-gradient(135deg, var(--muted-foreground) 50%, transparent 50%);
901
+ background-position:
902
+ calc(100% - 14px) 50%,
903
+ calc(100% - 10px) 50%;
904
+ background-repeat: no-repeat;
905
+ background-size: 4px 4px;
906
+ cursor: var(--cursor-interaction, default);
907
+ }
908
+
909
+ .form-select:not(:disabled):hover {
910
+ background-color: color-mix(in srgb, var(--foreground) 6%, var(--secondary));
911
+ }
912
+
913
+ .form-select:focus-visible {
914
+ border-color: var(--ring);
915
+ box-shadow: inset 0 0 0 1px var(--ring);
916
+ }
917
+
918
+ .form-check {
919
+ display: flex;
920
+ min-height: 20px;
921
+ align-items: center;
922
+ gap: 6px;
923
+ }
924
+
925
+ .form-check-input {
926
+ appearance: none;
927
+ width: 14px;
928
+ height: 14px;
929
+ flex: 0 0 auto;
930
+ margin: 0;
931
+ border: 1px solid var(--input);
932
+ color: var(--primary-foreground);
933
+ background-color: transparent;
934
+ cursor: var(--cursor-interaction, default);
935
+ transition:
936
+ background-color 150ms,
937
+ border-color 150ms,
938
+ box-shadow 150ms;
939
+ }
940
+
941
+ .form-check:not(.form-switch) .form-check-input[type="checkbox"] {
942
+ border-color: var(--input);
943
+ border-radius: var(--radius-sm);
944
+ corner-shape: var(--corner-shape);
945
+ background-color: var(--secondary);
946
+ box-shadow: var(--shadow-sm);
947
+ }
948
+
949
+ .form-check:not(.form-switch)
950
+ .form-check-input:not(:disabled):not(:checked):hover {
951
+ background-color: var(--card);
952
+ }
953
+
954
+ .form-check:not(.form-switch) .form-check-input[type="checkbox"]:checked {
955
+ border-color: var(--primary);
956
+ background-color: var(--primary);
957
+ }
958
+
959
+ .form-check:not(.form-switch)
960
+ .form-check-input[type="checkbox"]:checked::before {
961
+ display: block;
962
+ width: 100%;
963
+ height: 100%;
964
+ background: var(--primary-foreground);
965
+ content: "";
966
+ mask: var(--checkmark-image) center / 12px 12px no-repeat;
967
+ }
968
+
969
+ .form-check-input[type="radio"] {
970
+ width: 14px;
971
+ height: 14px;
972
+ border-radius: var(--radius-full);
973
+ }
974
+
975
+ .form-check-input[type="radio"]:checked {
976
+ border: 2px solid var(--primary);
977
+ background:
978
+ radial-gradient(circle, var(--primary-foreground) 0 2.5px, transparent 3px),
979
+ var(--primary);
980
+ }
981
+
982
+ .form-check:not(.form-switch) .form-check-input:focus-visible {
983
+ outline: 2px solid var(--ring);
984
+ outline-offset: 2px;
985
+ }
986
+
987
+ .form-check:not(.form-switch) .form-check-input:disabled {
988
+ cursor: not-allowed;
989
+ pointer-events: none;
990
+ }
991
+
992
+ .form-check:not(.form-switch) .form-check-input:disabled + .form-check-label {
993
+ cursor: not-allowed;
994
+ }
995
+
996
+ .form-switch .form-check-input:disabled,
997
+ .form-switch .form-check-input:disabled + .form-check-label {
998
+ cursor: not-allowed;
999
+ opacity: 0.6;
1000
+ }
1001
+
1002
+ .form-check-label {
1003
+ color: var(--foreground);
1004
+ cursor: var(--cursor-interaction, default);
1005
+ }
1006
+
1007
+ .form-switch .form-check-input {
1008
+ position: relative;
1009
+ width: 32px;
1010
+ height: 20px;
1011
+ border: 0;
1012
+ border-radius: var(--radius-full);
1013
+ background: var(--muted);
1014
+ box-shadow: none;
1015
+ transition: background-color 200ms cubic-bezier(0, 0, 0.2, 1);
1016
+ }
1017
+
1018
+ .form-switch .form-check-input::before {
1019
+ position: absolute;
1020
+ top: 50%;
1021
+ left: 0;
1022
+ width: 16px;
1023
+ height: 16px;
1024
+ box-sizing: border-box;
1025
+ border: 1px solid light-dark(var(--primary-foreground), var(--foreground));
1026
+ border-radius: var(--radius-full);
1027
+ background: light-dark(var(--primary-foreground), var(--foreground));
1028
+ box-shadow: var(--shadow-sm);
1029
+ content: "";
1030
+ transform: translate(2px, -50%);
1031
+ transition: transform 200ms cubic-bezier(0, 0, 0.2, 1);
1032
+ }
1033
+
1034
+ .form-switch .form-check-input:checked {
1035
+ background: var(--primary);
1036
+ }
1037
+
1038
+ .form-switch .form-check-input:checked::before {
1039
+ transform: translate(14px, -50%);
1040
+ }
1041
+
1042
+ .form-switch .form-check-input:focus-visible {
1043
+ box-shadow: 0 0 0 2px var(--ring);
1044
+ }
1045
+
1046
+ .form-range {
1047
+ appearance: none;
1048
+ display: block;
1049
+ width: 100%;
1050
+ height: 28px;
1051
+ flex: 1;
1052
+ margin: 0;
1053
+ padding: 0;
1054
+ outline: none;
1055
+ border: 0;
1056
+ accent-color: var(--primary);
1057
+ background: linear-gradient(
1058
+ color-mix(in srgb, var(--foreground) 7%, transparent),
1059
+ color-mix(in srgb, var(--foreground) 7%, transparent)
1060
+ )
1061
+ center / 100% 2px no-repeat;
1062
+ }
1063
+
1064
+ .form-range::-webkit-slider-runnable-track {
1065
+ height: 28px;
1066
+ background: transparent;
1067
+ }
1068
+
1069
+ .form-range::-webkit-slider-thumb {
1070
+ appearance: none;
1071
+ width: 20px;
1072
+ height: 20px;
1073
+ margin-top: 4px;
1074
+ border: 1px solid var(--border);
1075
+ border-radius: var(--radius-full);
1076
+ background: light-dark(var(--primary-foreground), var(--foreground));
1077
+ }
1078
+
1079
+ .form-range:focus-visible::-webkit-slider-thumb {
1080
+ border-color: var(--ring);
1081
+ box-shadow: inset 0 0 0 1px var(--ring);
1082
+ }
1083
+
1084
+ .form-range::-moz-range-track {
1085
+ height: 28px;
1086
+ background: transparent;
1087
+ }
1088
+
1089
+ .form-range::-moz-range-thumb {
1090
+ width: 20px;
1091
+ height: 20px;
1092
+ border: 1px solid var(--border);
1093
+ border-radius: var(--radius-full);
1094
+ background: light-dark(var(--primary-foreground), var(--foreground));
1095
+ }
1096
+
1097
+ .form-range:focus-visible::-moz-range-thumb {
1098
+ border-color: var(--ring);
1099
+ box-shadow: inset 0 0 0 1px var(--ring);
1100
+ }
1101
+
1102
+ .form-range:disabled {
1103
+ cursor: not-allowed;
1104
+ opacity: 0.4;
1105
+ }
1106
+
1107
+ .btn:not(.btn-primary, .viz-tile):is(
1108
+ [aria-pressed="true"],
1109
+ [aria-selected="true"],
1110
+ .is-selected
1111
+ ) {
1112
+ border-color: var(--primary);
1113
+ color: var(--primary-foreground);
1114
+ background: var(--primary);
1115
+ }
1116
+
1117
+ .btn.viz-tile:is([aria-pressed="true"], [aria-selected="true"], .is-selected) {
1118
+ border-color: var(--primary);
1119
+ box-shadow: inset 0 0 0 1px var(--primary);
1120
+ }
1121
+
1122
+ .btn:focus-visible,
1123
+ .nav-link:focus-visible {
1124
+ outline: 2px solid var(--ring);
1125
+ outline-offset: 2px;
1126
+ }
1127
+
1128
+ @media (pointer: coarse) {
1129
+ .btn,
1130
+ .nav-link,
1131
+ .form-control,
1132
+ .form-select {
1133
+ min-width: 44px;
1134
+ min-height: 44px;
1135
+ }
1136
+
1137
+ /* Keep small-screen WebKit from zooming when a text field receives focus. */
1138
+ .form-control,
1139
+ .form-select {
1140
+ font-size: max(16px, var(--font-size-normal));
1141
+ }
1142
+
1143
+ .form-control[type="file"]::file-selector-button {
1144
+ min-width: 44px;
1145
+ min-height: 44px;
1146
+ }
1147
+
1148
+ .form-control-color[type="color"] {
1149
+ width: 44px;
1150
+ height: 44px;
1151
+ }
1152
+
1153
+ .form-control:is(
1154
+ [type="date"],
1155
+ [type="datetime-local"],
1156
+ [type="month"],
1157
+ [type="time"],
1158
+ [type="week"]
1159
+ ) {
1160
+ min-width: 0;
1161
+ max-width: 100%;
1162
+ padding-block: 8px;
1163
+ }
1164
+
1165
+ .form-check {
1166
+ min-height: 44px;
1167
+ padding-inline: 15px;
1168
+ }
1169
+
1170
+ .form-check-input {
1171
+ position: relative;
1172
+ }
1173
+
1174
+ .form-check-input::after {
1175
+ position: absolute;
1176
+ top: 50%;
1177
+ left: 50%;
1178
+ width: 44px;
1179
+ height: 44px;
1180
+ content: "";
1181
+ transform: translate(-50%, -50%);
1182
+ }
1183
+
1184
+ .form-check-label {
1185
+ display: inline-flex;
1186
+ min-width: 44px;
1187
+ min-height: 44px;
1188
+ align-items: center;
1189
+ }
1190
+
1191
+ .form-range {
1192
+ height: 44px;
1193
+ touch-action: pan-y;
1194
+ }
1195
+
1196
+ .form-range::-webkit-slider-runnable-track {
1197
+ height: 44px;
1198
+ }
1199
+
1200
+ .form-range::-moz-range-track {
1201
+ height: 44px;
1202
+ }
1203
+
1204
+ .form-range::-webkit-slider-thumb {
1205
+ margin-top: 12px;
1206
+ }
1207
+ }
1208
+
1209
+ svg {
1210
+ display: block;
1211
+ max-width: 100%;
1212
+ height: auto;
1213
+ }
1214
+
1215
+ #widget > svg {
1216
+ width: 100%;
1217
+ }
1218
+
1219
+ /* Model-authored chart rules can otherwise stretch icons after these styles load. */
1220
+ svg.lucide {
1221
+ display: block;
1222
+ width: var(--icon-size) !important;
1223
+ height: var(--icon-size) !important;
1224
+ flex: none;
1225
+ margin: 0 !important;
1226
+ stroke-width: 1.6;
1227
+ }
1228
+
1229
+ .text-warning,
1230
+ .text-destructive {
1231
+ color: var(--destructive);
1232
+ }
1233
+ `;
1234
+ var VISUALIZATION_HELPERS = `
1235
+ <script src="https://unpkg.com/@floating-ui/core@1.7.3/dist/floating-ui.core.umd.min.js"></script>
1236
+ <script src="https://unpkg.com/@floating-ui/dom@1.7.4/dist/floating-ui.dom.umd.min.js"></script>
1237
+ <script>
1238
+ (() => {
1239
+ if (window.FloatingUIDOM == null) {
1240
+ return;
1241
+ }
1242
+ const { autoUpdate, computePosition, flip, offset, shift, size } = window.FloatingUIDOM;
1243
+ const tooltipPlacements = new Set(["top", "right", "bottom", "left"]);
1244
+ const tooltipId = \`codex-visualization-tooltip-\${
1245
+ window.crypto?.randomUUID?.() ?? Date.now().toString(36)
1246
+ }\`;
1247
+ const tooltipGap = 5;
1248
+ const hoverDelay = 700;
1249
+ const skipDelay = 300;
1250
+ let activeTrigger = null;
1251
+ let pendingTrigger = null;
1252
+ let tooltip = null;
1253
+ let openTimeout = null;
1254
+ let autoUpdateCleanup = null;
1255
+ let positionRequest = 0;
1256
+ let skipDelayUntil = 0;
1257
+ let lastPointerWasTouch = false;
1258
+ let pinnedByTouch = false;
1259
+
1260
+ const getTrigger = (target) =>
1261
+ target?.nodeType === Node.ELEMENT_NODE ? target.closest("[data-tooltip]") : null;
1262
+ const containsTarget = (trigger, target) =>
1263
+ target?.nodeType != null && trigger.contains(target);
1264
+ const getContent = (trigger) => trigger.getAttribute("data-tooltip")?.trim() ?? "";
1265
+ const getPlacement = (trigger) => {
1266
+ const placement = trigger.getAttribute("data-tooltip-placement");
1267
+ return tooltipPlacements.has(placement) ? placement : "top";
1268
+ };
1269
+ const getTooltip = () => {
1270
+ if (tooltip == null) {
1271
+ tooltip = document.createElement("div");
1272
+ tooltip.id = tooltipId;
1273
+ tooltip.className = "tooltip";
1274
+ tooltip.setAttribute("role", "tooltip");
1275
+ }
1276
+ return tooltip;
1277
+ };
1278
+ const setDescribedBy = (trigger, described) => {
1279
+ const ids = new Set(
1280
+ (trigger.getAttribute("aria-describedby") ?? "").split(/\\s+/).filter(Boolean),
1281
+ );
1282
+ if (described) {
1283
+ ids.add(tooltipId);
1284
+ } else {
1285
+ ids.delete(tooltipId);
1286
+ }
1287
+ if (ids.size === 0) {
1288
+ trigger.removeAttribute("aria-describedby");
1289
+ } else {
1290
+ trigger.setAttribute("aria-describedby", [...ids].join(" "));
1291
+ }
1292
+ };
1293
+ const clearOpenTimeout = () => {
1294
+ if (openTimeout != null) {
1295
+ window.clearTimeout(openTimeout);
1296
+ openTimeout = null;
1297
+ }
1298
+ pendingTrigger = null;
1299
+ };
1300
+ const closeTooltip = (activateSkipDelay = true) => {
1301
+ clearOpenTimeout();
1302
+ pinnedByTouch = false;
1303
+ positionRequest += 1;
1304
+ autoUpdateCleanup?.();
1305
+ autoUpdateCleanup = null;
1306
+ if (activeTrigger == null) {
1307
+ return;
1308
+ }
1309
+ setDescribedBy(activeTrigger, false);
1310
+ activeTrigger = null;
1311
+ tooltip?.remove();
1312
+ if (activateSkipDelay) {
1313
+ skipDelayUntil = Date.now() + skipDelay;
1314
+ }
1315
+ };
1316
+ const updatePosition = (trigger, floating) => {
1317
+ const request = ++positionRequest;
1318
+ void computePosition(trigger, floating, {
1319
+ middleware: [
1320
+ offset(tooltipGap),
1321
+ flip({ padding: tooltipGap }),
1322
+ shift({ padding: tooltipGap }),
1323
+ size({
1324
+ padding: tooltipGap,
1325
+ apply({ availableHeight, availableWidth, elements }) {
1326
+ elements.floating.style.setProperty(
1327
+ "--tooltip-available-width",
1328
+ \`\${Math.max(0, availableWidth)}px\`,
1329
+ );
1330
+ elements.floating.style.setProperty(
1331
+ "--tooltip-available-height",
1332
+ \`\${Math.max(0, availableHeight)}px\`,
1333
+ );
1334
+ },
1335
+ }),
1336
+ ],
1337
+ placement: getPlacement(trigger),
1338
+ strategy: "fixed",
1339
+ })
1340
+ .then(({ x, y }) => {
1341
+ if (activeTrigger !== trigger || request !== positionRequest) {
1342
+ return;
1343
+ }
1344
+ const scale = window.devicePixelRatio || 1;
1345
+ floating.style.transform = \`translate(\${Math.round(x * scale) / scale}px, \${Math.round(y * scale) / scale}px)\`;
1346
+ floating.style.visibility = "visible";
1347
+ })
1348
+ .catch(() => {
1349
+ if (activeTrigger === trigger && request === positionRequest) {
1350
+ closeTooltip(false);
1351
+ }
1352
+ });
1353
+ };
1354
+ const openTooltip = (trigger) => {
1355
+ const content = getContent(trigger);
1356
+ if (!trigger.isConnected || content.length === 0) {
1357
+ return;
1358
+ }
1359
+ clearOpenTimeout();
1360
+ if (activeTrigger === trigger) {
1361
+ return;
1362
+ }
1363
+ closeTooltip();
1364
+ const floating = getTooltip();
1365
+ floating.textContent = content;
1366
+ floating.style.visibility = "hidden";
1367
+ floating.style.transform = "translate(0, 0)";
1368
+ document.body.appendChild(floating);
1369
+ activeTrigger = trigger;
1370
+ setDescribedBy(trigger, true);
1371
+ autoUpdateCleanup = autoUpdate(trigger, floating, () => {
1372
+ updatePosition(trigger, floating);
1373
+ });
1374
+ };
1375
+ const requestOpen = (trigger, immediate = false) => {
1376
+ if (
1377
+ getContent(trigger).length === 0 ||
1378
+ activeTrigger === trigger ||
1379
+ pendingTrigger === trigger
1380
+ ) {
1381
+ return;
1382
+ }
1383
+ clearOpenTimeout();
1384
+ pendingTrigger = trigger;
1385
+ const delay =
1386
+ immediate || activeTrigger != null || Date.now() < skipDelayUntil ? 0 : hoverDelay;
1387
+ if (delay === 0) {
1388
+ openTooltip(trigger);
1389
+ return;
1390
+ }
1391
+ openTimeout = window.setTimeout(() => {
1392
+ openTimeout = null;
1393
+ pendingTrigger = null;
1394
+ openTooltip(trigger);
1395
+ }, delay);
1396
+ };
1397
+ const handlePointerOpen = (event) => {
1398
+ if (event.pointerType === "touch") {
1399
+ return;
1400
+ }
1401
+ const trigger = getTrigger(event.target);
1402
+ if (trigger == null || containsTarget(trigger, event.relatedTarget)) {
1403
+ return;
1404
+ }
1405
+ requestOpen(trigger);
1406
+ };
1407
+ const handlePointer = (event) => {
1408
+ lastPointerWasTouch = event.type === "pointerdown" && event.pointerType === "touch";
1409
+ };
1410
+ const handleTouchClick = (event) => {
1411
+ const isTouch = event.pointerType === "touch" || lastPointerWasTouch;
1412
+ lastPointerWasTouch = false;
1413
+ if (!isTouch || event.detail === 0) {
1414
+ return;
1415
+ }
1416
+ const trigger = getTrigger(event.target);
1417
+ if (
1418
+ trigger == null ||
1419
+ !trigger.isConnected ||
1420
+ getContent(trigger).length === 0 ||
1421
+ (pinnedByTouch && activeTrigger === trigger)
1422
+ ) {
1423
+ if (pinnedByTouch) {
1424
+ closeTooltip();
1425
+ }
1426
+ return;
1427
+ }
1428
+ openTooltip(trigger);
1429
+ pinnedByTouch = activeTrigger === trigger;
1430
+ window.setTimeout(() => {
1431
+ if (activeTrigger === trigger && !trigger.isConnected) {
1432
+ closeTooltip(false);
1433
+ }
1434
+ }, 0);
1435
+ };
1436
+ const handleLeave = (event) => {
1437
+ if (pinnedByTouch) {
1438
+ return;
1439
+ }
1440
+ const trigger = getTrigger(event.target);
1441
+ if (trigger == null || containsTarget(trigger, event.relatedTarget)) {
1442
+ return;
1443
+ }
1444
+ if (activeTrigger === trigger || pendingTrigger === trigger) {
1445
+ closeTooltip();
1446
+ }
1447
+ };
1448
+ const handleFocusIn = (event) => {
1449
+ const trigger = getTrigger(event.target);
1450
+ if (trigger?.matches(":focus-visible")) {
1451
+ requestOpen(trigger, true);
1452
+ }
1453
+ };
1454
+ const handleKeyDown = (event) => {
1455
+ if (event.key === "Escape") {
1456
+ closeTooltip();
1457
+ }
1458
+ };
1459
+ const handleContextMenu = (event) => {
1460
+ lastPointerWasTouch = false;
1461
+ const trigger = getTrigger(event.target);
1462
+ if (activeTrigger === trigger || pendingTrigger === trigger) {
1463
+ closeTooltip();
1464
+ }
1465
+ };
1466
+ const destroy = () => {
1467
+ closeTooltip(false);
1468
+ lastPointerWasTouch = false;
1469
+ document.removeEventListener("pointerover", handlePointerOpen);
1470
+ document.removeEventListener("pointerdown", handlePointer);
1471
+ document.removeEventListener("pointercancel", handlePointer);
1472
+ document.removeEventListener("click", handleTouchClick);
1473
+ document.removeEventListener("pointerout", handleLeave);
1474
+ document.removeEventListener("focusin", handleFocusIn);
1475
+ document.removeEventListener("focusout", handleLeave);
1476
+ document.removeEventListener("keydown", handleKeyDown);
1477
+ document.removeEventListener("contextmenu", handleContextMenu);
1478
+ tooltip = null;
1479
+ };
1480
+
1481
+ document.addEventListener("pointerover", handlePointerOpen);
1482
+ document.addEventListener("pointerdown", handlePointer);
1483
+ document.addEventListener("pointercancel", handlePointer);
1484
+ document.addEventListener("click", handleTouchClick);
1485
+ document.addEventListener("pointerout", handleLeave);
1486
+ document.addEventListener("focusin", handleFocusIn);
1487
+ document.addEventListener("focusout", handleLeave);
1488
+ document.addEventListener("keydown", handleKeyDown);
1489
+ document.addEventListener("contextmenu", handleContextMenu);
1490
+ window.addEventListener("pagehide", destroy, { once: true });
1491
+ })();
1492
+ </script>
1493
+ <script id="codex-visualization-tabs">
1494
+ (() => {
1495
+ const selector = '.nav[role="tablist"] [role="tab"]';
1496
+ const disabled = ':disabled,[aria-disabled="true"]';
1497
+ const selectTab = (selected) => {
1498
+ const panelId = selected.getAttribute("aria-controls");
1499
+ for (const tab of selected.closest('[role="tablist"]').querySelectorAll('[role="tab"]')) {
1500
+ const active = tab === selected;
1501
+ tab.classList.toggle("active", active);
1502
+ tab.setAttribute("aria-selected", String(active));
1503
+ const id = tab.getAttribute("aria-controls");
1504
+ const panel = id && document.getElementById(id);
1505
+ if (panel != null) {
1506
+ panel.hidden = id !== panelId;
1507
+ if (!panel.hidden && selected.id) {
1508
+ panel.setAttribute("aria-labelledby", selected.id);
1509
+ }
1510
+ }
1511
+ }
1512
+ };
1513
+ const interact = (event) => {
1514
+ const tab = event.target?.closest?.(selector);
1515
+ if (event.defaultPrevented || tab == null || tab.matches(disabled)) {
1516
+ return;
1517
+ }
1518
+ if (event.type === "click") {
1519
+ selectTab(tab);
1520
+ return;
1521
+ }
1522
+ const tabs = Array.from(
1523
+ tab.closest('[role="tablist"]').querySelectorAll('[role="tab"]'),
1524
+ ).filter((candidate) => !candidate.matches(disabled));
1525
+ const current = tabs.indexOf(tab);
1526
+ let next;
1527
+ if (event.key === "ArrowRight" || event.key === "ArrowDown") {
1528
+ next = (current + 1) % tabs.length;
1529
+ } else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
1530
+ next = (current + tabs.length - 1) % tabs.length;
1531
+ } else if (event.key === "Home") {
1532
+ next = 0;
1533
+ } else if (event.key === "End") {
1534
+ next = tabs.length - 1;
1535
+ } else {
1536
+ return;
1537
+ }
1538
+ event.preventDefault();
1539
+ tabs[next].focus();
1540
+ selectTab(tabs[next]);
1541
+ };
1542
+
1543
+ for (const list of document.querySelectorAll('.nav[role="tablist"]')) {
1544
+ const selected =
1545
+ list.querySelector('[role="tab"][aria-selected="true"]') ??
1546
+ list.querySelector('[role="tab"].active') ??
1547
+ list.querySelector('[role="tab"]');
1548
+ if (selected != null) {
1549
+ selectTab(selected);
1550
+ }
1551
+ }
1552
+ document.addEventListener("click", interact);
1553
+ document.addEventListener("keydown", interact);
1554
+ window.addEventListener(
1555
+ "pagehide",
1556
+ () => {
1557
+ document.removeEventListener("click", interact);
1558
+ document.removeEventListener("keydown", interact);
1559
+ },
1560
+ { once: true },
1561
+ );
1562
+ })();
1563
+ </script>
1564
+ <script
1565
+ id="codex-visualization-lucide"
1566
+ async
1567
+ src="https://unpkg.com/lucide@1.17.0/dist/umd/lucide.js"
1568
+ ></script>
1569
+ <script>
1570
+ (() => {
1571
+ const initialize = () => {
1572
+ globalThis.lucide?.createIcons({ attrs: { width: 16, height: 16 } });
1573
+ };
1574
+ if (globalThis.lucide != null) {
1575
+ initialize();
1576
+ return;
1577
+ }
1578
+ document
1579
+ .getElementById("codex-visualization-lucide")
1580
+ ?.addEventListener("load", initialize, { once: true });
1581
+ })();
1582
+ </script>
1583
+ `;
1584
+
1585
+ // src/components/artifacts/inline-html-document.ts
1586
+ function inlineHtmlDocument(fragment) {
1587
+ return '<!doctype html><html><head><meta name="viewport" content="width=device-width,initial-scale=1"><style>' + VISUALIZATION_CSS + "</style><style>html,body{margin:0;min-height:0}body{padding:16px;box-sizing:border-box}</style></head><body>" + fragment + VISUALIZATION_HELPERS + `<script>
1588
+ (()=>{
1589
+ window.addEventListener('message',event=>{
1590
+ if(event.source!==parent||event.data?.type!=='opengeni.preview.theme')return;
1591
+ if(event.data.theme==='light'||event.data.theme==='dark')document.documentElement.style.colorScheme=event.data.theme;
1592
+ previous=0;resize();
1593
+ });
1594
+ let previous=0;
1595
+ const resize=()=>{const height=Math.ceil(document.body.getBoundingClientRect().height);if(height!==previous){previous=height;parent.postMessage({type:'opengeni.preview.height',height},'*')}};
1596
+ new ResizeObserver(resize).observe(document.body);resize();
1597
+ })();
1598
+ </script></body></html>`;
1599
+ }
1600
+
1601
+ // src/components/artifacts/chat-interactive-block.tsx
1602
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1603
+ var INLINE_PREVIEW_HEIGHT = 360;
1604
+ var SITE_PREVIEW_HEIGHT = 400;
1605
+ var PREVIEW_CHROME_HEIGHT = 50;
1606
+ function ChatInteractiveBlock({ labels, ...props }) {
1607
+ return /* @__PURE__ */ jsx3(ArtifactLabelsProvider, { labels, children: /* @__PURE__ */ jsx3(InteractiveBlock, { ...props }) });
1608
+ }
1609
+ function InteractiveBlock(props) {
1610
+ const labels = useArtifactLabels();
1611
+ const height = (props.kind === "html" ? INLINE_PREVIEW_HEIGHT : SITE_PREVIEW_HEIGHT) + PREVIEW_CHROME_HEIGHT;
1612
+ return /* @__PURE__ */ jsx3(
1613
+ DeferredChatMedia,
1614
+ {
1615
+ height,
1616
+ actionLabel: props.kind === "html" ? labels.loadPreview : labels.loadSitePreview,
1617
+ children: /* @__PURE__ */ jsx3("div", { style: { height }, children: /* @__PURE__ */ jsx3(LoadedChatInteractiveBlock, { ...props }) })
1618
+ },
1619
+ `${props.workspaceId}:${props.kind}:${props.kind === "site" ? props.content : "inline"}`
1620
+ );
1621
+ }
1622
+ function LoadedChatInteractiveBlock(props) {
1623
+ const labels = useArtifactLabels();
1624
+ if (props.kind === "html") return /* @__PURE__ */ jsx3(InlineHtml, { ...props });
1625
+ try {
1626
+ const value = JSON.parse(props.content);
1627
+ if (!value || typeof value.siteId !== "string" || !/^[0-9a-f-]{36}$/i.test(value.siteId) || value.versionId !== void 0 && (typeof value.versionId !== "string" || !/^[0-9a-f-]{36}$/i.test(value.versionId)))
1628
+ throw new Error("Invalid Site reference");
1629
+ return /* @__PURE__ */ jsx3(
1630
+ SiteEmbed,
1631
+ {
1632
+ ...props,
1633
+ siteId: value.siteId,
1634
+ initialVersionId: value.versionId
1635
+ },
1636
+ `${props.workspaceId}:${value.siteId}:${value.versionId ?? "current"}`
1637
+ );
1638
+ } catch {
1639
+ return /* @__PURE__ */ jsx3("p", { role: "alert", children: labels.siteReferenceInvalid });
1640
+ }
1641
+ }
1642
+ function InlineHtml({ content, toolBridge, theme }) {
1643
+ const labels = useArtifactLabels();
1644
+ const html = useMemo(() => inlineHtmlDocument(content), [content]);
1645
+ const bridge = useMemo(() => toolBridge?.(), [toolBridge]);
1646
+ return /* @__PURE__ */ jsx3(
1647
+ ArtifactSandbox,
1648
+ {
1649
+ title: labels.preview,
1650
+ showTitle: false,
1651
+ showLiveStatus: false,
1652
+ html,
1653
+ toolBridge: bridge,
1654
+ height: INLINE_PREVIEW_HEIGHT,
1655
+ className: "h-full",
1656
+ fill: true,
1657
+ theme
1658
+ }
1659
+ );
1660
+ }
1661
+ function SiteEmbed(props) {
1662
+ const [versionId, setVersionId] = useState3(props.initialVersionId);
1663
+ return /* @__PURE__ */ jsx3(
1664
+ SiteEmbedContent,
1665
+ {
1666
+ ...props,
1667
+ versionId,
1668
+ onVersionChange: setVersionId
1669
+ },
1670
+ versionId ?? "current"
1671
+ );
1672
+ }
1673
+ function SiteEmbedContent({
1674
+ workspaceId,
1675
+ client,
1676
+ toolBridge,
1677
+ theme,
1678
+ siteId,
1679
+ versionId,
1680
+ onVersionChange
1681
+ }) {
1682
+ const [loaded, setLoaded] = useState3(null);
1683
+ const snapshot = loaded?.client === client ? loaded.snapshot : null;
1684
+ const [error, setError] = useState3(false);
1685
+ const [retry, setRetry] = useState3(0);
1686
+ useEffect2(() => {
1687
+ const abort = new AbortController();
1688
+ setError(false);
1689
+ setLoaded(null);
1690
+ void loadSiteSnapshot(client, workspaceId, siteId, {
1691
+ signal: abort.signal,
1692
+ ...versionId ? { versionId } : {}
1693
+ }).then((value) => {
1694
+ if (!abort.signal.aborted) setLoaded({ client, snapshot: value });
1695
+ }).catch(() => {
1696
+ if (!abort.signal.aborted) setError(true);
1697
+ });
1698
+ return () => abort.abort();
1699
+ }, [client, workspaceId, siteId, versionId, retry]);
1700
+ const content = snapshot?.content;
1701
+ const bridge = useMemo(
1702
+ () => content ? toolBridge?.({
1703
+ artifactId: siteId,
1704
+ siteVersionId: content.versionId,
1705
+ requestedTools: content.requestedTools
1706
+ }) : void 0,
1707
+ [toolBridge, siteId, content]
1708
+ );
1709
+ const open = useOpenGeniLinkResolver()?.({ kind: "site", artifactId: siteId, workspaceId });
1710
+ const labels = useArtifactLabels();
1711
+ if (error)
1712
+ return /* @__PURE__ */ jsxs2("p", { role: "alert", children: [
1713
+ labels.siteLoadFailed,
1714
+ " ",
1715
+ /* @__PURE__ */ jsx3(ArtifactButton, { size: "sm", onClick: () => setRetry((v) => v + 1), children: labels.retry })
1716
+ ] });
1717
+ if (!snapshot) return /* @__PURE__ */ jsx3("p", { role: "status", children: labels.loadingSite });
1718
+ if (!content) return /* @__PURE__ */ jsx3("p", { children: labels.siteUnpublished });
1719
+ return /* @__PURE__ */ jsx3(
1720
+ ArtifactSandbox,
1721
+ {
1722
+ title: snapshot.detail.artifact.title,
1723
+ html: content.html,
1724
+ toolBridge: bridge,
1725
+ height: SITE_PREVIEW_HEIGHT,
1726
+ className: "h-full",
1727
+ fill: true,
1728
+ theme,
1729
+ headerControls: /* @__PURE__ */ jsxs2(Fragment, { children: [
1730
+ snapshot.detail.versions.length > 1 || !snapshot.detail.versions.some((v) => v.id === content.versionId) ? /* @__PURE__ */ jsxs2(
1731
+ ArtifactSelect,
1732
+ {
1733
+ "aria-label": labels.siteVersion,
1734
+ className: "bg-transparent text-xs",
1735
+ value: content.versionId,
1736
+ onChange: (e) => onVersionChange(e.target.value),
1737
+ children: [
1738
+ !snapshot.detail.versions.some((v) => v.id === content.versionId) && /* @__PURE__ */ jsx3("option", { value: content.versionId, children: labels.savedVersion }),
1739
+ snapshot.detail.versions.map((v) => /* @__PURE__ */ jsx3("option", { value: v.id, children: labels.version(v.revision) }, v.id))
1740
+ ]
1741
+ }
1742
+ ) : null,
1743
+ open?.href ? /* @__PURE__ */ jsx3(
1744
+ "a",
1745
+ {
1746
+ className: "shrink-0 whitespace-nowrap text-xs underline",
1747
+ href: open.href,
1748
+ "data-og-open-site": "",
1749
+ children: labels.openSite
1750
+ }
1751
+ ) : open?.open ? /* @__PURE__ */ jsx3(
1752
+ "button",
1753
+ {
1754
+ type: "button",
1755
+ className: "shrink-0 cursor-pointer whitespace-nowrap text-xs underline",
1756
+ "data-og-open-site": "",
1757
+ onClick: () => void Promise.resolve().then(open.open).catch(() => void 0),
1758
+ children: labels.openSite
1759
+ }
1760
+ ) : null
1761
+ ] })
1762
+ }
1763
+ );
1764
+ }
1765
+
1766
+ export {
1767
+ ArtifactSandbox,
1768
+ DeferredChatMedia,
1769
+ inlineHtmlDocument,
1770
+ ChatInteractiveBlock
1771
+ };
1772
+ //# sourceMappingURL=chunk-YBXQDQFX.js.map