Skip to content

Commit

Permalink
feat(dropdown): add support for disabling dropdown items (#1018)
Browse files Browse the repository at this point in the history
Also use the appropriate custom event to ensure that the feature set
works as intended.

Closes #1017
  • Loading branch information
ogunb authored Feb 13, 2025
1 parent ea80786 commit fdd277a
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 32 deletions.
40 changes: 33 additions & 7 deletions src/components/dropdown/bl-dropdown.stories.mdx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
import { userEvent } from '@storybook/testing-library';
import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { styleMap } from 'lit/directives/style-map.js';
import { Meta, Canvas, ArgsTable, Story } from '@storybook/addon-docs';
import { userEvent } from '@storybook/testing-library';

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

export const dropdownOpener = async ({ canvasElement }) => {
const dropdown = canvasElement?.querySelector('bl-dropdown')
if(dropdown.shadowRoot) {
const button = dropdown.shadowRoot.querySelector('bl-button')
if (dropdown.shadowRoot) {
const button = dropdown.shadowRoot.querySelector("bl-button")?.shadowRoot?.querySelector("button");
await userEvent.click(button);
}
}
Expand Down Expand Up @@ -78,6 +78,22 @@ export const IconDropdownTemplate = (args) => html`<bl-dropdown
<bl-dropdown-item>Action 5</bl-dropdown-item>
</bl-dropdown>`

export const DisabledItemDropdownTemplate = (args) => html`<bl-dropdown
variant=${ifDefined(args.variant)}
kind=${ifDefined(args.kind)}
size=${ifDefined(args.size)}
label="${ifDefined(args.label)}"
?disabled=${args.disabled}
style=${ifDefined(args.styles ? styleMap(args.styles) : undefined)}
><bl-dropdown-group caption="Caption">
<bl-dropdown-item disabled>${args.content || 'Action 1'}</bl-dropdown-item>
<bl-dropdown-item>Action 2</bl-dropdown-item>
</bl-dropdown-group>
<bl-dropdown-item>Action 3</bl-dropdown-item>
<bl-dropdown-item icon="info" disabled>Action 4</bl-dropdown-item>
<bl-dropdown-item>Action 5</bl-dropdown-item>
</bl-dropdown>`

export const Template = (args) => html`
${SingleDropdownButtonTemplate({...args})}
${SingleDropdownButtonTemplate({variant: 'secondary', ...args})}
Expand Down Expand Up @@ -148,7 +164,7 @@ If dropdown button has an action with a long text that can not fit in a single l
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.

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

<Canvas columns={1}>
<Story name="Disabling Dropdown Buttons" args={{ label: 'Dropdown Button', disabled: true }} play={dropdownOpener}>
<Story name="Disabling Dropdown Buttons" args={{ label: 'Dropdown Button', disabled: true }}>
{SizesTemplate.bind({})}
</Story>
</Canvas>

Whereas Tertiary buttons keep their transparent backgrounds.

<Canvas columns={1}>
<Story name="Disabling Tertiary Dropdown Buttons" args={{ label: 'Dropdown Button', disabled: true, variant:"tertiary" }} play={dropdownOpener}>
<Story name="Disabling Tertiary Dropdown Buttons" args={{ label: 'Dropdown Button', disabled: true, variant:"tertiary" }}>
{SizesTemplate.bind({})}
</Story>
</Canvas>

## Disabling Dropdown Items

You can disable dropdown items by setting the `disabled` attribute on the `bl-dropdown-item` element.

<Canvas>
<Story name="Disabling Dropdown Items" args={{ label: 'Dropdown Button' }} play={dropdownOpener}>
{DisabledItemDropdownTemplate.bind({})}
</Story>
</Canvas>


## Reference

Expand Down
42 changes: 37 additions & 5 deletions src/components/dropdown/bl-dropdown.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import BlDropdown from "./bl-dropdown";
import {
assert,
elementUpdated,
expect,
fixture,
html,
oneEvent,
expect,
elementUpdated,
waitUntil,
} from "@open-wc/testing";
import { sendKeys } from "@web/test-runner-commands";
import BlDropdown from "./bl-dropdown";

import type typeOfBlDropdown from "./bl-dropdown";
import BlButton from "../button/bl-button";
import "../popover/bl-popover";
import BlPopover from "../popover/bl-popover";
import type typeOfBlDropdown from "./bl-dropdown";

describe("bl-dropdown", () => {
it("is defined", () => {
Expand Down Expand Up @@ -112,7 +112,12 @@ describe("bl-dropdown", () => {
.querySelector("bl-dropdown-item")
?.shadowRoot?.querySelector("bl-button") as HTMLElement | null;

item?.click();
item?.dispatchEvent(
new CustomEvent("bl-click", {
bubbles: true,
composed: true,
})
);

setTimeout(() => {
expect(el.opened).to.false;
Expand Down Expand Up @@ -167,6 +172,33 @@ describe("bl-dropdown", () => {
expect(popover.visible).to.false;
});

it("should not close dropdown when disabled item is clicked", async () => {
const el = await fixture<typeOfBlDropdown>(html`
<bl-dropdown label="Dropdown Button">
<bl-dropdown-item disabled>dropdown-item</bl-dropdown-item>
</bl-dropdown>
`);

const buttonHost = <BlButton>el.shadowRoot?.querySelector("bl-button");
const button = buttonHost.shadowRoot?.querySelector(".button") as HTMLElement | null;
const popover = <BlPopover>el.shadowRoot?.querySelector("bl-popover");

button?.click();
expect(el.opened).to.true;
expect(popover.visible).to.true;

const item = el
.querySelector("bl-dropdown-item")
?.shadowRoot?.querySelector("bl-button") as HTMLElement | null;

item?.click();

setTimeout(() => {
expect(el.opened).to.true;
expect(popover.visible).to.true;
});
});

describe("keyboard navigation", () => {
it("should focus next action with down arrow key", async () => {
//when
Expand Down
17 changes: 13 additions & 4 deletions src/components/dropdown/item/bl-dropdown-item.stories.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import {
Meta,
Canvas,
ArgsTable,
Canvas,
Meta,
Story,
} from '@storybook/addon-docs';
import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';

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

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

## Disabled
You can disable the item by setting the `disabled` attribute.
<Canvas>
<Story name="Disabled" args={{ disabled: true }}>
{Template.bind({})}
</Story>
</Canvas>


<ArgsTable of="bl-dropdown-item" />
9 changes: 7 additions & 2 deletions src/components/dropdown/item/bl-dropdown-item.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { assert, expect, fixture, html, oneEvent } from "@open-wc/testing";
import BlDropdownItem from "./bl-dropdown-item";
import { assert, fixture, html, oneEvent, expect } from "@open-wc/testing";

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

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

setTimeout(() => button?.click());
setTimeout(() => button?.dispatchEvent(
new CustomEvent("bl-click", {
bubbles: true,
composed: true,
})
));
const event = await oneEvent(el, "bl-dropdown-item-click");

expect(el).to.exist;
Expand Down
11 changes: 9 additions & 2 deletions src/components/dropdown/item/bl-dropdown-item.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LitElement, html, CSSResultGroup, TemplateResult } from "lit";
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, query } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import { event, EventDispatcher } from "../../../utilities/event";
Expand Down Expand Up @@ -32,6 +32,12 @@ export default class BlDropdownItem extends LitElement {
@property({ type: String })
icon?: BaklavaIcon;

/**
* Sets item as disabled
*/
@property({ type: Boolean, reflect: true })
disabled = false;

@event("bl-dropdown-item-click") private onClick: EventDispatcher<string>;

private _handleClick() {
Expand Down Expand Up @@ -78,7 +84,8 @@ export default class BlDropdownItem extends LitElement {
kind="neutral"
icon="${ifDefined(this.icon)}"
role="menuitem"
@click="${this._handleClick}"
?disabled="${this.disabled}"
@bl-click="${this._handleClick}"
><slot></slot>
</bl-button>`;
}
Expand Down
29 changes: 17 additions & 12 deletions src/components/split-button/bl-split-button.test.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import BlSplitButton from "./bl-split-button";
import {
assert,
fixture,
html,
oneEvent,
expect,
elementUpdated,
waitUntil,
} from "@open-wc/testing";
import type typeOfBlSplitButton from "./bl-split-button";
assert,
elementUpdated,
expect,
fixture,
html,
oneEvent,
waitUntil,
} from "@open-wc/testing";
import { sendKeys } from "@web/test-runner-commands";
import BlPopover from "../popover/bl-popover";
import BlButton from "../button/bl-button";
import "../popover/bl-popover";
import BlPopover from "../popover/bl-popover";
import type typeOfBlSplitButton from "./bl-split-button";
import BlSplitButton from "./bl-split-button";

describe("bl-split-button", () => {
it("is defined", () => {
Expand Down Expand Up @@ -143,7 +143,12 @@ describe("bl-split-button", () => {
.querySelector("bl-dropdown-item")
?.shadowRoot?.querySelector("bl-button") as HTMLElement | null;

item?.click();
item?.dispatchEvent(
new CustomEvent("bl-click", {
bubbles: true,
composed: true,
})
);

setTimeout(() => {
expect(el.opened).to.false;
Expand Down

0 comments on commit fdd277a

Please sign in to comment.