@crowdstrike/glide-core 0.29.2 → 0.30.1
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 +240 -1
- package/dist/accordion.styles.js +13 -7
- package/dist/button-group.button.js +143 -1
- package/dist/button-group.button.styles.js +43 -15
- package/dist/button-group.js +249 -1
- package/dist/button-group.styles.js +10 -5
- package/dist/button.js +206 -1
- package/dist/button.styles.js +12 -7
- package/dist/checkbox-group.js +479 -14
- package/dist/checkbox-group.styles.js +5 -2
- package/dist/checkbox.js +519 -32
- package/dist/checkbox.styles.js +10 -5
- package/dist/drawer.js +168 -1
- package/dist/drawer.styles.js +5 -2
- package/dist/dropdown.js +2423 -123
- package/dist/dropdown.option.js +536 -1
- package/dist/dropdown.option.styles.js +5 -2
- package/dist/dropdown.styles.js +15 -8
- package/dist/form-controls-layout.js +102 -1
- package/dist/form-controls-layout.styles.js +5 -2
- package/dist/icon-button.js +139 -1
- package/dist/icon-button.styles.js +19 -7
- package/dist/icons/checked.js +28 -1
- package/dist/icons/chevron.js +21 -1
- package/dist/icons/magnifying-glass.js +23 -1
- package/dist/icons/pencil.js +21 -1
- package/dist/icons/severity-critical.js +20 -1
- package/dist/icons/severity-informational.js +20 -1
- package/dist/icons/severity-medium.js +20 -1
- package/dist/icons/x.js +21 -1
- package/dist/inline-alert.js +118 -1
- package/dist/inline-alert.styles.js +5 -2
- package/dist/input.d.ts +8 -2
- package/dist/input.js +505 -41
- package/dist/input.styles.js +25 -4
- package/dist/label.js +303 -1
- package/dist/label.styles.js +11 -5
- package/dist/library/assert-slot.js +136 -1
- package/dist/library/expect-unhandled-rejection.js +14 -1
- package/dist/library/expect-window-error.js +26 -1
- package/dist/library/final.js +18 -1
- package/dist/library/form-control.js +1 -1
- package/dist/library/localize.js +10 -1
- package/dist/library/mouse.js +35 -1
- package/dist/library/on-resize.js +24 -1
- package/dist/library/required.js +35 -1
- package/dist/library/shadow-root-mode.js +4 -1
- package/dist/library/unique-id.js +3 -1
- package/dist/link.js +92 -1
- package/dist/link.styles.js +10 -5
- package/dist/menu.d.ts +3 -2
- package/dist/menu.js +1259 -1
- package/dist/menu.styles.js +35 -19
- package/dist/modal.d.ts +4 -0
- package/dist/modal.icon-button.js +60 -1
- package/dist/modal.icon-button.styles.js +5 -2
- package/dist/modal.js +473 -1
- package/dist/modal.styles.js +71 -22
- package/dist/option.d.ts +74 -0
- package/dist/option.js +498 -0
- package/dist/option.styles.js +140 -0
- package/dist/{menu.options.d.ts → options.d.ts} +5 -6
- package/dist/options.js +130 -0
- package/dist/options.styles.js +21 -0
- package/dist/popover.js +620 -1
- package/dist/popover.styles.js +11 -5
- package/dist/radio-group.js +624 -17
- package/dist/radio-group.radio.js +211 -1
- package/dist/radio-group.radio.styles.js +9 -4
- package/dist/radio-group.styles.js +5 -2
- package/dist/slider.js +1040 -61
- package/dist/slider.styles.js +9 -4
- package/dist/spinner.js +60 -1
- package/dist/spinner.styles.js +5 -2
- package/dist/split-button.js +116 -1
- package/dist/split-button.primary-button.js +100 -1
- package/dist/split-button.primary-button.styles.js +13 -6
- package/dist/split-button.primary-link.js +102 -1
- package/dist/split-button.secondary-button.d.ts +2 -3
- package/dist/split-button.secondary-button.js +121 -1
- package/dist/split-button.secondary-button.styles.js +12 -7
- package/dist/split-button.styles.js +9 -4
- package/dist/styles/focus-outline.js +9 -3
- package/dist/styles/fonts.css +6 -1
- package/dist/styles/opacity-and-scale-animation.js +6 -3
- package/dist/styles/skeleton.js +6 -3
- package/dist/styles/variables.css +410 -1
- package/dist/styles/visually-hidden.js +6 -3
- package/dist/tab.group.js +386 -1
- package/dist/tab.group.styles.js +5 -2
- package/dist/tab.js +133 -1
- package/dist/tab.panel.js +93 -1
- package/dist/tab.panel.styles.js +11 -5
- package/dist/tab.styles.js +9 -4
- package/dist/tag.js +207 -1
- package/dist/tag.styles.js +10 -5
- package/dist/textarea.js +353 -19
- package/dist/textarea.styles.js +23 -4
- package/dist/toast.js +130 -1
- package/dist/toast.toasts.js +248 -25
- package/dist/toast.toasts.styles.js +9 -4
- package/dist/toggle.js +178 -1
- package/dist/toggle.styles.js +25 -5
- package/dist/tooltip.container.js +130 -1
- package/dist/tooltip.container.styles.js +5 -2
- package/dist/tooltip.js +484 -1
- package/dist/tooltip.styles.js +21 -5
- package/dist/translations/en.js +36 -1
- package/dist/translations/fr.js +37 -1
- package/dist/translations/ja.js +37 -1
- package/package.json +8 -12
- package/dist/menu.button.d.ts +0 -42
- package/dist/menu.button.js +0 -1
- package/dist/menu.button.styles.js +0 -32
- package/dist/menu.link.d.ts +0 -44
- package/dist/menu.link.js +0 -1
- package/dist/menu.link.styles.js +0 -35
- package/dist/menu.options.js +0 -1
- package/dist/menu.options.styles.d.ts +0 -2
- package/dist/menu.options.styles.js +0 -20
- /package/dist/{menu.button.styles.d.ts → option.styles.d.ts} +0 -0
- /package/dist/{menu.link.styles.d.ts → options.styles.d.ts} +0 -0
@@ -1 +1,130 @@
|
|
1
|
-
var __decorate
|
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 { customElement, property } from 'lit/decorators.js';
|
9
|
+
import { classMap } from 'lit/directives/class-map.js';
|
10
|
+
import { map } from 'lit/directives/map.js';
|
11
|
+
import { when } from 'lit/directives/when.js';
|
12
|
+
import styles from './tooltip.container.styles.js';
|
13
|
+
import shadowRootMode from './library/shadow-root-mode.js';
|
14
|
+
import final from './library/final.js';
|
15
|
+
import uniqueId from './library/unique-id.js';
|
16
|
+
// This component exists because Tooltip's target and its tooltip both need to
|
17
|
+
// be in the light DOM so the `aria-describedby` on its target can be associated
|
18
|
+
// with the ID it references. Tooltip adds this element to its light DOM and then
|
19
|
+
// associates it with its target.
|
20
|
+
//
|
21
|
+
// One alternative solution is to ask consumers to add this component to Tooltip's
|
22
|
+
// default slot. But that would be additional work for them and would be a less
|
23
|
+
// natural API because consumers would pass `label`, `shortcut`, and other
|
24
|
+
// attributes to Tooltip Container instead of Tooltip.
|
25
|
+
//
|
26
|
+
// Another is to require that consumers always wrap their default slot content
|
27
|
+
// in an element, such as `<div>`. But an apparently stray `<div>` in our Storybook
|
28
|
+
// code example would beget questions or may be removed by the consumer after
|
29
|
+
// copying the code, resulting in an error from Tooltip and frustration.
|
30
|
+
//
|
31
|
+
// The latter solution would also prevent us from restricting allowed content by
|
32
|
+
// using an attribute (`label`). We'd be forced to allow arbitrary content via a
|
33
|
+
// slot.
|
34
|
+
/**
|
35
|
+
* @attr {string} [description]
|
36
|
+
* @attr {boolean} [disabled=false]
|
37
|
+
* @attr {string} [label]
|
38
|
+
* @attr {'bottom'|'left'|'right'|'top'} [placement]
|
39
|
+
* @attr {boolean} [screenreader-hidden=false]
|
40
|
+
* @attr {string[]} [shortcut=[]]
|
41
|
+
*/
|
42
|
+
let TooltipContainer = class TooltipContainer extends LitElement {
|
43
|
+
constructor() {
|
44
|
+
super(...arguments);
|
45
|
+
this.screenreaderHidden = false;
|
46
|
+
this.shortcut = [];
|
47
|
+
this.#isDisabled = false;
|
48
|
+
}
|
49
|
+
static { this.shadowRootOptions = {
|
50
|
+
...LitElement.shadowRootOptions,
|
51
|
+
mode: shadowRootMode,
|
52
|
+
}; }
|
53
|
+
static { this.styles = styles; }
|
54
|
+
/**
|
55
|
+
* @default false
|
56
|
+
*/
|
57
|
+
get disabled() {
|
58
|
+
return this.#isDisabled;
|
59
|
+
}
|
60
|
+
set disabled(isDisabled) {
|
61
|
+
this.#isDisabled = isDisabled;
|
62
|
+
this.role = isDisabled || this.screenreaderHidden ? 'none' : 'tooltip';
|
63
|
+
}
|
64
|
+
connectedCallback() {
|
65
|
+
super.connectedCallback();
|
66
|
+
this.id = uniqueId();
|
67
|
+
this.role = this.role =
|
68
|
+
this.disabled || this.screenreaderHidden ? 'none' : 'tooltip';
|
69
|
+
this.slot = 'private';
|
70
|
+
}
|
71
|
+
render() {
|
72
|
+
return html `
|
73
|
+
<div
|
74
|
+
aria-hidden=${this.screenreaderHidden}
|
75
|
+
class=${classMap({
|
76
|
+
component: true,
|
77
|
+
})}
|
78
|
+
>
|
79
|
+
<div class="label-and-shortcut">
|
80
|
+
<div class="label">${this.label}</div>
|
81
|
+
|
82
|
+
<kbd
|
83
|
+
class=${classMap({
|
84
|
+
shortcut: true,
|
85
|
+
visible: this.shortcut.length > 0,
|
86
|
+
})}
|
87
|
+
data-test="shortcut"
|
88
|
+
>
|
89
|
+
${this.shortcut.length === 1
|
90
|
+
? this.shortcut.at(0)
|
91
|
+
: map(this.shortcut, (shortcut, index) => {
|
92
|
+
return html `
|
93
|
+
<kbd>${shortcut}</kbd>
|
94
|
+
${index === this.shortcut.length - 1 ? '' : ' + '}
|
95
|
+
`;
|
96
|
+
})}
|
97
|
+
</kbd>
|
98
|
+
</div>
|
99
|
+
|
100
|
+
${when(this.description, () => {
|
101
|
+
return html `<div class="description">${this.description}</div>`;
|
102
|
+
})}
|
103
|
+
</div>
|
104
|
+
`;
|
105
|
+
}
|
106
|
+
#isDisabled;
|
107
|
+
};
|
108
|
+
__decorate([
|
109
|
+
property({ reflect: true })
|
110
|
+
], TooltipContainer.prototype, "description", void 0);
|
111
|
+
__decorate([
|
112
|
+
property({ type: Boolean })
|
113
|
+
], TooltipContainer.prototype, "disabled", null);
|
114
|
+
__decorate([
|
115
|
+
property()
|
116
|
+
], TooltipContainer.prototype, "label", void 0);
|
117
|
+
__decorate([
|
118
|
+
property()
|
119
|
+
], TooltipContainer.prototype, "placement", void 0);
|
120
|
+
__decorate([
|
121
|
+
property({ attribute: 'screenreader-hidden', type: Boolean })
|
122
|
+
], TooltipContainer.prototype, "screenreaderHidden", void 0);
|
123
|
+
__decorate([
|
124
|
+
property({ type: Array })
|
125
|
+
], TooltipContainer.prototype, "shortcut", void 0);
|
126
|
+
TooltipContainer = __decorate([
|
127
|
+
customElement('glide-core-private-tooltip-container'),
|
128
|
+
final
|
129
|
+
], TooltipContainer);
|
130
|
+
export default TooltipContainer;
|
@@ -1,4 +1,6 @@
|
|
1
|
-
import{css}from
|
1
|
+
import { css } from 'lit';
|
2
|
+
export default [
|
3
|
+
css `
|
2
4
|
.component {
|
3
5
|
background-color: var(
|
4
6
|
--glide-core-private-color-tooltip-surface-container
|
@@ -48,4 +50,5 @@ import{css}from"lit";export default[css`
|
|
48
50
|
kbd {
|
49
51
|
font-family: var(--glide-core-typography-family-primary);
|
50
52
|
}
|
51
|
-
|
53
|
+
`,
|
54
|
+
];
|
package/dist/tooltip.js
CHANGED
@@ -1 +1,484 @@
|
|
1
|
-
var __decorate
|
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 { arrow, autoUpdate, computePosition, flip, limitShift, offset, shift, } from '@floating-ui/dom';
|
9
|
+
import { choose } from 'lit/directives/choose.js';
|
10
|
+
import { classMap } from 'lit/directives/class-map.js';
|
11
|
+
import { createRef, ref } from 'lit/directives/ref.js';
|
12
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
13
|
+
import packageJson from '../package.json' with { type: 'json' };
|
14
|
+
import styles from './tooltip.styles.js';
|
15
|
+
import './tooltip.container.js';
|
16
|
+
import assertSlot from './library/assert-slot.js';
|
17
|
+
import shadowRootMode from './library/shadow-root-mode.js';
|
18
|
+
import final from './library/final.js';
|
19
|
+
import required from './library/required.js';
|
20
|
+
/**
|
21
|
+
* @attr {string} label
|
22
|
+
* @attr {string} [description]
|
23
|
+
* @attr {boolean} [disabled=false]
|
24
|
+
* @attr {number} [offset=4]
|
25
|
+
* @attr {boolean} [open=false]
|
26
|
+
* @attr {'bottom'|'left'|'right'|'top'} [placement] - The placement of the tooltip relative to its target. Automatic placement will take over if the tooltip is cut off by the viewport.
|
27
|
+
* @attr {boolean} [screenreader-hidden=false]
|
28
|
+
* @attr {string[]} [shortcut=[]]
|
29
|
+
*
|
30
|
+
* @readonly
|
31
|
+
* @attr {string} [version]
|
32
|
+
*
|
33
|
+
* @slot {TooltipContainer} [private]
|
34
|
+
* @slot {Element} target - The element to which the tooltip will anchor. Can be any element with an implicit or explicit ARIA role.
|
35
|
+
*
|
36
|
+
* @fires {Event} toggle
|
37
|
+
*/
|
38
|
+
let Tooltip = class Tooltip extends LitElement {
|
39
|
+
constructor() {
|
40
|
+
super(...arguments);
|
41
|
+
this.version = packageJson.version;
|
42
|
+
this.effectivePlacement = this.placement ?? 'bottom';
|
43
|
+
this.#arrowElementRef = createRef();
|
44
|
+
this.#isDisabled = false;
|
45
|
+
this.#isOpen = false;
|
46
|
+
this.#isScreenreaderHidden = false;
|
47
|
+
this.#shortcut = [];
|
48
|
+
this.#targetSlotElementRef = createRef();
|
49
|
+
this.#tooltipElementRef = createRef();
|
50
|
+
}
|
51
|
+
static { this.shadowRootOptions = {
|
52
|
+
...LitElement.shadowRootOptions,
|
53
|
+
mode: shadowRootMode,
|
54
|
+
}; }
|
55
|
+
static { this.styles = styles; }
|
56
|
+
/**
|
57
|
+
* @default undefined
|
58
|
+
*/
|
59
|
+
get label() {
|
60
|
+
return this.#label;
|
61
|
+
}
|
62
|
+
set label(label) {
|
63
|
+
this.#label = label;
|
64
|
+
const container = this.querySelector('glide-core-private-tooltip-container');
|
65
|
+
if (container) {
|
66
|
+
container.label = label;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
/**
|
70
|
+
* @default undefined
|
71
|
+
*/
|
72
|
+
get description() {
|
73
|
+
return this.#description;
|
74
|
+
}
|
75
|
+
set description(description) {
|
76
|
+
this.#description = description;
|
77
|
+
const container = this.querySelector('glide-core-private-tooltip-container');
|
78
|
+
if (container) {
|
79
|
+
container.description = description;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
/**
|
83
|
+
* @default false
|
84
|
+
*/
|
85
|
+
get disabled() {
|
86
|
+
return this.#isDisabled;
|
87
|
+
}
|
88
|
+
set disabled(isDisabled) {
|
89
|
+
this.#isDisabled = isDisabled;
|
90
|
+
if (this.open && !isDisabled) {
|
91
|
+
this.#show();
|
92
|
+
}
|
93
|
+
else {
|
94
|
+
this.#hide();
|
95
|
+
}
|
96
|
+
const container = this.querySelector('glide-core-private-tooltip-container');
|
97
|
+
if (container) {
|
98
|
+
container.disabled = isDisabled;
|
99
|
+
}
|
100
|
+
const target = this.#targetSlotElementRef.value?.assignedElements().at(0);
|
101
|
+
if (container && target && !this.disabled && !this.screenreaderHidden) {
|
102
|
+
target.setAttribute('aria-describedby', container.id);
|
103
|
+
}
|
104
|
+
else if (container && target) {
|
105
|
+
target.removeAttribute('aria-describedby');
|
106
|
+
}
|
107
|
+
}
|
108
|
+
/**
|
109
|
+
* @default 4
|
110
|
+
*/
|
111
|
+
get offset() {
|
112
|
+
return (this.#offset ??
|
113
|
+
Number.parseFloat(window
|
114
|
+
.getComputedStyle(document.body)
|
115
|
+
.getPropertyValue('--glide-core-spacing-base-xxs')) *
|
116
|
+
Number.parseFloat(window.getComputedStyle(document.documentElement).fontSize));
|
117
|
+
}
|
118
|
+
set offset(offset) {
|
119
|
+
this.#offset = offset;
|
120
|
+
}
|
121
|
+
/**
|
122
|
+
* @default false
|
123
|
+
*/
|
124
|
+
get open() {
|
125
|
+
return this.#isOpen;
|
126
|
+
}
|
127
|
+
/**
|
128
|
+
* @default false
|
129
|
+
*/
|
130
|
+
set open(isOpen) {
|
131
|
+
const hasChanged = isOpen !== this.#isOpen;
|
132
|
+
this.#isOpen = isOpen;
|
133
|
+
if (isOpen && hasChanged && !this.disabled) {
|
134
|
+
this.#show();
|
135
|
+
this.dispatchEvent(new Event('toggle', { bubbles: true, composed: true }));
|
136
|
+
}
|
137
|
+
else if (hasChanged && !this.disabled) {
|
138
|
+
this.#hide();
|
139
|
+
this.dispatchEvent(new Event('toggle', { bubbles: true, composed: true }));
|
140
|
+
}
|
141
|
+
}
|
142
|
+
/**
|
143
|
+
* @default false
|
144
|
+
*/
|
145
|
+
get screenreaderHidden() {
|
146
|
+
return this.#isScreenreaderHidden;
|
147
|
+
}
|
148
|
+
set screenreaderHidden(isHidden) {
|
149
|
+
this.#isScreenreaderHidden = isHidden;
|
150
|
+
const container = this.querySelector('glide-core-private-tooltip-container');
|
151
|
+
if (container) {
|
152
|
+
container.screenreaderHidden = isHidden;
|
153
|
+
}
|
154
|
+
const target = this.#targetSlotElementRef.value?.assignedElements().at(0);
|
155
|
+
if (container && target && !this.disabled && !this.screenreaderHidden) {
|
156
|
+
target.setAttribute('aria-describedby', container.id);
|
157
|
+
}
|
158
|
+
else if (container && target) {
|
159
|
+
target.removeAttribute('aria-describedby');
|
160
|
+
}
|
161
|
+
}
|
162
|
+
/**
|
163
|
+
* @default []
|
164
|
+
*/
|
165
|
+
get shortcut() {
|
166
|
+
return this.#shortcut;
|
167
|
+
}
|
168
|
+
set shortcut(shortcut) {
|
169
|
+
this.#shortcut = shortcut;
|
170
|
+
const container = this.querySelector('glide-core-private-tooltip-container');
|
171
|
+
if (container) {
|
172
|
+
container.shortcut = shortcut;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
disconnectedCallback() {
|
176
|
+
super.disconnectedCallback();
|
177
|
+
clearTimeout(this.#closeTimeoutId);
|
178
|
+
clearTimeout(this.#openTimeoutId);
|
179
|
+
}
|
180
|
+
firstUpdated() {
|
181
|
+
if (this.#tooltipElementRef.value) {
|
182
|
+
// `popover` is used so the tooltip can break out of Modal or another container
|
183
|
+
// that has `overflow: hidden`. And elements with `popover` are positioned
|
184
|
+
// relative to the viewport. Thus Floating UI in addition to `popover`.
|
185
|
+
//
|
186
|
+
// Set here instead of in the template to escape Lit Analyzer, which isn't aware
|
187
|
+
// of `popover` and doesn't have a way to disable its "no-unknown-attribute" rule.
|
188
|
+
//
|
189
|
+
// "auto" means only one popover can be open at a time. Consumers, however, may
|
190
|
+
// have popovers in own components that need to be open while this one is open.
|
191
|
+
//
|
192
|
+
// "auto" also automatically opens the popover when its target is clicked. We
|
193
|
+
// only want it to open on hover or focus.
|
194
|
+
this.#tooltipElementRef.value.popover = 'manual';
|
195
|
+
}
|
196
|
+
if (this.open && !this.disabled) {
|
197
|
+
this.#show();
|
198
|
+
}
|
199
|
+
const container = document.createElement('glide-core-private-tooltip-container');
|
200
|
+
container.label = this.label;
|
201
|
+
container.description = this.description;
|
202
|
+
container.screenreaderHidden = this.screenreaderHidden;
|
203
|
+
container.shortcut = this.shortcut;
|
204
|
+
// There's a comment at the top of `./tooltip.container.ts` explaining why we
|
205
|
+
// append this component to the light DOM.
|
206
|
+
this.append(container);
|
207
|
+
}
|
208
|
+
render() {
|
209
|
+
// Lit-a11y calls for "blur" and "focus" handlers but doesn't account for "focusin"
|
210
|
+
// and "focusout".
|
211
|
+
/* eslint-disable lit-a11y/mouse-events-have-key-events */
|
212
|
+
return html `
|
213
|
+
<div
|
214
|
+
class="component"
|
215
|
+
data-test="component"
|
216
|
+
@mouseover=${this.#onComponentMouseOver}
|
217
|
+
@mouseout=${this.#onComponentMouseOut}
|
218
|
+
>
|
219
|
+
<div class="target-slot-container">
|
220
|
+
<slot
|
221
|
+
class="target-slot"
|
222
|
+
data-test="target-slot"
|
223
|
+
name="target"
|
224
|
+
@focusin=${this.#onTargetSlotFocusIn}
|
225
|
+
@focusout=${this.#onTargetSlotFocusOut}
|
226
|
+
@keydown=${this.#onTargetSlotKeyDown}
|
227
|
+
@slotchange=${this.#onTargetSlotChange}
|
228
|
+
${assertSlot()}
|
229
|
+
${ref(this.#targetSlotElementRef)}
|
230
|
+
>
|
231
|
+
<!--
|
232
|
+
The element to which the tooltip will anchor.
|
233
|
+
Can be any element with an implicit or explicit ARIA role.
|
234
|
+
|
235
|
+
@required
|
236
|
+
@type {Element}
|
237
|
+
-->
|
238
|
+
</slot>
|
239
|
+
</div>
|
240
|
+
|
241
|
+
<div
|
242
|
+
class=${classMap({
|
243
|
+
tooltip: true,
|
244
|
+
[this.effectivePlacement]: true,
|
245
|
+
})}
|
246
|
+
id="tooltip"
|
247
|
+
data-test="tooltip"
|
248
|
+
data-open-delay="300"
|
249
|
+
data-close-delay="200"
|
250
|
+
${ref(this.#tooltipElementRef)}
|
251
|
+
>
|
252
|
+
<div
|
253
|
+
class=${classMap({
|
254
|
+
arrow: true,
|
255
|
+
[this.effectivePlacement]: true,
|
256
|
+
})}
|
257
|
+
data-test="arrow"
|
258
|
+
${ref(this.#arrowElementRef)}
|
259
|
+
>
|
260
|
+
${choose(this.effectivePlacement, [
|
261
|
+
['top', () => icons.topArrow],
|
262
|
+
['right', () => icons.rightArrow],
|
263
|
+
['bottom', () => icons.bottomArrow],
|
264
|
+
['left', () => icons.leftArrow],
|
265
|
+
])}
|
266
|
+
</div>
|
267
|
+
|
268
|
+
<div
|
269
|
+
class=${classMap({
|
270
|
+
content: true,
|
271
|
+
})}
|
272
|
+
>
|
273
|
+
<slot class="default-slot" name="private">
|
274
|
+
<!--
|
275
|
+
@type {TooltipContainer}
|
276
|
+
-->
|
277
|
+
</slot>
|
278
|
+
</div>
|
279
|
+
</div>
|
280
|
+
</div>
|
281
|
+
`;
|
282
|
+
}
|
283
|
+
#arrowElementRef;
|
284
|
+
#cleanUpFloatingUi;
|
285
|
+
#closeTimeoutId;
|
286
|
+
#description;
|
287
|
+
#isDisabled;
|
288
|
+
#isOpen;
|
289
|
+
#isScreenreaderHidden;
|
290
|
+
#label;
|
291
|
+
#offset;
|
292
|
+
#openTimeoutId;
|
293
|
+
#shortcut;
|
294
|
+
#targetSlotElementRef;
|
295
|
+
#tooltipElementRef;
|
296
|
+
#cancelClose() {
|
297
|
+
clearTimeout(this.#closeTimeoutId);
|
298
|
+
}
|
299
|
+
#hide() {
|
300
|
+
this.#tooltipElementRef.value?.hidePopover();
|
301
|
+
this.#cleanUpFloatingUi?.();
|
302
|
+
}
|
303
|
+
#onComponentMouseOut(event) {
|
304
|
+
// The timeout gives consumers a chance to cancel the event to prevent Tooltip
|
305
|
+
// from closing.
|
306
|
+
setTimeout(() => {
|
307
|
+
if (!event.defaultPrevented) {
|
308
|
+
this.#scheduleClose();
|
309
|
+
clearTimeout(this.#openTimeoutId);
|
310
|
+
}
|
311
|
+
});
|
312
|
+
}
|
313
|
+
#onComponentMouseOver(event) {
|
314
|
+
// The timeout gives consumers a chance to cancel the event to prevent Tooltip
|
315
|
+
// from opening.
|
316
|
+
setTimeout(() => {
|
317
|
+
if (!event.defaultPrevented) {
|
318
|
+
this.#cancelClose();
|
319
|
+
// The open and close delays are stored in data attributes so tests can
|
320
|
+
// configure them. Tests configure them, rather than using fake timers,
|
321
|
+
// because they need real timers so they can await Floating UI's setup.
|
322
|
+
//
|
323
|
+
// Conditionals based on `window.navigator.webdriver` in here and in
|
324
|
+
// `#scheduleClose()` would be a lot nicer. But one of that condition's
|
325
|
+
// branches would never get hit in tests. So we'd fail to meet our coverage
|
326
|
+
// thresholds.
|
327
|
+
this.#openTimeoutId = setTimeout(() => {
|
328
|
+
this.open = true;
|
329
|
+
}, Number(this.#tooltipElementRef.value?.dataset.openDelay));
|
330
|
+
}
|
331
|
+
});
|
332
|
+
}
|
333
|
+
#onTargetSlotChange() {
|
334
|
+
const container = this.querySelector('glide-core-private-tooltip-container');
|
335
|
+
const target = this.#targetSlotElementRef.value?.assignedElements().at(0);
|
336
|
+
if (container && target && !this.disabled && !this.screenreaderHidden) {
|
337
|
+
target.setAttribute('aria-describedby', container.id);
|
338
|
+
}
|
339
|
+
}
|
340
|
+
#onTargetSlotFocusIn() {
|
341
|
+
this.open = true;
|
342
|
+
}
|
343
|
+
#onTargetSlotFocusOut() {
|
344
|
+
this.open = false;
|
345
|
+
}
|
346
|
+
#onTargetSlotKeyDown(event) {
|
347
|
+
if (event.key === 'Escape') {
|
348
|
+
// Prevent Safari from leaving full screen.
|
349
|
+
event.preventDefault();
|
350
|
+
this.open = false;
|
351
|
+
}
|
352
|
+
}
|
353
|
+
#scheduleClose() {
|
354
|
+
this.#closeTimeoutId = setTimeout(() => {
|
355
|
+
this.open = false;
|
356
|
+
}, Number(this.#tooltipElementRef.value?.dataset.closeDelay));
|
357
|
+
}
|
358
|
+
#show() {
|
359
|
+
if (!this.disabled) {
|
360
|
+
this.#cleanUpFloatingUi?.();
|
361
|
+
if (this.#targetSlotElementRef.value && this.#tooltipElementRef.value) {
|
362
|
+
this.#cleanUpFloatingUi = autoUpdate(this.#targetSlotElementRef.value, this.#tooltipElementRef.value, () => {
|
363
|
+
(async () => {
|
364
|
+
if (this.#targetSlotElementRef.value &&
|
365
|
+
this.#tooltipElementRef.value &&
|
366
|
+
this.#arrowElementRef.value) {
|
367
|
+
const { x, y, placement, middlewareData } = await computePosition(this.#targetSlotElementRef.value, this.#tooltipElementRef.value, {
|
368
|
+
placement: this.placement,
|
369
|
+
middleware: [
|
370
|
+
offset(this.offset),
|
371
|
+
flip({
|
372
|
+
fallbackStrategy: 'initialPlacement',
|
373
|
+
}),
|
374
|
+
shift({
|
375
|
+
// So the tooltip can overlap its target in cases where it would otherwise
|
376
|
+
// overflow the viewport.
|
377
|
+
//
|
378
|
+
// Give a form control a super long label. Now reduce the size of your viewport.
|
379
|
+
// The tooltip should flip to the left instead of overflowing on the right.
|
380
|
+
//
|
381
|
+
// https://github.com/floating-ui/floating-ui/blob/933cacc6672e2ccd9409cf0e9f64acd7ebf450c4/website/pages/docs/shift.mdx#crossaxiskey
|
382
|
+
crossAxis: true,
|
383
|
+
limiter: limitShift({
|
384
|
+
// Shifting is limited so the arrow is never near the tooltip's rounded
|
385
|
+
// corners, which would leave a gap between the arrow and the part of
|
386
|
+
// the corner that's missing due to rounding. `20` is just a round number.
|
387
|
+
// `15` isn't enough.
|
388
|
+
offset: 20,
|
389
|
+
}),
|
390
|
+
}),
|
391
|
+
arrow({ element: this.#arrowElementRef.value }),
|
392
|
+
],
|
393
|
+
});
|
394
|
+
Object.assign(this.#tooltipElementRef.value.style, {
|
395
|
+
left: `${x}px`,
|
396
|
+
top: `${y}px`,
|
397
|
+
});
|
398
|
+
Object.assign(this.#arrowElementRef.value.style, {
|
399
|
+
left: middlewareData.arrow?.x
|
400
|
+
? `${middlewareData.arrow.x}px`
|
401
|
+
: null,
|
402
|
+
top: middlewareData.arrow?.y
|
403
|
+
? `${middlewareData.arrow.y}px`
|
404
|
+
: null,
|
405
|
+
});
|
406
|
+
this.effectivePlacement = placement;
|
407
|
+
this.#tooltipElementRef.value.showPopover();
|
408
|
+
const container = this.querySelector('glide-core-private-tooltip-container');
|
409
|
+
const isSupportedPlacement = placement === 'bottom' ||
|
410
|
+
placement === 'left' ||
|
411
|
+
placement === 'right' ||
|
412
|
+
placement === 'top';
|
413
|
+
if (container && isSupportedPlacement) {
|
414
|
+
container.placement = placement;
|
415
|
+
}
|
416
|
+
}
|
417
|
+
})();
|
418
|
+
});
|
419
|
+
}
|
420
|
+
}
|
421
|
+
}
|
422
|
+
};
|
423
|
+
__decorate([
|
424
|
+
property({ reflect: true }),
|
425
|
+
required
|
426
|
+
], Tooltip.prototype, "label", null);
|
427
|
+
__decorate([
|
428
|
+
property({ reflect: true })
|
429
|
+
], Tooltip.prototype, "description", null);
|
430
|
+
__decorate([
|
431
|
+
property({ reflect: true, type: Boolean })
|
432
|
+
], Tooltip.prototype, "disabled", null);
|
433
|
+
__decorate([
|
434
|
+
property({ reflect: true, type: Number })
|
435
|
+
], Tooltip.prototype, "offset", null);
|
436
|
+
__decorate([
|
437
|
+
property({ reflect: true, type: Boolean })
|
438
|
+
], Tooltip.prototype, "open", null);
|
439
|
+
__decorate([
|
440
|
+
property({ reflect: true })
|
441
|
+
], Tooltip.prototype, "placement", void 0);
|
442
|
+
__decorate([
|
443
|
+
property({ attribute: 'screenreader-hidden', reflect: true, type: Boolean })
|
444
|
+
], Tooltip.prototype, "screenreaderHidden", null);
|
445
|
+
__decorate([
|
446
|
+
property({ reflect: true, type: Array })
|
447
|
+
], Tooltip.prototype, "shortcut", null);
|
448
|
+
__decorate([
|
449
|
+
property({ reflect: true })
|
450
|
+
], Tooltip.prototype, "version", void 0);
|
451
|
+
__decorate([
|
452
|
+
state()
|
453
|
+
], Tooltip.prototype, "effectivePlacement", void 0);
|
454
|
+
Tooltip = __decorate([
|
455
|
+
customElement('glide-core-tooltip'),
|
456
|
+
final
|
457
|
+
], Tooltip);
|
458
|
+
export default Tooltip;
|
459
|
+
const icons = {
|
460
|
+
topArrow: html `<svg aria-hidden="true" viewBox="0 0 10 6" fill="none">
|
461
|
+
<path
|
462
|
+
d="M4.23178 5.07814C4.63157 5.55789 5.36843 5.55789 5.76822 5.07813L10 -7.9486e-08L-2.62268e-07 3.57628e-07L4.23178 5.07814Z"
|
463
|
+
fill="currentColor"
|
464
|
+
/>
|
465
|
+
</svg>`,
|
466
|
+
rightArrow: html `<svg aria-hidden="true" viewBox="0 0 6 10" fill="none">
|
467
|
+
<path
|
468
|
+
d="M0.921865 4.23178C0.442111 4.63157 0.442112 5.36843 0.921866 5.76822L6 10L6 -2.62268e-07L0.921865 4.23178Z"
|
469
|
+
fill="currentColor"
|
470
|
+
/>
|
471
|
+
</svg>`,
|
472
|
+
bottomArrow: html `<svg aria-hidden="true" viewBox="0 0 10 6" fill="none">
|
473
|
+
<path
|
474
|
+
d="M4.23178 0.921865C4.63157 0.442111 5.36843 0.442112 5.76822 0.921866L10 6L-2.62268e-07 6L4.23178 0.921865Z"
|
475
|
+
fill="currentColor"
|
476
|
+
/>
|
477
|
+
</svg>`,
|
478
|
+
leftArrow: html `<svg aria-hidden="true" viewBox="0 0 6 10" fill="none">
|
479
|
+
<path
|
480
|
+
d="M5.07814 4.23178C5.55789 4.63157 5.55789 5.36843 5.07813 5.76822L-4.37114e-07 10L0 -2.62268e-07L5.07814 4.23178Z"
|
481
|
+
fill="currentColor"
|
482
|
+
/>
|
483
|
+
</svg>`,
|
484
|
+
};
|