@opengeni/react 7.4.0-canary.36844267522001 → 7.4.0

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 (113) hide show
  1. package/README.md +0 -10
  2. package/dist/artifacts-document.js +2 -3
  3. package/dist/artifacts-presentation.js +2 -3
  4. package/dist/artifacts-spreadsheet.js +2 -2
  5. package/dist/artifacts.d.ts +0 -1
  6. package/dist/artifacts.js +1402 -505
  7. package/dist/artifacts.js.map +1 -1
  8. package/dist/{browser-viewer-AJO7LMVE.js → browser-viewer-2E6R2Y4W.js} +2 -2
  9. package/dist/{chunk-WUISZ3WU.js → chunk-3E2AITTZ.js} +28 -32
  10. package/dist/{chunk-WUISZ3WU.js.map → chunk-3E2AITTZ.js.map} +1 -1
  11. package/dist/{chunk-Y2PRMYLC.js → chunk-DUEBTL3N.js} +3 -4
  12. package/dist/{chunk-Y2PRMYLC.js.map → chunk-DUEBTL3N.js.map} +1 -1
  13. package/dist/{chunk-7UAMYXJY.js → chunk-KNDIXZN6.js} +18 -25
  14. package/dist/{chunk-7UAMYXJY.js.map → chunk-KNDIXZN6.js.map} +1 -1
  15. package/dist/{chunk-XVYRQ4PK.js → chunk-L4OSXQ6H.js} +116 -277
  16. package/dist/chunk-L4OSXQ6H.js.map +1 -0
  17. package/dist/{chunk-7B44WVGH.js → chunk-S5JQ4R22.js} +12 -31
  18. package/dist/chunk-S5JQ4R22.js.map +1 -0
  19. package/dist/{chunk-A4UJB2MM.js → chunk-SEEVCT36.js} +2 -2
  20. package/dist/chunk-UGMKPUEM.js +299 -0
  21. package/dist/chunk-UGMKPUEM.js.map +1 -0
  22. package/dist/{chunk-OQVBTOBJ.js → chunk-USXVQACU.js} +3 -3
  23. package/dist/{chunk-ASCSKOWU.js → chunk-V2ABIVYJ.js} +3 -50
  24. package/dist/chunk-V2ABIVYJ.js.map +1 -0
  25. package/dist/{chunk-UQUR5WG5.js → chunk-X4HIN6TV.js} +157 -66
  26. package/dist/chunk-X4HIN6TV.js.map +1 -0
  27. package/dist/{chunk-QLG6W33X.js → chunk-XEJEOAOV.js} +35 -46
  28. package/dist/chunk-XEJEOAOV.js.map +1 -0
  29. package/dist/components/artifacts/editable-artifact-ui.d.ts +1 -2
  30. package/dist/components/artifacts/index.d.ts +0 -7
  31. package/dist/components/message-timeline.d.ts +1 -7
  32. package/dist/components/open-geni-links.d.ts +0 -16
  33. package/dist/components/session-conversation.d.ts +1 -13
  34. package/dist/{computer-viewer-NB6O6BTV.js → computer-viewer-WMJE6OA3.js} +2 -2
  35. package/dist/connect.js +1 -2
  36. package/dist/connect.js.map +1 -1
  37. package/dist/hooks/latest-question.d.ts +1 -1
  38. package/dist/index.d.ts +2 -3
  39. package/dist/index.js +12 -22
  40. package/dist/index.js.map +1 -1
  41. package/dist/interaction.js +2 -2
  42. package/dist/{latest-question-3HGQUI2E.js → latest-question-QB4EUCW5.js} +2 -2
  43. package/dist/{markdown-table-layout-QXSLK4BY.js → markdown-table-layout-PFUEZ2U4.js} +5 -37
  44. package/dist/markdown-table-layout-PFUEZ2U4.js.map +1 -0
  45. package/dist/session-ui.d.ts +2 -3
  46. package/dist/session-ui.js +9 -18
  47. package/dist/session-ui.js.map +1 -1
  48. package/dist/session.js +2 -2
  49. package/dist/sites.js +289 -4
  50. package/dist/sites.js.map +1 -1
  51. package/package.json +3 -3
  52. package/src/artifacts.ts +0 -37
  53. package/src/components/artifacts/editable-artifact-ui.tsx +1 -3
  54. package/src/components/artifacts/editable-artifact-workbench.tsx +2 -5
  55. package/src/components/artifacts/editable-document.tsx +36 -34
  56. package/src/components/artifacts/editable-presentation.tsx +16 -21
  57. package/src/components/artifacts/index.ts +0 -41
  58. package/src/components/browser-viewer.tsx +20 -59
  59. package/src/components/computer-viewer.tsx +23 -51
  60. package/src/components/markdown-table-layout.ts +5 -49
  61. package/src/components/markdown.tsx +2 -5
  62. package/src/components/message-timeline.tsx +7 -59
  63. package/src/components/open-geni-links.tsx +0 -24
  64. package/src/components/session-conversation.tsx +20 -120
  65. package/src/index.ts +0 -7
  66. package/src/session-ui.ts +0 -7
  67. package/src/timeline/projection.ts +4 -54
  68. package/styles/compiled.css +0 -220
  69. package/dist/chat-interactive-block-VAGABN7J.js +0 -11
  70. package/dist/chunk-5CVXZA3Y.js +0 -292
  71. package/dist/chunk-5CVXZA3Y.js.map +0 -1
  72. package/dist/chunk-7B44WVGH.js.map +0 -1
  73. package/dist/chunk-ASCSKOWU.js.map +0 -1
  74. package/dist/chunk-QLG6W33X.js.map +0 -1
  75. package/dist/chunk-RAIQYITC.js +0 -1772
  76. package/dist/chunk-RAIQYITC.js.map +0 -1
  77. package/dist/chunk-SCOTPE2I.js +0 -589
  78. package/dist/chunk-SCOTPE2I.js.map +0 -1
  79. package/dist/chunk-UQUR5WG5.js.map +0 -1
  80. package/dist/chunk-WEHMPOXK.js +0 -39
  81. package/dist/chunk-WEHMPOXK.js.map +0 -1
  82. package/dist/chunk-XCHWDJ22.js +0 -107
  83. package/dist/chunk-XCHWDJ22.js.map +0 -1
  84. package/dist/chunk-XVYRQ4PK.js.map +0 -1
  85. package/dist/components/artifacts/artifact-chrome.d.ts +0 -120
  86. package/dist/components/artifacts/artifact-sandbox.d.ts +0 -27
  87. package/dist/components/artifacts/chat-interactive-block.d.ts +0 -29
  88. package/dist/components/artifacts/deferred-chat-media.d.ts +0 -15
  89. package/dist/components/artifacts/editable-artifact-view.d.ts +0 -46
  90. package/dist/components/artifacts/latest-task-runner.d.ts +0 -15
  91. package/dist/components/artifacts/session-artifact-viewer.d.ts +0 -39
  92. package/dist/components/artifacts/site-view.d.ts +0 -23
  93. package/dist/components/timeline-pill-geometry.d.ts +0 -6
  94. package/dist/components/timeline-pill-placement.d.ts +0 -18
  95. package/dist/computer-viewer-NB6O6BTV.js.map +0 -1
  96. package/dist/markdown-table-layout-QXSLK4BY.js.map +0 -1
  97. package/dist/timeline-pill-geometry-2G6EK47V.js +0 -73
  98. package/dist/timeline-pill-geometry-2G6EK47V.js.map +0 -1
  99. package/src/components/artifacts/artifact-chrome.tsx +0 -413
  100. package/src/components/artifacts/artifact-sandbox.tsx +0 -185
  101. package/src/components/artifacts/chat-interactive-block.tsx +0 -260
  102. package/src/components/artifacts/deferred-chat-media.tsx +0 -67
  103. package/src/components/artifacts/editable-artifact-view.tsx +0 -187
  104. package/src/components/artifacts/latest-task-runner.ts +0 -49
  105. package/src/components/artifacts/session-artifact-viewer.tsx +0 -376
  106. package/src/components/artifacts/site-view.tsx +0 -116
  107. package/src/components/timeline-pill-geometry.ts +0 -112
  108. package/src/components/timeline-pill-placement.ts +0 -81
  109. /package/dist/{browser-viewer-AJO7LMVE.js.map → browser-viewer-2E6R2Y4W.js.map} +0 -0
  110. /package/dist/{chunk-A4UJB2MM.js.map → chunk-SEEVCT36.js.map} +0 -0
  111. /package/dist/{chunk-OQVBTOBJ.js.map → chunk-USXVQACU.js.map} +0 -0
  112. /package/dist/{chat-interactive-block-VAGABN7J.js.map → computer-viewer-WMJE6OA3.js.map} +0 -0
  113. /package/dist/{latest-question-3HGQUI2E.js.map → latest-question-QB4EUCW5.js.map} +0 -0
package/dist/artifacts.js CHANGED
@@ -1,163 +1,1431 @@
1
- import {
2
- ArtifactSandbox,
3
- ChatInteractiveBlock,
4
- DeferredChatMedia,
5
- inlineHtmlDocument
6
- } from "./chunk-RAIQYITC.js";
7
1
  import {
8
2
  EditableSpreadsheetArtifactSurface,
9
3
  EditableSpreadsheetGrid,
10
4
  SpreadsheetArtifactSurface,
11
5
  SpreadsheetGrid,
12
6
  SpreadsheetProjectionGrid
13
- } from "./chunk-A4UJB2MM.js";
7
+ } from "./chunk-SEEVCT36.js";
14
8
  import {
15
9
  PUBLISHED_HTML_ARTIFACT_IFRAME_SANDBOX,
16
10
  PublishedHtmlArtifactFrame,
17
- loadSiteSnapshot,
18
11
  openGeniSiteBridgePortFromBootstrap,
19
12
  publishedHtmlArtifactDocument
20
- } from "./chunk-SCOTPE2I.js";
13
+ } from "./chunk-UGMKPUEM.js";
21
14
  import {
22
15
  EditablePresentationArtifactSurface,
23
16
  PresentationArtifactSurface,
24
17
  PresentationEditor,
25
18
  PresentationProjectionArtifactSurface,
26
19
  PresentationProjectionEditor
27
- } from "./chunk-7UAMYXJY.js";
20
+ } from "./chunk-KNDIXZN6.js";
28
21
  import {
29
22
  isRetainedImageContentType,
30
23
  useRetainedImageObjectUrl
31
24
  } from "./chunk-FZCP527Y.js";
32
- import {
33
- ArtifactBadge,
34
- ArtifactButton,
35
- ArtifactLabelsProvider,
36
- ArtifactLoading,
37
- ArtifactProblem,
38
- ArtifactSelect,
39
- ArtifactViewerHeader,
40
- DEFAULT_ARTIFACT_LABELS,
41
- artifactKindIcon,
42
- artifactKindSubtitle,
43
- artifactLoadErrorMessage,
44
- artifactLoadErrorView,
45
- useArtifactLabels
46
- } from "./chunk-5CVXZA3Y.js";
47
25
  import "./chunk-ERGYJIBB.js";
48
- import {
49
- useOpenGeni
50
- } from "./chunk-NEXLLTP4.js";
51
- import "./chunk-XCHWDJ22.js";
52
26
  import {
53
27
  DocumentArtifactSurface,
54
28
  DocumentEditor,
55
29
  DocumentProjectionArtifactSurface,
56
30
  DocumentProjectionEditor,
57
31
  EditableDocumentArtifactSurface
58
- } from "./chunk-WUISZ3WU.js";
59
- import "./chunk-WEHMPOXK.js";
32
+ } from "./chunk-3E2AITTZ.js";
60
33
  import {
61
34
  ArtifactSurface,
62
35
  EditableArtifactMessage
63
- } from "./chunk-Y2PRMYLC.js";
64
- import {
65
- cn
66
- } from "./chunk-22KP6LR5.js";
36
+ } from "./chunk-DUEBTL3N.js";
37
+ import "./chunk-22KP6LR5.js";
67
38
 
68
- // src/components/artifacts/site-view.tsx
69
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
70
- import { jsx } from "react/jsx-runtime";
71
- function SiteView({
72
- client,
73
- workspaceId,
74
- siteId,
75
- toolBridge,
76
- theme,
77
- archivedMessage,
78
- showTitle = true,
79
- loadingLabel,
80
- onTitle,
81
- className
82
- }) {
83
- const labels = useArtifactLabels();
84
- const [snapshot, setSnapshot] = useState(null);
85
- const [error, setError] = useState(null);
86
- const readAbort = useRef(null);
87
- const onTitleRef = useRef(onTitle);
88
- onTitleRef.current = onTitle;
89
- const load = useCallback(async () => {
90
- readAbort.current?.abort();
91
- const abort = new AbortController();
92
- readAbort.current = abort;
93
- try {
94
- setError(null);
95
- const next = await loadSiteSnapshot(client, workspaceId, siteId, {
96
- signal: abort.signal,
97
- includeArchivedContent: true
98
- });
99
- if (abort.signal.aborted) return;
100
- setSnapshot(next);
101
- onTitleRef.current?.(next.detail.artifact.title);
102
- } catch (nextError) {
103
- if (abort.signal.aborted) return;
104
- setSnapshot(null);
105
- setError(nextError);
106
- }
107
- }, [client, siteId, workspaceId]);
108
- useEffect(() => {
109
- setSnapshot(null);
110
- void load();
111
- return () => readAbort.current?.abort();
112
- }, [load]);
113
- const content = snapshot?.content;
114
- const bridge = useMemo(
115
- () => content ? toolBridge?.({
116
- artifactId: siteId,
117
- siteVersionId: content.versionId,
118
- requestedTools: content.requestedTools
119
- }) : void 0,
120
- [content, siteId, toolBridge]
39
+ // src/components/artifacts/visualization-assets.gen.ts
40
+ var VISUALIZATION_CSS = `/* Adapted from Codex visualize 1.0.32; shared with the OpenGeni visualization skill. */
41
+ :root {
42
+ color-scheme: light dark;
43
+ background-color: var(
44
+ --background,
45
+ var(--color-background-primary, light-dark(rgb(255 255 255), rgb(24 24 24)))
46
+ ) !important;
47
+
48
+ /* Agent-facing contract; keep in sync with SKILL.md. */
49
+ --background: var(
50
+ --color-background-primary,
51
+ light-dark(rgb(255 255 255), rgb(24 24 24))
121
52
  );
122
- if (error)
123
- return /* @__PURE__ */ jsx(
124
- ArtifactProblem,
125
- {
126
- view: artifactLoadErrorView(error, "site", labels),
127
- onRetry: () => void load()
53
+ --foreground: var(
54
+ --color-text-primary,
55
+ light-dark(rgb(26 28 31), rgb(255 255 255))
56
+ );
57
+ --card: color-mix(in oklab, var(--foreground) 5%, var(--background));
58
+ --card-foreground: var(
59
+ --color-text-primary,
60
+ light-dark(rgb(26 28 31), rgb(255 255 255))
61
+ );
62
+ --popover: var(
63
+ --color-background-secondary,
64
+ light-dark(rgb(255 255 255), rgb(45 45 45))
65
+ );
66
+ --popover-foreground: var(
67
+ --color-text-primary,
68
+ light-dark(rgb(26 28 31), rgb(255 255 255))
69
+ );
70
+ --primary: var(
71
+ --color-text-info,
72
+ light-dark(rgb(51 156 255), rgb(131 195 255))
73
+ );
74
+ --primary-foreground: var(
75
+ --color-text-inverse,
76
+ light-dark(rgb(255 255 255), rgb(13 13 13))
77
+ );
78
+ --secondary: var(
79
+ --color-background-secondary,
80
+ light-dark(rgb(255 255 255 / 96%), rgb(54 54 54 / 96%))
81
+ );
82
+ --secondary-foreground: var(
83
+ --color-text-primary,
84
+ light-dark(rgb(26 28 31), rgb(255 255 255))
85
+ );
86
+ --muted: color-mix(in srgb, var(--foreground) 10%, transparent);
87
+ --muted-foreground: var(
88
+ --color-text-secondary,
89
+ light-dark(rgb(26 28 31 / 49.4%), rgb(255 255 255 / 49.8%))
90
+ );
91
+ --accent: var(
92
+ --color-background-info,
93
+ light-dark(rgb(229 242 255), rgb(13 39 63))
94
+ );
95
+ --accent-foreground: var(
96
+ --color-text-info,
97
+ light-dark(rgb(51 156 255), rgb(131 195 255))
98
+ );
99
+ --destructive: var(
100
+ --color-text-warning,
101
+ light-dark(rgb(226 85 7), rgb(255 133 73))
102
+ );
103
+ --border: var(
104
+ --color-border-secondary,
105
+ light-dark(rgb(26 28 31 / 8%), rgb(255 255 255 / 8.2%))
106
+ );
107
+ --input: var(
108
+ --color-border-primary,
109
+ light-dark(
110
+ rgb(26 28 31 / 11.8%),
111
+ color-mix(in oklab, rgb(0 0 0) 10%, transparent)
112
+ )
113
+ );
114
+ --ring: var(
115
+ --color-ring-primary,
116
+ light-dark(rgb(51 156 255), rgb(131 195 255 / 76%))
117
+ );
118
+ --font-size-base: var(--font-text-md-size, 14px);
119
+ --blue: light-dark(rgb(51 156 255), rgb(51 156 255));
120
+ --orange: light-dark(rgb(226 85 7), rgb(251 106 34));
121
+ --green: light-dark(rgb(0 162 64), rgb(64 201 119));
122
+ --red: light-dark(rgb(224 46 42), rgb(255 103 100));
123
+ --purple: light-dark(rgb(146 79 247), rgb(173 123 249));
124
+ --yellow: light-dark(rgb(255 195 0), rgb(255 210 64));
125
+ --viz-series-1: var(--primary);
126
+ --viz-series-2: light-dark(rgb(243 136 59), rgb(245 154 86));
127
+ --viz-series-3: light-dark(rgb(93 201 119), rgb(116 213 139));
128
+ --viz-series-4: light-dark(rgb(235 119 177), rgb(240 143 192));
129
+ --viz-series-5: light-dark(rgb(155 121 236), rgb(170 145 239));
130
+ --viz-series-6: light-dark(rgb(58 185 177), rgb(90 203 194));
131
+
132
+ /* Internal implementation variables; not part of the agent contract. */
133
+ --font-sans: -apple-system, system-ui, "Segoe UI", sans-serif;
134
+ --font-mono:
135
+ ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono",
136
+ monospace;
137
+ --font-size-normal: max(11px, var(--font-size-base));
138
+ --font-size-tooltip: calc(var(--font-size-base) - 1px);
139
+ --font-size-small: max(11px, calc(var(--font-size-base) - 2px));
140
+ --font-size-h1: calc(var(--font-size-normal) * 1.7142857143);
141
+ --font-size-h2: calc(var(--font-size-normal) * 1.4285714286);
142
+ --font-size-h3: calc(var(--font-size-normal) * 1.2857142857);
143
+ --font-weight-normal: 430;
144
+ --font-weight-medium: 500;
145
+ --icon-size: 16px;
146
+ --line-height-normal: calc(var(--font-size-normal) * 1.5);
147
+ --line-height-tooltip: calc(var(--font-size-tooltip) * 1.4285714286);
148
+ --line-height-small: calc(var(--font-size-small) + 4px);
149
+ --corner-shape: round;
150
+ --radius: var(--border-radius-lg, 10px);
151
+ --radius-sm: calc(var(--radius) * 0.6);
152
+ --radius-md: calc(var(--radius) * 0.8);
153
+ --radius-lg: var(--radius);
154
+ --radius-2xl: calc(var(--radius) * 1.6);
155
+ --radius-full: 9999px;
156
+ --shadow-sm: 0 1px 2px -1px rgb(0 0 0 / 8%);
157
+ --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");
158
+
159
+ /* Legacy aliases; not part of the current agent contract. */
160
+ --viz-bg: transparent;
161
+ --viz-panel: var(--card);
162
+ --viz-border: var(--border);
163
+ --viz-text: var(--foreground);
164
+ --viz-muted: var(--muted-foreground);
165
+ --viz-accent: var(--primary);
166
+ --viz-accent-text: var(--primary-foreground);
167
+ --viz-accent-bg: var(--accent);
168
+ --viz-font-size: var(--font-size-base);
169
+ --viz-warning: var(--destructive);
170
+ }
171
+
172
+ :root[data-theme="light"] {
173
+ color-scheme: light;
174
+ }
175
+
176
+ :root[data-theme="dark"] {
177
+ color-scheme: dark;
178
+ }
179
+
180
+ * {
181
+ box-sizing: border-box;
182
+ }
183
+
184
+ html > body {
185
+ /* Preserve MCP aliases for older inline renderers without creating :root cycles. */
186
+ --color-background-primary: var(
187
+ --background,
188
+ light-dark(rgb(255 255 255), rgb(24 24 24))
189
+ );
190
+ --color-text-primary: var(
191
+ --foreground,
192
+ light-dark(rgb(26 28 31), rgb(255 255 255))
193
+ );
194
+ --color-border-secondary: var(
195
+ --border,
196
+ light-dark(rgb(26 28 31 / 8%), rgb(255 255 255 / 8.2%))
197
+ );
198
+
199
+ margin: 0;
200
+ padding: var(--visualize-paint-gutter, 16px);
201
+ color: var(--foreground);
202
+ background: transparent !important;
203
+ font-family: var(--font-sans) !important;
204
+ font-size: var(--font-size-normal);
205
+ font-weight: var(--font-weight-normal);
206
+ line-height: var(--line-height-normal);
207
+ }
208
+
209
+ a {
210
+ color: color-mix(in srgb, var(--viz-accent) 80%, var(--viz-text) 20%);
211
+ cursor: pointer;
212
+ font-weight: var(--font-weight-medium, 500);
213
+ text-decoration: none;
214
+ text-underline-offset: 2px;
215
+ }
216
+
217
+ a:is(:hover, :focus-visible) {
218
+ text-decoration-line: underline;
219
+ text-decoration-style: dashed;
220
+ text-decoration-thickness: 0.5px;
221
+ }
222
+
223
+ h1,
224
+ h2,
225
+ h3,
226
+ h4,
227
+ h5,
228
+ h6,
229
+ p {
230
+ margin-block: 0;
231
+ }
232
+
233
+ h1 {
234
+ font-size: var(--font-size-h1);
235
+ font-weight: var(--font-weight-medium);
236
+ line-height: 1.25;
237
+ }
238
+
239
+ h2 {
240
+ font-size: var(--font-size-h2);
241
+ font-weight: var(--font-weight-medium);
242
+ line-height: 1.25;
243
+ }
244
+
245
+ h3,
246
+ h4,
247
+ h5,
248
+ h6 {
249
+ font-size: var(--font-size-h3);
250
+ font-weight: var(--font-weight-medium);
251
+ line-height: 1.3;
252
+ }
253
+
254
+ b,
255
+ strong,
256
+ th {
257
+ font-weight: var(--font-weight-medium);
258
+ }
259
+
260
+ code:not(pre code) {
261
+ display: inline;
262
+ padding: 1px 6px;
263
+ border-radius: var(--radius-sm);
264
+ corner-shape: var(--corner-shape);
265
+ background: var(--muted);
266
+ font-family: var(--font-mono);
267
+ font-size: 0.92em;
268
+ overflow-wrap: anywhere;
269
+ -webkit-box-decoration-break: clone;
270
+ box-decoration-break: clone;
271
+ word-break: break-word;
272
+ }
273
+
274
+ .table-responsive {
275
+ width: 100%;
276
+ overflow-x: auto;
277
+ scrollbar-width: thin;
278
+ }
279
+
280
+ .table {
281
+ width: 100%;
282
+ border-collapse: collapse;
283
+ color: var(--foreground);
284
+ font: inherit;
285
+ text-align: start;
286
+ }
287
+
288
+ .table :is(th, td) {
289
+ padding-block: 10px;
290
+ padding-inline: 0 24px;
291
+ overflow-wrap: anywhere;
292
+ border-bottom: 1px solid var(--border);
293
+ text-align: start;
294
+ vertical-align: top;
295
+ }
296
+
297
+ .table-responsive > .table :is(th, td) {
298
+ overflow-wrap: break-word;
299
+ }
300
+
301
+ .table :is(th, td):last-child {
302
+ padding-inline-end: 0;
303
+ }
304
+
305
+ .table :is(caption, thead th) {
306
+ font-weight: 600;
307
+ }
308
+
309
+ .table thead th {
310
+ padding-block: 8px;
311
+ border-bottom-color: color-mix(in srgb, var(--foreground) 16%, transparent);
312
+ }
313
+
314
+ .table tbody tr:last-child :is(th, td) {
315
+ border-bottom: 0;
316
+ }
317
+
318
+ .table.table-sm :is(th, td) {
319
+ padding-block: 6px;
320
+ }
321
+
322
+ .table.table-sm :is(th, td):not(:last-child) {
323
+ padding-inline-end: 16px;
324
+ }
325
+
326
+ .table :is(.text-end, [align="right"]) {
327
+ text-align: end;
328
+ font-variant-numeric: tabular-nums;
329
+ }
330
+
331
+ .table :is(.text-center, [align="center"]) {
332
+ text-align: center;
333
+ }
334
+
335
+ .table .text-nowrap {
336
+ white-space: nowrap;
337
+ }
338
+
339
+ #widget {
340
+ display: flex;
341
+ flex-direction: column;
342
+ gap: 12px;
343
+ width: 100%;
344
+ padding: 0;
345
+ background: transparent !important;
346
+ }
347
+
348
+ .card {
349
+ min-width: 0;
350
+ padding: 12px;
351
+ overflow: hidden;
352
+ overflow-wrap: break-word;
353
+ border-radius: var(--radius-2xl);
354
+ corner-shape: var(--corner-shape);
355
+ color: var(--card-foreground);
356
+ background: var(--card);
357
+ }
358
+
359
+ #widget > :not(.card, .progress) {
360
+ width: 100% !important;
361
+ max-width: none !important;
362
+ margin: 0 !important;
363
+ padding: 0 !important;
364
+ border: 0 !important;
365
+ border-radius: 0 !important;
366
+ background: transparent !important;
367
+ box-shadow: none !important;
368
+ }
369
+
370
+ .tooltip {
371
+ position: fixed;
372
+ z-index: 50;
373
+ top: 0;
374
+ left: 0;
375
+ width: max-content;
376
+ max-width: min(
377
+ 20rem,
378
+ var(--tooltip-available-width, calc(100vw - 10px)),
379
+ calc(100vw - 10px)
380
+ );
381
+ max-height: min(
382
+ var(--tooltip-available-height, calc(100vh - 10px)),
383
+ calc(100vh - 10px)
384
+ );
385
+ padding: 4px 8px;
386
+ border: 1px solid var(--border);
387
+ border-radius: var(--radius-lg);
388
+ corner-shape: var(--corner-shape);
389
+ color: var(--popover-foreground);
390
+ background: var(--popover);
391
+ box-shadow: none;
392
+ font-size: var(--font-size-tooltip);
393
+ line-height: var(--line-height-tooltip);
394
+ overflow-wrap: break-word;
395
+ white-space: normal;
396
+ pointer-events: none;
397
+ user-select: none;
398
+ }
399
+
400
+ .viz-grid {
401
+ display: grid;
402
+ grid-template-columns: repeat(auto-fit, minmax(max(180px, 24%), 1fr));
403
+ gap: 10px;
404
+ }
405
+
406
+ .viz-stat {
407
+ display: flex;
408
+ flex-direction: column;
409
+ gap: 2px;
410
+ }
411
+
412
+ .viz-stat-value {
413
+ font-size: var(--font-size-h2);
414
+ font-weight: var(--font-weight-medium);
415
+ line-height: 1.25;
416
+ }
417
+
418
+ .viz-row {
419
+ display: flex;
420
+ flex-wrap: wrap;
421
+ align-items: center;
422
+ gap: 10px;
423
+ }
424
+
425
+ hr {
426
+ width: 100%;
427
+ height: 1px;
428
+ margin-block: 6px;
429
+ border: 0;
430
+ background: var(--border);
431
+ }
432
+
433
+ .nav {
434
+ display: flex;
435
+ min-width: 0;
436
+ align-items: center;
437
+ gap: 4px;
438
+ }
439
+
440
+ .progress {
441
+ display: flex;
442
+ height: 8px;
443
+ margin-block: calc((var(--line-height-normal, 1.5em) - 8px) / 2);
444
+ overflow: hidden;
445
+ border: 0;
446
+ border-radius: var(--radius-full);
447
+ background: var(--muted);
448
+ }
449
+
450
+ .progress-bar:only-child {
451
+ border-radius: var(--radius-full);
452
+ }
453
+
454
+ .progress-bar {
455
+ height: 100%;
456
+ flex-shrink: 0;
457
+ border: 0;
458
+ background: var(--viz-series-1);
459
+ }
460
+
461
+ .viz-badge {
462
+ padding: 3px 8px;
463
+ border-radius: var(--radius-full);
464
+ color: var(--accent-foreground);
465
+ background: var(--accent);
466
+ font-weight: var(--font-weight-medium);
467
+ }
468
+
469
+ small,
470
+ .text-small,
471
+ .viz-badge {
472
+ font-size: var(--font-size-small);
473
+ line-height: var(--line-height-small);
474
+ }
475
+
476
+ .text-muted {
477
+ color: var(--muted-foreground);
478
+ }
479
+
480
+ .tabular-nums {
481
+ font-variant-numeric: tabular-nums;
482
+ }
483
+
484
+ .sr-only {
485
+ position: absolute;
486
+ width: 1px;
487
+ height: 1px;
488
+ padding: 0;
489
+ overflow: hidden;
490
+ clip: rect(0, 0, 0, 0);
491
+ white-space: nowrap;
492
+ border: 0;
493
+ }
494
+
495
+ .viz-controls {
496
+ display: flex;
497
+ flex-wrap: wrap;
498
+ align-items: center;
499
+ gap: 8px;
500
+ }
501
+
502
+ .viz-controls > .form-label {
503
+ display: grid;
504
+ min-width: min(100%, 260px);
505
+ flex: 1 1 280px;
506
+ grid-template-columns: minmax(0, 1fr) auto;
507
+ align-items: baseline;
508
+ gap: 2px 12px;
509
+ margin-bottom: 0;
510
+ }
511
+
512
+ .viz-controls > .form-label > :is(.form-control, .form-range, .form-select) {
513
+ grid-column: 1 / -1;
514
+ }
515
+
516
+ .btn,
517
+ .nav-link,
518
+ .form-check-input,
519
+ .form-control,
520
+ .form-range,
521
+ .form-select {
522
+ font: inherit;
523
+ }
524
+
525
+ .btn,
526
+ .nav-link {
527
+ appearance: button;
528
+ display: inline-flex;
529
+ inline-size: fit-content;
530
+ max-inline-size: 100%;
531
+ min-height: 28px;
532
+ align-items: center;
533
+ justify-content: center;
534
+ gap: 4px;
535
+ margin: 0;
536
+ padding: 0 8px;
537
+ -webkit-app-region: no-drag;
538
+ border: 1px solid var(--input);
539
+ border-radius: var(--radius-lg);
540
+ corner-shape: var(--corner-shape);
541
+ color: var(--secondary-foreground);
542
+ background: var(--secondary);
543
+ cursor: var(--cursor-interaction, pointer);
544
+ text-align: center;
545
+ text-decoration: none;
546
+ white-space: nowrap;
547
+ user-select: none;
548
+ -webkit-font-smoothing: antialiased;
549
+ }
550
+
551
+ .btn:is(.btn-block, .viz-tile) {
552
+ inline-size: 100%;
553
+ }
554
+
555
+ .btn.viz-tile {
556
+ min-width: 0;
557
+ overflow-wrap: anywhere;
558
+ white-space: normal;
559
+ }
560
+
561
+ a.btn {
562
+ cursor: pointer;
563
+ text-decoration: none;
564
+ }
565
+
566
+ .btn:not(:disabled):hover,
567
+ .nav-link:not(:disabled):not([aria-disabled="true"]):hover {
568
+ background: color-mix(in srgb, var(--foreground) 6%, var(--secondary));
569
+ }
570
+
571
+ .btn-primary {
572
+ border-color: transparent;
573
+ color: var(--primary-foreground);
574
+ background: var(--foreground);
575
+ background-clip: padding-box;
576
+ }
577
+
578
+ .btn-primary .text-muted {
579
+ color: color-mix(in srgb, var(--primary-foreground) 50%, transparent);
580
+ }
581
+
582
+ .btn-primary:not(:disabled):hover {
583
+ background: color-mix(in srgb, var(--foreground) 80%, transparent);
584
+ background-clip: padding-box;
585
+ }
586
+
587
+ .btn-ghost {
588
+ border-color: transparent;
589
+ color: var(--muted-foreground);
590
+ background: transparent;
591
+ }
592
+
593
+ .btn-ghost:not(:disabled):hover {
594
+ color: var(--foreground);
595
+ background: color-mix(in srgb, var(--foreground) 6%, var(--secondary));
596
+ }
597
+
598
+ .nav-pills .nav-link {
599
+ min-width: 0;
600
+ border-color: transparent;
601
+ color: var(--muted-foreground);
602
+ background: transparent;
603
+ }
604
+
605
+ .nav-justified .nav-link {
606
+ flex: 1 1 0;
607
+ overflow-wrap: anywhere;
608
+ white-space: normal;
609
+ }
610
+
611
+ .nav-pills .nav-link.active {
612
+ color: var(--foreground);
613
+ background: var(--muted);
614
+ }
615
+
616
+ .btn:disabled,
617
+ .nav-link:disabled,
618
+ .nav-link[aria-disabled="true"] {
619
+ cursor: not-allowed;
620
+ opacity: 0.4;
621
+ }
622
+
623
+ [data-lucide] {
624
+ stroke-width: 1.6;
625
+ }
626
+
627
+ .form-label {
628
+ display: block;
629
+ margin-bottom: 6px;
630
+ color: var(--foreground);
631
+ }
632
+
633
+ .form-control {
634
+ display: block;
635
+ width: 100%;
636
+ min-height: 28px;
637
+ padding: 0 8px;
638
+ outline: none;
639
+ border: 1px solid var(--input);
640
+ border-radius: var(--radius-lg);
641
+ corner-shape: var(--corner-shape);
642
+ color: var(--foreground);
643
+ background: var(--secondary);
644
+ }
645
+
646
+ .form-control::placeholder {
647
+ color: var(--muted-foreground);
648
+ }
649
+
650
+ .form-control[type="file"] {
651
+ padding: 0;
652
+ overflow: hidden;
653
+ cursor: var(--cursor-interaction, pointer);
654
+ }
655
+
656
+ .form-control[type="file"]::file-selector-button {
657
+ min-height: 26px;
658
+ margin-right: 8px;
659
+ padding: 0 8px;
660
+ border: 0;
661
+ border-right: 1px solid var(--input);
662
+ color: var(--secondary-foreground);
663
+ background: var(--secondary);
664
+ cursor: inherit;
665
+ font: inherit;
666
+ }
667
+
668
+ .form-control[type="file"]:not(:disabled):hover::file-selector-button {
669
+ background: color-mix(in srgb, var(--foreground) 6%, var(--secondary));
670
+ }
671
+
672
+ .form-control-color[type="color"] {
673
+ width: 40px;
674
+ height: 28px;
675
+ padding: 3px;
676
+ cursor: var(--cursor-interaction, pointer);
677
+ }
678
+
679
+ .form-control-color[type="color"]::-webkit-color-swatch-wrapper {
680
+ padding: 0;
681
+ }
682
+
683
+ .form-control-color[type="color"]::-webkit-color-swatch {
684
+ border: 0;
685
+ border-radius: calc(var(--radius-lg) - 4px);
686
+ corner-shape: var(--corner-shape);
687
+ }
688
+
689
+ textarea.form-control {
690
+ height: auto;
691
+ min-height: 72px;
692
+ padding: 8px 10px;
693
+ resize: vertical;
694
+ }
695
+
696
+ .form-control:focus-visible {
697
+ border-color: var(--ring);
698
+ box-shadow: inset 0 0 0 1px var(--ring);
699
+ }
700
+
701
+ .form-control:disabled,
702
+ .form-select:disabled {
703
+ cursor: not-allowed;
704
+ opacity: 0.4;
705
+ }
706
+
707
+ .form-select {
708
+ appearance: none;
709
+ display: block;
710
+ width: 100%;
711
+ min-height: 28px;
712
+ margin: 0;
713
+ padding: 0 32px 0 8px;
714
+ outline: none;
715
+ border: 1px solid var(--input);
716
+ border-radius: var(--radius-lg);
717
+ corner-shape: var(--corner-shape);
718
+ color: var(--foreground);
719
+ background-color: var(--secondary);
720
+ background-image:
721
+ linear-gradient(45deg, transparent 50%, var(--muted-foreground) 50%),
722
+ linear-gradient(135deg, var(--muted-foreground) 50%, transparent 50%);
723
+ background-position:
724
+ calc(100% - 14px) 50%,
725
+ calc(100% - 10px) 50%;
726
+ background-repeat: no-repeat;
727
+ background-size: 4px 4px;
728
+ cursor: var(--cursor-interaction, default);
729
+ }
730
+
731
+ .form-select:not(:disabled):hover {
732
+ background-color: color-mix(in srgb, var(--foreground) 6%, var(--secondary));
733
+ }
734
+
735
+ .form-select:focus-visible {
736
+ border-color: var(--ring);
737
+ box-shadow: inset 0 0 0 1px var(--ring);
738
+ }
739
+
740
+ .form-check {
741
+ display: flex;
742
+ min-height: 20px;
743
+ align-items: center;
744
+ gap: 6px;
745
+ }
746
+
747
+ .form-check-input {
748
+ appearance: none;
749
+ width: 14px;
750
+ height: 14px;
751
+ flex: 0 0 auto;
752
+ margin: 0;
753
+ border: 1px solid var(--input);
754
+ color: var(--primary-foreground);
755
+ background-color: transparent;
756
+ cursor: var(--cursor-interaction, default);
757
+ transition:
758
+ background-color 150ms,
759
+ border-color 150ms,
760
+ box-shadow 150ms;
761
+ }
762
+
763
+ .form-check:not(.form-switch) .form-check-input[type="checkbox"] {
764
+ border-color: var(--input);
765
+ border-radius: var(--radius-sm);
766
+ corner-shape: var(--corner-shape);
767
+ background-color: var(--secondary);
768
+ box-shadow: var(--shadow-sm);
769
+ }
770
+
771
+ .form-check:not(.form-switch)
772
+ .form-check-input:not(:disabled):not(:checked):hover {
773
+ background-color: var(--card);
774
+ }
775
+
776
+ .form-check:not(.form-switch) .form-check-input[type="checkbox"]:checked {
777
+ border-color: var(--primary);
778
+ background-color: var(--primary);
779
+ }
780
+
781
+ .form-check:not(.form-switch)
782
+ .form-check-input[type="checkbox"]:checked::before {
783
+ display: block;
784
+ width: 100%;
785
+ height: 100%;
786
+ background: var(--primary-foreground);
787
+ content: "";
788
+ mask: var(--checkmark-image) center / 12px 12px no-repeat;
789
+ }
790
+
791
+ .form-check-input[type="radio"] {
792
+ width: 14px;
793
+ height: 14px;
794
+ border-radius: var(--radius-full);
795
+ }
796
+
797
+ .form-check-input[type="radio"]:checked {
798
+ border: 2px solid var(--primary);
799
+ background:
800
+ radial-gradient(circle, var(--primary-foreground) 0 2.5px, transparent 3px),
801
+ var(--primary);
802
+ }
803
+
804
+ .form-check:not(.form-switch) .form-check-input:focus-visible {
805
+ outline: 2px solid var(--ring);
806
+ outline-offset: 2px;
807
+ }
808
+
809
+ .form-check:not(.form-switch) .form-check-input:disabled {
810
+ cursor: not-allowed;
811
+ pointer-events: none;
812
+ }
813
+
814
+ .form-check:not(.form-switch) .form-check-input:disabled + .form-check-label {
815
+ cursor: not-allowed;
816
+ }
817
+
818
+ .form-switch .form-check-input:disabled,
819
+ .form-switch .form-check-input:disabled + .form-check-label {
820
+ cursor: not-allowed;
821
+ opacity: 0.6;
822
+ }
823
+
824
+ .form-check-label {
825
+ color: var(--foreground);
826
+ cursor: var(--cursor-interaction, default);
827
+ }
828
+
829
+ .form-switch .form-check-input {
830
+ position: relative;
831
+ width: 32px;
832
+ height: 20px;
833
+ border: 0;
834
+ border-radius: var(--radius-full);
835
+ background: var(--muted);
836
+ box-shadow: none;
837
+ transition: background-color 200ms cubic-bezier(0, 0, 0.2, 1);
838
+ }
839
+
840
+ .form-switch .form-check-input::before {
841
+ position: absolute;
842
+ top: 50%;
843
+ left: 0;
844
+ width: 16px;
845
+ height: 16px;
846
+ box-sizing: border-box;
847
+ border: 1px solid light-dark(var(--primary-foreground), var(--foreground));
848
+ border-radius: var(--radius-full);
849
+ background: light-dark(var(--primary-foreground), var(--foreground));
850
+ box-shadow: var(--shadow-sm);
851
+ content: "";
852
+ transform: translate(2px, -50%);
853
+ transition: transform 200ms cubic-bezier(0, 0, 0.2, 1);
854
+ }
855
+
856
+ .form-switch .form-check-input:checked {
857
+ background: var(--primary);
858
+ }
859
+
860
+ .form-switch .form-check-input:checked::before {
861
+ transform: translate(14px, -50%);
862
+ }
863
+
864
+ .form-switch .form-check-input:focus-visible {
865
+ box-shadow: 0 0 0 2px var(--ring);
866
+ }
867
+
868
+ .form-range {
869
+ appearance: none;
870
+ display: block;
871
+ width: 100%;
872
+ height: 28px;
873
+ flex: 1;
874
+ margin: 0;
875
+ padding: 0;
876
+ outline: none;
877
+ border: 0;
878
+ accent-color: var(--primary);
879
+ background: linear-gradient(
880
+ color-mix(in srgb, var(--foreground) 7%, transparent),
881
+ color-mix(in srgb, var(--foreground) 7%, transparent)
882
+ )
883
+ center / 100% 2px no-repeat;
884
+ }
885
+
886
+ .form-range::-webkit-slider-runnable-track {
887
+ height: 28px;
888
+ background: transparent;
889
+ }
890
+
891
+ .form-range::-webkit-slider-thumb {
892
+ appearance: none;
893
+ width: 20px;
894
+ height: 20px;
895
+ margin-top: 4px;
896
+ border: 1px solid var(--border);
897
+ border-radius: var(--radius-full);
898
+ background: light-dark(var(--primary-foreground), var(--foreground));
899
+ }
900
+
901
+ .form-range:focus-visible::-webkit-slider-thumb {
902
+ border-color: var(--ring);
903
+ box-shadow: inset 0 0 0 1px var(--ring);
904
+ }
905
+
906
+ .form-range::-moz-range-track {
907
+ height: 28px;
908
+ background: transparent;
909
+ }
910
+
911
+ .form-range::-moz-range-thumb {
912
+ width: 20px;
913
+ height: 20px;
914
+ border: 1px solid var(--border);
915
+ border-radius: var(--radius-full);
916
+ background: light-dark(var(--primary-foreground), var(--foreground));
917
+ }
918
+
919
+ .form-range:focus-visible::-moz-range-thumb {
920
+ border-color: var(--ring);
921
+ box-shadow: inset 0 0 0 1px var(--ring);
922
+ }
923
+
924
+ .form-range:disabled {
925
+ cursor: not-allowed;
926
+ opacity: 0.4;
927
+ }
928
+
929
+ .btn:not(.btn-primary, .viz-tile):is(
930
+ [aria-pressed="true"],
931
+ [aria-selected="true"],
932
+ .is-selected
933
+ ) {
934
+ border-color: var(--primary);
935
+ color: var(--primary-foreground);
936
+ background: var(--primary);
937
+ }
938
+
939
+ .btn.viz-tile:is([aria-pressed="true"], [aria-selected="true"], .is-selected) {
940
+ border-color: var(--primary);
941
+ box-shadow: inset 0 0 0 1px var(--primary);
942
+ }
943
+
944
+ .btn:focus-visible,
945
+ .nav-link:focus-visible {
946
+ outline: 2px solid var(--ring);
947
+ outline-offset: 2px;
948
+ }
949
+
950
+ @media (pointer: coarse) {
951
+ .btn,
952
+ .nav-link,
953
+ .form-control,
954
+ .form-select {
955
+ min-width: 44px;
956
+ min-height: 44px;
957
+ }
958
+
959
+ /* Keep small-screen WebKit from zooming when a text field receives focus. */
960
+ .form-control,
961
+ .form-select {
962
+ font-size: max(16px, var(--font-size-normal));
963
+ }
964
+
965
+ .form-control[type="file"]::file-selector-button {
966
+ min-width: 44px;
967
+ min-height: 44px;
968
+ }
969
+
970
+ .form-control-color[type="color"] {
971
+ width: 44px;
972
+ height: 44px;
973
+ }
974
+
975
+ .form-control:is(
976
+ [type="date"],
977
+ [type="datetime-local"],
978
+ [type="month"],
979
+ [type="time"],
980
+ [type="week"]
981
+ ) {
982
+ min-width: 0;
983
+ max-width: 100%;
984
+ padding-block: 8px;
985
+ }
986
+
987
+ .form-check {
988
+ min-height: 44px;
989
+ padding-inline: 15px;
990
+ }
991
+
992
+ .form-check-input {
993
+ position: relative;
994
+ }
995
+
996
+ .form-check-input::after {
997
+ position: absolute;
998
+ top: 50%;
999
+ left: 50%;
1000
+ width: 44px;
1001
+ height: 44px;
1002
+ content: "";
1003
+ transform: translate(-50%, -50%);
1004
+ }
1005
+
1006
+ .form-check-label {
1007
+ display: inline-flex;
1008
+ min-width: 44px;
1009
+ min-height: 44px;
1010
+ align-items: center;
1011
+ }
1012
+
1013
+ .form-range {
1014
+ height: 44px;
1015
+ touch-action: pan-y;
1016
+ }
1017
+
1018
+ .form-range::-webkit-slider-runnable-track {
1019
+ height: 44px;
1020
+ }
1021
+
1022
+ .form-range::-moz-range-track {
1023
+ height: 44px;
1024
+ }
1025
+
1026
+ .form-range::-webkit-slider-thumb {
1027
+ margin-top: 12px;
1028
+ }
1029
+ }
1030
+
1031
+ svg {
1032
+ display: block;
1033
+ max-width: 100%;
1034
+ height: auto;
1035
+ }
1036
+
1037
+ #widget > svg {
1038
+ width: 100%;
1039
+ }
1040
+
1041
+ /* Model-authored chart rules can otherwise stretch icons after these styles load. */
1042
+ svg.lucide {
1043
+ display: block;
1044
+ width: var(--icon-size) !important;
1045
+ height: var(--icon-size) !important;
1046
+ flex: none;
1047
+ margin: 0 !important;
1048
+ stroke-width: 1.6;
1049
+ }
1050
+
1051
+ .text-warning,
1052
+ .text-destructive {
1053
+ color: var(--destructive);
1054
+ }
1055
+ `;
1056
+ var VISUALIZATION_HELPERS = `
1057
+ <script src="https://unpkg.com/@floating-ui/core@1.7.3/dist/floating-ui.core.umd.min.js"></script>
1058
+ <script src="https://unpkg.com/@floating-ui/dom@1.7.4/dist/floating-ui.dom.umd.min.js"></script>
1059
+ <script>
1060
+ (() => {
1061
+ if (window.FloatingUIDOM == null) {
1062
+ return;
1063
+ }
1064
+ const { autoUpdate, computePosition, flip, offset, shift, size } = window.FloatingUIDOM;
1065
+ const tooltipPlacements = new Set(["top", "right", "bottom", "left"]);
1066
+ const tooltipId = \`codex-visualization-tooltip-\${
1067
+ window.crypto?.randomUUID?.() ?? Date.now().toString(36)
1068
+ }\`;
1069
+ const tooltipGap = 5;
1070
+ const hoverDelay = 700;
1071
+ const skipDelay = 300;
1072
+ let activeTrigger = null;
1073
+ let pendingTrigger = null;
1074
+ let tooltip = null;
1075
+ let openTimeout = null;
1076
+ let autoUpdateCleanup = null;
1077
+ let positionRequest = 0;
1078
+ let skipDelayUntil = 0;
1079
+ let lastPointerWasTouch = false;
1080
+ let pinnedByTouch = false;
1081
+
1082
+ const getTrigger = (target) =>
1083
+ target?.nodeType === Node.ELEMENT_NODE ? target.closest("[data-tooltip]") : null;
1084
+ const containsTarget = (trigger, target) =>
1085
+ target?.nodeType != null && trigger.contains(target);
1086
+ const getContent = (trigger) => trigger.getAttribute("data-tooltip")?.trim() ?? "";
1087
+ const getPlacement = (trigger) => {
1088
+ const placement = trigger.getAttribute("data-tooltip-placement");
1089
+ return tooltipPlacements.has(placement) ? placement : "top";
1090
+ };
1091
+ const getTooltip = () => {
1092
+ if (tooltip == null) {
1093
+ tooltip = document.createElement("div");
1094
+ tooltip.id = tooltipId;
1095
+ tooltip.className = "tooltip";
1096
+ tooltip.setAttribute("role", "tooltip");
1097
+ }
1098
+ return tooltip;
1099
+ };
1100
+ const setDescribedBy = (trigger, described) => {
1101
+ const ids = new Set(
1102
+ (trigger.getAttribute("aria-describedby") ?? "").split(/\\s+/).filter(Boolean),
1103
+ );
1104
+ if (described) {
1105
+ ids.add(tooltipId);
1106
+ } else {
1107
+ ids.delete(tooltipId);
1108
+ }
1109
+ if (ids.size === 0) {
1110
+ trigger.removeAttribute("aria-describedby");
1111
+ } else {
1112
+ trigger.setAttribute("aria-describedby", [...ids].join(" "));
1113
+ }
1114
+ };
1115
+ const clearOpenTimeout = () => {
1116
+ if (openTimeout != null) {
1117
+ window.clearTimeout(openTimeout);
1118
+ openTimeout = null;
1119
+ }
1120
+ pendingTrigger = null;
1121
+ };
1122
+ const closeTooltip = (activateSkipDelay = true) => {
1123
+ clearOpenTimeout();
1124
+ pinnedByTouch = false;
1125
+ positionRequest += 1;
1126
+ autoUpdateCleanup?.();
1127
+ autoUpdateCleanup = null;
1128
+ if (activeTrigger == null) {
1129
+ return;
1130
+ }
1131
+ setDescribedBy(activeTrigger, false);
1132
+ activeTrigger = null;
1133
+ tooltip?.remove();
1134
+ if (activateSkipDelay) {
1135
+ skipDelayUntil = Date.now() + skipDelay;
1136
+ }
1137
+ };
1138
+ const updatePosition = (trigger, floating) => {
1139
+ const request = ++positionRequest;
1140
+ void computePosition(trigger, floating, {
1141
+ middleware: [
1142
+ offset(tooltipGap),
1143
+ flip({ padding: tooltipGap }),
1144
+ shift({ padding: tooltipGap }),
1145
+ size({
1146
+ padding: tooltipGap,
1147
+ apply({ availableHeight, availableWidth, elements }) {
1148
+ elements.floating.style.setProperty(
1149
+ "--tooltip-available-width",
1150
+ \`\${Math.max(0, availableWidth)}px\`,
1151
+ );
1152
+ elements.floating.style.setProperty(
1153
+ "--tooltip-available-height",
1154
+ \`\${Math.max(0, availableHeight)}px\`,
1155
+ );
1156
+ },
1157
+ }),
1158
+ ],
1159
+ placement: getPlacement(trigger),
1160
+ strategy: "fixed",
1161
+ })
1162
+ .then(({ x, y }) => {
1163
+ if (activeTrigger !== trigger || request !== positionRequest) {
1164
+ return;
1165
+ }
1166
+ const scale = window.devicePixelRatio || 1;
1167
+ floating.style.transform = \`translate(\${Math.round(x * scale) / scale}px, \${Math.round(y * scale) / scale}px)\`;
1168
+ floating.style.visibility = "visible";
1169
+ })
1170
+ .catch(() => {
1171
+ if (activeTrigger === trigger && request === positionRequest) {
1172
+ closeTooltip(false);
1173
+ }
1174
+ });
1175
+ };
1176
+ const openTooltip = (trigger) => {
1177
+ const content = getContent(trigger);
1178
+ if (!trigger.isConnected || content.length === 0) {
1179
+ return;
1180
+ }
1181
+ clearOpenTimeout();
1182
+ if (activeTrigger === trigger) {
1183
+ return;
1184
+ }
1185
+ closeTooltip();
1186
+ const floating = getTooltip();
1187
+ floating.textContent = content;
1188
+ floating.style.visibility = "hidden";
1189
+ floating.style.transform = "translate(0, 0)";
1190
+ document.body.appendChild(floating);
1191
+ activeTrigger = trigger;
1192
+ setDescribedBy(trigger, true);
1193
+ autoUpdateCleanup = autoUpdate(trigger, floating, () => {
1194
+ updatePosition(trigger, floating);
1195
+ });
1196
+ };
1197
+ const requestOpen = (trigger, immediate = false) => {
1198
+ if (
1199
+ getContent(trigger).length === 0 ||
1200
+ activeTrigger === trigger ||
1201
+ pendingTrigger === trigger
1202
+ ) {
1203
+ return;
1204
+ }
1205
+ clearOpenTimeout();
1206
+ pendingTrigger = trigger;
1207
+ const delay =
1208
+ immediate || activeTrigger != null || Date.now() < skipDelayUntil ? 0 : hoverDelay;
1209
+ if (delay === 0) {
1210
+ openTooltip(trigger);
1211
+ return;
1212
+ }
1213
+ openTimeout = window.setTimeout(() => {
1214
+ openTimeout = null;
1215
+ pendingTrigger = null;
1216
+ openTooltip(trigger);
1217
+ }, delay);
1218
+ };
1219
+ const handlePointerOpen = (event) => {
1220
+ if (event.pointerType === "touch") {
1221
+ return;
128
1222
  }
1223
+ const trigger = getTrigger(event.target);
1224
+ if (trigger == null || containsTarget(trigger, event.relatedTarget)) {
1225
+ return;
1226
+ }
1227
+ requestOpen(trigger);
1228
+ };
1229
+ const handlePointer = (event) => {
1230
+ lastPointerWasTouch = event.type === "pointerdown" && event.pointerType === "touch";
1231
+ };
1232
+ const handleTouchClick = (event) => {
1233
+ const isTouch = event.pointerType === "touch" || lastPointerWasTouch;
1234
+ lastPointerWasTouch = false;
1235
+ if (!isTouch || event.detail === 0) {
1236
+ return;
1237
+ }
1238
+ const trigger = getTrigger(event.target);
1239
+ if (
1240
+ trigger == null ||
1241
+ !trigger.isConnected ||
1242
+ getContent(trigger).length === 0 ||
1243
+ (pinnedByTouch && activeTrigger === trigger)
1244
+ ) {
1245
+ if (pinnedByTouch) {
1246
+ closeTooltip();
1247
+ }
1248
+ return;
1249
+ }
1250
+ openTooltip(trigger);
1251
+ pinnedByTouch = activeTrigger === trigger;
1252
+ window.setTimeout(() => {
1253
+ if (activeTrigger === trigger && !trigger.isConnected) {
1254
+ closeTooltip(false);
1255
+ }
1256
+ }, 0);
1257
+ };
1258
+ const handleLeave = (event) => {
1259
+ if (pinnedByTouch) {
1260
+ return;
1261
+ }
1262
+ const trigger = getTrigger(event.target);
1263
+ if (trigger == null || containsTarget(trigger, event.relatedTarget)) {
1264
+ return;
1265
+ }
1266
+ if (activeTrigger === trigger || pendingTrigger === trigger) {
1267
+ closeTooltip();
1268
+ }
1269
+ };
1270
+ const handleFocusIn = (event) => {
1271
+ const trigger = getTrigger(event.target);
1272
+ if (trigger?.matches(":focus-visible")) {
1273
+ requestOpen(trigger, true);
1274
+ }
1275
+ };
1276
+ const handleKeyDown = (event) => {
1277
+ if (event.key === "Escape") {
1278
+ closeTooltip();
1279
+ }
1280
+ };
1281
+ const handleContextMenu = (event) => {
1282
+ lastPointerWasTouch = false;
1283
+ const trigger = getTrigger(event.target);
1284
+ if (activeTrigger === trigger || pendingTrigger === trigger) {
1285
+ closeTooltip();
1286
+ }
1287
+ };
1288
+ const destroy = () => {
1289
+ closeTooltip(false);
1290
+ lastPointerWasTouch = false;
1291
+ document.removeEventListener("pointerover", handlePointerOpen);
1292
+ document.removeEventListener("pointerdown", handlePointer);
1293
+ document.removeEventListener("pointercancel", handlePointer);
1294
+ document.removeEventListener("click", handleTouchClick);
1295
+ document.removeEventListener("pointerout", handleLeave);
1296
+ document.removeEventListener("focusin", handleFocusIn);
1297
+ document.removeEventListener("focusout", handleLeave);
1298
+ document.removeEventListener("keydown", handleKeyDown);
1299
+ document.removeEventListener("contextmenu", handleContextMenu);
1300
+ tooltip = null;
1301
+ };
1302
+
1303
+ document.addEventListener("pointerover", handlePointerOpen);
1304
+ document.addEventListener("pointerdown", handlePointer);
1305
+ document.addEventListener("pointercancel", handlePointer);
1306
+ document.addEventListener("click", handleTouchClick);
1307
+ document.addEventListener("pointerout", handleLeave);
1308
+ document.addEventListener("focusin", handleFocusIn);
1309
+ document.addEventListener("focusout", handleLeave);
1310
+ document.addEventListener("keydown", handleKeyDown);
1311
+ document.addEventListener("contextmenu", handleContextMenu);
1312
+ window.addEventListener("pagehide", destroy, { once: true });
1313
+ })();
1314
+ </script>
1315
+ <script id="codex-visualization-tabs">
1316
+ (() => {
1317
+ const selector = '.nav[role="tablist"] [role="tab"]';
1318
+ const disabled = ':disabled,[aria-disabled="true"]';
1319
+ const selectTab = (selected) => {
1320
+ const panelId = selected.getAttribute("aria-controls");
1321
+ for (const tab of selected.closest('[role="tablist"]').querySelectorAll('[role="tab"]')) {
1322
+ const active = tab === selected;
1323
+ tab.classList.toggle("active", active);
1324
+ tab.setAttribute("aria-selected", String(active));
1325
+ const id = tab.getAttribute("aria-controls");
1326
+ const panel = id && document.getElementById(id);
1327
+ if (panel != null) {
1328
+ panel.hidden = id !== panelId;
1329
+ if (!panel.hidden && selected.id) {
1330
+ panel.setAttribute("aria-labelledby", selected.id);
1331
+ }
1332
+ }
1333
+ }
1334
+ };
1335
+ const interact = (event) => {
1336
+ const tab = event.target?.closest?.(selector);
1337
+ if (event.defaultPrevented || tab == null || tab.matches(disabled)) {
1338
+ return;
1339
+ }
1340
+ if (event.type === "click") {
1341
+ selectTab(tab);
1342
+ return;
1343
+ }
1344
+ const tabs = Array.from(
1345
+ tab.closest('[role="tablist"]').querySelectorAll('[role="tab"]'),
1346
+ ).filter((candidate) => !candidate.matches(disabled));
1347
+ const current = tabs.indexOf(tab);
1348
+ let next;
1349
+ if (event.key === "ArrowRight" || event.key === "ArrowDown") {
1350
+ next = (current + 1) % tabs.length;
1351
+ } else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
1352
+ next = (current + tabs.length - 1) % tabs.length;
1353
+ } else if (event.key === "Home") {
1354
+ next = 0;
1355
+ } else if (event.key === "End") {
1356
+ next = tabs.length - 1;
1357
+ } else {
1358
+ return;
1359
+ }
1360
+ event.preventDefault();
1361
+ tabs[next].focus();
1362
+ selectTab(tabs[next]);
1363
+ };
1364
+
1365
+ for (const list of document.querySelectorAll('.nav[role="tablist"]')) {
1366
+ const selected =
1367
+ list.querySelector('[role="tab"][aria-selected="true"]') ??
1368
+ list.querySelector('[role="tab"].active') ??
1369
+ list.querySelector('[role="tab"]');
1370
+ if (selected != null) {
1371
+ selectTab(selected);
1372
+ }
1373
+ }
1374
+ document.addEventListener("click", interact);
1375
+ document.addEventListener("keydown", interact);
1376
+ window.addEventListener(
1377
+ "pagehide",
1378
+ () => {
1379
+ document.removeEventListener("click", interact);
1380
+ document.removeEventListener("keydown", interact);
1381
+ },
1382
+ { once: true },
129
1383
  );
130
- if (!snapshot || !content) return /* @__PURE__ */ jsx(ArtifactLoading, { label: loadingLabel ?? labels.loadingSite });
131
- if (snapshot.detail.artifact.status === "archived")
132
- return /* @__PURE__ */ jsx("div", { className: "p-4 text-sm text-fg-muted", children: archivedMessage ?? labels.siteArchived });
133
- return /* @__PURE__ */ jsx(
134
- ArtifactSandbox,
135
- {
136
- html: content.html,
137
- title: snapshot.detail.artifact.title,
138
- showTitle,
139
- versionLabel: `v${snapshot.detail.artifact.currentVersion?.revision}`,
140
- toolBridge: bridge,
141
- connectedToolCount: content.requestedTools.length,
142
- theme,
143
- fill: true,
144
- className: className ?? "h-full rounded-none border-0"
1384
+ })();
1385
+ </script>
1386
+ <script
1387
+ id="codex-visualization-lucide"
1388
+ async
1389
+ src="https://unpkg.com/lucide@1.17.0/dist/umd/lucide.js"
1390
+ ></script>
1391
+ <script>
1392
+ (() => {
1393
+ const initialize = () => {
1394
+ globalThis.lucide?.createIcons({ attrs: { width: 16, height: 16 } });
1395
+ };
1396
+ if (globalThis.lucide != null) {
1397
+ initialize();
1398
+ return;
145
1399
  }
146
- );
147
- }
1400
+ document
1401
+ .getElementById("codex-visualization-lucide")
1402
+ ?.addEventListener("load", initialize, { once: true });
1403
+ })();
1404
+ </script>
1405
+ `;
148
1406
 
149
- // src/components/artifacts/editable-artifact-view.tsx
150
- import {
151
- createBrowserEditableArtifactSession as createBrowserEditableArtifactSession2
152
- } from "@opengeni/sdk/editable-artifacts";
153
- import { useCallback as useCallback3, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef3, useState as useState3 } from "react";
1407
+ // src/components/artifacts/inline-html-document.ts
1408
+ function inlineHtmlDocument(fragment) {
1409
+ 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>
1410
+ (()=>{
1411
+ window.addEventListener('message',event=>{
1412
+ if(event.source!==parent||event.data?.type!=='opengeni.preview.theme')return;
1413
+ if(event.data.theme==='light'||event.data.theme==='dark')document.documentElement.style.colorScheme=event.data.theme;
1414
+ previous=0;resize();
1415
+ });
1416
+ let previous=0;
1417
+ const resize=()=>{const height=Math.ceil(document.body.getBoundingClientRect().height);if(height!==previous){previous=height;parent.postMessage({type:'opengeni.preview.height',height},'*')}};
1418
+ new ResizeObserver(resize).observe(document.body);resize();
1419
+ })();
1420
+ </script></body></html>`;
1421
+ }
154
1422
 
155
1423
  // src/components/artifacts/editable-artifact-workbench.tsx
156
1424
  import {
157
1425
  createBrowserEditableArtifactSession
158
1426
  } from "@opengeni/sdk/editable-artifacts";
159
- import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
160
- import { jsx as jsx2 } from "react/jsx-runtime";
1427
+ import { useCallback, useEffect, useRef, useState } from "react";
1428
+ import { jsx } from "react/jsx-runtime";
161
1429
  function EditableArtifactWorkbench({
162
1430
  session,
163
1431
  document,
@@ -166,7 +1434,7 @@ function EditableArtifactWorkbench({
166
1434
  }) {
167
1435
  switch (session.modality) {
168
1436
  case "document":
169
- return /* @__PURE__ */ jsx2(
1437
+ return /* @__PURE__ */ jsx(
170
1438
  EditableDocumentArtifactSurface,
171
1439
  {
172
1440
  ...document,
@@ -175,9 +1443,9 @@ function EditableArtifactWorkbench({
175
1443
  }
176
1444
  );
177
1445
  case "spreadsheet":
178
- return /* @__PURE__ */ jsx2(EditableSpreadsheetArtifactSurface, { ...spreadsheet, session });
1446
+ return /* @__PURE__ */ jsx(EditableSpreadsheetArtifactSurface, { ...spreadsheet, session });
179
1447
  case "presentation":
180
- return /* @__PURE__ */ jsx2(EditablePresentationArtifactSurface, { ...presentation, session });
1448
+ return /* @__PURE__ */ jsx(EditablePresentationArtifactSurface, { ...presentation, session });
181
1449
  }
182
1450
  }
183
1451
  function EditableArtifactWorkbenchHost({
@@ -187,13 +1455,13 @@ function EditableArtifactWorkbenchHost({
187
1455
  spreadsheet,
188
1456
  presentation
189
1457
  }) {
190
- const createSessionRef = useRef2(createSession);
191
- const [retryEpoch, setRetryEpoch] = useState2(0);
192
- const [state, setState] = useState2({ key: null, session: null, error: null });
193
- useEffect2(() => {
1458
+ const createSessionRef = useRef(createSession);
1459
+ const [retryEpoch, setRetryEpoch] = useState(0);
1460
+ const [state, setState] = useState({ key: null, session: null, error: null });
1461
+ useEffect(() => {
194
1462
  createSessionRef.current = createSession;
195
1463
  }, [createSession]);
196
- useEffect2(() => {
1464
+ useEffect(() => {
197
1465
  let owned = null;
198
1466
  setState({ key: sessionKey, session: null, error: null });
199
1467
  try {
@@ -212,11 +1480,10 @@ function EditableArtifactWorkbenchHost({
212
1480
  if (closing) void closing.close().catch(() => void 0);
213
1481
  };
214
1482
  }, [retryEpoch, sessionKey]);
215
- const retry = useCallback2(() => setRetryEpoch((value) => value + 1), []);
216
- const labels = useArtifactLabels();
1483
+ const retry = useCallback(() => setRetryEpoch((value) => value + 1), []);
217
1484
  const currentError = state.key === sessionKey ? state.error : null;
218
1485
  if (state.key === sessionKey && state.session) {
219
- return /* @__PURE__ */ jsx2(
1486
+ return /* @__PURE__ */ jsx(
220
1487
  EditableArtifactWorkbench,
221
1488
  {
222
1489
  session: state.session,
@@ -226,13 +1493,12 @@ function EditableArtifactWorkbenchHost({
226
1493
  }
227
1494
  );
228
1495
  }
229
- return /* @__PURE__ */ jsx2(
1496
+ return /* @__PURE__ */ jsx(
230
1497
  EditableArtifactMessage,
231
1498
  {
232
- title: currentError ? labels.editableErrors.transient.title : labels.opening,
233
- detail: currentError?.message ?? labels.startingEditor,
234
- retry: currentError ? retry : void 0,
235
- retryLabel: labels.retry
1499
+ title: currentError ? "Could not open this artifact" : "Opening artifact",
1500
+ detail: currentError?.message ?? "Starting the secure editing session\u2026",
1501
+ retry: currentError ? retry : void 0
236
1502
  }
237
1503
  );
238
1504
  }
@@ -243,8 +1509,8 @@ function BrowserEditableArtifactWorkbench({
243
1509
  presentation
244
1510
  }) {
245
1511
  const sessionKey = browserSessionKey(options);
246
- const createSession = useCallback2(() => createBrowserEditableArtifactSession(options), [options]);
247
- return /* @__PURE__ */ jsx2(
1512
+ const createSession = useCallback(() => createBrowserEditableArtifactSession(options), [options]);
1513
+ return /* @__PURE__ */ jsx(
248
1514
  EditableArtifactWorkbenchHost,
249
1515
  {
250
1516
  sessionKey,
@@ -275,375 +1541,13 @@ function browserSessionKey(options) {
275
1541
  (_key, value) => value instanceof URL ? value.href : value
276
1542
  );
277
1543
  }
278
-
279
- // src/components/artifacts/editable-artifact-view.tsx
280
- import { jsx as jsx3 } from "react/jsx-runtime";
281
- function EditableArtifactView({
282
- baseUrl,
283
- workspaceId,
284
- artifactId,
285
- open,
286
- runtimes,
287
- transport,
288
- showHeader = true,
289
- authorityKey,
290
- describeError,
291
- onTitle,
292
- loadingLabel
293
- }) {
294
- const [loadEpoch, setLoadEpoch] = useState3(0);
295
- const labels = useArtifactLabels();
296
- const loadKey = JSON.stringify([artifactId, authorityKey, baseUrl.href, workspaceId, loadEpoch]);
297
- const [state, setState] = useState3({ key: null, kind: "loading" });
298
- const current = state.key === loadKey ? state : null;
299
- const openRef = useRef3(open);
300
- openRef.current = open;
301
- const onTitleRef = useRef3(onTitle);
302
- onTitleRef.current = onTitle;
303
- useEffect3(() => {
304
- const abort = new AbortController();
305
- setState({ key: loadKey, kind: "loading" });
306
- void openRef.current(abort.signal).then((value) => {
307
- if (abort.signal.aborted) return;
308
- setState({ key: loadKey, kind: "ready", value });
309
- onTitleRef.current?.(value.artifact.title);
310
- }).catch((error) => {
311
- if (!abort.signal.aborted) setState({ key: loadKey, kind: "error", error });
312
- });
313
- return () => abort.abort();
314
- }, [loadKey]);
315
- const ready = current?.kind === "ready" ? current.value : null;
316
- const transportRef = useRef3(transport);
317
- transportRef.current = transport;
318
- const sessionKey = useMemo2(
319
- () => ready ? JSON.stringify({
320
- baseUrl: baseUrl.href,
321
- authorityKey,
322
- workspaceId,
323
- artifact: { id: ready.artifact.id, modality: ready.artifact.modality },
324
- authority: ready.authority,
325
- replicaId: ready.replicaId,
326
- workerUrl: runtimes.workerUrl
327
- }) : "",
328
- [authorityKey, baseUrl.href, ready, runtimes.workerUrl, workspaceId]
329
- );
330
- const createSession = useCallback3(() => {
331
- if (!ready) throw new Error("Artifact is not open");
332
- return createBrowserEditableArtifactSession2({
333
- baseUrl,
334
- workspaceId,
335
- artifact: ready.artifact,
336
- storageAuthority: ready.authority,
337
- replicaId: ready.replicaId,
338
- runtime: {
339
- ...runtimeFor(runtimes, ready.artifact.modality),
340
- workerUrl: runtimes.workerUrl,
341
- ...runtimes.applicationOrigin ? { applicationOrigin: runtimes.applicationOrigin } : {},
342
- ...runtimes.allowInsecureDevelopmentAssets ? { allowInsecureDevelopmentAssets: true } : {}
343
- },
344
- ...transportRef.current ? { transport: transportRef.current } : {}
345
- });
346
- }, [baseUrl, ready, runtimes, workspaceId]);
347
- if (!current || current.kind === "loading")
348
- return /* @__PURE__ */ jsx3(ArtifactLoading, { label: loadingLabel ?? labels.opening });
349
- if (current.kind === "error") {
350
- return /* @__PURE__ */ jsx3(
351
- ArtifactProblem,
352
- {
353
- view: describeError ? describeError(current.error) : artifactLoadErrorView(current.error, "editable", labels),
354
- onRetry: () => setLoadEpoch((value) => value + 1)
355
- }
356
- );
357
- }
358
- const { artifact } = current.value;
359
- const surface = { title: artifact.title, showHeader };
360
- return /* @__PURE__ */ jsx3("div", { className: "h-full min-h-0 bg-og-bg text-og-fg", children: /* @__PURE__ */ jsx3(
361
- EditableArtifactWorkbenchHost,
362
- {
363
- sessionKey,
364
- createSession,
365
- document: surface,
366
- spreadsheet: surface,
367
- presentation: surface
368
- }
369
- ) });
370
- }
371
- function runtimeFor(runtimes, modality) {
372
- switch (modality) {
373
- case "document":
374
- return runtimes.document;
375
- case "spreadsheet":
376
- return runtimes.spreadsheet;
377
- case "presentation":
378
- return runtimes.presentation;
379
- }
380
- }
381
-
382
- // src/components/artifacts/session-artifact-viewer.tsx
383
- import { SESSION_SCOPE_HEADER } from "@opengeni/sdk";
384
- import { createEditableArtifactReplicaId } from "@opengeni/sdk/editable-artifacts";
385
- import { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef4, useState as useState4 } from "react";
386
- import { jsx as jsx4, jsxs } from "react/jsx-runtime";
387
- var viewerClientKeys = /* @__PURE__ */ new WeakMap();
388
- function viewerClientKey(client) {
389
- let key = viewerClientKeys.get(client);
390
- if (!key) {
391
- key = crypto.randomUUID();
392
- viewerClientKeys.set(client, key);
393
- }
394
- return key;
395
- }
396
- function SessionArtifactViewer({ labels, ...props }) {
397
- return /* @__PURE__ */ jsx4(ArtifactLabelsProvider, { labels, children: /* @__PURE__ */ jsx4(Viewer, { ...props }) });
398
- }
399
- function Viewer({
400
- client: clientOverride,
401
- workspaceId: workspaceOverride,
402
- sessionId,
403
- target,
404
- onClose,
405
- onBack,
406
- editableRuntimes,
407
- theme,
408
- siteToolBridge,
409
- className
410
- }) {
411
- const labels = useArtifactLabels();
412
- const context = useOpenGeni({ client: clientOverride, workspaceId: workspaceOverride });
413
- const base = context.client;
414
- const workspaceId = context.workspaceId;
415
- const client = useMemo3(
416
- () => base.withHeaders({ [SESSION_SCOPE_HEADER]: sessionId }),
417
- [base, sessionId]
418
- );
419
- const [loaded, setLoaded] = useState4(null);
420
- const targetKey = `${target.kind}:${target.artifactId}`;
421
- const current = loaded?.key === targetKey && loaded.client === client && loaded.workspaceId === workspaceId ? loaded : null;
422
- const kind = target.kind === "site" ? "site" : current?.kind ?? null;
423
- const [unavailable, setUnavailable] = useState4(null);
424
- const markUnavailable = useCallback4(
425
- () => setUnavailable({ key: targetKey, client, workspaceId }),
426
- [client, targetKey, workspaceId]
427
- );
428
- const title = current?.title ?? target.title ?? (unavailable?.key === targetKey && unavailable.client === client && unavailable.workspaceId === workspaceId ? labels.artifact : labels.opening);
429
- return /* @__PURE__ */ jsxs(
430
- "section",
431
- {
432
- "aria-label": title,
433
- "data-og-artifact-viewer": target.kind,
434
- className: cn("og-root flex h-full min-h-0 w-full min-w-0 flex-col bg-bg text-fg", className),
435
- children: [
436
- /* @__PURE__ */ jsx4(
437
- ArtifactViewerHeader,
438
- {
439
- kind,
440
- title,
441
- onBack,
442
- backLabel: labels.back,
443
- onClose,
444
- closeLabel: labels.close
445
- }
446
- ),
447
- /* @__PURE__ */ jsx4("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden", children: target.kind === "site" ? /* @__PURE__ */ jsx4(
448
- SiteView,
449
- {
450
- client,
451
- workspaceId,
452
- siteId: target.artifactId,
453
- theme,
454
- toolBridge: siteToolBridge,
455
- showTitle: false,
456
- onTitle: (next) => setLoaded({ key: targetKey, client, workspaceId, title: next, kind: "site" })
457
- },
458
- targetKey
459
- ) : /* @__PURE__ */ jsx4(
460
- EditableBody,
461
- {
462
- client,
463
- workspaceId,
464
- sessionId,
465
- artifactId: target.artifactId,
466
- runtimes: editableRuntimes,
467
- onOpened: (next, modality) => setLoaded({ key: targetKey, client, workspaceId, title: next, kind: modality }),
468
- onUnavailable: markUnavailable
469
- },
470
- targetKey
471
- ) })
472
- ]
473
- }
474
- );
475
- }
476
- function EditableBody({
477
- client,
478
- workspaceId,
479
- sessionId,
480
- artifactId,
481
- runtimes,
482
- onOpened,
483
- onUnavailable
484
- }) {
485
- const labels = useArtifactLabels();
486
- const clientKey = viewerClientKey(client);
487
- const [retryEpoch, setRetryEpoch] = useState4(0);
488
- const [configState, setConfigState] = useState4(null);
489
- const current = configState?.client === client && configState.workspaceId === workspaceId && configState.sessionId === sessionId ? configState.result : null;
490
- const config = current?.kind === "ready" ? current.config : null;
491
- const scopeRef = useRef4({ client, workspaceId, sessionId });
492
- scopeRef.current = { client, workspaceId, sessionId };
493
- useEffect4(() => {
494
- let live = true;
495
- setConfigState(null);
496
- client.getClientConfig().then(
497
- (value) => live && setConfigState({
498
- client,
499
- workspaceId,
500
- sessionId,
501
- result: value.artifacts ? { kind: "ready", config: value.artifacts } : { kind: "unavailable" }
502
- }),
503
- (error) => live && setConfigState({ client, workspaceId, sessionId, result: { kind: "error", error } })
504
- );
505
- return () => {
506
- live = false;
507
- };
508
- }, [client, retryEpoch, sessionId, workspaceId]);
509
- const baseUrl = useMemo3(
510
- () => new URL(client.apiUrl("/"), globalThis.location?.href ?? "http://localhost/"),
511
- [client]
512
- );
513
- const transport = useMemo3(() => {
514
- if (!config) return void 0;
515
- const socket = new URL(config.editableLiveUrl);
516
- let scope = new AbortController();
517
- const checkCurrent = (signal) => {
518
- signal.throwIfAborted();
519
- if (scopeRef.current.client !== client || scopeRef.current.workspaceId !== workspaceId || scopeRef.current.sessionId !== sessionId) {
520
- throw new DOMException("Artifact viewer scope changed", "AbortError");
521
- }
522
- };
523
- return {
524
- activate: () => {
525
- if (scope.signal.aborted) scope = new AbortController();
526
- },
527
- abort: () => scope.abort(),
528
- fetch: async (input, init) => {
529
- const signal = AbortSignal.any([scope.signal, ...init?.signal ? [init.signal] : []]);
530
- checkCurrent(signal);
531
- const url = new URL(input instanceof Request ? input.url : input, baseUrl);
532
- if (init?.method === "POST" && url.pathname === new URL(
533
- `v1/workspaces/${encodeURIComponent(workspaceId)}/editable-artifacts/${encodeURIComponent(artifactId)}/live-ticket`,
534
- baseUrl
535
- ).pathname) {
536
- const next = (await client.getClientConfig({ signal })).artifacts;
537
- checkCurrent(signal);
538
- if (!next || artifactCapabilityKey(next) !== artifactCapabilityKey(config)) {
539
- setConfigState({
540
- client,
541
- workspaceId,
542
- sessionId,
543
- result: next ? { kind: "ready", config: next } : { kind: "unavailable" }
544
- });
545
- scope.abort();
546
- signal.throwIfAborted();
547
- }
548
- const { replicaId } = await new Request(input, init).json();
549
- if (typeof replicaId !== "string") throw new TypeError("Artifact replica is required");
550
- await client.getEditableArtifact(workspaceId, artifactId, { replicaId, signal });
551
- checkCurrent(signal);
552
- }
553
- return client.fetchApi(url, { ...init, signal });
554
- },
555
- webSocketUrl: socket,
556
- ...isLoopback(baseUrl) && isLoopback(socket) ? { allowInsecureDevelopmentTransport: true } : {}
557
- };
558
- }, [artifactId, baseUrl, client, config, sessionId, workspaceId]);
559
- useEffect4(() => {
560
- transport?.activate();
561
- return () => transport?.abort();
562
- }, [transport]);
563
- const blocked = current !== null && (current.kind !== "ready" || !runtimes);
564
- useEffect4(() => {
565
- if (blocked) onUnavailable();
566
- }, [blocked, onUnavailable]);
567
- if (!current) return /* @__PURE__ */ jsx4(ArtifactLoading, { label: labels.opening });
568
- if (current.kind === "error") {
569
- return /* @__PURE__ */ jsx4(
570
- ArtifactProblem,
571
- {
572
- view: artifactLoadErrorView(current.error, "editable", labels),
573
- onRetry: () => setRetryEpoch((value) => value + 1)
574
- }
575
- );
576
- }
577
- if (!config || !transport) {
578
- return /* @__PURE__ */ jsx4(ArtifactProblem, { view: { ...labels.viewingDisabled, retryable: false } });
579
- }
580
- if (!runtimes) {
581
- return /* @__PURE__ */ jsx4(ArtifactProblem, { view: { ...labels.editorsMissing, retryable: false } });
582
- }
583
- return /* @__PURE__ */ jsx4(
584
- EditableArtifactView,
585
- {
586
- baseUrl,
587
- workspaceId,
588
- artifactId,
589
- authorityKey: JSON.stringify([clientKey, sessionId, artifactCapabilityKey(config)]),
590
- runtimes: {
591
- ...runtimes,
592
- ...isLoopback(baseUrl) ? { allowInsecureDevelopmentAssets: true } : {}
593
- },
594
- transport,
595
- showHeader: false,
596
- open: async (signal) => {
597
- const replicaId = createEditableArtifactReplicaId();
598
- const artifact = await client.getEditableArtifact(workspaceId, artifactId, {
599
- replicaId,
600
- signal
601
- });
602
- signal.throwIfAborted();
603
- onOpened(artifact.title, artifact.modality);
604
- return {
605
- artifact,
606
- replicaId,
607
- authority: {
608
- deploymentOrigin: baseUrl.origin,
609
- workspaceId,
610
- ...config.cachePartition
611
- }
612
- };
613
- }
614
- }
615
- );
616
- }
617
- function artifactCapabilityKey(config) {
618
- return JSON.stringify([
619
- config.editableLiveUrl,
620
- config.cachePartition.accountId,
621
- config.cachePartition.principalId,
622
- config.cachePartition.authorizationEpoch
623
- ]);
624
- }
625
- function isLoopback(url) {
626
- return (url.protocol === "http:" || url.protocol === "ws:") && (url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]");
627
- }
628
1544
  export {
629
- ArtifactBadge,
630
- ArtifactButton,
631
- ArtifactLabelsProvider,
632
- ArtifactLoading,
633
- ArtifactProblem,
634
- ArtifactSandbox,
635
- ArtifactSelect,
636
1545
  ArtifactSurface,
637
- ArtifactViewerHeader,
638
1546
  BrowserEditableArtifactWorkbench,
639
- ChatInteractiveBlock,
640
- DEFAULT_ARTIFACT_LABELS,
641
- DeferredChatMedia,
642
1547
  DocumentArtifactSurface,
643
1548
  DocumentEditor,
644
1549
  DocumentProjectionArtifactSurface,
645
1550
  DocumentProjectionEditor,
646
- EditableArtifactView,
647
1551
  EditableArtifactWorkbench,
648
1552
  EditableArtifactWorkbenchHost,
649
1553
  EditableDocumentArtifactSurface,
@@ -656,20 +1560,13 @@ export {
656
1560
  PresentationProjectionArtifactSurface,
657
1561
  PresentationProjectionEditor,
658
1562
  PublishedHtmlArtifactFrame,
659
- SessionArtifactViewer,
660
- SiteView,
661
1563
  SpreadsheetArtifactSurface,
662
1564
  SpreadsheetGrid,
663
1565
  SpreadsheetProjectionGrid,
664
- artifactKindIcon,
665
- artifactKindSubtitle,
666
- artifactLoadErrorMessage,
667
- artifactLoadErrorView,
668
1566
  inlineHtmlDocument,
669
1567
  isRetainedImageContentType,
670
1568
  openGeniSiteBridgePortFromBootstrap,
671
1569
  publishedHtmlArtifactDocument,
672
- useArtifactLabels,
673
1570
  useRetainedImageObjectUrl
674
1571
  };
675
1572
  //# sourceMappingURL=artifacts.js.map