Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Does this specific 'step' feature exist? - possible feature request #76

Open
ShirinShirinak opened this issue May 16, 2023 · 2 comments

Comments

@ShirinShirinak
Copy link

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

@ShirinShirinak ShirinShirinak changed the title Does this 'step' feature exist? Does this specific 'step' feature exist? - possible feature request May 16, 2023
@prnews-io-tech
Copy link

In Vue 3 you can do it by yourself using Teleport feature

@prnews-io-tech
Copy link

prnews-io-tech commented Oct 18, 2023

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>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants