routie dev init since i didn't adhere to any proper guidance up until now

This commit is contained in:
2026-04-29 22:27:29 -06:00
commit e1dabb71e2
15301 changed files with 3562618 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
@layer vuetify-components {
.v-slider .v-slider__container input {
cursor: default;
padding: 0;
width: 100%;
display: none;
}
.v-slider > .v-input__append,
.v-slider > .v-input__prepend {
padding: 0;
}
.v-slider__container {
position: relative;
min-height: inherit;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.v-input--disabled .v-slider__container {
opacity: var(--v-disabled-opacity);
}
.v-input--error:not(.v-input--disabled) .v-slider__container {
color: rgb(var(--v-theme-error));
}
.v-slider.v-input--horizontal {
align-items: center;
}
.v-slider.v-input--horizontal > .v-input__prepend {
margin-inline-end: 8px;
}
.v-slider.v-input--horizontal > .v-input__append {
margin-inline-start: 8px;
}
.v-slider.v-input--horizontal > .v-input__control {
margin-inline: 8px 8px;
min-height: 32px;
display: flex;
align-items: center;
}
.v-slider.v-input--vertical {
justify-content: center;
margin-top: 12px;
margin-bottom: 12px;
}
.v-slider.v-input--vertical > .v-input__control {
min-height: 300px;
}
.v-slider.v-input--disabled {
pointer-events: none;
}
.v-slider--has-labels > .v-input__control {
margin-bottom: 4px;
}
.v-slider__label {
margin-inline-end: 12px;
}
}
File diff suppressed because it is too large Load Diff
+162
View File
@@ -0,0 +1,162 @@
import { Fragment as _Fragment, createVNode as _createVNode, createElementVNode as _createElementVNode, mergeProps as _mergeProps } from "vue";
// Styles
import "./VSlider.css";
// Components
import { VSliderThumb } from "./VSliderThumb.js";
import { VSliderTrack } from "./VSliderTrack.js";
import { makeVInputProps, VInput } from "../VInput/VInput.js";
import { VLabel } from "../VLabel/index.js"; // Composables
import { makeSliderProps, useSlider, useSteps } from "./slider.js";
import { makeFocusProps, useFocus } from "../../composables/focus.js";
import { forwardRefs } from "../../composables/forwardRefs.js";
import { useRtl } from "../../composables/locale.js";
import { useProxiedModel } from "../../composables/proxiedModel.js"; // Utilities
import { computed, ref } from 'vue';
import { filterInputAttrs, genericComponent, propsFactory, useRender } from "../../util/index.js"; // Types
export const makeVSliderProps = propsFactory({
...makeFocusProps(),
...makeSliderProps(),
...makeVInputProps(),
modelValue: {
type: [Number, String],
default: 0
}
}, 'VSlider');
export const VSlider = genericComponent()({
name: 'VSlider',
inheritAttrs: false,
props: makeVSliderProps(),
emits: {
'update:focused': value => true,
'update:modelValue': v => true,
start: value => true,
end: value => true
},
setup(props, {
slots,
emit,
attrs
}) {
const thumbContainerRef = ref();
const inputRef = ref();
const {
rtlClasses
} = useRtl();
const steps = useSteps(props);
const model = useProxiedModel(props, 'modelValue', undefined, value => {
return steps.roundValue(value == null ? steps.min.value : value);
});
const {
min,
max,
mousePressed,
roundValue,
onSliderMousedown,
onSliderTouchstart,
trackContainerRef,
position,
hasLabels,
disabled,
readonly,
noKeyboard
} = useSlider({
props,
steps,
onSliderStart: () => {
if (!disabled.value && !readonly.value) {
emit('start', model.value);
}
},
onSliderEnd: ({
value
}) => {
const roundedValue = roundValue(value);
if (!disabled.value && !readonly.value) {
model.value = roundedValue;
}
emit('end', roundedValue);
},
onSliderMove: ({
value
}) => {
if (!disabled.value && !readonly.value) {
model.value = roundValue(value);
}
},
getActiveThumb: () => thumbContainerRef.value?.$el
});
const {
isFocused,
focus,
blur
} = useFocus(props);
const trackStop = computed(() => position(model.value));
useRender(() => {
const inputProps = VInput.filterProps(props);
const [rootAttrs, inputAttrs] = filterInputAttrs(attrs);
const hasPrepend = !!(props.label || slots.label || slots.prepend);
return _createVNode(VInput, _mergeProps({
"ref": inputRef,
"class": ['v-slider', {
'v-slider--has-labels': !!slots['tick-label'] || hasLabels.value,
'v-slider--focused': isFocused.value,
'v-slider--pressed': mousePressed.value,
'v-slider--disabled': disabled.value
}, rtlClasses.value, props.class],
"style": props.style
}, inputProps, rootAttrs, {
"focused": isFocused.value
}), {
...slots,
prepend: hasPrepend ? slotProps => _createElementVNode(_Fragment, null, [slots.label?.(slotProps) ?? (props.label ? _createVNode(VLabel, {
"id": slotProps.id.value,
"class": "v-slider__label",
"text": props.label
}, null) : undefined), slots.prepend?.(slotProps)]) : undefined,
default: ({
id,
messagesId
}) => _createElementVNode("div", {
"class": "v-slider__container",
"onMousedown": !readonly.value ? onSliderMousedown : undefined,
"onTouchstartPassive": !readonly.value ? onSliderTouchstart : undefined
}, [_createElementVNode("input", {
"id": id.value,
"name": props.name || id.value,
"disabled": disabled.value,
"readonly": readonly.value,
"tabindex": "-1",
"value": model.value
}, null), _createVNode(VSliderTrack, {
"ref": trackContainerRef,
"start": 0,
"stop": trackStop.value
}, {
'tick-label': slots['tick-label']
}), _createVNode(VSliderThumb, _mergeProps({
"ref": thumbContainerRef,
"aria-describedby": messagesId.value,
"focused": isFocused.value,
"noKeyboard": noKeyboard.value,
"min": min.value,
"max": max.value,
"modelValue": model.value,
"onUpdate:modelValue": v => model.value = v,
"position": trackStop.value,
"elevation": props.elevation,
"onFocus": focus,
"onBlur": blur,
"ripple": props.ripple,
"name": props.name
}, inputAttrs), {
'thumb-label': slots['thumb-label']
})])
});
});
return forwardRefs({
focus: () => thumbContainerRef.value?.$el.focus()
}, inputRef);
}
});
//# sourceMappingURL=VSlider.js.map
File diff suppressed because one or more lines are too long
+71
View File
@@ -0,0 +1,71 @@
@use 'sass:map'
@use 'sass:selector'
@forward '../VInput/variables'
@use '../../styles/settings'
@use '../../styles/tools'
@use './variables' as *
@use '../VInput/variables' as *
@include tools.layer('components')
// Block
.v-slider
.v-slider__container
input
cursor: default
padding: 0
width: 100%
display: none
> .v-input__append,
> .v-input__prepend
padding: 0
// Elements
.v-slider__container
position: relative
min-height: inherit
width: 100%
height: 100%
display: flex
justify-content: center
align-items: center
cursor: pointer
.v-input--disabled &
opacity: var(--v-disabled-opacity)
.v-input--error:not(.v-input--disabled) &
color: rgb(var(--v-theme-error))
// Modifiers
.v-slider.v-input--horizontal
align-items: center
> .v-input__prepend
margin-inline-end: max(0px, calc($input-affix-margin-inside - $slider-horizontal-start))
> .v-input__append
margin-inline-start: max(0px, calc($input-affix-margin-inside - $slider-horizontal-end))
> .v-input__control
margin-inline: $slider-horizontal-start $slider-horizontal-end
min-height: $slider-horizontal-min-height
display: flex
align-items: center
.v-slider.v-input--vertical
justify-content: center
margin-top: $slider-vertical-margin-top
margin-bottom: $slider-vertical-margin-bottom
> .v-input__control
min-height: $slider-vertical-min-height
.v-slider.v-input--disabled
pointer-events: none
.v-slider--has-labels > .v-input__control
margin-bottom: $slider-tick-label-margin-top * .5
.v-slider__label
margin-inline-end: $slider-label-margin-end
+142
View File
@@ -0,0 +1,142 @@
@layer vuetify-components {
.v-slider-thumb {
touch-action: none;
color: rgb(var(--v-theme-surface-variant));
}
.v-input--error:not(.v-input--disabled) .v-slider-thumb {
color: inherit;
}
.v-slider-thumb__label {
background: color-mix(in srgb, rgb(var(--v-theme-surface-variant)) 70%, transparent);
color: rgb(var(--v-theme-on-surface-variant));
}
.v-slider-thumb__label > .v-slider-thumb__label-wedge {
background: inherit;
}
.v-slider-thumb {
outline: none;
position: absolute;
transition: 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
}
.v-slider-thumb__surface {
cursor: pointer;
width: var(--v-slider-thumb-size);
height: var(--v-slider-thumb-size);
border-radius: 50%;
user-select: none;
background-color: currentColor;
}
@media (forced-colors: active) {
.v-slider-thumb__surface {
background-color: highlight;
}
}
.v-slider-thumb__surface::before {
transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
content: "";
color: inherit;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 50%;
background: currentColor;
position: absolute;
pointer-events: none;
opacity: 0;
}
.v-slider-thumb__surface::after {
content: "";
width: 42px;
height: 42px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.v-slider-thumb__label-container {
position: absolute;
transition: 0.2s cubic-bezier(0.4, 0, 1, 1);
}
.v-slider-thumb__label {
display: flex;
align-items: center;
justify-content: center;
font-size: 0.6875rem;
min-width: 35px;
height: 25px;
border-radius: 4px;
padding: 6px;
position: absolute;
user-select: none;
transition: 0.2s cubic-bezier(0.4, 0, 1, 1);
}
.v-slider-thumb__label > .v-slider-thumb__label-wedge {
width: 12px;
height: 12px;
position: absolute;
}
.v-slider-thumb__ripple {
position: absolute;
left: calc(var(--v-slider-thumb-size) / -2);
top: calc(var(--v-slider-thumb-size) / -2);
width: calc(var(--v-slider-thumb-size) * 2);
height: calc(var(--v-slider-thumb-size) * 2);
background: inherit;
}
.v-slider.v-input--horizontal .v-slider-thumb {
top: 50%;
transform: translateY(-50%);
inset-inline-start: calc(var(--v-slider-thumb-position) - var(--v-slider-thumb-size) / 2);
}
.v-slider.v-input--horizontal .v-slider-thumb__label-container {
left: calc(var(--v-slider-thumb-size) / 2);
top: 0;
}
.v-slider.v-input--horizontal .v-slider-thumb__label {
bottom: calc(var(--v-slider-thumb-size) / 2);
}
.v-locale--is-ltr.v-slider.v-input--horizontal .v-slider-thumb__label, .v-locale--is-ltr .v-slider.v-input--horizontal .v-slider-thumb__label {
transform: translateX(-50%);
}
.v-locale--is-rtl.v-slider.v-input--horizontal .v-slider-thumb__label, .v-locale--is-rtl .v-slider.v-input--horizontal .v-slider-thumb__label {
transform: translateX(50%);
}
.v-slider.v-input--horizontal .v-slider-thumb__label > .v-slider-thumb__label-wedge {
clip-path: polygon(50% 100%, 0 50%, 100% 50%);
bottom: calc(-6px + 0.2px);
}
.v-slider.v-input--vertical .v-slider-thumb {
top: calc(var(--v-slider-thumb-position) - var(--v-slider-thumb-size) / 2);
}
.v-slider.v-input--vertical .v-slider-thumb__label-container {
top: calc(var(--v-slider-thumb-size) / 2);
right: 0;
}
.v-slider.v-input--vertical .v-slider-thumb__label {
top: -12.5px;
left: calc(var(--v-slider-thumb-size) / 2);
}
.v-slider.v-input--vertical .v-slider-thumb__label > .v-slider-thumb__label-wedge {
clip-path: polygon(0 50%, 50% 0, 50% 100%);
left: calc(-6px + 0.2px);
}
.v-slider-thumb--focused .v-slider-thumb__surface::before {
transform: scale(2);
opacity: var(--v-focus-opacity);
}
.v-slider-thumb--pressed {
transition: none;
}
.v-slider-thumb--pressed .v-slider-thumb__surface::before {
opacity: var(--v-pressed-opacity);
}
@media (hover: hover) {
.v-slider-thumb:hover .v-slider-thumb__surface::before {
transform: scale(2);
}
.v-slider-thumb:hover:not(.v-slider-thumb--focused) .v-slider-thumb__surface::before {
opacity: var(--v-hover-opacity);
}
}
}
+323
View File
@@ -0,0 +1,323 @@
import type { PropType } from 'vue';
import type { RippleDirectiveBinding } from '../../directives/ripple/index.js';
export type VSliderThumbSlots = {
'thumb-label': {
modelValue: number;
};
};
export declare const makeVSliderThumbProps: <Defaults extends {
class?: unknown;
style?: unknown;
focused?: unknown;
max?: unknown;
min?: unknown;
modelValue?: unknown;
position?: unknown;
ripple?: unknown;
name?: unknown;
noKeyboard?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
class: unknown extends Defaults["class"] ? PropType<any> : {
type: PropType<unknown extends Defaults["class"] ? any : any>;
default: unknown extends Defaults["class"] ? any : any;
};
style: unknown extends Defaults["style"] ? {
type: PropType<import("vue").StyleValue>;
default: null;
} : Omit<{
type: PropType<import("vue").StyleValue>;
default: null;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["style"] ? import("vue").StyleValue : Defaults["style"] | import("vue").StyleValue>;
default: unknown extends Defaults["style"] ? import("vue").StyleValue : Defaults["style"] | NonNullable<import("vue").StyleValue>;
};
focused: unknown extends Defaults["focused"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["focused"] ? boolean : boolean | Defaults["focused"]>;
default: unknown extends Defaults["focused"] ? boolean : boolean | Defaults["focused"];
};
max: unknown extends Defaults["max"] ? {
type: NumberConstructor;
required: true;
} : Omit<{
type: NumberConstructor;
required: true;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["max"] ? number : number | Defaults["max"]>;
default: unknown extends Defaults["max"] ? number : number | Defaults["max"];
};
min: unknown extends Defaults["min"] ? {
type: NumberConstructor;
required: true;
} : Omit<{
type: NumberConstructor;
required: true;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["min"] ? number : number | Defaults["min"]>;
default: unknown extends Defaults["min"] ? number : number | Defaults["min"];
};
modelValue: unknown extends Defaults["modelValue"] ? {
type: NumberConstructor;
required: true;
} : Omit<{
type: NumberConstructor;
required: true;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["modelValue"] ? number : number | Defaults["modelValue"]>;
default: unknown extends Defaults["modelValue"] ? number : number | Defaults["modelValue"];
};
position: unknown extends Defaults["position"] ? {
type: NumberConstructor;
required: true;
} : Omit<{
type: NumberConstructor;
required: true;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["position"] ? number : number | Defaults["position"]>;
default: unknown extends Defaults["position"] ? number : number | Defaults["position"];
};
ripple: unknown extends Defaults["ripple"] ? {
type: PropType<RippleDirectiveBinding['value']>;
default: boolean;
} : Omit<{
type: PropType<RippleDirectiveBinding['value']>;
default: boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["ripple"] ? boolean | {
class?: string;
keys?: string[];
} | undefined : boolean | {
class?: string;
keys?: string[];
} | Defaults["ripple"] | undefined>;
default: unknown extends Defaults["ripple"] ? boolean | {
class?: string;
keys?: string[];
} | undefined : Defaults["ripple"] | NonNullable<boolean | {
class?: string;
keys?: string[];
} | undefined>;
};
name: unknown extends Defaults["name"] ? StringConstructor : {
type: PropType<unknown extends Defaults["name"] ? string : string | Defaults["name"]>;
default: unknown extends Defaults["name"] ? string : string | Defaults["name"];
};
noKeyboard: unknown extends Defaults["noKeyboard"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["noKeyboard"] ? boolean : boolean | Defaults["noKeyboard"]>;
default: unknown extends Defaults["noKeyboard"] ? boolean : boolean | Defaults["noKeyboard"];
};
};
export declare const VSliderThumb: {
new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<{
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
focused: boolean;
max: number;
min: number;
modelValue: number;
position: number;
ripple: boolean | {
class?: string;
keys?: string[];
};
noKeyboard: boolean;
} & {
class?: any;
name?: string | undefined;
} & {
$children?: {
'thumb-label'?: ((arg: {
modelValue: number;
}) => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | {} | import("vue").VNodeChild;
'v-slots'?: {
'thumb-label'?: false | ((arg: {
modelValue: number;
}) => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:thumb-label"?: false | ((arg: {
modelValue: number;
}) => import("vue").VNodeChild) | undefined;
} & {
"onUpdate:modelValue"?: ((v: number) => any) | undefined;
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
'update:modelValue': (v: number) => true;
}, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, {
style: import("vue").StyleValue;
focused: boolean;
ripple: boolean | {
class?: string;
keys?: string[];
} | undefined;
noKeyboard: boolean;
}, true, {}, import("vue").SlotsType<Partial<{
'thumb-label': (arg: {
modelValue: number;
}) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, {}, any, import("vue").ComponentProvideOptions, {
P: {};
B: {};
D: {};
C: {};
M: {};
Defaults: {};
}, {
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
focused: boolean;
max: number;
min: number;
modelValue: number;
position: number;
ripple: boolean | {
class?: string;
keys?: string[];
};
noKeyboard: boolean;
} & {
class?: any;
name?: string | undefined;
} & {
$children?: {
'thumb-label'?: ((arg: {
modelValue: number;
}) => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | {} | import("vue").VNodeChild;
'v-slots'?: {
'thumb-label'?: false | ((arg: {
modelValue: number;
}) => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:thumb-label"?: false | ((arg: {
modelValue: number;
}) => import("vue").VNodeChild) | undefined;
} & {
"onUpdate:modelValue"?: ((v: number) => any) | undefined;
}, {}, {}, {}, {}, {
style: import("vue").StyleValue;
focused: boolean;
ripple: boolean | {
class?: string;
keys?: string[];
} | undefined;
noKeyboard: boolean;
}>;
__isFragment?: never;
__isTeleport?: never;
__isSuspense?: never;
} & import("vue").ComponentOptionsBase<{
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
focused: boolean;
max: number;
min: number;
modelValue: number;
position: number;
ripple: boolean | {
class?: string;
keys?: string[];
};
noKeyboard: boolean;
} & {
class?: any;
name?: string | undefined;
} & {
$children?: {
'thumb-label'?: ((arg: {
modelValue: number;
}) => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | {} | import("vue").VNodeChild;
'v-slots'?: {
'thumb-label'?: false | ((arg: {
modelValue: number;
}) => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:thumb-label"?: false | ((arg: {
modelValue: number;
}) => import("vue").VNodeChild) | undefined;
} & {
"onUpdate:modelValue"?: ((v: number) => any) | undefined;
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
'update:modelValue': (v: number) => true;
}, string, {
style: import("vue").StyleValue;
focused: boolean;
ripple: boolean | {
class?: string;
keys?: string[];
} | undefined;
noKeyboard: boolean;
}, {}, string, import("vue").SlotsType<Partial<{
'thumb-label': (arg: {
modelValue: number;
}) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & import("../../util/index.js").FilterPropsOptions<{
class: PropType<import("../../composables/component.js").ClassValue>;
style: {
type: PropType<import("vue").StyleValue>;
default: null;
};
focused: BooleanConstructor;
max: {
type: NumberConstructor;
required: true;
};
min: {
type: NumberConstructor;
required: true;
};
modelValue: {
type: NumberConstructor;
required: true;
};
position: {
type: NumberConstructor;
required: true;
};
ripple: {
type: PropType<RippleDirectiveBinding['value']>;
default: boolean;
};
name: StringConstructor;
noKeyboard: BooleanConstructor;
}, import("vue").ExtractPropTypes<{
class: PropType<import("../../composables/component.js").ClassValue>;
style: {
type: PropType<import("vue").StyleValue>;
default: null;
};
focused: BooleanConstructor;
max: {
type: NumberConstructor;
required: true;
};
min: {
type: NumberConstructor;
required: true;
};
modelValue: {
type: NumberConstructor;
required: true;
};
position: {
type: NumberConstructor;
required: true;
};
ripple: {
type: PropType<RippleDirectiveBinding['value']>;
default: boolean;
};
name: StringConstructor;
noKeyboard: BooleanConstructor;
}>>;
export type VSliderThumb = InstanceType<typeof VSliderThumb>;
+198
View File
@@ -0,0 +1,198 @@
import { normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle, createElementVNode as _createElementVNode, withDirectives as _withDirectives, vShow as _vShow, createVNode as _createVNode } from "vue";
// Styles
import "./VSliderThumb.css";
// Components
import { VSliderSymbol } from "./slider.js";
import { VScaleTransition } from "../transitions/index.js"; // Composables
import { useBackgroundColor, useTextColor } from "../../composables/color.js";
import { makeComponentProps } from "../../composables/component.js";
import { useElevation } from "../../composables/elevation.js";
import { useRtl } from "../../composables/locale.js"; // Directives
import vRipple from "../../directives/ripple/index.js"; // Utilities
import { computed, inject, shallowRef, watch } from 'vue';
import { convertToUnit, genericComponent, keyValues, propsFactory, useRender } from "../../util/index.js"; // Types
export const makeVSliderThumbProps = propsFactory({
focused: Boolean,
max: {
type: Number,
required: true
},
min: {
type: Number,
required: true
},
modelValue: {
type: Number,
required: true
},
position: {
type: Number,
required: true
},
ripple: {
type: [Boolean, Object],
default: true
},
name: String,
noKeyboard: Boolean,
...makeComponentProps()
}, 'VSliderThumb');
export const VSliderThumb = genericComponent()({
name: 'VSliderThumb',
directives: {
vRipple
},
props: makeVSliderThumbProps(),
emits: {
'update:modelValue': v => true
},
setup(props, {
slots,
emit
}) {
const slider = inject(VSliderSymbol);
const {
isRtl,
rtlClasses
} = useRtl();
if (!slider) throw new Error('[Vuetify] v-slider-thumb must be used inside v-slider or v-range-slider');
const {
min,
max,
thumbColor,
thumbLabelColor,
step,
disabled,
thumbSize,
thumbLabel,
direction,
isReversed,
vertical,
readonly,
elevation,
mousePressed,
decimals,
indexFromEnd
} = slider;
const isHovered = shallowRef(false);
const isHidden = shallowRef(false);
const elevationProps = computed(() => !disabled.value ? elevation.value : undefined);
const {
elevationClasses
} = useElevation(elevationProps);
const {
textColorClasses,
textColorStyles
} = useTextColor(thumbColor);
const {
backgroundColorClasses,
backgroundColorStyles
} = useBackgroundColor(thumbLabelColor);
const {
pageup,
pagedown,
end,
home,
left,
right,
down,
up
} = keyValues;
const relevantKeys = [pageup, pagedown, end, home, left, right, down, up];
const multipliers = computed(() => {
if (step.value) return [1, 2, 3];else return [1, 5, 10];
});
function parseKeydown(e, value) {
if (props.noKeyboard || disabled.value) return;
if (!relevantKeys.includes(e.key)) return;
e.preventDefault();
const _step = step.value || 0.1;
const steps = (max.value - min.value) / _step;
if ([left, right, down, up].includes(e.key)) {
const increase = vertical.value ? [isRtl.value ? left : right, isReversed.value ? down : up] : indexFromEnd.value !== isRtl.value ? [left, up] : [right, up];
const direction = increase.includes(e.key) ? 1 : -1;
const multiplier = e.shiftKey ? 2 : e.ctrlKey ? 1 : 0;
if (direction === -1 && value === max.value && !multiplier && !Number.isInteger(steps)) {
value = value - steps % 1 * _step;
} else {
value = value + direction * _step * multipliers.value[multiplier];
}
} else if (e.key === home) {
value = min.value;
} else if (e.key === end) {
value = max.value;
} else {
const direction = e.key === pagedown ? 1 : -1;
value = value - direction * _step * (steps > 100 ? steps / 10 : 10);
}
return Math.max(props.min, Math.min(props.max, value));
}
function onKeydown(e) {
const newValue = parseKeydown(e, props.modelValue);
if (newValue != null) {
isHidden.value = false;
emit('update:modelValue', newValue);
}
}
watch(() => props.focused, val => {
if (val) {
isHidden.value = false;
}
});
useRender(() => {
const positionPercentage = convertToUnit(indexFromEnd.value ? 100 - props.position : props.position, '%');
const thumbLabelVisible = thumbLabel.value === 'always' || thumbLabel.value === true && props.focused || thumbLabel.value === 'hover' && (isHovered.value || props.focused && !isHidden.value);
return _createElementVNode("div", {
"class": _normalizeClass(['v-slider-thumb', {
'v-slider-thumb--focused': props.focused,
'v-slider-thumb--pressed': props.focused && mousePressed.value
}, props.class, rtlClasses.value]),
"style": _normalizeStyle([{
'--v-slider-thumb-position': positionPercentage,
'--v-slider-thumb-size': convertToUnit(thumbSize.value)
}, props.style]),
"role": "slider",
"tabindex": disabled.value ? -1 : 0,
"aria-label": props.name,
"aria-valuemin": min.value,
"aria-valuemax": max.value,
"aria-valuenow": props.modelValue,
"aria-readonly": !!readonly.value,
"aria-orientation": direction.value,
"onKeydown": !readonly.value ? onKeydown : undefined,
"onMouseenter": () => {
isHovered.value = true;
},
"onMouseleave": () => {
isHovered.value = false;
isHidden.value = true;
}
}, [_createElementVNode("div", {
"class": _normalizeClass(['v-slider-thumb__surface', textColorClasses.value, elevationClasses.value]),
"style": _normalizeStyle(textColorStyles.value)
}, null), _withDirectives(_createElementVNode("div", {
"class": _normalizeClass(['v-slider-thumb__ripple', textColorClasses.value]),
"style": _normalizeStyle(textColorStyles.value)
}, null), [[vRipple, props.ripple, null, {
circle: true,
center: true
}]]), _createVNode(VScaleTransition, {
"origin": "bottom center"
}, {
default: () => [_withDirectives(_createElementVNode("div", {
"class": "v-slider-thumb__label-container"
}, [_createElementVNode("div", {
"class": _normalizeClass(['v-slider-thumb__label', backgroundColorClasses.value]),
"style": _normalizeStyle(backgroundColorStyles.value)
}, [_createElementVNode("div", null, [slots['thumb-label']?.({
modelValue: props.modelValue
}) ?? props.modelValue.toFixed(step.value ? decimals.value : 1)]), _createElementVNode("div", {
"class": "v-slider-thumb__label-wedge"
}, null)])]), [[_vShow, thumbLabelVisible]])]
})]);
});
return {};
}
});
//# sourceMappingURL=VSliderThumb.js.map
File diff suppressed because one or more lines are too long
+153
View File
@@ -0,0 +1,153 @@
@use 'sass:map'
@use 'sass:selector'
@use 'sass:math'
@use '../../styles/settings'
@use '../../styles/tools'
@use './variables' as *
@include tools.layer('components')
// Theme
.v-slider-thumb
touch-action: none
color: rgb(var(--v-theme-surface-variant))
.v-input--error:not(.v-input--disabled) &
color: inherit
.v-slider-thumb__label
background: tools.theme-color('surface-variant', .7)
color: rgb(var(--v-theme-on-surface-variant))
> .v-slider-thumb__label-wedge
background: inherit
// Block
.v-slider-thumb
outline: none
position: absolute
transition: $slider-transition
.v-slider-thumb__surface
cursor: pointer
width: var(--v-slider-thumb-size)
height: var(--v-slider-thumb-size)
border-radius: $slider-thumb-border-radius
user-select: none
background-color: currentColor
@media (forced-colors: active)
background-color: highlight
&::before
transition: 0.3s settings.$standard-easing
content: ''
color: inherit
top: 0
left: 0
width: 100%
height: 100%
border-radius: $slider-thumb-border-radius
background: currentColor
position: absolute
pointer-events: none
opacity: 0
&::after
content: ''
width: $slider-thumb-touch-size
height: $slider-thumb-touch-size
position: absolute
top: 50%
left: 50%
transform: translate(-50%, -50%)
.v-slider-thumb__label-container
position: absolute
transition: $slider-thumb-label-transition
.v-slider-thumb__label
display: flex
align-items: center
justify-content: center
font-size: $slider-thumb-label-font-size
min-width: $slider-thumb-label-min-width
height: $slider-thumb-label-height
border-radius: $slider-thumb-label-border-radius
padding: $slider-thumb-label-padding
position: absolute
user-select: none
transition: $slider-thumb-label-transition
> .v-slider-thumb__label-wedge
width: $slider-thumb-label-wedge-size * 2
height: $slider-thumb-label-wedge-size * 2
position: absolute
.v-slider-thumb__ripple
position: absolute
left: calc(var(--v-slider-thumb-size) / -2)
top: calc(var(--v-slider-thumb-size) / -2)
width: calc(var(--v-slider-thumb-size) * 2)
height: calc(var(--v-slider-thumb-size) * 2)
background: inherit
// Horizontal
.v-slider.v-input--horizontal
.v-slider-thumb
top: 50%
transform: translateY(-50%)
inset-inline-start: calc(var(--v-slider-thumb-position) - var(--v-slider-thumb-size) / 2)
.v-slider-thumb__label-container
left: calc(var(--v-slider-thumb-size) / 2)
top: 0
.v-slider-thumb__label
bottom: $slider-thumb-label-offset
@include tools.ltr()
transform: translateX(-50%)
@include tools.rtl()
transform: translateX(50%)
> .v-slider-thumb__label-wedge
clip-path: polygon(50% 100%, 0 50%, 100% 50%)
bottom: calc(#{-$slider-thumb-label-wedge-size} + 0.2px)
// Vertical
.v-slider.v-input--vertical
.v-slider-thumb
top: calc(var(--v-slider-thumb-position) - var(--v-slider-thumb-size) / 2)
.v-slider-thumb__label-container
top: calc(var(--v-slider-thumb-size) / 2)
right: 0
.v-slider-thumb__label
top: math.div($slider-thumb-label-height, -2)
left: $slider-thumb-label-offset
> .v-slider-thumb__label-wedge
clip-path: polygon(0 50%, 50% 0, 50% 100%)
left: calc(#{-$slider-thumb-label-wedge-size} + 0.2px)
// Modifiers
.v-slider-thumb--focused
.v-slider-thumb__surface::before
transform: scale(2)
opacity: $slider-thumb-focus-opacity
.v-slider-thumb--pressed
transition: none
.v-slider-thumb__surface::before
opacity: $slider-thumb-pressed-opacity
@media (hover: hover)
.v-slider-thumb:hover
.v-slider-thumb__surface::before
transform: scale(2)
.v-slider-thumb:hover:not(.v-slider-thumb--focused)
.v-slider-thumb__surface::before
opacity: $slider-thumb-hover-opacity
+159
View File
@@ -0,0 +1,159 @@
@layer vuetify-components {
.v-slider-track__background {
background-color: rgb(var(--v-theme-surface-variant));
}
@media (forced-colors: active) {
.v-slider-track__background {
background-color: highlight;
}
}
.v-slider-track__fill {
background-color: rgb(var(--v-theme-surface-variant));
}
@media (forced-colors: active) {
.v-slider-track__fill {
background-color: highlight;
}
}
.v-slider-track__tick {
background-color: rgb(var(--v-theme-surface-variant));
}
.v-slider-track__tick--filled {
background-color: rgb(var(--v-theme-surface-light));
}
.v-slider-track {
border-radius: 6px;
}
@media (forced-colors: active) {
.v-slider-track {
border: thin solid buttontext;
}
}
.v-slider-track__background, .v-slider-track__fill {
position: absolute;
transition: 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
border-radius: inherit;
}
.v-slider--pressed .v-slider-track__background, .v-slider--pressed .v-slider-track__fill {
transition: none;
}
.v-input--error:not(.v-input--disabled) .v-slider-track__background, .v-input--error:not(.v-input--disabled) .v-slider-track__fill {
background-color: currentColor;
}
.v-slider-track__ticks {
height: 100%;
width: 100%;
position: relative;
}
.v-slider-track__tick {
position: absolute;
opacity: 0;
transition: 0.2s opacity cubic-bezier(0.4, 0, 0.2, 1);
border-radius: 2px;
width: var(--v-slider-tick-size);
height: var(--v-slider-tick-size);
transform: translate(calc(var(--v-slider-tick-size) / -2), calc(var(--v-slider-tick-size) / -2));
}
.v-locale--is-ltr.v-slider-track__tick--first .v-slider-track__tick-label, .v-locale--is-ltr .v-slider-track__tick--first .v-slider-track__tick-label {
transform: none;
}
.v-locale--is-rtl.v-slider-track__tick--first .v-slider-track__tick-label, .v-locale--is-rtl .v-slider-track__tick--first .v-slider-track__tick-label {
transform: translateX(100%);
}
.v-locale--is-ltr.v-slider-track__tick--last .v-slider-track__tick-label, .v-locale--is-ltr .v-slider-track__tick--last .v-slider-track__tick-label {
transform: translateX(-100%);
}
.v-locale--is-rtl.v-slider-track__tick--last .v-slider-track__tick-label, .v-locale--is-rtl .v-slider-track__tick--last .v-slider-track__tick-label {
transform: none;
}
.v-slider-track__tick-label {
position: absolute;
user-select: none;
white-space: nowrap;
}
.v-slider.v-input--horizontal .v-slider-track {
display: flex;
align-items: center;
width: 100%;
height: calc(var(--v-slider-track-size) + 2px);
touch-action: pan-y;
}
.v-slider.v-input--horizontal .v-slider-track__background {
height: var(--v-slider-track-size);
}
.v-slider.v-input--horizontal .v-slider-track__fill {
height: inherit;
}
.v-slider.v-input--horizontal .v-slider-track__tick {
margin-top: calc(calc(var(--v-slider-track-size) + 2px) / 2);
}
.v-locale--is-rtl.v-slider.v-input--horizontal .v-slider-track__tick, .v-locale--is-rtl .v-slider.v-input--horizontal .v-slider-track__tick {
transform: translate(calc(var(--v-slider-tick-size) / 2), calc(var(--v-slider-tick-size) / -2));
}
.v-slider.v-input--horizontal .v-slider-track__tick .v-slider-track__tick-label {
margin-top: calc(var(--v-slider-track-size) / 2 + 8px);
}
.v-locale--is-ltr.v-slider.v-input--horizontal .v-slider-track__tick .v-slider-track__tick-label, .v-locale--is-ltr .v-slider.v-input--horizontal .v-slider-track__tick .v-slider-track__tick-label {
transform: translateX(-50%);
}
.v-locale--is-rtl.v-slider.v-input--horizontal .v-slider-track__tick .v-slider-track__tick-label, .v-locale--is-rtl .v-slider.v-input--horizontal .v-slider-track__tick .v-slider-track__tick-label {
transform: translateX(50%);
}
.v-slider.v-input--horizontal .v-slider-track__tick--first {
margin-inline-start: calc(var(--v-slider-tick-size) + 1px);
}
.v-locale--is-ltr.v-slider.v-input--horizontal .v-slider-track__tick--first .v-slider-track__tick-label, .v-locale--is-ltr .v-slider.v-input--horizontal .v-slider-track__tick--first .v-slider-track__tick-label {
transform: translateX(0%);
}
.v-locale--is-rtl.v-slider.v-input--horizontal .v-slider-track__tick--first .v-slider-track__tick-label, .v-locale--is-rtl .v-slider.v-input--horizontal .v-slider-track__tick--first .v-slider-track__tick-label {
transform: translateX(0%);
}
.v-slider.v-input--horizontal .v-slider-track__tick--last {
margin-inline-start: calc(100% - var(--v-slider-tick-size) - 1px);
}
.v-locale--is-ltr.v-slider.v-input--horizontal .v-slider-track__tick--last .v-slider-track__tick-label, .v-locale--is-ltr .v-slider.v-input--horizontal .v-slider-track__tick--last .v-slider-track__tick-label {
transform: translateX(-100%);
}
.v-locale--is-rtl.v-slider.v-input--horizontal .v-slider-track__tick--last .v-slider-track__tick-label, .v-locale--is-rtl .v-slider.v-input--horizontal .v-slider-track__tick--last .v-slider-track__tick-label {
transform: translateX(100%);
}
.v-slider.v-input--vertical .v-slider-track {
height: 100%;
display: flex;
justify-content: center;
width: calc(var(--v-slider-track-size) + 2px);
touch-action: pan-x;
}
.v-slider.v-input--vertical .v-slider-track__background {
width: var(--v-slider-track-size);
}
.v-slider.v-input--vertical .v-slider-track__fill {
width: inherit;
}
.v-slider.v-input--vertical .v-slider-track__ticks {
height: 100%;
}
.v-slider.v-input--vertical .v-slider-track__tick {
margin-inline-start: calc(calc(var(--v-slider-track-size) + 2px) / 2);
transform: translate(calc(var(--v-slider-tick-size) / -2), calc(var(--v-slider-tick-size) / 2));
}
.v-locale--is-rtl.v-slider.v-input--vertical .v-slider-track__tick, .v-locale--is-rtl .v-slider.v-input--vertical .v-slider-track__tick {
transform: translate(calc(var(--v-slider-tick-size) / 2), calc(var(--v-slider-tick-size) / 2));
}
.v-slider.v-input--vertical .v-slider-track__tick--first {
bottom: calc(0% + var(--v-slider-tick-size) + 1px);
}
.v-slider.v-input--vertical .v-slider-track__tick--last {
bottom: calc(100% - var(--v-slider-tick-size) - 1px);
}
.v-slider.v-input--vertical .v-slider-track__tick .v-slider-track__tick-label {
margin-inline-start: calc(var(--v-slider-track-size) / 2 + 12px);
transform: translateY(-50%);
}
.v-slider-track__ticks--always-show .v-slider-track__tick, .v-slider--focused .v-slider-track__tick {
opacity: 1;
}
.v-slider-track__background--opacity {
opacity: 0.38;
}
}
+189
View File
@@ -0,0 +1,189 @@
import type { Tick } from './slider.js';
export type VSliderTrackSlots = {
'tick-label': {
tick: Tick;
index: number;
};
};
export declare const makeVSliderTrackProps: <Defaults extends {
class?: unknown;
style?: unknown;
start?: unknown;
stop?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
class: unknown extends Defaults["class"] ? import("vue").PropType<any> : {
type: import("vue").PropType<unknown extends Defaults["class"] ? any : any>;
default: unknown extends Defaults["class"] ? any : any;
};
style: unknown extends Defaults["style"] ? {
type: import("vue").PropType<import("vue").StyleValue>;
default: null;
} : Omit<{
type: import("vue").PropType<import("vue").StyleValue>;
default: null;
}, "default" | "type"> & {
type: import("vue").PropType<unknown extends Defaults["style"] ? import("vue").StyleValue : Defaults["style"] | import("vue").StyleValue>;
default: unknown extends Defaults["style"] ? import("vue").StyleValue : Defaults["style"] | NonNullable<import("vue").StyleValue>;
};
start: unknown extends Defaults["start"] ? {
type: NumberConstructor;
required: true;
} : Omit<{
type: NumberConstructor;
required: true;
}, "default" | "type"> & {
type: import("vue").PropType<unknown extends Defaults["start"] ? number : number | Defaults["start"]>;
default: unknown extends Defaults["start"] ? number : number | Defaults["start"];
};
stop: unknown extends Defaults["stop"] ? {
type: NumberConstructor;
required: true;
} : Omit<{
type: NumberConstructor;
required: true;
}, "default" | "type"> & {
type: import("vue").PropType<unknown extends Defaults["stop"] ? number : number | Defaults["stop"]>;
default: unknown extends Defaults["stop"] ? number : number | Defaults["stop"];
};
};
export declare const VSliderTrack: {
new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<{
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
start: number;
stop: number;
} & {
class?: any;
} & {
$children?: {
'tick-label'?: ((arg: {
tick: Tick;
index: number;
}) => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | {} | import("vue").VNodeChild;
'v-slots'?: {
'tick-label'?: false | ((arg: {
tick: Tick;
index: number;
}) => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:tick-label"?: false | ((arg: {
tick: Tick;
index: number;
}) => import("vue").VNodeChild) | undefined;
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Record<string, any>, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, {
style: import("vue").StyleValue;
}, true, {}, import("vue").SlotsType<Partial<{
'tick-label': (arg: {
tick: Tick;
index: number;
}) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, {}, any, import("vue").ComponentProvideOptions, {
P: {};
B: {};
D: {};
C: {};
M: {};
Defaults: {};
}, {
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
start: number;
stop: number;
} & {
class?: any;
} & {
$children?: {
'tick-label'?: ((arg: {
tick: Tick;
index: number;
}) => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | {} | import("vue").VNodeChild;
'v-slots'?: {
'tick-label'?: false | ((arg: {
tick: Tick;
index: number;
}) => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:tick-label"?: false | ((arg: {
tick: Tick;
index: number;
}) => import("vue").VNodeChild) | undefined;
}, {}, {}, {}, {}, {
style: import("vue").StyleValue;
}>;
__isFragment?: never;
__isTeleport?: never;
__isSuspense?: never;
} & import("vue").ComponentOptionsBase<{
style: string | false | import("vue").StyleValue[] | import("vue").CSSProperties | null;
start: number;
stop: number;
} & {
class?: any;
} & {
$children?: {
'tick-label'?: ((arg: {
tick: Tick;
index: number;
}) => import("vue").VNodeChild) | undefined;
} | {
$stable?: boolean;
} | {} | import("vue").VNodeChild;
'v-slots'?: {
'tick-label'?: false | ((arg: {
tick: Tick;
index: number;
}) => import("vue").VNodeChild) | undefined;
} | undefined;
} & {
"v-slot:tick-label"?: false | ((arg: {
tick: Tick;
index: number;
}) => import("vue").VNodeChild) | undefined;
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, Record<string, any>, string, {
style: import("vue").StyleValue;
}, {}, string, import("vue").SlotsType<Partial<{
'tick-label': (arg: {
tick: Tick;
index: number;
}) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
[key: string]: any;
}>[];
}>>, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps & import("../../util/index.js").FilterPropsOptions<{
class: import("vue").PropType<any>;
style: {
type: import("vue").PropType<import("vue").StyleValue>;
default: null;
};
start: {
type: NumberConstructor;
required: true;
};
stop: {
type: NumberConstructor;
required: true;
};
}, import("vue").ExtractPropTypes<{
class: import("vue").PropType<any>;
style: {
type: import("vue").PropType<import("vue").StyleValue>;
default: null;
};
start: {
type: NumberConstructor;
required: true;
};
stop: {
type: NumberConstructor;
required: true;
};
}>>;
export type VSliderTrack = InstanceType<typeof VSliderTrack>;
+125
View File
@@ -0,0 +1,125 @@
import { createElementVNode as _createElementVNode, normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle } from "vue";
// Styles
import "./VSliderTrack.css";
// Components
import { VSliderSymbol } from "./slider.js"; // Composables
import { useBackgroundColor } from "../../composables/color.js";
import { makeComponentProps } from "../../composables/component.js";
import { useRounded } from "../../composables/rounded.js"; // Utilities
import { computed, inject } from 'vue';
import { convertToUnit, genericComponent, propsFactory, useRender } from "../../util/index.js"; // Types
export const makeVSliderTrackProps = propsFactory({
start: {
type: Number,
required: true
},
stop: {
type: Number,
required: true
},
...makeComponentProps()
}, 'VSliderTrack');
export const VSliderTrack = genericComponent()({
name: 'VSliderTrack',
props: makeVSliderTrackProps(),
emits: {},
setup(props, {
slots
}) {
const slider = inject(VSliderSymbol);
if (!slider) throw new Error('[Vuetify] v-slider-track must be inside v-slider or v-range-slider');
const {
color,
parsedTicks,
rounded,
showTicks,
tickSize,
trackColor,
trackFillColor,
trackSize,
vertical,
min,
max,
indexFromEnd
} = slider;
const {
roundedClasses
} = useRounded(rounded);
const {
backgroundColorClasses: trackFillColorClasses,
backgroundColorStyles: trackFillColorStyles
} = useBackgroundColor(trackFillColor);
const {
backgroundColorClasses: trackColorClasses,
backgroundColorStyles: trackColorStyles
} = useBackgroundColor(trackColor);
const startDir = computed(() => `inset-${vertical.value ? 'block' : 'inline'}-${indexFromEnd.value ? 'end' : 'start'}`);
const endDir = computed(() => vertical.value ? 'height' : 'width');
const backgroundStyles = computed(() => {
return {
[startDir.value]: '0%',
[endDir.value]: '100%'
};
});
const trackFillWidth = computed(() => props.stop - props.start);
const trackFillStyles = computed(() => {
return {
[startDir.value]: convertToUnit(props.start, '%'),
[endDir.value]: convertToUnit(trackFillWidth.value, '%')
};
});
const computedTicks = computed(() => {
if (!showTicks.value) return [];
const ticks = vertical.value ? parsedTicks.value.slice().reverse() : parsedTicks.value;
return ticks.map((tick, index) => {
const directionValue = tick.value !== min.value && tick.value !== max.value ? convertToUnit(tick.position, '%') : undefined;
return _createElementVNode("div", {
"key": tick.value,
"class": _normalizeClass(['v-slider-track__tick', {
'v-slider-track__tick--filled': tick.position >= props.start && tick.position <= props.stop,
'v-slider-track__tick--first': tick.value === min.value,
'v-slider-track__tick--last': tick.value === max.value
}]),
"style": {
[startDir.value]: directionValue
}
}, [(tick.label || slots['tick-label']) && _createElementVNode("div", {
"class": "v-slider-track__tick-label"
}, [slots['tick-label']?.({
tick,
index
}) ?? tick.label])]);
});
});
useRender(() => {
return _createElementVNode("div", {
"class": _normalizeClass(['v-slider-track', roundedClasses.value, props.class]),
"style": _normalizeStyle([{
'--v-slider-track-size': convertToUnit(trackSize.value),
'--v-slider-tick-size': convertToUnit(tickSize.value)
}, props.style])
}, [_createElementVNode("div", {
"class": _normalizeClass(['v-slider-track__background', trackColorClasses.value, {
'v-slider-track__background--opacity': !!color.value || !trackFillColor.value
}]),
"style": {
...backgroundStyles.value,
...trackColorStyles.value
}
}, null), _createElementVNode("div", {
"class": _normalizeClass(['v-slider-track__fill', trackFillColorClasses.value]),
"style": {
...trackFillStyles.value,
...trackFillColorStyles.value
}
}, null), showTicks.value && _createElementVNode("div", {
"class": _normalizeClass(['v-slider-track__ticks', {
'v-slider-track__ticks--always-show': showTicks.value === 'always'
}])
}, [computedTicks.value])]);
});
return {};
}
});
//# sourceMappingURL=VSliderTrack.js.map
File diff suppressed because one or more lines are too long
+169
View File
@@ -0,0 +1,169 @@
@use 'sass:map'
@use 'sass:selector'
@use '../../styles/settings'
@use '../../styles/tools'
@use './variables' as *
@include tools.layer('components')
// Theme
.v-slider-track__background
background-color: rgb(var(--v-theme-surface-variant))
@media (forced-colors: active)
background-color: highlight
.v-slider-track__fill
background-color: rgb(var(--v-theme-surface-variant))
@media (forced-colors: active)
background-color: highlight
.v-slider-track__tick
background-color: rgb(var(--v-theme-surface-variant))
&--filled
background-color: $slider-tick-background
// Elements
.v-slider-track
border-radius: $slider-track-border-radius
@media (forced-colors: active)
border: thin solid buttontext
.v-slider-track
&__background, &__fill
position: absolute
transition: $slider-transition
border-radius: inherit
.v-slider--pressed &
transition: none
.v-input--error:not(.v-input--disabled) &
background-color: currentColor
.v-slider-track__ticks
height: 100%
width: 100%
position: relative
.v-slider-track__tick
position: absolute
opacity: 0
transition: 0.2s opacity settings.$standard-easing
border-radius: $slider-tick-border-radius
width: var(--v-slider-tick-size)
height: var(--v-slider-tick-size)
transform: translate(calc(var(--v-slider-tick-size) / -2), calc(var(--v-slider-tick-size) / -2))
&--first .v-slider-track__tick-label
@include tools.ltr()
transform: none
@include tools.rtl()
transform: translateX(100%)
&--last .v-slider-track__tick-label
@include tools.ltr()
transform: translateX(-100%)
@include tools.rtl()
transform: none
.v-slider-track__tick-label
position: absolute
user-select: none
white-space: nowrap
// Horizontal
.v-slider.v-input--horizontal
.v-slider-track
display: flex
align-items: center
width: 100%
height: $slider-track-active-size
touch-action: pan-y
&__background
height: var(--v-slider-track-size)
&__fill
height: inherit
.v-slider-track__tick
margin-top: calc(#{$slider-track-active-size} / 2)
@include tools.rtl()
transform: translate(calc(var(--v-slider-tick-size) / 2), calc(var(--v-slider-tick-size) / -2))
.v-slider-track__tick-label
margin-top: calc(var(--v-slider-track-size) / 2 + #{$slider-tick-label-margin-top})
@include tools.ltr()
transform: translateX(-50%)
@include tools.rtl()
transform: translateX(50%)
&--first
margin-inline-start: calc(var(--v-slider-tick-size) + 1px)
.v-slider-track__tick-label
@include tools.ltr()
transform: translateX(0%)
@include tools.rtl()
transform: translateX(0%)
&--last
margin-inline-start: calc(100% - var(--v-slider-tick-size) - 1px)
.v-slider-track__tick-label
@include tools.ltr()
transform: translateX(-100%)
@include tools.rtl()
transform: translateX(100%)
// Vertical
.v-slider.v-input--vertical
.v-slider-track
height: 100%
display: flex
justify-content: center
width: $slider-track-active-size
touch-action: pan-x
&__background
width: var(--v-slider-track-size)
&__fill
width: inherit
.v-slider-track__ticks
height: 100%
.v-slider-track__tick
margin-inline-start: calc(#{$slider-track-active-size} / 2)
transform: translate(calc(var(--v-slider-tick-size) / -2), calc(var(--v-slider-tick-size) / 2))
@include tools.rtl()
transform: translate(calc(var(--v-slider-tick-size) / 2), calc(var(--v-slider-tick-size) / 2))
&--first
bottom: calc(0% + var(--v-slider-tick-size) + 1px)
&--last
bottom: calc(100% - var(--v-slider-tick-size) - 1px)
.v-slider-track__tick-label
margin-inline-start: calc(var(--v-slider-track-size) / 2 + #{$slider-tick-label-margin-start})
transform: translateY(-50%)
// Modifiers
.v-slider-track__ticks--always-show, .v-slider--focused
.v-slider-track__tick
opacity: 1
.v-slider-track__background--opacity
opacity: 0.38
+35
View File
@@ -0,0 +1,35 @@
@use '../../styles/settings';
@use '../../styles/tools';
$slider-horizontal-start: 8px !default;
$slider-horizontal-min-height: 32px !default;
$slider-horizontal-end: 8px !default;
$slider-label-margin-end: 12px !default;
$slider-label-margin-start: 12px !default;
$slider-state-track-background-opacity: 0.4 !default;
$slider-thumb-hover-opacity: var(--v-hover-opacity) !default;
$slider-thumb-focus-opacity: var(--v-focus-opacity) !default;
$slider-thumb-pressed-opacity: var(--v-pressed-opacity) !default;
$slider-thumb-border-radius: 50% !default;
$slider-thumb-focused-size-increase: 24px !default;
$slider-thumb-label-font-size: tools.map-deep-get(settings.$typography, 'label-small', 'size') !default;
$slider-thumb-label-border-radius: 4px !default;
$slider-thumb-label-height: 25px !default;
$slider-thumb-label-min-width: 35px !default;
$slider-thumb-label-wedge-size: 6px !default;
$slider-thumb-label-offset: calc(var(--v-slider-thumb-size) / 2) !default;
$slider-thumb-label-transition: .2s settings.$accelerated-easing !default;
$slider-thumb-label-padding: 6px !default;
$slider-thumb-touch-size: 42px !default;
$slider-tick-background: rgb(var(--v-theme-surface-light)) !default;
$slider-tick-border-radius: 2px !default;
$slider-tick-label-margin-top: 8px !default;
$slider-tick-label-margin-start: 12px !default;
$slider-track-border-radius: 6px !default;
$slider-track-active-size-offset: 2px !default;
$slider-transition: .3s cubic-bezier(0.25, 0.8, 0.5, 1) !default;
$slider-vertical-margin-bottom: 12px !default;
$slider-vertical-margin-top: 12px !default;
$slider-vertical-min-height: 300px !default;
$slider-track-active-size: calc(var(--v-slider-track-size) + #{$slider-track-active-size-offset}) !default;
+1
View File
@@ -0,0 +1 @@
export { VSlider } from './VSlider.js';
+2
View File
@@ -0,0 +1,2 @@
export { VSlider } from "./VSlider.js";
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","names":["VSlider"],"sources":["../../../src/components/VSlider/index.ts"],"sourcesContent":["export { VSlider } from './VSlider'\n"],"mappings":"SAASA,OAAO","ignoreList":[]}
+285
View File
@@ -0,0 +1,285 @@
import type { ExtractPropTypes, InjectionKey, PropType, Ref } from 'vue';
import type { VSliderTrack } from './VSliderTrack.js';
export type Tick = {
value: number;
position: number;
label?: string;
};
type SliderProvide = {
activeThumbRef: Ref<HTMLElement | undefined>;
color: Ref<string | undefined>;
decimals: Ref<number>;
direction: Ref<'vertical' | 'horizontal'>;
disabled: Ref<boolean>;
elevation: Ref<number | string | undefined>;
min: Ref<number>;
max: Ref<number>;
mousePressed: Ref<boolean>;
noKeyboard: Ref<boolean>;
numTicks: Ref<number>;
onSliderMousedown: (e: MouseEvent) => void;
onSliderTouchstart: (e: TouchEvent) => void;
parseMouseMove: (e: MouseEvent | TouchEvent) => number | void;
position: (val: number) => number;
readonly: Ref<boolean>;
rounded: Ref<boolean | number | string | undefined>;
roundValue: (value: number) => number;
thumbLabel: Ref<boolean | string | undefined>;
showTicks: Ref<boolean | 'always'>;
startOffset: Ref<number>;
step: Ref<number>;
thumbSize: Ref<number>;
thumbColor: Ref<string | undefined>;
thumbLabelColor: Ref<string | undefined>;
trackColor: Ref<string | undefined>;
trackFillColor: Ref<string | undefined>;
trackSize: Ref<number>;
ticks: Ref<readonly number[] | Record<string, string> | undefined>;
tickSize: Ref<number>;
trackContainerRef: Ref<VSliderTrack | undefined>;
vertical: Ref<boolean>;
parsedTicks: Ref<Tick[]>;
hasLabels: Ref<boolean>;
isReversed: Ref<boolean>;
indexFromEnd: Ref<boolean>;
};
export declare const VSliderSymbol: InjectionKey<SliderProvide>;
export declare function getOffset(e: MouseEvent | TouchEvent, el: HTMLElement, direction: string): number;
export declare const makeSliderProps: <Defaults extends {
elevation?: unknown;
rounded?: unknown;
tile?: unknown;
disabled?: unknown;
error?: unknown;
readonly?: unknown;
max?: unknown;
min?: unknown;
step?: unknown;
thumbColor?: unknown;
thumbLabel?: unknown;
thumbSize?: unknown;
showTicks?: unknown;
ticks?: unknown;
tickSize?: unknown;
color?: unknown;
trackColor?: unknown;
trackFillColor?: unknown;
trackSize?: unknown;
direction?: unknown;
reverse?: unknown;
noKeyboard?: unknown;
ripple?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
elevation: unknown extends Defaults["elevation"] ? Omit<{
type: (NumberConstructor | StringConstructor)[];
validator: (value: string | number) => boolean;
}, "default" | "type"> & {
type: PropType<string | number>;
default: NonNullable<string | number>;
} : Omit<Omit<{
type: (NumberConstructor | StringConstructor)[];
validator: (value: string | number) => boolean;
}, "default" | "type"> & {
type: PropType<string | number>;
default: NonNullable<string | number>;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["elevation"] ? string | number : string | number | Defaults["elevation"]>;
default: unknown extends Defaults["elevation"] ? string | number : Defaults["elevation"] | NonNullable<string | number>;
};
rounded: unknown extends Defaults["rounded"] ? {
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
default: undefined;
} : Omit<{
type: (BooleanConstructor | NumberConstructor | StringConstructor)[];
default: undefined;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["rounded"] ? string | number | boolean : string | number | boolean | Defaults["rounded"]>;
default: unknown extends Defaults["rounded"] ? string | number | boolean : Defaults["rounded"] | NonNullable<string | number | boolean>;
};
tile: unknown extends Defaults["tile"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["tile"] ? boolean : boolean | Defaults["tile"]>;
default: unknown extends Defaults["tile"] ? boolean : boolean | Defaults["tile"];
};
disabled: unknown extends Defaults["disabled"] ? {
type: PropType<boolean | null>;
default: null;
} : Omit<{
type: PropType<boolean | null>;
default: null;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["disabled"] ? boolean | null : boolean | Defaults["disabled"] | null>;
default: unknown extends Defaults["disabled"] ? boolean | null : Defaults["disabled"] | NonNullable<boolean | null>;
};
error: unknown extends Defaults["error"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["error"] ? boolean : boolean | Defaults["error"]>;
default: unknown extends Defaults["error"] ? boolean : boolean | Defaults["error"];
};
readonly: unknown extends Defaults["readonly"] ? {
type: PropType<boolean | null>;
default: null;
} : Omit<{
type: PropType<boolean | null>;
default: null;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["readonly"] ? boolean | null : boolean | Defaults["readonly"] | null>;
default: unknown extends Defaults["readonly"] ? boolean | null : Defaults["readonly"] | NonNullable<boolean | null>;
};
max: unknown extends Defaults["max"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["max"] ? string | number : string | number | Defaults["max"]>;
default: unknown extends Defaults["max"] ? string | number : Defaults["max"] | NonNullable<string | number>;
};
min: unknown extends Defaults["min"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["min"] ? string | number : string | number | Defaults["min"]>;
default: unknown extends Defaults["min"] ? string | number : Defaults["min"] | NonNullable<string | number>;
};
step: unknown extends Defaults["step"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["step"] ? string | number : string | number | Defaults["step"]>;
default: unknown extends Defaults["step"] ? string | number : Defaults["step"] | NonNullable<string | number>;
};
thumbColor: unknown extends Defaults["thumbColor"] ? StringConstructor : {
type: PropType<unknown extends Defaults["thumbColor"] ? string : string | Defaults["thumbColor"]>;
default: unknown extends Defaults["thumbColor"] ? string : string | Defaults["thumbColor"];
};
thumbLabel: unknown extends Defaults["thumbLabel"] ? {
type: PropType<boolean | 'always' | 'hover' | undefined>;
default: undefined;
validator: (v: any) => boolean;
} : Omit<{
type: PropType<boolean | 'always' | 'hover' | undefined>;
default: undefined;
validator: (v: any) => boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["thumbLabel"] ? "always" | "hover" | boolean | undefined : "always" | "hover" | boolean | Defaults["thumbLabel"] | undefined>;
default: unknown extends Defaults["thumbLabel"] ? "always" | "hover" | boolean | undefined : Defaults["thumbLabel"] | NonNullable<"always" | "hover" | boolean | undefined>;
};
thumbSize: unknown extends Defaults["thumbSize"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["thumbSize"] ? string | number : string | number | Defaults["thumbSize"]>;
default: unknown extends Defaults["thumbSize"] ? string | number : Defaults["thumbSize"] | NonNullable<string | number>;
};
showTicks: unknown extends Defaults["showTicks"] ? {
type: PropType<boolean | 'always'>;
default: boolean;
validator: (v: any) => boolean;
} : Omit<{
type: PropType<boolean | 'always'>;
default: boolean;
validator: (v: any) => boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["showTicks"] ? "always" | boolean : "always" | boolean | Defaults["showTicks"]>;
default: unknown extends Defaults["showTicks"] ? "always" | boolean : Defaults["showTicks"] | NonNullable<"always" | boolean>;
};
ticks: unknown extends Defaults["ticks"] ? {
type: PropType<readonly number[] | Record<number, string>>;
} : Omit<{
type: PropType<readonly number[] | Record<number, string>>;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["ticks"] ? readonly number[] | Record<number, string> : readonly number[] | Record<number, string> | Defaults["ticks"]>;
default: unknown extends Defaults["ticks"] ? readonly number[] | Record<number, string> : Defaults["ticks"] | NonNullable<readonly number[] | Record<number, string>>;
};
tickSize: unknown extends Defaults["tickSize"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["tickSize"] ? string | number : string | number | Defaults["tickSize"]>;
default: unknown extends Defaults["tickSize"] ? string | number : Defaults["tickSize"] | NonNullable<string | number>;
};
color: unknown extends Defaults["color"] ? StringConstructor : {
type: PropType<unknown extends Defaults["color"] ? string : string | Defaults["color"]>;
default: unknown extends Defaults["color"] ? string : string | Defaults["color"];
};
trackColor: unknown extends Defaults["trackColor"] ? StringConstructor : {
type: PropType<unknown extends Defaults["trackColor"] ? string : string | Defaults["trackColor"]>;
default: unknown extends Defaults["trackColor"] ? string : string | Defaults["trackColor"];
};
trackFillColor: unknown extends Defaults["trackFillColor"] ? StringConstructor : {
type: PropType<unknown extends Defaults["trackFillColor"] ? string : string | Defaults["trackFillColor"]>;
default: unknown extends Defaults["trackFillColor"] ? string : string | Defaults["trackFillColor"];
};
trackSize: unknown extends Defaults["trackSize"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["trackSize"] ? string | number : string | number | Defaults["trackSize"]>;
default: unknown extends Defaults["trackSize"] ? string | number : Defaults["trackSize"] | NonNullable<string | number>;
};
direction: unknown extends Defaults["direction"] ? {
type: PropType<'horizontal' | 'vertical'>;
default: string;
validator: (v: any) => boolean;
} : Omit<{
type: PropType<'horizontal' | 'vertical'>;
default: string;
validator: (v: any) => boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["direction"] ? "horizontal" | "vertical" : "horizontal" | "vertical" | Defaults["direction"]>;
default: unknown extends Defaults["direction"] ? "horizontal" | "vertical" : Defaults["direction"] | NonNullable<"horizontal" | "vertical">;
};
reverse: unknown extends Defaults["reverse"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["reverse"] ? boolean : boolean | Defaults["reverse"]>;
default: unknown extends Defaults["reverse"] ? boolean : boolean | Defaults["reverse"];
};
noKeyboard: unknown extends Defaults["noKeyboard"] ? BooleanConstructor : {
type: PropType<unknown extends Defaults["noKeyboard"] ? boolean : boolean | Defaults["noKeyboard"]>;
default: unknown extends Defaults["noKeyboard"] ? boolean : boolean | Defaults["noKeyboard"];
};
ripple: unknown extends Defaults["ripple"] ? {
type: BooleanConstructor;
default: boolean;
} : Omit<{
type: BooleanConstructor;
default: boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["ripple"] ? boolean : boolean | Defaults["ripple"]>;
default: unknown extends Defaults["ripple"] ? boolean : boolean | Defaults["ripple"];
};
};
type SliderProps = ExtractPropTypes<ReturnType<typeof makeSliderProps>>;
type SliderData = {
value: number;
};
export declare const useSteps: (props: SliderProps) => {
min: import("vue").ComputedRef<number>;
max: import("vue").ComputedRef<number>;
step: import("vue").ComputedRef<number>;
decimals: import("vue").ComputedRef<number>;
roundValue: (value: string | number) => number;
};
export declare const useSlider: ({ props, steps, onSliderStart, onSliderMove, onSliderEnd, getActiveThumb, }: {
props: SliderProps;
steps: ReturnType<typeof useSteps>;
onSliderEnd: (data: SliderData) => void;
onSliderStart: (data: SliderData) => void;
onSliderMove: (data: SliderData) => void;
getActiveThumb: (e: MouseEvent | TouchEvent) => HTMLElement;
}) => SliderProvide;
+311
View File
@@ -0,0 +1,311 @@
/* eslint-disable max-statements */
// Composables
import { makeElevationProps } from "../../composables/elevation.js";
import { useForm } from "../../composables/form.js";
import { useRtl } from "../../composables/locale.js";
import { makeRoundedProps } from "../../composables/rounded.js"; // Utilities
import { computed, nextTick, onScopeDispose, provide, ref, shallowRef, toRef } from 'vue';
import { clamp, createRange, getDecimals, IN_BROWSER, propsFactory } from "../../util/index.js"; // Types
export const VSliderSymbol = Symbol.for('vuetify:v-slider');
export function getOffset(e, el, direction) {
const vertical = direction === 'vertical';
const rect = el.getBoundingClientRect();
const touch = 'touches' in e ? e.touches[0] : e;
return vertical ? touch.clientY - (rect.top + rect.height / 2) : touch.clientX - (rect.left + rect.width / 2);
}
function getPosition(e, position) {
if ('touches' in e && e.touches.length) return e.touches[0][position];else if ('changedTouches' in e && e.changedTouches.length) return e.changedTouches[0][position];else return e[position];
}
export const makeSliderProps = propsFactory({
disabled: {
type: Boolean,
default: null
},
error: Boolean,
readonly: {
type: Boolean,
default: null
},
max: {
type: [Number, String],
default: 100
},
min: {
type: [Number, String],
default: 0
},
step: {
type: [Number, String],
default: 0
},
thumbColor: String,
thumbLabel: {
type: [Boolean, String],
default: undefined,
validator: v => typeof v === 'boolean' || v === 'always' || v === 'hover'
},
thumbSize: {
type: [Number, String],
default: 20
},
showTicks: {
type: [Boolean, String],
default: false,
validator: v => typeof v === 'boolean' || v === 'always'
},
ticks: {
type: [Array, Object]
},
tickSize: {
type: [Number, String],
default: 2
},
color: String,
trackColor: String,
trackFillColor: String,
trackSize: {
type: [Number, String],
default: 4
},
direction: {
type: String,
default: 'horizontal',
validator: v => ['vertical', 'horizontal'].includes(v)
},
reverse: Boolean,
noKeyboard: Boolean,
...makeRoundedProps(),
...makeElevationProps({
elevation: 1
}),
ripple: {
type: Boolean,
default: true
}
}, 'Slider');
export const useSteps = props => {
const min = computed(() => parseFloat(props.min));
const max = computed(() => parseFloat(props.max));
const step = computed(() => Number(props.step) > 0 ? parseFloat(props.step) : 0);
const decimals = computed(() => Math.max(getDecimals(step.value), getDecimals(min.value)));
function roundValue(value) {
value = parseFloat(value);
if (step.value <= 0) return value;
const clamped = clamp(value, min.value, max.value);
const offset = min.value % step.value;
let newValue = Math.round((clamped - offset) / step.value) * step.value + offset;
if (clamped > newValue && newValue + step.value > max.value) {
newValue = max.value;
}
return parseFloat(Math.min(newValue, max.value).toFixed(decimals.value));
}
return {
min,
max,
step,
decimals,
roundValue
};
};
export const useSlider = ({
props,
steps,
onSliderStart,
onSliderMove,
onSliderEnd,
getActiveThumb
}) => {
const form = useForm(props);
const {
isRtl
} = useRtl();
const isReversed = toRef(() => props.reverse);
const vertical = computed(() => props.direction === 'vertical');
const indexFromEnd = computed(() => vertical.value !== isReversed.value);
const {
min,
max,
step,
decimals,
roundValue
} = steps;
const thumbSize = computed(() => parseInt(props.thumbSize, 10));
const tickSize = computed(() => parseInt(props.tickSize, 10));
const trackSize = computed(() => parseInt(props.trackSize, 10));
const numTicks = computed(() => (max.value - min.value) / step.value);
const thumbColor = computed(() => props.error || form.isDisabled.value ? undefined : props.thumbColor ?? props.color);
const thumbLabelColor = computed(() => props.error || form.isDisabled.value ? undefined : props.thumbColor);
const trackColor = computed(() => props.error || form.isDisabled.value ? undefined : props.trackColor ?? props.color);
const trackFillColor = computed(() => props.error || form.isDisabled.value ? undefined : props.trackFillColor ?? props.color);
const mousePressed = shallowRef(false);
const startOffset = shallowRef(0);
const trackContainerRef = ref();
const activeThumbRef = ref();
function parseMouseMove(e) {
const el = trackContainerRef.value?.$el;
if (!el) return;
const vertical = props.direction === 'vertical';
const start = vertical ? 'top' : 'left';
const length = vertical ? 'height' : 'width';
const position = vertical ? 'clientY' : 'clientX';
const {
[start]: trackStart,
[length]: trackLength
} = el.getBoundingClientRect();
const clickOffset = getPosition(e, position);
// It is possible for left to be NaN, force to number
let clickPos = clamp((clickOffset - trackStart - startOffset.value) / trackLength) || 0;
if (vertical ? indexFromEnd.value : indexFromEnd.value !== isRtl.value) clickPos = 1 - clickPos;
return roundValue(min.value + clickPos * (max.value - min.value));
}
const handleStop = e => {
const value = parseMouseMove(e);
if (value != null) {
onSliderEnd({
value
});
}
mousePressed.value = false;
startOffset.value = 0;
};
const handleStart = e => {
const value = parseMouseMove(e);
activeThumbRef.value = getActiveThumb(e);
if (!activeThumbRef.value) return;
mousePressed.value = true;
if (activeThumbRef.value.contains(e.target)) {
startOffset.value = getOffset(e, activeThumbRef.value, props.direction);
} else {
startOffset.value = 0;
if (value != null) {
onSliderMove({
value
});
}
}
if (value != null) {
onSliderStart({
value
});
}
nextTick(() => activeThumbRef.value?.focus());
};
const moveListenerOptions = {
passive: true,
capture: true
};
function onMouseMove(e) {
const value = parseMouseMove(e);
if (value != null) {
onSliderMove({
value
});
}
}
function onSliderMouseUp(e) {
e.stopPropagation();
e.preventDefault();
handleStop(e);
window.removeEventListener('mousemove', onMouseMove, moveListenerOptions);
window.removeEventListener('mouseup', onSliderMouseUp);
}
function onSliderTouchend(e) {
handleStop(e);
window.removeEventListener('touchmove', onMouseMove, moveListenerOptions);
e.target?.removeEventListener('touchend', onSliderTouchend);
}
function onSliderTouchstart(e) {
handleStart(e);
window.addEventListener('touchmove', onMouseMove, moveListenerOptions);
e.target?.addEventListener('touchend', onSliderTouchend, {
passive: false
});
}
function onSliderMousedown(e) {
if (e.button !== 0) return;
e.preventDefault();
handleStart(e);
window.addEventListener('mousemove', onMouseMove, moveListenerOptions);
window.addEventListener('mouseup', onSliderMouseUp, {
passive: false
});
}
onScopeDispose(() => {
if (!IN_BROWSER) return;
window.removeEventListener('touchmove', onMouseMove);
window.removeEventListener('mousemove', onMouseMove);
window.removeEventListener('mouseup', onSliderMouseUp);
});
const position = val => {
const percentage = (val - min.value) / (max.value - min.value) * 100;
return clamp(isNaN(percentage) ? 0 : percentage, 0, 100);
};
const showTicks = toRef(() => props.showTicks);
const parsedTicks = computed(() => {
if (!showTicks.value) return [];
if (!props.ticks) {
return numTicks.value !== Infinity ? createRange(numTicks.value + 1).map(t => {
const value = min.value + t * step.value;
return {
value,
position: position(value)
};
}) : [];
}
if (Array.isArray(props.ticks)) return props.ticks.map(t => ({
value: t,
position: position(t),
label: t.toString()
}));
return Object.keys(props.ticks).map(key => ({
value: parseFloat(key),
position: position(parseFloat(key)),
label: props.ticks[key]
}));
});
const hasLabels = computed(() => parsedTicks.value.some(({
label
}) => !!label));
const data = {
activeThumbRef,
color: toRef(() => props.color),
decimals,
disabled: form.isDisabled,
direction: toRef(() => props.direction),
elevation: toRef(() => props.elevation),
hasLabels,
isReversed,
indexFromEnd,
min,
max,
mousePressed,
noKeyboard: toRef(() => props.noKeyboard),
numTicks,
onSliderMousedown,
onSliderTouchstart,
parsedTicks,
parseMouseMove,
position,
readonly: form.isReadonly,
rounded: toRef(() => props.rounded),
roundValue,
showTicks,
startOffset,
step,
thumbSize,
thumbColor,
thumbLabelColor,
thumbLabel: toRef(() => props.thumbLabel),
ticks: toRef(() => props.ticks),
tickSize,
trackColor,
trackContainerRef,
trackFillColor,
trackSize,
vertical
};
provide(VSliderSymbol, data);
return data;
};
//# sourceMappingURL=slider.js.map
File diff suppressed because one or more lines are too long