mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-25 16:59:45 +00:00
* feat: Initial shadcn configuration * component: Add Slider component from shadcn-vue * deps: Add tw-animate-css * component: Align slider with Figma styles * component: Set the step value for the slider, update styles * fix: update component tests to work with Array of values * vite: Don't reload dev server for test changes * component: Swap text for a number input kept in sync with the slider * cleanup: Don't need the override if the input isn't type="number" * test: add step size tests * cleanup: Don't need cn for these * css: Update token names to match new Figma Variables * lint: Fix camelCase vs train-case in passthrough * feat: If the value is deleted, revert to the slider state cc: @PabloWiedemann * feat: Improve cursor styles, grabbable thumb, clickable track * lint: temporarily disable some warnings * feat: Grabbing while sliding (most of the time)
79 lines
2.3 KiB
Vue
79 lines
2.3 KiB
Vue
<script setup lang="ts">
|
|
import { reactiveOmit } from '@vueuse/core'
|
|
import type { SliderRootEmits, SliderRootProps } from 'reka-ui'
|
|
import {
|
|
SliderRange,
|
|
SliderRoot,
|
|
SliderThumb,
|
|
SliderTrack,
|
|
useForwardPropsEmits
|
|
} from 'reka-ui'
|
|
import { type HTMLAttributes, ref } from 'vue'
|
|
|
|
import { cn } from '@/utils/tailwindUtil'
|
|
|
|
const props = defineProps<
|
|
SliderRootProps & { class?: HTMLAttributes['class'] }
|
|
>()
|
|
|
|
const pressed = ref(false)
|
|
const setPressed = (val: boolean) => {
|
|
pressed.value = val
|
|
}
|
|
|
|
const emits = defineEmits<SliderRootEmits>()
|
|
|
|
const delegatedProps = reactiveOmit(props, 'class')
|
|
|
|
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
|
</script>
|
|
|
|
<template>
|
|
<SliderRoot
|
|
v-slot="{ modelValue }"
|
|
data-slot="slider"
|
|
:class="
|
|
cn(
|
|
'relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50',
|
|
'data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col',
|
|
props.class
|
|
)
|
|
"
|
|
v-bind="forwarded"
|
|
@slide-start="() => setPressed(true)"
|
|
@slide-move="() => setPressed(true)"
|
|
@slide-end="() => setPressed(false)"
|
|
>
|
|
<SliderTrack
|
|
data-slot="slider-track"
|
|
:class="
|
|
cn(
|
|
'bg-node-stroke relative grow overflow-hidden rounded-full',
|
|
'cursor-pointer',
|
|
'data-[orientation=horizontal]:h-0.5 data-[orientation=horizontal]:w-full',
|
|
'data-[orientation=vertical]:h-full data-[orientation=vertical]:w-0.5'
|
|
)
|
|
"
|
|
>
|
|
<SliderRange
|
|
data-slot="slider-range"
|
|
class="bg-node-component-surface-highlight absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
|
|
/>
|
|
</SliderTrack>
|
|
|
|
<SliderThumb
|
|
v-for="(_, key) in modelValue"
|
|
:key="key"
|
|
data-slot="slider-thumb"
|
|
:class="
|
|
cn(
|
|
'bg-node-component-surface-highlight ring-node-component-surface-selected block size-3.5 shrink-0 rounded-full shadow-sm transition-[color,box-shadow]',
|
|
'cursor-grab',
|
|
'hover:ring-2 focus-visible:ring-2 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50',
|
|
{ 'cursor-grabbing': pressed }
|
|
)
|
|
"
|
|
/>
|
|
</SliderRoot>
|
|
</template>
|