Does this specific 'step' feature exist? - possible feature request
ShirinShirinak opened this issue · comments
Shirin Heidari commented
Can we do steps like: 0,100,200,1000,5000 (so the value would be changing and we would have markings on the slider, so in this case there would be 3 markings on the slider (100,200.1000).
If we can't do it right now, will it be possible to add this feature in the future please? Thank you
prnews-io-tech commented
In Vue 3 you can do it by yourself using Teleport feature
prnews-io-tech commented
As i see some demand on this feature i would like to share my solution to implement steps. Feel free to use it (just pass :discrete="true"
):
<script setup lang="ts">
// this plugin has bugged typescript annotations. See https://github.com/vueform/slider/issues/71
// eslint-disable-next-line import/default
import Slider from '@vueform/slider'
import '@vueform/slider/themes/default.css'
interface Props {
max?: number;
min?: number;
step?: number;
discrete?: boolean;
tooltips?: boolean;
modelValue: number | number[];
}
const props = withDefaults(defineProps<Props>(), {
min: 0,
max: 100,
step: 10,
tooltips: true
})
const emit = defineEmits(['update:modelValue'])
const slider = ref(null)
const model = computed({
get () {
return props.modelValue
},
set (newValue) {
emit('update:modelValue', newValue)
}
})
const isArray = computed(() => Array.isArray(model.value) && model.value.length > 1)
const isDefault = (index: number) => {
if (!isArray.value) {
return (model.value as number) < index * props.step
}
const modelArray = model.value as number[]
const first = modelArray[0]
const last = modelArray[modelArray.length - 1]
const value = (index + props.min / props.step) * props.step
return last < value || first > value
}
const isActive = (index: number) => {
if (!isArray.value) {
return (model.value as number) >= index * props.step
}
const modelArray = model.value as number[]
const first = modelArray[0]
const last = modelArray[modelArray.length - 1]
const value = (index + props.min / props.step) * props.step
return last >= value && first <= value
}
</script>
<template>
<Slider
id="slider"
ref="slider"
v-model="model"
class="slider"
:tooltips="props.tooltips"
:step="props.step"
:min="props.min"
:max="props.max"
tooltip-position="bottom"
:lazy="false"
/>
<Teleport v-if="slider" to="div.slider-handle-lower > .slider-touch-area">
@
</Teleport>
<Teleport v-if="slider && isArray" to="div.slider-handle-upper > .slider-touch-area">
@
</Teleport>
<Teleport v-if="slider && discrete" to="div.slider-base">
<div class="line absolute bottom-0 top-[-1px] grid grid-flow-col items-center w-full">
<div class="h-1 w-1" />
<div
v-for="i in ((props.max - props.min) / props.step) - 1"
:key="`point-${i}`"
class="h-1 w-1 border !box-content bg-white-100 rounded-full"
:class="{
'border-accent': isActive(i),
'border-black-5': isDefault(i)
}"
/>
</div>
</Teleport>
</template>
<style scoped lang="postcss">
.slider {
@apply my-4;
--slider-height: theme('spacing.1');
--slider-bg: theme('colors.black-5');
--slider-connect-bg: theme('colors.accent');
--slider-radius: theme('borderRadius.sm');
--slider-handle-border: theme('borderWidth.DEFAULT') solid theme('borderColor.black-10');
--slider-handle-shadow: theme('boxShadow.gray');
--slider-handle-shadow-active: theme('boxShadow.gray');
--slider-tooltip-bg: theme('colors.transparent');
--slider-tooltip-bg-disabled: theme('colors.transparent');
--slider-tooltip-color: theme('colors.black-100');
--slider-tooltip-radius: theme('borderRadius.none');
--slider-tooltip-py: theme('spacing.0');
--slider-tooltip-px: theme('spacing.0');
--slider-tooltip-arrow-size: theme('spacing.0');
--slider-tooltip-distance: theme('spacing.1');
:deep(.slider-base) {
.slider-origin {
.slider-handle {
&:focus {
box-shadow: none;
}
.slider-touch-area {
@apply flex items-center justify-center text-accent;
.nuxt-icon {
@apply h-3 w-3;
}
}
.slider-tooltip {
@apply text-other;
}
}
}
}
}
</style>