@aceshooting/lyra-ui 1.1.0 → 2.0.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 +12 -1
- package/custom-elements.json +21460 -8489
- package/dist/components/app-rail/app-rail.d.ts +171 -0
- package/dist/components/app-rail/app-rail.js +483 -0
- package/dist/components/app-rail/app-rail.styles.d.ts +1 -0
- package/dist/components/app-rail/app-rail.styles.js +125 -0
- package/dist/components/attachment-chip/attachment-chip.d.ts +114 -0
- package/dist/components/attachment-chip/attachment-chip.js +312 -0
- package/dist/components/attachment-chip/attachment-chip.styles.d.ts +1 -0
- package/dist/components/attachment-chip/attachment-chip.styles.js +184 -0
- package/dist/components/attachment-trigger/attachment-trigger.d.ts +83 -0
- package/dist/components/attachment-trigger/attachment-trigger.js +258 -0
- package/dist/components/attachment-trigger/attachment-trigger.styles.d.ts +1 -0
- package/dist/components/attachment-trigger/attachment-trigger.styles.js +68 -0
- package/dist/components/chart/box-plot.js +11 -1
- package/dist/components/chart/chart-loader.d.ts +44 -13
- package/dist/components/chart/chart-loader.js +65 -18
- package/dist/components/chart/chart.d.ts +12 -2
- package/dist/components/chart/chart.js +121 -14
- package/dist/components/chart/histogram-bin.d.ts +4 -1
- package/dist/components/chart/histogram-bin.js +24 -14
- package/dist/components/chart/lite-chart.d.ts +63 -0
- package/dist/components/chart/lite-chart.js +181 -23
- package/dist/components/chart/lite-chart.styles.js +9 -0
- package/dist/components/chat-composer/chat-composer.d.ts +92 -0
- package/dist/components/chat-composer/chat-composer.js +285 -0
- package/dist/components/chat-composer/chat-composer.styles.d.ts +1 -0
- package/dist/components/chat-composer/chat-composer.styles.js +135 -0
- package/dist/components/chat-message/chat-message.d.ts +113 -0
- package/dist/components/chat-message/chat-message.js +291 -0
- package/dist/components/chat-message/chat-message.styles.d.ts +1 -0
- package/dist/components/chat-message/chat-message.styles.js +203 -0
- package/dist/components/checkbox/checkbox.d.ts +59 -0
- package/dist/components/checkbox/checkbox.js +230 -0
- package/dist/components/checkbox/checkbox.styles.d.ts +1 -0
- package/dist/components/checkbox/checkbox.styles.js +70 -0
- package/dist/components/chip/chip-group.d.ts +56 -0
- package/dist/components/chip/chip-group.js +124 -0
- package/dist/components/chip/chip-group.styles.d.ts +1 -0
- package/dist/components/chip/chip-group.styles.js +57 -0
- package/dist/components/chip/chip.d.ts +64 -0
- package/dist/components/chip/chip.js +115 -0
- package/dist/components/chip/chip.styles.d.ts +1 -0
- package/dist/components/chip/chip.styles.js +115 -0
- package/dist/components/citation-badge/citation-badge.d.ts +113 -0
- package/dist/components/citation-badge/citation-badge.js +300 -0
- package/dist/components/citation-badge/citation-badge.styles.d.ts +1 -0
- package/dist/components/citation-badge/citation-badge.styles.js +96 -0
- package/dist/components/code-block/code-block.d.ts +89 -0
- package/dist/components/code-block/code-block.js +317 -0
- package/dist/components/code-block/code-block.styles.d.ts +1 -0
- package/dist/components/code-block/code-block.styles.js +187 -0
- package/dist/components/code-block/code-loader.d.ts +44 -0
- package/dist/components/code-block/code-loader.js +79 -0
- package/dist/components/combobox/combobox.d.ts +19 -1
- package/dist/components/combobox/combobox.js +84 -14
- package/dist/components/combobox/option.d.ts +5 -1
- package/dist/components/combobox/option.js +35 -0
- package/dist/components/context-meter/context-meter.d.ts +53 -0
- package/dist/components/context-meter/context-meter.js +150 -0
- package/dist/components/context-meter/context-meter.styles.d.ts +1 -0
- package/dist/components/context-meter/context-meter.styles.js +120 -0
- package/dist/components/conversation-item/conversation-item.d.ts +128 -0
- package/dist/components/conversation-item/conversation-item.js +322 -0
- package/dist/components/conversation-item/conversation-item.styles.d.ts +1 -0
- package/dist/components/conversation-item/conversation-item.styles.js +155 -0
- package/dist/components/date-picker/date-input.d.ts +24 -0
- package/dist/components/date-picker/date-input.js +134 -22
- package/dist/components/date-picker/date-picker.d.ts +7 -0
- package/dist/components/date-picker/date-picker.js +85 -16
- package/dist/components/dialog/confirm.d.ts +40 -0
- package/dist/components/dialog/confirm.js +79 -0
- package/dist/components/dialog/dialog.d.ts +85 -0
- package/dist/components/dialog/dialog.js +272 -0
- package/dist/components/dialog/dialog.styles.d.ts +1 -0
- package/dist/components/dialog/dialog.styles.js +52 -0
- package/dist/components/dock-panel/dock-panel.d.ts +134 -0
- package/dist/components/dock-panel/dock-panel.js +345 -0
- package/dist/components/dock-panel/dock-panel.styles.d.ts +1 -0
- package/dist/components/dock-panel/dock-panel.styles.js +145 -0
- package/dist/components/document-preview/document-preview.d.ts +135 -0
- package/dist/components/document-preview/document-preview.js +372 -0
- package/dist/components/document-preview/document-preview.styles.d.ts +1 -0
- package/dist/components/document-preview/document-preview.styles.js +191 -0
- package/dist/components/export-button/csv.js +1 -1
- package/dist/components/export-button/export-button.js +2 -0
- package/dist/components/flag/flag.d.ts +42 -5
- package/dist/components/flag/flag.js +70 -3
- package/dist/components/gauge/gauge.js +19 -10
- package/dist/components/generation-status/generation-status.d.ts +109 -0
- package/dist/components/generation-status/generation-status.js +273 -0
- package/dist/components/generation-status/generation-status.styles.d.ts +1 -0
- package/dist/components/generation-status/generation-status.styles.js +84 -0
- package/dist/components/heatmap/calendar-grid.d.ts +4 -1
- package/dist/components/heatmap/calendar-grid.js +25 -12
- package/dist/components/heatmap/heatmap-scale.d.ts +6 -0
- package/dist/components/heatmap/heatmap-scale.js +7 -1
- package/dist/components/heatmap/heatmap.d.ts +89 -3
- package/dist/components/heatmap/heatmap.js +158 -29
- package/dist/components/json-viewer/json-viewer.d.ts +53 -0
- package/dist/components/json-viewer/json-viewer.js +283 -0
- package/dist/components/json-viewer/json-viewer.styles.d.ts +1 -0
- package/dist/components/json-viewer/json-viewer.styles.js +176 -0
- package/dist/components/kbd/kbd.d.ts +77 -0
- package/dist/components/kbd/kbd.js +214 -0
- package/dist/components/kbd/kbd.styles.d.ts +1 -0
- package/dist/components/kbd/kbd.styles.js +52 -0
- package/dist/components/live-region/live-region.d.ts +81 -0
- package/dist/components/live-region/live-region.js +153 -0
- package/dist/components/live-region/live-region.styles.d.ts +1 -0
- package/dist/components/live-region/live-region.styles.js +10 -0
- package/dist/components/map/map.d.ts +8 -6
- package/dist/components/map/map.js +44 -8
- package/dist/components/markdown/markdown-loader.d.ts +34 -0
- package/dist/components/markdown/markdown-loader.js +43 -0
- package/dist/components/markdown/markdown.d.ts +81 -0
- package/dist/components/markdown/markdown.js +284 -0
- package/dist/components/markdown/markdown.styles.d.ts +1 -0
- package/dist/components/markdown/markdown.styles.js +82 -0
- package/dist/components/media-card/media-card.d.ts +122 -0
- package/dist/components/media-card/media-card.js +295 -0
- package/dist/components/media-card/media-card.styles.d.ts +1 -0
- package/dist/components/media-card/media-card.styles.js +132 -0
- package/dist/components/mention-popover/mention-popover.d.ts +200 -0
- package/dist/components/mention-popover/mention-popover.js +475 -0
- package/dist/components/mention-popover/mention-popover.styles.d.ts +1 -0
- package/dist/components/mention-popover/mention-popover.styles.js +101 -0
- package/dist/components/menu/menu-item.d.ts +62 -0
- package/dist/components/menu/menu-item.js +119 -0
- package/dist/components/menu/menu-item.styles.d.ts +1 -0
- package/dist/components/menu/menu-item.styles.js +67 -0
- package/dist/components/menu/menu.d.ts +143 -0
- package/dist/components/menu/menu.js +365 -0
- package/dist/components/menu/menu.styles.d.ts +1 -0
- package/dist/components/menu/menu.styles.js +66 -0
- package/dist/components/model-select/model-select.d.ts +125 -0
- package/dist/components/model-select/model-select.js +490 -0
- package/dist/components/model-select/model-select.styles.d.ts +1 -0
- package/dist/components/model-select/model-select.styles.js +189 -0
- package/dist/components/model-settings-panel/model-settings-panel.d.ts +69 -0
- package/dist/components/model-settings-panel/model-settings-panel.js +145 -0
- package/dist/components/model-settings-panel/model-settings-panel.styles.d.ts +1 -0
- package/dist/components/model-settings-panel/model-settings-panel.styles.js +82 -0
- package/dist/components/playback/playback.d.ts +13 -1
- package/dist/components/playback/playback.js +47 -14
- package/dist/components/responsive-panel/responsive-panel.d.ts +150 -0
- package/dist/components/responsive-panel/responsive-panel.js +365 -0
- package/dist/components/responsive-panel/responsive-panel.styles.d.ts +1 -0
- package/dist/components/responsive-panel/responsive-panel.styles.js +103 -0
- package/dist/components/result-card/result-card.d.ts +44 -0
- package/dist/components/result-card/result-card.js +83 -0
- package/dist/components/result-card/result-card.styles.d.ts +1 -0
- package/dist/components/result-card/result-card.styles.js +50 -0
- package/dist/components/result-card/result-field.d.ts +36 -0
- package/dist/components/result-card/result-field.js +87 -0
- package/dist/components/result-card/result-field.styles.d.ts +1 -0
- package/dist/components/result-card/result-field.styles.js +32 -0
- package/dist/components/select/select.d.ts +45 -1
- package/dist/components/select/select.js +114 -17
- package/dist/components/select/select.styles.js +26 -2
- package/dist/components/slider/slider.d.ts +89 -0
- package/dist/components/slider/slider.js +352 -0
- package/dist/components/slider/slider.styles.d.ts +1 -0
- package/dist/components/slider/slider.styles.js +87 -0
- package/dist/components/source-card/source-card.d.ts +92 -0
- package/dist/components/source-card/source-card.js +148 -0
- package/dist/components/source-card/source-card.styles.d.ts +1 -0
- package/dist/components/source-card/source-card.styles.js +69 -0
- package/dist/components/source-list/source-list.d.ts +63 -0
- package/dist/components/source-list/source-list.js +122 -0
- package/dist/components/source-list/source-list.styles.d.ts +1 -0
- package/dist/components/source-list/source-list.styles.js +59 -0
- package/dist/components/sparkline/sparkline.js +27 -13
- package/dist/components/split/split.d.ts +93 -1
- package/dist/components/split/split.js +284 -15
- package/dist/components/split/split.styles.js +30 -0
- package/dist/components/stat/stat.d.ts +22 -1
- package/dist/components/stat/stat.js +49 -3
- package/dist/components/stat/stat.styles.js +20 -0
- package/dist/components/stream-status/stream-status.d.ts +110 -0
- package/dist/components/stream-status/stream-status.js +210 -0
- package/dist/components/stream-status/stream-status.styles.d.ts +1 -0
- package/dist/components/stream-status/stream-status.styles.js +103 -0
- package/dist/components/streaming-text/streaming-text.d.ts +98 -0
- package/dist/components/streaming-text/streaming-text.js +209 -0
- package/dist/components/streaming-text/streaming-text.styles.d.ts +1 -0
- package/dist/components/streaming-text/streaming-text.styles.js +62 -0
- package/dist/components/switch/switch.d.ts +58 -0
- package/dist/components/switch/switch.js +179 -0
- package/dist/components/switch/switch.styles.d.ts +1 -0
- package/dist/components/switch/switch.styles.js +75 -0
- package/dist/components/table/table.d.ts +73 -4
- package/dist/components/table/table.js +169 -20
- package/dist/components/table/table.styles.js +6 -1
- package/dist/components/tabs/tabs.d.ts +51 -0
- package/dist/components/tabs/tabs.js +190 -0
- package/dist/components/tabs/tabs.styles.d.ts +1 -0
- package/dist/components/tabs/tabs.styles.js +63 -0
- package/dist/components/thinking-panel/thinking-panel.d.ts +121 -0
- package/dist/components/thinking-panel/thinking-panel.js +235 -0
- package/dist/components/thinking-panel/thinking-panel.styles.d.ts +1 -0
- package/dist/components/thinking-panel/thinking-panel.styles.js +117 -0
- package/dist/components/toast/toast-item.d.ts +1 -0
- package/dist/components/toast/toast-item.js +31 -6
- package/dist/components/tool-approval-dialog/tool-approval-dialog.d.ts +130 -0
- package/dist/components/tool-approval-dialog/tool-approval-dialog.js +403 -0
- package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.d.ts +1 -0
- package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.js +160 -0
- package/dist/components/tool-call-chip/tool-call-chip.d.ts +89 -0
- package/dist/components/tool-call-chip/tool-call-chip.js +288 -0
- package/dist/components/tool-call-chip/tool-call-chip.styles.d.ts +1 -0
- package/dist/components/tool-call-chip/tool-call-chip.styles.js +203 -0
- package/dist/components/tool-param-form/tool-param-form.d.ts +145 -0
- package/dist/components/tool-param-form/tool-param-form.js +366 -0
- package/dist/components/tool-param-form/tool-param-form.styles.d.ts +1 -0
- package/dist/components/tool-param-form/tool-param-form.styles.js +75 -0
- package/dist/components/tool-result-dialog/tool-result-dialog.d.ts +102 -0
- package/dist/components/tool-result-dialog/tool-result-dialog.js +393 -0
- package/dist/components/tool-result-dialog/tool-result-dialog.styles.d.ts +1 -0
- package/dist/components/tool-result-dialog/tool-result-dialog.styles.js +176 -0
- package/dist/components/tool-result-view/registry.d.ts +81 -0
- package/dist/components/tool-result-view/registry.js +84 -0
- package/dist/components/tool-result-view/tool-result-view.d.ts +55 -0
- package/dist/components/tool-result-view/tool-result-view.js +138 -0
- package/dist/components/tool-result-view/tool-result-view.styles.d.ts +1 -0
- package/dist/components/tool-result-view/tool-result-view.styles.js +13 -0
- package/dist/components/tool-select-dialog/tool-select-dialog.d.ts +151 -0
- package/dist/components/tool-select-dialog/tool-select-dialog.js +439 -0
- package/dist/components/tool-select-dialog/tool-select-dialog.styles.d.ts +1 -0
- package/dist/components/tool-select-dialog/tool-select-dialog.styles.js +182 -0
- package/dist/components/tree/tree-node.d.ts +11 -2
- package/dist/components/tree/tree-node.js +16 -6
- package/dist/components/tree/tree.d.ts +8 -2
- package/dist/components/tree/tree.js +18 -11
- package/dist/components/typing-indicator/typing-indicator.d.ts +60 -0
- package/dist/components/typing-indicator/typing-indicator.js +96 -0
- package/dist/components/typing-indicator/typing-indicator.styles.d.ts +1 -0
- package/dist/components/typing-indicator/typing-indicator.styles.js +132 -0
- package/dist/components/virtual-list/virtual-list.d.ts +173 -0
- package/dist/components/virtual-list/virtual-list.js +461 -0
- package/dist/components/virtual-list/virtual-list.styles.d.ts +1 -0
- package/dist/components/virtual-list/virtual-list.styles.js +44 -0
- package/dist/components/widget/widget.d.ts +10 -0
- package/dist/components/widget/widget.js +24 -1
- package/dist/components/widget/widget.styles.js +9 -2
- package/dist/components/word-cloud/word-cloud-layout.js +14 -1
- package/dist/components/word-cloud/word-cloud.d.ts +6 -0
- package/dist/components/word-cloud/word-cloud.js +25 -14
- package/dist/components/word-cloud/word-cloud.styles.js +4 -2
- package/dist/internal/announcer.d.ts +57 -0
- package/dist/internal/announcer.js +71 -0
- package/dist/internal/form-associated.d.ts +1 -0
- package/dist/internal/form-associated.js +55 -11
- package/dist/internal/group-by-recency.d.ts +50 -0
- package/dist/internal/group-by-recency.js +80 -0
- package/dist/internal/rtl.d.ts +23 -0
- package/dist/internal/rtl.js +28 -0
- package/dist/internal/scroll-lock.d.ts +10 -5
- package/dist/internal/scroll-lock.js +30 -14
- package/dist/internal/tokens.styles.js +6 -0
- package/dist/lyra.d.ts +130 -31
- package/dist/lyra.js +94 -26
- package/llms-full.txt +3921 -32
- package/llms.txt +16 -1
- package/package.json +23 -5
- package/dist/components/chart/bar-chart.stories.d.ts +0 -5
- package/dist/components/chart/bar-chart.stories.js +0 -20
- package/dist/components/chart/box-plot.stories.d.ts +0 -5
- package/dist/components/chart/box-plot.stories.js +0 -29
- package/dist/components/chart/bubble-chart.stories.d.ts +0 -5
- package/dist/components/chart/bubble-chart.stories.js +0 -26
- package/dist/components/chart/chart.stories.d.ts +0 -32
- package/dist/components/chart/chart.stories.js +0 -141
- package/dist/components/chart/doughnut-chart.stories.d.ts +0 -5
- package/dist/components/chart/doughnut-chart.stories.js +0 -26
- package/dist/components/chart/histogram.stories.d.ts +0 -5
- package/dist/components/chart/histogram.stories.js +0 -17
- package/dist/components/chart/line-chart.stories.d.ts +0 -22
- package/dist/components/chart/line-chart.stories.js +0 -99
- package/dist/components/chart/lite-chart.stories.d.ts +0 -12
- package/dist/components/chart/lite-chart.stories.js +0 -98
- package/dist/components/chart/pie-chart.stories.d.ts +0 -5
- package/dist/components/chart/pie-chart.stories.js +0 -26
- package/dist/components/chart/polar-area-chart.stories.d.ts +0 -5
- package/dist/components/chart/polar-area-chart.stories.js +0 -20
- package/dist/components/chart/radar-chart.stories.d.ts +0 -5
- package/dist/components/chart/radar-chart.stories.js +0 -20
- package/dist/components/chart/scatter-chart.stories.d.ts +0 -5
- package/dist/components/chart/scatter-chart.stories.js +0 -31
- package/dist/components/combobox/combobox.stories.d.ts +0 -24
- package/dist/components/combobox/combobox.stories.js +0 -102
- package/dist/components/date-picker/date-input.stories.d.ts +0 -10
- package/dist/components/date-picker/date-input.stories.js +0 -48
- package/dist/components/date-picker/date-picker.stories.d.ts +0 -10
- package/dist/components/date-picker/date-picker.stories.js +0 -25
- package/dist/components/empty/empty.stories.d.ts +0 -7
- package/dist/components/empty/empty.stories.js +0 -34
- package/dist/components/export-button/export-button.stories.d.ts +0 -7
- package/dist/components/export-button/export-button.stories.js +0 -37
- package/dist/components/file-input/file-input.stories.d.ts +0 -7
- package/dist/components/file-input/file-input.stories.js +0 -19
- package/dist/components/flag/flag.stories.d.ts +0 -5
- package/dist/components/flag/flag.stories.js +0 -17
- package/dist/components/gauge/gauge.stories.d.ts +0 -8
- package/dist/components/gauge/gauge.stories.js +0 -19
- package/dist/components/graph/graph.stories.d.ts +0 -8
- package/dist/components/graph/graph.stories.js +0 -68
- package/dist/components/heatmap/heatmap.stories.d.ts +0 -22
- package/dist/components/heatmap/heatmap.stories.js +0 -154
- package/dist/components/map/map.stories.d.ts +0 -15
- package/dist/components/map/map.stories.js +0 -135
- package/dist/components/playback/playback.stories.d.ts +0 -7
- package/dist/components/playback/playback.stories.js +0 -16
- package/dist/components/select/select.stories.d.ts +0 -19
- package/dist/components/select/select.stories.js +0 -75
- package/dist/components/skeleton/skeleton.stories.d.ts +0 -5
- package/dist/components/skeleton/skeleton.stories.js +0 -16
- package/dist/components/sparkline/sparkline.stories.d.ts +0 -11
- package/dist/components/sparkline/sparkline.stories.js +0 -39
- package/dist/components/split/split.stories.d.ts +0 -7
- package/dist/components/split/split.stories.js +0 -36
- package/dist/components/stat/stat.stories.d.ts +0 -8
- package/dist/components/stat/stat.stories.js +0 -64
- package/dist/components/table/table.stories.d.ts +0 -12
- package/dist/components/table/table.stories.js +0 -67
- package/dist/components/time-range/time-range.stories.d.ts +0 -8
- package/dist/components/time-range/time-range.stories.js +0 -26
- package/dist/components/toast/toast.stories.d.ts +0 -8
- package/dist/components/toast/toast.stories.js +0 -72
- package/dist/components/tree/tree.stories.d.ts +0 -9
- package/dist/components/tree/tree.stories.js +0 -52
- package/dist/components/widget/widget.stories.d.ts +0 -7
- package/dist/components/widget/widget.stories.js +0 -41
- package/dist/components/word-cloud/word-cloud.stories.d.ts +0 -10
- package/dist/components/word-cloud/word-cloud.stories.js +0 -55
|
@@ -28,6 +28,22 @@ export async function loadFlagUrl(importFlags = () => import('@aceshooting/lyra-
|
|
|
28
28
|
return null;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolves an ISO 3166-1 alpha-2 region code to a human-readable, localized
|
|
33
|
+
* display name (e.g. `'FR'` -> `'France'`) via `Intl.DisplayNames`, for use as
|
|
34
|
+
* the default accessible name (`alt`) instead of a bare code read
|
|
35
|
+
* letter-by-letter by most screen readers. Falls back to the uppercase code
|
|
36
|
+
* itself if `Intl.DisplayNames` throws (unrecognized region) or isn't
|
|
37
|
+
* available in the current runtime.
|
|
38
|
+
*/
|
|
39
|
+
function displayNameFor(code) {
|
|
40
|
+
try {
|
|
41
|
+
return new Intl.DisplayNames([navigator.language], { type: 'region' }).of(code.toUpperCase()) ?? code.toUpperCase();
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return code.toUpperCase();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
31
47
|
let flagUrlResolver;
|
|
32
48
|
/**
|
|
33
49
|
* Lazily loads the optional peer dependency '@aceshooting/lyra-flags' once per
|
|
@@ -40,6 +56,17 @@ function loadFlagUrlResolver() {
|
|
|
40
56
|
}
|
|
41
57
|
return flagUrlResolver;
|
|
42
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* @internal Test-only seam: overrides (or, with `undefined`, clears) the module-level cache that
|
|
61
|
+
* `willUpdate()` reads through `loadFlagUrlResolver()`. The real `@aceshooting/lyra-flags` peer's
|
|
62
|
+
* `flagUrl(code)` never actually rejects (unknown codes just resolve `undefined`), so this is the
|
|
63
|
+
* only way to exercise a resolver-function rejection — e.g. a network failure fetching a flag
|
|
64
|
+
* asset — without uninstalling the real package. Not part of the public API; not re-exported from
|
|
65
|
+
* the root barrel.
|
|
66
|
+
*/
|
|
67
|
+
export function __setFlagUrlResolverForTesting(value) {
|
|
68
|
+
flagUrlResolver = value;
|
|
69
|
+
}
|
|
43
70
|
/**
|
|
44
71
|
* `<lyra-flag>` — a country/language flag.
|
|
45
72
|
*
|
|
@@ -59,10 +86,19 @@ function loadFlagUrlResolver() {
|
|
|
59
86
|
* `src` instead to skip the peer-package round trip (and its loading-skeleton
|
|
60
87
|
* flash) entirely.
|
|
61
88
|
*
|
|
89
|
+
* The ~65 flags whose design includes a detailed coat of arms/seal/emblem (e.g. `es`, `pt`) ship
|
|
90
|
+
* three fidelity tiers; choose one with `variant`: `"compact"` (a tiny WebP raster for icon-scale
|
|
91
|
+
* use — menu items, language selectors, dense lists), the default `"standard"` (icon-optimized
|
|
92
|
+
* vector for card/row sizes), or `"detailed"` (the pristine full-detail vector for hero-scale
|
|
93
|
+
* display). A no-op for every other code — all tiers resolve to the same file. See `variant`'s own
|
|
94
|
+
* doc.
|
|
95
|
+
*
|
|
62
96
|
* @customElement lyra-flag
|
|
63
97
|
* @example <lyra-flag country="fr"></lyra-flag>
|
|
64
98
|
* @example <lyra-flag language="en" label="English"></lyra-flag>
|
|
65
99
|
* @example <lyra-flag src=${frUrl} label="French"></lyra-flag>
|
|
100
|
+
* @example <lyra-flag country="es" variant="compact"></lyra-flag>
|
|
101
|
+
* @example <lyra-flag country="es" variant="detailed"></lyra-flag>
|
|
66
102
|
* @csspart image - The underlying <img>.
|
|
67
103
|
*/
|
|
68
104
|
export class LyraFlag extends LyraElement {
|
|
@@ -70,6 +106,11 @@ export class LyraFlag extends LyraElement {
|
|
|
70
106
|
super(...arguments);
|
|
71
107
|
/** Render as a circular flag. */
|
|
72
108
|
this.round = false;
|
|
109
|
+
/**
|
|
110
|
+
* @deprecated Use `variant="detailed"` instead. Kept as an alias for one minor cycle; when
|
|
111
|
+
* `variant` is unset, `detailed` still maps to the detailed tier. Removed in the next major.
|
|
112
|
+
*/
|
|
113
|
+
this.detailed = false;
|
|
73
114
|
/** True while the lazy-loaded `@aceshooting/lyra-flags` peer resolver is in flight. */
|
|
74
115
|
this.loading = true;
|
|
75
116
|
/**
|
|
@@ -81,6 +122,11 @@ export class LyraFlag extends LyraElement {
|
|
|
81
122
|
this.resolveToken = 0;
|
|
82
123
|
}
|
|
83
124
|
static { this.styles = [LyraElement.styles, styles]; }
|
|
125
|
+
/** The effective tier to request: an explicit `variant` wins; otherwise the deprecated
|
|
126
|
+
* `detailed` boolean is honored; otherwise `"standard"`. */
|
|
127
|
+
get effectiveVariant() {
|
|
128
|
+
return this.variant ?? (this.detailed ? 'detailed' : 'standard');
|
|
129
|
+
}
|
|
84
130
|
get code() {
|
|
85
131
|
if (this.country) {
|
|
86
132
|
return ALPHA2_RE.test(this.country) ? this.country.toLowerCase() : undefined;
|
|
@@ -96,8 +142,14 @@ export class LyraFlag extends LyraElement {
|
|
|
96
142
|
// undefined -> undefined (no-op to Lit), so none of `changed.has(...)`
|
|
97
143
|
// would otherwise ever become true for a `<lyra-flag>` that never
|
|
98
144
|
// receives one, leaving `loading` stuck at its initial `true` forever.
|
|
99
|
-
if (this.hasUpdated &&
|
|
145
|
+
if (this.hasUpdated &&
|
|
146
|
+
!changed.has('country') &&
|
|
147
|
+
!changed.has('language') &&
|
|
148
|
+
!changed.has('src') &&
|
|
149
|
+
!changed.has('variant') &&
|
|
150
|
+
!changed.has('detailed')) {
|
|
100
151
|
return;
|
|
152
|
+
}
|
|
101
153
|
const token = ++this.resolveToken; // invalidates any in-flight peer resolution either way
|
|
102
154
|
if (this.src) {
|
|
103
155
|
this.resolvedSrc = undefined;
|
|
@@ -111,13 +163,21 @@ export class LyraFlag extends LyraElement {
|
|
|
111
163
|
return;
|
|
112
164
|
}
|
|
113
165
|
this.loading = true;
|
|
166
|
+
const variant = this.effectiveVariant;
|
|
114
167
|
void loadFlagUrlResolver()
|
|
115
|
-
.then((resolve) => resolve?.(code))
|
|
168
|
+
.then((resolve) => resolve?.(code, variant === 'standard' ? undefined : { variant }))
|
|
116
169
|
.then((url) => {
|
|
117
170
|
if (token !== this.resolveToken)
|
|
118
171
|
return; // superseded by a later country/language/src change
|
|
119
172
|
this.resolvedSrc = url;
|
|
120
173
|
this.loading = false;
|
|
174
|
+
})
|
|
175
|
+
.catch((err) => {
|
|
176
|
+
if (token !== this.resolveToken)
|
|
177
|
+
return; // superseded by a later country/language/src change
|
|
178
|
+
console.warn(`<lyra-flag> failed to resolve a flag URL for "${code}":`, err);
|
|
179
|
+
this.resolvedSrc = undefined;
|
|
180
|
+
this.loading = false;
|
|
121
181
|
});
|
|
122
182
|
}
|
|
123
183
|
updated() {
|
|
@@ -132,7 +192,8 @@ export class LyraFlag extends LyraElement {
|
|
|
132
192
|
const url = this.src ?? this.resolvedSrc;
|
|
133
193
|
if (!url)
|
|
134
194
|
return html ``;
|
|
135
|
-
const
|
|
195
|
+
const code = this.code;
|
|
196
|
+
const alt = this.label ?? (code ? displayNameFor(code) : '');
|
|
136
197
|
return html `<img part="image" src=${url} alt=${alt} loading="lazy" decoding="async" />`;
|
|
137
198
|
}
|
|
138
199
|
}
|
|
@@ -151,6 +212,12 @@ __decorate([
|
|
|
151
212
|
__decorate([
|
|
152
213
|
property({ type: Boolean, reflect: true })
|
|
153
214
|
], LyraFlag.prototype, "round", void 0);
|
|
215
|
+
__decorate([
|
|
216
|
+
property()
|
|
217
|
+
], LyraFlag.prototype, "variant", void 0);
|
|
218
|
+
__decorate([
|
|
219
|
+
property({ type: Boolean, reflect: true })
|
|
220
|
+
], LyraFlag.prototype, "detailed", void 0);
|
|
154
221
|
__decorate([
|
|
155
222
|
state()
|
|
156
223
|
], LyraFlag.prototype, "resolvedSrc", void 0);
|
|
@@ -57,28 +57,37 @@ export class LyraGauge extends LyraElement {
|
|
|
57
57
|
}
|
|
58
58
|
static { this.styles = [LyraElement.styles, styles]; }
|
|
59
59
|
get ratio() {
|
|
60
|
-
if (
|
|
60
|
+
if (!Number.isFinite(this.value) || !Number.isFinite(this.min) || !Number.isFinite(this.max))
|
|
61
61
|
return 0;
|
|
62
|
-
const
|
|
63
|
-
|
|
62
|
+
const lo = Math.min(this.min, this.max);
|
|
63
|
+
const hi = Math.max(this.min, this.max);
|
|
64
|
+
const span = hi - lo || 1;
|
|
65
|
+
return Math.min(1, Math.max(0, (this.value - lo) / span));
|
|
64
66
|
}
|
|
65
67
|
willUpdate() {
|
|
66
68
|
this.setAttribute('role', 'meter');
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
const finiteTrio = Number.isFinite(this.value) && Number.isFinite(this.min) && Number.isFinite(this.max);
|
|
70
|
+
// Normalize a reversed min > max domain the same way `ratio` does, so the
|
|
71
|
+
// announced aria-value* trio always agrees with the visual fill instead
|
|
72
|
+
// of aria-valuenow pinning to one bound regardless of `value` (and
|
|
73
|
+
// aria-valuemin/valuemax reporting an inverted, invalid ARIA range).
|
|
74
|
+
const lo = Number.isFinite(this.min) && Number.isFinite(this.max) ? Math.min(this.min, this.max) : this.min;
|
|
75
|
+
const hi = Number.isFinite(this.min) && Number.isFinite(this.max) ? Math.max(this.min, this.max) : this.max;
|
|
76
|
+
if (finiteTrio) {
|
|
77
|
+
const clamped = Math.min(hi, Math.max(lo, this.value));
|
|
69
78
|
this.setAttribute('aria-valuenow', String(clamped));
|
|
70
79
|
}
|
|
71
80
|
else {
|
|
72
81
|
this.removeAttribute('aria-valuenow');
|
|
73
82
|
}
|
|
74
|
-
if (
|
|
83
|
+
if (Number.isFinite(lo))
|
|
84
|
+
this.setAttribute('aria-valuemin', String(lo));
|
|
85
|
+
else
|
|
75
86
|
this.removeAttribute('aria-valuemin');
|
|
87
|
+
if (Number.isFinite(hi))
|
|
88
|
+
this.setAttribute('aria-valuemax', String(hi));
|
|
76
89
|
else
|
|
77
|
-
this.setAttribute('aria-valuemin', String(this.min));
|
|
78
|
-
if (isNaN(this.max))
|
|
79
90
|
this.removeAttribute('aria-valuemax');
|
|
80
|
-
else
|
|
81
|
-
this.setAttribute('aria-valuemax', String(this.max));
|
|
82
91
|
if (this.label)
|
|
83
92
|
this.setAttribute('aria-label', this.label);
|
|
84
93
|
else
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { type TemplateResult, type PropertyValues } from 'lit';
|
|
2
|
+
import { LyraElement } from '../../internal/lyra-element.js';
|
|
3
|
+
/**
|
|
4
|
+
* `<lyra-generation-status>` — a compact, ticking status readout shown
|
|
5
|
+
* alongside an in-progress AI response: elapsed time, token count, and
|
|
6
|
+
* token-throughput, plus a built-in Stop button. Renders as e.g.
|
|
7
|
+
* `12.3s · 340 tokens · 27 tok/s [Stop]`.
|
|
8
|
+
*
|
|
9
|
+
* This is deliberately a *different* concern than the already-landed
|
|
10
|
+
* `<lyra-stream-status>`: that component is about transport/connection
|
|
11
|
+
* health (idle/connecting/streaming/stalled, heartbeat-aware stall
|
|
12
|
+
* detection), while this one is a user-facing metrics readout for a
|
|
13
|
+
* generation that both components' hosts typically already know is
|
|
14
|
+
* healthily in progress. Neither imports or depends on the other, and a
|
|
15
|
+
* consumer building a full generation UI is expected to compose both side by
|
|
16
|
+
* side rather than pick one.
|
|
17
|
+
*
|
|
18
|
+
* `active` drives an internal ~1s `setInterval` ticker that recomputes the
|
|
19
|
+
* elapsed-time display (a plain interval is sufficient here -- unlike
|
|
20
|
+
* `<lyra-stream-status>`'s stall timer, this never needs to be armed with a
|
|
21
|
+
* precise deadline, only to refresh a display roughly once a second). The
|
|
22
|
+
* elapsed clock's start instant is `started-at` when set (an epoch-ms
|
|
23
|
+
* timestamp -- lets a host that already knows exactly when generation began,
|
|
24
|
+
* e.g. from its own request-dispatch timestamp, feed that in directly and
|
|
25
|
+
* survive this component being created slightly later than that instant);
|
|
26
|
+
* when `started-at` is unset, this component falls back to capturing
|
|
27
|
+
* `Date.now()` itself at the moment `active` flips from `false`/unset to
|
|
28
|
+
* `true`, so the ticker still starts from a sensible instant with zero
|
|
29
|
+
* required host bookkeeping. The ticker is cleared whenever `active` becomes
|
|
30
|
+
* `false` and on disconnect; the display is left at whatever it last showed
|
|
31
|
+
* (frozen, not reset to zero) -- a static "Generated in 12.3s" reads better
|
|
32
|
+
* as a completed-state summary than the readout blanking out the instant
|
|
33
|
+
* generation ends.
|
|
34
|
+
*
|
|
35
|
+
* `tokens-per-second`, when the host supplies it directly (e.g. from its own
|
|
36
|
+
* smoothed/windowed rate calculation), is always used as-is. When omitted,
|
|
37
|
+
* this component derives a live figure itself from `token-count` divided by
|
|
38
|
+
* elapsed seconds -- but only once at least one full second of elapsed time
|
|
39
|
+
* has accumulated, since dividing by a sub-second elapsed window can produce
|
|
40
|
+
* wildly-swinging, misleading early readings (e.g. 3 tokens in 40ms reading
|
|
41
|
+
* as "75 tok/s"). A host that wants a stable figure from the very first tick
|
|
42
|
+
* should supply `tokens-per-second` itself. The tokens segment and the
|
|
43
|
+
* throughput segment are independently optional: either, both, or neither
|
|
44
|
+
* may render depending on what's available, per each property's own doc.
|
|
45
|
+
*
|
|
46
|
+
* Accessibility: this readout ticks roughly once per second while active,
|
|
47
|
+
* which is exactly the kind of high-frequency update
|
|
48
|
+
* `<lyra-live-region>`/`Announcer` (`../../internal/announcer.js`) exists to
|
|
49
|
+
* *prevent* from being read aloud verbatim -- routing a per-second numeric
|
|
50
|
+
* tick through even a throttled announcer would still narrate a new number
|
|
51
|
+
* to a screen-reader user roughly once every throttle window for as long as
|
|
52
|
+
* generation runs, which is noise, not information. This component
|
|
53
|
+
* therefore carries no `role="status"`/`aria-live` of its own and never
|
|
54
|
+
* announces anything; a host that wants generation-start/-end announced
|
|
55
|
+
* should pair this with something that announces state *transitions* (e.g.
|
|
56
|
+
* `<lyra-typing-indicator>`'s mount-time announcement), not this ticking
|
|
57
|
+
* readout. The one genuinely actionable, infrequent control here -- the Stop
|
|
58
|
+
* button -- gets a normal, always-present `aria-label`, no different from
|
|
59
|
+
* any other icon-only button in this library.
|
|
60
|
+
*
|
|
61
|
+
* @customElement lyra-generation-status
|
|
62
|
+
* @event lyra-stop - The built-in Stop button was clicked. No detail payload.
|
|
63
|
+
* @csspart base - The root inline layout container.
|
|
64
|
+
* @csspart elapsed - The elapsed-time segment, e.g. `"12.3s"`. Always rendered (reads `"0.0s"` before the component has ever been active).
|
|
65
|
+
* @csspart tokens - The token-count segment, e.g. `"340 tokens"`. Only rendered when `token-count` is set.
|
|
66
|
+
* @csspart throughput - The throughput segment, e.g. `"27 tok/s"`. Only rendered when a value is available (host-supplied or derived; see the class doc).
|
|
67
|
+
* @csspart stop-button - The built-in Stop button. Only rendered while `show-stop` is true.
|
|
68
|
+
*/
|
|
69
|
+
export declare class LyraGenerationStatus extends LyraElement {
|
|
70
|
+
static styles: import("lit").CSSResultGroup[];
|
|
71
|
+
/** Whether generation is currently in progress. The elapsed-time ticker
|
|
72
|
+
* runs only while this is `true` (see the class doc). */
|
|
73
|
+
active: boolean;
|
|
74
|
+
/** Epoch-ms timestamp of when generation began. Optional -- when unset
|
|
75
|
+
* while `active` is `true`, this component captures the current time
|
|
76
|
+
* itself the moment `active` becomes `true` and counts from there instead
|
|
77
|
+
* (see the class doc). */
|
|
78
|
+
startedAt?: number;
|
|
79
|
+
/** Running token count so far. Omitted from the readout entirely (no
|
|
80
|
+
* `tokens` segment) while unset. */
|
|
81
|
+
tokenCount?: number;
|
|
82
|
+
/** Host-computed tokens/sec figure, used as-is when set. When unset, this
|
|
83
|
+
* component derives a live figure from `token-count` and elapsed time
|
|
84
|
+
* itself once one is available -- see the class doc for the exact rule
|
|
85
|
+
* and why. */
|
|
86
|
+
tokensPerSecond?: number;
|
|
87
|
+
/** Whether the built-in Stop button renders at all. */
|
|
88
|
+
showStop: boolean;
|
|
89
|
+
private elapsedMs;
|
|
90
|
+
private tickTimer?;
|
|
91
|
+
private fallbackStartMs?;
|
|
92
|
+
disconnectedCallback(): void;
|
|
93
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
94
|
+
protected updated(changed: PropertyValues): void;
|
|
95
|
+
private startTicker;
|
|
96
|
+
private stopTicker;
|
|
97
|
+
private computeElapsedMs;
|
|
98
|
+
/** `tokens-per-second` when set; otherwise a derived figure once enough
|
|
99
|
+
* elapsed time has accumulated for it to be meaningful; otherwise
|
|
100
|
+
* `undefined` (the throughput segment doesn't render at all). */
|
|
101
|
+
private get effectiveTokensPerSecond();
|
|
102
|
+
private onStopClick;
|
|
103
|
+
render(): TemplateResult;
|
|
104
|
+
}
|
|
105
|
+
declare global {
|
|
106
|
+
interface HTMLElementTagNameMap {
|
|
107
|
+
'lyra-generation-status': LyraGenerationStatus;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { html, nothing, svg } from 'lit';
|
|
8
|
+
import { property, state } from 'lit/decorators.js';
|
|
9
|
+
import { LyraElement } from '../../internal/lyra-element.js';
|
|
10
|
+
import { defineElement } from '../../internal/prefix.js';
|
|
11
|
+
import { styles } from './generation-status.styles.js';
|
|
12
|
+
// Mirrors the shared icon set's viewBox/stroke conventions
|
|
13
|
+
// (internal/icons.ts's chevronIcon()/closeIcon()/etc.) without adding a
|
|
14
|
+
// stop glyph to that module -- it's off limits here -- so this one-off icon
|
|
15
|
+
// still reads as part of the same visual language as the rest of the
|
|
16
|
+
// library's inline icons. Identical shape to `<lyra-chat-composer>`'s own
|
|
17
|
+
// local `stopIcon()` (the conventional filled-square "stop generating"
|
|
18
|
+
// glyph), duplicated rather than imported since these are two independently
|
|
19
|
+
// consumable components with no dependency between them.
|
|
20
|
+
function stopIcon() {
|
|
21
|
+
return svg `
|
|
22
|
+
<svg
|
|
23
|
+
width="1em"
|
|
24
|
+
height="1em"
|
|
25
|
+
viewBox="0 0 24 24"
|
|
26
|
+
fill="currentColor"
|
|
27
|
+
stroke="none"
|
|
28
|
+
aria-hidden="true"
|
|
29
|
+
focusable="false"
|
|
30
|
+
><rect x="6" y="6" width="12" height="12" rx="1.5"></rect></svg>
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
33
|
+
/** `4200` -> `"4.2s"`; `65000` -> `"1m 5s"`. Sub-minute durations get one
|
|
34
|
+
* decimal place of seconds (the common case: most single generations finish
|
|
35
|
+
* in single-digit seconds, where whole-second precision would look static
|
|
36
|
+
* between ticks); once a full minute is reached, `"Xm Ys"` reads better than
|
|
37
|
+
* a fractional-minute or a 3-4 digit seconds count. The `59.95` cutoff (not
|
|
38
|
+
* a plain `60`) exists so a value that *rounds* to `"60.0s"` at one-decimal
|
|
39
|
+
* precision is displayed as `"1m 0s"` instead -- without it, the two
|
|
40
|
+
* branches could each independently round the same instant to a different
|
|
41
|
+
* minute. */
|
|
42
|
+
function formatElapsed(ms) {
|
|
43
|
+
const totalSeconds = Math.max(0, ms) / 1000;
|
|
44
|
+
if (totalSeconds < 59.95) {
|
|
45
|
+
return `${(Math.round(totalSeconds * 10) / 10).toFixed(1)}s`;
|
|
46
|
+
}
|
|
47
|
+
const wholeSeconds = Math.round(totalSeconds);
|
|
48
|
+
const minutes = Math.floor(wholeSeconds / 60);
|
|
49
|
+
const seconds = wholeSeconds % 60;
|
|
50
|
+
return `${minutes}m ${seconds}s`;
|
|
51
|
+
}
|
|
52
|
+
/** `340` -> `"340 tokens"`; `1` -> `"1 token"`. Same plain singular/plural
|
|
53
|
+
* ternary `<lyra-json-viewer>`'s array/object summary already uses -- this
|
|
54
|
+
* library has no general i18n/pluralization system (see
|
|
55
|
+
* `<lyra-source-list>`'s class doc for that stance), but a two-way English
|
|
56
|
+
* ternary for one fixed noun is a different, much smaller thing than a
|
|
57
|
+
* general pluralization engine, and reads better than an unconditional
|
|
58
|
+
* "1 tokens". */
|
|
59
|
+
function formatTokenCount(count) {
|
|
60
|
+
const rounded = Math.max(0, Math.round(count));
|
|
61
|
+
return `${rounded} ${rounded === 1 ? 'token' : 'tokens'}`;
|
|
62
|
+
}
|
|
63
|
+
/** `27.4` -> `"27 tok/s"`; `3.2` -> `"3.2 tok/s"`. Same shape as this file's
|
|
64
|
+
* `formatElapsed`/`<lyra-tool-call-chip>`'s `formatDuration`: the low end of
|
|
65
|
+
* the range (where a whole-number rounding would flatten every early
|
|
66
|
+
* reading to the same "0" or "1") gets one decimal place, while anything at
|
|
67
|
+
* or above 10 tok/s rounds to a whole number, which is plenty precise for a
|
|
68
|
+
* live-updating throughput figure. */
|
|
69
|
+
function formatThroughput(value) {
|
|
70
|
+
const clamped = Math.max(0, value);
|
|
71
|
+
const rounded = clamped < 10 ? Math.round(clamped * 10) / 10 : Math.round(clamped);
|
|
72
|
+
return `${rounded} tok/s`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* `<lyra-generation-status>` — a compact, ticking status readout shown
|
|
76
|
+
* alongside an in-progress AI response: elapsed time, token count, and
|
|
77
|
+
* token-throughput, plus a built-in Stop button. Renders as e.g.
|
|
78
|
+
* `12.3s · 340 tokens · 27 tok/s [Stop]`.
|
|
79
|
+
*
|
|
80
|
+
* This is deliberately a *different* concern than the already-landed
|
|
81
|
+
* `<lyra-stream-status>`: that component is about transport/connection
|
|
82
|
+
* health (idle/connecting/streaming/stalled, heartbeat-aware stall
|
|
83
|
+
* detection), while this one is a user-facing metrics readout for a
|
|
84
|
+
* generation that both components' hosts typically already know is
|
|
85
|
+
* healthily in progress. Neither imports or depends on the other, and a
|
|
86
|
+
* consumer building a full generation UI is expected to compose both side by
|
|
87
|
+
* side rather than pick one.
|
|
88
|
+
*
|
|
89
|
+
* `active` drives an internal ~1s `setInterval` ticker that recomputes the
|
|
90
|
+
* elapsed-time display (a plain interval is sufficient here -- unlike
|
|
91
|
+
* `<lyra-stream-status>`'s stall timer, this never needs to be armed with a
|
|
92
|
+
* precise deadline, only to refresh a display roughly once a second). The
|
|
93
|
+
* elapsed clock's start instant is `started-at` when set (an epoch-ms
|
|
94
|
+
* timestamp -- lets a host that already knows exactly when generation began,
|
|
95
|
+
* e.g. from its own request-dispatch timestamp, feed that in directly and
|
|
96
|
+
* survive this component being created slightly later than that instant);
|
|
97
|
+
* when `started-at` is unset, this component falls back to capturing
|
|
98
|
+
* `Date.now()` itself at the moment `active` flips from `false`/unset to
|
|
99
|
+
* `true`, so the ticker still starts from a sensible instant with zero
|
|
100
|
+
* required host bookkeeping. The ticker is cleared whenever `active` becomes
|
|
101
|
+
* `false` and on disconnect; the display is left at whatever it last showed
|
|
102
|
+
* (frozen, not reset to zero) -- a static "Generated in 12.3s" reads better
|
|
103
|
+
* as a completed-state summary than the readout blanking out the instant
|
|
104
|
+
* generation ends.
|
|
105
|
+
*
|
|
106
|
+
* `tokens-per-second`, when the host supplies it directly (e.g. from its own
|
|
107
|
+
* smoothed/windowed rate calculation), is always used as-is. When omitted,
|
|
108
|
+
* this component derives a live figure itself from `token-count` divided by
|
|
109
|
+
* elapsed seconds -- but only once at least one full second of elapsed time
|
|
110
|
+
* has accumulated, since dividing by a sub-second elapsed window can produce
|
|
111
|
+
* wildly-swinging, misleading early readings (e.g. 3 tokens in 40ms reading
|
|
112
|
+
* as "75 tok/s"). A host that wants a stable figure from the very first tick
|
|
113
|
+
* should supply `tokens-per-second` itself. The tokens segment and the
|
|
114
|
+
* throughput segment are independently optional: either, both, or neither
|
|
115
|
+
* may render depending on what's available, per each property's own doc.
|
|
116
|
+
*
|
|
117
|
+
* Accessibility: this readout ticks roughly once per second while active,
|
|
118
|
+
* which is exactly the kind of high-frequency update
|
|
119
|
+
* `<lyra-live-region>`/`Announcer` (`../../internal/announcer.js`) exists to
|
|
120
|
+
* *prevent* from being read aloud verbatim -- routing a per-second numeric
|
|
121
|
+
* tick through even a throttled announcer would still narrate a new number
|
|
122
|
+
* to a screen-reader user roughly once every throttle window for as long as
|
|
123
|
+
* generation runs, which is noise, not information. This component
|
|
124
|
+
* therefore carries no `role="status"`/`aria-live` of its own and never
|
|
125
|
+
* announces anything; a host that wants generation-start/-end announced
|
|
126
|
+
* should pair this with something that announces state *transitions* (e.g.
|
|
127
|
+
* `<lyra-typing-indicator>`'s mount-time announcement), not this ticking
|
|
128
|
+
* readout. The one genuinely actionable, infrequent control here -- the Stop
|
|
129
|
+
* button -- gets a normal, always-present `aria-label`, no different from
|
|
130
|
+
* any other icon-only button in this library.
|
|
131
|
+
*
|
|
132
|
+
* @customElement lyra-generation-status
|
|
133
|
+
* @event lyra-stop - The built-in Stop button was clicked. No detail payload.
|
|
134
|
+
* @csspart base - The root inline layout container.
|
|
135
|
+
* @csspart elapsed - The elapsed-time segment, e.g. `"12.3s"`. Always rendered (reads `"0.0s"` before the component has ever been active).
|
|
136
|
+
* @csspart tokens - The token-count segment, e.g. `"340 tokens"`. Only rendered when `token-count` is set.
|
|
137
|
+
* @csspart throughput - The throughput segment, e.g. `"27 tok/s"`. Only rendered when a value is available (host-supplied or derived; see the class doc).
|
|
138
|
+
* @csspart stop-button - The built-in Stop button. Only rendered while `show-stop` is true.
|
|
139
|
+
*/
|
|
140
|
+
export class LyraGenerationStatus extends LyraElement {
|
|
141
|
+
constructor() {
|
|
142
|
+
super(...arguments);
|
|
143
|
+
/** Whether generation is currently in progress. The elapsed-time ticker
|
|
144
|
+
* runs only while this is `true` (see the class doc). */
|
|
145
|
+
this.active = false;
|
|
146
|
+
/** Whether the built-in Stop button renders at all. */
|
|
147
|
+
this.showStop = true;
|
|
148
|
+
// Recomputed on activation and on every ~1s tick; frozen (not reset) once
|
|
149
|
+
// `active` goes false -- see the class doc's "ticker" paragraph.
|
|
150
|
+
this.elapsedMs = 0;
|
|
151
|
+
this.onStopClick = () => {
|
|
152
|
+
this.emit('lyra-stop');
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
static { this.styles = [LyraElement.styles, styles]; }
|
|
156
|
+
disconnectedCallback() {
|
|
157
|
+
super.disconnectedCallback();
|
|
158
|
+
this.stopTicker();
|
|
159
|
+
}
|
|
160
|
+
// Recomputing `elapsedMs` here (rather than in `updated()`) matters: Lit
|
|
161
|
+
// runs `willUpdate()` *before* render, as part of the same update pass, so
|
|
162
|
+
// a property set here is picked up by this same render with no extra
|
|
163
|
+
// cycle. Setting a reactive property from inside `updated()` instead would
|
|
164
|
+
// schedule a *second* update after the first has already completed (Lit
|
|
165
|
+
// warns about exactly this in dev mode) -- meaning a caller doing
|
|
166
|
+
// `el.active = true; await el.updateComplete;` would still observe the
|
|
167
|
+
// stale pre-activation `elapsedMs` once that first promise resolves.
|
|
168
|
+
//
|
|
169
|
+
// `changed.has('active')` fires on the very first update too when the
|
|
170
|
+
// element mounts already `active` (the parsed-attribute/property value
|
|
171
|
+
// differs from the `false` field-initializer default that was seen first)
|
|
172
|
+
// -- same mechanism `<lyra-stream-status>`'s `onPhaseChanged` relies on to
|
|
173
|
+
// arm its stall timer on a `phase="streaming"` mount, so mounting this
|
|
174
|
+
// component already active correctly seeds `elapsedMs` with no separate
|
|
175
|
+
// first-update special case needed.
|
|
176
|
+
willUpdate(changed) {
|
|
177
|
+
if (changed.has('active') && this.active) {
|
|
178
|
+
if (this.startedAt == null)
|
|
179
|
+
this.fallbackStartMs = Date.now();
|
|
180
|
+
this.elapsedMs = this.computeElapsedMs();
|
|
181
|
+
}
|
|
182
|
+
else if (this.active && changed.has('startedAt')) {
|
|
183
|
+
// A `started-at` that arrives (or changes) mid-generation should
|
|
184
|
+
// immediately re-baseline the displayed elapsed time rather than wait
|
|
185
|
+
// up to ~1s for the next tick.
|
|
186
|
+
this.elapsedMs = this.computeElapsedMs();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Starting/stopping the interval is a genuine side effect (not a reactive-
|
|
190
|
+
// property write), so it belongs in `updated()`, unlike the `elapsedMs`
|
|
191
|
+
// computation above.
|
|
192
|
+
updated(changed) {
|
|
193
|
+
if (changed.has('active')) {
|
|
194
|
+
if (this.active)
|
|
195
|
+
this.startTicker();
|
|
196
|
+
else
|
|
197
|
+
this.stopTicker();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
startTicker() {
|
|
201
|
+
this.stopTicker();
|
|
202
|
+
// Setting `elapsedMs` here (unlike inside `updated()`, see that method's
|
|
203
|
+
// doc) is fine: an interval callback is a wholly separate future task,
|
|
204
|
+
// not a continuation of an in-progress Lit update, so this starts a
|
|
205
|
+
// normal, self-contained update cycle rather than a same-tick "second
|
|
206
|
+
// update" scheduled mid-render.
|
|
207
|
+
this.tickTimer = setInterval(() => {
|
|
208
|
+
this.elapsedMs = this.computeElapsedMs();
|
|
209
|
+
}, 1000);
|
|
210
|
+
}
|
|
211
|
+
stopTicker() {
|
|
212
|
+
if (this.tickTimer !== undefined) {
|
|
213
|
+
clearInterval(this.tickTimer);
|
|
214
|
+
this.tickTimer = undefined;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
computeElapsedMs() {
|
|
218
|
+
const start = this.startedAt ?? this.fallbackStartMs;
|
|
219
|
+
return start == null ? 0 : Math.max(0, Date.now() - start);
|
|
220
|
+
}
|
|
221
|
+
/** `tokens-per-second` when set; otherwise a derived figure once enough
|
|
222
|
+
* elapsed time has accumulated for it to be meaningful; otherwise
|
|
223
|
+
* `undefined` (the throughput segment doesn't render at all). */
|
|
224
|
+
get effectiveTokensPerSecond() {
|
|
225
|
+
if (this.tokensPerSecond != null && Number.isFinite(this.tokensPerSecond)) {
|
|
226
|
+
return this.tokensPerSecond;
|
|
227
|
+
}
|
|
228
|
+
if (this.tokenCount != null && Number.isFinite(this.tokenCount)) {
|
|
229
|
+
const elapsedSeconds = this.elapsedMs / 1000;
|
|
230
|
+
if (elapsedSeconds >= 1)
|
|
231
|
+
return this.tokenCount / elapsedSeconds;
|
|
232
|
+
}
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
render() {
|
|
236
|
+
const hasTokens = this.tokenCount != null && Number.isFinite(this.tokenCount);
|
|
237
|
+
const throughput = this.effectiveTokensPerSecond;
|
|
238
|
+
const hasThroughput = throughput !== undefined;
|
|
239
|
+
return html `
|
|
240
|
+
<div part="base">
|
|
241
|
+
<span part="elapsed">${formatElapsed(this.elapsedMs)}</span>
|
|
242
|
+
${hasTokens ? html `<span part="tokens">${formatTokenCount(this.tokenCount)}</span>` : nothing}
|
|
243
|
+
${hasThroughput ? html `<span part="throughput">${formatThroughput(throughput)}</span>` : nothing}
|
|
244
|
+
${this.showStop
|
|
245
|
+
? html `
|
|
246
|
+
<button part="stop-button" type="button" aria-label="Stop generating" @click=${this.onStopClick}>
|
|
247
|
+
${stopIcon()}
|
|
248
|
+
</button>
|
|
249
|
+
`
|
|
250
|
+
: nothing}
|
|
251
|
+
</div>
|
|
252
|
+
`;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
__decorate([
|
|
256
|
+
property({ type: Boolean, reflect: true })
|
|
257
|
+
], LyraGenerationStatus.prototype, "active", void 0);
|
|
258
|
+
__decorate([
|
|
259
|
+
property({ type: Number, attribute: 'started-at' })
|
|
260
|
+
], LyraGenerationStatus.prototype, "startedAt", void 0);
|
|
261
|
+
__decorate([
|
|
262
|
+
property({ type: Number, attribute: 'token-count' })
|
|
263
|
+
], LyraGenerationStatus.prototype, "tokenCount", void 0);
|
|
264
|
+
__decorate([
|
|
265
|
+
property({ type: Number, attribute: 'tokens-per-second' })
|
|
266
|
+
], LyraGenerationStatus.prototype, "tokensPerSecond", void 0);
|
|
267
|
+
__decorate([
|
|
268
|
+
property({ type: Boolean, attribute: 'show-stop' })
|
|
269
|
+
], LyraGenerationStatus.prototype, "showStop", void 0);
|
|
270
|
+
__decorate([
|
|
271
|
+
state()
|
|
272
|
+
], LyraGenerationStatus.prototype, "elapsedMs", void 0);
|
|
273
|
+
defineElement('generation-status', LyraGenerationStatus);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const styles: import("lit").CSSResult;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
export const styles = css `
|
|
3
|
+
:host {
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
vertical-align: middle;
|
|
6
|
+
max-inline-size: 100%;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
[part='base'] {
|
|
10
|
+
display: inline-flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
max-inline-size: 100%;
|
|
13
|
+
font-size: 0.8125rem;
|
|
14
|
+
line-height: 1.3;
|
|
15
|
+
color: var(--lyra-color-text-quiet);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
[part='elapsed'] {
|
|
19
|
+
/* Full-strength text, not the quieter --lyra-color-text-quiet the rest
|
|
20
|
+
of the readout uses -- elapsed time is the one figure this component
|
|
21
|
+
always shows (tokens/throughput are optional), so it gets the higher-
|
|
22
|
+
contrast treatment to read as the primary value at a glance. */
|
|
23
|
+
color: var(--lyra-color-text);
|
|
24
|
+
font-variant-numeric: tabular-nums;
|
|
25
|
+
white-space: nowrap;
|
|
26
|
+
}
|
|
27
|
+
[part='tokens'],
|
|
28
|
+
[part='throughput'] {
|
|
29
|
+
font-variant-numeric: tabular-nums;
|
|
30
|
+
white-space: nowrap;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Segments are joined with a middot rather than a flex gap + separate
|
|
34
|
+
separator element, so a segment that doesn't render (tokens/throughput
|
|
35
|
+
are both optional, see the class doc) never leaves a dangling
|
|
36
|
+
double-gap -- the dot only ever appears immediately before a segment
|
|
37
|
+
that's actually present. */
|
|
38
|
+
[part='tokens']::before,
|
|
39
|
+
[part='throughput']::before {
|
|
40
|
+
content: '·';
|
|
41
|
+
margin-inline: 0.4em;
|
|
42
|
+
opacity: 0.6;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
[part='stop-button'] {
|
|
46
|
+
flex: 0 0 auto;
|
|
47
|
+
display: inline-flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
justify-content: center;
|
|
50
|
+
/* Same "shrink the shared icon-button token for a compact inline
|
|
51
|
+
control" idiom as lyra-attachment-chip's retry-/remove-button. */
|
|
52
|
+
min-inline-size: min(var(--lyra-icon-button-size), 1.75rem);
|
|
53
|
+
min-block-size: min(var(--lyra-icon-button-size), 1.75rem);
|
|
54
|
+
margin-inline-start: var(--lyra-space-s);
|
|
55
|
+
padding: 0;
|
|
56
|
+
border: 1px solid var(--lyra-color-border);
|
|
57
|
+
border-radius: 50%;
|
|
58
|
+
background: var(--lyra-color-surface);
|
|
59
|
+
color: var(--lyra-color-text);
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
-webkit-tap-highlight-color: transparent;
|
|
62
|
+
transition:
|
|
63
|
+
background-color var(--lyra-transition-fast),
|
|
64
|
+
border-color var(--lyra-transition-fast),
|
|
65
|
+
color var(--lyra-transition-fast);
|
|
66
|
+
}
|
|
67
|
+
[part='stop-button']:hover {
|
|
68
|
+
border-color: var(--lyra-color-brand);
|
|
69
|
+
color: var(--lyra-color-brand);
|
|
70
|
+
}
|
|
71
|
+
[part='stop-button']:focus-visible {
|
|
72
|
+
outline: var(--lyra-focus-ring-width) solid var(--lyra-focus-ring-color);
|
|
73
|
+
outline-offset: var(--lyra-focus-ring-offset);
|
|
74
|
+
}
|
|
75
|
+
[part='stop-button'] svg {
|
|
76
|
+
display: block;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@media (prefers-reduced-motion: reduce) {
|
|
80
|
+
[part='stop-button'] {
|
|
81
|
+
transition: none !important;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
`;
|