@unofficialbox/box-open-elements 0.18.0 → 0.20.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 (217) hide show
  1. package/dist/components/actions/button-group.js +6 -0
  2. package/dist/components/actions/button.js +6 -0
  3. package/dist/components/actions/icon-button.js +6 -0
  4. package/dist/components/actions/link-button.js +6 -0
  5. package/dist/components/actions/menu-item.js +6 -0
  6. package/dist/components/actions/menu.js +6 -0
  7. package/dist/components/actions/segmented-control.js +6 -0
  8. package/dist/components/actions/toolbar.js +6 -0
  9. package/dist/components/collections/card.js +6 -0
  10. package/dist/components/collections/carousel.js +6 -0
  11. package/dist/components/collections/check-list.d.ts +10 -0
  12. package/dist/components/collections/check-list.js +8 -0
  13. package/dist/components/collections/datalist-item.js +6 -0
  14. package/dist/components/collections/document-list.d.ts +10 -0
  15. package/dist/components/collections/document-list.js +8 -0
  16. package/dist/components/collections/draggable-list.js +6 -0
  17. package/dist/components/collections/fact-list.d.ts +10 -0
  18. package/dist/components/collections/fact-list.js +8 -0
  19. package/dist/components/collections/grid-view.js +6 -0
  20. package/dist/components/collections/pagination.js +6 -0
  21. package/dist/components/collections/result-blocks.d.ts +54 -0
  22. package/dist/components/collections/result-blocks.js +71 -0
  23. package/dist/components/collections/table.js +6 -0
  24. package/dist/components/collections/thumbnail-card.js +6 -0
  25. package/dist/components/collections/tree-grid.js +6 -0
  26. package/dist/components/collections/tree.js +6 -0
  27. package/dist/components/feedback/alert.js +1 -1
  28. package/dist/components/feedback/badge.js +1 -1
  29. package/dist/components/feedback/badgeable.js +6 -0
  30. package/dist/components/feedback/chip.js +6 -0
  31. package/dist/components/feedback/due-badge.js +6 -0
  32. package/dist/components/feedback/empty-state.js +6 -0
  33. package/dist/components/feedback/error-mask.js +6 -0
  34. package/dist/components/feedback/help-text.js +6 -0
  35. package/dist/components/feedback/indicator.js +1 -1
  36. package/dist/components/feedback/nudge.js +6 -0
  37. package/dist/components/feedback/path.js +6 -0
  38. package/dist/components/feedback/progress-bar.d.ts +9 -0
  39. package/dist/components/feedback/progress-bar.js +35 -3
  40. package/dist/components/feedback/progress-ring.js +6 -0
  41. package/dist/components/feedback/progress-steps.js +6 -0
  42. package/dist/components/feedback/skeleton.js +6 -0
  43. package/dist/components/feedback/spinner.js +6 -0
  44. package/dist/components/feedback/status-icon.d.ts +10 -0
  45. package/dist/components/feedback/status-icon.js +26 -0
  46. package/dist/components/feedback/toast.js +1 -1
  47. package/dist/components/files/drop-zone.js +1 -1
  48. package/dist/components/forms/calendar.js +6 -0
  49. package/dist/components/forms/category-selector.js +6 -0
  50. package/dist/components/forms/checkbox-group.js +6 -0
  51. package/dist/components/forms/checkbox.js +6 -0
  52. package/dist/components/forms/color-picker.js +6 -0
  53. package/dist/components/forms/combobox.js +6 -0
  54. package/dist/components/forms/date-field.js +6 -0
  55. package/dist/components/forms/dropdown.js +6 -0
  56. package/dist/components/forms/dual-listbox.js +6 -0
  57. package/dist/components/forms/fieldset.js +6 -0
  58. package/dist/components/forms/multi-select.js +6 -0
  59. package/dist/components/forms/number-input.js +6 -0
  60. package/dist/components/forms/pill-cloud.js +6 -0
  61. package/dist/components/forms/pill-selector-dropdown.js +6 -0
  62. package/dist/components/forms/radio-group.js +6 -0
  63. package/dist/components/forms/range-slider.js +6 -0
  64. package/dist/components/forms/rating.js +6 -0
  65. package/dist/components/forms/rich-text-input.js +6 -0
  66. package/dist/components/forms/search-field.js +6 -0
  67. package/dist/components/forms/select.js +6 -0
  68. package/dist/components/forms/slider.js +6 -0
  69. package/dist/components/forms/spin-button.js +6 -0
  70. package/dist/components/forms/switch.js +6 -0
  71. package/dist/components/forms/tag-input.js +6 -0
  72. package/dist/components/forms/text-area.js +6 -0
  73. package/dist/components/forms/text-field.js +6 -0
  74. package/dist/components/forms/tile-group.js +1 -1
  75. package/dist/components/forms/time-field.js +6 -0
  76. package/dist/components/identity/avatar.js +6 -0
  77. package/dist/components/identity/contact-datalist-item.js +6 -0
  78. package/dist/components/identity/persona.js +6 -0
  79. package/dist/components/layout/app-shell.js +6 -0
  80. package/dist/components/layout/divider.js +6 -0
  81. package/dist/components/layout/grid.js +1 -1
  82. package/dist/components/layout/nav-sidebar.js +6 -0
  83. package/dist/components/layout/section.js +6 -0
  84. package/dist/components/layout/sidebar-toggle-button.js +6 -0
  85. package/dist/components/layout/split-view.js +6 -0
  86. package/dist/components/navigation/accordion.js +6 -0
  87. package/dist/components/navigation/breadcrumb.js +6 -0
  88. package/dist/components/navigation/tabs.js +6 -0
  89. package/dist/components/output/code-block.js +1 -1
  90. package/dist/components/output/formatted-value.js +1 -1
  91. package/dist/components/overlays/command-palette.js +6 -0
  92. package/dist/components/overlays/context-menu.js +6 -0
  93. package/dist/components/overlays/guide-tooltip.js +6 -0
  94. package/dist/components/overlays/popover.js +6 -0
  95. package/dist/components/overlays/shortcuts-overlay.js +6 -0
  96. package/dist/components/overlays/tooltip.js +6 -0
  97. package/dist/components/visuals/illustration.js +6 -0
  98. package/dist/element-maps.d.ts +39 -19
  99. package/dist/entries/agent-workspace.d.ts +1 -0
  100. package/dist/entries/agent-workspace.js +1 -0
  101. package/dist/entries/call-console.d.ts +1 -0
  102. package/dist/entries/call-console.js +1 -0
  103. package/dist/entries/check-list.d.ts +1 -0
  104. package/dist/entries/check-list.js +1 -0
  105. package/dist/entries/document-list.d.ts +1 -0
  106. package/dist/entries/document-list.js +1 -0
  107. package/dist/entries/fact-list.d.ts +1 -0
  108. package/dist/entries/fact-list.js +1 -0
  109. package/dist/entries/result-blocks.d.ts +1 -0
  110. package/dist/entries/result-blocks.js +1 -0
  111. package/dist/entries/run-summary.d.ts +1 -0
  112. package/dist/entries/run-summary.js +1 -0
  113. package/dist/entries/status-icon.d.ts +1 -0
  114. package/dist/entries/status-icon.js +1 -0
  115. package/dist/foundations/motion/behaviors.d.ts +8 -0
  116. package/dist/foundations/motion/behaviors.js +24 -0
  117. package/dist/foundations/motion/index.d.ts +2 -0
  118. package/dist/foundations/motion/index.js +2 -0
  119. package/dist/foundations/motion/scroll-pin.d.ts +19 -0
  120. package/dist/foundations/motion/scroll-pin.js +60 -0
  121. package/dist/foundations/motion/tokens.d.ts +2 -0
  122. package/dist/foundations/motion/tokens.js +2 -0
  123. package/dist/foundations/profiles/registry.d.ts +3 -0
  124. package/dist/foundations/profiles/registry.js +3 -0
  125. package/dist/foundations/profiles/types.d.ts +3 -0
  126. package/dist/foundations/status/index.d.ts +6 -0
  127. package/dist/foundations/status/index.js +33 -0
  128. package/dist/index.d.ts +10 -0
  129. package/dist/index.js +10 -0
  130. package/dist/patterns/agent-chat/agent-chat.d.ts +9 -0
  131. package/dist/patterns/agent-chat/agent-chat.js +141 -21
  132. package/dist/patterns/agent-chat/controller.d.ts +3 -1
  133. package/dist/patterns/agent-chat/controller.js +92 -16
  134. package/dist/patterns/agent-chat/index.d.ts +1 -0
  135. package/dist/patterns/agent-chat/index.js +1 -0
  136. package/dist/patterns/agent-chat/ndjson.d.ts +5 -0
  137. package/dist/patterns/agent-chat/ndjson.js +41 -0
  138. package/dist/patterns/agent-chat/types.d.ts +44 -1
  139. package/dist/patterns/agent-workspace/agent-workspace.d.ts +28 -0
  140. package/dist/patterns/agent-workspace/agent-workspace.js +215 -0
  141. package/dist/patterns/agent-workspace/controller.d.ts +38 -0
  142. package/dist/patterns/agent-workspace/controller.js +65 -0
  143. package/dist/patterns/agent-workspace/index.d.ts +2 -0
  144. package/dist/patterns/agent-workspace/index.js +2 -0
  145. package/dist/patterns/audit/activity-density.js +6 -0
  146. package/dist/patterns/audit/audit-log.js +6 -0
  147. package/dist/patterns/call-console/call-console.d.ts +17 -0
  148. package/dist/patterns/call-console/call-console.js +107 -0
  149. package/dist/patterns/call-console/controller.d.ts +23 -0
  150. package/dist/patterns/call-console/controller.js +50 -0
  151. package/dist/patterns/call-console/http-transport.d.ts +3 -0
  152. package/dist/patterns/call-console/http-transport.js +26 -0
  153. package/dist/patterns/call-console/index.d.ts +4 -0
  154. package/dist/patterns/call-console/index.js +4 -0
  155. package/dist/patterns/call-console/types.d.ts +32 -0
  156. package/dist/patterns/call-console/types.js +8 -0
  157. package/dist/patterns/comments/comment-thread.js +6 -0
  158. package/dist/patterns/content-explorer/adapters/action-menu.js +6 -0
  159. package/dist/patterns/content-explorer/adapters/breadcrumbs.js +6 -0
  160. package/dist/patterns/content-explorer/adapters/list.js +6 -0
  161. package/dist/patterns/content-explorer/adapters/table.js +6 -0
  162. package/dist/patterns/content-explorer/adapters/toolbar.js +6 -0
  163. package/dist/patterns/content-explorer/content-explorer.js +6 -0
  164. package/dist/patterns/content-picker/content-picker.js +6 -0
  165. package/dist/patterns/content-sidebar/content-sidebar.js +6 -0
  166. package/dist/patterns/content-uploader/content-uploader.js +8 -1
  167. package/dist/patterns/diff/compare-view.js +6 -0
  168. package/dist/patterns/diff/diff-viewer.js +6 -0
  169. package/dist/patterns/file-request/file-request-builder.js +6 -0
  170. package/dist/patterns/form-wizard/form-wizard.js +6 -0
  171. package/dist/patterns/form-wizard/wizard-summary.js +6 -0
  172. package/dist/patterns/governance/governance-panel.js +6 -0
  173. package/dist/patterns/insights/bar-chart.js +6 -0
  174. package/dist/patterns/insights/chart-panel.js +6 -0
  175. package/dist/patterns/insights/donut-chart.js +6 -0
  176. package/dist/patterns/insights/line-chart.js +6 -0
  177. package/dist/patterns/insights/metric-card.js +6 -0
  178. package/dist/patterns/item/bulk-action-bar.js +6 -0
  179. package/dist/patterns/item/item-details-panel.js +6 -0
  180. package/dist/patterns/item/item-form.js +6 -0
  181. package/dist/patterns/item/preview-header.js +6 -0
  182. package/dist/patterns/lineage/lineage-graph.js +6 -0
  183. package/dist/patterns/lineage/provenance-strip.js +6 -0
  184. package/dist/patterns/metadata/metadata-filter-builder.js +6 -0
  185. package/dist/patterns/metadata/metadata-inspector.js +6 -0
  186. package/dist/patterns/notifications/notification-bell.js +6 -0
  187. package/dist/patterns/notifications/notification-inbox.js +6 -0
  188. package/dist/patterns/preview/annotation-inspector.js +6 -0
  189. package/dist/patterns/preview/annotation-toolbar.js +6 -0
  190. package/dist/patterns/preview/preview-element.js +6 -0
  191. package/dist/patterns/run/index.d.ts +2 -0
  192. package/dist/patterns/run/index.js +2 -0
  193. package/dist/patterns/run/progress.d.ts +24 -0
  194. package/dist/patterns/run/progress.js +32 -0
  195. package/dist/patterns/run/run-summary.d.ts +21 -0
  196. package/dist/patterns/run/run-summary.js +82 -0
  197. package/dist/patterns/run/run-trace.d.ts +1 -0
  198. package/dist/patterns/run/run-trace.js +20 -3
  199. package/dist/patterns/search/filter-bar.js +6 -0
  200. package/dist/patterns/search/saved-view-picker.js +6 -0
  201. package/dist/patterns/search/search-results-header.js +6 -0
  202. package/dist/patterns/share/access-stats.js +6 -0
  203. package/dist/patterns/share/collaborator-avatars.js +6 -0
  204. package/dist/patterns/share/invite-collaborators-modal.js +6 -0
  205. package/dist/patterns/share/permission-matrix.js +6 -0
  206. package/dist/patterns/share/presence.js +6 -0
  207. package/dist/patterns/share/share-panel.js +6 -0
  208. package/dist/patterns/share/unified-share-modal.js +6 -0
  209. package/dist/patterns/signature/signature-ceremony.js +6 -0
  210. package/dist/patterns/task/review-queue-item.js +6 -0
  211. package/dist/patterns/task/task-assignment-panel.js +6 -0
  212. package/dist/patterns/timeline/timeline.js +6 -0
  213. package/dist/patterns/versions/version-graph.js +6 -0
  214. package/dist/patterns/versions/version-list.js +6 -0
  215. package/dist/patterns/work-queue/work-queue.js +6 -0
  216. package/dist/patterns/work-queue/workload-board.js +6 -0
  217. package/package.json +13 -1
@@ -0,0 +1,65 @@
1
+ export const conversationTitle = (body, max = 48) => {
2
+ const text = body.trim().replace(/\s+/g, " ");
3
+ if (text.length <= max)
4
+ return text || "New chat";
5
+ const cut = text.slice(0, max);
6
+ const space = cut.lastIndexOf(" ");
7
+ return `${space > 0 ? cut.slice(0, space) : cut}…`;
8
+ };
9
+ export function conversationDetails(state) {
10
+ const sources = new Map();
11
+ const approvals = [];
12
+ let context;
13
+ for (const message of state.messages) {
14
+ if (message.context)
15
+ context = message.context;
16
+ for (const citation of message.citations)
17
+ if (!sources.has(citation.id))
18
+ sources.set(citation.id, citation);
19
+ for (const block of message.blocks ?? [])
20
+ if (block.type === "documents")
21
+ for (const item of block.items) {
22
+ if (!sources.has(item.id))
23
+ sources.set(item.id, { id: item.id, label: item.name, ...(item.href ? { href: item.href } : {}) });
24
+ }
25
+ for (const proposal of message.proposals)
26
+ approvals.push({ messageId: message.id, proposal });
27
+ }
28
+ return { ...(context ? { context } : {}), approvals, sources: [...sources.values()] };
29
+ }
30
+ /** Owns independent sessions. Selecting a chat never disconnects another one. */
31
+ export class AgentWorkspaceController {
32
+ createSession;
33
+ chats = [];
34
+ activeId = null;
35
+ seq = 0;
36
+ listeners = new Set();
37
+ subscriptions = [];
38
+ constructor(createSession) {
39
+ this.createSession = createSession;
40
+ }
41
+ subscribe(listener) { this.listeners.add(listener); return () => this.listeners.delete(listener); }
42
+ emit() { this.listeners.forEach(fn => fn()); }
43
+ newChat() {
44
+ let chat = this.chats.find(c => c.controller.getState().messages.length === 0);
45
+ if (!chat) {
46
+ chat = { id: `chat-${++this.seq}`, controller: this.createSession() };
47
+ chat.controller.connect();
48
+ this.chats.push(chat);
49
+ this.subscriptions.push(chat.controller.subscribe("messagesChanged", () => this.emit()), chat.controller.subscribe("streamingChanged", () => this.emit()));
50
+ }
51
+ this.select(chat.id);
52
+ return chat;
53
+ }
54
+ select(id) { if (!this.chats.some(c => c.id === id))
55
+ return; this.activeId = id; this.emit(); }
56
+ get summaries() {
57
+ return this.chats.map(c => {
58
+ const state = c.controller.getState();
59
+ return { id: c.id, title: conversationTitle(state.messages.find(m => m.role === "user")?.body ?? ""),
60
+ status: state.messages.some(m => m.proposals.some(p => !p.decision)) ? "Needs your approval" : state.streaming ? "Working…" : "" };
61
+ });
62
+ }
63
+ get details() { const chat = this.chats.find(c => c.id === this.activeId); return chat ? conversationDetails(chat.controller.getState()) : { approvals: [], sources: [] }; }
64
+ destroy() { this.subscriptions.forEach(fn => fn()); this.subscriptions = []; this.chats.forEach(c => { c.controller.disconnect(); c.controller.destroy(); }); this.listeners.clear(); }
65
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./controller.js";
2
+ export * from "./agent-workspace.js";
@@ -0,0 +1,2 @@
1
+ export * from "./controller.js";
2
+ export * from "./agent-workspace.js";
@@ -16,6 +16,12 @@ const elementStyles = `
16
16
  font: inherit;
17
17
  }
18
18
 
19
+ /* The host's own display would otherwise beat the UA rule for [hidden],
20
+ leaving the element on screen when a host hides it. */
21
+ :host([hidden]) {
22
+ display: none !important;
23
+ }
24
+
19
25
  [part="panel"] {
20
26
  display: grid;
21
27
  gap: ${boePanel.gap};
@@ -32,6 +32,12 @@ const elementStyles = `
32
32
  font: inherit;
33
33
  }
34
34
 
35
+ /* The host's own display would otherwise beat the UA rule for [hidden],
36
+ leaving the element on screen when a host hides it. */
37
+ :host([hidden]) {
38
+ display: none !important;
39
+ }
40
+
35
41
  [part="panel"] {
36
42
  display: grid;
37
43
  gap: ${boePanel.gap};
@@ -0,0 +1,17 @@
1
+ import { BaseElement } from "../../core/element.js";
2
+ import type { CallConsoleController } from "./controller.js";
3
+ export declare function copyCallText(text: string, doc?: Document): Promise<boolean>;
4
+ export declare class CallConsole extends BaseElement {
5
+ static readonly tagName = "box-call-console";
6
+ private model;
7
+ private unsubscribe?;
8
+ private selected;
9
+ get callController(): CallConsoleController | null;
10
+ set callController(value: CallConsoleController | null);
11
+ private listen;
12
+ connectedCallback(): void;
13
+ disconnectedCallback(): void;
14
+ protected renderTemplate(): void;
15
+ protected setupListeners(): void;
16
+ protected update(): void;
17
+ }
@@ -0,0 +1,107 @@
1
+ import { BaseElement } from "../../core/element.js";
2
+ import { SplitView } from "../../components/layout/split-view.js";
3
+ import { boeEntrance, boeEntranceKeyframes, boeReducedMotionPolicy } from "../../foundations/motion/index.js";
4
+ import { callFailed, callStatus, formatCallHttp } from "./types.js";
5
+ const DEFAULT_TAG_NAME = "box-call-console";
6
+ export async function copyCallText(text, doc = document) {
7
+ try {
8
+ await doc.defaultView?.navigator.clipboard.writeText(text);
9
+ if (doc.defaultView?.navigator.clipboard)
10
+ return true;
11
+ }
12
+ catch { }
13
+ const active = doc.activeElement;
14
+ const textarea = doc.createElement("textarea");
15
+ textarea.value = text;
16
+ textarea.style.cssText = "position:fixed;opacity:0";
17
+ doc.body.append(textarea);
18
+ textarea.select();
19
+ try {
20
+ return doc.execCommand?.("copy") ?? false;
21
+ }
22
+ finally {
23
+ textarea.remove();
24
+ active?.focus({ preventScroll: true });
25
+ }
26
+ }
27
+ export class CallConsole extends BaseElement {
28
+ static tagName = DEFAULT_TAG_NAME;
29
+ model = null;
30
+ unsubscribe;
31
+ selected = "";
32
+ get callController() { return this.model; }
33
+ set callController(value) { this.unsubscribe?.(); this.model = value; if (this.isConnected)
34
+ this.listen(); if (this.isRendered)
35
+ this.update(); }
36
+ listen() { this.unsubscribe?.(); this.unsubscribe = this.model?.subscribe(() => this.update()); }
37
+ connectedCallback() { super.connectedCallback(); this.listen(); }
38
+ disconnectedCallback() { this.unsubscribe?.(); }
39
+ renderTemplate() {
40
+ SplitView.register();
41
+ this.shadowRoot.innerHTML = `<style>:host{display:block;min-width:0;color:var(--boe-token-text-text,#222);font:inherit}:host([hidden]){display:none !important}
42
+ header{display:flex;gap:.75rem;flex-wrap:wrap;align-items:center} pre{white-space:pre-wrap;overflow-wrap:anywhere;font-size:.8rem;max-height:30rem;overflow:auto}
43
+ button,select{font:inherit;color:inherit;background:var(--boe-token-surface-surface,#fff);border:1px solid var(--boe-token-stroke-stroke,#ddd);border-radius:5px;padding:.4rem;cursor:pointer}
44
+ [part="call"]{width:100%;display:grid;grid-template-columns:5rem 5rem minmax(0,1fr) 4rem;text-align:left;gap:.5rem;margin:.4rem 0;${boeEntrance()}}
45
+ #list{container-type:inline-size} [part="call"] span{min-width:0;overflow-wrap:anywhere}
46
+ @container(max-width:420px){[part="call"]{grid-template-columns:minmax(0,1fr) auto}[part="call"] span:nth-child(even){text-align:right}}
47
+ [aria-current="true"]{background:var(--boe-token-surface-surface-secondary,#f5f5f5)} [part="skeleton"]{height:2rem;margin:.5rem;background:var(--boe-token-surface-surface-secondary,#eee)}
48
+ ${boeEntranceKeyframes}${boeReducedMotionPolicy}</style>
49
+ <header><span id="connection" role="status"></span><label>Service <select id="service"><option value="">All</option></select></label><label><input type="checkbox" id="errors"> Errors only</label><button id="clear">Clear</button><span id="copy-status" role="status"></span></header>
50
+ <box-split-view resizable ratio="0.4"><div slot="primary" id="list"></div><div><button data-copy="request">Copy request</button><button data-copy="response">Copy response</button><button data-copy="both">Copy both</button><h3>Request <button data-copy="request" aria-label="Copy request code">⧉</button></h3><pre id="request"></pre><h3>Response <button data-copy="response" aria-label="Copy response code">⧉</button></h3><pre id="response"></pre></div></box-split-view>`;
51
+ }
52
+ setupListeners() {
53
+ this.shadowRoot.querySelector("#service").addEventListener("change", () => this.update());
54
+ this.shadowRoot.querySelector("#errors").addEventListener("change", () => this.update());
55
+ this.shadowRoot.querySelector("#clear").addEventListener("click", () => { void this.model?.clear().catch(() => { this.shadowRoot.querySelector("#copy-status").textContent = "Unable to clear calls"; }); });
56
+ this.shadowRoot.querySelectorAll("[data-copy]").forEach(b => b.addEventListener("click", async () => {
57
+ const entry = this.model?.entries.find(e => e.id === this.selected);
58
+ if (!entry)
59
+ return;
60
+ const ok = await copyCallText(formatCallHttp(entry, b.dataset.copy));
61
+ this.shadowRoot.querySelector("#copy-status").textContent = ok ? "Copied" : "Copy unavailable; select the text to copy";
62
+ }));
63
+ }
64
+ update() {
65
+ const state = this.model?.connection ?? "connecting";
66
+ this.shadowRoot.querySelector("#connection").textContent = state === "unavailable" ? "Restart the agent: /calls is unavailable" : state;
67
+ const service = this.shadowRoot.querySelector("#service");
68
+ const services = [...new Set(this.model?.entries.map(e => e.service) ?? [])];
69
+ for (const name of services)
70
+ if (!Array.from(service.options).some(o => o.value === name)) {
71
+ const option = document.createElement("option");
72
+ option.value = name;
73
+ option.textContent = name;
74
+ service.append(option);
75
+ }
76
+ const errors = this.shadowRoot.querySelector("#errors").checked;
77
+ const entries = this.model?.entries.filter(e => (!service.value || e.service === service.value) && (!errors || callFailed(e))) ?? [];
78
+ if (!entries.some(e => e.id === this.selected))
79
+ this.selected = entries[0]?.id ?? "";
80
+ const list = this.shadowRoot.querySelector("#list");
81
+ const focused = this.shadowRoot.activeElement?.getAttribute("data-call-id");
82
+ list.querySelectorAll('[part="skeleton"]').forEach(el => el.remove());
83
+ const existing = new Map(Array.from(list.children).map(el => [el.getAttribute("data-call-id"), el]));
84
+ for (const entry of entries) {
85
+ let button = existing.get(entry.id);
86
+ existing.delete(entry.id);
87
+ if (!button) {
88
+ button = document.createElement("button");
89
+ button.setAttribute("part", "call");
90
+ button.dataset.callId = entry.id;
91
+ button.addEventListener("click", () => { this.selected = entry.id; this.update(); });
92
+ }
93
+ button.setAttribute("aria-current", String(entry.id === this.selected));
94
+ button.replaceChildren(...[callStatus(entry), entry.service, entry.summary, `${Math.round(entry.durationMs)} ms`].map(text => { const span = document.createElement("span"); span.textContent = text; return span; }));
95
+ list.append(button);
96
+ if (entry.id === focused)
97
+ button.focus({ preventScroll: true });
98
+ }
99
+ existing.forEach(el => el.remove());
100
+ if (!entries.length && state === "connecting")
101
+ list.innerHTML = '<div part="skeleton"></div><div part="skeleton"></div><div part="skeleton"></div>';
102
+ const entry = entries.find(e => e.id === this.selected);
103
+ this.shadowRoot.querySelector("#request").textContent = entry ? formatCallHttp(entry, "request") : "Select a call";
104
+ this.shadowRoot.querySelector("#response").textContent = entry ? formatCallHttp(entry, "response") : "";
105
+ }
106
+ }
107
+ CallConsole.register();
@@ -0,0 +1,23 @@
1
+ import type { CallConnection, CallEntry, CallEvent } from "./types.js";
2
+ export interface CallConsoleTransport {
3
+ snapshot(signal: AbortSignal): Promise<CallEntry[]>;
4
+ subscribe(onEvent: (event: CallEvent) => void, onConnection: (state: CallConnection) => void): () => void;
5
+ clear(): Promise<void>;
6
+ }
7
+ /** Transport injection keeps networking out of the component. */
8
+ export declare class CallConsoleController {
9
+ readonly transport: CallConsoleTransport;
10
+ entries: CallEntry[];
11
+ connection: CallConnection;
12
+ private listeners;
13
+ private abort?;
14
+ private close?;
15
+ constructor(transport: CallConsoleTransport);
16
+ subscribe(fn: () => void): () => void;
17
+ private emit;
18
+ apply(event: CallEvent): void;
19
+ connect(): Promise<void>;
20
+ clear(): Promise<void>;
21
+ disconnect(): void;
22
+ destroy(): void;
23
+ }
@@ -0,0 +1,50 @@
1
+ /** Transport injection keeps networking out of the component. */
2
+ export class CallConsoleController {
3
+ transport;
4
+ entries = [];
5
+ connection = "connecting";
6
+ listeners = new Set();
7
+ abort;
8
+ close;
9
+ constructor(transport) {
10
+ this.transport = transport;
11
+ }
12
+ subscribe(fn) { this.listeners.add(fn); return () => this.listeners.delete(fn); }
13
+ emit() { this.listeners.forEach(fn => fn()); }
14
+ apply(event) {
15
+ if (event.type === "snapshot")
16
+ this.entries = event.entries;
17
+ else if (event.type === "clear")
18
+ this.entries = [];
19
+ else
20
+ this.entries = this.entries.some(e => e.id === event.entry.id) ? this.entries.map(e => e.id === event.entry.id ? event.entry : e) : [event.entry, ...this.entries];
21
+ this.emit();
22
+ }
23
+ async connect() {
24
+ this.disconnect();
25
+ const abort = new AbortController();
26
+ this.abort = abort;
27
+ this.connection = "connecting";
28
+ this.emit();
29
+ try {
30
+ const entries = await this.transport.snapshot(abort.signal);
31
+ if (abort.signal.aborted)
32
+ return;
33
+ this.apply({ type: "snapshot", entries });
34
+ this.close = this.transport.subscribe(event => { if (!abort.signal.aborted)
35
+ this.apply(event); }, state => { if (!abort.signal.aborted) {
36
+ this.connection = state;
37
+ this.emit();
38
+ } });
39
+ }
40
+ catch (error) {
41
+ if (!abort.signal.aborted) {
42
+ this.connection = error instanceof Error && error.message === "404" ? "unavailable" : "reconnecting";
43
+ this.emit();
44
+ }
45
+ }
46
+ }
47
+ async clear() { await this.transport.clear(); this.apply({ type: "clear" }); }
48
+ disconnect() { this.abort?.abort(); this.close?.(); this.close = undefined; }
49
+ destroy() { this.disconnect(); this.listeners.clear(); }
50
+ }
@@ -0,0 +1,3 @@
1
+ import type { CallConsoleTransport } from "./controller.js";
2
+ /** Optional browser adapter for the documented snapshot/SSE/DELETE contract. */
3
+ export declare function createCallConsoleTransport(base?: string): CallConsoleTransport;
@@ -0,0 +1,26 @@
1
+ /** Optional browser adapter for the documented snapshot/SSE/DELETE contract. */
2
+ export function createCallConsoleTransport(base = "/calls") {
3
+ return {
4
+ async snapshot(signal) { const response = await fetch(base, { signal }); if (!response.ok)
5
+ throw new Error(String(response.status)); return await response.json(); },
6
+ subscribe(onEvent, onConnection) {
7
+ const events = new EventSource(`${base}/stream`);
8
+ events.onopen = () => onConnection("live");
9
+ events.onerror = () => onConnection("reconnecting");
10
+ for (const type of ["snapshot", "call", "clear"])
11
+ events.addEventListener(type, event => {
12
+ try {
13
+ const data = JSON.parse(event.data);
14
+ if (data.type === type)
15
+ onEvent(data);
16
+ }
17
+ catch {
18
+ onConnection("reconnecting");
19
+ }
20
+ });
21
+ return () => events.close();
22
+ },
23
+ async clear() { const response = await fetch(base, { method: "DELETE" }); if (!response.ok)
24
+ throw new Error(String(response.status)); },
25
+ };
26
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./types.js";
2
+ export * from "./controller.js";
3
+ export * from "./http-transport.js";
4
+ export * from "./call-console.js";
@@ -0,0 +1,4 @@
1
+ export * from "./types.js";
2
+ export * from "./controller.js";
3
+ export * from "./http-transport.js";
4
+ export * from "./call-console.js";
@@ -0,0 +1,32 @@
1
+ export interface CallEntry {
2
+ id: string;
3
+ startedAt: number;
4
+ durationMs: number;
5
+ pending: boolean;
6
+ service: string;
7
+ summary: string;
8
+ method: string;
9
+ url: string;
10
+ requestHeaders: Record<string, string>;
11
+ requestBody?: string;
12
+ status: number;
13
+ statusText: string;
14
+ responseHeaders: Record<string, string>;
15
+ responseBody?: string;
16
+ error?: string;
17
+ expected?: string;
18
+ rpcError?: string;
19
+ }
20
+ export type CallEvent = {
21
+ type: "snapshot";
22
+ entries: CallEntry[];
23
+ } | {
24
+ type: "call";
25
+ entry: CallEntry;
26
+ } | {
27
+ type: "clear";
28
+ };
29
+ export type CallConnection = "connecting" | "live" | "reconnecting" | "unavailable";
30
+ export declare const callFailed: (entry: CallEntry) => boolean;
31
+ export declare const callStatus: (entry: CallEntry) => string;
32
+ export declare const formatCallHttp: (entry: CallEntry, side?: "request" | "response" | "both") => string;
@@ -0,0 +1,8 @@
1
+ export const callFailed = (entry) => !entry.pending && Boolean(entry.error || entry.rpcError || (!entry.expected && (entry.status < 200 || entry.status >= 300)));
2
+ export const callStatus = (entry) => entry.pending ? "Pending" : entry.rpcError ? "Tool error" : entry.error ? "Failed" : entry.expected ? "Expected" : callFailed(entry) ? "Failed" : "Done";
3
+ export const formatCallHttp = (entry, side = "both") => {
4
+ const headers = (h) => Object.entries(h).map(([k, v]) => `${k}: ${v}`).join("\n");
5
+ const request = `${entry.method} ${entry.url}\n${headers(entry.requestHeaders)}\n\n${entry.requestBody ?? ""}`;
6
+ const response = `HTTP ${entry.status} ${entry.statusText}\n${headers(entry.responseHeaders)}\n\n${entry.responseBody ?? ""}${entry.rpcError || entry.error ? `\n${entry.rpcError ?? entry.error}` : ""}`;
7
+ return side === "request" ? request : side === "response" ? response : `${request}\n\n${response}`;
8
+ };
@@ -22,6 +22,12 @@ const threadStyles = `
22
22
  font: inherit;
23
23
  }
24
24
 
25
+ /* The host's own display would otherwise beat the UA rule for [hidden],
26
+ leaving the element on screen when a host hides it. */
27
+ :host([hidden]) {
28
+ display: none !important;
29
+ }
30
+
25
31
  [part="thread"] {
26
32
  display: grid;
27
33
  gap: ${boePanel.gap};
@@ -19,6 +19,12 @@ const elementStyles = `
19
19
  font: inherit;
20
20
  }
21
21
 
22
+ /* The host's own display would otherwise beat the UA rule for [hidden],
23
+ leaving the element on screen when a host hides it. */
24
+ :host([hidden]) {
25
+ display: none !important;
26
+ }
27
+
22
28
  [part="menu-shell"] {
23
29
  position: relative;
24
30
  display: inline-grid;
@@ -15,6 +15,12 @@ const elementStyles = `
15
15
  font: inherit;
16
16
  }
17
17
 
18
+ /* The host's own display would otherwise beat the UA rule for [hidden],
19
+ leaving the element on screen when a host hides it. */
20
+ :host([hidden]) {
21
+ display: none !important;
22
+ }
23
+
18
24
  [part="breadcrumbs"] {
19
25
  display: flex;
20
26
  flex-wrap: wrap;
@@ -19,6 +19,12 @@ const elementStyles = `
19
19
  font: inherit;
20
20
  }
21
21
 
22
+ /* The host's own display would otherwise beat the UA rule for [hidden],
23
+ leaving the element on screen when a host hides it. */
24
+ :host([hidden]) {
25
+ display: none !important;
26
+ }
27
+
22
28
  [part="list-shell"] {
23
29
  border: 1px solid color-mix(in srgb, var(--boe-token-stroke-stroke, #e8e8e8) 84%, var(--boe-token-surface-surface, #ffffff) 16%);
24
30
  border-radius: ${boePanel.radius};
@@ -23,6 +23,12 @@ const elementStyles = `
23
23
  min-width: 0;
24
24
  }
25
25
 
26
+ /* The host's own display would otherwise beat the UA rule for [hidden],
27
+ leaving the element on screen when a host hides it. */
28
+ :host([hidden]) {
29
+ display: none !important;
30
+ }
31
+
26
32
  [part="table-shell"] {
27
33
  border: 1px solid color-mix(in srgb, var(--boe-token-stroke-stroke, #e8e8e8) 84%, var(--boe-token-surface-surface, #ffffff) 16%);
28
34
  border-radius: ${boePanel.radius};
@@ -13,6 +13,12 @@ const elementStyles = `
13
13
  font: inherit;
14
14
  }
15
15
 
16
+ /* The host's own display would otherwise beat the UA rule for [hidden],
17
+ leaving the element on screen when a host hides it. */
18
+ :host([hidden]) {
19
+ display: none !important;
20
+ }
21
+
16
22
  [part="toolbar"] {
17
23
  display: flex;
18
24
  flex-wrap: wrap;
@@ -30,6 +30,12 @@ const elementStyles = `
30
30
  font: inherit;
31
31
  }
32
32
 
33
+ /* The host's own display would otherwise beat the UA rule for [hidden],
34
+ leaving the element on screen when a host hides it. */
35
+ :host([hidden]) {
36
+ display: none !important;
37
+ }
38
+
33
39
  section {
34
40
  display: grid;
35
41
  gap: ${boePanel.gap};
@@ -31,6 +31,12 @@ const elementStyles = `
31
31
  font: inherit;
32
32
  }
33
33
 
34
+ /* The host's own display would otherwise beat the UA rule for [hidden],
35
+ leaving the element on screen when a host hides it. */
36
+ :host([hidden]) {
37
+ display: none !important;
38
+ }
39
+
34
40
  section {
35
41
  display: grid;
36
42
  gap: ${boePanel.gap};
@@ -25,6 +25,12 @@ const elementStyles = `
25
25
  font: inherit;
26
26
  }
27
27
 
28
+ /* The host's own display would otherwise beat the UA rule for [hidden],
29
+ leaving the element on screen when a host hides it. */
30
+ :host([hidden]) {
31
+ display: none !important;
32
+ }
33
+
28
34
  [part="sidebar"] {
29
35
  display: grid;
30
36
  gap: ${boePanel.gap};
@@ -63,6 +63,12 @@ const elementStyles = `
63
63
  font: inherit;
64
64
  }
65
65
 
66
+ /* The host's own display would otherwise beat the UA rule for [hidden],
67
+ leaving the element on screen when a host hides it. */
68
+ :host([hidden]) {
69
+ display: none !important;
70
+ }
71
+
66
72
  [part="panel"] {
67
73
  display: grid;
68
74
  gap: ${boePanel.gap};
@@ -722,7 +728,8 @@ export class ContentUploader extends BaseElement {
722
728
  </div>
723
729
  <box-progress-bar
724
730
  part="row-progress"
725
- label="${escapeHtml(`${item.name} upload progress`)}"
731
+ hide-label
732
+ label="${escapeHtml(item.name)}"
726
733
  max="100"
727
734
  value="${String(Math.round(item.progress * 100))}"
728
735
  ></box-progress-bar>
@@ -18,6 +18,12 @@ const elementStyles = `
18
18
  display: block;
19
19
  }
20
20
 
21
+ /* The host's own display would otherwise beat the UA rule for [hidden],
22
+ leaving the element on screen when a host hides it. */
23
+ :host([hidden]) {
24
+ display: none !important;
25
+ }
26
+
21
27
  /*
22
28
  * The height a host sets on the element has to reach the scrollers, or
23
29
  * the panes size to their content, never overflow, and the scroll lock
@@ -20,6 +20,12 @@ const elementStyles = `
20
20
  font: inherit;
21
21
  }
22
22
 
23
+ /* The host's own display would otherwise beat the UA rule for [hidden],
24
+ leaving the element on screen when a host hides it. */
25
+ :host([hidden]) {
26
+ display: none !important;
27
+ }
28
+
23
29
  [part="panel"] {
24
30
  display: grid;
25
31
  gap: ${boePanel.gap};
@@ -15,6 +15,12 @@ const elementStyles = `
15
15
  font: inherit;
16
16
  }
17
17
 
18
+ /* The host's own display would otherwise beat the UA rule for [hidden],
19
+ leaving the element on screen when a host hides it. */
20
+ :host([hidden]) {
21
+ display: none !important;
22
+ }
23
+
18
24
  [part="builder"] {
19
25
  display: grid;
20
26
  gap: 0.6rem;
@@ -25,6 +25,12 @@ const elementStyles = `
25
25
  font: inherit;
26
26
  }
27
27
 
28
+ /* The host's own display would otherwise beat the UA rule for [hidden],
29
+ leaving the element on screen when a host hides it. */
30
+ :host([hidden]) {
31
+ display: none !important;
32
+ }
33
+
28
34
  [part="wizard"] {
29
35
  display: grid;
30
36
  gap: ${boePanel.gap};
@@ -13,6 +13,12 @@ const elementStyles = `
13
13
  display: block;
14
14
  }
15
15
 
16
+ /* The host's own display would otherwise beat the UA rule for [hidden],
17
+ leaving the element on screen when a host hides it. */
18
+ :host([hidden]) {
19
+ display: none !important;
20
+ }
21
+
16
22
  [part="card"] {
17
23
  border: ${boePanel.border};
18
24
  border-radius: ${boePanel.radius};
@@ -15,6 +15,12 @@ const elementStyles = `
15
15
  font: inherit;
16
16
  }
17
17
 
18
+ /* The host's own display would otherwise beat the UA rule for [hidden],
19
+ leaving the element on screen when a host hides it. */
20
+ :host([hidden]) {
21
+ display: none !important;
22
+ }
23
+
18
24
  [part="panel"] {
19
25
  display: grid;
20
26
  gap: 0.6rem;
@@ -14,6 +14,12 @@ const elementStyles = `
14
14
  font: inherit;
15
15
  }
16
16
 
17
+ /* The host's own display would otherwise beat the UA rule for [hidden],
18
+ leaving the element on screen when a host hides it. */
19
+ :host([hidden]) {
20
+ display: none !important;
21
+ }
22
+
17
23
  [part="panel"] {
18
24
  display: grid;
19
25
  gap: 0.6rem;
@@ -15,6 +15,12 @@ const elementStyles = `
15
15
  font: inherit;
16
16
  }
17
17
 
18
+ /* The host's own display would otherwise beat the UA rule for [hidden],
19
+ leaving the element on screen when a host hides it. */
20
+ :host([hidden]) {
21
+ display: none !important;
22
+ }
23
+
18
24
  [part="panel"] {
19
25
  display: grid;
20
26
  gap: 0.6rem;