@tangle-network/ui 11.9.0 → 11.11.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 (155) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +14 -0
  3. package/dist/active-sessions-store-Gt1R0rFG.js +262 -0
  4. package/dist/{active-sessions-store-CeOmXgv5.d.ts → active-sessions-store-nl70ZnMC.d.ts} +40 -41
  5. package/dist/artifact-pane-BL_DFWNl.d.ts +32 -0
  6. package/dist/artifact-pane-DMXT9a8U.js +70 -0
  7. package/dist/auth-DixfCMCk.js +154 -0
  8. package/dist/auth.d.ts +2 -74
  9. package/dist/auth.js +2 -15
  10. package/dist/branding-26d5ARIr.d.ts +14 -0
  11. package/dist/button-uhNnwdsD.js +78 -0
  12. package/dist/button-yoIv77e2.d.ts +16 -0
  13. package/dist/chat-CPLL0Fd9.js +667 -0
  14. package/dist/chat.d.ts +2 -201
  15. package/dist/chat.js +2 -30
  16. package/dist/code-block-B9miUPht.d.ts +23 -0
  17. package/dist/code-block-CngSn37j.js +165 -0
  18. package/dist/diff-preview-cySuqowW.js +533 -0
  19. package/dist/document-editor-pane-BcoABlhn.d.ts +131 -0
  20. package/dist/document-editor-pane-Cz6oEF1o.js +1287 -0
  21. package/dist/dropdown-menu-BpcLa5vF.js +101 -0
  22. package/dist/editor.d.ts +76 -78
  23. package/dist/editor.js +2 -33
  24. package/dist/file-format-BgXbr-Ib.js +160 -0
  25. package/dist/files-CYlOo0mE.js +743 -0
  26. package/dist/files.d.ts +2 -243
  27. package/dist/files.js +3 -40
  28. package/dist/focus-Cw02pNSr.js +56 -0
  29. package/dist/format-DfcLWqMa.js +54 -0
  30. package/dist/hooks.d.ts +30 -37
  31. package/dist/hooks.js +111 -45
  32. package/dist/index-2UntyjBb.d.ts +52 -0
  33. package/dist/index-COgqsFAQ.d.ts +42 -0
  34. package/dist/index-CPDET_s1.d.ts +549 -0
  35. package/dist/index-CUhfHT_V.d.ts +204 -0
  36. package/dist/index-Cg6gYAqh.d.ts +73 -0
  37. package/dist/index-Cq-EJzqW.d.ts +16 -0
  38. package/dist/index-DhYmSaLF.d.ts +245 -0
  39. package/dist/index-DjKxO357.d.ts +128 -0
  40. package/dist/index-b56ew9aF.d.ts +107 -0
  41. package/dist/index.d.ts +26 -43
  42. package/dist/index.js +35 -460
  43. package/dist/markdown-BprL96Gl.js +45 -0
  44. package/dist/markdown.d.ts +3 -18
  45. package/dist/markdown.js +3 -14
  46. package/dist/message-vhUI0c5G.d.ts +16 -0
  47. package/dist/nav.d.ts +6 -8
  48. package/dist/nav.js +29 -11
  49. package/dist/openui-artifact-renderer-D3E5bIAI.d.ts +114 -0
  50. package/dist/openui-artifact-renderer-DT4xbvWt.js +266 -0
  51. package/dist/openui.d.ts +2 -115
  52. package/dist/openui.js +2 -12
  53. package/dist/parts-5mhy9yJ3.d.ts +37 -0
  54. package/dist/primitives-DE-blUz-.js +1239 -0
  55. package/dist/primitives.d.ts +5 -523
  56. package/dist/primitives.js +9 -211
  57. package/dist/redaction-CGGB2ENG.js +74 -0
  58. package/dist/redaction.d.ts +2 -42
  59. package/dist/redaction.js +2 -7
  60. package/dist/run-OyWmIDqu.d.ts +41 -0
  61. package/dist/run-ZsIKPA6J.js +17 -0
  62. package/dist/run-group-D1InSdQu.js +410 -0
  63. package/dist/run.d.ts +3 -126
  64. package/dist/run.js +5 -39
  65. package/dist/sdk-hooks.d.ts +2 -285
  66. package/dist/sdk-hooks.js +3 -35
  67. package/dist/stores.d.ts +13 -14
  68. package/dist/stores.js +34 -76
  69. package/dist/table-DHyqDPbU.js +146 -0
  70. package/dist/tabs-ujuqAdtb.js +40 -0
  71. package/dist/text-shimmer-BUUo6I-g.js +64 -0
  72. package/dist/tool-call-feed-BeB1_4pX.d.ts +47 -0
  73. package/dist/tool-call-feed-C1W1N54c.js +109 -0
  74. package/dist/tool-call-step-Bi3_YJRV.js +434 -0
  75. package/dist/tool-display-BAuAVa43.js +158 -0
  76. package/dist/{tool-display-z4JcDmMQ.d.ts → tool-display-DgmL5rIU.d.ts} +16 -16
  77. package/dist/tool-previews.d.ts +2 -48
  78. package/dist/tool-previews.js +2 -22
  79. package/dist/types.d.ts +6 -19
  80. package/dist/types.js +0 -1
  81. package/dist/use-auto-scroll-C5Pjeqon.js +153 -0
  82. package/dist/use-sse-stream-BjVBDbxK.js +884 -0
  83. package/dist/use-sse-stream-Dm6R5YWz.d.ts +282 -0
  84. package/dist/utils-Bl_CZ0Qp.js +37 -0
  85. package/dist/{chunk-RQHJBTEU.js → utils-C_uf36nf.js} +4 -6
  86. package/dist/utils.d.ts +2 -51
  87. package/dist/utils.js +6 -32
  88. package/package.json +39 -41
  89. package/src/auth/auth.tsx +5 -1
  90. package/src/chat/agent-timeline.tsx +6 -1
  91. package/src/chat/chat-container.tsx +2 -1
  92. package/src/editor/document-editor-pane.test.tsx +3 -1
  93. package/src/editor/document-editor-pane.tsx +5 -1
  94. package/src/editor/markdown-document-editor.test.tsx +9 -4
  95. package/src/files/file-artifact-pane.tsx +3 -2
  96. package/src/files/file-preview.tsx +3 -1
  97. package/src/files/file-tabs.tsx +9 -2
  98. package/src/lib/focus.ts +63 -0
  99. package/src/markdown/code-block.tsx +5 -1
  100. package/src/primitives/badge.tsx +2 -1
  101. package/src/primitives/button.tsx +2 -1
  102. package/src/primitives/card.tsx +1 -2
  103. package/src/primitives/dialog.tsx +7 -1
  104. package/src/primitives/input.tsx +15 -14
  105. package/src/primitives/segmented-control.tsx +5 -3
  106. package/src/primitives/select.tsx +3 -1
  107. package/src/primitives/switch.tsx +3 -1
  108. package/src/primitives/tabs.tsx +6 -4
  109. package/src/primitives/terminal-display.tsx +6 -8
  110. package/src/primitives/toast.tsx +5 -1
  111. package/src/tool-previews/command-preview.tsx +5 -1
  112. package/src/tool-previews/web-search-preview.tsx +2 -1
  113. package/src/utils/index.ts +7 -0
  114. package/dist/artifact-pane-DpuWcAiF.d.ts +0 -33
  115. package/dist/button-CMQuQEW_.d.ts +0 -17
  116. package/dist/chunk-34A66VBG.js +0 -214
  117. package/dist/chunk-3OI2QKFD.js +0 -0
  118. package/dist/chunk-3TI5DEHV.js +0 -299
  119. package/dist/chunk-4CLN43XT.js +0 -45
  120. package/dist/chunk-565EATZZ.js +0 -156
  121. package/dist/chunk-5Z5ZYMOJ.js +0 -0
  122. package/dist/chunk-6BGQA4BQ.js +0 -0
  123. package/dist/chunk-7YOCS6IF.js +0 -728
  124. package/dist/chunk-EOAX2ENE.js +0 -60
  125. package/dist/chunk-GYPQXTJU.js +0 -230
  126. package/dist/chunk-HFL6R6IF.js +0 -37
  127. package/dist/chunk-HGML45QH.js +0 -104
  128. package/dist/chunk-KNYSKNZX.js +0 -550
  129. package/dist/chunk-L57WRIND.js +0 -59
  130. package/dist/chunk-LDLOJKPC.js +0 -1585
  131. package/dist/chunk-LTEKI7YJ.js +0 -59
  132. package/dist/chunk-MKTSMWVD.js +0 -109
  133. package/dist/chunk-ND3ZFXQK.js +0 -179
  134. package/dist/chunk-NKDZ7GZE.js +0 -192
  135. package/dist/chunk-NWECTSOH.js +0 -589
  136. package/dist/chunk-OEX7NZE3.js +0 -321
  137. package/dist/chunk-Q56BYXQF.js +0 -61
  138. package/dist/chunk-REJESC5U.js +0 -117
  139. package/dist/chunk-RQGKSCEZ.js +0 -0
  140. package/dist/chunk-TN4FUEWY.js +0 -437
  141. package/dist/chunk-VPWY4I5O.js +0 -1048
  142. package/dist/chunk-WUQDUBJG.js +0 -168
  143. package/dist/chunk-XGKULLYE.js +0 -40
  144. package/dist/chunk-XU3HB5QL.js +0 -127
  145. package/dist/chunk-XYAIX4SU.js +0 -133
  146. package/dist/chunk-YJ6RE5WV.js +0 -875
  147. package/dist/chunk-YTO5V6QS.js +0 -19
  148. package/dist/chunk-ZKCEAIIZ.js +0 -1395
  149. package/dist/code-block-0kSpWMnf.d.ts +0 -25
  150. package/dist/document-editor-pane-EX25CEYW.js +0 -12
  151. package/dist/document-editor-pane-IAEQn_Dl.d.ts +0 -128
  152. package/dist/message-BHWbxBtT.d.ts +0 -15
  153. package/dist/parts-dj7AcUg0.d.ts +0 -36
  154. package/dist/run-PfLmDAox.d.ts +0 -41
  155. package/dist/tool-call-feed-D9iofJgW.d.ts +0 -46
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @tangle-network/ui
2
2
 
3
+ ## 11.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - dc84d1c: Update every dependency to its latest release and build with tsdown on TypeScript 7.
8
+ `@tangle-network/ui` now accepts `@nanostores/react` 2 as a peer, moves to lucide-react 1 and marked 18, and drops the unused `react-pdf` and `@radix-ui/react-toast` dependencies.
9
+ Export paths are unchanged; internal chunk file names differ.
10
+
11
+ ## 11.10.0
12
+
13
+ ### Minor Changes
14
+
15
+ - 4649d22: Replace the hard 2px indigo focus ring with one soft focus treatment for every control.
16
+
17
+ brand adds `--focus-border`, `--focus-halo`, `--focus-border-danger`, `--focus-halo-danger` and `--border-strong`. Each derives from the ring, danger-ink, border and foreground tokens, so every theme, named theme and light island resolves its own values. The focus border clears 3:1 against the field in every theme, which `focus.test.ts` enforces.
18
+
19
+ brand's `globals.css` also gives any control that styles no focus of its own (a hand-rolled button, link, radio card or tab) the same keyboard focus line and halo in the base layer, in place of the browser's blue outline. Component utilities still override it.
20
+
21
+ ui exports `focusField`, `focusFieldWithin`, `focusFieldInvalid`, `focusRing` and `focusRingInset` from `utils`, and the primitives use them:
22
+
23
+ - `Input`, `Textarea`, `SelectTrigger` and `TerminalInput` rest on the neutral `border-border` hairline instead of the muted-text `border-input`, darken slightly on hover, and on focus shift the border to `--focus-border` with a 3px `--focus-halo` ring. The `default` and `sandbox` variants now render the same field.
24
+ - `Button`, `Tabs`, `Switch`, `Badge`, `SegmentedControl`, the dialog and toast close buttons, the auth menu trigger, and the chat and file controls show a 1px focus line with the same halo on `:focus-visible` only. A mouse click no longer draws a ring.
25
+ - Interactive `Card`, tool-preview and code-block hovers darken the border instead of tinting it indigo.
26
+
27
+ A consumer that removed the old ring with `focus-visible:ring-0` on a field should pass `focus:ring-0` instead, because the field ring now keys off `:focus`.
28
+
29
+ ### Patch Changes
30
+
31
+ - 53add99: `focusFieldWithin` lights the container only while a field inside it has focus: a text input, textarea, select or contenteditable editor. It used `:focus-within`, so clicking a composer's send button drew the field ring around the whole composer, and tabbing to that button showed two indicators. A focused button, checkbox or button-type input inside the container now shows only its own ring. Because the rule keys off `:has()`, a consumer's `focus-within:*` class does not override it; compose your own classes for a different container focus.
32
+
3
33
  ## 11.9.0
4
34
 
5
35
  ### Minor Changes
package/README.md CHANGED
@@ -69,6 +69,20 @@ One consequence worth knowing. This is a scan, not a manifest, so a consumer emi
69
69
 
70
70
  See [`@tangle-network/brand`'s README](../brand/README.md) for the token-level breakdown, the finer-grained imports, and the fonts, which brand deliberately does not bundle.
71
71
 
72
+ ### Focus treatment
73
+
74
+ Every control shares one focus treatment, exported from `utils` as class strings.
75
+ Compose them with `cn` so tailwind-merge resolves any override.
76
+
77
+ - `focusField` — a text field: neutral hairline, a slightly darker border on hover, and on `:focus` a `--focus-border` border with a 3px `--focus-halo` ring.
78
+ - `focusFieldWithin` — the same, for a container that wraps a borderless field, such as a composer around a textarea. It lights while a text input, textarea, native `<select>` or contenteditable editor inside it has focus, not while a button inside it does. It keys off `:has()`, so a `focus-within:*` class does not override it.
79
+ - `focusFieldInvalid` — the error state of a field. Compose it after `focusField`.
80
+ - `focusRing` — keyboard focus on a button, tab, switch or link: a 1px `--focus-border` outline with the halo beyond it, on `:focus-visible` only.
81
+ - `focusRingInset` — `focusRing` drawn inside the box, for a control in a scrolling strip.
82
+
83
+ The colors come from the `--focus-*` tokens in `@tangle-network/brand`, so they need brand 1.6 or later.
84
+ To remove the ring from a field nested in a focusable container, pass `focus:ring-0 border-0` and put `focusFieldWithin` on the container.
85
+
72
86
  ## Subpaths
73
87
 
74
88
  Sixteen named exports: `primitives`, `chat`, `run`, `openui`, `files`, `editor`, `markdown`, `auth`, `hooks`, `sdk-hooks`, `stores`, `types`, `utils`, `tool-previews`, `nav`, `redaction`.
@@ -0,0 +1,262 @@
1
+ import { useMemo } from "react";
2
+ import { useStore } from "@nanostores/react";
3
+ import { atom } from "nanostores";
4
+ //#region src/stores/active-sessions-store.ts
5
+ const INITIAL_STATE = {
6
+ sessions: {},
7
+ lastUpdatedAt: 0
8
+ };
9
+ const STATUS_PRIORITY = {
10
+ running: 0,
11
+ error: 1,
12
+ "attention-needed": 2,
13
+ idle: 3
14
+ };
15
+ const DEFAULT_RECORD = {
16
+ status: "idle",
17
+ isRunning: false,
18
+ isForeground: false,
19
+ needsAttention: false,
20
+ connectionState: "disconnected",
21
+ reconnectState: "idle",
22
+ transportMode: null,
23
+ lastError: null,
24
+ lastEventAt: null
25
+ };
26
+ const activeSessionsAtom = atom(INITIAL_STATE);
27
+ let foregroundSessionId = null;
28
+ function createRecord(options, now) {
29
+ return {
30
+ sessionId: options.sessionId,
31
+ projectId: options.projectId ?? null,
32
+ projectLabel: options.projectLabel,
33
+ title: options.title,
34
+ href: options.href,
35
+ registeredAt: now,
36
+ lastActivityAt: now,
37
+ metadata: options.metadata,
38
+ ...DEFAULT_RECORD,
39
+ isForeground: options.sessionId === foregroundSessionId
40
+ };
41
+ }
42
+ function resolveStatus(session) {
43
+ if (session.isRunning) return "running";
44
+ if (session.lastError || session.reconnectState === "failed") return "error";
45
+ if (session.needsAttention) return "attention-needed";
46
+ return "idle";
47
+ }
48
+ function normalizeSession(session) {
49
+ return {
50
+ ...session,
51
+ status: resolveStatus(session)
52
+ };
53
+ }
54
+ function updateSession(sessionId, updater) {
55
+ const current = activeSessionsAtom.get();
56
+ const existing = current.sessions[sessionId];
57
+ if (!existing) return;
58
+ const now = Date.now();
59
+ activeSessionsAtom.set({
60
+ sessions: {
61
+ ...current.sessions,
62
+ [sessionId]: normalizeSession(updater(existing, now))
63
+ },
64
+ lastUpdatedAt: now
65
+ });
66
+ }
67
+ function registerActiveSession(options) {
68
+ const now = Date.now();
69
+ const current = activeSessionsAtom.get();
70
+ const existing = current.sessions[options.sessionId];
71
+ activeSessionsAtom.set({
72
+ sessions: {
73
+ ...current.sessions,
74
+ [options.sessionId]: normalizeSession(existing ? {
75
+ ...existing,
76
+ projectId: existing.projectId ?? options.projectId ?? null,
77
+ projectLabel: options.projectLabel ?? existing.projectLabel,
78
+ title: options.title ?? existing.title,
79
+ href: options.href ?? existing.href,
80
+ metadata: options.metadata ?? existing.metadata,
81
+ lastActivityAt: now,
82
+ isForeground: options.sessionId === foregroundSessionId || existing.isForeground
83
+ } : createRecord(options, now))
84
+ },
85
+ lastUpdatedAt: now
86
+ });
87
+ }
88
+ function unregisterActiveSession(sessionId) {
89
+ const current = activeSessionsAtom.get();
90
+ if (!current.sessions[sessionId]) return;
91
+ const { [sessionId]: _removed, ...remaining } = current.sessions;
92
+ if (foregroundSessionId === sessionId) foregroundSessionId = null;
93
+ activeSessionsAtom.set({
94
+ sessions: remaining,
95
+ lastUpdatedAt: Date.now()
96
+ });
97
+ }
98
+ function setForegroundActiveSession(sessionId) {
99
+ foregroundSessionId = sessionId;
100
+ const current = activeSessionsAtom.get();
101
+ const now = Date.now();
102
+ let changed = false;
103
+ const sessions = Object.fromEntries(Object.entries(current.sessions).map(([id, session]) => {
104
+ const isForeground = id === sessionId;
105
+ if (session.isForeground !== isForeground) changed = true;
106
+ return [id, {
107
+ ...session,
108
+ isForeground,
109
+ lastActivityAt: isForeground ? now : session.lastActivityAt
110
+ }];
111
+ }));
112
+ if (!changed) return;
113
+ activeSessionsAtom.set({
114
+ sessions,
115
+ lastUpdatedAt: now
116
+ });
117
+ }
118
+ function updateActiveSessionMeta(sessionId, meta) {
119
+ updateSession(sessionId, (session, now) => ({
120
+ ...session,
121
+ ...meta,
122
+ lastActivityAt: now
123
+ }));
124
+ }
125
+ function setActiveSessionConnection(sessionId, options) {
126
+ updateSession(sessionId, (session, now) => ({
127
+ ...session,
128
+ connectionState: options.connectionState,
129
+ reconnectState: options.reconnectState ?? session.reconnectState,
130
+ transportMode: options.transportMode ?? session.transportMode,
131
+ lastError: options.lastError === void 0 ? session.lastError : options.lastError,
132
+ lastEventAt: options.lastEventAt ?? session.lastEventAt,
133
+ lastActivityAt: now
134
+ }));
135
+ }
136
+ function setActiveSessionRunning(sessionId, isRunning, options) {
137
+ updateSession(sessionId, (session, now) => ({
138
+ ...session,
139
+ isRunning,
140
+ needsAttention: isRunning ? false : session.needsAttention,
141
+ lastError: isRunning ? null : session.lastError,
142
+ lastEventAt: options?.lastEventAt ?? session.lastEventAt,
143
+ lastActivityAt: now
144
+ }));
145
+ }
146
+ function setActiveSessionAttention(sessionId, needsAttention, options) {
147
+ updateSession(sessionId, (session, now) => ({
148
+ ...session,
149
+ needsAttention,
150
+ isRunning: needsAttention ? false : session.isRunning,
151
+ lastEventAt: options?.lastEventAt ?? session.lastEventAt,
152
+ lastActivityAt: now
153
+ }));
154
+ }
155
+ function setActiveSessionError(sessionId, error) {
156
+ updateSession(sessionId, (session, now) => ({
157
+ ...session,
158
+ isRunning: false,
159
+ needsAttention: false,
160
+ lastError: error,
161
+ reconnectState: error ? "failed" : "idle",
162
+ connectionState: error ? "error" : session.connectionState,
163
+ lastEventAt: now,
164
+ lastActivityAt: now
165
+ }));
166
+ }
167
+ function bumpActiveSessionActivity(sessionId, options) {
168
+ updateSession(sessionId, (session, now) => ({
169
+ ...session,
170
+ lastEventAt: options?.lastEventAt ?? session.lastEventAt ?? now,
171
+ lastActivityAt: now
172
+ }));
173
+ }
174
+ function resetActiveSessions() {
175
+ foregroundSessionId = null;
176
+ activeSessionsAtom.set(INITIAL_STATE);
177
+ }
178
+ function getAllActiveSessions(state) {
179
+ return Object.values(state.sessions);
180
+ }
181
+ function getActiveSession(state, sessionId) {
182
+ return state.sessions[sessionId] ?? null;
183
+ }
184
+ function getSessionsForProject(state, projectId) {
185
+ return Object.values(state.sessions).filter((session) => session.projectId === projectId);
186
+ }
187
+ function getSessionsForNavbar(state, projectId) {
188
+ return [...projectId == null ? Object.values(state.sessions) : getSessionsForProject(state, projectId)].sort((left, right) => {
189
+ if (left.isForeground !== right.isForeground) return Number(right.isForeground) - Number(left.isForeground);
190
+ const statusDiff = STATUS_PRIORITY[left.status] - STATUS_PRIORITY[right.status];
191
+ if (statusDiff !== 0) return statusDiff;
192
+ return right.lastActivityAt - left.lastActivityAt;
193
+ });
194
+ }
195
+ function getSessionsByActivity(state) {
196
+ return [...Object.values(state.sessions)].sort((left, right) => right.lastActivityAt - left.lastActivityAt);
197
+ }
198
+ function getTotalRunningSessionCount(state) {
199
+ return Object.values(state.sessions).filter((session) => session.isRunning).length;
200
+ }
201
+ function hasBackgroundRunningSessions(state) {
202
+ return Object.values(state.sessions).some((session) => session.isRunning && !session.isForeground);
203
+ }
204
+ function getAllProjectActivity(state) {
205
+ const grouped = /* @__PURE__ */ new Map();
206
+ for (const session of Object.values(state.sessions)) {
207
+ if (session.projectId == null) continue;
208
+ const existing = grouped.get(session.projectId);
209
+ if (existing) {
210
+ existing.activeSessionCount += 1;
211
+ existing.lastActivityAt = Math.max(existing.lastActivityAt, session.lastActivityAt);
212
+ if (session.isRunning) existing.runningSessionIds.push(session.sessionId);
213
+ if (!existing.projectLabel && session.projectLabel) existing.projectLabel = session.projectLabel;
214
+ continue;
215
+ }
216
+ grouped.set(session.projectId, {
217
+ projectId: session.projectId,
218
+ projectLabel: session.projectLabel,
219
+ activeSessionCount: 1,
220
+ runningSessionIds: session.isRunning ? [session.sessionId] : [],
221
+ lastActivityAt: session.lastActivityAt
222
+ });
223
+ }
224
+ return [...grouped.values()].sort((left, right) => right.lastActivityAt - left.lastActivityAt);
225
+ }
226
+ function useActiveSessionsState() {
227
+ return useStore(activeSessionsAtom);
228
+ }
229
+ function useActiveSessions() {
230
+ const state = useStore(activeSessionsAtom);
231
+ return useMemo(() => getAllActiveSessions(state), [state]);
232
+ }
233
+ function useActiveSession(sessionId) {
234
+ const state = useStore(activeSessionsAtom);
235
+ return useMemo(() => sessionId ? getActiveSession(state, sessionId) : null, [sessionId, state]);
236
+ }
237
+ function useProjectSessions(projectId) {
238
+ const state = useStore(activeSessionsAtom);
239
+ return useMemo(() => projectId == null ? [] : getSessionsForProject(state, projectId), [projectId, state]);
240
+ }
241
+ function useNavbarSessions(projectId) {
242
+ const state = useStore(activeSessionsAtom);
243
+ return useMemo(() => getSessionsForNavbar(state, projectId), [projectId, state]);
244
+ }
245
+ function useSessionsByActivity() {
246
+ const state = useStore(activeSessionsAtom);
247
+ return useMemo(() => getSessionsByActivity(state), [state]);
248
+ }
249
+ function useProjectActivity() {
250
+ const state = useStore(activeSessionsAtom);
251
+ return useMemo(() => getAllProjectActivity(state), [state]);
252
+ }
253
+ function useTotalRunningSessions() {
254
+ const state = useStore(activeSessionsAtom);
255
+ return useMemo(() => getTotalRunningSessionCount(state), [state]);
256
+ }
257
+ function useHasBackgroundRunningSessions() {
258
+ const state = useStore(activeSessionsAtom);
259
+ return useMemo(() => hasBackgroundRunningSessions(state), [state]);
260
+ }
261
+ //#endregion
262
+ export { useHasBackgroundRunningSessions as C, useSessionsByActivity as D, useProjectSessions as E, useTotalRunningSessions as O, useActiveSessionsState as S, useProjectActivity as T, setForegroundActiveSession as _, getAllProjectActivity as a, useActiveSession as b, getSessionsForProject as c, registerActiveSession as d, resetActiveSessions as f, setActiveSessionRunning as g, setActiveSessionError as h, getAllActiveSessions as i, getTotalRunningSessionCount as l, setActiveSessionConnection as m, bumpActiveSessionActivity as n, getSessionsByActivity as o, setActiveSessionAttention as p, getActiveSession as r, getSessionsForNavbar as s, activeSessionsAtom as t, hasBackgroundRunningSessions as u, unregisterActiveSession as v, useNavbarSessions as w, useActiveSessions as x, updateActiveSessionMeta as y };
@@ -1,59 +1,58 @@
1
- import * as nanostores from 'nanostores';
2
-
1
+ //#region src/stores/active-sessions-store.d.ts
3
2
  type SessionProjectKey = string | number;
4
3
  type ActiveSessionStatus = "idle" | "running" | "attention-needed" | "error";
5
4
  type ActiveSessionReconnectState = "idle" | "reconnecting" | "failed";
6
5
  type ActiveSessionConnectionState = "disconnected" | "connecting" | "connected" | "reconnecting" | "error";
7
6
  type ActiveSessionTransportMode = "websocket" | "sse" | "polling" | "custom";
8
7
  interface ActiveSessionRecord {
9
- sessionId: string;
10
- projectId: SessionProjectKey | null;
11
- projectLabel?: string;
12
- title?: string;
13
- href?: string;
14
- registeredAt: number;
15
- lastActivityAt: number;
16
- lastEventAt: number | null;
17
- status: ActiveSessionStatus;
18
- isRunning: boolean;
19
- isForeground: boolean;
20
- needsAttention: boolean;
21
- connectionState: ActiveSessionConnectionState;
22
- reconnectState: ActiveSessionReconnectState;
23
- transportMode: ActiveSessionTransportMode | null;
24
- lastError: string | null;
25
- metadata?: Record<string, unknown>;
8
+ sessionId: string;
9
+ projectId: SessionProjectKey | null;
10
+ projectLabel?: string;
11
+ title?: string;
12
+ href?: string;
13
+ registeredAt: number;
14
+ lastActivityAt: number;
15
+ lastEventAt: number | null;
16
+ status: ActiveSessionStatus;
17
+ isRunning: boolean;
18
+ isForeground: boolean;
19
+ needsAttention: boolean;
20
+ connectionState: ActiveSessionConnectionState;
21
+ reconnectState: ActiveSessionReconnectState;
22
+ transportMode: ActiveSessionTransportMode | null;
23
+ lastError: string | null;
24
+ metadata?: Record<string, unknown>;
26
25
  }
27
26
  interface ActiveSessionsState {
28
- sessions: Record<string, ActiveSessionRecord>;
29
- lastUpdatedAt: number;
27
+ sessions: Record<string, ActiveSessionRecord>;
28
+ lastUpdatedAt: number;
30
29
  }
31
30
  interface RegisterActiveSessionOptions {
32
- sessionId: string;
33
- projectId?: SessionProjectKey | null;
34
- projectLabel?: string;
35
- title?: string;
36
- href?: string;
37
- metadata?: Record<string, unknown>;
31
+ sessionId: string;
32
+ projectId?: SessionProjectKey | null;
33
+ projectLabel?: string;
34
+ title?: string;
35
+ href?: string;
36
+ metadata?: Record<string, unknown>;
38
37
  }
39
38
  interface ActiveSessionConnectionOptions {
40
- connectionState: ActiveSessionConnectionState;
41
- reconnectState?: ActiveSessionReconnectState;
42
- transportMode?: ActiveSessionTransportMode | null;
43
- lastError?: string | null;
44
- lastEventAt?: number | null;
39
+ connectionState: ActiveSessionConnectionState;
40
+ reconnectState?: ActiveSessionReconnectState;
41
+ transportMode?: ActiveSessionTransportMode | null;
42
+ lastError?: string | null;
43
+ lastEventAt?: number | null;
45
44
  }
46
45
  interface ActiveSessionActivityOptions {
47
- lastEventAt?: number | null;
46
+ lastEventAt?: number | null;
48
47
  }
49
48
  interface ActiveProjectActivity {
50
- projectId: SessionProjectKey;
51
- projectLabel?: string;
52
- activeSessionCount: number;
53
- runningSessionIds: string[];
54
- lastActivityAt: number;
49
+ projectId: SessionProjectKey;
50
+ projectLabel?: string;
51
+ activeSessionCount: number;
52
+ runningSessionIds: string[];
53
+ lastActivityAt: number;
55
54
  }
56
- declare const activeSessionsAtom: nanostores.PreinitializedWritableAtom<ActiveSessionsState> & object;
55
+ declare const activeSessionsAtom: import("nanostores").PreinitializedWritableAtom<ActiveSessionsState> & object;
57
56
  declare function registerActiveSession(options: RegisterActiveSessionOptions): void;
58
57
  declare function unregisterActiveSession(sessionId: string): void;
59
58
  declare function setForegroundActiveSession(sessionId: string | null): void;
@@ -81,5 +80,5 @@ declare function useSessionsByActivity(): ActiveSessionRecord[];
81
80
  declare function useProjectActivity(): ActiveProjectActivity[];
82
81
  declare function useTotalRunningSessions(): number;
83
82
  declare function useHasBackgroundRunningSessions(): boolean;
84
-
85
- export { type ActiveProjectActivity as A, updateActiveSessionMeta as B, useActiveSession as C, useActiveSessions as D, useActiveSessionsState as E, useHasBackgroundRunningSessions as F, useNavbarSessions as G, useProjectActivity as H, useProjectSessions as I, useSessionsByActivity as J, useTotalRunningSessions as K, type RegisterActiveSessionOptions as R, type SessionProjectKey as S, type ActiveSessionActivityOptions as a, type ActiveSessionConnectionOptions as b, type ActiveSessionConnectionState as c, type ActiveSessionReconnectState as d, type ActiveSessionRecord as e, type ActiveSessionStatus as f, type ActiveSessionTransportMode as g, type ActiveSessionsState as h, activeSessionsAtom as i, bumpActiveSessionActivity as j, getActiveSession as k, getAllActiveSessions as l, getAllProjectActivity as m, getSessionsByActivity as n, getSessionsForNavbar as o, getSessionsForProject as p, getTotalRunningSessionCount as q, hasBackgroundRunningSessions as r, registerActiveSession as s, resetActiveSessions as t, setActiveSessionAttention as u, setActiveSessionConnection as v, setActiveSessionError as w, setActiveSessionRunning as x, setForegroundActiveSession as y, unregisterActiveSession as z };
83
+ //#endregion
84
+ export { updateActiveSessionMeta as A, resetActiveSessions as C, setActiveSessionRunning as D, setActiveSessionError as E, useNavbarSessions as F, useProjectActivity as I, useProjectSessions as L, useActiveSessions as M, useActiveSessionsState as N, setForegroundActiveSession as O, useHasBackgroundRunningSessions as P, useSessionsByActivity as R, registerActiveSession as S, setActiveSessionConnection as T, getSessionsByActivity as _, ActiveSessionReconnectState as a, getTotalRunningSessionCount as b, ActiveSessionTransportMode as c, SessionProjectKey as d, activeSessionsAtom as f, getAllProjectActivity as g, getAllActiveSessions as h, ActiveSessionConnectionState as i, useActiveSession as j, unregisterActiveSession as k, ActiveSessionsState as l, getActiveSession as m, ActiveSessionActivityOptions as n, ActiveSessionRecord as o, bumpActiveSessionActivity as p, ActiveSessionConnectionOptions as r, ActiveSessionStatus as s, ActiveProjectActivity as t, RegisterActiveSessionOptions as u, getSessionsForNavbar as v, setActiveSessionAttention as w, hasBackgroundRunningSessions as x, getSessionsForProject as y, useTotalRunningSessions as z };
@@ -0,0 +1,32 @@
1
+ import { ReactNode } from "react";
2
+ //#region src/primitives/artifact-pane.d.ts
3
+ interface ArtifactPaneProps {
4
+ eyebrow?: ReactNode;
5
+ title: ReactNode;
6
+ subtitle?: ReactNode;
7
+ meta?: ReactNode;
8
+ headerActions?: ReactNode;
9
+ tabs?: ReactNode;
10
+ toolbar?: ReactNode;
11
+ footer?: ReactNode;
12
+ emptyState?: ReactNode;
13
+ children?: ReactNode;
14
+ className?: string;
15
+ contentClassName?: string;
16
+ /** Extra classes for the header band (e.g. to align its surface with the host chrome). */
17
+ headerClassName?: string;
18
+ /**
19
+ * Suppress the eyebrow/title/subtitle/meta block. Use when the host already
20
+ * shows the artifact's identity elsewhere (e.g. a surrounding path row), so the
21
+ * pane keeps only its tabs, toolbar, and header actions. The whole header row
22
+ * collapses when nothing else would render in it.
23
+ */
24
+ hideTitleBlock?: boolean;
25
+ }
26
+ /**
27
+ * ArtifactPane — shared frame for files, previews, documents, inspectors, and
28
+ * other artifact-like surfaces inside sandbox applications.
29
+ */
30
+ declare function ArtifactPane({ eyebrow, title, subtitle, meta, headerActions, tabs, toolbar, footer, emptyState, children, className, contentClassName, headerClassName, hideTitleBlock }: ArtifactPaneProps): import("react").JSX.Element;
31
+ //#endregion
32
+ export { ArtifactPaneProps as n, ArtifactPane as t };
@@ -0,0 +1,70 @@
1
+ import { t as cn } from "./utils-C_uf36nf.js";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ //#region src/primitives/artifact-pane.tsx
4
+ /**
5
+ * ArtifactPane — shared frame for files, previews, documents, inspectors, and
6
+ * other artifact-like surfaces inside sandbox applications.
7
+ */
8
+ function ArtifactPane({ eyebrow, title, subtitle, meta, headerActions, tabs, toolbar, footer, emptyState, children, className, contentClassName, headerClassName, hideTitleBlock = false }) {
9
+ const hasContent = children !== void 0 && children !== null;
10
+ const showTitleRow = !hideTitleBlock || Boolean(headerActions);
11
+ const hasHeader = showTitleRow || Boolean(tabs) || Boolean(toolbar);
12
+ const toolbarNeedsDivider = showTitleRow || Boolean(tabs);
13
+ return /* @__PURE__ */ jsxs("section", {
14
+ className: cn("flex h-full min-h-0 flex-col overflow-hidden bg-background text-foreground", className),
15
+ children: [
16
+ hasHeader && /* @__PURE__ */ jsxs("header", {
17
+ className: cn("border-b border-border bg-muted/10", headerClassName),
18
+ children: [
19
+ showTitleRow && /* @__PURE__ */ jsxs("div", {
20
+ className: "flex items-start justify-between gap-3 px-3 py-2",
21
+ children: [/* @__PURE__ */ jsx("div", {
22
+ className: "min-w-0 flex-1",
23
+ children: !hideTitleBlock && /* @__PURE__ */ jsxs(Fragment, { children: [
24
+ eyebrow && /* @__PURE__ */ jsx("div", {
25
+ className: "mb-1 inline-flex max-w-full items-center px-1 py-0.5 text-[10px] font-bold uppercase tracking-wider text-muted-foreground",
26
+ children: eyebrow
27
+ }),
28
+ /* @__PURE__ */ jsx("div", {
29
+ className: "min-w-0 text-[13px] font-medium text-foreground",
30
+ children: title
31
+ }),
32
+ (subtitle || meta) && /* @__PURE__ */ jsxs("div", {
33
+ className: "mt-1 flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1 text-xs leading-relaxed text-muted-foreground",
34
+ children: [subtitle && /* @__PURE__ */ jsx("span", {
35
+ className: "truncate",
36
+ children: subtitle
37
+ }), meta && /* @__PURE__ */ jsx("span", {
38
+ className: "flex items-center gap-2",
39
+ children: meta
40
+ })]
41
+ })
42
+ ] })
43
+ }), headerActions && /* @__PURE__ */ jsx("div", {
44
+ className: "flex shrink-0 items-center gap-1.5",
45
+ children: headerActions
46
+ })]
47
+ }),
48
+ tabs,
49
+ toolbar && /* @__PURE__ */ jsx("div", {
50
+ className: cn("px-3 py-2", toolbarNeedsDivider && "border-t border-border"),
51
+ children: toolbar
52
+ })
53
+ ]
54
+ }),
55
+ /* @__PURE__ */ jsx("div", {
56
+ className: cn("min-h-0 flex-1 overflow-auto", contentClassName),
57
+ children: hasContent ? children : emptyState ? /* @__PURE__ */ jsx("div", {
58
+ className: "flex h-full items-center justify-center p-6",
59
+ children: emptyState
60
+ }) : null
61
+ }),
62
+ footer && /* @__PURE__ */ jsx("footer", {
63
+ className: "shrink-0 border-t border-border bg-card px-3 py-2",
64
+ children: footer
65
+ })
66
+ ]
67
+ });
68
+ }
69
+ //#endregion
70
+ export { ArtifactPane as t };