@opengeni/react 5.1.0-canary.0 → 5.2.0-canary.1
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.
- package/README.md +12 -0
- package/dist/artifacts.d.ts +2 -0
- package/dist/artifacts.js +1391 -2
- package/dist/artifacts.js.map +1 -1
- package/dist/chunk-2TKI3WEG.js +73 -0
- package/dist/chunk-2TKI3WEG.js.map +1 -0
- package/dist/{chunk-M2HNWZYR.js → chunk-IHQII5WO.js} +69 -18
- package/dist/chunk-IHQII5WO.js.map +1 -0
- package/dist/{chunk-5PQJOCX5.js → chunk-KANFU34B.js} +6 -4
- package/dist/chunk-KANFU34B.js.map +1 -0
- package/dist/{chunk-WS6D5BHH.js → chunk-O4NQNMPG.js} +2393 -2123
- package/dist/chunk-O4NQNMPG.js.map +1 -0
- package/dist/{chunk-HUMIRRYI.js → chunk-PZ27MCZP.js} +54 -19
- package/dist/chunk-PZ27MCZP.js.map +1 -0
- package/dist/{chunk-BRFMGY4L.js → chunk-UGMKPUEM.js} +28 -3
- package/dist/chunk-UGMKPUEM.js.map +1 -0
- package/dist/{chunk-BV5A4OTE.js → chunk-YS24CFDI.js} +44 -10
- package/dist/chunk-YS24CFDI.js.map +1 -0
- package/dist/components/artifacts/inline-html-document.d.ts +2 -0
- package/dist/components/artifacts/published-html-artifact-frame.d.ts +2 -0
- package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
- package/dist/components/markdown.d.ts +13 -1
- package/dist/components/session-chrome.d.ts +6 -1
- package/dist/{computer-viewer-7TEZC6Y2.js → computer-viewer-CTFCJVS7.js} +2 -2
- package/dist/connect.js +1 -1
- package/dist/hooks/use-file-attachments.d.ts +2 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +16 -5
- package/dist/index.js.map +1 -1
- package/dist/interaction.js +1 -1
- package/dist/{platform-activity-row-27LKAWZD.js → platform-activity-row-DUE2W74J.js} +6 -3
- package/dist/platform-activity-row-DUE2W74J.js.map +1 -0
- package/dist/session-ui.d.ts +2 -0
- package/dist/session-ui.js +7 -107
- package/dist/session-ui.js.map +1 -1
- package/dist/session.js +2 -2
- package/dist/sites-ui.d.ts +2 -1
- package/dist/sites.js +12 -4
- package/dist/sites.js.map +1 -1
- package/dist/timeline/activity-rail.d.ts +1 -0
- package/dist/timeline/genie-loading.d.ts +9 -1
- package/dist/timeline/index.d.ts +3 -1
- package/dist/timeline/knowledge-receipt.d.ts +17 -0
- package/dist/timeline/platform-activity-row.d.ts +1 -2
- package/dist/timeline/retained-image.d.ts +16 -0
- package/dist/timeline/rolling-activity.d.ts +9 -0
- package/dist/timeline/shared.d.ts +4 -1
- package/dist/timeline/turn-summary.d.ts +4 -1
- package/dist/timeline/types.d.ts +13 -2
- package/package.json +4 -4
- package/src/artifacts.ts +2 -0
- package/src/components/artifacts/inline-html-document.ts +24 -0
- package/src/components/artifacts/published-html-artifact-frame.tsx +32 -2
- package/src/components/artifacts/visualization-assets/base.css +1015 -0
- package/src/components/artifacts/visualization-assets/helpers.html +349 -0
- package/src/components/artifacts/visualization-assets.gen.ts +3 -0
- package/src/components/computer-viewer.tsx +11 -3
- package/src/components/copy-button.tsx +7 -2
- package/src/components/markdown.tsx +111 -34
- package/src/components/message-timeline.tsx +48 -3
- package/src/components/session-chrome.tsx +14 -2
- package/src/hooks/use-computer-frame-stream.ts +17 -5
- package/src/hooks/use-computer-session.ts +36 -1
- package/src/hooks/use-file-attachments.ts +4 -1
- package/src/hooks/use-goal.ts +3 -1
- package/src/index.ts +12 -1
- package/src/session-ui.ts +3 -0
- package/src/sites-ui.tsx +23 -6
- package/src/timeline/activity-rail.tsx +31 -4
- package/src/timeline/genie-loading.tsx +18 -4
- package/src/timeline/index.ts +4 -0
- package/src/timeline/knowledge-receipt.tsx +100 -0
- package/src/timeline/platform-activity-row.tsx +5 -3
- package/src/timeline/projection.ts +40 -0
- package/src/timeline/retained-image.ts +91 -0
- package/src/timeline/rolling-activity.tsx +83 -0
- package/src/timeline/shared.tsx +33 -12
- package/src/timeline/tool-renderers.tsx +55 -91
- package/src/timeline/turn-summary.tsx +21 -15
- package/src/timeline/types.ts +14 -0
- package/styles/compiled.css +122 -0
- package/styles/index.css +49 -0
- package/dist/chunk-5PQJOCX5.js.map +0 -1
- package/dist/chunk-BRFMGY4L.js.map +0 -1
- package/dist/chunk-BV5A4OTE.js.map +0 -1
- package/dist/chunk-HUMIRRYI.js.map +0 -1
- package/dist/chunk-M2HNWZYR.js.map +0 -1
- package/dist/chunk-WS6D5BHH.js.map +0 -1
- package/dist/platform-activity-row-27LKAWZD.js.map +0 -1
- /package/dist/{computer-viewer-7TEZC6Y2.js.map → computer-viewer-CTFCJVS7.js.map} +0 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
<!--__INLINE_VISUALIZATION_FRAGMENT__-->
|
|
2
|
+
<script src="https://unpkg.com/@floating-ui/core@1.7.3/dist/floating-ui.core.umd.min.js"></script>
|
|
3
|
+
<script src="https://unpkg.com/@floating-ui/dom@1.7.4/dist/floating-ui.dom.umd.min.js"></script>
|
|
4
|
+
<script>
|
|
5
|
+
(() => {
|
|
6
|
+
if (window.FloatingUIDOM == null) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const { autoUpdate, computePosition, flip, offset, shift, size } = window.FloatingUIDOM;
|
|
10
|
+
const tooltipPlacements = new Set(["top", "right", "bottom", "left"]);
|
|
11
|
+
const tooltipId = `codex-visualization-tooltip-${
|
|
12
|
+
window.crypto?.randomUUID?.() ?? Date.now().toString(36)
|
|
13
|
+
}`;
|
|
14
|
+
const tooltipGap = 5;
|
|
15
|
+
const hoverDelay = 700;
|
|
16
|
+
const skipDelay = 300;
|
|
17
|
+
let activeTrigger = null;
|
|
18
|
+
let pendingTrigger = null;
|
|
19
|
+
let tooltip = null;
|
|
20
|
+
let openTimeout = null;
|
|
21
|
+
let autoUpdateCleanup = null;
|
|
22
|
+
let positionRequest = 0;
|
|
23
|
+
let skipDelayUntil = 0;
|
|
24
|
+
let lastPointerWasTouch = false;
|
|
25
|
+
let pinnedByTouch = false;
|
|
26
|
+
|
|
27
|
+
const getTrigger = (target) =>
|
|
28
|
+
target?.nodeType === Node.ELEMENT_NODE ? target.closest("[data-tooltip]") : null;
|
|
29
|
+
const containsTarget = (trigger, target) =>
|
|
30
|
+
target?.nodeType != null && trigger.contains(target);
|
|
31
|
+
const getContent = (trigger) => trigger.getAttribute("data-tooltip")?.trim() ?? "";
|
|
32
|
+
const getPlacement = (trigger) => {
|
|
33
|
+
const placement = trigger.getAttribute("data-tooltip-placement");
|
|
34
|
+
return tooltipPlacements.has(placement) ? placement : "top";
|
|
35
|
+
};
|
|
36
|
+
const getTooltip = () => {
|
|
37
|
+
if (tooltip == null) {
|
|
38
|
+
tooltip = document.createElement("div");
|
|
39
|
+
tooltip.id = tooltipId;
|
|
40
|
+
tooltip.className = "tooltip";
|
|
41
|
+
tooltip.setAttribute("role", "tooltip");
|
|
42
|
+
}
|
|
43
|
+
return tooltip;
|
|
44
|
+
};
|
|
45
|
+
const setDescribedBy = (trigger, described) => {
|
|
46
|
+
const ids = new Set(
|
|
47
|
+
(trigger.getAttribute("aria-describedby") ?? "").split(/\s+/).filter(Boolean),
|
|
48
|
+
);
|
|
49
|
+
if (described) {
|
|
50
|
+
ids.add(tooltipId);
|
|
51
|
+
} else {
|
|
52
|
+
ids.delete(tooltipId);
|
|
53
|
+
}
|
|
54
|
+
if (ids.size === 0) {
|
|
55
|
+
trigger.removeAttribute("aria-describedby");
|
|
56
|
+
} else {
|
|
57
|
+
trigger.setAttribute("aria-describedby", [...ids].join(" "));
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const clearOpenTimeout = () => {
|
|
61
|
+
if (openTimeout != null) {
|
|
62
|
+
window.clearTimeout(openTimeout);
|
|
63
|
+
openTimeout = null;
|
|
64
|
+
}
|
|
65
|
+
pendingTrigger = null;
|
|
66
|
+
};
|
|
67
|
+
const closeTooltip = (activateSkipDelay = true) => {
|
|
68
|
+
clearOpenTimeout();
|
|
69
|
+
pinnedByTouch = false;
|
|
70
|
+
positionRequest += 1;
|
|
71
|
+
autoUpdateCleanup?.();
|
|
72
|
+
autoUpdateCleanup = null;
|
|
73
|
+
if (activeTrigger == null) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
setDescribedBy(activeTrigger, false);
|
|
77
|
+
activeTrigger = null;
|
|
78
|
+
tooltip?.remove();
|
|
79
|
+
if (activateSkipDelay) {
|
|
80
|
+
skipDelayUntil = Date.now() + skipDelay;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const updatePosition = (trigger, floating) => {
|
|
84
|
+
const request = ++positionRequest;
|
|
85
|
+
void computePosition(trigger, floating, {
|
|
86
|
+
middleware: [
|
|
87
|
+
offset(tooltipGap),
|
|
88
|
+
flip({ padding: tooltipGap }),
|
|
89
|
+
shift({ padding: tooltipGap }),
|
|
90
|
+
size({
|
|
91
|
+
padding: tooltipGap,
|
|
92
|
+
apply({ availableHeight, availableWidth, elements }) {
|
|
93
|
+
elements.floating.style.setProperty(
|
|
94
|
+
"--tooltip-available-width",
|
|
95
|
+
`${Math.max(0, availableWidth)}px`,
|
|
96
|
+
);
|
|
97
|
+
elements.floating.style.setProperty(
|
|
98
|
+
"--tooltip-available-height",
|
|
99
|
+
`${Math.max(0, availableHeight)}px`,
|
|
100
|
+
);
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
],
|
|
104
|
+
placement: getPlacement(trigger),
|
|
105
|
+
strategy: "fixed",
|
|
106
|
+
})
|
|
107
|
+
.then(({ x, y }) => {
|
|
108
|
+
if (activeTrigger !== trigger || request !== positionRequest) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const scale = window.devicePixelRatio || 1;
|
|
112
|
+
floating.style.transform = `translate(${Math.round(x * scale) / scale}px, ${Math.round(y * scale) / scale}px)`;
|
|
113
|
+
floating.style.visibility = "visible";
|
|
114
|
+
})
|
|
115
|
+
.catch(() => {
|
|
116
|
+
if (activeTrigger === trigger && request === positionRequest) {
|
|
117
|
+
closeTooltip(false);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
const openTooltip = (trigger) => {
|
|
122
|
+
const content = getContent(trigger);
|
|
123
|
+
if (!trigger.isConnected || content.length === 0) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
clearOpenTimeout();
|
|
127
|
+
if (activeTrigger === trigger) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
closeTooltip();
|
|
131
|
+
const floating = getTooltip();
|
|
132
|
+
floating.textContent = content;
|
|
133
|
+
floating.style.visibility = "hidden";
|
|
134
|
+
floating.style.transform = "translate(0, 0)";
|
|
135
|
+
document.body.appendChild(floating);
|
|
136
|
+
activeTrigger = trigger;
|
|
137
|
+
setDescribedBy(trigger, true);
|
|
138
|
+
autoUpdateCleanup = autoUpdate(trigger, floating, () => {
|
|
139
|
+
updatePosition(trigger, floating);
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
const requestOpen = (trigger, immediate = false) => {
|
|
143
|
+
if (
|
|
144
|
+
getContent(trigger).length === 0 ||
|
|
145
|
+
activeTrigger === trigger ||
|
|
146
|
+
pendingTrigger === trigger
|
|
147
|
+
) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
clearOpenTimeout();
|
|
151
|
+
pendingTrigger = trigger;
|
|
152
|
+
const delay =
|
|
153
|
+
immediate || activeTrigger != null || Date.now() < skipDelayUntil ? 0 : hoverDelay;
|
|
154
|
+
if (delay === 0) {
|
|
155
|
+
openTooltip(trigger);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
openTimeout = window.setTimeout(() => {
|
|
159
|
+
openTimeout = null;
|
|
160
|
+
pendingTrigger = null;
|
|
161
|
+
openTooltip(trigger);
|
|
162
|
+
}, delay);
|
|
163
|
+
};
|
|
164
|
+
const handlePointerOpen = (event) => {
|
|
165
|
+
if (event.pointerType === "touch") {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const trigger = getTrigger(event.target);
|
|
169
|
+
if (trigger == null || containsTarget(trigger, event.relatedTarget)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
requestOpen(trigger);
|
|
173
|
+
};
|
|
174
|
+
const handlePointer = (event) => {
|
|
175
|
+
lastPointerWasTouch = event.type === "pointerdown" && event.pointerType === "touch";
|
|
176
|
+
};
|
|
177
|
+
const handleTouchClick = (event) => {
|
|
178
|
+
const isTouch = event.pointerType === "touch" || lastPointerWasTouch;
|
|
179
|
+
lastPointerWasTouch = false;
|
|
180
|
+
if (!isTouch || event.detail === 0) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const trigger = getTrigger(event.target);
|
|
184
|
+
if (
|
|
185
|
+
trigger == null ||
|
|
186
|
+
!trigger.isConnected ||
|
|
187
|
+
getContent(trigger).length === 0 ||
|
|
188
|
+
(pinnedByTouch && activeTrigger === trigger)
|
|
189
|
+
) {
|
|
190
|
+
if (pinnedByTouch) {
|
|
191
|
+
closeTooltip();
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
openTooltip(trigger);
|
|
196
|
+
pinnedByTouch = activeTrigger === trigger;
|
|
197
|
+
window.setTimeout(() => {
|
|
198
|
+
if (activeTrigger === trigger && !trigger.isConnected) {
|
|
199
|
+
closeTooltip(false);
|
|
200
|
+
}
|
|
201
|
+
}, 0);
|
|
202
|
+
};
|
|
203
|
+
const handleLeave = (event) => {
|
|
204
|
+
if (pinnedByTouch) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const trigger = getTrigger(event.target);
|
|
208
|
+
if (trigger == null || containsTarget(trigger, event.relatedTarget)) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (activeTrigger === trigger || pendingTrigger === trigger) {
|
|
212
|
+
closeTooltip();
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
const handleFocusIn = (event) => {
|
|
216
|
+
const trigger = getTrigger(event.target);
|
|
217
|
+
if (trigger?.matches(":focus-visible")) {
|
|
218
|
+
requestOpen(trigger, true);
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const handleKeyDown = (event) => {
|
|
222
|
+
if (event.key === "Escape") {
|
|
223
|
+
closeTooltip();
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
const handleContextMenu = (event) => {
|
|
227
|
+
lastPointerWasTouch = false;
|
|
228
|
+
const trigger = getTrigger(event.target);
|
|
229
|
+
if (activeTrigger === trigger || pendingTrigger === trigger) {
|
|
230
|
+
closeTooltip();
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
const destroy = () => {
|
|
234
|
+
closeTooltip(false);
|
|
235
|
+
lastPointerWasTouch = false;
|
|
236
|
+
document.removeEventListener("pointerover", handlePointerOpen);
|
|
237
|
+
document.removeEventListener("pointerdown", handlePointer);
|
|
238
|
+
document.removeEventListener("pointercancel", handlePointer);
|
|
239
|
+
document.removeEventListener("click", handleTouchClick);
|
|
240
|
+
document.removeEventListener("pointerout", handleLeave);
|
|
241
|
+
document.removeEventListener("focusin", handleFocusIn);
|
|
242
|
+
document.removeEventListener("focusout", handleLeave);
|
|
243
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
244
|
+
document.removeEventListener("contextmenu", handleContextMenu);
|
|
245
|
+
tooltip = null;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
document.addEventListener("pointerover", handlePointerOpen);
|
|
249
|
+
document.addEventListener("pointerdown", handlePointer);
|
|
250
|
+
document.addEventListener("pointercancel", handlePointer);
|
|
251
|
+
document.addEventListener("click", handleTouchClick);
|
|
252
|
+
document.addEventListener("pointerout", handleLeave);
|
|
253
|
+
document.addEventListener("focusin", handleFocusIn);
|
|
254
|
+
document.addEventListener("focusout", handleLeave);
|
|
255
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
256
|
+
document.addEventListener("contextmenu", handleContextMenu);
|
|
257
|
+
window.addEventListener("pagehide", destroy, { once: true });
|
|
258
|
+
})();
|
|
259
|
+
</script>
|
|
260
|
+
<script id="codex-visualization-tabs">
|
|
261
|
+
(() => {
|
|
262
|
+
const selector = '.nav[role="tablist"] [role="tab"]';
|
|
263
|
+
const disabled = ':disabled,[aria-disabled="true"]';
|
|
264
|
+
const selectTab = (selected) => {
|
|
265
|
+
const panelId = selected.getAttribute("aria-controls");
|
|
266
|
+
for (const tab of selected.closest('[role="tablist"]').querySelectorAll('[role="tab"]')) {
|
|
267
|
+
const active = tab === selected;
|
|
268
|
+
tab.classList.toggle("active", active);
|
|
269
|
+
tab.setAttribute("aria-selected", String(active));
|
|
270
|
+
const id = tab.getAttribute("aria-controls");
|
|
271
|
+
const panel = id && document.getElementById(id);
|
|
272
|
+
if (panel != null) {
|
|
273
|
+
panel.hidden = id !== panelId;
|
|
274
|
+
if (!panel.hidden && selected.id) {
|
|
275
|
+
panel.setAttribute("aria-labelledby", selected.id);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
const interact = (event) => {
|
|
281
|
+
const tab = event.target?.closest?.(selector);
|
|
282
|
+
if (event.defaultPrevented || tab == null || tab.matches(disabled)) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (event.type === "click") {
|
|
286
|
+
selectTab(tab);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
const tabs = Array.from(
|
|
290
|
+
tab.closest('[role="tablist"]').querySelectorAll('[role="tab"]'),
|
|
291
|
+
).filter((candidate) => !candidate.matches(disabled));
|
|
292
|
+
const current = tabs.indexOf(tab);
|
|
293
|
+
let next;
|
|
294
|
+
if (event.key === "ArrowRight" || event.key === "ArrowDown") {
|
|
295
|
+
next = (current + 1) % tabs.length;
|
|
296
|
+
} else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
|
|
297
|
+
next = (current + tabs.length - 1) % tabs.length;
|
|
298
|
+
} else if (event.key === "Home") {
|
|
299
|
+
next = 0;
|
|
300
|
+
} else if (event.key === "End") {
|
|
301
|
+
next = tabs.length - 1;
|
|
302
|
+
} else {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
event.preventDefault();
|
|
306
|
+
tabs[next].focus();
|
|
307
|
+
selectTab(tabs[next]);
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
for (const list of document.querySelectorAll('.nav[role="tablist"]')) {
|
|
311
|
+
const selected =
|
|
312
|
+
list.querySelector('[role="tab"][aria-selected="true"]') ??
|
|
313
|
+
list.querySelector('[role="tab"].active') ??
|
|
314
|
+
list.querySelector('[role="tab"]');
|
|
315
|
+
if (selected != null) {
|
|
316
|
+
selectTab(selected);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
document.addEventListener("click", interact);
|
|
320
|
+
document.addEventListener("keydown", interact);
|
|
321
|
+
window.addEventListener(
|
|
322
|
+
"pagehide",
|
|
323
|
+
() => {
|
|
324
|
+
document.removeEventListener("click", interact);
|
|
325
|
+
document.removeEventListener("keydown", interact);
|
|
326
|
+
},
|
|
327
|
+
{ once: true },
|
|
328
|
+
);
|
|
329
|
+
})();
|
|
330
|
+
</script>
|
|
331
|
+
<script
|
|
332
|
+
id="codex-visualization-lucide"
|
|
333
|
+
async
|
|
334
|
+
src="https://unpkg.com/lucide@1.17.0/dist/umd/lucide.js"
|
|
335
|
+
></script>
|
|
336
|
+
<script>
|
|
337
|
+
(() => {
|
|
338
|
+
const initialize = () => {
|
|
339
|
+
globalThis.lucide?.createIcons({ attrs: { width: 16, height: 16 } });
|
|
340
|
+
};
|
|
341
|
+
if (globalThis.lucide != null) {
|
|
342
|
+
initialize();
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
document
|
|
346
|
+
.getElementById("codex-visualization-lucide")
|
|
347
|
+
?.addEventListener("load", initialize, { once: true });
|
|
348
|
+
})();
|
|
349
|
+
</script>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// Generated by scripts/generate-visualization-assets.ts.
|
|
2
|
+
export const VISUALIZATION_CSS = "/* Adapted from Codex visualize 1.0.32; shared with the OpenGeni visualization skill. */\n:root {\n color-scheme: light dark;\n background-color: var(\n --background,\n var(--color-background-primary, light-dark(rgb(255 255 255), rgb(24 24 24)))\n ) !important;\n\n /* Agent-facing contract; keep in sync with SKILL.md. */\n --background: var(\n --color-background-primary,\n light-dark(rgb(255 255 255), rgb(24 24 24))\n );\n --foreground: var(\n --color-text-primary,\n light-dark(rgb(26 28 31), rgb(255 255 255))\n );\n --card: color-mix(in oklab, var(--foreground) 5%, var(--background));\n --card-foreground: var(\n --color-text-primary,\n light-dark(rgb(26 28 31), rgb(255 255 255))\n );\n --popover: var(\n --color-background-secondary,\n light-dark(rgb(255 255 255), rgb(45 45 45))\n );\n --popover-foreground: var(\n --color-text-primary,\n light-dark(rgb(26 28 31), rgb(255 255 255))\n );\n --primary: var(\n --color-text-info,\n light-dark(rgb(51 156 255), rgb(131 195 255))\n );\n --primary-foreground: var(\n --color-text-inverse,\n light-dark(rgb(255 255 255), rgb(13 13 13))\n );\n --secondary: var(\n --color-background-secondary,\n light-dark(rgb(255 255 255 / 96%), rgb(54 54 54 / 96%))\n );\n --secondary-foreground: var(\n --color-text-primary,\n light-dark(rgb(26 28 31), rgb(255 255 255))\n );\n --muted: color-mix(in srgb, var(--foreground) 10%, transparent);\n --muted-foreground: var(\n --color-text-secondary,\n light-dark(rgb(26 28 31 / 49.4%), rgb(255 255 255 / 49.8%))\n );\n --accent: var(\n --color-background-info,\n light-dark(rgb(229 242 255), rgb(13 39 63))\n );\n --accent-foreground: var(\n --color-text-info,\n light-dark(rgb(51 156 255), rgb(131 195 255))\n );\n --destructive: var(\n --color-text-warning,\n light-dark(rgb(226 85 7), rgb(255 133 73))\n );\n --border: var(\n --color-border-secondary,\n light-dark(rgb(26 28 31 / 8%), rgb(255 255 255 / 8.2%))\n );\n --input: var(\n --color-border-primary,\n light-dark(\n rgb(26 28 31 / 11.8%),\n color-mix(in oklab, rgb(0 0 0) 10%, transparent)\n )\n );\n --ring: var(\n --color-ring-primary,\n light-dark(rgb(51 156 255), rgb(131 195 255 / 76%))\n );\n --font-size-base: var(--font-text-md-size, 14px);\n --blue: light-dark(rgb(51 156 255), rgb(51 156 255));\n --orange: light-dark(rgb(226 85 7), rgb(251 106 34));\n --green: light-dark(rgb(0 162 64), rgb(64 201 119));\n --red: light-dark(rgb(224 46 42), rgb(255 103 100));\n --purple: light-dark(rgb(146 79 247), rgb(173 123 249));\n --yellow: light-dark(rgb(255 195 0), rgb(255 210 64));\n --viz-series-1: var(--primary);\n --viz-series-2: light-dark(rgb(243 136 59), rgb(245 154 86));\n --viz-series-3: light-dark(rgb(93 201 119), rgb(116 213 139));\n --viz-series-4: light-dark(rgb(235 119 177), rgb(240 143 192));\n --viz-series-5: light-dark(rgb(155 121 236), rgb(170 145 239));\n --viz-series-6: light-dark(rgb(58 185 177), rgb(90 203 194));\n\n /* Internal implementation variables; not part of the agent contract. */\n --font-sans: -apple-system, system-ui, \"Segoe UI\", sans-serif;\n --font-mono:\n ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\",\n monospace;\n --font-size-normal: max(11px, var(--font-size-base));\n --font-size-tooltip: calc(var(--font-size-base) - 1px);\n --font-size-small: max(11px, calc(var(--font-size-base) - 2px));\n --font-size-h1: calc(var(--font-size-normal) * 1.7142857143);\n --font-size-h2: calc(var(--font-size-normal) * 1.4285714286);\n --font-size-h3: calc(var(--font-size-normal) * 1.2857142857);\n --font-weight-normal: 430;\n --font-weight-medium: 500;\n --icon-size: 16px;\n --line-height-normal: calc(var(--font-size-normal) * 1.5);\n --line-height-tooltip: calc(var(--font-size-tooltip) * 1.4285714286);\n --line-height-small: calc(var(--font-size-small) + 4px);\n --corner-shape: round;\n --radius: var(--border-radius-lg, 10px);\n --radius-sm: calc(var(--radius) * 0.6);\n --radius-md: calc(var(--radius) * 0.8);\n --radius-lg: var(--radius);\n --radius-2xl: calc(var(--radius) * 1.6);\n --radius-full: 9999px;\n --shadow-sm: 0 1px 2px -1px rgb(0 0 0 / 8%);\n --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\");\n\n /* Legacy aliases; not part of the current agent contract. */\n --viz-bg: transparent;\n --viz-panel: var(--card);\n --viz-border: var(--border);\n --viz-text: var(--foreground);\n --viz-muted: var(--muted-foreground);\n --viz-accent: var(--primary);\n --viz-accent-text: var(--primary-foreground);\n --viz-accent-bg: var(--accent);\n --viz-font-size: var(--font-size-base);\n --viz-warning: var(--destructive);\n}\n\n:root[data-theme=\"light\"] {\n color-scheme: light;\n}\n\n:root[data-theme=\"dark\"] {\n color-scheme: dark;\n}\n\n* {\n box-sizing: border-box;\n}\n\nhtml > body {\n /* Preserve MCP aliases for older inline renderers without creating :root cycles. */\n --color-background-primary: var(\n --background,\n light-dark(rgb(255 255 255), rgb(24 24 24))\n );\n --color-text-primary: var(\n --foreground,\n light-dark(rgb(26 28 31), rgb(255 255 255))\n );\n --color-border-secondary: var(\n --border,\n light-dark(rgb(26 28 31 / 8%), rgb(255 255 255 / 8.2%))\n );\n\n margin: 0;\n padding: var(--visualize-paint-gutter, 16px);\n color: var(--foreground);\n background: transparent !important;\n font-family: var(--font-sans) !important;\n font-size: var(--font-size-normal);\n font-weight: var(--font-weight-normal);\n line-height: var(--line-height-normal);\n}\n\na {\n color: color-mix(in srgb, var(--viz-accent) 80%, var(--viz-text) 20%);\n cursor: pointer;\n font-weight: var(--font-weight-medium, 500);\n text-decoration: none;\n text-underline-offset: 2px;\n}\n\na:is(:hover, :focus-visible) {\n text-decoration-line: underline;\n text-decoration-style: dashed;\n text-decoration-thickness: 0.5px;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\np {\n margin-block: 0;\n}\n\nh1 {\n font-size: var(--font-size-h1);\n font-weight: var(--font-weight-medium);\n line-height: 1.25;\n}\n\nh2 {\n font-size: var(--font-size-h2);\n font-weight: var(--font-weight-medium);\n line-height: 1.25;\n}\n\nh3,\nh4,\nh5,\nh6 {\n font-size: var(--font-size-h3);\n font-weight: var(--font-weight-medium);\n line-height: 1.3;\n}\n\nb,\nstrong,\nth {\n font-weight: var(--font-weight-medium);\n}\n\ncode:not(pre code) {\n display: inline;\n padding: 1px 6px;\n border-radius: var(--radius-sm);\n corner-shape: var(--corner-shape);\n background: var(--muted);\n font-family: var(--font-mono);\n font-size: 0.92em;\n overflow-wrap: anywhere;\n -webkit-box-decoration-break: clone;\n box-decoration-break: clone;\n word-break: break-word;\n}\n\n.table-responsive {\n width: 100%;\n overflow-x: auto;\n scrollbar-width: thin;\n}\n\n.table {\n width: 100%;\n border-collapse: collapse;\n color: var(--foreground);\n font: inherit;\n text-align: start;\n}\n\n.table :is(th, td) {\n padding-block: 10px;\n padding-inline: 0 24px;\n overflow-wrap: anywhere;\n border-bottom: 1px solid var(--border);\n text-align: start;\n vertical-align: top;\n}\n\n.table-responsive > .table :is(th, td) {\n overflow-wrap: break-word;\n}\n\n.table :is(th, td):last-child {\n padding-inline-end: 0;\n}\n\n.table :is(caption, thead th) {\n font-weight: 600;\n}\n\n.table thead th {\n padding-block: 8px;\n border-bottom-color: color-mix(in srgb, var(--foreground) 16%, transparent);\n}\n\n.table tbody tr:last-child :is(th, td) {\n border-bottom: 0;\n}\n\n.table.table-sm :is(th, td) {\n padding-block: 6px;\n}\n\n.table.table-sm :is(th, td):not(:last-child) {\n padding-inline-end: 16px;\n}\n\n.table :is(.text-end, [align=\"right\"]) {\n text-align: end;\n font-variant-numeric: tabular-nums;\n}\n\n.table :is(.text-center, [align=\"center\"]) {\n text-align: center;\n}\n\n.table .text-nowrap {\n white-space: nowrap;\n}\n\n#widget {\n display: flex;\n flex-direction: column;\n gap: 12px;\n width: 100%;\n padding: 0;\n background: transparent !important;\n}\n\n.card {\n min-width: 0;\n padding: 12px;\n overflow: hidden;\n overflow-wrap: break-word;\n border-radius: var(--radius-2xl);\n corner-shape: var(--corner-shape);\n color: var(--card-foreground);\n background: var(--card);\n}\n\n#widget > :not(.card, .progress) {\n width: 100% !important;\n max-width: none !important;\n margin: 0 !important;\n padding: 0 !important;\n border: 0 !important;\n border-radius: 0 !important;\n background: transparent !important;\n box-shadow: none !important;\n}\n\n.tooltip {\n position: fixed;\n z-index: 50;\n top: 0;\n left: 0;\n width: max-content;\n max-width: min(\n 20rem,\n var(--tooltip-available-width, calc(100vw - 10px)),\n calc(100vw - 10px)\n );\n max-height: min(\n var(--tooltip-available-height, calc(100vh - 10px)),\n calc(100vh - 10px)\n );\n padding: 4px 8px;\n border: 1px solid var(--border);\n border-radius: var(--radius-lg);\n corner-shape: var(--corner-shape);\n color: var(--popover-foreground);\n background: var(--popover);\n box-shadow: none;\n font-size: var(--font-size-tooltip);\n line-height: var(--line-height-tooltip);\n overflow-wrap: break-word;\n white-space: normal;\n pointer-events: none;\n user-select: none;\n}\n\n.viz-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(max(180px, 24%), 1fr));\n gap: 10px;\n}\n\n.viz-stat {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.viz-stat-value {\n font-size: var(--font-size-h2);\n font-weight: var(--font-weight-medium);\n line-height: 1.25;\n}\n\n.viz-row {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 10px;\n}\n\nhr {\n width: 100%;\n height: 1px;\n margin-block: 6px;\n border: 0;\n background: var(--border);\n}\n\n.nav {\n display: flex;\n min-width: 0;\n align-items: center;\n gap: 4px;\n}\n\n.progress {\n display: flex;\n height: 8px;\n margin-block: calc((var(--line-height-normal, 1.5em) - 8px) / 2);\n overflow: hidden;\n border: 0;\n border-radius: var(--radius-full);\n background: var(--muted);\n}\n\n.progress-bar:only-child {\n border-radius: var(--radius-full);\n}\n\n.progress-bar {\n height: 100%;\n flex-shrink: 0;\n border: 0;\n background: var(--viz-series-1);\n}\n\n.viz-badge {\n padding: 3px 8px;\n border-radius: var(--radius-full);\n color: var(--accent-foreground);\n background: var(--accent);\n font-weight: var(--font-weight-medium);\n}\n\nsmall,\n.text-small,\n.viz-badge {\n font-size: var(--font-size-small);\n line-height: var(--line-height-small);\n}\n\n.text-muted {\n color: var(--muted-foreground);\n}\n\n.tabular-nums {\n font-variant-numeric: tabular-nums;\n}\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n.viz-controls {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n\n.viz-controls > .form-label {\n display: grid;\n min-width: min(100%, 260px);\n flex: 1 1 280px;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: baseline;\n gap: 2px 12px;\n margin-bottom: 0;\n}\n\n.viz-controls > .form-label > :is(.form-control, .form-range, .form-select) {\n grid-column: 1 / -1;\n}\n\n.btn,\n.nav-link,\n.form-check-input,\n.form-control,\n.form-range,\n.form-select {\n font: inherit;\n}\n\n.btn,\n.nav-link {\n appearance: button;\n display: inline-flex;\n inline-size: fit-content;\n max-inline-size: 100%;\n min-height: 28px;\n align-items: center;\n justify-content: center;\n gap: 4px;\n margin: 0;\n padding: 0 8px;\n -webkit-app-region: no-drag;\n border: 1px solid var(--input);\n border-radius: var(--radius-lg);\n corner-shape: var(--corner-shape);\n color: var(--secondary-foreground);\n background: var(--secondary);\n cursor: var(--cursor-interaction, pointer);\n text-align: center;\n text-decoration: none;\n white-space: nowrap;\n user-select: none;\n -webkit-font-smoothing: antialiased;\n}\n\n.btn:is(.btn-block, .viz-tile) {\n inline-size: 100%;\n}\n\n.btn.viz-tile {\n min-width: 0;\n overflow-wrap: anywhere;\n white-space: normal;\n}\n\na.btn {\n cursor: pointer;\n text-decoration: none;\n}\n\n.btn:not(:disabled):hover,\n.nav-link:not(:disabled):not([aria-disabled=\"true\"]):hover {\n background: color-mix(in srgb, var(--foreground) 6%, var(--secondary));\n}\n\n.btn-primary {\n border-color: transparent;\n color: var(--primary-foreground);\n background: var(--foreground);\n background-clip: padding-box;\n}\n\n.btn-primary .text-muted {\n color: color-mix(in srgb, var(--primary-foreground) 50%, transparent);\n}\n\n.btn-primary:not(:disabled):hover {\n background: color-mix(in srgb, var(--foreground) 80%, transparent);\n background-clip: padding-box;\n}\n\n.btn-ghost {\n border-color: transparent;\n color: var(--muted-foreground);\n background: transparent;\n}\n\n.btn-ghost:not(:disabled):hover {\n color: var(--foreground);\n background: color-mix(in srgb, var(--foreground) 6%, var(--secondary));\n}\n\n.nav-pills .nav-link {\n min-width: 0;\n border-color: transparent;\n color: var(--muted-foreground);\n background: transparent;\n}\n\n.nav-justified .nav-link {\n flex: 1 1 0;\n overflow-wrap: anywhere;\n white-space: normal;\n}\n\n.nav-pills .nav-link.active {\n color: var(--foreground);\n background: var(--muted);\n}\n\n.btn:disabled,\n.nav-link:disabled,\n.nav-link[aria-disabled=\"true\"] {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n[data-lucide] {\n stroke-width: 1.6;\n}\n\n.form-label {\n display: block;\n margin-bottom: 6px;\n color: var(--foreground);\n}\n\n.form-control {\n display: block;\n width: 100%;\n min-height: 28px;\n padding: 0 8px;\n outline: none;\n border: 1px solid var(--input);\n border-radius: var(--radius-lg);\n corner-shape: var(--corner-shape);\n color: var(--foreground);\n background: var(--secondary);\n}\n\n.form-control::placeholder {\n color: var(--muted-foreground);\n}\n\n.form-control[type=\"file\"] {\n padding: 0;\n overflow: hidden;\n cursor: var(--cursor-interaction, pointer);\n}\n\n.form-control[type=\"file\"]::file-selector-button {\n min-height: 26px;\n margin-right: 8px;\n padding: 0 8px;\n border: 0;\n border-right: 1px solid var(--input);\n color: var(--secondary-foreground);\n background: var(--secondary);\n cursor: inherit;\n font: inherit;\n}\n\n.form-control[type=\"file\"]:not(:disabled):hover::file-selector-button {\n background: color-mix(in srgb, var(--foreground) 6%, var(--secondary));\n}\n\n.form-control-color[type=\"color\"] {\n width: 40px;\n height: 28px;\n padding: 3px;\n cursor: var(--cursor-interaction, pointer);\n}\n\n.form-control-color[type=\"color\"]::-webkit-color-swatch-wrapper {\n padding: 0;\n}\n\n.form-control-color[type=\"color\"]::-webkit-color-swatch {\n border: 0;\n border-radius: calc(var(--radius-lg) - 4px);\n corner-shape: var(--corner-shape);\n}\n\ntextarea.form-control {\n height: auto;\n min-height: 72px;\n padding: 8px 10px;\n resize: vertical;\n}\n\n.form-control:focus-visible {\n border-color: var(--ring);\n box-shadow: inset 0 0 0 1px var(--ring);\n}\n\n.form-control:disabled,\n.form-select:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.form-select {\n appearance: none;\n display: block;\n width: 100%;\n min-height: 28px;\n margin: 0;\n padding: 0 32px 0 8px;\n outline: none;\n border: 1px solid var(--input);\n border-radius: var(--radius-lg);\n corner-shape: var(--corner-shape);\n color: var(--foreground);\n background-color: var(--secondary);\n background-image:\n linear-gradient(45deg, transparent 50%, var(--muted-foreground) 50%),\n linear-gradient(135deg, var(--muted-foreground) 50%, transparent 50%);\n background-position:\n calc(100% - 14px) 50%,\n calc(100% - 10px) 50%;\n background-repeat: no-repeat;\n background-size: 4px 4px;\n cursor: var(--cursor-interaction, default);\n}\n\n.form-select:not(:disabled):hover {\n background-color: color-mix(in srgb, var(--foreground) 6%, var(--secondary));\n}\n\n.form-select:focus-visible {\n border-color: var(--ring);\n box-shadow: inset 0 0 0 1px var(--ring);\n}\n\n.form-check {\n display: flex;\n min-height: 20px;\n align-items: center;\n gap: 6px;\n}\n\n.form-check-input {\n appearance: none;\n width: 14px;\n height: 14px;\n flex: 0 0 auto;\n margin: 0;\n border: 1px solid var(--input);\n color: var(--primary-foreground);\n background-color: transparent;\n cursor: var(--cursor-interaction, default);\n transition:\n background-color 150ms,\n border-color 150ms,\n box-shadow 150ms;\n}\n\n.form-check:not(.form-switch) .form-check-input[type=\"checkbox\"] {\n border-color: var(--input);\n border-radius: var(--radius-sm);\n corner-shape: var(--corner-shape);\n background-color: var(--secondary);\n box-shadow: var(--shadow-sm);\n}\n\n.form-check:not(.form-switch)\n .form-check-input:not(:disabled):not(:checked):hover {\n background-color: var(--card);\n}\n\n.form-check:not(.form-switch) .form-check-input[type=\"checkbox\"]:checked {\n border-color: var(--primary);\n background-color: var(--primary);\n}\n\n.form-check:not(.form-switch)\n .form-check-input[type=\"checkbox\"]:checked::before {\n display: block;\n width: 100%;\n height: 100%;\n background: var(--primary-foreground);\n content: \"\";\n mask: var(--checkmark-image) center / 12px 12px no-repeat;\n}\n\n.form-check-input[type=\"radio\"] {\n width: 14px;\n height: 14px;\n border-radius: var(--radius-full);\n}\n\n.form-check-input[type=\"radio\"]:checked {\n border: 2px solid var(--primary);\n background:\n radial-gradient(circle, var(--primary-foreground) 0 2.5px, transparent 3px),\n var(--primary);\n}\n\n.form-check:not(.form-switch) .form-check-input:focus-visible {\n outline: 2px solid var(--ring);\n outline-offset: 2px;\n}\n\n.form-check:not(.form-switch) .form-check-input:disabled {\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.form-check:not(.form-switch) .form-check-input:disabled + .form-check-label {\n cursor: not-allowed;\n}\n\n.form-switch .form-check-input:disabled,\n.form-switch .form-check-input:disabled + .form-check-label {\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n.form-check-label {\n color: var(--foreground);\n cursor: var(--cursor-interaction, default);\n}\n\n.form-switch .form-check-input {\n position: relative;\n width: 32px;\n height: 20px;\n border: 0;\n border-radius: var(--radius-full);\n background: var(--muted);\n box-shadow: none;\n transition: background-color 200ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.form-switch .form-check-input::before {\n position: absolute;\n top: 50%;\n left: 0;\n width: 16px;\n height: 16px;\n box-sizing: border-box;\n border: 1px solid light-dark(var(--primary-foreground), var(--foreground));\n border-radius: var(--radius-full);\n background: light-dark(var(--primary-foreground), var(--foreground));\n box-shadow: var(--shadow-sm);\n content: \"\";\n transform: translate(2px, -50%);\n transition: transform 200ms cubic-bezier(0, 0, 0.2, 1);\n}\n\n.form-switch .form-check-input:checked {\n background: var(--primary);\n}\n\n.form-switch .form-check-input:checked::before {\n transform: translate(14px, -50%);\n}\n\n.form-switch .form-check-input:focus-visible {\n box-shadow: 0 0 0 2px var(--ring);\n}\n\n.form-range {\n appearance: none;\n display: block;\n width: 100%;\n height: 28px;\n flex: 1;\n margin: 0;\n padding: 0;\n outline: none;\n border: 0;\n accent-color: var(--primary);\n background: linear-gradient(\n color-mix(in srgb, var(--foreground) 7%, transparent),\n color-mix(in srgb, var(--foreground) 7%, transparent)\n )\n center / 100% 2px no-repeat;\n}\n\n.form-range::-webkit-slider-runnable-track {\n height: 28px;\n background: transparent;\n}\n\n.form-range::-webkit-slider-thumb {\n appearance: none;\n width: 20px;\n height: 20px;\n margin-top: 4px;\n border: 1px solid var(--border);\n border-radius: var(--radius-full);\n background: light-dark(var(--primary-foreground), var(--foreground));\n}\n\n.form-range:focus-visible::-webkit-slider-thumb {\n border-color: var(--ring);\n box-shadow: inset 0 0 0 1px var(--ring);\n}\n\n.form-range::-moz-range-track {\n height: 28px;\n background: transparent;\n}\n\n.form-range::-moz-range-thumb {\n width: 20px;\n height: 20px;\n border: 1px solid var(--border);\n border-radius: var(--radius-full);\n background: light-dark(var(--primary-foreground), var(--foreground));\n}\n\n.form-range:focus-visible::-moz-range-thumb {\n border-color: var(--ring);\n box-shadow: inset 0 0 0 1px var(--ring);\n}\n\n.form-range:disabled {\n cursor: not-allowed;\n opacity: 0.4;\n}\n\n.btn:not(.btn-primary, .viz-tile):is(\n [aria-pressed=\"true\"],\n [aria-selected=\"true\"],\n .is-selected\n) {\n border-color: var(--primary);\n color: var(--primary-foreground);\n background: var(--primary);\n}\n\n.btn.viz-tile:is([aria-pressed=\"true\"], [aria-selected=\"true\"], .is-selected) {\n border-color: var(--primary);\n box-shadow: inset 0 0 0 1px var(--primary);\n}\n\n.btn:focus-visible,\n.nav-link:focus-visible {\n outline: 2px solid var(--ring);\n outline-offset: 2px;\n}\n\n@media (pointer: coarse) {\n .btn,\n .nav-link,\n .form-control,\n .form-select {\n min-width: 44px;\n min-height: 44px;\n }\n\n /* Keep small-screen WebKit from zooming when a text field receives focus. */\n .form-control,\n .form-select {\n font-size: max(16px, var(--font-size-normal));\n }\n\n .form-control[type=\"file\"]::file-selector-button {\n min-width: 44px;\n min-height: 44px;\n }\n\n .form-control-color[type=\"color\"] {\n width: 44px;\n height: 44px;\n }\n\n .form-control:is(\n [type=\"date\"],\n [type=\"datetime-local\"],\n [type=\"month\"],\n [type=\"time\"],\n [type=\"week\"]\n ) {\n min-width: 0;\n max-width: 100%;\n padding-block: 8px;\n }\n\n .form-check {\n min-height: 44px;\n padding-inline: 15px;\n }\n\n .form-check-input {\n position: relative;\n }\n\n .form-check-input::after {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 44px;\n height: 44px;\n content: \"\";\n transform: translate(-50%, -50%);\n }\n\n .form-check-label {\n display: inline-flex;\n min-width: 44px;\n min-height: 44px;\n align-items: center;\n }\n\n .form-range {\n height: 44px;\n touch-action: pan-y;\n }\n\n .form-range::-webkit-slider-runnable-track {\n height: 44px;\n }\n\n .form-range::-moz-range-track {\n height: 44px;\n }\n\n .form-range::-webkit-slider-thumb {\n margin-top: 12px;\n }\n}\n\nsvg {\n display: block;\n max-width: 100%;\n height: auto;\n}\n\n#widget > svg {\n width: 100%;\n}\n\n/* Model-authored chart rules can otherwise stretch icons after these styles load. */\nsvg.lucide {\n display: block;\n width: var(--icon-size) !important;\n height: var(--icon-size) !important;\n flex: none;\n margin: 0 !important;\n stroke-width: 1.6;\n}\n\n.text-warning,\n.text-destructive {\n color: var(--destructive);\n}\n";
|
|
3
|
+
export const VISUALIZATION_HELPERS = "\n<script src=\"https://unpkg.com/@floating-ui/core@1.7.3/dist/floating-ui.core.umd.min.js\"></script>\n<script src=\"https://unpkg.com/@floating-ui/dom@1.7.4/dist/floating-ui.dom.umd.min.js\"></script>\n<script>\n (() => {\n if (window.FloatingUIDOM == null) {\n return;\n }\n const { autoUpdate, computePosition, flip, offset, shift, size } = window.FloatingUIDOM;\n const tooltipPlacements = new Set([\"top\", \"right\", \"bottom\", \"left\"]);\n const tooltipId = `codex-visualization-tooltip-${\n window.crypto?.randomUUID?.() ?? Date.now().toString(36)\n }`;\n const tooltipGap = 5;\n const hoverDelay = 700;\n const skipDelay = 300;\n let activeTrigger = null;\n let pendingTrigger = null;\n let tooltip = null;\n let openTimeout = null;\n let autoUpdateCleanup = null;\n let positionRequest = 0;\n let skipDelayUntil = 0;\n let lastPointerWasTouch = false;\n let pinnedByTouch = false;\n\n const getTrigger = (target) =>\n target?.nodeType === Node.ELEMENT_NODE ? target.closest(\"[data-tooltip]\") : null;\n const containsTarget = (trigger, target) =>\n target?.nodeType != null && trigger.contains(target);\n const getContent = (trigger) => trigger.getAttribute(\"data-tooltip\")?.trim() ?? \"\";\n const getPlacement = (trigger) => {\n const placement = trigger.getAttribute(\"data-tooltip-placement\");\n return tooltipPlacements.has(placement) ? placement : \"top\";\n };\n const getTooltip = () => {\n if (tooltip == null) {\n tooltip = document.createElement(\"div\");\n tooltip.id = tooltipId;\n tooltip.className = \"tooltip\";\n tooltip.setAttribute(\"role\", \"tooltip\");\n }\n return tooltip;\n };\n const setDescribedBy = (trigger, described) => {\n const ids = new Set(\n (trigger.getAttribute(\"aria-describedby\") ?? \"\").split(/\\s+/).filter(Boolean),\n );\n if (described) {\n ids.add(tooltipId);\n } else {\n ids.delete(tooltipId);\n }\n if (ids.size === 0) {\n trigger.removeAttribute(\"aria-describedby\");\n } else {\n trigger.setAttribute(\"aria-describedby\", [...ids].join(\" \"));\n }\n };\n const clearOpenTimeout = () => {\n if (openTimeout != null) {\n window.clearTimeout(openTimeout);\n openTimeout = null;\n }\n pendingTrigger = null;\n };\n const closeTooltip = (activateSkipDelay = true) => {\n clearOpenTimeout();\n pinnedByTouch = false;\n positionRequest += 1;\n autoUpdateCleanup?.();\n autoUpdateCleanup = null;\n if (activeTrigger == null) {\n return;\n }\n setDescribedBy(activeTrigger, false);\n activeTrigger = null;\n tooltip?.remove();\n if (activateSkipDelay) {\n skipDelayUntil = Date.now() + skipDelay;\n }\n };\n const updatePosition = (trigger, floating) => {\n const request = ++positionRequest;\n void computePosition(trigger, floating, {\n middleware: [\n offset(tooltipGap),\n flip({ padding: tooltipGap }),\n shift({ padding: tooltipGap }),\n size({\n padding: tooltipGap,\n apply({ availableHeight, availableWidth, elements }) {\n elements.floating.style.setProperty(\n \"--tooltip-available-width\",\n `${Math.max(0, availableWidth)}px`,\n );\n elements.floating.style.setProperty(\n \"--tooltip-available-height\",\n `${Math.max(0, availableHeight)}px`,\n );\n },\n }),\n ],\n placement: getPlacement(trigger),\n strategy: \"fixed\",\n })\n .then(({ x, y }) => {\n if (activeTrigger !== trigger || request !== positionRequest) {\n return;\n }\n const scale = window.devicePixelRatio || 1;\n floating.style.transform = `translate(${Math.round(x * scale) / scale}px, ${Math.round(y * scale) / scale}px)`;\n floating.style.visibility = \"visible\";\n })\n .catch(() => {\n if (activeTrigger === trigger && request === positionRequest) {\n closeTooltip(false);\n }\n });\n };\n const openTooltip = (trigger) => {\n const content = getContent(trigger);\n if (!trigger.isConnected || content.length === 0) {\n return;\n }\n clearOpenTimeout();\n if (activeTrigger === trigger) {\n return;\n }\n closeTooltip();\n const floating = getTooltip();\n floating.textContent = content;\n floating.style.visibility = \"hidden\";\n floating.style.transform = \"translate(0, 0)\";\n document.body.appendChild(floating);\n activeTrigger = trigger;\n setDescribedBy(trigger, true);\n autoUpdateCleanup = autoUpdate(trigger, floating, () => {\n updatePosition(trigger, floating);\n });\n };\n const requestOpen = (trigger, immediate = false) => {\n if (\n getContent(trigger).length === 0 ||\n activeTrigger === trigger ||\n pendingTrigger === trigger\n ) {\n return;\n }\n clearOpenTimeout();\n pendingTrigger = trigger;\n const delay =\n immediate || activeTrigger != null || Date.now() < skipDelayUntil ? 0 : hoverDelay;\n if (delay === 0) {\n openTooltip(trigger);\n return;\n }\n openTimeout = window.setTimeout(() => {\n openTimeout = null;\n pendingTrigger = null;\n openTooltip(trigger);\n }, delay);\n };\n const handlePointerOpen = (event) => {\n if (event.pointerType === \"touch\") {\n return;\n }\n const trigger = getTrigger(event.target);\n if (trigger == null || containsTarget(trigger, event.relatedTarget)) {\n return;\n }\n requestOpen(trigger);\n };\n const handlePointer = (event) => {\n lastPointerWasTouch = event.type === \"pointerdown\" && event.pointerType === \"touch\";\n };\n const handleTouchClick = (event) => {\n const isTouch = event.pointerType === \"touch\" || lastPointerWasTouch;\n lastPointerWasTouch = false;\n if (!isTouch || event.detail === 0) {\n return;\n }\n const trigger = getTrigger(event.target);\n if (\n trigger == null ||\n !trigger.isConnected ||\n getContent(trigger).length === 0 ||\n (pinnedByTouch && activeTrigger === trigger)\n ) {\n if (pinnedByTouch) {\n closeTooltip();\n }\n return;\n }\n openTooltip(trigger);\n pinnedByTouch = activeTrigger === trigger;\n window.setTimeout(() => {\n if (activeTrigger === trigger && !trigger.isConnected) {\n closeTooltip(false);\n }\n }, 0);\n };\n const handleLeave = (event) => {\n if (pinnedByTouch) {\n return;\n }\n const trigger = getTrigger(event.target);\n if (trigger == null || containsTarget(trigger, event.relatedTarget)) {\n return;\n }\n if (activeTrigger === trigger || pendingTrigger === trigger) {\n closeTooltip();\n }\n };\n const handleFocusIn = (event) => {\n const trigger = getTrigger(event.target);\n if (trigger?.matches(\":focus-visible\")) {\n requestOpen(trigger, true);\n }\n };\n const handleKeyDown = (event) => {\n if (event.key === \"Escape\") {\n closeTooltip();\n }\n };\n const handleContextMenu = (event) => {\n lastPointerWasTouch = false;\n const trigger = getTrigger(event.target);\n if (activeTrigger === trigger || pendingTrigger === trigger) {\n closeTooltip();\n }\n };\n const destroy = () => {\n closeTooltip(false);\n lastPointerWasTouch = false;\n document.removeEventListener(\"pointerover\", handlePointerOpen);\n document.removeEventListener(\"pointerdown\", handlePointer);\n document.removeEventListener(\"pointercancel\", handlePointer);\n document.removeEventListener(\"click\", handleTouchClick);\n document.removeEventListener(\"pointerout\", handleLeave);\n document.removeEventListener(\"focusin\", handleFocusIn);\n document.removeEventListener(\"focusout\", handleLeave);\n document.removeEventListener(\"keydown\", handleKeyDown);\n document.removeEventListener(\"contextmenu\", handleContextMenu);\n tooltip = null;\n };\n\n document.addEventListener(\"pointerover\", handlePointerOpen);\n document.addEventListener(\"pointerdown\", handlePointer);\n document.addEventListener(\"pointercancel\", handlePointer);\n document.addEventListener(\"click\", handleTouchClick);\n document.addEventListener(\"pointerout\", handleLeave);\n document.addEventListener(\"focusin\", handleFocusIn);\n document.addEventListener(\"focusout\", handleLeave);\n document.addEventListener(\"keydown\", handleKeyDown);\n document.addEventListener(\"contextmenu\", handleContextMenu);\n window.addEventListener(\"pagehide\", destroy, { once: true });\n })();\n</script>\n<script id=\"codex-visualization-tabs\">\n (() => {\n const selector = '.nav[role=\"tablist\"] [role=\"tab\"]';\n const disabled = ':disabled,[aria-disabled=\"true\"]';\n const selectTab = (selected) => {\n const panelId = selected.getAttribute(\"aria-controls\");\n for (const tab of selected.closest('[role=\"tablist\"]').querySelectorAll('[role=\"tab\"]')) {\n const active = tab === selected;\n tab.classList.toggle(\"active\", active);\n tab.setAttribute(\"aria-selected\", String(active));\n const id = tab.getAttribute(\"aria-controls\");\n const panel = id && document.getElementById(id);\n if (panel != null) {\n panel.hidden = id !== panelId;\n if (!panel.hidden && selected.id) {\n panel.setAttribute(\"aria-labelledby\", selected.id);\n }\n }\n }\n };\n const interact = (event) => {\n const tab = event.target?.closest?.(selector);\n if (event.defaultPrevented || tab == null || tab.matches(disabled)) {\n return;\n }\n if (event.type === \"click\") {\n selectTab(tab);\n return;\n }\n const tabs = Array.from(\n tab.closest('[role=\"tablist\"]').querySelectorAll('[role=\"tab\"]'),\n ).filter((candidate) => !candidate.matches(disabled));\n const current = tabs.indexOf(tab);\n let next;\n if (event.key === \"ArrowRight\" || event.key === \"ArrowDown\") {\n next = (current + 1) % tabs.length;\n } else if (event.key === \"ArrowLeft\" || event.key === \"ArrowUp\") {\n next = (current + tabs.length - 1) % tabs.length;\n } else if (event.key === \"Home\") {\n next = 0;\n } else if (event.key === \"End\") {\n next = tabs.length - 1;\n } else {\n return;\n }\n event.preventDefault();\n tabs[next].focus();\n selectTab(tabs[next]);\n };\n\n for (const list of document.querySelectorAll('.nav[role=\"tablist\"]')) {\n const selected =\n list.querySelector('[role=\"tab\"][aria-selected=\"true\"]') ??\n list.querySelector('[role=\"tab\"].active') ??\n list.querySelector('[role=\"tab\"]');\n if (selected != null) {\n selectTab(selected);\n }\n }\n document.addEventListener(\"click\", interact);\n document.addEventListener(\"keydown\", interact);\n window.addEventListener(\n \"pagehide\",\n () => {\n document.removeEventListener(\"click\", interact);\n document.removeEventListener(\"keydown\", interact);\n },\n { once: true },\n );\n })();\n</script>\n<script\n id=\"codex-visualization-lucide\"\n async\n src=\"https://unpkg.com/lucide@1.17.0/dist/umd/lucide.js\"\n></script>\n<script>\n (() => {\n const initialize = () => {\n globalThis.lucide?.createIcons({ attrs: { width: 16, height: 16 } });\n };\n if (globalThis.lucide != null) {\n initialize();\n return;\n }\n document\n .getElementById(\"codex-visualization-lucide\")\n ?.addEventListener(\"load\", initialize, { once: true });\n })();\n</script>\n";
|
|
@@ -567,7 +567,12 @@ export function ComputerViewer({
|
|
|
567
567
|
if (relevant[0]) selectComputerSession({ sessionId: relevant[0].id, pinned: false });
|
|
568
568
|
}}
|
|
569
569
|
onCreate={hideGenericCreate ? undefined : createComputer}
|
|
570
|
-
onRefresh={() =>
|
|
570
|
+
onRefresh={() => {
|
|
571
|
+
if (frames.state === "error" && !generationLossSelected && !generationLossFrames) {
|
|
572
|
+
frames.reconnect();
|
|
573
|
+
}
|
|
574
|
+
void Promise.all([refreshRegistry(), refreshComputer()]);
|
|
575
|
+
}}
|
|
571
576
|
/>
|
|
572
577
|
<InteractionInterventionBanner
|
|
573
578
|
interventions={selectedInterventions}
|
|
@@ -1031,8 +1036,11 @@ function ComputerViewport(props: {
|
|
|
1031
1036
|
actionRef.current = props.onAction;
|
|
1032
1037
|
readClipboardRef.current = props.onReadClipboard;
|
|
1033
1038
|
errorRef.current = props.onError;
|
|
1039
|
+
const streamFailed = props.connectionState === "error";
|
|
1034
1040
|
const rawInputEnabled =
|
|
1035
|
-
!
|
|
1041
|
+
!streamFailed &&
|
|
1042
|
+
!props.machineLocked &&
|
|
1043
|
+
(!props.backgroundActions || props.target?.kind === "screen" || props.target?.focused === true);
|
|
1036
1044
|
|
|
1037
1045
|
const paintQueuedFrames = useCallback(() => {
|
|
1038
1046
|
if (decodingFrameRef.current) return;
|
|
@@ -1346,7 +1354,7 @@ function ComputerViewport(props: {
|
|
|
1346
1354
|
if (inputRef.current) inputRef.current.value = "";
|
|
1347
1355
|
};
|
|
1348
1356
|
|
|
1349
|
-
const showCanvas = props.frame !== null && !props.machineLocked;
|
|
1357
|
+
const showCanvas = props.frame !== null && !props.machineLocked && !streamFailed;
|
|
1350
1358
|
return (
|
|
1351
1359
|
<div className="relative min-h-0 flex-1 overflow-hidden bg-black">
|
|
1352
1360
|
<canvas
|
|
@@ -142,11 +142,16 @@ export function CopyHoverFrame({
|
|
|
142
142
|
<div
|
|
143
143
|
data-og-annotation-chrome=""
|
|
144
144
|
className={cn(
|
|
145
|
-
"
|
|
145
|
+
"flex h-6 items-center gap-1.5 pointer-coarse:h-11",
|
|
146
146
|
align === "end" ? "justify-end" : "justify-start",
|
|
147
147
|
)}
|
|
148
148
|
>
|
|
149
|
-
<CopyButton
|
|
149
|
+
<CopyButton
|
|
150
|
+
text={copyText}
|
|
151
|
+
label={label}
|
|
152
|
+
reveal="group-hover"
|
|
153
|
+
className="size-6 pointer-coarse:size-11"
|
|
154
|
+
/>
|
|
150
155
|
{trailing}
|
|
151
156
|
</div>
|
|
152
157
|
</div>
|