Skip to content

Commit f7b6823

Browse files
authored
Merge pull request #283 from US-CBP/feature/inline-drawer
Feature/inline drawer
2 parents dc5f99a + e2e35fb commit f7b6823

File tree

6 files changed

+595
-549
lines changed

6 files changed

+595
-549
lines changed

packages/web-components/src/components/cbp-dialog/cbp-dialog.stories.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ const Template = ({ title, content, color, open, uid, accessibilityText, actions
7777
<cbp-button
7878
type="button"
7979
color="secondary"
80-
accessibility-text="Open Drawer"
80+
variant="square"
81+
accessibility-text="Open Dialog"
8182
target-prop="open"
8283
controls=${uid}
8384
>

packages/web-components/src/components/cbp-drawer/cbp-drawer.scss

+39-23
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,36 @@
1212
[data-cbp-theme=dark] cbp-drawer:not([context=dark-inverts]):not([context=light-always]) {
1313
--cbp-drawer-color-bg: var(--cbp-color-gray-cool-70);
1414
}
15-
15+
1616

1717
cbp-drawer {
1818
all: unset;
1919
display: none;
20-
--cbp-panel-border-radius: 0;
21-
--cbp-panel-border-width: 0;
22-
// Use the panel CSS API to override the colors in dark mode for a specific drawer variant
23-
--cbp-panel-header-color-dark: var(--cbp-color-text-lighter);
24-
--cbp-panel-header-color-bg-dark: var(--cbp-color-branding-dhs-blue);
25-
--cbp-panel-header-color-bottom-border-dark: var(--cbp-color-gray-cool-50);
26-
--cbp-panel-content-color-dark: var(--cbp-color-text-lightest);
27-
--cbp-panel-content-color-bg-dark: var(--cbp-color-gray-cool-70);
28-
--cbp-panel-content-color-border-dark: var(--cbp-color-gray-cool-60);
29-
}
20+
position: relative;
3021

31-
cbp-drawer[open] {
32-
display: block;
33-
position: fixed;
34-
top: 0;
35-
right: 0;
36-
bottom: 0;
37-
left: 0;
38-
z-index: calc(var(--cbp-z-index-level-top) - 1);
39-
overflow-y: auto;
40-
background-color: rgba(0, 0, 0, 0.3); // backdrop
22+
&:not(.cbp-drawer--persistent) {
23+
--cbp-panel-border-radius: 0;
24+
--cbp-panel-border-width: 0;
25+
// Use the panel CSS API to override the colors in dark mode for a specific drawer variant
26+
--cbp-panel-header-color-dark: var(--cbp-color-text-lighter);
27+
--cbp-panel-header-color-bg-dark: var(--cbp-color-branding-dhs-blue);
28+
--cbp-panel-header-color-bottom-border-dark: var(--cbp-color-gray-cool-50);
29+
--cbp-panel-content-color-dark: var(--cbp-color-text-lightest);
30+
--cbp-panel-content-color-bg-dark: var(--cbp-color-gray-cool-70);
31+
--cbp-panel-content-color-border-dark: var(--cbp-color-gray-cool-60);
32+
}
33+
34+
&.cbp-drawer--persistent {
35+
display: block;
36+
37+
.cbp-drawer__content {
38+
height: auto;
39+
}
40+
}
4141

4242
.cbp-drawer__content {
4343
display: flex;
4444
flex-direction: column;
45-
position: fixed;
4645
top: 0;
4746
overflow-y: auto;
4847
z-index: var(--cbp-z-index-level-4);
@@ -65,6 +64,18 @@ cbp-drawer[open] {
6564
top: 1em;
6665
}
6766
}
67+
}
68+
69+
cbp-drawer[open] {
70+
display: block;
71+
position: fixed;
72+
top: 0;
73+
right: 0;
74+
bottom: 0;
75+
left: 0;
76+
z-index: calc(var(--cbp-z-index-level-top) - 1);
77+
overflow-y: auto;
78+
background-color: rgba(0, 0, 0, 0.3); // backdrop
6879

6980
&[position='left'] {
7081
.cbp-drawer__content {
@@ -87,10 +98,15 @@ cbp-drawer[open] {
8798
}
8899
}
89100
}
101+
102+
.cbp-drawer__content {
103+
position: fixed;
104+
}
90105

91106
@media (min-width: 37.5em) {
92107
.cbp-drawer__content {
93108
width: 25rem;
94109
}
95110
}
96-
}
111+
}
112+

packages/web-components/src/components/cbp-drawer/cbp-drawer.specs.mdx

+11
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ The Drawer is a container that may be hidden and revealed, sliding in from eithe
1616
* The Drawer may slide in from either the left or right side of the viewport, taking up the full height of the viewport.
1717
* A backdrop covers the visible portion of the page behind the drawer.
1818
* Clicking the backdrop or the designated close button will close (hide) the drawer.
19+
* In some instances, it may be desirable for a panel to "mobilize" into a drawer at a certain smaller screen size.
20+
* In this case the drawer acts as a block element while persistent.
21+
* While persistent, the Drawer cannot be closed.
1922

2023
## Technical Specifications
2124

@@ -29,6 +32,10 @@ The Drawer is a container that may be hidden and revealed, sliding in from eithe
2932

3033
* Under 600px (37.5rem), the Drawer takes 100% of the width of the viewport.
3134
* At larger viewport sizes, the Drawer renders at 25rem (400px at default font sizing) wide.
35+
* In some instances, it may be desirable for a panel to "mobilize" into a drawer at a certain smaller screen size.
36+
* In this case, the drawer is considered "persistent" above a specified media query breakpoint and rendered as a block-level element..
37+
* The media query breakpoint is set via the `persistAt` property.
38+
* When this functionality is implemented, the drawer control should be hidden using the `cbp-hide` component with the same breakpoint as the `hideAt` value.
3239

3340
### Accessibility
3441

@@ -39,6 +46,10 @@ The Drawer is a container that may be hidden and revealed, sliding in from eithe
3946
* When the drawer appears on the screen, keyboard focus should be moved to the default focusable control inside the drawer.
4047
* After the drawer is dismissed, keyboard focus should be moved back to where it was before it moved into the drawer.
4148
* The expected behavior is that the drawer's tab order wraps.
49+
* When a drawer is persistent on-screen (not an overlay):
50+
* Its `role` is changed to "region"
51+
* The `aria-modal` attribute is removed.
52+
* The "close" button is not rendered (and the drawer cannot be closed).
4253

4354
### Additional Notes and Considerations
4455

packages/web-components/src/components/cbp-drawer/cbp-drawer.stories.tsx

+23-10
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ export default {
1010
open: {
1111
description: 'Specifies whether the drawer is open or closed.',
1212
control: 'boolean',
13+
},
14+
persistAt: {
15+
control: 'text',
1316
},
1417
uid: {
1518
description: 'A unique `id` applied to the drawer and referenced by the control.',
@@ -19,6 +22,7 @@ export default {
1922
description: 'Accessibility text is required to label the drawer (dialog) and is applied as an `aria-label`.',
2023
control: 'text',
2124
},
25+
2226
withIcon: {
2327
control: 'boolean',
2428
},
@@ -33,21 +37,27 @@ export default {
3337
},
3438
};
3539

36-
const Template = ({ position, withIcon, open, uid, accessibilityText, context, sx }) => {
40+
const Template = ({ position, withIcon, open, persistAt, uid, accessibilityText, context, sx }) => {
3741
return `
38-
<cbp-button
39-
type="button"
40-
color="secondary"
41-
accessibility-text="Open Drawer"
42-
target-prop="open"
43-
controls=${uid}
42+
<cbp-hide
43+
${persistAt ? `hide-at=${persistAt}` : ''}
4444
>
45-
<cbp-icon name="bars"></cbp-icon>
46-
</cbp-button>
45+
<cbp-button
46+
type="button"
47+
color="secondary"
48+
variant="square"
49+
accessibility-text="Open Drawer"
50+
target-prop="open"
51+
controls=${uid}
52+
>
53+
<cbp-icon name="bars"></cbp-icon>
54+
</cbp-button>
55+
</cbp-hide>
4756
4857
<cbp-drawer
4958
${position ? `position=${position}` : ''}
5059
${open ? `open=${open}` : ''}
60+
${persistAt ? `persist-at=${persistAt}` : ''}
5161
${accessibilityText ? `accessibility-text=${accessibilityText}` : ''}
5262
${context && context != 'light-inverts' ? `context=${context}` : ''}
5363
${sx ? `sx=${JSON.stringify(sx)}` : ''}
@@ -77,15 +87,17 @@ export const Drawer = Template.bind({});
7787
Drawer.args = {
7888
position: 'left',
7989
uid: 'drawer',
90+
//persistAt: 'min-width:64rem',
8091
context: 'light-always'
8192
};
8293

8394

84-
const UserPreferencesTemplate = ({ position, open, uid, accessibilityText, withIcon, context, sx }) => {
95+
const UserPreferencesTemplate = ({ position, open, persistAt, uid, accessibilityText, withIcon, context, sx }) => {
8596
return `
8697
<cbp-button
8798
type="button"
8899
color="secondary"
100+
variant="square"
89101
accessibility-text="Open Drawer"
90102
target-prop="open"
91103
controls=${uid}
@@ -96,6 +108,7 @@ const UserPreferencesTemplate = ({ position, open, uid, accessibilityText, withI
96108
<cbp-drawer
97109
${position ? `position=${position}` : ''}
98110
${open ? `open=${open}` : ''}
111+
${persistAt ? `persist-at="${persistAt}"` : ''}
99112
${accessibilityText ? `accessibility-text=${accessibilityText}` : ''}
100113
${context && context != 'light-inverts' ? `context=${context}` : ''}
101114
${sx ? `sx=${JSON.stringify(sx)}` : ''}

packages/web-components/src/components/cbp-drawer/cbp-drawer.tsx

+38-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, Prop, Element, Event, EventEmitter, Method, Watch, Host, h } from '@stencil/core';
1+
import { Component, Prop, Element, Event, EventEmitter, Method, Watch, Host, h, State } from '@stencil/core';
22
import { setCSSProps, getFocusableElements } from '../../utils/utils';
33

44
@Component({
@@ -23,17 +23,23 @@ export class CbpDrawer {
2323
/** Creates an accessible label for the drawer (dialog). */
2424
@Prop() accessibilityText: string;
2525

26+
/** Specifies a valid CSS media query (preferably using relative units), when met will hide the wrapped content using display: none. E.g., `min-width:64em` */
27+
@Prop() persistAt: string;
28+
2629
/** Specifies the context of the component as it applies to the visual design and whether it inverts when light/dark mode is toggled. Default behavior is "light-inverts" and does not have to be specified. */
2730
@Prop({ reflect: true }) context: 'light-inverts' | 'light-always' | 'dark-inverts' | 'dark-always';
2831

2932
/** Supports adding inline styles as an object */
3033
@Prop() sx: any = {};
3134

35+
@State() persistent: boolean = false;
36+
3237
/** Custom event fired when the drawer is opened. */
3338
@Event() drawerOpen!: EventEmitter;
3439
/** Custom event fired when the drawer is closed. */
3540
@Event() drawerClose!: EventEmitter;
3641

42+
3743
@Watch('open')
3844
watchOpenHandler(newValue: boolean) {
3945
newValue == true ? this.setFocus() : this.closeDrawer();
@@ -65,7 +71,6 @@ export class CbpDrawer {
6571
this.focusableElements = getFocusableElements(this.host);
6672
}
6773
this.focusableElements[0]?.focus();
68-
//console.log(this.focusableElements,document.activeElement);
6974
}, 100);
7075
}
7176

@@ -77,7 +82,27 @@ export class CbpDrawer {
7782
e.key == 'Escape' && this.closeDrawer();
7883
}
7984

85+
86+
// Callback functions for the media query event listeners
87+
doPersistAt(mql) {
88+
if (mql.matches) {
89+
this.persistent = true;
90+
}
91+
else {
92+
this.persistent = false;
93+
}
94+
}
95+
96+
8097
componentDidLoad() {
98+
if (this.persistAt) {
99+
const MQ = window?.matchMedia(`(${this.persistAt})`);
100+
if (MQ) {
101+
MQ.addEventListener('change', mql => this.doPersistAt(mql)); // Add an event listener to the media query
102+
this.doPersistAt(MQ); // Run the breakpoint change handler once on load
103+
}
104+
}
105+
81106
if (typeof this.sx == 'string') {
82107
this.sx = JSON.parse(this.sx) || {};
83108
}
@@ -89,23 +114,29 @@ export class CbpDrawer {
89114
}
90115

91116
componentDidRender() {
117+
// Support animation by doing it this way
92118
setTimeout(() => {
93119
this.open ? this.drawer.classList.add('cbp-drawer--open') : this.drawer.classList.remove('cbp-drawer--open');
94120
}, 10);
95121
}
96122

123+
97124
render() {
98125
return (
99-
<Host onClick={e => this.handleBackdropClick(e)} onKeyUp={e => this.handleKeyUp(e)} id={this.uid}>
126+
<Host
127+
class={this.persistent ? "cbp-drawer--persistent" : ""}
128+
onClick={e => this.handleBackdropClick(e)}
129+
onKeyUp={e => this.handleKeyUp(e)} id={this.uid}
130+
>
100131
<div
101132
ref={el => (this.drawer = el)}
102-
role="dialog"
103-
aria-modal="true"
133+
role={this.persistent ? "region" : "dialog"}
134+
aria-modal={!this.persistent ? "true" : false}
104135
class="cbp-drawer__content"
105136
aria-label={this.accessibilityText}
106137
tabindex="-1"
107138
>
108-
<cbp-button
139+
{!this.persistent && <cbp-button
109140
class="cbp-drawer__close-button"
110141
variant="square"
111142
type="button"
@@ -117,7 +148,7 @@ export class CbpDrawer {
117148
context="dark-always"
118149
>
119150
<cbp-icon name="circle-xmark" size="1rem"></cbp-icon>
120-
</cbp-button>
151+
</cbp-button>}
121152

122153
<slot />
123154
</div>

0 commit comments

Comments
 (0)