@aceshooting/lyra-ui 2.0.0 → 2.1.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/README.md +87 -14
- package/custom-elements.json +11555 -5539
- package/dist/components/app-rail/app-rail-item.d.ts +30 -0
- package/dist/components/app-rail/app-rail-item.js +68 -0
- package/dist/components/app-rail/app-rail-item.styles.d.ts +1 -0
- package/dist/components/app-rail/app-rail-item.styles.js +65 -0
- package/dist/components/app-rail/app-rail.d.ts +21 -24
- package/dist/components/app-rail/app-rail.js +68 -132
- package/dist/components/app-rail/app-rail.styles.js +5 -2
- package/dist/components/attachment-chip/attachment-chip.d.ts +38 -11
- package/dist/components/attachment-chip/attachment-chip.js +73 -29
- package/dist/components/attachment-trigger/attachment-trigger.d.ts +13 -0
- package/dist/components/attachment-trigger/attachment-trigger.js +13 -1
- package/dist/components/attachment-trigger/attachment-trigger.styles.js +28 -6
- package/dist/components/chart/bar-chart.js +2 -18
- package/dist/components/chart/box-plot.d.ts +25 -1
- package/dist/components/chart/box-plot.js +136 -6
- package/dist/components/chart/box-plot.styles.js +13 -0
- package/dist/components/chart/bubble-chart.js +2 -18
- package/dist/components/chart/chart.d.ts +54 -10
- package/dist/components/chart/chart.js +182 -39
- package/dist/components/chart/doughnut-chart.js +2 -18
- package/dist/components/chart/histogram-bin.d.ts +5 -2
- package/dist/components/chart/histogram-bin.js +12 -4
- package/dist/components/chart/histogram.js +8 -16
- package/dist/components/chart/line-chart.js +2 -18
- package/dist/components/chart/lite-chart.d.ts +80 -3
- package/dist/components/chart/lite-chart.js +250 -53
- package/dist/components/chart/pie-chart.js +2 -18
- package/dist/components/chart/polar-area-chart.js +2 -18
- package/dist/components/chart/radar-chart.js +2 -18
- package/dist/components/chart/scatter-chart.js +2 -18
- package/dist/components/chat-composer/chat-composer.d.ts +42 -1
- package/dist/components/chat-composer/chat-composer.js +84 -3
- package/dist/components/chat-composer/chat-composer.styles.js +11 -1
- package/dist/components/chat-message/chat-message.d.ts +32 -4
- package/dist/components/chat-message/chat-message.js +57 -17
- package/dist/components/checkbox/checkbox.d.ts +66 -8
- package/dist/components/checkbox/checkbox.js +173 -50
- package/dist/components/checkbox/checkbox.styles.js +9 -2
- package/dist/components/chip/chip-group.js +8 -2
- package/dist/components/chip/chip.js +9 -2
- package/dist/components/citation-badge/citation-badge.js +21 -3
- package/dist/components/code-block/code-block.d.ts +38 -0
- package/dist/components/code-block/code-block.js +72 -7
- package/dist/components/code-block/code-loader.d.ts +44 -1
- package/dist/components/code-block/code-loader.js +63 -0
- package/dist/components/combobox/combobox.d.ts +46 -5
- package/dist/components/combobox/combobox.js +175 -35
- package/dist/components/combobox/combobox.styles.js +3 -3
- package/dist/components/context-meter/context-meter.js +17 -8
- package/dist/components/context-meter/context-meter.styles.js +0 -6
- package/dist/components/conversation-item/conversation-item.d.ts +13 -16
- package/dist/components/conversation-item/conversation-item.js +29 -20
- package/dist/components/date-picker/calendar-core.d.ts +24 -0
- package/dist/components/date-picker/calendar-core.js +51 -4
- package/dist/components/date-picker/date-input.d.ts +77 -10
- package/dist/components/date-picker/date-input.js +278 -73
- package/dist/components/date-picker/date-picker.d.ts +28 -4
- package/dist/components/date-picker/date-picker.js +95 -37
- package/dist/components/dialog/confirm.js +3 -6
- package/dist/components/dialog/dialog.d.ts +75 -31
- package/dist/components/dialog/dialog.js +147 -131
- package/dist/components/dialog/dialog.styles.js +46 -2
- package/dist/components/dock-panel/dock-panel.d.ts +8 -0
- package/dist/components/dock-panel/dock-panel.js +15 -1
- package/dist/components/dock-panel/dock-panel.styles.js +15 -1
- package/dist/components/document-preview/document-preview.d.ts +15 -7
- package/dist/components/document-preview/document-preview.js +29 -13
- package/dist/components/empty/empty.d.ts +1 -2
- package/dist/components/empty/empty.js +18 -12
- package/dist/components/empty/empty.styles.js +0 -3
- package/dist/components/export-button/export-button.d.ts +12 -0
- package/dist/components/export-button/export-button.js +33 -5
- package/dist/components/export-button/export-button.styles.js +5 -1
- package/dist/components/file-input/accept.js +2 -0
- package/dist/components/file-input/file-input.d.ts +10 -1
- package/dist/components/file-input/file-input.js +36 -5
- package/dist/components/flag/flag.d.ts +1 -1
- package/dist/components/flag/flag.js +15 -1
- package/dist/components/flag/flag.styles.js +1 -1
- package/dist/components/flag/language-map.d.ts +4 -1
- package/dist/components/flag/language-map.js +6 -3
- package/dist/components/gauge/gauge.d.ts +10 -1
- package/dist/components/gauge/gauge.js +28 -9
- package/dist/components/generation-status/generation-status.d.ts +13 -5
- package/dist/components/generation-status/generation-status.js +59 -5
- package/dist/components/graph/graph.d.ts +37 -3
- package/dist/components/graph/graph.js +132 -20
- package/dist/components/heatmap/calendar-grid.d.ts +15 -6
- package/dist/components/heatmap/calendar-grid.js +17 -6
- package/dist/components/heatmap/heatmap-scale.d.ts +5 -1
- package/dist/components/heatmap/heatmap-scale.js +8 -2
- package/dist/components/heatmap/heatmap.d.ts +166 -25
- package/dist/components/heatmap/heatmap.js +372 -89
- package/dist/components/json-viewer/json-viewer.d.ts +22 -5
- package/dist/components/json-viewer/json-viewer.js +115 -37
- package/dist/components/json-viewer/json-viewer.styles.js +2 -1
- package/dist/components/kbd/kbd.js +24 -7
- package/dist/components/live-region/live-region.d.ts +10 -1
- package/dist/components/live-region/live-region.js +42 -6
- package/dist/components/map/map.d.ts +24 -1
- package/dist/components/map/map.js +89 -24
- package/dist/components/markdown/markdown-loader.d.ts +24 -0
- package/dist/components/markdown/markdown-loader.js +35 -1
- package/dist/components/markdown/markdown.d.ts +46 -8
- package/dist/components/markdown/markdown.js +136 -31
- package/dist/components/markdown/markdown.styles.js +7 -1
- package/dist/components/media-card/media-card.d.ts +25 -17
- package/dist/components/media-card/media-card.js +43 -65
- package/dist/components/mention-popover/mention-popover.d.ts +4 -1
- package/dist/components/mention-popover/mention-popover.js +23 -5
- package/dist/components/menu/menu-item.d.ts +32 -3
- package/dist/components/menu/menu-item.js +94 -7
- package/dist/components/menu/menu-item.styles.js +8 -0
- package/dist/components/menu/menu.d.ts +25 -1
- package/dist/components/menu/menu.js +99 -3
- package/dist/components/menu/menu.styles.js +3 -2
- package/dist/components/model-select/model-select.d.ts +48 -3
- package/dist/components/model-select/model-select.js +120 -22
- package/dist/components/model-select/model-select.styles.js +17 -3
- package/dist/components/model-settings-panel/model-settings-panel.d.ts +25 -1
- package/dist/components/model-settings-panel/model-settings-panel.js +65 -1
- package/dist/components/playback/playback.d.ts +6 -2
- package/dist/components/playback/playback.js +72 -29
- package/dist/components/playback/playback.styles.js +6 -1
- package/dist/components/responsive-panel/responsive-panel.d.ts +29 -16
- package/dist/components/responsive-panel/responsive-panel.js +130 -132
- package/dist/components/responsive-panel/responsive-panel.styles.js +1 -1
- package/dist/components/result-card/result-card.d.ts +8 -2
- package/dist/components/result-card/result-card.js +9 -3
- package/dist/components/result-card/result-card.styles.js +0 -1
- package/dist/components/select/select.d.ts +59 -20
- package/dist/components/select/select.js +125 -43
- package/dist/components/skeleton/skeleton.d.ts +3 -0
- package/dist/components/skeleton/skeleton.js +7 -1
- package/dist/components/skeleton/skeleton.styles.js +5 -4
- package/dist/components/slider/slider.d.ts +57 -5
- package/dist/components/slider/slider.js +195 -80
- package/dist/components/source-card/source-card.d.ts +17 -5
- package/dist/components/source-card/source-card.js +55 -8
- package/dist/components/source-card/source-card.styles.js +1 -1
- package/dist/components/source-list/source-list.js +9 -1
- package/dist/components/sparkline/sparkline.js +34 -10
- package/dist/components/split/split.d.ts +141 -14
- package/dist/components/split/split.js +357 -52
- package/dist/components/split/split.styles.js +18 -1
- package/dist/components/stat/stat.d.ts +10 -4
- package/dist/components/stat/stat.js +46 -11
- package/dist/components/stream-status/stream-status.d.ts +27 -11
- package/dist/components/stream-status/stream-status.js +95 -13
- package/dist/components/streaming-text/streaming-text.d.ts +9 -3
- package/dist/components/streaming-text/streaming-text.js +25 -10
- package/dist/components/streaming-text/streaming-text.styles.js +3 -2
- package/dist/components/switch/switch.d.ts +52 -7
- package/dist/components/switch/switch.js +111 -40
- package/dist/components/switch/switch.styles.js +1 -1
- package/dist/components/table/table.d.ts +18 -3
- package/dist/components/table/table.js +88 -20
- package/dist/components/tabs/tabs.d.ts +23 -0
- package/dist/components/tabs/tabs.js +76 -12
- package/dist/components/tabs/tabs.styles.js +11 -0
- package/dist/components/thinking-panel/thinking-panel.d.ts +3 -1
- package/dist/components/thinking-panel/thinking-panel.js +34 -9
- package/dist/components/thinking-panel/thinking-panel.styles.js +6 -0
- package/dist/components/time-range/time-range.d.ts +59 -2
- package/dist/components/time-range/time-range.js +163 -67
- package/dist/components/toast/toast-item.d.ts +12 -3
- package/dist/components/toast/toast-item.js +90 -53
- package/dist/components/toast/toast-item.styles.js +59 -28
- package/dist/components/toast/toast.js +17 -5
- package/dist/components/toast/toaster.js +10 -1
- package/dist/components/tool-approval-dialog/tool-approval-dialog.d.ts +11 -10
- package/dist/components/tool-approval-dialog/tool-approval-dialog.js +50 -124
- package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.js +1 -1
- package/dist/components/tool-call-chip/tool-call-chip.d.ts +18 -2
- package/dist/components/tool-call-chip/tool-call-chip.js +86 -25
- package/dist/components/tool-param-form/tool-param-form.d.ts +89 -28
- package/dist/components/tool-param-form/tool-param-form.js +350 -106
- package/dist/components/tool-result-dialog/tool-result-dialog.d.ts +27 -7
- package/dist/components/tool-result-dialog/tool-result-dialog.js +80 -115
- package/dist/components/tool-result-dialog/tool-result-dialog.styles.js +1 -1
- package/dist/components/tool-result-view/registry.d.ts +0 -8
- package/dist/components/tool-result-view/registry.js +7 -2
- package/dist/components/tool-result-view/tool-result-view.d.ts +6 -3
- package/dist/components/tool-result-view/tool-result-view.js +18 -4
- package/dist/components/tool-select-dialog/tool-select-dialog.d.ts +11 -11
- package/dist/components/tool-select-dialog/tool-select-dialog.js +44 -133
- package/dist/components/tool-select-dialog/tool-select-dialog.styles.js +13 -4
- package/dist/components/tree/tree-node.d.ts +4 -1
- package/dist/components/tree/tree-node.js +4 -1
- package/dist/components/tree/tree.d.ts +17 -8
- package/dist/components/tree/tree.js +21 -20
- package/dist/components/typing-indicator/typing-indicator.d.ts +12 -2
- package/dist/components/typing-indicator/typing-indicator.js +16 -4
- package/dist/components/typing-indicator/typing-indicator.styles.js +2 -2
- package/dist/components/virtual-list/virtual-list.d.ts +56 -19
- package/dist/components/virtual-list/virtual-list.js +184 -38
- package/dist/components/virtual-list/virtual-list.styles.js +12 -0
- package/dist/components/widget/widget.d.ts +5 -4
- package/dist/components/widget/widget.js +54 -120
- package/dist/components/widget/widget.styles.js +8 -2
- package/dist/components/word-cloud/word-cloud-layout.d.ts +7 -0
- package/dist/components/word-cloud/word-cloud-layout.js +20 -6
- package/dist/components/word-cloud/word-cloud.d.ts +22 -2
- package/dist/components/word-cloud/word-cloud.js +45 -6
- package/dist/components/word-cloud/word-cloud.styles.js +13 -1
- package/dist/internal/anchored-validity.d.ts +1 -0
- package/dist/internal/anchored-validity.js +86 -0
- package/dist/internal/form-associated.d.ts +7 -0
- package/dist/internal/form-associated.js +43 -4
- package/dist/internal/numbers.d.ts +12 -0
- package/dist/internal/numbers.js +26 -0
- package/dist/internal/overlay-manager.d.ts +51 -0
- package/dist/internal/overlay-manager.js +523 -0
- package/dist/internal/positioner.js +27 -3
- package/dist/internal/safe-url.d.ts +12 -0
- package/dist/internal/safe-url.js +41 -0
- package/dist/internal/tokens.styles.js +17 -11
- package/dist/lyra.d.ts +5 -2
- package/dist/lyra.js +3 -1
- package/llms-full.txt +970 -426
- package/llms.txt +5 -4
- package/package.json +19 -2
|
@@ -60,7 +60,12 @@ function stopIcon() {
|
|
|
60
60
|
* border at runtime (`resizeTextarea()`) rather than assuming a fixed
|
|
61
61
|
* px-per-row constant, so it stays correct under a consumer's own font-size/
|
|
62
62
|
* line-height overrides. It grows between `min-rows` and `max-rows`, then
|
|
63
|
-
* switches to internal scrolling.
|
|
63
|
+
* switches to internal scrolling. A `ResizeObserver` on the textarea itself
|
|
64
|
+
* re-runs the same fit whenever its *width* changes (a responsive
|
|
65
|
+
* breakpoint, a sidebar toggling, a window resize, an orientation change)
|
|
66
|
+
* even though `value`/`min-rows`/`max-rows` never did -- a narrower box
|
|
67
|
+
* wraps the same text across more lines, so the previously-fitted height
|
|
68
|
+
* would otherwise go stale and clip content with no scrollbar to reveal it.
|
|
64
69
|
*
|
|
65
70
|
* Enter-to-send (only active while `submit-on-enter` is true, the default):
|
|
66
71
|
* plain Enter submits and is prevented from inserting a newline; Shift+Enter
|
|
@@ -97,8 +102,9 @@ function stopIcon() {
|
|
|
97
102
|
* @csspart action-button - The built-in send/stop button. Absent from the accessibility tree's meaningful content whenever `trailing` has assigned content. Style its busy treatment via `:host([status='sending'])`/`:host([status='streaming'])`.
|
|
98
103
|
*/
|
|
99
104
|
export class LyraChatComposer extends FormAssociated(LyraElement) {
|
|
105
|
+
static { this.styles = [LyraElement.styles, styles]; }
|
|
100
106
|
constructor() {
|
|
101
|
-
super(
|
|
107
|
+
super();
|
|
102
108
|
this.placeholder = '';
|
|
103
109
|
this.minRows = 1;
|
|
104
110
|
this.maxRows = 8;
|
|
@@ -107,6 +113,7 @@ export class LyraChatComposer extends FormAssociated(LyraElement) {
|
|
|
107
113
|
this.hasLeadingSlot = false;
|
|
108
114
|
this.hasChipsSlot = false;
|
|
109
115
|
this.hasTrailingSlot = false;
|
|
116
|
+
this.touched = false;
|
|
110
117
|
this.onTextareaInput = (e) => {
|
|
111
118
|
this.value = e.target.value;
|
|
112
119
|
this.emit('lyra-input', { value: this.value });
|
|
@@ -154,8 +161,13 @@ export class LyraChatComposer extends FormAssociated(LyraElement) {
|
|
|
154
161
|
this.onTrailingSlotChange = (e) => {
|
|
155
162
|
this.hasTrailingSlot = e.target.assignedElements({ flatten: true }).length > 0;
|
|
156
163
|
};
|
|
164
|
+
this.onTextareaBlur = () => {
|
|
165
|
+
this.touched = true;
|
|
166
|
+
};
|
|
167
|
+
this.addEventListener('invalid', () => {
|
|
168
|
+
this.touched = true;
|
|
169
|
+
});
|
|
157
170
|
}
|
|
158
|
-
static { this.styles = [LyraElement.styles, styles]; }
|
|
159
171
|
willUpdate() {
|
|
160
172
|
if (!this.hasUpdated) {
|
|
161
173
|
this.hasLeadingSlot = this.hasSlotted('leading');
|
|
@@ -166,6 +178,14 @@ export class LyraChatComposer extends FormAssociated(LyraElement) {
|
|
|
166
178
|
firstUpdated(changed) {
|
|
167
179
|
super.firstUpdated(changed);
|
|
168
180
|
this.resizeTextarea();
|
|
181
|
+
this.armTextareaResizeObserver();
|
|
182
|
+
}
|
|
183
|
+
disconnectedCallback() {
|
|
184
|
+
super.disconnectedCallback();
|
|
185
|
+
this.textareaResizeObserver?.disconnect();
|
|
186
|
+
if (this.textareaResizeRaf !== undefined)
|
|
187
|
+
cancelAnimationFrame(this.textareaResizeRaf);
|
|
188
|
+
this.textareaResizeRaf = undefined;
|
|
169
189
|
}
|
|
170
190
|
updated(changed) {
|
|
171
191
|
super.updated(changed);
|
|
@@ -173,6 +193,10 @@ export class LyraChatComposer extends FormAssociated(LyraElement) {
|
|
|
173
193
|
this.resizeTextarea();
|
|
174
194
|
}
|
|
175
195
|
}
|
|
196
|
+
formResetCallback() {
|
|
197
|
+
super.formResetCallback();
|
|
198
|
+
this.touched = false;
|
|
199
|
+
}
|
|
176
200
|
hasSlotted(name) {
|
|
177
201
|
return Array.from(this.children).some((el) => el.getAttribute('slot') === name);
|
|
178
202
|
}
|
|
@@ -209,6 +233,56 @@ export class LyraChatComposer extends FormAssociated(LyraElement) {
|
|
|
209
233
|
ta.style.height = `${next}px`;
|
|
210
234
|
ta.style.overflowY = contentHeight > maxHeight ? 'auto' : 'hidden';
|
|
211
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* Re-fits the textarea whenever its own box *width* changes, independent
|
|
238
|
+
* of any `value`/`min-rows`/`max-rows` update -- `updated()` above only
|
|
239
|
+
* reacts to those, so a pure layout change (a responsive breakpoint, a
|
|
240
|
+
* sidebar collapsing/expanding, a window resize, an orientation change)
|
|
241
|
+
* would otherwise leave the height pinned at whatever it last was, even
|
|
242
|
+
* though the same text now wraps across a different number of lines.
|
|
243
|
+
* Mirrors split.ts's `collapseResizeObserver`/virtual-list.ts's
|
|
244
|
+
* `containerResizeObserver`/lite-chart.ts's `resizeObserver`.
|
|
245
|
+
*
|
|
246
|
+
* Only reacts to an actual inline-size change rather than calling
|
|
247
|
+
* `resizeTextarea()` unconditionally on every callback: `resizeTextarea()`
|
|
248
|
+
* itself sets `ta.style.height`, a *block*-size change on the very element
|
|
249
|
+
* being observed, which would otherwise re-trigger this same observer
|
|
250
|
+
* every tick. Diffing against the last-seen width (same technique as
|
|
251
|
+
* split.ts keying its collapse state off `contentBoxSize[0].inlineSize`)
|
|
252
|
+
* keeps a same-width, height-only callback from doing anything.
|
|
253
|
+
*
|
|
254
|
+
* The actual recompute is deferred one animation frame rather than run
|
|
255
|
+
* synchronously inside the callback: `ResizeObserver`'s spec re-delivers,
|
|
256
|
+
* within the same notification pass, to any observed element resized by
|
|
257
|
+
* its own callback -- mutating `ta.style.height` synchronously here would
|
|
258
|
+
* do exactly that to the very box just observed, and the browser reports
|
|
259
|
+
* it as "ResizeObserver loop completed with undelivered notifications"
|
|
260
|
+
* (a real, user-visible console error, not just noise). Deferring the
|
|
261
|
+
* mutation to the next frame -- outside that notification pass -- avoids
|
|
262
|
+
* ever resizing the observed element from inside its own callback.
|
|
263
|
+
*/
|
|
264
|
+
armTextareaResizeObserver() {
|
|
265
|
+
const ta = this.textareaEl;
|
|
266
|
+
if (!ta || this.textareaResizeObserver)
|
|
267
|
+
return;
|
|
268
|
+
let lastWidth = ta.getBoundingClientRect().width;
|
|
269
|
+
this.textareaResizeObserver = new ResizeObserver((entries) => {
|
|
270
|
+
const box = entries[0]?.contentBoxSize?.[0];
|
|
271
|
+
const width = box ? box.inlineSize : (entries[0]?.contentRect.width ?? lastWidth);
|
|
272
|
+
// A sub-pixel-only difference (common with fractional layout/zoom)
|
|
273
|
+
// isn't worth a recompute.
|
|
274
|
+
if (Math.abs(width - lastWidth) < 0.5)
|
|
275
|
+
return;
|
|
276
|
+
lastWidth = width;
|
|
277
|
+
if (this.textareaResizeRaf !== undefined)
|
|
278
|
+
cancelAnimationFrame(this.textareaResizeRaf);
|
|
279
|
+
this.textareaResizeRaf = requestAnimationFrame(() => {
|
|
280
|
+
this.textareaResizeRaf = undefined;
|
|
281
|
+
this.resizeTextarea();
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
this.textareaResizeObserver.observe(ta);
|
|
285
|
+
}
|
|
212
286
|
submit() {
|
|
213
287
|
this.emit('lyra-submit', { value: this.value });
|
|
214
288
|
}
|
|
@@ -239,12 +313,16 @@ export class LyraChatComposer extends FormAssociated(LyraElement) {
|
|
|
239
313
|
<textarea
|
|
240
314
|
part="textarea"
|
|
241
315
|
aria-label=${this.placeholder || 'Message'}
|
|
316
|
+
aria-required=${this.required ? 'true' : 'false'}
|
|
317
|
+
aria-invalid=${this.touched && !this.internals.validity.valid ? 'true' : 'false'}
|
|
242
318
|
.value=${this.value}
|
|
243
319
|
placeholder=${this.placeholder}
|
|
244
320
|
rows=${Math.max(1, this.minRows || 1)}
|
|
321
|
+
?required=${this.required}
|
|
245
322
|
?disabled=${this.effectiveDisabled}
|
|
246
323
|
@input=${this.onTextareaInput}
|
|
247
324
|
@keydown=${this.onTextareaKeyDown}
|
|
325
|
+
@blur=${this.onTextareaBlur}
|
|
248
326
|
></textarea>
|
|
249
327
|
<span part="trailing">
|
|
250
328
|
<slot name="trailing" @slotchange=${this.onTrailingSlotChange}></slot>
|
|
@@ -279,6 +357,9 @@ __decorate([
|
|
|
279
357
|
__decorate([
|
|
280
358
|
state()
|
|
281
359
|
], LyraChatComposer.prototype, "hasTrailingSlot", void 0);
|
|
360
|
+
__decorate([
|
|
361
|
+
state()
|
|
362
|
+
], LyraChatComposer.prototype, "touched", void 0);
|
|
282
363
|
__decorate([
|
|
283
364
|
query('textarea')
|
|
284
365
|
], LyraChatComposer.prototype, "textareaEl", void 0);
|
|
@@ -17,7 +17,17 @@ export const styles = css `
|
|
|
17
17
|
[part='base']:focus-within {
|
|
18
18
|
border-color: var(--lyra-color-brand);
|
|
19
19
|
}
|
|
20
|
-
:host(
|
|
20
|
+
/* :host(:disabled), not :host([disabled]) -- this is a form-associated
|
|
21
|
+
custom element (FormAssociated mixin -> static formAssociated = true),
|
|
22
|
+
so the UA computes its disabled state (and therefore :disabled/:enabled
|
|
23
|
+
matching) the same way it does for a native form control: from its own
|
|
24
|
+
disabled content attribute *or* an ancestor <fieldset disabled>'s
|
|
25
|
+
cascade. Keying this off the attribute selector only ever matched the
|
|
26
|
+
first case -- a composer disabled purely via an ancestor fieldset had
|
|
27
|
+
effectiveDisabled correctly gating the textarea/button underneath, but
|
|
28
|
+
the card around them still rendered at full opacity with a normal
|
|
29
|
+
cursor. */
|
|
30
|
+
:host(:disabled) [part='base'] {
|
|
21
31
|
opacity: var(--lyra-opacity-disabled);
|
|
22
32
|
cursor: not-allowed;
|
|
23
33
|
}
|
|
@@ -49,7 +49,7 @@ export type ChatMessageStatus = 'sending' | 'sent' | 'failed' | 'streaming';
|
|
|
49
49
|
* @slot attachments - File/image attachment chips, rendered below the message body.
|
|
50
50
|
* @event lyra-retry - Fired by the built-in retry button, only rendered when `status="failed"`.
|
|
51
51
|
* @event lyra-collapse-toggle - `detail: boolean` (the new `collapsed` state) — fired when the user activates the built-in collapse button.
|
|
52
|
-
* @csspart bubble - The message bubble root.
|
|
52
|
+
* @csspart bubble - The message bubble root. Programmatically focusable (`tabindex="-1"`) so focus has a stable place to land when the built-in retry button is removed (e.g. a `lyra-retry` listener flipping `status` away from `"failed"`).
|
|
53
53
|
* @csspart header - The row above the message body — avatar, badges, and the collapse toggle. Hidden entirely when none of those have anything to show.
|
|
54
54
|
* @csspart avatar - The wrapper around the `avatar` slot.
|
|
55
55
|
* @csspart badges - The wrapper around the `badges` slot.
|
|
@@ -65,11 +65,14 @@ export type ChatMessageStatus = 'sending' | 'sent' | 'failed' | 'streaming';
|
|
|
65
65
|
*/
|
|
66
66
|
export declare class LyraChatMessage extends LyraElement {
|
|
67
67
|
static styles: import("lit").CSSResultGroup[];
|
|
68
|
+
static properties: {
|
|
69
|
+
status: {
|
|
70
|
+
reflect: boolean;
|
|
71
|
+
noAccessor: boolean;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
68
74
|
/** Who authored the message. Reflects to `data-role` — see the class doc. */
|
|
69
75
|
role: ChatMessageRole;
|
|
70
|
-
/** Delivery/generation state. Drives the footer's status dot/text and, for
|
|
71
|
-
* `"failed"`, the bubble's danger treatment and the built-in retry button. */
|
|
72
|
-
status: ChatMessageStatus;
|
|
73
76
|
/** When the message was sent/received. Accepts a `Date` or anything
|
|
74
77
|
* `new Date()` can parse (e.g. an ISO 8601 string); invalid input is
|
|
75
78
|
* treated the same as unset (no timestamp rendered). */
|
|
@@ -91,7 +94,32 @@ export declare class LyraChatMessage extends LyraElement {
|
|
|
91
94
|
private hasAttachmentsSlot;
|
|
92
95
|
private hasActionsSlot;
|
|
93
96
|
private liveRegion?;
|
|
97
|
+
private bubbleEl?;
|
|
94
98
|
private readonly bodyId;
|
|
99
|
+
private _status;
|
|
100
|
+
/** The value `status` held immediately before its current one, recorded
|
|
101
|
+
* at the point of assignment in the setter below -- *not* derived from
|
|
102
|
+
* Lit's `changed`/`changedProperties`, which only ever remembers the
|
|
103
|
+
* single oldest value seen since the last completed update. Without this,
|
|
104
|
+
* setting `status` to `"streaming"` and then immediately overwriting it
|
|
105
|
+
* (e.g. to `"sent"`) within the same task, with no render in between,
|
|
106
|
+
* would silently lose the `"streaming"` intermediate value before
|
|
107
|
+
* `announceStatusChange` ever gets to see it. */
|
|
108
|
+
private previousStatus;
|
|
109
|
+
/** True only until the component's first completed update -- gates the
|
|
110
|
+
* status-change announcement below so a message never announces
|
|
111
|
+
* whatever status it happens to mount with (mirrors the same "not on
|
|
112
|
+
* first paint" intent `willUpdate`'s `!this.hasUpdated` check has for the
|
|
113
|
+
* slot-presence flags, except `this.hasUpdated` itself is already `true`
|
|
114
|
+
* by the time `updated()` runs for the first time, so it can't be reused
|
|
115
|
+
* here). */
|
|
116
|
+
private isMounting;
|
|
117
|
+
/** Delivery/generation state. Drives the footer's status dot/text and,
|
|
118
|
+
* for `"failed"`, the bubble's danger treatment and the built-in retry
|
|
119
|
+
* button. Declared via `static properties` above with a hand-written
|
|
120
|
+
* accessor (see `previousStatus`). */
|
|
121
|
+
get status(): ChatMessageStatus;
|
|
122
|
+
set status(value: ChatMessageStatus);
|
|
95
123
|
protected willUpdate(): void;
|
|
96
124
|
protected updated(changed: PropertyValues): void;
|
|
97
125
|
private hasSlotted;
|
|
@@ -95,7 +95,7 @@ const STATUS_TEXT = {
|
|
|
95
95
|
* @slot attachments - File/image attachment chips, rendered below the message body.
|
|
96
96
|
* @event lyra-retry - Fired by the built-in retry button, only rendered when `status="failed"`.
|
|
97
97
|
* @event lyra-collapse-toggle - `detail: boolean` (the new `collapsed` state) — fired when the user activates the built-in collapse button.
|
|
98
|
-
* @csspart bubble - The message bubble root.
|
|
98
|
+
* @csspart bubble - The message bubble root. Programmatically focusable (`tabindex="-1"`) so focus has a stable place to land when the built-in retry button is removed (e.g. a `lyra-retry` listener flipping `status` away from `"failed"`).
|
|
99
99
|
* @csspart header - The row above the message body — avatar, badges, and the collapse toggle. Hidden entirely when none of those have anything to show.
|
|
100
100
|
* @csspart avatar - The wrapper around the `avatar` slot.
|
|
101
101
|
* @csspart badges - The wrapper around the `badges` slot.
|
|
@@ -114,9 +114,6 @@ export class LyraChatMessage extends LyraElement {
|
|
|
114
114
|
super(...arguments);
|
|
115
115
|
/** Who authored the message. Reflects to `data-role` — see the class doc. */
|
|
116
116
|
this.role = 'assistant';
|
|
117
|
-
/** Delivery/generation state. Drives the footer's status dot/text and, for
|
|
118
|
-
* `"failed"`, the bubble's danger treatment and the built-in retry button. */
|
|
119
|
-
this.status = 'sent';
|
|
120
117
|
/** Shows the built-in collapse/expand toggle in the header. */
|
|
121
118
|
this.collapsible = false;
|
|
122
119
|
/** Whether the message body is currently hidden. Effective whenever set,
|
|
@@ -129,6 +126,24 @@ export class LyraChatMessage extends LyraElement {
|
|
|
129
126
|
this.hasAttachmentsSlot = false;
|
|
130
127
|
this.hasActionsSlot = false;
|
|
131
128
|
this.bodyId = nextId('chat-message-body');
|
|
129
|
+
this._status = 'sent';
|
|
130
|
+
/** The value `status` held immediately before its current one, recorded
|
|
131
|
+
* at the point of assignment in the setter below -- *not* derived from
|
|
132
|
+
* Lit's `changed`/`changedProperties`, which only ever remembers the
|
|
133
|
+
* single oldest value seen since the last completed update. Without this,
|
|
134
|
+
* setting `status` to `"streaming"` and then immediately overwriting it
|
|
135
|
+
* (e.g. to `"sent"`) within the same task, with no render in between,
|
|
136
|
+
* would silently lose the `"streaming"` intermediate value before
|
|
137
|
+
* `announceStatusChange` ever gets to see it. */
|
|
138
|
+
this.previousStatus = 'sent';
|
|
139
|
+
/** True only until the component's first completed update -- gates the
|
|
140
|
+
* status-change announcement below so a message never announces
|
|
141
|
+
* whatever status it happens to mount with (mirrors the same "not on
|
|
142
|
+
* first paint" intent `willUpdate`'s `!this.hasUpdated` check has for the
|
|
143
|
+
* slot-presence flags, except `this.hasUpdated` itself is already `true`
|
|
144
|
+
* by the time `updated()` runs for the first time, so it can't be reused
|
|
145
|
+
* here). */
|
|
146
|
+
this.isMounting = true;
|
|
132
147
|
this.onAvatarSlotChange = (e) => {
|
|
133
148
|
this.hasAvatarSlot = e.target.assignedElements({ flatten: true }).length > 0;
|
|
134
149
|
};
|
|
@@ -146,10 +161,39 @@ export class LyraChatMessage extends LyraElement {
|
|
|
146
161
|
this.emit('lyra-collapse-toggle', this.collapsed);
|
|
147
162
|
};
|
|
148
163
|
this.onRetryClick = () => {
|
|
164
|
+
// A `lyra-retry` listener is documented to respond by flipping `status`
|
|
165
|
+
// away from `"failed"`, which removes this very button on the next
|
|
166
|
+
// render. Move focus to the always-rendered bubble first, synchronously,
|
|
167
|
+
// so it lands somewhere stable inside the message instead of silently
|
|
168
|
+
// reverting to `<body>` once the button it was on disappears.
|
|
169
|
+
this.bubbleEl?.focus();
|
|
149
170
|
this.emit('lyra-retry');
|
|
150
171
|
};
|
|
151
172
|
}
|
|
152
173
|
static { this.styles = [LyraElement.styles, styles]; }
|
|
174
|
+
// `status` needs a hand-written accessor (see `previousStatus` below) so
|
|
175
|
+
// it's declared via `static properties` + `noAccessor` rather than
|
|
176
|
+
// `@property()` directly -- the same pattern `lyra-playback`'s `playing`
|
|
177
|
+
// uses for the identical reason (a property whose setter must run real
|
|
178
|
+
// logic on every assignment, not just on the next completed render).
|
|
179
|
+
static { this.properties = {
|
|
180
|
+
status: { reflect: true, noAccessor: true },
|
|
181
|
+
}; }
|
|
182
|
+
/** Delivery/generation state. Drives the footer's status dot/text and,
|
|
183
|
+
* for `"failed"`, the bubble's danger treatment and the built-in retry
|
|
184
|
+
* button. Declared via `static properties` above with a hand-written
|
|
185
|
+
* accessor (see `previousStatus`). */
|
|
186
|
+
get status() {
|
|
187
|
+
return this._status;
|
|
188
|
+
}
|
|
189
|
+
set status(value) {
|
|
190
|
+
const old = this._status;
|
|
191
|
+
if (value === old)
|
|
192
|
+
return;
|
|
193
|
+
this.previousStatus = old;
|
|
194
|
+
this._status = value;
|
|
195
|
+
this.requestUpdate('status', old);
|
|
196
|
+
}
|
|
153
197
|
willUpdate() {
|
|
154
198
|
if (!this.hasUpdated) {
|
|
155
199
|
this.hasAvatarSlot = this.hasSlotted('avatar');
|
|
@@ -158,15 +202,11 @@ export class LyraChatMessage extends LyraElement {
|
|
|
158
202
|
this.hasActionsSlot = this.hasSlotted('actions');
|
|
159
203
|
}
|
|
160
204
|
}
|
|
161
|
-
// `changed.get('status')` is `undefined` on the very first update (Lit
|
|
162
|
-
// only records the *first* old value seen since the last completed
|
|
163
|
-
// update, and the constructor's own field-initializer assignment is that
|
|
164
|
-
// first change, from the truly-unset internal slot) -- so this naturally
|
|
165
|
-
// skips announcing whatever status a message happens to mount with, and
|
|
166
|
-
// only ever fires for a real, later transition.
|
|
167
205
|
updated(changed) {
|
|
168
|
-
|
|
169
|
-
|
|
206
|
+
const wasMounting = this.isMounting;
|
|
207
|
+
this.isMounting = false;
|
|
208
|
+
if (!wasMounting && changed.has('status')) {
|
|
209
|
+
this.announceStatusChange(this.previousStatus);
|
|
170
210
|
}
|
|
171
211
|
}
|
|
172
212
|
hasSlotted(name) {
|
|
@@ -182,7 +222,7 @@ export class LyraChatMessage extends LyraElement {
|
|
|
182
222
|
return this.status === 'sent' ? undefined : STATUS_TEXT[this.status];
|
|
183
223
|
}
|
|
184
224
|
announceStatusChange(previous) {
|
|
185
|
-
if (previous ===
|
|
225
|
+
if (previous === this.status)
|
|
186
226
|
return;
|
|
187
227
|
const region = this.liveRegion;
|
|
188
228
|
if (!region)
|
|
@@ -205,7 +245,7 @@ export class LyraChatMessage extends LyraElement {
|
|
|
205
245
|
// alone covers that case here too.
|
|
206
246
|
const showFooter = Boolean(statusText) || Boolean(ts) || this.hasActionsSlot;
|
|
207
247
|
return html `
|
|
208
|
-
<div part="bubble">
|
|
248
|
+
<div part="bubble" tabindex="-1">
|
|
209
249
|
<div part="header" ?hidden=${!showHeader}>
|
|
210
250
|
<span part="avatar" ?hidden=${!this.hasAvatarSlot}
|
|
211
251
|
><slot name="avatar" @slotchange=${this.onAvatarSlotChange}></slot
|
|
@@ -258,9 +298,6 @@ export class LyraChatMessage extends LyraElement {
|
|
|
258
298
|
__decorate([
|
|
259
299
|
property({ reflect: true, attribute: 'data-role' })
|
|
260
300
|
], LyraChatMessage.prototype, "role", void 0);
|
|
261
|
-
__decorate([
|
|
262
|
-
property({ reflect: true })
|
|
263
|
-
], LyraChatMessage.prototype, "status", void 0);
|
|
264
301
|
__decorate([
|
|
265
302
|
property({ attribute: false })
|
|
266
303
|
], LyraChatMessage.prototype, "timestamp", void 0);
|
|
@@ -288,4 +325,7 @@ __decorate([
|
|
|
288
325
|
__decorate([
|
|
289
326
|
query('lyra-live-region')
|
|
290
327
|
], LyraChatMessage.prototype, "liveRegion", void 0);
|
|
328
|
+
__decorate([
|
|
329
|
+
query('[part="bubble"]')
|
|
330
|
+
], LyraChatMessage.prototype, "bubbleEl", void 0);
|
|
291
331
|
defineElement('chat-message', LyraChatMessage);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type TemplateResult
|
|
1
|
+
import { type TemplateResult } from 'lit';
|
|
2
2
|
import { LyraElement } from '../../internal/lyra-element.js';
|
|
3
3
|
/**
|
|
4
4
|
* `<lyra-checkbox>` — a boolean form control. Structurally the same idea as
|
|
@@ -27,22 +27,78 @@ import { LyraElement } from '../../internal/lyra-element.js';
|
|
|
27
27
|
export declare class LyraCheckbox extends LyraElement {
|
|
28
28
|
static styles: import("lit").CSSResultGroup[];
|
|
29
29
|
static formAssociated: boolean;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
static properties: {
|
|
31
|
+
checked: {
|
|
32
|
+
type: BooleanConstructor;
|
|
33
|
+
reflect: boolean;
|
|
34
|
+
noAccessor: boolean;
|
|
35
|
+
};
|
|
36
|
+
indeterminate: {
|
|
37
|
+
type: BooleanConstructor;
|
|
38
|
+
reflect: boolean;
|
|
39
|
+
noAccessor: boolean;
|
|
40
|
+
};
|
|
41
|
+
disabled: {
|
|
42
|
+
type: BooleanConstructor;
|
|
43
|
+
reflect: boolean;
|
|
44
|
+
noAccessor: boolean;
|
|
45
|
+
};
|
|
46
|
+
name: {
|
|
47
|
+
reflect: boolean;
|
|
48
|
+
noAccessor: boolean;
|
|
49
|
+
};
|
|
50
|
+
required: {
|
|
51
|
+
type: BooleanConstructor;
|
|
52
|
+
reflect: boolean;
|
|
53
|
+
noAccessor: boolean;
|
|
54
|
+
};
|
|
55
|
+
value: {
|
|
56
|
+
noAccessor: boolean;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
36
59
|
private hasLabelSlot;
|
|
60
|
+
private touched;
|
|
37
61
|
private internals;
|
|
62
|
+
private validityController;
|
|
63
|
+
private labelObserver?;
|
|
38
64
|
private _defaultChecked;
|
|
39
65
|
private _defaultCaptured;
|
|
66
|
+
private _fieldsetDisabled;
|
|
67
|
+
private _name;
|
|
68
|
+
private _checked;
|
|
69
|
+
private _indeterminate;
|
|
70
|
+
private _disabled;
|
|
71
|
+
private _required;
|
|
72
|
+
private _value;
|
|
73
|
+
/** Whether the control is disabled explicitly or by an ancestor fieldset. */
|
|
74
|
+
get effectiveDisabled(): boolean;
|
|
75
|
+
get checked(): boolean;
|
|
76
|
+
set checked(next: boolean);
|
|
77
|
+
get indeterminate(): boolean;
|
|
78
|
+
set indeterminate(next: boolean);
|
|
79
|
+
get disabled(): boolean;
|
|
80
|
+
set disabled(next: boolean);
|
|
81
|
+
/** The form submission key, reflected synchronously for native form APIs. */
|
|
82
|
+
get name(): string;
|
|
83
|
+
set name(next: string);
|
|
84
|
+
get required(): boolean;
|
|
85
|
+
set required(next: boolean);
|
|
86
|
+
get value(): string;
|
|
87
|
+
set value(next: string);
|
|
40
88
|
constructor();
|
|
89
|
+
get form(): HTMLFormElement | null;
|
|
90
|
+
get labels(): NodeList;
|
|
91
|
+
get validity(): ValidityState;
|
|
92
|
+
get validationMessage(): string;
|
|
93
|
+
get willValidate(): boolean;
|
|
41
94
|
connectedCallback(): void;
|
|
95
|
+
disconnectedCallback(): void;
|
|
42
96
|
protected willUpdate(): void;
|
|
43
97
|
private updateValidity;
|
|
44
|
-
|
|
98
|
+
private reflectInvalid;
|
|
99
|
+
private syncFormState;
|
|
45
100
|
formResetCallback(): void;
|
|
101
|
+
formStateRestoreCallback(state: string | File | FormData | null, _mode?: 'restore' | 'autocomplete'): void;
|
|
46
102
|
formDisabledCallback(disabled: boolean): void;
|
|
47
103
|
checkValidity(): boolean;
|
|
48
104
|
reportValidity(): boolean;
|
|
@@ -50,6 +106,8 @@ export declare class LyraCheckbox extends LyraElement {
|
|
|
50
106
|
private onClick;
|
|
51
107
|
private onKeyDown;
|
|
52
108
|
private onSlotChange;
|
|
109
|
+
private recomputeHasLabelSlot;
|
|
110
|
+
private onBlur;
|
|
53
111
|
render(): TemplateResult;
|
|
54
112
|
}
|
|
55
113
|
declare global {
|