Skip to content

Commit ac22cf8

Browse files
committed
feat: Drawer
1 parent 02a8daf commit ac22cf8

File tree

5 files changed

+256
-0
lines changed

5 files changed

+256
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { ScoutDrawer } from "@scouterna/ui-react";
2+
import preview from "#.storybook/preview";
3+
4+
const meta = preview.meta({
5+
title: "Containers/Drawer",
6+
component: ScoutDrawer,
7+
parameters: {
8+
layout: "centered",
9+
},
10+
});
11+
12+
export default meta;
13+
14+
export const BasicExample = meta.story({
15+
args: {
16+
open: true,
17+
title: "Drawer Title",
18+
backButton: true,
19+
closeButton: true,
20+
},
21+
render: (args) => (
22+
<div>
23+
<p>some content within the page</p>
24+
<ScoutDrawer {...args}>
25+
<p>Content inside the drawer</p>
26+
</ScoutDrawer>
27+
</div>
28+
),
29+
});
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
.drawer--container-desktop {
2+
position: absolute;
3+
top: 0;
4+
bottom: 0;
5+
right: 0;
6+
height: 100%;
7+
max-width: 90%;
8+
width: 400px;
9+
transition: 0.3s;
10+
transition-timing-function: ease-out;
11+
z-index: 1;
12+
background-color: #fefefe;
13+
box-shadow: 0 0 20px 3px var(--color-gray-200);
14+
border-top-left-radius: var(--spacing-5);
15+
border-bottom-left-radius: var(--spacing-5);
16+
overflow: hidden;
17+
}
18+
19+
.open {
20+
transform: translateX(0);
21+
}
22+
.closed {
23+
transform: translateX(100%);
24+
}
25+
26+
.backdrop {
27+
position: absolute;
28+
top: 0;
29+
bottom: 0;
30+
left: 0;
31+
right: 0;
32+
transition: opacity 0.2s;
33+
}
34+
35+
.backdrop-hidden {
36+
opacity: 0;
37+
}
38+
39+
.backdrop-visible {
40+
opacity: 0.6;
41+
background-color: var(--color-gray-200);
42+
}
43+
44+
/**
45+
* Header styles
46+
*/
47+
.header {
48+
display: flex;
49+
position: relative;
50+
width: 100%;
51+
height: var(--spacing-20);
52+
flex-direction: row;
53+
justify-content: center;
54+
align-items: center;
55+
}
56+
57+
.title {
58+
font: var(--type-body-lg);
59+
font-weight: 600;
60+
color: var(--color-text-base);
61+
}
62+
63+
button {
64+
z-index: 2;
65+
pointer-events: all;
66+
cursor: pointer;
67+
background: none;
68+
box-shadow: none;
69+
position: absolute;
70+
border: none;
71+
/*top: calc(50% - 24px);*/
72+
width: 24px;
73+
height: 24px;
74+
padding: 24px;
75+
display: flex;
76+
align-items: center;
77+
justify-content: center;
78+
}
79+
80+
.close-button {
81+
right: 10px;
82+
}
83+
.back-button {
84+
left: 10px;
85+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import {
2+
Component,
3+
type ComponentInterface,
4+
Event,
5+
type EventEmitter,
6+
h,
7+
Prop,
8+
State,
9+
} from "@stencil/core";
10+
import { isMobile } from "../../utils/utils";
11+
12+
const backIcon =
13+
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-arrow-left"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 12l14 0" /><path d="M5 12l6 6" /><path d="M5 12l6 -6" /></svg>';
14+
const closeIcon =
15+
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-x"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M18 6l-12 12" /><path d="M6 6l12 12" /></svg>';
16+
17+
@Component({
18+
tag: "scout-drawer",
19+
styleUrl: "drawer.css",
20+
shadow: {
21+
delegatesFocus: true,
22+
},
23+
})
24+
export class ScoutDrawer implements ComponentInterface {
25+
/**
26+
* Open/closestate of the drawer.
27+
*/
28+
@Prop() open: boolean = false;
29+
/**
30+
* Open/closestate of the drawer.
31+
*/
32+
@Prop() title: string = "";
33+
/**
34+
* Render back button.
35+
*/
36+
@Prop() backButton: boolean = false;
37+
/**
38+
* Render close button.
39+
*/
40+
@Prop() closeButton: boolean = false;
41+
/**
42+
* Backdrop for the drawer. Will also make it clickable to close the drawer.
43+
*/
44+
@Prop() backdrop: boolean = false;
45+
46+
@State() openState: "opening" | "closing" | "open" | "close" = "close";
47+
48+
/**
49+
* Fired when clicking backButton (<-)
50+
*/
51+
@Event() backButtonClicked: EventEmitter<void>;
52+
/**
53+
* Fired when clicking backButton (X)
54+
*/
55+
@Event() exitButtonClicked: EventEmitter<void>;
56+
57+
onBackButtonClick() {
58+
this.backButtonClicked.emit();
59+
}
60+
onExitButtonClick() {
61+
this.exitButtonClicked.emit();
62+
}
63+
64+
render() {
65+
const shouldRenderHeader =
66+
this.title || this.backButton || this.closeButton;
67+
// const animateDrawer = (direction: "open" | "close") => {};
68+
return (
69+
<div>
70+
{this.backdrop && (
71+
// biome-ignore lint/a11y/noStaticElementInteractions: <closable backdrop>
72+
<div
73+
onKeyDown={() => {}}
74+
onChange={() => this.onExitButtonClick()}
75+
class={`backdrop ${this.open ? "backdrop-visible" : "backdrop-hidden"}`}
76+
></div>
77+
)}
78+
<div
79+
onAnimationStart={() => {}}
80+
onAnimationEnd={() => {}}
81+
class={`drawer--container-${isMobile() ? "desktop" : "desktop"} ${this.open ? "open" : "closed"}`}
82+
>
83+
{shouldRenderHeader && (
84+
<div class="header">
85+
{this.backButton && (
86+
// biome-ignore lint/a11y/useButtonType: <not needed>
87+
<button
88+
class="back-button"
89+
onClick={() => this.onBackButtonClick()}
90+
>
91+
<span class="icon" innerHTML={backIcon}></span>
92+
</button>
93+
)}
94+
{this.closeButton && (
95+
// biome-ignore lint/a11y/useButtonType: <not needed>
96+
<button
97+
class="close-button"
98+
onClick={() => this.onExitButtonClick()}
99+
>
100+
<span class="icon" innerHTML={closeIcon} />
101+
</button>
102+
)}
103+
{this.title && <h3 class="title">{this.title}</h3>}
104+
</div>
105+
)}
106+
<slot />
107+
</div>
108+
</div>
109+
);
110+
}
111+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# scout-drawer
2+
3+
<!-- Auto Generated Below -->
4+
5+
6+
## Properties
7+
8+
| Property | Attribute | Description | Type | Default |
9+
| ------------- | -------------- | ------------------------------------------------------------------------- | --------- | ------- |
10+
| `backButton` | `back-button` | Render back button. | `boolean` | `false` |
11+
| `backdrop` | `backdrop` | Backdrop for the drawer. Will also make it clickable to close the drawer. | `boolean` | `false` |
12+
| `closeButton` | `close-button` | Render close button. | `boolean` | `false` |
13+
| `open` | `open` | Open/closestate of the drawer. | `boolean` | `false` |
14+
| `title` | `title` | Open/closestate of the drawer. | `string` | `""` |
15+
16+
17+
## Events
18+
19+
| Event | Description | Type |
20+
| ------------------- | ----------------------------------- | ------------------- |
21+
| `backButtonClicked` | Fired when clicking backButton (<-) | `CustomEvent<void>` |
22+
| `exitButtonClicked` | Fired when clicking backButton (X) | `CustomEvent<void>` |
23+
24+
25+
----------------------------------------------
26+
27+
*Built with [StencilJS](https://stenciljs.com/)*

packages/ui-webc/src/utils/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@ export function format(first?: string, middle?: string, last?: string): string {
33
(first || "") + (middle ? ` ${middle}` : "") + (last ? ` ${last}` : "")
44
);
55
}
6+
7+
export const isMobile = () => {
8+
return window.innerWidth <= 768;
9+
};

0 commit comments

Comments
 (0)