@artooi/ag-ui-web-component 0.31.1 → 0.33.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/CHANGELOG.md +197 -1
- package/README.md +182 -23
- package/dist/ag-ui-web-component.bundle.js +352 -128
- package/dist/ag-ui-web-component.bundle.js.map +4 -4
- package/dist/constants.d.ts +34 -7
- package/dist/constants.d.ts.map +1 -1
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/core/agui_client.d.ts +25 -0
- package/dist/core/agui_client.d.ts.map +1 -1
- package/dist/index.js +1367 -388
- package/dist/index.js.map +4 -4
- package/dist/ui/clamp_launcher.d.ts +15 -0
- package/dist/ui/clamp_launcher.d.ts.map +1 -0
- package/dist/ui/copy_payload.d.ts +30 -0
- package/dist/ui/copy_payload.d.ts.map +1 -0
- package/dist/ui/launcher_drag.d.ts +43 -0
- package/dist/ui/launcher_drag.d.ts.map +1 -0
- package/dist/ui/launcher_placement.d.ts +64 -0
- package/dist/ui/launcher_placement.d.ts.map +1 -0
- package/dist/ui/message_actions.d.ts +30 -2
- package/dist/ui/message_actions.d.ts.map +1 -1
- package/dist/ui/resize_handle.d.ts +32 -26
- package/dist/ui/resize_handle.d.ts.map +1 -1
- package/dist/ui/styles.d.ts +1 -1
- package/dist/ui/styles.d.ts.map +1 -1
- package/dist/ui/subagent_panel.d.ts +9 -0
- package/dist/ui/subagent_panel.d.ts.map +1 -1
- package/dist/ui/subagent_update.d.ts +9 -0
- package/dist/ui/subagent_update.d.ts.map +1 -1
- package/dist/ui/ui_strings.d.ts +19 -0
- package/dist/ui/ui_strings.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/constants.ts +38 -7
- package/src/core/ag_ui_chat.ts +570 -24
- package/src/core/agui_client.ts +41 -0
- package/src/ui/clamp_launcher.ts +20 -0
- package/src/ui/copy_payload.ts +156 -0
- package/src/ui/launcher_drag.ts +182 -0
- package/src/ui/launcher_placement.ts +143 -0
- package/src/ui/message_actions.ts +93 -19
- package/src/ui/resize_handle.ts +109 -73
- package/src/ui/styles.ts +283 -81
- package/src/ui/subagent_panel.ts +14 -0
- package/src/ui/subagent_update.ts +9 -0
- package/src/ui/ui_strings.ts +22 -0
- package/src/version.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -60,6 +60,10 @@ var ICON_STOP = `<svg class="glyph glyph--solid" viewBox="0 0 24 24" aria-hidden
|
|
|
60
60
|
var ICON_ATTACH = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M17 8.5V15a5 5 0 0 1-10 0V7a3 3 0 0 1 6 0v7.5a1 1 0 0 1-2 0V8.5"/></svg>`;
|
|
61
61
|
var ICON_VOICE = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 4a3 3 0 0 1 3 3v5a3 3 0 0 1-6 0V7a3 3 0 0 1 3-3z"/><path d="M5 11v1a7 7 0 0 0 14 0v-1"/><path d="M12 19v3"/></svg>`;
|
|
62
62
|
var ICON_LAUNCHER = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 5.5A2.5 2.5 0 0 1 6.5 3h11A2.5 2.5 0 0 1 20 5.5v8a2.5 2.5 0 0 1-2.5 2.5H9l-5 4z"/></svg>`;
|
|
63
|
+
var ICON_COPY = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V6a2 2 0 0 1 2-2h8"/></svg>`;
|
|
64
|
+
var ICON_RETRY = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 12a8 8 0 1 1-2.5-5.8"/><path d="M20 4v4h-4"/></svg>`;
|
|
65
|
+
var ICON_THUMB_UP = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M7 10v10H4V10z"/><path d="M7 10l4.5-7a2 2 0 0 1 3.4 2L13.5 9H19a2 2 0 0 1 2 2.3l-1.1 6.4A2 2 0 0 1 17.9 20H7"/></svg>`;
|
|
66
|
+
var ICON_THUMB_DOWN = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M17 14V4h3v10z"/><path d="M17 14l-4.5 7a2 2 0 0 1-3.4-2l1.4-4H5a2 2 0 0 1-2-2.3l1.1-6.4A2 2 0 0 1 6.1 4H17"/></svg>`;
|
|
63
67
|
var ICON_FILE = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/></svg>`;
|
|
64
68
|
var ICON_FILE_IMAGE = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="4.5" width="17" height="15" rx="2.5"/><circle cx="9" cy="10" r="1.5"/><path d="M4.5 17.5 9 13.5l3.5 3 3-2.5 4.5 4"/></svg>`;
|
|
65
69
|
var ICON_FILE_PDF = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/><rect class="glyph--solid" x="7.5" y="13.5" width="9" height="4.5" rx="1"/></svg>`;
|
|
@@ -74,7 +78,7 @@ import { randomUUID as randomUUID5 } from "@ag-ui/client";
|
|
|
74
78
|
var PLACEHOLDER_RE = /\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g;
|
|
75
79
|
function fillTemplate(template, values) {
|
|
76
80
|
const missing = [];
|
|
77
|
-
const
|
|
81
|
+
const text4 = template.replace(PLACEHOLDER_RE, (token, key) => {
|
|
78
82
|
const value = values[key];
|
|
79
83
|
if (value === void 0 || value === null || value === "") {
|
|
80
84
|
if (!missing.includes(key)) {
|
|
@@ -84,7 +88,7 @@ function fillTemplate(template, values) {
|
|
|
84
88
|
}
|
|
85
89
|
return String(value);
|
|
86
90
|
});
|
|
87
|
-
return { text:
|
|
91
|
+
return { text: text4, missing };
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
// src/skills/parse_skills.ts
|
|
@@ -433,8 +437,8 @@ function createPageStateTools(binding) {
|
|
|
433
437
|
handler: () => binding.read()
|
|
434
438
|
}
|
|
435
439
|
];
|
|
436
|
-
const
|
|
437
|
-
if (
|
|
440
|
+
const write2 = binding.write;
|
|
441
|
+
if (write2 !== void 0) {
|
|
438
442
|
tools.push({
|
|
439
443
|
name: `set_${binding.name}`,
|
|
440
444
|
description: `Update the "${binding.name}" state.`,
|
|
@@ -443,7 +447,7 @@ function createPageStateTools(binding) {
|
|
|
443
447
|
[X_DESTRUCTIVE_KEY]: true,
|
|
444
448
|
[X_SUMMARY_KEY]: `Update ${binding.name}`
|
|
445
449
|
},
|
|
446
|
-
handler: (args) =>
|
|
450
|
+
handler: (args) => write2(args)
|
|
447
451
|
});
|
|
448
452
|
}
|
|
449
453
|
return tools;
|
|
@@ -601,6 +605,9 @@ var DEFAULT_UI_STRINGS = {
|
|
|
601
605
|
declinedLabel: "Declined",
|
|
602
606
|
details: "Details",
|
|
603
607
|
subAgentWorking: "Working\u2026",
|
|
608
|
+
subAgentDelegatedTo: "Delegated to {agent}",
|
|
609
|
+
subAgentFinished: "{agent} finished",
|
|
610
|
+
subAgentFailed: "The sub-agent failed",
|
|
604
611
|
subAgentSteps: "Steps the sub-agent took",
|
|
605
612
|
approvalEditArgs: "Edit the arguments before approving",
|
|
606
613
|
approvalArgsInvalid: "That is not valid JSON, so nothing was sent.",
|
|
@@ -777,7 +784,7 @@ function attachCopyButtons(root, strings) {
|
|
|
777
784
|
}
|
|
778
785
|
}
|
|
779
786
|
function button(code, strings) {
|
|
780
|
-
const
|
|
787
|
+
const text4 = code.textContent;
|
|
781
788
|
const copy = document.createElement("button");
|
|
782
789
|
copy.type = "button";
|
|
783
790
|
copy.className = "code-copy";
|
|
@@ -786,19 +793,19 @@ function button(code, strings) {
|
|
|
786
793
|
copy.title = strings.copyCode;
|
|
787
794
|
copy.setAttribute("aria-label", strings.copyCode);
|
|
788
795
|
copy.addEventListener("click", () => {
|
|
789
|
-
void writeText(
|
|
796
|
+
void writeText(text4).then((ok) => {
|
|
790
797
|
confirm(copy, ok ? strings.copied : strings.copyFailed, strings);
|
|
791
798
|
});
|
|
792
799
|
});
|
|
793
800
|
return copy;
|
|
794
801
|
}
|
|
795
|
-
async function writeText(
|
|
802
|
+
async function writeText(text4) {
|
|
796
803
|
const clipboard = navigator.clipboard;
|
|
797
804
|
if (clipboard === void 0) {
|
|
798
805
|
return false;
|
|
799
806
|
}
|
|
800
807
|
try {
|
|
801
|
-
await clipboard.writeText(
|
|
808
|
+
await clipboard.writeText(text4);
|
|
802
809
|
return true;
|
|
803
810
|
} catch {
|
|
804
811
|
return false;
|
|
@@ -1692,6 +1699,14 @@ var CheckpointMenu = class {
|
|
|
1692
1699
|
}
|
|
1693
1700
|
};
|
|
1694
1701
|
|
|
1702
|
+
// src/ui/clamp_launcher.ts
|
|
1703
|
+
function clampLauncher(launcher, viewport) {
|
|
1704
|
+
return {
|
|
1705
|
+
left: Math.max(0, Math.min(launcher.left, viewport.width - launcher.width)),
|
|
1706
|
+
top: Math.max(0, Math.min(launcher.top, viewport.height - launcher.height))
|
|
1707
|
+
};
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1695
1710
|
// src/ui/confirmation_card.ts
|
|
1696
1711
|
function actionButton2(modifier, label) {
|
|
1697
1712
|
const button2 = document.createElement("button");
|
|
@@ -1752,6 +1767,245 @@ function requestConfirmation(host, request, options = {}) {
|
|
|
1752
1767
|
});
|
|
1753
1768
|
}
|
|
1754
1769
|
|
|
1770
|
+
// src/ui/copy_payload.ts
|
|
1771
|
+
var BLOCK_TAGS = /* @__PURE__ */ new Set([
|
|
1772
|
+
"ADDRESS",
|
|
1773
|
+
"ARTICLE",
|
|
1774
|
+
"ASIDE",
|
|
1775
|
+
"BLOCKQUOTE",
|
|
1776
|
+
"DD",
|
|
1777
|
+
"DIV",
|
|
1778
|
+
"DL",
|
|
1779
|
+
"DT",
|
|
1780
|
+
"FIGCAPTION",
|
|
1781
|
+
"FIGURE",
|
|
1782
|
+
"FOOTER",
|
|
1783
|
+
"H1",
|
|
1784
|
+
"H2",
|
|
1785
|
+
"H3",
|
|
1786
|
+
"H4",
|
|
1787
|
+
"H5",
|
|
1788
|
+
"H6",
|
|
1789
|
+
"HEADER",
|
|
1790
|
+
"HR",
|
|
1791
|
+
"MAIN",
|
|
1792
|
+
"NAV",
|
|
1793
|
+
"OL",
|
|
1794
|
+
"P",
|
|
1795
|
+
"SECTION",
|
|
1796
|
+
"UL"
|
|
1797
|
+
]);
|
|
1798
|
+
function copyPayload(root) {
|
|
1799
|
+
const clone2 = root.cloneNode(true);
|
|
1800
|
+
for (const control of Array.from(clone2.querySelectorAll("button"))) {
|
|
1801
|
+
control.remove();
|
|
1802
|
+
}
|
|
1803
|
+
return { text: normalise(serialise(clone2)), html: clone2.innerHTML };
|
|
1804
|
+
}
|
|
1805
|
+
function serialise(node) {
|
|
1806
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
1807
|
+
return node.nodeValue.replace(/\s+/g, " ");
|
|
1808
|
+
}
|
|
1809
|
+
if (node.nodeType !== Node.ELEMENT_NODE) {
|
|
1810
|
+
return "";
|
|
1811
|
+
}
|
|
1812
|
+
const element = node;
|
|
1813
|
+
const tag = element.tagName;
|
|
1814
|
+
if (tag === "BR") {
|
|
1815
|
+
return "\n";
|
|
1816
|
+
}
|
|
1817
|
+
if (tag === "PRE") {
|
|
1818
|
+
return `
|
|
1819
|
+
|
|
1820
|
+
${text2(element)}
|
|
1821
|
+
|
|
1822
|
+
`;
|
|
1823
|
+
}
|
|
1824
|
+
if (tag === "TABLE") {
|
|
1825
|
+
return `
|
|
1826
|
+
|
|
1827
|
+
${tableText(element)}
|
|
1828
|
+
|
|
1829
|
+
`;
|
|
1830
|
+
}
|
|
1831
|
+
if (tag === "UL" || tag === "OL") {
|
|
1832
|
+
return `
|
|
1833
|
+
|
|
1834
|
+
${listText(element, tag === "OL")}
|
|
1835
|
+
|
|
1836
|
+
`;
|
|
1837
|
+
}
|
|
1838
|
+
const inner = children(element);
|
|
1839
|
+
return BLOCK_TAGS.has(tag) ? `
|
|
1840
|
+
|
|
1841
|
+
${inner}
|
|
1842
|
+
|
|
1843
|
+
` : inner;
|
|
1844
|
+
}
|
|
1845
|
+
function children(element) {
|
|
1846
|
+
let joined = "";
|
|
1847
|
+
for (const child of Array.from(element.childNodes)) {
|
|
1848
|
+
joined += serialise(child);
|
|
1849
|
+
}
|
|
1850
|
+
return joined;
|
|
1851
|
+
}
|
|
1852
|
+
function listText(list, numbered) {
|
|
1853
|
+
return Array.from(list.children).map((item, index) => `${numbered ? `${index + 1}. ` : "- "}${children(item).trim()}`).join("\n");
|
|
1854
|
+
}
|
|
1855
|
+
function tableText(table) {
|
|
1856
|
+
return Array.from(table.querySelectorAll("tr")).map(
|
|
1857
|
+
(row) => Array.from(row.children).map((cell) => text2(cell).replace(/\s+/g, " ").trim()).join(" ")
|
|
1858
|
+
).join("\n");
|
|
1859
|
+
}
|
|
1860
|
+
function text2(element) {
|
|
1861
|
+
return element.textContent;
|
|
1862
|
+
}
|
|
1863
|
+
function normalise(text4) {
|
|
1864
|
+
return text4.replace(/[^\S\n]+\n/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
// src/ui/launcher_drag.ts
|
|
1868
|
+
var DRAG_THRESHOLD = 4;
|
|
1869
|
+
var STEP = 16;
|
|
1870
|
+
var COARSE_STEP = 64;
|
|
1871
|
+
function enableLauncherDrag(launcher, options) {
|
|
1872
|
+
let suppressClick = false;
|
|
1873
|
+
launcher.addEventListener(
|
|
1874
|
+
"click",
|
|
1875
|
+
(event) => {
|
|
1876
|
+
if (!suppressClick || event.detail === 0) {
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
suppressClick = false;
|
|
1880
|
+
event.stopPropagation();
|
|
1881
|
+
event.preventDefault();
|
|
1882
|
+
},
|
|
1883
|
+
true
|
|
1884
|
+
);
|
|
1885
|
+
launcher.addEventListener("pointerdown", (event) => {
|
|
1886
|
+
suppressClick = false;
|
|
1887
|
+
if (!options.enabled()) {
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
const start = options.rect();
|
|
1891
|
+
const originX = event.clientX;
|
|
1892
|
+
const originY = event.clientY;
|
|
1893
|
+
let dragging = false;
|
|
1894
|
+
const onMove = (move) => {
|
|
1895
|
+
const dx = move.clientX - originX;
|
|
1896
|
+
const dy = move.clientY - originY;
|
|
1897
|
+
if (!dragging && Math.hypot(dx, dy) < DRAG_THRESHOLD) {
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1900
|
+
dragging = true;
|
|
1901
|
+
launcher.setAttribute("data-dragging", "true");
|
|
1902
|
+
const next = clampLauncher(
|
|
1903
|
+
{ ...start, left: start.left + dx, top: start.top + dy },
|
|
1904
|
+
options.viewport()
|
|
1905
|
+
);
|
|
1906
|
+
options.apply(next.left, next.top);
|
|
1907
|
+
};
|
|
1908
|
+
const onUp = (up) => {
|
|
1909
|
+
window.removeEventListener("pointermove", onMove);
|
|
1910
|
+
window.removeEventListener("pointerup", onUp);
|
|
1911
|
+
if (!dragging) {
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
launcher.removeAttribute("data-dragging");
|
|
1915
|
+
suppressClick = true;
|
|
1916
|
+
const next = clampLauncher(
|
|
1917
|
+
{
|
|
1918
|
+
...start,
|
|
1919
|
+
left: start.left + (up.clientX - originX),
|
|
1920
|
+
top: start.top + (up.clientY - originY)
|
|
1921
|
+
},
|
|
1922
|
+
options.viewport()
|
|
1923
|
+
);
|
|
1924
|
+
options.commit(next.left, next.top);
|
|
1925
|
+
};
|
|
1926
|
+
window.addEventListener("pointermove", onMove);
|
|
1927
|
+
window.addEventListener("pointerup", onUp);
|
|
1928
|
+
});
|
|
1929
|
+
let pending = null;
|
|
1930
|
+
const settle = () => {
|
|
1931
|
+
if (pending === null) {
|
|
1932
|
+
return;
|
|
1933
|
+
}
|
|
1934
|
+
const { left, top } = pending;
|
|
1935
|
+
pending = null;
|
|
1936
|
+
options.commit(left, top);
|
|
1937
|
+
};
|
|
1938
|
+
launcher.addEventListener("keydown", (event) => {
|
|
1939
|
+
if (!options.enabled()) {
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
const step = event.shiftKey ? COARSE_STEP : STEP;
|
|
1943
|
+
const rect = options.rect();
|
|
1944
|
+
let moved = null;
|
|
1945
|
+
if (event.key === "ArrowLeft") {
|
|
1946
|
+
moved = { left: rect.left - step, top: rect.top };
|
|
1947
|
+
} else if (event.key === "ArrowRight") {
|
|
1948
|
+
moved = { left: rect.left + step, top: rect.top };
|
|
1949
|
+
} else if (event.key === "ArrowUp") {
|
|
1950
|
+
moved = { left: rect.left, top: rect.top - step };
|
|
1951
|
+
} else if (event.key === "ArrowDown") {
|
|
1952
|
+
moved = { left: rect.left, top: rect.top + step };
|
|
1953
|
+
}
|
|
1954
|
+
if (moved === null) {
|
|
1955
|
+
return;
|
|
1956
|
+
}
|
|
1957
|
+
event.preventDefault();
|
|
1958
|
+
const next = clampLauncher({ ...rect, ...moved }, options.viewport());
|
|
1959
|
+
options.apply(next.left, next.top);
|
|
1960
|
+
pending = next;
|
|
1961
|
+
});
|
|
1962
|
+
launcher.addEventListener("keyup", settle);
|
|
1963
|
+
launcher.addEventListener("blur", settle);
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
// src/ui/launcher_placement.ts
|
|
1967
|
+
var EDGE_MARGIN = 24;
|
|
1968
|
+
function launcherPlacement(launcher, panel, viewport, margin = EDGE_MARGIN) {
|
|
1969
|
+
const roomRunningRight = viewport.width - launcher.left;
|
|
1970
|
+
const roomRunningLeft = launcher.left + launcher.width;
|
|
1971
|
+
const roomRunningDown = viewport.height - launcher.top;
|
|
1972
|
+
const roomRunningUp = launcher.top + launcher.height;
|
|
1973
|
+
const corner = {
|
|
1974
|
+
x: roomRunningRight >= roomRunningLeft ? "left" : "right",
|
|
1975
|
+
y: roomRunningDown >= roomRunningUp ? "top" : "bottom"
|
|
1976
|
+
};
|
|
1977
|
+
const wantedLeft = corner.x === "left" ? launcher.left : launcher.left + launcher.width - panel.width;
|
|
1978
|
+
const wantedTop = corner.y === "top" ? launcher.top : launcher.top + launcher.height - panel.height;
|
|
1979
|
+
const hostLeft = clamp(wantedLeft, margin, viewport.width - margin - panel.width);
|
|
1980
|
+
const hostTop = clamp(wantedTop, margin, viewport.height - margin - panel.height);
|
|
1981
|
+
const hostRight = hostLeft + panel.width;
|
|
1982
|
+
const hostBottom = hostTop + panel.height;
|
|
1983
|
+
return {
|
|
1984
|
+
corner,
|
|
1985
|
+
hostInset: inset({
|
|
1986
|
+
top: corner.y === "top" ? hostTop : null,
|
|
1987
|
+
right: corner.x === "right" ? viewport.width - hostRight : null,
|
|
1988
|
+
bottom: corner.y === "bottom" ? viewport.height - hostBottom : null,
|
|
1989
|
+
left: corner.x === "left" ? hostLeft : null
|
|
1990
|
+
}),
|
|
1991
|
+
// Measured from the host box's pinned corner to the launcher's matching
|
|
1992
|
+
// corner, so the launcher lands exactly where it was dropped.
|
|
1993
|
+
launcherInset: inset({
|
|
1994
|
+
top: corner.y === "top" ? launcher.top - hostTop : null,
|
|
1995
|
+
right: corner.x === "right" ? hostRight - (launcher.left + launcher.width) : null,
|
|
1996
|
+
bottom: corner.y === "bottom" ? hostBottom - (launcher.top + launcher.height) : null,
|
|
1997
|
+
left: corner.x === "left" ? launcher.left - hostLeft : null
|
|
1998
|
+
})
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
2001
|
+
function clamp(value, low, high) {
|
|
2002
|
+
return Math.max(low, Math.min(value, high));
|
|
2003
|
+
}
|
|
2004
|
+
function inset(sides) {
|
|
2005
|
+
const side = (value) => value === null ? "auto" : `${Math.round(value)}px`;
|
|
2006
|
+
return `${side(sides.top)} ${side(sides.right)} ${side(sides.bottom)} ${side(sides.left)}`;
|
|
2007
|
+
}
|
|
2008
|
+
|
|
1755
2009
|
// src/ui/message_actions.ts
|
|
1756
2010
|
var CONFIRM_MS2 = 1500;
|
|
1757
2011
|
function attachMessageActions(bubble, options) {
|
|
@@ -1759,9 +2013,9 @@ function attachMessageActions(bubble, options) {
|
|
|
1759
2013
|
return;
|
|
1760
2014
|
}
|
|
1761
2015
|
const bar = messageActionBar(bubble, options.strings);
|
|
1762
|
-
const
|
|
1763
|
-
if (
|
|
1764
|
-
bar.appendChild(copyButton(options.strings,
|
|
2016
|
+
const text4 = options.text;
|
|
2017
|
+
if (text4 !== void 0) {
|
|
2018
|
+
bar.appendChild(copyButton(options.strings, text4, options.html));
|
|
1765
2019
|
}
|
|
1766
2020
|
if (options.onFeedback !== void 0) {
|
|
1767
2021
|
bar.append(
|
|
@@ -1787,36 +2041,63 @@ function existingBar(bubble) {
|
|
|
1787
2041
|
const next = bubble.nextElementSibling;
|
|
1788
2042
|
return next?.classList.contains("message-actions") === true ? next : null;
|
|
1789
2043
|
}
|
|
1790
|
-
function messageActionButton(modifier, label,
|
|
2044
|
+
function messageActionButton(modifier, label, icon) {
|
|
1791
2045
|
const button2 = document.createElement("button");
|
|
1792
2046
|
button2.type = "button";
|
|
1793
2047
|
button2.className = `message-action message-action--${modifier}`;
|
|
1794
2048
|
button2.setAttribute("part", `message-action message-action-${modifier}`);
|
|
2049
|
+
setLabel(button2, label);
|
|
2050
|
+
const holder = document.createElement("span");
|
|
2051
|
+
holder.className = "message-action-icon";
|
|
2052
|
+
holder.setAttribute("part", `message-action-icon message-action-icon-${modifier}`);
|
|
2053
|
+
holder.setAttribute("aria-hidden", "true");
|
|
2054
|
+
holder.innerHTML = icon;
|
|
2055
|
+
button2.appendChild(holder);
|
|
2056
|
+
return button2;
|
|
2057
|
+
}
|
|
2058
|
+
function setLabel(button2, label) {
|
|
1795
2059
|
button2.title = label;
|
|
1796
2060
|
button2.setAttribute("aria-label", label);
|
|
1797
|
-
|
|
1798
|
-
icon.setAttribute("aria-hidden", "true");
|
|
1799
|
-
icon.textContent = glyph;
|
|
1800
|
-
button2.appendChild(icon);
|
|
1801
|
-
return button2;
|
|
2061
|
+
button2.dataset["tooltip"] = label;
|
|
1802
2062
|
}
|
|
1803
|
-
function copyButton(strings,
|
|
1804
|
-
const button2 = messageActionButton("copy", strings.copyMessage,
|
|
2063
|
+
function copyButton(strings, text4, html2) {
|
|
2064
|
+
const button2 = messageActionButton("copy", strings.copyMessage, ICON_COPY);
|
|
1805
2065
|
button2.addEventListener("click", () => {
|
|
1806
|
-
void
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
// say so on the button rather than throwing into an unhandled rejection.
|
|
1810
|
-
() => flash2(button2, strings.copyFailed, strings.copyMessage)
|
|
1811
|
-
);
|
|
2066
|
+
void write(text4(), html2?.()).then((ok) => {
|
|
2067
|
+
flash2(button2, ok ? strings.copied : strings.copyFailed, strings.copyMessage);
|
|
2068
|
+
});
|
|
1812
2069
|
});
|
|
1813
2070
|
return button2;
|
|
1814
2071
|
}
|
|
2072
|
+
async function write(text4, html2) {
|
|
2073
|
+
const clipboard = navigator.clipboard;
|
|
2074
|
+
if (clipboard === void 0) {
|
|
2075
|
+
return false;
|
|
2076
|
+
}
|
|
2077
|
+
if (html2 !== void 0 && typeof ClipboardItem === "function") {
|
|
2078
|
+
try {
|
|
2079
|
+
await clipboard.write([
|
|
2080
|
+
new ClipboardItem({
|
|
2081
|
+
"text/plain": new Blob([text4], { type: "text/plain" }),
|
|
2082
|
+
"text/html": new Blob([html2], { type: "text/html" })
|
|
2083
|
+
})
|
|
2084
|
+
]);
|
|
2085
|
+
return true;
|
|
2086
|
+
} catch {
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
try {
|
|
2090
|
+
await clipboard.writeText(text4);
|
|
2091
|
+
return true;
|
|
2092
|
+
} catch {
|
|
2093
|
+
return false;
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
1815
2096
|
function feedbackButton(rating, label, report) {
|
|
1816
2097
|
const button2 = messageActionButton(
|
|
1817
2098
|
rating === "up" ? "up" : "down",
|
|
1818
2099
|
label,
|
|
1819
|
-
rating === "up" ?
|
|
2100
|
+
rating === "up" ? ICON_THUMB_UP : ICON_THUMB_DOWN
|
|
1820
2101
|
);
|
|
1821
2102
|
button2.addEventListener("click", () => {
|
|
1822
2103
|
const pressed = button2.getAttribute("aria-pressed") === "true";
|
|
@@ -1827,12 +2108,10 @@ function feedbackButton(rating, label, report) {
|
|
|
1827
2108
|
return button2;
|
|
1828
2109
|
}
|
|
1829
2110
|
function flash2(button2, message, label) {
|
|
1830
|
-
button2
|
|
1831
|
-
button2.setAttribute("aria-label", message);
|
|
2111
|
+
setLabel(button2, message);
|
|
1832
2112
|
button2.classList.add("message-action--confirmed");
|
|
1833
2113
|
setTimeout(() => {
|
|
1834
|
-
button2
|
|
1835
|
-
button2.setAttribute("aria-label", label);
|
|
2114
|
+
setLabel(button2, label);
|
|
1836
2115
|
button2.classList.remove("message-action--confirmed");
|
|
1837
2116
|
}, CONFIRM_MS2);
|
|
1838
2117
|
}
|
|
@@ -1850,16 +2129,16 @@ function quotableSelection(container, roots = [], near) {
|
|
|
1850
2129
|
const range = document.createRange();
|
|
1851
2130
|
range.setStart(endpoints.startContainer, endpoints.startOffset);
|
|
1852
2131
|
range.setEnd(endpoints.endContainer, endpoints.endOffset);
|
|
1853
|
-
const
|
|
1854
|
-
if (
|
|
2132
|
+
const text4 = renderedText(range).trim();
|
|
2133
|
+
if (text4 === "") {
|
|
1855
2134
|
continue;
|
|
1856
2135
|
}
|
|
1857
|
-
return { text:
|
|
2136
|
+
return { text: text4, rect: lineToHangFrom(range, near) };
|
|
1858
2137
|
}
|
|
1859
2138
|
return null;
|
|
1860
2139
|
}
|
|
1861
|
-
function asQuote(
|
|
1862
|
-
const lines = tidy(
|
|
2140
|
+
function asQuote(text4) {
|
|
2141
|
+
const lines = tidy(text4);
|
|
1863
2142
|
if (lines.length === 0) {
|
|
1864
2143
|
return "";
|
|
1865
2144
|
}
|
|
@@ -1869,8 +2148,8 @@ function asQuote(text3) {
|
|
|
1869
2148
|
|
|
1870
2149
|
`;
|
|
1871
2150
|
}
|
|
1872
|
-
function tidy(
|
|
1873
|
-
const lines =
|
|
2151
|
+
function tidy(text4) {
|
|
2152
|
+
const lines = text4.split(/\r\n?|\n/).map((line) => line.trimEnd());
|
|
1874
2153
|
const indents = lines.filter((line) => line !== "").map(indentOf);
|
|
1875
2154
|
const shared = indents.length === 0 ? 0 : Math.min(...indents);
|
|
1876
2155
|
const kept = [];
|
|
@@ -1889,11 +2168,11 @@ function tidy(text3) {
|
|
|
1889
2168
|
function indentOf(line) {
|
|
1890
2169
|
return line.length - line.trimStart().length;
|
|
1891
2170
|
}
|
|
1892
|
-
function cap(
|
|
1893
|
-
return
|
|
2171
|
+
function cap(text4) {
|
|
2172
|
+
return text4.length > MAX_QUOTE_CHARS ? `${text4.slice(0, MAX_QUOTE_CHARS).trimEnd()}...` : text4;
|
|
1894
2173
|
}
|
|
1895
2174
|
function renderedText(range) {
|
|
1896
|
-
let
|
|
2175
|
+
let text4 = "";
|
|
1897
2176
|
for (const node of textNodesIn(range)) {
|
|
1898
2177
|
const parent = node.parentElement;
|
|
1899
2178
|
if (!isRendered(parent)) {
|
|
@@ -1901,15 +2180,15 @@ function renderedText(range) {
|
|
|
1901
2180
|
}
|
|
1902
2181
|
const from = node === range.startContainer ? range.startOffset : 0;
|
|
1903
2182
|
const to = node === range.endContainer ? range.endOffset : node.data.length;
|
|
1904
|
-
|
|
2183
|
+
text4 += collapse(node.data.slice(from, to), parent);
|
|
1905
2184
|
}
|
|
1906
|
-
return
|
|
2185
|
+
return text4;
|
|
1907
2186
|
}
|
|
1908
|
-
function collapse(
|
|
2187
|
+
function collapse(text4, parent) {
|
|
1909
2188
|
if (PREFORMATTED.has(whiteSpaceOf(parent))) {
|
|
1910
|
-
return
|
|
2189
|
+
return text4;
|
|
1911
2190
|
}
|
|
1912
|
-
return
|
|
2191
|
+
return text4.replace(/[^\S\n]*\n[^\S\n]*/g, "\n").replace(/[^\S\n]+/g, " ");
|
|
1913
2192
|
}
|
|
1914
2193
|
var PREFORMATTED = /* @__PURE__ */ new Set(["pre", "pre-wrap", "break-spaces"]);
|
|
1915
2194
|
function whiteSpaceOf(element) {
|
|
@@ -2059,10 +2338,10 @@ function attachQuoteOffer(options) {
|
|
|
2059
2338
|
event.preventDefault();
|
|
2060
2339
|
});
|
|
2061
2340
|
button2.addEventListener("click", () => {
|
|
2062
|
-
const
|
|
2341
|
+
const text4 = quoting;
|
|
2063
2342
|
window.getSelection()?.removeAllRanges();
|
|
2064
2343
|
hide();
|
|
2065
|
-
onQuote(
|
|
2344
|
+
onQuote(text4);
|
|
2066
2345
|
});
|
|
2067
2346
|
return {
|
|
2068
2347
|
element: button2,
|
|
@@ -2142,10 +2421,10 @@ function requestQuestion(host, request, options = {}) {
|
|
|
2142
2421
|
radio.name = group;
|
|
2143
2422
|
radio.value = choice;
|
|
2144
2423
|
radio.setAttribute("part", "question-radio");
|
|
2145
|
-
const
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
label.append(radio,
|
|
2424
|
+
const text4 = document.createElement("span");
|
|
2425
|
+
text4.setAttribute("part", "question-choice-text");
|
|
2426
|
+
text4.textContent = choice;
|
|
2427
|
+
label.append(radio, text4);
|
|
2149
2428
|
form.appendChild(label);
|
|
2150
2429
|
radios.push(radio);
|
|
2151
2430
|
}
|
|
@@ -2162,10 +2441,10 @@ function requestQuestion(host, request, options = {}) {
|
|
|
2162
2441
|
otherRadio.name = group;
|
|
2163
2442
|
otherRadio.value = "";
|
|
2164
2443
|
otherRadio.setAttribute("part", "question-radio");
|
|
2165
|
-
const
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
label.append(otherRadio,
|
|
2444
|
+
const text4 = document.createElement("span");
|
|
2445
|
+
text4.setAttribute("part", "question-choice-text");
|
|
2446
|
+
text4.textContent = strings.otherOption;
|
|
2447
|
+
label.append(otherRadio, text4);
|
|
2169
2448
|
form.appendChild(label);
|
|
2170
2449
|
input.disabled = true;
|
|
2171
2450
|
}
|
|
@@ -2247,7 +2526,7 @@ function requestQuestion(host, request, options = {}) {
|
|
|
2247
2526
|
});
|
|
2248
2527
|
}
|
|
2249
2528
|
|
|
2250
|
-
// node_modules/.pnpm/dompurify@3.4.
|
|
2529
|
+
// node_modules/.pnpm/dompurify@3.4.14/node_modules/dompurify/dist/purify.es.mjs
|
|
2251
2530
|
function _arrayLikeToArray(r, a) {
|
|
2252
2531
|
(null == a || a > r.length) && (a = r.length);
|
|
2253
2532
|
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
|
|
@@ -2486,9 +2765,9 @@ var svgFilters = freeze(["feBlend", "feColorMatrix", "feComponentTransfer", "feC
|
|
|
2486
2765
|
var svgDisallowed = freeze(["animate", "color-profile", "cursor", "discard", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "foreignobject", "hatch", "hatchpath", "mesh", "meshgradient", "meshpatch", "meshrow", "missing-glyph", "script", "set", "solidcolor", "unknown", "use"]);
|
|
2487
2766
|
var mathMl$1 = freeze(["math", "menclose", "merror", "mfenced", "mfrac", "mglyph", "mi", "mlabeledtr", "mmultiscripts", "mn", "mo", "mover", "mpadded", "mphantom", "mroot", "mrow", "ms", "mspace", "msqrt", "mstyle", "msub", "msup", "msubsup", "mtable", "mtd", "mtext", "mtr", "munder", "munderover", "mprescripts"]);
|
|
2488
2767
|
var mathMlDisallowed = freeze(["maction", "maligngroup", "malignmark", "mlongdiv", "mscarries", "mscarry", "msgroup", "mstack", "msline", "msrow", "semantics", "annotation", "annotation-xml", "mprescripts", "none"]);
|
|
2489
|
-
var
|
|
2768
|
+
var text3 = freeze(["#text"]);
|
|
2490
2769
|
var html = freeze(["accept", "action", "align", "alt", "autocapitalize", "autocomplete", "autopictureinpicture", "autoplay", "background", "bgcolor", "border", "capture", "cellpadding", "cellspacing", "checked", "cite", "class", "clear", "color", "cols", "colspan", "command", "commandfor", "controls", "controlslist", "coords", "crossorigin", "datetime", "decoding", "default", "dir", "disabled", "disablepictureinpicture", "disableremoteplayback", "download", "draggable", "enctype", "enterkeyhint", "exportparts", "face", "for", "headers", "height", "hidden", "high", "href", "hreflang", "id", "inert", "inputmode", "integrity", "ismap", "kind", "label", "lang", "list", "loading", "loop", "low", "max", "maxlength", "media", "method", "min", "minlength", "multiple", "muted", "name", "nonce", "noshade", "novalidate", "nowrap", "open", "optimum", "part", "pattern", "placeholder", "playsinline", "popover", "popovertarget", "popovertargetaction", "poster", "preload", "pubdate", "radiogroup", "readonly", "rel", "required", "rev", "reversed", "role", "rows", "rowspan", "spellcheck", "scope", "selected", "shape", "size", "sizes", "slot", "span", "srclang", "start", "src", "srcset", "step", "style", "summary", "tabindex", "title", "translate", "type", "usemap", "valign", "value", "width", "wrap", "xmlns"]);
|
|
2491
|
-
var svg = freeze(["accent-height", "accumulate", "additive", "alignment-baseline", "amplitude", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dominant-baseline", "dur", "edgemode", "elevation", "end", "exponent", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "intercept", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "mask-type", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "slope", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "tablevalues", "targetx", "targety", "transform", "transform-origin", "text-anchor", "text-decoration", "text-orientation", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"]);
|
|
2770
|
+
var svg = freeze(["accent-height", "accumulate", "additive", "alignment-baseline", "amplitude", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dominant-baseline", "dur", "edgemode", "elevation", "end", "exponent", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "intercept", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "mask-type", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "pointer-events", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "slope", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "tablevalues", "targetx", "targety", "transform", "transform-origin", "text-anchor", "text-decoration", "text-orientation", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "vector-effect", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"]);
|
|
2492
2771
|
var mathMl = freeze(["accent", "accentunder", "align", "bevelled", "close", "columnalign", "columnlines", "columnspacing", "columnspan", "denomalign", "depth", "dir", "display", "displaystyle", "encoding", "fence", "frame", "height", "href", "id", "largeop", "length", "linethickness", "lquote", "lspace", "mathbackground", "mathcolor", "mathsize", "mathvariant", "maxsize", "minsize", "movablelimits", "notation", "numalign", "open", "rowalign", "rowlines", "rowspacing", "rowspan", "rspace", "rquote", "scriptlevel", "scriptminsize", "scriptsizemultiplier", "selection", "separator", "separators", "stretchy", "subscriptshift", "supscriptshift", "symmetric", "voffset", "width", "xmlns"]);
|
|
2493
2772
|
var xml = freeze(["xlink:href", "xml:id", "xlink:title", "xml:space", "xmlns:xlink"]);
|
|
2494
2773
|
var MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g);
|
|
@@ -2528,6 +2807,15 @@ var NODE_TYPE = {
|
|
|
2528
2807
|
notation: 12
|
|
2529
2808
|
// Deprecated
|
|
2530
2809
|
};
|
|
2810
|
+
var LITERAL_TEXT_ELEMENT_NAMES = ["style", "script", "xmp", "iframe", "noembed", "noframes", "plaintext", "noscript"];
|
|
2811
|
+
var LITERAL_TEXT_ELEMENTS = freeze(addToSet({}, LITERAL_TEXT_ELEMENT_NAMES));
|
|
2812
|
+
var LITERAL_TEXT_CLOSE = (function() {
|
|
2813
|
+
const map = {};
|
|
2814
|
+
arrayForEach(LITERAL_TEXT_ELEMENT_NAMES, (name) => {
|
|
2815
|
+
map[name] = seal(new RegExp("</" + name + "(?=[\\t\\n\\f\\r />])", "i"));
|
|
2816
|
+
});
|
|
2817
|
+
return freeze(map);
|
|
2818
|
+
})();
|
|
2531
2819
|
var getGlobal = function getGlobal2() {
|
|
2532
2820
|
return typeof window === "undefined" ? null : window;
|
|
2533
2821
|
};
|
|
@@ -2571,10 +2859,14 @@ var _createHooksMap = function _createHooksMap2() {
|
|
|
2571
2859
|
var _resolveSetOption = function _resolveSetOption2(cfg, key, fallback, options) {
|
|
2572
2860
|
return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback;
|
|
2573
2861
|
};
|
|
2862
|
+
var _resolveObjectOption = function _resolveObjectOption2(cfg, key, makeFallback) {
|
|
2863
|
+
const value = objectHasOwnProperty(cfg, key) ? cfg[key] : void 0;
|
|
2864
|
+
return value && typeof value === "object" ? clone(value) : makeFallback();
|
|
2865
|
+
};
|
|
2574
2866
|
function createDOMPurify() {
|
|
2575
2867
|
let window2 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal();
|
|
2576
2868
|
const DOMPurify = (root) => createDOMPurify(root);
|
|
2577
|
-
DOMPurify.version = "3.4.
|
|
2869
|
+
DOMPurify.version = "3.4.14";
|
|
2578
2870
|
DOMPurify.removed = [];
|
|
2579
2871
|
if (!window2 || !window2.document || window2.document.nodeType !== NODE_TYPE.document || !window2.Element) {
|
|
2580
2872
|
DOMPurify.isSupported = false;
|
|
@@ -2599,6 +2891,12 @@ function createDOMPurify() {
|
|
|
2599
2891
|
const getNodeType = Node2 && Node2.prototype ? lookupGetter(Node2.prototype, "nodeType") : null;
|
|
2600
2892
|
const getNodeName = Node2 && Node2.prototype ? lookupGetter(Node2.prototype, "nodeName") : null;
|
|
2601
2893
|
const getOwnerDocument = Node2 && Node2.prototype ? lookupGetter(Node2.prototype, "ownerDocument") : null;
|
|
2894
|
+
const _readNodeType = function _readNodeType2(node) {
|
|
2895
|
+
return getNodeType ? getNodeType(node) : node.nodeType;
|
|
2896
|
+
};
|
|
2897
|
+
const _readNodeName = function _readNodeName2(node) {
|
|
2898
|
+
return getNodeName ? getNodeName(node) : node.nodeName;
|
|
2899
|
+
};
|
|
2602
2900
|
if (typeof HTMLTemplateElement === "function") {
|
|
2603
2901
|
const template = document2.createElement("template");
|
|
2604
2902
|
if (template.content && template.content.ownerDocument) {
|
|
@@ -2647,7 +2945,7 @@ function createDOMPurify() {
|
|
|
2647
2945
|
const MUSTACHE_EXPR$1 = MUSTACHE_EXPR, ERB_EXPR$1 = ERB_EXPR, TMPLIT_EXPR$1 = TMPLIT_EXPR, DATA_ATTR$1 = DATA_ATTR, ARIA_ATTR$1 = ARIA_ATTR, IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, ATTR_WHITESPACE$1 = ATTR_WHITESPACE, CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT;
|
|
2648
2946
|
let IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
|
|
2649
2947
|
let ALLOWED_TAGS2 = null;
|
|
2650
|
-
const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...
|
|
2948
|
+
const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text3]);
|
|
2651
2949
|
let ALLOWED_ATTR2 = null;
|
|
2652
2950
|
const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
|
|
2653
2951
|
let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {
|
|
@@ -2825,9 +3123,19 @@ function createDOMPurify() {
|
|
|
2825
3123
|
IN_PLACE = cfg.IN_PLACE || false;
|
|
2826
3124
|
IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI;
|
|
2827
3125
|
NAMESPACE = typeof cfg.NAMESPACE === "string" ? cfg.NAMESPACE : HTML_NAMESPACE;
|
|
2828
|
-
MATHML_TEXT_INTEGRATION_POINTS =
|
|
2829
|
-
|
|
2830
|
-
|
|
3126
|
+
MATHML_TEXT_INTEGRATION_POINTS = _resolveObjectOption(
|
|
3127
|
+
cfg,
|
|
3128
|
+
"MATHML_TEXT_INTEGRATION_POINTS",
|
|
3129
|
+
() => addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS)
|
|
3130
|
+
// Default built-in map
|
|
3131
|
+
);
|
|
3132
|
+
HTML_INTEGRATION_POINTS = _resolveObjectOption(
|
|
3133
|
+
cfg,
|
|
3134
|
+
"HTML_INTEGRATION_POINTS",
|
|
3135
|
+
() => addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS)
|
|
3136
|
+
// Default built-in map
|
|
3137
|
+
);
|
|
3138
|
+
const customElementHandling = _resolveObjectOption(cfg, "CUSTOM_ELEMENT_HANDLING", () => create(null));
|
|
2831
3139
|
CUSTOM_ELEMENT_HANDLING = create(null);
|
|
2832
3140
|
if (objectHasOwnProperty(customElementHandling, "tagNameCheck") && isRegexOrFunction(customElementHandling.tagNameCheck)) {
|
|
2833
3141
|
CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck;
|
|
@@ -2846,7 +3154,7 @@ function createDOMPurify() {
|
|
|
2846
3154
|
RETURN_DOM = true;
|
|
2847
3155
|
}
|
|
2848
3156
|
if (USE_PROFILES) {
|
|
2849
|
-
ALLOWED_TAGS2 = addToSet({},
|
|
3157
|
+
ALLOWED_TAGS2 = addToSet({}, text3);
|
|
2850
3158
|
ALLOWED_ATTR2 = create(null);
|
|
2851
3159
|
if (USE_PROFILES.html === true) {
|
|
2852
3160
|
addToSet(ALLOWED_TAGS2, html$1);
|
|
@@ -2890,15 +3198,6 @@ function createDOMPurify() {
|
|
|
2890
3198
|
addToSet(ALLOWED_ATTR2, cfg.ADD_ATTR, transformCaseFunc);
|
|
2891
3199
|
}
|
|
2892
3200
|
}
|
|
2893
|
-
if (objectHasOwnProperty(cfg, "ADD_URI_SAFE_ATTR") && arrayIsArray(cfg.ADD_URI_SAFE_ATTR)) {
|
|
2894
|
-
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
|
|
2895
|
-
}
|
|
2896
|
-
if (objectHasOwnProperty(cfg, "FORBID_CONTENTS") && arrayIsArray(cfg.FORBID_CONTENTS)) {
|
|
2897
|
-
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
2898
|
-
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
2899
|
-
}
|
|
2900
|
-
addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
|
|
2901
|
-
}
|
|
2902
3201
|
if (objectHasOwnProperty(cfg, "ADD_FORBID_CONTENTS") && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) {
|
|
2903
3202
|
if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
|
|
2904
3203
|
FORBID_CONTENTS = clone(FORBID_CONTENTS);
|
|
@@ -3015,6 +3314,16 @@ function createDOMPurify() {
|
|
|
3015
3314
|
}
|
|
3016
3315
|
}
|
|
3017
3316
|
};
|
|
3317
|
+
const _stripAttributeNode = function _stripAttributeNode2(element, attribute, name) {
|
|
3318
|
+
try {
|
|
3319
|
+
element.removeAttributeNode(attribute);
|
|
3320
|
+
} catch (_2) {
|
|
3321
|
+
try {
|
|
3322
|
+
element.removeAttribute(name);
|
|
3323
|
+
} catch (_3) {
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
};
|
|
3018
3327
|
const _neutralizeRoot = function _neutralizeRoot2(root) {
|
|
3019
3328
|
_neutralizeSubtree(root);
|
|
3020
3329
|
const childNodes = getChildNodes(root);
|
|
@@ -3036,27 +3345,35 @@ function createDOMPurify() {
|
|
|
3036
3345
|
const attribute = attributes[i];
|
|
3037
3346
|
const name = attribute && attribute.name;
|
|
3038
3347
|
if (typeof name === "string") {
|
|
3039
|
-
|
|
3040
|
-
root.removeAttribute(name);
|
|
3041
|
-
} catch (_2) {
|
|
3042
|
-
}
|
|
3348
|
+
_stripAttributeNode(root, attribute, name);
|
|
3043
3349
|
}
|
|
3044
3350
|
}
|
|
3045
3351
|
}
|
|
3046
3352
|
};
|
|
3047
|
-
const _removeAttribute = function _removeAttribute2(name, element) {
|
|
3353
|
+
const _removeAttribute = function _removeAttribute2(name, element, attr) {
|
|
3354
|
+
if (!attr) {
|
|
3355
|
+
try {
|
|
3356
|
+
attr = element.getAttributeNode(name);
|
|
3357
|
+
} catch (_2) {
|
|
3358
|
+
attr = null;
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
arrayPush(DOMPurify.removed, {
|
|
3362
|
+
attribute: attr || null,
|
|
3363
|
+
from: element
|
|
3364
|
+
});
|
|
3048
3365
|
try {
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3366
|
+
if (attr) {
|
|
3367
|
+
element.removeAttributeNode(attr);
|
|
3368
|
+
} else {
|
|
3369
|
+
element.removeAttribute(name);
|
|
3370
|
+
}
|
|
3053
3371
|
} catch (_2) {
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
}
|
|
3372
|
+
try {
|
|
3373
|
+
element.removeAttribute(name);
|
|
3374
|
+
} catch (_3) {
|
|
3375
|
+
}
|
|
3058
3376
|
}
|
|
3059
|
-
element.removeAttribute(name);
|
|
3060
3377
|
if (name === "is") {
|
|
3061
3378
|
if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
|
|
3062
3379
|
try {
|
|
@@ -3082,17 +3399,14 @@ function createDOMPurify() {
|
|
|
3082
3399
|
if (typeof name !== "string" || ALLOWED_ATTR2[transformCaseFunc(name)]) {
|
|
3083
3400
|
continue;
|
|
3084
3401
|
}
|
|
3085
|
-
|
|
3086
|
-
element.removeAttribute(name);
|
|
3087
|
-
} catch (_2) {
|
|
3088
|
-
}
|
|
3402
|
+
_stripAttributeNode(element, attribute, name);
|
|
3089
3403
|
}
|
|
3090
3404
|
};
|
|
3091
3405
|
const _neutralizeSubtree = function _neutralizeSubtree2(root) {
|
|
3092
3406
|
const stack = [root];
|
|
3093
3407
|
while (stack.length > 0) {
|
|
3094
3408
|
const node = stack.pop();
|
|
3095
|
-
const nodeType =
|
|
3409
|
+
const nodeType = _readNodeType(node);
|
|
3096
3410
|
if (nodeType === NODE_TYPE.element) {
|
|
3097
3411
|
_stripDisallowedAttributes(node);
|
|
3098
3412
|
}
|
|
@@ -3104,6 +3418,15 @@ function createDOMPurify() {
|
|
|
3104
3418
|
}
|
|
3105
3419
|
}
|
|
3106
3420
|
};
|
|
3421
|
+
const _isPatchLinkageAttribute = function _isPatchLinkageAttribute2(lcName, lcTag) {
|
|
3422
|
+
if (!SAFE_FOR_XML) {
|
|
3423
|
+
return false;
|
|
3424
|
+
}
|
|
3425
|
+
if (lcName === "patchsrc") {
|
|
3426
|
+
return true;
|
|
3427
|
+
}
|
|
3428
|
+
return lcName === "for" && lcTag !== "label" && lcTag !== "output";
|
|
3429
|
+
};
|
|
3107
3430
|
const _neutralizePatchLinkage = function _neutralizePatchLinkage2(root) {
|
|
3108
3431
|
if (!SAFE_FOR_XML) {
|
|
3109
3432
|
return;
|
|
@@ -3111,7 +3434,7 @@ function createDOMPurify() {
|
|
|
3111
3434
|
const stack = [root];
|
|
3112
3435
|
while (stack.length > 0) {
|
|
3113
3436
|
const node = stack.pop();
|
|
3114
|
-
const nodeType =
|
|
3437
|
+
const nodeType = _readNodeType(node);
|
|
3115
3438
|
if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) {
|
|
3116
3439
|
try {
|
|
3117
3440
|
remove(node);
|
|
@@ -3121,12 +3444,12 @@ function createDOMPurify() {
|
|
|
3121
3444
|
}
|
|
3122
3445
|
if (nodeType === NODE_TYPE.element) {
|
|
3123
3446
|
const element = node;
|
|
3124
|
-
const lcTag = transformCaseFunc(
|
|
3447
|
+
const lcTag = transformCaseFunc(_readNodeName(node));
|
|
3125
3448
|
try {
|
|
3126
3449
|
if (element.hasAttribute && element.hasAttribute("patchsrc")) {
|
|
3127
3450
|
element.removeAttribute("patchsrc");
|
|
3128
3451
|
}
|
|
3129
|
-
if (element.hasAttribute && element.hasAttribute("for") &&
|
|
3452
|
+
if (element.hasAttribute && element.hasAttribute("for") && _isPatchLinkageAttribute("for", lcTag)) {
|
|
3130
3453
|
element.removeAttribute("for");
|
|
3131
3454
|
}
|
|
3132
3455
|
} catch (_2) {
|
|
@@ -3281,7 +3604,7 @@ function createDOMPurify() {
|
|
|
3281
3604
|
if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) {
|
|
3282
3605
|
return true;
|
|
3283
3606
|
}
|
|
3284
|
-
if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === "
|
|
3607
|
+
if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && LITERAL_TEXT_ELEMENTS[tagName] && (_isNode(currentNode.firstElementChild) || typeof currentNode.textContent === "string" && regExpTest(LITERAL_TEXT_CLOSE[tagName], currentNode.textContent))) {
|
|
3285
3608
|
return true;
|
|
3286
3609
|
}
|
|
3287
3610
|
if (currentNode.nodeType === NODE_TYPE.processingInstruction) {
|
|
@@ -3292,14 +3615,21 @@ function createDOMPurify() {
|
|
|
3292
3615
|
}
|
|
3293
3616
|
return false;
|
|
3294
3617
|
};
|
|
3295
|
-
const
|
|
3296
|
-
if (
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3618
|
+
const _matchesNameCheck = function _matchesNameCheck2(check, name) {
|
|
3619
|
+
if (check instanceof RegExp) {
|
|
3620
|
+
return regExpTest(check, name);
|
|
3621
|
+
}
|
|
3622
|
+
if (check instanceof Function) {
|
|
3623
|
+
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
|
|
3624
|
+
args[_key - 2] = arguments[_key];
|
|
3302
3625
|
}
|
|
3626
|
+
return Boolean(check(name, ...args));
|
|
3627
|
+
}
|
|
3628
|
+
return false;
|
|
3629
|
+
};
|
|
3630
|
+
const _sanitizeDisallowedNode = function _sanitizeDisallowedNode2(currentNode, tagName, root) {
|
|
3631
|
+
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
|
|
3632
|
+
return false;
|
|
3303
3633
|
}
|
|
3304
3634
|
if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
|
|
3305
3635
|
const parentNode = getParentNode(currentNode);
|
|
@@ -3321,28 +3651,31 @@ function createDOMPurify() {
|
|
|
3321
3651
|
}
|
|
3322
3652
|
return set === defaultSet || set === setConfigSet ? clone(set) : set;
|
|
3323
3653
|
};
|
|
3654
|
+
const _handleHookDetachedNode = function _handleHookDetachedNode2(currentNode, root) {
|
|
3655
|
+
if (currentNode === root || getParentNode(currentNode) !== null) {
|
|
3656
|
+
return false;
|
|
3657
|
+
}
|
|
3658
|
+
if (IN_PLACE) {
|
|
3659
|
+
_neutralizeSubtree(currentNode);
|
|
3660
|
+
}
|
|
3661
|
+
return true;
|
|
3662
|
+
};
|
|
3324
3663
|
const _sanitizeElements = function _sanitizeElements2(currentNode, root) {
|
|
3325
3664
|
_executeHooks(hooks.beforeSanitizeElements, currentNode, null);
|
|
3326
|
-
if (currentNode
|
|
3327
|
-
if (IN_PLACE) {
|
|
3328
|
-
_neutralizeSubtree(currentNode);
|
|
3329
|
-
}
|
|
3665
|
+
if (_handleHookDetachedNode(currentNode, root)) {
|
|
3330
3666
|
return true;
|
|
3331
3667
|
}
|
|
3332
3668
|
if (_isClobbered(currentNode)) {
|
|
3333
3669
|
_forceRemove(currentNode);
|
|
3334
3670
|
return true;
|
|
3335
3671
|
}
|
|
3336
|
-
const tagName = transformCaseFunc(
|
|
3672
|
+
const tagName = transformCaseFunc(_readNodeName(currentNode));
|
|
3337
3673
|
ALLOWED_TAGS2 = _forkSharedAllowlist(hooks.uponSanitizeElement, ALLOWED_TAGS2, DEFAULT_ALLOWED_TAGS, SET_CONFIG_ALLOWED_TAGS);
|
|
3338
3674
|
_executeHooks(hooks.uponSanitizeElement, currentNode, {
|
|
3339
3675
|
tagName,
|
|
3340
3676
|
allowedTags: ALLOWED_TAGS2
|
|
3341
3677
|
});
|
|
3342
|
-
if (currentNode
|
|
3343
|
-
if (IN_PLACE) {
|
|
3344
|
-
_neutralizeSubtree(currentNode);
|
|
3345
|
-
}
|
|
3678
|
+
if (_handleHookDetachedNode(currentNode, root)) {
|
|
3346
3679
|
return true;
|
|
3347
3680
|
}
|
|
3348
3681
|
if (_isUnsafeNode(currentNode, tagName)) {
|
|
@@ -3356,7 +3689,7 @@ function createDOMPurify() {
|
|
|
3356
3689
|
}
|
|
3357
3690
|
return removed;
|
|
3358
3691
|
}
|
|
3359
|
-
const nt2 =
|
|
3692
|
+
const nt2 = _readNodeType(currentNode);
|
|
3360
3693
|
if (nt2 === NODE_TYPE.element && !_checkValidNamespace(currentNode)) {
|
|
3361
3694
|
_forceRemove(currentNode);
|
|
3362
3695
|
return true;
|
|
@@ -3381,38 +3714,43 @@ function createDOMPurify() {
|
|
|
3381
3714
|
if (FORBID_ATTR[lcName]) {
|
|
3382
3715
|
return false;
|
|
3383
3716
|
}
|
|
3384
|
-
if (
|
|
3385
|
-
return false;
|
|
3386
|
-
}
|
|
3387
|
-
if (SAFE_FOR_XML && lcName === "for" && lcTag !== "label" && lcTag !== "output") {
|
|
3717
|
+
if (_isPatchLinkageAttribute(lcName, lcTag)) {
|
|
3388
3718
|
return false;
|
|
3389
3719
|
}
|
|
3390
3720
|
if (SANITIZE_DOM && (lcName === "id" || lcName === "name") && (value in document2 || value in formElement)) {
|
|
3391
3721
|
return false;
|
|
3392
3722
|
}
|
|
3393
3723
|
const nameIsPermitted = ALLOWED_ATTR2[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
|
|
3394
|
-
if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName))
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
//
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3724
|
+
if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName)) {
|
|
3725
|
+
return true;
|
|
3726
|
+
}
|
|
3727
|
+
if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) {
|
|
3728
|
+
return true;
|
|
3729
|
+
}
|
|
3730
|
+
if (!nameIsPermitted) {
|
|
3731
|
+
return (
|
|
3732
|
+
// Condition a) covers a basically valid custom element tag name whose
|
|
3733
|
+
// tag passes the configured tagNameCheck and whose attribute name
|
|
3734
|
+
// passes the configured attributeNameCheck ...
|
|
3735
|
+
_isBasicCustomElement(lcTag) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName, lcTag) || // Condition b) covers an `is` attribute whose value passes the
|
|
3736
|
+
// configured tagNameCheck while customized built-in elements are
|
|
3737
|
+
// allowed.
|
|
3738
|
+
lcName === "is" && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && _matchesNameCheck(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value)
|
|
3739
|
+
);
|
|
3740
|
+
}
|
|
3741
|
+
if (URI_SAFE_ATTRIBUTES[lcName]) {
|
|
3742
|
+
return true;
|
|
3743
|
+
}
|
|
3744
|
+
if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) {
|
|
3745
|
+
return true;
|
|
3746
|
+
}
|
|
3747
|
+
if ((lcName === "src" || lcName === "xlink:href" || lcName === "href") && lcTag !== "script" && stringIndexOf(value, "data:") === 0 && DATA_URI_TAGS[lcTag]) {
|
|
3748
|
+
return true;
|
|
3749
|
+
}
|
|
3750
|
+
if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) {
|
|
3751
|
+
return true;
|
|
3752
|
+
}
|
|
3753
|
+
return !value;
|
|
3416
3754
|
};
|
|
3417
3755
|
const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, ["annotation-xml", "color-profile", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "missing-glyph"]);
|
|
3418
3756
|
const _isBasicCustomElement = function _isBasicCustomElement2(tagName) {
|
|
@@ -3476,33 +3814,33 @@ function createDOMPurify() {
|
|
|
3476
3814
|
_executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
|
|
3477
3815
|
value = hookEvent.attrValue;
|
|
3478
3816
|
if (SANITIZE_NAMED_PROPS && (lcName === "id" || lcName === "name") && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) {
|
|
3479
|
-
_removeAttribute(name, currentNode);
|
|
3817
|
+
_removeAttribute(name, currentNode, attr);
|
|
3480
3818
|
value = SANITIZE_NAMED_PROPS_PREFIX + value;
|
|
3481
3819
|
}
|
|
3482
3820
|
if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) {
|
|
3483
|
-
_removeAttribute(name, currentNode);
|
|
3821
|
+
_removeAttribute(name, currentNode, attr);
|
|
3484
3822
|
continue;
|
|
3485
3823
|
}
|
|
3486
3824
|
if (lcName === "attributename" && stringMatch(value, "href")) {
|
|
3487
|
-
_removeAttribute(name, currentNode);
|
|
3825
|
+
_removeAttribute(name, currentNode, attr);
|
|
3488
3826
|
continue;
|
|
3489
3827
|
}
|
|
3490
3828
|
if (hookEvent.forceKeepAttr) {
|
|
3491
3829
|
continue;
|
|
3492
3830
|
}
|
|
3493
3831
|
if (!hookEvent.keepAttr) {
|
|
3494
|
-
_removeAttribute(name, currentNode);
|
|
3832
|
+
_removeAttribute(name, currentNode, attr);
|
|
3495
3833
|
continue;
|
|
3496
3834
|
}
|
|
3497
3835
|
if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) {
|
|
3498
|
-
_removeAttribute(name, currentNode);
|
|
3836
|
+
_removeAttribute(name, currentNode, attr);
|
|
3499
3837
|
continue;
|
|
3500
3838
|
}
|
|
3501
3839
|
if (SAFE_FOR_TEMPLATES) {
|
|
3502
3840
|
value = _stripTemplateExpressions(value);
|
|
3503
3841
|
}
|
|
3504
3842
|
if (!_isValidAttribute(lcTag, lcName, value)) {
|
|
3505
|
-
_removeAttribute(name, currentNode);
|
|
3843
|
+
_removeAttribute(name, currentNode, attr);
|
|
3506
3844
|
continue;
|
|
3507
3845
|
}
|
|
3508
3846
|
value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value);
|
|
@@ -3523,8 +3861,7 @@ function createDOMPurify() {
|
|
|
3523
3861
|
if (_isDocumentFragment(shadowNode.content)) {
|
|
3524
3862
|
_sanitizeShadowDOM2(shadowNode.content);
|
|
3525
3863
|
}
|
|
3526
|
-
|
|
3527
|
-
if (shadowNodeType === NODE_TYPE.element) {
|
|
3864
|
+
if (_readNodeType(shadowNode) === NODE_TYPE.element) {
|
|
3528
3865
|
const innerSr = getShadowRoot(shadowNode);
|
|
3529
3866
|
if (_isDocumentFragment(innerSr)) {
|
|
3530
3867
|
_sanitizeAttachedShadowRoots(innerSr);
|
|
@@ -3546,7 +3883,7 @@ function createDOMPurify() {
|
|
|
3546
3883
|
continue;
|
|
3547
3884
|
}
|
|
3548
3885
|
const node = item.node;
|
|
3549
|
-
const nodeType =
|
|
3886
|
+
const nodeType = _readNodeType(node);
|
|
3550
3887
|
const isElement = nodeType === NODE_TYPE.element;
|
|
3551
3888
|
const childNodes = getChildNodes(node);
|
|
3552
3889
|
if (childNodes) {
|
|
@@ -3618,7 +3955,7 @@ function createDOMPurify() {
|
|
|
3618
3955
|
const inPlace = IN_PLACE && typeof dirty !== "string" && _isNode(dirty);
|
|
3619
3956
|
if (inPlace) {
|
|
3620
3957
|
_neutralizePatchLinkage(dirty);
|
|
3621
|
-
const nn2 =
|
|
3958
|
+
const nn2 = _readNodeName(dirty);
|
|
3622
3959
|
if (typeof nn2 === "string") {
|
|
3623
3960
|
const tagName = transformCaseFunc(nn2);
|
|
3624
3961
|
if (!ALLOWED_TAGS2[tagName] || FORBID_TAGS[tagName]) {
|
|
@@ -3773,7 +4110,7 @@ function createDOMPurify() {
|
|
|
3773
4110
|
}
|
|
3774
4111
|
var purify = createDOMPurify();
|
|
3775
4112
|
|
|
3776
|
-
// node_modules/.pnpm/marked@18.0.
|
|
4113
|
+
// node_modules/.pnpm/marked@18.0.10/node_modules/marked/lib/marked.esm.js
|
|
3777
4114
|
function C() {
|
|
3778
4115
|
return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null };
|
|
3779
4116
|
}
|
|
@@ -3789,7 +4126,7 @@ function A(l3) {
|
|
|
3789
4126
|
return s || (s = l3(n), e[n] = s), s;
|
|
3790
4127
|
};
|
|
3791
4128
|
}
|
|
3792
|
-
function
|
|
4129
|
+
function d(l3, e = "") {
|
|
3793
4130
|
let t = typeof l3 == "string" ? l3 : l3.source, n = { replace: (s, r) => {
|
|
3794
4131
|
let i = typeof r == "string" ? r : r.source;
|
|
3795
4132
|
return i = i.replace(m.caret, "$1"), t = t.replace(s, i), n;
|
|
@@ -3811,24 +4148,24 @@ var q = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
|
|
|
3811
4148
|
var Pe = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
|
|
3812
4149
|
var U = / {0,3}(?:[*+-]|\d{1,9}[.)])/;
|
|
3813
4150
|
var oe = /^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/;
|
|
3814
|
-
var ae =
|
|
3815
|
-
var Se =
|
|
4151
|
+
var ae = d(oe).replace(/bull/g, U).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}(?:\s|$)/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/\|table/g, "").getRegex();
|
|
4152
|
+
var Se = d(oe).replace(/bull/g, U).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}(?:\s|$)/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/table/g, / {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex();
|
|
3816
4153
|
var K = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table|[ \t]+\n)[^\n]+)*)/;
|
|
3817
4154
|
var _e = /^[^\n]+/;
|
|
3818
4155
|
var W = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/;
|
|
3819
|
-
var $e =
|
|
3820
|
-
var Le =
|
|
4156
|
+
var $e = d(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label", W).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex();
|
|
4157
|
+
var Le = d(/^(bull)([ \t][^\n]*?)?(?:\n|$)/).replace(/bull/g, U).getRegex();
|
|
3821
4158
|
var Q = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
|
|
3822
4159
|
var X = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
|
|
3823
|
-
var Me =
|
|
3824
|
-
var le = (l3) =>
|
|
4160
|
+
var Me = d("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n*|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>[^\\n]*\\n*|$)|<![A-Z][\\s\\S]*?(?:>[^\\n]*\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>[^\\n]*\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))", "i").replace("comment", X).replace("tag", Q).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
|
|
4161
|
+
var le = (l3) => d(K).replace("hr", q).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", l3).replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", Q).getRegex();
|
|
3825
4162
|
var ze = le(/ {0,3}(?:[*+-]|1[.)])[ \t]+[^ \t\n]/);
|
|
3826
4163
|
var Ee = le(/ {0,3}(?:[*+-]|\d{1,9}[.)])(?:[ \t]|\n|$)/);
|
|
3827
|
-
var Ce =
|
|
4164
|
+
var Ce = d(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", Ee).getRegex();
|
|
3828
4165
|
var J = { blockquote: Ce, code: we, def: $e, fences: ye, heading: Pe, hr: q, html: Me, lheading: ae, list: Le, newline: Oe, paragraph: ze, table: z, text: _e };
|
|
3829
|
-
var se =
|
|
3830
|
-
var Ae = { ...J, lheading: Se, table: se, paragraph:
|
|
3831
|
-
var Ie = { ...J, html:
|
|
4166
|
+
var se = d("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", q).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("blockquote", " {0,3}>").replace("code", "(?: {4}| {0,3} )[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", Q).getRegex();
|
|
4167
|
+
var Ae = { ...J, lheading: Se, table: se, paragraph: d(K).replace("hr", q).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", se).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*(?:\\n|$))|~~~)[^\\n]*(?:\\n|$)").replace("list", " {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", Q).getRegex() };
|
|
4168
|
+
var Ie = { ...J, html: d(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment", X).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(), def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, heading: /^(#{1,6})(.*)(?:\n+|$)/, fences: z, lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, paragraph: d(K).replace("hr", q).replace("heading", ` *#{1,6} *[^
|
|
3832
4169
|
]`).replace("lheading", ae).replace("|table", "").replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").replace("|tag", "").getRegex() };
|
|
3833
4170
|
var Be = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
|
|
3834
4171
|
var De = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
|
|
@@ -3837,42 +4174,42 @@ var qe = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}
|
|
|
3837
4174
|
var _ = /[\p{P}\p{S}]/u;
|
|
3838
4175
|
var I = /[\s\p{P}\p{S}]/u;
|
|
3839
4176
|
var v = /[^\s\p{P}\p{S}]/u;
|
|
3840
|
-
var ve =
|
|
4177
|
+
var ve = d(/^((?![*_])punctSpace)/, "u").replace(/punctSpace/g, I).getRegex();
|
|
3841
4178
|
var He = /[\p{Pi}\p{Ps}"']/u;
|
|
3842
4179
|
var ue = /(?!~)[\p{P}\p{S}]/u;
|
|
3843
4180
|
var Ze = /(?!~)[\s\p{P}\p{S}]/u;
|
|
3844
4181
|
var Ge = /(?:[^\s\p{P}\p{S}]|~)/u;
|
|
3845
|
-
var Qe =
|
|
4182
|
+
var Qe = d(/link|precode-code|html/, "g").replace("link", /\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-", Te ? "(?<!`)()" : "(^^|[^`])").replace("code", /(?<b>`+)[^`]+\k<b>(?!`)/).replace("html", /<(?! )[^<>]*?>/).getRegex();
|
|
3846
4183
|
var ce = /^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/;
|
|
3847
|
-
var Ne =
|
|
3848
|
-
var je =
|
|
4184
|
+
var Ne = d(ce, "u").replace(/punct/g, _).getRegex();
|
|
4185
|
+
var je = d(ce, "u").replace(/punct/g, ue).getRegex();
|
|
3849
4186
|
var Fe = /^(?:\*+(?:((?!\*)(?!openQuote)punct)|([^\s*]))?)|^_+(?:((?!_)(?!openQuote)punct)|([^\s_]))?/;
|
|
3850
|
-
var Ue =
|
|
4187
|
+
var Ue = d(Fe, "u").replace(/openQuote/g, He).replace(/punct/g, _).getRegex();
|
|
3851
4188
|
var he = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)";
|
|
3852
|
-
var Ke =
|
|
3853
|
-
var We =
|
|
4189
|
+
var Ke = d(he, "gu").replace(/notPunctSpace/g, v).replace(/punctSpace/g, I).replace(/punct/g, _).getRegex();
|
|
4190
|
+
var We = d(he, "gu").replace(/notPunctSpace/g, Ge).replace(/punctSpace/g, Ze).replace(/punct/g, ue).getRegex();
|
|
3854
4191
|
var Xe = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)[\\s](\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|(?:(?!\\*)punct|notPunctSpace)(\\*+)(?!\\*)(?=notPunctSpace)";
|
|
3855
|
-
var Je =
|
|
3856
|
-
var Ve =
|
|
4192
|
+
var Je = d(Xe, "gu").replace(/notPunctSpace/g, v).replace(/punctSpace/g, I).replace(/punct/g, _).getRegex();
|
|
4193
|
+
var Ve = d("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)", "gu").replace(/notPunctSpace/g, v).replace(/punctSpace/g, I).replace(/punct/g, _).getRegex();
|
|
3857
4194
|
var Ye = "^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)[\\s](_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)|(?:(?!_)punct|notPunctSpace)(_+)(?!_)(?=notPunctSpace)";
|
|
3858
|
-
var et =
|
|
3859
|
-
var tt =
|
|
4195
|
+
var et = d(Ye, "gu").replace(/notPunctSpace/g, v).replace(/punctSpace/g, I).replace(/punct/g, _).getRegex();
|
|
4196
|
+
var tt = d(/^~~?(?:((?!~)punct)|[^\s~])/, "u").replace(/punct/g, _).getRegex();
|
|
3860
4197
|
var nt = "^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)";
|
|
3861
|
-
var rt =
|
|
3862
|
-
var st =
|
|
3863
|
-
var it =
|
|
3864
|
-
var ot =
|
|
3865
|
-
var at =
|
|
4198
|
+
var rt = d(nt, "gu").replace(/notPunctSpace/g, v).replace(/punctSpace/g, I).replace(/punct/g, _).getRegex();
|
|
4199
|
+
var st = d(/\\(punct)/, "gu").replace(/punct/g, _).getRegex();
|
|
4200
|
+
var it = d(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme", /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email", /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex();
|
|
4201
|
+
var ot = d(X).replace("(?:-->|$)", "-->").getRegex();
|
|
4202
|
+
var at = d("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment", ot).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex();
|
|
3866
4203
|
var G = /(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/;
|
|
3867
|
-
var lt =
|
|
3868
|
-
var de =
|
|
3869
|
-
var ke =
|
|
3870
|
-
var pt =
|
|
4204
|
+
var lt = d(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace("label", G).replace("href", /<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]+|(?=\))/).replace("title", /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex();
|
|
4205
|
+
var de = d(/^!?\[(label)\]\[(ref)\]/).replace("label", G).replace("ref", W).getRegex();
|
|
4206
|
+
var ke = d(/^!?\[(ref)\](?:\[\])?/).replace("ref", W).getRegex();
|
|
4207
|
+
var pt = d("reflink|nolink(?!\\()", "g").replace("reflink", de).replace("nolink", ke).getRegex();
|
|
3871
4208
|
var ie = /[hH][tT][tT][pP][sS]?|[fF][tT][pP]/;
|
|
3872
4209
|
var V = { _backpedal: z, anyPunctuation: st, autolink: it, blockSkip: Qe, br: pe, code: De, del: z, delLDelim: z, delRDelim: z, emStrongLDelim: Ne, emStrongRDelimAst: Ke, emStrongRDelimUnd: Ve, escape: Be, link: lt, nolink: ke, punctuation: ve, reflink: de, reflinkSearch: pt, tag: at, text: qe, url: z };
|
|
3873
|
-
var ut = { ...V, emStrongLDelim: Ue, emStrongRDelimAst: Je, emStrongRDelimUnd: et, link:
|
|
3874
|
-
var F = { ...V, emStrongRDelimAst: We, emStrongLDelim: je, delLDelim: tt, delRDelim: rt, url:
|
|
3875
|
-
var ct = { ...F, br:
|
|
4210
|
+
var ut = { ...V, emStrongLDelim: Ue, emStrongRDelimAst: Je, emStrongRDelimUnd: et, link: d(/^!?\[(label)\]\((.*?)\)/).replace("label", G).getRegex(), reflink: d(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", G).getRegex() };
|
|
4211
|
+
var F = { ...V, emStrongRDelimAst: We, emStrongLDelim: je, delLDelim: tt, delRDelim: rt, url: d(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol", ie).replace("email", /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(), _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, del: /^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/, text: d(/^(`+|~+|[^`~])(?:(?=[`~])|(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol", ie).getRegex() };
|
|
4212
|
+
var ct = { ...F, br: d(pe).replace("{2,}", "*").getRegex(), text: d(F.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex() };
|
|
3876
4213
|
var H = { normal: J, gfm: Ae, pedantic: Ie };
|
|
3877
4214
|
var B = { normal: V, gfm: F, breaks: ct, pedantic: ut };
|
|
3878
4215
|
var ht = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
@@ -4018,20 +4355,20 @@ ${u}` : u, r = r ? `${r}
|
|
|
4018
4355
|
${c}` : c;
|
|
4019
4356
|
let h = this.lexer.state.top;
|
|
4020
4357
|
if (this.lexer.state.top = true, this.lexer.blockTokens(c, i, true), this.lexer.state.top = h, n.length === 0) break;
|
|
4021
|
-
let
|
|
4022
|
-
if (
|
|
4023
|
-
if (
|
|
4024
|
-
let T =
|
|
4358
|
+
let k = i.at(-1);
|
|
4359
|
+
if (k?.type === "code") break;
|
|
4360
|
+
if (k?.type === "blockquote") {
|
|
4361
|
+
let T = k, g = n.join(`
|
|
4025
4362
|
`), w = T.raw + `
|
|
4026
4363
|
` + g.replace(this.rules.other.blockquoteSetextReplace2, ""), M = this.blockquote(w);
|
|
4027
4364
|
i[i.length - 1] = M, s = `${s}
|
|
4028
4365
|
${g}`, r = r.substring(0, r.length - T.text.length) + M.text;
|
|
4029
4366
|
break;
|
|
4030
|
-
} else if (
|
|
4031
|
-
let T =
|
|
4367
|
+
} else if (k?.type === "list") {
|
|
4368
|
+
let T = k, g = T.raw + `
|
|
4032
4369
|
` + n.join(`
|
|
4033
4370
|
`), w = this.list(g);
|
|
4034
|
-
i[i.length - 1] = w, s = s.substring(0, s.length -
|
|
4371
|
+
i[i.length - 1] = w, s = s.substring(0, s.length - k.raw.length) + w.raw, r = r.substring(0, r.length - T.raw.length) + w.raw, n = g.substring(i.at(-1).raw.length).split(`
|
|
4035
4372
|
`);
|
|
4036
4373
|
continue;
|
|
4037
4374
|
}
|
|
@@ -4050,23 +4387,23 @@ ${g}`, r = r.substring(0, r.length - T.text.length) + M.text;
|
|
|
4050
4387
|
if (!(t = i.exec(e)) || this.rules.block.hr.test(e)) break;
|
|
4051
4388
|
u = t[0], e = e.substring(u.length);
|
|
4052
4389
|
let h = me(t[2].split(`
|
|
4053
|
-
`, 1)[0], t[1].length),
|
|
4390
|
+
`, 1)[0], t[1].length), k = e.split(`
|
|
4054
4391
|
`, 1)[0], T = !h.trim(), g = 0;
|
|
4055
|
-
if (this.options.pedantic ? (g = 2, c = h.trimStart()) : T ? g = t[1].length + 1 : (g = h.search(this.rules.other.nonSpaceChar), g = g > 4 ? 1 : g, c = h.slice(g), g += t[1].length), T && this.rules.other.blankLine.test(
|
|
4056
|
-
`, e = e.substring(
|
|
4392
|
+
if (this.options.pedantic ? (g = 2, c = h.trimStart()) : T ? g = t[1].length + 1 : (g = h.search(this.rules.other.nonSpaceChar), g = g > 4 ? 1 : g, c = h.slice(g), g += t[1].length), T && this.rules.other.blankLine.test(k) && (u += k + `
|
|
4393
|
+
`, e = e.substring(k.length + 1), a = true), !a) {
|
|
4057
4394
|
let w = this.rules.other.nextBulletRegex(g), M = this.rules.other.hrRegex(g), ne = this.rules.other.fencesBeginRegex(g), re = this.rules.other.headingBeginRegex(g), be = this.rules.other.htmlBeginRegex(g), Re = this.rules.other.blockquoteBeginRegex(g);
|
|
4058
4395
|
for (; e; ) {
|
|
4059
4396
|
let N = e.split(`
|
|
4060
4397
|
`, 1)[0], D;
|
|
4061
|
-
if (
|
|
4062
|
-
if (D.search(this.rules.other.nonSpaceChar) >= g || !
|
|
4398
|
+
if (k = N, this.options.pedantic ? (k = k.replace(this.rules.other.listReplaceNesting, " "), D = k) : D = k.replace(this.rules.other.tabCharGlobal, " "), ne.test(k) || re.test(k) || be.test(k) || Re.test(k) || w.test(k) || M.test(k)) break;
|
|
4399
|
+
if (D.search(this.rules.other.nonSpaceChar) >= g || !k.trim()) c += `
|
|
4063
4400
|
` + D.slice(g);
|
|
4064
4401
|
else {
|
|
4065
4402
|
if (T || h.replace(this.rules.other.tabCharGlobal, " ").search(this.rules.other.nonSpaceChar) >= 4 || ne.test(h) || re.test(h) || M.test(h)) break;
|
|
4066
4403
|
c += `
|
|
4067
|
-
` +
|
|
4404
|
+
` + k;
|
|
4068
4405
|
}
|
|
4069
|
-
T = !
|
|
4406
|
+
T = !k.trim(), u += N + `
|
|
4070
4407
|
`, e = e.substring(N.length + 1), h = D.slice(g);
|
|
4071
4408
|
}
|
|
4072
4409
|
}
|
|
@@ -4076,8 +4413,11 @@ ${g}`, r = r.substring(0, r.length - T.text.length) + M.text;
|
|
|
4076
4413
|
if (p) p.raw = p.raw.trimEnd(), p.text = p.text.trimEnd();
|
|
4077
4414
|
else return;
|
|
4078
4415
|
r.raw = r.raw.trimEnd();
|
|
4416
|
+
for (let a of r.items) if (this.lexer.state.top = false, a.tokens = this.lexer.blockTokens(a.text, []), !r.loose) {
|
|
4417
|
+
let u = a.tokens.filter((h) => h.type === "space"), c = u.length > 0 && u.some((h) => this.rules.other.anyLine.test(h.raw));
|
|
4418
|
+
r.loose = c;
|
|
4419
|
+
}
|
|
4079
4420
|
for (let a of r.items) {
|
|
4080
|
-
this.lexer.state.top = false, a.tokens = this.lexer.blockTokens(a.text, []);
|
|
4081
4421
|
let u = a.tokens[0];
|
|
4082
4422
|
if (a.task && (u?.type === "text" || u?.type === "paragraph")) {
|
|
4083
4423
|
a.text = a.text.replace(this.rules.other.listReplaceTask, ""), u.raw = u.raw.replace(this.rules.other.listReplaceTask, ""), u.text = u.text.replace(this.rules.other.listReplaceTask, "");
|
|
@@ -4091,10 +4431,6 @@ ${g}`, r = r.substring(0, r.length - T.text.length) + M.text;
|
|
|
4091
4431
|
a.checked = h.checked, r.loose ? a.tokens[0] && ["paragraph", "text"].includes(a.tokens[0].type) && "tokens" in a.tokens[0] && a.tokens[0].tokens ? (a.tokens[0].raw = h.raw + a.tokens[0].raw, a.tokens[0].text = h.raw + a.tokens[0].text, a.tokens[0].tokens.unshift(h)) : a.tokens.unshift({ type: "paragraph", raw: h.raw, text: h.raw, tokens: [h] }) : a.tokens.unshift(h);
|
|
4092
4432
|
}
|
|
4093
4433
|
} else a.task && (a.task = false);
|
|
4094
|
-
if (!r.loose) {
|
|
4095
|
-
let c = a.tokens.filter((d) => d.type === "space"), h = c.length > 0 && c.some((d) => this.rules.other.anyLine.test(d.raw));
|
|
4096
|
-
r.loose = h;
|
|
4097
|
-
}
|
|
4098
4434
|
}
|
|
4099
4435
|
if (r.loose) for (let a of r.items) {
|
|
4100
4436
|
a.loose = true;
|
|
@@ -4198,8 +4534,8 @@ ${g}`, r = r.substring(0, r.length - T.text.length) + M.text;
|
|
|
4198
4534
|
let s = this.rules.inline.emStrongLDelim.exec(e);
|
|
4199
4535
|
if (!s || !s[1] && !s[2] && !s[3] && !s[4] || s[4] && n.match(this.rules.other.unicodeAlphaNumeric)) return;
|
|
4200
4536
|
if (!(s[1] || s[3] || "") || !n || this.rules.inline.punctuation.exec(n)) {
|
|
4201
|
-
let i = [...s[0]].length - 1, o, p, a = i, u = 0, c = s[0][0], h = n === c,
|
|
4202
|
-
for (
|
|
4537
|
+
let i = [...s[0]].length - 1, o, p, a = i, u = 0, c = s[0][0], h = n === c, k = c === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;
|
|
4538
|
+
for (k.lastIndex = 0, t = t.slice(-1 * e.length + i); (s = k.exec(t)) !== null; ) {
|
|
4203
4539
|
if (o = s[1] || s[2] || s[3] || s[4] || s[5] || s[6], !o) continue;
|
|
4204
4540
|
if (p = [...o].length, s[3] || s[4]) {
|
|
4205
4541
|
a += p;
|
|
@@ -4247,8 +4583,8 @@ ${g}`, r = r.substring(0, r.length - T.text.length) + M.text;
|
|
|
4247
4583
|
}
|
|
4248
4584
|
if (a -= p, a > 0) continue;
|
|
4249
4585
|
p = Math.min(p, p + a);
|
|
4250
|
-
let c = [...s[0]][0].length, h = e.slice(0, i + s.index + c + p),
|
|
4251
|
-
return { type: "del", raw: h, text:
|
|
4586
|
+
let c = [...s[0]][0].length, h = e.slice(0, i + s.index + c + p), k = h.slice(i, -i);
|
|
4587
|
+
return { type: "del", raw: h, text: k, tokens: this.lexer.inlineTokens(k) };
|
|
4252
4588
|
}
|
|
4253
4589
|
}
|
|
4254
4590
|
}
|
|
@@ -4420,7 +4756,7 @@ var x = class l {
|
|
|
4420
4756
|
let o = Object.keys(this.tokens.links);
|
|
4421
4757
|
o.length > 0 && (n = n.replace(this.tokenizer.rules.inline.reflinkSearch, (p) => o.includes(p.slice(p.lastIndexOf("[") + 1, -1)) ? "[" + "a".repeat(p.length - 2) + "]" : p));
|
|
4422
4758
|
}
|
|
4423
|
-
n = n.replace(this.tokenizer.rules.inline.anyPunctuation, "
|
|
4759
|
+
n = n.replace(this.tokenizer.rules.inline.anyPunctuation, (o) => "+".repeat(o.length)), n = n.replace(this.tokenizer.rules.inline.blockSkip, (o, p, a) => {
|
|
4424
4760
|
let u = a ? a.length : 0;
|
|
4425
4761
|
return o.slice(0, u) + "[" + "a".repeat(o.length - u - 2) + "]";
|
|
4426
4762
|
}), n = this.options.hooks?.emStrongMask?.call({ lexer: this }, n) ?? n;
|
|
@@ -4966,8 +5302,8 @@ var Z = class {
|
|
|
4966
5302
|
if (i.hooks && (i.hooks.options = i, i.hooks.block = e), i.async) return (async () => {
|
|
4967
5303
|
let p = i.hooks ? await i.hooks.preprocess(n) : n, u = await (i.hooks ? await i.hooks.provideLexer(e) : e ? x.lex : x.lexInline)(p, i), c = i.hooks ? await i.hooks.processAllTokens(u) : u;
|
|
4968
5304
|
i.walkTokens && await Promise.all(this.walkTokens(c, i.walkTokens));
|
|
4969
|
-
let
|
|
4970
|
-
return i.hooks ? await i.hooks.postprocess(
|
|
5305
|
+
let k = await (i.hooks ? await i.hooks.provideParser(e) : e ? b.parse : b.parseInline)(c, i);
|
|
5306
|
+
return i.hooks ? await i.hooks.postprocess(k) : k;
|
|
4971
5307
|
})().catch(o);
|
|
4972
5308
|
try {
|
|
4973
5309
|
i.hooks && (n = i.hooks.preprocess(n));
|
|
@@ -5100,46 +5436,43 @@ function sanitizer() {
|
|
|
5100
5436
|
}
|
|
5101
5437
|
return purifier;
|
|
5102
5438
|
}
|
|
5103
|
-
function renderMarkdown(
|
|
5439
|
+
function renderMarkdown(text4, options) {
|
|
5104
5440
|
const allowImages = options?.allowImages === true;
|
|
5105
|
-
const rendered = parser.parse(
|
|
5441
|
+
const rendered = parser.parse(text4, { async: false });
|
|
5106
5442
|
return sanitizer().sanitize(rendered, allowImages ? SANITIZE_CONFIG_WITH_IMAGES : SANITIZE_CONFIG).trim();
|
|
5107
5443
|
}
|
|
5108
5444
|
|
|
5109
5445
|
// src/ui/resize_handle.ts
|
|
5110
5446
|
var MIN_WIDTH = 280;
|
|
5111
5447
|
var MIN_HEIGHT = 240;
|
|
5112
|
-
|
|
5448
|
+
var STEP2 = 16;
|
|
5449
|
+
var COARSE_STEP2 = 64;
|
|
5450
|
+
function createResizeHandle(grip, options) {
|
|
5113
5451
|
const handle = document.createElement("div");
|
|
5114
|
-
handle.className =
|
|
5115
|
-
handle.setAttribute("part",
|
|
5452
|
+
handle.className = `resize-handle resize-handle--${gripName(grip)}`;
|
|
5453
|
+
handle.setAttribute("part", `resize-handle resize-handle-${gripName(grip)}`);
|
|
5116
5454
|
handle.setAttribute("role", "separator");
|
|
5455
|
+
if (grip.x === void 0) {
|
|
5456
|
+
handle.setAttribute("aria-orientation", "horizontal");
|
|
5457
|
+
} else if (grip.y === void 0) {
|
|
5458
|
+
handle.setAttribute("aria-orientation", "vertical");
|
|
5459
|
+
}
|
|
5117
5460
|
handle.setAttribute("aria-label", options.label);
|
|
5118
5461
|
handle.tabIndex = 0;
|
|
5119
|
-
const sizeAt = (axis, anchor, rect, x2, y2) => {
|
|
5120
|
-
const width = anchor.x === "right" ? rect.right - x2 : x2 - rect.left;
|
|
5121
|
-
const clamped = { width: Math.max(MIN_WIDTH, width) };
|
|
5122
|
-
if (axis !== "both") {
|
|
5123
|
-
return clamped;
|
|
5124
|
-
}
|
|
5125
|
-
const height = anchor.y === "bottom" ? rect.bottom - y2 : y2 - rect.top;
|
|
5126
|
-
return { ...clamped, height: Math.max(MIN_HEIGHT, height) };
|
|
5127
|
-
};
|
|
5128
5462
|
handle.addEventListener("pointerdown", (event) => {
|
|
5129
5463
|
const axis = options.axis();
|
|
5130
|
-
if (axis === "none") {
|
|
5464
|
+
if (axis === "none" || !movable(grip, axis)) {
|
|
5131
5465
|
return;
|
|
5132
5466
|
}
|
|
5133
|
-
const anchor = options.anchor();
|
|
5134
5467
|
const rect = options.rect();
|
|
5135
5468
|
const onMove = (move) => {
|
|
5136
|
-
options.apply(
|
|
5469
|
+
options.apply(boxAt(grip, axis, rect, move.clientX, move.clientY));
|
|
5137
5470
|
};
|
|
5138
5471
|
const onUp = (up) => {
|
|
5139
5472
|
window.removeEventListener("pointermove", onMove);
|
|
5140
5473
|
window.removeEventListener("pointerup", onUp);
|
|
5141
5474
|
handle.removeAttribute("data-dragging");
|
|
5142
|
-
options.commit(
|
|
5475
|
+
options.commit(boxAt(grip, axis, rect, up.clientX, up.clientY));
|
|
5143
5476
|
};
|
|
5144
5477
|
handle.setAttribute("data-dragging", "true");
|
|
5145
5478
|
window.addEventListener("pointermove", onMove);
|
|
@@ -5151,34 +5484,28 @@ function createResizeHandle(options) {
|
|
|
5151
5484
|
if (pending === null) {
|
|
5152
5485
|
return;
|
|
5153
5486
|
}
|
|
5154
|
-
const
|
|
5487
|
+
const box = pending;
|
|
5155
5488
|
pending = null;
|
|
5156
|
-
options.commit(
|
|
5489
|
+
options.commit(box);
|
|
5157
5490
|
};
|
|
5158
5491
|
handle.addEventListener("keydown", (event) => {
|
|
5159
5492
|
const axis = options.axis();
|
|
5160
|
-
if (axis === "none") {
|
|
5493
|
+
if (axis === "none" || !movable(grip, axis)) {
|
|
5161
5494
|
return;
|
|
5162
5495
|
}
|
|
5163
|
-
const
|
|
5496
|
+
const step = event.shiftKey ? COARSE_STEP2 : STEP2;
|
|
5164
5497
|
const rect = options.rect();
|
|
5165
|
-
const
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
const height = rect.bottom - rect.top;
|
|
5169
|
-
let next = null;
|
|
5170
|
-
if (event.key === "ArrowLeft") {
|
|
5171
|
-
next = { width: Math.max(MIN_WIDTH, width - step * outward) };
|
|
5172
|
-
} else if (event.key === "ArrowRight") {
|
|
5173
|
-
next = { width: Math.max(MIN_WIDTH, width + step * outward) };
|
|
5174
|
-
} else if (axis === "both" && (event.key === "ArrowUp" || event.key === "ArrowDown")) {
|
|
5175
|
-
const grow = event.key === (anchor.y === "bottom" ? "ArrowUp" : "ArrowDown");
|
|
5176
|
-
next = { height: Math.max(MIN_HEIGHT, height + (grow ? step : -step)) };
|
|
5498
|
+
const delta = ARROWS[event.key];
|
|
5499
|
+
if (delta === void 0) {
|
|
5500
|
+
return;
|
|
5177
5501
|
}
|
|
5178
|
-
if (
|
|
5502
|
+
if (delta.x !== 0 && grip.x === void 0 || delta.y !== 0 && grip.y === void 0) {
|
|
5179
5503
|
return;
|
|
5180
5504
|
}
|
|
5181
5505
|
event.preventDefault();
|
|
5506
|
+
const x2 = (grip.x === "left" ? rect.left : rect.right) + delta.x * step;
|
|
5507
|
+
const y2 = (grip.y === "top" ? rect.top : rect.bottom) + delta.y * step;
|
|
5508
|
+
const next = boxAt(grip, axis, rect, x2, y2);
|
|
5182
5509
|
options.apply(next);
|
|
5183
5510
|
pending = next;
|
|
5184
5511
|
});
|
|
@@ -5186,6 +5513,26 @@ function createResizeHandle(options) {
|
|
|
5186
5513
|
handle.addEventListener("blur", settle);
|
|
5187
5514
|
return handle;
|
|
5188
5515
|
}
|
|
5516
|
+
var ARROWS = {
|
|
5517
|
+
ArrowLeft: { x: -1, y: 0 },
|
|
5518
|
+
ArrowRight: { x: 1, y: 0 },
|
|
5519
|
+
ArrowUp: { x: 0, y: -1 },
|
|
5520
|
+
ArrowDown: { x: 0, y: 1 }
|
|
5521
|
+
};
|
|
5522
|
+
function gripName(grip) {
|
|
5523
|
+
return [grip.y, grip.x].filter((side) => side !== void 0).join("-");
|
|
5524
|
+
}
|
|
5525
|
+
function movable(grip, axis) {
|
|
5526
|
+
return axis === "both" || grip.x !== void 0;
|
|
5527
|
+
}
|
|
5528
|
+
function boxAt(grip, axis, rect, x2, y2) {
|
|
5529
|
+
const left = grip.x === "left" ? Math.min(x2, rect.right - MIN_WIDTH) : rect.left;
|
|
5530
|
+
const right = grip.x === "right" ? Math.max(x2, rect.left + MIN_WIDTH) : rect.right;
|
|
5531
|
+
const vertical = axis === "both";
|
|
5532
|
+
const top = vertical && grip.y === "top" ? Math.min(y2, rect.bottom - MIN_HEIGHT) : rect.top;
|
|
5533
|
+
const bottom = vertical && grip.y === "bottom" ? Math.max(y2, rect.top + MIN_HEIGHT) : rect.bottom;
|
|
5534
|
+
return { left, top, right, bottom };
|
|
5535
|
+
}
|
|
5189
5536
|
|
|
5190
5537
|
// src/ui/reveal_words.ts
|
|
5191
5538
|
function collectTextNodes(root, out) {
|
|
@@ -5223,7 +5570,7 @@ function wrapWords(root) {
|
|
|
5223
5570
|
}
|
|
5224
5571
|
|
|
5225
5572
|
// src/ui/run_notice.ts
|
|
5226
|
-
function renderRunNotice(icon,
|
|
5573
|
+
function renderRunNotice(icon, text4, kind) {
|
|
5227
5574
|
const notice = document.createElement("div");
|
|
5228
5575
|
notice.className = `run-notice run-notice--${kind}`;
|
|
5229
5576
|
notice.setAttribute("part", `run-notice run-notice-${kind}`);
|
|
@@ -5236,7 +5583,7 @@ function renderRunNotice(icon, text3, kind) {
|
|
|
5236
5583
|
const label = document.createElement("span");
|
|
5237
5584
|
label.className = "run-notice-text";
|
|
5238
5585
|
label.setAttribute("part", "run-notice-text");
|
|
5239
|
-
label.textContent =
|
|
5586
|
+
label.textContent = text4;
|
|
5240
5587
|
notice.append(glyph, label);
|
|
5241
5588
|
return notice;
|
|
5242
5589
|
}
|
|
@@ -5492,6 +5839,30 @@ var STYLES = `
|
|
|
5492
5839
|
--_text: var(--ag-ui-text, var(--_fg));
|
|
5493
5840
|
--_surface: var(--ag-ui-surface, transparent);
|
|
5494
5841
|
|
|
5842
|
+
/* Message action row: the control box and the mark inside it. The box has a
|
|
5843
|
+
floor of 24px so it stays a reliable target at every density. */
|
|
5844
|
+
--_action-size: var(--ag-ui-action-size, 28px);
|
|
5845
|
+
--_action-icon-size: var(--ag-ui-action-icon-size, 15px);
|
|
5846
|
+
--_tooltip-bg: var(--ag-ui-tooltip-bg, #1f2430);
|
|
5847
|
+
--_tooltip-fg: var(--ag-ui-tooltip-fg, #f5f6fa);
|
|
5848
|
+
|
|
5849
|
+
/* Text and marks drawn on top of the accent and danger fills. Separate
|
|
5850
|
+
tokens because they are not free: a host that themes the accent to a pale
|
|
5851
|
+
colour has white-on-pale with no way to correct it, which is the one
|
|
5852
|
+
theming change that makes a control unreadable rather than merely off. */
|
|
5853
|
+
--_on-accent: var(--ag-ui-on-accent, #ffffff);
|
|
5854
|
+
--_on-danger: var(--ag-ui-on-danger, #ffffff);
|
|
5855
|
+
|
|
5856
|
+
/* Resize grips: the corner squares and the edge strips between them. Wide
|
|
5857
|
+
enough to hit without being wide enough to swallow a click on the content
|
|
5858
|
+
underneath, and adjustable for a host with a coarser pointer. */
|
|
5859
|
+
--_grip-corner: var(--ag-ui-grip-corner, 14px);
|
|
5860
|
+
--_grip-edge: var(--ag-ui-grip-edge, 6px);
|
|
5861
|
+
--_grip-edge-docked: var(--ag-ui-grip-edge-docked, 8px);
|
|
5862
|
+
/* The mark drawn inside a grip, as opposed to the area it answers to. */
|
|
5863
|
+
--_grip-mark-length: var(--ag-ui-grip-mark-length, 28px);
|
|
5864
|
+
--_grip-mark-thickness: var(--ag-ui-grip-mark-thickness, 3px);
|
|
5865
|
+
|
|
5495
5866
|
/* Status accents for tool-call cards. */
|
|
5496
5867
|
--_success: var(--ag-ui-success, #15803d);
|
|
5497
5868
|
--_danger: var(--ag-ui-danger, #b91c1c);
|
|
@@ -5502,6 +5873,12 @@ var STYLES = `
|
|
|
5502
5873
|
--_tool-icon-done: var(--ag-ui-tool-icon-done, "\u2713");
|
|
5503
5874
|
--_tool-icon-error: var(--ag-ui-tool-icon-error, "\u2715");
|
|
5504
5875
|
--_tool-icon-declined: var(--ag-ui-tool-icon-declined, "\u2298");
|
|
5876
|
+
|
|
5877
|
+
/* Disclosure marks on every expandable row. Tokenised for the same reason
|
|
5878
|
+
the status icons above are: a host re-theming one set and not the other
|
|
5879
|
+
ends up with two vocabularies in one transcript. */
|
|
5880
|
+
--_disclosure-collapsed: var(--ag-ui-disclosure-collapsed, "\u25B8");
|
|
5881
|
+
--_disclosure-expanded: var(--ag-ui-disclosure-expanded, "\u25BE");
|
|
5505
5882
|
--_tool-spin-duration: var(--ag-ui-tool-spin-duration, 0.7s);
|
|
5506
5883
|
|
|
5507
5884
|
/* Answer well (opt-in via data-answer-well) \u2014 boxes a whole assistant turn. */
|
|
@@ -5782,6 +6159,9 @@ var STYLES = `
|
|
|
5782
6159
|
font: inherit;
|
|
5783
6160
|
cursor: pointer;
|
|
5784
6161
|
pointer-events: auto;
|
|
6162
|
+
/* A touch drag on the launcher moves it; without this the page scrolls under
|
|
6163
|
+
the finger instead and the launcher never moves at all. */
|
|
6164
|
+
touch-action: none;
|
|
5785
6165
|
opacity: 0;
|
|
5786
6166
|
transform: scale(0.4);
|
|
5787
6167
|
visibility: hidden;
|
|
@@ -5811,6 +6191,15 @@ var STYLES = `
|
|
|
5811
6191
|
transform: scale(0.94);
|
|
5812
6192
|
}
|
|
5813
6193
|
|
|
6194
|
+
/* A drag is a press and a hover at the same time, so both scale rules above are
|
|
6195
|
+
live throughout it. Cancelling them is what keeps the launcher the size of
|
|
6196
|
+
the thing under the pointer while it travels; the position itself comes from
|
|
6197
|
+
inset, which nothing here transitions, so it tracks the pointer exactly. */
|
|
6198
|
+
:host([collapsed]) .launcher[data-dragging] {
|
|
6199
|
+
transform: none;
|
|
6200
|
+
cursor: grabbing;
|
|
6201
|
+
}
|
|
6202
|
+
|
|
5814
6203
|
.launcher .icon-holder {
|
|
5815
6204
|
width: var(--_launcher-icon-size);
|
|
5816
6205
|
height: var(--_launcher-icon-size);
|
|
@@ -6005,6 +6394,31 @@ var STYLES = `
|
|
|
6005
6394
|
transform-origin: bottom left;
|
|
6006
6395
|
}
|
|
6007
6396
|
|
|
6397
|
+
/* Once the launcher has been dragged the element places itself, and stamps the
|
|
6398
|
+
corner it chose to open away from. The morph has to start at that same
|
|
6399
|
+
corner: scaling out of the one the placement originally guessed reads as the
|
|
6400
|
+
panel leaping across the screen before it opens.
|
|
6401
|
+
|
|
6402
|
+
Equal specificity to the placement rule above, so source order is what lets
|
|
6403
|
+
the stamped value win -- the same arrangement the resize grip uses, and the
|
|
6404
|
+
same trap. Write these with = on the whole hyphenated token; a ~= would match
|
|
6405
|
+
whitespace-separated words and so could never match at all. */
|
|
6406
|
+
:host([data-expand-corner="top-left"]) .chat {
|
|
6407
|
+
transform-origin: top left;
|
|
6408
|
+
}
|
|
6409
|
+
|
|
6410
|
+
:host([data-expand-corner="top-right"]) .chat {
|
|
6411
|
+
transform-origin: top right;
|
|
6412
|
+
}
|
|
6413
|
+
|
|
6414
|
+
:host([data-expand-corner="bottom-left"]) .chat {
|
|
6415
|
+
transform-origin: bottom left;
|
|
6416
|
+
}
|
|
6417
|
+
|
|
6418
|
+
:host([data-expand-corner="bottom-right"]) .chat {
|
|
6419
|
+
transform-origin: bottom right;
|
|
6420
|
+
}
|
|
6421
|
+
|
|
6008
6422
|
/* The two in-flow placements keep the original collapse: hide the body, let
|
|
6009
6423
|
the host shrink to the header bar. */
|
|
6010
6424
|
:host([collapsed]:is([placement="embedded"], [placement="page"])) {
|
|
@@ -6430,11 +6844,11 @@ var STYLES = `
|
|
|
6430
6844
|
}
|
|
6431
6845
|
|
|
6432
6846
|
.thoughts-toggle::before {
|
|
6433
|
-
content: "
|
|
6847
|
+
content: var(--_disclosure-expanded) " ";
|
|
6434
6848
|
}
|
|
6435
6849
|
|
|
6436
6850
|
.thoughts-toggle[aria-expanded="false"]::before {
|
|
6437
|
-
content: "
|
|
6851
|
+
content: var(--_disclosure-collapsed) " ";
|
|
6438
6852
|
}
|
|
6439
6853
|
|
|
6440
6854
|
/* A gentle pulse on the label while reasoning is still streaming. */
|
|
@@ -6776,14 +7190,14 @@ var STYLES = `
|
|
|
6776
7190
|
}
|
|
6777
7191
|
|
|
6778
7192
|
.subagent-row::after {
|
|
6779
|
-
content:
|
|
7193
|
+
content: var(--_disclosure-collapsed);
|
|
6780
7194
|
flex: none;
|
|
6781
7195
|
margin-left: auto;
|
|
6782
7196
|
color: var(--_accent);
|
|
6783
7197
|
}
|
|
6784
7198
|
|
|
6785
7199
|
.subagent-row[aria-expanded="true"]::after {
|
|
6786
|
-
content:
|
|
7200
|
+
content: var(--_disclosure-expanded);
|
|
6787
7201
|
}
|
|
6788
7202
|
|
|
6789
7203
|
.subagent-row:disabled::after {
|
|
@@ -6910,16 +7324,23 @@ var STYLES = `
|
|
|
6910
7324
|
}
|
|
6911
7325
|
|
|
6912
7326
|
.tool-call-toggle::before {
|
|
6913
|
-
content: "
|
|
7327
|
+
content: var(--_disclosure-collapsed) " ";
|
|
6914
7328
|
}
|
|
6915
7329
|
|
|
6916
7330
|
.tool-call-toggle[aria-expanded="true"]::before {
|
|
6917
|
-
content: "
|
|
7331
|
+
content: var(--_disclosure-expanded) " ";
|
|
6918
7332
|
}
|
|
6919
7333
|
|
|
6920
|
-
/* Resize
|
|
6921
|
-
|
|
6922
|
-
nothing to drag.
|
|
7334
|
+
/* Resize grips: every edge and every corner, so the panel can be dragged from
|
|
7335
|
+
whichever side the reader is already near. Absent entirely where the
|
|
7336
|
+
placement is full-bleed, since there is nothing to drag.
|
|
7337
|
+
|
|
7338
|
+
The whole set is always laid out. Which edges the *layout* pins is not a
|
|
7339
|
+
question the stylesheet needs to answer any more -- it decided where the one
|
|
7340
|
+
grip went, and there is no longer one grip. The element still measures and
|
|
7341
|
+
stamps data-resize-anchor, because it decides what a drag on a pinned edge
|
|
7342
|
+
costs in position and which grip carries the tab stop, but no rule here
|
|
7343
|
+
reads it. */
|
|
6923
7344
|
.resize-handle {
|
|
6924
7345
|
position: absolute;
|
|
6925
7346
|
z-index: 2;
|
|
@@ -6932,95 +7353,102 @@ var STYLES = `
|
|
|
6932
7353
|
outline-offset: -2px;
|
|
6933
7354
|
}
|
|
6934
7355
|
|
|
6935
|
-
/*
|
|
6936
|
-
|
|
7356
|
+
/* Corners first in the file and last in the DOM, so they take the pointer
|
|
7357
|
+
where they overlap an edge strip. */
|
|
7358
|
+
.resize-handle--top-left,
|
|
7359
|
+
.resize-handle--top-right,
|
|
7360
|
+
.resize-handle--bottom-left,
|
|
7361
|
+
.resize-handle--bottom-right {
|
|
7362
|
+
width: var(--_grip-corner);
|
|
7363
|
+
height: var(--_grip-corner);
|
|
7364
|
+
}
|
|
6937
7365
|
|
|
6938
|
-
|
|
6939
|
-
.resize-handle {
|
|
7366
|
+
.resize-handle--top-left {
|
|
6940
7367
|
top: 0;
|
|
6941
7368
|
left: 0;
|
|
6942
|
-
width: 14px;
|
|
6943
|
-
height: 14px;
|
|
6944
7369
|
cursor: nwse-resize;
|
|
6945
7370
|
}
|
|
6946
7371
|
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
bottom-left is pinned there, so its free corner is top-right. */
|
|
6950
|
-
:host([placement="embedded"]) .resize-handle {
|
|
6951
|
-
top: auto;
|
|
6952
|
-
left: auto;
|
|
7372
|
+
.resize-handle--top-right {
|
|
7373
|
+
top: 0;
|
|
6953
7374
|
right: 0;
|
|
6954
|
-
|
|
6955
|
-
cursor: nwse-resize;
|
|
7375
|
+
cursor: nesw-resize;
|
|
6956
7376
|
}
|
|
6957
7377
|
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
7378
|
+
.resize-handle--bottom-left {
|
|
7379
|
+
bottom: 0;
|
|
7380
|
+
left: 0;
|
|
6961
7381
|
cursor: nesw-resize;
|
|
6962
7382
|
}
|
|
6963
7383
|
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
anchored bottom-left -- so the element measures them and stamps a single
|
|
6967
|
-
hyphenated "<y>-<x>" token here. Equal specificity to the rules above, so
|
|
6968
|
-
source order is what lets the measured value win.
|
|
6969
|
-
|
|
6970
|
-
Two traps, both of which silently draw the grip on the corner that moves:
|
|
6971
|
-
|
|
6972
|
-
Never write these as [data-resize-anchor~="left"]. The stamped value is one
|
|
6973
|
-
hyphenated token and ~= matches whitespace-separated words, so it can never
|
|
6974
|
-
match.
|
|
6975
|
-
|
|
6976
|
-
Each rule must set both sides of its axis, not only the side it moves, or it
|
|
6977
|
-
cannot undo a placement guess that flipped the other way. */
|
|
6978
|
-
:host([data-resize-anchor$="-left"]) .resize-handle {
|
|
6979
|
-
left: auto;
|
|
7384
|
+
.resize-handle--bottom-right {
|
|
7385
|
+
bottom: 0;
|
|
6980
7386
|
right: 0;
|
|
7387
|
+
cursor: nwse-resize;
|
|
7388
|
+
}
|
|
7389
|
+
|
|
7390
|
+
/* Edge strips, held clear of the corners at both ends so a corner drag is
|
|
7391
|
+
never swallowed by the edge next to it. */
|
|
7392
|
+
.resize-handle--left,
|
|
7393
|
+
.resize-handle--right {
|
|
7394
|
+
top: var(--_grip-corner);
|
|
7395
|
+
bottom: var(--_grip-corner);
|
|
7396
|
+
width: var(--_grip-edge);
|
|
7397
|
+
cursor: ew-resize;
|
|
6981
7398
|
}
|
|
6982
7399
|
|
|
6983
|
-
|
|
7400
|
+
.resize-handle--left {
|
|
6984
7401
|
left: 0;
|
|
6985
|
-
right: auto;
|
|
6986
7402
|
}
|
|
6987
7403
|
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
bottom: 0;
|
|
7404
|
+
.resize-handle--right {
|
|
7405
|
+
right: 0;
|
|
6991
7406
|
}
|
|
6992
7407
|
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
7408
|
+
.resize-handle--top,
|
|
7409
|
+
.resize-handle--bottom {
|
|
7410
|
+
left: var(--_grip-corner);
|
|
7411
|
+
right: var(--_grip-corner);
|
|
7412
|
+
height: var(--_grip-edge);
|
|
7413
|
+
cursor: ns-resize;
|
|
6996
7414
|
}
|
|
6997
7415
|
|
|
6998
|
-
|
|
6999
|
-
:
|
|
7000
|
-
:host([data-resize-anchor="bottom-right"]) .resize-handle {
|
|
7001
|
-
cursor: nwse-resize;
|
|
7416
|
+
.resize-handle--top {
|
|
7417
|
+
top: 0;
|
|
7002
7418
|
}
|
|
7003
7419
|
|
|
7004
|
-
|
|
7005
|
-
:
|
|
7006
|
-
cursor: nesw-resize;
|
|
7420
|
+
.resize-handle--bottom {
|
|
7421
|
+
bottom: 0;
|
|
7007
7422
|
}
|
|
7008
7423
|
|
|
7009
|
-
/* Docked: the placement owns the height, so
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7424
|
+
/* Docked: the placement owns the height, so the horizontal edges and every
|
|
7425
|
+
corner are inert and must not advertise a drag that does nothing. The two
|
|
7426
|
+
vertical edges remain, which is the same affordance these placements had
|
|
7427
|
+
when there was one grip -- now on both sides, since either may be the inner
|
|
7428
|
+
one depending on which side the rail is docked to. */
|
|
7429
|
+
:host([placement="sidebar"]) .resize-handle--top,
|
|
7430
|
+
:host([placement="sidebar"]) .resize-handle--bottom,
|
|
7431
|
+
:host([placement="sidebar"]) .resize-handle--top-left,
|
|
7432
|
+
:host([placement="sidebar"]) .resize-handle--top-right,
|
|
7433
|
+
:host([placement="sidebar"]) .resize-handle--bottom-left,
|
|
7434
|
+
:host([placement="sidebar"]) .resize-handle--bottom-right,
|
|
7435
|
+
:host([placement="side"]) .resize-handle--top,
|
|
7436
|
+
:host([placement="side"]) .resize-handle--bottom,
|
|
7437
|
+
:host([placement="side"]) .resize-handle--top-left,
|
|
7438
|
+
:host([placement="side"]) .resize-handle--top-right,
|
|
7439
|
+
:host([placement="side"]) .resize-handle--bottom-left,
|
|
7440
|
+
:host([placement="side"]) .resize-handle--bottom-right {
|
|
7441
|
+
display: none;
|
|
7018
7442
|
}
|
|
7019
7443
|
|
|
7020
|
-
/*
|
|
7021
|
-
:host([placement="sidebar"]
|
|
7022
|
-
|
|
7023
|
-
|
|
7444
|
+
/* The vertical edges run the full height once no corner shares them. */
|
|
7445
|
+
:host([placement="sidebar"]) .resize-handle--left,
|
|
7446
|
+
:host([placement="sidebar"]) .resize-handle--right,
|
|
7447
|
+
:host([placement="side"]) .resize-handle--left,
|
|
7448
|
+
:host([placement="side"]) .resize-handle--right {
|
|
7449
|
+
top: 0;
|
|
7450
|
+
bottom: 0;
|
|
7451
|
+
width: var(--_grip-edge-docked);
|
|
7024
7452
|
}
|
|
7025
7453
|
|
|
7026
7454
|
/* Full-bleed: nothing to drag. */
|
|
@@ -7029,9 +7457,62 @@ var STYLES = `
|
|
|
7029
7457
|
display: none;
|
|
7030
7458
|
}
|
|
7031
7459
|
|
|
7032
|
-
.
|
|
7460
|
+
/* The visible mark on a grip.
|
|
7461
|
+
|
|
7462
|
+
Filling the whole strip was what the single corner grip did, and at 14px
|
|
7463
|
+
square nobody ever saw it. On a strip running the length of an edge the same
|
|
7464
|
+
fill reads as a border the panel grew -- square ended, stopping short of the
|
|
7465
|
+
corner radius at both ends, and easily mistaken for a rendering fault rather
|
|
7466
|
+
than for something to grab.
|
|
7467
|
+
|
|
7468
|
+
So the hit area stays the full strip and the mark is a short pill centred on
|
|
7469
|
+
it, which cannot be read as an edge of anything and never meets the radius.
|
|
7470
|
+
|
|
7471
|
+
It shows on hover and focus as well as during the drag. With eight grips, a
|
|
7472
|
+
mark that appears only once you are already dragging is a mark that never
|
|
7473
|
+
told anyone the grips were there. */
|
|
7474
|
+
.resize-handle::after {
|
|
7475
|
+
content: "";
|
|
7476
|
+
position: absolute;
|
|
7477
|
+
top: 50%;
|
|
7478
|
+
left: 50%;
|
|
7479
|
+
transform: translate(-50%, -50%);
|
|
7480
|
+
border-radius: 999px;
|
|
7033
7481
|
background: var(--_accent);
|
|
7034
|
-
opacity: 0
|
|
7482
|
+
opacity: 0;
|
|
7483
|
+
transition: opacity var(--_motion) var(--_ease);
|
|
7484
|
+
}
|
|
7485
|
+
|
|
7486
|
+
.resize-handle--top::after,
|
|
7487
|
+
.resize-handle--bottom::after {
|
|
7488
|
+
width: var(--_grip-mark-length);
|
|
7489
|
+
height: var(--_grip-mark-thickness);
|
|
7490
|
+
}
|
|
7491
|
+
|
|
7492
|
+
.resize-handle--left::after,
|
|
7493
|
+
.resize-handle--right::after {
|
|
7494
|
+
width: var(--_grip-mark-thickness);
|
|
7495
|
+
height: var(--_grip-mark-length);
|
|
7496
|
+
}
|
|
7497
|
+
|
|
7498
|
+
/* A corner has no length to run along, so it gets a dot instead of a pill. */
|
|
7499
|
+
.resize-handle--top-left::after,
|
|
7500
|
+
.resize-handle--top-right::after,
|
|
7501
|
+
.resize-handle--bottom-left::after,
|
|
7502
|
+
.resize-handle--bottom-right::after {
|
|
7503
|
+
width: var(--_grip-mark-thickness);
|
|
7504
|
+
height: var(--_grip-mark-thickness);
|
|
7505
|
+
}
|
|
7506
|
+
|
|
7507
|
+
.resize-handle:hover::after,
|
|
7508
|
+
.resize-handle:focus-visible::after {
|
|
7509
|
+
opacity: 0.5;
|
|
7510
|
+
}
|
|
7511
|
+
|
|
7512
|
+
/* Equal specificity to the pair above, so source order is what makes the drag
|
|
7513
|
+
the stronger of the two states. */
|
|
7514
|
+
.resize-handle[data-dragging]::after {
|
|
7515
|
+
opacity: 0.9;
|
|
7035
7516
|
}
|
|
7036
7517
|
|
|
7037
7518
|
/* \u2500\u2500 Composer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
@@ -7145,7 +7626,7 @@ var STYLES = `
|
|
|
7145
7626
|
border: none;
|
|
7146
7627
|
border-radius: 50%;
|
|
7147
7628
|
background: var(--_accent);
|
|
7148
|
-
color:
|
|
7629
|
+
color: var(--_on-accent);
|
|
7149
7630
|
font: inherit;
|
|
7150
7631
|
line-height: 1;
|
|
7151
7632
|
cursor: pointer;
|
|
@@ -7219,13 +7700,13 @@ var STYLES = `
|
|
|
7219
7700
|
/* Recording: a red tint + a gentle pulse so it's clearly "live". */
|
|
7220
7701
|
.voice-btn[data-state="recording"] {
|
|
7221
7702
|
background: var(--_danger);
|
|
7222
|
-
color:
|
|
7703
|
+
color: var(--_on-danger);
|
|
7223
7704
|
animation: ag-ui-voice-pulse 1.2s ease-in-out infinite;
|
|
7224
7705
|
}
|
|
7225
7706
|
|
|
7226
7707
|
.voice-btn[data-state="recording"]:hover {
|
|
7227
7708
|
background: var(--_danger);
|
|
7228
|
-
color:
|
|
7709
|
+
color: var(--_on-danger);
|
|
7229
7710
|
}
|
|
7230
7711
|
|
|
7231
7712
|
@keyframes ag-ui-voice-pulse {
|
|
@@ -7515,7 +7996,7 @@ var STYLES = `
|
|
|
7515
7996
|
.confirm-btn--confirm {
|
|
7516
7997
|
border-color: var(--_accent);
|
|
7517
7998
|
background: var(--_accent);
|
|
7518
|
-
color:
|
|
7999
|
+
color: var(--_on-accent);
|
|
7519
8000
|
}
|
|
7520
8001
|
|
|
7521
8002
|
/* The session waiver. Deliberately the quietest of the three: it is the widest
|
|
@@ -7583,16 +8064,29 @@ var STYLES = `
|
|
|
7583
8064
|
margin-top: -6px;
|
|
7584
8065
|
}
|
|
7585
8066
|
|
|
8067
|
+
/* The row's controls are icon-only, so the box is the whole target. Sized from
|
|
8068
|
+
a variable a host can raise, with a floor rather than a fixed height: the
|
|
8069
|
+
compact density shrinks the font, and a target that shrinks with it lands
|
|
8070
|
+
under the 24px minimum that makes a control reliably tappable. It used to,
|
|
8071
|
+
at roughly 20px square. */
|
|
7586
8072
|
.message-action {
|
|
8073
|
+
display: inline-flex;
|
|
8074
|
+
align-items: center;
|
|
8075
|
+
justify-content: center;
|
|
8076
|
+
box-sizing: border-box;
|
|
8077
|
+
min-width: var(--_action-size);
|
|
8078
|
+
min-height: var(--_action-size);
|
|
8079
|
+
padding: 4px;
|
|
7587
8080
|
border: none;
|
|
7588
8081
|
border-radius: 6px;
|
|
7589
|
-
padding: 2px 6px;
|
|
7590
8082
|
font: inherit;
|
|
7591
8083
|
line-height: 1.2;
|
|
7592
8084
|
cursor: pointer;
|
|
7593
8085
|
background: transparent;
|
|
7594
8086
|
color: var(--_muted);
|
|
7595
8087
|
opacity: 0.75;
|
|
8088
|
+
/* The tooltip below is positioned against this box. */
|
|
8089
|
+
position: relative;
|
|
7596
8090
|
}
|
|
7597
8091
|
|
|
7598
8092
|
.message-action:hover,
|
|
@@ -7601,6 +8095,61 @@ var STYLES = `
|
|
|
7601
8095
|
background: var(--_border);
|
|
7602
8096
|
}
|
|
7603
8097
|
|
|
8098
|
+
.message-action-icon {
|
|
8099
|
+
display: inline-flex;
|
|
8100
|
+
width: var(--_action-icon-size);
|
|
8101
|
+
height: var(--_action-icon-size);
|
|
8102
|
+
}
|
|
8103
|
+
|
|
8104
|
+
.message-action-icon .glyph {
|
|
8105
|
+
width: 100%;
|
|
8106
|
+
height: 100%;
|
|
8107
|
+
}
|
|
8108
|
+
|
|
8109
|
+
/* The label, drawn rather than left to the browser.
|
|
8110
|
+
|
|
8111
|
+
A title attribute is the usual answer and covers only half the readers: it
|
|
8112
|
+
never appears on keyboard focus, so tabbing onto an icon-only control shows
|
|
8113
|
+
nothing at all. The attribute stays for the pointer users who expect it, and
|
|
8114
|
+
this shows the same words on hover and on focus alike.
|
|
8115
|
+
|
|
8116
|
+
Left-aligned rather than centred because the row sits at the left edge of an
|
|
8117
|
+
answer inside a scrolling column, and a centred tooltip on the first control
|
|
8118
|
+
is clipped by that column. Growing rightward keeps it inside.
|
|
8119
|
+
|
|
8120
|
+
Not exposed to assistive technology: the button already carries the same
|
|
8121
|
+
string as its accessible name, and this would be a second copy of it. */
|
|
8122
|
+
.message-action::after {
|
|
8123
|
+
content: attr(data-tooltip);
|
|
8124
|
+
position: absolute;
|
|
8125
|
+
bottom: calc(100% + 4px);
|
|
8126
|
+
left: 0;
|
|
8127
|
+
z-index: 3;
|
|
8128
|
+
padding: 3px 6px;
|
|
8129
|
+
border-radius: 4px;
|
|
8130
|
+
background: var(--_tooltip-bg);
|
|
8131
|
+
color: var(--_tooltip-fg);
|
|
8132
|
+
font-size: 11px;
|
|
8133
|
+
line-height: 1.4;
|
|
8134
|
+
white-space: nowrap;
|
|
8135
|
+
pointer-events: none;
|
|
8136
|
+
opacity: 0;
|
|
8137
|
+
transition: opacity var(--_motion) var(--_ease);
|
|
8138
|
+
}
|
|
8139
|
+
|
|
8140
|
+
.message-action:hover::after,
|
|
8141
|
+
.message-action:focus-visible::after {
|
|
8142
|
+
opacity: 1;
|
|
8143
|
+
}
|
|
8144
|
+
|
|
8145
|
+
/* Touch has no hover to reveal it, and a tooltip that latches open under a
|
|
8146
|
+
finger covers the answer it belongs to. */
|
|
8147
|
+
@media (hover: none) {
|
|
8148
|
+
.message-action::after {
|
|
8149
|
+
content: none;
|
|
8150
|
+
}
|
|
8151
|
+
}
|
|
8152
|
+
|
|
7604
8153
|
.message-action[aria-pressed="true"] {
|
|
7605
8154
|
opacity: 1;
|
|
7606
8155
|
color: var(--_accent);
|
|
@@ -7658,7 +8207,7 @@ var STYLES = `
|
|
|
7658
8207
|
.approval-btn--approve {
|
|
7659
8208
|
border-color: var(--_accent);
|
|
7660
8209
|
background: var(--_accent);
|
|
7661
|
-
color:
|
|
8210
|
+
color: var(--_on-accent);
|
|
7662
8211
|
}
|
|
7663
8212
|
|
|
7664
8213
|
/* Question card \u2014 the built-in ask_user prompt (radios and/or free text). */
|
|
@@ -7724,7 +8273,7 @@ var STYLES = `
|
|
|
7724
8273
|
font-weight: 600;
|
|
7725
8274
|
cursor: pointer;
|
|
7726
8275
|
background: var(--_accent);
|
|
7727
|
-
color:
|
|
8276
|
+
color: var(--_on-accent);
|
|
7728
8277
|
}
|
|
7729
8278
|
|
|
7730
8279
|
.question-btn:disabled {
|
|
@@ -7993,7 +8542,7 @@ var STYLES = `
|
|
|
7993
8542
|
font-weight: 600;
|
|
7994
8543
|
border-color: var(--_accent);
|
|
7995
8544
|
background: var(--_accent);
|
|
7996
|
-
color:
|
|
8545
|
+
color: var(--_on-accent);
|
|
7997
8546
|
}
|
|
7998
8547
|
|
|
7999
8548
|
.checkpoint-fork:hover {
|
|
@@ -8168,7 +8717,7 @@ var STYLES = `
|
|
|
8168
8717
|
border: none;
|
|
8169
8718
|
border-radius: 6px;
|
|
8170
8719
|
background: var(--_danger);
|
|
8171
|
-
color:
|
|
8720
|
+
color: var(--_on-danger);
|
|
8172
8721
|
padding: 3px 10px;
|
|
8173
8722
|
font: inherit;
|
|
8174
8723
|
cursor: pointer;
|
|
@@ -8201,6 +8750,17 @@ var STYLES = `
|
|
|
8201
8750
|
var SubAgentPanel = class {
|
|
8202
8751
|
/** The panel's root; append this into the delegating card's slot. */
|
|
8203
8752
|
element;
|
|
8753
|
+
/**
|
|
8754
|
+
* The child agent's name, as the last update that carried one gave it.
|
|
8755
|
+
*
|
|
8756
|
+
* Read back rather than only written to the DOM, because the two carriers
|
|
8757
|
+
* split the name away from the close: `SUBAGENT_STARTED` names the agent and
|
|
8758
|
+
* `SUBAGENT_FINISHED` carries only an id, so whoever words the closing line
|
|
8759
|
+
* has to recover the name from what the delegation already told it.
|
|
8760
|
+
*/
|
|
8761
|
+
get agent() {
|
|
8762
|
+
return this.#agent;
|
|
8763
|
+
}
|
|
8204
8764
|
/**
|
|
8205
8765
|
* The collapsed row, which is the expander as well as the status.
|
|
8206
8766
|
*
|
|
@@ -8213,6 +8773,7 @@ var SubAgentPanel = class {
|
|
|
8213
8773
|
#steps;
|
|
8214
8774
|
/** The child's tool calls, keyed by the child's own call id. */
|
|
8215
8775
|
#stepRows = /* @__PURE__ */ new Map();
|
|
8776
|
+
#agent = null;
|
|
8216
8777
|
constructor(strings = DEFAULT_UI_STRINGS) {
|
|
8217
8778
|
this.element = document.createElement("div");
|
|
8218
8779
|
this.element.className = "subagent";
|
|
@@ -8254,6 +8815,7 @@ var SubAgentPanel = class {
|
|
|
8254
8815
|
report(update) {
|
|
8255
8816
|
this.element.setAttribute("data-phase", update.phase);
|
|
8256
8817
|
if (update.agent !== null) {
|
|
8818
|
+
this.#agent = update.agent;
|
|
8257
8819
|
this.element.setAttribute("data-agent", update.agent);
|
|
8258
8820
|
}
|
|
8259
8821
|
if (update.status !== null) {
|
|
@@ -8732,11 +9294,11 @@ function resultLabels(strings) {
|
|
|
8732
9294
|
[TOOL_CALL_STATUS.DECLINED]: strings.declinedLabel
|
|
8733
9295
|
};
|
|
8734
9296
|
}
|
|
8735
|
-
function formatPayload(
|
|
9297
|
+
function formatPayload(text4) {
|
|
8736
9298
|
try {
|
|
8737
|
-
return JSON.stringify(JSON.parse(
|
|
9299
|
+
return JSON.stringify(JSON.parse(text4), null, 2);
|
|
8738
9300
|
} catch {
|
|
8739
|
-
return
|
|
9301
|
+
return text4;
|
|
8740
9302
|
}
|
|
8741
9303
|
}
|
|
8742
9304
|
var ToolCallCard = class {
|
|
@@ -8885,7 +9447,7 @@ var ToolCallCard = class {
|
|
|
8885
9447
|
* Flip the status pill to `status` and fill in the result region, whose
|
|
8886
9448
|
* heading names the outcome (result / error / declined).
|
|
8887
9449
|
*/
|
|
8888
|
-
settle(status,
|
|
9450
|
+
settle(status, text4) {
|
|
8889
9451
|
if (this.#settled) {
|
|
8890
9452
|
return;
|
|
8891
9453
|
}
|
|
@@ -8895,8 +9457,8 @@ var ToolCallCard = class {
|
|
|
8895
9457
|
this.#resultLabel.textContent = resultLabels(this.#strings)[status];
|
|
8896
9458
|
this.#renderPayload(
|
|
8897
9459
|
this.#resultBody,
|
|
8898
|
-
{ kind: "result", toolName: this.#name, status, text:
|
|
8899
|
-
formatPayload(
|
|
9460
|
+
{ kind: "result", toolName: this.#name, status, text: text4 },
|
|
9461
|
+
formatPayload(text4)
|
|
8900
9462
|
);
|
|
8901
9463
|
this.#resultSection.hidden = false;
|
|
8902
9464
|
}
|
|
@@ -9056,7 +9618,7 @@ var VoiceInput = class {
|
|
|
9056
9618
|
this.#setState("transcribing");
|
|
9057
9619
|
const audio = new Blob(this.#chunks, { type: mimeType || "audio/webm" });
|
|
9058
9620
|
try {
|
|
9059
|
-
const
|
|
9621
|
+
const text4 = await this.#transcribe(audio);
|
|
9060
9622
|
this.#setState("idle");
|
|
9061
9623
|
if (this.#hitCap) {
|
|
9062
9624
|
this.element.title = this.#strings.recordingLimit.replace(
|
|
@@ -9064,8 +9626,8 @@ var VoiceInput = class {
|
|
|
9064
9626
|
String(MAX_RECORDING_MS / 6e4)
|
|
9065
9627
|
);
|
|
9066
9628
|
}
|
|
9067
|
-
if (
|
|
9068
|
-
this.#onText(
|
|
9629
|
+
if (text4 !== "") {
|
|
9630
|
+
this.#onText(text4);
|
|
9069
9631
|
}
|
|
9070
9632
|
} catch (error) {
|
|
9071
9633
|
this.#fail(error instanceof Error ? error.message : this.#strings.transcriptionFailed);
|
|
@@ -9398,6 +9960,22 @@ var AgUiClient = class {
|
|
|
9398
9960
|
onCustomEvent({ event }) {
|
|
9399
9961
|
h.onCustomEvent(event.name, event.value);
|
|
9400
9962
|
},
|
|
9963
|
+
// The delegation lifecycle. Forwarded rather than interpreted here, for
|
|
9964
|
+
// the reason every other subscriber in this block is thin: this file
|
|
9965
|
+
// adapts the protocol to the handler surface, and what a delegation looks
|
|
9966
|
+
// like on screen is the element's business.
|
|
9967
|
+
//
|
|
9968
|
+
// `parentToolCallId` is optional on the wire and normalised to `null` so
|
|
9969
|
+
// the handler has one absent-value to check rather than two.
|
|
9970
|
+
onSubagentStartedEvent({ event }) {
|
|
9971
|
+
h.onSubAgentStarted(event.subagentRunId, event.name, event.parentToolCallId ?? null);
|
|
9972
|
+
},
|
|
9973
|
+
onSubagentFinishedEvent({ event }) {
|
|
9974
|
+
h.onSubAgentFinished(event.subagentRunId);
|
|
9975
|
+
},
|
|
9976
|
+
onSubagentErrorEvent({ event }) {
|
|
9977
|
+
h.onSubAgentError(event.subagentRunId, event.message);
|
|
9978
|
+
},
|
|
9401
9979
|
onMessagesSnapshotEvent({ event }) {
|
|
9402
9980
|
h.onMessagesSnapshot(event.messages);
|
|
9403
9981
|
},
|
|
@@ -9679,9 +10257,9 @@ function isOwnedSuffix(suffix) {
|
|
|
9679
10257
|
function deriveTitle(messages) {
|
|
9680
10258
|
for (const message of messages) {
|
|
9681
10259
|
if (message.role === "user") {
|
|
9682
|
-
const
|
|
9683
|
-
if (
|
|
9684
|
-
return truncate(
|
|
10260
|
+
const text4 = cleanText(message.content);
|
|
10261
|
+
if (text4 !== "") {
|
|
10262
|
+
return truncate(text4, TITLE_LIMIT);
|
|
9685
10263
|
}
|
|
9686
10264
|
}
|
|
9687
10265
|
}
|
|
@@ -9689,9 +10267,9 @@ function deriveTitle(messages) {
|
|
|
9689
10267
|
}
|
|
9690
10268
|
function derivePreview(messages) {
|
|
9691
10269
|
for (const message of [...messages].reverse()) {
|
|
9692
|
-
const
|
|
9693
|
-
if (
|
|
9694
|
-
return truncate(
|
|
10270
|
+
const text4 = cleanText(message.content);
|
|
10271
|
+
if (text4 !== "") {
|
|
10272
|
+
return truncate(text4, PREVIEW_LIMIT);
|
|
9695
10273
|
}
|
|
9696
10274
|
}
|
|
9697
10275
|
return "";
|
|
@@ -9699,8 +10277,8 @@ function derivePreview(messages) {
|
|
|
9699
10277
|
function cleanText(content) {
|
|
9700
10278
|
return typeof content === "string" ? content.replace(/\s+/g, " ").trim() : "";
|
|
9701
10279
|
}
|
|
9702
|
-
function truncate(
|
|
9703
|
-
return
|
|
10280
|
+
function truncate(text4, limit) {
|
|
10281
|
+
return text4.length <= limit ? text4 : `${text4.slice(0, limit - 1).trimEnd()}\u2026`;
|
|
9704
10282
|
}
|
|
9705
10283
|
|
|
9706
10284
|
// src/core/create_http_agent.ts
|
|
@@ -10104,6 +10682,18 @@ function isCredentialsMode(value) {
|
|
|
10104
10682
|
var COLLAPSED_KEY = "ag-ui-chat:collapsed";
|
|
10105
10683
|
var SIZE_KEY = "ag-ui-chat:size";
|
|
10106
10684
|
var THEME_KEY = "ag-ui-chat:theme";
|
|
10685
|
+
var LAUNCHER_KEY = "ag-ui-chat:launcher";
|
|
10686
|
+
var DRAGGABLE_PLACEMENTS = /* @__PURE__ */ new Set([null, "", "floating", "bottom-left"]);
|
|
10687
|
+
var RESIZE_GRIPS = [
|
|
10688
|
+
{ y: "top" },
|
|
10689
|
+
{ y: "bottom" },
|
|
10690
|
+
{ x: "left" },
|
|
10691
|
+
{ x: "right" },
|
|
10692
|
+
{ x: "left", y: "top" },
|
|
10693
|
+
{ x: "right", y: "top" },
|
|
10694
|
+
{ x: "left", y: "bottom" },
|
|
10695
|
+
{ x: "right", y: "bottom" }
|
|
10696
|
+
];
|
|
10107
10697
|
var QUOTE_GAP = 6;
|
|
10108
10698
|
var CLAIMED_NAMESPACES = /* @__PURE__ */ new Set();
|
|
10109
10699
|
var AgUiChat = class extends HTMLElement {
|
|
@@ -10380,6 +10970,17 @@ var AgUiChat = class extends HTMLElement {
|
|
|
10380
10970
|
* approval prompt already uses.
|
|
10381
10971
|
*/
|
|
10382
10972
|
#subagentPanels = /* @__PURE__ */ new Map();
|
|
10973
|
+
/**
|
|
10974
|
+
* Which delegation each live `subagentRunId` belongs to.
|
|
10975
|
+
*
|
|
10976
|
+
* The protocol's closing events -- `SUBAGENT_FINISHED` and `SUBAGENT_ERROR`
|
|
10977
|
+
* -- carry the child's run id and nothing else, while everything drawn here
|
|
10978
|
+
* is keyed on the parent's `delegate_task` call id. `SUBAGENT_STARTED` is the
|
|
10979
|
+
* one event carrying both, so the pairing is recorded there and read back on
|
|
10980
|
+
* the close. A close naming a run this never saw open is dropped, which is
|
|
10981
|
+
* the same refusal a step for an undrawn card gets.
|
|
10982
|
+
*/
|
|
10983
|
+
#subagentRunDelegations = /* @__PURE__ */ new Map();
|
|
10383
10984
|
/**
|
|
10384
10985
|
* Call ids whose card was already settled from a streamed server-side result
|
|
10385
10986
|
* (`TOOL_CALL_RESULT`), so the post-run executeTool sweep doesn't overwrite
|
|
@@ -10504,6 +11105,32 @@ var AgUiChat = class extends HTMLElement {
|
|
|
10504
11105
|
#emptyWrap;
|
|
10505
11106
|
/** Upload tray; created on connect only when `data-attachments-url` is set. */
|
|
10506
11107
|
#attachTray = null;
|
|
11108
|
+
/**
|
|
11109
|
+
* Where the user dragged the launcher, in viewport coordinates, or null
|
|
11110
|
+
* while the host's own CSS still places it. Set means this element owns its
|
|
11111
|
+
* position -- see #applyLauncherPlacement for what that costs the host.
|
|
11112
|
+
*/
|
|
11113
|
+
#launcherPos = null;
|
|
11114
|
+
/**
|
|
11115
|
+
* The corner the panel opens away from, once this element is placing itself.
|
|
11116
|
+
* Null means the host's layout still decides, and the anchor is measured.
|
|
11117
|
+
*/
|
|
11118
|
+
#expandCorner = null;
|
|
11119
|
+
/**
|
|
11120
|
+
* The edges the layout is holding still, as last measured. Cached because a
|
|
11121
|
+
* resize reads it per pointer move and measuring forces a reflow -- thirty a
|
|
11122
|
+
* second while the panel is already being laid out on every one of them.
|
|
11123
|
+
*/
|
|
11124
|
+
#anchor = { x: "right", y: "bottom" };
|
|
11125
|
+
/** The eight grips, by name, so the keyboard-reachable one can be moved. */
|
|
11126
|
+
#resizeHandles = /* @__PURE__ */ new Map();
|
|
11127
|
+
/**
|
|
11128
|
+
* Re-clamp the dragged launcher when the window changes size. Bound once as
|
|
11129
|
+
* a field so `removeEventListener` on disconnect gets the same reference.
|
|
11130
|
+
*/
|
|
11131
|
+
#onViewportResize = () => {
|
|
11132
|
+
this.#restoreLauncherPosition();
|
|
11133
|
+
};
|
|
10507
11134
|
/** Mic button mount point (input row); the control mounts on connect when enabled. */
|
|
10508
11135
|
#voiceSlot;
|
|
10509
11136
|
/** Voice-input control; created on connect when transcription is available. */
|
|
@@ -10712,6 +11339,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
10712
11339
|
}
|
|
10713
11340
|
if (name === "placement") {
|
|
10714
11341
|
this.#releaseOwnedAxes();
|
|
11342
|
+
this.#releaseLauncherPosition();
|
|
10715
11343
|
requestAnimationFrame(() => this.#syncResizeAnchor());
|
|
10716
11344
|
return;
|
|
10717
11345
|
}
|
|
@@ -11059,7 +11687,10 @@ var AgUiChat = class extends HTMLElement {
|
|
|
11059
11687
|
connectedCallback() {
|
|
11060
11688
|
this.#storageNs = this.#claimNamespace();
|
|
11061
11689
|
this.#applySize(this.#readSize());
|
|
11062
|
-
requestAnimationFrame(() =>
|
|
11690
|
+
requestAnimationFrame(() => {
|
|
11691
|
+
this.#restoreLauncherPosition();
|
|
11692
|
+
this.#syncResizeAnchor();
|
|
11693
|
+
});
|
|
11063
11694
|
this.#strings = mergeUiStrings({ ...this.#readStringOverrides(), ...this.strings });
|
|
11064
11695
|
if (this.getAttribute("data-theme-toggle") !== null) {
|
|
11065
11696
|
const saved = this.#readScopedItem(THEME_KEY);
|
|
@@ -11080,6 +11711,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
11080
11711
|
this.#builtinStore = namespace === "" ? this.conversationStore : new SessionStorageStore(namespace);
|
|
11081
11712
|
this.conversationStore = this.#builtinStore;
|
|
11082
11713
|
}
|
|
11714
|
+
window.addEventListener("resize", this.#onViewportResize);
|
|
11083
11715
|
this.#wireThreadStore();
|
|
11084
11716
|
this.#wireAttachments();
|
|
11085
11717
|
this.#wireVoice();
|
|
@@ -11142,6 +11774,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
11142
11774
|
*/
|
|
11143
11775
|
disconnectedCallback() {
|
|
11144
11776
|
this.#connected = false;
|
|
11777
|
+
window.removeEventListener("resize", this.#onViewportResize);
|
|
11145
11778
|
if (this.#claimedNs !== null) {
|
|
11146
11779
|
CLAIMED_NAMESPACES.delete(this.#claimedNs);
|
|
11147
11780
|
this.#claimedNs = null;
|
|
@@ -11214,6 +11847,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
11214
11847
|
this.#fileInput.accept = accept;
|
|
11215
11848
|
this.#attachButton.hidden = false;
|
|
11216
11849
|
this.#enableDragAndDrop();
|
|
11850
|
+
this.#enablePaste();
|
|
11217
11851
|
}
|
|
11218
11852
|
/** The built-in multipart upload handler for `data-attachments-url`, or `null`. */
|
|
11219
11853
|
#defaultUploadHandler(url) {
|
|
@@ -11243,7 +11877,7 @@ var AgUiChat = class extends HTMLElement {
|
|
|
11243
11877
|
}
|
|
11244
11878
|
this.#voice = new VoiceInput({
|
|
11245
11879
|
transcribe,
|
|
11246
|
-
onText: (
|
|
11880
|
+
onText: (text4) => this.#insertVoiceText(text4),
|
|
11247
11881
|
strings: this.#strings
|
|
11248
11882
|
});
|
|
11249
11883
|
this.#voiceSlot.appendChild(this.#voice.element);
|
|
@@ -11260,9 +11894,9 @@ var AgUiChat = class extends HTMLElement {
|
|
|
11260
11894
|
});
|
|
11261
11895
|
}
|
|
11262
11896
|
/** Drop a voice transcript into the composer (appended to any typed text). */
|
|
11263
|
-
#insertVoiceText(
|
|
11897
|
+
#insertVoiceText(text4) {
|
|
11264
11898
|
const current = this.#input.value.trim();
|
|
11265
|
-
this.#input.value = current === "" ?
|
|
11899
|
+
this.#input.value = current === "" ? text4 : `${current} ${text4}`;
|
|
11266
11900
|
this.#onInput();
|
|
11267
11901
|
this.#input.focus();
|
|
11268
11902
|
}
|
|
@@ -11280,8 +11914,8 @@ var AgUiChat = class extends HTMLElement {
|
|
|
11280
11914
|
*
|
|
11281
11915
|
* No-ops on text that is empty or only whitespace.
|
|
11282
11916
|
*/
|
|
11283
|
-
quote(
|
|
11284
|
-
const quoted = asQuote(
|
|
11917
|
+
quote(text4) {
|
|
11918
|
+
const quoted = asQuote(text4);
|
|
11285
11919
|
if (quoted === "") {
|
|
11286
11920
|
return;
|
|
11287
11921
|
}
|
|
@@ -11320,7 +11954,7 @@ ${quoted}`;
|
|
|
11320
11954
|
within,
|
|
11321
11955
|
label: this.#strings.quoteSelection,
|
|
11322
11956
|
exclude: this,
|
|
11323
|
-
onQuote: (
|
|
11957
|
+
onQuote: (text4) => this.quote(text4)
|
|
11324
11958
|
});
|
|
11325
11959
|
this.#pageQuote = offer;
|
|
11326
11960
|
return () => {
|
|
@@ -11448,6 +12082,37 @@ ${quoted}`;
|
|
|
11448
12082
|
}
|
|
11449
12083
|
});
|
|
11450
12084
|
}
|
|
12085
|
+
/**
|
|
12086
|
+
* Accept files pasted into the composer.
|
|
12087
|
+
*
|
|
12088
|
+
* The whole tray already exists behind this: a paste is one more way to hand
|
|
12089
|
+
* it a `File`, alongside the picker and a drop.
|
|
12090
|
+
*
|
|
12091
|
+
* Two rules keep it from stealing a paste that was never about files.
|
|
12092
|
+
* `clipboardData.files` is empty for text, so ordinary pasting is untouched.
|
|
12093
|
+
* And the default is only prevented when the clipboard carries **no text**:
|
|
12094
|
+
* copying a rich selection that happens to contain an image puts both on the
|
|
12095
|
+
* clipboard, and swallowing the words someone meant to paste in order to
|
|
12096
|
+
* attach a picture they did not is the worse of the two failures.
|
|
12097
|
+
*/
|
|
12098
|
+
#enablePaste() {
|
|
12099
|
+
this.#chat.addEventListener("paste", (event) => {
|
|
12100
|
+
const clipboard = event.clipboardData ?? null;
|
|
12101
|
+
if (clipboard === null) {
|
|
12102
|
+
return;
|
|
12103
|
+
}
|
|
12104
|
+
const files = Array.from(clipboard.files);
|
|
12105
|
+
if (files.length === 0) {
|
|
12106
|
+
return;
|
|
12107
|
+
}
|
|
12108
|
+
if (clipboard.getData("text/plain") === "") {
|
|
12109
|
+
event.preventDefault();
|
|
12110
|
+
}
|
|
12111
|
+
for (const file of files) {
|
|
12112
|
+
this.#attachTray?.add(named(file));
|
|
12113
|
+
}
|
|
12114
|
+
});
|
|
12115
|
+
}
|
|
11451
12116
|
/**
|
|
11452
12117
|
* When `data-threads-url` is set, route thread enumeration / load / rename /
|
|
11453
12118
|
* delete through that server endpoint (wrapping the current store as the
|
|
@@ -11555,18 +12220,18 @@ ${quoted}`;
|
|
|
11555
12220
|
void this.sendMessage(`/${skill.name}`);
|
|
11556
12221
|
return;
|
|
11557
12222
|
}
|
|
11558
|
-
const { text:
|
|
12223
|
+
const { text: text4, missing } = fillTemplate(skill.prompt, this.skillContext());
|
|
11559
12224
|
if (missing.length > 0) {
|
|
11560
12225
|
this.#skillHint.textContent = this.#strings.skillNeeds.replace("{title}", skill.title).replace("{fields}", missing.join(", "));
|
|
11561
12226
|
this.#skillHint.hidden = false;
|
|
11562
|
-
this.#input.value =
|
|
12227
|
+
this.#input.value = text4;
|
|
11563
12228
|
this.#autoGrow();
|
|
11564
12229
|
this.#input.focus();
|
|
11565
|
-
this.#selectFirstPlaceholder(
|
|
12230
|
+
this.#selectFirstPlaceholder(text4);
|
|
11566
12231
|
return;
|
|
11567
12232
|
}
|
|
11568
12233
|
this.#skillHint.hidden = true;
|
|
11569
|
-
this.#input.value =
|
|
12234
|
+
this.#input.value = text4;
|
|
11570
12235
|
this.#autoGrow();
|
|
11571
12236
|
if (skill.sendImmediately === false) {
|
|
11572
12237
|
this.#input.focus();
|
|
@@ -11580,9 +12245,9 @@ ${quoted}`;
|
|
|
11580
12245
|
* Typing then replaces it, which is the shortest path from "this skill needs
|
|
11581
12246
|
* a topic" to a sendable prompt.
|
|
11582
12247
|
*/
|
|
11583
|
-
#selectFirstPlaceholder(
|
|
11584
|
-
const start =
|
|
11585
|
-
this.#input.setSelectionRange(start,
|
|
12248
|
+
#selectFirstPlaceholder(text4) {
|
|
12249
|
+
const start = text4.indexOf("{");
|
|
12250
|
+
this.#input.setSelectionRange(start, text4.indexOf("}", start) + 1);
|
|
11586
12251
|
}
|
|
11587
12252
|
/** Whether the widget is collapsed (reflected as the `collapsed` attribute). */
|
|
11588
12253
|
get collapsed() {
|
|
@@ -11599,6 +12264,9 @@ ${quoted}`;
|
|
|
11599
12264
|
* its own chrome.
|
|
11600
12265
|
*/
|
|
11601
12266
|
setCollapsed(collapsed) {
|
|
12267
|
+
if (!collapsed) {
|
|
12268
|
+
this.#restoreLauncherPosition();
|
|
12269
|
+
}
|
|
11602
12270
|
if (collapsed) {
|
|
11603
12271
|
this.setAttribute("collapsed", "");
|
|
11604
12272
|
} else {
|
|
@@ -11671,13 +12339,32 @@ ${quoted}`;
|
|
|
11671
12339
|
const before = this.getBoundingClientRect();
|
|
11672
12340
|
const width = this.style.getPropertyValue("--ag-ui-width");
|
|
11673
12341
|
const height = this.style.getPropertyValue("--ag-ui-height");
|
|
11674
|
-
this.#
|
|
11675
|
-
const
|
|
12342
|
+
const shrunk = this.#probeAnchor(before, -1);
|
|
12343
|
+
const grown = shrunk.x === null || shrunk.y === null ? this.#probeAnchor(before, 1) : shrunk;
|
|
11676
12344
|
this.#restoreProperty("--ag-ui-width", width);
|
|
11677
12345
|
this.#restoreProperty("--ag-ui-height", height);
|
|
11678
12346
|
return {
|
|
11679
|
-
|
|
11680
|
-
|
|
12347
|
+
// Neither direction moved it: the axis cannot be resized at all, so the
|
|
12348
|
+
// floating default is the best answer available and is the one the
|
|
12349
|
+
// stylesheet would have used with no measurement at all.
|
|
12350
|
+
x: shrunk.x ?? grown.x ?? "right",
|
|
12351
|
+
y: shrunk.y ?? grown.y ?? "bottom"
|
|
12352
|
+
};
|
|
12353
|
+
}
|
|
12354
|
+
/**
|
|
12355
|
+
* Which edge each axis holds still when the panel changes size by `delta`.
|
|
12356
|
+
*
|
|
12357
|
+
* Null for an axis whose size did not change: nothing moved, so nothing was
|
|
12358
|
+
* learned, and reporting the unmoved edge as the pinned one would be exactly
|
|
12359
|
+
* backwards.
|
|
12360
|
+
*/
|
|
12361
|
+
#probeAnchor(before, delta) {
|
|
12362
|
+
this.#applySize({ width: before.width + delta, height: before.height + delta });
|
|
12363
|
+
const after = this.getBoundingClientRect();
|
|
12364
|
+
const moved = (a, b2) => Math.abs(a - b2) >= 0.5;
|
|
12365
|
+
return {
|
|
12366
|
+
x: moved(after.width, before.width) ? moved(after.left, before.left) ? "right" : "left" : null,
|
|
12367
|
+
y: moved(after.height, before.height) ? moved(after.top, before.top) ? "bottom" : "top" : null
|
|
11681
12368
|
};
|
|
11682
12369
|
}
|
|
11683
12370
|
/** Stamp the measured anchor so the shadow CSS can place the grip. */
|
|
@@ -11685,8 +12372,10 @@ ${quoted}`;
|
|
|
11685
12372
|
if (!this.#connected) {
|
|
11686
12373
|
return;
|
|
11687
12374
|
}
|
|
11688
|
-
const anchor = this.#measureAnchor();
|
|
12375
|
+
const anchor = this.#expandCorner ?? this.#measureAnchor();
|
|
12376
|
+
this.#anchor = anchor;
|
|
11689
12377
|
this.setAttribute("data-resize-anchor", `${anchor.y}-${anchor.x}`);
|
|
12378
|
+
this.#focusableGrip();
|
|
11690
12379
|
}
|
|
11691
12380
|
/** Put a custom property back to a previous value, or remove it if there was none. */
|
|
11692
12381
|
#restoreProperty(name, value) {
|
|
@@ -11735,6 +12424,203 @@ ${quoted}`;
|
|
|
11735
12424
|
this.style.removeProperty("--ag-ui-width");
|
|
11736
12425
|
}
|
|
11737
12426
|
}
|
|
12427
|
+
/**
|
|
12428
|
+
* Whether this placement lets the launcher be dragged, read per interaction
|
|
12429
|
+
* because `placement` is a live attribute. `data-launcher-drag="false"` opts
|
|
12430
|
+
* a host out without giving up the launcher itself.
|
|
12431
|
+
*/
|
|
12432
|
+
#launcherDraggable() {
|
|
12433
|
+
return this.getAttribute("data-launcher-drag") !== "false" && DRAGGABLE_PLACEMENTS.has(this.getAttribute("placement"));
|
|
12434
|
+
}
|
|
12435
|
+
/** The viewport the launcher and the panel both have to fit inside. */
|
|
12436
|
+
#viewport() {
|
|
12437
|
+
return { width: window.innerWidth, height: window.innerHeight };
|
|
12438
|
+
}
|
|
12439
|
+
/**
|
|
12440
|
+
* The launcher's box in viewport coordinates, with its transform divided out.
|
|
12441
|
+
*
|
|
12442
|
+
* The launcher is scaled in four states -- the collapse animation, hover,
|
|
12443
|
+
* press, and the resting scale(0.4) it sits at while the panel is open -- and
|
|
12444
|
+
* `getBoundingClientRect` reports every one of them. A drag that started from
|
|
12445
|
+
* that rect would begin a couple of pixels off, because a press is one of
|
|
12446
|
+
* those states.
|
|
12447
|
+
*
|
|
12448
|
+
* So the size comes from `offsetWidth`/`offsetHeight`, which are layout
|
|
12449
|
+
* metrics no transform reaches, and the position from the rect's *centre*,
|
|
12450
|
+
* which a centred scale is the one point that cannot move.
|
|
12451
|
+
*/
|
|
12452
|
+
#launcherBox() {
|
|
12453
|
+
const width = this.#launcher.offsetWidth;
|
|
12454
|
+
const height = this.#launcher.offsetHeight;
|
|
12455
|
+
const dragged = this.#launcherPos;
|
|
12456
|
+
if (dragged !== null) {
|
|
12457
|
+
return { left: dragged.left, top: dragged.top, width, height };
|
|
12458
|
+
}
|
|
12459
|
+
const rect = this.#launcher.getBoundingClientRect();
|
|
12460
|
+
return {
|
|
12461
|
+
left: rect.left + rect.width / 2 - width / 2,
|
|
12462
|
+
top: rect.top + rect.height / 2 - height / 2,
|
|
12463
|
+
width,
|
|
12464
|
+
height
|
|
12465
|
+
};
|
|
12466
|
+
}
|
|
12467
|
+
/**
|
|
12468
|
+
* Place the host box and the launcher for the position the user dragged to.
|
|
12469
|
+
*
|
|
12470
|
+
* This writes `--ag-ui-inset`, which is a host-facing property: an inline
|
|
12471
|
+
* value outranks the page's own rule for it, exactly as a dragged width
|
|
12472
|
+
* outranks a placement's. That is the intent -- the user moved it -- and it
|
|
12473
|
+
* is why switching to a placement that owns its position hands the property
|
|
12474
|
+
* back rather than leaving a stale inline one behind.
|
|
12475
|
+
*/
|
|
12476
|
+
#applyLauncherPlacement(at2) {
|
|
12477
|
+
if (!this.#launcherDraggable()) {
|
|
12478
|
+
return;
|
|
12479
|
+
}
|
|
12480
|
+
this.#launcherPos = at2;
|
|
12481
|
+
const panel = this.getBoundingClientRect();
|
|
12482
|
+
const placement = launcherPlacement(
|
|
12483
|
+
this.#launcherBox(),
|
|
12484
|
+
{ width: panel.width, height: panel.height },
|
|
12485
|
+
this.#viewport()
|
|
12486
|
+
);
|
|
12487
|
+
this.style.setProperty("--ag-ui-inset", placement.hostInset);
|
|
12488
|
+
this.style.setProperty("--ag-ui-launcher-inset", placement.launcherInset);
|
|
12489
|
+
this.#expandCorner = placement.corner;
|
|
12490
|
+
this.setAttribute("data-expand-corner", `${placement.corner.y}-${placement.corner.x}`);
|
|
12491
|
+
this.#syncResizeAnchor();
|
|
12492
|
+
}
|
|
12493
|
+
/** Move the launcher live during a drag, without persisting. */
|
|
12494
|
+
#moveLauncher(left, top) {
|
|
12495
|
+
this.#applyLauncherPlacement({ left, top });
|
|
12496
|
+
}
|
|
12497
|
+
/** Move the launcher and remember where, per tab, like the dragged size. */
|
|
12498
|
+
#commitLauncher(left, top) {
|
|
12499
|
+
this.#moveLauncher(left, top);
|
|
12500
|
+
this.#storeLauncherPosition();
|
|
12501
|
+
}
|
|
12502
|
+
/** Write the current launcher position, if this element owns one. */
|
|
12503
|
+
#storeLauncherPosition() {
|
|
12504
|
+
const position = this.#launcherPos;
|
|
12505
|
+
if (position === null) {
|
|
12506
|
+
return;
|
|
12507
|
+
}
|
|
12508
|
+
writeStoredItem(this.#storageKey(LAUNCHER_KEY), JSON.stringify(position));
|
|
12509
|
+
}
|
|
12510
|
+
/**
|
|
12511
|
+
* Re-apply the dragged position against the current viewport: on connect,
|
|
12512
|
+
* whenever the window resizes, and before an expand. The viewport that
|
|
12513
|
+
* stored a position may since have shrunk, and a launcher past the edge is
|
|
12514
|
+
* unreachable -- it is the only way back to a collapsed conversation.
|
|
12515
|
+
*/
|
|
12516
|
+
#restoreLauncherPosition() {
|
|
12517
|
+
const stored = this.#launcherPos ?? this.#readLauncherPosition();
|
|
12518
|
+
if (stored === null) {
|
|
12519
|
+
return;
|
|
12520
|
+
}
|
|
12521
|
+
const box = this.#launcherBox();
|
|
12522
|
+
this.#applyLauncherPlacement(
|
|
12523
|
+
clampLauncher({ ...box, left: stored.left, top: stored.top }, this.#viewport())
|
|
12524
|
+
);
|
|
12525
|
+
}
|
|
12526
|
+
/** The persisted launcher position for this instance, or null. */
|
|
12527
|
+
#readLauncherPosition() {
|
|
12528
|
+
const raw = this.#readScopedItem(LAUNCHER_KEY);
|
|
12529
|
+
if (raw === null) {
|
|
12530
|
+
return null;
|
|
12531
|
+
}
|
|
12532
|
+
try {
|
|
12533
|
+
const parsed = JSON.parse(raw);
|
|
12534
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
12535
|
+
return null;
|
|
12536
|
+
}
|
|
12537
|
+
const { left, top } = parsed;
|
|
12538
|
+
return typeof left === "number" && typeof top === "number" ? { left, top } : null;
|
|
12539
|
+
} catch {
|
|
12540
|
+
return null;
|
|
12541
|
+
}
|
|
12542
|
+
}
|
|
12543
|
+
/**
|
|
12544
|
+
* Give the position back to the host when the new placement owns it, the way
|
|
12545
|
+
* #releaseOwnedAxes gives back a size. Without this a dragged inset survives
|
|
12546
|
+
* the switch inline and pins a sidebar to wherever the floating launcher was.
|
|
12547
|
+
*/
|
|
12548
|
+
#releaseLauncherPosition() {
|
|
12549
|
+
if (this.#launcherDraggable()) {
|
|
12550
|
+
return;
|
|
12551
|
+
}
|
|
12552
|
+
this.#launcherPos = null;
|
|
12553
|
+
this.#expandCorner = null;
|
|
12554
|
+
this.style.removeProperty("--ag-ui-inset");
|
|
12555
|
+
this.style.removeProperty("--ag-ui-launcher-inset");
|
|
12556
|
+
this.removeAttribute("data-expand-corner");
|
|
12557
|
+
}
|
|
12558
|
+
/**
|
|
12559
|
+
* Apply the box a grip is asking for.
|
|
12560
|
+
*
|
|
12561
|
+
* The size is the easy half. The other half is that **dragging the edge the
|
|
12562
|
+
* layout is holding still moves the panel as well as resizing it**, and the
|
|
12563
|
+
* layout cannot express that on its own: a floating panel pinned bottom-right
|
|
12564
|
+
* cannot grow rightward, because its right edge is what the placement fixed.
|
|
12565
|
+
* So a grip on a pinned edge takes the position over -- which is the same
|
|
12566
|
+
* ownership the launcher drag takes, written the same way.
|
|
12567
|
+
*
|
|
12568
|
+
* A grip on a free edge writes nothing but the size, exactly as before, so a
|
|
12569
|
+
* host positioning the panel with its own rule keeps that rule until someone
|
|
12570
|
+
* drags the edge it was holding.
|
|
12571
|
+
*/
|
|
12572
|
+
#applyResize(grip, box) {
|
|
12573
|
+
this.#applySize({ width: box.right - box.left, height: box.bottom - box.top });
|
|
12574
|
+
if (grip.x !== this.#anchor.x && grip.y !== this.#anchor.y) {
|
|
12575
|
+
return;
|
|
12576
|
+
}
|
|
12577
|
+
const viewport = this.#viewport();
|
|
12578
|
+
const anchor = this.#anchor;
|
|
12579
|
+
const side = (value) => `${Math.round(value)}px`;
|
|
12580
|
+
this.style.setProperty(
|
|
12581
|
+
"--ag-ui-inset",
|
|
12582
|
+
[
|
|
12583
|
+
anchor.y === "top" ? side(box.top) : "auto",
|
|
12584
|
+
anchor.x === "right" ? side(viewport.width - box.right) : "auto",
|
|
12585
|
+
anchor.y === "bottom" ? side(viewport.height - box.bottom) : "auto",
|
|
12586
|
+
anchor.x === "left" ? side(box.left) : "auto"
|
|
12587
|
+
].join(" ")
|
|
12588
|
+
);
|
|
12589
|
+
if (this.#launcherPos !== null) {
|
|
12590
|
+
const size = this.#launcher.offsetWidth;
|
|
12591
|
+
this.#launcherPos = {
|
|
12592
|
+
left: anchor.x === "left" ? box.left : box.right - size,
|
|
12593
|
+
top: anchor.y === "top" ? box.top : box.bottom - size
|
|
12594
|
+
};
|
|
12595
|
+
}
|
|
12596
|
+
}
|
|
12597
|
+
/** Finish a resize: keep the box, remember it, and re-read the pinned edges. */
|
|
12598
|
+
#commitResize(grip, box) {
|
|
12599
|
+
this.#applyResize(grip, box);
|
|
12600
|
+
this.#persistSize({ width: box.right - box.left, height: box.bottom - box.top });
|
|
12601
|
+
this.#storeLauncherPosition();
|
|
12602
|
+
this.#syncResizeAnchor();
|
|
12603
|
+
}
|
|
12604
|
+
/**
|
|
12605
|
+
* Put the tab stop on the grip diagonally opposite the pinned corner.
|
|
12606
|
+
*
|
|
12607
|
+
* That is the corner a resize grows the panel from, so an arrow key there
|
|
12608
|
+
* changes the size and never the position -- the behaviour the single grip
|
|
12609
|
+
* this replaced had, kept for the one path that cannot simply grab a
|
|
12610
|
+
* different edge.
|
|
12611
|
+
*/
|
|
12612
|
+
#focusableGrip() {
|
|
12613
|
+
const free = `${this.#anchor.y === "top" ? "bottom" : "top"}-${this.#anchor.x === "left" ? "right" : "left"}`;
|
|
12614
|
+
for (const [name, handle] of this.#resizeHandles) {
|
|
12615
|
+
const reachable = name === free;
|
|
12616
|
+
handle.tabIndex = reachable ? 0 : -1;
|
|
12617
|
+
if (reachable) {
|
|
12618
|
+
handle.removeAttribute("aria-hidden");
|
|
12619
|
+
} else {
|
|
12620
|
+
handle.setAttribute("aria-hidden", "true");
|
|
12621
|
+
}
|
|
12622
|
+
}
|
|
12623
|
+
}
|
|
11738
12624
|
/** Persist a dragged size per tab, alongside the collapsed/theme preferences. */
|
|
11739
12625
|
#persistSize(size) {
|
|
11740
12626
|
const stored = { ...this.#readSize(), ...size };
|
|
@@ -11955,6 +12841,7 @@ ${quoted}`;
|
|
|
11955
12841
|
this.#hidePending();
|
|
11956
12842
|
this.#toolCards.clear();
|
|
11957
12843
|
this.#subagentPanels.clear();
|
|
12844
|
+
this.#subagentRunDelegations.clear();
|
|
11958
12845
|
this.#serverSettled.clear();
|
|
11959
12846
|
this.#cardElements.clear();
|
|
11960
12847
|
this.#activityBlocks.clear();
|
|
@@ -12102,11 +12989,11 @@ ${quoted}`;
|
|
|
12102
12989
|
* the full transcript — tool calls and their results — not just the prose.
|
|
12103
12990
|
*/
|
|
12104
12991
|
#renderHistoricMessage(message) {
|
|
12105
|
-
const
|
|
12992
|
+
const text4 = typeof message.content === "string" ? message.content : "";
|
|
12106
12993
|
if (message.role === MESSAGE_ROLE.USER) {
|
|
12107
12994
|
const attachments = messageAttachments(message);
|
|
12108
|
-
if (
|
|
12109
|
-
const bubble = this.appendMessage(MESSAGE_ROLE.USER,
|
|
12995
|
+
if (text4 !== "" || attachments.length > 0) {
|
|
12996
|
+
const bubble = this.appendMessage(MESSAGE_ROLE.USER, text4);
|
|
12110
12997
|
if (attachments.length > 0) {
|
|
12111
12998
|
bubble.appendChild(renderAttachmentChips(attachments));
|
|
12112
12999
|
}
|
|
@@ -12114,8 +13001,8 @@ ${quoted}`;
|
|
|
12114
13001
|
return;
|
|
12115
13002
|
}
|
|
12116
13003
|
if (message.role === MESSAGE_ROLE.ASSISTANT) {
|
|
12117
|
-
if (
|
|
12118
|
-
const restoredBubble = this.appendMessage(MESSAGE_ROLE.ASSISTANT,
|
|
13004
|
+
if (text4 !== "") {
|
|
13005
|
+
const restoredBubble = this.appendMessage(MESSAGE_ROLE.ASSISTANT, text4);
|
|
12119
13006
|
restoredBubble.classList.add("message--restored");
|
|
12120
13007
|
this.#attachActions(restoredBubble);
|
|
12121
13008
|
}
|
|
@@ -12409,19 +13296,27 @@ ${quoted}`;
|
|
|
12409
13296
|
this.#badge
|
|
12410
13297
|
);
|
|
12411
13298
|
this.#launcher.addEventListener("click", () => this.setCollapsed(false));
|
|
12412
|
-
this.#
|
|
12413
|
-
|
|
13299
|
+
enableLauncherDrag(this.#launcher, {
|
|
13300
|
+
enabled: () => this.collapsed && this.#launcherDraggable(),
|
|
13301
|
+
rect: () => this.#launcherBox(),
|
|
13302
|
+
viewport: () => this.#viewport(),
|
|
13303
|
+
apply: (left, top) => this.#moveLauncher(left, top),
|
|
13304
|
+
commit: (left, top) => this.#commitLauncher(left, top)
|
|
13305
|
+
});
|
|
13306
|
+
for (const grip of RESIZE_GRIPS) {
|
|
13307
|
+
const handle = createResizeHandle(grip, {
|
|
12414
13308
|
axis: () => this.#resizeAxis(),
|
|
12415
|
-
anchor: () => this.#measureAnchor(),
|
|
12416
13309
|
rect: () => this.getBoundingClientRect(),
|
|
12417
|
-
apply: (
|
|
12418
|
-
commit: (
|
|
12419
|
-
this.#persistSize(size);
|
|
12420
|
-
this.#syncResizeAnchor();
|
|
12421
|
-
},
|
|
13310
|
+
apply: (box) => this.#applyResize(grip, box),
|
|
13311
|
+
commit: (box) => this.#commitResize(grip, box),
|
|
12422
13312
|
label: this.#strings.resizePanel
|
|
12423
|
-
})
|
|
12424
|
-
|
|
13313
|
+
});
|
|
13314
|
+
handle.tabIndex = -1;
|
|
13315
|
+
handle.setAttribute("aria-hidden", "true");
|
|
13316
|
+
this.#resizeHandles.set(gripName(grip), handle);
|
|
13317
|
+
this.#chat.appendChild(handle);
|
|
13318
|
+
}
|
|
13319
|
+
this.#focusableGrip();
|
|
12425
13320
|
this.#adoptStyles();
|
|
12426
13321
|
this.#root.append(this.#announcer, this.#chat, this.#launcher);
|
|
12427
13322
|
}
|
|
@@ -12815,13 +13710,18 @@ ${quoted}`;
|
|
|
12815
13710
|
strings: this.#strings,
|
|
12816
13711
|
// Read at click time, not captured: a bubble rendered from markdown
|
|
12817
13712
|
// holds its text in the DOM, and that is what the user sees and means
|
|
12818
|
-
// to copy.
|
|
12819
|
-
|
|
13713
|
+
// to copy. Serialised rather than read off `textContent`, which welds
|
|
13714
|
+
// a table into one run of digits and picks up the code blocks' own
|
|
13715
|
+
// copy buttons on the way past.
|
|
13716
|
+
...copyable ? {
|
|
13717
|
+
text: () => copyPayload(bubble).text,
|
|
13718
|
+
html: () => copyPayload(bubble).html
|
|
13719
|
+
} : {},
|
|
12820
13720
|
...rateable ? {
|
|
12821
13721
|
onFeedback: (rating) => {
|
|
12822
13722
|
this.dispatchEvent(
|
|
12823
13723
|
new CustomEvent(FEEDBACK_EVENT, {
|
|
12824
|
-
detail: { content: bubble.
|
|
13724
|
+
detail: { content: copyPayload(bubble).text, rating },
|
|
12825
13725
|
bubbles: true,
|
|
12826
13726
|
composed: true
|
|
12827
13727
|
})
|
|
@@ -12837,7 +13737,7 @@ ${quoted}`;
|
|
|
12837
13737
|
/** Move the Retry button onto `bar`, taking it off whoever held it. */
|
|
12838
13738
|
#moveRetryTo(bar) {
|
|
12839
13739
|
this.#retryOwner?.querySelector(".message-action--retry")?.remove();
|
|
12840
|
-
const retry = messageActionButton("retry", this.#strings.retryMessage,
|
|
13740
|
+
const retry = messageActionButton("retry", this.#strings.retryMessage, ICON_RETRY);
|
|
12841
13741
|
retry.addEventListener("click", () => {
|
|
12842
13742
|
void this.retryLastTurn();
|
|
12843
13743
|
});
|
|
@@ -13081,6 +13981,31 @@ ${quoted}`;
|
|
|
13081
13981
|
})
|
|
13082
13982
|
);
|
|
13083
13983
|
},
|
|
13984
|
+
// The delegation's own lifetime, on the protocol's events rather than the
|
|
13985
|
+
// CUSTOM channel its steps ride. Both end at the same panel.
|
|
13986
|
+
onSubAgentStarted: (subagentRunId, agent, parentToolCallId) => {
|
|
13987
|
+
if (parentToolCallId === null) {
|
|
13988
|
+
return;
|
|
13989
|
+
}
|
|
13990
|
+
this.#subagentRunDelegations.set(subagentRunId, parentToolCallId);
|
|
13991
|
+
this.#applySubAgent({
|
|
13992
|
+
delegationId: parentToolCallId,
|
|
13993
|
+
agent: agent === "" ? null : agent,
|
|
13994
|
+
phase: SUBAGENT_PHASE.STARTED,
|
|
13995
|
+
status: this.#strings.subAgentDelegatedTo.replace("{agent}", agent),
|
|
13996
|
+
tool: null
|
|
13997
|
+
});
|
|
13998
|
+
},
|
|
13999
|
+
onSubAgentFinished: (subagentRunId) => {
|
|
14000
|
+
this.#closeSubAgent(subagentRunId, SUBAGENT_PHASE.FINISHED, null);
|
|
14001
|
+
},
|
|
14002
|
+
onSubAgentError: (subagentRunId, message) => {
|
|
14003
|
+
this.#closeSubAgent(
|
|
14004
|
+
subagentRunId,
|
|
14005
|
+
SUBAGENT_PHASE.FAILED,
|
|
14006
|
+
message === "" ? this.#strings.subAgentFailed : message
|
|
14007
|
+
);
|
|
14008
|
+
},
|
|
13084
14009
|
onMessagesSnapshot: () => {
|
|
13085
14010
|
this.#appendNotice("\u{1F504}", this.#strings.historyReplaced, "history-replaced");
|
|
13086
14011
|
},
|
|
@@ -13221,6 +14146,50 @@ ${quoted}`;
|
|
|
13221
14146
|
if (update === null) {
|
|
13222
14147
|
return;
|
|
13223
14148
|
}
|
|
14149
|
+
this.#applySubAgent(update);
|
|
14150
|
+
}
|
|
14151
|
+
/**
|
|
14152
|
+
* Fold one already-narrowed update into the delegation's panel.
|
|
14153
|
+
*
|
|
14154
|
+
* The join point of the two carriers, and the reason it is separate from
|
|
14155
|
+
* {@link #reportSubAgent}: a `CUSTOM` step arrives as `unknown` and has to be
|
|
14156
|
+
* vouched for, while a lifecycle event arrives typed off the protocol and has
|
|
14157
|
+
* nothing left to check. Both end up here, so the panel has one way in and
|
|
14158
|
+
* the phases stay a single state machine regardless of which wire they came
|
|
14159
|
+
* from.
|
|
14160
|
+
*/
|
|
14161
|
+
/**
|
|
14162
|
+
* Settle the delegation a closing lifecycle event names.
|
|
14163
|
+
*
|
|
14164
|
+
* `status` is the server's text on a failure and `null` on a success, where
|
|
14165
|
+
* the wording is this element's own -- the protocol's finish event carries no
|
|
14166
|
+
* message, which is the better shape for a localised UI and the reason
|
|
14167
|
+
* {@link UiStrings.subAgentFinished} exists.
|
|
14168
|
+
*
|
|
14169
|
+
* The pairing is deliberately not deleted on close. A panel outlives the
|
|
14170
|
+
* delegation it drew, the map is cleared with the transcript alongside the
|
|
14171
|
+
* panels, and forgetting the id here would only make a duplicate close draw
|
|
14172
|
+
* nothing instead of drawing the same settled row again.
|
|
14173
|
+
*/
|
|
14174
|
+
#closeSubAgent(subagentRunId, phase, status) {
|
|
14175
|
+
const delegationId = this.#subagentRunDelegations.get(subagentRunId);
|
|
14176
|
+
if (delegationId === void 0) {
|
|
14177
|
+
return;
|
|
14178
|
+
}
|
|
14179
|
+
const agent = this.#subagentPanels.get(delegationId)?.agent ?? null;
|
|
14180
|
+
this.#applySubAgent({
|
|
14181
|
+
delegationId,
|
|
14182
|
+
agent,
|
|
14183
|
+
phase,
|
|
14184
|
+
status: status === null ? this.#finishedLine(agent) : status,
|
|
14185
|
+
tool: null
|
|
14186
|
+
});
|
|
14187
|
+
}
|
|
14188
|
+
/** The row's line for a delegation that completed, named if its name is known. */
|
|
14189
|
+
#finishedLine(agent) {
|
|
14190
|
+
return agent === null ? this.#strings.subAgentWorking : this.#strings.subAgentFinished.replace("{agent}", agent);
|
|
14191
|
+
}
|
|
14192
|
+
#applySubAgent(update) {
|
|
13224
14193
|
const card = this.#toolCards.get(update.delegationId);
|
|
13225
14194
|
if (card === void 0) {
|
|
13226
14195
|
return;
|
|
@@ -13382,8 +14351,8 @@ ${quoted}`;
|
|
|
13382
14351
|
this.#appendNotice("\u2728", this.#strings.usingSkill.replace("{name}", skill), "skill");
|
|
13383
14352
|
return true;
|
|
13384
14353
|
}
|
|
13385
|
-
#appendNotice(icon,
|
|
13386
|
-
this.#ensureGroup().appendChild(renderRunNotice(icon,
|
|
14354
|
+
#appendNotice(icon, text4, kind) {
|
|
14355
|
+
this.#ensureGroup().appendChild(renderRunNotice(icon, text4, kind));
|
|
13387
14356
|
this.#updateEmptyState();
|
|
13388
14357
|
this.#scroller.follow();
|
|
13389
14358
|
}
|
|
@@ -13590,6 +14559,16 @@ function confirmPhrase(interrupt) {
|
|
|
13590
14559
|
function restoredToolCalls(value) {
|
|
13591
14560
|
return Array.isArray(value) ? value.filter(isRestoredToolCall) : [];
|
|
13592
14561
|
}
|
|
14562
|
+
function named(file) {
|
|
14563
|
+
if (file.name !== "") {
|
|
14564
|
+
return file;
|
|
14565
|
+
}
|
|
14566
|
+
const subtype = file.type.split("/")[1] ?? file.type;
|
|
14567
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
14568
|
+
return new File([file], subtype === "" ? `pasted-${stamp}` : `pasted-${stamp}.${subtype}`, {
|
|
14569
|
+
type: file.type
|
|
14570
|
+
});
|
|
14571
|
+
}
|
|
13593
14572
|
function isRestoredToolCall(value) {
|
|
13594
14573
|
if (typeof value !== "object" || value === null) {
|
|
13595
14574
|
return false;
|
|
@@ -13649,7 +14628,7 @@ function setControlValue(el2, value) {
|
|
|
13649
14628
|
}
|
|
13650
14629
|
|
|
13651
14630
|
// src/version.ts
|
|
13652
|
-
var VERSION = "0.
|
|
14631
|
+
var VERSION = "0.33.0";
|
|
13653
14632
|
export {
|
|
13654
14633
|
ATTACHMENT_EVENT,
|
|
13655
14634
|
AgUiChat,
|
|
@@ -13741,6 +14720,6 @@ export {
|
|
|
13741
14720
|
/*! Bundled license information:
|
|
13742
14721
|
|
|
13743
14722
|
dompurify/dist/purify.es.mjs:
|
|
13744
|
-
(*! @license DOMPurify 3.4.
|
|
14723
|
+
(*! @license DOMPurify 3.4.14 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.14/LICENSE *)
|
|
13745
14724
|
*/
|
|
13746
14725
|
//# sourceMappingURL=index.js.map
|