-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: drawer component * test(drawer): add unit tests * fix(drawer): fix linter check error * fix(drawer): refactor for new rules * feat(drawer): add stories for drawer * fix(drawer): refactor for attribute, css, stories * fix(drawer): update attribute names in stories * fix(drawer): remove unnecessary console log * fix(drawer): add gap between header buttons Co-authored-by: semih.ozker <[email protected]> Co-authored-by: Murat Çorlu <[email protected]>
- Loading branch information
1 parent
fe3eed3
commit f1d49f9
Showing
7 changed files
with
488 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,4 +6,7 @@ | |
justify-content: center; | ||
align-items: center; | ||
} | ||
.sb-main-fullscreen #root-inner { | ||
height: 600px; | ||
} | ||
</style> |
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 |
---|---|---|
|
@@ -21,6 +21,7 @@ module.exports = { | |
'pagination', | ||
'radio', | ||
'dialog', | ||
'drawer', | ||
], | ||
], | ||
}, | ||
|
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,80 @@ | ||
@keyframes slide-from-right{ | ||
0% { | ||
transform: translateX(+100%); | ||
} | ||
|
||
100% { | ||
transform: translateX(0); | ||
} | ||
} | ||
|
||
.drawer{ | ||
position: fixed; | ||
top:0; | ||
right: 0; | ||
width: 424px; | ||
height: 100%; | ||
background: var(--bl-color-primary-background); | ||
box-shadow: var(--bl-size-xs) 0 var(--bl-size-2xl) rgba(0 0 0 / 50%); | ||
animation: 0.25s slide-from-right; | ||
|
||
/* FIXME: Use z-index variable */ | ||
z-index: 999; | ||
} | ||
|
||
iframe{ | ||
height: 100%; | ||
width: 100%; | ||
border: none; | ||
} | ||
|
||
.container{ | ||
display: flex; | ||
flex-direction: column; | ||
width: 100%; | ||
height: 100%; | ||
} | ||
|
||
header { | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: baseline; | ||
gap: var(--bl-size-2xs); | ||
padding: var(--bl-size-xl) var(--bl-size-xl) 0 var(--bl-size-xl); | ||
background-color: white; | ||
} | ||
|
||
header .header-buttons { | ||
display: flex; | ||
gap:24px; | ||
margin-left: auto; | ||
} | ||
|
||
header h2 { | ||
font: var(--bl-font-title-1-medium); | ||
color: var(--bl-color-secondary); | ||
overflow: hidden; | ||
margin: 0; | ||
padding: 0; | ||
} | ||
|
||
section { | ||
padding: var(--bl-size-xl) var(--bl-size-xl) var(--bl-size-m) var(--bl-size-xl); | ||
} | ||
|
||
.content { | ||
overflow-y: scroll; | ||
} | ||
|
||
.iframe-content { | ||
height: 100%; | ||
} | ||
|
||
@media only screen and (max-width: 424px) { | ||
:host([open]) .drawer { | ||
width: calc(100vw - 24px); | ||
} | ||
} | ||
|
||
|
||
|
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,121 @@ | ||
import { html } from 'lit'; | ||
import { ifDefined } from 'lit/directives/if-defined.js'; | ||
import { Meta, Canvas, ArgsTable, Story, Preview, Source } from '@storybook/addon-docs'; | ||
|
||
<Meta | ||
title="Components/Drawer" | ||
component="bl-drawer" | ||
parameters={{ | ||
layout: 'fullscreen', | ||
chromatic: { viewports: [1000]}, | ||
}} | ||
argTypes={{ | ||
open: { | ||
control: "boolean", | ||
default: false | ||
}, | ||
caption: { | ||
control: "text", | ||
default: "", | ||
}, | ||
externalLink: { | ||
control: "text", | ||
default: "", | ||
}, | ||
embedUrl: { | ||
control: "text", | ||
default: "", | ||
}, | ||
}} | ||
/> | ||
|
||
export const openDialog = async (event,args) => { | ||
const insideCanvas = !event.target || event.target.parentNode.parentNode.getAttribute("id") === "root"; | ||
let selector= insideCanvas ? `#root #${args.id}`: `#docs-root #${args.id}`; | ||
const drawer = document.querySelector(selector); | ||
drawer.open = true; | ||
await new Promise(resolve => setTimeout(resolve,1000)); | ||
} | ||
|
||
export const DummyContent = () => html` | ||
<div style="font: var(--bl-font-body-text-2)"> | ||
<p> | ||
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. | ||
</p> | ||
<p> | ||
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. | ||
</p> | ||
<p> | ||
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. | ||
</p> | ||
<p> | ||
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. | ||
</p> | ||
<p> | ||
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. | ||
</p> | ||
</div> | ||
` | ||
|
||
export const DrawerTemplate = (args) => html` | ||
<bl-drawer id=${ifDefined(args.id)} | ||
caption=${ifDefined(args.caption)} | ||
embed-url=${ifDefined(args.embedUrl)} | ||
external-link=${ifDefined(args.externalLink)}> | ||
${ifDefined(args.content)} | ||
</bl-drawer> | ||
` | ||
|
||
export const StoryTemplate = (args) => html` | ||
${DrawerTemplate(args)} | ||
<bl-button @click="${(event)=>openDialog(event,args)}">${ifDefined(args.buttonText)}</bl-button> | ||
` | ||
|
||
# Drawer | ||
|
||
A drawer presents context-specific information and/or actions without leaving the current page | ||
|
||
<bl-alert variant="warning" icon caption="Note">Inline styles in examples are only for **demo purposes**. Use regular CSS classes or tag selectors to set styles.</bl-alert> | ||
|
||
### Design Rules | ||
|
||
* Title and external link displayed on header section in drawer. Both of them are optional. | ||
* Close button always displayed on header section and drawer can be closed by clicking close button. | ||
* By default, Drawer can not close by clicking somewhere outside drawer. | ||
* Drawer appears right side on the page with full height expanded. | ||
* Title can be multiline automatically if it does not fit one line. | ||
* When drawer does not fit in its fixed size, it switches to mobile view. | ||
* There is an attribute about iframe and drawer component handle iframe rendering itself. | ||
* Only one drawer can display at the same time. When one drawer opens others will be closed. | ||
|
||
## Usage | ||
|
||
<Canvas> | ||
<Story name="Default Values" | ||
play={(event) => openDialog(event,{id:'drawer-1'})} | ||
args={{id:"drawer-1", buttonText:"default drawer", content:DummyContent()}}> | ||
{StoryTemplate.bind({})} | ||
</Story> | ||
<Story name="With caption" | ||
play={(event)=> openDialog(event,{id:'drawer-2'})} | ||
args={{id:"drawer-2", buttonText:"with caption", caption: "Caption", content:'example content'}}> | ||
{StoryTemplate.bind({})} | ||
</Story> | ||
<Story name="With long caption" | ||
play={(event) => openDialog(event,{id:'drawer-3'})} | ||
args={{id:"drawer-3", buttonText:"with long caption", caption: "This drawer has a long caption and automatically handle it", content:'example content'}}> | ||
{StoryTemplate.bind({})} | ||
</Story> | ||
<Story name="With caption and externalLink" | ||
play={(event) => openDialog(event,{id:'drawer-4'})} | ||
args={{id:"drawer-4", buttonText:"with caption and external", caption: "Caption", externalLink:"some-url", content:'example content'}}> | ||
{StoryTemplate.bind({})} | ||
</Story> | ||
<Story name="With caption and embedUrl" | ||
play={(event) => openDialog(event,{id:'drawer-5'})} | ||
args={{id:"drawer-5", buttonText:"with caption, embedUrl", caption: "Caption", embedUrl:"some-url"}}> | ||
{StoryTemplate.bind({})} | ||
</Story> | ||
</Canvas> | ||
|
||
<ArgsTable of="bl-drawer" /> |
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,144 @@ | ||
import {assert, elementUpdated, expect, fixture, html, oneEvent} from '@open-wc/testing'; | ||
import BlDrawer from "./bl-drawer"; | ||
import type typeOfBlDrawer from './bl-drawer'; | ||
|
||
describe('bl-drawer',() => { | ||
it('is defined', () => { | ||
const el = document.createElement('bl-drawer'); | ||
assert.instanceOf(el, BlDrawer); | ||
}); | ||
|
||
describe('render tests',()=>{ | ||
it('should render drawer component with default values', async ()=>{ | ||
const el = await fixture<typeOfBlDrawer>(html`<bl-drawer open></bl-drawer>`); | ||
assert.shadowDom.equal( | ||
el, | ||
` | ||
<div class="drawer"> | ||
<div class="container"> | ||
<header> | ||
<div class="header-buttons"> | ||
<bl-button | ||
icon="close" | ||
variant="tertiary" | ||
size="small" | ||
kind="neutral" | ||
></bl-button> | ||
</div> | ||
</header> | ||
<section class="content"> | ||
<slot></slot> | ||
</section> | ||
</div> | ||
</div> | ||
` | ||
); | ||
}); | ||
it('should render the caption, externalLink and content if provided', async ()=>{ | ||
const el = await fixture<typeOfBlDrawer>(html`<bl-drawer caption="My Caption" external-link="some-url" open> | ||
<div>example content</div> | ||
</bl-drawer>`); | ||
|
||
assert.shadowDom.equal( | ||
el, | ||
` | ||
<div class="drawer"> | ||
<div class="container"> | ||
<header> | ||
<h2 id="drawer-caption"> | ||
My Caption | ||
</h2> | ||
<div class="header-buttons"> | ||
<bl-button | ||
href="some-url" | ||
icon="external_link" | ||
variant="tertiary" | ||
size="small" | ||
target="_blank" | ||
kind="neutral" | ||
></bl-button> | ||
<bl-button | ||
icon="close" | ||
variant="tertiary" | ||
size="small" | ||
kind="neutral" | ||
></bl-button> | ||
</div> | ||
</header> | ||
<section class="content"> | ||
<slot></slot> | ||
</section> | ||
</div> | ||
</div> | ||
` | ||
); | ||
}); | ||
|
||
it('should render the caption, embedUrl if provided', async ()=>{ | ||
const el = await fixture<typeOfBlDrawer>(html`<bl-drawer caption="My Caption" embed-url="some-url" open><div>example content</div></bl-drawer>`); | ||
|
||
const caption = el.shadowRoot?.querySelector('#drawer-caption') as HTMLElement; | ||
const iframeEl = el.shadowRoot?.querySelector('iframe') as HTMLElement; | ||
|
||
expect(iframeEl).to.exist; | ||
expect(iframeEl.attributes.getNamedItem('src')?.value).to.contain("some-url"); | ||
|
||
expect(caption).to.exist; | ||
expect(caption.innerText).to.equal('My Caption'); | ||
}); | ||
|
||
it('should open the drawer when change open attribute as true', async () => { | ||
const el = await fixture<typeOfBlDrawer>(html`<bl-drawer caption="Drawer Title"> | ||
<div>Drawer Content</div> | ||
</bl-drawer>`); | ||
|
||
expect(el.open).to.equal(false); | ||
|
||
el.open = true; | ||
await elementUpdated(el); | ||
|
||
setTimeout(() => { | ||
expect(el.open).to.equal(true); | ||
}); | ||
}); | ||
it('should close the drawer when change click close button', async () => { | ||
const el = await fixture<typeOfBlDrawer>(html`<bl-drawer open caption="Drawer Title"> | ||
<div>Drawer Content</div> | ||
</bl-drawer>`); | ||
|
||
const closeBtn = el?.shadowRoot?.querySelector('bl-button'); | ||
|
||
expect(closeBtn).to.exist; | ||
expect(el.open).to.equal(true); | ||
closeBtn?.click(); | ||
|
||
setTimeout(()=>{ | ||
expect(el.open).to.equal(false); | ||
expect(el.offsetWidth).to.equal(0); | ||
}); | ||
}); | ||
}); | ||
describe('event tests',()=>{ | ||
it('should fire bl-drawer-open when dialog opens',async ()=>{ | ||
const el = await fixture<typeOfBlDrawer>(html`<bl-drawer caption="My Drawer"></bl-drawer>`) | ||
|
||
setTimeout(async () => { | ||
const openEvent = await oneEvent(el,'bl-drawer-open'); | ||
expect(openEvent).to.exist; | ||
expect(openEvent.detail.isOpen).to.equal(true); | ||
}); | ||
}); | ||
it('should fire bl-drawer-close when dialog closes',async ()=>{ | ||
const el = await fixture<typeOfBlDrawer>(html`<bl-drawer open caption="My Drawer"></bl-drawer>`) | ||
|
||
const closeBtn = el?.shadowRoot?.querySelector('bl-button'); | ||
|
||
setTimeout(async () => { | ||
closeBtn?.click(); | ||
const openEvent = await oneEvent(el,'bl-drawer-close'); | ||
expect(openEvent).to.exist; | ||
expect(openEvent.detail.isOpen).to.equal(false); | ||
}); | ||
}); | ||
}) | ||
}); |
Oops, something went wrong.