@artooi/ag-ui-web-component 0.33.1 → 0.34.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 +63 -1
- package/README.md +47 -3
- package/dist/ag-ui-web-component.bundle.js +106 -49
- package/dist/ag-ui-web-component.bundle.js.map +4 -4
- package/dist/constants.d.ts +7 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/index.js +433 -99
- package/dist/index.js.map +4 -4
- package/dist/ui/chart_block.d.ts +18 -0
- package/dist/ui/chart_block.d.ts.map +1 -1
- package/dist/ui/clamp_panel.d.ts +13 -0
- package/dist/ui/clamp_panel.d.ts.map +1 -0
- package/dist/ui/launcher_placement.d.ts.map +1 -1
- package/dist/ui/panel_drag.d.ts +40 -0
- package/dist/ui/panel_drag.d.ts.map +1 -0
- package/dist/ui/place_widget.d.ts +23 -0
- package/dist/ui/place_widget.d.ts.map +1 -0
- package/dist/ui/styles.d.ts +1 -1
- package/dist/ui/styles.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +8 -0
- package/src/core/ag_ui_chat.ts +207 -9
- package/src/ui/chart_block.ts +222 -57
- package/src/ui/clamp_panel.ts +24 -0
- package/src/ui/launcher_placement.ts +18 -54
- package/src/ui/panel_drag.ts +134 -0
- package/src/ui/place_widget.ts +56 -0
- package/src/ui/styles.ts +59 -2
- package/src/version.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -69,6 +69,7 @@ var ICON_FILE_IMAGE = `<svg class="glyph" viewBox="0 0 24 24" aria-hidden="true"
|
|
|
69
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>`;
|
|
70
70
|
var ICON_FILE_TEXT = `<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"/><path d="M8.5 13.5h7M8.5 17h4.5"/></svg>`;
|
|
71
71
|
var CHART_ACTIVITY_TYPE = "chart";
|
|
72
|
+
var EDGE_MARGIN = 24;
|
|
72
73
|
var ANNOUNCE_CLEAR_MS = 150;
|
|
73
74
|
|
|
74
75
|
// src/core/ag_ui_chat.ts
|
|
@@ -1093,11 +1094,14 @@ function accepts(accept, file) {
|
|
|
1093
1094
|
|
|
1094
1095
|
// src/ui/chart_block.ts
|
|
1095
1096
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1096
|
-
var WIDTH = 480;
|
|
1097
|
-
var HEIGHT = 220;
|
|
1098
1097
|
var PAD = { top: 20, right: 12, bottom: 30, left: 44 };
|
|
1099
|
-
var
|
|
1100
|
-
var
|
|
1098
|
+
var DEFAULT_WIDTH = 480;
|
|
1099
|
+
var MIN_WIDTH = 220;
|
|
1100
|
+
var HEIGHT_RATIO = 220 / 480;
|
|
1101
|
+
var MIN_HEIGHT = 160;
|
|
1102
|
+
var MAX_HEIGHT = 320;
|
|
1103
|
+
var WIDTH_STEP = 8;
|
|
1104
|
+
var AXIS_CHAR_WIDTH = 5.6;
|
|
1101
1105
|
var SERIES_COLORS = [
|
|
1102
1106
|
"var(--ag-ui-chart-1, #4f7cff)",
|
|
1103
1107
|
"var(--ag-ui-chart-2, #21b573)",
|
|
@@ -1109,6 +1113,16 @@ var SERIES_COLORS = [
|
|
|
1109
1113
|
function seriesColor(index) {
|
|
1110
1114
|
return SERIES_COLORS[index % SERIES_COLORS.length];
|
|
1111
1115
|
}
|
|
1116
|
+
function geometryFor(width) {
|
|
1117
|
+
const w = Math.max(MIN_WIDTH, width);
|
|
1118
|
+
const h = Math.min(MAX_HEIGHT, Math.max(MIN_HEIGHT, Math.round(w * HEIGHT_RATIO)));
|
|
1119
|
+
return {
|
|
1120
|
+
width: w,
|
|
1121
|
+
height: h,
|
|
1122
|
+
plotW: w - PAD.left - PAD.right,
|
|
1123
|
+
plotH: h - PAD.top - PAD.bottom
|
|
1124
|
+
};
|
|
1125
|
+
}
|
|
1112
1126
|
function el(name, attrs) {
|
|
1113
1127
|
const node = document.createElementNS(SVG_NS, name);
|
|
1114
1128
|
for (const [key, value] of Object.entries(attrs)) {
|
|
@@ -1143,21 +1157,26 @@ function extent(spec) {
|
|
|
1143
1157
|
const min = Math.min(0, ...values);
|
|
1144
1158
|
return max === min ? { min, max: max + 1 } : { min, max };
|
|
1145
1159
|
}
|
|
1146
|
-
function scaleY(value, min, max) {
|
|
1147
|
-
return PAD.top +
|
|
1160
|
+
function scaleY(value, min, max, geo) {
|
|
1161
|
+
return PAD.top + geo.plotH - (value - min) / (max - min) * geo.plotH;
|
|
1148
1162
|
}
|
|
1149
|
-
function bandCentre(index, count) {
|
|
1150
|
-
const step =
|
|
1163
|
+
function bandCentre(index, count, geo) {
|
|
1164
|
+
const step = geo.plotW / count;
|
|
1151
1165
|
return PAD.left + step * index + step / 2;
|
|
1152
1166
|
}
|
|
1153
|
-
function
|
|
1167
|
+
function labelStride(labels, geo) {
|
|
1168
|
+
const band = geo.plotW / labels.length;
|
|
1169
|
+
const widest = Math.max(...labels.map((label) => label.length)) * AXIS_CHAR_WIDTH;
|
|
1170
|
+
return Math.max(1, Math.ceil(widest / band));
|
|
1171
|
+
}
|
|
1172
|
+
function drawAxes(svg2, spec, geo, min, max) {
|
|
1154
1173
|
for (const value of [min, max]) {
|
|
1155
|
-
const y2 = scaleY(value, min, max);
|
|
1174
|
+
const y2 = scaleY(value, min, max, geo);
|
|
1156
1175
|
svg2.appendChild(
|
|
1157
1176
|
el("line", {
|
|
1158
1177
|
x1: PAD.left,
|
|
1159
1178
|
y1: y2,
|
|
1160
|
-
x2:
|
|
1179
|
+
x2: geo.width - PAD.right,
|
|
1161
1180
|
y2,
|
|
1162
1181
|
stroke: "currentColor",
|
|
1163
1182
|
"stroke-opacity": value === min ? 0.35 : 0.12
|
|
@@ -1167,23 +1186,27 @@ function drawAxes(svg2, spec, min, max) {
|
|
|
1167
1186
|
text(String(Math.round(value)), { x: PAD.left - 6, y: y2 + 4, "text-anchor": "end" })
|
|
1168
1187
|
);
|
|
1169
1188
|
}
|
|
1189
|
+
const stride = labelStride(spec.labels, geo);
|
|
1170
1190
|
spec.labels.forEach((label, i) => {
|
|
1191
|
+
if (i % stride !== 0) {
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1171
1194
|
svg2.appendChild(
|
|
1172
1195
|
text(label, {
|
|
1173
|
-
x: bandCentre(i, spec.labels.length),
|
|
1174
|
-
y:
|
|
1196
|
+
x: bandCentre(i, spec.labels.length, geo),
|
|
1197
|
+
y: geo.height - PAD.bottom + 16,
|
|
1175
1198
|
"text-anchor": "middle"
|
|
1176
1199
|
})
|
|
1177
1200
|
);
|
|
1178
1201
|
});
|
|
1179
1202
|
}
|
|
1180
|
-
function drawBars(svg2, spec, min, max) {
|
|
1181
|
-
const step =
|
|
1203
|
+
function drawBars(svg2, spec, geo, min, max) {
|
|
1204
|
+
const step = geo.plotW / spec.labels.length;
|
|
1182
1205
|
const width = step * 0.7 / spec.series.length;
|
|
1183
|
-
const base = scaleY(min, min, max);
|
|
1206
|
+
const base = scaleY(min, min, max, geo);
|
|
1184
1207
|
spec.series.forEach((series, s) => {
|
|
1185
1208
|
series.points.forEach((value, i) => {
|
|
1186
|
-
const y2 = scaleY(value, min, max);
|
|
1209
|
+
const y2 = scaleY(value, min, max, geo);
|
|
1187
1210
|
svg2.appendChild(
|
|
1188
1211
|
el("rect", {
|
|
1189
1212
|
x: PAD.left + step * i + step * 0.15 + width * s,
|
|
@@ -1197,8 +1220,8 @@ function drawBars(svg2, spec, min, max) {
|
|
|
1197
1220
|
});
|
|
1198
1221
|
});
|
|
1199
1222
|
}
|
|
1200
|
-
function drawStacked(svg2, spec, min, max) {
|
|
1201
|
-
const step =
|
|
1223
|
+
function drawStacked(svg2, spec, geo, min, max) {
|
|
1224
|
+
const step = geo.plotW / spec.labels.length;
|
|
1202
1225
|
const width = step * 0.7;
|
|
1203
1226
|
const running = spec.labels.map(() => 0);
|
|
1204
1227
|
spec.series.forEach((series, s) => {
|
|
@@ -1206,22 +1229,24 @@ function drawStacked(svg2, spec, min, max) {
|
|
|
1206
1229
|
const from = running[i] ?? 0;
|
|
1207
1230
|
const to = from + value;
|
|
1208
1231
|
running[i] = to;
|
|
1209
|
-
const y2 = scaleY(to, min, max);
|
|
1232
|
+
const y2 = scaleY(to, min, max, geo);
|
|
1210
1233
|
svg2.appendChild(
|
|
1211
1234
|
el("rect", {
|
|
1212
1235
|
x: PAD.left + step * i + step * 0.15,
|
|
1213
1236
|
y: y2,
|
|
1214
1237
|
width,
|
|
1215
|
-
height: Math.max(1, scaleY(from, min, max) - y2),
|
|
1238
|
+
height: Math.max(1, scaleY(from, min, max, geo) - y2),
|
|
1216
1239
|
fill: seriesColor(s)
|
|
1217
1240
|
})
|
|
1218
1241
|
);
|
|
1219
1242
|
});
|
|
1220
1243
|
});
|
|
1221
1244
|
}
|
|
1222
|
-
function drawLines(svg2, spec, min, max) {
|
|
1245
|
+
function drawLines(svg2, spec, geo, min, max) {
|
|
1223
1246
|
spec.series.forEach((series, s) => {
|
|
1224
|
-
const points = series.points.map(
|
|
1247
|
+
const points = series.points.map(
|
|
1248
|
+
(value, i) => `${bandCentre(i, spec.labels.length, geo)},${scaleY(value, min, max, geo)}`
|
|
1249
|
+
).join(" ");
|
|
1225
1250
|
svg2.appendChild(
|
|
1226
1251
|
el("polyline", {
|
|
1227
1252
|
points,
|
|
@@ -1233,13 +1258,13 @@ function drawLines(svg2, spec, min, max) {
|
|
|
1233
1258
|
);
|
|
1234
1259
|
});
|
|
1235
1260
|
}
|
|
1236
|
-
function drawScatter(svg2, spec, min, max) {
|
|
1261
|
+
function drawScatter(svg2, spec, geo, min, max) {
|
|
1237
1262
|
spec.series.forEach((series, s) => {
|
|
1238
1263
|
series.points.forEach((value, i) => {
|
|
1239
1264
|
svg2.appendChild(
|
|
1240
1265
|
el("circle", {
|
|
1241
|
-
cx: bandCentre(i, spec.labels.length),
|
|
1242
|
-
cy: scaleY(value, min, max),
|
|
1266
|
+
cx: bandCentre(i, spec.labels.length, geo),
|
|
1267
|
+
cy: scaleY(value, min, max, geo),
|
|
1243
1268
|
r: 4,
|
|
1244
1269
|
fill: seriesColor(s),
|
|
1245
1270
|
"fill-opacity": 0.85
|
|
@@ -1248,11 +1273,11 @@ function drawScatter(svg2, spec, min, max) {
|
|
|
1248
1273
|
});
|
|
1249
1274
|
});
|
|
1250
1275
|
}
|
|
1251
|
-
function drawPie(svg2, points) {
|
|
1276
|
+
function drawPie(svg2, points, geo) {
|
|
1252
1277
|
const total = points.reduce((sum, value) => sum + value, 0);
|
|
1253
|
-
const cx =
|
|
1254
|
-
const cy = PAD.top +
|
|
1255
|
-
const r = Math.min(
|
|
1278
|
+
const cx = geo.width / 2;
|
|
1279
|
+
const cy = PAD.top + geo.plotH / 2;
|
|
1280
|
+
const r = Math.min(geo.plotW, geo.plotH) / 2;
|
|
1256
1281
|
if (total === 0) {
|
|
1257
1282
|
svg2.appendChild(
|
|
1258
1283
|
el("circle", { cx, cy, r, fill: "none", stroke: "currentColor", "stroke-opacity": 0.3 })
|
|
@@ -1281,6 +1306,35 @@ function drawPie(svg2, points) {
|
|
|
1281
1306
|
angle = end;
|
|
1282
1307
|
});
|
|
1283
1308
|
}
|
|
1309
|
+
function drawSvg(spec, geo) {
|
|
1310
|
+
const svg2 = el("svg", {
|
|
1311
|
+
viewBox: `0 0 ${geo.width} ${geo.height}`,
|
|
1312
|
+
width: "100%",
|
|
1313
|
+
role: "img"
|
|
1314
|
+
});
|
|
1315
|
+
svg2.setAttribute("aria-label", spec.title ?? `${spec.kind} chart`);
|
|
1316
|
+
if (spec.kind === "pie") {
|
|
1317
|
+
const first = spec.series[0];
|
|
1318
|
+
drawPie(
|
|
1319
|
+
svg2,
|
|
1320
|
+
first.points.map((value) => Math.max(0, value)),
|
|
1321
|
+
geo
|
|
1322
|
+
);
|
|
1323
|
+
return svg2;
|
|
1324
|
+
}
|
|
1325
|
+
const { min, max } = extent(spec);
|
|
1326
|
+
drawAxes(svg2, spec, geo, min, max);
|
|
1327
|
+
if (spec.kind === "bar") {
|
|
1328
|
+
drawBars(svg2, spec, geo, min, max);
|
|
1329
|
+
} else if (spec.kind === "stacked") {
|
|
1330
|
+
drawStacked(svg2, spec, geo, min, max);
|
|
1331
|
+
} else if (spec.kind === "line") {
|
|
1332
|
+
drawLines(svg2, spec, geo, min, max);
|
|
1333
|
+
} else {
|
|
1334
|
+
drawScatter(svg2, spec, geo, min, max);
|
|
1335
|
+
}
|
|
1336
|
+
return svg2;
|
|
1337
|
+
}
|
|
1284
1338
|
function buildLegend(entries2) {
|
|
1285
1339
|
if (entries2.length < 2) {
|
|
1286
1340
|
return null;
|
|
@@ -1299,6 +1353,12 @@ function buildLegend(entries2) {
|
|
|
1299
1353
|
});
|
|
1300
1354
|
return row;
|
|
1301
1355
|
}
|
|
1356
|
+
function fitToWidth(block, redraw) {
|
|
1357
|
+
const observer = new ResizeObserver(() => {
|
|
1358
|
+
redraw(Math.round(block.clientWidth / WIDTH_STEP) * WIDTH_STEP);
|
|
1359
|
+
});
|
|
1360
|
+
observer.observe(block);
|
|
1361
|
+
}
|
|
1302
1362
|
function renderChart(spec) {
|
|
1303
1363
|
if (spec.labels.length === 0 || spec.series.length === 0) {
|
|
1304
1364
|
return null;
|
|
@@ -1313,27 +1373,8 @@ function renderChart(spec) {
|
|
|
1313
1373
|
heading.textContent = spec.title;
|
|
1314
1374
|
block.appendChild(heading);
|
|
1315
1375
|
}
|
|
1316
|
-
|
|
1317
|
-
svg2
|
|
1318
|
-
if (spec.kind === "pie") {
|
|
1319
|
-
const first = spec.series[0];
|
|
1320
|
-
drawPie(
|
|
1321
|
-
svg2,
|
|
1322
|
-
first.points.map((value) => Math.max(0, value))
|
|
1323
|
-
);
|
|
1324
|
-
} else {
|
|
1325
|
-
const { min, max } = extent(spec);
|
|
1326
|
-
drawAxes(svg2, spec, min, max);
|
|
1327
|
-
if (spec.kind === "bar") {
|
|
1328
|
-
drawBars(svg2, spec, min, max);
|
|
1329
|
-
} else if (spec.kind === "stacked") {
|
|
1330
|
-
drawStacked(svg2, spec, min, max);
|
|
1331
|
-
} else if (spec.kind === "line") {
|
|
1332
|
-
drawLines(svg2, spec, min, max);
|
|
1333
|
-
} else {
|
|
1334
|
-
drawScatter(svg2, spec, min, max);
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1376
|
+
let width = DEFAULT_WIDTH;
|
|
1377
|
+
let svg2 = drawSvg(spec, geometryFor(width));
|
|
1337
1378
|
block.appendChild(svg2);
|
|
1338
1379
|
const legend = buildLegend(
|
|
1339
1380
|
spec.kind === "pie" ? spec.labels : spec.series.map((series) => series.label)
|
|
@@ -1341,6 +1382,15 @@ function renderChart(spec) {
|
|
|
1341
1382
|
if (legend !== null) {
|
|
1342
1383
|
block.appendChild(legend);
|
|
1343
1384
|
}
|
|
1385
|
+
fitToWidth(block, (measured) => {
|
|
1386
|
+
if (measured === width) {
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
width = measured;
|
|
1390
|
+
const next = drawSvg(spec, geometryFor(width));
|
|
1391
|
+
svg2.replaceWith(next);
|
|
1392
|
+
svg2 = next;
|
|
1393
|
+
});
|
|
1344
1394
|
return block;
|
|
1345
1395
|
}
|
|
1346
1396
|
|
|
@@ -1707,6 +1757,15 @@ function clampLauncher(launcher, viewport) {
|
|
|
1707
1757
|
};
|
|
1708
1758
|
}
|
|
1709
1759
|
|
|
1760
|
+
// src/ui/clamp_panel.ts
|
|
1761
|
+
function clampPanel(host, viewport, margin = EDGE_MARGIN) {
|
|
1762
|
+
const width = host.right - host.left;
|
|
1763
|
+
const height = host.bottom - host.top;
|
|
1764
|
+
const left = Math.max(margin, Math.min(host.left, viewport.width - margin - width));
|
|
1765
|
+
const top = Math.max(margin, Math.min(host.top, viewport.height - margin - height));
|
|
1766
|
+
return { left, top, right: left + width, bottom: top + height };
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1710
1769
|
// src/ui/confirmation_card.ts
|
|
1711
1770
|
function actionButton2(modifier, label) {
|
|
1712
1771
|
const button2 = document.createElement("button");
|
|
@@ -1963,8 +2022,29 @@ function enableLauncherDrag(launcher, options) {
|
|
|
1963
2022
|
launcher.addEventListener("blur", settle);
|
|
1964
2023
|
}
|
|
1965
2024
|
|
|
2025
|
+
// src/ui/place_widget.ts
|
|
2026
|
+
function placeWidget(host, launcher, corner, viewport) {
|
|
2027
|
+
return {
|
|
2028
|
+
hostInset: inset({
|
|
2029
|
+
top: corner.y === "top" ? host.top : null,
|
|
2030
|
+
right: corner.x === "right" ? viewport.width - host.right : null,
|
|
2031
|
+
bottom: corner.y === "bottom" ? viewport.height - host.bottom : null,
|
|
2032
|
+
left: corner.x === "left" ? host.left : null
|
|
2033
|
+
}),
|
|
2034
|
+
launcherInset: inset({
|
|
2035
|
+
top: corner.y === "top" ? launcher.top - host.top : null,
|
|
2036
|
+
right: corner.x === "right" ? host.right - (launcher.left + launcher.width) : null,
|
|
2037
|
+
bottom: corner.y === "bottom" ? host.bottom - (launcher.top + launcher.height) : null,
|
|
2038
|
+
left: corner.x === "left" ? launcher.left - host.left : null
|
|
2039
|
+
})
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
2042
|
+
function inset(sides) {
|
|
2043
|
+
const side = (value) => value === null ? "auto" : `${Math.round(value)}px`;
|
|
2044
|
+
return `${side(sides.top)} ${side(sides.right)} ${side(sides.bottom)} ${side(sides.left)}`;
|
|
2045
|
+
}
|
|
2046
|
+
|
|
1966
2047
|
// src/ui/launcher_placement.ts
|
|
1967
|
-
var EDGE_MARGIN = 24;
|
|
1968
2048
|
function launcherPlacement(launcher, panel, viewport, margin = EDGE_MARGIN) {
|
|
1969
2049
|
const roomRunningRight = viewport.width - launcher.left;
|
|
1970
2050
|
const roomRunningLeft = launcher.left + launcher.width;
|
|
@@ -1976,34 +2056,17 @@ function launcherPlacement(launcher, panel, viewport, margin = EDGE_MARGIN) {
|
|
|
1976
2056
|
};
|
|
1977
2057
|
const wantedLeft = corner.x === "left" ? launcher.left : launcher.left + launcher.width - panel.width;
|
|
1978
2058
|
const wantedTop = corner.y === "top" ? launcher.top : launcher.top + launcher.height - panel.height;
|
|
1979
|
-
const
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
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)}`;
|
|
2059
|
+
const host = clampPanel(
|
|
2060
|
+
{
|
|
2061
|
+
left: wantedLeft,
|
|
2062
|
+
top: wantedTop,
|
|
2063
|
+
right: wantedLeft + panel.width,
|
|
2064
|
+
bottom: wantedTop + panel.height
|
|
2065
|
+
},
|
|
2066
|
+
viewport,
|
|
2067
|
+
margin
|
|
2068
|
+
);
|
|
2069
|
+
return { corner, ...placeWidget(host, launcher, corner, viewport) };
|
|
2007
2070
|
}
|
|
2008
2071
|
|
|
2009
2072
|
// src/ui/message_actions.ts
|
|
@@ -2374,6 +2437,55 @@ function place(button2, rect) {
|
|
|
2374
2437
|
button2.style.left = `${Math.min(Math.max(centre, half), width - half)}px`;
|
|
2375
2438
|
}
|
|
2376
2439
|
|
|
2440
|
+
// src/ui/panel_drag.ts
|
|
2441
|
+
var DRAG_THRESHOLD2 = 4;
|
|
2442
|
+
var CONTROLS = "button, a[href], input, select, textarea, [contenteditable]";
|
|
2443
|
+
function enablePanelDrag(handle, options) {
|
|
2444
|
+
handle.addEventListener("pointerdown", (event) => {
|
|
2445
|
+
if (event.button !== 0 || !options.enabled() || onControl(event, handle)) {
|
|
2446
|
+
return;
|
|
2447
|
+
}
|
|
2448
|
+
const start = options.rect();
|
|
2449
|
+
const originX = event.clientX;
|
|
2450
|
+
const originY = event.clientY;
|
|
2451
|
+
let dragging = false;
|
|
2452
|
+
const boxAt2 = (x2, y2) => {
|
|
2453
|
+
const dx = x2 - originX;
|
|
2454
|
+
const dy = y2 - originY;
|
|
2455
|
+
return {
|
|
2456
|
+
left: start.left + dx,
|
|
2457
|
+
top: start.top + dy,
|
|
2458
|
+
right: start.right + dx,
|
|
2459
|
+
bottom: start.bottom + dy
|
|
2460
|
+
};
|
|
2461
|
+
};
|
|
2462
|
+
const onMove = (move) => {
|
|
2463
|
+
if (!dragging && Math.hypot(move.clientX - originX, move.clientY - originY) < DRAG_THRESHOLD2) {
|
|
2464
|
+
return;
|
|
2465
|
+
}
|
|
2466
|
+
dragging = true;
|
|
2467
|
+
handle.setAttribute("data-dragging", "true");
|
|
2468
|
+
options.apply(boxAt2(move.clientX, move.clientY), start);
|
|
2469
|
+
};
|
|
2470
|
+
const onUp = (up) => {
|
|
2471
|
+
window.removeEventListener("pointermove", onMove);
|
|
2472
|
+
window.removeEventListener("pointerup", onUp);
|
|
2473
|
+
if (!dragging) {
|
|
2474
|
+
return;
|
|
2475
|
+
}
|
|
2476
|
+
handle.removeAttribute("data-dragging");
|
|
2477
|
+
options.commit(boxAt2(up.clientX, up.clientY), start);
|
|
2478
|
+
};
|
|
2479
|
+
event.preventDefault();
|
|
2480
|
+
window.addEventListener("pointermove", onMove);
|
|
2481
|
+
window.addEventListener("pointerup", onUp);
|
|
2482
|
+
});
|
|
2483
|
+
}
|
|
2484
|
+
function onControl(event, handle) {
|
|
2485
|
+
const path = event.composedPath();
|
|
2486
|
+
return path.slice(0, path.indexOf(handle)).some((node) => node instanceof Element && node.matches(CONTROLS));
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2377
2489
|
// src/ui/prettify_tool_name.ts
|
|
2378
2490
|
function prettifyToolName(name) {
|
|
2379
2491
|
const spaced = name.replace(/[._-]+/g, " ").trim();
|
|
@@ -2876,11 +2988,11 @@ function createDOMPurify() {
|
|
|
2876
2988
|
const originalDocument = document2;
|
|
2877
2989
|
const currentScript = originalDocument.currentScript;
|
|
2878
2990
|
window2.DocumentFragment;
|
|
2879
|
-
const HTMLTemplateElement = window2.HTMLTemplateElement, Node2 = window2.Node,
|
|
2991
|
+
const HTMLTemplateElement = window2.HTMLTemplateElement, Node2 = window2.Node, Element2 = window2.Element, NodeFilter2 = window2.NodeFilter, _window$NamedNodeMap = window2.NamedNodeMap;
|
|
2880
2992
|
_window$NamedNodeMap === void 0 ? window2.NamedNodeMap || window2.MozNamedAttrMap : _window$NamedNodeMap;
|
|
2881
2993
|
window2.HTMLFormElement;
|
|
2882
2994
|
const DOMParser = window2.DOMParser, trustedTypes = window2.trustedTypes;
|
|
2883
|
-
const ElementPrototype =
|
|
2995
|
+
const ElementPrototype = Element2.prototype;
|
|
2884
2996
|
const cloneNode = lookupGetter(ElementPrototype, "cloneNode");
|
|
2885
2997
|
const remove = lookupGetter(ElementPrototype, "remove");
|
|
2886
2998
|
const getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
|
|
@@ -5443,8 +5555,8 @@ function renderMarkdown(text4, options) {
|
|
|
5443
5555
|
}
|
|
5444
5556
|
|
|
5445
5557
|
// src/ui/resize_handle.ts
|
|
5446
|
-
var
|
|
5447
|
-
var
|
|
5558
|
+
var MIN_WIDTH2 = 280;
|
|
5559
|
+
var MIN_HEIGHT2 = 240;
|
|
5448
5560
|
var STEP2 = 16;
|
|
5449
5561
|
var COARSE_STEP2 = 64;
|
|
5450
5562
|
function createResizeHandle(grip, options) {
|
|
@@ -5526,11 +5638,11 @@ function movable(grip, axis) {
|
|
|
5526
5638
|
return axis === "both" || grip.x !== void 0;
|
|
5527
5639
|
}
|
|
5528
5640
|
function boxAt(grip, axis, rect, x2, y2) {
|
|
5529
|
-
const left = grip.x === "left" ? Math.min(x2, rect.right -
|
|
5530
|
-
const right = grip.x === "right" ? Math.max(x2, rect.left +
|
|
5641
|
+
const left = grip.x === "left" ? Math.min(x2, rect.right - MIN_WIDTH2) : rect.left;
|
|
5642
|
+
const right = grip.x === "right" ? Math.max(x2, rect.left + MIN_WIDTH2) : rect.right;
|
|
5531
5643
|
const vertical = axis === "both";
|
|
5532
|
-
const top = vertical && grip.y === "top" ? Math.min(y2, rect.bottom -
|
|
5533
|
-
const bottom = vertical && grip.y === "bottom" ? Math.max(y2, rect.top +
|
|
5644
|
+
const top = vertical && grip.y === "top" ? Math.min(y2, rect.bottom - MIN_HEIGHT2) : rect.top;
|
|
5645
|
+
const bottom = vertical && grip.y === "bottom" ? Math.max(y2, rect.top + MIN_HEIGHT2) : rect.bottom;
|
|
5534
5646
|
return { left, top, right, bottom };
|
|
5535
5647
|
}
|
|
5536
5648
|
|
|
@@ -5903,6 +6015,11 @@ var STYLES = `
|
|
|
5903
6015
|
--_glyph-size: var(--ag-ui-glyph-size, 18px);
|
|
5904
6016
|
--_glyph-stroke: var(--ag-ui-glyph-stroke, 1.75);
|
|
5905
6017
|
|
|
6018
|
+
/* How wide a chart is allowed to get. A cap rather than a width: below it
|
|
6019
|
+
the chart fills its column, and above it a wider panel is just a wider
|
|
6020
|
+
panel. */
|
|
6021
|
+
--_chart-max-width: var(--ag-ui-chart-max-width, 480px);
|
|
6022
|
+
|
|
5906
6023
|
/* Unread badge on the launcher. */
|
|
5907
6024
|
--_badge-bg: var(--ag-ui-badge-bg, var(--_danger));
|
|
5908
6025
|
--_badge-fg: var(--ag-ui-badge-fg, #ffffff);
|
|
@@ -6293,6 +6410,41 @@ var STYLES = `
|
|
|
6293
6410
|
color: var(--_header-fg);
|
|
6294
6411
|
}
|
|
6295
6412
|
|
|
6413
|
+
/* The header is the panel's title bar: on the placements that let the widget
|
|
6414
|
+
be moved it drags the whole thing, matching the launcher's own drag. The
|
|
6415
|
+
selector lists those placements rather than asking JS to stamp an attribute,
|
|
6416
|
+
because a cursor that appears one frame late reads as a control that only
|
|
6417
|
+
sometimes exists. touch-action keeps a finger drag here moving the panel
|
|
6418
|
+
instead of scrolling the page behind it. */
|
|
6419
|
+
:host(:not([placement])) .header,
|
|
6420
|
+
:host([placement=""]) .header,
|
|
6421
|
+
:host([placement="floating"]) .header,
|
|
6422
|
+
:host([placement="bottom-left"]) .header {
|
|
6423
|
+
cursor: move;
|
|
6424
|
+
touch-action: none;
|
|
6425
|
+
}
|
|
6426
|
+
|
|
6427
|
+
/* A host that turned the drag off keeps a header that says so. */
|
|
6428
|
+
:host([data-launcher-drag="false"]) .header {
|
|
6429
|
+
cursor: auto;
|
|
6430
|
+
touch-action: auto;
|
|
6431
|
+
}
|
|
6432
|
+
|
|
6433
|
+
/* :host is carried for the specificity, not the scope: the placement rules
|
|
6434
|
+
above are a host selector plus a class plus an attribute, and a bare
|
|
6435
|
+
.header[data-dragging] loses to them -- silently, because the drag still
|
|
6436
|
+
works and only the cursor is wrong. */
|
|
6437
|
+
:host .header[data-dragging] {
|
|
6438
|
+
cursor: grabbing;
|
|
6439
|
+
}
|
|
6440
|
+
|
|
6441
|
+
/* The cursor inherits, so a control a host slots into the header would show
|
|
6442
|
+
the drag cursor over something the drag deliberately ignores. Named to
|
|
6443
|
+
match the controls panel_drag steps aside for. */
|
|
6444
|
+
.header ::slotted(:is(button, a, input, select, textarea)) {
|
|
6445
|
+
cursor: pointer;
|
|
6446
|
+
}
|
|
6447
|
+
|
|
6296
6448
|
.header-title {
|
|
6297
6449
|
flex: 1;
|
|
6298
6450
|
min-width: 0;
|
|
@@ -7776,13 +7928,30 @@ var STYLES = `
|
|
|
7776
7928
|
* values, and the axis furniture inherits currentColor at low opacity so it
|
|
7777
7929
|
* reads correctly in either theme without a second palette.
|
|
7778
7930
|
*/
|
|
7931
|
+
/* A chart is sized like a message, not like a panel: it takes the width it
|
|
7932
|
+
needs and stops, rather than stretching into whatever room the transcript
|
|
7933
|
+
has. A message bubble caps at 80% for the same reason -- widening the panel
|
|
7934
|
+
should not resize what is already in it. The cap is a token so a host with a
|
|
7935
|
+
wide panel and a real reason can raise it; the default is the width this
|
|
7936
|
+
renderer has always drawn at. Below the cap the block still fills its column,
|
|
7937
|
+
which is what a narrow panel needs. */
|
|
7779
7938
|
.chart-block {
|
|
7780
|
-
align-self:
|
|
7781
|
-
|
|
7939
|
+
align-self: flex-start;
|
|
7940
|
+
width: 100%;
|
|
7941
|
+
max-width: var(--_chart-max-width);
|
|
7782
7942
|
margin: 6px 0;
|
|
7783
7943
|
color: var(--_fg);
|
|
7784
7944
|
}
|
|
7785
7945
|
|
|
7946
|
+
/* The drawing fills the block's width and carries its own height in the
|
|
7947
|
+
viewBox, so it is laid out rather than magnified: block display keeps the
|
|
7948
|
+
inline baseline gap from adding a stripe under every chart. */
|
|
7949
|
+
.chart-block svg {
|
|
7950
|
+
display: block;
|
|
7951
|
+
width: 100%;
|
|
7952
|
+
height: auto;
|
|
7953
|
+
}
|
|
7954
|
+
|
|
7786
7955
|
.chart-title {
|
|
7787
7956
|
margin-bottom: 2px;
|
|
7788
7957
|
font-size: 0.85em;
|
|
@@ -10698,6 +10867,13 @@ var COLLAPSED_KEY = "ag-ui-chat:collapsed";
|
|
|
10698
10867
|
var SIZE_KEY = "ag-ui-chat:size";
|
|
10699
10868
|
var THEME_KEY = "ag-ui-chat:theme";
|
|
10700
10869
|
var LAUNCHER_KEY = "ag-ui-chat:launcher";
|
|
10870
|
+
function asPoint(value) {
|
|
10871
|
+
if (typeof value !== "object" || value === null) {
|
|
10872
|
+
return null;
|
|
10873
|
+
}
|
|
10874
|
+
const { left, top } = value;
|
|
10875
|
+
return typeof left === "number" && typeof top === "number" ? { left, top } : null;
|
|
10876
|
+
}
|
|
10701
10877
|
var DRAGGABLE_PLACEMENTS = /* @__PURE__ */ new Set([null, "", "floating", "bottom-left"]);
|
|
10702
10878
|
var RESIZE_GRIPS = [
|
|
10703
10879
|
{ y: "top" },
|
|
@@ -11126,6 +11302,18 @@ var AgUiChat = class extends HTMLElement {
|
|
|
11126
11302
|
* position -- see #applyLauncherPlacement for what that costs the host.
|
|
11127
11303
|
*/
|
|
11128
11304
|
#launcherPos = null;
|
|
11305
|
+
/**
|
|
11306
|
+
* Where the user dragged the *panel*, in viewport coordinates, or null while
|
|
11307
|
+
* its position is still derived from the launcher's.
|
|
11308
|
+
*
|
|
11309
|
+
* The two gestures state different things and are restored differently. A
|
|
11310
|
+
* launcher drag says where the bubble goes and leaves the panel to open into
|
|
11311
|
+
* whatever space the viewport has, so it is re-derived every time -- which is
|
|
11312
|
+
* what lets a widget re-decide its direction when the window changes under
|
|
11313
|
+
* it. A header drag states the panel's own position, and re-deriving that
|
|
11314
|
+
* from the launcher would move the panel the user just placed.
|
|
11315
|
+
*/
|
|
11316
|
+
#panelPos = null;
|
|
11129
11317
|
/**
|
|
11130
11318
|
* The corner the panel opens away from, once this element is placing itself.
|
|
11131
11319
|
* Null means the host's layout still decides, and the anchor is measured.
|
|
@@ -12493,6 +12681,7 @@ ${quoted}`;
|
|
|
12493
12681
|
return;
|
|
12494
12682
|
}
|
|
12495
12683
|
this.#launcherPos = at2;
|
|
12684
|
+
this.#panelPos = null;
|
|
12496
12685
|
const panel = this.getBoundingClientRect();
|
|
12497
12686
|
const placement = launcherPlacement(
|
|
12498
12687
|
this.#launcherBox(),
|
|
@@ -12514,13 +12703,137 @@ ${quoted}`;
|
|
|
12514
12703
|
this.#moveLauncher(left, top);
|
|
12515
12704
|
this.#storeLauncherPosition();
|
|
12516
12705
|
}
|
|
12517
|
-
/**
|
|
12706
|
+
/**
|
|
12707
|
+
* Move the panel live during a header drag, without persisting.
|
|
12708
|
+
*
|
|
12709
|
+
* Only the host box is written, and that is the whole trick: the launcher is
|
|
12710
|
+
* positioned *inside* that box, so leaving its own inset alone carries it
|
|
12711
|
+
* along by exactly the distance the panel travelled -- which is what a person
|
|
12712
|
+
* dragging a window expects of the thing it collapses into. Placing it on the
|
|
12713
|
+
* panel's pinned corner instead, as an earlier version did, sent it leaping
|
|
12714
|
+
* across the panel the moment the drag re-picked that corner.
|
|
12715
|
+
*
|
|
12716
|
+
* The corner is therefore held for the length of the gesture. Both insets are
|
|
12717
|
+
* measured from it, and rewriting one of them from a new corner while the
|
|
12718
|
+
* other still names the old one would move the launcher for no reason.
|
|
12719
|
+
*/
|
|
12720
|
+
#movePanel(box) {
|
|
12721
|
+
if (!this.#launcherDraggable()) {
|
|
12722
|
+
return box;
|
|
12723
|
+
}
|
|
12724
|
+
if (this.#launcherPos === null) {
|
|
12725
|
+
const resting = this.#launcherBox();
|
|
12726
|
+
this.#launcherPos = { left: resting.left, top: resting.top };
|
|
12727
|
+
}
|
|
12728
|
+
const held = clampPanel(box, this.#viewport());
|
|
12729
|
+
const corner = this.#expandCorner ?? this.#anchor;
|
|
12730
|
+
const viewport = this.#viewport();
|
|
12731
|
+
this.style.setProperty(
|
|
12732
|
+
"--ag-ui-inset",
|
|
12733
|
+
[
|
|
12734
|
+
corner.y === "top" ? `${Math.round(held.top)}px` : "auto",
|
|
12735
|
+
corner.x === "right" ? `${Math.round(viewport.width - held.right)}px` : "auto",
|
|
12736
|
+
corner.y === "bottom" ? `${Math.round(viewport.height - held.bottom)}px` : "auto",
|
|
12737
|
+
corner.x === "left" ? `${Math.round(held.left)}px` : "auto"
|
|
12738
|
+
].join(" ")
|
|
12739
|
+
);
|
|
12740
|
+
this.#panelPos = { left: held.left, top: held.top };
|
|
12741
|
+
return held;
|
|
12742
|
+
}
|
|
12743
|
+
/**
|
|
12744
|
+
* Finish a header drag: settle where both halves ended up, and remember it.
|
|
12745
|
+
*
|
|
12746
|
+
* The launcher travels the distance the panel actually travelled, which is
|
|
12747
|
+
* the clamped distance rather than the pointer's -- a panel held against the
|
|
12748
|
+
* viewport margin stops, and so does the bubble attached to it. Measured from
|
|
12749
|
+
* the box the press started on, so a long drag cannot accumulate the rounding
|
|
12750
|
+
* each move writes into the inset.
|
|
12751
|
+
*
|
|
12752
|
+
* Only now is the corner re-picked, from where the launcher has ended up, so
|
|
12753
|
+
* the panel opens into clear space next time. Re-picking it moves nothing:
|
|
12754
|
+
* both insets are rewritten from positions that are already decided.
|
|
12755
|
+
*/
|
|
12756
|
+
#commitPanel(box, from) {
|
|
12757
|
+
const held = this.#movePanel(box);
|
|
12758
|
+
const start = this.#launcherPos;
|
|
12759
|
+
if (!this.#launcherDraggable() || start === null) {
|
|
12760
|
+
return;
|
|
12761
|
+
}
|
|
12762
|
+
const carried = {
|
|
12763
|
+
...this.#launcherBox(),
|
|
12764
|
+
left: start.left + (held.left - from.left),
|
|
12765
|
+
top: start.top + (held.top - from.top)
|
|
12766
|
+
};
|
|
12767
|
+
this.#placePanelAndLauncher(held, {
|
|
12768
|
+
...carried,
|
|
12769
|
+
...clampLauncher(carried, this.#viewport())
|
|
12770
|
+
});
|
|
12771
|
+
this.#storeLauncherPosition();
|
|
12772
|
+
}
|
|
12773
|
+
/**
|
|
12774
|
+
* Write both insets for a panel and launcher that are already positioned,
|
|
12775
|
+
* re-picking the corner they are measured from.
|
|
12776
|
+
*/
|
|
12777
|
+
#placePanelAndLauncher(host, launcher) {
|
|
12778
|
+
const viewport = this.#viewport();
|
|
12779
|
+
const size = { width: host.right - host.left, height: host.bottom - host.top };
|
|
12780
|
+
const { corner } = launcherPlacement(launcher, size, viewport);
|
|
12781
|
+
const insets = placeWidget(host, launcher, corner, viewport);
|
|
12782
|
+
this.style.setProperty("--ag-ui-inset", insets.hostInset);
|
|
12783
|
+
this.style.setProperty("--ag-ui-launcher-inset", insets.launcherInset);
|
|
12784
|
+
this.#launcherPos = { left: launcher.left, top: launcher.top };
|
|
12785
|
+
this.#panelPos = { left: host.left, top: host.top };
|
|
12786
|
+
this.#expandCorner = corner;
|
|
12787
|
+
this.setAttribute("data-expand-corner", `${corner.y}-${corner.x}`);
|
|
12788
|
+
this.#syncResizeAnchor();
|
|
12789
|
+
}
|
|
12790
|
+
/**
|
|
12791
|
+
* Re-apply a panel position the user stated, against the current viewport.
|
|
12792
|
+
*
|
|
12793
|
+
* The launcher keeps its offset from the panel through the clamp -- it was
|
|
12794
|
+
* put where it is relative to the panel, and a viewport that has since shrunk
|
|
12795
|
+
* is no reason to move one without the other -- and is then held on screen in
|
|
12796
|
+
* its own right.
|
|
12797
|
+
*/
|
|
12798
|
+
#restorePanelPosition(at2) {
|
|
12799
|
+
if (!this.#launcherDraggable()) {
|
|
12800
|
+
return;
|
|
12801
|
+
}
|
|
12802
|
+
const rect = this.getBoundingClientRect();
|
|
12803
|
+
const held = clampPanel(
|
|
12804
|
+
{ left: at2.left, top: at2.top, right: at2.left + rect.width, bottom: at2.top + rect.height },
|
|
12805
|
+
this.#viewport()
|
|
12806
|
+
);
|
|
12807
|
+
const launcher = this.#launcherBox();
|
|
12808
|
+
const carried = {
|
|
12809
|
+
...launcher,
|
|
12810
|
+
left: launcher.left + (held.left - at2.left),
|
|
12811
|
+
top: launcher.top + (held.top - at2.top)
|
|
12812
|
+
};
|
|
12813
|
+
this.#placePanelAndLauncher(held, {
|
|
12814
|
+
...carried,
|
|
12815
|
+
...clampLauncher(carried, this.#viewport())
|
|
12816
|
+
});
|
|
12817
|
+
}
|
|
12818
|
+
/**
|
|
12819
|
+
* Write the current position, if this element owns one.
|
|
12820
|
+
*
|
|
12821
|
+
* The panel's own position rides along only when the user stated it, because
|
|
12822
|
+
* its presence is what tells a restore which of the two gestures to honour:
|
|
12823
|
+
* with it, the panel goes back where it was put; without it, the panel is
|
|
12824
|
+
* re-derived from the launcher and opens into whatever room the viewport has
|
|
12825
|
+
* now.
|
|
12826
|
+
*/
|
|
12518
12827
|
#storeLauncherPosition() {
|
|
12519
12828
|
const position = this.#launcherPos;
|
|
12520
12829
|
if (position === null) {
|
|
12521
12830
|
return;
|
|
12522
12831
|
}
|
|
12523
|
-
|
|
12832
|
+
const panel = this.#panelPos;
|
|
12833
|
+
writeStoredItem(
|
|
12834
|
+
this.#storageKey(LAUNCHER_KEY),
|
|
12835
|
+
JSON.stringify(panel === null ? position : { ...position, panel })
|
|
12836
|
+
);
|
|
12524
12837
|
}
|
|
12525
12838
|
/**
|
|
12526
12839
|
* Re-apply the dragged position against the current viewport: on connect,
|
|
@@ -12529,16 +12842,23 @@ ${quoted}`;
|
|
|
12529
12842
|
* unreachable -- it is the only way back to a collapsed conversation.
|
|
12530
12843
|
*/
|
|
12531
12844
|
#restoreLauncherPosition() {
|
|
12532
|
-
const stored = this.#
|
|
12533
|
-
|
|
12845
|
+
const stored = this.#readLauncherPosition();
|
|
12846
|
+
const launcher = this.#launcherPos ?? stored;
|
|
12847
|
+
if (launcher === null) {
|
|
12848
|
+
return;
|
|
12849
|
+
}
|
|
12850
|
+
const panel = this.#panelPos ?? stored?.panel ?? null;
|
|
12851
|
+
if (panel !== null) {
|
|
12852
|
+
this.#launcherPos = { left: launcher.left, top: launcher.top };
|
|
12853
|
+
this.#restorePanelPosition(panel);
|
|
12534
12854
|
return;
|
|
12535
12855
|
}
|
|
12536
12856
|
const box = this.#launcherBox();
|
|
12537
12857
|
this.#applyLauncherPlacement(
|
|
12538
|
-
clampLauncher({ ...box, left:
|
|
12858
|
+
clampLauncher({ ...box, left: launcher.left, top: launcher.top }, this.#viewport())
|
|
12539
12859
|
);
|
|
12540
12860
|
}
|
|
12541
|
-
/** The persisted
|
|
12861
|
+
/** The persisted position for this instance, or null. */
|
|
12542
12862
|
#readLauncherPosition() {
|
|
12543
12863
|
const raw = this.#readScopedItem(LAUNCHER_KEY);
|
|
12544
12864
|
if (raw === null) {
|
|
@@ -12549,8 +12869,12 @@ ${quoted}`;
|
|
|
12549
12869
|
if (typeof parsed !== "object" || parsed === null) {
|
|
12550
12870
|
return null;
|
|
12551
12871
|
}
|
|
12552
|
-
const { left, top } = parsed;
|
|
12553
|
-
|
|
12872
|
+
const { left, top, panel } = parsed;
|
|
12873
|
+
if (typeof left !== "number" || typeof top !== "number") {
|
|
12874
|
+
return null;
|
|
12875
|
+
}
|
|
12876
|
+
const at2 = asPoint(panel);
|
|
12877
|
+
return at2 === null ? { left, top } : { left, top, panel: at2 };
|
|
12554
12878
|
} catch {
|
|
12555
12879
|
return null;
|
|
12556
12880
|
}
|
|
@@ -12565,6 +12889,7 @@ ${quoted}`;
|
|
|
12565
12889
|
return;
|
|
12566
12890
|
}
|
|
12567
12891
|
this.#launcherPos = null;
|
|
12892
|
+
this.#panelPos = null;
|
|
12568
12893
|
this.#expandCorner = null;
|
|
12569
12894
|
this.style.removeProperty("--ag-ui-inset");
|
|
12570
12895
|
this.style.removeProperty("--ag-ui-launcher-inset");
|
|
@@ -12608,6 +12933,9 @@ ${quoted}`;
|
|
|
12608
12933
|
top: anchor.y === "top" ? box.top : box.bottom - size
|
|
12609
12934
|
};
|
|
12610
12935
|
}
|
|
12936
|
+
if (this.#panelPos !== null) {
|
|
12937
|
+
this.#panelPos = { left: box.left, top: box.top };
|
|
12938
|
+
}
|
|
12611
12939
|
}
|
|
12612
12940
|
/** Finish a resize: keep the box, remember it, and re-read the pinned edges. */
|
|
12613
12941
|
#commitResize(grip, box) {
|
|
@@ -13174,6 +13502,12 @@ ${quoted}`;
|
|
|
13174
13502
|
}
|
|
13175
13503
|
controls.append(collapse2);
|
|
13176
13504
|
header.append(title, headerActions, controls);
|
|
13505
|
+
enablePanelDrag(header, {
|
|
13506
|
+
enabled: () => !this.collapsed && this.#launcherDraggable(),
|
|
13507
|
+
rect: () => this.getBoundingClientRect(),
|
|
13508
|
+
apply: (box) => this.#movePanel(box),
|
|
13509
|
+
commit: (box, from) => this.#commitPanel(box, from)
|
|
13510
|
+
});
|
|
13177
13511
|
this.#messages.className = "messages";
|
|
13178
13512
|
this.#messages.setAttribute("part", "messages");
|
|
13179
13513
|
this.#messages.setAttribute("role", "log");
|
|
@@ -14643,7 +14977,7 @@ function setControlValue(el2, value) {
|
|
|
14643
14977
|
}
|
|
14644
14978
|
|
|
14645
14979
|
// src/version.ts
|
|
14646
|
-
var VERSION = "0.
|
|
14980
|
+
var VERSION = "0.34.0";
|
|
14647
14981
|
export {
|
|
14648
14982
|
ATTACHMENT_EVENT,
|
|
14649
14983
|
AgUiChat,
|