Skip to content

Commit f8c5a93

Browse files
feat(wizard-dialog): allow used-defined actions in menu
1 parent 2501fb7 commit f8c5a93

File tree

4 files changed

+168
-21
lines changed

4 files changed

+168
-21
lines changed

src/foundation.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,16 @@ export function getMultiplier(input: WizardInput): string | null {
225225
else return null;
226226
}
227227

228+
/** @returns [[`WizardAction`]]s to dispatch on [[`WizardDialog`]] menu action. */
229+
export type WizardMenuActor = () => WizardAction[];
230+
231+
/** User interactions rendered in the wizard-dialog menu */
232+
interface MenuAction {
233+
label: string;
234+
icon?: string;
235+
action: WizardMenuActor;
236+
}
237+
228238
/** Represents a page of a wizard dialog */
229239
export interface WizardPage {
230240
title: string;
@@ -242,6 +252,7 @@ export interface WizardPage {
242252
};
243253
initial?: boolean;
244254
element?: Element;
255+
menuActions?: MenuAction[];
245256
}
246257
export type Wizard = WizardPage[];
247258
export type WizardFactory = () => Wizard;
@@ -2307,10 +2318,7 @@ export const tags: Record<
23072318
identity: namingIdentity,
23082319
selector: namingSelector,
23092320
parents: ['SCL'],
2310-
children: [...tEquipmentContainerSequence,
2311-
'VoltageLevel',
2312-
'Function',
2313-
],
2321+
children: [...tEquipmentContainerSequence, 'VoltageLevel', 'Function'],
23142322
},
23152323
SupSubscription: {
23162324
identity: singletonIdentity,
@@ -2387,11 +2395,7 @@ export const tags: Record<
23872395
identity: namingIdentity,
23882396
selector: namingSelector,
23892397
parents: ['Substation'],
2390-
children: [...tEquipmentContainerSequence,
2391-
'Voltage',
2392-
'Bay',
2393-
'Function',
2394-
],
2398+
children: [...tEquipmentContainerSequence, 'Voltage', 'Bay', 'Function'],
23952399
},
23962400
};
23972401

src/wizard-dialog.ts

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,19 @@ import {
77
internalProperty,
88
TemplateResult,
99
html,
10+
query,
1011
} from 'lit-element';
1112
import { get, translate } from 'lit-translate';
1213

1314
import '@material/mwc-button';
1415
import '@material/mwc-dialog';
16+
import '@material/mwc-icon-button';
1517
import '@material/mwc-icon-button-toggle';
18+
import '@material/mwc-menu';
1619
import { Dialog } from '@material/mwc-dialog';
20+
import { IconButton } from '@material/mwc-icon-button';
1721
import { List } from '@material/mwc-list';
22+
import { Menu } from '@material/mwc-menu';
1823

1924
import 'ace-custom-element';
2025
import {
@@ -31,6 +36,8 @@ import {
3136
Delete,
3237
Create,
3338
identity,
39+
WizardMenuActor,
40+
newSubWizardEvent,
3441
} from './foundation.js';
3542

3643
function dialogInputs(dialog?: Dialog): WizardInput[] {
@@ -84,10 +91,10 @@ export class WizardDialog extends LitElement {
8491
@internalProperty()
8592
pageIndex = 0;
8693

87-
@queryAll('mwc-dialog')
88-
dialogs!: NodeListOf<Dialog>;
89-
@queryAll(wizardInputSelector)
90-
inputs!: NodeListOf<WizardInput>;
94+
@queryAll('mwc-dialog') dialogs!: NodeListOf<Dialog>;
95+
@queryAll(wizardInputSelector) inputs!: NodeListOf<WizardInput>;
96+
@query('.actions-menu') actionsMenu!: Menu;
97+
@query('mwc-icon-button[icon="more_vert"]') menuButton!: IconButton;
9198

9299
/** The `Dialog` showing the active [[`WizardPage`]]. */
93100
get dialog(): Dialog | undefined {
@@ -150,6 +157,20 @@ export class WizardDialog extends LitElement {
150157
return true;
151158
}
152159

160+
/** Triggers sub-wizard or editor-action with valid manu action */
161+
async menuAct(action?: WizardMenuActor): Promise<boolean> {
162+
if (!action) return false;
163+
164+
const wizardActions = action();
165+
166+
wizardActions.forEach(wa =>
167+
isWizardFactory(wa)
168+
? this.dispatchEvent(newSubWizardEvent(wa))
169+
: this.dispatchEvent(newActionEvent(wa))
170+
);
171+
return true;
172+
}
173+
153174
private onClosed(ae: CustomEvent<{ action: string } | null>): void {
154175
if (!(ae.target instanceof Dialog && ae.detail?.action)) return;
155176
if (ae.detail.action === 'close') this.dispatchEvent(newWizardEvent());
@@ -181,21 +202,60 @@ export class WizardDialog extends LitElement {
181202
this.act(this.wizard[this.pageIndex].primary!.action)
182203
);
183204
}
205+
206+
if (this.actionsMenu)
207+
this.actionsMenu.anchor = <HTMLElement>this.menuButton;
208+
}
209+
210+
renderMenu(page: WizardPage): TemplateResult {
211+
const someIconsDefined = page.menuActions?.some(
212+
menuAction => menuAction.icon
213+
);
214+
215+
return html` <mwc-icon-button
216+
icon="more_vert"
217+
@click=${() => {
218+
if (!this.actionsMenu.open) this.actionsMenu.show();
219+
else this.actionsMenu.close();
220+
}}
221+
></mwc-icon-button>
222+
<mwc-menu class="actions-menu" corner="BOTTOM_RIGHT" menuCorner="END">
223+
${page.menuActions!.map(
224+
menuAction =>
225+
html`<mwc-list-item
226+
.graphic=${someIconsDefined ? 'icon' : null}
227+
@click=${() => this.menuAct(menuAction.action)}
228+
>
229+
<span>${menuAction.label}</span>
230+
${menuAction.icon
231+
? html`<mwc-icon slot="graphic">${menuAction.icon}</mwc-icon>`
232+
: html``}
233+
</mwc-list-item>`
234+
)}
235+
</mwc-menu>`;
184236
}
185237

186238
renderPage(page: WizardPage, index: number): TemplateResult {
239+
const showCodeToggleButton =
240+
page.element && localStorage.getItem('mode') === 'pro';
241+
187242
return html`<mwc-dialog
188243
defaultAction="close"
189244
?open=${index === this.pageIndex}
190245
heading=${page.title}
191246
@closed=${this.onClosed}
192247
>
193-
${page.element && localStorage.getItem('mode') === 'pro'
194-
? html`<mwc-icon-button-toggle
195-
onicon="code"
196-
officon="code_off"
197-
@click=${() => this.requestUpdate()}
198-
></mwc-icon-button-toggle>`
248+
${showCodeToggleButton || page.menuActions
249+
? html`<nav>
250+
${showCodeToggleButton
251+
? html`<mwc-icon-button-toggle
252+
onicon="code"
253+
officon="code_off"
254+
@click=${() => this.requestUpdate()}
255+
></mwc-icon-button-toggle>`
256+
: ''}
257+
${page.menuActions ? this.renderMenu(page) : ''}
258+
</nav>`
199259
: ''}
200260
<div id="wizard-content">
201261
${this.code && page.element
@@ -270,14 +330,14 @@ export class WizardDialog extends LitElement {
270330
--mdc-dialog-max-width: 92vw;
271331
}
272332
273-
mwc-dialog > mwc-icon-button-toggle {
333+
mwc-dialog > nav {
274334
position: absolute;
275335
top: 8px;
276336
right: 14px;
277337
color: var(--base00);
278338
}
279339
280-
mwc-dialog > mwc-icon-button-toggle[on] {
340+
mwc-dialog > nav > mwc-icon-button-toggle[on] {
281341
color: var(--mdc-theme-primary);
282342
}
283343

test/unit/__snapshots__/wizard-dialog.test.snap.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,60 @@ snapshots["wizard-dialog with a nonempty wizard property in pro mode switches to
1313
`;
1414
/* end snapshot wizard-dialog with a nonempty wizard property in pro mode switches to code editor view on code toggle button click */
1515

16+
snapshots["wizard-dialog with user defined menu actions set looks like its snapshot"] =
17+
`<mwc-dialog
18+
defaultaction="close"
19+
heading="Page 1"
20+
open=""
21+
>
22+
<nav>
23+
<mwc-icon-button icon="more_vert">
24+
</mwc-icon-button>
25+
<mwc-menu
26+
class="actions-menu"
27+
corner="BOTTOM_RIGHT"
28+
menucorner="END"
29+
>
30+
<mwc-list-item
31+
aria-disabled="false"
32+
graphic="icon"
33+
mwc-list-item=""
34+
role="menuitem"
35+
tabindex="-1"
36+
>
37+
<span>
38+
remove
39+
</span>
40+
<mwc-icon slot="graphic">
41+
delete
42+
</mwc-icon>
43+
</mwc-list-item>
44+
<mwc-list-item
45+
aria-disabled="false"
46+
graphic="icon"
47+
mwc-list-item=""
48+
role="menuitem"
49+
tabindex="-1"
50+
>
51+
<span>
52+
remove
53+
</span>
54+
<mwc-icon slot="graphic">
55+
delete
56+
</mwc-icon>
57+
</mwc-list-item>
58+
</mwc-menu>
59+
</nav>
60+
<div id="wizard-content">
61+
</div>
62+
<mwc-button
63+
dialogaction="close"
64+
label="[cancel]"
65+
slot="secondaryAction"
66+
style="--mdc-theme-primary: var(--mdc-theme-error)"
67+
>
68+
</mwc-button>
69+
</mwc-dialog>
70+
`;
71+
/* end snapshot wizard-dialog with user defined menu actions set looks like its snapshot */
72+

test/unit/wizard-dialog.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,32 @@ describe('wizard-dialog', () => {
1515
element = await fixture(html`<wizard-dialog></wizard-dialog>`);
1616
});
1717

18+
describe('with user defined menu actions set', () => {
19+
beforeEach(async () => {
20+
element.wizard = [
21+
{
22+
title: 'Page 1',
23+
menuActions: [
24+
{
25+
icon: 'delete',
26+
label: 'remove',
27+
action: () => [],
28+
},
29+
{
30+
icon: 'delete',
31+
label: 'remove',
32+
action: () => [],
33+
},
34+
],
35+
},
36+
];
37+
await element.updateComplete;
38+
});
39+
40+
it('looks like its snapshot', async () =>
41+
await expect(element).shadowDom.to.equalSnapshot());
42+
});
43+
1844
describe('with an empty wizard property', () => {
1945
it('shows no dialog', () =>
2046
expect(element).property('dialog').to.not.exist);

0 commit comments

Comments
 (0)