@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.
Files changed (224) hide show
  1. package/README.md +87 -14
  2. package/custom-elements.json +11555 -5539
  3. package/dist/components/app-rail/app-rail-item.d.ts +30 -0
  4. package/dist/components/app-rail/app-rail-item.js +68 -0
  5. package/dist/components/app-rail/app-rail-item.styles.d.ts +1 -0
  6. package/dist/components/app-rail/app-rail-item.styles.js +65 -0
  7. package/dist/components/app-rail/app-rail.d.ts +21 -24
  8. package/dist/components/app-rail/app-rail.js +68 -132
  9. package/dist/components/app-rail/app-rail.styles.js +5 -2
  10. package/dist/components/attachment-chip/attachment-chip.d.ts +38 -11
  11. package/dist/components/attachment-chip/attachment-chip.js +73 -29
  12. package/dist/components/attachment-trigger/attachment-trigger.d.ts +13 -0
  13. package/dist/components/attachment-trigger/attachment-trigger.js +13 -1
  14. package/dist/components/attachment-trigger/attachment-trigger.styles.js +28 -6
  15. package/dist/components/chart/bar-chart.js +2 -18
  16. package/dist/components/chart/box-plot.d.ts +25 -1
  17. package/dist/components/chart/box-plot.js +136 -6
  18. package/dist/components/chart/box-plot.styles.js +13 -0
  19. package/dist/components/chart/bubble-chart.js +2 -18
  20. package/dist/components/chart/chart.d.ts +54 -10
  21. package/dist/components/chart/chart.js +182 -39
  22. package/dist/components/chart/doughnut-chart.js +2 -18
  23. package/dist/components/chart/histogram-bin.d.ts +5 -2
  24. package/dist/components/chart/histogram-bin.js +12 -4
  25. package/dist/components/chart/histogram.js +8 -16
  26. package/dist/components/chart/line-chart.js +2 -18
  27. package/dist/components/chart/lite-chart.d.ts +80 -3
  28. package/dist/components/chart/lite-chart.js +250 -53
  29. package/dist/components/chart/pie-chart.js +2 -18
  30. package/dist/components/chart/polar-area-chart.js +2 -18
  31. package/dist/components/chart/radar-chart.js +2 -18
  32. package/dist/components/chart/scatter-chart.js +2 -18
  33. package/dist/components/chat-composer/chat-composer.d.ts +42 -1
  34. package/dist/components/chat-composer/chat-composer.js +84 -3
  35. package/dist/components/chat-composer/chat-composer.styles.js +11 -1
  36. package/dist/components/chat-message/chat-message.d.ts +32 -4
  37. package/dist/components/chat-message/chat-message.js +57 -17
  38. package/dist/components/checkbox/checkbox.d.ts +66 -8
  39. package/dist/components/checkbox/checkbox.js +173 -50
  40. package/dist/components/checkbox/checkbox.styles.js +9 -2
  41. package/dist/components/chip/chip-group.js +8 -2
  42. package/dist/components/chip/chip.js +9 -2
  43. package/dist/components/citation-badge/citation-badge.js +21 -3
  44. package/dist/components/code-block/code-block.d.ts +38 -0
  45. package/dist/components/code-block/code-block.js +72 -7
  46. package/dist/components/code-block/code-loader.d.ts +44 -1
  47. package/dist/components/code-block/code-loader.js +63 -0
  48. package/dist/components/combobox/combobox.d.ts +46 -5
  49. package/dist/components/combobox/combobox.js +175 -35
  50. package/dist/components/combobox/combobox.styles.js +3 -3
  51. package/dist/components/context-meter/context-meter.js +17 -8
  52. package/dist/components/context-meter/context-meter.styles.js +0 -6
  53. package/dist/components/conversation-item/conversation-item.d.ts +13 -16
  54. package/dist/components/conversation-item/conversation-item.js +29 -20
  55. package/dist/components/date-picker/calendar-core.d.ts +24 -0
  56. package/dist/components/date-picker/calendar-core.js +51 -4
  57. package/dist/components/date-picker/date-input.d.ts +77 -10
  58. package/dist/components/date-picker/date-input.js +278 -73
  59. package/dist/components/date-picker/date-picker.d.ts +28 -4
  60. package/dist/components/date-picker/date-picker.js +95 -37
  61. package/dist/components/dialog/confirm.js +3 -6
  62. package/dist/components/dialog/dialog.d.ts +75 -31
  63. package/dist/components/dialog/dialog.js +147 -131
  64. package/dist/components/dialog/dialog.styles.js +46 -2
  65. package/dist/components/dock-panel/dock-panel.d.ts +8 -0
  66. package/dist/components/dock-panel/dock-panel.js +15 -1
  67. package/dist/components/dock-panel/dock-panel.styles.js +15 -1
  68. package/dist/components/document-preview/document-preview.d.ts +15 -7
  69. package/dist/components/document-preview/document-preview.js +29 -13
  70. package/dist/components/empty/empty.d.ts +1 -2
  71. package/dist/components/empty/empty.js +18 -12
  72. package/dist/components/empty/empty.styles.js +0 -3
  73. package/dist/components/export-button/export-button.d.ts +12 -0
  74. package/dist/components/export-button/export-button.js +33 -5
  75. package/dist/components/export-button/export-button.styles.js +5 -1
  76. package/dist/components/file-input/accept.js +2 -0
  77. package/dist/components/file-input/file-input.d.ts +10 -1
  78. package/dist/components/file-input/file-input.js +36 -5
  79. package/dist/components/flag/flag.d.ts +1 -1
  80. package/dist/components/flag/flag.js +15 -1
  81. package/dist/components/flag/flag.styles.js +1 -1
  82. package/dist/components/flag/language-map.d.ts +4 -1
  83. package/dist/components/flag/language-map.js +6 -3
  84. package/dist/components/gauge/gauge.d.ts +10 -1
  85. package/dist/components/gauge/gauge.js +28 -9
  86. package/dist/components/generation-status/generation-status.d.ts +13 -5
  87. package/dist/components/generation-status/generation-status.js +59 -5
  88. package/dist/components/graph/graph.d.ts +37 -3
  89. package/dist/components/graph/graph.js +132 -20
  90. package/dist/components/heatmap/calendar-grid.d.ts +15 -6
  91. package/dist/components/heatmap/calendar-grid.js +17 -6
  92. package/dist/components/heatmap/heatmap-scale.d.ts +5 -1
  93. package/dist/components/heatmap/heatmap-scale.js +8 -2
  94. package/dist/components/heatmap/heatmap.d.ts +166 -25
  95. package/dist/components/heatmap/heatmap.js +372 -89
  96. package/dist/components/json-viewer/json-viewer.d.ts +22 -5
  97. package/dist/components/json-viewer/json-viewer.js +115 -37
  98. package/dist/components/json-viewer/json-viewer.styles.js +2 -1
  99. package/dist/components/kbd/kbd.js +24 -7
  100. package/dist/components/live-region/live-region.d.ts +10 -1
  101. package/dist/components/live-region/live-region.js +42 -6
  102. package/dist/components/map/map.d.ts +24 -1
  103. package/dist/components/map/map.js +89 -24
  104. package/dist/components/markdown/markdown-loader.d.ts +24 -0
  105. package/dist/components/markdown/markdown-loader.js +35 -1
  106. package/dist/components/markdown/markdown.d.ts +46 -8
  107. package/dist/components/markdown/markdown.js +136 -31
  108. package/dist/components/markdown/markdown.styles.js +7 -1
  109. package/dist/components/media-card/media-card.d.ts +25 -17
  110. package/dist/components/media-card/media-card.js +43 -65
  111. package/dist/components/mention-popover/mention-popover.d.ts +4 -1
  112. package/dist/components/mention-popover/mention-popover.js +23 -5
  113. package/dist/components/menu/menu-item.d.ts +32 -3
  114. package/dist/components/menu/menu-item.js +94 -7
  115. package/dist/components/menu/menu-item.styles.js +8 -0
  116. package/dist/components/menu/menu.d.ts +25 -1
  117. package/dist/components/menu/menu.js +99 -3
  118. package/dist/components/menu/menu.styles.js +3 -2
  119. package/dist/components/model-select/model-select.d.ts +48 -3
  120. package/dist/components/model-select/model-select.js +120 -22
  121. package/dist/components/model-select/model-select.styles.js +17 -3
  122. package/dist/components/model-settings-panel/model-settings-panel.d.ts +25 -1
  123. package/dist/components/model-settings-panel/model-settings-panel.js +65 -1
  124. package/dist/components/playback/playback.d.ts +6 -2
  125. package/dist/components/playback/playback.js +72 -29
  126. package/dist/components/playback/playback.styles.js +6 -1
  127. package/dist/components/responsive-panel/responsive-panel.d.ts +29 -16
  128. package/dist/components/responsive-panel/responsive-panel.js +130 -132
  129. package/dist/components/responsive-panel/responsive-panel.styles.js +1 -1
  130. package/dist/components/result-card/result-card.d.ts +8 -2
  131. package/dist/components/result-card/result-card.js +9 -3
  132. package/dist/components/result-card/result-card.styles.js +0 -1
  133. package/dist/components/select/select.d.ts +59 -20
  134. package/dist/components/select/select.js +125 -43
  135. package/dist/components/skeleton/skeleton.d.ts +3 -0
  136. package/dist/components/skeleton/skeleton.js +7 -1
  137. package/dist/components/skeleton/skeleton.styles.js +5 -4
  138. package/dist/components/slider/slider.d.ts +57 -5
  139. package/dist/components/slider/slider.js +195 -80
  140. package/dist/components/source-card/source-card.d.ts +17 -5
  141. package/dist/components/source-card/source-card.js +55 -8
  142. package/dist/components/source-card/source-card.styles.js +1 -1
  143. package/dist/components/source-list/source-list.js +9 -1
  144. package/dist/components/sparkline/sparkline.js +34 -10
  145. package/dist/components/split/split.d.ts +141 -14
  146. package/dist/components/split/split.js +357 -52
  147. package/dist/components/split/split.styles.js +18 -1
  148. package/dist/components/stat/stat.d.ts +10 -4
  149. package/dist/components/stat/stat.js +46 -11
  150. package/dist/components/stream-status/stream-status.d.ts +27 -11
  151. package/dist/components/stream-status/stream-status.js +95 -13
  152. package/dist/components/streaming-text/streaming-text.d.ts +9 -3
  153. package/dist/components/streaming-text/streaming-text.js +25 -10
  154. package/dist/components/streaming-text/streaming-text.styles.js +3 -2
  155. package/dist/components/switch/switch.d.ts +52 -7
  156. package/dist/components/switch/switch.js +111 -40
  157. package/dist/components/switch/switch.styles.js +1 -1
  158. package/dist/components/table/table.d.ts +18 -3
  159. package/dist/components/table/table.js +88 -20
  160. package/dist/components/tabs/tabs.d.ts +23 -0
  161. package/dist/components/tabs/tabs.js +76 -12
  162. package/dist/components/tabs/tabs.styles.js +11 -0
  163. package/dist/components/thinking-panel/thinking-panel.d.ts +3 -1
  164. package/dist/components/thinking-panel/thinking-panel.js +34 -9
  165. package/dist/components/thinking-panel/thinking-panel.styles.js +6 -0
  166. package/dist/components/time-range/time-range.d.ts +59 -2
  167. package/dist/components/time-range/time-range.js +163 -67
  168. package/dist/components/toast/toast-item.d.ts +12 -3
  169. package/dist/components/toast/toast-item.js +90 -53
  170. package/dist/components/toast/toast-item.styles.js +59 -28
  171. package/dist/components/toast/toast.js +17 -5
  172. package/dist/components/toast/toaster.js +10 -1
  173. package/dist/components/tool-approval-dialog/tool-approval-dialog.d.ts +11 -10
  174. package/dist/components/tool-approval-dialog/tool-approval-dialog.js +50 -124
  175. package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.js +1 -1
  176. package/dist/components/tool-call-chip/tool-call-chip.d.ts +18 -2
  177. package/dist/components/tool-call-chip/tool-call-chip.js +86 -25
  178. package/dist/components/tool-param-form/tool-param-form.d.ts +89 -28
  179. package/dist/components/tool-param-form/tool-param-form.js +350 -106
  180. package/dist/components/tool-result-dialog/tool-result-dialog.d.ts +27 -7
  181. package/dist/components/tool-result-dialog/tool-result-dialog.js +80 -115
  182. package/dist/components/tool-result-dialog/tool-result-dialog.styles.js +1 -1
  183. package/dist/components/tool-result-view/registry.d.ts +0 -8
  184. package/dist/components/tool-result-view/registry.js +7 -2
  185. package/dist/components/tool-result-view/tool-result-view.d.ts +6 -3
  186. package/dist/components/tool-result-view/tool-result-view.js +18 -4
  187. package/dist/components/tool-select-dialog/tool-select-dialog.d.ts +11 -11
  188. package/dist/components/tool-select-dialog/tool-select-dialog.js +44 -133
  189. package/dist/components/tool-select-dialog/tool-select-dialog.styles.js +13 -4
  190. package/dist/components/tree/tree-node.d.ts +4 -1
  191. package/dist/components/tree/tree-node.js +4 -1
  192. package/dist/components/tree/tree.d.ts +17 -8
  193. package/dist/components/tree/tree.js +21 -20
  194. package/dist/components/typing-indicator/typing-indicator.d.ts +12 -2
  195. package/dist/components/typing-indicator/typing-indicator.js +16 -4
  196. package/dist/components/typing-indicator/typing-indicator.styles.js +2 -2
  197. package/dist/components/virtual-list/virtual-list.d.ts +56 -19
  198. package/dist/components/virtual-list/virtual-list.js +184 -38
  199. package/dist/components/virtual-list/virtual-list.styles.js +12 -0
  200. package/dist/components/widget/widget.d.ts +5 -4
  201. package/dist/components/widget/widget.js +54 -120
  202. package/dist/components/widget/widget.styles.js +8 -2
  203. package/dist/components/word-cloud/word-cloud-layout.d.ts +7 -0
  204. package/dist/components/word-cloud/word-cloud-layout.js +20 -6
  205. package/dist/components/word-cloud/word-cloud.d.ts +22 -2
  206. package/dist/components/word-cloud/word-cloud.js +45 -6
  207. package/dist/components/word-cloud/word-cloud.styles.js +13 -1
  208. package/dist/internal/anchored-validity.d.ts +1 -0
  209. package/dist/internal/anchored-validity.js +86 -0
  210. package/dist/internal/form-associated.d.ts +7 -0
  211. package/dist/internal/form-associated.js +43 -4
  212. package/dist/internal/numbers.d.ts +12 -0
  213. package/dist/internal/numbers.js +26 -0
  214. package/dist/internal/overlay-manager.d.ts +51 -0
  215. package/dist/internal/overlay-manager.js +523 -0
  216. package/dist/internal/positioner.js +27 -3
  217. package/dist/internal/safe-url.d.ts +12 -0
  218. package/dist/internal/safe-url.js +41 -0
  219. package/dist/internal/tokens.styles.js +17 -11
  220. package/dist/lyra.d.ts +5 -2
  221. package/dist/lyra.js +3 -1
  222. package/llms-full.txt +970 -426
  223. package/llms.txt +5 -4
  224. 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(...arguments);
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([disabled]) [part='base'] {
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
- if (changed.has('status')) {
169
- this.announceStatusChange(changed.get('status'));
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 === undefined || previous === this.status)
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, type PropertyValues } from 'lit';
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
- checked: boolean;
31
- indeterminate: boolean;
32
- disabled: boolean;
33
- required: boolean;
34
- name: string;
35
- value: string;
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
- protected updated(changed: PropertyValues): void;
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 {