Skip to content

Commit fdd277a

Browse files
authored
feat(dropdown): add support for disabling dropdown items (#1018)
Also use the appropriate custom event to ensure that the feature set works as intended. Closes #1017
1 parent ea80786 commit fdd277a

File tree

6 files changed

+116
-32
lines changed

6 files changed

+116
-32
lines changed

src/components/dropdown/bl-dropdown.stories.mdx

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
2+
import { userEvent } from '@storybook/testing-library';
13
import { html } from 'lit';
24
import { ifDefined } from 'lit/directives/if-defined.js';
35
import { styleMap } from 'lit/directives/style-map.js';
4-
import { Meta, Canvas, ArgsTable, Story } from '@storybook/addon-docs';
5-
import { userEvent } from '@storybook/testing-library';
66

77
<Meta
88
title="Components/Dropdown Button/Dropdown"
@@ -35,8 +35,8 @@ import { userEvent } from '@storybook/testing-library';
3535

3636
export const dropdownOpener = async ({ canvasElement }) => {
3737
const dropdown = canvasElement?.querySelector('bl-dropdown')
38-
if(dropdown.shadowRoot) {
39-
const button = dropdown.shadowRoot.querySelector('bl-button')
38+
if (dropdown.shadowRoot) {
39+
const button = dropdown.shadowRoot.querySelector("bl-button")?.shadowRoot?.querySelector("button");
4040
await userEvent.click(button);
4141
}
4242
}
@@ -78,6 +78,22 @@ export const IconDropdownTemplate = (args) => html`<bl-dropdown
7878
<bl-dropdown-item>Action 5</bl-dropdown-item>
7979
</bl-dropdown>`
8080

81+
export const DisabledItemDropdownTemplate = (args) => html`<bl-dropdown
82+
variant=${ifDefined(args.variant)}
83+
kind=${ifDefined(args.kind)}
84+
size=${ifDefined(args.size)}
85+
label="${ifDefined(args.label)}"
86+
?disabled=${args.disabled}
87+
style=${ifDefined(args.styles ? styleMap(args.styles) : undefined)}
88+
><bl-dropdown-group caption="Caption">
89+
<bl-dropdown-item disabled>${args.content || 'Action 1'}</bl-dropdown-item>
90+
<bl-dropdown-item>Action 2</bl-dropdown-item>
91+
</bl-dropdown-group>
92+
<bl-dropdown-item>Action 3</bl-dropdown-item>
93+
<bl-dropdown-item icon="info" disabled>Action 4</bl-dropdown-item>
94+
<bl-dropdown-item>Action 5</bl-dropdown-item>
95+
</bl-dropdown>`
96+
8197
export const Template = (args) => html`
8298
${SingleDropdownButtonTemplate({...args})}
8399
${SingleDropdownButtonTemplate({variant: 'secondary', ...args})}
@@ -148,7 +164,7 @@ If dropdown button has an action with a long text that can not fit in a single l
148164
You can add icons to your dropdown buttons using the `icon` attribute. The icon will be displayed on the left side of the button label.
149165

150166
<Canvas>
151-
<Story name="With Icons" args={{ label: 'Dropdown Button' }}>
167+
<Story name="With Icons" args={{ label: 'Dropdown Button' }} play={dropdownOpener}>
152168
{html`
153169
${IconDropdownTemplate({label: 'Settings', icon: 'settings', variant: 'primary'})}
154170
${IconDropdownTemplate({label: 'Settings', icon: 'settings', variant: 'secondary'})}
@@ -162,19 +178,29 @@ You can add icons to your dropdown buttons using the `icon` attribute. The icon
162178
We have 2 types of disabled dropdown buttons: Disable version of Primary and Secondary buttons is the same.
163179

164180
<Canvas columns={1}>
165-
<Story name="Disabling Dropdown Buttons" args={{ label: 'Dropdown Button', disabled: true }} play={dropdownOpener}>
181+
<Story name="Disabling Dropdown Buttons" args={{ label: 'Dropdown Button', disabled: true }}>
166182
{SizesTemplate.bind({})}
167183
</Story>
168184
</Canvas>
169185

170186
Whereas Tertiary buttons keep their transparent backgrounds.
171187

172188
<Canvas columns={1}>
173-
<Story name="Disabling Tertiary Dropdown Buttons" args={{ label: 'Dropdown Button', disabled: true, variant:"tertiary" }} play={dropdownOpener}>
189+
<Story name="Disabling Tertiary Dropdown Buttons" args={{ label: 'Dropdown Button', disabled: true, variant:"tertiary" }}>
174190
{SizesTemplate.bind({})}
175191
</Story>
176192
</Canvas>
177193

194+
## Disabling Dropdown Items
195+
196+
You can disable dropdown items by setting the `disabled` attribute on the `bl-dropdown-item` element.
197+
198+
<Canvas>
199+
<Story name="Disabling Dropdown Items" args={{ label: 'Dropdown Button' }} play={dropdownOpener}>
200+
{DisabledItemDropdownTemplate.bind({})}
201+
</Story>
202+
</Canvas>
203+
178204

179205
## Reference
180206

src/components/dropdown/bl-dropdown.test.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
import BlDropdown from "./bl-dropdown";
21
import {
32
assert,
3+
elementUpdated,
4+
expect,
45
fixture,
56
html,
67
oneEvent,
7-
expect,
8-
elementUpdated,
98
waitUntil,
109
} from "@open-wc/testing";
1110
import { sendKeys } from "@web/test-runner-commands";
11+
import BlDropdown from "./bl-dropdown";
1212

13-
import type typeOfBlDropdown from "./bl-dropdown";
1413
import BlButton from "../button/bl-button";
1514
import "../popover/bl-popover";
1615
import BlPopover from "../popover/bl-popover";
16+
import type typeOfBlDropdown from "./bl-dropdown";
1717

1818
describe("bl-dropdown", () => {
1919
it("is defined", () => {
@@ -112,7 +112,12 @@ describe("bl-dropdown", () => {
112112
.querySelector("bl-dropdown-item")
113113
?.shadowRoot?.querySelector("bl-button") as HTMLElement | null;
114114

115-
item?.click();
115+
item?.dispatchEvent(
116+
new CustomEvent("bl-click", {
117+
bubbles: true,
118+
composed: true,
119+
})
120+
);
116121

117122
setTimeout(() => {
118123
expect(el.opened).to.false;
@@ -167,6 +172,33 @@ describe("bl-dropdown", () => {
167172
expect(popover.visible).to.false;
168173
});
169174

175+
it("should not close dropdown when disabled item is clicked", async () => {
176+
const el = await fixture<typeOfBlDropdown>(html`
177+
<bl-dropdown label="Dropdown Button">
178+
<bl-dropdown-item disabled>dropdown-item</bl-dropdown-item>
179+
</bl-dropdown>
180+
`);
181+
182+
const buttonHost = <BlButton>el.shadowRoot?.querySelector("bl-button");
183+
const button = buttonHost.shadowRoot?.querySelector(".button") as HTMLElement | null;
184+
const popover = <BlPopover>el.shadowRoot?.querySelector("bl-popover");
185+
186+
button?.click();
187+
expect(el.opened).to.true;
188+
expect(popover.visible).to.true;
189+
190+
const item = el
191+
.querySelector("bl-dropdown-item")
192+
?.shadowRoot?.querySelector("bl-button") as HTMLElement | null;
193+
194+
item?.click();
195+
196+
setTimeout(() => {
197+
expect(el.opened).to.true;
198+
expect(popover.visible).to.true;
199+
});
200+
});
201+
170202
describe("keyboard navigation", () => {
171203
it("should focus next action with down arrow key", async () => {
172204
//when

src/components/dropdown/item/bl-dropdown-item.stories.mdx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { html } from 'lit';
2-
import { ifDefined } from 'lit/directives/if-defined.js';
31
import {
4-
Meta,
5-
Canvas,
62
ArgsTable,
3+
Canvas,
4+
Meta,
75
Story,
86
} from '@storybook/addon-docs';
7+
import { html } from 'lit';
8+
import { ifDefined } from 'lit/directives/if-defined.js';
99

1010
<Meta
1111
title="Components/Dropdown Button/Dropdown Item"
@@ -25,6 +25,7 @@ Dropdown Item component is a component should be used inside a bl-dropdown or bl
2525
export const Template = (args) => html`
2626
<bl-dropdown-item
2727
icon='${ifDefined(args.icon)}'
28+
?disabled=${args.disabled}
2829
>Dropdown Item</bl-dropdown-item>
2930
`
3031

@@ -43,5 +44,13 @@ If you want to have an icon for your actions, you can use the `icon` attribute.
4344
</Story>
4445
</Canvas>
4546

47+
## Disabled
48+
You can disable the item by setting the `disabled` attribute.
49+
<Canvas>
50+
<Story name="Disabled" args={{ disabled: true }}>
51+
{Template.bind({})}
52+
</Story>
53+
</Canvas>
54+
4655

4756
<ArgsTable of="bl-dropdown-item" />

src/components/dropdown/item/bl-dropdown-item.test.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import { assert, expect, fixture, html, oneEvent } from "@open-wc/testing";
12
import BlDropdownItem from "./bl-dropdown-item";
2-
import { assert, fixture, html, oneEvent, expect } from "@open-wc/testing";
33

44
import type typeOfBlDropdownItem from "./bl-dropdown-item";
55

@@ -55,7 +55,12 @@ describe("bl-dropdown-item", () => {
5555
);
5656
const button = el.shadowRoot?.querySelector("bl-button");
5757

58-
setTimeout(() => button?.click());
58+
setTimeout(() => button?.dispatchEvent(
59+
new CustomEvent("bl-click", {
60+
bubbles: true,
61+
composed: true,
62+
})
63+
));
5964
const event = await oneEvent(el, "bl-dropdown-item-click");
6065

6166
expect(el).to.exist;

src/components/dropdown/item/bl-dropdown-item.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { LitElement, html, CSSResultGroup, TemplateResult } from "lit";
1+
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
22
import { customElement, property, query } from "lit/decorators.js";
33
import { ifDefined } from "lit/directives/if-defined.js";
44
import { event, EventDispatcher } from "../../../utilities/event";
@@ -32,6 +32,12 @@ export default class BlDropdownItem extends LitElement {
3232
@property({ type: String })
3333
icon?: BaklavaIcon;
3434

35+
/**
36+
* Sets item as disabled
37+
*/
38+
@property({ type: Boolean, reflect: true })
39+
disabled = false;
40+
3541
@event("bl-dropdown-item-click") private onClick: EventDispatcher<string>;
3642

3743
private _handleClick() {
@@ -78,7 +84,8 @@ export default class BlDropdownItem extends LitElement {
7884
kind="neutral"
7985
icon="${ifDefined(this.icon)}"
8086
role="menuitem"
81-
@click="${this._handleClick}"
87+
?disabled="${this.disabled}"
88+
@bl-click="${this._handleClick}"
8289
><slot></slot>
8390
</bl-button>`;
8491
}

src/components/split-button/bl-split-button.test.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
import BlSplitButton from "./bl-split-button";
21
import {
3-
assert,
4-
fixture,
5-
html,
6-
oneEvent,
7-
expect,
8-
elementUpdated,
9-
waitUntil,
10-
} from "@open-wc/testing";
11-
import type typeOfBlSplitButton from "./bl-split-button";
2+
assert,
3+
elementUpdated,
4+
expect,
5+
fixture,
6+
html,
7+
oneEvent,
8+
waitUntil,
9+
} from "@open-wc/testing";
1210
import { sendKeys } from "@web/test-runner-commands";
13-
import BlPopover from "../popover/bl-popover";
1411
import BlButton from "../button/bl-button";
1512
import "../popover/bl-popover";
13+
import BlPopover from "../popover/bl-popover";
14+
import type typeOfBlSplitButton from "./bl-split-button";
15+
import BlSplitButton from "./bl-split-button";
1616

1717
describe("bl-split-button", () => {
1818
it("is defined", () => {
@@ -143,7 +143,12 @@ describe("bl-split-button", () => {
143143
.querySelector("bl-dropdown-item")
144144
?.shadowRoot?.querySelector("bl-button") as HTMLElement | null;
145145

146-
item?.click();
146+
item?.dispatchEvent(
147+
new CustomEvent("bl-click", {
148+
bubbles: true,
149+
composed: true,
150+
})
151+
);
147152

148153
setTimeout(() => {
149154
expect(el.opened).to.false;

0 commit comments

Comments
 (0)