@tangle-network/sandbox-ui 2.0.11 → 2.0.12

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.
@@ -1,55 +0,0 @@
1
- import { useLayoutEffect, useState } from "react";
2
- // src/workflows/elk-loader.ts
3
- /** One ELK instance per page. `null` once loading failed, so a host without
4
- * the peer pays for one failed import, not one per render. */
5
- let elkInstance;
6
- function loadElk() {
7
- elkInstance ??= import("elkjs/lib/elk.bundled.js").then((mod) => {
8
- const Elk = mod.default;
9
- return new Elk();
10
- }).catch(() => null);
11
- return elkInstance;
12
- }
13
- // src/workflows/canvas-theme.ts
14
- /** Motion is opt-OUT, so it is only used where the reader's preference can be
15
- * read and says nothing against it. Somewhere without `matchMedia` cannot say
16
- * a reader tolerates movement, so it gets none. */
17
- function motionAllowed() {
18
- return typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches === false;
19
- }
20
- /** React Flow adds its own .light/.dark class below the graph wrapper. Read
21
- * that wrapper's inherited scheme so a nested WorkspaceLayout theme wins over
22
- * the page root without React Flow's class influencing the answer. */
23
- function currentColorMode(anchor) {
24
- if (typeof document === "undefined" || typeof window === "undefined") return "light";
25
- const scheme = window.getComputedStyle(anchor ?? document.documentElement).colorScheme;
26
- if (scheme.startsWith("dark")) return "dark";
27
- if (scheme.startsWith("light")) return "light";
28
- return (anchor ?? document.documentElement).closest(".dark") ? "dark" : "light";
29
- }
30
- function useColorMode(wrapperRef, hasGraph) {
31
- const [mode, setMode] = useState(() => currentColorMode(null));
32
- useLayoutEffect(() => {
33
- const anchor = hasGraph ? wrapperRef.current : null;
34
- const update = () => setMode(currentColorMode(anchor));
35
- update();
36
- const observer = new MutationObserver(update);
37
- for (let el = anchor ?? document.documentElement; el; el = el.parentElement) observer.observe(el, {
38
- attributes: true,
39
- attributeFilter: [
40
- "class",
41
- "data-theme",
42
- "data-sandbox-theme",
43
- "style"
44
- ]
45
- });
46
- return () => observer.disconnect();
47
- }, [wrapperRef, hasGraph]);
48
- return mode;
49
- }
50
- /** Selection preserves the status border and stays quieter than failure or a response request. */
51
- const SELECTION_OUTLINE = {
52
- outline: "1px solid hsl(var(--foreground) / .45)",
53
- outlineOffset: 2
54
- };
55
- export { loadElk as i, motionAllowed as n, useColorMode as r, SELECTION_OUTLINE as t };
@@ -1,169 +0,0 @@
1
- import { g as useRunNow, o as fmtEventTime, p as tokenMilliseconds } from "./AgentGraph-CFlI9qta.js";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
4
- import { RunStatusIcon, statusMeta } from "@tangle-network/ui/run";
5
- // src/run/latest-events.tsx
6
- function EventRow({ entry, now, onSelect }) {
7
- const meta = statusMeta(entry.observed ? entry.status : "unknown"), age = fmtEventTime(entry.at, now);
8
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("button", {
9
- type: "button",
10
- disabled: !onSelect,
11
- onClick: () => onSelect?.(entry),
12
- title: entry.name + ": " + entry.label,
13
- children: [
14
- /* @__PURE__ */ jsx("span", {
15
- className: "ag-latest-dot",
16
- style: {
17
- background: entry.observed ? "var(" + meta.token + ")" : "transparent",
18
- border: entry.observed ? void 0 : "1.5px solid var(" + meta.token + ")"
19
- },
20
- "aria-hidden": true
21
- }),
22
- /* @__PURE__ */ jsx("strong", { children: entry.name }),
23
- entry.observed && /* @__PURE__ */ jsxs("span", {
24
- className: "ag-latest-state",
25
- style: { color: "var(" + meta.token + ")" },
26
- children: [entry.status !== "running" && /* @__PURE__ */ jsx(RunStatusIcon, {
27
- status: entry.status,
28
- size: 14,
29
- "aria-hidden": true
30
- }), meta.label]
31
- }),
32
- /* @__PURE__ */ jsx("span", {
33
- className: "ag-latest-label",
34
- children: entry.label
35
- }),
36
- /* @__PURE__ */ jsxs("time", { children: [
37
- entry.observed ? "Observed " : "",
38
- age,
39
- age !== "now" && age !== "—" ? " ago" : ""
40
- ] })
41
- ]
42
- }) });
43
- }
44
- /** Recorded events and locally observed state changes. Hover or focus holds the reading position. */
45
- function LatestEvents({ agents, n = 5, now, live = now === void 0, selectedId, onSelect }) {
46
- const clock = useRunNow(now), limit = Number.isFinite(n) ? Math.max(1, Math.trunc(n)) : 5;
47
- const latest = useMemo(() => agents.flatMap((agent) => (agent.events ?? []).map((event) => ({
48
- id: agent.id + ":" + event.id,
49
- agentId: agent.id,
50
- name: agent.label,
51
- label: event.label,
52
- at: event.at,
53
- status: agent.status
54
- }))).sort((a, b) => (Number.isFinite(b.at) ? b.at : -Infinity) - (Number.isFinite(a.at) ? a.at : -Infinity) || a.id.localeCompare(b.id)).slice(0, limit), [agents, limit]);
55
- const [rows, setRows] = useState(latest), [pins, setPins] = useState([]), [announcement, setAnnouncement] = useState("");
56
- const [hovered, setHovered] = useState(false), [focused, setFocused] = useState(false), paused = hovered || focused;
57
- const source = useRef(latest), pending = useRef(void 0);
58
- const announce = useRef(void 0), messages = useRef(/* @__PURE__ */ new Map());
59
- source.current = latest;
60
- const previous = useRef(new Map(agents.map((agent) => [agent.id, agent.status])));
61
- useEffect(() => {
62
- const changes = agents.filter((agent) => previous.current.has(agent.id) && previous.current.get(agent.id) !== agent.status).map((agent) => ({
63
- id: agent.id + ":status:" + clock,
64
- agentId: agent.id,
65
- name: agent.label,
66
- status: agent.status,
67
- label: agent.result ?? agent.turn ?? "Status changed",
68
- at: clock,
69
- observed: true
70
- }));
71
- previous.current = new Map(agents.map((agent) => [agent.id, agent.status]));
72
- if (!live) {
73
- setPins((old) => old.length ? [] : old);
74
- messages.current.clear();
75
- clearTimeout(announce.current);
76
- announce.current = void 0;
77
- return;
78
- }
79
- const ids = new Set(agents.map((agent) => agent.id));
80
- setPins((old) => {
81
- const next = [...changes, ...old.filter((entry) => ids.has(entry.agentId) && !changes.some((change) => change.agentId === entry.agentId))].slice(0, limit);
82
- return !changes.length && next.length === old.length ? old : next;
83
- });
84
- if (!changes.length) return;
85
- for (const entry of changes) messages.current.set(entry.agentId, entry.name + ": " + statusMeta(entry.status).label);
86
- if (announce.current === void 0) announce.current = setTimeout(() => {
87
- setAnnouncement([...messages.current.values()].join("; "));
88
- messages.current.clear();
89
- announce.current = void 0;
90
- }, tokenMilliseconds("--duration-ambient"));
91
- }, [
92
- agents,
93
- clock,
94
- limit,
95
- live
96
- ]);
97
- useEffect(() => {
98
- if (selectedId) setPins((old) => old.filter((entry) => entry.agentId !== selectedId));
99
- }, [selectedId]);
100
- useEffect(() => {
101
- if (paused) {
102
- clearTimeout(pending.current);
103
- pending.current = void 0;
104
- return;
105
- }
106
- if (pending.current === void 0) pending.current = setTimeout(() => {
107
- setRows(source.current);
108
- pending.current = void 0;
109
- }, tokenMilliseconds("--duration-ambient") / 2);
110
- }, [latest, paused]);
111
- useEffect(() => () => {
112
- clearTimeout(pending.current);
113
- clearTimeout(announce.current);
114
- }, []);
115
- const current = [...pins, ...rows.filter((entry) => !pins.some((pin) => pin.agentId === entry.agentId))].slice(0, limit);
116
- const held = useRef(current);
117
- useLayoutEffect(() => {
118
- if (!paused) held.current = current;
119
- }, [current, paused]);
120
- const visible = paused ? held.current : current;
121
- const refresh = () => {
122
- setRows([...source.current]);
123
- held.current = [...pins, ...source.current.filter((entry) => !pins.some((pin) => pin.agentId === entry.agentId))].slice(0, limit);
124
- };
125
- return /* @__PURE__ */ jsxs("section", {
126
- className: "ag-latest",
127
- "aria-label": "Latest activity",
128
- tabIndex: 0,
129
- onPointerEnter: () => setHovered(true),
130
- onPointerLeave: () => setHovered(false),
131
- onFocusCapture: () => setFocused(true),
132
- onBlurCapture: (event) => {
133
- if (!event.currentTarget.contains(event.relatedTarget)) setFocused(false);
134
- },
135
- children: [
136
- /* @__PURE__ */ jsxs("header", { children: [
137
- /* @__PURE__ */ jsx("strong", { children: "Latest activity" }),
138
- /* @__PURE__ */ jsx("span", { children: paused ? "Paused while reading" : "Recorded events · age" }),
139
- paused && /* @__PURE__ */ jsx("button", {
140
- type: "button",
141
- onClick: refresh,
142
- children: "Show latest"
143
- })
144
- ] }),
145
- /* @__PURE__ */ jsx("ol", {
146
- tabIndex: 0,
147
- "aria-label": "Recorded activity events",
148
- children: visible.length ? visible.map((entry) => /* @__PURE__ */ jsx(EventRow, {
149
- entry,
150
- now: clock,
151
- onSelect: onSelect ? (item) => {
152
- setPins((old) => old.filter((pin) => pin.agentId !== item.agentId));
153
- onSelect(item.agentId);
154
- } : void 0
155
- }, entry.id)) : /* @__PURE__ */ jsx("li", {
156
- className: "ag-latest-empty",
157
- children: "No activity events were reported."
158
- })
159
- }),
160
- /* @__PURE__ */ jsx("span", {
161
- className: "sr-only",
162
- role: "status",
163
- "aria-live": "polite",
164
- children: announcement
165
- })
166
- ]
167
- });
168
- }
169
- export { LatestEvents as t };
@@ -1,6 +0,0 @@
1
- // src/lib/motion.ts
2
- /** Brand owns complete duration/easing roles. Keep properties explicit. */
3
- const MOTION_CONTROL = "[transition:color_var(--motion-control),background-color_var(--motion-control),border-color_var(--motion-control),box-shadow_var(--motion-control),transform_var(--motion-control),scale_var(--motion-control),opacity_var(--motion-control)] motion-reduce:transition-none";
4
- /** Technical floating surfaces may change opacity/transform, never layout. */
5
- const MOTION_SURFACE = "[transition:opacity_var(--motion-surface),transform_var(--motion-surface)] motion-reduce:transition-none";
6
- export { MOTION_SURFACE as n, MOTION_CONTROL as t };