Skip to content
This repository was archived by the owner on Nov 13, 2025. It is now read-only.

Commit 0f44767

Browse files
ynotdrawclintcsdanwenzel
authored
Make use of the new @required decorator (#685)
* Make use of the new required decorator * Apply suggestions from code review Co-authored-by: clintcs <[email protected]> * Remove unnecessary this.selectedOptions.length > 0 checks * Update CONTRIBUTING.md Co-authored-by: Dan Wenzel <[email protected]> --------- Co-authored-by: clintcs <[email protected]> Co-authored-by: Dan Wenzel <[email protected]>
1 parent d727d44 commit 0f44767

File tree

85 files changed

+735
-161
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+735
-161
lines changed

.changeset/funny-windows-appear.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@crowdstrike/glide-core': patch
3+
---
4+
5+
The `label` of a Dropdown Option with a checkbox is now displayed in a tooltip when the label is truncated.

.changeset/spicy-pumpkins-obey.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
'@crowdstrike/glide-core': minor
3+
---
4+
5+
Required attributes now throw during development when missing. The following are now required:
6+
7+
- `label`
8+
- Accordion
9+
- Button Group Button
10+
- Button Group
11+
- Button
12+
- Checkbox Group
13+
- Checkbox
14+
- Drawer
15+
- Dropdown Option
16+
- Dropdown
17+
- Icon Button
18+
- Input
19+
- Menu Button
20+
- Menu Link
21+
- Modal Icon Button
22+
- Modal
23+
- Radio Group Radio
24+
- Radio Group
25+
- Split Button Primary Button
26+
- Split Button Primary Link
27+
- Split Button Secondary Button
28+
- Tag
29+
- Textarea
30+
- Toggle
31+
- Tooltip
32+
- Tree Item Icon Button
33+
- Tree Item Menu
34+
- Tree Item
35+
- `name`
36+
- Tab Panel
37+
- `panel`
38+
- Tab
39+
- `url`
40+
- Split Button Primary Link

CONTRIBUTING.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
- [Prefer using animations only when the user has no reduced motion preference](#prefer-using-animations-only-when-the-user-has-no-reduced-motion-preference)
2222
- [Prefer `rem`s](#prefer-rems)
2323
- [Throw when slotted content is missing or the wrong type](#throw-when-slotted-content-is-missing-or-the-wrong-type)
24+
- [Throw when required properties are missing](#throw-when-required-properties-are-missing)
2425
- [Prefer conventions set by built-in elements](#prefer-conventions-set-by-built-in-elements)
2526
- [Prefer separate test files](#prefer-separate-test-files)
2627
- [Typing property decorators](#typing-property-decorators)
@@ -402,6 +403,22 @@ export default class GlideCoreExample extends LitElement {
402403
}
403404
```
404405

406+
### Throw when required properties are missing
407+
408+
Some properties are required for accessibility or ensure proper functionality.
409+
When a property is required, use the `@required` decorator to assert its existence.
410+
411+
```ts
412+
import required from './library/required.js';
413+
414+
@customElement('glide-core-example')
415+
export default class GlideCoreExample extends LitElement {
416+
@property()
417+
@required
418+
name: string;
419+
}
420+
```
421+
405422
### Prefer conventions set by built-in elements
406423

407424
A built-in element is one that is provided by the platform, such as `<input />`.

src/accordion.test.basics.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,18 @@ it('is accessible', async () => {
2121
await expect(host).to.be.accessible();
2222
});
2323

24+
it('throws when `label` is empty', async () => {
25+
const spy = sinon.spy();
26+
27+
try {
28+
await fixture(html`<glide-core-accordion>Content</glide-core-accordion>`);
29+
} catch {
30+
spy();
31+
}
32+
33+
expect(spy.callCount).to.equal(1);
34+
});
35+
2436
it('throws when subclassed', async () => {
2537
const spy = sinon.spy();
2638

src/accordion.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import styles from './accordion.styles.js';
88
import assertSlot from './library/assert-slot.js';
99
import shadowRootMode from './library/shadow-root-mode.js';
1010
import final from './library/final.js';
11+
import required from './library/required.js';
1112

1213
declare global {
1314
interface HTMLElementTagNameMap {
@@ -33,7 +34,9 @@ export default class GlideCoreAccordion extends LitElement {
3334

3435
static override styles = styles;
3536

36-
@property({ reflect: true }) label?: string;
37+
@property({ reflect: true })
38+
@required
39+
label?: string;
3740

3841
@property({ reflect: true, type: Boolean })
3942
get open() {

src/button-group.button.test.basics.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,20 @@ it('is not tabbable when not selected', async () => {
9898
expect(radio?.tabIndex).to.equal(-1);
9999
});
100100

101+
it('throws when `label` is empty', async () => {
102+
const spy = sinon.spy();
103+
104+
try {
105+
await fixture(
106+
html`<glide-core-button-group-button></glide-core-button-group-button>`,
107+
);
108+
} catch {
109+
spy();
110+
}
111+
112+
expect(spy.callCount).to.equal(1);
113+
});
114+
101115
it('throws when subclassed', async () => {
102116
const spy = sinon.spy();
103117

@@ -114,6 +128,7 @@ it('throws when `icon-only` and no "icon" slot', async () => {
114128
await expectUnhandledRejection(() => {
115129
return fixture(
116130
html`<glide-core-button-group-button
131+
label="Label"
117132
privateVariant="icon-only"
118133
></glide-core-button-group-button>`,
119134
);

src/button-group.button.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import styles from './button-group.button.styles.js';
77
import assertSlot from './library/assert-slot.js';
88
import shadowRootMode from './library/shadow-root-mode.js';
99
import final from './library/final.js';
10+
import required from './library/required.js';
1011

1112
declare global {
1213
interface HTMLElementTagNameMap {
@@ -29,7 +30,8 @@ export default class GlideCoreButtonGroupButton extends LitElement {
2930
static override styles = styles;
3031

3132
@property({ reflect: true })
32-
label? = '';
33+
@required
34+
label?: string;
3335

3436
@property({ type: Boolean, reflect: true })
3537
get selected() {

src/button-group.test.basics.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ it('is accessible', async () => {
3939

4040
it('sets the orientation of its buttons when horizontal', async () => {
4141
const host = await fixture(
42-
html`<glide-core-button-group>
42+
html`<glide-core-button-group label="Label">
4343
<glide-core-button-group-button
4444
label="One"
4545
></glide-core-button-group-button>
@@ -58,7 +58,7 @@ it('sets the orientation of its buttons when horizontal', async () => {
5858

5959
it('sets the orientation of its buttons when vertical', async () => {
6060
const host = await fixture(
61-
html`<glide-core-button-group orientation="vertical">
61+
html`<glide-core-button-group label="Label" orientation="vertical">
6262
<glide-core-button-group-button
6363
label="One"
6464
></glide-core-button-group-button>
@@ -96,7 +96,7 @@ it('sets `privateVariant` on its buttons', async () => {
9696

9797
it('selects the first button not disabled', async () => {
9898
const host = await fixture(
99-
html`<glide-core-button-group>
99+
html`<glide-core-button-group label="Label">
100100
<glide-core-button-group-button
101101
label="One"
102102
disabled
@@ -121,7 +121,7 @@ it('selects the first button not disabled', async () => {
121121

122122
it('selects no buttons when all are disabled', async () => {
123123
const host = await fixture(
124-
html`<glide-core-button-group>
124+
html`<glide-core-button-group label="Label">
125125
<glide-core-button-group-button
126126
label="One"
127127
disabled
@@ -140,6 +140,24 @@ it('selects no buttons when all are disabled', async () => {
140140
expect(buttons[1].selected).to.be.false;
141141
});
142142

143+
it('throws when `label` is empty', async () => {
144+
const spy = sinon.spy();
145+
146+
try {
147+
await fixture(
148+
html`<glide-core-button-group>
149+
<glide-core-button-group-button
150+
label="One"
151+
></glide-core-button-group-button>
152+
</glide-core-button-group>`,
153+
);
154+
} catch {
155+
spy();
156+
}
157+
158+
expect(spy.callCount).to.equal(1);
159+
});
160+
143161
it('throws when subclassed', async () => {
144162
const spy = sinon.spy();
145163

src/button-group.test.events.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import './button-group.js';
77

88
it('dispatches a "selected" event when a button is clicked and not already selected', async () => {
99
const host = await fixture(
10-
html`<glide-core-button-group>
10+
html`<glide-core-button-group label="Label">
1111
<glide-core-button-group-button
1212
label="One"
1313
></glide-core-button-group-button>
@@ -34,7 +34,7 @@ it('dispatches a "selected" event when a button is clicked and not already selec
3434

3535
it('does not dispatch a "selected" event when an already selected button is clicked', async () => {
3636
const host = await fixture(
37-
html`<glide-core-button-group>
37+
html`<glide-core-button-group label="Label">
3838
<glide-core-button-group-button
3939
label="One"
4040
selected
@@ -56,7 +56,7 @@ it('does not dispatch a "selected" event when an already selected button is clic
5656

5757
it('dispatches "selected" events when arrowing', async () => {
5858
const host = await fixture(
59-
html`<glide-core-button-group>
59+
html`<glide-core-button-group label="Label">
6060
<glide-core-button-group-button
6161
label="One"
6262
selected
@@ -104,7 +104,7 @@ it('dispatches "selected" events when arrowing', async () => {
104104

105105
it('dispatches a "selected" event when a button is selected via Space', async () => {
106106
const host = await fixture(
107-
html`<glide-core-button-group>
107+
html`<glide-core-button-group label="Label">
108108
<glide-core-button-group-button
109109
label="One"
110110
selected
@@ -131,7 +131,7 @@ it('dispatches a "selected" event when a button is selected via Space', async ()
131131

132132
it('does not dispatch a "selected" event when a button is selected programmatically', async () => {
133133
const host = await fixture(
134-
html`<glide-core-button-group>
134+
html`<glide-core-button-group label="Label">
135135
<glide-core-button-group-button
136136
label="One"
137137
selected
@@ -160,7 +160,7 @@ it('does not dispatch a "selected" event when a button is selected programmatica
160160

161161
it('does not dispatch a "selected" event when an already selected button is selected via Space', async () => {
162162
const host = await fixture(
163-
html`<glide-core-button-group>
163+
html`<glide-core-button-group label="Label">
164164
<glide-core-button-group-button
165165
label="One"
166166
selected
@@ -183,7 +183,7 @@ it('does not dispatch a "selected" event when an already selected button is sele
183183

184184
it('does not dispatch a "selected" event a button is selected programmatically', async () => {
185185
const host = await fixture(
186-
html`<glide-core-button-group>
186+
html`<glide-core-button-group label="Label">
187187
<glide-core-button-group-button
188188
label="One"
189189
selected

src/button-group.test.focus.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import './button-group.js';
55

66
it('moves focus when arrowing', async () => {
77
const host = await fixture(
8-
html`<glide-core-button-group>
8+
html`<glide-core-button-group label="Label">
99
<glide-core-button-group-button
1010
label="One"
1111
></glide-core-button-group-button>

0 commit comments

Comments
 (0)