-
Notifications
You must be signed in to change notification settings - Fork 117
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Closes #739 --------- Co-authored-by: Levent Anil Ozen <[email protected]> Co-authored-by: Enes Yıldırım <[email protected]> Co-authored-by: Erbil <[email protected]>
- Loading branch information
1 parent
af8bef0
commit c21191d
Showing
10 changed files
with
676 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
:host { | ||
display: block; | ||
} | ||
|
||
.accordion { | ||
--border: 1px solid var(--bl-color-neutral-lighter); | ||
--default-radius: var(--bl-size-2xs); | ||
--radius-top-left: var(--bl-accordion-radius-top-left, var(--default-radius)); | ||
--radius-top-right: var(--bl-accordion-radius-top-right, var(--default-radius)); | ||
--radius-bottom-right: var(--bl-accordion-radius-bottom-right, var(--default-radius)); | ||
--radius-bottom-left: var(--bl-accordion-radius-bottom-left, var(--default-radius)); | ||
|
||
width: 100%; | ||
} | ||
|
||
.summary { | ||
list-style: none; | ||
user-select: none; | ||
cursor: pointer; | ||
font: var(--bl-font-title-3-medium); | ||
display: flex; | ||
align-items: center; | ||
justify-content: space-between; | ||
gap: var(--bl-size-2xs); | ||
padding: var(--bl-size-m); | ||
background: var(--bl-color-neutral-full); | ||
color: var(--bl-color-neutral-darker); | ||
border: var(--border); | ||
border-bottom: var(--bl-accordion-border-bottom, var(--border)); | ||
border-radius: var(--radius-top-left) var(--radius-top-right) var(--radius-bottom-right) | ||
var(--radius-bottom-left); | ||
transition: background-color 200ms; | ||
} | ||
|
||
.summary::-webkit-details-marker { | ||
display: none; | ||
} | ||
|
||
.summary:hover { | ||
background: var(--bl-color-neutral-lightest); | ||
} | ||
|
||
.summary:focus-visible { | ||
outline: 2px solid var(--bl-color-primary); | ||
outline-offset: -1px; | ||
} | ||
|
||
.indicator { | ||
transition: transform 200ms; | ||
} | ||
|
||
.accordion[open] .indicator { | ||
transform: rotate(180deg); | ||
} | ||
|
||
.accordion[open] .summary { | ||
border-bottom: 0; | ||
border-bottom-left-radius: 0; | ||
border-bottom-right-radius: 0; | ||
} | ||
|
||
.caption { | ||
flex: 1; | ||
} | ||
|
||
.accordion-content { | ||
padding: var(--bl-size-m); | ||
background: var(--bl-color-neutral-full); | ||
border: var(--border); | ||
border-top: 0; | ||
border-bottom: var(--bl-accordion-border-bottom, var(--border)); | ||
border-bottom-left-radius: var(--radius-bottom-left); | ||
border-bottom-right-radius: var(--radius-bottom-right); | ||
font: var(--bl-font-body-text-2-regular); | ||
} | ||
|
||
.disabled .summary { | ||
cursor: not-allowed; | ||
background: var(--bl-color-neutral-lightest); | ||
color: var(--bl-color-neutral-light); | ||
} |
92 changes: 92 additions & 0 deletions
92
src/components/accordion-group/accordion/bl-accordion.stories.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { ArgsTable, Canvas, Meta, Story } from "@storybook/addon-docs"; | ||
import { html } from "lit"; | ||
import { ifDefined } from 'lit/directives/if-defined.js'; | ||
import { unsafeHTML } from 'lit/directives/unsafe-html.js'; | ||
|
||
<Meta | ||
title="Components/Accordion/Accordion" | ||
component="bl-accordion" | ||
argTypes={{ | ||
icon: { control: "text" }, | ||
disabled: { control: "boolean" }, | ||
caption: { | ||
control: 'text' | ||
}, | ||
}} | ||
/> | ||
|
||
export const AccordionTemplate = (args) => html` | ||
<bl-accordion icon="${ifDefined(args.icon)}" caption="${ifDefined(args.caption)}" | ||
disabled="${ifDefined(args.disabled)}">${unsafeHTML(args.content)} | ||
</bl-accordion>`; | ||
|
||
# Accordion | ||
|
||
<bl-badge icon="document">[ADR](https://github.com/Trendyol/baklava/issues/739)</bl-badge> | ||
<bl-badge | ||
icon="puzzle">[Figma](https://www.figma.com/file/RrcLH0mWpIUy4vwuTlDeKN/Baklava-Design-Guide?type=design&node-id=15548%3A20910)</bl-badge> | ||
|
||
Accordion is a component that allows the user to show and hide sections of related content on a page. | ||
|
||
### Usage | ||
|
||
|
||
* The accordion component includes a free content area. | ||
* The caption can be set either via **attribute** or **slot**. | ||
* An icon can be added to the beginning of the caption. | ||
* Accordion can be disabled. | ||
* The accordion group component combines accordions and only allows one accordion to be open by default | ||
|
||
<Canvas> | ||
<Story name="Basic Usage" args={{ | ||
caption: "Toggle Me", | ||
content: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci architecto debitis earum fuga iusto modi molestias necessitatibus provident quam! Nisi!" | ||
}}> | ||
{AccordionTemplate.bind({})} | ||
</Story> | ||
</Canvas> | ||
|
||
|
||
## With Icon | ||
|
||
Add icon to beginning of caption with `icon` attribute. | ||
|
||
<Canvas> | ||
<Story name="With Icon" args={{ | ||
caption: "Toggle Me", | ||
content: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci architecto debitis earum fuga iusto modi molestias necessitatibus provident quam! Nisi!", | ||
icon: "info" | ||
}}> | ||
{AccordionTemplate.bind({})} | ||
</Story> | ||
</Canvas> | ||
|
||
## Disabled | ||
|
||
Use the `disable` attribute to prevent the details from expanding. | ||
|
||
<Canvas> | ||
<Story name="Disabled" args={{ | ||
caption: "Toggle Me", | ||
content: "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci architecto debitis earum fuga iusto modi molestias necessitatibus provident quam! Nisi!", | ||
disabled: true | ||
}}> | ||
{AccordionTemplate.bind({})} | ||
</Story> | ||
</Canvas> | ||
|
||
## Reference | ||
|
||
<ArgsTable of="bl-accordion" /> | ||
|
||
## Public Functions | ||
|
||
* `expand()`: Can be used to expand accordion. | ||
* `collapse()`: Can be used to collapse accordion. | ||
|
||
Example usage; | ||
|
||
```js | ||
document.querySelector('bl-accordion').expand(); | ||
document.querySelector('bl-accordion').collapse(); | ||
``` |
184 changes: 184 additions & 0 deletions
184
src/components/accordion-group/accordion/bl-accordion.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
import { assert, fixture, html, expect, waitUntil, aTimeout } from "@open-wc/testing"; | ||
import { spy } from "sinon"; | ||
import BlAccordion from "./bl-accordion"; | ||
|
||
describe("bl-accordion", () => { | ||
it("is defined", () => { | ||
const el = document.createElement("bl-accordion"); | ||
|
||
assert.instanceOf(el, BlAccordion); | ||
}); | ||
|
||
it("renders with default values", async () => { | ||
const el = await fixture<BlAccordion>(html` | ||
<bl-accordion></bl-accordion>`); | ||
|
||
assert.shadowDom.equal( | ||
el, | ||
`<details class="accordion"> | ||
<summary aria-controls="content" aria-disabled="false" aria-expanded="false" class="summary" tabindex="0"> | ||
<slot name="caption"> | ||
<span class="caption"> | ||
</span> | ||
</slot> | ||
<bl-icon | ||
class="indicator" | ||
name="arrow_down" | ||
> | ||
</bl-icon> | ||
</summary> | ||
<div aria-labelledby="header" class="accordion-content" id="content" role="region"> | ||
<slot> | ||
</slot> | ||
</div> | ||
</details>` | ||
); | ||
}); | ||
|
||
it("should set icon", async () => { | ||
const el = await fixture<BlAccordion>(html`<bl-accordion icon="eye_on"></bl-accordion>`); | ||
|
||
await el.updateComplete; | ||
const iconEl = el.shadowRoot!.querySelector(".icon")!; | ||
|
||
expect(iconEl.getAttribute("name")).to.eq("eye_on"); | ||
}); | ||
|
||
it("should set info icon when icon is boolean", async () => { | ||
const el = await fixture<BlAccordion>(html`<bl-accordion icon></bl-accordion>`); | ||
|
||
const iconEl = el.shadowRoot!.querySelector(".icon")!; | ||
|
||
expect(iconEl.getAttribute("name")).to.eq("info"); | ||
}); | ||
|
||
it("should set caption", async () => { | ||
const captionText = "Best caption"; | ||
const el = await fixture<BlAccordion>(html`<bl-accordion caption="${captionText}"></bl-accordion>`); | ||
const captionEl = el.shadowRoot?.querySelector<HTMLSpanElement>(".caption"); | ||
|
||
expect(captionEl).to.exist; | ||
expect(captionEl!.innerText).to.eq(captionText); | ||
}); | ||
|
||
it("should set caption via slot", async () => { | ||
const captionText = "Best caption"; | ||
const el = await fixture<BlAccordion>(html`<bl-accordion><div slot="caption">${captionText}</div></bl-accordion>`); | ||
const captionSlot = el.shadowRoot!.querySelector<HTMLSlotElement>('slot[name="caption"]'); | ||
const captionSlotContent = captionSlot!.assignedNodes()[0] as HTMLDivElement; | ||
|
||
expect(captionSlotContent.innerText).to.eq(captionText); | ||
}); | ||
|
||
it("should be visible with the open attribute", async () => { | ||
const el = await fixture<BlAccordion>(html` | ||
<bl-accordion open> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et | ||
dolore magna aliqua. Molestie at elementum eu facilisis. Morbi quis commodo odio aenean sed adipiscing diam | ||
donec. | ||
</bl-accordion>`); | ||
|
||
const body = el.shadowRoot!.querySelector(".accordion-content")!; | ||
|
||
expect(body.clientHeight).greaterThan(0); | ||
}); | ||
|
||
it("should not be visible without the open attribute", async () => { | ||
const el = await fixture<BlAccordion>(html` | ||
<bl-accordion> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et | ||
dolore magna aliqua. Molestie at elementum eu facilisis. Morbi quis commodo odio aenean sed adipiscing diam | ||
donec. | ||
</bl-accordion>`); | ||
|
||
const body = el.shadowRoot!.querySelector(".accordion-content")!; | ||
|
||
expect(body.clientHeight).to.eq(0); | ||
}); | ||
|
||
it("should emit bl-toggle when click on collapsed accordion", async () => { | ||
const el = await fixture<BlAccordion>(html` | ||
<bl-accordion> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et | ||
dolore magna aliqua. Molestie at elementum eu facilisis. Morbi quis commodo odio aenean sed adipiscing diam | ||
donec. | ||
</bl-accordion>`); | ||
|
||
const toggleHandler = spy(); | ||
|
||
el.addEventListener("bl-toggle", (e) => toggleHandler((e as CustomEvent).detail)); | ||
|
||
const summary = el.shadowRoot!.querySelector("summary")!; | ||
|
||
summary.click(); | ||
|
||
await waitUntil(() => toggleHandler.calledOnce); | ||
|
||
expect(toggleHandler).to.have.been.calledWith(true); | ||
}); | ||
|
||
it("should emit bl-toggle when click on expanded accordion", async () => { | ||
const el = await fixture<BlAccordion>(html` | ||
<bl-accordion open> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et | ||
dolore magna aliqua. Molestie at elementum eu facilisis. Morbi quis commodo odio aenean sed adipiscing diam | ||
donec. | ||
</bl-accordion>`); | ||
|
||
const toggleHandler = spy(); | ||
|
||
el.addEventListener("bl-toggle", (e) => toggleHandler((e as CustomEvent).detail)); | ||
|
||
const summary = el.shadowRoot!.querySelector("summary")!; | ||
|
||
summary.click(); | ||
|
||
await waitUntil(() => toggleHandler.calledOnce); | ||
|
||
expect(toggleHandler).to.have.been.calledWith(false); | ||
}); | ||
|
||
it("should not open when disabled", async () => { | ||
const el = await fixture<BlAccordion>(html` | ||
<bl-accordion disabled> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et | ||
dolore magna aliqua. Molestie at elementum eu facilisis. Morbi quis commodo odio aenean sed adipiscing diam | ||
donec. | ||
</bl-accordion>`); | ||
|
||
const summary = el.shadowRoot!.querySelector("summary")!; | ||
|
||
summary.click(); | ||
|
||
expect(el.open).to.eq(false); | ||
}); | ||
|
||
it("should not change open attribute when disabled", async () => { | ||
const el = await fixture<BlAccordion>(html` | ||
<bl-accordion disabled open> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et | ||
dolore magna aliqua. Molestie at elementum eu facilisis. Morbi quis commodo odio aenean sed adipiscing diam | ||
donec. | ||
</bl-accordion>`); | ||
|
||
expect(el.open).to.eq(false); | ||
}); | ||
|
||
it("should not affect animation", async () => { | ||
const el = await fixture<BlAccordion>(html` | ||
<bl-accordion> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et | ||
dolore magna aliqua. Molestie at elementum eu facilisis. Morbi quis commodo odio aenean sed adipiscing diam | ||
donec. | ||
</bl-accordion>`); | ||
|
||
const summary = el.shadowRoot!.querySelector("summary")!; | ||
|
||
summary.click(); | ||
summary.click(); | ||
summary.click(); | ||
|
||
await aTimeout(200); | ||
expect(el.open).to.eq(true); | ||
}); | ||
}); |
Oops, something went wrong.