@crowdstrike/glide-core 0.31.1 → 0.32.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 +4 -1
- package/dist/accordion.styles.js +7 -0
- package/dist/library/request-idle-callback.d.ts +1 -0
- package/dist/library/request-idle-callback.js +5 -0
- package/dist/link.js +34 -16
- package/dist/menu.d.ts +5 -1
- package/dist/menu.js +95 -69
- package/dist/menu.styles.js +0 -1
- package/dist/popover.d.ts +6 -2
- package/dist/popover.js +58 -57
- package/dist/slider.js +1 -0
- package/dist/tooltip.d.ts +4 -4
- package/dist/tooltip.js +14 -14
- package/package.json +1 -1
package/dist/accordion.js
CHANGED
@@ -140,7 +140,10 @@ let Accordion = class Accordion extends LitElement {
|
|
140
140
|
|
141
141
|
<div class="label-container">
|
142
142
|
<slot
|
143
|
-
class
|
143
|
+
class=${classMap({
|
144
|
+
'prefix-icon-slot': true,
|
145
|
+
'slotted-content': this.hasPrefixIcon,
|
146
|
+
})}
|
144
147
|
name="prefix-icon"
|
145
148
|
@slotchange=${this.#onPrefixIconSlotChange}
|
146
149
|
${ref(this.#prefixIconSlotElementRef)}
|
package/dist/accordion.styles.js
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
export default function (): Promise<unknown>;
|
package/dist/link.js
CHANGED
@@ -41,22 +41,40 @@ let Link = class Link extends LitElement {
|
|
41
41
|
this.#componentElementRef.value?.click();
|
42
42
|
}
|
43
43
|
render() {
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
44
|
+
// Lit-a11y also wants a keyboard listener on anything with a "click" listener and
|
45
|
+
// doesn't account for `role="link"`.
|
46
|
+
//
|
47
|
+
/* eslint-disable lit-a11y/click-events-have-key-events */
|
48
|
+
return this.disabled
|
49
|
+
? html `<span
|
50
|
+
aria-disabled="true"
|
51
|
+
class=${classMap({
|
52
|
+
component: true,
|
53
|
+
disabled: this.disabled,
|
54
|
+
})}
|
55
|
+
data-test="component"
|
56
|
+
role="link"
|
57
|
+
tabindex="0"
|
58
|
+
@click=${this.#onClick}
|
59
|
+
${ref(this.#componentElementRef)}
|
60
|
+
>
|
61
|
+
${this.label}
|
62
|
+
</span>`
|
63
|
+
: html `<a
|
64
|
+
class=${classMap({
|
65
|
+
component: true,
|
66
|
+
disabled: this.disabled,
|
67
|
+
href: Boolean(this.href),
|
68
|
+
})}
|
69
|
+
data-test="component"
|
70
|
+
download=${ifDefined(this.download)}
|
71
|
+
href=${ifDefined(this.href)}
|
72
|
+
target=${ifDefined(this.target)}
|
73
|
+
@click=${this.#onClick}
|
74
|
+
${ref(this.#componentElementRef)}
|
75
|
+
>
|
76
|
+
${this.label}
|
77
|
+
</a>`;
|
60
78
|
}
|
61
79
|
#componentElementRef;
|
62
80
|
#onClick(event) {
|
package/dist/menu.d.ts
CHANGED
@@ -8,7 +8,7 @@ declare global {
|
|
8
8
|
* @attr {boolean} [loading=false]
|
9
9
|
* @attr {number} [offset=4]
|
10
10
|
* @attr {boolean} [open=false]
|
11
|
-
* @attr {'bottom'|'left'|'right'|'top'|'bottom-start'|'bottom-end'|'left-start'|'left-end'|'right-start'|'right-end'|'top-start'|'top-end'} [placement='bottom-start']
|
11
|
+
* @attr {'bottom'|'left'|'right'|'top'|'bottom-start'|'bottom-end'|'left-start'|'left-end'|'right-start'|'right-end'|'top-start'|'top-end'} [placement='bottom-start'] - Menu 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".
|
12
12
|
*
|
13
13
|
* @readonly
|
14
14
|
* @attr {string} [version]
|
@@ -37,6 +37,10 @@ export default class Menu extends LitElement {
|
|
37
37
|
*/
|
38
38
|
get open(): boolean;
|
39
39
|
set open(isOpen: boolean);
|
40
|
+
/**
|
41
|
+
* Menu will try to move itself to the opposite of this value if not doing so would result in overflow.
|
42
|
+
* For example, if "bottom" results in overflow Menu will try "top" but not "right" or "left".
|
43
|
+
*/
|
40
44
|
placement: 'bottom' | 'left' | 'right' | 'top' | 'bottom-start' | 'bottom-end' | 'left-start' | 'left-end' | 'right-start' | 'right-end' | 'top-start' | 'top-end';
|
41
45
|
privateOpenedViaKeyboard: boolean;
|
42
46
|
readonly version: string;
|
package/dist/menu.js
CHANGED
@@ -25,7 +25,7 @@ import uniqueId from './library/unique-id.js';
|
|
25
25
|
* @attr {boolean} [loading=false]
|
26
26
|
* @attr {number} [offset=4]
|
27
27
|
* @attr {boolean} [open=false]
|
28
|
-
* @attr {'bottom'|'left'|'right'|'top'|'bottom-start'|'bottom-end'|'left-start'|'left-end'|'right-start'|'right-end'|'top-start'|'top-end'} [placement='bottom-start']
|
28
|
+
* @attr {'bottom'|'left'|'right'|'top'|'bottom-start'|'bottom-end'|'left-start'|'left-end'|'right-start'|'right-end'|'top-start'|'top-end'} [placement='bottom-start'] - Menu 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".
|
29
29
|
*
|
30
30
|
* @readonly
|
31
31
|
* @attr {string} [version]
|
@@ -38,6 +38,10 @@ import uniqueId from './library/unique-id.js';
|
|
38
38
|
let Menu = class Menu extends LitElement {
|
39
39
|
constructor() {
|
40
40
|
super(...arguments);
|
41
|
+
/**
|
42
|
+
* Menu will try to move itself to the opposite of this value if not doing so would result in overflow.
|
43
|
+
* For example, if "bottom" results in overflow Menu will try "top" but not "right" or "left".
|
44
|
+
*/
|
41
45
|
this.placement = 'bottom-start';
|
42
46
|
// Used in `#show()` to open the active Option's tooltip when Menu is opened via
|
43
47
|
// keyboard. Unlike mouse users, keyboard users can't hover an Option to reveal
|
@@ -55,7 +59,7 @@ let Menu = class Menu extends LitElement {
|
|
55
59
|
// `#onComponentFocusOut()` to decide if Menu should close. Also used in
|
56
60
|
// `#onTargetAndDefaultSlotKeyDown()` to decide if we need to move focus.
|
57
61
|
this.#hasVoiceOverMovedFocusToOptionsOrAnOption = false;
|
58
|
-
// Set in `#
|
62
|
+
// Set in `#onDefaultSlotClick()`. Used in `#onDocumentClick()` to guard against
|
59
63
|
// Menu closing when any number of things that are not an Option are clicked. Those
|
60
64
|
// "click" events will be retargeted to Menu's host the moment they bubble out of
|
61
65
|
// Menu. So checking in `#onDocumentClick()` if the click's `event.target` came
|
@@ -224,7 +228,7 @@ let Menu = class Menu extends LitElement {
|
|
224
228
|
}
|
225
229
|
}
|
226
230
|
if (this.#defaultSlotElementRef.value) {
|
227
|
-
// `popover` so Options can break out of Modal or another
|
231
|
+
// `popover` so Options can break out of Modal or another element that has
|
228
232
|
// `overflow: hidden`. Elements with `popover` are positioned relative to the
|
229
233
|
// viewport. Thus Floating UI in addition to `popover` until anchor positioning is
|
230
234
|
// well supported.
|
@@ -294,7 +298,6 @@ let Menu = class Menu extends LitElement {
|
|
294
298
|
@keydown=${this.#onTargetAndDefaultSlotKeyDown}
|
295
299
|
@mousedown=${this.#onDefaultSlotMouseDown}
|
296
300
|
@mouseover=${this.#onDefaultSlotMouseOver}
|
297
|
-
@mouseup=${this.#onDefaultSlotMouseUp}
|
298
301
|
@private-disabled-change=${this.#onDefaultSlotDisabledChange}
|
299
302
|
@private-slot-change=${this.#onDefaultSlotSlotChange}
|
300
303
|
@toggle=${this.#onDefaultSlotToggle}
|
@@ -316,7 +319,7 @@ let Menu = class Menu extends LitElement {
|
|
316
319
|
// `#onComponentFocusOut()` to decide if Menu should close. Also used in
|
317
320
|
// `#onTargetAndDefaultSlotKeyDown()` to decide if we need to move focus.
|
318
321
|
#hasVoiceOverMovedFocusToOptionsOrAnOption;
|
319
|
-
// Set in `#
|
322
|
+
// Set in `#onDefaultSlotClick()`. Used in `#onDocumentClick()` to guard against
|
320
323
|
// Menu closing when any number of things that are not an Option are clicked. Those
|
321
324
|
// "click" events will be retargeted to Menu's host the moment they bubble out of
|
322
325
|
// Menu. So checking in `#onDocumentClick()` if the click's `event.target` came
|
@@ -494,6 +497,7 @@ let Menu = class Menu extends LitElement {
|
|
494
497
|
}
|
495
498
|
}
|
496
499
|
#onDefaultSlotClick(event) {
|
500
|
+
this.#isDefaultSlotClick = true;
|
497
501
|
// When the padding or border on the default slot of a sub-Menu is clicked, the
|
498
502
|
// event will be retargeted by the browser to the sub-Menu's parent Option.
|
499
503
|
//
|
@@ -571,62 +575,41 @@ let Menu = class Menu extends LitElement {
|
|
571
575
|
event.preventDefault();
|
572
576
|
}
|
573
577
|
#onDefaultSlotMouseOver(event) {
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
//
|
580
|
-
//
|
581
|
-
//
|
582
|
-
//
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
// to keep an eye on: https://issues.chromium.org/issues/364669918.
|
588
|
-
const isOutOfBounds = this.#componentElementRef.value &&
|
589
|
-
event.y < this.#componentElementRef.value.getBoundingClientRect().y;
|
590
|
-
if (!isOutOfBounds) {
|
591
|
-
const option = event.target instanceof Element &&
|
592
|
-
event.target.closest('glide-core-option');
|
593
|
-
const isSubMenuTarget = event.target instanceof Element &&
|
594
|
-
event.target.closest('[slot="target"]');
|
595
|
-
const isOwnOption = option && this.#optionElements?.includes(option);
|
596
|
-
// This handler is also called when a sub-Menu Option is hovered because sub-Menu
|
597
|
-
// Option(s) are children of their super-Menu's default slot. And hovering a
|
598
|
-
// sub-Menu Option shouldn't deactivate the super-Menu's active Option. Thus
|
599
|
-
// `isOwnOption`.
|
600
|
-
if (isOwnOption && !isSubMenuTarget && !option.disabled) {
|
601
|
-
this.#previouslyActiveOption = this.#activeOption;
|
602
|
-
if (this.#activeOption) {
|
603
|
-
this.#activeOption.privateActive = false;
|
604
|
-
}
|
605
|
-
option.privateActive = true;
|
606
|
-
if (this.#optionsElement) {
|
607
|
-
this.#optionsElement.ariaActivedescendant = event.target.id;
|
608
|
-
}
|
609
|
-
}
|
610
|
-
if (this.#isSubMenu) {
|
611
|
-
// Allowing the event to propagate from a sub-Menu's parent Option means it would
|
612
|
-
// get picked up by the super-Menu Option's Tooltip "mouseover" handler. Then it
|
613
|
-
// would open the super-Menu's tooltip.
|
614
|
-
event.stopPropagation();
|
578
|
+
const option = event.target instanceof Element &&
|
579
|
+
event.target.closest('glide-core-option');
|
580
|
+
const isSubMenuTarget = event.target instanceof Element &&
|
581
|
+
event.target.closest('[slot="target"]');
|
582
|
+
const isOwnOption = option && this.#optionElements?.includes(option);
|
583
|
+
// This handler is also called when a sub-Menu Option is hovered because sub-Menu
|
584
|
+
// Option(s) are children of their super-Menu's default slot. And hovering a
|
585
|
+
// sub-Menu Option shouldn't deactivate the super-Menu's active Option. Thus
|
586
|
+
// `isOwnOption`.
|
587
|
+
if (isOwnOption && !isSubMenuTarget && !option.disabled) {
|
588
|
+
this.#previouslyActiveOption = this.#activeOption;
|
589
|
+
if (this.#activeOption) {
|
590
|
+
this.#activeOption.privateActive = false;
|
615
591
|
}
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
//
|
620
|
-
// The Option's tooltip will pick up both events and will remain open because the
|
621
|
-
// tooltip will be closed then immediately reopened. But we want the tooltip to
|
622
|
-
// close when a sub-Menu target is hovered. Canceling the event stops the tooltip
|
623
|
-
// from reopening.
|
624
|
-
event.preventDefault();
|
592
|
+
option.privateActive = true;
|
593
|
+
if (this.#optionsElement) {
|
594
|
+
this.#optionsElement.ariaActivedescendant = event.target.id;
|
625
595
|
}
|
626
596
|
}
|
627
|
-
|
628
|
-
|
629
|
-
|
597
|
+
if (this.#isSubMenu) {
|
598
|
+
// Allowing the event to propagate from a sub-Menu's parent Option means it would
|
599
|
+
// get picked up by the super-Menu Option's Tooltip "mouseover" handler. Then it
|
600
|
+
// would open the super-Menu's tooltip.
|
601
|
+
event.stopPropagation();
|
602
|
+
}
|
603
|
+
if (isSubMenuTarget && this.#activeOption) {
|
604
|
+
// When the cursor is already inside an Option and the user mouses to the Option's
|
605
|
+
// sub-Menu target, the browser will dispatch "mouseout" followed by "mouseover".
|
606
|
+
//
|
607
|
+
// The Option's tooltip will pick up both events and will remain open because the
|
608
|
+
// tooltip will be closed then immediately reopened. But we want the tooltip to
|
609
|
+
// close when a sub-Menu target is hovered. Canceling the event stops the tooltip
|
610
|
+
// from reopening.
|
611
|
+
event.preventDefault();
|
612
|
+
}
|
630
613
|
}
|
631
614
|
#onDefaultSlotSlotChange() {
|
632
615
|
const wasActiveOptionRemoved = this.#optionElements?.every((option) => option !== this.#activeOption);
|
@@ -1164,6 +1147,60 @@ let Menu = class Menu extends LitElement {
|
|
1164
1147
|
}
|
1165
1148
|
#show() {
|
1166
1149
|
this.#cleanUpFloatingUi?.();
|
1150
|
+
// Ideally, we wouldn't show the popover until after Floating UI has calculated its
|
1151
|
+
// position. But calling `showPopover()` changes the nature of how `top` and `left`
|
1152
|
+
// affect an element's position when the element's containing block is something
|
1153
|
+
// other than the document.
|
1154
|
+
//
|
1155
|
+
// Unlike non-popovers, popovers break out of containing blocks¹. So `top` and
|
1156
|
+
// `left` are always relative to the document. For non-popovers, however, `top`
|
1157
|
+
// and `left` are relative to the element's containing block.
|
1158
|
+
//
|
1159
|
+
// Imagine that Menu has a parent with `transform: scale(1)` and we let Floating UI
|
1160
|
+
// calculate the default slot's position before calling `showPopover()`. Floating
|
1161
|
+
// UI will correctly position the default slot relative to that parent. But, after
|
1162
|
+
// `showPopover()` is called, Floating UI will recalculate the default slot's
|
1163
|
+
// position and position it relative to the document.
|
1164
|
+
//
|
1165
|
+
// The problem is, during the time between when `showPopover()` is called and
|
1166
|
+
// Floating UI does its recalculation, the default slot will have a `top` and
|
1167
|
+
// `left` that were correct when it was positioned relative to its containing
|
1168
|
+
// block, but are now incorrect. So the default slot will, for a moment, be
|
1169
|
+
// positioned above or below where it should be.
|
1170
|
+
//
|
1171
|
+
// The recalculation and subsequent repositioning will happen so quickly that the
|
1172
|
+
// user won't see it. But, if the user's mouse happens to be on top of the default
|
1173
|
+
// slot while it's positioned incorrectly, then `#onDefaultSlotMouseOver()` will
|
1174
|
+
// be called and whatever Option the user's mouse is on will be activated. Floating
|
1175
|
+
// UI will finish its work, then default slot will become visible. But the wrong
|
1176
|
+
// Option will be active when Menu finally appears open.
|
1177
|
+
//
|
1178
|
+
// To reproduce the issue:
|
1179
|
+
//
|
1180
|
+
// 1. Move the `showPopover()` call below inside `computePosition().then()`.
|
1181
|
+
// 2. Go to Menu's Overview page in Storybook.
|
1182
|
+
// 3. Place your mouse just above Menu's target.
|
1183
|
+
// 4. Tab to Menu's target.
|
1184
|
+
// 5. Press Space to open Menu.
|
1185
|
+
//
|
1186
|
+
// Note how the second or third Option is active instead of the first.
|
1187
|
+
//
|
1188
|
+
// I've omitted a test for this because calling `sendKey({ press: 'Tab' })`
|
1189
|
+
// followed by `sendKey({ press: ' ' })`, after moving the mouse above Menu's
|
1190
|
+
// target, introduces just enough of a delay for Floating UI to complete its
|
1191
|
+
// recalculation, making the issue impossible to reproduce in a test.
|
1192
|
+
//
|
1193
|
+
// 1. https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_display/Containing_block#identifying_the_containing_block
|
1194
|
+
this.#defaultSlotElementRef.value?.showPopover();
|
1195
|
+
if (this.#isSubMenu && this.#parentOption) {
|
1196
|
+
this.#parentOption.ariaExpanded = 'true';
|
1197
|
+
}
|
1198
|
+
else if (!this.#isSubMenu && this.#targetElement) {
|
1199
|
+
this.#targetElement.ariaExpanded = 'true';
|
1200
|
+
}
|
1201
|
+
if (this.#optionsElement && this.#activeOption?.id) {
|
1202
|
+
this.#optionsElement.ariaActivedescendant = this.#activeOption.id;
|
1203
|
+
}
|
1167
1204
|
if (this.#previouslyActiveOption &&
|
1168
1205
|
!this.#previouslyActiveOption.disabled &&
|
1169
1206
|
this.#optionsElement) {
|
@@ -1196,17 +1233,6 @@ let Menu = class Menu extends LitElement {
|
|
1196
1233
|
left: `${x}px`,
|
1197
1234
|
top: `${y}px`,
|
1198
1235
|
});
|
1199
|
-
if (this.#isSubMenu && this.#parentOption) {
|
1200
|
-
this.#parentOption.ariaExpanded = 'true';
|
1201
|
-
}
|
1202
|
-
else if (!this.#isSubMenu && this.#targetElement) {
|
1203
|
-
this.#targetElement.ariaExpanded = 'true';
|
1204
|
-
}
|
1205
|
-
this.#defaultSlotElementRef.value.showPopover();
|
1206
|
-
}
|
1207
|
-
if (this.#optionsElement && this.#activeOption?.id) {
|
1208
|
-
this.#optionsElement.ariaActivedescendant =
|
1209
|
-
this.#activeOption.id;
|
1210
1236
|
}
|
1211
1237
|
});
|
1212
1238
|
}
|
package/dist/menu.styles.js
CHANGED
@@ -35,7 +35,6 @@ 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;
|
39
38
|
|
40
39
|
/*
|
41
40
|
This little hack replaces "padding-block-end", which the last option overlaps
|
package/dist/popover.d.ts
CHANGED
@@ -8,13 +8,13 @@ declare global {
|
|
8
8
|
* @attr {boolean} [disabled=false]
|
9
9
|
* @attr {number} [offset=4]
|
10
10
|
* @attr {boolean} [open=false]
|
11
|
-
* @attr {'bottom'|'left'|'right'|'top'} [placement]
|
11
|
+
* @attr {'bottom'|'left'|'right'|'top'} [placement] - Popover 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 Popover will try "top" but not "right" or "left".
|
12
12
|
*
|
13
13
|
* @readonly
|
14
14
|
* @attr {string} [version]
|
15
15
|
*
|
16
16
|
* @slot {Element | string} - The content of the popover
|
17
|
-
* @slot {Element} [target] - The element to which
|
17
|
+
* @slot {Element} [target] - The element to which Popover will anchor. Can be any focusable element.
|
18
18
|
*
|
19
19
|
* @fires {Event} toggle
|
20
20
|
*/
|
@@ -37,6 +37,10 @@ export default class Popover extends LitElement {
|
|
37
37
|
*/
|
38
38
|
get open(): boolean;
|
39
39
|
set open(isOpen: boolean);
|
40
|
+
/**
|
41
|
+
* Popover will try to move itself to the opposite of this value if not doing so would result in overflow.
|
42
|
+
* For example, if "bottom" results in overflow Popover will try "top" but not "right" or "left".
|
43
|
+
*/
|
40
44
|
placement?: 'bottom' | 'left' | 'right' | 'top';
|
41
45
|
readonly version: string;
|
42
46
|
connectedCallback(): void;
|
package/dist/popover.js
CHANGED
@@ -19,13 +19,13 @@ import final from './library/final.js';
|
|
19
19
|
* @attr {boolean} [disabled=false]
|
20
20
|
* @attr {number} [offset=4]
|
21
21
|
* @attr {boolean} [open=false]
|
22
|
-
* @attr {'bottom'|'left'|'right'|'top'} [placement]
|
22
|
+
* @attr {'bottom'|'left'|'right'|'top'} [placement] - Popover 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 Popover will try "top" but not "right" or "left".
|
23
23
|
*
|
24
24
|
* @readonly
|
25
25
|
* @attr {string} [version]
|
26
26
|
*
|
27
27
|
* @slot {Element | string} - The content of the popover
|
28
|
-
* @slot {Element} [target] - The element to which
|
28
|
+
* @slot {Element} [target] - The element to which Popover will anchor. Can be any focusable element.
|
29
29
|
*
|
30
30
|
* @fires {Event} toggle
|
31
31
|
*/
|
@@ -36,19 +36,26 @@ let Popover = class Popover extends LitElement {
|
|
36
36
|
this.effectivePlacement = this.placement ?? 'bottom';
|
37
37
|
this.#arrowElementRef = createRef();
|
38
38
|
this.#defaultSlotElementRef = createRef();
|
39
|
+
// Set in `#onArrowClick()`. Used in `#onDocumentClick()` to guard against closing
|
40
|
+
// Popover when the user accidentally clicks the arrow.
|
39
41
|
this.#isArrowClick = false;
|
42
|
+
// Set in `#onDefaultSlotClick()`. Used in `#onDocumentClick()` to guard against
|
43
|
+
// closing Popover when the user interacts with its default slot.
|
40
44
|
this.#isDefaultSlotClick = false;
|
41
45
|
this.#isDisabled = false;
|
42
46
|
this.#isOpen = false;
|
47
|
+
// Set in `#onTargetSlotClick()`. Used in `#onDocumentClick()` to guard against
|
48
|
+
// immediately closing Popover when it's opened via `onTargetSlotClick()`.
|
43
49
|
this.#isTargetSlotClick = false;
|
44
50
|
this.#popoverElementRef = createRef();
|
45
51
|
this.#targetSlotElementRef = createRef();
|
46
52
|
// An arrow function field instead of a method so `this` is closed over and
|
47
53
|
// set to the component instead of `document`.
|
48
54
|
this.#onDocumentClick = () => {
|
49
|
-
// Checking that
|
50
|
-
//
|
51
|
-
//
|
55
|
+
// Checking that `event.target` is equal to `this.#defaultSlotElementRef.value`
|
56
|
+
// would be simpler. But, when the default slot is inside of another web component,
|
57
|
+
// `event.target` will be that component instead.
|
58
|
+
//
|
52
59
|
// Same for `this.#isTargetSlotClick` and `this.#isArrowClick`.
|
53
60
|
if (this.#isDefaultSlotClick ||
|
54
61
|
this.#isTargetSlotClick ||
|
@@ -122,65 +129,34 @@ let Popover = class Popover extends LitElement {
|
|
122
129
|
}
|
123
130
|
connectedCallback() {
|
124
131
|
super.connectedCallback();
|
125
|
-
|
126
|
-
// 2. The user clicks the button.
|
127
|
-
// 3. The button's click handler is called and it sets `this.open` to `true`.
|
128
|
-
// 4. The "click" event bubbles up and is handled by `#onDocumentClick`.
|
129
|
-
// 5. That handler sets `open` to `false` because the click came from outside
|
130
|
-
// Popover.
|
131
|
-
// 6. Popover is opened then closed in the same frame and so never opens.
|
132
|
-
//
|
133
|
-
// `capture` ensures `#onDocumentClick` is called before #3, so the button click
|
134
|
-
// handler setting `open` to `true` isn't overwritten by this handler setting
|
135
|
-
// `open` to `false`.
|
136
|
-
document.addEventListener('click', this.#onDocumentClick, {
|
137
|
-
capture: true,
|
138
|
-
});
|
132
|
+
document.addEventListener('click', this.#onDocumentClick);
|
139
133
|
}
|
140
134
|
firstUpdated() {
|
141
135
|
if (this.#popoverElementRef.value) {
|
142
|
-
// `popover`
|
143
|
-
//
|
144
|
-
//
|
136
|
+
// `popover` so Popover can break out of Modal or another element that has
|
137
|
+
// `overflow: hidden`. Elements with `popover` are positioned relative to the
|
138
|
+
// viewport. Thus Floating UI in addition to `popover` until anchor positioning is
|
139
|
+
// well supported.
|
145
140
|
//
|
146
|
-
//
|
147
|
-
// of `popover` and doesn't
|
141
|
+
// "manual" is set here instead of in the template to circumvent Lit Analyzer,
|
142
|
+
// which isn't aware of `popover` and doesn't provide a way to disable its
|
143
|
+
// "no-unknown-attribute" rule.
|
148
144
|
//
|
149
|
-
// "auto"
|
150
|
-
//
|
151
|
-
//
|
152
|
-
// "auto" also automatically opens the popover when its target is clicked. We want
|
153
|
-
// it to remain closed when clicked when there are no menu options.
|
145
|
+
// "manual" instead of "auto" because the latter only allows one popover to be open
|
146
|
+
// at a time. And consumers may have other popovers that need to remain open while
|
147
|
+
// this popover is open.
|
154
148
|
this.#popoverElementRef.value.popover = 'manual';
|
155
149
|
}
|
156
150
|
if (this.open && !this.disabled) {
|
157
151
|
this.#show();
|
158
152
|
}
|
159
|
-
// Popover's "click" handler on `document` listens for clicks in the capture
|
160
|
-
// phase. There's a comment explaining why. `#isDefaultSlotclick` must be
|
161
|
-
// set before that handler is called so it has the information it needs
|
162
|
-
// to determine whether or not to close Popover. Same for `#isTargetSlotClick`
|
163
|
-
// and `#isArrowClick`.
|
164
|
-
this.#defaultSlotElementRef.value?.addEventListener('mouseup', () => {
|
165
|
-
this.#isDefaultSlotClick = true;
|
166
|
-
});
|
167
|
-
this.#targetSlotElementRef.value?.addEventListener('mouseup', () => {
|
168
|
-
this.#isTargetSlotClick = true;
|
169
|
-
});
|
170
|
-
this.#arrowElementRef.value?.addEventListener('mouseup', () => {
|
171
|
-
this.#isArrowClick = true;
|
172
|
-
});
|
173
|
-
this.#targetSlotElementRef.value?.addEventListener('keydown', (event) => {
|
174
|
-
if (event.key === 'Enter' || event.key === ' ') {
|
175
|
-
this.#isTargetSlotClick = true;
|
176
|
-
}
|
177
|
-
});
|
178
153
|
}
|
179
154
|
render() {
|
180
|
-
// Lit-a11y
|
181
|
-
//
|
182
|
-
//
|
183
|
-
//
|
155
|
+
// Lit-a11y also wants a keyboard listener on anything with a "click" listener. The
|
156
|
+
// "click" listeners on the arrow and default slot, however, are for a specific
|
157
|
+
// purpose that Lit-a11y isn't aware of.
|
158
|
+
//
|
159
|
+
/* eslint-disable lit-a11y/click-events-have-key-events */
|
184
160
|
return html `
|
185
161
|
<div class="component">
|
186
162
|
<slot
|
@@ -193,7 +169,7 @@ let Popover = class Popover extends LitElement {
|
|
193
169
|
${ref(this.#targetSlotElementRef)}
|
194
170
|
>
|
195
171
|
<!--
|
196
|
-
The element to which
|
172
|
+
The element to which Popover will anchor. Can be any focusable element.
|
197
173
|
@type {Element}
|
198
174
|
-->
|
199
175
|
</slot>
|
@@ -213,6 +189,7 @@ let Popover = class Popover extends LitElement {
|
|
213
189
|
[this.effectivePlacement]: true,
|
214
190
|
})}
|
215
191
|
data-test="arrow"
|
192
|
+
@click=${this.#onArrowClick}
|
216
193
|
${ref(this.#arrowElementRef)}
|
217
194
|
>
|
218
195
|
${choose(this.effectivePlacement, [
|
@@ -225,6 +202,7 @@ let Popover = class Popover extends LitElement {
|
|
225
202
|
|
226
203
|
<slot
|
227
204
|
class="default-slot"
|
205
|
+
@click=${this.#onDefaultSlotClick}
|
228
206
|
${assertSlot()}
|
229
207
|
${ref(this.#defaultSlotElementRef)}
|
230
208
|
>
|
@@ -240,10 +218,16 @@ let Popover = class Popover extends LitElement {
|
|
240
218
|
#arrowElementRef;
|
241
219
|
#cleanUpFloatingUi;
|
242
220
|
#defaultSlotElementRef;
|
221
|
+
// Set in `#onArrowClick()`. Used in `#onDocumentClick()` to guard against closing
|
222
|
+
// Popover when the user accidentally clicks the arrow.
|
243
223
|
#isArrowClick;
|
224
|
+
// Set in `#onDefaultSlotClick()`. Used in `#onDocumentClick()` to guard against
|
225
|
+
// closing Popover when the user interacts with its default slot.
|
244
226
|
#isDefaultSlotClick;
|
245
227
|
#isDisabled;
|
246
228
|
#isOpen;
|
229
|
+
// Set in `#onTargetSlotClick()`. Used in `#onDocumentClick()` to guard against
|
230
|
+
// immediately closing Popover when it's opened via `onTargetSlotClick()`.
|
247
231
|
#isTargetSlotClick;
|
248
232
|
#offset;
|
249
233
|
#popoverElementRef;
|
@@ -258,14 +242,31 @@ let Popover = class Popover extends LitElement {
|
|
258
242
|
}
|
259
243
|
this.#cleanUpFloatingUi?.();
|
260
244
|
}
|
261
|
-
#
|
262
|
-
this
|
245
|
+
#onArrowClick() {
|
246
|
+
this.#isArrowClick = true;
|
247
|
+
}
|
248
|
+
#onDefaultSlotClick() {
|
249
|
+
this.#isDefaultSlotClick = true;
|
250
|
+
}
|
251
|
+
#onTargetSlotClick(event) {
|
252
|
+
this.#isTargetSlotClick = true;
|
253
|
+
// The timeout gives consumers a chance to cancel the event to prevent Popover
|
254
|
+
// from opening or closing.
|
255
|
+
setTimeout(() => {
|
256
|
+
if (!event.defaultPrevented) {
|
257
|
+
this.open = !this.open;
|
258
|
+
}
|
259
|
+
});
|
263
260
|
}
|
264
261
|
#onTargetSlotKeydown(event) {
|
262
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
263
|
+
this.#isTargetSlotClick = true;
|
264
|
+
return;
|
265
|
+
}
|
265
266
|
if (event.key === 'Escape') {
|
266
|
-
// Prevent Safari from leaving full screen.
|
267
|
-
event.preventDefault();
|
267
|
+
event.preventDefault(); // Prevent Safari from leaving full screen.
|
268
268
|
this.open = false;
|
269
|
+
return;
|
269
270
|
}
|
270
271
|
}
|
271
272
|
get #targetElement() {
|
package/dist/slider.js
CHANGED
@@ -345,6 +345,7 @@ let Slider = class Slider extends LitElement {
|
|
345
345
|
// input elements directly or via the handles. Exposing the
|
346
346
|
// track via keyboard wouldn't bring any real value in this
|
347
347
|
// instance.
|
348
|
+
//
|
348
349
|
/* eslint-disable lit-a11y/click-events-have-key-events */
|
349
350
|
return html `
|
350
351
|
<glide-core-private-label
|
package/dist/tooltip.d.ts
CHANGED
@@ -11,7 +11,7 @@ declare global {
|
|
11
11
|
* @attr {boolean} [disabled=false]
|
12
12
|
* @attr {number} [offset=4]
|
13
13
|
* @attr {boolean} [open=false]
|
14
|
-
* @attr {'bottom'|'left'|'right'|'top'} [placement] -
|
14
|
+
* @attr {'bottom'|'left'|'right'|'top'} [placement] - Tooltip 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 Tooltip will try "top" but not "right" or "left".
|
15
15
|
* @attr {boolean} [screenreader-hidden=false]
|
16
16
|
* @attr {string[]} [shortcut=[]]
|
17
17
|
*
|
@@ -19,7 +19,7 @@ declare global {
|
|
19
19
|
* @attr {string} [version]
|
20
20
|
*
|
21
21
|
* @slot {TooltipContainer} [private]
|
22
|
-
* @slot {Element} target - The element to which
|
22
|
+
* @slot {Element} target - The element to which Tooltip will anchor. Can be any interactive element with an implicit or explicit ARIA role.
|
23
23
|
*
|
24
24
|
* @fires {Event} toggle
|
25
25
|
*/
|
@@ -56,8 +56,8 @@ export default class Tooltip extends LitElement {
|
|
56
56
|
*/
|
57
57
|
set open(isOpen: boolean);
|
58
58
|
/**
|
59
|
-
*
|
60
|
-
*
|
59
|
+
* Tooltip will try to move itself to the opposite of this value if not doing so would result in overflow.
|
60
|
+
* For example, if "bottom" results in overflow Tooltip will try "top" but not "right" or "left".
|
61
61
|
*/
|
62
62
|
placement?: 'bottom' | 'left' | 'right' | 'top';
|
63
63
|
/**
|
package/dist/tooltip.js
CHANGED
@@ -23,7 +23,7 @@ import required from './library/required.js';
|
|
23
23
|
* @attr {boolean} [disabled=false]
|
24
24
|
* @attr {number} [offset=4]
|
25
25
|
* @attr {boolean} [open=false]
|
26
|
-
* @attr {'bottom'|'left'|'right'|'top'} [placement] -
|
26
|
+
* @attr {'bottom'|'left'|'right'|'top'} [placement] - Tooltip 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 Tooltip will try "top" but not "right" or "left".
|
27
27
|
* @attr {boolean} [screenreader-hidden=false]
|
28
28
|
* @attr {string[]} [shortcut=[]]
|
29
29
|
*
|
@@ -31,7 +31,7 @@ import required from './library/required.js';
|
|
31
31
|
* @attr {string} [version]
|
32
32
|
*
|
33
33
|
* @slot {TooltipContainer} [private]
|
34
|
-
* @slot {Element} target - The element to which
|
34
|
+
* @slot {Element} target - The element to which Tooltip will anchor. Can be any interactive element with an implicit or explicit ARIA role.
|
35
35
|
*
|
36
36
|
* @fires {Event} toggle
|
37
37
|
*/
|
@@ -179,18 +179,18 @@ let Tooltip = class Tooltip extends LitElement {
|
|
179
179
|
}
|
180
180
|
firstUpdated() {
|
181
181
|
if (this.#tooltipElementRef.value) {
|
182
|
-
// `popover`
|
183
|
-
//
|
184
|
-
//
|
182
|
+
// `popover` so Tooltip can break out of Modal or another element that has
|
183
|
+
// `overflow: hidden`. Elements with `popover` are positioned relative to the
|
184
|
+
// viewport. Thus Floating UI in addition to `popover` until anchor positioning is
|
185
|
+
// well supported.
|
185
186
|
//
|
186
|
-
//
|
187
|
-
// of `popover` and doesn't
|
187
|
+
// "manual" is set here instead of in the template to circumvent Lit Analyzer,
|
188
|
+
// which isn't aware of `popover` and doesn't provide a way to disable its
|
189
|
+
// "no-unknown-attribute" rule.
|
188
190
|
//
|
189
|
-
// "auto"
|
190
|
-
//
|
191
|
-
//
|
192
|
-
// "auto" also automatically opens the popover when its target is clicked. We
|
193
|
-
// only want it to open on hover or focus.
|
191
|
+
// "manual" instead of "auto" because the latter only allows one popover to be open
|
192
|
+
// at a time. And consumers may have other popovers that need to remain open while
|
193
|
+
// this popover is open.
|
194
194
|
this.#tooltipElementRef.value.popover = 'manual';
|
195
195
|
}
|
196
196
|
if (this.open && !this.disabled) {
|
@@ -229,8 +229,8 @@ let Tooltip = class Tooltip extends LitElement {
|
|
229
229
|
${ref(this.#targetSlotElementRef)}
|
230
230
|
>
|
231
231
|
<!--
|
232
|
-
The element to which
|
233
|
-
Can be any element with an implicit or explicit ARIA role.
|
232
|
+
The element to which Tooltip will anchor.
|
233
|
+
Can be any interactive element with an implicit or explicit ARIA role.
|
234
234
|
|
235
235
|
@required
|
236
236
|
@type {Element}
|