@artooi/ag-ui-web-component 0.32.0 → 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 +162 -1
- package/README.md +182 -23
- package/dist/ag-ui-web-component.bundle.js +341 -117
- package/dist/ag-ui-web-component.bundle.js.map +4 -4
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/index.js +1259 -389
- 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/package.json +1 -1
- package/src/constants.ts +12 -0
- package/src/core/ag_ui_chat.ts +480 -24
- 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/version.ts +1 -1
package/src/ui/styles.ts
CHANGED
|
@@ -45,6 +45,30 @@ export const STYLES = `
|
|
|
45
45
|
--_text: var(--ag-ui-text, var(--_fg));
|
|
46
46
|
--_surface: var(--ag-ui-surface, transparent);
|
|
47
47
|
|
|
48
|
+
/* Message action row: the control box and the mark inside it. The box has a
|
|
49
|
+
floor of 24px so it stays a reliable target at every density. */
|
|
50
|
+
--_action-size: var(--ag-ui-action-size, 28px);
|
|
51
|
+
--_action-icon-size: var(--ag-ui-action-icon-size, 15px);
|
|
52
|
+
--_tooltip-bg: var(--ag-ui-tooltip-bg, #1f2430);
|
|
53
|
+
--_tooltip-fg: var(--ag-ui-tooltip-fg, #f5f6fa);
|
|
54
|
+
|
|
55
|
+
/* Text and marks drawn on top of the accent and danger fills. Separate
|
|
56
|
+
tokens because they are not free: a host that themes the accent to a pale
|
|
57
|
+
colour has white-on-pale with no way to correct it, which is the one
|
|
58
|
+
theming change that makes a control unreadable rather than merely off. */
|
|
59
|
+
--_on-accent: var(--ag-ui-on-accent, #ffffff);
|
|
60
|
+
--_on-danger: var(--ag-ui-on-danger, #ffffff);
|
|
61
|
+
|
|
62
|
+
/* Resize grips: the corner squares and the edge strips between them. Wide
|
|
63
|
+
enough to hit without being wide enough to swallow a click on the content
|
|
64
|
+
underneath, and adjustable for a host with a coarser pointer. */
|
|
65
|
+
--_grip-corner: var(--ag-ui-grip-corner, 14px);
|
|
66
|
+
--_grip-edge: var(--ag-ui-grip-edge, 6px);
|
|
67
|
+
--_grip-edge-docked: var(--ag-ui-grip-edge-docked, 8px);
|
|
68
|
+
/* The mark drawn inside a grip, as opposed to the area it answers to. */
|
|
69
|
+
--_grip-mark-length: var(--ag-ui-grip-mark-length, 28px);
|
|
70
|
+
--_grip-mark-thickness: var(--ag-ui-grip-mark-thickness, 3px);
|
|
71
|
+
|
|
48
72
|
/* Status accents for tool-call cards. */
|
|
49
73
|
--_success: var(--ag-ui-success, #15803d);
|
|
50
74
|
--_danger: var(--ag-ui-danger, #b91c1c);
|
|
@@ -55,6 +79,12 @@ export const STYLES = `
|
|
|
55
79
|
--_tool-icon-done: var(--ag-ui-tool-icon-done, "✓");
|
|
56
80
|
--_tool-icon-error: var(--ag-ui-tool-icon-error, "✕");
|
|
57
81
|
--_tool-icon-declined: var(--ag-ui-tool-icon-declined, "⊘");
|
|
82
|
+
|
|
83
|
+
/* Disclosure marks on every expandable row. Tokenised for the same reason
|
|
84
|
+
the status icons above are: a host re-theming one set and not the other
|
|
85
|
+
ends up with two vocabularies in one transcript. */
|
|
86
|
+
--_disclosure-collapsed: var(--ag-ui-disclosure-collapsed, "▸");
|
|
87
|
+
--_disclosure-expanded: var(--ag-ui-disclosure-expanded, "▾");
|
|
58
88
|
--_tool-spin-duration: var(--ag-ui-tool-spin-duration, 0.7s);
|
|
59
89
|
|
|
60
90
|
/* Answer well (opt-in via data-answer-well) — boxes a whole assistant turn. */
|
|
@@ -335,6 +365,9 @@ export const STYLES = `
|
|
|
335
365
|
font: inherit;
|
|
336
366
|
cursor: pointer;
|
|
337
367
|
pointer-events: auto;
|
|
368
|
+
/* A touch drag on the launcher moves it; without this the page scrolls under
|
|
369
|
+
the finger instead and the launcher never moves at all. */
|
|
370
|
+
touch-action: none;
|
|
338
371
|
opacity: 0;
|
|
339
372
|
transform: scale(0.4);
|
|
340
373
|
visibility: hidden;
|
|
@@ -364,6 +397,15 @@ export const STYLES = `
|
|
|
364
397
|
transform: scale(0.94);
|
|
365
398
|
}
|
|
366
399
|
|
|
400
|
+
/* A drag is a press and a hover at the same time, so both scale rules above are
|
|
401
|
+
live throughout it. Cancelling them is what keeps the launcher the size of
|
|
402
|
+
the thing under the pointer while it travels; the position itself comes from
|
|
403
|
+
inset, which nothing here transitions, so it tracks the pointer exactly. */
|
|
404
|
+
:host([collapsed]) .launcher[data-dragging] {
|
|
405
|
+
transform: none;
|
|
406
|
+
cursor: grabbing;
|
|
407
|
+
}
|
|
408
|
+
|
|
367
409
|
.launcher .icon-holder {
|
|
368
410
|
width: var(--_launcher-icon-size);
|
|
369
411
|
height: var(--_launcher-icon-size);
|
|
@@ -558,6 +600,31 @@ export const STYLES = `
|
|
|
558
600
|
transform-origin: bottom left;
|
|
559
601
|
}
|
|
560
602
|
|
|
603
|
+
/* Once the launcher has been dragged the element places itself, and stamps the
|
|
604
|
+
corner it chose to open away from. The morph has to start at that same
|
|
605
|
+
corner: scaling out of the one the placement originally guessed reads as the
|
|
606
|
+
panel leaping across the screen before it opens.
|
|
607
|
+
|
|
608
|
+
Equal specificity to the placement rule above, so source order is what lets
|
|
609
|
+
the stamped value win -- the same arrangement the resize grip uses, and the
|
|
610
|
+
same trap. Write these with = on the whole hyphenated token; a ~= would match
|
|
611
|
+
whitespace-separated words and so could never match at all. */
|
|
612
|
+
:host([data-expand-corner="top-left"]) .chat {
|
|
613
|
+
transform-origin: top left;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
:host([data-expand-corner="top-right"]) .chat {
|
|
617
|
+
transform-origin: top right;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
:host([data-expand-corner="bottom-left"]) .chat {
|
|
621
|
+
transform-origin: bottom left;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
:host([data-expand-corner="bottom-right"]) .chat {
|
|
625
|
+
transform-origin: bottom right;
|
|
626
|
+
}
|
|
627
|
+
|
|
561
628
|
/* The two in-flow placements keep the original collapse: hide the body, let
|
|
562
629
|
the host shrink to the header bar. */
|
|
563
630
|
:host([collapsed]:is([placement="embedded"], [placement="page"])) {
|
|
@@ -983,11 +1050,11 @@ export const STYLES = `
|
|
|
983
1050
|
}
|
|
984
1051
|
|
|
985
1052
|
.thoughts-toggle::before {
|
|
986
|
-
content: "
|
|
1053
|
+
content: var(--_disclosure-expanded) " ";
|
|
987
1054
|
}
|
|
988
1055
|
|
|
989
1056
|
.thoughts-toggle[aria-expanded="false"]::before {
|
|
990
|
-
content: "
|
|
1057
|
+
content: var(--_disclosure-collapsed) " ";
|
|
991
1058
|
}
|
|
992
1059
|
|
|
993
1060
|
/* A gentle pulse on the label while reasoning is still streaming. */
|
|
@@ -1329,14 +1396,14 @@ export const STYLES = `
|
|
|
1329
1396
|
}
|
|
1330
1397
|
|
|
1331
1398
|
.subagent-row::after {
|
|
1332
|
-
content:
|
|
1399
|
+
content: var(--_disclosure-collapsed);
|
|
1333
1400
|
flex: none;
|
|
1334
1401
|
margin-left: auto;
|
|
1335
1402
|
color: var(--_accent);
|
|
1336
1403
|
}
|
|
1337
1404
|
|
|
1338
1405
|
.subagent-row[aria-expanded="true"]::after {
|
|
1339
|
-
content:
|
|
1406
|
+
content: var(--_disclosure-expanded);
|
|
1340
1407
|
}
|
|
1341
1408
|
|
|
1342
1409
|
.subagent-row:disabled::after {
|
|
@@ -1463,16 +1530,23 @@ export const STYLES = `
|
|
|
1463
1530
|
}
|
|
1464
1531
|
|
|
1465
1532
|
.tool-call-toggle::before {
|
|
1466
|
-
content: "
|
|
1533
|
+
content: var(--_disclosure-collapsed) " ";
|
|
1467
1534
|
}
|
|
1468
1535
|
|
|
1469
1536
|
.tool-call-toggle[aria-expanded="true"]::before {
|
|
1470
|
-
content: "
|
|
1537
|
+
content: var(--_disclosure-expanded) " ";
|
|
1471
1538
|
}
|
|
1472
1539
|
|
|
1473
|
-
/* Resize
|
|
1474
|
-
|
|
1475
|
-
nothing to drag.
|
|
1540
|
+
/* Resize grips: every edge and every corner, so the panel can be dragged from
|
|
1541
|
+
whichever side the reader is already near. Absent entirely where the
|
|
1542
|
+
placement is full-bleed, since there is nothing to drag.
|
|
1543
|
+
|
|
1544
|
+
The whole set is always laid out. Which edges the *layout* pins is not a
|
|
1545
|
+
question the stylesheet needs to answer any more -- it decided where the one
|
|
1546
|
+
grip went, and there is no longer one grip. The element still measures and
|
|
1547
|
+
stamps data-resize-anchor, because it decides what a drag on a pinned edge
|
|
1548
|
+
costs in position and which grip carries the tab stop, but no rule here
|
|
1549
|
+
reads it. */
|
|
1476
1550
|
.resize-handle {
|
|
1477
1551
|
position: absolute;
|
|
1478
1552
|
z-index: 2;
|
|
@@ -1485,95 +1559,102 @@ export const STYLES = `
|
|
|
1485
1559
|
outline-offset: -2px;
|
|
1486
1560
|
}
|
|
1487
1561
|
|
|
1488
|
-
/*
|
|
1489
|
-
|
|
1562
|
+
/* Corners first in the file and last in the DOM, so they take the pointer
|
|
1563
|
+
where they overlap an edge strip. */
|
|
1564
|
+
.resize-handle--top-left,
|
|
1565
|
+
.resize-handle--top-right,
|
|
1566
|
+
.resize-handle--bottom-left,
|
|
1567
|
+
.resize-handle--bottom-right {
|
|
1568
|
+
width: var(--_grip-corner);
|
|
1569
|
+
height: var(--_grip-corner);
|
|
1570
|
+
}
|
|
1490
1571
|
|
|
1491
|
-
|
|
1492
|
-
.resize-handle {
|
|
1572
|
+
.resize-handle--top-left {
|
|
1493
1573
|
top: 0;
|
|
1494
1574
|
left: 0;
|
|
1495
|
-
width: 14px;
|
|
1496
|
-
height: 14px;
|
|
1497
1575
|
cursor: nwse-resize;
|
|
1498
1576
|
}
|
|
1499
1577
|
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
bottom-left is pinned there, so its free corner is top-right. */
|
|
1503
|
-
:host([placement="embedded"]) .resize-handle {
|
|
1504
|
-
top: auto;
|
|
1505
|
-
left: auto;
|
|
1578
|
+
.resize-handle--top-right {
|
|
1579
|
+
top: 0;
|
|
1506
1580
|
right: 0;
|
|
1507
|
-
|
|
1508
|
-
cursor: nwse-resize;
|
|
1581
|
+
cursor: nesw-resize;
|
|
1509
1582
|
}
|
|
1510
1583
|
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1584
|
+
.resize-handle--bottom-left {
|
|
1585
|
+
bottom: 0;
|
|
1586
|
+
left: 0;
|
|
1514
1587
|
cursor: nesw-resize;
|
|
1515
1588
|
}
|
|
1516
1589
|
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
anchored bottom-left -- so the element measures them and stamps a single
|
|
1520
|
-
hyphenated "<y>-<x>" token here. Equal specificity to the rules above, so
|
|
1521
|
-
source order is what lets the measured value win.
|
|
1522
|
-
|
|
1523
|
-
Two traps, both of which silently draw the grip on the corner that moves:
|
|
1524
|
-
|
|
1525
|
-
Never write these as [data-resize-anchor~="left"]. The stamped value is one
|
|
1526
|
-
hyphenated token and ~= matches whitespace-separated words, so it can never
|
|
1527
|
-
match.
|
|
1528
|
-
|
|
1529
|
-
Each rule must set both sides of its axis, not only the side it moves, or it
|
|
1530
|
-
cannot undo a placement guess that flipped the other way. */
|
|
1531
|
-
:host([data-resize-anchor$="-left"]) .resize-handle {
|
|
1532
|
-
left: auto;
|
|
1590
|
+
.resize-handle--bottom-right {
|
|
1591
|
+
bottom: 0;
|
|
1533
1592
|
right: 0;
|
|
1593
|
+
cursor: nwse-resize;
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
/* Edge strips, held clear of the corners at both ends so a corner drag is
|
|
1597
|
+
never swallowed by the edge next to it. */
|
|
1598
|
+
.resize-handle--left,
|
|
1599
|
+
.resize-handle--right {
|
|
1600
|
+
top: var(--_grip-corner);
|
|
1601
|
+
bottom: var(--_grip-corner);
|
|
1602
|
+
width: var(--_grip-edge);
|
|
1603
|
+
cursor: ew-resize;
|
|
1534
1604
|
}
|
|
1535
1605
|
|
|
1536
|
-
|
|
1606
|
+
.resize-handle--left {
|
|
1537
1607
|
left: 0;
|
|
1538
|
-
right: auto;
|
|
1539
1608
|
}
|
|
1540
1609
|
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
bottom: 0;
|
|
1610
|
+
.resize-handle--right {
|
|
1611
|
+
right: 0;
|
|
1544
1612
|
}
|
|
1545
1613
|
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1614
|
+
.resize-handle--top,
|
|
1615
|
+
.resize-handle--bottom {
|
|
1616
|
+
left: var(--_grip-corner);
|
|
1617
|
+
right: var(--_grip-corner);
|
|
1618
|
+
height: var(--_grip-edge);
|
|
1619
|
+
cursor: ns-resize;
|
|
1549
1620
|
}
|
|
1550
1621
|
|
|
1551
|
-
|
|
1552
|
-
:
|
|
1553
|
-
:host([data-resize-anchor="bottom-right"]) .resize-handle {
|
|
1554
|
-
cursor: nwse-resize;
|
|
1622
|
+
.resize-handle--top {
|
|
1623
|
+
top: 0;
|
|
1555
1624
|
}
|
|
1556
1625
|
|
|
1557
|
-
|
|
1558
|
-
:
|
|
1559
|
-
cursor: nesw-resize;
|
|
1626
|
+
.resize-handle--bottom {
|
|
1627
|
+
bottom: 0;
|
|
1560
1628
|
}
|
|
1561
1629
|
|
|
1562
|
-
/* Docked: the placement owns the height, so
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1630
|
+
/* Docked: the placement owns the height, so the horizontal edges and every
|
|
1631
|
+
corner are inert and must not advertise a drag that does nothing. The two
|
|
1632
|
+
vertical edges remain, which is the same affordance these placements had
|
|
1633
|
+
when there was one grip -- now on both sides, since either may be the inner
|
|
1634
|
+
one depending on which side the rail is docked to. */
|
|
1635
|
+
:host([placement="sidebar"]) .resize-handle--top,
|
|
1636
|
+
:host([placement="sidebar"]) .resize-handle--bottom,
|
|
1637
|
+
:host([placement="sidebar"]) .resize-handle--top-left,
|
|
1638
|
+
:host([placement="sidebar"]) .resize-handle--top-right,
|
|
1639
|
+
:host([placement="sidebar"]) .resize-handle--bottom-left,
|
|
1640
|
+
:host([placement="sidebar"]) .resize-handle--bottom-right,
|
|
1641
|
+
:host([placement="side"]) .resize-handle--top,
|
|
1642
|
+
:host([placement="side"]) .resize-handle--bottom,
|
|
1643
|
+
:host([placement="side"]) .resize-handle--top-left,
|
|
1644
|
+
:host([placement="side"]) .resize-handle--top-right,
|
|
1645
|
+
:host([placement="side"]) .resize-handle--bottom-left,
|
|
1646
|
+
:host([placement="side"]) .resize-handle--bottom-right {
|
|
1647
|
+
display: none;
|
|
1571
1648
|
}
|
|
1572
1649
|
|
|
1573
|
-
/*
|
|
1574
|
-
:host([placement="sidebar"]
|
|
1575
|
-
|
|
1576
|
-
|
|
1650
|
+
/* The vertical edges run the full height once no corner shares them. */
|
|
1651
|
+
:host([placement="sidebar"]) .resize-handle--left,
|
|
1652
|
+
:host([placement="sidebar"]) .resize-handle--right,
|
|
1653
|
+
:host([placement="side"]) .resize-handle--left,
|
|
1654
|
+
:host([placement="side"]) .resize-handle--right {
|
|
1655
|
+
top: 0;
|
|
1656
|
+
bottom: 0;
|
|
1657
|
+
width: var(--_grip-edge-docked);
|
|
1577
1658
|
}
|
|
1578
1659
|
|
|
1579
1660
|
/* Full-bleed: nothing to drag. */
|
|
@@ -1582,9 +1663,62 @@ export const STYLES = `
|
|
|
1582
1663
|
display: none;
|
|
1583
1664
|
}
|
|
1584
1665
|
|
|
1585
|
-
.
|
|
1666
|
+
/* The visible mark on a grip.
|
|
1667
|
+
|
|
1668
|
+
Filling the whole strip was what the single corner grip did, and at 14px
|
|
1669
|
+
square nobody ever saw it. On a strip running the length of an edge the same
|
|
1670
|
+
fill reads as a border the panel grew -- square ended, stopping short of the
|
|
1671
|
+
corner radius at both ends, and easily mistaken for a rendering fault rather
|
|
1672
|
+
than for something to grab.
|
|
1673
|
+
|
|
1674
|
+
So the hit area stays the full strip and the mark is a short pill centred on
|
|
1675
|
+
it, which cannot be read as an edge of anything and never meets the radius.
|
|
1676
|
+
|
|
1677
|
+
It shows on hover and focus as well as during the drag. With eight grips, a
|
|
1678
|
+
mark that appears only once you are already dragging is a mark that never
|
|
1679
|
+
told anyone the grips were there. */
|
|
1680
|
+
.resize-handle::after {
|
|
1681
|
+
content: "";
|
|
1682
|
+
position: absolute;
|
|
1683
|
+
top: 50%;
|
|
1684
|
+
left: 50%;
|
|
1685
|
+
transform: translate(-50%, -50%);
|
|
1686
|
+
border-radius: 999px;
|
|
1586
1687
|
background: var(--_accent);
|
|
1587
|
-
opacity: 0
|
|
1688
|
+
opacity: 0;
|
|
1689
|
+
transition: opacity var(--_motion) var(--_ease);
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
.resize-handle--top::after,
|
|
1693
|
+
.resize-handle--bottom::after {
|
|
1694
|
+
width: var(--_grip-mark-length);
|
|
1695
|
+
height: var(--_grip-mark-thickness);
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
.resize-handle--left::after,
|
|
1699
|
+
.resize-handle--right::after {
|
|
1700
|
+
width: var(--_grip-mark-thickness);
|
|
1701
|
+
height: var(--_grip-mark-length);
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
/* A corner has no length to run along, so it gets a dot instead of a pill. */
|
|
1705
|
+
.resize-handle--top-left::after,
|
|
1706
|
+
.resize-handle--top-right::after,
|
|
1707
|
+
.resize-handle--bottom-left::after,
|
|
1708
|
+
.resize-handle--bottom-right::after {
|
|
1709
|
+
width: var(--_grip-mark-thickness);
|
|
1710
|
+
height: var(--_grip-mark-thickness);
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
.resize-handle:hover::after,
|
|
1714
|
+
.resize-handle:focus-visible::after {
|
|
1715
|
+
opacity: 0.5;
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
/* Equal specificity to the pair above, so source order is what makes the drag
|
|
1719
|
+
the stronger of the two states. */
|
|
1720
|
+
.resize-handle[data-dragging]::after {
|
|
1721
|
+
opacity: 0.9;
|
|
1588
1722
|
}
|
|
1589
1723
|
|
|
1590
1724
|
/* ── Composer ───────────────────────────────────────────────────────────────
|
|
@@ -1698,7 +1832,7 @@ export const STYLES = `
|
|
|
1698
1832
|
border: none;
|
|
1699
1833
|
border-radius: 50%;
|
|
1700
1834
|
background: var(--_accent);
|
|
1701
|
-
color:
|
|
1835
|
+
color: var(--_on-accent);
|
|
1702
1836
|
font: inherit;
|
|
1703
1837
|
line-height: 1;
|
|
1704
1838
|
cursor: pointer;
|
|
@@ -1772,13 +1906,13 @@ export const STYLES = `
|
|
|
1772
1906
|
/* Recording: a red tint + a gentle pulse so it's clearly "live". */
|
|
1773
1907
|
.voice-btn[data-state="recording"] {
|
|
1774
1908
|
background: var(--_danger);
|
|
1775
|
-
color:
|
|
1909
|
+
color: var(--_on-danger);
|
|
1776
1910
|
animation: ag-ui-voice-pulse 1.2s ease-in-out infinite;
|
|
1777
1911
|
}
|
|
1778
1912
|
|
|
1779
1913
|
.voice-btn[data-state="recording"]:hover {
|
|
1780
1914
|
background: var(--_danger);
|
|
1781
|
-
color:
|
|
1915
|
+
color: var(--_on-danger);
|
|
1782
1916
|
}
|
|
1783
1917
|
|
|
1784
1918
|
@keyframes ag-ui-voice-pulse {
|
|
@@ -2068,7 +2202,7 @@ export const STYLES = `
|
|
|
2068
2202
|
.confirm-btn--confirm {
|
|
2069
2203
|
border-color: var(--_accent);
|
|
2070
2204
|
background: var(--_accent);
|
|
2071
|
-
color:
|
|
2205
|
+
color: var(--_on-accent);
|
|
2072
2206
|
}
|
|
2073
2207
|
|
|
2074
2208
|
/* The session waiver. Deliberately the quietest of the three: it is the widest
|
|
@@ -2136,16 +2270,29 @@ export const STYLES = `
|
|
|
2136
2270
|
margin-top: -6px;
|
|
2137
2271
|
}
|
|
2138
2272
|
|
|
2273
|
+
/* The row's controls are icon-only, so the box is the whole target. Sized from
|
|
2274
|
+
a variable a host can raise, with a floor rather than a fixed height: the
|
|
2275
|
+
compact density shrinks the font, and a target that shrinks with it lands
|
|
2276
|
+
under the 24px minimum that makes a control reliably tappable. It used to,
|
|
2277
|
+
at roughly 20px square. */
|
|
2139
2278
|
.message-action {
|
|
2279
|
+
display: inline-flex;
|
|
2280
|
+
align-items: center;
|
|
2281
|
+
justify-content: center;
|
|
2282
|
+
box-sizing: border-box;
|
|
2283
|
+
min-width: var(--_action-size);
|
|
2284
|
+
min-height: var(--_action-size);
|
|
2285
|
+
padding: 4px;
|
|
2140
2286
|
border: none;
|
|
2141
2287
|
border-radius: 6px;
|
|
2142
|
-
padding: 2px 6px;
|
|
2143
2288
|
font: inherit;
|
|
2144
2289
|
line-height: 1.2;
|
|
2145
2290
|
cursor: pointer;
|
|
2146
2291
|
background: transparent;
|
|
2147
2292
|
color: var(--_muted);
|
|
2148
2293
|
opacity: 0.75;
|
|
2294
|
+
/* The tooltip below is positioned against this box. */
|
|
2295
|
+
position: relative;
|
|
2149
2296
|
}
|
|
2150
2297
|
|
|
2151
2298
|
.message-action:hover,
|
|
@@ -2154,6 +2301,61 @@ export const STYLES = `
|
|
|
2154
2301
|
background: var(--_border);
|
|
2155
2302
|
}
|
|
2156
2303
|
|
|
2304
|
+
.message-action-icon {
|
|
2305
|
+
display: inline-flex;
|
|
2306
|
+
width: var(--_action-icon-size);
|
|
2307
|
+
height: var(--_action-icon-size);
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
.message-action-icon .glyph {
|
|
2311
|
+
width: 100%;
|
|
2312
|
+
height: 100%;
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
/* The label, drawn rather than left to the browser.
|
|
2316
|
+
|
|
2317
|
+
A title attribute is the usual answer and covers only half the readers: it
|
|
2318
|
+
never appears on keyboard focus, so tabbing onto an icon-only control shows
|
|
2319
|
+
nothing at all. The attribute stays for the pointer users who expect it, and
|
|
2320
|
+
this shows the same words on hover and on focus alike.
|
|
2321
|
+
|
|
2322
|
+
Left-aligned rather than centred because the row sits at the left edge of an
|
|
2323
|
+
answer inside a scrolling column, and a centred tooltip on the first control
|
|
2324
|
+
is clipped by that column. Growing rightward keeps it inside.
|
|
2325
|
+
|
|
2326
|
+
Not exposed to assistive technology: the button already carries the same
|
|
2327
|
+
string as its accessible name, and this would be a second copy of it. */
|
|
2328
|
+
.message-action::after {
|
|
2329
|
+
content: attr(data-tooltip);
|
|
2330
|
+
position: absolute;
|
|
2331
|
+
bottom: calc(100% + 4px);
|
|
2332
|
+
left: 0;
|
|
2333
|
+
z-index: 3;
|
|
2334
|
+
padding: 3px 6px;
|
|
2335
|
+
border-radius: 4px;
|
|
2336
|
+
background: var(--_tooltip-bg);
|
|
2337
|
+
color: var(--_tooltip-fg);
|
|
2338
|
+
font-size: 11px;
|
|
2339
|
+
line-height: 1.4;
|
|
2340
|
+
white-space: nowrap;
|
|
2341
|
+
pointer-events: none;
|
|
2342
|
+
opacity: 0;
|
|
2343
|
+
transition: opacity var(--_motion) var(--_ease);
|
|
2344
|
+
}
|
|
2345
|
+
|
|
2346
|
+
.message-action:hover::after,
|
|
2347
|
+
.message-action:focus-visible::after {
|
|
2348
|
+
opacity: 1;
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
/* Touch has no hover to reveal it, and a tooltip that latches open under a
|
|
2352
|
+
finger covers the answer it belongs to. */
|
|
2353
|
+
@media (hover: none) {
|
|
2354
|
+
.message-action::after {
|
|
2355
|
+
content: none;
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2157
2359
|
.message-action[aria-pressed="true"] {
|
|
2158
2360
|
opacity: 1;
|
|
2159
2361
|
color: var(--_accent);
|
|
@@ -2211,7 +2413,7 @@ export const STYLES = `
|
|
|
2211
2413
|
.approval-btn--approve {
|
|
2212
2414
|
border-color: var(--_accent);
|
|
2213
2415
|
background: var(--_accent);
|
|
2214
|
-
color:
|
|
2416
|
+
color: var(--_on-accent);
|
|
2215
2417
|
}
|
|
2216
2418
|
|
|
2217
2419
|
/* Question card — the built-in ask_user prompt (radios and/or free text). */
|
|
@@ -2277,7 +2479,7 @@ export const STYLES = `
|
|
|
2277
2479
|
font-weight: 600;
|
|
2278
2480
|
cursor: pointer;
|
|
2279
2481
|
background: var(--_accent);
|
|
2280
|
-
color:
|
|
2482
|
+
color: var(--_on-accent);
|
|
2281
2483
|
}
|
|
2282
2484
|
|
|
2283
2485
|
.question-btn:disabled {
|
|
@@ -2546,7 +2748,7 @@ export const STYLES = `
|
|
|
2546
2748
|
font-weight: 600;
|
|
2547
2749
|
border-color: var(--_accent);
|
|
2548
2750
|
background: var(--_accent);
|
|
2549
|
-
color:
|
|
2751
|
+
color: var(--_on-accent);
|
|
2550
2752
|
}
|
|
2551
2753
|
|
|
2552
2754
|
.checkpoint-fork:hover {
|
|
@@ -2721,7 +2923,7 @@ export const STYLES = `
|
|
|
2721
2923
|
border: none;
|
|
2722
2924
|
border-radius: 6px;
|
|
2723
2925
|
background: var(--_danger);
|
|
2724
|
-
color:
|
|
2926
|
+
color: var(--_on-danger);
|
|
2725
2927
|
padding: 3px 10px;
|
|
2726
2928
|
font: inherit;
|
|
2727
2929
|
cursor: pointer;
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION: string = "0.
|
|
1
|
+
export const VERSION: string = "0.33.0";
|