@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
|
@@ -8,7 +8,7 @@ import { html, nothing } from 'lit';
|
|
|
8
8
|
import { property } from 'lit/decorators.js';
|
|
9
9
|
import { repeat } from 'lit/directives/repeat.js';
|
|
10
10
|
import { LyraElement } from '../../internal/lyra-element.js';
|
|
11
|
-
import { defineElement } from '../../internal/prefix.js';
|
|
11
|
+
import { defineElement, tag } from '../../internal/prefix.js';
|
|
12
12
|
import { chevronIcon } from '../../internal/icons.js';
|
|
13
13
|
import { css } from 'lit';
|
|
14
14
|
import { cascadeUpdateComplete } from './update-cascade.js';
|
|
@@ -89,7 +89,7 @@ const styles = css `
|
|
|
89
89
|
*
|
|
90
90
|
* @customElement lyra-tree-node
|
|
91
91
|
* @event lyra-node-toggle - `detail: { id, expanded }`, fired when this node is expanded or collapsed (via `expand()`/`collapse()`, the toggle button, or ArrowRight/ArrowLeft).
|
|
92
|
-
* @event lyra-node-select - `detail: { id }`, fired when this node's primary action is activated (via `select()`, clicking its
|
|
92
|
+
* @event lyra-node-select - `detail: { id }`, fired when this node's primary action is activated (via `select()`, clicking anywhere in its row, or Enter/Space).
|
|
93
93
|
* @csspart row, toggle, label, badge
|
|
94
94
|
*/
|
|
95
95
|
export class LyraTreeNode extends LyraElement {
|
|
@@ -145,19 +145,29 @@ export class LyraTreeNode extends LyraElement {
|
|
|
145
145
|
this.expanded = false;
|
|
146
146
|
this.emit('lyra-node-toggle', { id: this.item.id, expanded: false });
|
|
147
147
|
}
|
|
148
|
-
/**
|
|
148
|
+
/**
|
|
149
|
+
* Fire this item's primary "select" action (Enter/Space, or clicking
|
|
150
|
+
* anywhere in the row). Emits *before* calling `.focus()`: `<lyra-tree>`'s
|
|
151
|
+
* `onNodeActivate` listener for `lyra-node-select` runs synchronously
|
|
152
|
+
* (native `dispatchEvent` is sync) and updates `activeId`, which pushes
|
|
153
|
+
* `tabIndex = 0` down onto this node via its own render -- calling
|
|
154
|
+
* `.focus()` after that emit, rather than before, means real DOM focus
|
|
155
|
+
* lands correctly the very first time a previously-inactive node is
|
|
156
|
+
* clicked, not one render late.
|
|
157
|
+
*/
|
|
149
158
|
select() {
|
|
150
159
|
this.emit('lyra-node-select', { id: this.item.id });
|
|
160
|
+
this.focus();
|
|
151
161
|
}
|
|
152
162
|
/** See `cascadeUpdateComplete` and the matching override on `<lyra-tree>`. */
|
|
153
163
|
async getUpdateComplete() {
|
|
154
164
|
const result = await super.getUpdateComplete();
|
|
155
|
-
await cascadeUpdateComplete(this.shadowRoot?.querySelectorAll('
|
|
165
|
+
await cascadeUpdateComplete([...(this.shadowRoot?.querySelectorAll(tag('tree-node')) ?? [])]);
|
|
156
166
|
return result;
|
|
157
167
|
}
|
|
158
168
|
render() {
|
|
159
169
|
return html `
|
|
160
|
-
<div part="row" style=${`--lyra-tree-depth:${this.depth}`}>
|
|
170
|
+
<div part="row" style=${`--lyra-tree-depth:${this.depth}`} @click=${() => this.select()}>
|
|
161
171
|
<button
|
|
162
172
|
part="toggle"
|
|
163
173
|
type="button"
|
|
@@ -172,7 +182,7 @@ export class LyraTreeNode extends LyraElement {
|
|
|
172
182
|
>
|
|
173
183
|
${this.hasChildren ? chevronIcon() : nothing}
|
|
174
184
|
</button>
|
|
175
|
-
<span part="label"
|
|
185
|
+
<span part="label">${this.item.label}</span>
|
|
176
186
|
${this.item.badge != null ? html `<span part="badge">${this.item.badge}</span>` : nothing}
|
|
177
187
|
</div>
|
|
178
188
|
${this.expanded && this.hasChildren
|
|
@@ -94,8 +94,14 @@ export declare class LyraTree extends LyraElement {
|
|
|
94
94
|
*/
|
|
95
95
|
protected getUpdateComplete(): Promise<boolean>;
|
|
96
96
|
private onTreeKeyDown;
|
|
97
|
-
/**
|
|
98
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Expand every node in the tree, recursively. Resolves once every
|
|
99
|
+
* descendant has actually finished expanding (not just had `expanded` set)
|
|
100
|
+
* -- callers that immediately read `visibleNodeElements()`-derived state
|
|
101
|
+
* (or call `collapseAll()` right after) should `await` this instead of
|
|
102
|
+
* firing it and moving on.
|
|
103
|
+
*/
|
|
104
|
+
expandAll(): Promise<void>;
|
|
99
105
|
/**
|
|
100
106
|
* Collapse every node in the tree, recursively. Goes through each node's
|
|
101
107
|
* own `collapse()` (rather than assigning `expanded` directly) so its
|
|
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { html, nothing } from 'lit';
|
|
8
8
|
import { property, state } from 'lit/decorators.js';
|
|
9
9
|
import { LyraElement } from '../../internal/lyra-element.js';
|
|
10
|
-
import { defineElement } from '../../internal/prefix.js';
|
|
10
|
+
import { defineElement, tag } from '../../internal/prefix.js';
|
|
11
11
|
import { isRtl } from '../../internal/rtl.js';
|
|
12
12
|
import { styles } from './tree.styles.js';
|
|
13
13
|
import { cascadeUpdateComplete } from './update-cascade.js';
|
|
@@ -133,10 +133,10 @@ export class LyraTree extends LyraElement {
|
|
|
133
133
|
}
|
|
134
134
|
static { this.styles = [LyraElement.styles, styles]; }
|
|
135
135
|
get nodeElements() {
|
|
136
|
-
return [...this.querySelectorAll('
|
|
136
|
+
return [...this.querySelectorAll(tag('tree-node'))];
|
|
137
137
|
}
|
|
138
138
|
childrenOf(node) {
|
|
139
|
-
return [...(node.shadowRoot?.querySelectorAll('
|
|
139
|
+
return [...(node.shadowRoot?.querySelectorAll(tag('tree-node')) ?? [])];
|
|
140
140
|
}
|
|
141
141
|
invalidateVisibleCache() {
|
|
142
142
|
this.cachedVisible = null;
|
|
@@ -206,7 +206,7 @@ export class LyraTree extends LyraElement {
|
|
|
206
206
|
let previousSibling = null;
|
|
207
207
|
for (const item of this.data) {
|
|
208
208
|
const reused = !seen.has(item.id) ? existingById.get(item.id) : undefined;
|
|
209
|
-
const node = reused ?? document.createElement('
|
|
209
|
+
const node = reused ?? document.createElement(tag('tree-node'));
|
|
210
210
|
node.item = item;
|
|
211
211
|
node.depth = 0;
|
|
212
212
|
seen.add(item.id);
|
|
@@ -263,16 +263,23 @@ export class LyraTree extends LyraElement {
|
|
|
263
263
|
}
|
|
264
264
|
return result;
|
|
265
265
|
}
|
|
266
|
-
/**
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
266
|
+
/**
|
|
267
|
+
* Expand every node in the tree, recursively. Resolves once every
|
|
268
|
+
* descendant has actually finished expanding (not just had `expanded` set)
|
|
269
|
+
* -- callers that immediately read `visibleNodeElements()`-derived state
|
|
270
|
+
* (or call `collapseAll()` right after) should `await` this instead of
|
|
271
|
+
* firing it and moving on.
|
|
272
|
+
*/
|
|
273
|
+
async expandAll() {
|
|
274
|
+
const setAll = async (nodes) => {
|
|
275
|
+
await Promise.all(nodes.map(async (n) => {
|
|
270
276
|
n.expanded = true;
|
|
271
277
|
this.invalidateVisibleCache();
|
|
272
|
-
|
|
273
|
-
|
|
278
|
+
await n.updateComplete;
|
|
279
|
+
await setAll(this.childrenOf(n));
|
|
280
|
+
}));
|
|
274
281
|
};
|
|
275
|
-
setAll(this.nodeElements);
|
|
282
|
+
await setAll(this.nodeElements);
|
|
276
283
|
}
|
|
277
284
|
/**
|
|
278
285
|
* Collapse every node in the tree, recursively. Goes through each node's
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type TemplateResult, type PropertyValues } from 'lit';
|
|
2
|
+
import { LyraElement } from '../../internal/lyra-element.js';
|
|
3
|
+
export type TypingIndicatorVariant = 'dots' | 'pulse' | 'cursor';
|
|
4
|
+
export type TypingIndicatorSize = 'sm' | 'md';
|
|
5
|
+
/**
|
|
6
|
+
* `<lyra-typing-indicator>` — a purely presentational "assistant is
|
|
7
|
+
* responding" presence cue. No events, no interactivity: a consumer mounts
|
|
8
|
+
* it while a response is being generated and removes it (or hides it) once
|
|
9
|
+
* real content has arrived.
|
|
10
|
+
*
|
|
11
|
+
* Three visual variants share one component rather than three separate tags
|
|
12
|
+
* because callers pick between them along a single axis — how the
|
|
13
|
+
* surrounding surface wants the cue to read — and nothing else about the
|
|
14
|
+
* component differs:
|
|
15
|
+
* - `dots` (default) — three dots with a staggered bounce, the classic
|
|
16
|
+
* "typing…" affordance for a standalone status line.
|
|
17
|
+
* - `pulse` — a single breathing dot, a quieter cue for a tighter space
|
|
18
|
+
* (e.g. next to an avatar).
|
|
19
|
+
* - `cursor` — a blinking vertical bar, meant to sit inline at the tail end
|
|
20
|
+
* of streamed text that is still being appended to.
|
|
21
|
+
*
|
|
22
|
+
* Accessibility: this indicator typically mounts and unmounts around a real
|
|
23
|
+
* generation lifecycle (appears when a response starts, disappears once one
|
|
24
|
+
* arrives) rather than emitting a stream of updates of its own, so it does
|
|
25
|
+
* *not* route through `<lyra-live-region>`/`Announcer`
|
|
26
|
+
* (`../../internal/announcer.js`) — that machinery exists to coalesce many
|
|
27
|
+
* rapidly-changing announcements into one, and there is only ever a single
|
|
28
|
+
* announcement here: the mount itself. A plain `role="status"` plus an
|
|
29
|
+
* accessible name derived from `label` is sufficient, set both as an
|
|
30
|
+
* `aria-label` on the host *and* as a visually-hidden text node in the
|
|
31
|
+
* shadow tree, so the name survives even if only one of the two is picked up
|
|
32
|
+
* by a given assistive-tech/browser pairing. The animated dots/pulse/cursor
|
|
33
|
+
* shape is `aria-hidden="true"` — it's decorative; `label` is the entire
|
|
34
|
+
* accessible content, so nothing narrates individual animation frames.
|
|
35
|
+
*
|
|
36
|
+
* @customElement lyra-typing-indicator
|
|
37
|
+
* @csspart base - The decorative (`aria-hidden`) wrapper around the animated shape.
|
|
38
|
+
* @csspart dot - Each of the three dots in the `dots` variant.
|
|
39
|
+
* @csspart pulse - The single pulsing dot in the `pulse` variant.
|
|
40
|
+
* @csspart cursor - The blinking bar in the `cursor` variant.
|
|
41
|
+
*/
|
|
42
|
+
export declare class LyraTypingIndicator extends LyraElement {
|
|
43
|
+
static styles: import("lit").CSSResultGroup[];
|
|
44
|
+
/** Which decorative presentation to render. */
|
|
45
|
+
variant: TypingIndicatorVariant;
|
|
46
|
+
/** Accessible name, exposed via `role="status"`. Not re-announced on every
|
|
47
|
+
* animation frame — only mount (and any later change to this property)
|
|
48
|
+
* produces a new announcement. */
|
|
49
|
+
label: string;
|
|
50
|
+
/** Compact sizing for dense layouts (e.g. inline with a message bubble). */
|
|
51
|
+
size: TypingIndicatorSize;
|
|
52
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
53
|
+
render(): TemplateResult;
|
|
54
|
+
private renderShape;
|
|
55
|
+
}
|
|
56
|
+
declare global {
|
|
57
|
+
interface HTMLElementTagNameMap {
|
|
58
|
+
'lyra-typing-indicator': LyraTypingIndicator;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
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 } from 'lit';
|
|
8
|
+
import { property } from 'lit/decorators.js';
|
|
9
|
+
import { LyraElement } from '../../internal/lyra-element.js';
|
|
10
|
+
import { defineElement } from '../../internal/prefix.js';
|
|
11
|
+
import { srOnly } from '../../internal/a11y.js';
|
|
12
|
+
import { styles } from './typing-indicator.styles.js';
|
|
13
|
+
/**
|
|
14
|
+
* `<lyra-typing-indicator>` — a purely presentational "assistant is
|
|
15
|
+
* responding" presence cue. No events, no interactivity: a consumer mounts
|
|
16
|
+
* it while a response is being generated and removes it (or hides it) once
|
|
17
|
+
* real content has arrived.
|
|
18
|
+
*
|
|
19
|
+
* Three visual variants share one component rather than three separate tags
|
|
20
|
+
* because callers pick between them along a single axis — how the
|
|
21
|
+
* surrounding surface wants the cue to read — and nothing else about the
|
|
22
|
+
* component differs:
|
|
23
|
+
* - `dots` (default) — three dots with a staggered bounce, the classic
|
|
24
|
+
* "typing…" affordance for a standalone status line.
|
|
25
|
+
* - `pulse` — a single breathing dot, a quieter cue for a tighter space
|
|
26
|
+
* (e.g. next to an avatar).
|
|
27
|
+
* - `cursor` — a blinking vertical bar, meant to sit inline at the tail end
|
|
28
|
+
* of streamed text that is still being appended to.
|
|
29
|
+
*
|
|
30
|
+
* Accessibility: this indicator typically mounts and unmounts around a real
|
|
31
|
+
* generation lifecycle (appears when a response starts, disappears once one
|
|
32
|
+
* arrives) rather than emitting a stream of updates of its own, so it does
|
|
33
|
+
* *not* route through `<lyra-live-region>`/`Announcer`
|
|
34
|
+
* (`../../internal/announcer.js`) — that machinery exists to coalesce many
|
|
35
|
+
* rapidly-changing announcements into one, and there is only ever a single
|
|
36
|
+
* announcement here: the mount itself. A plain `role="status"` plus an
|
|
37
|
+
* accessible name derived from `label` is sufficient, set both as an
|
|
38
|
+
* `aria-label` on the host *and* as a visually-hidden text node in the
|
|
39
|
+
* shadow tree, so the name survives even if only one of the two is picked up
|
|
40
|
+
* by a given assistive-tech/browser pairing. The animated dots/pulse/cursor
|
|
41
|
+
* shape is `aria-hidden="true"` — it's decorative; `label` is the entire
|
|
42
|
+
* accessible content, so nothing narrates individual animation frames.
|
|
43
|
+
*
|
|
44
|
+
* @customElement lyra-typing-indicator
|
|
45
|
+
* @csspart base - The decorative (`aria-hidden`) wrapper around the animated shape.
|
|
46
|
+
* @csspart dot - Each of the three dots in the `dots` variant.
|
|
47
|
+
* @csspart pulse - The single pulsing dot in the `pulse` variant.
|
|
48
|
+
* @csspart cursor - The blinking bar in the `cursor` variant.
|
|
49
|
+
*/
|
|
50
|
+
export class LyraTypingIndicator extends LyraElement {
|
|
51
|
+
constructor() {
|
|
52
|
+
super(...arguments);
|
|
53
|
+
/** Which decorative presentation to render. */
|
|
54
|
+
this.variant = 'dots';
|
|
55
|
+
/** Accessible name, exposed via `role="status"`. Not re-announced on every
|
|
56
|
+
* animation frame — only mount (and any later change to this property)
|
|
57
|
+
* produces a new announcement. */
|
|
58
|
+
this.label = 'Thinking…';
|
|
59
|
+
/** Compact sizing for dense layouts (e.g. inline with a message bubble). */
|
|
60
|
+
this.size = 'md';
|
|
61
|
+
}
|
|
62
|
+
static { this.styles = [LyraElement.styles, styles, srOnly]; }
|
|
63
|
+
willUpdate(changed) {
|
|
64
|
+
this.setAttribute('role', 'status');
|
|
65
|
+
if (changed.has('label')) {
|
|
66
|
+
this.setAttribute('aria-label', this.label);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
render() {
|
|
70
|
+
return html `
|
|
71
|
+
<span part="base" aria-hidden="true">${this.renderShape()}</span>
|
|
72
|
+
<span class="sr-only">${this.label}</span>
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
renderShape() {
|
|
76
|
+
switch (this.variant) {
|
|
77
|
+
case 'pulse':
|
|
78
|
+
return html `<span part="pulse"></span>`;
|
|
79
|
+
case 'cursor':
|
|
80
|
+
return html `<span part="cursor"></span>`;
|
|
81
|
+
case 'dots':
|
|
82
|
+
default:
|
|
83
|
+
return html `<span part="dot"></span><span part="dot"></span><span part="dot"></span>`;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
__decorate([
|
|
88
|
+
property({ reflect: true })
|
|
89
|
+
], LyraTypingIndicator.prototype, "variant", void 0);
|
|
90
|
+
__decorate([
|
|
91
|
+
property()
|
|
92
|
+
], LyraTypingIndicator.prototype, "label", void 0);
|
|
93
|
+
__decorate([
|
|
94
|
+
property({ reflect: true })
|
|
95
|
+
], LyraTypingIndicator.prototype, "size", void 0);
|
|
96
|
+
defineElement('typing-indicator', LyraTypingIndicator);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const styles: import("lit").CSSResult;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
// `--lyra-transition-base` is used (rather than `--lyra-transition-fast`) as
|
|
3
|
+
// the animation-cycle length for every variant below: it's the token the
|
|
4
|
+
// rest of the library reserves for slightly-more-noticeable motion (gauge
|
|
5
|
+
// fill, dialog/popover open), whereas `-fast` is reserved for snappy
|
|
6
|
+
// discrete state flips (checkbox check, switch thumb). A continuous ambient
|
|
7
|
+
// loop reads calmer at the longer of the two. Note this token is a *compound*
|
|
8
|
+
// value (`180ms ease-out`, duration + timing-function together, exactly like
|
|
9
|
+
// every `transition:` shorthand elsewhere in this library) so it can only
|
|
10
|
+
// ever be spliced into the `animation:` *shorthand* below, never assigned to
|
|
11
|
+
// `animation-duration` alone -- that longhand requires a bare `<time>` and
|
|
12
|
+
// would silently invalidate (collapsing the duration to 0) if given the
|
|
13
|
+
// compound value. For the same reason no extra timing-function keyword can
|
|
14
|
+
// follow it in the shorthand: the token already supplies one.
|
|
15
|
+
export const styles = css `
|
|
16
|
+
:host {
|
|
17
|
+
display: inline-flex;
|
|
18
|
+
align-items: center;
|
|
19
|
+
vertical-align: middle;
|
|
20
|
+
line-height: 1;
|
|
21
|
+
--lyra-typing-dot-size: 0.5rem;
|
|
22
|
+
--lyra-typing-gap: 0.25rem;
|
|
23
|
+
--lyra-typing-cursor-width: 0.125rem;
|
|
24
|
+
--lyra-typing-cursor-height: 1em;
|
|
25
|
+
}
|
|
26
|
+
:host([size='sm']) {
|
|
27
|
+
--lyra-typing-dot-size: 0.375rem;
|
|
28
|
+
--lyra-typing-gap: 0.1875rem;
|
|
29
|
+
--lyra-typing-cursor-width: 0.09375rem;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
[part='base'] {
|
|
33
|
+
display: inline-flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
gap: var(--lyra-typing-gap);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* -- dots -------------------------------------------------------------- */
|
|
39
|
+
[part='dot'] {
|
|
40
|
+
inline-size: var(--lyra-typing-dot-size);
|
|
41
|
+
block-size: var(--lyra-typing-dot-size);
|
|
42
|
+
border-radius: 50%;
|
|
43
|
+
background: currentColor;
|
|
44
|
+
opacity: 0.5;
|
|
45
|
+
animation: lyra-typing-dot-bounce var(--lyra-transition-base) infinite;
|
|
46
|
+
}
|
|
47
|
+
/* Fixed (not token-derived) stagger offsets -- --lyra-transition-base is
|
|
48
|
+
a compound "duration timing-function" value like every other transition
|
|
49
|
+
token in this library, so it can't be decomposed via calc() to derive a
|
|
50
|
+
fraction of just its duration; these two delays approximate a third and
|
|
51
|
+
two-thirds of that token's own fallback duration. */
|
|
52
|
+
[part='dot']:nth-child(2) {
|
|
53
|
+
animation-delay: 60ms;
|
|
54
|
+
}
|
|
55
|
+
[part='dot']:nth-child(3) {
|
|
56
|
+
animation-delay: 120ms;
|
|
57
|
+
}
|
|
58
|
+
@keyframes lyra-typing-dot-bounce {
|
|
59
|
+
0%,
|
|
60
|
+
80%,
|
|
61
|
+
100% {
|
|
62
|
+
transform: translateY(0);
|
|
63
|
+
opacity: 0.5;
|
|
64
|
+
}
|
|
65
|
+
40% {
|
|
66
|
+
transform: translateY(-35%);
|
|
67
|
+
opacity: 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* -- pulse --------------------------------------------------------------
|
|
72
|
+
A single breathing dot, meant for tighter spaces than three dots allow. */
|
|
73
|
+
[part='pulse'] {
|
|
74
|
+
inline-size: var(--lyra-typing-dot-size);
|
|
75
|
+
block-size: var(--lyra-typing-dot-size);
|
|
76
|
+
border-radius: 50%;
|
|
77
|
+
background: currentColor;
|
|
78
|
+
opacity: 1;
|
|
79
|
+
transform: scale(1);
|
|
80
|
+
animation: lyra-typing-pulse var(--lyra-transition-base) infinite;
|
|
81
|
+
}
|
|
82
|
+
@keyframes lyra-typing-pulse {
|
|
83
|
+
0%,
|
|
84
|
+
100% {
|
|
85
|
+
transform: scale(0.85);
|
|
86
|
+
opacity: 0.55;
|
|
87
|
+
}
|
|
88
|
+
50% {
|
|
89
|
+
transform: scale(1);
|
|
90
|
+
opacity: 1;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/* -- cursor -------------------------------------------------------------
|
|
95
|
+
A blinking vertical bar for inline placement at the tail of streamed
|
|
96
|
+
text. The two adjacent keyframe stops (49% / 50%) hold identical values
|
|
97
|
+
either side of an instant flip, so the blink still reads as a sharp
|
|
98
|
+
on/off even though the token's ease-out timing-function is in effect
|
|
99
|
+
across the whole animation. */
|
|
100
|
+
[part='cursor'] {
|
|
101
|
+
inline-size: var(--lyra-typing-cursor-width);
|
|
102
|
+
block-size: var(--lyra-typing-cursor-height);
|
|
103
|
+
background: currentColor;
|
|
104
|
+
border-radius: var(--lyra-typing-cursor-width);
|
|
105
|
+
opacity: 1;
|
|
106
|
+
animation: lyra-typing-cursor-blink var(--lyra-transition-base) infinite;
|
|
107
|
+
}
|
|
108
|
+
@keyframes lyra-typing-cursor-blink {
|
|
109
|
+
0%,
|
|
110
|
+
49% {
|
|
111
|
+
opacity: 1;
|
|
112
|
+
}
|
|
113
|
+
50%,
|
|
114
|
+
100% {
|
|
115
|
+
opacity: 0;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* Every variant collapses to its plain, fully-visible resting state
|
|
120
|
+
under reduced motion -- never a static mid-animation frame (e.g. a
|
|
121
|
+
permanently-invisible cursor, had the blink's "off" half been frozen
|
|
122
|
+
instead). */
|
|
123
|
+
@media (prefers-reduced-motion: reduce) {
|
|
124
|
+
[part='dot'],
|
|
125
|
+
[part='pulse'],
|
|
126
|
+
[part='cursor'] {
|
|
127
|
+
animation: none !important;
|
|
128
|
+
opacity: 1;
|
|
129
|
+
transform: none;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
`;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { type TemplateResult, type PropertyValues } from 'lit';
|
|
2
|
+
import { LyraElement } from '../../internal/lyra-element.js';
|
|
3
|
+
/** `lyra-visible-range-changed` detail -- the current visible (non-overscanned) item index range. */
|
|
4
|
+
export interface VirtualListRange {
|
|
5
|
+
start: number;
|
|
6
|
+
end: number;
|
|
7
|
+
}
|
|
8
|
+
/** Placeholder for a later phase's sticky-header sectioning feature -- see the class doc. */
|
|
9
|
+
export interface VirtualListGroup {
|
|
10
|
+
key: string | number;
|
|
11
|
+
label?: string;
|
|
12
|
+
startIndex: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* `<lyra-virtual-list>` — a generic windowed/virtualized list host. Renders
|
|
16
|
+
* only the items within the current viewport (plus `overscan` padding rows
|
|
17
|
+
* on each side) as real DOM, regardless of how large `items` is, so a
|
|
18
|
+
* multi-thousand-row chat history sidebar (or, in a later phase, a long
|
|
19
|
+
* message thread) stays cheap to scroll.
|
|
20
|
+
*
|
|
21
|
+
* Content is entirely caller-supplied: `renderItem(item, index)` returns
|
|
22
|
+
* whatever `lit-html` value should represent that row (typically a
|
|
23
|
+
* `TemplateResult`), and `keyFunction(item, index)` gives it a stable
|
|
24
|
+
* identity for `repeat()`'s DOM-reconciliation key, so scroll position and
|
|
25
|
+
* any per-row state (e.g. an `<audio>` element's playback position) survive
|
|
26
|
+
* an `items` mutation instead of every row remounting from scratch.
|
|
27
|
+
*
|
|
28
|
+
* **Windowing math.** Every row — in both `row-height` modes — is positioned
|
|
29
|
+
* by a `transform: translateY(offset)` computed from a single cumulative
|
|
30
|
+
* `offsets` array (`offsets[i]` = the pixel top of row `i`), rather than by
|
|
31
|
+
* page flow. This is what lets only a small DOM window exist while the
|
|
32
|
+
* scrollbar still reflects the *true* total content height:
|
|
33
|
+
* - **`row-height="auto"` (default).** Each currently-rendered row is
|
|
34
|
+
* watched by a `ResizeObserver`; its real height lands in a per-key
|
|
35
|
+
* `Map`, and any row not yet measured contributes `DEFAULT_ROW_ESTIMATE_PX`
|
|
36
|
+
* to the offsets array until it has been. `offsets` is *not* the same
|
|
37
|
+
* thing as a page-count-based `padding-top`/`padding-bottom` spacer pair —
|
|
38
|
+
* that approach reflows every unmeasured row's position on every new
|
|
39
|
+
* measurement, which is exactly what per-row transform offsets avoid: only
|
|
40
|
+
* the rows *after* a newly-measured one shift, and even that shift is a
|
|
41
|
+
* cheap style recompute, not a layout-affecting padding change.
|
|
42
|
+
* - **Fixed numeric `row-height`.** No measurement needed — `offsets[i]` is
|
|
43
|
+
* just `i * rowHeightPx`, computed by the exact same cumulative-array code
|
|
44
|
+
* path (a dedicated "single spacer + start-index" special case was
|
|
45
|
+
* considered and would work too, but reusing one code path for both modes
|
|
46
|
+
* avoids maintaining two parallel rendering strategies for a difference
|
|
47
|
+
* that's otherwise just "how is row *i*'s height looked up").
|
|
48
|
+
*
|
|
49
|
+
* The `offsets` array is rebuilt on every update. For the list sizes this
|
|
50
|
+
* component is meant for (a scrollable history sidebar, realistically
|
|
51
|
+
* hundreds to a few thousand rows) that's a trivial `O(n)` arithmetic loop,
|
|
52
|
+
* even at scroll-driven ~60fps; it is *not* the right approach for a
|
|
53
|
+
* hundred-thousand-row list without further work (e.g. a Fenwick/segment
|
|
54
|
+
* tree for `O(log n)` offset queries+updates), which is out of scope here.
|
|
55
|
+
*
|
|
56
|
+
* **Accessibility.** The scroll container is `role="list"` and each rendered
|
|
57
|
+
* row is `role="listitem"`, deliberately *not* `listbox`/`option` — this
|
|
58
|
+
* component only provides windowing, not the roving-tabindex/
|
|
59
|
+
* `aria-activedescendant` keyboard-interaction contract ARIA requires
|
|
60
|
+
* alongside a real `listbox`. A consumer that wants full single-select
|
|
61
|
+
* listbox semantics on top of this should compose that behavior itself (see
|
|
62
|
+
* `<lyra-select>`'s pattern), the same way this component's `active-id`
|
|
63
|
+
* only *scrolls* the matching row into view and marks it `aria-current` —
|
|
64
|
+
* it never claims to be a selection widget. `aria-setsize`/`aria-posinset`
|
|
65
|
+
* are computed from the row's real index in the full `items` array (not its
|
|
66
|
+
* position among the currently-rendered DOM window), so a screen reader
|
|
67
|
+
* still announces e.g. "item 12 of 340" correctly. `[part="base"]` itself
|
|
68
|
+
* carries `tabindex="0"` — `renderItem`'s content is caller-supplied and not
|
|
69
|
+
* guaranteed to contain a focusable element, and a scrollable region with no
|
|
70
|
+
* focusable content of its own is otherwise unreachable by keyboard (native
|
|
71
|
+
* arrow/Page Up/Page Down scrolling included).
|
|
72
|
+
*
|
|
73
|
+
* **Grouping.** `groups` is accepted for forward API compatibility with a
|
|
74
|
+
* later phase's sticky-header sectioning feature (paired with a
|
|
75
|
+
* `groupByRecency()` helper that doesn't exist yet) but is not read or
|
|
76
|
+
* rendered by this pass — every row still renders flat, in `items` order.
|
|
77
|
+
*
|
|
78
|
+
* @customElement lyra-virtual-list
|
|
79
|
+
* @event lyra-load-more - Fired once per approach to the bottom of the list
|
|
80
|
+
* while `has-more` is true and `loading` is false. Deliberately does not
|
|
81
|
+
* refire on every scroll tick while still near the bottom (`loading`
|
|
82
|
+
* gates the in-flight case; scrolling back away from the bottom and
|
|
83
|
+
* returning, or `items` growing enough to move the window away from the
|
|
84
|
+
* end, re-arms it) — a consumer wanting an automatic retry after a failed
|
|
85
|
+
* fetch should surface its own retry affordance rather than relying on
|
|
86
|
+
* this firing again unprompted.
|
|
87
|
+
* @event lyra-visible-range-changed - `detail: { start, end }` (see
|
|
88
|
+
* `VirtualListRange`) — the current visible (non-overscanned) item index
|
|
89
|
+
* range, fired only when it actually changes.
|
|
90
|
+
* @csspart base - The scrollable container (`role="list"`).
|
|
91
|
+
* @csspart spacer - The full-content-height inner element that gives the
|
|
92
|
+
* container its true scrollable extent.
|
|
93
|
+
* @csspart row - One rendered row's absolutely-positioned wrapper
|
|
94
|
+
* (`role="listitem"`); `renderItem`'s return value renders inside it.
|
|
95
|
+
*/
|
|
96
|
+
export declare class LyraVirtualList extends LyraElement {
|
|
97
|
+
static styles: import("lit").CSSResultGroup[];
|
|
98
|
+
/** The full (non-windowed) item collection. */
|
|
99
|
+
items: unknown[];
|
|
100
|
+
/** Renders one row's content — typically returns a `lit-html` `TemplateResult`. */
|
|
101
|
+
renderItem: (item: unknown, index: number) => unknown;
|
|
102
|
+
/** Derives a row's stable `repeat()` key. Falls back to the item's index
|
|
103
|
+
* in `items` when omitted, which is only a safe identity while `items`
|
|
104
|
+
* never reorders/inserts/removes — provide this whenever it can, or
|
|
105
|
+
* scroll position and any per-row DOM state can attach to the wrong row
|
|
106
|
+
* across a mutation (same caveat as `<lyra-table>`'s `rowKey`). */
|
|
107
|
+
keyFunction?: (item: unknown, index: number) => string | number;
|
|
108
|
+
/** Reserved for a later phase's sticky-header sectioning — accepted but not yet rendered. See the class doc. */
|
|
109
|
+
groups?: VirtualListGroup[];
|
|
110
|
+
/** `'auto'` (default) measures each row's real height via `ResizeObserver`;
|
|
111
|
+
* a numeric string fixes every row to that many pixels. */
|
|
112
|
+
rowHeight: string;
|
|
113
|
+
/** Extra rows rendered beyond the visible viewport on each side, to reduce blank-frame risk during fast scrolling. */
|
|
114
|
+
overscan: number;
|
|
115
|
+
/** When set and it matches a row's `keyFunction` result, that row is smoothly scrolled into view whenever this changes. */
|
|
116
|
+
activeId: string;
|
|
117
|
+
loading: boolean;
|
|
118
|
+
/** When true, scrolling near the bottom fires `lyra-load-more`. */
|
|
119
|
+
hasMore: boolean;
|
|
120
|
+
private containerScrollTop;
|
|
121
|
+
private viewportHeight;
|
|
122
|
+
/** `offsets[i]` = row `i`'s pixel top; `offsets[items.length]` = total content height. Rebuilt every update. */
|
|
123
|
+
private offsets;
|
|
124
|
+
/** Parsed `rowHeight`: a positive pixel number, or `null` for `'auto'` (measured) mode. */
|
|
125
|
+
private fixedRowHeight;
|
|
126
|
+
/** `row-height="auto"` per-row measured heights, keyed by `String(keyFunction(item, index))`. */
|
|
127
|
+
private readonly measuredHeights;
|
|
128
|
+
private renderStart;
|
|
129
|
+
private renderEnd;
|
|
130
|
+
private visibleStart;
|
|
131
|
+
private visibleEnd;
|
|
132
|
+
private lastEmittedStart;
|
|
133
|
+
private lastEmittedEnd;
|
|
134
|
+
/** Re-armed whenever the window moves away from the end of `items` -- see the `lyra-load-more` event doc. */
|
|
135
|
+
private loadMoreArmed;
|
|
136
|
+
private isFirstUpdate;
|
|
137
|
+
private rowResizeObserver?;
|
|
138
|
+
private containerResizeObserver?;
|
|
139
|
+
private readonly observedRows;
|
|
140
|
+
private scrollRafId?;
|
|
141
|
+
private pendingScrollTop;
|
|
142
|
+
connectedCallback(): void;
|
|
143
|
+
disconnectedCallback(): void;
|
|
144
|
+
firstUpdated(): void;
|
|
145
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
146
|
+
protected updated(changed: PropertyValues): void;
|
|
147
|
+
private parseRowHeight;
|
|
148
|
+
private keyOf;
|
|
149
|
+
private recomputeOffsets;
|
|
150
|
+
/** First item index whose bottom edge is at/after `offset`. */
|
|
151
|
+
private findIndexAtOrAfter;
|
|
152
|
+
/** Last item index whose top edge is at/before `offset`. */
|
|
153
|
+
private findIndexAtOrBefore;
|
|
154
|
+
private computeRange;
|
|
155
|
+
private attachContainerListeners;
|
|
156
|
+
private onScroll;
|
|
157
|
+
private onRowsResized;
|
|
158
|
+
/** Keeps the row `ResizeObserver` watching exactly the currently-rendered
|
|
159
|
+
* rows in `row-height="auto"` mode -- rows that scroll out of the
|
|
160
|
+
* rendered window are unobserved so the observer doesn't accumulate
|
|
161
|
+
* references to detached elements it can never usefully report on again. */
|
|
162
|
+
private syncRowObservers;
|
|
163
|
+
private scrollActiveIntoView;
|
|
164
|
+
private emitRangeChangeIfNeeded;
|
|
165
|
+
private maybeFireLoadMore;
|
|
166
|
+
private renderRow;
|
|
167
|
+
render(): TemplateResult;
|
|
168
|
+
}
|
|
169
|
+
declare global {
|
|
170
|
+
interface HTMLElementTagNameMap {
|
|
171
|
+
'lyra-virtual-list': LyraVirtualList;
|
|
172
|
+
}
|
|
173
|
+
}
|