You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

112 lines
4.2 KiB
Svelte

<!-- Reference: https://dribbble.com/shots/16221169-Figma-Material-Ui-components-Steppers-and-sliders -->
<script>import { getContext, onDestroy } from "svelte";
import { dynamicTransition } from "../../internal/transitions.js";
export let locked = false;
export let regionHeader = "";
export let regionContent = "";
export let regionNavigation = "";
export let state = getContext("state");
export let dispatchParent = getContext("dispatchParent");
export let stepTerm = getContext("stepTerm");
export let gap = getContext("gap");
export let justify = getContext("justify");
export let buttonBack = getContext("buttonBack");
export let buttonBackType = getContext("buttonBackType");
export let buttonBackLabel = getContext("buttonBackLabel");
export let buttonNext = getContext("buttonNext");
export let buttonNextType = getContext("buttonNextType");
export let buttonNextLabel = getContext("buttonNextLabel");
export let buttonComplete = getContext("buttonComplete");
export let buttonCompleteType = getContext("buttonCompleteType");
export let buttonCompleteLabel = getContext("buttonCompleteLabel");
export let transitions = getContext("transitions");
export let transitionIn = getContext("transitionIn");
export let transitionInParams = getContext("transitionInParams");
export let transitionOut = getContext("transitionOut");
export let transitionOutParams = getContext("transitionOutParams");
const stepIndex = $state.total;
$state.total++;
const cBase = "space-y-4";
const cHeader = "text-2xl font-bold";
const cContent = "space-y-4";
const cNavigation = "flex";
async function onNext() {
await new Promise((resolve) => setTimeout(resolve));
if (locked)
return;
$state.current++;
dispatchParent("next", { step: stepIndex, state: $state });
dispatchParent("step", { step: stepIndex, state: $state });
}
function onBack() {
$state.current--;
dispatchParent("back", { step: stepIndex, state: $state });
dispatchParent("step", { step: stepIndex, state: $state });
}
function onComplete() {
dispatchParent("complete", { step: stepIndex, state: $state });
}
$:
classesBase = `${cBase} ${$$props.class ?? ""}`;
$:
classesHeader = `${cHeader} ${regionHeader}`;
$:
classesContent = `${cContent} ${regionContent}`;
$:
classesNavigation = `${cNavigation} ${justify} ${gap} ${regionNavigation}`;
onDestroy(() => {
$state.total--;
});
</script>
{#if stepIndex === $state.current}
<div class="step {classesBase}" data-testid="step">
<!-- Slot: Header -->
<header class="step-header {classesHeader}">
<slot name="header">{stepTerm} {stepIndex + 1}</slot>
</header>
<!-- Slot: Default -->
<div class="step-content {classesContent}">
<slot>({stepTerm} {stepIndex + 1} Content)</slot>
</div>
<!-- Navigation -->
{#if $state.total > 1}
<div
class="step-navigation {classesNavigation}"
in:dynamicTransition|local={{ transition: transitionIn, params: transitionInParams, enabled: transitions }}
out:dynamicTransition|local={{ transition: transitionOut, params: transitionOutParams, enabled: transitions }}
>
{#if stepIndex === 0 && $$slots.navigation}
<!-- Slot: Navigation -->
<div class="step-navigation-slot">
<slot name="navigation" />
</div>
{:else}
<!-- Button: Back -->
<button type={buttonBackType} class="btn {buttonBack}" on:click={onBack} disabled={$state.current === 0}>
{@html buttonBackLabel}
</button>
{/if}
{#if stepIndex < $state.total - 1}
<!-- Button: Next -->
<button type={buttonNextType} class="btn {buttonNext}" on:click={onNext} disabled={locked}>
{#if locked}
<svg class="w-3 aspect-square fill-current" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path
d="M144 144v48H304V144c0-44.2-35.8-80-80-80s-80 35.8-80 80zM80 192V144C80 64.5 144.5 0 224 0s144 64.5 144 144v48h16c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V256c0-35.3 28.7-64 64-64H80z"
/>
</svg>
{/if}
<span>{@html buttonNextLabel}</span>
</button>
{:else}
<!-- Button: Complete -->
<button type={buttonCompleteType} class="btn {buttonComplete}" on:click={onComplete} disabled={locked}>
{@html buttonCompleteLabel}
</button>
{/if}
</div>
{/if}
</div>
{/if}