@aceshooting/lyra-ui 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -14
- package/custom-elements.json +11555 -5539
- package/dist/components/app-rail/app-rail-item.d.ts +30 -0
- package/dist/components/app-rail/app-rail-item.js +68 -0
- package/dist/components/app-rail/app-rail-item.styles.d.ts +1 -0
- package/dist/components/app-rail/app-rail-item.styles.js +65 -0
- package/dist/components/app-rail/app-rail.d.ts +21 -24
- package/dist/components/app-rail/app-rail.js +68 -132
- package/dist/components/app-rail/app-rail.styles.js +5 -2
- package/dist/components/attachment-chip/attachment-chip.d.ts +38 -11
- package/dist/components/attachment-chip/attachment-chip.js +73 -29
- package/dist/components/attachment-trigger/attachment-trigger.d.ts +13 -0
- package/dist/components/attachment-trigger/attachment-trigger.js +13 -1
- package/dist/components/attachment-trigger/attachment-trigger.styles.js +28 -6
- package/dist/components/chart/bar-chart.js +2 -18
- package/dist/components/chart/box-plot.d.ts +25 -1
- package/dist/components/chart/box-plot.js +136 -6
- package/dist/components/chart/box-plot.styles.js +13 -0
- package/dist/components/chart/bubble-chart.js +2 -18
- package/dist/components/chart/chart.d.ts +54 -10
- package/dist/components/chart/chart.js +182 -39
- package/dist/components/chart/doughnut-chart.js +2 -18
- package/dist/components/chart/histogram-bin.d.ts +5 -2
- package/dist/components/chart/histogram-bin.js +12 -4
- package/dist/components/chart/histogram.js +8 -16
- package/dist/components/chart/line-chart.js +2 -18
- package/dist/components/chart/lite-chart.d.ts +80 -3
- package/dist/components/chart/lite-chart.js +250 -53
- package/dist/components/chart/pie-chart.js +2 -18
- package/dist/components/chart/polar-area-chart.js +2 -18
- package/dist/components/chart/radar-chart.js +2 -18
- package/dist/components/chart/scatter-chart.js +2 -18
- package/dist/components/chat-composer/chat-composer.d.ts +42 -1
- package/dist/components/chat-composer/chat-composer.js +84 -3
- package/dist/components/chat-composer/chat-composer.styles.js +11 -1
- package/dist/components/chat-message/chat-message.d.ts +32 -4
- package/dist/components/chat-message/chat-message.js +57 -17
- package/dist/components/checkbox/checkbox.d.ts +66 -8
- package/dist/components/checkbox/checkbox.js +173 -50
- package/dist/components/checkbox/checkbox.styles.js +9 -2
- package/dist/components/chip/chip-group.js +8 -2
- package/dist/components/chip/chip.js +9 -2
- package/dist/components/citation-badge/citation-badge.js +21 -3
- package/dist/components/code-block/code-block.d.ts +38 -0
- package/dist/components/code-block/code-block.js +72 -7
- package/dist/components/code-block/code-loader.d.ts +44 -1
- package/dist/components/code-block/code-loader.js +63 -0
- package/dist/components/combobox/combobox.d.ts +46 -5
- package/dist/components/combobox/combobox.js +175 -35
- package/dist/components/combobox/combobox.styles.js +3 -3
- package/dist/components/context-meter/context-meter.js +17 -8
- package/dist/components/context-meter/context-meter.styles.js +0 -6
- package/dist/components/conversation-item/conversation-item.d.ts +13 -16
- package/dist/components/conversation-item/conversation-item.js +29 -20
- package/dist/components/date-picker/calendar-core.d.ts +24 -0
- package/dist/components/date-picker/calendar-core.js +51 -4
- package/dist/components/date-picker/date-input.d.ts +77 -10
- package/dist/components/date-picker/date-input.js +278 -73
- package/dist/components/date-picker/date-picker.d.ts +28 -4
- package/dist/components/date-picker/date-picker.js +95 -37
- package/dist/components/dialog/confirm.js +3 -6
- package/dist/components/dialog/dialog.d.ts +75 -31
- package/dist/components/dialog/dialog.js +147 -131
- package/dist/components/dialog/dialog.styles.js +46 -2
- package/dist/components/dock-panel/dock-panel.d.ts +8 -0
- package/dist/components/dock-panel/dock-panel.js +15 -1
- package/dist/components/dock-panel/dock-panel.styles.js +15 -1
- package/dist/components/document-preview/document-preview.d.ts +15 -7
- package/dist/components/document-preview/document-preview.js +29 -13
- package/dist/components/empty/empty.d.ts +1 -2
- package/dist/components/empty/empty.js +18 -12
- package/dist/components/empty/empty.styles.js +0 -3
- package/dist/components/export-button/export-button.d.ts +12 -0
- package/dist/components/export-button/export-button.js +33 -5
- package/dist/components/export-button/export-button.styles.js +5 -1
- package/dist/components/file-input/accept.js +2 -0
- package/dist/components/file-input/file-input.d.ts +10 -1
- package/dist/components/file-input/file-input.js +36 -5
- package/dist/components/flag/flag.d.ts +1 -1
- package/dist/components/flag/flag.js +15 -1
- package/dist/components/flag/flag.styles.js +1 -1
- package/dist/components/flag/language-map.d.ts +4 -1
- package/dist/components/flag/language-map.js +6 -3
- package/dist/components/gauge/gauge.d.ts +10 -1
- package/dist/components/gauge/gauge.js +28 -9
- package/dist/components/generation-status/generation-status.d.ts +13 -5
- package/dist/components/generation-status/generation-status.js +59 -5
- package/dist/components/graph/graph.d.ts +37 -3
- package/dist/components/graph/graph.js +132 -20
- package/dist/components/heatmap/calendar-grid.d.ts +15 -6
- package/dist/components/heatmap/calendar-grid.js +17 -6
- package/dist/components/heatmap/heatmap-scale.d.ts +5 -1
- package/dist/components/heatmap/heatmap-scale.js +8 -2
- package/dist/components/heatmap/heatmap.d.ts +166 -25
- package/dist/components/heatmap/heatmap.js +372 -89
- package/dist/components/json-viewer/json-viewer.d.ts +22 -5
- package/dist/components/json-viewer/json-viewer.js +115 -37
- package/dist/components/json-viewer/json-viewer.styles.js +2 -1
- package/dist/components/kbd/kbd.js +24 -7
- package/dist/components/live-region/live-region.d.ts +10 -1
- package/dist/components/live-region/live-region.js +42 -6
- package/dist/components/map/map.d.ts +24 -1
- package/dist/components/map/map.js +89 -24
- package/dist/components/markdown/markdown-loader.d.ts +24 -0
- package/dist/components/markdown/markdown-loader.js +35 -1
- package/dist/components/markdown/markdown.d.ts +46 -8
- package/dist/components/markdown/markdown.js +136 -31
- package/dist/components/markdown/markdown.styles.js +7 -1
- package/dist/components/media-card/media-card.d.ts +25 -17
- package/dist/components/media-card/media-card.js +43 -65
- package/dist/components/mention-popover/mention-popover.d.ts +4 -1
- package/dist/components/mention-popover/mention-popover.js +23 -5
- package/dist/components/menu/menu-item.d.ts +32 -3
- package/dist/components/menu/menu-item.js +94 -7
- package/dist/components/menu/menu-item.styles.js +8 -0
- package/dist/components/menu/menu.d.ts +25 -1
- package/dist/components/menu/menu.js +99 -3
- package/dist/components/menu/menu.styles.js +3 -2
- package/dist/components/model-select/model-select.d.ts +48 -3
- package/dist/components/model-select/model-select.js +120 -22
- package/dist/components/model-select/model-select.styles.js +17 -3
- package/dist/components/model-settings-panel/model-settings-panel.d.ts +25 -1
- package/dist/components/model-settings-panel/model-settings-panel.js +65 -1
- package/dist/components/playback/playback.d.ts +6 -2
- package/dist/components/playback/playback.js +72 -29
- package/dist/components/playback/playback.styles.js +6 -1
- package/dist/components/responsive-panel/responsive-panel.d.ts +29 -16
- package/dist/components/responsive-panel/responsive-panel.js +130 -132
- package/dist/components/responsive-panel/responsive-panel.styles.js +1 -1
- package/dist/components/result-card/result-card.d.ts +8 -2
- package/dist/components/result-card/result-card.js +9 -3
- package/dist/components/result-card/result-card.styles.js +0 -1
- package/dist/components/select/select.d.ts +59 -20
- package/dist/components/select/select.js +125 -43
- package/dist/components/skeleton/skeleton.d.ts +3 -0
- package/dist/components/skeleton/skeleton.js +7 -1
- package/dist/components/skeleton/skeleton.styles.js +5 -4
- package/dist/components/slider/slider.d.ts +57 -5
- package/dist/components/slider/slider.js +195 -80
- package/dist/components/source-card/source-card.d.ts +17 -5
- package/dist/components/source-card/source-card.js +55 -8
- package/dist/components/source-card/source-card.styles.js +1 -1
- package/dist/components/source-list/source-list.js +9 -1
- package/dist/components/sparkline/sparkline.js +34 -10
- package/dist/components/split/split.d.ts +141 -14
- package/dist/components/split/split.js +357 -52
- package/dist/components/split/split.styles.js +18 -1
- package/dist/components/stat/stat.d.ts +10 -4
- package/dist/components/stat/stat.js +46 -11
- package/dist/components/stream-status/stream-status.d.ts +27 -11
- package/dist/components/stream-status/stream-status.js +95 -13
- package/dist/components/streaming-text/streaming-text.d.ts +9 -3
- package/dist/components/streaming-text/streaming-text.js +25 -10
- package/dist/components/streaming-text/streaming-text.styles.js +3 -2
- package/dist/components/switch/switch.d.ts +52 -7
- package/dist/components/switch/switch.js +111 -40
- package/dist/components/switch/switch.styles.js +1 -1
- package/dist/components/table/table.d.ts +18 -3
- package/dist/components/table/table.js +88 -20
- package/dist/components/tabs/tabs.d.ts +23 -0
- package/dist/components/tabs/tabs.js +76 -12
- package/dist/components/tabs/tabs.styles.js +11 -0
- package/dist/components/thinking-panel/thinking-panel.d.ts +3 -1
- package/dist/components/thinking-panel/thinking-panel.js +34 -9
- package/dist/components/thinking-panel/thinking-panel.styles.js +6 -0
- package/dist/components/time-range/time-range.d.ts +59 -2
- package/dist/components/time-range/time-range.js +163 -67
- package/dist/components/toast/toast-item.d.ts +12 -3
- package/dist/components/toast/toast-item.js +90 -53
- package/dist/components/toast/toast-item.styles.js +59 -28
- package/dist/components/toast/toast.js +17 -5
- package/dist/components/toast/toaster.js +10 -1
- package/dist/components/tool-approval-dialog/tool-approval-dialog.d.ts +11 -10
- package/dist/components/tool-approval-dialog/tool-approval-dialog.js +50 -124
- package/dist/components/tool-approval-dialog/tool-approval-dialog.styles.js +1 -1
- package/dist/components/tool-call-chip/tool-call-chip.d.ts +18 -2
- package/dist/components/tool-call-chip/tool-call-chip.js +86 -25
- package/dist/components/tool-param-form/tool-param-form.d.ts +89 -28
- package/dist/components/tool-param-form/tool-param-form.js +350 -106
- package/dist/components/tool-result-dialog/tool-result-dialog.d.ts +27 -7
- package/dist/components/tool-result-dialog/tool-result-dialog.js +80 -115
- package/dist/components/tool-result-dialog/tool-result-dialog.styles.js +1 -1
- package/dist/components/tool-result-view/registry.d.ts +0 -8
- package/dist/components/tool-result-view/registry.js +7 -2
- package/dist/components/tool-result-view/tool-result-view.d.ts +6 -3
- package/dist/components/tool-result-view/tool-result-view.js +18 -4
- package/dist/components/tool-select-dialog/tool-select-dialog.d.ts +11 -11
- package/dist/components/tool-select-dialog/tool-select-dialog.js +44 -133
- package/dist/components/tool-select-dialog/tool-select-dialog.styles.js +13 -4
- package/dist/components/tree/tree-node.d.ts +4 -1
- package/dist/components/tree/tree-node.js +4 -1
- package/dist/components/tree/tree.d.ts +17 -8
- package/dist/components/tree/tree.js +21 -20
- package/dist/components/typing-indicator/typing-indicator.d.ts +12 -2
- package/dist/components/typing-indicator/typing-indicator.js +16 -4
- package/dist/components/typing-indicator/typing-indicator.styles.js +2 -2
- package/dist/components/virtual-list/virtual-list.d.ts +56 -19
- package/dist/components/virtual-list/virtual-list.js +184 -38
- package/dist/components/virtual-list/virtual-list.styles.js +12 -0
- package/dist/components/widget/widget.d.ts +5 -4
- package/dist/components/widget/widget.js +54 -120
- package/dist/components/widget/widget.styles.js +8 -2
- package/dist/components/word-cloud/word-cloud-layout.d.ts +7 -0
- package/dist/components/word-cloud/word-cloud-layout.js +20 -6
- package/dist/components/word-cloud/word-cloud.d.ts +22 -2
- package/dist/components/word-cloud/word-cloud.js +45 -6
- package/dist/components/word-cloud/word-cloud.styles.js +13 -1
- package/dist/internal/anchored-validity.d.ts +1 -0
- package/dist/internal/anchored-validity.js +86 -0
- package/dist/internal/form-associated.d.ts +7 -0
- package/dist/internal/form-associated.js +43 -4
- package/dist/internal/numbers.d.ts +12 -0
- package/dist/internal/numbers.js +26 -0
- package/dist/internal/overlay-manager.d.ts +51 -0
- package/dist/internal/overlay-manager.js +523 -0
- package/dist/internal/positioner.js +27 -3
- package/dist/internal/safe-url.d.ts +12 -0
- package/dist/internal/safe-url.js +41 -0
- package/dist/internal/tokens.styles.js +17 -11
- package/dist/lyra.d.ts +5 -2
- package/dist/lyra.js +3 -1
- package/llms-full.txt +970 -426
- package/llms.txt +5 -4
- package/package.json +19 -2
|
@@ -7,46 +7,14 @@ 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 { activateOverlay } from '../../internal/overlay-manager.js';
|
|
10
11
|
import { defineElement } from '../../internal/prefix.js';
|
|
11
12
|
import { lockScroll } from '../../internal/scroll-lock.js';
|
|
12
|
-
import { nextId } from '../../internal/a11y.js';
|
|
13
|
+
import { nextId, srOnly } from '../../internal/a11y.js';
|
|
13
14
|
import { styles } from './tool-select-dialog.styles.js';
|
|
14
15
|
import '../checkbox/checkbox.js';
|
|
15
16
|
import '../switch/switch.js';
|
|
16
17
|
const OTHER_CATEGORY = 'Other';
|
|
17
|
-
const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
18
|
-
// Shadow-piercing so both a slotted custom element's real focusable target
|
|
19
|
-
// (footer content) and a directly-rendered one (the search input, the
|
|
20
|
-
// use-defaults <lyra-switch>, each row's <lyra-checkbox> -- all live in this
|
|
21
|
-
// component's own shadow tree, not projected via <slot>) are found even
|
|
22
|
-
// though the tag itself doesn't match FOCUSABLE_SELECTOR. Deliberately
|
|
23
|
-
// duplicated from lyra-dialog's/lyra-tool-result-dialog's identical helper
|
|
24
|
-
// rather than imported/shared -- this component is its own standalone
|
|
25
|
-
// overlay and must not depend on either (see this file's class doc).
|
|
26
|
-
function collectFocusable(el) {
|
|
27
|
-
const result = [];
|
|
28
|
-
if (el.matches(FOCUSABLE_SELECTOR)) {
|
|
29
|
-
result.push(el);
|
|
30
|
-
}
|
|
31
|
-
if (el instanceof HTMLSlotElement) {
|
|
32
|
-
for (const assigned of el.assignedElements({ flatten: true })) {
|
|
33
|
-
result.push(...collectFocusable(assigned));
|
|
34
|
-
}
|
|
35
|
-
return result;
|
|
36
|
-
}
|
|
37
|
-
const container = el.shadowRoot ?? el;
|
|
38
|
-
for (const child of Array.from(container.children)) {
|
|
39
|
-
result.push(...collectFocusable(child));
|
|
40
|
-
}
|
|
41
|
-
return result;
|
|
42
|
-
}
|
|
43
|
-
/** Whether `el` is actually laid out/paintable -- `checkVisibility()` (falling
|
|
44
|
-
* back to `getClientRects().length` where unsupported) correctly follows
|
|
45
|
-
* flattened-tree/slot assignment, unlike `offsetParent`. Mirrors
|
|
46
|
-
* lyra-dialog's/lyra-tool-result-dialog's identical helper. */
|
|
47
|
-
function isRendered(el) {
|
|
48
|
-
return el.checkVisibility ? el.checkVisibility() : el.getClientRects().length > 0;
|
|
49
|
-
}
|
|
50
18
|
/** Default `filter`: case-insensitive substring match against the tool's name and description. */
|
|
51
19
|
function defaultFilter(tool, query) {
|
|
52
20
|
return tool.name.toLowerCase().includes(query) || (tool.description ?? '').toLowerCase().includes(query);
|
|
@@ -56,11 +24,10 @@ function defaultFilter(tool, query) {
|
|
|
56
24
|
* tool-enablement dialog for picking which agent tools are available in a
|
|
57
25
|
* conversation.
|
|
58
26
|
*
|
|
59
|
-
* This
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* duplicates that pattern locally instead of composing the previous one.
|
|
27
|
+
* This renders its own dialog panel rather than nesting a `<lyra-dialog>` in
|
|
28
|
+
* its shadow template. Shared overlay infrastructure coordinates stacking,
|
|
29
|
+
* focus trapping, Escape/backdrop dismissal, and focus return with every
|
|
30
|
+
* other overlay in the same document.
|
|
64
31
|
*
|
|
65
32
|
* `useDefaults` is a single top-level switch: while `true`, every per-tool
|
|
66
33
|
* checkbox below renders disabled (still reflecting whatever `selected`
|
|
@@ -98,14 +65,17 @@ function defaultFilter(tool, query) {
|
|
|
98
65
|
* @csspart empty - The "no tools" / "no matches" message.
|
|
99
66
|
* @csspart category - A single category's wrapper (`role="group"`).
|
|
100
67
|
* @csspart category-heading - A category's heading.
|
|
101
|
-
* @csspart category-count - The
|
|
68
|
+
* @csspart category-count - The terse, `aria-hidden` tool count next to a category heading
|
|
69
|
+
* (the heading's accessible name gets the full sentence from an sr-only sibling instead).
|
|
102
70
|
* @csspart category-list - The `<ul>` of tool rows within a category.
|
|
103
71
|
* @csspart tool-row - A single tool's `<li>` row.
|
|
104
72
|
* @csspart tool-checkbox - A row's `<lyra-checkbox>`.
|
|
105
73
|
* @csspart tool-name - A row's name text (plus its `icon`, if set).
|
|
106
74
|
* @csspart tool-icon - A row's leading icon glyph, when `icon` is set.
|
|
107
75
|
* @csspart tool-description - A row's optional description text.
|
|
108
|
-
* @csspart tool-disabled-reason - A disabled row's `disabledReason` text
|
|
76
|
+
* @csspart tool-disabled-reason - A disabled row's `disabledReason` text, slotted inside
|
|
77
|
+
* `tool-checkbox` (alongside `tool-name`/`tool-description`) so it contributes to the
|
|
78
|
+
* checkbox's accessible name/description instead of going unannounced.
|
|
109
79
|
* @csspart footer - The wrapper around the `footer` slot.
|
|
110
80
|
*/
|
|
111
81
|
export class LyraToolSelectDialog extends LyraElement {
|
|
@@ -135,34 +105,7 @@ export class LyraToolSelectDialog extends LyraElement {
|
|
|
135
105
|
this.hasFooterSlot = e.target.assignedElements({ flatten: true }).length > 0;
|
|
136
106
|
};
|
|
137
107
|
this.onBackdropClick = () => {
|
|
138
|
-
this.
|
|
139
|
-
};
|
|
140
|
-
this.onDocKeyDown = (e) => {
|
|
141
|
-
if (!this.open)
|
|
142
|
-
return;
|
|
143
|
-
if (e.key === 'Escape') {
|
|
144
|
-
e.preventDefault();
|
|
145
|
-
this.close('escape');
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
if (e.key !== 'Tab')
|
|
149
|
-
return;
|
|
150
|
-
const focusable = this.getFocusableElements();
|
|
151
|
-
if (focusable.length === 0) {
|
|
152
|
-
e.preventDefault();
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
const first = focusable[0];
|
|
156
|
-
const last = focusable[focusable.length - 1];
|
|
157
|
-
const active = this.getActiveElement();
|
|
158
|
-
if (e.shiftKey && active === first) {
|
|
159
|
-
e.preventDefault();
|
|
160
|
-
last.focus();
|
|
161
|
-
}
|
|
162
|
-
else if (!e.shiftKey && active === last) {
|
|
163
|
-
e.preventDefault();
|
|
164
|
-
first.focus();
|
|
165
|
-
}
|
|
108
|
+
this.overlay?.dismissBackdrop();
|
|
166
109
|
};
|
|
167
110
|
this.onSearchInput = (e) => {
|
|
168
111
|
this.query = e.target.value;
|
|
@@ -172,27 +115,25 @@ export class LyraToolSelectDialog extends LyraElement {
|
|
|
172
115
|
this.emitChange();
|
|
173
116
|
};
|
|
174
117
|
}
|
|
175
|
-
static { this.styles = [LyraElement.styles, styles]; }
|
|
118
|
+
static { this.styles = [LyraElement.styles, styles, srOnly]; }
|
|
176
119
|
willUpdate(changed) {
|
|
177
120
|
if (!this.hasUpdated) {
|
|
178
121
|
this.hasFooterSlot = Array.from(this.children).some((el) => el.getAttribute('slot') === 'footer');
|
|
179
122
|
}
|
|
180
123
|
if (changed.has('open')) {
|
|
181
124
|
if (this.open) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
// typically lives *outside* this component entirely, so "whatever
|
|
185
|
-
// had focus right before open" is the only generally correct
|
|
186
|
-
// definition of "the trigger".
|
|
187
|
-
const active = this.getActiveElement();
|
|
188
|
-
this.lastTrigger = active instanceof HTMLElement ? active : undefined;
|
|
189
|
-
this.releaseScrollLock = lockScroll();
|
|
190
|
-
document.addEventListener('keydown', this.onDocKeyDown);
|
|
125
|
+
this.releaseScrollLock ??= lockScroll(this.ownerDocument);
|
|
126
|
+
this.activateOverlay();
|
|
191
127
|
}
|
|
192
128
|
else {
|
|
193
129
|
this.releaseScrollLock?.();
|
|
194
130
|
this.releaseScrollLock = undefined;
|
|
195
|
-
|
|
131
|
+
this.overlay?.deactivate();
|
|
132
|
+
this.overlay = undefined;
|
|
133
|
+
// Otherwise a long-lived instance reopens still showing whatever
|
|
134
|
+
// search filter/collapsed-category state the previous session left
|
|
135
|
+
// behind, rather than the fresh, unfiltered list a reopen implies.
|
|
136
|
+
this.query = '';
|
|
196
137
|
}
|
|
197
138
|
}
|
|
198
139
|
}
|
|
@@ -202,31 +143,34 @@ export class LyraToolSelectDialog extends LyraElement {
|
|
|
202
143
|
// ordering rationale.
|
|
203
144
|
updated(changed) {
|
|
204
145
|
if (changed.has('open') && this.open) {
|
|
205
|
-
|
|
206
|
-
if (first) {
|
|
207
|
-
first.focus();
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
this.shadowRoot?.querySelector('[part="panel"]')?.focus();
|
|
211
|
-
}
|
|
146
|
+
this.overlay?.focusInitial();
|
|
212
147
|
}
|
|
213
148
|
}
|
|
214
149
|
connectedCallback() {
|
|
215
150
|
super.connectedCallback();
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (this.hasUpdated && this.open && !this.releaseScrollLock) {
|
|
221
|
-
this.releaseScrollLock = lockScroll();
|
|
222
|
-
document.addEventListener('keydown', this.onDocKeyDown);
|
|
151
|
+
if (this.hasUpdated && this.open) {
|
|
152
|
+
this.releaseScrollLock ??= lockScroll(this.ownerDocument);
|
|
153
|
+
this.activateOverlay();
|
|
154
|
+
queueMicrotask(() => this.overlay?.focusInitial());
|
|
223
155
|
}
|
|
224
156
|
}
|
|
225
157
|
disconnectedCallback() {
|
|
226
158
|
super.disconnectedCallback();
|
|
227
159
|
this.releaseScrollLock?.();
|
|
228
160
|
this.releaseScrollLock = undefined;
|
|
229
|
-
|
|
161
|
+
this.overlay?.suspend();
|
|
162
|
+
}
|
|
163
|
+
activateOverlay() {
|
|
164
|
+
if (this.overlay?.isActive()) {
|
|
165
|
+
this.overlay.resume();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
this.overlay = activateOverlay({
|
|
169
|
+
host: this,
|
|
170
|
+
panel: () => this.shadowRoot?.querySelector('[part="panel"]') ?? null,
|
|
171
|
+
onEscape: () => this.close('escape'),
|
|
172
|
+
onBackdrop: () => this.close('backdrop'),
|
|
173
|
+
});
|
|
230
174
|
}
|
|
231
175
|
/**
|
|
232
176
|
* Close the dialog and return focus to whatever had it before the dialog
|
|
@@ -241,40 +185,6 @@ export class LyraToolSelectDialog extends LyraElement {
|
|
|
241
185
|
return;
|
|
242
186
|
this.open = false;
|
|
243
187
|
this.emit('lyra-close', reason);
|
|
244
|
-
this.lastTrigger?.focus();
|
|
245
|
-
}
|
|
246
|
-
// Bounds Tab/Shift+Tab to the panel while open. Order follows the search
|
|
247
|
-
// input, then the use-defaults switch, then each visible tool row's
|
|
248
|
-
// checkbox, then the footer slot -- the same order the flattened tree
|
|
249
|
-
// already tabs through (mirrors lyra-tool-result-dialog's identical
|
|
250
|
-
// header-buttons-then-body-then-footer ordering rationale).
|
|
251
|
-
getFocusableElements() {
|
|
252
|
-
const root = this.shadowRoot;
|
|
253
|
-
if (!root)
|
|
254
|
-
return [];
|
|
255
|
-
const searchInput = root.querySelector('[part="search-input"]');
|
|
256
|
-
const defaultsToggle = root.querySelector('[part="defaults-toggle"]');
|
|
257
|
-
const checkboxes = Array.from(root.querySelectorAll('[part="tool-checkbox"]'));
|
|
258
|
-
const fromSlot = (selector) => {
|
|
259
|
-
const slot = root.querySelector(selector);
|
|
260
|
-
return slot ? slot.assignedElements({ flatten: true }).flatMap(collectFocusable) : [];
|
|
261
|
-
};
|
|
262
|
-
return [
|
|
263
|
-
...(searchInput ? collectFocusable(searchInput) : []),
|
|
264
|
-
...(defaultsToggle ? collectFocusable(defaultsToggle) : []),
|
|
265
|
-
...checkboxes.flatMap(collectFocusable),
|
|
266
|
-
...fromSlot('slot[name="footer"]'),
|
|
267
|
-
].filter(isRendered);
|
|
268
|
-
}
|
|
269
|
-
getActiveElement() {
|
|
270
|
-
let active = document.activeElement;
|
|
271
|
-
while (active) {
|
|
272
|
-
const inner = active.shadowRoot?.activeElement ?? null;
|
|
273
|
-
if (!inner)
|
|
274
|
-
break;
|
|
275
|
-
active = inner;
|
|
276
|
-
}
|
|
277
|
-
return active;
|
|
278
188
|
}
|
|
279
189
|
emitChange() {
|
|
280
190
|
this.emit('lyra-change', {
|
|
@@ -337,10 +247,10 @@ export class LyraToolSelectDialog extends LyraElement {
|
|
|
337
247
|
${tool.icon ? html `<span part="tool-icon" aria-hidden="true">${tool.icon}</span>` : nothing}${tool.name}
|
|
338
248
|
</span>
|
|
339
249
|
${tool.description ? html `<span part="tool-description">${tool.description}</span>` : nothing}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
? html `<p part="tool-disabled-reason">${tool.disabledReason}</p>`
|
|
250
|
+
${tool.disabled && tool.disabledReason
|
|
251
|
+
? html `<span part="tool-disabled-reason">${tool.disabledReason}</span>`
|
|
343
252
|
: nothing}
|
|
253
|
+
</lyra-checkbox>
|
|
344
254
|
</li>
|
|
345
255
|
`;
|
|
346
256
|
}
|
|
@@ -349,7 +259,8 @@ export class LyraToolSelectDialog extends LyraElement {
|
|
|
349
259
|
return html `
|
|
350
260
|
<div part="category" role="group" aria-labelledby=${headingId}>
|
|
351
261
|
<h3 part="category-heading" id=${headingId}>
|
|
352
|
-
${group.category}<span part="category-count">${group.tools.length}</span
|
|
262
|
+
${group.category}<span part="category-count" aria-hidden="true">${group.tools.length}</span
|
|
263
|
+
><span class="sr-only">${group.tools.length} tool${group.tools.length === 1 ? '' : 's'}</span>
|
|
353
264
|
</h3>
|
|
354
265
|
<ul part="category-list">
|
|
355
266
|
${group.tools.map((tool) => this.renderTool(tool))}
|
|
@@ -10,7 +10,7 @@ export const styles = css `
|
|
|
10
10
|
display: none;
|
|
11
11
|
position: fixed;
|
|
12
12
|
inset: 0;
|
|
13
|
-
z-index: 1000;
|
|
13
|
+
z-index: var(--lyra-overlay-stack-index, 1000);
|
|
14
14
|
align-items: center;
|
|
15
15
|
justify-content: center;
|
|
16
16
|
padding: var(--lyra-space-l);
|
|
@@ -79,7 +79,13 @@ export const styles = css `
|
|
|
79
79
|
}
|
|
80
80
|
[part='defaults-hint'] {
|
|
81
81
|
margin: 0;
|
|
82
|
-
|
|
82
|
+
/* Lines the hint up under the switch's label text, not its track --
|
|
83
|
+
lyra-switch's own [part="base"] uses a fixed 2.25rem track
|
|
84
|
+
inline-size plus a --lyra-space-s gap before its label (both defined
|
|
85
|
+
in switch.styles.ts, not exposed as tokens), so this indent is
|
|
86
|
+
coupled to that fixed geometry rather than derived from an unrelated
|
|
87
|
+
component's token. */
|
|
88
|
+
padding-inline-start: calc(2.25rem + var(--lyra-space-s));
|
|
83
89
|
font-size: 0.75rem;
|
|
84
90
|
color: var(--lyra-color-text-quiet);
|
|
85
91
|
}
|
|
@@ -162,8 +168,11 @@ export const styles = css `
|
|
|
162
168
|
color: var(--lyra-color-text-quiet);
|
|
163
169
|
}
|
|
164
170
|
[part='tool-disabled-reason'] {
|
|
165
|
-
|
|
166
|
-
|
|
171
|
+
/* Slotted into lyra-checkbox's default slot alongside tool-name/
|
|
172
|
+
tool-description (see tool-select-dialog.ts's renderTool()), so it
|
|
173
|
+
inherits its indent for free from ::part(label)'s column layout
|
|
174
|
+
above instead of needing its own guessed padding. */
|
|
175
|
+
display: block;
|
|
167
176
|
font-size: 0.75rem;
|
|
168
177
|
color: var(--lyra-color-warning);
|
|
169
178
|
}
|
|
@@ -15,7 +15,10 @@ import type { TreeItem } from './tree.js';
|
|
|
15
15
|
* @customElement lyra-tree-node
|
|
16
16
|
* @event lyra-node-toggle - `detail: { id, expanded }`, fired when this node is expanded or collapsed (via `expand()`/`collapse()`, the toggle button, or ArrowRight/ArrowLeft).
|
|
17
17
|
* @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).
|
|
18
|
-
* @csspart row
|
|
18
|
+
* @csspart row - The tree row.
|
|
19
|
+
* @csspart toggle - The expand/collapse button.
|
|
20
|
+
* @csspart label - The node label.
|
|
21
|
+
* @csspart badge - The optional node badge.
|
|
19
22
|
*/
|
|
20
23
|
export declare class LyraTreeNode extends LyraElement {
|
|
21
24
|
static styles: import("lit").CSSResultGroup[];
|
|
@@ -90,7 +90,10 @@ const styles = css `
|
|
|
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
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
|
-
* @csspart row
|
|
93
|
+
* @csspart row - The tree row.
|
|
94
|
+
* @csspart toggle - The expand/collapse button.
|
|
95
|
+
* @csspart label - The node label.
|
|
96
|
+
* @csspart badge - The optional node badge.
|
|
94
97
|
*/
|
|
95
98
|
export class LyraTreeNode extends LyraElement {
|
|
96
99
|
constructor() {
|
|
@@ -35,15 +35,18 @@ export declare class LyraTree extends LyraElement {
|
|
|
35
35
|
private get nodeElements();
|
|
36
36
|
private childrenOf;
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
38
|
+
* Every currently *visible* (ancestor-expanded) node, top-to-bottom.
|
|
39
|
+
*
|
|
40
|
+
* Recomputed on every call rather than memoized: `item`/`expanded` are
|
|
41
|
+
* plain public settable properties on `<lyra-tree-node>` (not just
|
|
42
|
+
* reachable through this class's own `data` setter or the bubbling
|
|
43
|
+
* `lyra-node-toggle` event), so a cache keyed off those two entry points
|
|
44
|
+
* alone would go stale the moment a caller mutated a node directly --
|
|
45
|
+
* e.g. `node.item = { ...node.item, children: [...] }` to append a child
|
|
46
|
+
* in place. This walk only runs from user-paced `keydown` handling (never
|
|
47
|
+
* a hot render-loop path), so the cost of a `shadowRoot.querySelectorAll`
|
|
48
|
+
* per currently-expanded node is not worth trading for that staleness risk.
|
|
43
49
|
*/
|
|
44
|
-
private cachedVisible;
|
|
45
|
-
private invalidateVisibleCache;
|
|
46
|
-
/** Every currently *visible* (ancestor-expanded) node, top-to-bottom. */
|
|
47
50
|
private visibleNodeElements;
|
|
48
51
|
private findItem;
|
|
49
52
|
protected willUpdate(changed: PropertyValues): void;
|
|
@@ -100,6 +103,12 @@ export declare class LyraTree extends LyraElement {
|
|
|
100
103
|
* -- callers that immediately read `visibleNodeElements()`-derived state
|
|
101
104
|
* (or call `collapseAll()` right after) should `await` this instead of
|
|
102
105
|
* firing it and moving on.
|
|
106
|
+
*
|
|
107
|
+
* Guarded on `n.hasChildren`, matching `expand()`'s own invariant -- a leaf
|
|
108
|
+
* node's `expanded` must never be set to `true`, since `collapse()` (and
|
|
109
|
+
* this method's own counterpart, `collapseAll()`) refuse to act on a node
|
|
110
|
+
* that's `!hasChildren`, which would otherwise leave the leaf permanently
|
|
111
|
+
* stuck with a reflected `expanded` attribute nothing can clear.
|
|
103
112
|
*/
|
|
104
113
|
expandAll(): Promise<void>;
|
|
105
114
|
/**
|
|
@@ -38,14 +38,6 @@ export class LyraTree extends LyraElement {
|
|
|
38
38
|
this.activeId = null;
|
|
39
39
|
/** Set by `willUpdate()` when a `data` reassignment removes the node that currently holds real DOM focus; consumed by `updated()` to refocus the newly-designated `activeId` node once it's actually focusable. */
|
|
40
40
|
this.pendingFocusId = null;
|
|
41
|
-
/**
|
|
42
|
-
* Memoized result of the last `visibleNodeElements()` walk. Every keydown
|
|
43
|
-
* (ArrowUp/Down/Home/End especially) reads the full visible-node list, and
|
|
44
|
-
* rebuilding it means a `shadowRoot.querySelectorAll` per currently-expanded
|
|
45
|
-
* node -- invalidated below on the only two things that can change which
|
|
46
|
-
* nodes are visible: a `data` reassignment, or a node expanding/collapsing.
|
|
47
|
-
*/
|
|
48
|
-
this.cachedVisible = null;
|
|
49
41
|
/**
|
|
50
42
|
* A mouse click always lands directly on the node it interacts with --
|
|
51
43
|
* `select()`/`expand()`/`collapse()` all emit their own node's id --
|
|
@@ -62,8 +54,6 @@ export class LyraTree extends LyraElement {
|
|
|
62
54
|
* same-value, no-op assignment for them.
|
|
63
55
|
*/
|
|
64
56
|
this.onNodeActivate = (e) => {
|
|
65
|
-
if (e.type === 'lyra-node-toggle')
|
|
66
|
-
this.invalidateVisibleCache();
|
|
67
57
|
this.activeId = e.detail.id;
|
|
68
58
|
};
|
|
69
59
|
this.onTreeKeyDown = (e) => {
|
|
@@ -138,13 +128,20 @@ export class LyraTree extends LyraElement {
|
|
|
138
128
|
childrenOf(node) {
|
|
139
129
|
return [...(node.shadowRoot?.querySelectorAll(tag('tree-node')) ?? [])];
|
|
140
130
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Every currently *visible* (ancestor-expanded) node, top-to-bottom.
|
|
133
|
+
*
|
|
134
|
+
* Recomputed on every call rather than memoized: `item`/`expanded` are
|
|
135
|
+
* plain public settable properties on `<lyra-tree-node>` (not just
|
|
136
|
+
* reachable through this class's own `data` setter or the bubbling
|
|
137
|
+
* `lyra-node-toggle` event), so a cache keyed off those two entry points
|
|
138
|
+
* alone would go stale the moment a caller mutated a node directly --
|
|
139
|
+
* e.g. `node.item = { ...node.item, children: [...] }` to append a child
|
|
140
|
+
* in place. This walk only runs from user-paced `keydown` handling (never
|
|
141
|
+
* a hot render-loop path), so the cost of a `shadowRoot.querySelectorAll`
|
|
142
|
+
* per currently-expanded node is not worth trading for that staleness risk.
|
|
143
|
+
*/
|
|
145
144
|
visibleNodeElements() {
|
|
146
|
-
if (this.cachedVisible)
|
|
147
|
-
return this.cachedVisible;
|
|
148
145
|
const acc = [];
|
|
149
146
|
const walk = (nodes) => {
|
|
150
147
|
for (const n of nodes) {
|
|
@@ -154,7 +151,6 @@ export class LyraTree extends LyraElement {
|
|
|
154
151
|
}
|
|
155
152
|
};
|
|
156
153
|
walk(this.nodeElements);
|
|
157
|
-
this.cachedVisible = acc;
|
|
158
154
|
return acc;
|
|
159
155
|
}
|
|
160
156
|
findItem(items, id) {
|
|
@@ -169,7 +165,6 @@ export class LyraTree extends LyraElement {
|
|
|
169
165
|
}
|
|
170
166
|
willUpdate(changed) {
|
|
171
167
|
if (changed.has('data')) {
|
|
172
|
-
this.invalidateVisibleCache();
|
|
173
168
|
// `document.activeElement` collapses to the outermost light-DOM node
|
|
174
169
|
// even when the real focus target is a nested descendant several
|
|
175
170
|
// shadow roots down, so this also catches a focused nested node whose
|
|
@@ -269,12 +264,18 @@ export class LyraTree extends LyraElement {
|
|
|
269
264
|
* -- callers that immediately read `visibleNodeElements()`-derived state
|
|
270
265
|
* (or call `collapseAll()` right after) should `await` this instead of
|
|
271
266
|
* firing it and moving on.
|
|
267
|
+
*
|
|
268
|
+
* Guarded on `n.hasChildren`, matching `expand()`'s own invariant -- a leaf
|
|
269
|
+
* node's `expanded` must never be set to `true`, since `collapse()` (and
|
|
270
|
+
* this method's own counterpart, `collapseAll()`) refuse to act on a node
|
|
271
|
+
* that's `!hasChildren`, which would otherwise leave the leaf permanently
|
|
272
|
+
* stuck with a reflected `expanded` attribute nothing can clear.
|
|
272
273
|
*/
|
|
273
274
|
async expandAll() {
|
|
274
275
|
const setAll = async (nodes) => {
|
|
275
276
|
await Promise.all(nodes.map(async (n) => {
|
|
276
|
-
n.
|
|
277
|
-
|
|
277
|
+
if (n.hasChildren)
|
|
278
|
+
n.expanded = true;
|
|
278
279
|
await n.updateComplete;
|
|
279
280
|
await setAll(this.childrenOf(n));
|
|
280
281
|
}));
|
|
@@ -29,7 +29,9 @@ export type TypingIndicatorSize = 'sm' | 'md';
|
|
|
29
29
|
* accessible name derived from `label` is sufficient, set both as an
|
|
30
30
|
* `aria-label` on the host *and* as a visually-hidden text node in the
|
|
31
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.
|
|
32
|
+
* by a given assistive-tech/browser pairing. An empty or whitespace-only
|
|
33
|
+
* `label` falls back to the default "Thinking…" copy in both places, rather
|
|
34
|
+
* than leaving the component with no accessible name at all. The animated dots/pulse/cursor
|
|
33
35
|
* shape is `aria-hidden="true"` — it's decorative; `label` is the entire
|
|
34
36
|
* accessible content, so nothing narrates individual animation frames.
|
|
35
37
|
*
|
|
@@ -45,10 +47,18 @@ export declare class LyraTypingIndicator extends LyraElement {
|
|
|
45
47
|
variant: TypingIndicatorVariant;
|
|
46
48
|
/** Accessible name, exposed via `role="status"`. Not re-announced on every
|
|
47
49
|
* animation frame — only mount (and any later change to this property)
|
|
48
|
-
* produces a new announcement.
|
|
50
|
+
* produces a new announcement. An empty or whitespace-only value falls
|
|
51
|
+
* back to the default "Thinking…" copy (see `accessibleLabel`) so the
|
|
52
|
+
* component never loses its accessible name. */
|
|
49
53
|
label: string;
|
|
50
54
|
/** Compact sizing for dense layouts (e.g. inline with a message bubble). */
|
|
51
55
|
size: TypingIndicatorSize;
|
|
56
|
+
/** The accessible name actually used, falling back to the default
|
|
57
|
+
* "Thinking…" copy when `label` is set to an empty or whitespace-only
|
|
58
|
+
* string -- otherwise both the `aria-label` and the sr-only text node
|
|
59
|
+
* would go blank, leaving this purely-decorative component with no
|
|
60
|
+
* accessible name at all. */
|
|
61
|
+
private get accessibleLabel();
|
|
52
62
|
protected willUpdate(changed: PropertyValues): void;
|
|
53
63
|
render(): TemplateResult;
|
|
54
64
|
private renderShape;
|
|
@@ -37,7 +37,9 @@ import { styles } from './typing-indicator.styles.js';
|
|
|
37
37
|
* accessible name derived from `label` is sufficient, set both as an
|
|
38
38
|
* `aria-label` on the host *and* as a visually-hidden text node in the
|
|
39
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.
|
|
40
|
+
* by a given assistive-tech/browser pairing. An empty or whitespace-only
|
|
41
|
+
* `label` falls back to the default "Thinking…" copy in both places, rather
|
|
42
|
+
* than leaving the component with no accessible name at all. The animated dots/pulse/cursor
|
|
41
43
|
* shape is `aria-hidden="true"` — it's decorative; `label` is the entire
|
|
42
44
|
* accessible content, so nothing narrates individual animation frames.
|
|
43
45
|
*
|
|
@@ -54,22 +56,32 @@ export class LyraTypingIndicator extends LyraElement {
|
|
|
54
56
|
this.variant = 'dots';
|
|
55
57
|
/** Accessible name, exposed via `role="status"`. Not re-announced on every
|
|
56
58
|
* animation frame — only mount (and any later change to this property)
|
|
57
|
-
* produces a new announcement.
|
|
59
|
+
* produces a new announcement. An empty or whitespace-only value falls
|
|
60
|
+
* back to the default "Thinking…" copy (see `accessibleLabel`) so the
|
|
61
|
+
* component never loses its accessible name. */
|
|
58
62
|
this.label = 'Thinking…';
|
|
59
63
|
/** Compact sizing for dense layouts (e.g. inline with a message bubble). */
|
|
60
64
|
this.size = 'md';
|
|
61
65
|
}
|
|
62
66
|
static { this.styles = [LyraElement.styles, styles, srOnly]; }
|
|
67
|
+
/** The accessible name actually used, falling back to the default
|
|
68
|
+
* "Thinking…" copy when `label` is set to an empty or whitespace-only
|
|
69
|
+
* string -- otherwise both the `aria-label` and the sr-only text node
|
|
70
|
+
* would go blank, leaving this purely-decorative component with no
|
|
71
|
+
* accessible name at all. */
|
|
72
|
+
get accessibleLabel() {
|
|
73
|
+
return this.label.trim() || 'Thinking…';
|
|
74
|
+
}
|
|
63
75
|
willUpdate(changed) {
|
|
64
76
|
this.setAttribute('role', 'status');
|
|
65
77
|
if (changed.has('label')) {
|
|
66
|
-
this.setAttribute('aria-label', this.
|
|
78
|
+
this.setAttribute('aria-label', this.accessibleLabel);
|
|
67
79
|
}
|
|
68
80
|
}
|
|
69
81
|
render() {
|
|
70
82
|
return html `
|
|
71
83
|
<span part="base" aria-hidden="true">${this.renderShape()}</span>
|
|
72
|
-
<span class="sr-only">${this.
|
|
84
|
+
<span class="sr-only">${this.accessibleLabel}</span>
|
|
73
85
|
`;
|
|
74
86
|
}
|
|
75
87
|
renderShape() {
|
|
@@ -18,8 +18,8 @@ export const styles = css `
|
|
|
18
18
|
align-items: center;
|
|
19
19
|
vertical-align: middle;
|
|
20
20
|
line-height: 1;
|
|
21
|
-
--lyra-typing-dot-size:
|
|
22
|
-
--lyra-typing-gap:
|
|
21
|
+
--lyra-typing-dot-size: var(--lyra-space-s);
|
|
22
|
+
--lyra-typing-gap: var(--lyra-space-xs);
|
|
23
23
|
--lyra-typing-cursor-width: 0.125rem;
|
|
24
24
|
--lyra-typing-cursor-height: 1em;
|
|
25
25
|
}
|