11import {
22 Component ,
33 type ComponentInterface ,
4+ Element ,
45 Event ,
56 type EventEmitter ,
67 h ,
78 Prop ,
89 State ,
10+ Watch ,
911} from "@stencil/core" ;
10- import { isMobile } from "../../utils/utils " ;
12+ import focusLock from "dom-focus-lock " ;
1113
1214const backIcon =
1315 '<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 =
16+ const exitIcon =
1517 '<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>' ;
1618
1719@Component ( {
@@ -22,35 +24,57 @@ const closeIcon =
2224 } ,
2325} )
2426export class ScoutDrawer implements ComponentInterface {
27+ @Element ( ) rootElement : HTMLElement ;
2528 /**
2629 * Open/closestate of the drawer.
2730 */
2831 @Prop ( ) open : boolean = false ;
2932 /**
30- * Open/closestate of the drawer.
33+ * Open/close state of the drawer.
3134 */
32- @Prop ( ) title : string = "" ;
35+ @Prop ( ) heading : string = "" ;
3336 /**
3437 * Render back button.
3538 */
36- @Prop ( ) backButton : boolean = false ;
39+ @Prop ( ) showBackButton : boolean = false ;
40+ /**
41+ * Back button label.
42+ */
43+ @Prop ( ) backButtonLabel : string = "" ;
44+ /**
45+ * Render exit button.
46+ */
47+ @Prop ( ) showExitButton : boolean = false ;
48+ /**
49+ * Back button label.
50+ */
51+ @Prop ( ) exitButtonLabel : string = "" ;
3752 /**
38- * Render close button .
53+ * Disable backdrop for the drawer. Will also make it clickable to close the drawer .
3954 */
40- @Prop ( ) closeButton : boolean = false ;
55+ @Prop ( ) disableBackdrop : boolean = false ;
56+
4157 /**
42- * Backdrop for the drawer. Will also make it clickable to close the drawer .
58+ * Disable drawer content padding. Use only if you have specific use case and you need to use full width .
4359 */
44- @Prop ( ) backdrop : boolean = false ;
60+ @Prop ( ) disableContentPadding : boolean = false ;
4561
46- @State ( ) openState : "opening" | "closing" | "open" | "close" = "close" ;
62+ @State ( ) drawerState : "opening" | "closing" | "open" | "closed" = "closed" ;
63+ @State ( ) focusedNode : Element = null ;
4764
65+ componentWillLoad ( ) : Promise < void > | void {
66+ this . focusedNode = document . activeElement ;
67+ }
68+ disconnectedCallback ( ) : void {
69+ this . focusedNode ;
70+ }
4871 /**
4972 * Fired when clicking backButton (<-)
5073 */
5174 @Event ( ) backButtonClicked : EventEmitter < void > ;
75+
5276 /**
53- * Fired when clicking backButton (X)
77+ * Fired when clicking backButton (X). Also sent when clicking the backdrop.
5478 */
5579 @Event ( ) exitButtonClicked : EventEmitter < void > ;
5680
@@ -61,49 +85,82 @@ export class ScoutDrawer implements ComponentInterface {
6185 this . exitButtonClicked . emit ( ) ;
6286 }
6387
88+ @Watch ( "open" )
89+ setDialogOpenState ( open : boolean ) {
90+ const drawer = this . rootElement . shadowRoot . querySelector (
91+ ".drawer--container" ,
92+ ) as HTMLElement ;
93+ if ( open ) {
94+ this . drawerState = "opening" ;
95+ focusLock . on ( drawer ) ;
96+ } else {
97+ focusLock . off ( drawer ) ;
98+ this . drawerState = "closing" ;
99+ }
100+ }
101+
64102 render ( ) {
65103 const shouldRenderHeader =
66- this . title || this . backButton || this . closeButton ;
67- // const animateDrawer = (direction: "open" | "close") => {};
104+ this . heading || this . showBackButton || this . showExitButton ;
105+
106+ const getDrawerStateClass = ( state : string ) => {
107+ switch ( state ) {
108+ case "opening" :
109+ case "open" :
110+ return "open" ;
111+ case "closing" :
112+ return "close" ;
113+ }
114+ } ;
115+
68116 return (
69- < div >
70- { this . backdrop && (
117+ < div class = "drawer" >
118+ { ! this . disableBackdrop && (
71119 // biome-ignore lint/a11y/noStaticElementInteractions: <closable backdrop>
120+ // biome-ignore lint/a11y/useKeyWithClickEvents: <closable backdrop>
72121 < div
73- onKeyDown = { ( ) => { } }
74- onChange = { ( ) => this . onExitButtonClick ( ) }
75- class = { `backdrop ${ this . open ? "backdrop-visible" : "backdrop-hidden" } ` }
122+ onClick = { ( ) => {
123+ this . onExitButtonClick ( ) ;
124+ } }
125+ class = { `backdrop ${ this . drawerState !== "closed" ? "backdrop-visible" : "backdrop-hidden" } ` }
76126 > </ div >
77127 ) }
78128 < div
79- onAnimationStart = { ( ) => { } }
80- onAnimationEnd = { ( ) => { } }
81- class = { `drawer--container-${ isMobile ( ) ? "desktop" : "desktop" } ${ this . open ? "open" : "closed" } ` }
129+ class = { `drawer--container ${ getDrawerStateClass ( this . drawerState ) } ` }
130+ onAnimationEnd = { ( ) => {
131+ this . drawerState = this . open ? "open" : "closed" ;
132+ } }
82133 >
83134 { shouldRenderHeader && (
84- < div class = "header" >
85- { this . backButton && (
135+ < div class = "header--wrapper " >
136+ { this . showBackButton && (
86137 // biome-ignore lint/a11y/useButtonType: <not needed>
87138 < button
88139 class = "back-button"
89140 onClick = { ( ) => this . onBackButtonClick ( ) }
90141 >
91- < span class = "icon" innerHTML = { backIcon } > </ span >
142+ < span class = "icon" innerHTML = { backIcon } >
143+ < span class = "visually-hidden" > { this . backButtonLabel } </ span >
144+ </ span >
92145 </ button >
93146 ) }
94- { this . closeButton && (
147+ { this . showExitButton && (
95148 // biome-ignore lint/a11y/useButtonType: <not needed>
96149 < button
97- class = "close -button"
150+ class = "exit -button"
98151 onClick = { ( ) => this . onExitButtonClick ( ) }
99152 >
100- < span class = "icon" innerHTML = { closeIcon } />
153+ < span class = "icon" innerHTML = { exitIcon } >
154+ < span class = "visually-hidden" > { this . exitButtonLabel } </ span >
155+ </ span >
101156 </ button >
102157 ) }
103- { this . title && < h3 class = "title" > { this . title } </ h3 > }
158+ { this . heading && < h3 class = "title" > { this . heading } </ h3 > }
104159 </ div >
105160 ) }
106- < slot />
161+ < div class = { ! this . disableContentPadding && `content--wrapper` } >
162+ < slot />
163+ </ div >
107164 </ div >
108165 </ div >
109166 ) ;
0 commit comments