Skip to content

Commit

Permalink
feat(elements|ino-nav-drawer): add mobile variant (#1035)
Browse files Browse the repository at this point in the history
* feat: initial setup with isMobile prop

* chore: auto-generated

* feat: utilize modal for mobile drawer and avoid focus trap

* feat: add mobile nav-drawer

* chore: auto-generated

* chore: final auto-generated

* refactor: use stencil watcher, use clip-path instead of deprecated clip, fix typo

* refactor: add alt-text for ino-img

* refactor: implement mobile as a drawer variant

* chore: auto-generated
  • Loading branch information
TobiasHeimGalindo authored Sep 28, 2023
1 parent d370dc2 commit 5617375
Show file tree
Hide file tree
Showing 10 changed files with 227 additions and 129 deletions.
4 changes: 2 additions & 2 deletions packages/elements/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ export namespace Components {
*/
"open"?: boolean;
/**
* The variant to use for the drawer Possible values: `docked` (default), `dismissible`, `modal`.
* The variant to use for the drawer.
*/
"variant"?: NavDrawerVariant;
}
Expand Down Expand Up @@ -2724,7 +2724,7 @@ declare namespace LocalJSX {
*/
"open"?: boolean;
/**
* The variant to use for the drawer Possible values: `docked` (default), `dismissible`, `modal`.
* The variant to use for the drawer.
*/
"variant"?: NavDrawerVariant;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
@use '../base/mdc-customize';
@use '@material/drawer/mdc-drawer';
@use "@material/drawer";
@use "@material/list";
@use '../base/theme';
@use '@material/drawer';
@use '@material/list';
@use '../base/theme' as theme;
@use '../base/new-theme' as new-theme;

@include drawer.core-styles;
@include drawer.dismissible-core-styles;
Expand All @@ -13,6 +14,7 @@
/**
* @prop --ino-nav-drawer-width-open: The width of the open drawer.
* @prop --ino-nav-drawer-width-closed: Docked variant only! The width of the collapsed drawer.
* @prop --ino-nav-drawer-mobile-width-open: Mobile variant only! The width of the open drawer.
* @prop --ino-nav-drawer-background: Background of the drawer.
* @prop --ino-nav-drawer-height: Height of the drawer.
* @prop --ino-nav-drawer-text-color: Color of text inside the drawer.
Expand All @@ -22,12 +24,16 @@

--nav-drawer-width-open: var(--ino-nav-drawer-width-open, 250px);
--nav-drawer-width-closed: var(--ino-nav-drawer-width-closed, 72px);
--nav-drawer-mobile-width-open: var(
--ino-nav-drawer-mobile-width-open,
171px
);
--nav-drawer-height: var(--ino-nav-drawer-height, 100%);
--nav-drawer-background: var(
--ino-nav-drawer-background,
#{theme.color(primary, contrast)}
);
--nav-drawer-text-color: var(--ino-nav-drawer-text-color, theme.$brand);
--nav-drawer-text-color: var(--ino-nav-drawer-text-color, #{new-theme.$p-7});
--nav-drawer-transition-duration: var(
--ino-nav-drawer-transition-duration,
0.25s
Expand Down Expand Up @@ -117,6 +123,7 @@
justify-content: center;
align-items: center;
text-align: center;
white-space: normal;

.mdc-drawer__subtitle {
font-size: 12px;
Expand Down Expand Up @@ -223,4 +230,40 @@
top: 0;
}
}

// Styles for mobile nav drawer
.mdc-drawer.mobile-drawer {
@include drawer.width(var(--nav-drawer-mobile-width-open));

.mdc-drawer__content {
margin-top: 87px;
}
.mdc-drawer__header {
font-size: 12px;
::slotted(div) {
display: flex;
align-items: center;
gap: 13px;
}
}

& + .mdc-drawer-app-content {
box-shadow: none;
}

& + .mdc-drawer-scrim {
backdrop-filter: blur(4.5px);
background: rgba(167, 183, 212, 0.41);
}
}

.visually-hidden {
position: absolute;
clip-path: inset(50%);
padding: 0;
border: 0;
height: 1px;
width: 1px;
overflow: hidden;
}
}
57 changes: 46 additions & 11 deletions packages/elements/src/components/ino-nav-drawer/ino-nav-drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export class NavDrawer implements ComponentInterface {
*/
private drawerInstance: MDCDrawer;
private drawerEl: HTMLElement;

@Element() el!: HTMLInoNavDrawerElement;

/**
Expand All @@ -55,8 +54,7 @@ export class NavDrawer implements ComponentInterface {
@Prop() anchor?: NavDrawerAnchor = 'left';

/**
* The variant to use for the drawer
* Possible values: `docked` (default), `dismissible`, `modal`.
* The variant to use for the drawer.
*/
@Prop() variant?: NavDrawerVariant = 'docked';

Expand All @@ -67,9 +65,17 @@ export class NavDrawer implements ComponentInterface {
@Prop() a11yLabels?: NavDrawerLabels = {
content: 'Main Navigation',
footer: 'Footer Navigation',
toggleBtn: 'Toggle Navigation'
toggleBtn: 'Toggle Navigation',
};

@Watch('variant')
variantChanged(newVariant: NavDrawerVariant) {
if (newVariant === 'mobile') {
this.activateMobileMode();
} else {
this.deactivateMobileMode();
}
}

componentDidLoad() {
this.drawerInstance = new MDCDrawer(
Expand All @@ -79,17 +85,36 @@ export class NavDrawer implements ComponentInterface {
if (this.drawerInstance) {
this.drawerInstance.open = this.open || false;
}

this.drawerEl.addEventListener('MDCDrawer:closed', this.closeDrawer);
this.initTabindex('content');
this.initTabindex('footer');

// set initial mobile or desktop mode
if (this.variant === 'mobile') {
this.activateMobileMode();
} else {
this.deactivateMobileMode();
}
}

disconnectedCallback() {
this.drawerEl.removeEventListener('MDCDrawer:closed', this.closeDrawer);
this.drawerInstance?.destroy();
}

private activateMobileMode() {
const navItems = this.el.querySelectorAll('ino-nav-item');
navItems.forEach((item) => {
item.classList.add('mobile-nav-item');
});
}

private deactivateMobileMode() {
const navItems = this.el.querySelectorAll('ino-nav-item');
navItems.forEach((item) => {
item.classList.remove('mobile-nav-item');
});
}
// This listener ensures that only the most recently clicked/selected list item appears as "activated"
@Listen('clickEl')
handleListItemClick(event: CustomEvent) {
Expand Down Expand Up @@ -127,21 +152,24 @@ export class NavDrawer implements ComponentInterface {

private initTabindex(slotName: string) {
const contentElements = this.el.querySelector(`[slot="${slotName}"]`);
const contenListItems = contentElements.querySelectorAll('ino-list-item');
contenListItems[0].attrs = {tabIndex:0}
const contentListItems = contentElements.querySelectorAll('ino-list-item');
contentListItems[0].attrs = { tabIndex: 0 };
}

render() {
const { anchor, variant } = this;

const isMobile = variant === 'mobile';

const classDrawer = classNames({
'mdc-drawer': true,
'mdc-drawer--docked': variant === 'docked',
'mdc-drawer--dismissible':
variant === 'dismissible' || variant === 'docked', // docked is a modifier of MDC's dismissible inoVariant
'mdc-drawer--modal': variant === 'modal',
'mdc-drawer--modal': variant === 'modal' || isMobile,
'mdc-drawer--anchor-left': anchor === 'left',
'mdc-drawer--anchor-right': anchor === 'right',
'mobile-drawer': isMobile, // custom class for mobile drawer
});

const classAppContent = classNames({
Expand Down Expand Up @@ -169,11 +197,16 @@ export class NavDrawer implements ComponentInterface {
<nav class="mdc-drawer__footer" aria-label={this.a11yLabels.footer}>
<slot name="footer"></slot>
<ino-icon-button
class="mdc-drawer__toggle"
class={{
'mdc-drawer__toggle': true,
'visually-hidden': isMobile, // Hide visually on mobile, but remains in DOM to meet focus-trap requirements
}}
icon="arrow_right"
tabIndex={isMobile ? -1 : null} // Exclude from tab navigation on mobile drawer
aria-hidden={isMobile} // Hide from screen readers on mobile as it's only used to prevent focus-trap error and has no functional use
onClick={this.toggleDrawer}
attrs={{
ariaLabel: this.a11yLabels.toggleBtn
ariaLabel: this.a11yLabels.toggleBtn,
}}
/>
</nav>
Expand All @@ -189,7 +222,9 @@ export class NavDrawer implements ComponentInterface {
return (
<Host>
{nav}
{variant === 'modal' && <div class="mdc-drawer-scrim"></div>}
{(isMobile || variant === 'modal') && (
<div class="mdc-drawer-scrim"></div>
)}
{main}
</Host>
);
Expand Down
25 changes: 6 additions & 19 deletions packages/elements/src/components/ino-nav-drawer/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,12 @@ class MyComponent extends Component {

## Properties

| Property | Attribute | Description | Type | Default |
| ------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `a11yLabels` | -- | The aria-labels used for content and footer nav elements. https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/navigation_role. | `{ content: string; footer: string; toggleBtn: string; }` | `{ content: 'Main Navigation', footer: 'Footer Navigation', toggleBtn: 'Toggle Navigation' }` |
| `anchor` | `anchor` | Side from which the drawer will appear. Possible values: `left` (default), `right`. | `"left" \| "right"` | `'left'` |
| `open` | `open` | Marks this element as open. (**unmanaged**) | `boolean` | `false` |
| `variant` | `variant` | The variant to use for the drawer Possible values: `docked` (default), `dismissible`, `modal`. | `"dismissible" \| "docked" \| "modal"` | `'docked'` |
| Property | Attribute | Description | Type | Default |
| ------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `a11yLabels` | -- | The aria-labels used for content and footer nav elements. https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/navigation_role. | `{ content: string; footer: string; toggleBtn: string; }` | `{ content: 'Main Navigation', footer: 'Footer Navigation', toggleBtn: 'Toggle Navigation', }` |
| `anchor` | `anchor` | Side from which the drawer will appear. Possible values: `left` (default), `right`. | `"left" \| "right"` | `'left'` |
| `open` | `open` | Marks this element as open. (**unmanaged**) | `boolean` | `false` |
| `variant` | `variant` | The variant to use for the drawer. | `"dismissible" \| "docked" \| "mobile" \| "modal"` | `'docked'` |


## Events
Expand All @@ -145,19 +145,6 @@ class MyComponent extends Component {
| `"subtitle"` | For the element just below the logo (cannot be used with the `header` slot) |


## CSS Custom Properties

| Name | Description |
| -------------------------------------- | ------------------------------------------------------- |
| `--ino-nav-drawer-background` | Background of the drawer. |
| `--ino-nav-drawer-height` | Height of the drawer. |
| `--ino-nav-drawer-text-color` | Color of text inside the drawer. |
| `--ino-nav-drawer-timing-function` | Timing function of the slide animation of the drawer. |
| `--ino-nav-drawer-transition-duration` | Duration of the slide animation of the drawer. |
| `--ino-nav-drawer-width-closed` | Docked variant only! The width of the collapsed drawer. |
| `--ino-nav-drawer-width-open` | The width of the open drawer. |


## Dependencies

### Depends on
Expand Down
23 changes: 22 additions & 1 deletion packages/elements/src/components/ino-nav-item/ino-nav-item.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
@use '../base/mdc-customize';
@use '@material/list/mdc-list';
@use '../base/theme';
@use '../base/typography-new' as typography;

ino-nav-item  {
ino-nav-item {
/**
* @prop --ino-nav-item-color: Inactive color of icon.
* @prop --ino-nav-item-color-active: Active color of icon.
Expand Down Expand Up @@ -69,4 +70,24 @@ ino-nav-item  {
}
}
}

// Styles for mobile-nav-item
&.mobile-nav-item {
.mdc-deprecated-list-item,
ino-list-item .mdc-deprecated-list-item {
@include typography.typo(label-s);

&__graphic {
margin-right: 0px;
}

// icon
::slotted(ino-icon),
ino-icon,
.ino-list-item__icon {
--icon-width: 16px;
--icon-height: 16px;
}
}
}
}
2 changes: 1 addition & 1 deletion packages/elements/src/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export type HorizontalLocation = 'left' | 'right';
export type ImageDecodingTypes = 'async' | 'auto' | 'sync';
export type Locations = HorizontalLocation | VerticalLocation;
export type NavDrawerAnchor = 'left' | 'right';
export type NavDrawerVariant = 'docked' | 'dismissible' | 'modal';
export type NavDrawerVariant = 'docked' | 'dismissible' | 'modal' | 'mobile';
export type SnackbarType = 'info' | 'success' | 'error';
export type SpinnerType = 'tile' | 'bounce' | 'circle';
export type SurfaceType = 'filled' | 'outlined' | 'text';
Expand Down
Loading

0 comments on commit 5617375

Please sign in to comment.