@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/option.js ADDED
@@ -0,0 +1,498 @@
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 { LitElement } from 'lit';
8
+ import { classMap } from 'lit/directives/class-map.js';
9
+ import { customElement, property, state } from 'lit/decorators.js';
10
+ import { createRef, ref } from 'lit/directives/ref.js';
11
+ import { when } from 'lit/directives/when.js';
12
+ import { html, unsafeStatic } from 'lit/static-html.js';
13
+ import { ifDefined } from 'lit/directives/if-defined.js';
14
+ import packageJson from '../package.json' with { type: 'json' };
15
+ import styles from './option.styles.js';
16
+ import assertSlot from './library/assert-slot.js';
17
+ import checkedIcon from './icons/checked.js';
18
+ import shadowRootMode from './library/shadow-root-mode.js';
19
+ import final from './library/final.js';
20
+ import uniqueId from './library/unique-id.js';
21
+ import Menu from './menu.js';
22
+ import './options.js';
23
+ import Tooltip from './tooltip.js';
24
+ import required from './library/required.js';
25
+ /**
26
+ * @attr {string} label
27
+ * @attr {string} [description]
28
+ * @attr {boolean} [disabled=false]
29
+ * @attr {string} [href]
30
+ *
31
+ * @readonly
32
+ * @attr {string} [id]
33
+ *
34
+ * @attr {'menuitem'|'option'} [role='menuitem']
35
+ * @attr {boolean} [selected=false]
36
+ *
37
+ * @readonly
38
+ * @attr {number} [tabindex=-1]
39
+ *
40
+ * @attr {string} [value='']
41
+ *
42
+ * @readonly
43
+ * @attr {string} [version]
44
+ *
45
+ * @slot {Element | Text} [content] - This is the unhappy path. It's the escape hatch where you can render arbitrary content and lay it out however you need to. If you go this route, `slot="icon"` and `slot="submenu"` will become unavailable. And the `label` and `description` attributes won't be rendered. The `label` attribute is still required. We'll show it in a tooltip when your content overflows. If you need a second line of text in the tooltip, provide you can provide it via the `description` attribute.
46
+ * @slot {Element} [icon]
47
+ * @slot {Menu} [submenu]
48
+ */
49
+ let Option = class Option extends LitElement {
50
+ constructor() {
51
+ super(...arguments);
52
+ // On the host so screenreaders can find it when Options refers to it via
53
+ // `aria-activedescendant`.
54
+ this.id = uniqueId();
55
+ this.privateTooltipOpen = false;
56
+ this.role = 'menuitem';
57
+ this.tabIndex = -1;
58
+ this.value = '';
59
+ this.version = packageJson.version;
60
+ this.hasContentSlot = false;
61
+ this.hasIconSlot = false;
62
+ this.hasSubMenuSlot = false;
63
+ this.isContentSlotOverflow = false;
64
+ // Set in `#onSubmenuToggle()`. Used to toggle the sub-Menu's target as open
65
+ // or closed visually.
66
+ this.isSubmenuOpen = false;
67
+ this.#containerElementRef = createRef();
68
+ this.#contentSlotElementRef = createRef();
69
+ this.#descriptionElementRef = createRef();
70
+ this.#isActive = false;
71
+ this.#isDisabled = false;
72
+ this.#isSelected = false;
73
+ this.#labelElementRef = createRef();
74
+ this.#tooltipElementRef = createRef();
75
+ }
76
+ static { this.shadowRootOptions = {
77
+ ...LitElement.shadowRootOptions,
78
+ mode: shadowRootMode,
79
+ }; }
80
+ static { this.styles = styles; }
81
+ // Consumers may chose not to take the happy path and instead use the "content"
82
+ // slot. In that case, we don't render `label`. But `label` still needs to be
83
+ // supplied so we can pass it to Tooltip. That's why it's required.
84
+ /**
85
+ * @default undefined
86
+ */
87
+ get label() {
88
+ return this.#label;
89
+ }
90
+ set label(label) {
91
+ this.#label = label;
92
+ // Wait for the label to render. A rerender won't be scheduled by Lit until after
93
+ // this setter finishes. So awaiting `this.updateComplete` won't fly.
94
+ setTimeout(() => {
95
+ this.#updateContentSlotOverflow();
96
+ });
97
+ }
98
+ /**
99
+ * @default undefined
100
+ */
101
+ get description() {
102
+ return this.#description;
103
+ }
104
+ set description(description) {
105
+ this.#description = description;
106
+ // Wait for the description to render. A rerender won't be scheduled by Lit until
107
+ // after this setter finishes. So awaiting `this.updateComplete` won't fly.
108
+ setTimeout(() => {
109
+ this.#updateContentSlotOverflow();
110
+ });
111
+ }
112
+ /**
113
+ * @default false
114
+ */
115
+ get disabled() {
116
+ return this.#isDisabled;
117
+ }
118
+ set disabled(isDisabled) {
119
+ this.#isDisabled = isDisabled;
120
+ this.ariaDisabled = isDisabled ? 'true' : 'false';
121
+ this.dispatchEvent(new Event('private-disabled-change', { bubbles: true }));
122
+ }
123
+ get privateActive() {
124
+ return this.#isActive;
125
+ }
126
+ set privateActive(isActive) {
127
+ this.#isActive = isActive;
128
+ // Options are arbitrarily shown and hidden when Menu is opened and closed. So
129
+ // calling the below method in the `label` or `description` setters isn't enough
130
+ // because `scrollWidth` and `clientWidth` of the `label` and `description` will
131
+ // both be zero until Menu is open. Rather than expose a pseudo-private method for
132
+ // Menu to call on open, we simply check for overflow when an Option becomes
133
+ // active. But first we wait a tick for Menu to open.
134
+ setTimeout(() => {
135
+ this.#updateContentSlotOverflow();
136
+ });
137
+ }
138
+ /**
139
+ * @default false
140
+ */
141
+ get selected() {
142
+ return this.#isSelected;
143
+ }
144
+ set selected(isSelected) {
145
+ this.ariaSelected = isSelected.toString();
146
+ this.#isSelected = isSelected;
147
+ }
148
+ click() {
149
+ // You'd think this condition wouldn't be needed because `#onTooltipClick()` has a
150
+ // `this.disabled` condition that stops propagation of the event. But Menu's
151
+ // `#onDocumentClick()` handles "click" events in their capture phase, which means
152
+ // that handler will pick up the event and close Menu before `#onTooltipClick()`
153
+ // has stopped it from propagating. So we have to avoid dispatching the event
154
+ // altogether.
155
+ if (!this.disabled) {
156
+ this.#tooltipElementRef.value?.click();
157
+ }
158
+ }
159
+ connectedCallback() {
160
+ super.connectedCallback();
161
+ this.ariaDisabled = this.disabled.toString();
162
+ }
163
+ render() {
164
+ const tag = this.href === undefined || this.role === 'option' ? 'div' : 'a';
165
+ // We have a "content" slot instead of the usual default slot because whitespace
166
+ // in a slot will prevent the slot from falling back.
167
+ //
168
+ // So even a single stray space in the default slot will take the consumer off the
169
+ // happy path and prevent the `label` and `description` attributes, as well as the
170
+ // "icon" and "submenu" slots, from rendering.
171
+ //
172
+ // More importantly, even if the consumer doesn't have stray whitespace in the
173
+ // default slot, but provides "icon" or "submenu" slots, then whitespace will
174
+ // necessarily be introduced into the default slot via the whitespace around that
175
+ // content. And neither the "icon" or "default" slots nor the `label` or
176
+ // `description` attributes will be rendered.
177
+ //
178
+ // A slot dedicated to arbitrary content is the only way we can avoid these false
179
+ // positives.
180
+ // Both rules are disabled because of `unsafeStatic()`.
181
+ /*
182
+ eslint-disable lit/binding-positions, lit/no-invalid-html
183
+ */
184
+ return html `
185
+ <glide-core-tooltip
186
+ class="tooltip"
187
+ data-test="tooltip"
188
+ description=${ifDefined(this.description)}
189
+ label=${ifDefined(this.label)}
190
+ screenreader-hidden
191
+ ?disabled=${!this.isContentSlotOverflow || this.disabled}
192
+ ?open=${this.privateTooltipOpen}
193
+ @click=${this.#onTooltipClick}
194
+ @toggle=${this.#onTooltipToggle}
195
+ ${ref(this.#tooltipElementRef)}>
196
+
197
+ <${unsafeStatic(tag)}
198
+ class=${classMap({
199
+ container: true,
200
+ active: this.privateActive,
201
+ disabled: this.disabled,
202
+ href: Boolean(this.href),
203
+ })}
204
+ data-test="container"
205
+ href=${ifDefined(tag === 'a' ? this.href : undefined)}
206
+ slot="target"
207
+ ${ref(this.#containerElementRef)}
208
+ >
209
+ <slot
210
+ class=${classMap({
211
+ 'content-slot': true,
212
+ fallback: !this.hasContentSlot,
213
+ icon: this.hasIconSlot,
214
+ selected: this.selected && this.role === 'option',
215
+ submenu: this.hasSubMenuSlot,
216
+ })}
217
+ data-test="content-slot"
218
+ name="content"
219
+ @slotchange=${this.#onContentSlotChange}
220
+ ${ref(this.#contentSlotElementRef)}
221
+ >
222
+ <!--
223
+ This is the unhappy path. It's the escape hatch where you can render arbitrary
224
+ content and lay it out however you need to.
225
+
226
+ If you go this route, \`slot="icon"\` and \`slot="submenu"\` will become
227
+ unavailable. And the \`label\` and \`description\` attributes won't be rendered.
228
+
229
+ The \`label\` attribute is still required. We'll show it in a tooltip when your
230
+ content overflows. If you need a second line of text in the tooltip, provide you
231
+ can provide it via the \`description\` attribute.
232
+
233
+ @type {Element | Text}
234
+ -->
235
+
236
+ <slot
237
+ data-test="icon-slot"
238
+ name="icon"
239
+ @slotchange=${this.#onIconSlotChange}
240
+ ${assertSlot([Element], true)}
241
+ >
242
+ <!-- @type {Element} -->
243
+ </slot>
244
+
245
+ <div
246
+ class=${classMap({
247
+ label: true,
248
+ bold: Boolean(this.description),
249
+ })}
250
+ ${ref(this.#labelElementRef)}
251
+ >
252
+ ${this.label}
253
+ </div>
254
+
255
+ <slot
256
+ class=${classMap({
257
+ 'submenu-slot': true,
258
+ active: this.privateActive,
259
+ disabled: this.disabled,
260
+ open: this.isSubmenuOpen,
261
+ })}
262
+ data-test="submenu-slot"
263
+ name="submenu"
264
+ @slotchange=${this.#onSubmenuSlotChange}
265
+ @toggle=${this.#onSubmenuToggle}
266
+ ${assertSlot([Menu], true)}
267
+ >
268
+ <!-- @type {Menu} -->
269
+ </slot>
270
+
271
+ ${when(this.selected && !this.disabled && this.role === 'option', () => {
272
+ return html `<div
273
+ class="checked-icon-container"
274
+ data-test="checked-icon-container"
275
+ >
276
+ ${checkedIcon}
277
+ </div>`;
278
+ })}
279
+
280
+ ${when(this.description, () => {
281
+ return html `
282
+ <div
283
+ class=${classMap({
284
+ description: true,
285
+ icon: this.hasIconSlot,
286
+ })}
287
+ data-test="description"
288
+ ${ref(this.#descriptionElementRef)}
289
+ >
290
+ ${this.description}
291
+ </div>
292
+ `;
293
+ })}
294
+ </slot>
295
+ </${unsafeStatic(tag)}>
296
+ </glide-core-tooltip>
297
+ `;
298
+ }
299
+ updated() {
300
+ // `this.ariaSelected` needs updating whenever `this.disabled`, `this.selected`, or
301
+ // `this.role` changes.
302
+ //
303
+ // It's updated here to avoid creating a getter and setter for each of those
304
+ // properties.
305
+ this.ariaSelected =
306
+ this.selected && this.role === 'option' && !this.disabled
307
+ ? 'true'
308
+ : this.role === 'option'
309
+ ? 'false'
310
+ : null;
311
+ }
312
+ #containerElementRef;
313
+ #contentSlotElementRef;
314
+ #description;
315
+ #descriptionElementRef;
316
+ #isActive;
317
+ #isDisabled;
318
+ #isSelected;
319
+ #label;
320
+ #labelElementRef;
321
+ #tooltipElementRef;
322
+ get #contentSlotElements() {
323
+ // These are the elements that are checked for overflow in
324
+ // `#updateContentSlotOverflow()`.
325
+ //
326
+ // The slot fallback case is straightforward. And simply returning its assigned
327
+ // elements is sufficient. With the non-fallback case, however, consumers give us
328
+ // arbitrary markup. So it may not be to the assigned element that's overflowing.
329
+ // Instead, One or more children of the assigned element may be overflowing.
330
+ //
331
+ // For example, the assigned element might be DIV. And that DIV might contain an
332
+ // icon and another DIV with some text. In this case, it's the nested DIV that's
333
+ // likely to overflow, similar to how this slot's fallback content has an icon with
334
+ // a DIV that can overflow.
335
+ //
336
+ // Thus we query for every element.
337
+ if (this.#contentSlotElementRef.value) {
338
+ return [
339
+ ...this.#contentSlotElementRef.value.assignedElements({
340
+ flatten: true,
341
+ }),
342
+ ].flatMap((element) => [element, ...element.querySelectorAll('*')]);
343
+ }
344
+ }
345
+ #onContentSlotChange(event) {
346
+ if (event.target === this.#contentSlotElementRef.value) {
347
+ this.hasContentSlot =
348
+ this.#contentSlotElementRef.value.assignedNodes().length > 0;
349
+ }
350
+ this.#updateContentSlotOverflow();
351
+ }
352
+ #onIconSlotChange(event) {
353
+ if (event.target instanceof HTMLSlotElement) {
354
+ this.hasIconSlot = event.target.assignedElements().length > 0;
355
+ }
356
+ }
357
+ #onSubmenuSlotChange(event) {
358
+ if (event.target instanceof HTMLSlotElement) {
359
+ this.hasSubMenuSlot = event.target.assignedElements().length > 0;
360
+ }
361
+ }
362
+ #onSubmenuToggle(event) {
363
+ const isOwnSubmenu = this.querySelector(':scope > glide-core-menu') === event.target;
364
+ // Nested sub-Menus can be opened or closed and the target of the Option's
365
+ // own sub-Menu shouldn't change visually. As long as the Option's own
366
+ // sub-Menu is open, the sub-Menu's target should appear open. Similar for
367
+ // when a nested sub-Menu is closed.
368
+ if (isOwnSubmenu && event.target instanceof Menu && event.target.open) {
369
+ this.isSubmenuOpen = true;
370
+ }
371
+ else if (isOwnSubmenu) {
372
+ this.isSubmenuOpen = false;
373
+ }
374
+ }
375
+ #onTooltipClick(event) {
376
+ if (this.disabled) {
377
+ if (this.href) {
378
+ event.preventDefault();
379
+ }
380
+ // Consumers listen for "click" events to know when an Option is selected. Letting
381
+ // the event propagate would result in a false positive event bubbling up to the
382
+ // consumer. It would also get picked up by Menu, which would close.
383
+ event.stopPropagation();
384
+ return;
385
+ }
386
+ const isTooltipClick = Boolean(event.target === this.#tooltipElementRef.value);
387
+ const isContainerClick = Boolean(event.target === this.#containerElementRef.value);
388
+ const isTargetClick = Boolean(event.target instanceof Element &&
389
+ event.target.closest('[slot="target"]'));
390
+ const isSubmenuOption = event.target instanceof Element &&
391
+ event.target.closest('glide-core-option') !== this;
392
+ // Consumers rely on an Option's `value` property to determine which Option was
393
+ // clicked. Options, however, can have an icon or arbitrary content. So
394
+ // `event.target` may not always be the Option itself.
395
+ //
396
+ // Stopping the event and calling `this.click()` retargets `event.target` to the
397
+ // Option, which means consumers don't have to call `closest('glide-core-option')`
398
+ // on `event.target` in their click handler to get the Option before checking its
399
+ // `value`.
400
+ //
401
+ // `!isTooltipClick` because events that originate from inside the shadow DOM will
402
+ // be retarged to the host for us by the browser. Same for `!isContainerClick`.
403
+ //
404
+ // `!isTargetClick` because Menu needs to know if a target of a sub-Menu was
405
+ // clicked to avoid closing itself.
406
+ //
407
+ // `!isSubmenuOption` so we don't retarget sub-Menu Option clicks to their super-
408
+ // Menu Option.
409
+ if (!isTooltipClick &&
410
+ !isContainerClick &&
411
+ !isTargetClick &&
412
+ !isSubmenuOption) {
413
+ event.stopImmediatePropagation();
414
+ event.stopPropagation();
415
+ if (this.href) {
416
+ event.preventDefault();
417
+ }
418
+ this.click();
419
+ return;
420
+ }
421
+ }
422
+ #onTooltipToggle(event) {
423
+ if (event.target instanceof Tooltip) {
424
+ // Menu dispatches its own "toggle" event. Letting Tooltip's "toggle" event
425
+ // propagate would mean that consumers listening for the event on Menu would have
426
+ // to filter out the one coming from Tooltip.
427
+ //
428
+ // But first they'll probably file a bug. It's likely no consumer will be
429
+ // interested in knowing when an Option's tooltip is open. So it's probably best to
430
+ // stop the event from propagating.
431
+ event.stopPropagation();
432
+ }
433
+ }
434
+ #updateContentSlotOverflow() {
435
+ const isContentSlotOverflow = this.#contentSlotElements !== undefined &&
436
+ this.#contentSlotElements.some((element) => {
437
+ return element.scrollWidth > element.clientWidth;
438
+ });
439
+ this.isContentSlotOverflow = isContentSlotOverflow;
440
+ }
441
+ };
442
+ __decorate([
443
+ property({ reflect: true }),
444
+ required
445
+ ], Option.prototype, "label", null);
446
+ __decorate([
447
+ property({ reflect: true })
448
+ ], Option.prototype, "description", null);
449
+ __decorate([
450
+ property({ reflect: true, type: Boolean, useDefault: true })
451
+ ], Option.prototype, "disabled", null);
452
+ __decorate([
453
+ property({ reflect: true })
454
+ ], Option.prototype, "href", void 0);
455
+ __decorate([
456
+ property({ reflect: true })
457
+ ], Option.prototype, "id", void 0);
458
+ __decorate([
459
+ property({ type: Boolean, useDefault: true })
460
+ ], Option.prototype, "privateActive", null);
461
+ __decorate([
462
+ property({ type: Boolean })
463
+ ], Option.prototype, "privateTooltipOpen", void 0);
464
+ __decorate([
465
+ property({ reflect: true })
466
+ ], Option.prototype, "role", void 0);
467
+ __decorate([
468
+ property({ type: Boolean })
469
+ ], Option.prototype, "selected", null);
470
+ __decorate([
471
+ property({ attribute: 'tabindex', reflect: true, type: Number })
472
+ ], Option.prototype, "tabIndex", void 0);
473
+ __decorate([
474
+ property({ reflect: true, useDefault: true })
475
+ ], Option.prototype, "value", void 0);
476
+ __decorate([
477
+ property({ reflect: true })
478
+ ], Option.prototype, "version", void 0);
479
+ __decorate([
480
+ state()
481
+ ], Option.prototype, "hasContentSlot", void 0);
482
+ __decorate([
483
+ state()
484
+ ], Option.prototype, "hasIconSlot", void 0);
485
+ __decorate([
486
+ state()
487
+ ], Option.prototype, "hasSubMenuSlot", void 0);
488
+ __decorate([
489
+ state()
490
+ ], Option.prototype, "isContentSlotOverflow", void 0);
491
+ __decorate([
492
+ state()
493
+ ], Option.prototype, "isSubmenuOpen", void 0);
494
+ Option = __decorate([
495
+ customElement('glide-core-option'),
496
+ final
497
+ ], Option);
498
+ export default Option;
@@ -0,0 +1,140 @@
1
+ import { css } from 'lit';
2
+ export default [
3
+ css `
4
+ .tooltip {
5
+ display: block;
6
+ }
7
+
8
+ .container {
9
+ border-radius: var(--glide-core-rounding-base-radius-xs);
10
+ box-sizing: border-box;
11
+ color: var(--glide-core-color-static-text-default);
12
+ cursor: pointer;
13
+ font-family: var(--glide-core-typography-family-primary);
14
+ font-size: var(--glide-core-typography-size-body-default);
15
+ font-weight: var(--glide-core-typography-weight-regular);
16
+ inline-size: 100%;
17
+ max-inline-size: 21.875rem;
18
+ padding-block: var(--glide-core-spacing-base-xxs);
19
+ padding-inline: var(--glide-core-spacing-base-sm);
20
+ transition: background-color var(--glide-core-duration-fast-02) ease-in-out;
21
+ user-select: none;
22
+
23
+ &.active {
24
+ background-color: var(
25
+ --glide-core-color-interactive-surface-container--hover
26
+ );
27
+ }
28
+
29
+ &.disabled {
30
+ color: var(--glide-core-color-interactive-icon-default--disabled);
31
+
32
+ /*
33
+ If this is an Option in a sub-Menu, "cursor: pointer" (above) will be inherited
34
+ from the parent Option (the one the contains the sub-Menu). So we make sure we
35
+ override it.
36
+ */
37
+ cursor: default;
38
+ }
39
+
40
+ &.href {
41
+ display: block;
42
+ text-decoration: none;
43
+
44
+ &:not(.disabled) {
45
+ color: inherit;
46
+ }
47
+ }
48
+ }
49
+
50
+ .content-slot {
51
+ &.fallback {
52
+ align-items: center;
53
+ display: grid;
54
+ grid-column-gap: var(--glide-core-spacing-base-xs);
55
+
56
+ &.icon {
57
+ grid-template-columns: auto 1fr;
58
+
59
+ &.submenu {
60
+ display: grid;
61
+ grid-template-columns: auto 1fr auto;
62
+ }
63
+ }
64
+
65
+ &.submenu {
66
+ grid-template-columns: 1fr auto;
67
+ }
68
+
69
+ &.selected {
70
+ grid-template-columns: 1fr auto;
71
+
72
+ &.icon {
73
+ grid-template-columns: auto 1fr auto;
74
+
75
+ &.submenu {
76
+ grid-template-columns: auto 1fr auto auto;
77
+ }
78
+ }
79
+
80
+ &.submenu {
81
+ grid-template-columns: 1fr auto auto;
82
+ }
83
+ }
84
+ }
85
+ }
86
+
87
+ .label {
88
+ overflow-x: hidden;
89
+ text-overflow: ellipsis;
90
+ white-space: nowrap;
91
+
92
+ &.bold {
93
+ font-weight: var(--glide-core-typography-weight-bold);
94
+ }
95
+ }
96
+
97
+ .description {
98
+ grid-column: 1 / 2;
99
+ overflow-x: hidden;
100
+ text-overflow: ellipsis;
101
+ white-space: nowrap;
102
+
103
+ &.icon {
104
+ grid-column: 2 / 3;
105
+ }
106
+ }
107
+
108
+ .checked-icon-container {
109
+ --private-size: 1rem;
110
+
111
+ display: contents;
112
+ }
113
+
114
+ .submenu-slot {
115
+ &::slotted(*) {
116
+ opacity: 0;
117
+ }
118
+
119
+ &.active {
120
+ &::slotted(*) {
121
+ opacity: 1;
122
+ }
123
+ }
124
+
125
+ &:hover {
126
+ &::slotted(*) {
127
+ color: var(--glide-core-color-interactive-text-link--hover);
128
+ opacity: 1;
129
+ }
130
+ }
131
+
132
+ &.open {
133
+ &::slotted(*) {
134
+ color: var(--glide-core-color-interactive-text-link--hover);
135
+ opacity: 1;
136
+ }
137
+ }
138
+ }
139
+ `,
140
+ ];
@@ -1,7 +1,7 @@
1
1
  import { LitElement } from 'lit';
2
2
  declare global {
3
3
  interface HTMLElementTagNameMap {
4
- 'glide-core-menu-options': MenuOptions;
4
+ 'glide-core-options': Options;
5
5
  }
6
6
  }
7
7
  /**
@@ -11,8 +11,7 @@ declare global {
11
11
  * @readonly
12
12
  * @attr {string} [id]
13
13
  *
14
- * @readonly
15
- * @attr {string} [role='menu']
14
+ * @attr {'menu'|'listbox'} [role='menu']
16
15
  *
17
16
  * @readonly
18
17
  * @attr {number} [tabindex=-1]
@@ -20,9 +19,9 @@ declare global {
20
19
  * @readonly
21
20
  * @attr {string} [version]
22
21
  *
23
- * @slot {MenuButton | MenuLink}
22
+ * @slot {Option | Text}
24
23
  */
25
- export default class MenuOptions extends LitElement {
24
+ export default class Options extends LitElement {
26
25
  #private;
27
26
  static shadowRootOptions: ShadowRootInit;
28
27
  static styles: import("lit").CSSResult[];
@@ -30,7 +29,7 @@ export default class MenuOptions extends LitElement {
30
29
  ariaLabelledby: string;
31
30
  readonly id: string;
32
31
  privateLoading: boolean;
33
- readonly role = "menu";
32
+ role: 'menu' | 'listbox';
34
33
  readonly tabIndex = -1;
35
34
  readonly version: string;
36
35
  render(): import("lit").TemplateResult<1>;