@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,47 +7,12 @@ 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, collectFocusableElements, 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 { nextId } from '../../internal/a11y.js';
|
|
13
14
|
import { chevronIcon, closeIcon, expandIcon } from '../../internal/icons.js';
|
|
14
15
|
import { styles } from './widget.styles.js';
|
|
15
|
-
const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
16
|
-
// Shadow-piercing so a slotted custom element's real focusable target (e.g.
|
|
17
|
-
// an <input> inside its own shadow root) is found even though the host tag
|
|
18
|
-
// itself doesn't match FOCUSABLE_SELECTOR.
|
|
19
|
-
function collectFocusable(el) {
|
|
20
|
-
const result = [];
|
|
21
|
-
if (el.matches(FOCUSABLE_SELECTOR)) {
|
|
22
|
-
result.push(el);
|
|
23
|
-
}
|
|
24
|
-
if (el instanceof HTMLSlotElement) {
|
|
25
|
-
for (const assigned of el.assignedElements({ flatten: true })) {
|
|
26
|
-
result.push(...collectFocusable(assigned));
|
|
27
|
-
}
|
|
28
|
-
return result;
|
|
29
|
-
}
|
|
30
|
-
const container = el.shadowRoot ?? el;
|
|
31
|
-
for (const child of Array.from(container.children)) {
|
|
32
|
-
result.push(...collectFocusable(child));
|
|
33
|
-
}
|
|
34
|
-
return result;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Whether `el` is actually laid out/paintable — used to drop e.g. a
|
|
38
|
-
* `[collapsed]` body's slotted content from the fullscreen tab order.
|
|
39
|
-
* `el.offsetParent !== null` is the usual shorthand for this, but it's
|
|
40
|
-
* unreliable here: it resolves `null` for an element whose nearest
|
|
41
|
-
* *positioned* ancestor (fullscreen's `[part="base"] { position: fixed }`)
|
|
42
|
-
* lives across a slot-projection boundary from the element itself (true for
|
|
43
|
-
* every element this scans, since they're all slotted content), even though
|
|
44
|
-
* the element is genuinely rendered. `checkVisibility()` (falling back to
|
|
45
|
-
* `getClientRects().length` on engines without it) correctly follows
|
|
46
|
-
* flattened-tree/slot assignment instead.
|
|
47
|
-
*/
|
|
48
|
-
function isRendered(el) {
|
|
49
|
-
return el.checkVisibility ? el.checkVisibility() : el.getClientRects().length > 0;
|
|
50
|
-
}
|
|
51
16
|
/**
|
|
52
17
|
* `<lyra-widget>` — a titled panel shell with an optional collapse toggle and
|
|
53
18
|
* an optional fullscreen-expand toggle. Fullscreen promotes the same host
|
|
@@ -99,48 +64,19 @@ export class LyraWidget extends LyraElement {
|
|
|
99
64
|
this.emit('lyra-collapse-change', this.collapsed);
|
|
100
65
|
};
|
|
101
66
|
this.toggleFullscreen = (e) => {
|
|
102
|
-
this.
|
|
67
|
+
if (!this.fullscreen)
|
|
68
|
+
this.explicitTrigger = e.currentTarget;
|
|
103
69
|
this.fullscreen = !this.fullscreen;
|
|
104
70
|
this.emit('lyra-fullscreen-change', this.fullscreen);
|
|
105
|
-
if (!this.fullscreen) {
|
|
106
|
-
this.lastTrigger?.focus();
|
|
107
|
-
}
|
|
108
71
|
};
|
|
109
|
-
this.
|
|
110
|
-
if (!this.fullscreen)
|
|
111
|
-
return;
|
|
112
|
-
if (e.key === 'Escape') {
|
|
113
|
-
e.preventDefault();
|
|
114
|
-
this.fullscreen = false;
|
|
115
|
-
this.emit('lyra-fullscreen-change', false);
|
|
116
|
-
this.lastTrigger?.focus();
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
if (e.key !== 'Tab')
|
|
120
|
-
return;
|
|
121
|
-
const focusable = this.getFocusableElements();
|
|
122
|
-
if (focusable.length === 0) {
|
|
123
|
-
e.preventDefault();
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const first = focusable[0];
|
|
127
|
-
const last = focusable[focusable.length - 1];
|
|
128
|
-
const active = this.getActiveElement();
|
|
129
|
-
if (e.shiftKey && active === first) {
|
|
130
|
-
e.preventDefault();
|
|
131
|
-
last.focus();
|
|
132
|
-
}
|
|
133
|
-
else if (!e.shiftKey && active === last) {
|
|
134
|
-
e.preventDefault();
|
|
135
|
-
first.focus();
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
this.onBackdropClick = () => {
|
|
72
|
+
this.dismissFullscreen = () => {
|
|
139
73
|
if (!this.fullscreen)
|
|
140
74
|
return;
|
|
141
75
|
this.fullscreen = false;
|
|
142
76
|
this.emit('lyra-fullscreen-change', false);
|
|
143
|
-
|
|
77
|
+
};
|
|
78
|
+
this.onBackdropClick = () => {
|
|
79
|
+
this.overlayHandle?.dismissBackdrop();
|
|
144
80
|
};
|
|
145
81
|
}
|
|
146
82
|
static { this.styles = [LyraElement.styles, styles]; }
|
|
@@ -150,13 +86,10 @@ export class LyraWidget extends LyraElement {
|
|
|
150
86
|
}
|
|
151
87
|
if (changed.has('fullscreen')) {
|
|
152
88
|
if (this.fullscreen) {
|
|
153
|
-
this.
|
|
154
|
-
document.addEventListener('keydown', this.onDocKeyDown);
|
|
89
|
+
this.activateFullscreenOverlay();
|
|
155
90
|
}
|
|
156
91
|
else {
|
|
157
|
-
this.
|
|
158
|
-
this.releaseScrollLock = undefined;
|
|
159
|
-
document.removeEventListener('keydown', this.onDocKeyDown);
|
|
92
|
+
this.deactivateFullscreenOverlay();
|
|
160
93
|
}
|
|
161
94
|
}
|
|
162
95
|
}
|
|
@@ -167,14 +100,23 @@ export class LyraWidget extends LyraElement {
|
|
|
167
100
|
// because a mouse click natively focuses the button that triggered it --
|
|
168
101
|
// not true for a directly-set `fullscreen` property, and not guaranteed
|
|
169
102
|
// for every input method/browser even in the click case.
|
|
103
|
+
//
|
|
104
|
+
// The `collapsed` branch covers the same modal-focus-trap requirement for
|
|
105
|
+
// a second case: collapsing the body while fullscreen hides (display:none)
|
|
106
|
+
// whatever was focused inside it, which the browser resolves by silently
|
|
107
|
+
// moving focus outside the panel. The shared manager then reclaims it while
|
|
108
|
+
// preserving focus that is still on one of the visible header controls.
|
|
170
109
|
updated(changed) {
|
|
171
110
|
if (changed.has('fullscreen') && this.fullscreen) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
111
|
+
this.overlayHandle?.focusInitial();
|
|
112
|
+
}
|
|
113
|
+
else if (changed.has('collapsed') && this.fullscreen) {
|
|
114
|
+
const panel = this.shadowRoot?.querySelector('[part="base"]');
|
|
115
|
+
const active = deepActiveElement(this.ownerDocument);
|
|
116
|
+
if (panel && !collectFocusableElements(panel).includes(active)) {
|
|
117
|
+
if (active && typeof active.blur === 'function')
|
|
118
|
+
active.blur();
|
|
119
|
+
this.overlayHandle?.focusInitial();
|
|
178
120
|
}
|
|
179
121
|
}
|
|
180
122
|
}
|
|
@@ -183,49 +125,42 @@ export class LyraWidget extends LyraElement {
|
|
|
183
125
|
// A reconnect (e.g. a drag-and-drop reparent that keeps this same
|
|
184
126
|
// element instance) fires disconnectedCallback then connectedCallback
|
|
185
127
|
// synchronously with no update in between, so willUpdate never reruns
|
|
186
|
-
// to notice `fullscreen` is still true. Restore the
|
|
187
|
-
//
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
128
|
+
// to notice `fullscreen` is still true. Restore the shared overlay
|
|
129
|
+
// registration and scroll lock it dropped.
|
|
130
|
+
if (this.hasUpdated && this.fullscreen) {
|
|
131
|
+
if (this.overlayHandle?.isActive()) {
|
|
132
|
+
this.overlayHandle.resume();
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
this.activateFullscreenOverlay();
|
|
136
|
+
}
|
|
137
|
+
if (!this.releaseScrollLock)
|
|
138
|
+
this.releaseScrollLock = lockScroll(this.ownerDocument);
|
|
139
|
+
queueMicrotask(() => this.overlayHandle?.focusInitial());
|
|
192
140
|
}
|
|
193
141
|
}
|
|
194
142
|
disconnectedCallback() {
|
|
195
143
|
super.disconnectedCallback();
|
|
196
144
|
this.releaseScrollLock?.();
|
|
197
145
|
this.releaseScrollLock = undefined;
|
|
198
|
-
|
|
146
|
+
this.overlayHandle?.suspend();
|
|
199
147
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const slot = root.querySelector(selector);
|
|
211
|
-
return slot ? slot.assignedElements({ flatten: true }).flatMap(collectFocusable) : [];
|
|
212
|
-
};
|
|
213
|
-
const shadowButtons = Array.from(root.querySelectorAll('[part="collapse-button"], [part="fullscreen-button"]'));
|
|
214
|
-
return [
|
|
215
|
-
...fromSlot('slot[name="actions"]'),
|
|
216
|
-
...shadowButtons,
|
|
217
|
-
...fromSlot('[part="body"] slot:not([name])'),
|
|
218
|
-
].filter(isRendered);
|
|
148
|
+
activateFullscreenOverlay() {
|
|
149
|
+
this.releaseScrollLock ??= lockScroll(this.ownerDocument);
|
|
150
|
+
this.overlayHandle = activateOverlay({
|
|
151
|
+
host: this,
|
|
152
|
+
panel: () => this.shadowRoot?.querySelector('[part="base"]') ?? null,
|
|
153
|
+
onEscape: this.dismissFullscreen,
|
|
154
|
+
onBackdrop: this.dismissFullscreen,
|
|
155
|
+
restoreFocusTo: this.explicitTrigger,
|
|
156
|
+
});
|
|
157
|
+
this.explicitTrigger = undefined;
|
|
219
158
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
break;
|
|
226
|
-
active = inner;
|
|
227
|
-
}
|
|
228
|
-
return active;
|
|
159
|
+
deactivateFullscreenOverlay() {
|
|
160
|
+
this.releaseScrollLock?.();
|
|
161
|
+
this.releaseScrollLock = undefined;
|
|
162
|
+
this.overlayHandle?.deactivate();
|
|
163
|
+
this.overlayHandle = undefined;
|
|
229
164
|
}
|
|
230
165
|
render() {
|
|
231
166
|
const hasLabel = this.label.length > 0;
|
|
@@ -261,11 +196,10 @@ export class LyraWidget extends LyraElement {
|
|
|
261
196
|
aria-expanded=${this.collapsed ? 'false' : 'true'}
|
|
262
197
|
aria-label=${this.collapsed ? 'Expand panel' : 'Collapse panel'}
|
|
263
198
|
aria-controls=${this.bodyId}
|
|
199
|
+
style="transform:rotate(${this.collapsed ? '0deg' : '90deg'})"
|
|
264
200
|
@click=${this.toggleCollapsed}
|
|
265
201
|
>
|
|
266
|
-
|
|
267
|
-
>${chevronIcon()}</span
|
|
268
|
-
>
|
|
202
|
+
${chevronIcon()}
|
|
269
203
|
</button>`
|
|
270
204
|
: nothing}
|
|
271
205
|
${this.expandable
|
|
@@ -29,6 +29,12 @@ export const styles = css `
|
|
|
29
29
|
flex: 1 1 auto;
|
|
30
30
|
min-inline-size: 0;
|
|
31
31
|
}
|
|
32
|
+
[part='label'],
|
|
33
|
+
[part='sublabel'] {
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
text-overflow: ellipsis;
|
|
36
|
+
white-space: nowrap;
|
|
37
|
+
}
|
|
32
38
|
[part='label'] {
|
|
33
39
|
font-weight: 600;
|
|
34
40
|
}
|
|
@@ -80,12 +86,12 @@ export const styles = css `
|
|
|
80
86
|
position: fixed;
|
|
81
87
|
inset: var(--lyra-widget-fullscreen-inset, 0);
|
|
82
88
|
background: var(--lyra-widget-overlay-color);
|
|
83
|
-
z-index:
|
|
89
|
+
z-index: var(--lyra-overlay-stack-index, 1000);
|
|
84
90
|
}
|
|
85
91
|
:host([fullscreen]) [part='base'] {
|
|
86
92
|
position: fixed;
|
|
87
93
|
inset: var(--lyra-widget-fullscreen-inset);
|
|
88
|
-
z-index: 1000;
|
|
94
|
+
z-index: calc(var(--lyra-overlay-stack-index, 1000) + 1);
|
|
89
95
|
box-shadow: var(--lyra-shadow);
|
|
90
96
|
}
|
|
91
97
|
:host([fullscreen]) [part='body'] {
|
|
@@ -52,6 +52,13 @@ export interface WordCloudLayoutResult {
|
|
|
52
52
|
}
|
|
53
53
|
/** DOM-node/compute-time safety cap — mirrors lyra-sparkline's `MAX_BARS`. */
|
|
54
54
|
export declare const MAX_WORDS = 150;
|
|
55
|
+
/** Largest accepted font size in CSS pixels. This keeps measurement and
|
|
56
|
+
* placement geometry finite enough for an interactive render even when a
|
|
57
|
+
* caller supplies an otherwise-valid but impractically large number. */
|
|
58
|
+
export declare const MAX_FONT_SIZE_PX = 512;
|
|
59
|
+
/** Maximum number of candidate positions tested for any one word. Together
|
|
60
|
+
* with `MAX_WORDS`, this puts a hard upper bound on spiral-search work. */
|
|
61
|
+
export declare const MAX_SPIRAL_ITERATIONS = 4096;
|
|
55
62
|
/** Minimum gap enforced both between placed words and around the returned bounding box. */
|
|
56
63
|
export declare const GAP = 3;
|
|
57
64
|
/**
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
/** DOM-node/compute-time safety cap — mirrors lyra-sparkline's `MAX_BARS`. */
|
|
2
2
|
export const MAX_WORDS = 150;
|
|
3
|
+
/** Largest accepted font size in CSS pixels. This keeps measurement and
|
|
4
|
+
* placement geometry finite enough for an interactive render even when a
|
|
5
|
+
* caller supplies an otherwise-valid but impractically large number. */
|
|
6
|
+
export const MAX_FONT_SIZE_PX = 512;
|
|
7
|
+
/** Maximum number of candidate positions tested for any one word. Together
|
|
8
|
+
* with `MAX_WORDS`, this puts a hard upper bound on spiral-search work. */
|
|
9
|
+
export const MAX_SPIRAL_ITERATIONS = 4096;
|
|
3
10
|
/** Minimum gap enforced both between placed words and around the returned bounding box. */
|
|
4
11
|
export const GAP = 3;
|
|
5
12
|
const ROTATE_PROBABILITY = 0.25;
|
|
@@ -13,12 +20,17 @@ const MAX_RADIUS_AREA_FACTOR = 6;
|
|
|
13
20
|
* `minFontSize`/`maxFontSize` input. */
|
|
14
21
|
const MIN_SANE_FONT_SIZE = 1;
|
|
15
22
|
/** Normalizes possibly-invalid minFontSize/maxFontSize into a finite,
|
|
16
|
-
* positive, correctly-ordered pair — non-finite/negative inputs
|
|
17
|
-
* to MIN_SANE_FONT_SIZE,
|
|
18
|
-
* than left to invert the
|
|
23
|
+
* positive, bounded, correctly-ordered pair — non-finite/negative inputs
|
|
24
|
+
* fall back to MIN_SANE_FONT_SIZE, huge finite values are capped, and a
|
|
25
|
+
* reversed pair (max < min) is swapped rather than left to invert the
|
|
26
|
+
* weight-to-size mapping. */
|
|
19
27
|
function resolveFontSizeBounds(minFontSize, maxFontSize) {
|
|
20
|
-
const min = Number.isFinite(minFontSize) && minFontSize > 0
|
|
21
|
-
|
|
28
|
+
const min = Number.isFinite(minFontSize) && minFontSize > 0
|
|
29
|
+
? Math.min(minFontSize, MAX_FONT_SIZE_PX)
|
|
30
|
+
: MIN_SANE_FONT_SIZE;
|
|
31
|
+
const max = Number.isFinite(maxFontSize) && maxFontSize > 0
|
|
32
|
+
? Math.min(maxFontSize, MAX_FONT_SIZE_PX)
|
|
33
|
+
: MIN_SANE_FONT_SIZE;
|
|
22
34
|
return min <= max ? [min, max] : [max, min];
|
|
23
35
|
}
|
|
24
36
|
/** Clamps a (possibly negative/non-finite) input weight for scale math only —
|
|
@@ -89,7 +101,9 @@ export function layoutWordCloud(words, options) {
|
|
|
89
101
|
let x = 0;
|
|
90
102
|
let y = 0;
|
|
91
103
|
let foundSpot = placed.length === 0;
|
|
92
|
-
|
|
104
|
+
let iterations = 0;
|
|
105
|
+
while (!foundSpot && radius < maxRadius && iterations < MAX_SPIRAL_ITERATIONS) {
|
|
106
|
+
iterations++;
|
|
93
107
|
x = radius * Math.cos(theta);
|
|
94
108
|
y = radius * Math.sin(theta);
|
|
95
109
|
let collides = false;
|
|
@@ -16,12 +16,19 @@ export type { WordCloudWord };
|
|
|
16
16
|
* Instead, like `lyra-heatmap`'s cells, the whole `[part="svg"]` is one tab
|
|
17
17
|
* stop with roving arrow-key focus (Home/End jump to the first/last word,
|
|
18
18
|
* Enter/Space activates the focused one), a drawn `[part="focus-ring"]`, and
|
|
19
|
-
* a visually-hidden `aria-live="polite"` status announcement.
|
|
19
|
+
* a visually-hidden `aria-live="polite"` status announcement. The SVG focus
|
|
20
|
+
* target carries the group role and accessible name so the semantics follow
|
|
21
|
+
* the element a keyboard user actually focuses.
|
|
20
22
|
*
|
|
21
23
|
* @customElement lyra-word-cloud
|
|
22
24
|
* @event lyra-word-click - Fired on click, or Enter/Space on the focused word.
|
|
23
25
|
* `detail: { text, weight, group }`.
|
|
24
|
-
* @csspart base
|
|
26
|
+
* @csspart base - The word-cloud wrapper.
|
|
27
|
+
* @csspart svg - The word-cloud SVG.
|
|
28
|
+
* @csspart word - A rendered word.
|
|
29
|
+
* @csspart focus-ring - The keyboard focus ring.
|
|
30
|
+
* @csspart live-region - The visually hidden announcement region.
|
|
31
|
+
* @csspart empty - The empty-state message.
|
|
25
32
|
*/
|
|
26
33
|
export declare class LyraWordCloud extends LyraElement {
|
|
27
34
|
static styles: import("lit").CSSResultGroup[];
|
|
@@ -43,6 +50,19 @@ export declare class LyraWordCloud extends LyraElement {
|
|
|
43
50
|
private focusedIndex;
|
|
44
51
|
/** Text of the visually-hidden `aria-live="polite"` status announcement. */
|
|
45
52
|
private liveText;
|
|
53
|
+
/**
|
|
54
|
+
* Whether `role`/`aria-label` were present on the host *before* this
|
|
55
|
+
* element's own code ever wrote to them -- snapshotted once, in the very
|
|
56
|
+
* first `willUpdate()` (guarded by `hasUpdated`, which Lit only flips to
|
|
57
|
+
* `true` after that first update commits). Re-checking `hasAttribute()` on
|
|
58
|
+
* every update instead would self-poison: once this element writes its own
|
|
59
|
+
* default `aria-label` on the first render, `hasAttribute('aria-label')` is
|
|
60
|
+
* permanently `true` afterwards, which would wrongly look like an
|
|
61
|
+
* author-supplied value and freeze the label instead of refreshing it as
|
|
62
|
+
* `words` changes on later updates.
|
|
63
|
+
*/
|
|
64
|
+
private authorSuppliedRole;
|
|
65
|
+
private authorSuppliedAriaLabel;
|
|
46
66
|
private measureText;
|
|
47
67
|
private fontFamily;
|
|
48
68
|
private paletteColors;
|
|
@@ -53,12 +53,19 @@ function warnSkippedWords(count) {
|
|
|
53
53
|
* Instead, like `lyra-heatmap`'s cells, the whole `[part="svg"]` is one tab
|
|
54
54
|
* stop with roving arrow-key focus (Home/End jump to the first/last word,
|
|
55
55
|
* Enter/Space activates the focused one), a drawn `[part="focus-ring"]`, and
|
|
56
|
-
* a visually-hidden `aria-live="polite"` status announcement.
|
|
56
|
+
* a visually-hidden `aria-live="polite"` status announcement. The SVG focus
|
|
57
|
+
* target carries the group role and accessible name so the semantics follow
|
|
58
|
+
* the element a keyboard user actually focuses.
|
|
57
59
|
*
|
|
58
60
|
* @customElement lyra-word-cloud
|
|
59
61
|
* @event lyra-word-click - Fired on click, or Enter/Space on the focused word.
|
|
60
62
|
* `detail: { text, weight, group }`.
|
|
61
|
-
* @csspart base
|
|
63
|
+
* @csspart base - The word-cloud wrapper.
|
|
64
|
+
* @csspart svg - The word-cloud SVG.
|
|
65
|
+
* @csspart word - A rendered word.
|
|
66
|
+
* @csspart focus-ring - The keyboard focus ring.
|
|
67
|
+
* @csspart live-region - The visually hidden announcement region.
|
|
68
|
+
* @csspart empty - The empty-state message.
|
|
62
69
|
*/
|
|
63
70
|
export class LyraWordCloud extends LyraElement {
|
|
64
71
|
constructor() {
|
|
@@ -78,6 +85,19 @@ export class LyraWordCloud extends LyraElement {
|
|
|
78
85
|
this.focusedIndex = null;
|
|
79
86
|
/** Text of the visually-hidden `aria-live="polite"` status announcement. */
|
|
80
87
|
this.liveText = '';
|
|
88
|
+
/**
|
|
89
|
+
* Whether `role`/`aria-label` were present on the host *before* this
|
|
90
|
+
* element's own code ever wrote to them -- snapshotted once, in the very
|
|
91
|
+
* first `willUpdate()` (guarded by `hasUpdated`, which Lit only flips to
|
|
92
|
+
* `true` after that first update commits). Re-checking `hasAttribute()` on
|
|
93
|
+
* every update instead would self-poison: once this element writes its own
|
|
94
|
+
* default `aria-label` on the first render, `hasAttribute('aria-label')` is
|
|
95
|
+
* permanently `true` afterwards, which would wrongly look like an
|
|
96
|
+
* author-supplied value and freeze the label instead of refreshing it as
|
|
97
|
+
* `words` changes on later updates.
|
|
98
|
+
*/
|
|
99
|
+
this.authorSuppliedRole = false;
|
|
100
|
+
this.authorSuppliedAriaLabel = false;
|
|
81
101
|
this.measureText = (text, fontSize) => {
|
|
82
102
|
const ctx = getScratchCtx();
|
|
83
103
|
if (!ctx)
|
|
@@ -152,8 +172,19 @@ export class LyraWordCloud extends LyraElement {
|
|
|
152
172
|
changed.has('orientations')) {
|
|
153
173
|
this.relayout();
|
|
154
174
|
}
|
|
155
|
-
this.
|
|
156
|
-
|
|
175
|
+
if (!this.hasUpdated) {
|
|
176
|
+
this.authorSuppliedRole = this.hasAttribute('role');
|
|
177
|
+
this.authorSuppliedAriaLabel = this.hasAttribute('aria-label');
|
|
178
|
+
}
|
|
179
|
+
// Only default role/aria-label when the author hasn't already supplied
|
|
180
|
+
// one -- unconditionally overwriting them on every update (including
|
|
181
|
+
// ones triggered purely by a `words` re-layout) would silently clobber a
|
|
182
|
+
// host's own accessible name/role on the very next data refresh.
|
|
183
|
+
if (!this.authorSuppliedRole)
|
|
184
|
+
this.setAttribute('role', 'group');
|
|
185
|
+
if (!this.authorSuppliedAriaLabel) {
|
|
186
|
+
this.setAttribute('aria-label', `Word cloud of ${this.cachedLayout.placed.length} word${this.cachedLayout.placed.length === 1 ? '' : 's'}`);
|
|
187
|
+
}
|
|
157
188
|
}
|
|
158
189
|
relayout() {
|
|
159
190
|
this.cachedLayout = layoutWordCloud(this.words, {
|
|
@@ -217,7 +248,15 @@ export class LyraWordCloud extends LyraElement {
|
|
|
217
248
|
const ring = focused ? this.focusRingRect(focused) : undefined;
|
|
218
249
|
return html `
|
|
219
250
|
<div part="base">
|
|
220
|
-
<svg
|
|
251
|
+
<svg
|
|
252
|
+
part="svg"
|
|
253
|
+
role="group"
|
|
254
|
+
aria-label=${this.getAttribute('aria-label') ?? nothing}
|
|
255
|
+
aria-describedby="live-region"
|
|
256
|
+
tabindex="0"
|
|
257
|
+
viewBox="0 0 ${layout.width} ${layout.height}"
|
|
258
|
+
@keydown=${this.onKeyDown}
|
|
259
|
+
>
|
|
221
260
|
${layout.placed.map((w) => svg `<text
|
|
222
261
|
part="word"
|
|
223
262
|
x=${w.x}
|
|
@@ -231,7 +270,7 @@ export class LyraWordCloud extends LyraElement {
|
|
|
231
270
|
? svg `<rect part="focus-ring" x=${ring.x} y=${ring.y} width=${ring.width} height=${ring.height}></rect>`
|
|
232
271
|
: ''}
|
|
233
272
|
</svg>
|
|
234
|
-
<div part="live-region" class="sr-only" role="status" aria-live="polite">${this.liveText}</div>
|
|
273
|
+
<div id="live-region" part="live-region" class="sr-only" role="status" aria-live="polite">${this.liveText}</div>
|
|
235
274
|
</div>
|
|
236
275
|
`;
|
|
237
276
|
}
|
|
@@ -16,6 +16,18 @@ export const styles = css `
|
|
|
16
16
|
--lyra-word-cloud-color-7: #0a7d91;
|
|
17
17
|
--lyra-word-cloud-color-8: #57606a;
|
|
18
18
|
}
|
|
19
|
+
@media (prefers-color-scheme: dark) {
|
|
20
|
+
:host {
|
|
21
|
+
--lyra-word-cloud-color-1: var(--wa-color-brand-fill-loud, #4ea0f0);
|
|
22
|
+
--lyra-word-cloud-color-2: var(--wa-color-success-fill-loud, #3fb950);
|
|
23
|
+
--lyra-word-cloud-color-3: var(--wa-color-warning-fill-loud, #d29922);
|
|
24
|
+
--lyra-word-cloud-color-4: var(--wa-color-danger-fill-loud, #fa524a);
|
|
25
|
+
--lyra-word-cloud-color-5: #b083f5;
|
|
26
|
+
--lyra-word-cloud-color-6: #f470b8;
|
|
27
|
+
--lyra-word-cloud-color-7: #52d6e8;
|
|
28
|
+
--lyra-word-cloud-color-8: #c9d1d9;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
19
31
|
[part='base'] {
|
|
20
32
|
display: flex;
|
|
21
33
|
flex-direction: column;
|
|
@@ -46,7 +58,7 @@ export const styles = css `
|
|
|
46
58
|
[part='focus-ring'] {
|
|
47
59
|
fill: none;
|
|
48
60
|
stroke: var(--lyra-focus-ring-color);
|
|
49
|
-
stroke-width:
|
|
61
|
+
stroke-width: var(--lyra-focus-ring-width);
|
|
50
62
|
pointer-events: none;
|
|
51
63
|
}
|
|
52
64
|
[part='empty'] {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** @internal */
|
|
2
|
+
export const VALIDITY_ANCHOR = Symbol('lyra-validity-anchor');
|
|
3
|
+
/** @internal */
|
|
4
|
+
export const SET_ANCHORED_VALIDITY = Symbol('lyra-set-anchored-validity');
|
|
5
|
+
/** @internal */
|
|
6
|
+
export function resolveValidityAnchor(provider) {
|
|
7
|
+
if (!provider || (typeof provider !== 'object' && typeof provider !== 'function'))
|
|
8
|
+
return undefined;
|
|
9
|
+
const resolver = provider[VALIDITY_ANCHOR];
|
|
10
|
+
if (typeof resolver !== 'function')
|
|
11
|
+
return undefined;
|
|
12
|
+
return resolver.call(provider) ?? undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Keeps ElementInternals validity synchronous while refreshing its focus
|
|
16
|
+
* anchor after every render. The refresh is required because validity can be
|
|
17
|
+
* computed before the first shadow render and because conditional templates
|
|
18
|
+
* can replace a previously registered anchor.
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export class AnchoredValidityController {
|
|
23
|
+
constructor(host, internals, getAnchor) {
|
|
24
|
+
this.host = host;
|
|
25
|
+
this.internals = internals;
|
|
26
|
+
this.getAnchor = getAnchor;
|
|
27
|
+
this.flags = {};
|
|
28
|
+
this.message = '';
|
|
29
|
+
this.revision = 0;
|
|
30
|
+
this.refreshToken = 0;
|
|
31
|
+
host.addController(this);
|
|
32
|
+
}
|
|
33
|
+
setValidity(flags = {}, message = '') {
|
|
34
|
+
this.flags = { ...flags };
|
|
35
|
+
this.message = message;
|
|
36
|
+
this.revision += 1;
|
|
37
|
+
this.apply();
|
|
38
|
+
}
|
|
39
|
+
refreshAnchor() {
|
|
40
|
+
if (this.isInvalid())
|
|
41
|
+
this.apply();
|
|
42
|
+
}
|
|
43
|
+
hostUpdated() {
|
|
44
|
+
if (!this.isInvalid())
|
|
45
|
+
return;
|
|
46
|
+
const revision = this.revision;
|
|
47
|
+
const token = ++this.refreshToken;
|
|
48
|
+
// Rebind just after the host's update so focus side effects from an
|
|
49
|
+
// already-visible validation UI cannot schedule a new Lit update from
|
|
50
|
+
// inside hostUpdated(). This microtask runs before updateComplete settles.
|
|
51
|
+
queueMicrotask(() => {
|
|
52
|
+
if (token !== this.refreshToken || revision !== this.revision)
|
|
53
|
+
return;
|
|
54
|
+
if (this.apply())
|
|
55
|
+
return;
|
|
56
|
+
// Nested custom controls may render one microtask after their parent.
|
|
57
|
+
// Retry once so an outer form can anchor inside that nested shadow tree.
|
|
58
|
+
queueMicrotask(() => {
|
|
59
|
+
if (token === this.refreshToken && revision === this.revision)
|
|
60
|
+
this.apply();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
isInvalid() {
|
|
65
|
+
return Object.values(this.flags).some(Boolean);
|
|
66
|
+
}
|
|
67
|
+
/** Returns true when an invalid state was installed with a real anchor. */
|
|
68
|
+
apply() {
|
|
69
|
+
const anchor = this.isInvalid() ? this.getAnchor() : undefined;
|
|
70
|
+
if (anchor?.isConnected) {
|
|
71
|
+
try {
|
|
72
|
+
this.internals.setValidity(this.flags, this.message, anchor);
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
// A stale or incorrectly provided non-descendant anchor must not
|
|
77
|
+
// break the host's update. Preserve validity and fall back to the
|
|
78
|
+
// host until the next fresh render resolves a legal descendant.
|
|
79
|
+
if (!(error instanceof DOMException) || error.name !== 'NotFoundError')
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
this.internals.setValidity(this.flags, this.message);
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -8,9 +8,16 @@ export interface FormAssociatedInterface {
|
|
|
8
8
|
disabled: boolean;
|
|
9
9
|
required: boolean;
|
|
10
10
|
readonly effectiveDisabled: boolean;
|
|
11
|
+
readonly form: HTMLFormElement | null;
|
|
12
|
+
readonly labels: NodeList;
|
|
13
|
+
readonly validity: ValidityState;
|
|
14
|
+
readonly validationMessage: string;
|
|
15
|
+
readonly willValidate: boolean;
|
|
11
16
|
setFormValue(next: string): void;
|
|
12
17
|
checkValidity(): boolean;
|
|
13
18
|
reportValidity(): boolean;
|
|
19
|
+
formResetCallback(): void;
|
|
20
|
+
formStateRestoreCallback(state: string | File | FormData | null, mode?: 'restore' | 'autocomplete'): void;
|
|
14
21
|
}
|
|
15
22
|
/**
|
|
16
23
|
* Mixin that turns a Lit component into a form-associated custom element via
|