@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,262 @@
|
|
|
1
|
+
// Messages: the answer well, incoming-text animations, rendered markdown,
|
|
2
|
+
// code blocks and their copy button, tables, and the pending dots.
|
|
3
|
+
export const MESSAGE_STYLES: string = `
|
|
4
|
+
/* ── Answer group / well ─────────────────────────────────────────
|
|
5
|
+
One .answer per assistant turn wraps the streamed text, its tool cards,
|
|
6
|
+
and the pending indicator so a whole answer reads (and can be boxed) as one
|
|
7
|
+
unit. A flex column on the message-list gap, stretched to the list width so
|
|
8
|
+
its children keep their own left/right alignment. data-answer-well opts into
|
|
9
|
+
the bordered "well"; without it the turn renders as a flat stack. */
|
|
10
|
+
.answer {
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
gap: var(--_space);
|
|
14
|
+
align-self: stretch;
|
|
15
|
+
min-width: 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
:host([data-answer-well]) .answer {
|
|
19
|
+
padding: var(--_pad);
|
|
20
|
+
background: var(--_well-bg);
|
|
21
|
+
border: 1px solid var(--_well-border);
|
|
22
|
+
border-radius: var(--_well-radius);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.message {
|
|
26
|
+
max-width: 80%;
|
|
27
|
+
padding: var(--_msg-pad);
|
|
28
|
+
border-radius: var(--_msg-radius);
|
|
29
|
+
line-height: 1.4;
|
|
30
|
+
white-space: pre-wrap;
|
|
31
|
+
/* overflow-wrap, not word-break, and the difference is the whole reason a
|
|
32
|
+
markdown table used to be unreadable.
|
|
33
|
+
|
|
34
|
+
Both stop one long unbroken token blowing out the bubble, which is all this
|
|
35
|
+
is for. But word-break: break-word is the legacy spelling of "break
|
|
36
|
+
anywhere", and breaking anywhere drops the *min-content* width of every
|
|
37
|
+
descendant to one character. A table's column algorithm takes min-content
|
|
38
|
+
as an input, so the table always fitted max-width: 100%, the overflow-x:
|
|
39
|
+
auto below it never had anything to scroll, and the columns absorbed the
|
|
40
|
+
pressure by rendering one letter per line instead. A seven-column header
|
|
41
|
+
came out 162px tall.
|
|
42
|
+
|
|
43
|
+
overflow-wrap: break-word breaks a word only when it would otherwise
|
|
44
|
+
overflow its line, and leaves min-content alone -- so the bubble is still
|
|
45
|
+
protected and the table is free to be wider than the panel and scroll. */
|
|
46
|
+
overflow-wrap: break-word;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* ── Incoming-text animations (data-text-animation) ─────────────────────── */
|
|
50
|
+
/* .message--restored (rehydrated history) is excluded: entrance animations are
|
|
51
|
+
for freshly-arriving messages, not the whole transcript replaying on reload.
|
|
52
|
+
Word mode is excluded implicitly — restored bubbles aren't wrapped. */
|
|
53
|
+
:host([data-text-animation="fade"]) .message--assistant:not(.message--restored) {
|
|
54
|
+
animation: ag-ui-msg-fade 0.25s ease both;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@keyframes ag-ui-msg-fade {
|
|
58
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
59
|
+
to { opacity: 1; transform: none; }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.message--assistant .word {
|
|
63
|
+
animation: ag-ui-word-in 0.3s ease both;
|
|
64
|
+
animation-delay: calc(var(--ag-ui-word-index, 0) * 35ms);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@keyframes ag-ui-word-in {
|
|
68
|
+
from { opacity: 0; }
|
|
69
|
+
to { opacity: 1; }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@media (prefers-reduced-motion: reduce) {
|
|
73
|
+
:host([data-text-animation="fade"]) .message--assistant,
|
|
74
|
+
.message--assistant .word {
|
|
75
|
+
animation: none;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.message--user {
|
|
80
|
+
align-self: flex-end;
|
|
81
|
+
background: var(--_user-bg);
|
|
82
|
+
color: var(--_user-fg);
|
|
83
|
+
border-bottom-right-radius: 4px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.message--assistant {
|
|
87
|
+
align-self: flex-start;
|
|
88
|
+
background: var(--_assistant-bg);
|
|
89
|
+
border-bottom-left-radius: 4px;
|
|
90
|
+
/* Assistant bubbles hold rendered markdown/HTML, so collapse the source
|
|
91
|
+
whitespace the renderer leaves between block tags. */
|
|
92
|
+
white-space: normal;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Rendered-markdown elements inside an assistant bubble. */
|
|
96
|
+
.message--assistant > :first-child {
|
|
97
|
+
margin-top: 0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.message--assistant > :last-child {
|
|
101
|
+
margin-bottom: 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.message--assistant p,
|
|
105
|
+
.message--assistant ul,
|
|
106
|
+
.message--assistant ol,
|
|
107
|
+
.message--assistant blockquote,
|
|
108
|
+
.message--assistant pre {
|
|
109
|
+
margin: 0.5em 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.message--assistant ul,
|
|
113
|
+
.message--assistant ol {
|
|
114
|
+
padding-left: 1.3em;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.message--assistant a {
|
|
118
|
+
color: var(--_accent);
|
|
119
|
+
text-decoration: underline;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.message--assistant code {
|
|
123
|
+
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
|
124
|
+
font-size: 0.92em;
|
|
125
|
+
background: rgba(127, 127, 127, 0.16);
|
|
126
|
+
padding: 1px 4px;
|
|
127
|
+
border-radius: 4px;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.message--assistant pre {
|
|
131
|
+
padding: 8px 10px;
|
|
132
|
+
overflow: auto;
|
|
133
|
+
background: var(--_bg);
|
|
134
|
+
border: 1px solid var(--_border);
|
|
135
|
+
border-radius: 6px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.message--assistant pre code {
|
|
139
|
+
background: none;
|
|
140
|
+
padding: 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* The copy button sits inside the block, so it scrolls with wide code rather
|
|
144
|
+
than floating over the bubble. Positioning is on the pre; the button only
|
|
145
|
+
appears once one has been attached. */
|
|
146
|
+
.message--assistant pre.has-copy {
|
|
147
|
+
position: relative;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* The only reader of --ag-ui-surface and --ag-ui-text. Their defaults are
|
|
151
|
+
transparent and the body foreground, which is what this button rendered as
|
|
152
|
+
before either token existed; changing them repaints only this control. */
|
|
153
|
+
.code-copy {
|
|
154
|
+
position: absolute;
|
|
155
|
+
top: 4px;
|
|
156
|
+
right: 4px;
|
|
157
|
+
padding: 2px 8px;
|
|
158
|
+
font: inherit;
|
|
159
|
+
font-size: 0.75em;
|
|
160
|
+
line-height: 1.6;
|
|
161
|
+
color: var(--_muted);
|
|
162
|
+
background: var(--_surface);
|
|
163
|
+
border: 1px solid var(--_border);
|
|
164
|
+
border-radius: 4px;
|
|
165
|
+
cursor: pointer;
|
|
166
|
+
opacity: 0;
|
|
167
|
+
transition: opacity 0.12s ease;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* Revealed on hover or keyboard focus. Focus matters as much as hover here:
|
|
171
|
+
hidden-until-hover is invisible to a keyboard user otherwise. */
|
|
172
|
+
.message--assistant pre.has-copy:hover .code-copy,
|
|
173
|
+
.code-copy:focus-visible {
|
|
174
|
+
opacity: 1;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.code-copy:hover {
|
|
178
|
+
color: var(--_text);
|
|
179
|
+
background: var(--_hover);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.code-copy[data-state="copied"] {
|
|
183
|
+
opacity: 1;
|
|
184
|
+
color: var(--_text);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.code-copy[data-state="failed"] {
|
|
188
|
+
opacity: 1;
|
|
189
|
+
color: var(--_danger, var(--_text));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.message--assistant blockquote {
|
|
193
|
+
padding-left: 10px;
|
|
194
|
+
border-left: 3px solid var(--_border);
|
|
195
|
+
color: var(--_muted);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Markdown tables. table/thead/tbody/tr/th/td are all in the sanitizer's
|
|
199
|
+
ALLOWED_TAGS, so an agent can emit one. A wide table must scroll inside its
|
|
200
|
+
own box rather than stretch the message: the bubble is width-constrained, so
|
|
201
|
+
without this the columns either crush or push the layout sideways. */
|
|
202
|
+
.message--assistant table {
|
|
203
|
+
display: block;
|
|
204
|
+
width: fit-content;
|
|
205
|
+
max-width: 100%;
|
|
206
|
+
overflow-x: auto;
|
|
207
|
+
border-collapse: collapse;
|
|
208
|
+
font-size: 0.95em;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.message--assistant th,
|
|
212
|
+
.message--assistant td {
|
|
213
|
+
padding: 6px 10px;
|
|
214
|
+
border: 1px solid var(--_border);
|
|
215
|
+
text-align: left;
|
|
216
|
+
vertical-align: top;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.message--assistant th {
|
|
220
|
+
background: var(--_hover);
|
|
221
|
+
font-weight: 600;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.pending {
|
|
225
|
+
align-self: flex-start;
|
|
226
|
+
display: inline-flex;
|
|
227
|
+
gap: 4px;
|
|
228
|
+
align-items: center;
|
|
229
|
+
padding: 12px 14px;
|
|
230
|
+
background: var(--_assistant-bg);
|
|
231
|
+
border-radius: 14px;
|
|
232
|
+
border-bottom-left-radius: 4px;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.pending-dot {
|
|
236
|
+
width: 6px;
|
|
237
|
+
height: 6px;
|
|
238
|
+
border-radius: 50%;
|
|
239
|
+
background: var(--_muted);
|
|
240
|
+
animation: ag-ui-pending 1.2s infinite ease-in-out both;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.pending-dot:nth-child(2) {
|
|
244
|
+
animation-delay: 0.16s;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.pending-dot:nth-child(3) {
|
|
248
|
+
animation-delay: 0.32s;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
@keyframes ag-ui-pending {
|
|
252
|
+
0%, 80%, 100% { opacity: 0.3; transform: translateY(0); }
|
|
253
|
+
40% { opacity: 1; transform: translateY(-3px); }
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
@media (prefers-reduced-motion: reduce) {
|
|
257
|
+
.pending-dot {
|
|
258
|
+
animation: none;
|
|
259
|
+
opacity: 0.6;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
`;
|
|
@@ -8,8 +8,14 @@ import { fillUiString } from "../fill_ui_string.js";
|
|
|
8
8
|
import { prettifyToolName } from "../progress/prettify_tool_name.js";
|
|
9
9
|
import { renderRunNotice } from "../progress/run_notice.js";
|
|
10
10
|
import { ThoughtsBlock } from "../progress/thoughts_block.js";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
ToolCallCard,
|
|
13
|
+
type ToolDisplayMode,
|
|
14
|
+
type ToolPayload,
|
|
15
|
+
} from "../progress/tool_call_card.js";
|
|
16
|
+
import { ToolStepGroup } from "../progress/tool_step_group.js";
|
|
12
17
|
import type { UiStrings } from "../ui_strings.js";
|
|
18
|
+
import { groupsToolSteps } from "./groups_tool_steps.js";
|
|
13
19
|
import { renderMarkdown } from "./render_markdown.js";
|
|
14
20
|
import { renderOrWarn } from "./render_or_warn.js";
|
|
15
21
|
import { wrapWords } from "./reveal_words.js";
|
|
@@ -35,6 +41,8 @@ export interface TranscriptHost {
|
|
|
35
41
|
readonly serverSummary: (name: string) => string | undefined;
|
|
36
42
|
/** The element's `formatToolPayload`, asked per region of a card. */
|
|
37
43
|
readonly formatToolPayload: (payload: ToolPayload) => Node | string | null;
|
|
44
|
+
/** The element's `toolDisplay`, read per card: it decides whether calls fold into a step group. */
|
|
45
|
+
readonly toolDisplay: () => ToolDisplayMode;
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
/**
|
|
@@ -54,6 +62,12 @@ export class Transcript {
|
|
|
54
62
|
readonly #toolCards = new Map<string, ToolCallCard>();
|
|
55
63
|
/** Card elements by call id, so a rendering handler can find its own card. */
|
|
56
64
|
readonly #cardElements = new Map<string, HTMLElement>();
|
|
65
|
+
/**
|
|
66
|
+
* Cards whose call is being run, by call id. A card leaves the awaiting ones
|
|
67
|
+
* the moment its call is dispatched, and a handler that opens a prompt on its
|
|
68
|
+
* own card is still running long after, so it is found here.
|
|
69
|
+
*/
|
|
70
|
+
readonly #running = new Map<string | undefined, ToolCallCard>();
|
|
57
71
|
/**
|
|
58
72
|
* Call ids whose card was already settled from a streamed server-side result
|
|
59
73
|
* (`TOOL_CALL_RESULT`), so the post-run executeTool sweep doesn't overwrite
|
|
@@ -74,6 +88,24 @@ export class Transcript {
|
|
|
74
88
|
// the answer group while a reasoning model thinks and collapsed once the
|
|
75
89
|
// answer's first text token arrives. `null` outside a reasoning turn.
|
|
76
90
|
#thoughts: ThoughtsBlock | null = null;
|
|
91
|
+
/** The step group behind each group element, so a new card can find its run. */
|
|
92
|
+
readonly #stepGroups = new WeakMap<Element, ToolStepGroup>();
|
|
93
|
+
/**
|
|
94
|
+
* An empty comment after each step group that has rendered output, which
|
|
95
|
+
* every later output is placed before, so a group's outputs come out in call
|
|
96
|
+
* order. Every card of a round joins its group before any handler runs, so
|
|
97
|
+
* placing each output straight after the group would put the newest first;
|
|
98
|
+
* and a marker rather than the last output, because an output may be a
|
|
99
|
+
* fragment, which leaves nothing behind to place the next one after.
|
|
100
|
+
*/
|
|
101
|
+
readonly #groupEnds = new WeakMap<Element, Comment>();
|
|
102
|
+
/**
|
|
103
|
+
* The step group element each placed output belongs to. A tool's own output
|
|
104
|
+
* does not end its group: the next call joins the group above it. Without
|
|
105
|
+
* that, replay -- which draws each restored call's output before the next
|
|
106
|
+
* call's card -- would split a run the live stream drew as one group.
|
|
107
|
+
*/
|
|
108
|
+
readonly #outputGroups = new WeakMap<Node, Element>();
|
|
77
109
|
|
|
78
110
|
constructor(host: TranscriptHost) {
|
|
79
111
|
this.#host = host;
|
|
@@ -185,6 +217,20 @@ export class Transcript {
|
|
|
185
217
|
forgetCards(): void {
|
|
186
218
|
this.#serverSettled.clear();
|
|
187
219
|
this.#cardElements.clear();
|
|
220
|
+
this.#running.clear();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Remember the card of a call being run, for {@link setAsking}. */
|
|
224
|
+
holdRunning(callId: string, card: ToolCallCard): void {
|
|
225
|
+
this.#running.set(callId, card);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Say whether a prompt is open on the card of a running call. A call id of
|
|
230
|
+
* none, or one no card was held for, has no card to say it on.
|
|
231
|
+
*/
|
|
232
|
+
setAsking(callId: string | undefined, asking: boolean): void {
|
|
233
|
+
this.#running.get(callId)?.setAsking(asking);
|
|
188
234
|
}
|
|
189
235
|
|
|
190
236
|
/** Empty the list back to its empty-state region. The last half of wiping it. */
|
|
@@ -383,7 +429,26 @@ export class Transcript {
|
|
|
383
429
|
// `after` rather than an insert-or-append branch: both callers set the card
|
|
384
430
|
// element immediately before calling, and a parentless anchor makes `after`
|
|
385
431
|
// a no-op, so the alternative would be a branch nothing can reach.
|
|
386
|
-
|
|
432
|
+
//
|
|
433
|
+
// A card folded into a step group has its output placed after the group
|
|
434
|
+
// rather than inside it, so a chart is never hidden one click down.
|
|
435
|
+
const anchor = this.#cardElements.get(call.id);
|
|
436
|
+
const group = anchor?.closest(".tool-group");
|
|
437
|
+
if (group === null || group === undefined) {
|
|
438
|
+
anchor?.after(node);
|
|
439
|
+
} else {
|
|
440
|
+
let end = this.#groupEnds.get(group);
|
|
441
|
+
if (end === undefined) {
|
|
442
|
+
end = document.createComment("");
|
|
443
|
+
group.after(end);
|
|
444
|
+
this.#groupEnds.set(group, end);
|
|
445
|
+
}
|
|
446
|
+
const placed = node instanceof DocumentFragment ? [...node.children] : [node];
|
|
447
|
+
end.before(node);
|
|
448
|
+
for (const output of placed) {
|
|
449
|
+
this.#outputGroups.set(output, group);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
387
452
|
this.afterGrew();
|
|
388
453
|
}
|
|
389
454
|
|
|
@@ -421,9 +486,50 @@ export class Transcript {
|
|
|
421
486
|
formatPayload: (payload) => this.#host.formatToolPayload(payload),
|
|
422
487
|
});
|
|
423
488
|
this.#toolCards.set(call.id, card);
|
|
424
|
-
this.
|
|
489
|
+
if (groupsToolSteps(this.#host.toolDisplay())) {
|
|
490
|
+
this.#stepGroup().add(card.element, summary);
|
|
491
|
+
} else {
|
|
492
|
+
this.ensureGroup().appendChild(card.element);
|
|
493
|
+
}
|
|
425
494
|
this.updateEmptyState();
|
|
426
495
|
this.follow();
|
|
427
496
|
return card;
|
|
428
497
|
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Open the step group ``card`` sits in, at once, ahead of a prompt about to be
|
|
501
|
+
* drawn inside it. A no-op for a card drawn in a card display mode, which has
|
|
502
|
+
* no group.
|
|
503
|
+
*/
|
|
504
|
+
revealStep(card: ToolCallCard): void {
|
|
505
|
+
const group = card.element.closest(".tool-group");
|
|
506
|
+
(group === null ? undefined : this.#stepGroups.get(group))?.reveal();
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* The step group a new card joins. Consecutive cards share one, and so do
|
|
511
|
+
* cards separated only by the group's own rendered output; anything else in
|
|
512
|
+
* between (text, a confirmation, a question) starts the next.
|
|
513
|
+
*
|
|
514
|
+
* The pending dots are not skipped over: a tool call takes them down before
|
|
515
|
+
* its card is drawn, so they are never what a card finds at the foot of the
|
|
516
|
+
* turn.
|
|
517
|
+
*/
|
|
518
|
+
#stepGroup(): ToolStepGroup {
|
|
519
|
+
const answer = this.ensureGroup();
|
|
520
|
+
const last = answer.lastElementChild;
|
|
521
|
+
const existing =
|
|
522
|
+
last === null ? undefined : this.#stepGroups.get(this.#outputGroups.get(last) ?? last);
|
|
523
|
+
if (existing !== undefined) {
|
|
524
|
+
return existing;
|
|
525
|
+
}
|
|
526
|
+
const group = new ToolStepGroup(this.#host.strings());
|
|
527
|
+
this.#stepGroups.set(group.element, group);
|
|
528
|
+
if (last === null) {
|
|
529
|
+
answer.prepend(group.element);
|
|
530
|
+
} else {
|
|
531
|
+
last.after(group.element);
|
|
532
|
+
}
|
|
533
|
+
return group;
|
|
534
|
+
}
|
|
429
535
|
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// The scrolling message list and what is positioned against it: jump to
|
|
2
|
+
// latest, the quote-selection offer, the live region and the inset probe.
|
|
3
|
+
export const TRANSCRIPT_STYLES: string = `
|
|
4
|
+
/* Jump-to-latest: shown only once the reader has scrolled away *and* missed
|
|
5
|
+
something. Anchored to the panel rather than the list so it does not scroll
|
|
6
|
+
with the content it is offering to scroll to. */
|
|
7
|
+
/* The transcript's own box, and the only one whose foot is the transcript's
|
|
8
|
+
foot. The panel's foot is below the composer, the chips and the footer. */
|
|
9
|
+
.messages-wrap {
|
|
10
|
+
position: relative;
|
|
11
|
+
flex: 1;
|
|
12
|
+
min-height: 0;
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.jump-latest {
|
|
18
|
+
position: absolute;
|
|
19
|
+
left: 50%;
|
|
20
|
+
transform: translateX(-50%);
|
|
21
|
+
bottom: var(--_pad);
|
|
22
|
+
z-index: 2;
|
|
23
|
+
display: none;
|
|
24
|
+
align-items: center;
|
|
25
|
+
gap: 0.35em;
|
|
26
|
+
padding: 0.4em 0.9em;
|
|
27
|
+
border: 1px solid var(--_border);
|
|
28
|
+
border-radius: 999px;
|
|
29
|
+
/* A raised surface, not the panel's own background. Reusing --_bg made the
|
|
30
|
+
pill the same colour as everything behind it, leaving a 1px border and a
|
|
31
|
+
shadow to carry the whole affordance -- and a dark-on-dark shadow carries
|
|
32
|
+
nothing. --_hover is the token that already means "lifted off the panel",
|
|
33
|
+
and it separates in both themes without competing with the accent the send
|
|
34
|
+
button owns. */
|
|
35
|
+
background: var(--_hover);
|
|
36
|
+
color: var(--_text);
|
|
37
|
+
font: inherit;
|
|
38
|
+
font-size: 0.85em;
|
|
39
|
+
cursor: pointer;
|
|
40
|
+
box-shadow: 0 2px 10px rgb(0 0 0 / 0.18);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.jump-latest[data-missed="true"] {
|
|
44
|
+
display: flex;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.jump-latest:hover {
|
|
48
|
+
border-color: var(--_accent);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* The offer to quote a selection. Positioned in script against the transcript
|
|
52
|
+
box, which is the only ancestor whose top and foot are the transcript's --
|
|
53
|
+
the same reason .jump-latest lives here. The translate is the half the
|
|
54
|
+
script does not do: script sets the point the offer hangs from, CSS decides
|
|
55
|
+
which corner of the offer that point is. */
|
|
56
|
+
.quote-selection {
|
|
57
|
+
position: absolute;
|
|
58
|
+
z-index: 2;
|
|
59
|
+
transform: translate(-50%, -100%);
|
|
60
|
+
padding: 0.25em 0.7em;
|
|
61
|
+
border: 1px solid var(--_border);
|
|
62
|
+
border-radius: 999px;
|
|
63
|
+
background: var(--_hover);
|
|
64
|
+
color: var(--_text);
|
|
65
|
+
font: inherit;
|
|
66
|
+
font-size: 0.8em;
|
|
67
|
+
line-height: 1.6;
|
|
68
|
+
white-space: nowrap;
|
|
69
|
+
cursor: pointer;
|
|
70
|
+
box-shadow: 0 2px 10px rgb(0 0 0 / 0.18);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Flipped under the selection when there was no room above it. Only the
|
|
74
|
+
vertical half of the translate changes: it still hangs from its own centre
|
|
75
|
+
horizontally. */
|
|
76
|
+
.quote-selection[data-below="true"] {
|
|
77
|
+
transform: translate(-50%, 0);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.quote-selection:hover {
|
|
81
|
+
border-color: var(--_accent);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Screen-reader-only status region. Off-screen rather than display:none or
|
|
85
|
+
visibility:hidden, both of which take the element out of the accessibility
|
|
86
|
+
tree entirely -- a hidden live region announces nothing at all, which is the
|
|
87
|
+
classic way this pattern is written wrong.
|
|
88
|
+
|
|
89
|
+
The 1px box with clip-path, rather than width/height 0, is the shape that
|
|
90
|
+
survives: a zero-sized element is dropped from the tree by some engines. */
|
|
91
|
+
/* A used-value reader for the four viewport-inset tokens, and the only
|
|
92
|
+
reliable one. getComputedStyle().getPropertyValue() on an unregistered
|
|
93
|
+
custom property hands back the substituted token stream, not a length: it
|
|
94
|
+
returns "4rem" verbatim, and "calc(56px + env(safe-area-inset-top))" as
|
|
95
|
+
"calc(56px + 0px)" -- which parses as NaN and takes the whole inset with it.
|
|
96
|
+
Padding is a real property, so the same tokens come back resolved to px.
|
|
97
|
+
|
|
98
|
+
visibility rather than display: none, because a box that generates no
|
|
99
|
+
layout has no used values to read. Zero-sized, absolutely positioned and
|
|
100
|
+
inert, so it costs nothing but the read. */
|
|
101
|
+
.viewport-probe {
|
|
102
|
+
position: absolute;
|
|
103
|
+
top: 0;
|
|
104
|
+
left: 0;
|
|
105
|
+
width: 0;
|
|
106
|
+
height: 0;
|
|
107
|
+
visibility: hidden;
|
|
108
|
+
pointer-events: none;
|
|
109
|
+
padding: var(--_viewport-inset-top) var(--_viewport-inset-right)
|
|
110
|
+
var(--_viewport-inset-bottom) var(--_viewport-inset-left);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.sr-only {
|
|
114
|
+
position: absolute;
|
|
115
|
+
width: 1px;
|
|
116
|
+
height: 1px;
|
|
117
|
+
margin: -1px;
|
|
118
|
+
padding: 0;
|
|
119
|
+
border: 0;
|
|
120
|
+
overflow: hidden;
|
|
121
|
+
white-space: nowrap;
|
|
122
|
+
clip-path: inset(50%);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.messages {
|
|
126
|
+
flex: 1;
|
|
127
|
+
overflow-y: auto;
|
|
128
|
+
/* Scrolling past the end of this must not scroll the page behind it. */
|
|
129
|
+
overscroll-behavior: contain;
|
|
130
|
+
/* The browser's own scroll anchoring competes with the scroller for the same
|
|
131
|
+
job and wins unpredictably -- it can hold the view still exactly when we
|
|
132
|
+
want to follow. Turned off so following is decided in one place. Safari
|
|
133
|
+
does not implement it, which is itself a reason not to depend on it. */
|
|
134
|
+
overflow-anchor: none;
|
|
135
|
+
padding: var(--_pad);
|
|
136
|
+
display: flex;
|
|
137
|
+
flex-direction: column;
|
|
138
|
+
gap: var(--_space);
|
|
139
|
+
}
|
|
140
|
+
`;
|
package/src/ui/ui_strings.ts
CHANGED
|
@@ -184,6 +184,29 @@ export interface UiStrings {
|
|
|
184
184
|
/** Label on the toggle that expands a tool card's body. */
|
|
185
185
|
details: string;
|
|
186
186
|
|
|
187
|
+
// ── Tool-step group ─────────────────────────────────────────────────────────
|
|
188
|
+
// The row a run's consecutive calls fold into under the default
|
|
189
|
+
// data-tool-display. A group of one shows that call's own label instead, so
|
|
190
|
+
// the three labels are filled with 2 or more; the notes count from 1.
|
|
191
|
+
/** The group's label while a step waits on the user. Token: `{count}` (steps). */
|
|
192
|
+
toolGroupSteps: string;
|
|
193
|
+
/** The group's label while a step runs. Token: `{count}` (steps). */
|
|
194
|
+
toolGroupWorking: string;
|
|
195
|
+
/** The group's label once every step has settled. Token: `{count}` (steps). */
|
|
196
|
+
toolGroupWorked: string;
|
|
197
|
+
/** Note on the group's row: steps waiting on the user. Token: `{count}`. */
|
|
198
|
+
toolGroupWaiting: string;
|
|
199
|
+
/** Note on the group's row: steps that failed. Token: `{count}`. */
|
|
200
|
+
toolGroupFailed: string;
|
|
201
|
+
/** Note on the group's row: steps that were declined. Token: `{count}`. */
|
|
202
|
+
toolGroupDeclined: string;
|
|
203
|
+
/**
|
|
204
|
+
* Set after a step's label when an earlier step in its group has the same
|
|
205
|
+
* one, so two "Fill field" steps read "Fill field" and "Fill field (2)".
|
|
206
|
+
* Grouped mode only. Token: `{n}` (which occurrence, from 2).
|
|
207
|
+
*/
|
|
208
|
+
toolStepRepeat: string;
|
|
209
|
+
|
|
187
210
|
// ── Delegated sub-agent ─────────────────────────────────────────────────────
|
|
188
211
|
/**
|
|
189
212
|
* The delegation row's text before the server's own status line lands.
|
|
@@ -423,6 +446,14 @@ export const DEFAULT_UI_STRINGS: UiStrings = {
|
|
|
423
446
|
interruptedLabel: "Not finished",
|
|
424
447
|
details: "Details",
|
|
425
448
|
|
|
449
|
+
toolGroupSteps: "{count} steps",
|
|
450
|
+
toolGroupWorking: "Working through {count} steps",
|
|
451
|
+
toolGroupWorked: "Worked through {count} steps",
|
|
452
|
+
toolGroupWaiting: "{count} waiting for you",
|
|
453
|
+
toolGroupFailed: "{count} failed",
|
|
454
|
+
toolGroupDeclined: "{count} declined",
|
|
455
|
+
toolStepRepeat: "({n})",
|
|
456
|
+
|
|
426
457
|
subAgentWorking: "Working…",
|
|
427
458
|
subAgentDelegatedTo: "Delegated to {agent}",
|
|
428
459
|
subAgentFinished: "{agent} finished",
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION: string = "0.
|
|
1
|
+
export const VERSION: string = "0.46.0";
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Whether `placement` has a collapsed state at all.
|
|
3
|
-
*
|
|
4
|
-
* `page` does not. It is a dedicated route rather than a panel sitting on
|
|
5
|
-
* someone else's page, so there is no "away" for it to go to: collapsing it
|
|
6
|
-
* left a strip of application chrome fixed over a route that no longer had an
|
|
7
|
-
* owner. It is also the placement that hides the launcher, so the usual way
|
|
8
|
-
* back does not exist here.
|
|
9
|
-
*
|
|
10
|
-
* The header hides its collapse control under this placement, but a control
|
|
11
|
-
* removed from the UI is not a state removed from the model -- the property,
|
|
12
|
-
* the attribute and a value restored from storage all still reach it. This is
|
|
13
|
-
* what the reachable paths are gated on; the stylesheet covers the one path
|
|
14
|
-
* that never passes through here, an attribute written straight onto the
|
|
15
|
-
* element.
|
|
16
|
-
*/
|
|
17
|
-
export declare function isCollapsiblePlacement(placement: string | null): boolean;
|
|
18
|
-
//# sourceMappingURL=is_collapsible_placement.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"is_collapsible_placement.d.ts","sourceRoot":"","sources":["../../../src/ui/placement/is_collapsible_placement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAExE"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Whether `placement` is one whose launcher can be dragged.
|
|
3
|
-
*
|
|
4
|
-
* Asked by two owners: the placement, deciding whether a gesture may move the
|
|
5
|
-
* widget, and the element, deciding whether a first mount starts collapsed --
|
|
6
|
-
* the corner placements are the two with a launcher to collapse to.
|
|
7
|
-
*/
|
|
8
|
-
export declare function isDraggablePlacement(placement: string | null): boolean;
|
|
9
|
-
//# sourceMappingURL=is_draggable_placement.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"is_draggable_placement.d.ts","sourceRoot":"","sources":["../../../src/ui/placement/is_draggable_placement.ts"],"names":[],"mappings":"AAaA;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAEtE"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Whether `placement` has a collapsed state at all.
|
|
3
|
-
*
|
|
4
|
-
* `page` does not. It is a dedicated route rather than a panel sitting on
|
|
5
|
-
* someone else's page, so there is no "away" for it to go to: collapsing it
|
|
6
|
-
* left a strip of application chrome fixed over a route that no longer had an
|
|
7
|
-
* owner. It is also the placement that hides the launcher, so the usual way
|
|
8
|
-
* back does not exist here.
|
|
9
|
-
*
|
|
10
|
-
* The header hides its collapse control under this placement, but a control
|
|
11
|
-
* removed from the UI is not a state removed from the model -- the property,
|
|
12
|
-
* the attribute and a value restored from storage all still reach it. This is
|
|
13
|
-
* what the reachable paths are gated on; the stylesheet covers the one path
|
|
14
|
-
* that never passes through here, an attribute written straight onto the
|
|
15
|
-
* element.
|
|
16
|
-
*/
|
|
17
|
-
export function isCollapsiblePlacement(placement: string | null): boolean {
|
|
18
|
-
return placement !== "page";
|
|
19
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Placements whose launcher can be dragged. The rest have nowhere to put it:
|
|
3
|
-
* a sidebar collapses to a full-height edge rail, "embedded" and "page" hide
|
|
4
|
-
* the launcher entirely and keep their header bar, and a full-bleed panel
|
|
5
|
-
* covers the screen it would be opening into.
|
|
6
|
-
*/
|
|
7
|
-
const DRAGGABLE_PLACEMENTS: ReadonlySet<string | null> = new Set([
|
|
8
|
-
null,
|
|
9
|
-
"",
|
|
10
|
-
"floating",
|
|
11
|
-
"bottom-left",
|
|
12
|
-
]);
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Whether `placement` is one whose launcher can be dragged.
|
|
16
|
-
*
|
|
17
|
-
* Asked by two owners: the placement, deciding whether a gesture may move the
|
|
18
|
-
* widget, and the element, deciding whether a first mount starts collapsed --
|
|
19
|
-
* the corner placements are the two with a launcher to collapse to.
|
|
20
|
-
*/
|
|
21
|
-
export function isDraggablePlacement(placement: string | null): boolean {
|
|
22
|
-
return DRAGGABLE_PLACEMENTS.has(placement);
|
|
23
|
-
}
|