Skip to content

Commit

Permalink
fix(VsStepper): apply index-selector-composable (#280)
Browse files Browse the repository at this point in the history
  • Loading branch information
smithoo committed Sep 11, 2024
1 parent 718ff8c commit 61451f6
Show file tree
Hide file tree
Showing 8 changed files with 793 additions and 313 deletions.
24 changes: 15 additions & 9 deletions packages/vlossom/src/components/vs-stepper/VsStepper.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ $stepButtonW: var(--vs-stepper-stepSize, 2.4rem);
position: relative;
-webkit-tap-highlight-color: transparent;

.vs-item-line {
.vs-step-line {
background-color: var(--vs-area-bg-active);
height: 0.3rem;
left: $stepButtonW;
Expand All @@ -16,7 +16,7 @@ $stepButtonW: var(--vs-stepper-stepSize, 2.4rem);
top: 50%;
transform: translateY(-50%);

.vs-progress-line {
.vs-step-progress {
background-color: var(--vs-stepper-activeColor, var(--vs-primary-comp-bg-active));
height: 100%;
opacity: 0.8;
Expand All @@ -33,15 +33,19 @@ $stepButtonW: var(--vs-stepper-stepSize, 2.4rem);
list-style: none;
margin-bottom: 4rem;

.vs-step {
&.vs-stepper-no-label {
margin-bottom: 0;
}

.vs-step-item {
align-items: center;
cursor: pointer;
display: flex;
flex-direction: row;
justify-content: center;
position: relative;

.vs-item-step {
.vs-step-num {
align-items: center;
background-color: var(--vs-comp-bg);
color: var(--vs-comp-font);
Expand All @@ -67,7 +71,7 @@ $stepButtonW: var(--vs-stepper-stepSize, 2.4rem);
}
}

.vs-item-name {
.vs-step-label {
color: var(--vs-stepper-labelFontColor, var(--vs-font-color));
font-size: $fontSize;
font-weight: 400;
Expand All @@ -83,28 +87,30 @@ $stepButtonW: var(--vs-stepper-stepSize, 2.4rem);
}

&.vs-previous {
.vs-item-step {
.vs-step-num {
border: var(--vs-stepper-activeColor, var(--vs-primary-comp-bg));
background-color: var(--vs-stepper-activeBackgroundColor, var(--vs-primary-comp-bg));
color: var(--vs-primary-comp-font);
}

.vs-item-name {
.vs-step-label {
color: var(--vs-stepper-labelFontColor, var(--vs-primary-comp-bg-active));
}
}

&.vs-selected {
.vs-item-step {
.vs-step-num {
border: 1px solid var(--vs-stepper-activeColor, var(--vs-primary-comp-bg));
background-color: var(--vs-stepper-activeBackgroundColor, var(--vs-primary-comp-bg));
color: var(--vs-primary-comp-font);

outline: 3px solid var(--vs-primary-comp-bg);
outline-offset: 3px;
transition: outline;
transition-delay: 0.15s;
}

.vs-item-name {
.vs-step-label {
font-weight: 600;
color: var(--vs-stepper-labelFontColor, var(--vs-primary-comp-bg));
}
Expand Down
155 changes: 48 additions & 107 deletions packages/vlossom/src/components/vs-stepper/VsStepper.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<template>
<vs-responsive :width="width" :grid="grid">
<div :class="['vs-stepper', colorSchemeClass]" :style="{ ...computedStyleSet, ...fixedWidth }">
<div class="vs-item-line">
<div class="vs-progress-line" :style="progressWidth" />
<div class="vs-step-line">
<div class="vs-step-progress" :style="progressWidth" />
</div>
<ul role="tablist" class="vs-steps">
<ul role="tablist" :class="['vs-steps', { 'vs-stepper-no-label': noLabel }]">
<li
v-for="(item, index) in steps"
v-for="(step, index) in steps"
ref="stepRefs"
class="vs-step"
:key="item"
class="vs-step-item"
:key="step"
:class="[
{
'vs-previous': isPrevious(index),
Expand All @@ -24,11 +24,11 @@
@click.stop="selectStep(index)"
@keydown.stop="handleKeydown"
>
<div class="vs-item-step">
<slot :name="`${item}-step`" :item="item" :index="index"> {{ index + 1 }} </slot>
<div class="vs-step-num">
<slot :name="`step-${step}`" :step="step" :index="index">{{ index + 1 }}</slot>
</div>
<div class="vs-item-name">
<slot :name="`${item}-name`" :item="item" :index="index"> {{ item }} </slot>
<div class="vs-step-label" v-if="!noLabel">
<slot :name="`label-${step}`" :step="step" :index="index">{{ step }}</slot>
</div>
</li>
</ul>
Expand All @@ -38,7 +38,7 @@

<script lang="ts">
import { computed, defineComponent, toRefs, ref, watch, type Ref, type PropType } from 'vue';
import { useColorScheme, useStyleSet, getResponsiveProps } from '@/composables';
import { useColorScheme, useStyleSet, getResponsiveProps, useIndexSelector } from '@/composables';
import { VsComponent, ColorScheme } from '@/declaration';
import { utils } from '@/utils';
import VsResponsive from '@/components/vs-responsive/VsResponsive.vue';
Expand All @@ -53,19 +53,24 @@ export default defineComponent({
...getResponsiveProps(),
colorScheme: { type: String as PropType<ColorScheme> },
styleSet: { type: [String, Object] as PropType<string | VsStepperStyleSet> },
disabled: { type: Array as PropType<number[]>, default: () => [] },
gap: { type: [String, Number], default: '' },
steps: {
type: Array as PropType<string[]>,
required: true,
validator: (prop: string[]) => {
const isValid = utils.object.isUniq(prop);
disabled: {
type: Array as PropType<number[]>,
default: () => [],
validator: (value: number[], props: any) => {
const stepsLength = props.steps.length;
const isValid = value.every((i) => i >= 0 && i < stepsLength);
if (!isValid) {
utils.log.propError(name, 'steps', 'steps with duplicate items are not allowed');
utils.log.propWarning(name, 'disabled', 'Disabled index is out of range.');
}
return isValid;
},
},
gap: { type: [String, Number], default: '' },
noLabel: { type: Boolean, default: false },
steps: {
type: Array as PropType<string[]>,
required: true,
},
// v-model
modelValue: { type: Number, default: 0 },
},
Expand All @@ -79,7 +84,18 @@ export default defineComponent({
const stepRefs: Ref<HTMLElement[]> = ref([]);
const selected = ref(modelValue.value);
const {
selectedIndex,
isSelected,
isDisabled,
isPrevious,
findNextActivedIndex,
getInitialIndex,
selectIndex: selectStep,
handleKeydown,
} = useIndexSelector(steps, disabled);
selectStep(getInitialIndex(modelValue.value));
const gapCount = computed(() => steps.value.length - 1);
Expand Down Expand Up @@ -117,110 +133,35 @@ export default defineComponent({
width: `${gapCount.value * value}${unit}`,
};
});
const progressWidth = computed(() => {
if (selectedIndex.value === -1) {
return { width: '0%' };
}
return {
width: (selected.value / gapCount.value) * 100 + '%',
width: (selectedIndex.value / gapCount.value) * 100 + '%',
};
});
function isDisabled(index: number) {
return disabled.value.includes(index);
}
function isPrevious(index: number) {
return index < selected.value;
}
function isSelected(index: number) {
return selected.value === index;
}
function selectStep(index: number) {
if (index < 0 || index > gapCount.value) {
selected.value = 0;
return;
}
if (isDisabled(index)) {
return;
}
selected.value = index;
}
watch(steps, () => {
selectStep(modelValue.value);
selectStep(findNextActivedIndex(0));
});
watch(selected, (index: number) => {
watch(selectedIndex, (index: number) => {
stepRefs.value[index]?.focus();
if (index !== modelValue.value) {
emit('update:modelValue', index);
emit('change', index);
}
emit('update:modelValue', index);
emit('change', index);
});
watch(
modelValue,
(index: number) => {
selectStep(index);
},
{ immediate: true },
);
function findNextActivedIndex(startIndex: number): number {
let length = steps.value.length;
for (let i = startIndex; i < length + startIndex; i++) {
const index = i % length;
if (!isDisabled(index)) {
return index;
}
}
return startIndex;
}
function findPreviousActivedIndex(startIndex: number): number {
let length = steps.value.length;
for (let i = startIndex; i > startIndex - length; i--) {
const index = (i + length) % length;
if (!isDisabled(index)) {
return index;
}
}
return startIndex;
}
function handleKeydown(event: KeyboardEvent) {
const length = steps.value.length;
let targetIndex = selected.value;
switch (event.code) {
case 'ArrowLeft':
targetIndex = findPreviousActivedIndex(targetIndex - 1);
break;
case 'ArrowRight':
targetIndex = findNextActivedIndex(targetIndex + 1);
break;
case 'Home':
targetIndex = findNextActivedIndex(0);
break;
case 'End':
targetIndex = findPreviousActivedIndex(length - 1);
break;
default:
return;
}
event.preventDefault();
selectStep(targetIndex);
}
watch(modelValue, selectStep);
return {
colorSchemeClass,
computedStyleSet,
progressWidth,
fixedWidth,
selected,
selectedIndex,
selectStep,
isPrevious,
isSelected,
Expand Down
Loading

0 comments on commit 61451f6

Please sign in to comment.