@aparte/core 0.12.0 → 0.13.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.
- package/dist/client/aparte-client.d.ts +25 -0
- package/dist/client/aparte-client.d.ts.map +1 -1
- package/dist/components/bubble/aparte-chat-bubble.d.ts +117 -0
- package/dist/components/bubble/aparte-chat-bubble.d.ts.map +1 -1
- package/dist/components/chat/aparte-chat.d.ts +70 -15
- package/dist/components/chat/aparte-chat.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-action.d.ts +48 -7
- package/dist/components/composer/aparte-composer-action.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-add-attachment.d.ts +37 -4
- package/dist/components/composer/aparte-composer-add-attachment.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-attachments.d.ts +35 -3
- package/dist/components/composer/aparte-composer-attachments.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-cancel.d.ts +25 -2
- package/dist/components/composer/aparte-composer-cancel.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-input.d.ts +54 -5
- package/dist/components/composer/aparte-composer-input.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-send.d.ts +47 -4
- package/dist/components/composer/aparte-composer-send.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-toolbar.d.ts +15 -4
- package/dist/components/composer/aparte-composer-toolbar.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer.d.ts +139 -7
- package/dist/components/composer/aparte-composer.d.ts.map +1 -1
- package/dist/components/composer/index.d.ts +1 -1
- package/dist/components/composer/index.d.ts.map +1 -1
- package/dist/components/conversation-list/aparte-conversation-list.d.ts +50 -8
- package/dist/components/conversation-list/aparte-conversation-list.d.ts.map +1 -1
- package/dist/components/elicitation/aparte-elicitation.d.ts +45 -0
- package/dist/components/elicitation/aparte-elicitation.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/status/aparte-chat-status.d.ts +47 -5
- package/dist/components/status/aparte-chat-status.d.ts.map +1 -1
- package/dist/components/viewport/aparte-chat-viewport.d.ts +78 -8
- package/dist/components/viewport/aparte-chat-viewport.d.ts.map +1 -1
- package/dist/config/aparte-config.d.ts +22 -0
- package/dist/config/aparte-config.d.ts.map +1 -1
- package/dist/config/icon-provider.d.ts +17 -15
- package/dist/config/icon-provider.d.ts.map +1 -1
- package/dist/config/sanitize.d.ts.map +1 -1
- package/dist/custom-elements.json +5400 -3278
- package/dist/elicitation/approval-panel.d.ts.map +1 -1
- package/dist/elicitation/panel.d.ts +23 -2
- package/dist/elicitation/panel.d.ts.map +1 -1
- package/dist/generated/element-attributes.d.ts +21 -15
- package/dist/generated/element-attributes.d.ts.map +1 -1
- package/dist/glyphs-QXfbL3n_.js +81 -0
- package/dist/glyphs-QXfbL3n_.js.map +1 -0
- package/dist/host/aparte-chat-host.d.ts +22 -21
- package/dist/host/aparte-chat-host.d.ts.map +1 -1
- package/dist/icons/extended.d.ts +153 -0
- package/dist/icons/extended.d.ts.map +1 -0
- package/dist/icons/glyphs.d.ts +98 -0
- package/dist/icons/glyphs.d.ts.map +1 -0
- package/dist/icons/index.d.ts +24 -0
- package/dist/icons/index.d.ts.map +1 -0
- package/dist/icons.d.ts +14 -0
- package/dist/icons.d.ts.map +1 -0
- package/dist/icons.js +157 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.css +5082 -2119
- package/dist/index.d.ts +37 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +167 -67
- package/dist/index.js.map +1 -1
- package/dist/index.node.d.ts +2 -2
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +1 -1
- package/dist/index.node.js.map +1 -1
- package/dist/{is-awaiting-reply-CxWRISBC.js → is-awaiting-reply-DrO_oR32.js} +369 -148
- package/dist/is-awaiting-reply-DrO_oR32.js.map +1 -0
- package/dist/primitives/icon/aparte-icon.d.ts +49 -0
- package/dist/primitives/icon/aparte-icon.d.ts.map +1 -0
- package/dist/primitives/icon/index.d.ts +2 -0
- package/dist/primitives/icon/index.d.ts.map +1 -0
- package/dist/primitives/index.d.ts +1 -0
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/progress-spinner/aparte-progress-spinner.d.ts +20 -5
- package/dist/primitives/progress-spinner/aparte-progress-spinner.d.ts.map +1 -1
- package/dist/primitives/select/aparte-optgroup.d.ts +30 -7
- package/dist/primitives/select/aparte-optgroup.d.ts.map +1 -1
- package/dist/primitives/select/aparte-option.d.ts +29 -3
- package/dist/primitives/select/aparte-option.d.ts.map +1 -1
- package/dist/primitives/select/aparte-select.d.ts +36 -11
- package/dist/primitives/select/aparte-select.d.ts.map +1 -1
- package/dist/renderers/segments/artifact/card.d.ts.map +1 -1
- package/dist/renderers/segments/thinking.d.ts.map +1 -1
- package/dist/renderers/segments/tool-call.d.ts.map +1 -1
- package/dist/types/element-map.d.ts +2 -0
- package/dist/types/element-map.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/segments.d.ts +92 -7
- package/dist/types/segments.d.ts.map +1 -1
- package/dist/types/tools.d.ts +2 -0
- package/dist/types/tools.d.ts.map +1 -1
- package/package.json +7 -1
- package/dist/is-awaiting-reply-CxWRISBC.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { A, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, q, r, t, u, v, w, z, B, C, D, E, G, H, I, J, M, N, R, S, T, U, V, X, Y, Z, _, a2, a3, a5 } from "./is-awaiting-reply-
|
|
1
|
+
import { $ as resolveConfig, a4 as subscribeConfigChange, a1 as runWithConfig, p as AparteElicitationAbortError, x as buildApprovalPanel, y as buildElicitationPanel, K as escapeAttr, F as cssEscape, a7 as mergeSegmentUpdate, L as escapeHtml, a8 as writeStreamedMarkdown, O as getSegmentRenderer, P as installDefaultRenderersOnce, s as AparteMessageRepository, a9 as stampSegmentActivity, aa as stampSegmentOnInsert, ab as stampSegmentOnUpdate, ac as renumberSegments, ad as openSegmentIds, ae as isTerminalStatus, af as adoptMessageSegments, Q as isAwaitingReply, W as populateBubbleFromMessage, a6 as uuid, a0 as revokeAttachmentUrls } from "./is-awaiting-reply-DrO_oR32.js";
|
|
2
|
+
import { A, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, q, r, t, u, v, w, z, B, C, D, E, G, H, I, J, M, N, R, S, T, U, V, X, Y, Z, _, a2, a3, a5 } from "./is-awaiting-reply-DrO_oR32.js";
|
|
3
3
|
class AparteOption extends HTMLElement {
|
|
4
4
|
static get observedAttributes() {
|
|
5
5
|
return ["value", "disabled", "selected", "data-status"];
|
|
@@ -132,6 +132,7 @@ class AparteOptgroup extends HTMLElement {
|
|
|
132
132
|
if (this.collapsible) {
|
|
133
133
|
const chevron = document.createElement("span");
|
|
134
134
|
chevron.className = "aparte-optgroup-chevron";
|
|
135
|
+
chevron.innerHTML = resolveConfig(this).getIcon("expand");
|
|
135
136
|
header.appendChild(chevron);
|
|
136
137
|
header.style.cursor = "pointer";
|
|
137
138
|
header.addEventListener("click", (e2) => {
|
|
@@ -204,8 +205,7 @@ class AparteSelect extends HTMLElement {
|
|
|
204
205
|
* document-level handlers and could not touch this one.
|
|
205
206
|
*
|
|
206
207
|
* This is verbatim the bug class `aparte-chat-viewport` documents having fixed
|
|
207
|
-
* for its own listeners
|
|
208
|
-
* listener on a persistent node.
|
|
208
|
+
* for its own listeners.
|
|
209
209
|
*/
|
|
210
210
|
_boundHandleOptionClick = this._handleOptionClick.bind(this);
|
|
211
211
|
_boundHandleDocumentClick = this._handleDocumentClick.bind(this);
|
|
@@ -289,7 +289,7 @@ class AparteSelect extends HTMLElement {
|
|
|
289
289
|
labelSpan.textContent = placeholder;
|
|
290
290
|
const chevronSpan = document.createElement("span");
|
|
291
291
|
chevronSpan.className = "aparte-select-chevron";
|
|
292
|
-
chevronSpan.innerHTML =
|
|
292
|
+
chevronSpan.innerHTML = resolveConfig(this).getIcon("expand");
|
|
293
293
|
trigger.append(labelSpan, chevronSpan);
|
|
294
294
|
const dropdown = document.createElement("div");
|
|
295
295
|
dropdown.className = "aparte-select-dropdown";
|
|
@@ -631,6 +631,32 @@ class AparteProgressSpinner extends HTMLElement {
|
|
|
631
631
|
if (!customElements.get("aparte-progress-spinner")) {
|
|
632
632
|
customElements.define("aparte-progress-spinner", AparteProgressSpinner);
|
|
633
633
|
}
|
|
634
|
+
class AparteIcon extends HTMLElement {
|
|
635
|
+
static get observedAttributes() {
|
|
636
|
+
return ["name"];
|
|
637
|
+
}
|
|
638
|
+
_unsubscribe = null;
|
|
639
|
+
connectedCallback() {
|
|
640
|
+
this._render();
|
|
641
|
+
this._unsubscribe = subscribeConfigChange(this, () => this._render());
|
|
642
|
+
}
|
|
643
|
+
disconnectedCallback() {
|
|
644
|
+
this._unsubscribe?.();
|
|
645
|
+
this._unsubscribe = null;
|
|
646
|
+
}
|
|
647
|
+
attributeChangedCallback() {
|
|
648
|
+
if (this.isConnected) this._render();
|
|
649
|
+
}
|
|
650
|
+
_render() {
|
|
651
|
+
const name = this.getAttribute("name");
|
|
652
|
+
const glyph = name ? resolveConfig(this).getIconProvider()[name]?.() : null;
|
|
653
|
+
this.innerHTML = glyph ?? "";
|
|
654
|
+
this.firstElementChild?.setAttribute("aria-hidden", "true");
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (!customElements.get("aparte-icon")) {
|
|
658
|
+
customElements.define("aparte-icon", AparteIcon);
|
|
659
|
+
}
|
|
634
660
|
class AparteElicitation extends HTMLElement {
|
|
635
661
|
_pending = null;
|
|
636
662
|
/**
|
|
@@ -727,17 +753,15 @@ class AparteElicitation extends HTMLElement {
|
|
|
727
753
|
}
|
|
728
754
|
const cfg = resolveConfig(this);
|
|
729
755
|
if (request.kind === "approval") {
|
|
756
|
+
const approvalMode = () => panel2.isComplete() ? "submit" : "none";
|
|
730
757
|
const panel2 = runWithConfig(cfg, () => buildApprovalPanel(request.message, request.options ?? [], () => {
|
|
731
|
-
composer.setPanelSubmitEnabled(panel2.isComplete(),
|
|
758
|
+
composer.setPanelSubmitEnabled(panel2.isComplete(), approvalMode());
|
|
732
759
|
}));
|
|
733
760
|
panel2.onSettle((answer) => settle({ action: "accept", content: answer }));
|
|
734
761
|
this._pending = { abort: () => fail(), composer, relabel: () => panel2.relabel() };
|
|
735
762
|
slot.token = composer.showPanel(panel2.el, {
|
|
736
763
|
submitEnabled: panel2.isComplete(),
|
|
737
|
-
mode:
|
|
738
|
-
// The composer's button carries the INSTRUCTION, which is written
|
|
739
|
-
// text — exactly the act that button already means. The options
|
|
740
|
-
// never route through it: a decision is its own click.
|
|
764
|
+
mode: approvalMode(),
|
|
741
765
|
onSubmit: () => {
|
|
742
766
|
if (panel2.isComplete()) settle({ action: "accept", content: panel2.getContent() });
|
|
743
767
|
},
|
|
@@ -752,10 +776,11 @@ class AparteElicitation extends HTMLElement {
|
|
|
752
776
|
}));
|
|
753
777
|
const skip = document.createElement("button");
|
|
754
778
|
skip.type = "button";
|
|
755
|
-
skip.className = "aparte-elic-skip";
|
|
779
|
+
skip.className = "aparte-btn aparte-elic-skip";
|
|
756
780
|
skip.textContent = cfg.t("elicitationSkip");
|
|
757
781
|
skip.addEventListener("click", () => settle({ action: "decline" }));
|
|
758
782
|
panel.dismiss.appendChild(skip);
|
|
783
|
+
panel.onSettle((content) => settle({ action: "accept", content }));
|
|
759
784
|
this._pending = {
|
|
760
785
|
abort: () => fail(),
|
|
761
786
|
composer,
|
|
@@ -968,6 +993,14 @@ function warnMissingRenderer(type) {
|
|
|
968
993
|
_warnedNoRenderer = true;
|
|
969
994
|
console.warn(`[aparte] No renderer for segment "${type}". Register one with registerSegmentRenderer({ type: '${type}', render }) from @aparte/core — see https://apartejs.dev/guides/customization/#custom-segment-types`);
|
|
970
995
|
}
|
|
996
|
+
function unrenderedSegment(segment) {
|
|
997
|
+
const fallback = typeof segment.fallback === "string" && segment.fallback.trim() ? segment.fallback : null;
|
|
998
|
+
if (!fallback) warnMissingRenderer(segment.type);
|
|
999
|
+
const el = document.createElement("div");
|
|
1000
|
+
el.className = fallback ? "aparte-segment aparte-segment-fallback" : "aparte-segment aparte-segment-unknown";
|
|
1001
|
+
el.textContent = fallback ?? `[Unknown segment type: ${segment.type}]`;
|
|
1002
|
+
return el;
|
|
1003
|
+
}
|
|
971
1004
|
function resolveSegmentRenderer(type, config) {
|
|
972
1005
|
const renderer = getSegmentRenderer(type, config);
|
|
973
1006
|
if (renderer) return renderer;
|
|
@@ -980,7 +1013,6 @@ function segmentRenderResultToElement(result) {
|
|
|
980
1013
|
wrapper.innerHTML = result;
|
|
981
1014
|
return wrapper.firstElementChild;
|
|
982
1015
|
}
|
|
983
|
-
const INFO_ICON_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>';
|
|
984
1016
|
class AparteChatBubble extends HTMLElement {
|
|
985
1017
|
_contentEl = null;
|
|
986
1018
|
_segmentsEl = null;
|
|
@@ -1106,6 +1138,7 @@ class AparteChatBubble extends HTMLElement {
|
|
|
1106
1138
|
break;
|
|
1107
1139
|
case "content":
|
|
1108
1140
|
this._content = newValue || "";
|
|
1141
|
+
this._resetMarkdownStream();
|
|
1109
1142
|
this._updateContent();
|
|
1110
1143
|
break;
|
|
1111
1144
|
case "timestamp":
|
|
@@ -1131,8 +1164,20 @@ class AparteChatBubble extends HTMLElement {
|
|
|
1131
1164
|
setContent(content) {
|
|
1132
1165
|
this._content = content;
|
|
1133
1166
|
this.setAttribute("content", content);
|
|
1167
|
+
this._resetMarkdownStream();
|
|
1134
1168
|
this._updateContent();
|
|
1135
1169
|
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Drop the incremental Markdown parser's state.
|
|
1172
|
+
*
|
|
1173
|
+
* Only needed where `_content` is REPLACED rather than grown. `appendToken` grows it, so
|
|
1174
|
+
* the parser's cursor stays valid there — which is the whole point of the seam.
|
|
1175
|
+
*/
|
|
1176
|
+
_resetMarkdownStream() {
|
|
1177
|
+
const host = this;
|
|
1178
|
+
if (host._aparteSmd) host._aparteSmd.renderer.end();
|
|
1179
|
+
host._aparteSmd = void 0;
|
|
1180
|
+
}
|
|
1136
1181
|
/** Get current content */
|
|
1137
1182
|
getContent() {
|
|
1138
1183
|
return this._content;
|
|
@@ -1267,11 +1312,7 @@ class AparteChatBubble extends HTMLElement {
|
|
|
1267
1312
|
runWithConfig(this._cfg, () => renderer.setup?.(el, segment));
|
|
1268
1313
|
}
|
|
1269
1314
|
} else {
|
|
1270
|
-
|
|
1271
|
-
const fallback = document.createElement("div");
|
|
1272
|
-
fallback.className = "aparte-segment aparte-segment-unknown";
|
|
1273
|
-
fallback.textContent = `[Unknown segment type: ${segment.type}]`;
|
|
1274
|
-
this._segmentsEl.appendChild(fallback);
|
|
1315
|
+
this._segmentsEl.appendChild(unrenderedSegment(segment));
|
|
1275
1316
|
}
|
|
1276
1317
|
if (this._contentEl) this._contentEl.style.display = "none";
|
|
1277
1318
|
this._reflectError();
|
|
@@ -1350,9 +1391,16 @@ class AparteChatBubble extends HTMLElement {
|
|
|
1350
1391
|
</div>
|
|
1351
1392
|
<div class="aparte-footer">
|
|
1352
1393
|
<div class="aparte-branch-picker" hidden>
|
|
1353
|
-
<button class="aparte-branch-prev" aria-label="${escapeAttr(this._cfg.getLocale().previousResponse ?? "Previous response")}">‹</button>
|
|
1394
|
+
<button class="aparte-btn aparte-btn--icon aparte-btn--sm aparte-branch-prev" aria-label="${escapeAttr(this._cfg.getLocale().previousResponse ?? "Previous response")}">‹</button>
|
|
1354
1395
|
<span class="aparte-branch-label">1 / 1</span>
|
|
1355
|
-
|
|
1396
|
+
<!-- The move has to be ANNOUNCED. Pressing the arrows deliberately does not
|
|
1397
|
+
take focus, so without a live region a screen-reader user gets the new
|
|
1398
|
+
branch and no indication anything changed. The visible label cannot be
|
|
1399
|
+
the region itself: a custom sibling-nav renderer may replace it with
|
|
1400
|
+
dots, which reads as nothing. No new locale key — the position is
|
|
1401
|
+
digits, and the buttons beside it already carry translated labels. -->
|
|
1402
|
+
<span class="aparte-sr-only aparte-branch-status" aria-live="polite"></span>
|
|
1403
|
+
<button class="aparte-btn aparte-btn--icon aparte-btn--sm aparte-branch-next" aria-label="${escapeAttr(this._cfg.getLocale().nextResponse ?? "Next response")}">›</button>
|
|
1356
1404
|
</div>
|
|
1357
1405
|
<div class="aparte-action-bar" role="toolbar" aria-label="${escapeAttr(this._cfg.getLocale().messageActions ?? "Message actions")}"></div>
|
|
1358
1406
|
</div>
|
|
@@ -1453,7 +1501,10 @@ class AparteChatBubble extends HTMLElement {
|
|
|
1453
1501
|
return;
|
|
1454
1502
|
}
|
|
1455
1503
|
this._contentEl.style.display = "";
|
|
1456
|
-
|
|
1504
|
+
runWithConfig(
|
|
1505
|
+
this._cfg,
|
|
1506
|
+
() => writeStreamedMarkdown(this, this._contentEl, this._content, this._streaming)
|
|
1507
|
+
);
|
|
1457
1508
|
this._updateWaiting();
|
|
1458
1509
|
if (!this._streaming) this._highlightContentCode();
|
|
1459
1510
|
}
|
|
@@ -1496,11 +1547,7 @@ class AparteChatBubble extends HTMLElement {
|
|
|
1496
1547
|
runWithConfig(this._cfg, () => renderer.setup?.(el, segment));
|
|
1497
1548
|
}
|
|
1498
1549
|
} else {
|
|
1499
|
-
|
|
1500
|
-
const fallback = document.createElement("div");
|
|
1501
|
-
fallback.className = "aparte-segment aparte-segment-unknown";
|
|
1502
|
-
fallback.textContent = `[Unknown segment type: ${segment.type}]`;
|
|
1503
|
-
this._segmentsEl.appendChild(fallback);
|
|
1550
|
+
this._segmentsEl.appendChild(unrenderedSegment(segment));
|
|
1504
1551
|
}
|
|
1505
1552
|
}
|
|
1506
1553
|
if (this._contentEl) {
|
|
@@ -1649,6 +1696,11 @@ class AparteChatBubble extends HTMLElement {
|
|
|
1649
1696
|
label.textContent = `${this._siblingIndex + 1} / ${this._siblingCount}`;
|
|
1650
1697
|
}
|
|
1651
1698
|
}
|
|
1699
|
+
const status = this._branchPickerEl.querySelector(".aparte-branch-status");
|
|
1700
|
+
if (status) {
|
|
1701
|
+
const position = `${this._siblingIndex + 1} / ${this._siblingCount}`;
|
|
1702
|
+
if (status.textContent !== position) status.textContent = position;
|
|
1703
|
+
}
|
|
1652
1704
|
const prevBtn = this._branchPickerEl.querySelector(".aparte-branch-prev");
|
|
1653
1705
|
const nextBtn = this._branchPickerEl.querySelector(".aparte-branch-next");
|
|
1654
1706
|
if (prevBtn) prevBtn.disabled = this._siblingIndex === 0;
|
|
@@ -1715,7 +1767,7 @@ class AparteChatBubble extends HTMLElement {
|
|
|
1715
1767
|
const roles = a4.bubble?.roles ?? ["user", "assistant"];
|
|
1716
1768
|
if (!roles.includes(this._role)) continue;
|
|
1717
1769
|
const btn = document.createElement("button");
|
|
1718
|
-
btn.className = "aparte-action-btn aparte-action-custom";
|
|
1770
|
+
btn.className = "aparte-btn aparte-btn--icon aparte-action-btn aparte-action-custom";
|
|
1719
1771
|
btn.dataset["action"] = `custom:${a4.id}`;
|
|
1720
1772
|
btn.setAttribute("aria-label", a4.label);
|
|
1721
1773
|
btn.setAttribute("title", a4.label);
|
|
@@ -1729,28 +1781,28 @@ class AparteChatBubble extends HTMLElement {
|
|
|
1729
1781
|
switch (action) {
|
|
1730
1782
|
case "copy": {
|
|
1731
1783
|
const l2 = locale.copy ?? "Copy";
|
|
1732
|
-
return `<button class="aparte-action-btn aparte-action-copy" data-action="copy" aria-label="${escapeAttr(l2)}" title="${escapeAttr(l2)}">${icons.copy()}</button>`;
|
|
1784
|
+
return `<button class="aparte-btn aparte-btn--icon aparte-action-btn aparte-action-copy" data-action="copy" aria-label="${escapeAttr(l2)}" title="${escapeAttr(l2)}">${icons.copy()}</button>`;
|
|
1733
1785
|
}
|
|
1734
1786
|
case "edit": {
|
|
1735
1787
|
const l2 = locale.edit ?? "Edit message";
|
|
1736
|
-
return `<button class="aparte-action-btn aparte-action-edit" data-action="edit" aria-label="${escapeAttr(l2)}" title="${escapeAttr(l2)}">${icons.edit()}</button>`;
|
|
1788
|
+
return `<button class="aparte-btn aparte-btn--icon aparte-action-btn aparte-action-edit" data-action="edit" aria-label="${escapeAttr(l2)}" title="${escapeAttr(l2)}">${icons.edit()}</button>`;
|
|
1737
1789
|
}
|
|
1738
1790
|
case "retry": {
|
|
1739
1791
|
const l2 = locale.retry ?? "Retry";
|
|
1740
|
-
return `<button class="aparte-action-btn aparte-action-retry" data-action="retry" aria-label="${escapeAttr(l2)}" title="${escapeAttr(l2)}">${icons.retry()}</button>`;
|
|
1792
|
+
return `<button class="aparte-btn aparte-btn--icon aparte-action-btn aparte-action-retry" data-action="retry" aria-label="${escapeAttr(l2)}" title="${escapeAttr(l2)}">${icons.retry()}</button>`;
|
|
1741
1793
|
}
|
|
1742
1794
|
case "thumbUp": {
|
|
1743
1795
|
const l2 = locale.feedbackPositive ?? "Good response";
|
|
1744
|
-
return `<button class="aparte-action-btn aparte-action-feedback-pos" data-action="feedback-positive" aria-label="${escapeAttr(l2)}" title="${escapeAttr(l2)}">${icons.thumbUp()}</button>`;
|
|
1796
|
+
return `<button class="aparte-btn aparte-btn--icon aparte-action-btn aparte-action-feedback-pos" data-action="feedback-positive" aria-label="${escapeAttr(l2)}" title="${escapeAttr(l2)}">${icons.thumbUp()}</button>`;
|
|
1745
1797
|
}
|
|
1746
1798
|
case "thumbDown": {
|
|
1747
1799
|
const l2 = locale.feedbackNegative ?? "Bad response";
|
|
1748
|
-
return `<button class="aparte-action-btn aparte-action-feedback-neg" data-action="feedback-negative" aria-label="${escapeAttr(l2)}" title="${escapeAttr(l2)}">${icons.thumbDown()}</button>`;
|
|
1800
|
+
return `<button class="aparte-btn aparte-btn--icon aparte-action-btn aparte-action-feedback-neg" data-action="feedback-negative" aria-label="${escapeAttr(l2)}" title="${escapeAttr(l2)}">${icons.thumbDown()}</button>`;
|
|
1749
1801
|
}
|
|
1750
1802
|
case "info": {
|
|
1751
1803
|
if (!this._usage) return "";
|
|
1752
1804
|
const l2 = locale.messageInfo ?? "Details";
|
|
1753
|
-
return `<button class="aparte-action-btn aparte-action-info" data-action="info" aria-label="${escapeAttr(l2)}" title="${escapeAttr(l2)}">${
|
|
1805
|
+
return `<button class="aparte-btn aparte-btn--icon aparte-action-btn aparte-action-info" data-action="info" aria-label="${escapeAttr(l2)}" title="${escapeAttr(l2)}">${this._cfg.getIcon("info")}</button>`;
|
|
1754
1806
|
}
|
|
1755
1807
|
default:
|
|
1756
1808
|
return "";
|
|
@@ -1762,7 +1814,7 @@ class AparteChatBubble extends HTMLElement {
|
|
|
1762
1814
|
const locale = this._cfg.getLocale();
|
|
1763
1815
|
const saveLabel = locale.editConfirm ?? "Save";
|
|
1764
1816
|
const cancelLabel = locale.editCancel ?? "Cancel";
|
|
1765
|
-
this._actionBarEl.innerHTML = `<button class="aparte-action-btn aparte-action-edit-save" data-action="edit-save" aria-label="${escapeAttr(saveLabel)}" title="${escapeAttr(saveLabel)}">${this._cfg.getIcon("check")}</button><button class="aparte-action-btn aparte-action-edit-cancel" data-action="edit-cancel" aria-label="${escapeAttr(cancelLabel)}" title="${escapeAttr(cancelLabel)}">${this._cfg.getIcon("close")}</button>`;
|
|
1817
|
+
this._actionBarEl.innerHTML = `<button class="aparte-btn aparte-btn--icon aparte-btn--sm aparte-btn--success aparte-action-btn aparte-action-edit-save" data-action="edit-save" aria-label="${escapeAttr(saveLabel)}" title="${escapeAttr(saveLabel)}">${this._cfg.getIcon("check")}</button><button class="aparte-btn aparte-btn--icon aparte-btn--sm aparte-btn--danger aparte-action-btn aparte-action-edit-cancel" data-action="edit-cancel" aria-label="${escapeAttr(cancelLabel)}" title="${escapeAttr(cancelLabel)}">${this._cfg.getIcon("close")}</button>`;
|
|
1766
1818
|
this._actionBarEl.querySelectorAll(".aparte-action-btn").forEach((btn) => {
|
|
1767
1819
|
btn.addEventListener("click", (e2) => this._handleActionClick(e2));
|
|
1768
1820
|
});
|
|
@@ -2572,6 +2624,11 @@ class AparteChatViewport extends HTMLElement {
|
|
|
2572
2624
|
getMessage(messageId) {
|
|
2573
2625
|
return this._repo.getMessageById(messageId);
|
|
2574
2626
|
}
|
|
2627
|
+
/**
|
|
2628
|
+
* The messages on the currently ACTIVE path, root → head — not the whole tree.
|
|
2629
|
+
* A message that was retried contributes only the branch currently selected;
|
|
2630
|
+
* `exportTree()` is what returns every sibling.
|
|
2631
|
+
*/
|
|
2575
2632
|
getMessages() {
|
|
2576
2633
|
return this._repo.getMessages();
|
|
2577
2634
|
}
|
|
@@ -2836,11 +2893,11 @@ class AparteChatViewport extends HTMLElement {
|
|
|
2836
2893
|
this.appendChild(container);
|
|
2837
2894
|
this._container = container;
|
|
2838
2895
|
this._scrollBtn = document.createElement("button");
|
|
2839
|
-
this._scrollBtn.className = "aparte-scroll-btn aparte-scroll-btn--hidden";
|
|
2896
|
+
this._scrollBtn.className = "aparte-btn aparte-btn--surface aparte-btn--circle aparte-btn--lg aparte-scroll-btn aparte-scroll-btn--hidden";
|
|
2840
2897
|
this._scrollBtn.setAttribute("type", "button");
|
|
2841
2898
|
this._scrollBtn.setAttribute("aria-label", "Scroll to bottom");
|
|
2842
2899
|
const scrollIcon = resolveConfig(this).getIcon("scrollDown");
|
|
2843
|
-
this._scrollBtn.innerHTML = scrollIcon
|
|
2900
|
+
this._scrollBtn.innerHTML = scrollIcon;
|
|
2844
2901
|
this.appendChild(this._scrollBtn);
|
|
2845
2902
|
} else {
|
|
2846
2903
|
this._container = this.querySelector(".aparte-viewport-container");
|
|
@@ -2869,11 +2926,11 @@ class AparteChatViewport extends HTMLElement {
|
|
|
2869
2926
|
}
|
|
2870
2927
|
this.classList.add("aparte-viewport--framework");
|
|
2871
2928
|
const scrollBtn = document.createElement("button");
|
|
2872
|
-
scrollBtn.className = "aparte-scroll-btn aparte-scroll-btn--hidden";
|
|
2929
|
+
scrollBtn.className = "aparte-btn aparte-btn--surface aparte-btn--circle aparte-btn--lg aparte-scroll-btn aparte-scroll-btn--hidden";
|
|
2873
2930
|
scrollBtn.setAttribute("type", "button");
|
|
2874
2931
|
scrollBtn.setAttribute("aria-label", "Scroll to bottom");
|
|
2875
2932
|
const scrollIcon = resolveConfig(this).getIcon("scrollDown");
|
|
2876
|
-
scrollBtn.innerHTML = scrollIcon
|
|
2933
|
+
scrollBtn.innerHTML = scrollIcon;
|
|
2877
2934
|
this.appendChild(scrollBtn);
|
|
2878
2935
|
this._scrollBtn = scrollBtn;
|
|
2879
2936
|
}
|
|
@@ -3293,18 +3350,31 @@ class AparteComposer extends HTMLElement {
|
|
|
3293
3350
|
submitEnabled: this._panelSubmitEnabled
|
|
3294
3351
|
};
|
|
3295
3352
|
}
|
|
3353
|
+
/**
|
|
3354
|
+
* Set the composer's value — both what a send will submit and what the editor
|
|
3355
|
+
* shows. `<aparte-composer-input>` writes through any value it does not already
|
|
3356
|
+
* hold, so this prefills the visible field (a template button, a restored draft)
|
|
3357
|
+
* as readily as it stages text for an immediate `submit()`.
|
|
3358
|
+
*/
|
|
3296
3359
|
setValue(value) {
|
|
3297
3360
|
this._value = value;
|
|
3298
3361
|
this._emit("value-change", { value });
|
|
3299
3362
|
}
|
|
3363
|
+
/** Append files to the pending attachments and notify. Does not de-duplicate. */
|
|
3300
3364
|
addAttachments(files) {
|
|
3301
3365
|
this._attachments = [...this._attachments, ...Array.from(files)];
|
|
3302
3366
|
this._emit("attachments-change", { attachments: this._attachments });
|
|
3303
3367
|
}
|
|
3368
|
+
/**
|
|
3369
|
+
* Drop one pending attachment and notify. Matched by IDENTITY — pass the same
|
|
3370
|
+
* `File` object the composer handed you, not an equal one; two picks of the same
|
|
3371
|
+
* file on disk are two distinct objects.
|
|
3372
|
+
*/
|
|
3304
3373
|
removeAttachment(file) {
|
|
3305
3374
|
this._attachments = this._attachments.filter((f2) => f2 !== file);
|
|
3306
3375
|
this._emit("attachments-change", { attachments: this._attachments });
|
|
3307
3376
|
}
|
|
3377
|
+
/** Drop every pending attachment and notify. */
|
|
3308
3378
|
clearAttachments() {
|
|
3309
3379
|
this._attachments = [];
|
|
3310
3380
|
this._emit("attachments-change", { attachments: [] });
|
|
@@ -3323,6 +3393,15 @@ class AparteComposer extends HTMLElement {
|
|
|
3323
3393
|
* are the user's state and not an action to offer — hiding them would look like
|
|
3324
3394
|
* losing them; and the toolbar, because switching model still does something.
|
|
3325
3395
|
*
|
|
3396
|
+
* The send button is the part the PANEL decides, through `mode`. `'submit'` and
|
|
3397
|
+
* `'advance'` keep it; `'none'` says this panel has no act for it and it is not
|
|
3398
|
+
* drawn. That third value is what a panel whose options settle on the first click
|
|
3399
|
+
* needs — a single-choice question, an approval — and until it existed such a
|
|
3400
|
+
* panel left a permanently disabled button beside options that never routed
|
|
3401
|
+
* through it. Flip between them at any time with {@link setPanelSubmitEnabled},
|
|
3402
|
+
* which is how a panel that grows an act (an "Other…" field, a written
|
|
3403
|
+
* instruction) turns the button back on.
|
|
3404
|
+
*
|
|
3326
3405
|
* Declared with an attribute + CSS rather than the inline `style.display` this
|
|
3327
3406
|
* used to set on a child: an attribute is themeable, is visible to a consumer's
|
|
3328
3407
|
* own rules, and does not clobber a `display` the consumer had set (the restore
|
|
@@ -3346,6 +3425,7 @@ class AparteComposer extends HTMLElement {
|
|
|
3346
3425
|
this._panelActive = true;
|
|
3347
3426
|
this._panelSubmitEnabled = options?.submitEnabled ?? false;
|
|
3348
3427
|
this._panelMode = options?.mode ?? "submit";
|
|
3428
|
+
this._reflectPanelMode();
|
|
3349
3429
|
this._panelOnSubmit = options?.onSubmit ?? null;
|
|
3350
3430
|
this._panelOnEvict = options?.onEvict ?? null;
|
|
3351
3431
|
const token = Symbol("aparte-composer-panel");
|
|
@@ -3405,6 +3485,7 @@ class AparteComposer extends HTMLElement {
|
|
|
3405
3485
|
this._panelActive = false;
|
|
3406
3486
|
this._panelSubmitEnabled = false;
|
|
3407
3487
|
this._panelMode = "submit";
|
|
3488
|
+
this._reflectPanelMode();
|
|
3408
3489
|
this._panelOnSubmit = null;
|
|
3409
3490
|
this._panelOnEvict = null;
|
|
3410
3491
|
this._panelToken = null;
|
|
@@ -3423,8 +3504,21 @@ class AparteComposer extends HTMLElement {
|
|
|
3423
3504
|
if (!this._panelActive) return;
|
|
3424
3505
|
this._panelSubmitEnabled = enabled;
|
|
3425
3506
|
if (mode) this._panelMode = mode;
|
|
3507
|
+
this._reflectPanelMode();
|
|
3426
3508
|
this._emit("panel-change", { active: true, submitEnabled: enabled, mode: this._panelMode });
|
|
3427
3509
|
}
|
|
3510
|
+
/**
|
|
3511
|
+
* Publish the panel mode as an attribute, so CSS can act on it.
|
|
3512
|
+
*
|
|
3513
|
+
* The same reasoning `data-panel-active` is set for and the same one that took
|
|
3514
|
+
* the old `style.display` off a child: an attribute is themeable, is visible to
|
|
3515
|
+
* a consumer's own rules, and does not clobber what the consumer set. It is what
|
|
3516
|
+
* lets `'none'` remove the send button without this component reaching into it.
|
|
3517
|
+
*/
|
|
3518
|
+
_reflectPanelMode() {
|
|
3519
|
+
if (this._panelActive) this.setAttribute("data-panel-mode", this._panelMode);
|
|
3520
|
+
else this.removeAttribute("data-panel-mode");
|
|
3521
|
+
}
|
|
3428
3522
|
get panelActive() {
|
|
3429
3523
|
return this._panelActive;
|
|
3430
3524
|
}
|
|
@@ -3443,7 +3537,7 @@ class AparteComposer extends HTMLElement {
|
|
|
3443
3537
|
/** Submit the current value. Called by aparte-composer-send or programmatically. */
|
|
3444
3538
|
submit() {
|
|
3445
3539
|
if (this._panelActive) {
|
|
3446
|
-
if (this._panelSubmitEnabled) this._panelOnSubmit?.();
|
|
3540
|
+
if (this._panelMode !== "none" && this._panelSubmitEnabled) this._panelOnSubmit?.();
|
|
3447
3541
|
return;
|
|
3448
3542
|
}
|
|
3449
3543
|
if (this._streaming) {
|
|
@@ -3596,6 +3690,10 @@ class AparteComposerInput extends HTMLElement {
|
|
|
3596
3690
|
if (name === "disabled") this._updateDisabled(value !== null);
|
|
3597
3691
|
}
|
|
3598
3692
|
// ── Public API ──────────────────────────────────────────────────────────
|
|
3693
|
+
/**
|
|
3694
|
+
* The editor's text, with `<br>` serialized back to newlines — `textContent`
|
|
3695
|
+
* alone would collapse a multi-line draft onto a single line.
|
|
3696
|
+
*/
|
|
3599
3697
|
getValue() {
|
|
3600
3698
|
if (!this._editor) return "";
|
|
3601
3699
|
let out = "";
|
|
@@ -3609,6 +3707,7 @@ class AparteComposerInput extends HTMLElement {
|
|
|
3609
3707
|
walk(this._editor);
|
|
3610
3708
|
return out.trim();
|
|
3611
3709
|
}
|
|
3710
|
+
/** Replace the editor's content and mirror the value onto the parent composer. */
|
|
3612
3711
|
setValue(value) {
|
|
3613
3712
|
if (!this._editor) return;
|
|
3614
3713
|
this._editor.textContent = value;
|
|
@@ -3616,6 +3715,7 @@ class AparteComposerInput extends HTMLElement {
|
|
|
3616
3715
|
this._adjustHeight();
|
|
3617
3716
|
this._getRoot()?.setValue(value);
|
|
3618
3717
|
}
|
|
3718
|
+
/** Empty the editor and mirror the empty value onto the parent composer. */
|
|
3619
3719
|
clear() {
|
|
3620
3720
|
if (!this._editor) return;
|
|
3621
3721
|
this._editor.innerHTML = "";
|
|
@@ -3623,9 +3723,11 @@ class AparteComposerInput extends HTMLElement {
|
|
|
3623
3723
|
this._adjustHeight();
|
|
3624
3724
|
this._getRoot()?.setValue("");
|
|
3625
3725
|
}
|
|
3726
|
+
/** Focus the inner contenteditable rather than the host element. */
|
|
3626
3727
|
focus() {
|
|
3627
3728
|
this._editor?.focus();
|
|
3628
3729
|
}
|
|
3730
|
+
/** Blur the inner contenteditable rather than the host element. */
|
|
3629
3731
|
blur() {
|
|
3630
3732
|
this._editor?.blur();
|
|
3631
3733
|
}
|
|
@@ -3678,7 +3780,9 @@ class AparteComposerInput extends HTMLElement {
|
|
|
3678
3780
|
);
|
|
3679
3781
|
this._unsubscribes.push(
|
|
3680
3782
|
root._on("value-change", ({ value }) => {
|
|
3681
|
-
if (
|
|
3783
|
+
if (this.getValue() === value.trim()) return;
|
|
3784
|
+
if (value === "") this.clear();
|
|
3785
|
+
else this.setValue(value);
|
|
3682
3786
|
})
|
|
3683
3787
|
);
|
|
3684
3788
|
this._unsubscribes.push(
|
|
@@ -3814,7 +3918,7 @@ class AparteComposerSend extends HTMLElement {
|
|
|
3814
3918
|
const root = this._getRoot();
|
|
3815
3919
|
const disabled = !root || root.disabled || root.value.trim() === "";
|
|
3816
3920
|
this.innerHTML = `<button
|
|
3817
|
-
class="aparte-cs-button aparte-send-button"
|
|
3921
|
+
class="aparte-btn aparte-btn--primary aparte-btn--solid aparte-btn--icon aparte-cs-button aparte-send-button"
|
|
3818
3922
|
aria-label="${escapeAttr(label)}"
|
|
3819
3923
|
title="${escapeAttr(label)}"
|
|
3820
3924
|
${disabled ? "disabled" : ""}
|
|
@@ -3884,6 +3988,10 @@ class AparteComposerSend extends HTMLElement {
|
|
|
3884
3988
|
const panel = this._panel;
|
|
3885
3989
|
if (!this._button || !panel?.active) return;
|
|
3886
3990
|
const cfg = resolveConfig(this);
|
|
3991
|
+
if (panel.mode === "none") {
|
|
3992
|
+
this._button.disabled = true;
|
|
3993
|
+
return;
|
|
3994
|
+
}
|
|
3887
3995
|
const advancing = panel.mode === "advance";
|
|
3888
3996
|
this._button.disabled = !panel.submitEnabled;
|
|
3889
3997
|
this._button.innerHTML = advancing ? cfg.getIcon("nextBranch") : this._getSubmitIcon();
|
|
@@ -3962,7 +4070,7 @@ class AparteComposerCancel extends HTMLElement {
|
|
|
3962
4070
|
const label = resolveConfig(this).t("stopButton") || "Stop";
|
|
3963
4071
|
const icon = this._getStopIcon();
|
|
3964
4072
|
this.innerHTML = `<button
|
|
3965
|
-
class="aparte-cc-button"
|
|
4073
|
+
class="aparte-btn aparte-btn--icon aparte-cc-button"
|
|
3966
4074
|
aria-label="${escapeAttr(label)}"
|
|
3967
4075
|
title="${escapeAttr(label)}"
|
|
3968
4076
|
hidden
|
|
@@ -4005,7 +4113,6 @@ class AparteComposerCancel extends HTMLElement {
|
|
|
4005
4113
|
if (!customElements.get("aparte-composer-cancel")) {
|
|
4006
4114
|
customElements.define("aparte-composer-cancel", AparteComposerCancel);
|
|
4007
4115
|
}
|
|
4008
|
-
const REMOVE_ICON = '<svg width="10" height="10" viewBox="0 0 12 12" fill="currentColor" aria-hidden="true"><path d="M9.5 3.205 8.795 2.5 6 5.295 3.205 2.5 2.5 3.205 5.295 6 2.5 8.795l.705.705L6 6.705l2.795 2.795.705-.705L6.705 6z"/></svg>';
|
|
4009
4116
|
class AparteComposerAttachments extends HTMLElement {
|
|
4010
4117
|
_unsubscribes = [];
|
|
4011
4118
|
/** Object URLs minted for image previews — revoked on re-render/disconnect. */
|
|
@@ -4041,13 +4148,13 @@ class AparteComposerAttachments extends HTMLElement {
|
|
|
4041
4148
|
this._revokeUrls();
|
|
4042
4149
|
this.innerHTML = files.map((file) => {
|
|
4043
4150
|
const name = this._escape(file.name);
|
|
4044
|
-
const remove = `<button class="aparte-thumb__remove" type="button" aria-label="Remove ${name}">${
|
|
4151
|
+
const remove = `<button class="aparte-btn aparte-btn--icon aparte-btn--sm aparte-thumb__remove" type="button" aria-label="Remove ${name}">${resolveConfig(this).getIcon("close")}</button>`;
|
|
4045
4152
|
if (file.type.startsWith("image/")) {
|
|
4046
4153
|
const url = URL.createObjectURL(file);
|
|
4047
4154
|
this._objectUrls.push(url);
|
|
4048
|
-
return `<div class="aparte-thumb aparte-thumb--image" title="${escapeAttr(name)}"><img class="aparte-thumb__img" src="${escapeAttr(url)}" alt="${escapeAttr(name)}" /><span class="aparte-thumb__name">${name}</span>${remove}</div>`;
|
|
4155
|
+
return `<div class="aparte-thumbnail aparte-thumb aparte-thumb--image" title="${escapeAttr(name)}"><img class="aparte-thumb__img" src="${escapeAttr(url)}" alt="${escapeAttr(name)}" /><span class="aparte-thumb__name">${name}</span>${remove}</div>`;
|
|
4049
4156
|
}
|
|
4050
|
-
return `<div class="aparte-thumb aparte-thumb--file" title="${escapeAttr(name)}"><span class="aparte-thumb__ext">${this._escape(this._ext(file.name))}</span><span class="aparte-thumb__name">${name}</span>${remove}</div>`;
|
|
4157
|
+
return `<div class="aparte-thumbnail aparte-thumb aparte-thumb--file" title="${escapeAttr(name)}"><span class="aparte-thumb__ext">${this._escape(this._ext(file.name))}</span><span class="aparte-thumb__name">${name}</span>${remove}</div>`;
|
|
4051
4158
|
}).join("");
|
|
4052
4159
|
this.querySelectorAll(".aparte-thumb__remove").forEach((btn, i2) => {
|
|
4053
4160
|
btn.addEventListener("click", (e2) => {
|
|
@@ -4136,15 +4243,15 @@ class AparteComposerAddAttachment extends HTMLElement {
|
|
|
4136
4243
|
const label = cfg.t("actionUpload") || "Attach file";
|
|
4137
4244
|
this._button.setAttribute("aria-label", label);
|
|
4138
4245
|
this._button.setAttribute("title", label);
|
|
4139
|
-
this._button.innerHTML = cfg.getIcon("paperclip")
|
|
4246
|
+
this._button.innerHTML = cfg.getIcon("paperclip");
|
|
4140
4247
|
}
|
|
4141
4248
|
_render() {
|
|
4142
4249
|
if (this.querySelector(".aparte-caa-button")) return;
|
|
4143
4250
|
const label = resolveConfig(this).t("actionUpload") || "Attach file";
|
|
4144
|
-
const icon = resolveConfig(this).getIcon("paperclip")
|
|
4251
|
+
const icon = resolveConfig(this).getIcon("paperclip");
|
|
4145
4252
|
const disabled = this.hasAttribute("disabled") || this._getRoot()?.disabled || false;
|
|
4146
4253
|
this.innerHTML = `<button
|
|
4147
|
-
class="aparte-caa-button aparte-action-button"
|
|
4254
|
+
class="aparte-btn aparte-btn--icon aparte-caa-button aparte-action-button"
|
|
4148
4255
|
aria-label="${escapeAttr(label)}"
|
|
4149
4256
|
title="${escapeAttr(label)}"
|
|
4150
4257
|
type="button"
|
|
@@ -4213,9 +4320,6 @@ class AparteComposerAddAttachment extends HTMLElement {
|
|
|
4213
4320
|
root.removeEventListener("drop", onDrop);
|
|
4214
4321
|
};
|
|
4215
4322
|
}
|
|
4216
|
-
_defaultIcon() {
|
|
4217
|
-
return `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>`;
|
|
4218
|
-
}
|
|
4219
4323
|
}
|
|
4220
4324
|
if (!customElements.get("aparte-composer-add-attachment")) {
|
|
4221
4325
|
customElements.define("aparte-composer-add-attachment", AparteComposerAddAttachment);
|
|
@@ -4263,7 +4367,7 @@ class AparteComposerAction extends HTMLElement {
|
|
|
4263
4367
|
const icon = this._resolveIcon(this.getAttribute("icon") ?? "");
|
|
4264
4368
|
const disabled = this.hasAttribute("disabled") || this._getRoot()?.disabled || false;
|
|
4265
4369
|
this.innerHTML = `<button
|
|
4266
|
-
class="aparte-cact-button aparte-action-button"
|
|
4370
|
+
class="aparte-btn aparte-btn--icon aparte-cact-button aparte-action-button"
|
|
4267
4371
|
aria-label="${label}"
|
|
4268
4372
|
title="${label}"
|
|
4269
4373
|
type="button"
|
|
@@ -4298,7 +4402,6 @@ class AparteComposerAction extends HTMLElement {
|
|
|
4298
4402
|
if (icon.trimStart().startsWith("<")) return icon;
|
|
4299
4403
|
return resolveConfig(this).getIcon(icon) ?? icon;
|
|
4300
4404
|
}
|
|
4301
|
-
/** Escape a value before it lands in a double-quoted HTML attribute. */
|
|
4302
4405
|
}
|
|
4303
4406
|
if (!customElements.get("aparte-composer-action")) {
|
|
4304
4407
|
customElements.define("aparte-composer-action", AparteComposerAction);
|
|
@@ -4400,10 +4503,10 @@ class AparteConversationList extends HTMLElement {
|
|
|
4400
4503
|
const unarchiveLabel = this._esc(locale["unarchiveConversation"] ?? "Unarchive conversation");
|
|
4401
4504
|
const archiveAction = isArchived ? "unarchive" : "archive";
|
|
4402
4505
|
const archiveAriaLabel = isArchived ? unarchiveLabel : archiveLabel;
|
|
4403
|
-
const
|
|
4506
|
+
const archiveGlyph = resolveConfig(this).getIcon(isArchived ? "unarchive" : "archive");
|
|
4404
4507
|
return `
|
|
4405
4508
|
<div
|
|
4406
|
-
class="aparte-conv-item${activeClass}${archivedClass}"
|
|
4509
|
+
class="aparte-menu__item aparte-conv-item${activeClass}${archivedClass}"
|
|
4407
4510
|
role="button"
|
|
4408
4511
|
tabindex="0"
|
|
4409
4512
|
data-conv-id="${escapedId}"
|
|
@@ -4411,24 +4514,21 @@ class AparteConversationList extends HTMLElement {
|
|
|
4411
4514
|
>
|
|
4412
4515
|
<span class="aparte-conv-item__title">${escapedTitle}</span>
|
|
4413
4516
|
<button
|
|
4414
|
-
class="aparte-conv-item__archive"
|
|
4517
|
+
class="aparte-btn aparte-btn--icon aparte-btn--sm aparte-conv-item__archive"
|
|
4415
4518
|
type="button"
|
|
4416
4519
|
data-archive-id="${escapedId}"
|
|
4417
4520
|
data-archive-action="${escapeAttr(archiveAction)}"
|
|
4418
4521
|
aria-label="${escapeAttr(archiveAriaLabel)}"
|
|
4419
4522
|
tabindex="0"
|
|
4420
|
-
>${
|
|
4523
|
+
>${archiveGlyph}</button>
|
|
4421
4524
|
<button
|
|
4422
|
-
class="aparte-conv-item__delete"
|
|
4525
|
+
class="aparte-btn aparte-btn--icon aparte-btn--sm aparte-conv-item__delete"
|
|
4423
4526
|
type="button"
|
|
4424
4527
|
data-delete-id="${escapedId}"
|
|
4425
4528
|
aria-label="${deleteLabel}"
|
|
4426
4529
|
tabindex="0"
|
|
4427
4530
|
>
|
|
4428
|
-
|
|
4429
|
-
stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
4430
|
-
<path d="M18 6L6 18M6 6l12 12"/>
|
|
4431
|
-
</svg>
|
|
4531
|
+
${resolveConfig(this).getIcon("close")}
|
|
4432
4532
|
</button>
|
|
4433
4533
|
</div>`;
|
|
4434
4534
|
}
|
|
@@ -4471,11 +4571,10 @@ class AparteConversationList extends HTMLElement {
|
|
|
4471
4571
|
};
|
|
4472
4572
|
_onKeydown = (e2) => {
|
|
4473
4573
|
if (e2.key !== "Enter" && e2.key !== " ") return;
|
|
4474
|
-
const
|
|
4475
|
-
if (
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
}
|
|
4574
|
+
const target = e2.target;
|
|
4575
|
+
if (!target.matches("[data-conv-id]")) return;
|
|
4576
|
+
e2.preventDefault();
|
|
4577
|
+
target.click();
|
|
4479
4578
|
};
|
|
4480
4579
|
/** Update active class without full re-render (perf optimisation). */
|
|
4481
4580
|
_updateActiveState() {
|
|
@@ -4535,6 +4634,7 @@ export {
|
|
|
4535
4634
|
AparteElicitationAbortError,
|
|
4536
4635
|
q as AparteError,
|
|
4537
4636
|
r as AparteErrorCode,
|
|
4637
|
+
AparteIcon,
|
|
4538
4638
|
AparteMessageRepository,
|
|
4539
4639
|
AparteOptgroup,
|
|
4540
4640
|
AparteOption,
|