@crowdstrike/glide-core 0.29.1 → 0.30.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.
Files changed (124) hide show
  1. package/dist/accordion.js +240 -1
  2. package/dist/accordion.styles.js +13 -7
  3. package/dist/button-group.button.js +143 -1
  4. package/dist/button-group.button.styles.js +43 -15
  5. package/dist/button-group.js +249 -1
  6. package/dist/button-group.styles.js +10 -5
  7. package/dist/button.js +206 -1
  8. package/dist/button.styles.js +12 -7
  9. package/dist/checkbox-group.js +479 -14
  10. package/dist/checkbox-group.styles.js +5 -2
  11. package/dist/checkbox.js +519 -32
  12. package/dist/checkbox.styles.js +10 -5
  13. package/dist/drawer.js +168 -1
  14. package/dist/drawer.styles.js +5 -2
  15. package/dist/dropdown.js +2423 -123
  16. package/dist/dropdown.option.js +536 -1
  17. package/dist/dropdown.option.styles.js +5 -2
  18. package/dist/dropdown.styles.js +14 -7
  19. package/dist/form-controls-layout.js +102 -1
  20. package/dist/form-controls-layout.styles.js +5 -2
  21. package/dist/icon-button.js +139 -1
  22. package/dist/icon-button.styles.js +19 -7
  23. package/dist/icons/checked.js +28 -1
  24. package/dist/icons/chevron.js +21 -1
  25. package/dist/icons/magnifying-glass.js +23 -1
  26. package/dist/icons/pencil.js +21 -1
  27. package/dist/icons/severity-critical.js +20 -1
  28. package/dist/icons/severity-informational.js +20 -1
  29. package/dist/icons/severity-medium.js +20 -1
  30. package/dist/icons/x.js +21 -1
  31. package/dist/inline-alert.js +118 -1
  32. package/dist/inline-alert.styles.js +5 -2
  33. package/dist/input.d.ts +8 -2
  34. package/dist/input.js +505 -41
  35. package/dist/input.styles.js +25 -4
  36. package/dist/label.js +303 -1
  37. package/dist/label.styles.js +11 -5
  38. package/dist/library/assert-slot.js +136 -1
  39. package/dist/library/expect-unhandled-rejection.js +14 -1
  40. package/dist/library/expect-window-error.js +26 -1
  41. package/dist/library/final.js +18 -1
  42. package/dist/library/form-control.js +1 -1
  43. package/dist/library/localize.js +10 -1
  44. package/dist/library/mouse.js +35 -1
  45. package/dist/library/on-resize.js +24 -1
  46. package/dist/library/required.js +35 -1
  47. package/dist/library/shadow-root-mode.js +4 -1
  48. package/dist/library/unique-id.js +3 -1
  49. package/dist/link.js +92 -1
  50. package/dist/link.styles.js +10 -5
  51. package/dist/menu.d.ts +3 -2
  52. package/dist/menu.js +1259 -1
  53. package/dist/menu.styles.js +34 -17
  54. package/dist/modal.d.ts +4 -0
  55. package/dist/modal.icon-button.js +60 -1
  56. package/dist/modal.icon-button.styles.js +5 -2
  57. package/dist/modal.js +473 -1
  58. package/dist/modal.styles.js +71 -22
  59. package/dist/option.d.ts +74 -0
  60. package/dist/option.js +498 -0
  61. package/dist/option.styles.js +140 -0
  62. package/dist/{menu.options.d.ts → options.d.ts} +5 -6
  63. package/dist/options.js +130 -0
  64. package/dist/options.styles.js +21 -0
  65. package/dist/popover.js +620 -1
  66. package/dist/popover.styles.js +11 -5
  67. package/dist/radio-group.js +624 -17
  68. package/dist/radio-group.radio.js +211 -1
  69. package/dist/radio-group.radio.styles.js +9 -4
  70. package/dist/radio-group.styles.js +5 -2
  71. package/dist/slider.js +1040 -61
  72. package/dist/slider.styles.js +9 -4
  73. package/dist/spinner.js +60 -1
  74. package/dist/spinner.styles.js +5 -2
  75. package/dist/split-button.js +116 -1
  76. package/dist/split-button.primary-button.js +100 -1
  77. package/dist/split-button.primary-button.styles.js +13 -6
  78. package/dist/split-button.primary-link.js +102 -1
  79. package/dist/split-button.secondary-button.d.ts +2 -3
  80. package/dist/split-button.secondary-button.js +121 -1
  81. package/dist/split-button.secondary-button.styles.js +12 -7
  82. package/dist/split-button.styles.js +9 -4
  83. package/dist/styles/focus-outline.js +9 -3
  84. package/dist/styles/fonts.css +6 -1
  85. package/dist/styles/opacity-and-scale-animation.js +6 -3
  86. package/dist/styles/skeleton.js +6 -3
  87. package/dist/styles/variables.css +410 -1
  88. package/dist/styles/visually-hidden.js +6 -3
  89. package/dist/tab.group.js +386 -1
  90. package/dist/tab.group.styles.js +5 -2
  91. package/dist/tab.js +133 -1
  92. package/dist/tab.panel.js +93 -1
  93. package/dist/tab.panel.styles.js +11 -5
  94. package/dist/tab.styles.js +9 -4
  95. package/dist/tag.js +207 -1
  96. package/dist/tag.styles.js +10 -5
  97. package/dist/textarea.js +353 -19
  98. package/dist/textarea.styles.js +23 -4
  99. package/dist/toast.js +130 -1
  100. package/dist/toast.toasts.js +248 -25
  101. package/dist/toast.toasts.styles.js +9 -4
  102. package/dist/toggle.js +178 -1
  103. package/dist/toggle.styles.js +25 -5
  104. package/dist/tooltip.container.d.ts +2 -0
  105. package/dist/tooltip.container.js +130 -1
  106. package/dist/tooltip.container.styles.js +18 -4
  107. package/dist/tooltip.d.ts +6 -0
  108. package/dist/tooltip.js +484 -1
  109. package/dist/tooltip.styles.js +21 -5
  110. package/dist/translations/en.js +36 -1
  111. package/dist/translations/fr.js +37 -1
  112. package/dist/translations/ja.js +37 -1
  113. package/package.json +8 -12
  114. package/dist/menu.button.d.ts +0 -42
  115. package/dist/menu.button.js +0 -1
  116. package/dist/menu.button.styles.js +0 -32
  117. package/dist/menu.link.d.ts +0 -44
  118. package/dist/menu.link.js +0 -1
  119. package/dist/menu.link.styles.js +0 -35
  120. package/dist/menu.options.js +0 -1
  121. package/dist/menu.options.styles.d.ts +0 -2
  122. package/dist/menu.options.styles.js +0 -20
  123. /package/dist/{menu.button.styles.d.ts → option.styles.d.ts} +0 -0
  124. /package/dist/{menu.link.styles.d.ts → options.styles.d.ts} +0 -0
package/dist/tooltip.js CHANGED
@@ -1 +1,484 @@
1
- var __decorate=this&&this.__decorate||function(e,t,o,i){var r,s=arguments.length,l=s<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,o):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(e,t,o,i);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(l=(s<3?r(l):s>3?r(t,o,l):r(t,o))||l);return s>3&&l&&Object.defineProperty(t,o,l),l};import{html,LitElement}from"lit";import{arrow,autoUpdate,computePosition,flip,limitShift,offset,shift}from"@floating-ui/dom";import{choose}from"lit/directives/choose.js";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,state}from"lit/decorators.js";import packageJson from"../package.json"with{type:"json"};import styles from"./tooltip.styles.js";import"./tooltip.container.js";import assertSlot from"./library/assert-slot.js";import shadowRootMode from"./library/shadow-root-mode.js";import final from"./library/final.js";import required from"./library/required.js";let Tooltip=class Tooltip extends LitElement{constructor(){super(...arguments),this.version=packageJson.version,this.effectivePlacement=this.placement??"bottom",this.#e=createRef(),this.#t=!1,this.#o=!1,this.#i=!1,this.#r=[],this.#s=createRef(),this.#l=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:shadowRootMode}}static{this.styles=styles}get label(){return this.#a}set label(e){this.#a=e;const t=this.querySelector("glide-core-private-tooltip-container");t&&(t.label=e)}get disabled(){return this.#t}set disabled(e){this.#t=e,this.open&&!e?this.#n():this.#c();const t=this.querySelector("glide-core-private-tooltip-container");t&&(t.disabled=e);const o=this.#s.value?.assignedElements().at(0);t&&o&&!this.disabled&&!this.screenreaderHidden?o.setAttribute("aria-describedby",t.id):t&&o&&o.removeAttribute("aria-describedby")}get offset(){return this.#d??Number.parseFloat(window.getComputedStyle(document.body).getPropertyValue("--glide-core-spacing-base-xxs"))*Number.parseFloat(window.getComputedStyle(document.documentElement).fontSize)}set offset(e){this.#d=e}get open(){return this.#o}set open(e){const t=e!==this.#o;this.#o=e,e&&t&&!this.disabled?(this.#n(),this.dispatchEvent(new Event("toggle",{bubbles:!0,composed:!0}))):t&&!this.disabled&&(this.#c(),this.dispatchEvent(new Event("toggle",{bubbles:!0,composed:!0})))}get screenreaderHidden(){return this.#i}set screenreaderHidden(e){this.#i=e;const t=this.querySelector("glide-core-private-tooltip-container");t&&(t.screenreaderHidden=e);const o=this.#s.value?.assignedElements().at(0);t&&o&&!this.disabled&&!this.screenreaderHidden?o.setAttribute("aria-describedby",t.id):t&&o&&o.removeAttribute("aria-describedby")}get shortcut(){return this.#r}set shortcut(e){this.#r=e;const t=this.querySelector("glide-core-private-tooltip-container");t&&(t.shortcut=e)}disconnectedCallback(){super.disconnectedCallback(),clearTimeout(this.#p),clearTimeout(this.#h)}firstUpdated(){this.#l.value&&(this.#l.value.popover="manual"),this.open&&!this.disabled&&this.#n();const e=document.createElement("glide-core-private-tooltip-container");e.label=this.label,e.screenreaderHidden=this.screenreaderHidden,e.shortcut=this.shortcut,this.append(e)}render(){return html`<div class="component" data-test="component" @mouseover="${this.#m}" @mouseout="${this.#u}"><div class="target-slot-container"><slot class="target-slot" data-test="target-slot" name="target" @focusin="${this.#f}" @focusout="${this.#v}" @keydown="${this.#g}" @slotchange="${this.#b}" ${assertSlot()} ${ref(this.#s)}></slot></div><div class="${classMap({tooltip:!0,[this.effectivePlacement]:!0})}" id="tooltip" data-test="tooltip" data-open-delay="300" data-close-delay="200" ${ref(this.#l)}><div class="${classMap({arrow:!0,[this.effectivePlacement]:!0})}" data-test="arrow" ${ref(this.#e)}>${choose(this.effectivePlacement,[["top",()=>icons.topArrow],["right",()=>icons.rightArrow],["bottom",()=>icons.bottomArrow],["left",()=>icons.leftArrow]])}</div><div class="${classMap({content:!0})}"><slot class="default-slot" name="private"></slot></div></div></div>`}#e;#y;#p;#t;#o;#i;#a;#d;#h;#r;#s;#l;#w(){clearTimeout(this.#p)}#c(){this.#l.value?.hidePopover(),this.#y?.()}#u(){this.#E(),clearTimeout(this.#h)}#m(){this.#w(),this.#h=setTimeout((()=>{this.open=!0}),Number(this.#l.value?.dataset.openDelay))}#b(){const e=this.querySelector("glide-core-private-tooltip-container"),t=this.#s.value?.assignedElements().at(0);e&&t&&!this.disabled&&!this.screenreaderHidden&&t.setAttribute("aria-describedby",e.id)}#f(){this.open=!0}#v(){this.open=!1}#g(e){"Escape"===e.key&&(e.preventDefault(),this.open=!1)}#E(){this.#p=setTimeout((()=>{this.open=!1}),Number(this.#l.value?.dataset.closeDelay))}#n(){this.disabled||(this.#y?.(),this.#s.value&&this.#l.value&&(this.#y=autoUpdate(this.#s.value,this.#l.value,(()=>{(async()=>{if(this.#s.value&&this.#l.value&&this.#e.value){const{x:e,y:t,placement:o,middlewareData:i}=await computePosition(this.#s.value,this.#l.value,{placement:this.placement,middleware:[offset(this.offset),flip({fallbackStrategy:"initialPlacement"}),shift({crossAxis:!0,limiter:limitShift({offset:20})}),arrow({element:this.#e.value})]});Object.assign(this.#l.value.style,{left:`${e}px`,top:`${t}px`}),Object.assign(this.#e.value.style,{left:i.arrow?.x?`${i.arrow.x}px`:null,top:i.arrow?.y?`${i.arrow.y}px`:null}),this.effectivePlacement=o,this.#l.value.showPopover();const r=this.querySelector("glide-core-private-tooltip-container");r&&("bottom"===o||"left"===o||"right"===o||"top"===o)&&(r.placement=o)}})()}))))}};__decorate([property({reflect:!0}),required],Tooltip.prototype,"label",null),__decorate([property({reflect:!0,type:Boolean})],Tooltip.prototype,"disabled",null),__decorate([property({reflect:!0,type:Number})],Tooltip.prototype,"offset",null),__decorate([property({reflect:!0,type:Boolean})],Tooltip.prototype,"open",null),__decorate([property({reflect:!0})],Tooltip.prototype,"placement",void 0),__decorate([property({attribute:"screenreader-hidden",reflect:!0,type:Boolean})],Tooltip.prototype,"screenreaderHidden",null),__decorate([property({reflect:!0,type:Array})],Tooltip.prototype,"shortcut",null),__decorate([property({reflect:!0})],Tooltip.prototype,"version",void 0),__decorate([state()],Tooltip.prototype,"effectivePlacement",void 0),Tooltip=__decorate([customElement("glide-core-tooltip"),final],Tooltip);export default Tooltip;const icons={topArrow:html`<svg aria-hidden="true" viewBox="0 0 10 6" fill="none"><path 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" fill="currentColor"/></svg>`,rightArrow:html`<svg aria-hidden="true" viewBox="0 0 6 10" fill="none"><path d="M0.921865 4.23178C0.442111 4.63157 0.442112 5.36843 0.921866 5.76822L6 10L6 -2.62268e-07L0.921865 4.23178Z" fill="currentColor"/></svg>`,bottomArrow:html`<svg aria-hidden="true" viewBox="0 0 10 6" fill="none"><path d="M4.23178 0.921865C4.63157 0.442111 5.36843 0.442112 5.76822 0.921866L10 6L-2.62268e-07 6L4.23178 0.921865Z" fill="currentColor"/></svg>`,leftArrow:html`<svg aria-hidden="true" viewBox="0 0 6 10" fill="none"><path 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" fill="currentColor"/></svg>`};
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
+ };
@@ -1,10 +1,25 @@
1
- import{css}from"lit";import focusOutline from"./styles/focus-outline.js";import opacityAndScaleAnimation from"./styles/opacity-and-scale-animation.js";export default[css`
2
- ${opacityAndScaleAnimation(".tooltip:popover-open")}
3
- ${focusOutline(".target-slot:focus-visible")}
4
- `,css`
1
+ import { css } from 'lit';
2
+ import focusOutline from './styles/focus-outline.js';
3
+ import opacityAndScaleAnimation from './styles/opacity-and-scale-animation.js';
4
+ export default [
5
+ css `
6
+ ${opacityAndScaleAnimation('.tooltip:popover-open')}
7
+ ${focusOutline('.target-slot:focus-visible')}
8
+ `,
9
+ css `
5
10
  :host {
6
11
  /* https://github.com/CrowdStrike/glide-core/pull/307/files#r1718545771 */
7
12
  display: inline-block;
13
+
14
+ /*
15
+ We've found that many consumers put Tooltip in a container that has
16
+ "white-space: nowrap", preventing Tooltip's "label" and "description"
17
+ from wrapping.
18
+
19
+ It's easy enough for them to add "white-space: normal" to Tooltip's
20
+ host. But it reduces our support load to add it for them.
21
+ */
22
+ white-space: normal;
8
23
  }
9
24
 
10
25
  .component {
@@ -94,4 +109,5 @@ import{css}from"lit";import focusOutline from"./styles/focus-outline.js";import
94
109
  order: 2;
95
110
  }
96
111
  }
97
- `];
112
+ `,
113
+ ];
@@ -1 +1,36 @@
1
- const translation={$code:"en",$name:"English",$dir:"ltr",close:"Close",dismiss:"Dismiss",selectAll:"Select all",notifications:"Notifications",nextTab:"Next tab",previousTab:"Previous tab",noAvailableOptions:"No options available",noMatchingOptions:"No matching options",tooltip:"Tooltip:",severityInformational:"Severity: Informational",severityCritical:"Severity: Critical",severityMedium:"Severity: Medium",success:"Success:",error:"Error:",informational:"Informational:",loading:"Loading",add:"Add",announcedCharacterCount:(i,t)=>`Character count ${i} of ${t}`,displayedCharacterCount:(i,t)=>`${i}/${t}`,clearEntry:i=>`Clear ${i} entry`,editOption:i=>`Edit option: ${i}`,editTag:i=>`Edit tag: ${i}`,removeTag:i=>`Remove tag: ${i}`,itemCount:i=>`${i} items`,maximum:i=>`Maximum ${i}`,setMaximum:i=>`Set maximum ${i}`,minimum:i=>`Minimum ${i}`,setMinimum:i=>`Set minimum ${i}`};export default translation;
1
+ const translation = {
2
+ $code: 'en',
3
+ $name: 'English',
4
+ $dir: 'ltr',
5
+ // All of these should have corresponding entries in ./en.json,
6
+ // using ICU message syntax in place of any of dynamic functions
7
+ close: 'Close',
8
+ dismiss: 'Dismiss',
9
+ selectAll: 'Select all',
10
+ notifications: 'Notifications',
11
+ nextTab: 'Next tab',
12
+ previousTab: 'Previous tab',
13
+ noAvailableOptions: 'No options available',
14
+ noMatchingOptions: 'No matching options',
15
+ tooltip: 'Tooltip:',
16
+ severityInformational: 'Severity: Informational',
17
+ severityCritical: 'Severity: Critical',
18
+ severityMedium: 'Severity: Medium',
19
+ success: 'Success:',
20
+ error: 'Error:',
21
+ informational: 'Informational:',
22
+ loading: 'Loading',
23
+ add: 'Add',
24
+ announcedCharacterCount: (current, maximum) => `Character count ${current} of ${maximum}`,
25
+ displayedCharacterCount: (current, maximum) => `${current}/${maximum}`,
26
+ clearEntry: (label) => `Clear ${label} entry`,
27
+ editOption: (label) => `Edit option: ${label}`,
28
+ editTag: (label) => `Edit tag: ${label}`,
29
+ removeTag: (label) => `Remove tag: ${label}`,
30
+ itemCount: (count) => `${count} items`,
31
+ maximum: (label) => `Maximum ${label}`,
32
+ setMaximum: (label) => `Set maximum ${label}`,
33
+ minimum: (label) => `Minimum ${label}`,
34
+ setMinimum: (label) => `Set minimum ${label}`,
35
+ };
36
+ export default translation;
@@ -1 +1,37 @@
1
- export const PENDING_STRINGS=["severityInformational","severityCritical","severityMedium","success","error","informational","loading","noAvailableOptions","noMatchingOptions","maximum","setMaximum","minimum","setMinimum","add"];const translation={$code:"fr",$name:"French",$dir:"ltr",close:"FERMER",dismiss:"Ignorer",selectAll:"Tout sélectionner",notifications:"Notifications",nextTab:"Onglet suivant",previousTab:"Onglet précédent",tooltip:"Info-bulle :",announcedCharacterCount:(e,t)=>`Nombre de caractères ${e} sur ${t}`,displayedCharacterCount:(e,t)=>`${e}/${t}`,clearEntry:e=>`Effacer l'entrée ${e}`,editOption:e=>`Modifier l'option : ${e}`,editTag:e=>`Modifier la balise : ${e}`,removeTag:e=>`Enlever la balise : ${e}`,itemCount:e=>`${e} éléments`};export default translation;
1
+ export const PENDING_STRINGS = [
2
+ 'severityInformational',
3
+ 'severityCritical',
4
+ 'severityMedium',
5
+ 'success',
6
+ 'error',
7
+ 'informational',
8
+ 'loading',
9
+ 'noAvailableOptions',
10
+ 'noMatchingOptions',
11
+ 'maximum',
12
+ 'setMaximum',
13
+ 'minimum',
14
+ 'setMinimum',
15
+ 'add',
16
+ ];
17
+ const translation = {
18
+ $code: 'fr',
19
+ $name: 'French',
20
+ $dir: 'ltr',
21
+ // These come from ./fr.json
22
+ close: 'FERMER',
23
+ dismiss: 'Ignorer',
24
+ selectAll: 'Tout sélectionner',
25
+ notifications: 'Notifications',
26
+ nextTab: 'Onglet suivant',
27
+ previousTab: 'Onglet précédent',
28
+ tooltip: 'Info-bulle :',
29
+ announcedCharacterCount: (current, maximum) => `Nombre de caractères ${current} sur ${maximum}`,
30
+ displayedCharacterCount: (current, maximum) => `${current}/${maximum}`,
31
+ clearEntry: (label) => `Effacer l'entrée ${label}`,
32
+ editOption: (label) => `Modifier l'option : ${label}`,
33
+ editTag: (label) => `Modifier la balise : ${label}`,
34
+ removeTag: (label) => `Enlever la balise : ${label}`,
35
+ itemCount: (count) => `${count} éléments`,
36
+ };
37
+ export default translation;
@@ -1 +1,37 @@
1
- export const PENDING_STRINGS=["severityInformational","severityCritical","severityMedium","success","error","informational","loading","noAvailableOptions","noMatchingOptions","maximum","setMaximum","minimum","setMinimum","add"];const translation={$code:"ja",$name:"Japanese",$dir:"ltr",close:"閉じる",dismiss:"閉じる",selectAll:"すべて選択",notifications:"通知",nextTab:"Onglet suivant",previousTab:"Onglet précédent",tooltip:"ツールチップ:",announcedCharacterCount:(t,e)=>`文字数 ${t}/${e}`,displayedCharacterCount:(t,e)=>`${t}/${e}`,clearEntry:t=>`${t}入力をクリア`,editOption:t=>`編集オプション:${t}`,editTag:t=>`タグの編集:${t}`,removeTag:t=>`タグの削除:${t}`,itemCount:t=>`${t}件`};export default translation;
1
+ export const PENDING_STRINGS = [
2
+ 'severityInformational',
3
+ 'severityCritical',
4
+ 'severityMedium',
5
+ 'success',
6
+ 'error',
7
+ 'informational',
8
+ 'loading',
9
+ 'noAvailableOptions',
10
+ 'noMatchingOptions',
11
+ 'maximum',
12
+ 'setMaximum',
13
+ 'minimum',
14
+ 'setMinimum',
15
+ 'add',
16
+ ];
17
+ const translation = {
18
+ $code: 'ja',
19
+ $name: 'Japanese',
20
+ $dir: 'ltr',
21
+ // These come from ./ja.json
22
+ close: '閉じる',
23
+ dismiss: '閉じる',
24
+ selectAll: 'すべて選択',
25
+ notifications: '通知',
26
+ nextTab: 'Onglet suivant',
27
+ previousTab: 'Onglet précédent',
28
+ tooltip: 'ツールチップ:',
29
+ announcedCharacterCount: (current, maximum) => `文字数 ${current}/${maximum}`,
30
+ displayedCharacterCount: (current, maximum) => `${current}/${maximum}`,
31
+ clearEntry: (label) => `${label}入力をクリア`,
32
+ editOption: (label) => `編集オプション:${label}`,
33
+ editTag: (label) => `タグの編集:${label}`,
34
+ removeTag: (label) => `タグの削除:${label}`,
35
+ itemCount: (count) => `${count}件`,
36
+ };
37
+ export default translation;