Skip to content

Commit 7b88347

Browse files
author
shleewhite
committed
chore: add some more examples for app side nav
1 parent 1c10424 commit 7b88347

File tree

5 files changed

+197
-105
lines changed

5 files changed

+197
-105
lines changed

showcase/app/components/mock/app/sidebar/app-side-nav.gts

Lines changed: 113 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface MockAppSidebarAppSideNavSignature {
2424
isResponsive?: HdsAppSideNavSignature['Args']['isResponsive'];
2525
isCollapsible?: HdsAppSideNavSignature['Args']['isCollapsible'];
2626
showDevToggle?: boolean;
27+
shouldRemoveFromDomOnCollapse?: boolean;
2728
};
2829
Element: HdsAppSideNavSignature['Element'];
2930
}
@@ -32,6 +33,7 @@ export default class MockAppSidebarAppSideNav extends Component<MockAppSidebarAp
3233
isResponsive;
3334
isCollapsible;
3435
@tracked showMockInteractionState = false;
36+
@tracked isRendered = true;
3537

3638
constructor(owner: Owner, args: MockAppSidebarAppSideNavSignature['Args']) {
3739
super(owner, args);
@@ -43,110 +45,118 @@ export default class MockAppSidebarAppSideNav extends Component<MockAppSidebarAp
4345
this.showMockInteractionState = !this.showMockInteractionState;
4446
};
4547

48+
removeSideNavFromDOM = (isOpen: boolean) => {
49+
if (isOpen && this.args.shouldRemoveFromDomOnCollapse)
50+
this.isRendered = false;
51+
};
52+
4653
<template>
47-
<HdsAppSideNav
48-
@isResponsive={{this.isResponsive}}
49-
@isCollapsible={{this.isCollapsible}}
50-
>
51-
<HdsAppSideNavList
52-
class="hds-side-nav-hide-when-minimized"
53-
aria-label="Dashboard"
54-
as |SNL|
55-
>
56-
<SNL.Link @icon="dashboard" @text="Dashboard" @isActive={{true}} />
57-
</HdsAppSideNavList>
58-
<HdsAppSideNavList
59-
class="hds-side-nav-hide-when-minimized"
60-
aria-label="Services"
61-
as |SNL|
62-
>
63-
<SNL.Title>Services</SNL.Title>
64-
<SNL.Link
65-
@text={{if this.showMockInteractionState "isActive" "Boundary"}}
66-
@icon="boundary"
67-
@href="#"
68-
class="active"
69-
/>
70-
<SNL.Link
71-
@text={{if this.showMockInteractionState ":focus" "Consul"}}
72-
@icon="consul"
73-
@href="#"
74-
class="mock-focus"
75-
/>
76-
<SNL.Link
77-
@text={{if this.showMockInteractionState ":hover" "Packer"}}
78-
@icon="packer"
79-
@href="#"
80-
class="mock-hover"
81-
/>
82-
<SNL.Link
83-
@text={{if this.showMockInteractionState ":active" "Vault"}}
84-
@icon="vault"
85-
@href="#"
86-
class="mock-active"
87-
/>
88-
<SNL.Link
89-
@text="Vault Secrets"
90-
@icon="vault-secrets-square"
91-
@href="#"
92-
/>
93-
<SNL.Link @text="Terraform" @icon="terraform" @href="#" />
94-
<SNL.Link @text="Vagrant" @icon="vagrant" @badge="Alpha" @href="#" />
95-
<SNL.Link
96-
@text="Waypoint"
97-
@icon="waypoint"
98-
@badge="Alpha"
99-
@hasSubItems={{true}}
100-
/>
101-
</HdsAppSideNavList>
102-
<HdsAppSideNavList
103-
class="hds-side-nav-hide-when-minimized"
104-
aria-label="Organization"
105-
as |SNL|
54+
{{#if this.isRendered}}
55+
<HdsAppSideNav
56+
@isResponsive={{this.isResponsive}}
57+
@isCollapsible={{this.isCollapsible}}
58+
@onToggleMinimizedStatus={{this.removeSideNavFromDOM}}
10659
>
107-
<SNL.Title>Default Org</SNL.Title>
108-
<SNL.Link
109-
@text="HashiCorp Virtual Networks"
110-
@icon="network"
111-
@href="#"
112-
/>
113-
<SNL.Link
114-
@text="Access control (IAM)"
115-
@icon="users"
116-
@href="#"
117-
@hasSubItems={{true}}
118-
/>
119-
<SNL.Link
120-
@text="Billing"
121-
@icon="credit-card"
122-
@href="#"
123-
@hasSubItems={{true}}
124-
/>
125-
<SNL.Link
126-
@text="Settings"
127-
@icon="settings"
128-
@href="#"
129-
@hasSubItems={{true}}
130-
/>
131-
<SNL.Link
132-
@href="#"
133-
@isHrefExternal={{true}}
134-
@icon="guide"
135-
@text="Documentation"
136-
/>
137-
{{#if @showDevToggle}}
138-
<SNL.ExtraAfter>
139-
<div {{style margin="32px 6px"}}>
140-
<HdsFormToggleField
141-
{{on "change" this.toggleMockInteractionState}}
142-
as |F|
143-
>
144-
<F.Label>Show mock states</F.Label>
145-
</HdsFormToggleField>
146-
</div>
147-
</SNL.ExtraAfter>
148-
{{/if}}
149-
</HdsAppSideNavList>
150-
</HdsAppSideNav>
60+
<HdsAppSideNavList
61+
class="hds-side-nav-hide-when-minimized"
62+
aria-label="Dashboard"
63+
as |SNL|
64+
>
65+
<SNL.Link @icon="dashboard" @text="Dashboard" @isActive={{true}} />
66+
</HdsAppSideNavList>
67+
<HdsAppSideNavList
68+
class="hds-side-nav-hide-when-minimized"
69+
aria-label="Services"
70+
as |SNL|
71+
>
72+
<SNL.Title>Services</SNL.Title>
73+
<SNL.Link
74+
@text={{if this.showMockInteractionState "isActive" "Boundary"}}
75+
@icon="boundary"
76+
@href="#"
77+
class="active"
78+
/>
79+
<SNL.Link
80+
@text={{if this.showMockInteractionState ":focus" "Consul"}}
81+
@icon="consul"
82+
@href="#"
83+
class="mock-focus"
84+
/>
85+
<SNL.Link
86+
@text={{if this.showMockInteractionState ":hover" "Packer"}}
87+
@icon="packer"
88+
@href="#"
89+
class="mock-hover"
90+
/>
91+
<SNL.Link
92+
@text={{if this.showMockInteractionState ":active" "Vault"}}
93+
@icon="vault"
94+
@href="#"
95+
class="mock-active"
96+
/>
97+
<SNL.Link
98+
@text="Vault Secrets"
99+
@icon="vault-secrets-square"
100+
@href="#"
101+
/>
102+
<SNL.Link @text="Terraform" @icon="terraform" @href="#" />
103+
<SNL.Link @text="Vagrant" @icon="vagrant" @badge="Alpha" @href="#" />
104+
<SNL.Link
105+
@text="Waypoint"
106+
@icon="waypoint"
107+
@badge="Alpha"
108+
@hasSubItems={{true}}
109+
/>
110+
</HdsAppSideNavList>
111+
<HdsAppSideNavList
112+
class="hds-side-nav-hide-when-minimized"
113+
aria-label="Organization"
114+
as |SNL|
115+
>
116+
<SNL.Title>Default Org</SNL.Title>
117+
<SNL.Link
118+
@text="HashiCorp Virtual Networks"
119+
@icon="network"
120+
@href="#"
121+
/>
122+
<SNL.Link
123+
@text="Access control (IAM)"
124+
@icon="users"
125+
@href="#"
126+
@hasSubItems={{true}}
127+
/>
128+
<SNL.Link
129+
@text="Billing"
130+
@icon="credit-card"
131+
@href="#"
132+
@hasSubItems={{true}}
133+
/>
134+
<SNL.Link
135+
@text="Settings"
136+
@icon="settings"
137+
@href="#"
138+
@hasSubItems={{true}}
139+
/>
140+
<SNL.Link
141+
@href="#"
142+
@isHrefExternal={{true}}
143+
@icon="guide"
144+
@text="Documentation"
145+
/>
146+
{{#if @showDevToggle}}
147+
<SNL.ExtraAfter>
148+
<div {{style margin="32px 6px"}}>
149+
<HdsFormToggleField
150+
{{on "change" this.toggleMockInteractionState}}
151+
as |F|
152+
>
153+
<F.Label>Show mock states</F.Label>
154+
</HdsFormToggleField>
155+
</div>
156+
</SNL.ExtraAfter>
157+
{{/if}}
158+
</HdsAppSideNavList>
159+
</HdsAppSideNav>
160+
{{/if}}
151161
</template>
152162
}

showcase/app/router.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Router.map(function () {
3737
this.route('app-side-nav', function () {
3838
this.route('frameless', function () {
3939
this.route('demo-responsiveness');
40+
this.route('demo-remove-from-dom');
4041
});
4142
});
4243
this.route('application-state');
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { TemplateOnlyComponent } from '@ember/component/template-only';
2+
import { pageTitle } from 'ember-page-title';
3+
4+
import MockApp from 'showcase/components/mock/app';
5+
6+
const PageComponentsAppSideNavFramelessDemoRemoveFromDom: TemplateOnlyComponent =
7+
<template>
8+
{{pageTitle "App SideNav remove from DOM demo - Frameless"}}
9+
10+
<MockApp>
11+
<:sidebar as |S|>
12+
<S.SideNav
13+
@showDevToggle={{true}}
14+
@shouldRemoveFromDomOnCollapse={{true}}
15+
/>
16+
</:sidebar>
17+
<:main as |M|>
18+
<M.PageHeader @showActionButton={{true}} />
19+
<M.GenericTextContent />
20+
<M.GenericTextContent />
21+
<M.GenericTextContent />
22+
<M.GenericTextContent />
23+
</:main>
24+
</MockApp>
25+
</template>;
26+
27+
export default PageComponentsAppSideNavFramelessDemoRemoveFromDom;

showcase/app/templates/page-components/app-side-nav/index.hbs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,4 +699,22 @@
699699
@label="Full AppFrame with AppHeader & AppSideNav (small viewport)"
700700
/>
701701

702+
<Shw::Divider />
703+
704+
<Shw::Frame
705+
@id="demo-full-app-frame-with-remove-from-dom"
706+
@src="/components/app-side-nav/frameless/demo-remove-from-dom"
707+
@height="780"
708+
@width="800"
709+
@label="Remove AppSideNav from DOM when collapse"
710+
/>
711+
<Shw::Text::Body>
712+
This demo verifies that when the `AppSideNav` component is removed from the DOM while page overflow styles are
713+
overridden, the page's scroll functionality is properly restored.
714+
</Shw::Text::Body>
715+
716+
<Shw::Text::Body>
717+
To check this, expand and then collapse the AppSideNav. Then try to scroll the page.
718+
</Shw::Text::Body>
719+
702720
</section>

showcase/tests/integration/components/hds/app-side-nav/index-test.js

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,13 +314,49 @@ module('Integration | Component | hds/app-side-nav/index', function (hooks) {
314314
assert.dom('body', document).doesNotHaveStyle('overflow');
315315
});
316316

317+
test('when expanded in mobile and the component is removed from the DOM, scrolling is enabled', async function (assert) {
318+
this.mockMedia();
319+
320+
let calls = [];
321+
this.setProperties({
322+
onDesktopViewportChange: (...args) => calls.push(args),
323+
});
324+
325+
this.set('isAppSideNavRendered', true);
326+
327+
await render(hbs`{{#if this.isAppSideNavRendered}}
328+
<Hds::AppSideNav
329+
@isCollapsible={{true}}
330+
@onDesktopViewportChange={{this.onDesktopViewportChange}}
331+
/>
332+
{{/if}}`);
333+
334+
await this.changeBrowserSize(false);
335+
336+
assert.deepEqual(
337+
calls[1],
338+
[false],
339+
'resizing to mobile triggers a false event',
340+
);
341+
342+
await click('.hds-app-side-nav__toggle-button');
343+
344+
assert.dom('body', document).hasStyle({
345+
overflow: 'hidden',
346+
});
347+
348+
this.set('isAppSideNavRendered', false);
349+
350+
assert.dom('body', document).doesNotHaveStyle('overflow');
351+
});
352+
317353
test('when collapsed, the content in the AppSideNav is not focusable', async function (assert) {
318354
await render(hbs`<Hds::AppSideNav
319355
id='test-app-side-nav'
320356
@isCollapsible={{true}}
321357
>
322-
<button id='button-inside'>Click</button>
323-
</Hds::AppSideNav><button id='button-outside'>Click</button>`);
358+
<button id='button-inside' type="button">Click</button>
359+
</Hds::AppSideNav><button id='button-outside' type="button">Click</button>`);
324360

325361
await click('.hds-app-side-nav__toggle-button');
326362
assert.dom('#test-app-side-nav').hasClass('hds-app-side-nav--is-minimized');

0 commit comments

Comments
 (0)