@crowdstrike/glide-core 0.31.0 → 0.31.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/dropdown.js +2 -2
- package/dist/menu.js +20 -2
- package/dist/option.styles.js +3 -1
- package/dist/options.group.d.ts +30 -0
- package/dist/options.group.js +84 -0
- package/dist/options.group.styles.d.ts +2 -0
- package/dist/options.group.styles.js +31 -0
- package/dist/options.js +2 -1
- package/package.json +3 -3
package/dist/dropdown.js
CHANGED
@@ -1556,8 +1556,8 @@ let Dropdown = class Dropdown extends LitElement {
|
|
1556
1556
|
// Prevent page scroll. When filterable, also prevent the insertion point from
|
1557
1557
|
// moving to the beginning of the field.
|
1558
1558
|
event.preventDefault();
|
1559
|
-
const firstOption =
|
1560
|
-
.
|
1559
|
+
const firstOption = this.#optionElementsNotHiddenIncludingSelectAll
|
1560
|
+
.toReversed()
|
1561
1561
|
.findLast((option) => !option.disabled);
|
1562
1562
|
if (firstOption) {
|
1563
1563
|
this.#previouslyActiveOption = this.activeOption;
|
package/dist/menu.js
CHANGED
@@ -13,6 +13,7 @@ import { customElement, property } from 'lit/decorators.js';
|
|
13
13
|
import packageJson from '../package.json' with { type: 'json' };
|
14
14
|
import { LocalizeController } from './library/localize.js';
|
15
15
|
import Options from './options.js';
|
16
|
+
import OptionsGroup from './options.group.js';
|
16
17
|
import Option from './option.js';
|
17
18
|
import Input from './input.js';
|
18
19
|
import assertSlot from './library/assert-slot.js';
|
@@ -399,7 +400,9 @@ let Menu = class Menu extends LitElement {
|
|
399
400
|
.flatMap((element) => {
|
400
401
|
return element instanceof HTMLSlotElement
|
401
402
|
? element.assignedElements({ flatten: true })
|
402
|
-
: element
|
403
|
+
: element instanceof OptionsGroup
|
404
|
+
? [...element.children]
|
405
|
+
: element;
|
403
406
|
})
|
404
407
|
?.filter((element) => {
|
405
408
|
return element instanceof Option;
|
@@ -415,8 +418,14 @@ let Menu = class Menu extends LitElement {
|
|
415
418
|
// The "content" slot case.
|
416
419
|
':scope > glide-core-options > glide-core-option > [slot="content"] > glide-core-menu'),
|
417
420
|
...this.querySelectorAll(
|
421
|
+
// The "content" slot and Options Group case.
|
422
|
+
':scope > glide-core-options > glide-core-options-group > glide-core-option > [slot="content"] > glide-core-menu'),
|
423
|
+
...this.querySelectorAll(
|
418
424
|
// The "content" slot fallback case.
|
419
425
|
':scope > glide-core-options > glide-core-option > [slot="submenu"]'),
|
426
|
+
...this.querySelectorAll(
|
427
|
+
// The "content" slot fallback and Options Group case.
|
428
|
+
':scope > glide-core-options > glide-core-options-group > glide-core-option > [slot="submenu"]'),
|
420
429
|
];
|
421
430
|
}
|
422
431
|
get #targetElement() {
|
@@ -496,6 +505,15 @@ let Menu = class Menu extends LitElement {
|
|
496
505
|
if (this.#isSubMenu && event.target === this.#defaultSlotElementRef.value) {
|
497
506
|
event.stopPropagation();
|
498
507
|
}
|
508
|
+
// When Menu is in the shadow DOM of another component, `event.target` will be
|
509
|
+
// retargeted to the host of that component the moment the event bubbles out of
|
510
|
+
// it.
|
511
|
+
//
|
512
|
+
// So, when the timeout callback below is called, `event.target` will have been
|
513
|
+
// retargeted and the `instanceof` check will wrongly fail when an Option is
|
514
|
+
// clicked, and Menu will never close. So we store a reference to the original
|
515
|
+
// `event.target` and use it in the `instanceof` condition.
|
516
|
+
const originalEventTarget = event.target;
|
499
517
|
// The timeout gives consumers a chance to cancel the event to prevent Menu from
|
500
518
|
// closing.
|
501
519
|
setTimeout(() => {
|
@@ -510,7 +528,7 @@ let Menu = class Menu extends LitElement {
|
|
510
528
|
//
|
511
529
|
// When the default slot's padding is clicked, Menu should remain open because the
|
512
530
|
// user most likely meant to click an Option but missed.
|
513
|
-
if (!event.defaultPrevented &&
|
531
|
+
if (!event.defaultPrevented && originalEventTarget instanceof Option) {
|
514
532
|
this.open = false;
|
515
533
|
}
|
516
534
|
});
|
package/dist/option.styles.js
CHANGED
@@ -15,9 +15,11 @@ export default [
|
|
15
15
|
font-weight: var(--glide-core-typography-weight-regular);
|
16
16
|
inline-size: 100%;
|
17
17
|
max-inline-size: 21.875rem;
|
18
|
+
min-block-size: 1.75rem;
|
18
19
|
padding-block: var(--glide-core-spacing-base-xxs);
|
19
20
|
padding-inline: var(--glide-core-spacing-base-sm);
|
20
|
-
transition: background-color var(--glide-core-duration-fast-02)
|
21
|
+
transition: background-color var(--glide-core-duration-fast-02)
|
22
|
+
ease-in-out;
|
21
23
|
user-select: none;
|
22
24
|
|
23
25
|
&.active {
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { LitElement } from 'lit';
|
2
|
+
declare global {
|
3
|
+
interface HTMLElementTagNameMap {
|
4
|
+
'glide-core-options-group': OptionsGroup;
|
5
|
+
}
|
6
|
+
}
|
7
|
+
/**
|
8
|
+
* @attr {string} label
|
9
|
+
* @attr {boolean} [hide-label=false]
|
10
|
+
* @attr {'group'|'optgroup'} [role='group']
|
11
|
+
*
|
12
|
+
* @readonly
|
13
|
+
* @attr {string} [version]
|
14
|
+
*
|
15
|
+
* @slot {Option}
|
16
|
+
*/
|
17
|
+
export default class OptionsGroup extends LitElement {
|
18
|
+
#private;
|
19
|
+
static shadowRootOptions: ShadowRootInit;
|
20
|
+
static styles: import("lit").CSSResult[];
|
21
|
+
/**
|
22
|
+
* @default undefined
|
23
|
+
*/
|
24
|
+
get label(): string | undefined;
|
25
|
+
set label(label: string);
|
26
|
+
hideLabel: boolean;
|
27
|
+
role: 'group' | 'optgroup';
|
28
|
+
readonly version: string;
|
29
|
+
render(): import("lit").TemplateResult<1>;
|
30
|
+
}
|
@@ -0,0 +1,84 @@
|
|
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 packageJson from '../package.json' with { type: 'json' };
|
11
|
+
import styles from './options.group.styles.js';
|
12
|
+
import shadowRootMode from './library/shadow-root-mode.js';
|
13
|
+
import final from './library/final.js';
|
14
|
+
import assertSlot from './library/assert-slot.js';
|
15
|
+
import Option from './option.js';
|
16
|
+
import required from './library/required.js';
|
17
|
+
/**
|
18
|
+
* @attr {string} label
|
19
|
+
* @attr {boolean} [hide-label=false]
|
20
|
+
* @attr {'group'|'optgroup'} [role='group']
|
21
|
+
*
|
22
|
+
* @readonly
|
23
|
+
* @attr {string} [version]
|
24
|
+
*
|
25
|
+
* @slot {Option}
|
26
|
+
*/
|
27
|
+
let OptionsGroup = class OptionsGroup extends LitElement {
|
28
|
+
constructor() {
|
29
|
+
super(...arguments);
|
30
|
+
this.hideLabel = false;
|
31
|
+
this.role = 'group';
|
32
|
+
this.version = packageJson.version;
|
33
|
+
}
|
34
|
+
static { this.shadowRootOptions = {
|
35
|
+
...LitElement.shadowRootOptions,
|
36
|
+
mode: shadowRootMode,
|
37
|
+
}; }
|
38
|
+
static { this.styles = styles; }
|
39
|
+
/**
|
40
|
+
* @default undefined
|
41
|
+
*/
|
42
|
+
get label() {
|
43
|
+
return this.#label;
|
44
|
+
}
|
45
|
+
set label(label) {
|
46
|
+
this.#label = label;
|
47
|
+
this.ariaLabel = label;
|
48
|
+
}
|
49
|
+
render() {
|
50
|
+
return html `
|
51
|
+
<div class="component">
|
52
|
+
<div
|
53
|
+
aria-hidden="true"
|
54
|
+
class=${classMap({ label: true, 'visually-hidden': this.hideLabel })}
|
55
|
+
>
|
56
|
+
${this.label}
|
57
|
+
</div>
|
58
|
+
|
59
|
+
<slot ${assertSlot([Option])}>
|
60
|
+
<!-- @type {Option} -->
|
61
|
+
</slot>
|
62
|
+
</div>
|
63
|
+
`;
|
64
|
+
}
|
65
|
+
#label;
|
66
|
+
};
|
67
|
+
__decorate([
|
68
|
+
property({ reflect: true }),
|
69
|
+
required
|
70
|
+
], OptionsGroup.prototype, "label", null);
|
71
|
+
__decorate([
|
72
|
+
property({ attribute: 'hide-label', reflect: true, type: Boolean })
|
73
|
+
], OptionsGroup.prototype, "hideLabel", void 0);
|
74
|
+
__decorate([
|
75
|
+
property({ reflect: true })
|
76
|
+
], OptionsGroup.prototype, "role", void 0);
|
77
|
+
__decorate([
|
78
|
+
property({ reflect: true })
|
79
|
+
], OptionsGroup.prototype, "version", void 0);
|
80
|
+
OptionsGroup = __decorate([
|
81
|
+
customElement('glide-core-options-group'),
|
82
|
+
final
|
83
|
+
], OptionsGroup);
|
84
|
+
export default OptionsGroup;
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import { css } from 'lit';
|
2
|
+
import visuallyHidden from './styles/visually-hidden.js';
|
3
|
+
export default [
|
4
|
+
css `
|
5
|
+
${visuallyHidden('.label.visually-hidden')}
|
6
|
+
`,
|
7
|
+
css `
|
8
|
+
:host(:not(:last-of-type)) .component::after {
|
9
|
+
background-color: var(--glide-core-color-static-stroke-secondary);
|
10
|
+
block-size: 1px;
|
11
|
+
border-radius: var(--glide-core-rounding-base-radius-sm);
|
12
|
+
content: '';
|
13
|
+
display: block;
|
14
|
+
margin-block: var(--glide-core-spacing-base-xxxs);
|
15
|
+
}
|
16
|
+
|
17
|
+
.label {
|
18
|
+
block-size: 1.75rem;
|
19
|
+
box-sizing: border-box;
|
20
|
+
font-family: var(--glide-core-typography-family-primary);
|
21
|
+
font-size: var(--glide-core-typography-size-body-small);
|
22
|
+
font-weight: var(--glide-core-typography-weight-bold);
|
23
|
+
max-inline-size: 21.875rem;
|
24
|
+
overflow: hidden;
|
25
|
+
padding-block: var(--glide-core-spacing-base-xxs);
|
26
|
+
padding-inline: var(--glide-core-spacing-base-sm);
|
27
|
+
text-overflow: ellipsis;
|
28
|
+
white-space: nowrap;
|
29
|
+
}
|
30
|
+
`,
|
31
|
+
];
|
package/dist/options.js
CHANGED
@@ -17,6 +17,7 @@ import final from './library/final.js';
|
|
17
17
|
import uniqueId from './library/unique-id.js';
|
18
18
|
import assertSlot from './library/assert-slot.js';
|
19
19
|
import Option from './option.js';
|
20
|
+
import OptionsGroup from './options.group.js';
|
20
21
|
// This component exists because Menu's target and its menu (`"role="menu"` or
|
21
22
|
// `role="listbox"`) both need to be in the light DOM so the target and menu can
|
22
23
|
// reference each other's IDs in ARIA attributes.
|
@@ -82,7 +83,7 @@ let Options = class Options extends LitElement {
|
|
82
83
|
loading: this.privateLoading,
|
83
84
|
})}
|
84
85
|
@slotchange=${this.#onDefaultSlotChange}
|
85
|
-
${assertSlot([Option, Text], true)}
|
86
|
+
${assertSlot([OptionsGroup, Option, Text], true)}
|
86
87
|
>
|
87
88
|
<!-- @type {Option | Text} -->
|
88
89
|
</slot>
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@crowdstrike/glide-core",
|
3
|
-
"version": "0.31.
|
3
|
+
"version": "0.31.1",
|
4
4
|
"description": "A Web Component design system",
|
5
5
|
"author": "CrowdStrike UX Team",
|
6
6
|
"license": "Apache-2.0",
|
@@ -94,13 +94,13 @@
|
|
94
94
|
"comment-parser": "^1.4.1",
|
95
95
|
"custom-elements-manifest": "^2.1.0",
|
96
96
|
"esbuild": "^0.25.0",
|
97
|
-
"eslint": "^9.
|
97
|
+
"eslint": "^9.31.0",
|
98
98
|
"eslint-config-prettier": "^10.1.5",
|
99
99
|
"eslint-plugin-import": "^2.31.0",
|
100
100
|
"eslint-plugin-lit": "^1.15.0",
|
101
101
|
"eslint-plugin-lit-a11y": "^4.1.4",
|
102
102
|
"eslint-plugin-sort-class-members": "^1.21.0",
|
103
|
-
"eslint-plugin-unicorn": "^
|
103
|
+
"eslint-plugin-unicorn": "^60.0.0",
|
104
104
|
"globals": "^15.13.0",
|
105
105
|
"globby": "^14.0.2",
|
106
106
|
"husky": "^8.0.3",
|