pith-ui 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/AI.md +8 -0
  2. package/API.md +656 -249
  3. package/README.md +1 -1
  4. package/dist/composer.d.ts.map +1 -1
  5. package/dist/composer.js +13 -4
  6. package/dist/composer.js.map +1 -1
  7. package/dist/content/conversation-view.d.ts +21 -4
  8. package/dist/content/conversation-view.d.ts.map +1 -1
  9. package/dist/content/conversation-view.js +38 -5
  10. package/dist/content/conversation-view.js.map +1 -1
  11. package/dist/content/image-viewer.d.ts +4 -2
  12. package/dist/content/image-viewer.d.ts.map +1 -1
  13. package/dist/content/image-viewer.js +25 -12
  14. package/dist/content/image-viewer.js.map +1 -1
  15. package/dist/content/paged-preview.d.ts.map +1 -1
  16. package/dist/content/paged-preview.js +6 -3
  17. package/dist/content/paged-preview.js.map +1 -1
  18. package/dist/content/welcome.d.ts.map +1 -1
  19. package/dist/content/welcome.js +14 -5
  20. package/dist/content/welcome.js.map +1 -1
  21. package/dist/files/panels.d.ts +6 -1
  22. package/dist/files/panels.d.ts.map +1 -1
  23. package/dist/files/panels.js +48 -7
  24. package/dist/files/panels.js.map +1 -1
  25. package/dist/files/systems.d.ts.map +1 -1
  26. package/dist/files/systems.js +47 -30
  27. package/dist/files/systems.js.map +1 -1
  28. package/dist/forms/actions.d.ts +7 -7
  29. package/dist/forms/actions.d.ts.map +1 -1
  30. package/dist/forms/actions.js +28 -8
  31. package/dist/forms/actions.js.map +1 -1
  32. package/dist/forms/custom-connection.d.ts +2 -1
  33. package/dist/forms/custom-connection.d.ts.map +1 -1
  34. package/dist/forms/custom-connection.js +34 -27
  35. package/dist/forms/custom-connection.js.map +1 -1
  36. package/dist/forms/dialog-frame.d.ts +2 -0
  37. package/dist/forms/dialog-frame.d.ts.map +1 -1
  38. package/dist/forms/dialog-frame.js +46 -26
  39. package/dist/forms/dialog-frame.js.map +1 -1
  40. package/dist/forms/identity.d.ts +12 -0
  41. package/dist/forms/identity.d.ts.map +1 -1
  42. package/dist/forms/identity.js +32 -0
  43. package/dist/forms/identity.js.map +1 -1
  44. package/dist/forms/model-editor.d.ts +8 -3
  45. package/dist/forms/model-editor.d.ts.map +1 -1
  46. package/dist/forms/model-editor.js +73 -62
  47. package/dist/forms/model-editor.js.map +1 -1
  48. package/dist/forms/panels.d.ts +95 -6
  49. package/dist/forms/panels.d.ts.map +1 -1
  50. package/dist/forms/panels.js +142 -27
  51. package/dist/forms/panels.js.map +1 -1
  52. package/dist/forms/provider-login.d.ts.map +1 -1
  53. package/dist/forms/provider-login.js +9 -7
  54. package/dist/forms/provider-login.js.map +1 -1
  55. package/dist/forms/resource-editor.d.ts +9 -5
  56. package/dist/forms/resource-editor.d.ts.map +1 -1
  57. package/dist/forms/resource-editor.js +18 -8
  58. package/dist/forms/resource-editor.js.map +1 -1
  59. package/dist/foundations.d.ts +95 -0
  60. package/dist/foundations.d.ts.map +1 -0
  61. package/dist/foundations.js +315 -0
  62. package/dist/foundations.js.map +1 -0
  63. package/dist/navigation/context-menu.d.ts +1 -0
  64. package/dist/navigation/context-menu.d.ts.map +1 -1
  65. package/dist/navigation/context-menu.js +48 -34
  66. package/dist/navigation/context-menu.js.map +1 -1
  67. package/dist/navigation/navigation.d.ts +42 -7
  68. package/dist/navigation/navigation.d.ts.map +1 -1
  69. package/dist/navigation/navigation.js +197 -14
  70. package/dist/navigation/navigation.js.map +1 -1
  71. package/dist/primitives.d.ts +3 -0
  72. package/dist/primitives.d.ts.map +1 -1
  73. package/dist/primitives.js +60 -168
  74. package/dist/primitives.js.map +1 -1
  75. package/dist/styles.css +32 -28
  76. package/dist/surface.d.ts +29 -0
  77. package/dist/surface.d.ts.map +1 -0
  78. package/dist/surface.js +154 -0
  79. package/dist/surface.js.map +1 -0
  80. package/dist/tasks/approval.d.ts.map +1 -1
  81. package/dist/tasks/approval.js +5 -2
  82. package/dist/tasks/approval.js.map +1 -1
  83. package/dist/tasks/permission.d.ts +5 -3
  84. package/dist/tasks/permission.d.ts.map +1 -1
  85. package/dist/tasks/permission.js +11 -5
  86. package/dist/tasks/permission.js.map +1 -1
  87. package/dist/workspace.d.ts +58 -4
  88. package/dist/workspace.d.ts.map +1 -1
  89. package/dist/workspace.js +120 -15
  90. package/dist/workspace.js.map +1 -1
  91. package/package.json +1 -1
package/README.md CHANGED
@@ -18,7 +18,7 @@ npm run dev
18
18
  ## Use the package
19
19
 
20
20
  ```sh
21
- npm install --save-exact pith-ui@0.1.0
21
+ npm install --save-exact pith-ui@0.1.1
22
22
  ```
23
23
 
24
24
  ```ts
@@ -1 +1 @@
1
- {"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,MAAM,WAAW,cAAc;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAAE;AAChG,MAAM,WAAW,oBAAoB;IAAG,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;CAAE;AAC5G,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACtE;AACD,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAuCzG;AAED,MAAM,WAAW,cAAc;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;CAAE;AAE1E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAAE,SAAS,EAAE,WAAW,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAQxH;AACD,MAAM,WAAW,gBAAgB;IAAG,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAAE;AAC3F,wBAAgB,iBAAiB,CAAC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAA;CAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuBnL"}
1
+ {"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,MAAM,WAAW,cAAc;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAAE;AAChG,MAAM,WAAW,oBAAoB;IAAG,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;CAAE;AAC5G,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACtE;AACD,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAyCzG;AAED,MAAM,WAAW,cAAc;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;CAAE;AAE1E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAAE,SAAS,EAAE,WAAW,CAAA;CAAE,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAQxH;AACD,MAAM,WAAW,gBAAgB;IAAG,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAAE;AAC3F,wBAAgB,iBAAiB,CAAC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAA;CAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA2BnL"}
package/dist/composer.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import { escape, icon } from './dom.js';
2
+ import { adoptProductParts } from './foundations.js';
2
3
  export function createPendingMessages(options = {}) {
3
4
  const element = options.container ?? document.createElement('section');
4
5
  element.classList.add('pui-queued-messages');
5
6
  element.setAttribute('aria-label', 'Pending messages');
7
+ const parts = adoptProductParts(element);
6
8
  let destroyed = false;
7
9
  const rows = new Map();
8
10
  const heading = document.createElement('div');
@@ -47,7 +49,7 @@ export function createPendingMessages(options = {}) {
47
49
  count.hidden = !item.imageCount;
48
50
  for (const button of row.querySelectorAll('[data-queue-action]')) {
49
51
  button.dataset.queuedMessage = item.id;
50
- button.disabled = state.busy;
52
+ parts.action(button).update({ disabled: state.busy });
51
53
  if (button.dataset.queueAction === 'steer')
52
54
  button.hidden = item.mode !== 'follow-up' || !state.running;
53
55
  }
@@ -55,8 +57,9 @@ export function createPendingMessages(options = {}) {
55
57
  element.insertBefore(row, cursor);
56
58
  cursor = row.nextElementSibling;
57
59
  }
60
+ parts.update();
58
61
  }, destroy() { if (destroyed)
59
- return; destroyed = true; element.removeEventListener('click', click); rows.clear(); element.replaceChildren(); } };
62
+ return; destroyed = true; parts.destroy(); element.removeEventListener('click', click); rows.clear(); element.replaceChildren(); } };
60
63
  }
61
64
  export function createDropFeedback(options) {
62
65
  const element = options.container;
@@ -74,6 +77,8 @@ export function createAttachments(options = {}) {
74
77
  const element = options.container ?? document.createElement('div');
75
78
  element.classList.add('pui-draft-images');
76
79
  element.setAttribute('aria-label', 'Image attachments');
80
+ const parts = adoptProductParts(element);
81
+ let destroyed = false;
77
82
  const click = (event) => {
78
83
  const target = event.target;
79
84
  const button = target.closest('[data-remove-image]');
@@ -84,6 +89,8 @@ export function createAttachments(options = {}) {
84
89
  };
85
90
  element.addEventListener('click', click);
86
91
  return { element, update(state) {
92
+ if (destroyed)
93
+ return;
87
94
  element.hidden = !state.items.length;
88
95
  const keys = new Set(state.items.map(item => item.id));
89
96
  for (const node of element.querySelectorAll('[data-attachment-id]'))
@@ -105,10 +112,12 @@ export function createAttachments(options = {}) {
105
112
  const button = figure.querySelector('button');
106
113
  button.dataset.removeImage = item.id;
107
114
  button.setAttribute('aria-label', 'Remove ' + item.name);
108
- button.disabled = !!state.disabled;
115
+ parts.action(button).update({ disabled: !!state.disabled });
109
116
  if (element.children[state.items.indexOf(item)] !== figure)
110
117
  element.insertBefore(figure, element.children[state.items.indexOf(item)] ?? null);
111
118
  }
112
- }, destroy() { element.removeEventListener('click', click); element.replaceChildren(); } };
119
+ parts.update();
120
+ }, destroy() { if (destroyed)
121
+ return; destroyed = true; parts.destroy(); element.removeEventListener('click', click); element.replaceChildren(); } };
113
122
  }
114
123
  //# sourceMappingURL=composer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"composer.js","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { UIBlock } from './core.js';\nimport { escape, icon } from './dom.js';\n\nexport interface PendingMessage { id: string; text: string; mode: string; imageCount?: number; }\nexport interface PendingMessagesState { items: readonly PendingMessage[]; running: boolean; busy: boolean; }\nexport interface PendingMessagesOptions {\n container?: HTMLElement;\n onAction?: (action: 'edit' | 'delete' | 'steer', id: string) => void;\n}\nexport function createPendingMessages(options: PendingMessagesOptions = {}): UIBlock<PendingMessagesState> {\n const element = options.container ?? document.createElement('section');\n element.classList.add('pui-queued-messages'); element.setAttribute('aria-label', 'Pending messages');\n let destroyed = false;\n const rows = new Map<string, HTMLElement>();\n const heading = document.createElement('div'); heading.className = 'pui-section-heading'; heading.textContent = 'Pending messages';\n element.append(heading);\n const click = (event: Event) => {\n const button = (event.target as Element).closest<HTMLButtonElement>('[data-queue-action]');\n if (button && !button.disabled) options.onAction?.(button.dataset.queueAction as 'edit' | 'delete' | 'steer', button.dataset.queuedMessage!);\n };\n element.addEventListener('click', click);\n return { element, update(state) {\n if (destroyed) return;\n element.hidden = !state.items.length;\n const keep = new Set(state.items.map(item => item.id));\n for (const [key, row] of rows) if (!keep.has(key)) { row.remove(); rows.delete(key); }\n let cursor: Element | null = heading.nextElementSibling;\n for (const item of state.items) {\n let row = rows.get(item.id);\n if (!row) {\n row = document.createElement('div'); row.className = 'pui-queued-message';\n row.innerHTML = `<span class=\"pui-queue-badge\">Instruction</span><div class=\"pui-queued-message-content\"><span class=\"pui-queued-message-text\"></span><small class=\"pui-queue-image-count\"></small></div><div class=\"pui-queued-message-actions\"><button type=\"button\" class=\"pui-quiet-icon pui-queue-steer\" data-queue-action=\"steer\" title=\"Steer the current task at its next turn\">${icon('steer')}<span>Steer</span></button><button type=\"button\" class=\"pui-quiet-icon\" data-queue-action=\"edit\" aria-label=\"Edit pending message\" title=\"Edit message\">${icon('edit')}</button><button type=\"button\" class=\"pui-quiet-icon\" data-queue-action=\"delete\" aria-label=\"Delete pending message\" title=\"Delete message\">${icon('trash')}</button></div>`;\n rows.set(item.id, row);\n }\n row.querySelector<HTMLElement>('.pui-queue-badge')!.hidden = item.mode !== 'steer';\n const text = row.querySelector<HTMLElement>('.pui-queued-message-text')!;\n const value = item.text || 'Image attachment'; if (text.textContent !== value) text.textContent = value; text.title = item.text;\n const count = row.querySelector<HTMLElement>('.pui-queue-image-count')!;\n const label = item.imageCount ? `${item.imageCount} image${item.imageCount === 1 ? '' : 's'}` : '';\n if (count.textContent !== label) count.textContent = label; count.hidden = !item.imageCount;\n for (const button of row.querySelectorAll<HTMLButtonElement>('[data-queue-action]')) {\n button.dataset.queuedMessage = item.id; button.disabled = state.busy;\n if (button.dataset.queueAction === 'steer') button.hidden = item.mode !== 'follow-up' || !state.running;\n }\n if (row !== cursor) element.insertBefore(row, cursor);\n cursor = row.nextElementSibling;\n }\n }, destroy() { if (destroyed) return; destroyed = true; element.removeEventListener('click', click); rows.clear(); element.replaceChildren(); } };\n}\n\nexport interface AttachmentItem { id: string; url: string; name: string; }\n\nexport function createDropFeedback(options: { container: HTMLElement }): UIBlock<{ active: boolean; disabled?: boolean }> {\n const element = options.container;\n let destroyed = false;\n return { element, update(state) {\n if (destroyed) return;\n if (state.active && !state.disabled) element.classList.add('pui-drag-images');\n else element.classList.remove('pui-drag-images');\n }, destroy() { destroyed = true; element.classList.remove('pui-drag-images'); } };\n}\nexport interface AttachmentsState { items: readonly AttachmentItem[]; disabled?: boolean; }\nexport function createAttachments(options: { container?: HTMLElement; onRemove?: (id: string) => void; onOpen?: (image: HTMLImageElement) => void } = {}): UIBlock<AttachmentsState> {\n const element = options.container ?? document.createElement('div'); element.classList.add('pui-draft-images'); element.setAttribute('aria-label', 'Image attachments');\n const click = (event: Event) => {\n const target = event.target as Element;\n const button = target.closest<HTMLButtonElement>('[data-remove-image]');\n if (button && !button.disabled) options.onRemove?.(button.dataset.removeImage!);\n if (target instanceof HTMLImageElement) options.onOpen?.(target);\n };\n element.addEventListener('click', click);\n return { element, update(state) {\n element.hidden = !state.items.length;\n const keys = new Set(state.items.map(item => item.id));\n for (const node of element.querySelectorAll<HTMLElement>('[data-attachment-id]')) if (!keys.has(node.dataset.attachmentId!)) node.remove();\n for (const item of state.items) {\n let figure = [...element.children].find(node => (node as HTMLElement).dataset.attachmentId === item.id) as HTMLElement | undefined;\n if (!figure) { figure = document.createElement('figure'); figure.className = 'pui-draft-image'; figure.dataset.attachmentId = item.id;\n figure.innerHTML = `<img role=\"button\" tabindex=\"0\" title=\"Click to enlarge\" /><figcaption></figcaption><button type=\"button\" class=\"pui-remove-image\">${icon('close')}</button>`; }\n const image = figure.querySelector('img')!; if (image.getAttribute('src') !== item.url) image.src = item.url; image.alt = item.name;\n figure.querySelector('figcaption')!.textContent = item.name;\n const button = figure.querySelector('button')!; button.dataset.removeImage = item.id; button.setAttribute('aria-label', 'Remove ' + item.name); button.disabled = !!state.disabled;\n if (element.children[state.items.indexOf(item)] !== figure) element.insertBefore(figure, element.children[state.items.indexOf(item)] ?? null);\n }\n }, destroy() { element.removeEventListener('click', click); element.replaceChildren(); } };\n}\n"]}
1
+ {"version":3,"file":"composer.js","sourceRoot":"","sources":["../src/composer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { UIBlock } from './core.js';\nimport { escape, icon } from './dom.js';\nimport { adoptProductParts } from './foundations.js';\n\nexport interface PendingMessage { id: string; text: string; mode: string; imageCount?: number; }\nexport interface PendingMessagesState { items: readonly PendingMessage[]; running: boolean; busy: boolean; }\nexport interface PendingMessagesOptions {\n container?: HTMLElement;\n onAction?: (action: 'edit' | 'delete' | 'steer', id: string) => void;\n}\nexport function createPendingMessages(options: PendingMessagesOptions = {}): UIBlock<PendingMessagesState> {\n const element = options.container ?? document.createElement('section');\n element.classList.add('pui-queued-messages'); element.setAttribute('aria-label', 'Pending messages');\n const parts = adoptProductParts(element);\n let destroyed = false;\n const rows = new Map<string, HTMLElement>();\n const heading = document.createElement('div'); heading.className = 'pui-section-heading'; heading.textContent = 'Pending messages';\n element.append(heading);\n const click = (event: Event) => {\n const button = (event.target as Element).closest<HTMLButtonElement>('[data-queue-action]');\n if (button && !button.disabled) options.onAction?.(button.dataset.queueAction as 'edit' | 'delete' | 'steer', button.dataset.queuedMessage!);\n };\n element.addEventListener('click', click);\n return { element, update(state) {\n if (destroyed) return;\n element.hidden = !state.items.length;\n const keep = new Set(state.items.map(item => item.id));\n for (const [key, row] of rows) if (!keep.has(key)) { row.remove(); rows.delete(key); }\n let cursor: Element | null = heading.nextElementSibling;\n for (const item of state.items) {\n let row = rows.get(item.id);\n if (!row) {\n row = document.createElement('div'); row.className = 'pui-queued-message';\n row.innerHTML = `<span class=\"pui-queue-badge\">Instruction</span><div class=\"pui-queued-message-content\"><span class=\"pui-queued-message-text\"></span><small class=\"pui-queue-image-count\"></small></div><div class=\"pui-queued-message-actions\"><button type=\"button\" class=\"pui-quiet-icon pui-queue-steer\" data-queue-action=\"steer\" title=\"Steer the current task at its next turn\">${icon('steer')}<span>Steer</span></button><button type=\"button\" class=\"pui-quiet-icon\" data-queue-action=\"edit\" aria-label=\"Edit pending message\" title=\"Edit message\">${icon('edit')}</button><button type=\"button\" class=\"pui-quiet-icon\" data-queue-action=\"delete\" aria-label=\"Delete pending message\" title=\"Delete message\">${icon('trash')}</button></div>`;\n rows.set(item.id, row);\n }\n row.querySelector<HTMLElement>('.pui-queue-badge')!.hidden = item.mode !== 'steer';\n const text = row.querySelector<HTMLElement>('.pui-queued-message-text')!;\n const value = item.text || 'Image attachment'; if (text.textContent !== value) text.textContent = value; text.title = item.text;\n const count = row.querySelector<HTMLElement>('.pui-queue-image-count')!;\n const label = item.imageCount ? `${item.imageCount} image${item.imageCount === 1 ? '' : 's'}` : '';\n if (count.textContent !== label) count.textContent = label; count.hidden = !item.imageCount;\n for (const button of row.querySelectorAll<HTMLButtonElement>('[data-queue-action]')) {\n button.dataset.queuedMessage = item.id; parts.action(button).update({ disabled: state.busy });\n if (button.dataset.queueAction === 'steer') button.hidden = item.mode !== 'follow-up' || !state.running;\n }\n if (row !== cursor) element.insertBefore(row, cursor);\n cursor = row.nextElementSibling;\n }\n parts.update();\n }, destroy() { if (destroyed) return; destroyed = true; parts.destroy(); element.removeEventListener('click', click); rows.clear(); element.replaceChildren(); } };\n}\n\nexport interface AttachmentItem { id: string; url: string; name: string; }\n\nexport function createDropFeedback(options: { container: HTMLElement }): UIBlock<{ active: boolean; disabled?: boolean }> {\n const element = options.container;\n let destroyed = false;\n return { element, update(state) {\n if (destroyed) return;\n if (state.active && !state.disabled) element.classList.add('pui-drag-images');\n else element.classList.remove('pui-drag-images');\n }, destroy() { destroyed = true; element.classList.remove('pui-drag-images'); } };\n}\nexport interface AttachmentsState { items: readonly AttachmentItem[]; disabled?: boolean; }\nexport function createAttachments(options: { container?: HTMLElement; onRemove?: (id: string) => void; onOpen?: (image: HTMLImageElement) => void } = {}): UIBlock<AttachmentsState> {\n const element = options.container ?? document.createElement('div'); element.classList.add('pui-draft-images'); element.setAttribute('aria-label', 'Image attachments');\n const parts = adoptProductParts(element);\n let destroyed = false;\n const click = (event: Event) => {\n const target = event.target as Element;\n const button = target.closest<HTMLButtonElement>('[data-remove-image]');\n if (button && !button.disabled) options.onRemove?.(button.dataset.removeImage!);\n if (target instanceof HTMLImageElement) options.onOpen?.(target);\n };\n element.addEventListener('click', click);\n return { element, update(state) {\n if (destroyed) return;\n element.hidden = !state.items.length;\n const keys = new Set(state.items.map(item => item.id));\n for (const node of element.querySelectorAll<HTMLElement>('[data-attachment-id]')) if (!keys.has(node.dataset.attachmentId!)) node.remove();\n for (const item of state.items) {\n let figure = [...element.children].find(node => (node as HTMLElement).dataset.attachmentId === item.id) as HTMLElement | undefined;\n if (!figure) { figure = document.createElement('figure'); figure.className = 'pui-draft-image'; figure.dataset.attachmentId = item.id;\n figure.innerHTML = `<img role=\"button\" tabindex=\"0\" title=\"Click to enlarge\" /><figcaption></figcaption><button type=\"button\" class=\"pui-remove-image\">${icon('close')}</button>`; }\n const image = figure.querySelector('img')!; if (image.getAttribute('src') !== item.url) image.src = item.url; image.alt = item.name;\n figure.querySelector('figcaption')!.textContent = item.name;\n const button = figure.querySelector('button')!; button.dataset.removeImage = item.id; button.setAttribute('aria-label', 'Remove ' + item.name); parts.action(button).update({ disabled: !!state.disabled });\n if (element.children[state.items.indexOf(item)] !== figure) element.insertBefore(figure, element.children[state.items.indexOf(item)] ?? null);\n }\n parts.update();\n }, destroy() { if (destroyed) return; destroyed = true; parts.destroy(); element.removeEventListener('click', click); element.replaceChildren(); } };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { UIBlock } from '../core.js';
1
+ import { type UIBlock } from '../core.js';
2
2
  import { type MarkdownOptions } from './markdown.js';
3
3
  /** UI data only. Hosts decide copy/edit/branch eligibility and resolve images. */
4
4
  export interface ConversationMessage {
@@ -38,11 +38,28 @@ export interface ConversationAction {
38
38
  messageId: string;
39
39
  branchKey?: string;
40
40
  }
41
+ export interface ConversationActionAvailability {
42
+ copy?: boolean;
43
+ edit?: boolean;
44
+ branch?: boolean;
45
+ }
46
+ export type ConversationImageState = {
47
+ status: 'ready';
48
+ src: string;
49
+ } | {
50
+ status: 'unavailable';
51
+ };
52
+ export interface ConversationViewBlock extends UIBlock<ConversationViewState> {
53
+ /** Disabled state, separate from whether an action exists for a message. */
54
+ updateActionAvailability(disabled: Readonly<ConversationActionAvailability>): void;
55
+ images(): readonly HTMLImageElement[];
56
+ setImageState(image: HTMLImageElement, state: ConversationImageState): void;
57
+ }
41
58
  export interface ConversationViewOptions {
42
59
  container?: HTMLElement;
43
60
  markdown?: (conversationId: string) => MarkdownOptions;
44
- onAction?: (action: ConversationAction) => void;
45
- onCopyCode?: (text: string) => void;
61
+ onAction?: (action: ConversationAction, button: HTMLButtonElement) => void;
62
+ onCopyCode?: (text: string, button: HTMLButtonElement) => void;
46
63
  }
47
- export declare function createConversationView(options?: ConversationViewOptions): UIBlock<ConversationViewState>;
64
+ export declare function createConversationView(options?: ConversationViewOptions): ConversationViewBlock;
48
65
  //# sourceMappingURL=conversation-view.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-view.d.ts","sourceRoot":"","sources":["../../src/content/conversation-view.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAGrE,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CACjG;AACD,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AACD,MAAM,WAAW,kBAAkB;IAAG,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AACjH,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,eAAe,CAAC;IACvD,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAChD,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAGD,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAqD5G"}
1
+ {"version":3,"file":"conversation-view.d.ts","sourceRoot":"","sources":["../../src/content/conversation-view.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAGrE,kFAAkF;AAClF,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CACjG;AACD,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AACD,MAAM,WAAW,kBAAkB;IAAG,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AACjH,MAAM,WAAW,8BAA8B;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAC;AAClG,MAAM,MAAM,sBAAsB,GAAG;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,GAAG;IAAC,MAAM,EAAE,aAAa,CAAA;CAAC,CAAC;AAC9F,MAAM,WAAW,qBAAsB,SAAQ,OAAO,CAAC,qBAAqB,CAAC;IAC3E,4EAA4E;IAC5E,wBAAwB,CAAC,QAAQ,EAAE,QAAQ,CAAC,8BAA8B,CAAC,GAAG,IAAI,CAAC;IACnF,MAAM,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACtC,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAC7E;AACD,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,eAAe,CAAC;IACvD,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC3E,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAChE;AAGD,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,qBAAqB,CAuEnG"}
@@ -1,9 +1,16 @@
1
1
  import { escape, icon } from '../dom.js';
2
+ import { controlDisabled } from '../core.js';
3
+ import { adoptProductParts } from '../foundations.js';
2
4
  import { renderMarkdown } from './markdown.js';
3
5
  import { reconcileViews, clearViews } from './views.js';
4
6
  export function createConversationView(options = {}) {
5
7
  const container = options.container || document.createElement('div');
6
8
  container.classList.add('pui-conversation-messages');
9
+ const parts = adoptProductParts(container);
10
+ let actionButtons = [];
11
+ let disabledActions = {};
12
+ const syncAvailability = () => { for (const button of actionButtons)
13
+ parts.action(button).update({ disabled: controlDisabled(button, !!disabledActions[button.dataset.messageAction]) }); };
7
14
  let destroyed = false;
8
15
  const click = (event) => {
9
16
  const target = event.target.closest('[data-message-action], [data-copy-code]');
@@ -11,10 +18,16 @@ export function createConversationView(options = {}) {
11
18
  return;
12
19
  if (target.hasAttribute('data-copy-code')) {
13
20
  const text = target.closest('.pui-code-block')?.querySelector('pre > code')?.textContent || '';
14
- options.onCopyCode?.(text);
21
+ if (options.onCopyCode) {
22
+ event.stopPropagation();
23
+ options.onCopyCode(text, target);
24
+ }
15
25
  return;
16
26
  }
17
- options.onAction?.({ action: target.dataset.messageAction, messageId: target.dataset.messageActionId, branchKey: target.dataset.branchKey });
27
+ if (options.onAction) {
28
+ event.stopPropagation();
29
+ options.onAction({ action: target.dataset.messageAction, messageId: target.dataset.messageActionId, branchKey: target.dataset.branchKey }, target);
30
+ }
18
31
  };
19
32
  container.addEventListener('click', click);
20
33
  let activeId = '';
@@ -50,6 +63,9 @@ export function createConversationView(options = {}) {
50
63
  if (working)
51
64
  views.push({ key: 'working', signature: 'working', html: () => '<div class="pui-agent-working" role="status"><span class="pui-working-dots" aria-hidden="true"><i></i><i></i><i></i></span><span>Working…</span></div>' });
52
65
  reconcileViews(container, views);
66
+ actionButtons = [...container.querySelectorAll('[data-message-action]')];
67
+ parts.update();
68
+ syncAvailability();
53
69
  }
54
70
  return {
55
71
  element: container,
@@ -57,12 +73,29 @@ export function createConversationView(options = {}) {
57
73
  const folds = state.folds || new Map(Array.from(container.querySelectorAll('[data-tool-fold]'), (element) => [element.dataset.toolFold, element.open]));
58
74
  update(state.id, state.messages, state.working, folds);
59
75
  },
76
+ updateActionAvailability(disabled) {
77
+ if (destroyed || (disabled.copy === disabledActions.copy && disabled.edit === disabledActions.edit && disabled.branch === disabledActions.branch))
78
+ return;
79
+ disabledActions = { ...disabled };
80
+ syncAvailability();
81
+ },
82
+ images: () => destroyed ? [] : [...container.querySelectorAll('img[data-image-key]')],
83
+ setImageState(image, state) {
84
+ if (destroyed || !container.contains(image))
85
+ return;
86
+ image.classList.toggle('pui-image-unavailable', state.status === 'unavailable');
87
+ image.alt = state.status === 'unavailable' ? 'Image unavailable' : `Image ${Number(image.dataset.imageIndex) + 1}`;
88
+ if (state.status === 'ready')
89
+ image.src = state.src;
90
+ },
60
91
  destroy() {
61
92
  if (destroyed)
62
93
  return;
63
94
  destroyed = true;
64
95
  container.removeEventListener('click', click);
65
96
  clearViews(container);
97
+ parts.destroy();
98
+ actionButtons = [];
66
99
  },
67
100
  };
68
101
  }
@@ -82,10 +115,10 @@ function renderMessage(conversationId, message, expanded = false, foldKey = '',
82
115
  const images = (message.images || []).map((image) => `<img class="pui-history-image" data-image-key="${escape(`${conversationId}/${message.id}/${image.index}`)}" data-message-id="${escape(message.id)}" data-image-index="${image.index}" alt="Image ${image.index + 1}" role="button" tabindex="0" title="Click to enlarge" loading="lazy" />`).join('');
83
116
  const gallery = images ? `<div class="pui-message-images">${images}</div>` : '';
84
117
  const copyLabel = typeof message.actions?.copy === 'string' ? message.actions.copy : 'Copy message';
85
- const copy = message.actions?.copy ? `<button type="button" class="pui-quiet-icon pui-message-action" data-message-action="copy" data-message-action-id="${escape(message.id)}" title="${escape(copyLabel)}" aria-label="${escape(copyLabel)}">${icon('copy')}</button>` : '';
86
- const edit = message.actions?.edit ? `<button type="button" class="pui-quiet-icon pui-message-action" data-message-action="edit" data-message-action-id="${escape(message.id)}" title="Edit message" aria-label="Edit message">${icon('edit')}</button>` : '';
118
+ const copy = message.actions?.copy ? `<button type="button" class="pui-quiet-icon pui-message-action" data-message-action="copy" data-message-action-id="${escape(message.id)}" data-copy-message="${escape(message.id)}" title="${escape(copyLabel)}" aria-label="${escape(copyLabel)}">${icon('copy')}</button>` : '';
119
+ const edit = message.actions?.edit ? `<button type="button" class="pui-quiet-icon pui-message-action" data-message-action="edit" data-message-action-id="${escape(message.id)}" data-edit-message="${escape(message.id)}" title="Edit message" aria-label="Edit message">${icon('edit')}</button>` : '';
87
120
  const branchAction = message.actions?.branch;
88
- const branch = branchAction ? `<button type="button" class="pui-quiet-icon pui-message-action" data-message-action="branch" data-message-action-id="${escape(message.id)}" data-branch-key="${escape(branchAction.key)}" title="${escape(branchAction.label || 'Branch from this message')}" aria-label="${escape(branchAction.label || 'Branch from this message')}">${icon('branch')}</button>` : '';
121
+ const branch = branchAction ? `<button type="button" class="pui-quiet-icon pui-message-action" data-message-action="branch" data-message-action-id="${escape(message.id)}" data-branch-key="${escape(branchAction.key)}" data-node="${escape(branchAction.key)}" title="${escape(branchAction.label || 'Branch from this message')}" aria-label="${escape(branchAction.label || 'Branch from this message')}">${icon('branch')}</button>` : '';
89
122
  const actions = copy || edit || branch ? `<div class="pui-message-actions">${copy}${edit}${branch}</div>` : '';
90
123
  const date = new Date(message.timestamp || NaN);
91
124
  const time = Number.isFinite(date.getTime()) ? `<time class="pui-message-time" datetime="${date.toISOString()}" title="${escape(date.toLocaleString())}">${escape(date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }))}</time>` : '';
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-view.js","sourceRoot":"","sources":["../../src/content/conversation-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { escape, icon } from '../dom.js';\nimport type { UIBlock } from '../core.js';\nimport { renderMarkdown, type MarkdownOptions } from './markdown.js';\nimport { reconcileViews, clearViews, type View } from './views.js';\n\n/** UI data only. Hosts decide copy/edit/branch eligibility and resolve images. */\nexport interface ConversationMessage {\n id: string;\n role: string;\n text: string;\n timestamp?: number;\n toolName?: string;\n toolCallId?: string;\n status?: string;\n images?: Array<{ index: number; mimeType?: string }>;\n command?: { text: string; cwd: string; exitCode?: number };\n actions?: { copy?: boolean | string; edit?: boolean; branch?: { key: string; label?: string } };\n}\nexport interface ConversationViewState {\n id: string;\n messages: readonly ConversationMessage[];\n working: boolean;\n folds?: ReadonlyMap<string, boolean>;\n}\nexport interface ConversationAction { action: 'copy' | 'edit' | 'branch'; messageId: string; branchKey?: string }\nexport interface ConversationViewOptions {\n container?: HTMLElement;\n markdown?: (conversationId: string) => MarkdownOptions;\n onAction?: (action: ConversationAction) => void;\n onCopyCode?: (text: string) => void;\n}\n\n\nexport function createConversationView(options: ConversationViewOptions = {}): UIBlock<ConversationViewState> {\n const container = options.container || document.createElement('div');\n container.classList.add('pui-conversation-messages');\n let destroyed = false;\n const click = (event: Event) => {\n const target = (event.target as Element).closest<HTMLElement>('[data-message-action], [data-copy-code]');\n if (!target || !container.contains(target) || (target as HTMLButtonElement).disabled) return;\n if (target.hasAttribute('data-copy-code')) {\n const text = target.closest('.pui-code-block')?.querySelector('pre > code')?.textContent || '';\n options.onCopyCode?.(text);\n return;\n }\n options.onAction?.({ action: target.dataset.messageAction as ConversationAction['action'], messageId: target.dataset.messageActionId!, branchKey: target.dataset.branchKey });\n };\n container.addEventListener('click', click);\n let activeId = '';\n function update(id: string, messages: readonly ConversationMessage[], working: boolean, folds: ReadonlyMap<string, boolean>): void {\n if (destroyed) return;\n if (id !== activeId) { clearViews(container); activeId = id; }\n const views: View[] = [];\n const messageView = (message: ConversationMessage, key = message.id, foldKey = ''): View => ({\n key, signature: JSON.stringify(message), html: () => renderMessage(id, message, folds.get(foldKey), foldKey, (text, conversationId) => renderMarkdown(text, options.markdown?.(conversationId))),\n });\n let groupIndex = 0;\n for (let index = 0; index < messages.length;) {\n if (messages[index].role !== 'tool') { views.push(messageView(messages[index++])); continue; }\n const start = index;\n while (index < messages.length && messages[index].role === 'tool') index++;\n const tools = messages.slice(start, index), key = `group-${groupIndex++}`;\n const running = tools.filter((tool) => tool.status === 'running').length;\n const failed = tools.filter((tool) => tool.status === 'error').length;\n const label = toolGroupLabel(tools);\n views.push({ key, signature: JSON.stringify([label, tools.length, failed, running]),\n html: () => `<details class=\"pui-tool-group\" data-tool-fold=\"${key}\" ${folds.get(key) ? 'open' : ''}><summary>${icon('terminal')}<span class=\"pui-tool-group-label\">${label}</span><span class=\"pui-tool-group-count\">${tools.length} ${tools.length === 1 ? 'call' : 'calls'}</span>${failed ? `<span class=\"pui-tool-group-failed\">${failed} failed</span>` : ''}${running ? `<span class=\"pui-tool-group-running\">${running} running</span>` : ''}${icon('down')}</summary><div class=\"pui-tool-group-content\" data-view-children></div></details>`,\n children: tools.map((tool) => { const toolKey = `${key}-tool-${tool.toolCallId || tool.id}`; return messageView(tool, toolKey, toolKey); }),\n });\n }\n if (working) views.push({ key: 'working', signature: 'working', html: () => '<div class=\"pui-agent-working\" role=\"status\"><span class=\"pui-working-dots\" aria-hidden=\"true\"><i></i><i></i><i></i></span><span>Working…</span></div>' });\n reconcileViews(container, views);\n }\n return {\n element: container,\n update(state): void {\n const folds = state.folds || new Map(Array.from(container.querySelectorAll<HTMLDetailsElement>('[data-tool-fold]'), (element) => [element.dataset.toolFold!, element.open] as const));\n update(state.id, state.messages, state.working, folds);\n },\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n container.removeEventListener('click', click);\n clearViews(container);\n },\n };\n}\n\nfunction toolGroupLabel(tools: readonly ConversationMessage[]): string {\n if (tools.length === 1) return ({ list_files: 'Listed files', read_file: 'Read a file', run_command: 'Ran a command', write_file: 'Wrote a file', edit_file: 'Edited a file', tool_search: 'Searched tools', codemode: 'Ran code' } as Record<string, string>)[tools[0].toolName || ''] || 'Used a tool';\n const hasCommands = tools.some((tool) => tool.toolName === 'run_command');\n const exploredFiles = tools.every((tool) => ['list_files', 'read_file', 'grep', 'find', 'ls', 'run_command'].includes(tool.toolName || ''));\n if (tools.every((tool) => tool.toolName === 'run_command')) return 'Ran commands';\n if (exploredFiles) return hasCommands ? 'Ran commands and explored files' : 'Explored files';\n return 'Used tools';\n}\n\nfunction renderMessage(conversationId: string, message: ConversationMessage, expanded = false, foldKey = '', markdown: (value: string, conversationId: string) => string = (text) => renderMarkdown(text)): string {\n const text = message.text ?? '';\n const images = (message.images || []).map((image) => `<img class=\"pui-history-image\" data-image-key=\"${escape(`${conversationId}/${message.id}/${image.index}`)}\" data-message-id=\"${escape(message.id)}\" data-image-index=\"${image.index}\" alt=\"Image ${image.index + 1}\" role=\"button\" tabindex=\"0\" title=\"Click to enlarge\" loading=\"lazy\" />`).join('');\n const gallery = images ? `<div class=\"pui-message-images\">${images}</div>` : '';\n const copyLabel = typeof message.actions?.copy === 'string' ? message.actions.copy : 'Copy message';\n const copy = message.actions?.copy ? `<button type=\"button\" class=\"pui-quiet-icon pui-message-action\" data-message-action=\"copy\" data-message-action-id=\"${escape(message.id)}\" title=\"${escape(copyLabel)}\" aria-label=\"${escape(copyLabel)}\">${icon('copy')}</button>` : '';\n const edit = message.actions?.edit ? `<button type=\"button\" class=\"pui-quiet-icon pui-message-action\" data-message-action=\"edit\" data-message-action-id=\"${escape(message.id)}\" title=\"Edit message\" aria-label=\"Edit message\">${icon('edit')}</button>` : '';\n const branchAction = message.actions?.branch;\n const branch = branchAction ? `<button type=\"button\" class=\"pui-quiet-icon pui-message-action\" data-message-action=\"branch\" data-message-action-id=\"${escape(message.id)}\" data-branch-key=\"${escape(branchAction.key)}\" title=\"${escape(branchAction.label || 'Branch from this message')}\" aria-label=\"${escape(branchAction.label || 'Branch from this message')}\">${icon('branch')}</button>` : '';\n const actions = copy || edit || branch ? `<div class=\"pui-message-actions\">${copy}${edit}${branch}</div>` : '';\n const date = new Date(message.timestamp || NaN);\n const time = Number.isFinite(date.getTime()) ? `<time class=\"pui-message-time\" datetime=\"${date.toISOString()}\" title=\"${escape(date.toLocaleString())}\">${escape(date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }))}</time>` : '';\n const footer = time || actions ? `<div class=\"pui-message-footer\">${time}${actions}</div>` : '';\n if (message.role === 'tool') {\n const command = message.command;\n const details = command ? `<div class=\"pui-command-details\"><span class=\"pui-tool-field-label\">Command</span><pre class=\"pui-command-text\">${escape(command.text)}</pre><div class=\"pui-command-directory\"><span class=\"pui-tool-field-label\">Directory</span><code>${escape(command.cwd)}</code></div></div>` : '';\n const status = command ? ({ running: 'Running', done: 'Completed', error: 'Failed' } as Record<string, string>)[message.status || ''] || message.status || 'Result' : message.status || 'Result';\n const exit = command?.exitCode !== undefined ? ` · Exit ${command.exitCode}` : '';\n const output = command ? `<div class=\"pui-command-output\"><span class=\"pui-tool-field-label\">Output</span><pre>${escape(text)}</pre></div>` : `<pre>${escape(text)}</pre>`;\n return `<details class=\"pui-tool-message\" data-reading-id=\"${escape(message.id)}\" data-tool-fold=\"${escape(foldKey)}\" ${expanded ? 'open' : ''}><summary>${icon('terminal')}<span>${command ? 'Command' : escape(message.toolName || 'Tool result')}</span><span class=\"pui-tool-status${message.status === 'error' ? ' pui-tool-status-error' : ''}\">${escape(status + exit)}</span>${icon('down')}</summary>${details}${output}${gallery}</details>`;\n }\n if (message.role === 'user') return `<article class=\"pui-message pui-user-message\" data-reading-id=\"${escape(message.id)}\" aria-label=\"Your message\"><div class=\"pui-message-content\">${gallery}${text ? `<div class=\"pui-user-text\">${escape(text)}</div>` : ''}${footer}</div></article>`;\n if (message.role === 'system') return `<div class=\"pui-system-message\" data-reading-id=\"${escape(message.id)}\">${escape(text)}</div>`;\n return `<article class=\"pui-message pui-assistant-message\" data-reading-id=\"${escape(message.id)}\" aria-label=\"Agent response\"><div class=\"pui-message-content\"><div class=\"pui-markdown\">${markdown(text, conversationId)}</div>${message.status === 'error' ? '<span class=\"pui-message-error-label\">Response interrupted</span>' : ''}${footer}</div></article>`;\n}\n"]}
1
+ {"version":3,"file":"conversation-view.js","sourceRoot":"","sources":["../../src/content/conversation-view.ts"],"names":[],"mappings":"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","sourcesContent":["import { escape, icon } from '../dom.js';\nimport { controlDisabled, type UIBlock } from '../core.js';\nimport { adoptProductParts } from '../foundations.js';\nimport { renderMarkdown, type MarkdownOptions } from './markdown.js';\nimport { reconcileViews, clearViews, type View } from './views.js';\n\n/** UI data only. Hosts decide copy/edit/branch eligibility and resolve images. */\nexport interface ConversationMessage {\n id: string;\n role: string;\n text: string;\n timestamp?: number;\n toolName?: string;\n toolCallId?: string;\n status?: string;\n images?: Array<{ index: number; mimeType?: string }>;\n command?: { text: string; cwd: string; exitCode?: number };\n actions?: { copy?: boolean | string; edit?: boolean; branch?: { key: string; label?: string } };\n}\nexport interface ConversationViewState {\n id: string;\n messages: readonly ConversationMessage[];\n working: boolean;\n folds?: ReadonlyMap<string, boolean>;\n}\nexport interface ConversationAction { action: 'copy' | 'edit' | 'branch'; messageId: string; branchKey?: string }\nexport interface ConversationActionAvailability {copy?: boolean; edit?: boolean; branch?: boolean}\nexport type ConversationImageState = {status: 'ready'; src: string} | {status: 'unavailable'};\nexport interface ConversationViewBlock extends UIBlock<ConversationViewState> {\n /** Disabled state, separate from whether an action exists for a message. */\n updateActionAvailability(disabled: Readonly<ConversationActionAvailability>): void;\n images(): readonly HTMLImageElement[];\n setImageState(image: HTMLImageElement, state: ConversationImageState): void;\n}\nexport interface ConversationViewOptions {\n container?: HTMLElement;\n markdown?: (conversationId: string) => MarkdownOptions;\n onAction?: (action: ConversationAction, button: HTMLButtonElement) => void;\n onCopyCode?: (text: string, button: HTMLButtonElement) => void;\n}\n\n\nexport function createConversationView(options: ConversationViewOptions = {}): ConversationViewBlock {\n const container = options.container || document.createElement('div');\n container.classList.add('pui-conversation-messages');\n const parts = adoptProductParts(container);\n let actionButtons: HTMLButtonElement[] = [];\n let disabledActions: Readonly<ConversationActionAvailability> = {};\n const syncAvailability = () => {for (const button of actionButtons) parts.action(button).update({disabled: controlDisabled(button, !!disabledActions[button.dataset.messageAction as ConversationAction['action']])});};\n let destroyed = false;\n const click = (event: Event) => {\n const target = (event.target as Element).closest<HTMLButtonElement>('[data-message-action], [data-copy-code]');\n if (!target || !container.contains(target) || target.disabled) return;\n if (target.hasAttribute('data-copy-code')) {\n const text = target.closest('.pui-code-block')?.querySelector('pre > code')?.textContent || '';\n if (options.onCopyCode) {event.stopPropagation(); options.onCopyCode(text, target);}\n return;\n }\n if (options.onAction) {event.stopPropagation(); options.onAction({ action: target.dataset.messageAction as ConversationAction['action'], messageId: target.dataset.messageActionId!, branchKey: target.dataset.branchKey }, target);}\n };\n container.addEventListener('click', click);\n let activeId = '';\n function update(id: string, messages: readonly ConversationMessage[], working: boolean, folds: ReadonlyMap<string, boolean>): void {\n if (destroyed) return;\n if (id !== activeId) { clearViews(container); activeId = id; }\n const views: View[] = [];\n const messageView = (message: ConversationMessage, key = message.id, foldKey = ''): View => ({\n key, signature: JSON.stringify(message), html: () => renderMessage(id, message, folds.get(foldKey), foldKey, (text, conversationId) => renderMarkdown(text, options.markdown?.(conversationId))),\n });\n let groupIndex = 0;\n for (let index = 0; index < messages.length;) {\n if (messages[index].role !== 'tool') { views.push(messageView(messages[index++])); continue; }\n const start = index;\n while (index < messages.length && messages[index].role === 'tool') index++;\n const tools = messages.slice(start, index), key = `group-${groupIndex++}`;\n const running = tools.filter((tool) => tool.status === 'running').length;\n const failed = tools.filter((tool) => tool.status === 'error').length;\n const label = toolGroupLabel(tools);\n views.push({ key, signature: JSON.stringify([label, tools.length, failed, running]),\n html: () => `<details class=\"pui-tool-group\" data-tool-fold=\"${key}\" ${folds.get(key) ? 'open' : ''}><summary>${icon('terminal')}<span class=\"pui-tool-group-label\">${label}</span><span class=\"pui-tool-group-count\">${tools.length} ${tools.length === 1 ? 'call' : 'calls'}</span>${failed ? `<span class=\"pui-tool-group-failed\">${failed} failed</span>` : ''}${running ? `<span class=\"pui-tool-group-running\">${running} running</span>` : ''}${icon('down')}</summary><div class=\"pui-tool-group-content\" data-view-children></div></details>`,\n children: tools.map((tool) => { const toolKey = `${key}-tool-${tool.toolCallId || tool.id}`; return messageView(tool, toolKey, toolKey); }),\n });\n }\n if (working) views.push({ key: 'working', signature: 'working', html: () => '<div class=\"pui-agent-working\" role=\"status\"><span class=\"pui-working-dots\" aria-hidden=\"true\"><i></i><i></i><i></i></span><span>Working…</span></div>' });\n reconcileViews(container, views);\n actionButtons = [...container.querySelectorAll<HTMLButtonElement>('[data-message-action]')];\n parts.update(); syncAvailability();\n }\n return {\n element: container,\n update(state): void {\n const folds = state.folds || new Map(Array.from(container.querySelectorAll<HTMLDetailsElement>('[data-tool-fold]'), (element) => [element.dataset.toolFold!, element.open] as const));\n update(state.id, state.messages, state.working, folds);\n },\n updateActionAvailability(disabled): void {\n if (destroyed || (disabled.copy === disabledActions.copy && disabled.edit === disabledActions.edit && disabled.branch === disabledActions.branch)) return;\n disabledActions = {...disabled}; syncAvailability();\n },\n images: () => destroyed ? [] : [...container.querySelectorAll<HTMLImageElement>('img[data-image-key]')],\n setImageState(image, state): void {\n if (destroyed || !container.contains(image)) return;\n image.classList.toggle('pui-image-unavailable', state.status === 'unavailable');\n image.alt = state.status === 'unavailable' ? 'Image unavailable' : `Image ${Number(image.dataset.imageIndex) + 1}`;\n if (state.status === 'ready') image.src = state.src;\n },\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n container.removeEventListener('click', click);\n clearViews(container);\n parts.destroy(); actionButtons = [];\n },\n };\n}\n\nfunction toolGroupLabel(tools: readonly ConversationMessage[]): string {\n if (tools.length === 1) return ({ list_files: 'Listed files', read_file: 'Read a file', run_command: 'Ran a command', write_file: 'Wrote a file', edit_file: 'Edited a file', tool_search: 'Searched tools', codemode: 'Ran code' } as Record<string, string>)[tools[0].toolName || ''] || 'Used a tool';\n const hasCommands = tools.some((tool) => tool.toolName === 'run_command');\n const exploredFiles = tools.every((tool) => ['list_files', 'read_file', 'grep', 'find', 'ls', 'run_command'].includes(tool.toolName || ''));\n if (tools.every((tool) => tool.toolName === 'run_command')) return 'Ran commands';\n if (exploredFiles) return hasCommands ? 'Ran commands and explored files' : 'Explored files';\n return 'Used tools';\n}\n\nfunction renderMessage(conversationId: string, message: ConversationMessage, expanded = false, foldKey = '', markdown: (value: string, conversationId: string) => string = (text) => renderMarkdown(text)): string {\n const text = message.text ?? '';\n const images = (message.images || []).map((image) => `<img class=\"pui-history-image\" data-image-key=\"${escape(`${conversationId}/${message.id}/${image.index}`)}\" data-message-id=\"${escape(message.id)}\" data-image-index=\"${image.index}\" alt=\"Image ${image.index + 1}\" role=\"button\" tabindex=\"0\" title=\"Click to enlarge\" loading=\"lazy\" />`).join('');\n const gallery = images ? `<div class=\"pui-message-images\">${images}</div>` : '';\n const copyLabel = typeof message.actions?.copy === 'string' ? message.actions.copy : 'Copy message';\n const copy = message.actions?.copy ? `<button type=\"button\" class=\"pui-quiet-icon pui-message-action\" data-message-action=\"copy\" data-message-action-id=\"${escape(message.id)}\" data-copy-message=\"${escape(message.id)}\" title=\"${escape(copyLabel)}\" aria-label=\"${escape(copyLabel)}\">${icon('copy')}</button>` : '';\n const edit = message.actions?.edit ? `<button type=\"button\" class=\"pui-quiet-icon pui-message-action\" data-message-action=\"edit\" data-message-action-id=\"${escape(message.id)}\" data-edit-message=\"${escape(message.id)}\" title=\"Edit message\" aria-label=\"Edit message\">${icon('edit')}</button>` : '';\n const branchAction = message.actions?.branch;\n const branch = branchAction ? `<button type=\"button\" class=\"pui-quiet-icon pui-message-action\" data-message-action=\"branch\" data-message-action-id=\"${escape(message.id)}\" data-branch-key=\"${escape(branchAction.key)}\" data-node=\"${escape(branchAction.key)}\" title=\"${escape(branchAction.label || 'Branch from this message')}\" aria-label=\"${escape(branchAction.label || 'Branch from this message')}\">${icon('branch')}</button>` : '';\n const actions = copy || edit || branch ? `<div class=\"pui-message-actions\">${copy}${edit}${branch}</div>` : '';\n const date = new Date(message.timestamp || NaN);\n const time = Number.isFinite(date.getTime()) ? `<time class=\"pui-message-time\" datetime=\"${date.toISOString()}\" title=\"${escape(date.toLocaleString())}\">${escape(date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }))}</time>` : '';\n const footer = time || actions ? `<div class=\"pui-message-footer\">${time}${actions}</div>` : '';\n if (message.role === 'tool') {\n const command = message.command;\n const details = command ? `<div class=\"pui-command-details\"><span class=\"pui-tool-field-label\">Command</span><pre class=\"pui-command-text\">${escape(command.text)}</pre><div class=\"pui-command-directory\"><span class=\"pui-tool-field-label\">Directory</span><code>${escape(command.cwd)}</code></div></div>` : '';\n const status = command ? ({ running: 'Running', done: 'Completed', error: 'Failed' } as Record<string, string>)[message.status || ''] || message.status || 'Result' : message.status || 'Result';\n const exit = command?.exitCode !== undefined ? ` · Exit ${command.exitCode}` : '';\n const output = command ? `<div class=\"pui-command-output\"><span class=\"pui-tool-field-label\">Output</span><pre>${escape(text)}</pre></div>` : `<pre>${escape(text)}</pre>`;\n return `<details class=\"pui-tool-message\" data-reading-id=\"${escape(message.id)}\" data-tool-fold=\"${escape(foldKey)}\" ${expanded ? 'open' : ''}><summary>${icon('terminal')}<span>${command ? 'Command' : escape(message.toolName || 'Tool result')}</span><span class=\"pui-tool-status${message.status === 'error' ? ' pui-tool-status-error' : ''}\">${escape(status + exit)}</span>${icon('down')}</summary>${details}${output}${gallery}</details>`;\n }\n if (message.role === 'user') return `<article class=\"pui-message pui-user-message\" data-reading-id=\"${escape(message.id)}\" aria-label=\"Your message\"><div class=\"pui-message-content\">${gallery}${text ? `<div class=\"pui-user-text\">${escape(text)}</div>` : ''}${footer}</div></article>`;\n if (message.role === 'system') return `<div class=\"pui-system-message\" data-reading-id=\"${escape(message.id)}\">${escape(text)}</div>`;\n return `<article class=\"pui-message pui-assistant-message\" data-reading-id=\"${escape(message.id)}\" aria-label=\"Agent response\"><div class=\"pui-message-content\"><div class=\"pui-markdown\">${markdown(text, conversationId)}</div>${message.status === 'error' ? '<span class=\"pui-message-error-label\">Response interrupted</span>' : ''}${footer}</div></article>`;\n}\n"]}
@@ -14,10 +14,12 @@ export declare function createImageViewer(options?: ImageViewerOptions): {
14
14
  close: () => void;
15
15
  destroy(): void;
16
16
  };
17
- export declare function installImageViewer(dialog: HTMLDialogElement): {
17
+ export declare function installImageViewer(dialog: HTMLDialogElement, options?: {
18
+ triggerRoot?: HTMLElement;
19
+ }): {
20
+ destroy(): void;
18
21
  element: HTMLDialogElement;
19
22
  open(target: HTMLImageElement | ImageViewerInput): void;
20
23
  close: () => void;
21
- destroy(): void;
22
24
  };
23
25
  //# sourceMappingURL=image-viewer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"image-viewer.d.ts","sourceRoot":"","sources":["../../src/content/image-viewer.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IAAG,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AACtF,MAAM,WAAW,gBAAgB;IAAG,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,WAAW,CAAA;CAAE;AAG1F,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB;;iBA8CjD,gBAAgB,GAAG,gBAAgB,GAAG,IAAI;iBAHvC,IAAI;eAqBT,IAAI;EAalB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,iBAAiB;;iBAjC3C,gBAAgB,GAAG,gBAAgB,GAAG,IAAI;iBAHvC,IAAI;eAqBT,IAAI;EAiBlB"}
1
+ {"version":3,"file":"image-viewer.d.ts","sourceRoot":"","sources":["../../src/content/image-viewer.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IAAG,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AACtF,MAAM,WAAW,gBAAgB;IAAG,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,WAAW,CAAA;CAAE;AAG1F,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB;;iBA6CjD,gBAAgB,GAAG,gBAAgB,GAAG,IAAI;iBAHvC,IAAI;eAqBT,IAAI;EAclB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,WAAW,CAAA;CAAO;;;iBAlCxF,gBAAgB,GAAG,gBAAgB,GAAG,IAAI;iBAHvC,IAAI;EAkDvB"}
@@ -1,4 +1,5 @@
1
1
  import { escape, icon } from '../dom.js';
2
+ import { installDialogLifecycle } from '../surface.js';
2
3
  let sequence = 0;
3
4
  /** A modal above either a generated-file preview or a conversation attachment. */
4
5
  export function createImageViewer(options = {}) {
@@ -37,12 +38,11 @@ export function createImageViewer(options = {}) {
37
38
  const observer = new ResizeObserver(() => { if (dialog.open && fitted)
38
39
  update(); });
39
40
  observer.observe(viewport);
40
- dialog.addEventListener('close', () => {
41
- image.removeAttribute('src');
42
- image.removeAttribute('style');
43
- source?.focus({ preventScroll: true });
44
- source = null;
45
- }, { signal });
41
+ const lifecycle = installDialogLifecycle(dialog, { returnFocus: () => source, onClose: () => {
42
+ image.removeAttribute('src');
43
+ image.removeAttribute('style');
44
+ source = null;
45
+ } });
46
46
  document.addEventListener('keydown', (event) => {
47
47
  if (!dialog.open || event.isComposing || event.metaKey || event.ctrlKey || event.altKey)
48
48
  return;
@@ -55,8 +55,7 @@ export function createImageViewer(options = {}) {
55
55
  resize(1 / 1.25);
56
56
  }
57
57
  }, { signal });
58
- function close() { if (dialog.open)
59
- dialog.close(); }
58
+ function close() { lifecycle.close(); }
60
59
  return {
61
60
  element: dialog,
62
61
  open(target) {
@@ -74,8 +73,7 @@ export function createImageViewer(options = {}) {
74
73
  fitted = true;
75
74
  status.textContent = 'Loading…';
76
75
  image.src = input.src;
77
- if (!dialog.open)
78
- dialog.showModal();
76
+ lifecycle.open();
79
77
  viewport.scrollTop = viewport.scrollLeft = 0;
80
78
  update();
81
79
  },
@@ -90,12 +88,27 @@ export function createImageViewer(options = {}) {
90
88
  source = null;
91
89
  destroyed = true;
92
90
  observer.disconnect();
91
+ lifecycle.destroy();
93
92
  listeners.abort();
94
93
  dialog.replaceChildren();
95
94
  },
96
95
  };
97
96
  }
98
- export function installImageViewer(dialog) {
99
- return createImageViewer({ dialog, headingId: dialog.getAttribute('aria-labelledby') || undefined });
97
+ export function installImageViewer(dialog, options = {}) {
98
+ const viewer = createImageViewer({ dialog, headingId: dialog.getAttribute('aria-labelledby') || undefined });
99
+ const abort = new AbortController();
100
+ const trigger = (event) => {
101
+ const image = event.target;
102
+ if (!(image instanceof HTMLImageElement) || !image.matches('.pui-history-image, .pui-draft-image img, .pui-file-preview-image'))
103
+ return;
104
+ if (event instanceof KeyboardEvent && (event.isComposing || !['Enter', ' '].includes(event.key)))
105
+ return;
106
+ if (event instanceof KeyboardEvent)
107
+ event.preventDefault();
108
+ viewer.open(image);
109
+ };
110
+ options.triggerRoot?.addEventListener('click', trigger, { signal: abort.signal });
111
+ options.triggerRoot?.addEventListener('keydown', trigger, { signal: abort.signal });
112
+ return { ...viewer, destroy() { abort.abort(); viewer.destroy(); } };
100
113
  }
101
114
  //# sourceMappingURL=image-viewer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"image-viewer.js","sourceRoot":"","sources":["../../src/content/image-viewer.ts"],"names":[],"mappings":"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","sourcesContent":["import { escape, icon } from '../dom.js';\n\nexport interface ImageViewerOptions { dialog?: HTMLDialogElement; headingId?: string }\nexport interface ImageViewerInput { src: string; alt?: string; returnFocus?: HTMLElement }\nlet sequence = 0;\n\n/** A modal above either a generated-file preview or a conversation attachment. */\nexport function createImageViewer(options: ImageViewerOptions = {}) {\n const dialog = options.dialog || document.createElement('dialog');\n const headingId = options.headingId || `pui-image-title-${++sequence}`;\n dialog.classList.add('pui-modal', 'pui-image-viewer');\n dialog.setAttribute('aria-labelledby', headingId);\n dialog.innerHTML = `<div class=\"pui-modal-heading\"><h2 id=\"${escape(headingId)}\">Image</h2><button type=\"button\" class=\"pui-quiet-icon\" data-image-close aria-label=\"Close image\">${icon('close')}</button></div>\n <div class=\"pui-image-viewer-viewport\"><img alt=\"\" /></div>\n <div class=\"pui-image-viewer-toolbar\"><span data-image-scale role=\"status\"></span><div><button type=\"button\" class=\"pui-secondary-button\" data-image-out aria-label=\"Zoom out\">−</button><button type=\"button\" class=\"pui-secondary-button\" data-image-in aria-label=\"Zoom in\">+</button><button type=\"button\" class=\"pui-secondary-button\" data-image-fit>Fit</button><button type=\"button\" class=\"pui-secondary-button\" data-image-original>Original size</button></div></div>`;\n const image = dialog.querySelector<HTMLImageElement>('img')!;\n const viewport = dialog.querySelector<HTMLElement>('.pui-image-viewer-viewport')!;\n const title = dialog.querySelector<HTMLElement>('h2')!;\n const status = dialog.querySelector<HTMLElement>('[data-image-scale]')!;\n const listeners = new AbortController();\n const signal = listeners.signal;\n let destroyed = false;\n let scale = 1, fitted = true, source: HTMLElement | null = null;\n function update(): void {\n if (destroyed || !image.naturalWidth) return;\n if (fitted) scale = Math.min(1, viewport.clientWidth / image.naturalWidth, viewport.clientHeight / image.naturalHeight);\n image.style.width = `${image.naturalWidth * scale}px`;\n image.style.height = `${image.naturalHeight * scale}px`;\n status.textContent = `${Math.round(scale * 100)}% · ${image.naturalWidth} × ${image.naturalHeight}`;\n }\n function resize(factor: number): void { fitted = false; const next = scale * factor; if (Number.isFinite(next) && next > 0) scale = next; update(); }\n dialog.querySelector('[data-image-fit]')!.addEventListener('click', () => { fitted = true; update(); }, { signal });\n dialog.querySelector('[data-image-original]')!.addEventListener('click', () => { fitted = false; scale = 1; update(); }, { signal });\n dialog.querySelector('[data-image-in]')!.addEventListener('click', () => resize(1.25), { signal });\n dialog.querySelector('[data-image-out]')!.addEventListener('click', () => resize(1 / 1.25), { signal });\n dialog.querySelector('[data-image-close]')!.addEventListener('click', () => dialog.close(), { signal });\n image.addEventListener('load', update, { signal });\n const observer = new ResizeObserver(() => { if (dialog.open && fitted) update(); });\n observer.observe(viewport);\n dialog.addEventListener('close', () => {\n image.removeAttribute('src');\n image.removeAttribute('style');\n source?.focus({ preventScroll: true });\n source = null;\n }, { signal });\n document.addEventListener('keydown', (event) => {\n if (!dialog.open || event.isComposing || event.metaKey || event.ctrlKey || event.altKey) return;\n if (event.key === '+' || event.key === '=') { event.preventDefault(); resize(1.25); }\n if (event.key === '-') { event.preventDefault(); resize(1 / 1.25); }\n }, { signal });\n function close(): void { if (dialog.open) dialog.close(); }\n return {\n element: dialog,\n open(target: HTMLImageElement | ImageViewerInput): void {\n if (destroyed) return;\n const input = target instanceof HTMLImageElement\n ? target.getAttribute('src') && !target.classList.contains('pui-image-unavailable') ? { src: target.src, alt: target.alt, returnFocus: target } : null\n : target;\n if (!input?.src) return;\n source = input.returnFocus || null;\n title.textContent = input.alt || 'Image';\n image.alt = input.alt || '';\n scale = 1;\n fitted = true;\n status.textContent = 'Loading…';\n image.src = input.src;\n if (!dialog.open) dialog.showModal();\n viewport.scrollTop = viewport.scrollLeft = 0;\n update();\n },\n close,\n destroy(): void {\n if (destroyed) return;\n close();\n image.removeAttribute('src');\n image.removeAttribute('style');\n source?.focus({ preventScroll: true });\n source = null;\n destroyed = true;\n observer.disconnect();\n listeners.abort();\n dialog.replaceChildren();\n },\n };\n}\n\nexport function installImageViewer(dialog: HTMLDialogElement) {\n return createImageViewer({ dialog, headingId: dialog.getAttribute('aria-labelledby') || undefined });\n}\n"]}
1
+ {"version":3,"file":"image-viewer.js","sourceRoot":"","sources":["../../src/content/image-viewer.ts"],"names":[],"mappings":"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","sourcesContent":["import { escape, icon } from '../dom.js';\nimport { installDialogLifecycle } from '../surface.js';\n\nexport interface ImageViewerOptions { dialog?: HTMLDialogElement; headingId?: string }\nexport interface ImageViewerInput { src: string; alt?: string; returnFocus?: HTMLElement }\nlet sequence = 0;\n\n/** A modal above either a generated-file preview or a conversation attachment. */\nexport function createImageViewer(options: ImageViewerOptions = {}) {\n const dialog = options.dialog || document.createElement('dialog');\n const headingId = options.headingId || `pui-image-title-${++sequence}`;\n dialog.classList.add('pui-modal', 'pui-image-viewer');\n dialog.setAttribute('aria-labelledby', headingId);\n dialog.innerHTML = `<div class=\"pui-modal-heading\"><h2 id=\"${escape(headingId)}\">Image</h2><button type=\"button\" class=\"pui-quiet-icon\" data-image-close aria-label=\"Close image\">${icon('close')}</button></div>\n <div class=\"pui-image-viewer-viewport\"><img alt=\"\" /></div>\n <div class=\"pui-image-viewer-toolbar\"><span data-image-scale role=\"status\"></span><div><button type=\"button\" class=\"pui-secondary-button\" data-image-out aria-label=\"Zoom out\">−</button><button type=\"button\" class=\"pui-secondary-button\" data-image-in aria-label=\"Zoom in\">+</button><button type=\"button\" class=\"pui-secondary-button\" data-image-fit>Fit</button><button type=\"button\" class=\"pui-secondary-button\" data-image-original>Original size</button></div></div>`;\n const image = dialog.querySelector<HTMLImageElement>('img')!;\n const viewport = dialog.querySelector<HTMLElement>('.pui-image-viewer-viewport')!;\n const title = dialog.querySelector<HTMLElement>('h2')!;\n const status = dialog.querySelector<HTMLElement>('[data-image-scale]')!;\n const listeners = new AbortController();\n const signal = listeners.signal;\n let destroyed = false;\n let scale = 1, fitted = true, source: HTMLElement | null = null;\n function update(): void {\n if (destroyed || !image.naturalWidth) return;\n if (fitted) scale = Math.min(1, viewport.clientWidth / image.naturalWidth, viewport.clientHeight / image.naturalHeight);\n image.style.width = `${image.naturalWidth * scale}px`;\n image.style.height = `${image.naturalHeight * scale}px`;\n status.textContent = `${Math.round(scale * 100)}% · ${image.naturalWidth} × ${image.naturalHeight}`;\n }\n function resize(factor: number): void { fitted = false; const next = scale * factor; if (Number.isFinite(next) && next > 0) scale = next; update(); }\n dialog.querySelector('[data-image-fit]')!.addEventListener('click', () => { fitted = true; update(); }, { signal });\n dialog.querySelector('[data-image-original]')!.addEventListener('click', () => { fitted = false; scale = 1; update(); }, { signal });\n dialog.querySelector('[data-image-in]')!.addEventListener('click', () => resize(1.25), { signal });\n dialog.querySelector('[data-image-out]')!.addEventListener('click', () => resize(1 / 1.25), { signal });\n dialog.querySelector('[data-image-close]')!.addEventListener('click', () => dialog.close(), { signal });\n image.addEventListener('load', update, { signal });\n const observer = new ResizeObserver(() => { if (dialog.open && fitted) update(); });\n observer.observe(viewport);\n const lifecycle = installDialogLifecycle(dialog, { returnFocus: () => source, onClose: () => {\n image.removeAttribute('src');\n image.removeAttribute('style');\n source = null;\n } });\n document.addEventListener('keydown', (event) => {\n if (!dialog.open || event.isComposing || event.metaKey || event.ctrlKey || event.altKey) return;\n if (event.key === '+' || event.key === '=') { event.preventDefault(); resize(1.25); }\n if (event.key === '-') { event.preventDefault(); resize(1 / 1.25); }\n }, { signal });\n function close(): void { lifecycle.close(); }\n return {\n element: dialog,\n open(target: HTMLImageElement | ImageViewerInput): void {\n if (destroyed) return;\n const input = target instanceof HTMLImageElement\n ? target.getAttribute('src') && !target.classList.contains('pui-image-unavailable') ? { src: target.src, alt: target.alt, returnFocus: target } : null\n : target;\n if (!input?.src) return;\n source = input.returnFocus || null;\n title.textContent = input.alt || 'Image';\n image.alt = input.alt || '';\n scale = 1;\n fitted = true;\n status.textContent = 'Loading…';\n image.src = input.src;\n lifecycle.open();\n viewport.scrollTop = viewport.scrollLeft = 0;\n update();\n },\n close,\n destroy(): void {\n if (destroyed) return;\n close();\n image.removeAttribute('src');\n image.removeAttribute('style');\n source?.focus({ preventScroll: true });\n source = null;\n destroyed = true;\n observer.disconnect();\n lifecycle.destroy();\n listeners.abort();\n dialog.replaceChildren();\n },\n };\n}\n\nexport function installImageViewer(dialog: HTMLDialogElement, options: { triggerRoot?: HTMLElement } = {}) {\n const viewer = createImageViewer({ dialog, headingId: dialog.getAttribute('aria-labelledby') || undefined });\n const abort = new AbortController();\n const trigger = (event: Event) => {\n const image = event.target;\n if (!(image instanceof HTMLImageElement) || !image.matches('.pui-history-image, .pui-draft-image img, .pui-file-preview-image')) return;\n if (event instanceof KeyboardEvent && (event.isComposing || !['Enter', ' '].includes(event.key))) return;\n if (event instanceof KeyboardEvent) event.preventDefault();\n viewer.open(image);\n };\n options.triggerRoot?.addEventListener('click', trigger, { signal: abort.signal });\n options.triggerRoot?.addEventListener('keydown', trigger, { signal: abort.signal });\n return { ...viewer, destroy() { abort.abort(); viewer.destroy(); } };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"paged-preview.d.ts","sourceRoot":"","sources":["../../src/content/paged-preview.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAI1C,eAAO,MAAM,gBAAgB,QAAa,CAAC;AAE3C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,SAAmB,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAgBvG;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;AACvD,MAAM,WAAW,iBAAiB;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE;AACtE,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAAG,SAAS,CAAC,EAAE,WAAW,CAAC;IAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE;AAE/H,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA0B3F;AAGD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAG/F"}
1
+ {"version":3,"file":"paged-preview.d.ts","sourceRoot":"","sources":["../../src/content/paged-preview.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAK1C,eAAO,MAAM,gBAAgB,QAAa,CAAC;AAE3C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,SAAmB,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAgBvG;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;AACvD,MAAM,WAAW,iBAAiB;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE;AACtE,MAAM,WAAW,mBAAoB,SAAQ,iBAAiB;IAAG,SAAS,CAAC,EAAE,WAAW,CAAC;IAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE;AAE/H,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA0B3F;AAGD,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CAG/F"}
@@ -1,4 +1,5 @@
1
1
  import { renderDiff, renderMarkdown } from './markdown.js';
2
+ import { adoptProductParts } from '../foundations.js';
2
3
  // A rendering window, not a file acceptance cap. Large Markdown is shown as
3
4
  // original text so page boundaries cannot change the meaning of fenced code.
4
5
  export const previewPageBytes = 256 * 1024;
@@ -80,6 +81,7 @@ function renderPreview(container, text, kind) {
80
81
  previous.textContent = 'Previous';
81
82
  next.textContent = 'Next';
82
83
  toolbar.append(previous, status, next);
84
+ const parts = adoptProductParts(container);
83
85
  let page = 0;
84
86
  const decoder = new TextDecoder('utf-8', { fatal: true });
85
87
  const render = () => {
@@ -91,15 +93,16 @@ function renderPreview(container, text, kind) {
91
93
  content.innerHTML = renderDiff(value);
92
94
  else
93
95
  content.textContent = value;
94
- previous.disabled = page === 0;
95
- next.disabled = page === ranges.length - 1;
96
+ parts.action(previous).update({ disabled: page === 0 });
97
+ parts.action(next).update({ disabled: page === ranges.length - 1 });
96
98
  status.textContent = `${page + 1} / ${ranges.length}${kind === 'markdown' && ranges.length > 1 ? ' · Plain text preview' : ''}`;
97
99
  content.scrollTop = 0;
100
+ parts.update();
98
101
  };
99
102
  previous.onclick = () => { page--; render(); };
100
103
  next.onclick = () => { page++; render(); };
101
104
  container.replaceChildren(...(ranges.length > 1 ? [toolbar, content] : [content]));
102
105
  render();
103
- return () => { previous.onclick = null; next.onclick = null; };
106
+ return () => { parts.destroy(); previous.onclick = null; next.onclick = null; };
104
107
  }
105
108
  //# sourceMappingURL=paged-preview.js.map