@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,43 +7,11 @@ 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, deepActiveElement } from '../../internal/overlay-manager.js';
|
|
10
11
|
import { defineElement } from '../../internal/prefix.js';
|
|
11
12
|
import { lockScroll } from '../../internal/scroll-lock.js';
|
|
12
13
|
import { styles } from './responsive-panel.styles.js';
|
|
13
|
-
const
|
|
14
|
-
// Shadow-piercing so a slotted custom element's real focusable target (e.g.
|
|
15
|
-
// an <input> inside its own shadow root) is found even though the host tag
|
|
16
|
-
// itself doesn't match FOCUSABLE_SELECTOR. Deliberately duplicated from
|
|
17
|
-
// lyra-dialog's identical helper rather than imported/shared -- every
|
|
18
|
-
// overlay-shaped component in this family (lyra-dialog, lyra-widget,
|
|
19
|
-
// lyra-tool-result-dialog, lyra-tool-select-dialog) re-implements this
|
|
20
|
-
// locally rather than nesting a previous overlay component inside its own
|
|
21
|
-
// shadow DOM, because slot-forwarding would break the inner component's own
|
|
22
|
-
// light-DOM scanning.
|
|
23
|
-
function collectFocusable(el) {
|
|
24
|
-
const result = [];
|
|
25
|
-
if (el.matches(FOCUSABLE_SELECTOR)) {
|
|
26
|
-
result.push(el);
|
|
27
|
-
}
|
|
28
|
-
if (el instanceof HTMLSlotElement) {
|
|
29
|
-
for (const assigned of el.assignedElements({ flatten: true })) {
|
|
30
|
-
result.push(...collectFocusable(assigned));
|
|
31
|
-
}
|
|
32
|
-
return result;
|
|
33
|
-
}
|
|
34
|
-
const container = el.shadowRoot ?? el;
|
|
35
|
-
for (const child of Array.from(container.children)) {
|
|
36
|
-
result.push(...collectFocusable(child));
|
|
37
|
-
}
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
40
|
-
/** Whether `el` is actually laid out/paintable -- `checkVisibility()` (falling
|
|
41
|
-
* back to `getClientRects().length` where unsupported) correctly follows
|
|
42
|
-
* flattened-tree/slot assignment, unlike `offsetParent`. Mirrors
|
|
43
|
-
* lyra-dialog's identical helper. */
|
|
44
|
-
function isRendered(el) {
|
|
45
|
-
return el.checkVisibility ? el.checkVisibility() : el.getClientRects().length > 0;
|
|
46
|
-
}
|
|
14
|
+
const HEADING_SELECTOR = 'h1, h2, h3, h4, h5, h6, [role="heading"]';
|
|
47
15
|
/**
|
|
48
16
|
* Pure resolution of the `mode` prop + current viewport into the actual
|
|
49
17
|
* presentation. Kept separate from the `matchMedia` listener wiring below so
|
|
@@ -73,18 +41,26 @@ export function resolveEffectiveMode(mode, belowBreakpoint) {
|
|
|
73
41
|
* attributes and backdrop element, differ), so lit-html's diffing keeps
|
|
74
42
|
* `[part="body"]` and its `<slot>` as the same DOM node across the
|
|
75
43
|
* transition -- scroll position and focus inside the slotted content survive
|
|
76
|
-
* it for free
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
44
|
+
* it for free. When an open inline panel becomes modal, focus already inside
|
|
45
|
+
* is preserved and outside focus moves to the first available target. Closing
|
|
46
|
+
* still returns to the opener captured by the original inline open.
|
|
47
|
+
*
|
|
48
|
+
* The overlay presentation uses the library's shared overlay coordinator for
|
|
49
|
+
* focus trapping, Escape/backdrop dismissal, inerting, and stack ordering,
|
|
50
|
+
* while retaining this component's own responsive rendering and close event.
|
|
82
51
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
52
|
+
* Accessible name (overlay presentation only -- the inline presentation has
|
|
53
|
+
* no dialog semantics to name): `label`, when set, is used verbatim. When
|
|
54
|
+
* `label` is empty, this falls back to the `header` slot's content -- a
|
|
55
|
+
* heading element (`h1`–`h6` or `[role="heading"]`) among the slotted header
|
|
56
|
+
* content wins if present, otherwise the header slot's full text content is
|
|
57
|
+
* used, mirroring lyra-dialog's `detectHeading()`/`headingText` fallback (see
|
|
58
|
+
* dialog.ts's module doc for why this uses `aria-label`, a copied string,
|
|
59
|
+
* rather than `aria-labelledby`: the header content is light DOM while
|
|
60
|
+
* `[part="panel"]` lives in this element's shadow tree, and an ID-reference
|
|
61
|
+
* attribute can't resolve across that boundary). A panel opened without
|
|
62
|
+
* either `label` or header content still renders `role="dialog"` with no
|
|
63
|
+
* accessible name -- set one of the two to avoid that.
|
|
88
64
|
*
|
|
89
65
|
* @customElement lyra-responsive-panel
|
|
90
66
|
* @slot - The panel body.
|
|
@@ -126,7 +102,8 @@ export class LyraResponsivePanel extends LyraElement {
|
|
|
126
102
|
* height. */
|
|
127
103
|
this.variant = 'fullscreen';
|
|
128
104
|
/** Accessible name for the overlay presentation's `role="dialog"`. Unused in the inline
|
|
129
|
-
* presentation, which has no dialog semantics to name.
|
|
105
|
+
* presentation, which has no dialog semantics to name. When empty, falls back to the `header`
|
|
106
|
+
* slot's content -- see the class doc for the full fallback order. */
|
|
130
107
|
this.label = '';
|
|
131
108
|
/** CSS length passed to `matchMedia` as `(max-width: <this>)` to decide, in `mode="auto"`,
|
|
132
109
|
* whether the effective presentation is `'overlay'` (below/at this width) or `'inline'`
|
|
@@ -136,50 +113,25 @@ export class LyraResponsivePanel extends LyraElement {
|
|
|
136
113
|
this.effectiveMode = 'inline';
|
|
137
114
|
this.hasHeaderSlot = false;
|
|
138
115
|
this.hasFooterSlot = false;
|
|
139
|
-
/** Whether the overlay-only mechanics (scroll-lock
|
|
116
|
+
/** Whether the overlay-only mechanics (scroll-lock and shared overlay registration) are currently
|
|
140
117
|
* engaged -- derived from `effectiveMode === 'overlay' && open`, tracked separately from those
|
|
141
118
|
* two properties so willUpdate can diff "was engaged" vs "should be engaged now" regardless of
|
|
142
119
|
* which of the two changed. */
|
|
143
120
|
this.overlayChromeActive = false;
|
|
121
|
+
this.focusOverlayAfterUpdate = false;
|
|
144
122
|
this.isFirstUpdate = true;
|
|
145
123
|
this.onMediaChange = (e) => {
|
|
146
124
|
this.handleBreakpointChange(e.matches);
|
|
147
125
|
};
|
|
148
126
|
this.onHeaderSlotChange = (e) => {
|
|
149
127
|
this.hasHeaderSlot = e.target.assignedElements({ flatten: true }).length > 0;
|
|
128
|
+
this.headingText = this.detectHeadingText();
|
|
150
129
|
};
|
|
151
130
|
this.onFooterSlotChange = (e) => {
|
|
152
131
|
this.hasFooterSlot = e.target.assignedElements({ flatten: true }).length > 0;
|
|
153
132
|
};
|
|
154
133
|
this.onBackdropClick = () => {
|
|
155
|
-
this.
|
|
156
|
-
};
|
|
157
|
-
this.onDocKeyDown = (e) => {
|
|
158
|
-
if (!this.overlayChromeActive)
|
|
159
|
-
return;
|
|
160
|
-
if (e.key === 'Escape') {
|
|
161
|
-
e.preventDefault();
|
|
162
|
-
this.close('escape');
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
if (e.key !== 'Tab')
|
|
166
|
-
return;
|
|
167
|
-
const focusable = this.getFocusableElements();
|
|
168
|
-
if (focusable.length === 0) {
|
|
169
|
-
e.preventDefault();
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
const first = focusable[0];
|
|
173
|
-
const last = focusable[focusable.length - 1];
|
|
174
|
-
const active = this.getActiveElement();
|
|
175
|
-
if (e.shiftKey && active === first) {
|
|
176
|
-
e.preventDefault();
|
|
177
|
-
last.focus();
|
|
178
|
-
}
|
|
179
|
-
else if (!e.shiftKey && active === last) {
|
|
180
|
-
e.preventDefault();
|
|
181
|
-
first.focus();
|
|
182
|
-
}
|
|
134
|
+
this.overlayHandle?.dismissBackdrop();
|
|
183
135
|
};
|
|
184
136
|
}
|
|
185
137
|
static { this.styles = [LyraElement.styles, styles]; }
|
|
@@ -188,46 +140,69 @@ export class LyraResponsivePanel extends LyraElement {
|
|
|
188
140
|
if (this.isFirstUpdate) {
|
|
189
141
|
this.hasHeaderSlot = Array.from(this.children).some((el) => el.getAttribute('slot') === 'header');
|
|
190
142
|
this.hasFooterSlot = Array.from(this.children).some((el) => el.getAttribute('slot') === 'footer');
|
|
143
|
+
this.headingText = this.detectHeadingText();
|
|
144
|
+
}
|
|
145
|
+
// Must run before the effectiveMode computation below reads
|
|
146
|
+
// belowBreakpoint: setupMediaQuery() -> handleBreakpointChange() mutates
|
|
147
|
+
// belowBreakpoint synchronously, and a runtime mobileBreakpoint change is
|
|
148
|
+
// otherwise the only kind of change in this method that doesn't itself
|
|
149
|
+
// touch mode/belowBreakpoint, so computing effectiveMode first would read
|
|
150
|
+
// the not-yet-updated belowBreakpoint and never get another chance to
|
|
151
|
+
// react -- a property write from inside willUpdate doesn't schedule a
|
|
152
|
+
// fresh update, it only folds into the one already in progress.
|
|
153
|
+
// mobileBreakpoint is present on the very first willUpdate too (Lit's
|
|
154
|
+
// changed-properties map includes every class-field default from
|
|
155
|
+
// construction), but connectedCallback() already called setupMediaQuery()
|
|
156
|
+
// once before this first update runs, so repeating it here would be
|
|
157
|
+
// redundant -- only a live post-mount change should re-run it.
|
|
158
|
+
if (!this.isFirstUpdate && changed.has('mobileBreakpoint') && this.isConnected) {
|
|
159
|
+
this.setupMediaQuery();
|
|
191
160
|
}
|
|
192
161
|
if (this.isFirstUpdate || changed.has('mode') || changed.has('belowBreakpoint')) {
|
|
193
162
|
this.effectiveMode = resolveEffectiveMode(this.mode, this.belowBreakpoint);
|
|
194
163
|
}
|
|
195
|
-
|
|
196
|
-
|
|
164
|
+
// Captured on a genuine open transition only, independent of
|
|
165
|
+
// effectiveMode at that moment -- so it reflects whatever triggered the
|
|
166
|
+
// open even if a later breakpoint crossing (while still open) switches
|
|
167
|
+
// the presentation to overlay before close() runs. Deliberately not
|
|
168
|
+
// folded into the overlayOpen-engage branch below: that branch also
|
|
169
|
+
// fires when only effectiveMode (not open) changes, which would
|
|
170
|
+
// re-capture whatever currently has focus (e.g. something inside the
|
|
171
|
+
// panel) instead of the original external trigger.
|
|
172
|
+
if (changed.has('open') && this.open) {
|
|
173
|
+
const active = deepActiveElement(this.ownerDocument);
|
|
174
|
+
this.lastTrigger = active && typeof active.focus === 'function' ? active : undefined;
|
|
197
175
|
}
|
|
198
176
|
const overlayOpen = this.effectiveMode === 'overlay' && this.open;
|
|
199
177
|
if (overlayOpen !== this.overlayChromeActive) {
|
|
200
178
|
this.overlayChromeActive = overlayOpen;
|
|
201
179
|
if (overlayOpen) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
180
|
+
this.activateOverlayChrome();
|
|
181
|
+
// Once the presentation becomes modal, focus cannot remain behind
|
|
182
|
+
// it. The manager preserves focus that is already inside the panel
|
|
183
|
+
// and otherwise moves it to the first composed focus target.
|
|
184
|
+
this.focusOverlayAfterUpdate = true;
|
|
206
185
|
}
|
|
207
186
|
else {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
187
|
+
// Removing modal chrome while the still-open panel becomes inline
|
|
188
|
+
// must preserve focus in that same panel. Only a real open -> closed
|
|
189
|
+
// transition restores the opener.
|
|
190
|
+
this.deactivateOverlayChrome(changed.has('open') && !this.open);
|
|
211
191
|
}
|
|
212
192
|
}
|
|
193
|
+
if (changed.has('open') && !this.open)
|
|
194
|
+
this.lastTrigger = undefined;
|
|
213
195
|
}
|
|
214
196
|
// Runs after render (not willUpdate) so [part="panel"] has already landed
|
|
215
197
|
// in the DOM before the fallback .focus() call below can rely on it --
|
|
216
|
-
// mirrors lyra-dialog's identical ordering rationale.
|
|
217
|
-
// transition steals focus (see the class doc for why a breakpoint-crossing
|
|
218
|
-
// while already open deliberately does not).
|
|
198
|
+
// mirrors lyra-dialog's identical ordering rationale.
|
|
219
199
|
updated(changed) {
|
|
220
200
|
if (!this.isFirstUpdate && changed.has('effectiveMode')) {
|
|
221
201
|
this.emit('lyra-mode-change', { mode: this.effectiveMode });
|
|
222
202
|
}
|
|
223
|
-
if (
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
first.focus();
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
this.shadowRoot?.querySelector('[part="panel"]')?.focus();
|
|
230
|
-
}
|
|
203
|
+
if (this.focusOverlayAfterUpdate) {
|
|
204
|
+
this.focusOverlayAfterUpdate = false;
|
|
205
|
+
this.overlayHandle?.focusInitial();
|
|
231
206
|
}
|
|
232
207
|
}
|
|
233
208
|
connectedCallback() {
|
|
@@ -237,10 +212,17 @@ export class LyraResponsivePanel extends LyraElement {
|
|
|
237
212
|
// instance) fires disconnectedCallback then connectedCallback
|
|
238
213
|
// synchronously with no update in between, so willUpdate never reruns to
|
|
239
214
|
// notice overlay chrome is still supposed to be active -- restore it.
|
|
240
|
-
|
|
241
|
-
if (this.hasUpdated &&
|
|
242
|
-
this.
|
|
243
|
-
|
|
215
|
+
const overlayOpen = resolveEffectiveMode(this.mode, this.belowBreakpoint) === 'overlay' && this.open;
|
|
216
|
+
if (this.hasUpdated && overlayOpen) {
|
|
217
|
+
if (this.overlayHandle?.isActive()) {
|
|
218
|
+
this.overlayHandle.resume();
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
this.activateOverlayChrome();
|
|
222
|
+
}
|
|
223
|
+
if (!this.releaseScrollLock)
|
|
224
|
+
this.releaseScrollLock = lockScroll(this.ownerDocument);
|
|
225
|
+
queueMicrotask(() => this.overlayHandle?.focusInitial());
|
|
244
226
|
}
|
|
245
227
|
}
|
|
246
228
|
disconnectedCallback() {
|
|
@@ -249,11 +231,32 @@ export class LyraResponsivePanel extends LyraElement {
|
|
|
249
231
|
this.mediaQuery = undefined;
|
|
250
232
|
this.releaseScrollLock?.();
|
|
251
233
|
this.releaseScrollLock = undefined;
|
|
252
|
-
|
|
234
|
+
this.overlayHandle?.suspend();
|
|
235
|
+
}
|
|
236
|
+
activateOverlayChrome() {
|
|
237
|
+
this.releaseScrollLock ??= lockScroll(this.ownerDocument);
|
|
238
|
+
this.overlayHandle = activateOverlay({
|
|
239
|
+
host: this,
|
|
240
|
+
panel: () => this.shadowRoot?.querySelector('[part="panel"]') ?? null,
|
|
241
|
+
onEscape: () => this.close('escape'),
|
|
242
|
+
onBackdrop: () => this.close('backdrop'),
|
|
243
|
+
restoreFocusTo: this.lastTrigger ?? null,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
deactivateOverlayChrome(restoreFocus = true) {
|
|
247
|
+
this.releaseScrollLock?.();
|
|
248
|
+
this.releaseScrollLock = undefined;
|
|
249
|
+
this.overlayHandle?.deactivate({ restoreFocus });
|
|
250
|
+
this.overlayHandle = undefined;
|
|
253
251
|
}
|
|
254
252
|
setupMediaQuery() {
|
|
255
253
|
this.mediaQuery?.removeEventListener('change', this.onMediaChange);
|
|
256
|
-
|
|
254
|
+
const view = this.ownerDocument.defaultView;
|
|
255
|
+
if (!view?.matchMedia) {
|
|
256
|
+
this.mediaQuery = undefined;
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
this.mediaQuery = view.matchMedia(`(max-width: ${this.mobileBreakpoint})`);
|
|
257
260
|
this.mediaQuery.addEventListener('change', this.onMediaChange);
|
|
258
261
|
this.handleBreakpointChange(this.mediaQuery.matches);
|
|
259
262
|
}
|
|
@@ -263,6 +266,27 @@ export class LyraResponsivePanel extends LyraElement {
|
|
|
263
266
|
handleBreakpointChange(matches) {
|
|
264
267
|
this.belowBreakpoint = matches;
|
|
265
268
|
}
|
|
269
|
+
// Only direct children slotted into `header` are scanned -- same depth
|
|
270
|
+
// limit lyra-dialog's own detectHeading() applies to its direct children.
|
|
271
|
+
// A heading tag among them wins (its own text only, so a header slot mixing
|
|
272
|
+
// a heading with e.g. a trailing icon button doesn't pull the button's
|
|
273
|
+
// label into the accessible name); otherwise the header slot's combined
|
|
274
|
+
// text stands in for it, since this component (unlike lyra-dialog) has a
|
|
275
|
+
// dedicated header slot that's already the conventional place a heading
|
|
276
|
+
// would go. Recomputed only on slot assignment changes, not on every
|
|
277
|
+
// render -- same rationale as lyra-dialog's detectHeading().
|
|
278
|
+
detectHeadingText() {
|
|
279
|
+
const headerChildren = Array.from(this.children).filter((el) => el.getAttribute('slot') === 'header');
|
|
280
|
+
if (headerChildren.length === 0)
|
|
281
|
+
return undefined;
|
|
282
|
+
const heading = headerChildren.find((el) => el.matches(HEADING_SELECTOR));
|
|
283
|
+
if (heading)
|
|
284
|
+
return heading.textContent?.trim() || undefined;
|
|
285
|
+
return (headerChildren
|
|
286
|
+
.map((el) => el.textContent?.trim())
|
|
287
|
+
.filter(Boolean)
|
|
288
|
+
.join(' ') || undefined);
|
|
289
|
+
}
|
|
266
290
|
/**
|
|
267
291
|
* Close the panel. `reason` is forwarded as the `lyra-close` detail --
|
|
268
292
|
* built-in overlay triggers pass `'escape'`/`'backdrop'`; a consumer's own
|
|
@@ -278,39 +302,10 @@ export class LyraResponsivePanel extends LyraElement {
|
|
|
278
302
|
return;
|
|
279
303
|
this.open = false;
|
|
280
304
|
this.emit('lyra-close', reason);
|
|
281
|
-
if (this.effectiveMode === 'overlay') {
|
|
282
|
-
this.lastTrigger?.focus();
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
// Bounds Tab/Shift+Tab to the panel while overlay chrome is active. Order
|
|
286
|
-
// follows the header slot, then the body slot, then the footer slot -- the
|
|
287
|
-
// same order the flattened tree already tabs through.
|
|
288
|
-
getFocusableElements() {
|
|
289
|
-
const root = this.shadowRoot;
|
|
290
|
-
if (!root)
|
|
291
|
-
return [];
|
|
292
|
-
const fromSlot = (selector) => {
|
|
293
|
-
const slot = root.querySelector(selector);
|
|
294
|
-
return slot ? slot.assignedElements({ flatten: true }).flatMap(collectFocusable) : [];
|
|
295
|
-
};
|
|
296
|
-
return [
|
|
297
|
-
...fromSlot('slot[name="header"]'),
|
|
298
|
-
...fromSlot('slot:not([name])'),
|
|
299
|
-
...fromSlot('slot[name="footer"]'),
|
|
300
|
-
].filter(isRendered);
|
|
301
|
-
}
|
|
302
|
-
getActiveElement() {
|
|
303
|
-
let active = document.activeElement;
|
|
304
|
-
while (active) {
|
|
305
|
-
const inner = active.shadowRoot?.activeElement ?? null;
|
|
306
|
-
if (!inner)
|
|
307
|
-
break;
|
|
308
|
-
active = inner;
|
|
309
|
-
}
|
|
310
|
-
return active;
|
|
311
305
|
}
|
|
312
306
|
render() {
|
|
313
307
|
const overlay = this.effectiveMode === 'overlay';
|
|
308
|
+
const accessibleName = this.label || this.headingText;
|
|
314
309
|
return html `
|
|
315
310
|
<div part="base" class=${overlay ? 'overlay' : 'inline'}>
|
|
316
311
|
${overlay ? html `<div part="backdrop" @click=${this.onBackdropClick}></div>` : nothing}
|
|
@@ -318,7 +313,7 @@ export class LyraResponsivePanel extends LyraElement {
|
|
|
318
313
|
part="panel"
|
|
319
314
|
role=${overlay ? 'dialog' : nothing}
|
|
320
315
|
aria-modal=${overlay ? 'true' : nothing}
|
|
321
|
-
aria-label=${overlay &&
|
|
316
|
+
aria-label=${overlay && accessibleName ? accessibleName : nothing}
|
|
322
317
|
tabindex=${overlay ? '-1' : nothing}
|
|
323
318
|
>
|
|
324
319
|
<div part="header" ?hidden=${!this.hasHeaderSlot}>
|
|
@@ -362,4 +357,7 @@ __decorate([
|
|
|
362
357
|
__decorate([
|
|
363
358
|
state()
|
|
364
359
|
], LyraResponsivePanel.prototype, "hasFooterSlot", void 0);
|
|
360
|
+
__decorate([
|
|
361
|
+
state()
|
|
362
|
+
], LyraResponsivePanel.prototype, "headingText", void 0);
|
|
365
363
|
defineElement('responsive-panel', LyraResponsivePanel);
|
|
@@ -24,7 +24,7 @@ export const styles = css `
|
|
|
24
24
|
display: flex;
|
|
25
25
|
position: fixed;
|
|
26
26
|
inset: 0;
|
|
27
|
-
z-index: 1000;
|
|
27
|
+
z-index: var(--lyra-overlay-stack-index, 1000);
|
|
28
28
|
}
|
|
29
29
|
/* Bottom-sheet anchors its panel to the block-end edge instead of
|
|
30
30
|
stretching it full-height like fullscreen does. */
|
|
@@ -22,7 +22,10 @@ import { LyraElement } from '../../internal/lyra-element.js';
|
|
|
22
22
|
* `actions` is still observed) but `hidden` whenever there is no `title`
|
|
23
23
|
* and no `actions` content — an untitled, action-less card has no visible
|
|
24
24
|
* header bar at all.
|
|
25
|
-
* @csspart title - The title text.
|
|
25
|
+
* @csspart title - The title text. Truncates with an ellipsis when it
|
|
26
|
+
* overflows; carries its own native `title` attribute (the full string) so
|
|
27
|
+
* hovering the truncated text reveals it via the browser's default tooltip,
|
|
28
|
+
* scoped to just this element rather than the whole card.
|
|
26
29
|
* @csspart actions - The wrapper around the `actions` slot. `hidden`
|
|
27
30
|
* whenever the slot has no assigned content.
|
|
28
31
|
* @csspart body - The wrapper around the default slot.
|
|
@@ -30,7 +33,10 @@ import { LyraElement } from '../../internal/lyra-element.js';
|
|
|
30
33
|
export declare class LyraResultCard extends LyraElement {
|
|
31
34
|
static styles: import("lit").CSSResultGroup[];
|
|
32
35
|
/** Small heading for the card. Leave unset for an untitled card (e.g. a
|
|
33
|
-
* bare block of `<lyra-result-field>` rows with no natural heading).
|
|
36
|
+
* bare block of `<lyra-result-field>` rows with no natural heading).
|
|
37
|
+
* Rendered into the truncating `[part="title"]` span, which also carries
|
|
38
|
+
* this value as its own `title` attribute so the disclosure tooltip is
|
|
39
|
+
* scoped to that element rather than the whole host. */
|
|
34
40
|
title: string;
|
|
35
41
|
private hasActionsSlot;
|
|
36
42
|
protected willUpdate(): void;
|
|
@@ -31,7 +31,10 @@ import { styles } from './result-card.styles.js';
|
|
|
31
31
|
* `actions` is still observed) but `hidden` whenever there is no `title`
|
|
32
32
|
* and no `actions` content — an untitled, action-less card has no visible
|
|
33
33
|
* header bar at all.
|
|
34
|
-
* @csspart title - The title text.
|
|
34
|
+
* @csspart title - The title text. Truncates with an ellipsis when it
|
|
35
|
+
* overflows; carries its own native `title` attribute (the full string) so
|
|
36
|
+
* hovering the truncated text reveals it via the browser's default tooltip,
|
|
37
|
+
* scoped to just this element rather than the whole card.
|
|
35
38
|
* @csspart actions - The wrapper around the `actions` slot. `hidden`
|
|
36
39
|
* whenever the slot has no assigned content.
|
|
37
40
|
* @csspart body - The wrapper around the default slot.
|
|
@@ -40,7 +43,10 @@ export class LyraResultCard extends LyraElement {
|
|
|
40
43
|
constructor() {
|
|
41
44
|
super(...arguments);
|
|
42
45
|
/** Small heading for the card. Leave unset for an untitled card (e.g. a
|
|
43
|
-
* bare block of `<lyra-result-field>` rows with no natural heading).
|
|
46
|
+
* bare block of `<lyra-result-field>` rows with no natural heading).
|
|
47
|
+
* Rendered into the truncating `[part="title"]` span, which also carries
|
|
48
|
+
* this value as its own `title` attribute so the disclosure tooltip is
|
|
49
|
+
* scoped to that element rather than the whole host. */
|
|
44
50
|
this.title = '';
|
|
45
51
|
// See `<lyra-widget>`'s identical `hasActionsSlot` -- a `[part]` wrapper
|
|
46
52
|
// always contains a literal `<slot>` child regardless of assigned
|
|
@@ -64,7 +70,7 @@ export class LyraResultCard extends LyraElement {
|
|
|
64
70
|
return html `
|
|
65
71
|
<div part="base">
|
|
66
72
|
<div part="header" ?hidden=${!hasHeader}>
|
|
67
|
-
${hasTitle ? html `<span part="title">${this.title}</span>` : nothing}
|
|
73
|
+
${hasTitle ? html `<span part="title" title=${this.title}>${this.title}</span>` : nothing}
|
|
68
74
|
<div part="actions" ?hidden=${!this.hasActionsSlot}>
|
|
69
75
|
<slot name="actions" @slotchange=${this.onActionsSlotChange}></slot>
|
|
70
76
|
</div>
|
|
@@ -21,16 +21,21 @@ export type LyraSelectSize = 'xs' | 's' | 'm' | 'l' | 'xl';
|
|
|
21
21
|
* "active" row is conveyed via `aria-activedescendant`, never actual focus),
|
|
22
22
|
* matching the WAI-ARIA "select-only combobox" pattern.
|
|
23
23
|
*
|
|
24
|
-
* When exactly one option is enabled
|
|
25
|
-
* exist alongside it), the popup never
|
|
26
|
-
* ArrowDown, or ArrowUp on the trigger
|
|
27
|
-
* and the trigger renders as a plain
|
|
28
|
-
* `aria-haspopup`/`aria-expanded` rather than
|
|
29
|
-
* inert popup state — opening a one-row list to
|
|
30
|
-
* choice is pure friction with no real decision
|
|
31
|
-
* changes `value`/validity defaults on its own — an
|
|
32
|
-
* select stays unselected (and a `required` one
|
|
33
|
-
* the multi-option case, until the trigger is
|
|
24
|
+
* When `autoCommitSingleOption` is set and exactly one option is enabled
|
|
25
|
+
* (regardless of how many disabled ones exist alongside it), the popup never
|
|
26
|
+
* opens at all: a click, Enter, Space, ArrowDown, or ArrowUp on the trigger
|
|
27
|
+
* commits that sole option directly, and the trigger renders as a plain
|
|
28
|
+
* `role="button"` with no chevron/`aria-haspopup`/`aria-expanded` rather than
|
|
29
|
+
* a combobox with a permanently inert popup state — opening a one-row list to
|
|
30
|
+
* pick the only available choice is pure friction with no real decision
|
|
31
|
+
* behind it. This never changes `value`/validity defaults on its own — an
|
|
32
|
+
* unselected single-option select stays unselected (and a `required` one
|
|
33
|
+
* stays invalid) exactly like the multi-option case, until the trigger is
|
|
34
|
+
* actually activated. `autoCommitSingleOption` defaults to `false`: by
|
|
35
|
+
* default a select always renders the normal combobox/listbox/chevron
|
|
36
|
+
* trigger no matter how many options are enabled, matching pre-1.3.0
|
|
37
|
+
* behavior — opt in explicitly if a narrowing-to-one option list should
|
|
38
|
+
* auto-commit.
|
|
34
39
|
*
|
|
35
40
|
* @customElement lyra-select
|
|
36
41
|
* @slot - `<lyra-option>` elements.
|
|
@@ -58,6 +63,16 @@ export declare class LyraSelect extends LyraElement {
|
|
|
58
63
|
static formAssociated: boolean;
|
|
59
64
|
static styles: import("lit").CSSResultGroup[];
|
|
60
65
|
static properties: {
|
|
66
|
+
disabled: {
|
|
67
|
+
type: BooleanConstructor;
|
|
68
|
+
reflect: boolean;
|
|
69
|
+
noAccessor: boolean;
|
|
70
|
+
};
|
|
71
|
+
required: {
|
|
72
|
+
type: BooleanConstructor;
|
|
73
|
+
reflect: boolean;
|
|
74
|
+
noAccessor: boolean;
|
|
75
|
+
};
|
|
61
76
|
value: {
|
|
62
77
|
noAccessor: boolean;
|
|
63
78
|
};
|
|
@@ -67,14 +82,22 @@ export declare class LyraSelect extends LyraElement {
|
|
|
67
82
|
};
|
|
68
83
|
};
|
|
69
84
|
placeholder: string;
|
|
70
|
-
disabled: boolean;
|
|
71
|
-
required: boolean;
|
|
72
85
|
label: string;
|
|
73
86
|
hint: string;
|
|
74
87
|
errorText: string;
|
|
75
88
|
open: boolean;
|
|
76
89
|
/** Visual size — same `xs`–`xl` scale as `lyra-toast-item`'s `size`. */
|
|
77
90
|
size: LyraSelectSize;
|
|
91
|
+
/**
|
|
92
|
+
* Opt-in: when `true` and exactly one `<lyra-option>` is enabled, the
|
|
93
|
+
* trigger commits that option directly (click/Enter/Space/ArrowDown/
|
|
94
|
+
* ArrowUp) instead of opening the listbox, and renders as a plain
|
|
95
|
+
* `role="button"` with no chevron. Defaults to `false`, which always
|
|
96
|
+
* renders the normal combobox/listbox/chevron trigger regardless of how
|
|
97
|
+
* many options are enabled — the pre-1.3.0 behavior. See the class doc
|
|
98
|
+
* above and `onlyOption` below for the full rationale.
|
|
99
|
+
*/
|
|
100
|
+
autoCommitSingleOption: boolean;
|
|
78
101
|
private activeIndex;
|
|
79
102
|
private options;
|
|
80
103
|
private touched;
|
|
@@ -82,22 +105,35 @@ export declare class LyraSelect extends LyraElement {
|
|
|
82
105
|
private hasErrorSlot;
|
|
83
106
|
private hasLabelSlot;
|
|
84
107
|
private internals;
|
|
108
|
+
private validityController;
|
|
85
109
|
private _fieldsetDisabled;
|
|
86
110
|
private listId;
|
|
87
111
|
private triggerId;
|
|
88
112
|
private cleanup?;
|
|
89
113
|
private _isFirstUpdate;
|
|
90
114
|
private _selected;
|
|
115
|
+
private _disabled;
|
|
116
|
+
private _required;
|
|
91
117
|
private _defaultSelected;
|
|
92
118
|
private _defaultCaptured;
|
|
119
|
+
private _restoredStateActive;
|
|
93
120
|
private typeAheadBuffer;
|
|
94
121
|
private typeAheadTimer?;
|
|
95
122
|
private _name;
|
|
96
123
|
constructor();
|
|
124
|
+
get form(): HTMLFormElement | null;
|
|
125
|
+
get labels(): NodeList;
|
|
126
|
+
get validity(): ValidityState;
|
|
127
|
+
get validationMessage(): string;
|
|
128
|
+
get willValidate(): boolean;
|
|
97
129
|
connectedCallback(): void;
|
|
98
130
|
protected willUpdate(): void;
|
|
99
131
|
get name(): string;
|
|
100
132
|
set name(next: string);
|
|
133
|
+
get disabled(): boolean;
|
|
134
|
+
set disabled(next: boolean);
|
|
135
|
+
get required(): boolean;
|
|
136
|
+
set required(next: boolean);
|
|
101
137
|
/** The selected value: a single string (empty when nothing is selected). */
|
|
102
138
|
get value(): string;
|
|
103
139
|
set value(next: string);
|
|
@@ -108,6 +144,7 @@ export declare class LyraSelect extends LyraElement {
|
|
|
108
144
|
* own `disabled` IDL property/attribute is never mutated by a fieldset. */
|
|
109
145
|
get effectiveDisabled(): boolean;
|
|
110
146
|
formResetCallback(): void;
|
|
147
|
+
formStateRestoreCallback(state: string | File | FormData | null, _mode?: 'restore' | 'autocomplete'): void;
|
|
111
148
|
/**
|
|
112
149
|
* Called by the browser when an ancestor `<fieldset disabled>` toggles.
|
|
113
150
|
* Tracked separately from the consumer's own `disabled` (see
|
|
@@ -121,14 +158,16 @@ export declare class LyraSelect extends LyraElement {
|
|
|
121
158
|
private collectOptions;
|
|
122
159
|
private reflectSelected;
|
|
123
160
|
/**
|
|
124
|
-
* The sole navigable (non-disabled) option, when
|
|
125
|
-
* popup to pick the only available choice is pure
|
|
126
|
-
* it, so
|
|
127
|
-
* which commit this option directly on
|
|
128
|
-
* `render()`, which drops the popup-trigger
|
|
129
|
-
* `aria-haspopup`, `aria-expanded`, the chevron) in favor
|
|
130
|
-
* popup can ever appear while this getter returns a value.
|
|
131
|
-
*
|
|
161
|
+
* The sole navigable (non-disabled) option, when `autoCommitSingleOption` is set and
|
|
162
|
+
* there's exactly one. Opening a one-row popup to pick the only available choice is pure
|
|
163
|
+
* friction with no real decision behind it, so an opted-in single-option select skips the
|
|
164
|
+
* popup entirely -- see `onTriggerClick`/`onKeyDown`, which commit this option directly on
|
|
165
|
+
* activation instead of opening the listbox, and `render()`, which drops the popup-trigger
|
|
166
|
+
* ARIA semantics (`role="combobox"`, `aria-haspopup`, `aria-expanded`, the chevron) in favor
|
|
167
|
+
* of a plain button's, since no popup can ever appear while this getter returns a value.
|
|
168
|
+
* Returns `undefined` whenever `autoCommitSingleOption` is `false` (the default), regardless
|
|
169
|
+
* of option count, so the normal combobox trigger renders unconditionally. Does not affect
|
|
170
|
+
* `value`/validity defaults in any way -- an unselected single-option select stays unselected
|
|
132
171
|
* until the trigger is actually activated, exactly like the multi-option case.
|
|
133
172
|
*/
|
|
134
173
|
private get onlyOption();
|