@crowdstrike/glide-core 0.32.2 → 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 +7 -11
- package/dist/button.styles.js +10 -8
- package/dist/checkbox-group.js +8 -7
- package/dist/checkbox.d.ts +1 -0
- package/dist/checkbox.js +26 -17
- 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 +9 -9
- 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 +83 -44
- 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 +7 -7
- 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.d.ts +1 -0
- package/dist/textarea.js +19 -10
- package/dist/toast.js +2 -2
- package/dist/toast.toasts.js +3 -2
- package/dist/toggle.d.ts +1 -0
- package/dist/toggle.js +13 -4
- 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/icon-button.js
CHANGED
@@ -12,7 +12,6 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
|
12
12
|
import packageJson from '../package.json' with { type: 'json' };
|
13
13
|
import styles from './icon-button.styles.js';
|
14
14
|
import assertSlot from './library/assert-slot.js';
|
15
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
16
15
|
import final from './library/final.js';
|
17
16
|
import required from './library/required.js';
|
18
17
|
/**
|
@@ -42,10 +41,11 @@ let IconButton = class IconButton extends LitElement {
|
|
42
41
|
this.#buttonElementRef = createRef();
|
43
42
|
this.#defaultSlotElementRef = createRef();
|
44
43
|
}
|
44
|
+
/* c8 ignore start */
|
45
45
|
static { this.shadowRootOptions = {
|
46
46
|
...LitElement.shadowRootOptions,
|
47
47
|
delegatesFocus: true,
|
48
|
-
mode:
|
48
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
49
49
|
}; }
|
50
50
|
static { this.styles = styles; }
|
51
51
|
// A getter and setter because Lit Analzyer doesn't recognize "aria-description"
|
package/dist/inline-alert.js
CHANGED
@@ -15,7 +15,6 @@ import severityInformationalIcon from './icons/severity-informational.js';
|
|
15
15
|
import severityMediumIcon from './icons/severity-medium.js';
|
16
16
|
import severityCriticalIcon from './icons/severity-critical.js';
|
17
17
|
import assertSlot from './library/assert-slot.js';
|
18
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
19
18
|
import final from './library/final.js';
|
20
19
|
/**
|
21
20
|
* @attr {'informational'|'medium'|'high'|'critical'} [variant='informational']
|
@@ -33,10 +32,12 @@ let InlineAlert = class InlineAlert extends LitElement {
|
|
33
32
|
this.#animationDuration = 100;
|
34
33
|
this.#componentElementRef = createRef();
|
35
34
|
}
|
35
|
+
/* c8 ignore start */
|
36
36
|
static { this.shadowRootOptions = {
|
37
37
|
...LitElement.shadowRootOptions,
|
38
|
-
mode:
|
38
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
39
39
|
}; }
|
40
|
+
/* c8 ignore end */
|
40
41
|
static { this.styles = styles; }
|
41
42
|
firstUpdated() {
|
42
43
|
this.#componentElementRef.value?.addEventListener('animationend', () => {
|
package/dist/input.js
CHANGED
@@ -19,7 +19,6 @@ import { LocalizeController } from './library/localize.js';
|
|
19
19
|
import magnifyingGlassIcon from './icons/magnifying-glass.js';
|
20
20
|
import styles from './input.styles.js';
|
21
21
|
import xIcon from './icons/x.js';
|
22
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
23
22
|
import final from './library/final.js';
|
24
23
|
import required from './library/required.js';
|
25
24
|
/**
|
@@ -82,9 +81,10 @@ import required from './library/required.js';
|
|
82
81
|
*/
|
83
82
|
let Input = class Input extends LitElement {
|
84
83
|
static { this.formAssociated = true; }
|
84
|
+
/* c8 ignore start */
|
85
85
|
static { this.shadowRootOptions = {
|
86
86
|
...LitElement.shadowRootOptions,
|
87
|
-
mode:
|
87
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
88
88
|
delegatesFocus: true,
|
89
89
|
}; }
|
90
90
|
static { this.styles = styles; }
|
@@ -318,7 +318,7 @@ let Input = class Input extends LitElement {
|
|
318
318
|
reportValidity() {
|
319
319
|
this.isReportValidityOrSubmit = true;
|
320
320
|
const isValid = this.#internals.reportValidity();
|
321
|
-
// Ensures
|
321
|
+
// Ensures getters referencing `this.validity.valid` re-run.
|
322
322
|
this.requestUpdate();
|
323
323
|
return isValid;
|
324
324
|
}
|
@@ -397,12 +397,12 @@ let Input = class Input extends LitElement {
|
|
397
397
|
this.isReportValidityOrSubmit = true;
|
398
398
|
const isFirstInvalidFormElement = this.form?.querySelector(':invalid') === this;
|
399
399
|
if (isFirstInvalidFormElement) {
|
400
|
-
// - `
|
401
|
-
//
|
402
|
-
//
|
400
|
+
// - `delegatesFocus` is preferred because it's declarative. But it's limited to
|
401
|
+
// focusing the first focusable element. That doesn't work for us because the first
|
402
|
+
// focusable element is the Tooltip when it's present.
|
403
403
|
//
|
404
404
|
// - Canceling this event means the input won't get focus, even if we were to use
|
405
|
-
// `
|
405
|
+
// `delegatesFocus`.
|
406
406
|
//
|
407
407
|
// - The browser will ignore this if Input isn't the first invalid form control.
|
408
408
|
//
|
@@ -453,8 +453,8 @@ let Input = class Input extends LitElement {
|
|
453
453
|
if (this.#inputElementRef.value?.value) {
|
454
454
|
this.value = this.#inputElementRef.value?.value;
|
455
455
|
}
|
456
|
-
// Unlike "input" events, "change" events aren't composed. So we have to
|
457
|
-
//
|
456
|
+
// Unlike "input" events, "change" events aren't composed. So we have to manually
|
457
|
+
// dispatch them.
|
458
458
|
this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
459
459
|
}
|
460
460
|
#onInputFocus() {
|
package/dist/label.js
CHANGED
@@ -16,7 +16,6 @@ import styles from './label.styles.js';
|
|
16
16
|
import { LocalizeController } from './library/localize.js';
|
17
17
|
import assertSlot from './library/assert-slot.js';
|
18
18
|
import onResize from './library/on-resize.js';
|
19
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
20
19
|
import final from './library/final.js';
|
21
20
|
/**
|
22
21
|
* @attr {boolean} [disabled=false]
|
@@ -50,10 +49,12 @@ let Label = class Label extends LitElement {
|
|
50
49
|
this.#localize = new LocalizeController(this);
|
51
50
|
this.#summarySlotElementRef = createRef();
|
52
51
|
}
|
52
|
+
/* c8 ignore start */
|
53
53
|
static { this.shadowRootOptions = {
|
54
54
|
...LitElement.shadowRootOptions,
|
55
|
-
mode:
|
55
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
56
56
|
}; }
|
57
|
+
/* c8 ignore end */
|
57
58
|
static { this.styles = styles; }
|
58
59
|
render() {
|
59
60
|
// `aria-hidden` is used on the tooltip so the contents of the label aren't
|
@@ -48,11 +48,11 @@ class AssertSlot extends Directive {
|
|
48
48
|
part.element?.addEventListener('slotchange', () => {
|
49
49
|
if (isOptional &&
|
50
50
|
part.element instanceof HTMLSlotElement &&
|
51
|
-
part.element.assignedNodes().length === 0) {
|
51
|
+
part.element.assignedNodes({ flatten: true }).length === 0) {
|
52
52
|
return;
|
53
53
|
}
|
54
54
|
if (part.element instanceof HTMLSlotElement &&
|
55
|
-
part.element.assignedNodes().length === 0) {
|
55
|
+
part.element.assignedNodes({ flatten: true }).length === 0) {
|
56
56
|
if (slotted && slotted.length > 0) {
|
57
57
|
const message = part.element.name
|
58
58
|
? `Expected the "${part.element.name}" slot of ${host.constructor.name} to have a slotted element that extends ${slotted
|
@@ -51,6 +51,34 @@ let WhenNotUsedInsideATag = class WhenNotUsedInsideATag extends LitElement {
|
|
51
51
|
WhenNotUsedInsideATag = __decorate([
|
52
52
|
customElement('glide-core-when-not-used-inside-tag')
|
53
53
|
], WhenNotUsedInsideATag);
|
54
|
+
let Reslotted = class Reslotted extends LitElement {
|
55
|
+
constructor() {
|
56
|
+
super(...arguments);
|
57
|
+
this.optional = false;
|
58
|
+
this.slotted = [];
|
59
|
+
}
|
60
|
+
render() {
|
61
|
+
return html `<glide-core-with-slot
|
62
|
+
name=${ifDefined(this.name)}
|
63
|
+
.slotted=${this.slotted}
|
64
|
+
?optional=${this.optional}
|
65
|
+
>
|
66
|
+
<slot name=${ifDefined(this.name)}></slot>
|
67
|
+
</glide-core-with-slot>`;
|
68
|
+
}
|
69
|
+
};
|
70
|
+
__decorate([
|
71
|
+
property()
|
72
|
+
], Reslotted.prototype, "name", void 0);
|
73
|
+
__decorate([
|
74
|
+
property({ type: Boolean })
|
75
|
+
], Reslotted.prototype, "optional", void 0);
|
76
|
+
__decorate([
|
77
|
+
property({ type: Array })
|
78
|
+
], Reslotted.prototype, "slotted", void 0);
|
79
|
+
Reslotted = __decorate([
|
80
|
+
customElement('glide-core-reslotted')
|
81
|
+
], Reslotted);
|
54
82
|
it('throws when a required default slot is empty', async () => {
|
55
83
|
const stub = sinon.stub(console, 'error');
|
56
84
|
const spy = sinon.spy();
|
@@ -283,3 +311,67 @@ it('throws when not used inside an opening tag', async () => {
|
|
283
311
|
}
|
284
312
|
expect(spy.args.at(0)?.at(0).message).to.equal("Directive must be inside the element's opening tag.");
|
285
313
|
});
|
314
|
+
it('throws when a reslotted and required default slot is empty', async () => {
|
315
|
+
const stub = sinon.stub(console, 'error');
|
316
|
+
const spy = sinon.spy();
|
317
|
+
const onerror = window.onerror;
|
318
|
+
// eslint-disable-next-line unicorn/prefer-add-event-listener
|
319
|
+
window.onerror = spy;
|
320
|
+
await fixture(html `<glide-core-reslotted
|
321
|
+
.slotted=${[HTMLDivElement]}
|
322
|
+
></glide-core-reslotted>`);
|
323
|
+
expect(spy.callCount).to.equal(1);
|
324
|
+
expect(spy.args.at(0)?.at(0)).to.equal('Uncaught TypeError: Expected WithSlot to have a slotted element that extends HTMLDivElement.');
|
325
|
+
// eslint-disable-next-line unicorn/prefer-add-event-listener
|
326
|
+
window.onerror = onerror;
|
327
|
+
stub.restore();
|
328
|
+
});
|
329
|
+
it('throws when a reslotted default slot has the wrong element', async () => {
|
330
|
+
const stub = sinon.stub(console, 'error');
|
331
|
+
const spy = sinon.spy();
|
332
|
+
const onerror = window.onerror;
|
333
|
+
// eslint-disable-next-line unicorn/prefer-add-event-listener
|
334
|
+
window.onerror = spy;
|
335
|
+
await fixture(html `<glide-core-reslotted .slotted=${[HTMLDivElement]}>
|
336
|
+
<a href="/">Link</a>
|
337
|
+
</glide-core-reslotted>`);
|
338
|
+
expect(spy.callCount).to.equal(1);
|
339
|
+
expect(spy.args.at(0)?.at(0)).to.equal('Uncaught TypeError: Expected WithSlot to have a slotted element that extends HTMLDivElement. Extends HTMLAnchorElement instead.');
|
340
|
+
// eslint-disable-next-line unicorn/prefer-add-event-listener
|
341
|
+
window.onerror = onerror;
|
342
|
+
stub.restore();
|
343
|
+
});
|
344
|
+
it('does not throw when a reslotted default slot has the correct element', async () => {
|
345
|
+
const spy = sinon.spy();
|
346
|
+
window.addEventListener('error', spy);
|
347
|
+
await fixture(html `<glide-core-reslotted .slotted=${[HTMLDivElement]}>
|
348
|
+
<div>Content</div>
|
349
|
+
</glide-core-reslotted>`);
|
350
|
+
expect(spy.callCount).to.equal(0);
|
351
|
+
});
|
352
|
+
it('throws when a reslotted and required named slot is empty', async () => {
|
353
|
+
const stub = sinon.stub(console, 'error');
|
354
|
+
const spy = sinon.spy();
|
355
|
+
window.addEventListener('unhandledrejection', spy, { once: true });
|
356
|
+
await fixture(html `<glide-core-reslotted
|
357
|
+
name="test"
|
358
|
+
.slotted=${[HTMLDivElement]}
|
359
|
+
></glide-core-reslotted>`);
|
360
|
+
await waitUntil(() => spy.callCount);
|
361
|
+
expect(spy.callCount).to.equal(1);
|
362
|
+
expect(spy.args.at(0)?.at(0) instanceof PromiseRejectionEvent).to.be.true;
|
363
|
+
expect(spy.args.at(0)?.at(0).reason.message).to.equal('Expected the "test" slot of WithSlot to have a slotted element that extends HTMLDivElement.');
|
364
|
+
stub.restore();
|
365
|
+
});
|
366
|
+
it('does not throw when a reslotted optional named slot is empty', async () => {
|
367
|
+
const spy = sinon.spy();
|
368
|
+
window.addEventListener('unhandledrejection', spy, { once: true });
|
369
|
+
await fixture(html `<glide-core-reslotted name="test" optional></glide-core-reslotted>`);
|
370
|
+
expect(spy.callCount).to.equal(0);
|
371
|
+
});
|
372
|
+
it('does not throw when a reslotted optional slot is empty', async () => {
|
373
|
+
const spy = sinon.spy();
|
374
|
+
window.addEventListener('unhandledrejection', spy, { once: true });
|
375
|
+
await fixture(html `<glide-core-reslotted optional></glide-core-reslotted>`);
|
376
|
+
expect(spy.callCount).to.equal(0);
|
377
|
+
});
|
package/dist/link.js
CHANGED
@@ -11,7 +11,6 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
|
11
11
|
import { createRef, ref } from 'lit/directives/ref.js';
|
12
12
|
import packageJson from '../package.json' with { type: 'json' };
|
13
13
|
import styles from './link.styles.js';
|
14
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
15
14
|
import final from './library/final.js';
|
16
15
|
import required from './library/required.js';
|
17
16
|
/**
|
@@ -32,10 +31,11 @@ let Link = class Link extends LitElement {
|
|
32
31
|
this.version = packageJson.version;
|
33
32
|
this.#componentElementRef = createRef();
|
34
33
|
}
|
34
|
+
/* c8 ignore start */
|
35
35
|
static { this.shadowRootOptions = {
|
36
36
|
...LitElement.shadowRootOptions,
|
37
37
|
delegatesFocus: true,
|
38
|
-
mode:
|
38
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
39
39
|
}; }
|
40
40
|
static { this.styles = styles; }
|
41
41
|
click() {
|
package/dist/menu.js
CHANGED
@@ -18,7 +18,6 @@ import Option from './option.js';
|
|
18
18
|
import Input from './input.js';
|
19
19
|
import assertSlot from './library/assert-slot.js';
|
20
20
|
import styles from './menu.styles.js';
|
21
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
22
21
|
import final from './library/final.js';
|
23
22
|
import uniqueId from './library/unique-id.js';
|
24
23
|
/**
|
@@ -107,10 +106,12 @@ let Menu = class Menu extends LitElement {
|
|
107
106
|
};
|
108
107
|
}
|
109
108
|
static { Menu_1 = this; }
|
109
|
+
/* c8 ignore start */
|
110
110
|
static { this.shadowRootOptions = {
|
111
111
|
...LitElement.shadowRootOptions,
|
112
|
-
mode:
|
112
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
113
113
|
}; }
|
114
|
+
/* c8 ignore end */
|
114
115
|
static { this.styles = styles; }
|
115
116
|
/**
|
116
117
|
* @default false
|
@@ -184,9 +185,9 @@ let Menu = class Menu extends LitElement {
|
|
184
185
|
firstUpdated() {
|
185
186
|
if (this.#optionsElement && this.#targetElement) {
|
186
187
|
this.#optionsElement.privateLoading = this.loading;
|
187
|
-
|
188
|
-
|
189
|
-
|
188
|
+
if (this.loading) {
|
189
|
+
this.#targetElement.ariaDescription = this.#localize.term('loading');
|
190
|
+
}
|
190
191
|
}
|
191
192
|
if (this.open && !this.isTargetDisabled) {
|
192
193
|
const openedSubMenus = this.#subMenus.filter(({ open }) => open);
|
@@ -298,8 +299,8 @@ let Menu = class Menu extends LitElement {
|
|
298
299
|
@keydown=${this.#onTargetAndDefaultSlotKeyDown}
|
299
300
|
@mousedown=${this.#onDefaultSlotMouseDown}
|
300
301
|
@mouseover=${this.#onDefaultSlotMouseOver}
|
301
|
-
@
|
302
|
-
@
|
302
|
+
@disabled=${this.#onDefaultSlotDisabled}
|
303
|
+
@slotchange=${this.#onDefaultSlotSlotChange}
|
303
304
|
@toggle=${this.#onDefaultSlotToggle}
|
304
305
|
${assertSlot([Element])}
|
305
306
|
${ref(this.#defaultSlotElementRef)}
|
@@ -416,20 +417,28 @@ let Menu = class Menu extends LitElement {
|
|
416
417
|
return this.closest('glide-core-option');
|
417
418
|
}
|
418
419
|
get #subMenus() {
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
420
|
+
const assignedElements = this.#defaultSlotElementRef.value?.assignedElements({ flatten: true });
|
421
|
+
if (!assignedElements) {
|
422
|
+
return [];
|
423
|
+
}
|
424
|
+
return assignedElements
|
425
|
+
.filter((element) => element instanceof Options)
|
426
|
+
.flatMap((element) => {
|
427
|
+
return [
|
428
|
+
...element.querySelectorAll(
|
429
|
+
// The "content" slot case.
|
430
|
+
':scope > glide-core-option > [slot="content"] > glide-core-menu'),
|
431
|
+
...element.querySelectorAll(
|
432
|
+
// The "content" slot and Options Group case.
|
433
|
+
':scope > glide-core-options-group > glide-core-option > [slot="content"] > glide-core-menu'),
|
434
|
+
...element.querySelectorAll(
|
435
|
+
// The "content" slot fallback case.
|
436
|
+
':scope > glide-core-option > [slot="submenu"]'),
|
437
|
+
...element.querySelectorAll(
|
438
|
+
// The "content" slot fallback and Options Group case.
|
439
|
+
':scope > glide-core-options-group > glide-core-option > [slot="submenu"]'),
|
440
|
+
];
|
441
|
+
});
|
433
442
|
}
|
434
443
|
get #targetElement() {
|
435
444
|
const element = this.#targetSlotElementRef.value
|
@@ -449,7 +458,9 @@ let Menu = class Menu extends LitElement {
|
|
449
458
|
this.#targetElement?.focus(options);
|
450
459
|
}
|
451
460
|
}
|
452
|
-
#hide() {
|
461
|
+
async #hide() {
|
462
|
+
// There's a comment in `#show()` explaining why.
|
463
|
+
await this.#activeOption?.updateComplete;
|
453
464
|
this.#cleanUpFloatingUi?.();
|
454
465
|
this.#defaultSlotElementRef.value?.hidePopover();
|
455
466
|
if (this.#optionsElement) {
|
@@ -537,7 +548,7 @@ let Menu = class Menu extends LitElement {
|
|
537
548
|
}
|
538
549
|
});
|
539
550
|
}
|
540
|
-
#
|
551
|
+
#onDefaultSlotDisabled(event) {
|
541
552
|
if (this.#activeOption === event.target &&
|
542
553
|
event.target instanceof Option &&
|
543
554
|
event.target.disabled &&
|
@@ -1043,6 +1054,13 @@ let Menu = class Menu extends LitElement {
|
|
1043
1054
|
this.#hide();
|
1044
1055
|
}
|
1045
1056
|
});
|
1057
|
+
/* c8 ignore start */
|
1058
|
+
if (this.#targetElement?.ariaDescription !== null &&
|
1059
|
+
this.#targetElement?.ariaDescription !== this.#localize.term('loading')) {
|
1060
|
+
// eslint-disable-next-line no-console
|
1061
|
+
console.warn("Menu will overwrite the `aria-description` on your target when Menu's `loading` attribute it set.");
|
1062
|
+
}
|
1063
|
+
/* c8 ignore end */
|
1046
1064
|
if (this.#targetElement && this.#optionsElement) {
|
1047
1065
|
observer.observe(this.#targetElement, {
|
1048
1066
|
attributeFilter: ['aria-disabled', 'disabled'],
|
@@ -1145,7 +1163,44 @@ let Menu = class Menu extends LitElement {
|
|
1145
1163
|
#onTargetSlotInput() {
|
1146
1164
|
this.open = true;
|
1147
1165
|
}
|
1148
|
-
#show() {
|
1166
|
+
async #show() {
|
1167
|
+
if (this.#previouslyActiveOption &&
|
1168
|
+
!this.#previouslyActiveOption.disabled &&
|
1169
|
+
this.#optionsElement) {
|
1170
|
+
this.#previouslyActiveOption.privateActive = true;
|
1171
|
+
}
|
1172
|
+
else if (this.#firstEnabledOption && this.#optionsElement) {
|
1173
|
+
this.#firstEnabledOption.privateActive = true;
|
1174
|
+
this.#previouslyActiveOption = this.#firstEnabledOption;
|
1175
|
+
}
|
1176
|
+
if (this.#optionsElement && this.#activeOption?.id) {
|
1177
|
+
this.#optionsElement.ariaActivedescendant = this.#activeOption.id;
|
1178
|
+
this.#activeOption.privateTooltipOpen = this.privateOpenedViaKeyboard;
|
1179
|
+
}
|
1180
|
+
else if (this.#optionsElement) {
|
1181
|
+
this.#optionsElement.ariaActivedescendant = '';
|
1182
|
+
}
|
1183
|
+
// If we don't wait for the Option to update, it'll briefly appear as inactive when
|
1184
|
+
// Menu opens because `showPopover()` is synchronous and component updates are not.
|
1185
|
+
//
|
1186
|
+
// A side effect of waiting, however, is that calling `#show()` then immediately
|
1187
|
+
// calling `#hide()` won't work as expected: Menu will never close because the
|
1188
|
+
// `showPopover()` call below will be slightly delayed. So `hidePopover()`, via
|
1189
|
+
// `#hide()`, will be called just before `showPopover()`.
|
1190
|
+
//
|
1191
|
+
// That's why we also wait for the Option to update in `#hide()`. `#hide()` being
|
1192
|
+
// called immediately after `#show()` may seem unlikely. But Menu itself does it
|
1193
|
+
// when multiple sub-Menus are initially open.
|
1194
|
+
//
|
1195
|
+
// When, for example, Menu and two of its sub-Menus are initially open, each
|
1196
|
+
// sub-Menu's `open` setter will get called, and each `open` setter will call
|
1197
|
+
// `#show()`.
|
1198
|
+
//
|
1199
|
+
// But two open sub-Menus doesn't make sense. So Menu, shortly after the sub-Menus'
|
1200
|
+
// `open` setters are initially called, will set the `open` property of the other
|
1201
|
+
// sub-Menu to `false` in `firstUpdated()`. Thus a `#hide()` call immediately after
|
1202
|
+
// `#show()`.
|
1203
|
+
await this.#activeOption?.updateComplete;
|
1149
1204
|
this.#cleanUpFloatingUi?.();
|
1150
1205
|
// Ideally, we wouldn't show the popover until after Floating UI has calculated its
|
1151
1206
|
// position. But calling `showPopover()` changes the nature of how `top` and `left`
|
@@ -1198,27 +1253,11 @@ let Menu = class Menu extends LitElement {
|
|
1198
1253
|
else if (!this.#isSubMenu && this.#targetElement) {
|
1199
1254
|
this.#targetElement.ariaExpanded = 'true';
|
1200
1255
|
}
|
1201
|
-
if (this.#
|
1202
|
-
this.#
|
1203
|
-
}
|
1204
|
-
if (this.#previouslyActiveOption &&
|
1205
|
-
!this.#previouslyActiveOption.disabled &&
|
1206
|
-
this.#optionsElement) {
|
1207
|
-
this.#previouslyActiveOption.privateActive = true;
|
1208
|
-
this.#previouslyActiveOption.privateTooltipOpen =
|
1209
|
-
this.privateOpenedViaKeyboard;
|
1210
|
-
this.#optionsElement.ariaActivedescendant =
|
1211
|
-
this.#previouslyActiveOption.id;
|
1212
|
-
}
|
1213
|
-
else if (this.#firstEnabledOption && this.#optionsElement) {
|
1214
|
-
this.#firstEnabledOption.privateActive = true;
|
1215
|
-
this.#firstEnabledOption.privateTooltipOpen =
|
1216
|
-
this.privateOpenedViaKeyboard;
|
1217
|
-
this.#previouslyActiveOption = this.#firstEnabledOption;
|
1218
|
-
this.#optionsElement.ariaActivedescendant = this.#firstEnabledOption.id;
|
1256
|
+
if (this.#isSubMenu && this.#parentOption) {
|
1257
|
+
this.#parentOption.ariaExpanded = 'true';
|
1219
1258
|
}
|
1220
|
-
else if (this.#
|
1221
|
-
this.#
|
1259
|
+
else if (!this.#isSubMenu && this.#targetElement) {
|
1260
|
+
this.#targetElement.ariaExpanded = 'true';
|
1222
1261
|
}
|
1223
1262
|
if (this.#targetElement && this.#defaultSlotElementRef.value) {
|
1224
1263
|
this.#cleanUpFloatingUi = autoUpdate(this.#targetElement, this.#defaultSlotElementRef.value, () => {
|
package/dist/menu.styles.js
CHANGED
@@ -35,6 +35,7 @@ export default [
|
|
35
35
|
padding-block-end: 0;
|
36
36
|
padding-block-start: var(--glide-core-spacing-base-xxxs);
|
37
37
|
padding-inline: var(--glide-core-spacing-base-xxxs);
|
38
|
+
position: absolute;
|
38
39
|
|
39
40
|
/*
|
40
41
|
This little hack replaces "padding-block-end", which the last option overlaps
|
@@ -11,7 +11,6 @@ import { ifDefined } from 'lit/directives/if-defined.js';
|
|
11
11
|
import packageJson from '../package.json' with { type: 'json' };
|
12
12
|
import styles from './modal.icon-button.styles.js';
|
13
13
|
import assertSlot from './library/assert-slot.js';
|
14
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
15
14
|
import final from './library/final.js';
|
16
15
|
import required from './library/required.js';
|
17
16
|
/**
|
@@ -27,10 +26,12 @@ let ModalIconButton = class ModalIconButton extends LitElement {
|
|
27
26
|
super(...arguments);
|
28
27
|
this.version = packageJson.version;
|
29
28
|
}
|
29
|
+
/* c8 ignore start */
|
30
30
|
static { this.shadowRootOptions = {
|
31
31
|
...LitElement.shadowRootOptions,
|
32
|
-
mode:
|
32
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
33
33
|
}; }
|
34
|
+
/* c8 ignore end */
|
34
35
|
static { this.styles = styles; }
|
35
36
|
render() {
|
36
37
|
return html `
|
package/dist/modal.js
CHANGED
@@ -18,7 +18,6 @@ import Tooltip from './tooltip.js';
|
|
18
18
|
import styles from './modal.styles.js';
|
19
19
|
import xIcon from './icons/x.js';
|
20
20
|
import assertSlot from './library/assert-slot.js';
|
21
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
22
21
|
import severityInformationalIcon from './icons/severity-informational.js';
|
23
22
|
import severityMediumIcon from './icons/severity-medium.js';
|
24
23
|
import severityCriticalIcon from './icons/severity-critical.js';
|
@@ -107,10 +106,12 @@ let Modal = class Modal extends LitElement {
|
|
107
106
|
});
|
108
107
|
};
|
109
108
|
}
|
109
|
+
/* c8 ignore start */
|
110
110
|
static { this.shadowRootOptions = {
|
111
111
|
...LitElement.shadowRootOptions,
|
112
|
-
mode:
|
112
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
113
113
|
}; }
|
114
|
+
/* c8 ignore end */
|
114
115
|
static { this.styles = styles; }
|
115
116
|
/**
|
116
117
|
* @default false
|
package/dist/option.d.ts
CHANGED
@@ -28,6 +28,11 @@ declare global {
|
|
28
28
|
* @slot {Element | Text} [content] - This is the unhappy path. It's the escape hatch where you can render arbitrary content and lay it out however you need to. If you go this route, `slot="icon"` and `slot="submenu"` will become unavailable. And the `label` and `description` attributes won't be rendered. The `label` attribute is still required. We'll show it in a tooltip when your content overflows. If you need a second line of text in the tooltip, provide you can provide it via the `description` attribute.
|
29
29
|
* @slot {Element} [icon]
|
30
30
|
* @slot {Menu} [submenu]
|
31
|
+
*
|
32
|
+
* @fires {Event} deselected
|
33
|
+
* @fires {Event} disabled
|
34
|
+
* @fires {Event} enabled
|
35
|
+
* @fires {Event} selected
|
31
36
|
*/
|
32
37
|
export default class Option extends LitElement {
|
33
38
|
#private;
|
package/dist/option.js
CHANGED
@@ -15,7 +15,6 @@ import packageJson from '../package.json' with { type: 'json' };
|
|
15
15
|
import styles from './option.styles.js';
|
16
16
|
import assertSlot from './library/assert-slot.js';
|
17
17
|
import checkedIcon from './icons/checked.js';
|
18
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
19
18
|
import final from './library/final.js';
|
20
19
|
import uniqueId from './library/unique-id.js';
|
21
20
|
import Menu from './menu.js';
|
@@ -45,6 +44,11 @@ import required from './library/required.js';
|
|
45
44
|
* @slot {Element | Text} [content] - This is the unhappy path. It's the escape hatch where you can render arbitrary content and lay it out however you need to. If you go this route, `slot="icon"` and `slot="submenu"` will become unavailable. And the `label` and `description` attributes won't be rendered. The `label` attribute is still required. We'll show it in a tooltip when your content overflows. If you need a second line of text in the tooltip, provide you can provide it via the `description` attribute.
|
46
45
|
* @slot {Element} [icon]
|
47
46
|
* @slot {Menu} [submenu]
|
47
|
+
*
|
48
|
+
* @fires {Event} deselected
|
49
|
+
* @fires {Event} disabled
|
50
|
+
* @fires {Event} enabled
|
51
|
+
* @fires {Event} selected
|
48
52
|
*/
|
49
53
|
let Option = class Option extends LitElement {
|
50
54
|
constructor() {
|
@@ -61,8 +65,8 @@ let Option = class Option extends LitElement {
|
|
61
65
|
this.hasIconSlot = false;
|
62
66
|
this.hasSubMenuSlot = false;
|
63
67
|
this.isContentSlotOverflow = false;
|
64
|
-
// Set in `#onSubmenuToggle()`. Used to toggle the sub-Menu's target as open
|
65
|
-
//
|
68
|
+
// Set in `#onSubmenuToggle()`. Used to toggle the sub-Menu's target as open or
|
69
|
+
// closed visually.
|
66
70
|
this.isSubmenuOpen = false;
|
67
71
|
this.#containerElementRef = createRef();
|
68
72
|
this.#contentSlotElementRef = createRef();
|
@@ -73,10 +77,12 @@ let Option = class Option extends LitElement {
|
|
73
77
|
this.#labelElementRef = createRef();
|
74
78
|
this.#tooltipElementRef = createRef();
|
75
79
|
}
|
80
|
+
/* c8 ignore start */
|
76
81
|
static { this.shadowRootOptions = {
|
77
82
|
...LitElement.shadowRootOptions,
|
78
|
-
mode:
|
83
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
79
84
|
}; }
|
85
|
+
/* c8 ignore end */
|
80
86
|
static { this.styles = styles; }
|
81
87
|
// Consumers may chose not to take the happy path and instead use the "content"
|
82
88
|
// slot. In that case, we don't render `label`. But `label` still needs to be
|
@@ -116,9 +122,15 @@ let Option = class Option extends LitElement {
|
|
116
122
|
return this.#isDisabled;
|
117
123
|
}
|
118
124
|
set disabled(isDisabled) {
|
125
|
+
const hasChanged = isDisabled !== this.#isDisabled;
|
119
126
|
this.#isDisabled = isDisabled;
|
120
127
|
this.ariaDisabled = isDisabled ? 'true' : 'false';
|
121
|
-
|
128
|
+
if (hasChanged && isDisabled) {
|
129
|
+
this.dispatchEvent(new Event('disabled', { bubbles: true }));
|
130
|
+
}
|
131
|
+
else if (hasChanged) {
|
132
|
+
this.dispatchEvent(new Event('enabled', { bubbles: true }));
|
133
|
+
}
|
122
134
|
}
|
123
135
|
get privateActive() {
|
124
136
|
return this.#isActive;
|
@@ -142,8 +154,19 @@ let Option = class Option extends LitElement {
|
|
142
154
|
return this.#isSelected;
|
143
155
|
}
|
144
156
|
set selected(isSelected) {
|
157
|
+
const hasChanged = isSelected !== this.#isSelected;
|
145
158
|
this.ariaSelected = isSelected.toString();
|
146
159
|
this.#isSelected = isSelected;
|
160
|
+
if (hasChanged && isSelected) {
|
161
|
+
this.dispatchEvent(new Event('selected', {
|
162
|
+
bubbles: true,
|
163
|
+
}));
|
164
|
+
}
|
165
|
+
else if (hasChanged) {
|
166
|
+
this.dispatchEvent(new Event('deselected', {
|
167
|
+
bubbles: true,
|
168
|
+
}));
|
169
|
+
}
|
147
170
|
}
|
148
171
|
click() {
|
149
172
|
// You'd think this condition wouldn't be needed because `#onTooltipClick()` has a
|
package/dist/options.d.ts
CHANGED
package/dist/options.group.js
CHANGED
@@ -9,7 +9,6 @@ import { customElement, property } from 'lit/decorators.js';
|
|
9
9
|
import { classMap } from 'lit/directives/class-map.js';
|
10
10
|
import packageJson from '../package.json' with { type: 'json' };
|
11
11
|
import styles from './options.group.styles.js';
|
12
|
-
import shadowRootMode from './library/shadow-root-mode.js';
|
13
12
|
import final from './library/final.js';
|
14
13
|
import assertSlot from './library/assert-slot.js';
|
15
14
|
import Option from './option.js';
|
@@ -31,10 +30,12 @@ let OptionsGroup = class OptionsGroup extends LitElement {
|
|
31
30
|
this.role = 'group';
|
32
31
|
this.version = packageJson.version;
|
33
32
|
}
|
33
|
+
/* c8 ignore start */
|
34
34
|
static { this.shadowRootOptions = {
|
35
35
|
...LitElement.shadowRootOptions,
|
36
|
-
mode:
|
36
|
+
mode: window.navigator.webdriver ? 'open' : 'closed',
|
37
37
|
}; }
|
38
|
+
/* c8 ignore end */
|
38
39
|
static { this.styles = styles; }
|
39
40
|
/**
|
40
41
|
* @default undefined
|