@artooi/ag-ui-web-component 0.44.0 → 0.46.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 +182 -1
- package/README.md +245 -32
- package/dist/ag-ui-web-component.bundle.js +3696 -2798
- package/dist/ag-ui-web-component.bundle.js.map +4 -4
- package/dist/constants.d.ts +4 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/core/ag_ui_chat.d.ts +28 -8
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/core/read_flag.d.ts +11 -0
- package/dist/core/read_flag.d.ts.map +1 -0
- package/dist/core/read_json_attribute.d.ts +15 -0
- package/dist/core/read_json_attribute.d.ts.map +1 -0
- package/dist/index.js +5084 -3481
- package/dist/index.js.map +4 -4
- package/dist/tools/tool_catalog.d.ts +5 -0
- package/dist/tools/tool_catalog.d.ts.map +1 -1
- package/dist/tools/tool_dispatch.d.ts.map +1 -1
- package/dist/ui/charts/chart_styles.d.ts +2 -0
- package/dist/ui/charts/chart_styles.d.ts.map +1 -0
- package/dist/ui/composer/attachment_styles.d.ts +2 -0
- package/dist/ui/composer/attachment_styles.d.ts.map +1 -0
- package/dist/ui/composer/build_composer.d.ts +30 -0
- package/dist/ui/composer/build_composer.d.ts.map +1 -0
- package/dist/ui/composer/composer_styles.d.ts +2 -0
- package/dist/ui/composer/composer_styles.d.ts.map +1 -0
- package/dist/ui/composer/skill_styles.d.ts +2 -0
- package/dist/ui/composer/skill_styles.d.ts.map +1 -0
- package/dist/ui/history/history_styles.d.ts +2 -0
- package/dist/ui/history/history_styles.d.ts.map +1 -0
- package/dist/ui/interrupts/approval_styles.d.ts +2 -0
- package/dist/ui/interrupts/approval_styles.d.ts.map +1 -0
- package/dist/ui/interrupts/confirmation_styles.d.ts +2 -0
- package/dist/ui/interrupts/confirmation_styles.d.ts.map +1 -0
- package/dist/ui/interrupts/question_styles.d.ts +2 -0
- package/dist/ui/interrupts/question_styles.d.ts.map +1 -0
- package/dist/ui/placement/collapse_styles.d.ts +2 -0
- package/dist/ui/placement/collapse_styles.d.ts.map +1 -0
- package/dist/ui/placement/embedded_styles.d.ts +2 -0
- package/dist/ui/placement/embedded_styles.d.ts.map +1 -0
- package/dist/ui/placement/launcher_styles.d.ts +2 -0
- package/dist/ui/placement/launcher_styles.d.ts.map +1 -0
- package/dist/ui/placement/page_styles.d.ts +2 -0
- package/dist/ui/placement/page_styles.d.ts.map +1 -0
- package/dist/ui/placement/panel_placement.d.ts.map +1 -1
- package/dist/ui/placement/preset_styles.d.ts +2 -0
- package/dist/ui/placement/preset_styles.d.ts.map +1 -0
- package/dist/ui/placement/resize_styles.d.ts +2 -0
- package/dist/ui/placement/resize_styles.d.ts.map +1 -0
- package/dist/ui/placement/sidebar_styles.d.ts +2 -0
- package/dist/ui/placement/sidebar_styles.d.ts.map +1 -0
- package/dist/ui/placement/small_viewport_styles.d.ts +2 -0
- package/dist/ui/placement/small_viewport_styles.d.ts.map +1 -0
- package/dist/ui/placement/surface_for.d.ts +74 -0
- package/dist/ui/placement/surface_for.d.ts.map +1 -0
- package/dist/ui/progress/run_notice_styles.d.ts +2 -0
- package/dist/ui/progress/run_notice_styles.d.ts.map +1 -0
- package/dist/ui/progress/thoughts_styles.d.ts +2 -0
- package/dist/ui/progress/thoughts_styles.d.ts.map +1 -0
- package/dist/ui/progress/tool_call_card.d.ts +8 -0
- package/dist/ui/progress/tool_call_card.d.ts.map +1 -1
- package/dist/ui/progress/tool_group_styles.d.ts +2 -0
- package/dist/ui/progress/tool_group_styles.d.ts.map +1 -0
- package/dist/ui/progress/tool_step_group.d.ts +47 -0
- package/dist/ui/progress/tool_step_group.d.ts.map +1 -0
- package/dist/ui/progress/tool_step_styles.d.ts +2 -0
- package/dist/ui/progress/tool_step_styles.d.ts.map +1 -0
- package/dist/ui/shell/adopt_styles.d.ts +9 -4
- package/dist/ui/shell/adopt_styles.d.ts.map +1 -1
- package/dist/ui/shell/build_header.d.ts +40 -0
- package/dist/ui/shell/build_header.d.ts.map +1 -0
- package/dist/ui/shell/build_launcher.d.ts +20 -0
- package/dist/ui/shell/build_launcher.d.ts.map +1 -0
- package/dist/ui/shell/frame_styles.d.ts +2 -0
- package/dist/ui/shell/frame_styles.d.ts.map +1 -0
- package/dist/ui/shell/theme_styles.d.ts +2 -0
- package/dist/ui/shell/theme_styles.d.ts.map +1 -0
- package/dist/ui/shell/token_styles.d.ts +2 -0
- package/dist/ui/shell/token_styles.d.ts.map +1 -0
- package/dist/ui/styles.d.ts +1 -1
- package/dist/ui/styles.d.ts.map +1 -1
- package/dist/ui/themes/classic_styles.d.ts +2 -0
- package/dist/ui/themes/classic_styles.d.ts.map +1 -0
- package/dist/ui/themes/classic_tokens.d.ts +2 -0
- package/dist/ui/themes/classic_tokens.d.ts.map +1 -0
- package/dist/ui/themes/code_tokens.d.ts +2 -0
- package/dist/ui/themes/code_tokens.d.ts.map +1 -0
- package/dist/ui/themes/ledger_styles.d.ts +2 -0
- package/dist/ui/themes/ledger_styles.d.ts.map +1 -0
- package/dist/ui/themes/ledger_tokens.d.ts +2 -0
- package/dist/ui/themes/ledger_tokens.d.ts.map +1 -0
- package/dist/ui/themes/modern_styles.d.ts +2 -0
- package/dist/ui/themes/modern_styles.d.ts.map +1 -0
- package/dist/ui/themes/quiet_styles.d.ts +2 -0
- package/dist/ui/themes/quiet_styles.d.ts.map +1 -0
- package/dist/ui/themes/scheme_styles.d.ts +2 -0
- package/dist/ui/themes/scheme_styles.d.ts.map +1 -0
- package/dist/ui/themes/soft_styles.d.ts +2 -0
- package/dist/ui/themes/soft_styles.d.ts.map +1 -0
- package/dist/ui/themes/soft_tokens.d.ts +2 -0
- package/dist/ui/themes/soft_tokens.d.ts.map +1 -0
- package/dist/ui/themes/theme_hosts.d.ts +15 -0
- package/dist/ui/themes/theme_hosts.d.ts.map +1 -0
- package/dist/ui/transcript/attachment_chip_styles.d.ts +2 -0
- package/dist/ui/transcript/attachment_chip_styles.d.ts.map +1 -0
- package/dist/ui/transcript/build_transcript.d.ts +21 -0
- package/dist/ui/transcript/build_transcript.d.ts.map +1 -0
- package/dist/ui/transcript/greeting_styles.d.ts +2 -0
- package/dist/ui/transcript/greeting_styles.d.ts.map +1 -0
- package/dist/ui/transcript/groups_tool_steps.d.ts +13 -0
- package/dist/ui/transcript/groups_tool_steps.d.ts.map +1 -0
- package/dist/ui/transcript/message_action_styles.d.ts +2 -0
- package/dist/ui/transcript/message_action_styles.d.ts.map +1 -0
- package/dist/ui/transcript/message_styles.d.ts +2 -0
- package/dist/ui/transcript/message_styles.d.ts.map +1 -0
- package/dist/ui/transcript/transcript.d.ts +16 -1
- package/dist/ui/transcript/transcript.d.ts.map +1 -1
- package/dist/ui/transcript/transcript_styles.d.ts +2 -0
- package/dist/ui/transcript/transcript_styles.d.ts.map +1 -0
- package/dist/ui/ui_strings.d.ts +18 -0
- package/dist/ui/ui_strings.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/constants.ts +4 -1
- package/src/core/ag_ui_chat.ts +164 -299
- package/src/core/read_flag.ts +13 -0
- package/src/core/read_json_attribute.ts +30 -0
- package/src/tools/tool_catalog.ts +23 -10
- package/src/tools/tool_dispatch.ts +26 -11
- package/src/ui/charts/chart_block.ts +9 -9
- package/src/ui/charts/chart_styles.ts +63 -0
- package/src/ui/composer/attachment_styles.ts +71 -0
- package/src/ui/composer/build_composer.ts +112 -0
- package/src/ui/composer/composer_styles.ts +174 -0
- package/src/ui/composer/skill_styles.ts +120 -0
- package/src/ui/history/history_styles.ts +484 -0
- package/src/ui/interrupts/approval_styles.ts +52 -0
- package/src/ui/interrupts/confirmation_styles.ts +114 -0
- package/src/ui/interrupts/question_styles.ts +73 -0
- package/src/ui/placement/collapse_styles.ts +137 -0
- package/src/ui/placement/embedded_styles.ts +14 -0
- package/src/ui/placement/launcher_styles.ts +189 -0
- package/src/ui/placement/page_styles.ts +47 -0
- package/src/ui/placement/panel_placement.ts +3 -12
- package/src/ui/placement/preset_styles.ts +33 -0
- package/src/ui/placement/resize_styles.ts +186 -0
- package/src/ui/placement/sidebar_styles.ts +88 -0
- package/src/ui/placement/small_viewport_styles.ts +56 -0
- package/src/ui/placement/surface_for.ts +135 -0
- package/src/ui/progress/run_notice_styles.ts +52 -0
- package/src/ui/progress/thoughts_styles.ts +65 -0
- package/src/ui/progress/tool_call_card.ts +11 -0
- package/src/ui/progress/tool_group_styles.ts +232 -0
- package/src/ui/progress/tool_step_group.ts +269 -0
- package/src/ui/progress/tool_step_styles.ts +472 -0
- package/src/ui/shell/adopt_styles.ts +11 -5
- package/src/ui/shell/build_header.ts +108 -0
- package/src/ui/shell/build_launcher.ts +50 -0
- package/src/ui/shell/frame_styles.ts +119 -0
- package/src/ui/shell/theme_styles.ts +11 -0
- package/src/ui/shell/token_styles.ts +406 -0
- package/src/ui/styles.ts +104 -3774
- package/src/ui/themes/classic_styles.ts +32 -0
- package/src/ui/themes/classic_tokens.ts +50 -0
- package/src/ui/themes/code_tokens.ts +21 -0
- package/src/ui/themes/ledger_styles.ts +168 -0
- package/src/ui/themes/ledger_tokens.ts +32 -0
- package/src/ui/themes/modern_styles.ts +80 -0
- package/src/ui/themes/quiet_styles.ts +115 -0
- package/src/ui/themes/scheme_styles.ts +17 -0
- package/src/ui/themes/soft_styles.ts +148 -0
- package/src/ui/themes/soft_tokens.ts +28 -0
- package/src/ui/themes/theme_hosts.ts +14 -0
- package/src/ui/transcript/attachment_chip_styles.ts +116 -0
- package/src/ui/transcript/build_transcript.ts +67 -0
- package/src/ui/transcript/greeting_styles.ts +171 -0
- package/src/ui/transcript/groups_tool_steps.ts +16 -0
- package/src/ui/transcript/message_action_styles.ts +155 -0
- package/src/ui/transcript/message_styles.ts +262 -0
- package/src/ui/transcript/transcript.ts +109 -3
- package/src/ui/transcript/transcript_styles.ts +140 -0
- package/src/ui/ui_strings.ts +31 -0
- package/src/version.ts +1 -1
- package/dist/ui/placement/is_collapsible_placement.d.ts +0 -18
- package/dist/ui/placement/is_collapsible_placement.d.ts.map +0 -1
- package/dist/ui/placement/is_draggable_placement.d.ts +0 -9
- package/dist/ui/placement/is_draggable_placement.d.ts.map +0 -1
- package/src/ui/placement/is_collapsible_placement.ts +0 -19
- package/src/ui/placement/is_draggable_placement.ts +0 -23
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// The resize grips on every edge and corner, and which placements keep them.
|
|
2
|
+
export const RESIZE_STYLES: string = `
|
|
3
|
+
/* Resize grips: every edge and every corner, so the panel can be dragged from
|
|
4
|
+
whichever side the reader is already near. Absent entirely where the
|
|
5
|
+
placement is full-bleed, since there is nothing to drag.
|
|
6
|
+
|
|
7
|
+
The whole set is always laid out. Which edges the *layout* pins is not a
|
|
8
|
+
question the stylesheet needs to answer any more -- it decided where the one
|
|
9
|
+
grip went, and there is no longer one grip. The element still measures and
|
|
10
|
+
stamps data-resize-anchor, because it decides what a drag on a pinned edge
|
|
11
|
+
costs in position and which grip carries the tab stop, but no rule here
|
|
12
|
+
reads it. */
|
|
13
|
+
.resize-handle {
|
|
14
|
+
position: absolute;
|
|
15
|
+
z-index: 2;
|
|
16
|
+
background: transparent;
|
|
17
|
+
touch-action: none;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.resize-handle:focus-visible {
|
|
21
|
+
outline: 2px solid var(--_accent);
|
|
22
|
+
outline-offset: -2px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Corners first in the file and last in the DOM, so they take the pointer
|
|
26
|
+
where they overlap an edge strip. */
|
|
27
|
+
.resize-handle--top-left,
|
|
28
|
+
.resize-handle--top-right,
|
|
29
|
+
.resize-handle--bottom-left,
|
|
30
|
+
.resize-handle--bottom-right {
|
|
31
|
+
width: var(--_grip-corner);
|
|
32
|
+
height: var(--_grip-corner);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.resize-handle--top-left {
|
|
36
|
+
top: 0;
|
|
37
|
+
left: 0;
|
|
38
|
+
cursor: nwse-resize;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.resize-handle--top-right {
|
|
42
|
+
top: 0;
|
|
43
|
+
right: 0;
|
|
44
|
+
cursor: nesw-resize;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.resize-handle--bottom-left {
|
|
48
|
+
bottom: 0;
|
|
49
|
+
left: 0;
|
|
50
|
+
cursor: nesw-resize;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.resize-handle--bottom-right {
|
|
54
|
+
bottom: 0;
|
|
55
|
+
right: 0;
|
|
56
|
+
cursor: nwse-resize;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Edge strips, held clear of the corners at both ends so a corner drag is
|
|
60
|
+
never swallowed by the edge next to it. */
|
|
61
|
+
.resize-handle--left,
|
|
62
|
+
.resize-handle--right {
|
|
63
|
+
top: var(--_grip-corner);
|
|
64
|
+
bottom: var(--_grip-corner);
|
|
65
|
+
width: var(--_grip-edge);
|
|
66
|
+
cursor: ew-resize;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.resize-handle--left {
|
|
70
|
+
left: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.resize-handle--right {
|
|
74
|
+
right: 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.resize-handle--top,
|
|
78
|
+
.resize-handle--bottom {
|
|
79
|
+
left: var(--_grip-corner);
|
|
80
|
+
right: var(--_grip-corner);
|
|
81
|
+
height: var(--_grip-edge);
|
|
82
|
+
cursor: ns-resize;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.resize-handle--top {
|
|
86
|
+
top: 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.resize-handle--bottom {
|
|
90
|
+
bottom: 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* Docked: the placement owns the height, so the horizontal edges and every
|
|
94
|
+
corner are inert and must not advertise a drag that does nothing. The two
|
|
95
|
+
vertical edges remain, which is the same affordance these placements had
|
|
96
|
+
when there was one grip -- now on both sides, since either may be the inner
|
|
97
|
+
one depending on which side the rail is docked to. */
|
|
98
|
+
:host([placement="sidebar"]) .resize-handle--top,
|
|
99
|
+
:host([placement="sidebar"]) .resize-handle--bottom,
|
|
100
|
+
:host([placement="sidebar"]) .resize-handle--top-left,
|
|
101
|
+
:host([placement="sidebar"]) .resize-handle--top-right,
|
|
102
|
+
:host([placement="sidebar"]) .resize-handle--bottom-left,
|
|
103
|
+
:host([placement="sidebar"]) .resize-handle--bottom-right,
|
|
104
|
+
:host([placement="side"]) .resize-handle--top,
|
|
105
|
+
:host([placement="side"]) .resize-handle--bottom,
|
|
106
|
+
:host([placement="side"]) .resize-handle--top-left,
|
|
107
|
+
:host([placement="side"]) .resize-handle--top-right,
|
|
108
|
+
:host([placement="side"]) .resize-handle--bottom-left,
|
|
109
|
+
:host([placement="side"]) .resize-handle--bottom-right {
|
|
110
|
+
display: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* The vertical edges run the full height once no corner shares them. */
|
|
114
|
+
:host([placement="sidebar"]) .resize-handle--left,
|
|
115
|
+
:host([placement="sidebar"]) .resize-handle--right,
|
|
116
|
+
:host([placement="side"]) .resize-handle--left,
|
|
117
|
+
:host([placement="side"]) .resize-handle--right {
|
|
118
|
+
top: 0;
|
|
119
|
+
bottom: 0;
|
|
120
|
+
width: var(--_grip-edge-docked);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* Full-bleed: nothing to drag. */
|
|
124
|
+
:host([placement="full"]) .resize-handle,
|
|
125
|
+
:host([placement="page"]) .resize-handle {
|
|
126
|
+
display: none;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* The visible mark on a grip.
|
|
130
|
+
|
|
131
|
+
Filling the whole strip was what the single corner grip did, and at 14px
|
|
132
|
+
square nobody ever saw it. On a strip running the length of an edge the same
|
|
133
|
+
fill reads as a border the panel grew -- square ended, stopping short of the
|
|
134
|
+
corner radius at both ends, and easily mistaken for a rendering fault rather
|
|
135
|
+
than for something to grab.
|
|
136
|
+
|
|
137
|
+
So the hit area stays the full strip and the mark is a short pill centred on
|
|
138
|
+
it, which cannot be read as an edge of anything and never meets the radius.
|
|
139
|
+
|
|
140
|
+
It shows on hover and focus as well as during the drag. With eight grips, a
|
|
141
|
+
mark that appears only once you are already dragging is a mark that never
|
|
142
|
+
told anyone the grips were there. */
|
|
143
|
+
.resize-handle::after {
|
|
144
|
+
content: "";
|
|
145
|
+
position: absolute;
|
|
146
|
+
top: 50%;
|
|
147
|
+
left: 50%;
|
|
148
|
+
transform: translate(-50%, -50%);
|
|
149
|
+
border-radius: 999px;
|
|
150
|
+
background: var(--_accent);
|
|
151
|
+
opacity: 0;
|
|
152
|
+
transition: opacity var(--_motion) var(--_ease);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.resize-handle--top::after,
|
|
156
|
+
.resize-handle--bottom::after {
|
|
157
|
+
width: var(--_grip-mark-length);
|
|
158
|
+
height: var(--_grip-mark-thickness);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.resize-handle--left::after,
|
|
162
|
+
.resize-handle--right::after {
|
|
163
|
+
width: var(--_grip-mark-thickness);
|
|
164
|
+
height: var(--_grip-mark-length);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* A corner has no length to run along, so it gets a dot instead of a pill. */
|
|
168
|
+
.resize-handle--top-left::after,
|
|
169
|
+
.resize-handle--top-right::after,
|
|
170
|
+
.resize-handle--bottom-left::after,
|
|
171
|
+
.resize-handle--bottom-right::after {
|
|
172
|
+
width: var(--_grip-mark-thickness);
|
|
173
|
+
height: var(--_grip-mark-thickness);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.resize-handle:hover::after,
|
|
177
|
+
.resize-handle:focus-visible::after {
|
|
178
|
+
opacity: 0.5;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* Equal specificity to the pair above, so source order is what makes the drag
|
|
182
|
+
the stronger of the two states. */
|
|
183
|
+
.resize-handle[data-dragging]::after {
|
|
184
|
+
opacity: 0.9;
|
|
185
|
+
}
|
|
186
|
+
`;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// The sidebar placement: a docked full-height panel that slides to a rail.
|
|
2
|
+
export const SIDEBAR_STYLES: string = `
|
|
3
|
+
/* Sidebar: a full-height docked panel that slides open/closed and
|
|
4
|
+
collapses to a slim icon rail (not the floating launcher). Docked right by
|
|
5
|
+
default; data-side="left" docks it left. Overlay by default — set
|
|
6
|
+
--ag-ui-position: static (and place this element in your own layout) for a
|
|
7
|
+
host-managed push instead. */
|
|
8
|
+
:host([placement="sidebar"]) {
|
|
9
|
+
--_inset: var(--ag-ui-inset, calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) var(--_viewport-inset-right) var(--_viewport-inset-bottom) auto);
|
|
10
|
+
--_width: var(--ag-ui-width, 420px);
|
|
11
|
+
--_height: var(--ag-ui-height, var(--_viewport-height));
|
|
12
|
+
--_max-height: var(--ag-ui-max-height, var(--_viewport-height));
|
|
13
|
+
--_panel-radius: var(--ag-ui-panel-radius, 0);
|
|
14
|
+
transition: width var(--_motion) var(--_ease);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
:host([placement="sidebar"][data-side="left"]) {
|
|
18
|
+
--_inset: var(
|
|
19
|
+
--ag-ui-inset,
|
|
20
|
+
calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) auto var(--_viewport-inset-bottom)
|
|
21
|
+
var(--_viewport-inset-left)
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* The docked panel is pinned to the edge it docks against rather than filling
|
|
26
|
+
the host as a flex child. Collapsing shrinks the host to the rail width, and
|
|
27
|
+
a flex child would be squashed to 52px on the way out instead of sliding out
|
|
28
|
+
at full width. */
|
|
29
|
+
/* The panel is taken out of flow so the collapse can slide it out at full
|
|
30
|
+
width; see the note above. That makes the host its containing block, and the
|
|
31
|
+
host is only one by accident: it is position: fixed by default. A host that
|
|
32
|
+
takes the documented route to a pushed layout instead of an overlay sets
|
|
33
|
+
--ag-ui-position: static, and a static element establishes nothing -- so the
|
|
34
|
+
panel resolved against the initial containing block, landed at the document
|
|
35
|
+
origin, and scrolled away with the page. Docked left it pinned to the
|
|
36
|
+
document's left edge rather than the host's.
|
|
37
|
+
|
|
38
|
+
It looked correct wherever it was first tried, because a full-height column
|
|
39
|
+
at the top of an unscrolled document is exactly where those two answers
|
|
40
|
+
coincide. Containment makes the host a containing block whatever its
|
|
41
|
+
position, so the panel stays in the box the host was given. It is a no-op in
|
|
42
|
+
the default case, which is already positioned. */
|
|
43
|
+
:host([placement="sidebar"]) {
|
|
44
|
+
contain: layout;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
:host([placement="sidebar"]) .chat {
|
|
48
|
+
position: absolute;
|
|
49
|
+
inset: 0 0 0 auto;
|
|
50
|
+
width: var(--_width);
|
|
51
|
+
transform-origin: right center;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
:host([placement="sidebar"][data-side="left"]) .chat {
|
|
55
|
+
inset: 0 auto 0 0;
|
|
56
|
+
transform-origin: left center;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Collapsed sidebar: shrink the host to the rail width and slide the panel out
|
|
60
|
+
through the edge it docks against. Higher specificity than the generic
|
|
61
|
+
collapse rules, so it wins regardless of source order. */
|
|
62
|
+
/* The rail is the full height of what the host left, not of the screen. It
|
|
63
|
+
said 100vh and pinned its own bottom, which put it under any chrome the host
|
|
64
|
+
had reserved -- and the icon lives at the top of the rail, so the one control
|
|
65
|
+
that reopens the panel was the first thing to disappear behind a sticky
|
|
66
|
+
header. */
|
|
67
|
+
:host([placement="sidebar"][collapsed]) {
|
|
68
|
+
width: var(--_rail-width);
|
|
69
|
+
height: var(--_viewport-height);
|
|
70
|
+
max-height: var(--_viewport-height);
|
|
71
|
+
pointer-events: auto;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
:host([placement="sidebar"][collapsed]) .chat {
|
|
75
|
+
transform: translateX(100%);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
:host([placement="sidebar"][data-side="left"][collapsed]) .chat {
|
|
79
|
+
transform: translateX(-100%);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@media (prefers-reduced-motion: reduce) {
|
|
83
|
+
:host([placement="sidebar"]),
|
|
84
|
+
:host([placement="sidebar"]) .chat {
|
|
85
|
+
transition: none;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
`;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// The one shape every placement takes on a phone-sized viewport.
|
|
2
|
+
export const SMALL_VIEWPORT_STYLES: string = `
|
|
3
|
+
/* Small viewports: one shape, reached from whichever placement the host chose.
|
|
4
|
+
|
|
5
|
+
A phone is not an eighth placement, it is an override that collapses the
|
|
6
|
+
others onto one of them. The host picked a placement for the desktop it was
|
|
7
|
+
designing; a 380x560 panel with a 24px margin is not a smaller version of
|
|
8
|
+
that decision, it is most of the screen with a frame drawn round it.
|
|
9
|
+
|
|
10
|
+
The breakpoint is a literal because a custom property cannot be read in a
|
|
11
|
+
media query -- which is exactly why there is an opt-out. Everything the block
|
|
12
|
+
sets is a token a host can re-state, but the *trigger* is unreachable, so a
|
|
13
|
+
host whose layout wants a different threshold, or none, sets
|
|
14
|
+
data-small-viewport="off" and keeps its desktop shape at every width. 600px is above every common phone in portrait and below every
|
|
15
|
+
tablet in landscape, and it is a width rather than a pointer test on purpose:
|
|
16
|
+
a touch laptop is coarse-pointered and wide, a narrow desktop window is
|
|
17
|
+
fine-pointered and small, and conflating the two gets both wrong. What the
|
|
18
|
+
pointer decides is which controls make sense, further down.
|
|
19
|
+
|
|
20
|
+
Two placements are left alone. "page" is already this shape. "embedded" sits
|
|
21
|
+
in a box the host sized and placed, and taking that over would break the app
|
|
22
|
+
shell it was embedded into -- the host is the only party that knows whether
|
|
23
|
+
its column should become the whole screen. */
|
|
24
|
+
@media (max-width: 600px) {
|
|
25
|
+
:host([placement="floating"]:not([data-small-viewport="off"])),
|
|
26
|
+
:host([placement="bottom-left"]:not([data-small-viewport="off"])),
|
|
27
|
+
:host([placement="sidebar"]:not([data-small-viewport="off"])),
|
|
28
|
+
:host([placement="side"]:not([data-small-viewport="off"])),
|
|
29
|
+
:host(:not([placement]):not([data-small-viewport="off"])),
|
|
30
|
+
:host([placement=""]:not([data-small-viewport="off"])) {
|
|
31
|
+
--_inset: var(
|
|
32
|
+
--ag-ui-inset,
|
|
33
|
+
calc(var(--_viewport-inset-top) + var(--_keyboard-inset-top)) var(--_viewport-inset-right)
|
|
34
|
+
calc(var(--_viewport-inset-bottom) + var(--_keyboard-inset))
|
|
35
|
+
var(--_viewport-inset-left)
|
|
36
|
+
);
|
|
37
|
+
--_width: var(--ag-ui-width, var(--_viewport-width));
|
|
38
|
+
--_height: var(--ag-ui-height, var(--_viewport-height));
|
|
39
|
+
--_max-width: var(--ag-ui-max-width, var(--_viewport-width));
|
|
40
|
+
--_max-height: var(--ag-ui-max-height, var(--_viewport-height));
|
|
41
|
+
--_panel-radius: var(--ag-ui-panel-radius, 0);
|
|
42
|
+
--_shadow: var(--ag-ui-shadow, none);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* Nothing to resize once the panel is the screen, and the grips would sit
|
|
46
|
+
under the thumbs holding the phone. */
|
|
47
|
+
:host([placement="floating"]:not([data-small-viewport="off"])) .resize-handle,
|
|
48
|
+
:host([placement="bottom-left"]:not([data-small-viewport="off"])) .resize-handle,
|
|
49
|
+
:host([placement="sidebar"]:not([data-small-viewport="off"])) .resize-handle,
|
|
50
|
+
:host([placement="side"]:not([data-small-viewport="off"])) .resize-handle,
|
|
51
|
+
:host(:not([placement]):not([data-small-viewport="off"])) .resize-handle,
|
|
52
|
+
:host([placement=""]:not([data-small-viewport="off"])) .resize-handle {
|
|
53
|
+
display: none;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
`;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { ResizeAxis } from "./resize_handle.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What a collapsed panel shrinks to.
|
|
5
|
+
*
|
|
6
|
+
* Only `null` versus not-`null` is read today: every caller asks whether the
|
|
7
|
+
* surface can collapse at all, never which target it collapses to. The three
|
|
8
|
+
* names below therefore describe the surface rather than drive it, and nothing
|
|
9
|
+
* relies on them (changing one fails only the test of this record). The
|
|
10
|
+
* bottom-bar collapse is expected to read or replace them, and a reader that
|
|
11
|
+
* does should come with a test outside this record's own.
|
|
12
|
+
*
|
|
13
|
+
* - `launcher` -- the round button in a corner.
|
|
14
|
+
* - `rail` -- the slim full-height edge the sidebar docks against; the same
|
|
15
|
+
* launcher element, shaped by the stylesheet.
|
|
16
|
+
* - `header` -- the in-flow collapse: the body hides and the header bar stays
|
|
17
|
+
* in the host's layout, so there is no launcher at all.
|
|
18
|
+
* - `null` -- no collapsed state. `page` is a dedicated route rather than a
|
|
19
|
+
* panel on someone else's page, so there is no "away" for it to go to:
|
|
20
|
+
* collapsing it left a strip of application chrome fixed over a route with
|
|
21
|
+
* no owner, and it hides the launcher, so the usual way back did not exist.
|
|
22
|
+
* The header drops its collapse control here, but a control removed from
|
|
23
|
+
* the UI is not a state removed from the model: the property, the attribute
|
|
24
|
+
* and a value restored from storage all still reach it, so every one of
|
|
25
|
+
* those paths asks this record; the stylesheet covers the one path that
|
|
26
|
+
* never does, an attribute written straight onto the element.
|
|
27
|
+
*/
|
|
28
|
+
export type CollapseTarget = "launcher" | "rail" | "header" | null;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Everything the script needs to know about one display surface, in one
|
|
32
|
+
* record, so a placement's behaviour is read in one place rather than
|
|
33
|
+
* assembled from a table per question.
|
|
34
|
+
*
|
|
35
|
+
* The stylesheet still carries each surface's look (one module per placement
|
|
36
|
+
* under this directory); this is the part of a surface that code decides.
|
|
37
|
+
*/
|
|
38
|
+
export interface Surface {
|
|
39
|
+
/**
|
|
40
|
+
* What collapsing shrinks the panel to; `null` when it cannot collapse. Only
|
|
41
|
+
* the `null` test is authoritative: the non-null names are descriptive (see
|
|
42
|
+
* {@link CollapseTarget}), and nothing branches on which one a surface has.
|
|
43
|
+
*/
|
|
44
|
+
readonly collapseTo: CollapseTarget;
|
|
45
|
+
/**
|
|
46
|
+
* Whether a gesture may move the launcher. The rest have nowhere to put it:
|
|
47
|
+
* the rail is a docked edge, `header` and `null` have no launcher, and a
|
|
48
|
+
* full-bleed panel covers the screen it would be opening into.
|
|
49
|
+
*/
|
|
50
|
+
readonly launcherDraggable: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Which axes the resize grips may change. A full-bleed layout is the whole
|
|
53
|
+
* viewport by definition and cannot be resized; a docked panel owns its
|
|
54
|
+
* height, leaving only its inner edge.
|
|
55
|
+
*/
|
|
56
|
+
readonly resizeAxis: ResizeAxis;
|
|
57
|
+
/**
|
|
58
|
+
* Whether a first mount with nothing stored starts collapsed. Only the
|
|
59
|
+
* corner placements do: a launcher is the resting state of every corner chat
|
|
60
|
+
* in the field, and mounting open put a 380x560 panel over the host page's
|
|
61
|
+
* corner on a visitor's first load, uninvited. The placements that place
|
|
62
|
+
* themselves start open -- a host that docks a sidebar has already decided
|
|
63
|
+
* the widget belongs on screen, and one that embeds it has given it a box.
|
|
64
|
+
*
|
|
65
|
+
* Separate from {@link launcherDraggable} although the two agree today:
|
|
66
|
+
* "has a launcher to rest on" and "the launcher can be moved" are different
|
|
67
|
+
* questions, and a surface with a fixed launcher would answer them apart.
|
|
68
|
+
*/
|
|
69
|
+
readonly startsCollapsed: boolean;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const CORNER: Surface = {
|
|
73
|
+
collapseTo: "launcher",
|
|
74
|
+
launcherDraggable: true,
|
|
75
|
+
resizeAxis: "both",
|
|
76
|
+
startsCollapsed: true,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const DOCKED: Surface = {
|
|
80
|
+
collapseTo: "launcher",
|
|
81
|
+
launcherDraggable: false,
|
|
82
|
+
resizeAxis: "width",
|
|
83
|
+
startsCollapsed: false,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* One record per `placement` value. Absent (`null`) and empty are the default
|
|
88
|
+
* floating corner, as the stylesheet treats them.
|
|
89
|
+
*/
|
|
90
|
+
const SURFACES: ReadonlyMap<string | null, Surface> = new Map<string | null, Surface>([
|
|
91
|
+
[null, CORNER],
|
|
92
|
+
["", CORNER],
|
|
93
|
+
["floating", CORNER],
|
|
94
|
+
["bottom-left", CORNER],
|
|
95
|
+
["side", DOCKED],
|
|
96
|
+
["sidebar", { ...DOCKED, collapseTo: "rail" }],
|
|
97
|
+
[
|
|
98
|
+
"full",
|
|
99
|
+
{
|
|
100
|
+
collapseTo: "launcher",
|
|
101
|
+
launcherDraggable: false,
|
|
102
|
+
resizeAxis: "none",
|
|
103
|
+
startsCollapsed: false,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
[
|
|
107
|
+
"page",
|
|
108
|
+
{ collapseTo: null, launcherDraggable: false, resizeAxis: "none", startsCollapsed: false },
|
|
109
|
+
],
|
|
110
|
+
[
|
|
111
|
+
"embedded",
|
|
112
|
+
{ collapseTo: "header", launcherDraggable: false, resizeAxis: "both", startsCollapsed: false },
|
|
113
|
+
],
|
|
114
|
+
]);
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* A value no record names. The stylesheet lays it out as the default corner,
|
|
118
|
+
* but the script has never treated an unknown value as one: its launcher stays
|
|
119
|
+
* put and it mounts open, so a typo in a host's markup does not start moving
|
|
120
|
+
* or hiding a panel the host meant to show.
|
|
121
|
+
*/
|
|
122
|
+
const UNKNOWN: Surface = {
|
|
123
|
+
collapseTo: "launcher",
|
|
124
|
+
launcherDraggable: false,
|
|
125
|
+
resizeAxis: "both",
|
|
126
|
+
startsCollapsed: false,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* The surface `placement` describes. Read per interaction by every caller,
|
|
131
|
+
* because `placement` is a live attribute.
|
|
132
|
+
*/
|
|
133
|
+
export function surfaceFor(placement: string | null): Surface {
|
|
134
|
+
return SURFACES.get(placement) ?? UNKNOWN;
|
|
135
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// The one-line notice a run leaves in the transcript, with its undo.
|
|
2
|
+
export const RUN_NOTICE_STYLES: string = `
|
|
3
|
+
.run-notice {
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
gap: 6px;
|
|
7
|
+
align-self: flex-start;
|
|
8
|
+
max-width: 100%;
|
|
9
|
+
margin: 2px 0;
|
|
10
|
+
padding: 3px 10px;
|
|
11
|
+
border: 1px dashed var(--_border);
|
|
12
|
+
border-radius: 999px;
|
|
13
|
+
background: transparent;
|
|
14
|
+
color: var(--_muted);
|
|
15
|
+
font-size: 0.8em;
|
|
16
|
+
line-height: 1.4;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.run-notice-icon {
|
|
20
|
+
flex: none;
|
|
21
|
+
opacity: 0.75;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* The one control a notice may carry. Quiet, because it reports something
|
|
25
|
+
already done rather than asking for a decision. */
|
|
26
|
+
.run-notice-undo {
|
|
27
|
+
flex: 0 0 auto;
|
|
28
|
+
margin-inline-start: auto;
|
|
29
|
+
padding: 2px 8px;
|
|
30
|
+
border: 1px solid var(--_border);
|
|
31
|
+
border-radius: var(--_radius);
|
|
32
|
+
background: var(--_bg);
|
|
33
|
+
color: var(--_accent);
|
|
34
|
+
font: inherit;
|
|
35
|
+
font-size: 0.9em;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.run-notice-undo:hover:not(:disabled) {
|
|
40
|
+
background: var(--_hover);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.run-notice-undo:disabled {
|
|
44
|
+
opacity: 0.5;
|
|
45
|
+
cursor: default;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.run-notice-text {
|
|
49
|
+
min-width: 0;
|
|
50
|
+
overflow-wrap: anywhere;
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// The collapsible reasoning region over an assistant turn.
|
|
2
|
+
export const THOUGHTS_STYLES: string = `
|
|
3
|
+
/* ── Thoughts region ────────────────────────────────────────────
|
|
4
|
+
A muted, collapsible chain-of-thought at the top of the answer group: open
|
|
5
|
+
while the model reasons, folded once the answer text starts. */
|
|
6
|
+
.thoughts {
|
|
7
|
+
align-self: stretch;
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
gap: 4px;
|
|
11
|
+
font-size: 12px;
|
|
12
|
+
color: var(--_muted);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.thoughts-toggle {
|
|
16
|
+
align-self: flex-start;
|
|
17
|
+
border: none;
|
|
18
|
+
padding: 0;
|
|
19
|
+
background: none;
|
|
20
|
+
font: inherit;
|
|
21
|
+
font-size: 12px;
|
|
22
|
+
font-weight: 600;
|
|
23
|
+
color: var(--_muted);
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.thoughts-toggle::before {
|
|
28
|
+
content: var(--_disclosure-expanded) " ";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.thoughts-toggle[aria-expanded="false"]::before {
|
|
32
|
+
content: var(--_disclosure-collapsed) " ";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* A gentle pulse on the label while reasoning is still streaming. */
|
|
36
|
+
.thoughts[data-streaming] .thoughts-label {
|
|
37
|
+
animation: ag-ui-thoughts-pulse 1.4s ease-in-out infinite;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@keyframes ag-ui-thoughts-pulse {
|
|
41
|
+
0%, 100% { opacity: 0.55; }
|
|
42
|
+
50% { opacity: 1; }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.thoughts-body {
|
|
46
|
+
margin: 0;
|
|
47
|
+
padding: 4px 0 4px 10px;
|
|
48
|
+
border-left: 2px solid var(--_border);
|
|
49
|
+
max-height: 220px;
|
|
50
|
+
overflow: auto;
|
|
51
|
+
white-space: pre-wrap;
|
|
52
|
+
word-break: break-word;
|
|
53
|
+
font-family: inherit;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.thoughts-body[hidden] {
|
|
57
|
+
display: none;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@media (prefers-reduced-motion: reduce) {
|
|
61
|
+
.thoughts[data-streaming] .thoughts-label {
|
|
62
|
+
animation: none;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
`;
|
|
@@ -287,6 +287,17 @@ export class ToolCallCard {
|
|
|
287
287
|
this.#status.textContent = statusLabels(this.#strings)[status];
|
|
288
288
|
}
|
|
289
289
|
|
|
290
|
+
/**
|
|
291
|
+
* Say whether a prompt is open on this call, a question it asked or a
|
|
292
|
+
* confirmation it needs. A flag of its own beside the status, which stays
|
|
293
|
+
* `pending`: the call is still running as far as the status goes, and a card
|
|
294
|
+
* display mode that reads the status draws it exactly as before. The step
|
|
295
|
+
* group reads the flag to tell a call waiting on a person from one working.
|
|
296
|
+
*/
|
|
297
|
+
setAsking(asking: boolean): void {
|
|
298
|
+
this.element.toggleAttribute("data-asking", asking);
|
|
299
|
+
}
|
|
300
|
+
|
|
290
301
|
/**
|
|
291
302
|
* Record that a human approved or declined this call, as a line in the card.
|
|
292
303
|
* The prompt disappears once answered, so this is the only lasting trace that
|