@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type TemplateResult } from 'lit';
|
|
1
|
+
import { type TemplateResult, type PropertyValues } from 'lit';
|
|
2
2
|
import { LyraElement } from '../../internal/lyra-element.js';
|
|
3
3
|
export type StatVariant = 'neutral' | 'success' | 'warning' | 'danger';
|
|
4
4
|
export type StatGoodDirection = 'up' | 'down';
|
|
@@ -24,7 +24,9 @@ export interface StatRow {
|
|
|
24
24
|
* @csspart icon - Container for the leading icon slot.
|
|
25
25
|
* @csspart label - The label text.
|
|
26
26
|
* @csspart value-row - Wrapper around the value and unit.
|
|
27
|
-
* @csspart value - The value text.
|
|
27
|
+
* @csspart value - The value text. Accessibly labelled by the `label` part (via
|
|
28
|
+
* `aria-labelledby`) whenever `label` is set, so tabbing directly to this
|
|
29
|
+
* (focusable when `exactValue` is set) control still announces which metric it is.
|
|
28
30
|
* @csspart unit - The unit text.
|
|
29
31
|
* @csspart trend - The trend pill.
|
|
30
32
|
* @csspart sub - Container for the `sub` attribute/slot.
|
|
@@ -34,7 +36,8 @@ export interface StatRow {
|
|
|
34
36
|
* @csspart row - A single breakdown row (one per `rows` entry).
|
|
35
37
|
* @csspart row-label - The label text of a breakdown row.
|
|
36
38
|
* @csspart row-value - The value text of a breakdown row. Shows the row's `exactValue` (if any) as
|
|
37
|
-
* a hover/focus tooltip, same as the headline `value
|
|
39
|
+
* a hover/focus tooltip, same as the headline `value`, and is accessibly labelled by its
|
|
40
|
+
* `row-label` (via `aria-labelledby`) the same way the headline `value` is.
|
|
38
41
|
*/
|
|
39
42
|
export declare class LyraStat extends LyraElement {
|
|
40
43
|
static styles: import("lit").CSSResultGroup[];
|
|
@@ -69,7 +72,10 @@ export declare class LyraStat extends LyraElement {
|
|
|
69
72
|
private hasCaptionSlot;
|
|
70
73
|
private hasSparkSlot;
|
|
71
74
|
private hasSubSlot;
|
|
72
|
-
|
|
75
|
+
private readonly labelId;
|
|
76
|
+
private readonly valueId;
|
|
77
|
+
private rowLabelIds;
|
|
78
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
73
79
|
private onIconSlotChange;
|
|
74
80
|
private onCaptionSlotChange;
|
|
75
81
|
private onSparkSlotChange;
|
|
@@ -9,7 +9,7 @@ import { property, state } from 'lit/decorators.js';
|
|
|
9
9
|
import { LyraElement } from '../../internal/lyra-element.js';
|
|
10
10
|
import { defineElement } from '../../internal/prefix.js';
|
|
11
11
|
import { chevronIcon } from '../../internal/icons.js';
|
|
12
|
-
import { srOnly } from '../../internal/a11y.js';
|
|
12
|
+
import { nextId, srOnly } from '../../internal/a11y.js';
|
|
13
13
|
import { styles } from './stat.styles.js';
|
|
14
14
|
/**
|
|
15
15
|
* `<lyra-stat>` — a KPI/stat card. First-party invention consolidating the
|
|
@@ -25,7 +25,9 @@ import { styles } from './stat.styles.js';
|
|
|
25
25
|
* @csspart icon - Container for the leading icon slot.
|
|
26
26
|
* @csspart label - The label text.
|
|
27
27
|
* @csspart value-row - Wrapper around the value and unit.
|
|
28
|
-
* @csspart value - The value text.
|
|
28
|
+
* @csspart value - The value text. Accessibly labelled by the `label` part (via
|
|
29
|
+
* `aria-labelledby`) whenever `label` is set, so tabbing directly to this
|
|
30
|
+
* (focusable when `exactValue` is set) control still announces which metric it is.
|
|
29
31
|
* @csspart unit - The unit text.
|
|
30
32
|
* @csspart trend - The trend pill.
|
|
31
33
|
* @csspart sub - Container for the `sub` attribute/slot.
|
|
@@ -35,7 +37,8 @@ import { styles } from './stat.styles.js';
|
|
|
35
37
|
* @csspart row - A single breakdown row (one per `rows` entry).
|
|
36
38
|
* @csspart row-label - The label text of a breakdown row.
|
|
37
39
|
* @csspart row-value - The value text of a breakdown row. Shows the row's `exactValue` (if any) as
|
|
38
|
-
* a hover/focus tooltip, same as the headline `value
|
|
40
|
+
* a hover/focus tooltip, same as the headline `value`, and is accessibly labelled by its
|
|
41
|
+
* `row-label` (via `aria-labelledby`) the same way the headline `value` is.
|
|
39
42
|
*/
|
|
40
43
|
export class LyraStat extends LyraElement {
|
|
41
44
|
constructor() {
|
|
@@ -74,6 +77,16 @@ export class LyraStat extends LyraElement {
|
|
|
74
77
|
this.hasCaptionSlot = false;
|
|
75
78
|
this.hasSparkSlot = false;
|
|
76
79
|
this.hasSubSlot = false;
|
|
80
|
+
// Stable id pairing `[part='label']` with `[part='value']` via
|
|
81
|
+
// aria-labelledby, so a keyboard user tabbing straight to the (focusable,
|
|
82
|
+
// tooltip-bearing) value still gets an accessible name like "Revenue
|
|
83
|
+
// $1.2K" instead of the bare value.
|
|
84
|
+
this.labelId = nextId('stat-label');
|
|
85
|
+
this.valueId = `${this.labelId}-value`;
|
|
86
|
+
// One id per `rows` entry, regenerated only when the `rows` array itself is
|
|
87
|
+
// reassigned (not on every render) so `aria-labelledby` references stay
|
|
88
|
+
// stable across unrelated re-renders.
|
|
89
|
+
this.rowLabelIds = [];
|
|
77
90
|
this.onIconSlotChange = (e) => {
|
|
78
91
|
this.hasIcon = e.target.assignedElements({ flatten: true }).length > 0;
|
|
79
92
|
};
|
|
@@ -88,16 +101,24 @@ export class LyraStat extends LyraElement {
|
|
|
88
101
|
};
|
|
89
102
|
}
|
|
90
103
|
static { this.styles = [LyraElement.styles, styles, srOnly]; }
|
|
91
|
-
willUpdate() {
|
|
104
|
+
willUpdate(changed) {
|
|
92
105
|
if (!this.hasUpdated) {
|
|
93
106
|
this.hasIcon = Array.from(this.children).some((el) => !el.hasAttribute('slot'));
|
|
94
107
|
this.hasCaptionSlot = Array.from(this.children).some((el) => el.getAttribute('slot') === 'caption');
|
|
95
108
|
this.hasSparkSlot = Array.from(this.children).some((el) => el.getAttribute('slot') === 'spark');
|
|
96
109
|
this.hasSubSlot = Array.from(this.children).some((el) => el.getAttribute('slot') === 'sub');
|
|
97
110
|
}
|
|
111
|
+
if (changed.has('rows')) {
|
|
112
|
+
this.rowLabelIds = this.rows.map(() => nextId('stat-row-label'));
|
|
113
|
+
}
|
|
98
114
|
}
|
|
99
115
|
render() {
|
|
100
|
-
|
|
116
|
+
// Lit's built-in Number converter maps a removed/absent attribute to
|
|
117
|
+
// `null`, not NaN, even though the property is typed `number` — so
|
|
118
|
+
// `isNaN(this.trend)` alone is false for a cleared attribute and the pill
|
|
119
|
+
// would reappear showing a fabricated "unchanged, 0%". Treat null/undefined
|
|
120
|
+
// the same as NaN here instead of trusting the static type.
|
|
121
|
+
const hasTrend = this.trend != null && !isNaN(this.trend);
|
|
101
122
|
const rawDirection = this.trend > 0 ? 'up' : this.trend < 0 ? 'down' : 'flat';
|
|
102
123
|
const isGood = rawDirection === 'flat' ? null : rawDirection === this.goodDirection;
|
|
103
124
|
// The trend pill previously rendered literal ▲/▼ glyphs — font-dependent
|
|
@@ -118,9 +139,14 @@ export class LyraStat extends LyraElement {
|
|
|
118
139
|
<span part="icon" ?hidden=${!this.hasIcon}
|
|
119
140
|
><slot @slotchange=${this.onIconSlotChange}></slot
|
|
120
141
|
></span>
|
|
121
|
-
<span part="label">${this.label}</span>
|
|
142
|
+
<span part="label" id=${this.labelId}>${this.label}</span>
|
|
122
143
|
<div part="value-row">
|
|
123
|
-
<span
|
|
144
|
+
<span
|
|
145
|
+
part="value"
|
|
146
|
+
id=${this.valueId}
|
|
147
|
+
title=${this.exactValue || nothing}
|
|
148
|
+
tabindex=${this.exactValue ? '0' : nothing}
|
|
149
|
+
aria-labelledby=${this.label ? `${this.labelId} ${this.valueId}` : nothing}
|
|
124
150
|
>${this.value}</span
|
|
125
151
|
>
|
|
126
152
|
<span part="unit">${this.unit}</span>
|
|
@@ -136,7 +162,7 @@ export class LyraStat extends LyraElement {
|
|
|
136
162
|
</span>`
|
|
137
163
|
: nothing}
|
|
138
164
|
<div part="sub" ?hidden=${!hasSub}>
|
|
139
|
-
|
|
165
|
+
<slot name="sub" @slotchange=${this.onSubSlotChange}>${this.sub}</slot>
|
|
140
166
|
</div>
|
|
141
167
|
<div part="spark" ?hidden=${!this.hasSparkSlot}>
|
|
142
168
|
<slot name="spark" @slotchange=${this.onSparkSlotChange}></slot>
|
|
@@ -145,17 +171,23 @@ export class LyraStat extends LyraElement {
|
|
|
145
171
|
<slot name="caption" @slotchange=${this.onCaptionSlotChange}>${this.caption}</slot>
|
|
146
172
|
</div>
|
|
147
173
|
<div part="rows" ?hidden=${this.rows.length === 0}>
|
|
148
|
-
${this.rows.map((row) =>
|
|
174
|
+
${this.rows.map((row, i) => {
|
|
175
|
+
const rowLabelId = this.rowLabelIds[i];
|
|
176
|
+
const rowValueId = `${rowLabelId}-value`;
|
|
177
|
+
return html `
|
|
149
178
|
<div part="row">
|
|
150
|
-
<span part="row-label">${row.label}</span>
|
|
179
|
+
<span part="row-label" id=${rowLabelId}>${row.label}</span>
|
|
151
180
|
<span
|
|
152
181
|
part="row-value"
|
|
182
|
+
id=${rowValueId}
|
|
153
183
|
title=${row.exactValue || nothing}
|
|
154
184
|
tabindex=${row.exactValue ? '0' : nothing}
|
|
185
|
+
aria-labelledby=${row.label ? `${rowLabelId} ${rowValueId}` : nothing}
|
|
155
186
|
>${row.value}</span
|
|
156
187
|
>
|
|
157
188
|
</div>
|
|
158
|
-
|
|
189
|
+
`;
|
|
190
|
+
})}
|
|
159
191
|
</div>
|
|
160
192
|
</div>
|
|
161
193
|
`;
|
|
@@ -212,4 +244,7 @@ __decorate([
|
|
|
212
244
|
__decorate([
|
|
213
245
|
state()
|
|
214
246
|
], LyraStat.prototype, "hasSubSlot", void 0);
|
|
247
|
+
__decorate([
|
|
248
|
+
state()
|
|
249
|
+
], LyraStat.prototype, "rowLabelIds", void 0);
|
|
215
250
|
defineElement('stat', LyraStat);
|
|
@@ -18,12 +18,20 @@ export type StreamStatusPhase = 'idle' | 'connecting' | 'streaming' | 'stalled';
|
|
|
18
18
|
*
|
|
19
19
|
* Internally, an inactivity timer runs only while `phase === 'streaming'`.
|
|
20
20
|
* It's (re)armed whenever the phase transitions to `'streaming'` (directly,
|
|
21
|
-
* or via `recordActivity()` recovering from `'stalled'`)
|
|
22
|
-
* subsequent `recordActivity()` call while already streaming
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* `phase
|
|
21
|
+
* or via `recordActivity()` recovering from `'stalled'`), on every
|
|
22
|
+
* subsequent `recordActivity()` call while already streaming, whenever
|
|
23
|
+
* `stall-threshold-ms` itself changes while already streaming (the new
|
|
24
|
+
* value takes effect immediately, the same way `<lyra-toast-item>`'s
|
|
25
|
+
* `duration` re-applies mid-flight, rather than waiting for the next
|
|
26
|
+
* `recordActivity()`/phase change), and whenever this element (re)connects
|
|
27
|
+
* to the DOM while `phase` is still `'streaming'` (a disconnect always
|
|
28
|
+
* disarms it, so moving the element elsewhere in the page — disconnect then
|
|
29
|
+
* reconnect with `phase` unchanged — must resume detection rather than
|
|
30
|
+
* silently disabling it for the rest of the streaming session). It's
|
|
31
|
+
* disarmed the instant `phase` becomes anything else, including a
|
|
32
|
+
* host-driven reassignment away from `'streaming'` — so a stale timer can
|
|
33
|
+
* never fire a stall transition after the host has already moved on. If it
|
|
34
|
+
* ever fires, `phase` becomes `'stalled'` and `lyra-stall` is dispatched.
|
|
27
35
|
*
|
|
28
36
|
* `phase` remains a fully public, directly settable property at all times —
|
|
29
37
|
* a host can assign `'stalled'` (or any other phase) itself as a manual
|
|
@@ -45,10 +53,15 @@ export type StreamStatusPhase = 'idle' | 'connecting' | 'streaming' | 'stalled';
|
|
|
45
53
|
* routing through the throttled announcer instead of writing to a live
|
|
46
54
|
* region on every call. Entering `'stalled'` announces with `mode="assertive"`
|
|
47
55
|
* (a stall can need the user's attention, e.g. before they give up and
|
|
48
|
-
* navigate away);
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
56
|
+
* navigate away); leaving `'stalled'` always announces with `mode="polite"`
|
|
57
|
+
* (good news doesn't need to interrupt), but the *wording* depends on where
|
|
58
|
+
* it lands: `"Connection restored."` only when the destination is
|
|
59
|
+
* `'streaming'` (a genuine recovery), or a neutral `"No longer stalled."`
|
|
60
|
+
* when the destination is `'idle'`/`'connecting'` instead — that's the host
|
|
61
|
+
* giving up on the stream, not the stream recovering, and a screen-reader
|
|
62
|
+
* user must never be told the opposite of what a sighted user sees on
|
|
63
|
+
* screen. The decorative indicator dot is `aria-hidden` — it's a
|
|
64
|
+
* color/motion cue only, never the sole carrier of state.
|
|
52
65
|
*
|
|
53
66
|
* Visual: `'stalled'` is styled as a warning, not a danger — a stall is
|
|
54
67
|
* usually recoverable (the stream may resume on its own, or the host's own
|
|
@@ -62,7 +75,7 @@ export type StreamStatusPhase = 'idle' | 'connecting' | 'streaming' | 'stalled';
|
|
|
62
75
|
* @slot - Custom copy shown only while `phase="stalled"` (e.g. "Taking longer than usual…"). A sensible built-in default is used when nothing is slotted.
|
|
63
76
|
* @slot actions - A stop/retry button row. Always present in the template regardless of `phase` — visibility is driven purely by whether anything is slotted, not by `phase`; what to put here, and when, is entirely the host's call.
|
|
64
77
|
* @event lyra-stall - Fired whenever `phase` transitions into `'stalled'` from anything else (timer-driven, or a direct host assignment).
|
|
65
|
-
* @event lyra-recover - Fired whenever `phase` transitions out of `'stalled'` to anything else (via `recordActivity()`, or a direct host assignment).
|
|
78
|
+
* @event lyra-recover - Fired whenever `phase` transitions out of `'stalled'` to anything else (via `recordActivity()`, or a direct host assignment) — fired unconditionally regardless of destination phase, even though the accompanying announcement's wording varies (see the class doc's "Accessibility" section).
|
|
66
79
|
* @csspart base - The root layout container.
|
|
67
80
|
* @csspart indicator - The decorative (`aria-hidden`) status dot.
|
|
68
81
|
* @csspart message - Wrapper around the default slot; only rendered while `phase="stalled"`.
|
|
@@ -78,9 +91,11 @@ export declare class LyraStreamStatus extends LyraElement {
|
|
|
78
91
|
stallThresholdMs: number;
|
|
79
92
|
private stallTimer?;
|
|
80
93
|
private hasActionsSlot;
|
|
94
|
+
private hasMessageContent;
|
|
81
95
|
private liveRegion?;
|
|
82
96
|
protected willUpdate(): void;
|
|
83
97
|
protected updated(changed: PropertyValues): void;
|
|
98
|
+
connectedCallback(): void;
|
|
84
99
|
disconnectedCallback(): void;
|
|
85
100
|
/**
|
|
86
101
|
* Call on every semantic (non-heartbeat) frame received while streaming.
|
|
@@ -101,6 +116,7 @@ export declare class LyraStreamStatus extends LyraElement {
|
|
|
101
116
|
private announceTransition;
|
|
102
117
|
private hasSlotted;
|
|
103
118
|
private onActionsSlotChange;
|
|
119
|
+
private onMessageSlotChange;
|
|
104
120
|
render(): TemplateResult;
|
|
105
121
|
}
|
|
106
122
|
declare global {
|
|
@@ -13,6 +13,26 @@ import { styles } from './stream-status.styles.js';
|
|
|
13
13
|
const DEFAULT_STALL_MESSAGE = 'Taking longer than usual…';
|
|
14
14
|
const STALL_ANNOUNCEMENT = 'Connection stalled.';
|
|
15
15
|
const RECOVER_ANNOUNCEMENT = 'Connection restored.';
|
|
16
|
+
// Used instead of RECOVER_ANNOUNCEMENT when a stall is left behind by moving
|
|
17
|
+
// to 'idle'/'connecting' rather than back to 'streaming' -- see
|
|
18
|
+
// announceTransition()'s caller in onPhaseChanged() for why "restored" would
|
|
19
|
+
// be actively misleading in that case.
|
|
20
|
+
const STALL_CLEARED_ANNOUNCEMENT = 'No longer stalled.';
|
|
21
|
+
// The default slot's stalled-message content is often plain text with no
|
|
22
|
+
// wrapping element at all (see the CustomStalledMessage story), so an
|
|
23
|
+
// Element-only check never counts it, and ordinary indented-markup
|
|
24
|
+
// whitespace (a newline + indentation before a slotted `actions` button, as
|
|
25
|
+
// in the DefaultStalledMessage story) must not count either -- native <slot>
|
|
26
|
+
// fallback content is suppressed by *any* assigned node, whitespace or not,
|
|
27
|
+
// which previously left the message area blank in exactly that common case.
|
|
28
|
+
// Mirrors lyra-citation-badge's identical isRealPreviewNode: a node counts as
|
|
29
|
+
// real message content if it's an element not assigned to some other named
|
|
30
|
+
// slot (e.g. `actions`), or non-whitespace text.
|
|
31
|
+
function isRealMessageNode(n) {
|
|
32
|
+
return n.nodeType === Node.ELEMENT_NODE
|
|
33
|
+
? !n.hasAttribute('slot')
|
|
34
|
+
: (n.textContent ?? '').trim().length > 0;
|
|
35
|
+
}
|
|
16
36
|
/**
|
|
17
37
|
* `<lyra-stream-status>` — a compact status indicator for a single streaming
|
|
18
38
|
* connection (SSE, WebSocket, long-poll, …), with built-in heartbeat-aware
|
|
@@ -29,12 +49,20 @@ const RECOVER_ANNOUNCEMENT = 'Connection restored.';
|
|
|
29
49
|
*
|
|
30
50
|
* Internally, an inactivity timer runs only while `phase === 'streaming'`.
|
|
31
51
|
* It's (re)armed whenever the phase transitions to `'streaming'` (directly,
|
|
32
|
-
* or via `recordActivity()` recovering from `'stalled'`)
|
|
33
|
-
* subsequent `recordActivity()` call while already streaming
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* `phase
|
|
52
|
+
* or via `recordActivity()` recovering from `'stalled'`), on every
|
|
53
|
+
* subsequent `recordActivity()` call while already streaming, whenever
|
|
54
|
+
* `stall-threshold-ms` itself changes while already streaming (the new
|
|
55
|
+
* value takes effect immediately, the same way `<lyra-toast-item>`'s
|
|
56
|
+
* `duration` re-applies mid-flight, rather than waiting for the next
|
|
57
|
+
* `recordActivity()`/phase change), and whenever this element (re)connects
|
|
58
|
+
* to the DOM while `phase` is still `'streaming'` (a disconnect always
|
|
59
|
+
* disarms it, so moving the element elsewhere in the page — disconnect then
|
|
60
|
+
* reconnect with `phase` unchanged — must resume detection rather than
|
|
61
|
+
* silently disabling it for the rest of the streaming session). It's
|
|
62
|
+
* disarmed the instant `phase` becomes anything else, including a
|
|
63
|
+
* host-driven reassignment away from `'streaming'` — so a stale timer can
|
|
64
|
+
* never fire a stall transition after the host has already moved on. If it
|
|
65
|
+
* ever fires, `phase` becomes `'stalled'` and `lyra-stall` is dispatched.
|
|
38
66
|
*
|
|
39
67
|
* `phase` remains a fully public, directly settable property at all times —
|
|
40
68
|
* a host can assign `'stalled'` (or any other phase) itself as a manual
|
|
@@ -56,10 +84,15 @@ const RECOVER_ANNOUNCEMENT = 'Connection restored.';
|
|
|
56
84
|
* routing through the throttled announcer instead of writing to a live
|
|
57
85
|
* region on every call. Entering `'stalled'` announces with `mode="assertive"`
|
|
58
86
|
* (a stall can need the user's attention, e.g. before they give up and
|
|
59
|
-
* navigate away);
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
87
|
+
* navigate away); leaving `'stalled'` always announces with `mode="polite"`
|
|
88
|
+
* (good news doesn't need to interrupt), but the *wording* depends on where
|
|
89
|
+
* it lands: `"Connection restored."` only when the destination is
|
|
90
|
+
* `'streaming'` (a genuine recovery), or a neutral `"No longer stalled."`
|
|
91
|
+
* when the destination is `'idle'`/`'connecting'` instead — that's the host
|
|
92
|
+
* giving up on the stream, not the stream recovering, and a screen-reader
|
|
93
|
+
* user must never be told the opposite of what a sighted user sees on
|
|
94
|
+
* screen. The decorative indicator dot is `aria-hidden` — it's a
|
|
95
|
+
* color/motion cue only, never the sole carrier of state.
|
|
63
96
|
*
|
|
64
97
|
* Visual: `'stalled'` is styled as a warning, not a danger — a stall is
|
|
65
98
|
* usually recoverable (the stream may resume on its own, or the host's own
|
|
@@ -73,7 +106,7 @@ const RECOVER_ANNOUNCEMENT = 'Connection restored.';
|
|
|
73
106
|
* @slot - Custom copy shown only while `phase="stalled"` (e.g. "Taking longer than usual…"). A sensible built-in default is used when nothing is slotted.
|
|
74
107
|
* @slot actions - A stop/retry button row. Always present in the template regardless of `phase` — visibility is driven purely by whether anything is slotted, not by `phase`; what to put here, and when, is entirely the host's call.
|
|
75
108
|
* @event lyra-stall - Fired whenever `phase` transitions into `'stalled'` from anything else (timer-driven, or a direct host assignment).
|
|
76
|
-
* @event lyra-recover - Fired whenever `phase` transitions out of `'stalled'` to anything else (via `recordActivity()`, or a direct host assignment).
|
|
109
|
+
* @event lyra-recover - Fired whenever `phase` transitions out of `'stalled'` to anything else (via `recordActivity()`, or a direct host assignment) — fired unconditionally regardless of destination phase, even though the accompanying announcement's wording varies (see the class doc's "Accessibility" section).
|
|
77
110
|
* @csspart base - The root layout container.
|
|
78
111
|
* @csspart indicator - The decorative (`aria-hidden`) status dot.
|
|
79
112
|
* @csspart message - Wrapper around the default slot; only rendered while `phase="stalled"`.
|
|
@@ -89,14 +122,23 @@ export class LyraStreamStatus extends LyraElement {
|
|
|
89
122
|
* before this component declares it stalled. */
|
|
90
123
|
this.stallThresholdMs = 10000;
|
|
91
124
|
this.hasActionsSlot = false;
|
|
125
|
+
// Seeded from light-DOM childNodes in willUpdate() (mirrors hasActionsSlot
|
|
126
|
+
// above), then kept current via onMessageSlotChange() -- see
|
|
127
|
+
// isRealMessageNode()'s doc comment for why native <slot> fallback content
|
|
128
|
+
// can't be relied on for the default stalled-message text.
|
|
129
|
+
this.hasMessageContent = false;
|
|
92
130
|
this.onActionsSlotChange = (e) => {
|
|
93
131
|
this.hasActionsSlot = e.target.assignedElements({ flatten: true }).length > 0;
|
|
94
132
|
};
|
|
133
|
+
this.onMessageSlotChange = (e) => {
|
|
134
|
+
this.hasMessageContent = e.target.assignedNodes({ flatten: true }).some(isRealMessageNode);
|
|
135
|
+
};
|
|
95
136
|
}
|
|
96
137
|
static { this.styles = [LyraElement.styles, styles]; }
|
|
97
138
|
willUpdate() {
|
|
98
139
|
if (!this.hasUpdated) {
|
|
99
140
|
this.hasActionsSlot = this.hasSlotted('actions');
|
|
141
|
+
this.hasMessageContent = Array.from(this.childNodes).some(isRealMessageNode);
|
|
100
142
|
}
|
|
101
143
|
}
|
|
102
144
|
// `changed.get('phase')` is `undefined` on the very first update, for the
|
|
@@ -107,10 +149,36 @@ export class LyraStreamStatus extends LyraElement {
|
|
|
107
149
|
// skips firing an event/announcement for whatever phase this element
|
|
108
150
|
// happens to mount with, while still arming the stall timer below if it
|
|
109
151
|
// mounts already `'streaming'`.
|
|
152
|
+
//
|
|
153
|
+
// The `else if` below only matters while `phase` itself didn't also change
|
|
154
|
+
// in this same update -- if it did, onPhaseChanged() above already
|
|
155
|
+
// (re)armed the timer with the current `stallThresholdMs`, so re-arming it
|
|
156
|
+
// again here would just be redundant, not wrong, but the `else` skips that
|
|
157
|
+
// double work.
|
|
110
158
|
updated(changed) {
|
|
111
159
|
if (changed.has('phase')) {
|
|
112
160
|
this.onPhaseChanged(changed.get('phase'));
|
|
113
161
|
}
|
|
162
|
+
else if (changed.has('stallThresholdMs') && this.phase === 'streaming') {
|
|
163
|
+
// Unlike `phase` itself, `stallThresholdMs` has no dedicated handler --
|
|
164
|
+
// the already-armed timer was scheduled against the *old* value and
|
|
165
|
+
// keeps counting down against it otherwise, so a shortened (or
|
|
166
|
+
// lengthened) threshold would silently have no effect until the next
|
|
167
|
+
// recordActivity() call or phase transition happened to re-arm it.
|
|
168
|
+
this.armStallTimer();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
connectedCallback() {
|
|
172
|
+
super.connectedCallback();
|
|
173
|
+
// A disconnect always disarms the timer (see disconnectedCallback()
|
|
174
|
+
// below), but reparenting this element elsewhere in the page while still
|
|
175
|
+
// `'streaming'` fires disconnectedCallback then connectedCallback with
|
|
176
|
+
// `phase` unchanged -- no `updated()` cycle runs in between, so nothing
|
|
177
|
+
// else would ever re-arm it. Without this, a reparent mid-stream would
|
|
178
|
+
// permanently disable stall detection for the rest of that streaming
|
|
179
|
+
// session.
|
|
180
|
+
if (this.phase === 'streaming')
|
|
181
|
+
this.armStallTimer();
|
|
114
182
|
}
|
|
115
183
|
disconnectedCallback() {
|
|
116
184
|
super.disconnectedCallback();
|
|
@@ -150,8 +218,15 @@ export class LyraStreamStatus extends LyraElement {
|
|
|
150
218
|
this.announceTransition('assertive', STALL_ANNOUNCEMENT);
|
|
151
219
|
}
|
|
152
220
|
else if (previous === 'stalled' && this.phase !== 'stalled') {
|
|
221
|
+
// `lyra-recover` fires unconditionally -- a host may still want the
|
|
222
|
+
// event for any exit from 'stalled' -- but the *announced text* must
|
|
223
|
+
// not claim the connection was "restored" when the destination is
|
|
224
|
+
// 'idle'/'connecting': that's the host abandoning the stream, not it
|
|
225
|
+
// recovering, and telling a screen-reader user otherwise would be the
|
|
226
|
+
// opposite of what a sighted user sees on screen.
|
|
153
227
|
this.emit('lyra-recover');
|
|
154
|
-
this.
|
|
228
|
+
const text = this.phase === 'streaming' ? RECOVER_ANNOUNCEMENT : STALL_CLEARED_ANNOUNCEMENT;
|
|
229
|
+
this.announceTransition('polite', text);
|
|
155
230
|
}
|
|
156
231
|
}
|
|
157
232
|
armStallTimer() {
|
|
@@ -185,7 +260,11 @@ export class LyraStreamStatus extends LyraElement {
|
|
|
185
260
|
<div part="base">
|
|
186
261
|
<span part="indicator" aria-hidden="true"></span>
|
|
187
262
|
${this.phase === 'stalled'
|
|
188
|
-
? html `<div part="message"
|
|
263
|
+
? html `<div part="message">
|
|
264
|
+
<slot @slotchange=${this.onMessageSlotChange}></slot>${this.hasMessageContent
|
|
265
|
+
? nothing
|
|
266
|
+
: DEFAULT_STALL_MESSAGE}
|
|
267
|
+
</div>`
|
|
189
268
|
: nothing}
|
|
190
269
|
<div part="actions" ?hidden=${!this.hasActionsSlot}>
|
|
191
270
|
<slot name="actions" @slotchange=${this.onActionsSlotChange}></slot>
|
|
@@ -204,6 +283,9 @@ __decorate([
|
|
|
204
283
|
__decorate([
|
|
205
284
|
state()
|
|
206
285
|
], LyraStreamStatus.prototype, "hasActionsSlot", void 0);
|
|
286
|
+
__decorate([
|
|
287
|
+
state()
|
|
288
|
+
], LyraStreamStatus.prototype, "hasMessageContent", void 0);
|
|
207
289
|
__decorate([
|
|
208
290
|
query('lyra-live-region')
|
|
209
291
|
], LyraStreamStatus.prototype, "liveRegion", void 0);
|
|
@@ -29,8 +29,10 @@ export declare function looksLikeMarkdown(text: string): boolean;
|
|
|
29
29
|
* the throttle and flush immediately instead of waiting out the window: the
|
|
30
30
|
* very first `content` assignment after mount (so an already-complete
|
|
31
31
|
* message never shows an artificial startup delay), and any transition of
|
|
32
|
-
* `streaming`
|
|
33
|
-
* stream can never be left stranded mid-window
|
|
32
|
+
* `streaming` between `true` and `false` in either direction (so the final
|
|
33
|
+
* chunk of a finished stream can never be left stranded mid-window, and a
|
|
34
|
+
* stream restarting on a reused element can never keep showing the
|
|
35
|
+
* previous stream's stale final content for the length of the window).
|
|
34
36
|
*
|
|
35
37
|
* `markdown` is a tri-state property, not a plain boolean: left unset (the
|
|
36
38
|
* default), it auto-detects via a lightweight regex heuristic (see
|
|
@@ -82,12 +84,16 @@ export declare class LyraStreamingText extends LyraElement {
|
|
|
82
84
|
* `false` force that rendering mode regardless of content. */
|
|
83
85
|
markdown?: boolean;
|
|
84
86
|
private displayedContent;
|
|
87
|
+
private lastScannedContent?;
|
|
88
|
+
private lastScannedResult;
|
|
85
89
|
private readonly coalescer;
|
|
86
90
|
constructor();
|
|
87
91
|
protected willUpdate(changed: PropertyValues): void;
|
|
88
92
|
disconnectedCallback(): void;
|
|
89
93
|
/** Whether Markdown mode is actually in effect right now, resolving the
|
|
90
|
-
* tri-state `markdown` property against `looksLikeMarkdown
|
|
94
|
+
* tri-state `markdown` property against the memoized `looksLikeMarkdown`
|
|
95
|
+
* result for the currently-displayed content (see `lastScannedContent`/
|
|
96
|
+
* `lastScannedResult` above). */
|
|
91
97
|
private get effectiveMarkdown();
|
|
92
98
|
render(): TemplateResult;
|
|
93
99
|
}
|
|
@@ -86,8 +86,10 @@ const optionalBooleanConverter = {
|
|
|
86
86
|
* the throttle and flush immediately instead of waiting out the window: the
|
|
87
87
|
* very first `content` assignment after mount (so an already-complete
|
|
88
88
|
* message never shows an artificial startup delay), and any transition of
|
|
89
|
-
* `streaming`
|
|
90
|
-
* stream can never be left stranded mid-window
|
|
89
|
+
* `streaming` between `true` and `false` in either direction (so the final
|
|
90
|
+
* chunk of a finished stream can never be left stranded mid-window, and a
|
|
91
|
+
* stream restarting on a reused element can never keep showing the
|
|
92
|
+
* previous stream's stale final content for the length of the window).
|
|
91
93
|
*
|
|
92
94
|
* `markdown` is a tri-state property, not a plain boolean: left unset (the
|
|
93
95
|
* default), it auto-detects via a lightweight regex heuristic (see
|
|
@@ -140,6 +142,7 @@ export class LyraStreamingText extends LyraElement {
|
|
|
140
142
|
// The coalesced value actually rendered -- lags `content` by up to
|
|
141
143
|
// `coalesceMs` (or zero, for the immediate-flush cases documented above).
|
|
142
144
|
this.displayedContent = '';
|
|
145
|
+
this.lastScannedResult = false;
|
|
143
146
|
// Built in the constructor (not a class-field initializer) so it reads
|
|
144
147
|
// `this.coalesceMs` only after that property's own field initializer has
|
|
145
148
|
// already run and set the declared default -- same ordering rationale as
|
|
@@ -162,23 +165,35 @@ export class LyraStreamingText extends LyraElement {
|
|
|
162
165
|
// coalescing window technically applies to it.
|
|
163
166
|
this.coalescer.announce(this.content, { force: !this.hasUpdated });
|
|
164
167
|
}
|
|
165
|
-
//
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
|
|
168
|
+
// Neither a stream finishing nor a stream (re)starting on a reused
|
|
169
|
+
// element may leave stale content stranded inside an in-progress
|
|
170
|
+
// coalescing window -- force whatever `content` currently holds through
|
|
171
|
+
// immediately in both directions. Without the restart side of this, a
|
|
172
|
+
// reused element would keep showing the *previous* stream's final
|
|
173
|
+
// content for up to a full coalesce-ms window after a new stream had
|
|
174
|
+
// already begun. `changed.get('streaming')` is only defined for a real
|
|
175
|
+
// transition (never the initial mount value, per Lit's documented
|
|
176
|
+
// first-change semantics), so this can't misfire on connect.
|
|
177
|
+
if (changed.has('streaming') &&
|
|
178
|
+
changed.get('streaming') !== undefined &&
|
|
179
|
+
changed.get('streaming') !== this.streaming) {
|
|
171
180
|
this.coalescer.announce(this.content, { force: true });
|
|
172
181
|
}
|
|
182
|
+
if (changed.has('displayedContent') && this.displayedContent !== this.lastScannedContent) {
|
|
183
|
+
this.lastScannedContent = this.displayedContent;
|
|
184
|
+
this.lastScannedResult = looksLikeMarkdown(this.displayedContent);
|
|
185
|
+
}
|
|
173
186
|
}
|
|
174
187
|
disconnectedCallback() {
|
|
175
188
|
super.disconnectedCallback();
|
|
176
189
|
this.coalescer.cancel();
|
|
177
190
|
}
|
|
178
191
|
/** Whether Markdown mode is actually in effect right now, resolving the
|
|
179
|
-
* tri-state `markdown` property against `looksLikeMarkdown
|
|
192
|
+
* tri-state `markdown` property against the memoized `looksLikeMarkdown`
|
|
193
|
+
* result for the currently-displayed content (see `lastScannedContent`/
|
|
194
|
+
* `lastScannedResult` above). */
|
|
180
195
|
get effectiveMarkdown() {
|
|
181
|
-
return this.markdown ??
|
|
196
|
+
return this.markdown ?? this.lastScannedResult;
|
|
182
197
|
}
|
|
183
198
|
render() {
|
|
184
199
|
return html `
|
|
@@ -5,10 +5,11 @@ export const styles = css `
|
|
|
5
5
|
overflow-wrap: break-word;
|
|
6
6
|
/* Not derived from any --lyra-* token in tokens.styles.ts -- there's no
|
|
7
7
|
shared "inline cursor bar" token to resolve through, so this component
|
|
8
|
-
defines its own scoped custom
|
|
8
|
+
defines its own scoped custom properties, exactly the way
|
|
9
9
|
lyra-typing-indicator's --lyra-typing-cursor-width/-height do for its
|
|
10
10
|
own (near-identical) blinking cursor. */
|
|
11
11
|
--lyra-streaming-text-cursor-width: 0.125rem;
|
|
12
|
+
--lyra-streaming-text-cursor-height: 1em;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
[part='base'] {
|
|
@@ -30,7 +31,7 @@ export const styles = css `
|
|
|
30
31
|
display: inline-block;
|
|
31
32
|
vertical-align: text-bottom;
|
|
32
33
|
inline-size: var(--lyra-streaming-text-cursor-width);
|
|
33
|
-
block-size:
|
|
34
|
+
block-size: var(--lyra-streaming-text-cursor-height);
|
|
34
35
|
margin-inline-start: var(--lyra-space-xs);
|
|
35
36
|
background: currentColor;
|
|
36
37
|
border-radius: var(--lyra-streaming-text-cursor-width);
|
|
@@ -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-switch>` — a boolean toggle-switch form control. Structurally the
|
|
@@ -27,21 +27,66 @@ import { LyraElement } from '../../internal/lyra-element.js';
|
|
|
27
27
|
export declare class LyraSwitch extends LyraElement {
|
|
28
28
|
static styles: import("lit").CSSResultGroup[];
|
|
29
29
|
static formAssociated: boolean;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
static properties: {
|
|
31
|
+
checked: {
|
|
32
|
+
type: BooleanConstructor;
|
|
33
|
+
reflect: boolean;
|
|
34
|
+
noAccessor: boolean;
|
|
35
|
+
};
|
|
36
|
+
disabled: {
|
|
37
|
+
type: BooleanConstructor;
|
|
38
|
+
reflect: boolean;
|
|
39
|
+
noAccessor: boolean;
|
|
40
|
+
};
|
|
41
|
+
name: {
|
|
42
|
+
reflect: boolean;
|
|
43
|
+
noAccessor: boolean;
|
|
44
|
+
};
|
|
45
|
+
required: {
|
|
46
|
+
type: BooleanConstructor;
|
|
47
|
+
reflect: boolean;
|
|
48
|
+
noAccessor: boolean;
|
|
49
|
+
};
|
|
50
|
+
value: {
|
|
51
|
+
noAccessor: boolean;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
35
54
|
private hasLabelSlot;
|
|
36
55
|
private internals;
|
|
56
|
+
private validityController;
|
|
37
57
|
private _defaultChecked;
|
|
38
58
|
private _defaultCaptured;
|
|
59
|
+
private _fieldsetDisabled;
|
|
60
|
+
private _name;
|
|
61
|
+
private _checked;
|
|
62
|
+
private _disabled;
|
|
63
|
+
private _required;
|
|
64
|
+
private _value;
|
|
65
|
+
/** Whether the control is disabled explicitly or by an ancestor fieldset. */
|
|
66
|
+
get effectiveDisabled(): boolean;
|
|
67
|
+
get checked(): boolean;
|
|
68
|
+
set checked(next: boolean);
|
|
69
|
+
get disabled(): boolean;
|
|
70
|
+
set disabled(next: boolean);
|
|
71
|
+
/** The form submission key, reflected synchronously for native form APIs. */
|
|
72
|
+
get name(): string;
|
|
73
|
+
set name(next: string);
|
|
74
|
+
get required(): boolean;
|
|
75
|
+
set required(next: boolean);
|
|
76
|
+
get value(): string;
|
|
77
|
+
set value(next: string);
|
|
39
78
|
constructor();
|
|
79
|
+
get form(): HTMLFormElement | null;
|
|
80
|
+
get labels(): NodeList;
|
|
81
|
+
get validity(): ValidityState;
|
|
82
|
+
get validationMessage(): string;
|
|
83
|
+
get willValidate(): boolean;
|
|
40
84
|
connectedCallback(): void;
|
|
41
85
|
protected willUpdate(): void;
|
|
42
86
|
private updateValidity;
|
|
43
|
-
|
|
87
|
+
private syncFormState;
|
|
44
88
|
formResetCallback(): void;
|
|
89
|
+
formStateRestoreCallback(state: string | File | FormData | null, _mode?: 'restore' | 'autocomplete'): void;
|
|
45
90
|
formDisabledCallback(disabled: boolean): void;
|
|
46
91
|
checkValidity(): boolean;
|
|
47
92
|
reportValidity(): boolean;
|