dees-catalog/ts_web/elements/dees-stepper.ts

283 lines
7.9 KiB
TypeScript
Raw Permalink Normal View History

2024-01-18 01:08:19 +00:00
import * as plugins from './00plugins.js';
import * as colors from './00colors.js';
2021-09-01 19:48:22 +00:00
import {
DeesElement,
customElement,
html,
css,
unsafeCSS,
2023-08-07 18:02:18 +00:00
type CSSResult,
2021-09-01 19:48:22 +00:00
cssManager,
property,
2023-08-07 18:02:18 +00:00
type TemplateResult,
2023-08-07 17:13:29 +00:00
} from '@design.estate/dees-element';
2021-08-29 15:10:25 +00:00
2023-08-07 17:13:29 +00:00
import * as domtools from '@design.estate/dees-domtools';
2021-08-29 15:10:25 +00:00
2021-09-01 19:48:22 +00:00
export interface IStep {
title: string;
content: TemplateResult;
2021-09-08 22:35:10 +00:00
validationFunc?: (stepper: DeesStepper, htmlElement: HTMLElement) => Promise<any>;
2021-09-10 13:51:30 +00:00
onReturnToStepFunc?: (stepper: DeesStepper, htmlElement: HTMLElement) => Promise<any>;
2021-09-08 22:35:10 +00:00
validationFuncCalled?: boolean;
2021-09-01 19:48:22 +00:00
}
2021-09-08 22:02:35 +00:00
declare global {
interface HTMLElementTagNameMap {
'dees-stepper': DeesStepper;
}
}
2021-08-29 15:10:25 +00:00
@customElement('dees-stepper')
export class DeesStepper extends DeesElement {
2021-09-14 15:31:16 +00:00
public static demo = () =>
html`
<dees-stepper
.steps=${[
{
title: 'Whats your name?',
content: html`
<dees-form>
<dees-input-text
key="email"
label="Your Email"
value="hello@something.com"
disabled
></dees-input-text>
<dees-input-text key="firstName" required label="Vorname"></dees-input-text>
<dees-input-text key="lastName" required label="Nachname"></dees-input-text>
<dees-form-submit>Next</dees-form-submit>
</dees-form>
`,
validationFunc: async (stepperArg, elementArg) => {
const deesForm = elementArg.querySelector('dees-form');
2023-04-12 00:47:45 +00:00
deesForm.addEventListener('formData', (eventArg) => {
2021-09-14 15:31:16 +00:00
stepperArg.goNext();
2023-04-12 00:47:45 +00:00
});
},
2021-09-14 15:31:16 +00:00
},
{
title: 'Whats your mobile number?',
content: html``,
2023-04-12 00:47:45 +00:00
},
2021-09-14 15:31:16 +00:00
] as IStep[]}
></dees-stepper>
`;
2021-08-29 15:10:25 +00:00
2021-09-01 19:48:22 +00:00
@property({
type: Array,
})
2021-09-14 15:31:16 +00:00
public steps: IStep[] = [];
2021-08-29 15:10:25 +00:00
@property({
2021-09-01 19:48:22 +00:00
type: Object,
2021-08-29 15:10:25 +00:00
})
2021-09-01 19:48:22 +00:00
public selectedStep: IStep;
constructor() {
super();
}
2021-08-29 15:10:25 +00:00
public static styles = [
cssManager.defaultStyles,
css`
:host {
position: absolute;
width: 100%;
height: 100%;
}
.stepperContainer {
position: absolute;
width: 100%;
height: 100%;
2021-09-01 19:48:22 +00:00
background: ${cssManager.bdTheme('#eeeeeb', '#000')};
2021-08-29 15:10:25 +00:00
overflow: hidden;
}
.step {
2021-09-01 19:48:22 +00:00
position: relative;
2021-09-01 20:43:31 +00:00
pointer-events: none;
2021-09-01 19:48:22 +00:00
overflow: hidden;
2021-09-01 20:43:31 +00:00
transition: all 0.7s ease-in-out;
max-width: 500px;
2021-08-29 15:10:25 +00:00
min-height: 300px;
2024-01-10 04:11:55 +00:00
border-radius: 8px;
2021-09-01 20:43:31 +00:00
background: ${cssManager.bdTheme('#ffffff', '#181818')};
2021-09-14 22:48:29 +00:00
border-top: 1px solid ${cssManager.bdTheme('#ffffff', '#181818')};
2021-09-01 19:48:22 +00:00
color: ${cssManager.bdTheme('#333', '#fff')};
2021-08-29 15:10:25 +00:00
margin: auto;
margin-bottom: 20px;
2021-09-10 13:23:54 +00:00
filter: opacity(0.5) grayscale(1);
2021-09-01 19:48:22 +00:00
box-shadow: 0px 0px 3px #00000010;
2021-09-10 13:56:37 +00:00
user-select: none;
2021-09-01 19:48:22 +00:00
}
.step.selected {
2021-09-14 22:48:29 +00:00
border-top: 1px solid #e4002b;
2021-09-01 20:43:31 +00:00
pointer-events: all;
2021-09-10 13:42:16 +00:00
filter: opacity(1) grayscale(0);
2021-09-01 19:48:22 +00:00
box-shadow: 0px 0px 5px #00000010;
2021-09-10 13:56:37 +00:00
user-select: auto;
2021-09-01 19:48:22 +00:00
}
2021-08-29 15:10:25 +00:00
2021-09-01 20:43:31 +00:00
.step.hiddenStep {
filter: opacity(0);
}
2021-09-14 22:45:14 +00:00
.step:last-child {
2021-09-14 15:31:16 +00:00
margin-bottom: 100vh;
}
2021-09-01 19:48:22 +00:00
.step .stepCounter {
2024-01-10 04:11:55 +00:00
color: #999;
2021-09-01 19:48:22 +00:00
position: absolute;
top: 0px;
right: 0px;
padding: 10px 15px;
font-size: 12px;
2021-09-01 20:43:31 +00:00
border-bottom-left-radius: 3px;
background: ${cssManager.bdTheme('#00000008', '#ffffff08')};
}
.step .goBack {
2024-01-10 04:11:55 +00:00
color: #999;
cursor: default;
2021-09-01 20:43:31 +00:00
position: absolute;
top: 0px;
left: 0px;
padding: 10px 15px;
font-size: 12px;
border-bottom-right-radius: 3px;
2021-09-01 19:48:22 +00:00
background: ${cssManager.bdTheme('#00000008', '#ffffff08')};
2021-09-01 20:43:31 +00:00
}
.step .goBack:hover {
2024-01-18 01:08:19 +00:00
color: ${cssManager.bdTheme('#333', '#fff')};
background: ${cssManager.bdTheme('#00000012', colors.dark.blue)};
}
.step .goBack:active {
color: ${cssManager.bdTheme('#333', '#fff')};
background: ${cssManager.bdTheme('#00000012', colors.dark.blueActive)};
}
.step .goBack span {
transition: all 0.2s;
display: inline-block;
}
.step .goBack:hover span {
transform: translateX(-2px);
2021-09-01 19:48:22 +00:00
}
.step .title {
text-align: center;
2021-09-01 20:43:31 +00:00
padding-top: 50px;
font-family: 'Geist Sans', sans-serif;
2021-09-01 19:48:22 +00:00
font-size: 25px;
font-weight: 300;
2021-08-29 15:10:25 +00:00
}
2021-09-01 20:43:31 +00:00
.step .content {
padding: 20px;
}
2021-09-01 19:48:22 +00:00
`,
];
2021-08-29 15:10:25 +00:00
2021-09-01 19:48:22 +00:00
public render() {
2021-08-29 15:10:25 +00:00
return html`
<div class="stepperContainer">
2021-09-01 19:48:22 +00:00
${this.steps.map(
(stepArg) =>
2021-09-14 15:31:16 +00:00
html`<div
class="step ${stepArg === this.selectedStep
? 'selected'
: null} ${this.getIndexOfStep(stepArg) > this.getIndexOfStep(this.selectedStep)
? 'hiddenStep'
: ''}"
>
${this.getIndexOfStep(stepArg) > 0
2024-01-18 01:08:19 +00:00
? html`<div class="goBack" @click=${this.goBack}><span style="font-family: Inter"><-</span> go to previous step</div>`
2021-09-14 15:31:16 +00:00
: ``}
<div class="stepCounter">
Step ${this.steps.findIndex((elementArg) => elementArg === stepArg) + 1} of
${this.steps.length}
</div>
2021-09-01 20:43:31 +00:00
<div class="title">${stepArg.title}</div>
2021-09-01 19:48:22 +00:00
<div class="content">${stepArg.content}</div>
</div> `
)}
2021-08-29 15:10:25 +00:00
</div>
`;
}
2021-09-01 19:48:22 +00:00
2021-09-01 20:43:31 +00:00
public getIndexOfStep = (stepArg: IStep): number => {
2021-09-14 15:31:16 +00:00
return this.steps.findIndex((stepArg2) => stepArg === stepArg2);
};
2021-09-01 20:43:31 +00:00
2023-04-12 00:47:45 +00:00
public async firstUpdated() {
await this.domtoolsPromise;
await this.domtools.convenience.smartdelay.delayFor(0);
2021-09-01 19:48:22 +00:00
this.selectedStep = this.steps[0];
this.setScrollStatus();
}
2023-04-12 00:47:45 +00:00
public async updated() {
this.setScrollStatus();
2021-09-01 19:48:22 +00:00
}
2021-09-01 20:44:43 +00:00
public scroller: typeof domtools.plugins.SweetScroll.prototype;
2021-09-01 19:48:22 +00:00
public async setScrollStatus() {
const stepperContainer: HTMLElement = this.shadowRoot.querySelector('.stepperContainer');
const firstStepElement: HTMLElement = this.shadowRoot.querySelector('.step');
const selectedStepElement: HTMLElement = this.shadowRoot.querySelector('.selected');
2023-04-12 00:47:45 +00:00
if (!selectedStepElement) {
return;
}
2021-09-01 20:43:31 +00:00
if (!stepperContainer.style.paddingTop) {
2021-09-14 15:31:16 +00:00
stepperContainer.style.paddingTop = `${
stepperContainer.offsetHeight / 2 - selectedStepElement.offsetHeight / 2
}px`;
2021-09-01 20:43:31 +00:00
}
2021-09-01 19:48:22 +00:00
console.log('Setting scroll status');
console.log(selectedStepElement);
2021-09-14 15:31:16 +00:00
const scrollPosition =
selectedStepElement.offsetTop -
stepperContainer.offsetHeight / 2 +
selectedStepElement.offsetHeight / 2;
2021-09-01 19:48:22 +00:00
console.log(scrollPosition);
2021-09-14 15:31:16 +00:00
const domtoolsInstance = await domtools.DomTools.setupDomTools();
2021-09-01 19:48:22 +00:00
if (!this.scroller) {
2021-09-14 15:31:16 +00:00
this.scroller = new domtools.plugins.SweetScroll(
{
vertical: true,
horizontal: false,
2022-12-07 01:28:31 +00:00
easing: 'easeInOutExpo',
duration: 700,
2021-09-14 15:31:16 +00:00
},
stepperContainer
);
2021-09-01 19:48:22 +00:00
}
2021-09-08 22:35:10 +00:00
if (!this.selectedStep.validationFuncCalled && this.selectedStep.validationFunc) {
this.selectedStep.validationFuncCalled = true;
await this.selectedStep.validationFunc(this, selectedStepElement);
}
2021-09-01 19:48:22 +00:00
this.scroller.to(scrollPosition);
}
2021-09-10 13:51:30 +00:00
public async goBack() {
2021-09-14 15:31:16 +00:00
const currentIndex = this.steps.findIndex((stepArg) => stepArg === this.selectedStep);
2021-09-01 19:48:22 +00:00
this.selectedStep = this.steps[currentIndex - 1];
2021-09-10 13:51:30 +00:00
await this.domtoolsPromise;
await this.domtools.convenience.smartdelay.delayFor(100);
this.selectedStep.onReturnToStepFunc?.(this, this.shadowRoot.querySelector('.selected'));
2021-09-01 19:48:22 +00:00
}
public goNext() {
2021-09-14 15:31:16 +00:00
const currentIndex = this.steps.findIndex((stepArg) => stepArg === this.selectedStep);
2021-09-01 20:43:31 +00:00
this.selectedStep = this.steps[currentIndex + 1];
2021-09-01 19:48:22 +00:00
}
}