@crowdstrike/glide-core 0.32.3 → 0.33.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/dist/accordion.js +3 -2
- package/dist/button-group.button.js +3 -2
- package/dist/button-group.js +3 -2
- package/dist/button.js +5 -10
- package/dist/button.styles.js +0 -12
- package/dist/checkbox-group.js +8 -7
- package/dist/checkbox.js +8 -7
- package/dist/checkbox.styles.js +1 -1
- package/dist/drawer.js +3 -2
- package/dist/dropdown.js +19 -18
- package/dist/dropdown.option.d.ts +2 -0
- package/dist/dropdown.option.js +26 -25
- package/dist/form-controls-layout.js +3 -2
- package/dist/icon-button.js +2 -2
- package/dist/inline-alert.js +3 -2
- package/dist/input.js +7 -7
- package/dist/label.js +3 -2
- package/dist/library/assert-slot.js +2 -2
- package/dist/library/assert-slot.test.js +92 -0
- package/dist/link.js +2 -2
- package/dist/menu.js +61 -30
- package/dist/menu.styles.js +1 -0
- package/dist/modal.icon-button.js +3 -2
- package/dist/modal.js +3 -2
- package/dist/option.d.ts +5 -0
- package/dist/option.js +28 -5
- package/dist/options.d.ts +2 -0
- package/dist/options.group.js +3 -2
- package/dist/options.js +7 -8
- package/dist/options.styles.js +0 -6
- package/dist/popover.js +3 -2
- package/dist/radio-group.js +4 -3
- package/dist/radio-group.radio.js +3 -2
- package/dist/select.d.ts +90 -0
- package/dist/select.js +532 -0
- package/dist/slider.js +3 -3
- package/dist/spinner.js +2 -2
- package/dist/split-button.js +3 -2
- package/dist/split-button.primary-button.js +2 -2
- package/dist/split-button.primary-link.js +2 -2
- package/dist/split-button.secondary-button.js +2 -2
- package/dist/styles/opacity-and-scale-animation.js +2 -1
- package/dist/styles/variables.css +7 -4
- package/dist/tab.group.js +3 -2
- package/dist/tab.js +3 -2
- package/dist/tab.panel.js +3 -2
- package/dist/tag.js +2 -2
- package/dist/textarea.js +8 -7
- package/dist/toast.js +2 -2
- package/dist/toast.toasts.js +3 -2
- package/dist/toggle.js +3 -2
- package/dist/tooltip.container.js +3 -2
- package/dist/tooltip.js +4 -7
- package/package.json +4 -4
- package/dist/library/shadow-root-mode.d.ts +0 -2
- package/dist/library/shadow-root-mode.js +0 -4
package/dist/select.d.ts
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
import { LitElement } from 'lit';
|
2
|
+
import type FormControl from './library/form-control.js';
|
3
|
+
declare global {
|
4
|
+
interface HTMLElementTagNameMap {
|
5
|
+
'glide-core-select': Select;
|
6
|
+
}
|
7
|
+
}
|
8
|
+
/**
|
9
|
+
* @attr {boolean} [disabled=false]
|
10
|
+
* @attr {boolean} [loading=false]
|
11
|
+
* @attr {string} [name='']
|
12
|
+
* @attr {number} [offset=4]
|
13
|
+
* @attr {boolean} [open=false]
|
14
|
+
* @attr {'bottom'|'left'|'right'|'top'|'bottom-start'|'bottom-end'|'left-start'|'left-end'|'right-start'|'right-end'|'top-start'|'top-end'} [placement='bottom-start'] - Select will try to move itself to the opposite of this value if not doing so would result in overflow. For example, if "bottom" results in overflow Menu will try "top" but not "right" or "left".
|
15
|
+
* @attr {boolean} [required=false]
|
16
|
+
* @attr {string[]} [value=[]]
|
17
|
+
*
|
18
|
+
* @readonly
|
19
|
+
* @attr {string} [version]
|
20
|
+
*
|
21
|
+
* @slot {Element}
|
22
|
+
* @slot {Element} target - The element to which Select will anchor. Can be any focusable element. If you want Select to be filterable, put an Input in this slot. Listen for Input's "input" event, then add and remove Option(s) from Select's default slot based on Input's value.
|
23
|
+
*
|
24
|
+
* @fires {Event} change
|
25
|
+
* @fires {Event} input
|
26
|
+
*
|
27
|
+
* @readonly
|
28
|
+
* @prop {HTMLFormElement | null} form
|
29
|
+
*
|
30
|
+
* @readonly
|
31
|
+
* @prop {ValidityState} validity
|
32
|
+
*
|
33
|
+
* @method checkValidity
|
34
|
+
* @returns boolean
|
35
|
+
*
|
36
|
+
* @method formAssociatedCallback
|
37
|
+
* @method formResetCallback
|
38
|
+
*
|
39
|
+
* @method reportValidity
|
40
|
+
* @returns boolean
|
41
|
+
*
|
42
|
+
* @method setValidity
|
43
|
+
* @param {ValidityStateFlags} [flags]
|
44
|
+
*/
|
45
|
+
export default class Select extends LitElement implements Omit<FormControl, 'hideLabel' | 'orientation' | 'resetValidityFeedback' | 'setCustomValidity'> {
|
46
|
+
#private;
|
47
|
+
static formAssociated: boolean;
|
48
|
+
static shadowRootOptions: ShadowRootInit;
|
49
|
+
static styles: import("lit").CSSResult[];
|
50
|
+
disabled: boolean;
|
51
|
+
loading: boolean;
|
52
|
+
name: string;
|
53
|
+
/**
|
54
|
+
* @default 4
|
55
|
+
*/
|
56
|
+
get offset(): number;
|
57
|
+
set offset(offset: number);
|
58
|
+
/**
|
59
|
+
* @default false
|
60
|
+
*/
|
61
|
+
get open(): boolean;
|
62
|
+
set open(isOpen: boolean);
|
63
|
+
/**
|
64
|
+
* Select will try to move itself to the opposite of this value if not doing so would result in overflow.
|
65
|
+
* For example, if "bottom" results in overflow Menu will try "top" but not "right" or "left".
|
66
|
+
*/
|
67
|
+
placement: 'bottom' | 'left' | 'right' | 'top' | 'bottom-start' | 'bottom-end' | 'left-start' | 'left-end' | 'right-start' | 'right-end' | 'top-start' | 'top-end';
|
68
|
+
/**
|
69
|
+
* @default false
|
70
|
+
*/
|
71
|
+
get required(): boolean;
|
72
|
+
set required(isRequired: boolean);
|
73
|
+
/**
|
74
|
+
* @default []
|
75
|
+
*/
|
76
|
+
get value(): string[];
|
77
|
+
set value(value: string[]);
|
78
|
+
readonly version: string;
|
79
|
+
get form(): HTMLFormElement | null;
|
80
|
+
checkValidity(): boolean;
|
81
|
+
firstUpdated(): void;
|
82
|
+
formAssociatedCallback(): void;
|
83
|
+
formResetCallback(): void;
|
84
|
+
render(): import("lit").TemplateResult<1>;
|
85
|
+
reportValidity(): boolean;
|
86
|
+
setValidity(flags?: ValidityStateFlags): void;
|
87
|
+
get validity(): ValidityState;
|
88
|
+
constructor();
|
89
|
+
private isCheckingValidity;
|
90
|
+
}
|
package/dist/select.js
ADDED
@@ -0,0 +1,532 @@
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
6
|
+
};
|
7
|
+
import { html, LitElement } from 'lit';
|
8
|
+
import { createRef, ref } from 'lit/directives/ref.js';
|
9
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
10
|
+
import packageJson from '../package.json' with { type: 'json' };
|
11
|
+
import assertSlot from './library/assert-slot.js';
|
12
|
+
import styles from './menu.styles.js';
|
13
|
+
import final from './library/final.js';
|
14
|
+
import Menu from './menu.js';
|
15
|
+
import Option from './option.js';
|
16
|
+
import Options from './options.js';
|
17
|
+
import OptionsGroup from './options.group.js';
|
18
|
+
/**
|
19
|
+
* @attr {boolean} [disabled=false]
|
20
|
+
* @attr {boolean} [loading=false]
|
21
|
+
* @attr {string} [name='']
|
22
|
+
* @attr {number} [offset=4]
|
23
|
+
* @attr {boolean} [open=false]
|
24
|
+
* @attr {'bottom'|'left'|'right'|'top'|'bottom-start'|'bottom-end'|'left-start'|'left-end'|'right-start'|'right-end'|'top-start'|'top-end'} [placement='bottom-start'] - Select will try to move itself to the opposite of this value if not doing so would result in overflow. For example, if "bottom" results in overflow Menu will try "top" but not "right" or "left".
|
25
|
+
* @attr {boolean} [required=false]
|
26
|
+
* @attr {string[]} [value=[]]
|
27
|
+
*
|
28
|
+
* @readonly
|
29
|
+
* @attr {string} [version]
|
30
|
+
*
|
31
|
+
* @slot {Element}
|
32
|
+
* @slot {Element} target - The element to which Select will anchor. Can be any focusable element. If you want Select to be filterable, put an Input in this slot. Listen for Input's "input" event, then add and remove Option(s) from Select's default slot based on Input's value.
|
33
|
+
*
|
34
|
+
* @fires {Event} change
|
35
|
+
* @fires {Event} input
|
36
|
+
*
|
37
|
+
* @readonly
|
38
|
+
* @prop {HTMLFormElement | null} form
|
39
|
+
*
|
40
|
+
* @readonly
|
41
|
+
* @prop {ValidityState} validity
|
42
|
+
*
|
43
|
+
* @method checkValidity
|
44
|
+
* @returns boolean
|
45
|
+
*
|
46
|
+
* @method formAssociatedCallback
|
47
|
+
* @method formResetCallback
|
48
|
+
*
|
49
|
+
* @method reportValidity
|
50
|
+
* @returns boolean
|
51
|
+
*
|
52
|
+
* @method setValidity
|
53
|
+
* @param {ValidityStateFlags} [flags]
|
54
|
+
*/
|
55
|
+
let Select = class Select extends LitElement {
|
56
|
+
static { this.formAssociated = true; }
|
57
|
+
/* c8 ignore start */
|
58
|
+
static { this.shadowRootOptions = {
|
59
|
+
...LitElement.shadowRootOptions,
|
60
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
61
|
+
}; }
|
62
|
+
/* c8 ignore end */
|
63
|
+
static { this.styles = styles; }
|
64
|
+
/**
|
65
|
+
* @default 4
|
66
|
+
*/
|
67
|
+
get offset() {
|
68
|
+
return (this.#offset ??
|
69
|
+
Number.parseFloat(window
|
70
|
+
.getComputedStyle(document.body)
|
71
|
+
.getPropertyValue('--glide-core-spacing-base-xxs')) *
|
72
|
+
Number.parseFloat(window.getComputedStyle(document.documentElement).fontSize));
|
73
|
+
}
|
74
|
+
/* v8 ignore start */
|
75
|
+
set offset(offset) {
|
76
|
+
this.#offset = offset;
|
77
|
+
}
|
78
|
+
/* v8 ignore end */
|
79
|
+
/**
|
80
|
+
* @default false
|
81
|
+
*/
|
82
|
+
get open() {
|
83
|
+
return this.#isOpen;
|
84
|
+
}
|
85
|
+
set open(isOpen) {
|
86
|
+
this.#isOpen = isOpen;
|
87
|
+
if (this.#menuElementRef.value) {
|
88
|
+
this.#menuElementRef.value.open = isOpen;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
/**
|
92
|
+
* @default false
|
93
|
+
*/
|
94
|
+
get required() {
|
95
|
+
return this.#isRequired;
|
96
|
+
}
|
97
|
+
set required(isRequired) {
|
98
|
+
this.#isRequired = isRequired;
|
99
|
+
this.#setValidity();
|
100
|
+
}
|
101
|
+
/**
|
102
|
+
* @default []
|
103
|
+
*/
|
104
|
+
get value() {
|
105
|
+
return this.#value;
|
106
|
+
}
|
107
|
+
set value(value) {
|
108
|
+
if (value.length > 1) {
|
109
|
+
throw this.#tooManySelectedOptionsError;
|
110
|
+
}
|
111
|
+
this.#value = value;
|
112
|
+
if (this.#optionElements) {
|
113
|
+
for (const option of this.#optionElements) {
|
114
|
+
this.#isSelectionFromValueSetter = true;
|
115
|
+
option.selected = false;
|
116
|
+
this.#isSelectionFromValueSetter = false;
|
117
|
+
}
|
118
|
+
}
|
119
|
+
for (const value$ of value) {
|
120
|
+
const option = this.#optionElements?.find((option) => option.value === value$);
|
121
|
+
if (option) {
|
122
|
+
this.#isSelectionFromValueSetter = true;
|
123
|
+
option.selected = true;
|
124
|
+
this.#isSelectionFromValueSetter = false;
|
125
|
+
}
|
126
|
+
}
|
127
|
+
this.#setValidity();
|
128
|
+
}
|
129
|
+
get form() {
|
130
|
+
return this.#internals.form;
|
131
|
+
}
|
132
|
+
checkValidity() {
|
133
|
+
this.isCheckingValidity = true;
|
134
|
+
const isValid = this.#internals.checkValidity();
|
135
|
+
this.isCheckingValidity = false;
|
136
|
+
return isValid;
|
137
|
+
}
|
138
|
+
firstUpdated() {
|
139
|
+
const options = this.querySelector('glide-core-options');
|
140
|
+
if (options) {
|
141
|
+
options.role = 'listbox';
|
142
|
+
}
|
143
|
+
const hasNoSelectedOptions = this.#optionElements?.every(({ selected }) => !selected);
|
144
|
+
// When `value` is set on initial render, its setter is called before
|
145
|
+
// `connectedCallback()` and thus before the default slot has any assigned
|
146
|
+
// elements. So we select options here after the initial render is complete
|
147
|
+
// and `this.#optionElements` isn't empty.
|
148
|
+
//
|
149
|
+
// Additionally, `#onDefaultSlotSlotChange()` is called after `firstUpdated()`
|
150
|
+
// and sets `value` based on which options are selected. And the initial `value`
|
151
|
+
// may conflict with the one derived from which options are selected.
|
152
|
+
//
|
153
|
+
// So we have a decision to make. On first render, do we defer to the initial
|
154
|
+
// `value` and select and deselect options below? Or do we defer to
|
155
|
+
// `#onDefaultSlotSlotChange()` and let that method change `value` from its initial
|
156
|
+
// value?
|
157
|
+
//
|
158
|
+
// It's largely a toss-up. But the latter seems like the logical choice given
|
159
|
+
// `#onDefaultSlotSlotChange()` is called after `firstUpdated()`. In other words,
|
160
|
+
// we defer to the lifecycle. `#onDefaultSlotSlotChange()` is called second. So
|
161
|
+
// it gets to override what `value` was initially.
|
162
|
+
//
|
163
|
+
// If no options are selected, then it's obvious that the consumer's intention is
|
164
|
+
// to select options based on the initial `value`. So we proceed.
|
165
|
+
if (hasNoSelectedOptions) {
|
166
|
+
if (this.value.length > 1) {
|
167
|
+
throw this.#tooManySelectedOptionsError;
|
168
|
+
}
|
169
|
+
for (const value of this.value) {
|
170
|
+
const option = this.#optionElements?.find((option) => option.value === value);
|
171
|
+
if (option) {
|
172
|
+
option.selected = true;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}
|
176
|
+
if (this.open && this.#menuElementRef.value) {
|
177
|
+
// Simply passing `this.open` to Menu in the template below would be more
|
178
|
+
// convenient. But, when an attribute's value is an expression, Lit will set the
|
179
|
+
// attribute on a slight delay, and that's a problem when a sub-Menu is also
|
180
|
+
// initially open because it means the sub-Menu wil be opened before the top-level
|
181
|
+
// Menu. So the top-level Menu below will be positioned underneath the sub-Menu.
|
182
|
+
this.#menuElementRef.value.open = true;
|
183
|
+
}
|
184
|
+
}
|
185
|
+
formAssociatedCallback() {
|
186
|
+
this.form?.addEventListener('formdata', this.#onFormdata);
|
187
|
+
}
|
188
|
+
formResetCallback() {
|
189
|
+
if (this.#optionElements) {
|
190
|
+
for (const option of this.#optionElements) {
|
191
|
+
option.selected = option.hasAttribute('selected');
|
192
|
+
if (option.selected) {
|
193
|
+
this.#value = [option.value];
|
194
|
+
}
|
195
|
+
}
|
196
|
+
}
|
197
|
+
}
|
198
|
+
render() {
|
199
|
+
// Lit-a11y doesn't know that we're not interested in certain keys being pressed.
|
200
|
+
//
|
201
|
+
/* eslint-disable lit-a11y/click-events-have-key-events */
|
202
|
+
return html `<glide-core-menu
|
203
|
+
offset=${this.offset}
|
204
|
+
placement=${this.placement}
|
205
|
+
?loading=${this.loading}
|
206
|
+
@toggle=${this.#onMenuToggle}
|
207
|
+
${ref(this.#menuElementRef)}
|
208
|
+
>
|
209
|
+
<slot
|
210
|
+
name="target"
|
211
|
+
slot="target"
|
212
|
+
@click=${this.#onTargetSlotClick}
|
213
|
+
@keydown=${this.#onTargetSlotKeyDown}
|
214
|
+
@slotchange=${this.#onTargetSlotChange}
|
215
|
+
${assertSlot([Element])}
|
216
|
+
${ref(this.#targetSlotElementRef)}
|
217
|
+
>
|
218
|
+
<!--
|
219
|
+
The element to which Select will anchor. Can be any focusable element.
|
220
|
+
|
221
|
+
If you want Select to be filterable, put an Input in this slot. Listen for Input's
|
222
|
+
"input" event, then add and remove Option(s) from Select's default slot based on
|
223
|
+
Input's value.
|
224
|
+
|
225
|
+
@required
|
226
|
+
@type {Element}
|
227
|
+
-->
|
228
|
+
</slot>
|
229
|
+
|
230
|
+
<slot
|
231
|
+
@click=${this.#onDefaultSlotClick}
|
232
|
+
@deselected=${this.#onDefaultSlotDeselected}
|
233
|
+
@disabled=${this.#onDefaultSlotDisabled}
|
234
|
+
@selected=${this.#onDefaultSlotSelected}
|
235
|
+
@slotchange=${this.#onDefaultSlotSlotChange}
|
236
|
+
${ref(this.#defaultSlotElementRef)}
|
237
|
+
>
|
238
|
+
<!--
|
239
|
+
@required
|
240
|
+
@type {Element}
|
241
|
+
-->
|
242
|
+
</slot>
|
243
|
+
</glide-core-menu>`;
|
244
|
+
}
|
245
|
+
reportValidity() {
|
246
|
+
return this.#internals.reportValidity();
|
247
|
+
}
|
248
|
+
setValidity(flags) {
|
249
|
+
this.#hasCustomValidity = true;
|
250
|
+
this.#internals.setValidity(flags, ' ',
|
251
|
+
// `setValidity()` isn't typed for an SVG. But an SVG is valid as long as it's
|
252
|
+
// focusable. Thus the cast.
|
253
|
+
this.#targetElement);
|
254
|
+
}
|
255
|
+
get validity() {
|
256
|
+
return this.#internals.validity;
|
257
|
+
}
|
258
|
+
constructor() {
|
259
|
+
super();
|
260
|
+
this.disabled = false;
|
261
|
+
this.loading = false;
|
262
|
+
this.name = '';
|
263
|
+
/**
|
264
|
+
* Select will try to move itself to the opposite of this value if not doing so would result in overflow.
|
265
|
+
* For example, if "bottom" results in overflow Menu will try "top" but not "right" or "left".
|
266
|
+
*/
|
267
|
+
this.placement = 'bottom-start';
|
268
|
+
this.version = packageJson.version;
|
269
|
+
this.isCheckingValidity = false;
|
270
|
+
this.#defaultSlotElementRef = createRef();
|
271
|
+
this.#hasCustomValidity = false;
|
272
|
+
this.#hasEmittedAnInvalidEvent = false;
|
273
|
+
this.#isOpen = false;
|
274
|
+
this.#isRequired = false;
|
275
|
+
this.#isSelectionFromValueSetter = false;
|
276
|
+
this.#isTargetClickViaEnter = false;
|
277
|
+
this.#menuElementRef = createRef();
|
278
|
+
this.#targetSlotElementRef = createRef();
|
279
|
+
this.#tooManySelectedOptionsError = new Error('Only one option may be selected at a time.');
|
280
|
+
this.#value = [];
|
281
|
+
// An arrow function field instead of a method so `this` is closed over and
|
282
|
+
// set to the component instead of the form.
|
283
|
+
this.#onFormdata = ({ formData }) => {
|
284
|
+
if (this.name && this.value.length > 0 && !this.disabled) {
|
285
|
+
formData.append(this.name, JSON.stringify(this.value));
|
286
|
+
}
|
287
|
+
};
|
288
|
+
this.#internals = this.attachInternals();
|
289
|
+
// Event handlers on the host aren't great because consumers can remove them.
|
290
|
+
// Unfortunately, the host is the only thing on which this event is dispatched
|
291
|
+
// because it's the host that is form-associated.
|
292
|
+
this.addEventListener('invalid', (event) => {
|
293
|
+
// Canceled so the native validation message isn't shown.
|
294
|
+
event.preventDefault();
|
295
|
+
if (this.isCheckingValidity) {
|
296
|
+
return;
|
297
|
+
}
|
298
|
+
this.#hasEmittedAnInvalidEvent = true;
|
299
|
+
const isFirstInvalidFormElement = this.form?.querySelector(':invalid') === this;
|
300
|
+
if (isFirstInvalidFormElement) {
|
301
|
+
// Canceling the event means the target won't get focus, even if we were to use
|
302
|
+
// `delegatesFocus`. So we have to it focus manually.
|
303
|
+
this.#targetElement?.focus();
|
304
|
+
}
|
305
|
+
if (this.#targetElement) {
|
306
|
+
this.#targetElement.ariaInvalid = this.validity.valid
|
307
|
+
? 'false'
|
308
|
+
: 'true';
|
309
|
+
}
|
310
|
+
});
|
311
|
+
}
|
312
|
+
#defaultSlotElementRef;
|
313
|
+
#hasCustomValidity;
|
314
|
+
#hasEmittedAnInvalidEvent;
|
315
|
+
#internals;
|
316
|
+
#isOpen;
|
317
|
+
#isRequired;
|
318
|
+
#isSelectionFromValueSetter;
|
319
|
+
#isTargetClickViaEnter;
|
320
|
+
#menuElementRef;
|
321
|
+
#offset;
|
322
|
+
#targetSlotElementRef;
|
323
|
+
#tooManySelectedOptionsError;
|
324
|
+
#value;
|
325
|
+
get #optionElements() {
|
326
|
+
if (this.#optionsElement) {
|
327
|
+
return [...this.#optionsElement.children]
|
328
|
+
.filter((element) => {
|
329
|
+
return element instanceof Option || element instanceof OptionsGroup;
|
330
|
+
})
|
331
|
+
.flatMap((element) => {
|
332
|
+
return element instanceof OptionsGroup
|
333
|
+
? [
|
334
|
+
...element.querySelectorAll(':scope > glide-core-option'),
|
335
|
+
]
|
336
|
+
: element;
|
337
|
+
});
|
338
|
+
}
|
339
|
+
}
|
340
|
+
get #optionsElement() {
|
341
|
+
const firstAssignedElement = this.#defaultSlotElementRef.value
|
342
|
+
?.assignedElements({ flatten: true })
|
343
|
+
.at(0);
|
344
|
+
return firstAssignedElement instanceof Options
|
345
|
+
? firstAssignedElement
|
346
|
+
: null;
|
347
|
+
}
|
348
|
+
// An arrow function field instead of a method so `this` is closed over and
|
349
|
+
// set to the component instead of the form.
|
350
|
+
#onFormdata;
|
351
|
+
#onDefaultSlotClick(event) {
|
352
|
+
const isSubMenuOption = this.#optionElements?.every((option) => option !== event.target);
|
353
|
+
if (isSubMenuOption) {
|
354
|
+
return;
|
355
|
+
}
|
356
|
+
if (event.target instanceof Option && !event.target.selected) {
|
357
|
+
if (this.#optionElements) {
|
358
|
+
for (const option of this.#optionElements) {
|
359
|
+
if (option.selected) {
|
360
|
+
option.selected = false;
|
361
|
+
}
|
362
|
+
}
|
363
|
+
}
|
364
|
+
if (this.#menuElementRef.value) {
|
365
|
+
// Menu waits a tick or so before closing after an Option is clicked to give its
|
366
|
+
// consumers a chance to cancel the event and prevent Menu from closing.
|
367
|
+
//
|
368
|
+
// When `selected` is set below, the Option will rerender to include a checkmark.
|
369
|
+
// If the Option has a sub-Menu, the Option will also move its sub-Menu target so
|
370
|
+
// it's to the left of the checkmark.
|
371
|
+
//
|
372
|
+
// Because Menu doesn't close immediately, the user will see the checkmark suddenly
|
373
|
+
// appear and the sub-Menu's target move moments before Menu closes.
|
374
|
+
//
|
375
|
+
// To avoid all that, we close Menu ourselves before setting `selected`.
|
376
|
+
this.#menuElementRef.value.open = false;
|
377
|
+
}
|
378
|
+
event.target.selected = true;
|
379
|
+
this.#value = [event.target.value];
|
380
|
+
this.dispatchEvent(new Event('input', {
|
381
|
+
bubbles: true,
|
382
|
+
composed: true,
|
383
|
+
}));
|
384
|
+
this.dispatchEvent(new Event('change', {
|
385
|
+
bubbles: true,
|
386
|
+
composed: true,
|
387
|
+
}));
|
388
|
+
}
|
389
|
+
}
|
390
|
+
#onDefaultSlotDeselected() {
|
391
|
+
if (this.#isSelectionFromValueSetter) {
|
392
|
+
return;
|
393
|
+
}
|
394
|
+
this.#value = [];
|
395
|
+
this.#setValidity();
|
396
|
+
}
|
397
|
+
#onDefaultSlotDisabled(event) {
|
398
|
+
if (event.target instanceof Option && event.target.selected) {
|
399
|
+
event.target.selected = false;
|
400
|
+
}
|
401
|
+
}
|
402
|
+
#onDefaultSlotSelected(event) {
|
403
|
+
if (this.#targetElement) {
|
404
|
+
// The `label` of the selected Option(s) should actually be read before the label
|
405
|
+
// or text content of the target. But we don't always know what the target's label
|
406
|
+
// is because the target is an arbitrary element.
|
407
|
+
//
|
408
|
+
// For example, it could be a custom element without `textContent`. Button is like
|
409
|
+
// this. Button doesn't have any `textContent` because nothing gets slotted into
|
410
|
+
// it. Yet it is labeled.
|
411
|
+
//
|
412
|
+
// So the best we can do is set `ariaDescription`.
|
413
|
+
this.#targetElement.ariaDescription = this.#optionElements
|
414
|
+
? this.#optionElements
|
415
|
+
.filter(({ selected }) => selected)
|
416
|
+
.map(({ label }) => label)
|
417
|
+
.join(',')
|
418
|
+
: '';
|
419
|
+
}
|
420
|
+
if (this.#isSelectionFromValueSetter) {
|
421
|
+
return;
|
422
|
+
}
|
423
|
+
if (event.target instanceof Option && this.#optionElements) {
|
424
|
+
for (const option of this.#optionElements) {
|
425
|
+
if (option !== event.target) {
|
426
|
+
option.selected = false;
|
427
|
+
}
|
428
|
+
}
|
429
|
+
this.#value = [event.target.value];
|
430
|
+
}
|
431
|
+
this.#setValidity();
|
432
|
+
}
|
433
|
+
#onDefaultSlotSlotChange() {
|
434
|
+
const selectedOptions = this.#optionElements &&
|
435
|
+
this.#optionElements.filter(({ selected }) => selected);
|
436
|
+
if (selectedOptions && selectedOptions.length > 1) {
|
437
|
+
throw this.#tooManySelectedOptionsError;
|
438
|
+
}
|
439
|
+
const selectedOption = selectedOptions?.at(0);
|
440
|
+
if (selectedOption) {
|
441
|
+
this.#value = [selectedOption.value];
|
442
|
+
}
|
443
|
+
if (this.#optionElements) {
|
444
|
+
for (const option of this.#optionElements) {
|
445
|
+
option.role = 'option';
|
446
|
+
}
|
447
|
+
}
|
448
|
+
this.#setValidity();
|
449
|
+
}
|
450
|
+
#onMenuToggle(event) {
|
451
|
+
if (event.target instanceof Menu &&
|
452
|
+
event.target === this.#menuElementRef.value) {
|
453
|
+
this.open = event.target.open;
|
454
|
+
}
|
455
|
+
}
|
456
|
+
#onTargetSlotChange() {
|
457
|
+
if (this.#targetElement) {
|
458
|
+
this.#targetElement.ariaInvalid =
|
459
|
+
!this.#hasEmittedAnInvalidEvent || this.validity.valid
|
460
|
+
? 'false'
|
461
|
+
: 'true';
|
462
|
+
}
|
463
|
+
}
|
464
|
+
#onTargetSlotClick(event) {
|
465
|
+
if (this.#isTargetClickViaEnter) {
|
466
|
+
this.#isTargetClickViaEnter = false;
|
467
|
+
event.preventDefault(); // Prevent Menu from opening.
|
468
|
+
}
|
469
|
+
}
|
470
|
+
#onTargetSlotKeyDown(event) {
|
471
|
+
if (event.key === 'Enter' && !this.open) {
|
472
|
+
this.#isTargetClickViaEnter = true;
|
473
|
+
this.form?.requestSubmit();
|
474
|
+
}
|
475
|
+
}
|
476
|
+
#setValidity() {
|
477
|
+
if (this.#hasCustomValidity) {
|
478
|
+
return;
|
479
|
+
}
|
480
|
+
if (this.required && this.value.length === 0) {
|
481
|
+
this.#internals.setValidity({ valueMissing: true }, ' ',
|
482
|
+
// `setValidity()` isn't typed for an SVG. But an SVG is valid as long as it's
|
483
|
+
// focusable. Thus the cast.
|
484
|
+
this.#targetElement);
|
485
|
+
return;
|
486
|
+
}
|
487
|
+
this.#internals.setValidity({});
|
488
|
+
}
|
489
|
+
get #targetElement() {
|
490
|
+
const element = this.#targetSlotElementRef.value
|
491
|
+
?.assignedElements({ flatten: true })
|
492
|
+
.at(0);
|
493
|
+
if (element instanceof HTMLElement || element instanceof SVGElement) {
|
494
|
+
return element;
|
495
|
+
}
|
496
|
+
}
|
497
|
+
};
|
498
|
+
__decorate([
|
499
|
+
property({ type: Boolean, reflect: true })
|
500
|
+
], Select.prototype, "disabled", void 0);
|
501
|
+
__decorate([
|
502
|
+
property({ reflect: true, type: Boolean })
|
503
|
+
], Select.prototype, "loading", void 0);
|
504
|
+
__decorate([
|
505
|
+
property({ reflect: true, useDefault: true })
|
506
|
+
], Select.prototype, "name", void 0);
|
507
|
+
__decorate([
|
508
|
+
property({ reflect: true, type: Number })
|
509
|
+
], Select.prototype, "offset", null);
|
510
|
+
__decorate([
|
511
|
+
property({ type: Boolean, reflect: true })
|
512
|
+
], Select.prototype, "open", null);
|
513
|
+
__decorate([
|
514
|
+
property({ reflect: true, useDefault: true })
|
515
|
+
], Select.prototype, "placement", void 0);
|
516
|
+
__decorate([
|
517
|
+
property({ reflect: true, type: Boolean })
|
518
|
+
], Select.prototype, "required", null);
|
519
|
+
__decorate([
|
520
|
+
property({ type: Array })
|
521
|
+
], Select.prototype, "value", null);
|
522
|
+
__decorate([
|
523
|
+
property({ reflect: true })
|
524
|
+
], Select.prototype, "version", void 0);
|
525
|
+
__decorate([
|
526
|
+
state()
|
527
|
+
], Select.prototype, "isCheckingValidity", void 0);
|
528
|
+
Select = __decorate([
|
529
|
+
customElement('glide-core-select'),
|
530
|
+
final
|
531
|
+
], Select);
|
532
|
+
export default Select;
|
package/dist/slider.js
CHANGED
@@ -15,7 +15,6 @@ import { when } from 'lit/directives/when.js';
|
|
15
15
|
import packageJson from '../package.json' with { type: 'json' };
|
16
16
|
import { LocalizeController } from './library/localize.js';
|
17
17
|
import styles from './slider.styles.js';
|
18
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
19
18
|
import final from './library/final.js';
|
20
19
|
import required from './library/required.js';
|
21
20
|
/**
|
@@ -68,9 +67,10 @@ import required from './library/required.js';
|
|
68
67
|
*/
|
69
68
|
let Slider = class Slider extends LitElement {
|
70
69
|
static { this.formAssociated = true; }
|
70
|
+
/* c8 ignore start */
|
71
71
|
static { this.shadowRootOptions = {
|
72
72
|
...LitElement.shadowRootOptions,
|
73
|
-
mode:
|
73
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
74
74
|
delegatesFocus: true,
|
75
75
|
}; }
|
76
76
|
static { this.styles = styles; }
|
@@ -592,7 +592,7 @@ let Slider = class Slider extends LitElement {
|
|
592
592
|
reportValidity() {
|
593
593
|
this.isReportValidityOrSubmit = true;
|
594
594
|
const isValid = this.#internals.reportValidity();
|
595
|
-
// Ensures
|
595
|
+
// Ensures getters referencing `this.validity.valid` re-run.
|
596
596
|
this.requestUpdate();
|
597
597
|
return isValid;
|
598
598
|
}
|
package/dist/spinner.js
CHANGED
@@ -10,7 +10,6 @@ import { customElement, property } from 'lit/decorators.js';
|
|
10
10
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
11
11
|
import packageJson from '../package.json' with { type: 'json' };
|
12
12
|
import styles from './spinner.styles.js';
|
13
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
14
13
|
import final from './library/final.js';
|
15
14
|
import required from './library/required.js';
|
16
15
|
/**
|
@@ -26,10 +25,11 @@ let Spinner = class Spinner extends LitElement {
|
|
26
25
|
this.size = 'medium';
|
27
26
|
this.version = packageJson.version;
|
28
27
|
}
|
28
|
+
/* c8 ignore start */
|
29
29
|
static { this.shadowRootOptions = {
|
30
30
|
...LitElement.shadowRootOptions,
|
31
31
|
delegatesFocus: true,
|
32
|
-
mode:
|
32
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
33
33
|
}; }
|
34
34
|
static { this.styles = styles; }
|
35
35
|
render() {
|
package/dist/split-button.js
CHANGED
@@ -13,7 +13,6 @@ import SplitButtonPrimaryLink from './split-button.primary-link.js';
|
|
13
13
|
import SplitButtonSecondaryButton from './split-button.secondary-button.js';
|
14
14
|
import styles from './split-button.styles.js';
|
15
15
|
import assertSlot from './library/assert-slot.js';
|
16
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
17
16
|
import final from './library/final.js';
|
18
17
|
/**
|
19
18
|
* @attr {'primary'|'secondary'} [variant='primary']
|
@@ -32,10 +31,12 @@ let SplitButton = class SplitButton extends LitElement {
|
|
32
31
|
this.#secondaryButtonSlotElementRef = createRef();
|
33
32
|
this.#variant = 'primary';
|
34
33
|
}
|
34
|
+
/* c8 ignore start */
|
35
35
|
static { this.shadowRootOptions = {
|
36
36
|
...LitElement.shadowRootOptions,
|
37
|
-
mode:
|
37
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
38
38
|
}; }
|
39
|
+
/* c8 ignore end */
|
39
40
|
static { this.styles = styles; }
|
40
41
|
/**
|
41
42
|
* @default 'primary'
|