@unofficialbox/box-open-elements 0.5.0 → 0.6.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 (219) hide show
  1. package/README.md +3 -3
  2. package/dist/components/collections/table.d.ts +57 -3
  3. package/dist/components/collections/table.js +339 -20
  4. package/dist/components/feedback/due-badge.d.ts +38 -0
  5. package/dist/components/feedback/due-badge.js +168 -0
  6. package/dist/components/feedback/due-types.d.ts +32 -0
  7. package/dist/components/feedback/due-types.js +91 -0
  8. package/dist/components/feedback/progress-steps.d.ts +51 -5
  9. package/dist/components/feedback/progress-steps.js +200 -22
  10. package/dist/components/feedback/stage-path.d.ts +44 -0
  11. package/dist/components/feedback/stage-path.js +235 -0
  12. package/dist/components/forms/select.d.ts +21 -0
  13. package/dist/components/forms/select.js +100 -3
  14. package/dist/components/forms/text-field.d.ts +21 -0
  15. package/dist/components/forms/text-field.js +100 -1
  16. package/dist/components/layout/nav-sidebar.d.ts +14 -0
  17. package/dist/components/layout/nav-sidebar.js +49 -0
  18. package/dist/components/layout/split-view.d.ts +14 -0
  19. package/dist/components/layout/split-view.js +80 -1
  20. package/dist/components/overlays/command-palette.d.ts +62 -0
  21. package/dist/components/overlays/command-palette.js +537 -0
  22. package/dist/components/overlays/command-types.d.ts +90 -0
  23. package/dist/components/overlays/command-types.js +259 -0
  24. package/dist/components/overlays/drawer.d.ts +18 -0
  25. package/dist/components/overlays/drawer.js +135 -9
  26. package/dist/components/overlays/shortcuts-overlay.d.ts +48 -0
  27. package/dist/components/overlays/shortcuts-overlay.js +385 -0
  28. package/dist/components/overlays/tooltip.js +1 -1
  29. package/dist/element-maps.d.ts +292 -0
  30. package/dist/element-maps.js +1 -0
  31. package/dist/entries/activity-density.d.ts +1 -0
  32. package/dist/entries/activity-density.js +1 -0
  33. package/dist/entries/agent-chat.d.ts +1 -0
  34. package/dist/entries/agent-chat.js +1 -0
  35. package/dist/entries/audit-log.d.ts +1 -0
  36. package/dist/entries/audit-log.js +1 -0
  37. package/dist/entries/command-palette.d.ts +1 -0
  38. package/dist/entries/command-palette.js +1 -0
  39. package/dist/entries/compare-view.d.ts +1 -0
  40. package/dist/entries/compare-view.js +1 -0
  41. package/dist/entries/diff-viewer.d.ts +1 -0
  42. package/dist/entries/diff-viewer.js +1 -0
  43. package/dist/entries/due-badge.d.ts +1 -0
  44. package/dist/entries/due-badge.js +1 -0
  45. package/dist/entries/form-wizard.d.ts +1 -0
  46. package/dist/entries/form-wizard.js +1 -0
  47. package/dist/entries/lineage-graph.d.ts +1 -0
  48. package/dist/entries/lineage-graph.js +1 -0
  49. package/dist/entries/notification-bell.d.ts +1 -0
  50. package/dist/entries/notification-bell.js +1 -0
  51. package/dist/entries/notification-inbox.d.ts +1 -0
  52. package/dist/entries/notification-inbox.js +1 -0
  53. package/dist/entries/provenance-strip.d.ts +1 -0
  54. package/dist/entries/provenance-strip.js +1 -0
  55. package/dist/entries/run-trace.d.ts +1 -0
  56. package/dist/entries/run-trace.js +1 -0
  57. package/dist/entries/shortcuts-overlay.d.ts +1 -0
  58. package/dist/entries/shortcuts-overlay.js +1 -0
  59. package/dist/entries/signature-ceremony.d.ts +1 -0
  60. package/dist/entries/signature-ceremony.js +1 -0
  61. package/dist/entries/stage-path.d.ts +1 -0
  62. package/dist/entries/stage-path.js +1 -0
  63. package/dist/entries/timeline.d.ts +1 -0
  64. package/dist/entries/timeline.js +1 -0
  65. package/dist/entries/version-graph.d.ts +1 -0
  66. package/dist/entries/version-graph.js +1 -0
  67. package/dist/entries/version-list.d.ts +1 -0
  68. package/dist/entries/version-list.js +1 -0
  69. package/dist/entries/wizard-summary.d.ts +1 -0
  70. package/dist/entries/wizard-summary.js +1 -0
  71. package/dist/entries/work-queue.d.ts +1 -0
  72. package/dist/entries/work-queue.js +1 -0
  73. package/dist/entries/workload-board.d.ts +1 -0
  74. package/dist/entries/workload-board.js +1 -0
  75. package/dist/index.d.ts +21 -0
  76. package/dist/index.js +21 -0
  77. package/dist/patterns/agent-chat/agent-chat.d.ts +75 -0
  78. package/dist/patterns/agent-chat/agent-chat.js +820 -0
  79. package/dist/patterns/agent-chat/controller.d.ts +27 -0
  80. package/dist/patterns/agent-chat/controller.js +182 -0
  81. package/dist/patterns/agent-chat/index.d.ts +3 -0
  82. package/dist/patterns/agent-chat/index.js +6 -0
  83. package/dist/patterns/agent-chat/types.d.ts +109 -0
  84. package/dist/patterns/agent-chat/types.js +1 -0
  85. package/dist/patterns/audit/activity-density.d.ts +68 -0
  86. package/dist/patterns/audit/activity-density.js +428 -0
  87. package/dist/patterns/audit/audit-log.d.ts +81 -0
  88. package/dist/patterns/audit/audit-log.js +794 -0
  89. package/dist/patterns/audit/index.d.ts +3 -0
  90. package/dist/patterns/audit/index.js +7 -0
  91. package/dist/patterns/audit/shared.d.ts +10 -0
  92. package/dist/patterns/audit/shared.js +50 -0
  93. package/dist/patterns/audit/types.d.ts +143 -0
  94. package/dist/patterns/audit/types.js +327 -0
  95. package/dist/patterns/content-explorer/actions/controller.js +12 -2
  96. package/dist/patterns/content-explorer/box-transport.js +117 -25
  97. package/dist/patterns/content-explorer/content-explorer.d.ts +13 -1
  98. package/dist/patterns/content-explorer/content-explorer.js +36 -3
  99. package/dist/patterns/content-explorer/contracts.d.ts +24 -1
  100. package/dist/patterns/content-explorer/contracts.js +68 -11
  101. package/dist/patterns/content-explorer/controller.d.ts +16 -1
  102. package/dist/patterns/content-explorer/controller.js +130 -4
  103. package/dist/patterns/content-explorer/navigation/controller.js +11 -9
  104. package/dist/patterns/content-explorer/types.d.ts +58 -1
  105. package/dist/patterns/content-picker/content-picker.d.ts +71 -0
  106. package/dist/patterns/content-picker/content-picker.js +747 -0
  107. package/dist/patterns/content-picker/controller.d.ts +38 -0
  108. package/dist/patterns/content-picker/controller.js +141 -0
  109. package/dist/patterns/content-picker/index.d.ts +3 -0
  110. package/dist/patterns/content-picker/index.js +6 -0
  111. package/dist/patterns/content-picker/types.d.ts +52 -0
  112. package/dist/patterns/content-picker/types.js +26 -0
  113. package/dist/patterns/content-sidebar/content-sidebar.d.ts +43 -0
  114. package/dist/patterns/content-sidebar/content-sidebar.js +293 -0
  115. package/dist/patterns/content-sidebar/index.d.ts +2 -0
  116. package/dist/patterns/content-sidebar/index.js +4 -0
  117. package/dist/patterns/content-sidebar/types.d.ts +18 -0
  118. package/dist/patterns/content-sidebar/types.js +20 -0
  119. package/dist/patterns/content-uploader/box-transport.d.ts +14 -0
  120. package/dist/patterns/content-uploader/box-transport.js +54 -0
  121. package/dist/patterns/content-uploader/content-uploader.d.ts +62 -0
  122. package/dist/patterns/content-uploader/content-uploader.js +559 -0
  123. package/dist/patterns/content-uploader/controller.d.ts +39 -0
  124. package/dist/patterns/content-uploader/controller.js +227 -0
  125. package/dist/patterns/content-uploader/index.d.ts +4 -0
  126. package/dist/patterns/content-uploader/index.js +8 -0
  127. package/dist/patterns/content-uploader/types.d.ts +120 -0
  128. package/dist/patterns/content-uploader/types.js +38 -0
  129. package/dist/patterns/diff/compare-view.d.ts +47 -0
  130. package/dist/patterns/diff/compare-view.js +276 -0
  131. package/dist/patterns/diff/diff-viewer.d.ts +42 -0
  132. package/dist/patterns/diff/diff-viewer.js +434 -0
  133. package/dist/patterns/diff/engine.d.ts +22 -0
  134. package/dist/patterns/diff/engine.js +276 -0
  135. package/dist/patterns/diff/index.d.ts +4 -0
  136. package/dist/patterns/diff/index.js +8 -0
  137. package/dist/patterns/diff/types.d.ts +69 -0
  138. package/dist/patterns/diff/types.js +24 -0
  139. package/dist/patterns/form-wizard/controller.d.ts +39 -0
  140. package/dist/patterns/form-wizard/controller.js +157 -0
  141. package/dist/patterns/form-wizard/form-wizard.d.ts +63 -0
  142. package/dist/patterns/form-wizard/form-wizard.js +468 -0
  143. package/dist/patterns/form-wizard/index.d.ts +4 -0
  144. package/dist/patterns/form-wizard/index.js +8 -0
  145. package/dist/patterns/form-wizard/types.d.ts +109 -0
  146. package/dist/patterns/form-wizard/types.js +83 -0
  147. package/dist/patterns/form-wizard/wizard-summary.d.ts +62 -0
  148. package/dist/patterns/form-wizard/wizard-summary.js +324 -0
  149. package/dist/patterns/internal/safe-href.d.ts +17 -0
  150. package/dist/patterns/internal/safe-href.js +17 -0
  151. package/dist/patterns/lineage/index.d.ts +3 -0
  152. package/dist/patterns/lineage/index.js +6 -0
  153. package/dist/patterns/lineage/lineage-graph.d.ts +30 -0
  154. package/dist/patterns/lineage/lineage-graph.js +434 -0
  155. package/dist/patterns/lineage/provenance-strip.d.ts +22 -0
  156. package/dist/patterns/lineage/provenance-strip.js +194 -0
  157. package/dist/patterns/lineage/types.d.ts +53 -0
  158. package/dist/patterns/lineage/types.js +49 -0
  159. package/dist/patterns/notifications/index.d.ts +3 -0
  160. package/dist/patterns/notifications/index.js +6 -0
  161. package/dist/patterns/notifications/notification-bell.d.ts +38 -0
  162. package/dist/patterns/notifications/notification-bell.js +198 -0
  163. package/dist/patterns/notifications/notification-inbox.d.ts +46 -0
  164. package/dist/patterns/notifications/notification-inbox.js +537 -0
  165. package/dist/patterns/notifications/types.d.ts +61 -0
  166. package/dist/patterns/notifications/types.js +108 -0
  167. package/dist/patterns/preview/annotation-inspector.d.ts +25 -6
  168. package/dist/patterns/preview/annotation-inspector.js +239 -94
  169. package/dist/patterns/preview/annotation-thread.d.ts +25 -5
  170. package/dist/patterns/preview/annotation-thread.js +233 -82
  171. package/dist/patterns/preview/annotation-toolbar.d.ts +20 -6
  172. package/dist/patterns/preview/annotation-toolbar.js +162 -96
  173. package/dist/patterns/preview/content-preview-adapter.d.ts +10 -1
  174. package/dist/patterns/preview/content-preview-adapter.js +26 -1
  175. package/dist/patterns/preview/preview-element.d.ts +15 -2
  176. package/dist/patterns/preview/preview-element.js +223 -52
  177. package/dist/patterns/preview/provider-adapter.d.ts +47 -0
  178. package/dist/patterns/preview/provider-adapter.js +17 -0
  179. package/dist/patterns/run/index.d.ts +2 -0
  180. package/dist/patterns/run/index.js +4 -0
  181. package/dist/patterns/run/run-trace.d.ts +40 -0
  182. package/dist/patterns/run/run-trace.js +441 -0
  183. package/dist/patterns/run/types.d.ts +66 -0
  184. package/dist/patterns/run/types.js +152 -0
  185. package/dist/patterns/signature/index.d.ts +2 -0
  186. package/dist/patterns/signature/index.js +4 -0
  187. package/dist/patterns/signature/signature-ceremony.d.ts +33 -0
  188. package/dist/patterns/signature/signature-ceremony.js +317 -0
  189. package/dist/patterns/signature/types.d.ts +68 -0
  190. package/dist/patterns/signature/types.js +89 -0
  191. package/dist/patterns/timeline/index.d.ts +2 -0
  192. package/dist/patterns/timeline/index.js +4 -0
  193. package/dist/patterns/timeline/timeline.d.ts +27 -0
  194. package/dist/patterns/timeline/timeline.js +430 -0
  195. package/dist/patterns/timeline/types.d.ts +36 -0
  196. package/dist/patterns/timeline/types.js +27 -0
  197. package/dist/patterns/versions/graph-layout.d.ts +43 -0
  198. package/dist/patterns/versions/graph-layout.js +159 -0
  199. package/dist/patterns/versions/index.d.ts +4 -0
  200. package/dist/patterns/versions/index.js +8 -0
  201. package/dist/patterns/versions/shared.d.ts +4 -0
  202. package/dist/patterns/versions/shared.js +13 -0
  203. package/dist/patterns/versions/types.d.ts +37 -0
  204. package/dist/patterns/versions/types.js +39 -0
  205. package/dist/patterns/versions/version-graph.d.ts +36 -0
  206. package/dist/patterns/versions/version-graph.js +438 -0
  207. package/dist/patterns/versions/version-list.d.ts +39 -0
  208. package/dist/patterns/versions/version-list.js +407 -0
  209. package/dist/patterns/work-queue/controller.d.ts +26 -0
  210. package/dist/patterns/work-queue/controller.js +150 -0
  211. package/dist/patterns/work-queue/index.d.ts +4 -0
  212. package/dist/patterns/work-queue/index.js +7 -0
  213. package/dist/patterns/work-queue/types.d.ts +128 -0
  214. package/dist/patterns/work-queue/types.js +45 -0
  215. package/dist/patterns/work-queue/work-queue.d.ts +48 -0
  216. package/dist/patterns/work-queue/work-queue.js +534 -0
  217. package/dist/patterns/work-queue/workload-board.d.ts +53 -0
  218. package/dist/patterns/work-queue/workload-board.js +608 -0
  219. package/package.json +89 -5
@@ -9,7 +9,14 @@ const escapeHtml = (value) => value
9
9
  .replaceAll(">", ">")
10
10
  .replaceAll('"', """)
11
11
  .replaceAll("'", "'");
12
+ const isSafeColorValue = (value) => /^#[0-9a-fA-F]{3,8}$/.test(value) || /^[a-zA-Z]+$/.test(value);
12
13
  const elementStyles = `
14
+ /* Author display rules on parts would otherwise defeat the UA's
15
+ [hidden] rule — state toggling relies on the hidden attribute. */
16
+ [hidden] {
17
+ display: none !important;
18
+ }
19
+
13
20
  :host {
14
21
  display: block;
15
22
  color: inherit;
@@ -154,6 +161,14 @@ export class AnnotationToolbar extends BaseElement {
154
161
  static get observedAttributes() {
155
162
  return ["actions", "active-tool-id", "color-options", "current-color", "label", "tools"];
156
163
  }
164
+ headerEl;
165
+ toolsEl;
166
+ colorsEl;
167
+ actionsSectionEl;
168
+ actionsEl;
169
+ toolsSignature = null;
170
+ colorsSignature = null;
171
+ actionsSignature = "";
157
172
  get actions() {
158
173
  return this.parseJsonAttribute("actions", []);
159
174
  }
@@ -202,12 +217,6 @@ export class AnnotationToolbar extends BaseElement {
202
217
  set tools(value) {
203
218
  this.setAttribute("tools", JSON.stringify(value));
204
219
  }
205
- connectedCallback() {
206
- super.connectedCallback();
207
- }
208
- attributeChangedCallback(name, oldValue, newValue) {
209
- super.attributeChangedCallback(name, oldValue, newValue);
210
- }
211
220
  parseJsonAttribute(name, fallback) {
212
221
  const raw = this.getAttribute(name);
213
222
  if (!raw) {
@@ -243,52 +252,43 @@ export class AnnotationToolbar extends BaseElement {
243
252
  detail: color,
244
253
  }));
245
254
  }
246
- renderTemplate() {
247
- if (!this.shadowRoot) {
248
- return;
249
- }
250
- this.shadowRoot.innerHTML = `
251
- <style>${elementStyles}</style>
252
- <div part="content-host"></div>
253
- `;
255
+ enabledButtons(container) {
256
+ return Array.from(container.querySelectorAll("button")).filter(button => !button.disabled);
254
257
  }
255
- update() {
256
- if (!this.shadowRoot) {
257
- return;
258
- }
259
- const toolMarkup = this.tools.length
258
+ rebuildTools() {
259
+ this.toolsEl.innerHTML = this.tools.length
260
260
  ? this.tools
261
- .map(tool => {
262
- const isActive = tool.id === this.activeToolId;
263
- return `
261
+ .map(tool => `
264
262
  <button
265
263
  type="button"
266
264
  part="tool"
267
265
  data-tool-id="${escapeHtml(tool.id)}"
268
266
  ${tool.disabled ? "disabled" : ""}
269
- aria-pressed="${isActive ? "true" : "false"}"
267
+ aria-pressed="false"
270
268
  >
271
269
  <span part="tool-icon">${escapeHtml(tool.icon ?? "")}</span>
272
270
  <span part="tool-label">${escapeHtml(tool.label)}</span>
273
271
  </button>
274
- `;
275
- })
272
+ `)
276
273
  .join("")
277
274
  : `<div part="empty">No annotation tools configured.</div>`;
278
- const colorMarkup = this.colorOptions.length
275
+ }
276
+ rebuildColors() {
277
+ this.colorsEl.innerHTML = this.colorOptions.length
279
278
  ? this.colorOptions
280
279
  .map(color => {
281
- const selected = color.value === this.currentColor;
280
+ const styleAttr = isSafeColorValue(color.value)
281
+ ? ` style="--annotation-color:${escapeHtml(color.value)};"`
282
+ : "";
282
283
  return `
283
284
  <button
284
285
  type="button"
285
286
  part="color"
286
287
  data-color-id="${escapeHtml(color.id)}"
287
288
  data-color-value="${escapeHtml(color.value)}"
288
- aria-pressed="${selected ? "true" : "false"}"
289
+ aria-pressed="false"
289
290
  aria-label="${escapeHtml(color.label)}"
290
- title="${escapeHtml(color.label)}"
291
- style="--annotation-color:${escapeHtml(color.value)};"
291
+ title="${escapeHtml(color.label)}"${styleAttr}
292
292
  >
293
293
  <span part="color-swatch"></span>
294
294
  </button>
@@ -296,92 +296,158 @@ export class AnnotationToolbar extends BaseElement {
296
296
  })
297
297
  .join("")
298
298
  : `<div part="empty">No colors configured.</div>`;
299
- const actionMarkup = this.actions.length
300
- ? this.actions
301
- .map(action => `
302
- <button
303
- type="button"
304
- part="action"
305
- data-action-id="${escapeHtml(action.id)}"
306
- data-tone="${escapeHtml(action.tone ?? "neutral")}"
307
- >
308
- ${escapeHtml(action.label)}
309
- </button>
310
- `)
311
- .join("")
312
- : "";
313
- const host = this.shadowRoot.querySelector('[part="content-host"]');
314
- if (!host) {
299
+ }
300
+ rebuildActions() {
301
+ this.actionsEl.innerHTML = this.actions
302
+ .map(action => `
303
+ <button
304
+ type="button"
305
+ part="action"
306
+ data-action-id="${escapeHtml(action.id)}"
307
+ data-tone="${escapeHtml(action.tone ?? "neutral")}"
308
+ >
309
+ ${escapeHtml(action.label)}
310
+ </button>
311
+ `)
312
+ .join("");
313
+ }
314
+ patchToolSelection() {
315
+ this.toolsEl.querySelectorAll('[part="tool"]').forEach(button => {
316
+ const isActive = button.getAttribute("data-tool-id") === this.activeToolId;
317
+ button.setAttribute("aria-pressed", isActive ? "true" : "false");
318
+ });
319
+ const buttons = this.enabledButtons(this.toolsEl);
320
+ const activeIndex = buttons.findIndex(button => button.getAttribute("aria-pressed") === "true");
321
+ applyRovingTabindex(buttons, activeIndex >= 0 ? activeIndex : 0);
322
+ }
323
+ patchColorSelection() {
324
+ this.colorsEl.querySelectorAll('[part="color"]').forEach(button => {
325
+ const selected = button.getAttribute("data-color-value") === this.currentColor;
326
+ button.setAttribute("aria-pressed", selected ? "true" : "false");
327
+ });
328
+ const buttons = this.enabledButtons(this.colorsEl);
329
+ const activeIndex = buttons.findIndex(button => button.getAttribute("aria-pressed") === "true");
330
+ applyRovingTabindex(buttons, activeIndex >= 0 ? activeIndex : 0);
331
+ }
332
+ renderTemplate() {
333
+ if (!this.shadowRoot) {
315
334
  return;
316
335
  }
317
- host.innerHTML = `
336
+ this.shadowRoot.innerHTML = `
337
+ <style>${elementStyles}</style>
318
338
  <article part="toolbar">
319
- <div part="header">${escapeHtml(this.label)}</div>
339
+ <div part="header"></div>
320
340
  <div part="body">
321
341
  <section part="section">
322
342
  <div part="section-title">Tools</div>
323
- <div part="tools" role="toolbar" aria-label="${escapeHtml(this.label)} tools">
324
- ${toolMarkup}
325
- </div>
343
+ <div part="tools" role="toolbar"></div>
326
344
  </section>
327
345
  <section part="section">
328
346
  <div part="section-title">Colors</div>
329
- <div part="colors" role="toolbar" aria-label="${escapeHtml(this.label)} colors">
330
- ${colorMarkup}
331
- </div>
347
+ <div part="colors" role="toolbar"></div>
348
+ </section>
349
+ <section part="section" hidden>
350
+ <div part="section-title">Actions</div>
351
+ <div part="actions"></div>
332
352
  </section>
333
- ${actionMarkup
334
- ? `
335
- <section part="section">
336
- <div part="section-title">Actions</div>
337
- <div part="actions">
338
- ${actionMarkup}
339
- </div>
340
- </section>
341
- `
342
- : ""}
343
353
  </div>
344
354
  </article>
345
355
  `;
346
- this.shadowRoot.querySelectorAll('[part="tool"]').forEach(button => {
347
- button.addEventListener("click", () => {
348
- const toolId = button.getAttribute("data-tool-id");
349
- const tool = this.tools.find(item => item.id === toolId);
350
- if (tool && !tool.disabled) {
351
- this.emitToolSelected(tool);
352
- }
353
- });
356
+ this.headerEl = this.shadowRoot.querySelector('[part="header"]');
357
+ this.toolsEl = this.shadowRoot.querySelector('[part="tools"]');
358
+ this.colorsEl = this.shadowRoot.querySelector('[part="colors"]');
359
+ this.actionsEl = this.shadowRoot.querySelector('[part="actions"]');
360
+ this.actionsSectionEl = this.actionsEl.closest("section");
361
+ }
362
+ setupListeners() {
363
+ this.toolsEl.addEventListener("click", event => {
364
+ const button = event.target.closest('[part="tool"]');
365
+ if (!button || !this.toolsEl.contains(button)) {
366
+ return;
367
+ }
368
+ const toolId = button.getAttribute("data-tool-id");
369
+ const tool = this.tools.find(item => item.id === toolId);
370
+ if (tool && !tool.disabled) {
371
+ this.emitToolSelected(tool);
372
+ }
373
+ });
374
+ this.colorsEl.addEventListener("click", event => {
375
+ const button = event.target.closest('[part="color"]');
376
+ if (!button || !this.colorsEl.contains(button)) {
377
+ return;
378
+ }
379
+ const colorId = button.getAttribute("data-color-id");
380
+ const color = this.colorOptions.find(item => item.id === colorId);
381
+ if (color) {
382
+ this.emitColorSelected(color);
383
+ }
354
384
  });
355
- this.shadowRoot.querySelectorAll('[part="color"]').forEach(button => {
356
- button.addEventListener("click", () => {
357
- const colorId = button.getAttribute("data-color-id");
358
- const color = this.colorOptions.find(item => item.id === colorId);
359
- if (color) {
360
- this.emitColorSelected(color);
361
- }
385
+ this.actionsEl.addEventListener("click", event => {
386
+ const button = event.target.closest('[part="action"]');
387
+ if (!button || !this.actionsEl.contains(button)) {
388
+ return;
389
+ }
390
+ const actionId = button.getAttribute("data-action-id");
391
+ if (actionId) {
392
+ this.emitAction(actionId);
393
+ }
394
+ });
395
+ this.toolsEl.addEventListener("keydown", event => {
396
+ handleRovingKeydown(event, this.enabledButtons(this.toolsEl), {
397
+ orientation: "horizontal",
362
398
  });
363
399
  });
364
- this.shadowRoot.querySelectorAll('[part="action"]').forEach(button => {
365
- button.addEventListener("click", () => {
366
- const actionId = button.getAttribute("data-action-id");
367
- if (actionId) {
368
- this.emitAction(actionId);
369
- }
400
+ this.colorsEl.addEventListener("keydown", event => {
401
+ handleRovingKeydown(event, this.enabledButtons(this.colorsEl), {
402
+ orientation: "horizontal",
370
403
  });
371
404
  });
372
- const bindToolbar = (selector) => {
373
- const toolbar = this.shadowRoot?.querySelector(selector);
374
- if (!toolbar) {
405
+ }
406
+ update() {
407
+ if (!this.toolsEl) {
408
+ return;
409
+ }
410
+ this.headerEl.textContent = this.label;
411
+ this.toolsEl.setAttribute("aria-label", `${this.label} tools`);
412
+ this.colorsEl.setAttribute("aria-label", `${this.label} colors`);
413
+ const nextTools = this.getAttribute("tools");
414
+ if (nextTools !== this.toolsSignature || this.toolsEl.childElementCount === 0) {
415
+ this.toolsSignature = nextTools;
416
+ this.rebuildTools();
417
+ }
418
+ this.patchToolSelection();
419
+ const nextColors = this.getAttribute("color-options");
420
+ if (nextColors !== this.colorsSignature || this.colorsEl.childElementCount === 0) {
421
+ this.colorsSignature = nextColors;
422
+ this.rebuildColors();
423
+ }
424
+ this.patchColorSelection();
425
+ const actions = this.actions;
426
+ this.actionsSectionEl.hidden = actions.length === 0;
427
+ const nextActions = this.actionsKey();
428
+ if (nextActions !== this.actionsSignature || this.actionsEl.childElementCount === 0) {
429
+ this.actionsSignature = nextActions;
430
+ this.rebuildActions();
431
+ }
432
+ else {
433
+ this.patchActionLabels();
434
+ }
435
+ }
436
+ actionsKey() {
437
+ return JSON.stringify(this.actions.map(action => action.id));
438
+ }
439
+ patchActionLabels() {
440
+ // Action IDs are arbitrary strings (quotes, newlines, …) — match on the
441
+ // dataset instead of interpolating them into a CSS selector.
442
+ const buttons = Array.from(this.actionsEl.querySelectorAll('[part="action"]'));
443
+ this.actions.forEach(action => {
444
+ const button = buttons.find(candidate => candidate.dataset.actionId === action.id);
445
+ if (!button) {
375
446
  return;
376
447
  }
377
- const buttons = Array.from(toolbar.querySelectorAll("button")).filter(button => !button.disabled);
378
- applyRovingTabindex(buttons, 0);
379
- toolbar.addEventListener("keydown", event => {
380
- handleRovingKeydown(event, buttons, { orientation: "horizontal" });
381
- });
382
- };
383
- bindToolbar('[part="tools"]');
384
- bindToolbar('[part="colors"]');
448
+ button.textContent = action.label;
449
+ button.dataset.tone = action.tone ?? "neutral";
450
+ });
385
451
  }
386
452
  }
387
453
  AnnotationToolbar.register();
@@ -1,13 +1,22 @@
1
- import { type PreviewAdapterState, type PreviewProvider, type PreviewProviderActionDetail, type StaticPreviewProviderAdapter } from "./provider-adapter.js";
1
+ import { type PreviewAdapterState, type PreviewCommand, type PreviewProvider, type PreviewProviderActionDetail, type StaticPreviewProviderAdapter } from "./provider-adapter.js";
2
2
  export type ContentPreviewAdapterConfig = {
3
3
  onAction?: (detail: PreviewProviderActionDetail) => void | Promise<void>;
4
+ onCommand?: (command: PreviewCommand) => void | Promise<void>;
4
5
  onMount?: (container: HTMLElement) => void;
5
6
  onUnmount?: () => void;
7
+ /**
8
+ * Boot the real preview engine into the container (e.g. `new Preview()` +
9
+ * `preview.show(fileId, token, { container })` for the Box Preview SDK).
10
+ * Return a teardown function; the adapter invokes it on unmount and before
11
+ * re-mounting into a different container.
12
+ */
13
+ createViewer?: (container: HTMLElement) => (() => void) | void;
6
14
  provider?: Partial<PreviewProvider>;
7
15
  state?: PreviewAdapterState | null;
8
16
  };
9
17
  export type ContentPreviewAdapter = StaticPreviewProviderAdapter & {
10
18
  mount: (container: HTMLElement) => void;
11
19
  unmount: () => void;
20
+ getMountedContainer: () => HTMLElement | null;
12
21
  };
13
22
  export declare const createContentPreviewAdapter: (config?: ContentPreviewAdapterConfig) => ContentPreviewAdapter;
@@ -2,6 +2,7 @@ import { createStaticPreviewProviderAdapter, } from "./provider-adapter.js";
2
2
  export const createContentPreviewAdapter = (config = {}) => {
3
3
  const adapter = createStaticPreviewProviderAdapter({
4
4
  onAction: config.onAction,
5
+ onCommand: config.onCommand,
5
6
  provider: {
6
7
  id: "box-content-preview",
7
8
  label: "Box Content Preview",
@@ -12,19 +13,43 @@ export const createContentPreviewAdapter = (config = {}) => {
12
13
  state: config.state ?? null,
13
14
  });
14
15
  let mountedContainer = null;
16
+ let teardownViewer = null;
17
+ const teardown = () => {
18
+ teardownViewer?.();
19
+ teardownViewer = null;
20
+ mountedContainer = null;
21
+ };
15
22
  return {
16
23
  ...adapter,
17
24
  mount(container) {
25
+ if (mountedContainer === container) {
26
+ return;
27
+ }
28
+ // Re-mounting elsewhere tears the previous viewer down first.
29
+ if (mountedContainer) {
30
+ teardown();
31
+ }
18
32
  mountedContainer = container;
19
33
  config.onMount?.(container);
34
+ teardownViewer = config.createViewer?.(container) ?? null;
20
35
  adapter.setState({
21
36
  ...(adapter.getState() ?? {}),
22
37
  ready: true,
38
+ status: "ready",
23
39
  });
24
40
  },
25
41
  unmount() {
26
- mountedContainer = null;
42
+ if (!mountedContainer) {
43
+ return;
44
+ }
45
+ teardown();
27
46
  config.onUnmount?.();
47
+ adapter.setState({
48
+ ...(adapter.getState() ?? {}),
49
+ ready: false,
50
+ status: "idle",
51
+ });
28
52
  },
53
+ getMountedContainer: () => mountedContainer,
29
54
  };
30
55
  };
@@ -1,14 +1,20 @@
1
- import type { PreviewAdapterState, PreviewProvider, PreviewProviderAdapter } from "./provider-adapter.js";
1
+ import { type PreviewAdapterState, type PreviewCommand, type PreviewProvider, type PreviewProviderAdapter } from "./provider-adapter.js";
2
2
  import { BaseElement } from "../../core/index.js";
3
3
  export type PreviewElementAction = {
4
4
  id: string;
5
5
  label: string;
6
6
  tone?: string;
7
7
  };
8
+ /** Detail for the `command` event mirrored alongside adapter.sendCommand. */
9
+ export type PreviewElementCommandDetail = {
10
+ command: PreviewCommand;
11
+ providerId: string | null;
12
+ };
8
13
  export declare class Preview extends BaseElement {
9
14
  static readonly tagName: string;
10
15
  private providerAdapterValue;
11
16
  private providerAdapterUnsubscribe;
17
+ private adapterMounted;
12
18
  static get observedAttributes(): string[];
13
19
  get actions(): PreviewElementAction[];
14
20
  set actions(value: PreviewElementAction[]);
@@ -30,12 +36,19 @@ export declare class Preview extends BaseElement {
30
36
  set providerAdapter(value: PreviewProviderAdapter | null);
31
37
  connectedCallback(): void;
32
38
  disconnectedCallback(): void;
33
- attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
34
39
  private parseJsonAttribute;
40
+ private attachProviderAdapter;
35
41
  private teardownProviderAdapter;
36
42
  private getActiveProvider;
37
43
  private getActiveAdapterState;
38
44
  private emitAction;
45
+ private emitCommand;
39
46
  protected renderTemplate(): void;
47
+ protected setupListeners(): void;
40
48
  protected update(): void;
49
+ /**
50
+ * Paging/zoom controls render only when the adapter accepts commands and the
51
+ * state carries the numeric fields to drive them.
52
+ */
53
+ private renderControls;
41
54
  }