Skip to content

Instantly share code, notes, and snippets.

@jwx
Forked from fkleuver/index.html
Last active October 22, 2020 23:34
Show Gist options
  • Save jwx/1d3f7842b3bf40657c21f429aac89f20 to your computer and use it in GitHub Desktop.
Save jwx/1d3f7842b3bf40657c21f429aac89f20 to your computer and use it in GitHub Desktop.
Custom Element with Slots
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Dumber Gist</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<base href="/">
</head>
<!--
Dumber Gist uses dumber bundler, the default bundle file
is /dist/entry-bundle.js.
The starting module is pointed to "main" (data-main attribute on script)
which is your src/main.js.
-->
<body>
<my-app></my-app>
<script src="/dist/entry-bundle.js" data-main="main"></script>
</body>
</html>
{
"dependencies": {
"aurelia": "dev"
}
}
<use-shadow-dom></use-shadow-dom>
<template display.style="selectedStepIndex === stepIndex && isVisible ? 'block' : 'none !important'" class="m-1 p-1 d-block border border-primary">
<slot></slot>
</template>
import { inject, customElement, bindable, BindingMode, ISignaler, EventAggregator, shadowCSS } from 'aurelia';
import style from './form-wizard.css';
let counter = 0;
@inject(ISignaler, EventAggregator)
export class FormWizardItem {
static get dependencies() { return [shadowCSS(style)]; }
@bindable title = '';
@bindable stepIndex = 0;
@bindable selectedStepIndex = 0;
@bindable isComplete = false;
@bindable disabled = false;
@bindable navClick;
@bindable isVisible = true;
constructor(signaler, messageBus) {
this.signaler = signaler;
this.messageBus = messageBus;
this.id = `form-wizard-item-${counter++}`;
}
}
:host .pointer-events-none,
.pointer-events-none {
pointer-events: none;
}
.grid {display: grid;}
.grid-cols-1 {grid-template-columns: auto;}
.grid-cols-2 {grid-template-columns: auto auto;}
.grid-cols-3 {grid-template-columns: auto auto auto;}
.grid-rows-1 {grid-template-rows: auto;}
.grid-rows-2 {grid-template-rows: auto auto;}
.grid-rows-3 {grid-template-rows: auto auto auto;}
:host form-wizard,
form-wizard
{
position: relative;
height: calc(100% - 10px);
}
:host form-wizard #wizard-container,
form-wizard #wizard-container
{
height: 100%;
}
:host form-wizard #wizard-header,
:host form-wizard #wizard-content,
form-wizard #wizard-header,
form-wizard #wizard-content
{
position: relative;
}
:host form-wizard #wizard-header,
form-wizard #wizard-header
{
line-height: 2.2em;
}
:host form-wizard #wizard-header.header-top,
form-wizard #wizard-header.header-top
{
margin-top: .5em;
}
:host form-wizard #wizard-header>span,
form-wizard #wizard-header>span
{
position: relative;
padding: 1.5em;
cursor: pointer;
user-select: none;
}
:host form-wizard #wizard-container.orientation-left,
form-wizard #wizard-container.orientation-left
{
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: auto;
grid-template-areas: "header" "main";
}
:host form-wizard #wizard-content.flex-row-1,
form-wizard #wizard-content.flex-row-1
{
margin: 0;
}
:host form-wizard #wizard-content.flex-column-1,
form-wizard #wizard-content.flex-column-1
{
margin: 0;
}
:host form-wizard #wizard-content,
form-wizard #wizard-content
{
padding: 15px;
}
:host #wizard-header .step,
#wizard-header .step
{
border-left: 4px solid transparent;
}
:host #wizard-header .step.active,
#wizard-header .step.active
{
border-left: 4px solid var(--primary-color);
}
:host .wizard-title-container.visible,
.wizard-title-container.visible
{
margin-top: 15px;
margin-bottom: 15px;
padding-bottom: 15px;
/*border-color: #e7eaec;*/
/*border-style: solid solid none;*/
border-bottom: solid 1px #e7eaec;
}
:host form-wizard .wizard-title,
form-wizard .wizard-title
{
margin-left: 15px;
margin-right: 15px;
font-size: 14px;
font-weight: 600;
}
:host form-wizard #wizard-header > span .badge-lg,
form-wizard #wizard-header > span .badge-lg
{
color: var(--primary-text-color);
background-color: var(--primary-color);
}
:host form-wizard #wizard-header > span .title,
form-wizard #wizard-header > span .title {
font-size: 16px;
font-weight: 300;
}
:host form-wizard #wizard-header > span.is-complete .badge-lg,
form-wizard #wizard-header > span.is-complete .badge-lg
{
color: var(--btn-success-color);
background-color: var(--btn-success-bg-color);
}
:host form-wizard #wizard-header > span.active .badge-lg,
form-wizard #wizard-header > span.active .badge-lg
{
color: var(--primary-text-color);
background-color: var(--primary-color);
}
:host form-wizard #wizard-header > span.active .title,
form-wizard #wizard-header > span.active .title
{
/* color: var(--wizard-header-active-color); */
}
:host form-wizard #wizard-header > span.step:hover:not(.step-disabled),
form-wizard #wizard-header > span.step:hover:not(.step-disabled)
{
/* background: #f3f3f4; */
}
:host form-wizard #wizard-header > span.step:hover:not(.step-disabled) .title,
form-wizard #wizard-header > span.step:hover:not(.step-disabled) .title
{
/* color: var(--wizard-header-active-color); */
}
:host form-wizard #wizard-header > span.step:hover:not(.step-disabled):not(.is-complete) .badge-lg,
form-wizard #wizard-header > span.step:hover:not(.step-disabled):not(.is-complete) .badge-lg
{
color: var(--btn-primary-color-hover);
background-color: var(--btn-primary-bg-color-hover);
}
:host form-wizard #wizard-header > span.step.is-complete:hover:not(.active) .badge-lg,
form-wizard #wizard-header > span.step.is-complete:hover:not(.active) .badge-lg
{
color: var(--btn-success-color-hover);
background-color: var(--btn-success-bg-color-hover);
}
:host form-wizard #wizard-header > span.step.step-disabled .badge-lg,
form-wizard #wizard-header > span.step.step-disabled .badge-lg
{
background-color: var(--btn-primary-bg-color-disabled);
border: var(--btn-primary-border-disabled);
}
:host form-wizard #wizard-header > span.step.step-disabled:hover,
form-wizard #wizard-header > span.step.step-disabled:hover
{
cursor: initial;
}
:host form-wizard .badge-lg,
form-wizard .badge-lg
{
height: 45px;
width: 45px;
padding: 15px 20px;
border-radius: 50px !important;
font-size: 16px;
}
:host form-wizard progress::-webkit-progress-value,
form-wizard progress::-webkit-progress-value
{
transition: width .6s ease;
}
:host form-wizard progress[value],
form-wizard progress[value]
{
-webkit-appearance: none;
appearance: none;
background-color: #f5f5f5;
border-radius: 3px;
/* width: calc(100% - 40px); */
width: calc(100%);
height: 20px;
}
:host form-wizard progress[value]::-webkit-progress-bar,
form-wizard progress[value]::-webkit-progress-bar
{
background-color: #f5f5f5;
border-radius: 3px;
}
:host form-wizard progress[value]::-webkit-progress-value,
form-wizard progress[value]::-webkit-progress-value
{
/*background-size: 35px 35px, 100% 100%, 100% 100%;*/
border-radius:3px;
/* background-color: #0369B1; */
background-color: var(--primary-color);
}
:host form-wizard form-wizard-item,
form-wizard form-wizard-item
{
min-height: 225px;
}
<use-shadow-dom></use-shadow-dom>
<div id="wizard-title"
class="flex-column-none"
display.style="titleVisibility === 'visible' ? 'block' : 'none !important'">
<slot name="title"></slot>
</div>
<div id="wizard-container" class="${containerClass}">
<div id="wizard-header" class="${headerClass}">
<span repeat.for="step of steps & signal:'name-signal'"
click.trigger="navClick($event)"
class="${selectedStepIndex === step.stepIndex ? 'active' : ''} ${step.isComplete ? 'is-complete' : ''} ${step.disabled ? 'step-disabled' : ''} ${step.isVisible ? '' : 'hidden'} step"
disabled.bind="step.disabled"
data-index="${step.stepIndex & signal:'name-signal'}">
<span class="badge-lg pointer-events-none">${step.stepIndex + 1 & signal:'name-signal'}</span>
<span class="margin-left-10 title pointer-events-none"> ${step.title} </span>
</span>
</div>
<div id="wizard-content" class="${contentClass} ${contentCustomClass}" style="min-height: 0;">
<progress if.bind="progressOrientation === 'top'" id="wizard-progress" class="${progressClass} ${progressVisibility === 'visible' ? '' : 'hidden'}" max="${numberSteps & signal:'name-signal'}"
value="${progressValue}">
</progress>
<slot></slot>
<progress if.bind="progressOrientation === 'bottom'" id="wizard-progress" class="${progressClass} ${progressVisibility === 'visible' ? '' : 'hidden'}" max="${numberSteps & signal:'name-signal'}"
value="${progressValue}">
</progress>
</div>
</div>
import { inject, customElement, bindable, BindingMode, children, ISignaler, EventAggregator, shadowCSS } from 'aurelia';
import {FormWizardItem} from './form-wizard-item';
@inject(Element, ISignaler, EventAggregator)
export class FormWizard {
@children({ filter: el => el && el.nodeType === 1 && el.matches('form-wizard-item') }) steps = [];
// @children('form-wizard-item') steps = [];
@bindable titleVisibility = 'hidden';
@bindable orientation = 'top';
@bindable containerClass = '';
@bindable headerClass = '';
@bindable contentClass = '';
@bindable contentCustomClass = '';
@bindable progressVisibility = 'hidden';
@bindable progressOrientation = 'top';
@bindable progressClass = '';
@bindable numberSteps = 1;
@bindable progressValue = 0;
@bindable selectedStepIndex = 0;
@bindable computeStepsTrigger;
@bindable credential;
constructor(element, signaler, messageBus) {
this.element = element;
this.signaler = signaler;
this.messageBus = messageBus;
}
/**
* This function fires whenever the selectedStep property changes.
* It then determines the correct step and calls the firesSelectionChange
* function.
*/
selectedStepIndexChanged(newValue, oldValue) {
this.progressValue = this.selectedStepIndex + 1;
this.fireSelectionChange();
}
/**
* This function fires whenever the orientation property changes.
* It then determines the layout of the wizard.
*/
orientationChanged(newValue, oldValue) {
// console.log('orientationChanged', newValue);
if (newValue === 'top') {
this.containerClass = 'flex-column-1'
this.headerClass = 'flex-row-none order-0 header-top'
this.contentClass = 'flex-row-1 order-1'
} else if (newValue === 'bottom') {
this.containerClass = 'flex-column-1'
this.headerClass = 'flex-row-none order-1'
this.contentClass = 'flex-row-1 order-0'
} else if (newValue === 'left') {
debugger;
this.containerClass = 'grid-cols-2';
// this.containerClass = 'flex-row-1'
// this.headerClass = 'flex-column-none order-0'
// this.contentClass = 'flex-column-1 order-1'
} else if (newValue === 'right') {
this.containerClass = 'flex-row-1'
this.headerClass = 'flex-column-none order-1'
this.contentClass = 'flex-column-1 order-0'
}
}
/**
* This function fires whenever the computeStepsTrigger expression
* changes. It will then filter and compute the steps based on the
* expression.
* @param {*} newValue
*/
async computeStepsTriggerChanged(newValue) {
await wait(150);
this.steps.forEach((step, index) => {
if (!step.isVisible) {
step.stepIndex = -step.stepIndex;
}
});
const visibleSteps = this.steps.filter(s => s.isVisible);
visibleSteps.forEach((step, index) => {
step.stepIndex = index;
});
this.numberSteps = visibleSteps.length;
this.signaler.signal('name-signal');
}
/**
* This function is called when the element is attached to the DOM.
*/
afterAttach() {
this.firstStepSub = this.messageBus.subscribe('wizard:firststep', this.firstStep.bind(this));
this.nextStepSub = this.messageBus.subscribe('wizard:nextstep', this.nextStep.bind(this));
this.gotoStepSub = this.messageBus.subscribe('wizard:gotostep', this.gotoStep.bind(this));
this.prevStepSub = this.messageBus.subscribe('wizard:prevstep', this.prevStep.bind(this));
this.lastStepSub = this.messageBus.subscribe('wizard:laststep', this.lastStep.bind(this));
this.completeStepSub = this.messageBus.subscribe('wizard:complete-step', (payload) => {
const {index} = payload;
this.completeStep(index);
});
this.completeCurrentStepSub = this.messageBus.subscribe('wizard:complete-current-step', () => {
this.completeCurrentStep();
});
this.completeStepAndGoToLastStepSub = this.messageBus.subscribe('wizard:complete-current-step-and-go-to-last', () => {
this.completeStepAndGoToLastStep();
});
this.numberSteps = this.steps.length;
this.steps.forEach((item, index) => {
item.stepIndex = index;
});
this.progressValue = this.selectedStepIndex + 1;
}
/**
* This function is called when the element detached from the DOM.
*/
afterDetach() {
this.firstStepSub.dispose();
this.nextStepSub.dispose();
this.gotoStepSub.dispose();
this.prevStepSub.dispose();
this.lastStepSub.dispose();
this.completeStepSub.dispose();
this.completeCurrentStepSub.dispose();
this.completeStepAndGoToLastStepSub.dispose();
}
/**
* This function is fired when a user clicks on individual
* steps. It then navigates the user to the corresponding
* step.
*/
async navClick(e) {
e.preventDefault();
e.stopPropagation();
debugger;
let canContinue = false;
const index = Number(e.currentTarget.attributes['data-index'].value);
const isMovingForward = index > this.selectedStepIndex;
const currentStep = this.steps[this.selectedStepIndex];
const nextStep = this.steps[index];
if (nextStep.disabled) return;
if (!isMovingForward) {
canContinue = true;
} else if (nextStep.navClick) {
canContinue = await nextStep.navClick();
}
if (canContinue) {
if (isMovingForward) {
currentStep.isComplete = true;
}
this.selectedStepIndex = index;
}
}
/**
* This function fires whenever the seletectStepChange event fires.
* It dispatches events for both changing and changed events.
*/
async fireSelectionChange() {
const selectionChangingEvent = new CustomEvent('wizard-selection-changing', {bubbles: true, detail: this.selectedStepIndex});
this.element.dispatchEvent(selectionChangingEvent);
await wait(25);
this.steps.forEach((item, index) => {
item.selectedStepIndex = this.selectedStepIndex;
});
const selectionChangedEvent = new CustomEvent('wizard-selection-changed', {bubbles: true, detail: this.selectedStepIndex});
this.element.dispatchEvent(selectionChangedEvent);
}
/**
* This function navigates the wizard to the first step.
*/
firstStep() {
this.selectedStepIndex = 0;
}
/**
* This function navigates the wizard to the next step.
*/
nextStep() {
let count = this.steps.length;
if (this.selectedStepIndex < count - 1) {
this.selectedStepIndex++;
}
}
/**
* This function navigates the wizard to the index provided.
*/
gotoStep(payload) {
let count = this.steps.length;
if (payload.index > 0 && payload.index < count) {
this.selectedStepIndex = payload.index;
}
}
/**
* This function navigates the wizard to the previous step.
*/
prevStep() {
let count = this.steps.length;
if (this.selectedStepIndex > 0) {
this.selectedStepIndex--;
}
}
/**
* This function navigates the wizard to the last step.
*/
lastStep() {
this.selectedStepIndex = this.steps.length - 1;
}
completeStep(index) {
this.steps[index].isComplete = true;
}
completeStepAndGoToLastStep() {
this.steps[this.selectedStepIndex].isComplete = true;
this.selectedStepIndex = this.steps.length - 1;
}
completeCurrentStep() {
this.steps[this.selectedStepIndex].isComplete = true;
this.nextStep();
}
}
function wait(t) {
return new Promise(r => setTimeout(r, t));
}
import Aurelia from 'aurelia';
import { MyApp } from './my-app';
import {FormWizard} from './form-wizard';
import {FormWizardItem} from './form-wizard-item';
import {Wizard} from './wizard';
Aurelia
.register(FormWizard)
.register(FormWizardItem)
.register(Wizard)
.app(MyApp).start();
<!--
Try to create a paired css/scss/sass/less file like my-app.scss.
It will be automatically imported based on convention.
-->
<!--
There is no bundler config you can change in Dumber Gist to
turn on shadow DOM.
But you can turn shadow DOM on by adding a meta tag in every
html template:
<use-shadow-dom>
-->
<h1>${message}</h1>
<form-wizard view-model.ref="wizard"
title-visibility="visible"
title="Create Ticket"
progress-class="margin-bottom-15"
progress-visibility="visible"
progress-orientation="top"
orientation="left"
content-custom-class="margin-20"
compute-steps-trigger.bind="project.type & throttle:500">
<div slot="title" class="wizard-title-container">
<span class="wizard-title">New Project Wizard</span>
</div>
</form-wizard>
<wizard steps.bind="[
{ title: 'Project name', component: 'project-name' },
{ title: 'Project description', component: 'project-description' },
]">
<div slot="title" class="wizard-title-container">
<span class="wizard-title">New New Project Wizard</span>
</div>
</wizard>
export class MyApp {
message = 'Hello Aurelia 2!';
wizard = null;
}
<use-shadow-dom></use-shadow-dom>
Wizard:
<div id="wizard-title"
class="flex-column-none"
display.style="titleVisibility === 'visible' ? 'block' : 'none !important'">
<slot name="title"></slot>
</div>
<div id="wizard-container" class="${containerClass}">
<div id="wizard-header" class="${headerClass}">
<a repeat.for="step of steps"
load.bind="step.component"
class="${step.isComplete ? 'is-complete' : ''} ${step.disabled ? 'step-disabled' : ''} ${step.isVisible ? '' : 'hidden'} step"
disabled.bind="step.disabled">
<span class="badge-lg pointer-events-none">${step.stepIndex + 1}</span>
<span class="margin-left-10 title pointer-events-none"> ${step.title} </span>
</a>
</div>
<div id="wizard-content" class="${contentClass} ${contentCustomClass}" style="min-height: 0;">
<progress if.bind="progressOrientation === 'top'" id="wizard-progress" class="${progressClass} ${progressVisibility === 'visible' ? '' : 'hidden'}" max="${numberSteps & signal:'name-signal'}"
value="${progressValue}">
</progress>
<au-viewport name="wizard-viewport"></au-viewport>
<progress if.bind="progressOrientation === 'bottom'" id="wizard-progress" class="${progressClass} ${progressVisibility === 'visible' ? '' : 'hidden'}" max="${numberSteps & signal:'name-signal'}"
value="${progressValue}">
</progress>
</div>
</div>
import { inject, customElement, bindable, BindingMode, children, ISignaler, EventAggregator, shadowCSS } from 'aurelia';
import {FormWizardItem} from './form-wizard-item';
@inject(Element, ISignaler, EventAggregator)
export class Wizard {
@bindable steps = [];
@bindable titleVisibility = 'hidden';
@bindable orientation = 'top';
@bindable containerClass = '';
@bindable headerClass = '';
@bindable contentClass = '';
@bindable contentCustomClass = '';
@bindable progressVisibility = 'hidden';
@bindable progressOrientation = 'top';
@bindable progressClass = '';
@bindable numberSteps = 1;
@bindable progressValue = 0;
@bindable selectedStepIndex = 0;
@bindable computeStepsTrigger;
@bindable credential;
constructor(element, signaler, messageBus) {
this.element = element;
this.signaler = signaler;
this.messageBus = messageBus;
}
/**
* This function fires whenever the selectedStep property changes.
* It then determines the correct step and calls the firesSelectionChange
* function.
*/
selectedStepIndexChanged(newValue, oldValue) {
this.progressValue = this.selectedStepIndex + 1;
this.fireSelectionChange();
}
/**
* This function fires whenever the orientation property changes.
* It then determines the layout of the wizard.
*/
orientationChanged(newValue, oldValue) {
// console.log('orientationChanged', newValue);
if (newValue === 'top') {
this.containerClass = 'flex-column-1'
this.headerClass = 'flex-row-none order-0 header-top'
this.contentClass = 'flex-row-1 order-1'
} else if (newValue === 'bottom') {
this.containerClass = 'flex-column-1'
this.headerClass = 'flex-row-none order-1'
this.contentClass = 'flex-row-1 order-0'
} else if (newValue === 'left') {
debugger;
this.containerClass = 'grid-cols-2';
// this.containerClass = 'flex-row-1'
// this.headerClass = 'flex-column-none order-0'
// this.contentClass = 'flex-column-1 order-1'
} else if (newValue === 'right') {
this.containerClass = 'flex-row-1'
this.headerClass = 'flex-column-none order-1'
this.contentClass = 'flex-column-1 order-0'
}
}
/**
* This function fires whenever the computeStepsTrigger expression
* changes. It will then filter and compute the steps based on the
* expression.
* @param {*} newValue
*/
async computeStepsTriggerChanged(newValue) {
await wait(150);
this.steps.forEach((step, index) => {
if (!step.isVisible) {
step.stepIndex = -step.stepIndex;
}
});
const visibleSteps = this.steps.filter(s => s.isVisible);
visibleSteps.forEach((step, index) => {
step.stepIndex = index;
});
this.numberSteps = visibleSteps.length;
this.signaler.signal('name-signal');
}
/**
* This function is called when the element is attached to the DOM.
*/
afterAttach() {
this.firstStepSub = this.messageBus.subscribe('wizard:firststep', this.firstStep.bind(this));
this.nextStepSub = this.messageBus.subscribe('wizard:nextstep', this.nextStep.bind(this));
this.gotoStepSub = this.messageBus.subscribe('wizard:gotostep', this.gotoStep.bind(this));
this.prevStepSub = this.messageBus.subscribe('wizard:prevstep', this.prevStep.bind(this));
this.lastStepSub = this.messageBus.subscribe('wizard:laststep', this.lastStep.bind(this));
this.completeStepSub = this.messageBus.subscribe('wizard:complete-step', (payload) => {
const {index} = payload;
this.completeStep(index);
});
this.completeCurrentStepSub = this.messageBus.subscribe('wizard:complete-current-step', () => {
this.completeCurrentStep();
});
this.completeStepAndGoToLastStepSub = this.messageBus.subscribe('wizard:complete-current-step-and-go-to-last', () => {
this.completeStepAndGoToLastStep();
});
this.numberSteps = this.steps.length;
this.steps.forEach((item, index) => {
item.stepIndex = index;
});
this.progressValue = this.selectedStepIndex + 1;
}
/**
* This function is called when the element detached from the DOM.
*/
afterDetach() {
this.firstStepSub.dispose();
this.nextStepSub.dispose();
this.gotoStepSub.dispose();
this.prevStepSub.dispose();
this.lastStepSub.dispose();
this.completeStepSub.dispose();
this.completeCurrentStepSub.dispose();
this.completeStepAndGoToLastStepSub.dispose();
}
/**
* This function is fired when a user clicks on individual
* steps. It then navigates the user to the corresponding
* step.
*/
async navClick(e) {
e.preventDefault();
e.stopPropagation();
debugger;
let canContinue = false;
const index = Number(e.currentTarget.attributes['data-index'].value);
const isMovingForward = index > this.selectedStepIndex;
const currentStep = this.steps[this.selectedStepIndex];
const nextStep = this.steps[index];
if (nextStep.disabled) return;
if (!isMovingForward) {
canContinue = true;
} else if (nextStep.navClick) {
canContinue = await nextStep.navClick();
}
if (canContinue) {
if (isMovingForward) {
currentStep.isComplete = true;
}
this.selectedStepIndex = index;
}
}
/**
* This function fires whenever the seletectStepChange event fires.
* It dispatches events for both changing and changed events.
*/
async fireSelectionChange() {
const selectionChangingEvent = new CustomEvent('wizard-selection-changing', {bubbles: true, detail: this.selectedStepIndex});
this.element.dispatchEvent(selectionChangingEvent);
await wait(25);
this.steps.forEach((item, index) => {
item.selectedStepIndex = this.selectedStepIndex;
});
const selectionChangedEvent = new CustomEvent('wizard-selection-changed', {bubbles: true, detail: this.selectedStepIndex});
this.element.dispatchEvent(selectionChangedEvent);
}
/**
* This function navigates the wizard to the first step.
*/
firstStep() {
this.selectedStepIndex = 0;
}
/**
* This function navigates the wizard to the next step.
*/
nextStep() {
let count = this.steps.length;
if (this.selectedStepIndex < count - 1) {
this.selectedStepIndex++;
}
}
/**
* This function navigates the wizard to the index provided.
*/
gotoStep(payload) {
let count = this.steps.length;
if (payload.index > 0 && payload.index < count) {
this.selectedStepIndex = payload.index;
}
}
/**
* This function navigates the wizard to the previous step.
*/
prevStep() {
let count = this.steps.length;
if (this.selectedStepIndex > 0) {
this.selectedStepIndex--;
}
}
/**
* This function navigates the wizard to the last step.
*/
lastStep() {
this.selectedStepIndex = this.steps.length - 1;
}
completeStep(index) {
this.steps[index].isComplete = true;
}
completeStepAndGoToLastStep() {
this.steps[this.selectedStepIndex].isComplete = true;
this.selectedStepIndex = this.steps.length - 1;
}
completeCurrentStep() {
this.steps[this.selectedStepIndex].isComplete = true;
this.nextStep();
}
}
function wait(t) {
return new Promise(r => setTimeout(r, t));
}
<div title="Project Description" class="flex-row-1">
<div class="flex-column-1">
<div class="flex-column-1">
<div class="form-group">
<label>Project Description</label>
<input class="form-control" value.bind="description">
</div>
<p>Enter a description for your project.</p>
</div>
<div class="flex-row-none justify-content-end">
<div class="flex-row-1 justify-content-start">
</div>
<div class="flex-row-1 justify-content-center">
</div>
<div class="flex-row-1 justify-content-end">
<button class="btn btn-primary"
click.trigger="wizard.prevStep($event)">
Previous
</button>
<button class="btn btn-primary"
click.trigger="wizard.nextStep($event)">
Next
</button>
</div>
</div>
</div>
</div>
<div title="Project Name" class="flex-row-1">
<div class="flex-column-1">
<div class="flex-column-1">
<div class="form-group">
<label>Project Name</label>
<input class="form-control" value.bind="name">
</div>
<p>Enter a unique name for your project.</p>
</div>
<div class="flex-row-none justify-content-end">
<div class="flex-row-1 justify-content-start">
</div>
<div class="flex-row-1 justify-content-center">
</div>
<div class="flex-row-1 justify-content-end">
<button class="btn btn-primary"
click.trigger="wizard.nextStep($event)">
Next
</button>
</div>
</div>
</div>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment