feat(Stepper): add lockOnComplete prop

This commit is contained in:
Alfarish Fizikri
2025-07-27 07:22:43 +07:00
parent b7562ef2ba
commit bafee9ccbd
2 changed files with 24 additions and 9 deletions

View File

@@ -14,7 +14,7 @@
@click="() => handleStepClick(index + 1)" @click="() => handleStepClick(index + 1)"
:class="[ :class="[
'relative outline-none flex h-8 w-8 items-center justify-center rounded-full font-semibold', 'relative outline-none flex h-8 w-8 items-center justify-center rounded-full font-semibold',
isCompleted ? 'cursor-default' : 'cursor-pointer' isCompleted && lockOnComplete ? 'cursor-default' : 'cursor-pointer'
]" ]"
:style="getStepIndicatorStyle(index + 1)" :style="getStepIndicatorStyle(index + 1)"
> >
@@ -154,6 +154,7 @@ interface StepperProps {
nextButtonText?: string; nextButtonText?: string;
disableStepIndicators?: boolean; disableStepIndicators?: boolean;
renderStepIndicator?: Component; renderStepIndicator?: Component;
lockOnComplete?: boolean;
} }
const props = withDefaults(defineProps<StepperProps>(), { const props = withDefaults(defineProps<StepperProps>(), {
@@ -169,7 +170,8 @@ const props = withDefaults(defineProps<StepperProps>(), {
backButtonText: 'Back', backButtonText: 'Back',
nextButtonText: 'Continue', nextButtonText: 'Continue',
disableStepIndicators: false, disableStepIndicators: false,
renderStepIndicator: undefined renderStepIndicator: undefined,
lockOnComplete: true
}); });
const slots = useSlots(); const slots = useSlots();
@@ -212,7 +214,7 @@ const getStepContentExit = () => ({
}); });
const handleStepClick = (step: number) => { const handleStepClick = (step: number) => {
if (isCompleted.value) return; if (isCompleted.value && props.lockOnComplete) return;
if (!props.disableStepIndicators) { if (!props.disableStepIndicators) {
direction.value = step > currentStep.value ? 1 : -1; direction.value = step > currentStep.value ? 1 : -1;
updateStep(step); updateStep(step);
@@ -220,7 +222,7 @@ const handleStepClick = (step: number) => {
}; };
const handleCustomStepClick = (clicked: number) => { const handleCustomStepClick = (clicked: number) => {
if (isCompleted.value) return; if (isCompleted.value && props.lockOnComplete) return;
if (clicked !== currentStep.value && !props.disableStepIndicators) { if (clicked !== currentStep.value && !props.disableStepIndicators) {
direction.value = clicked > currentStep.value ? 1 : -1; direction.value = clicked > currentStep.value ? 1 : -1;
updateStep(clicked); updateStep(clicked);
@@ -259,12 +261,18 @@ const handleComplete = () => {
props.onFinalStepCompleted?.(); props.onFinalStepCompleted?.();
}; };
watch(currentStep, newStep => { watch(
props.onStepChange?.(newStep); currentStep,
if (!isCompleted.value) { (newStep, oldStep) => {
measureHeight(); props.onStepChange?.(newStep);
if (newStep !== oldStep && !isCompleted.value) {
nextTick(measureHeight);
} else if (!props.lockOnComplete && isCompleted.value) {
isCompleted.value = false;
nextTick(measureHeight);
}
} }
}); );
onMounted(() => { onMounted(() => {
if (props.initialStep !== 1) { if (props.initialStep !== 1) {

View File

@@ -21,6 +21,7 @@
:on-final-step-completed="handleFinalStepCompleted" :on-final-step-completed="handleFinalStepCompleted"
:next-button-props="{ disabled: step === 3 && !name }" :next-button-props="{ disabled: step === 3 && !name }"
:disable-step-indicators="step === 3 && !name" :disable-step-indicators="step === 3 && !name"
:lock-on-complete="false"
back-button-text="Previous" back-button-text="Previous"
next-button-text="Next" next-button-text="Next"
> >
@@ -170,6 +171,12 @@ const propData = [
type: '(props: RenderStepIndicatorProps) => VNode', type: '(props: RenderStepIndicatorProps) => VNode',
default: 'undefined', default: 'undefined',
description: 'Renders a custom step indicator component.' description: 'Renders a custom step indicator component.'
},
{
name: 'lockOnComplete',
type: 'boolean',
default: 'false',
description: 'Prevents returning to previous steps after completing the stepper.'
} }
]; ];