@coreui/vue-pro
Version:
UI Components Library for Vue.js
322 lines (318 loc) • 14.1 kB
JavaScript
'use strict';
var vue = require('vue');
var utils = require('./utils.js');
var isRTL = require('../../utils/isRTL.js');
const CRangeSlider = vue.defineComponent({
name: 'CRangeSlider',
props: {
/**
* Enable or disable clickable labels in the Vue Range Slider.
* When set to `true`, users can click on labels to adjust the slider's value directly, enhancing interactivity and user experience.
*/
clickableLabels: {
type: Boolean,
default: true,
},
/**
* Control the interactive state of the Vue Range Slider with the `disabled` prop.
* Setting it to `true` will disable all slider functionalities, preventing user interaction and visually indicating a non-interactive state.
*/
disabled: {
type: Boolean,
default: false,
},
/**
* Define the minimum distance between slider handles using the `distance` prop in the Vue Range Slider.
* This ensures that the handles maintain a specified separation, preventing overlap and maintaining clear value distinctions.
*/
distance: {
type: Number,
default: 0,
},
/**
* Add descriptive labels to your Vue Range Slider by providing an array of `labels`.
* These labels enhance the slider's usability by clearly indicating key values and providing contextual information to users.
*/
labels: {
type: Array,
default: () => [],
},
/**
* Specify the maximum value for the Vue Range Slider with the `max` prop.
* This determines the upper limit of the slider's range, enabling precise control over the highest selectable value.
*/
max: {
type: Number,
default: 100,
},
/**
* Set the minimum value for the Vue Range Slider using the `min` prop.
* This defines the lower bound of the slider's range, allowing you to control the starting point of user selection.
*/
min: {
type: Number,
default: 0,
},
/**
* The default name for a value passed using v-model.
*/
modelValue: [Number, Array],
/**
* Assign a `name` to the Vue Range Slider for form integration.
* Whether using a single string or an array of strings, this prop ensures that the slider's values are correctly identified when submitting forms.
*/
name: {
type: [String, Array],
default: '',
},
/**
* Control the granularity of the Vue Range Slider by setting the `step` prop.
* This defines the increment intervals between selectable values, allowing for precise adjustments based on your application's requirements.
*/
step: {
type: Number,
default: 1,
},
/**
* Toggle the visibility of tooltips in the Vue Range Slider with the `tooltips` prop.
* When enabled, tooltips display the current value of the slider handles, providing real-time feedback to users.
*/
tooltips: {
type: Boolean,
default: true,
},
/**
* Customize the display format of tooltips in the Vue Range Slider using the `tooltipsFormat` function.
* This allows you to format the tooltip values according to your specific requirements, enhancing the clarity and presentation of information.
*/
tooltipsFormat: {
type: Function,
default: null,
},
/**
* Controls the visual representation of the slider's track. When set to `'fill'`, the track is dynamically filled based on the slider's value(s). Setting it to `false` disables the filled track.
*/
track: {
type: [Boolean, String],
default: 'fill',
validator: (value) => {
return typeof value === 'boolean' || value === 'fill';
},
},
/**
* Set the current value(s) of the Vue Range Slider using the `value` prop.
* Whether you're using a single value or an array for multi-handle sliders, this prop controls the slider's position and ensures it reflects the desired state.
*/
value: {
type: [Number, Array],
default: () => [0],
},
/**
* Orient the Vue Range Slider vertically by setting the `vertical` prop to `true`.
* This changes the slider's layout from horizontal to vertical, providing a different aesthetic and fitting various UI designs.
*/
vertical: {
type: Boolean,
default: false,
},
},
emits: [
'change',
/**
* Emit the new value whenever there’s a change event.
*/
'update:modelValue',
],
setup(props, { emit }) {
const rangeSliderRef = vue.ref(null);
const inputsRef = vue.ref([]);
const labelsContainerRef = vue.ref(null);
const labelsRef = vue.ref([]);
const trackRef = vue.ref(null);
const currentValue = vue.ref(props.modelValue
? Array.isArray(props.modelValue)
? props.modelValue
: [props.modelValue]
: Array.isArray(props.value)
? props.value
: [props.value]);
const isDragging = vue.ref(false);
const _isRTL = vue.ref(false);
const dragIndex = vue.ref(0);
const thumbSize = vue.ref();
vue.watch(() => props.value, (newVal) => {
currentValue.value = Array.isArray(newVal) ? newVal : [newVal];
});
vue.watch(() => props.modelValue, (newVal) => {
if (newVal !== undefined) {
currentValue.value = Array.isArray(newVal) ? newVal : [newVal];
}
});
// Adjust labels container size based on labels
vue.onMounted(() => {
const maxSize = Math.max(...labelsRef.value.map((label) => props.vertical ? label.offsetWidth : label.offsetHeight));
if (labelsContainerRef.value) {
labelsContainerRef.value.style[props.vertical ? 'width' : 'height'] = `${maxSize}px`;
}
if (rangeSliderRef.value) {
_isRTL.value = isRTL.default(rangeSliderRef.value);
thumbSize.value = utils.getThumbSize(rangeSliderRef.value, props.vertical);
}
});
vue.watch(isDragging, (newVal) => {
if (newVal) {
globalThis.addEventListener('mousemove', handleMouseMove);
globalThis.addEventListener('mouseup', handleMouseUp);
}
else {
globalThis.removeEventListener('mousemove', handleMouseMove);
globalThis.removeEventListener('mouseup', handleMouseUp);
}
});
const updateNearestValue = (value) => {
const nearestIndex = utils.getNearestValueIndex(value, currentValue.value);
const newCurrentValue = [...currentValue.value];
newCurrentValue[nearestIndex] = utils.validateValue(value, currentValue.value, props.distance, nearestIndex);
setTimeout(() => {
if (inputsRef.value[nearestIndex]) {
inputsRef.value[nearestIndex].focus();
}
}, 0);
currentValue.value = newCurrentValue;
emit('change', newCurrentValue);
emit('update:modelValue', newCurrentValue);
};
const handleInputChange = (event, index) => {
if (props.disabled)
return;
const target = event.target;
const value = Number(target.value);
const newCurrentValue = utils.updateValue(value, currentValue.value, props.distance, index);
currentValue.value = newCurrentValue;
emit('change', newCurrentValue);
emit('update:modelValue', newCurrentValue);
};
const handleInputsContainerMouseDown = (event) => {
if (!trackRef.value || event.button !== 0 || props.disabled)
return;
const target = event.target;
if (!(target instanceof HTMLInputElement) && target !== trackRef.value) {
return;
}
const clickValue = utils.calculateClickValue(event, trackRef.value, props.min, props.max, props.step, props.vertical, _isRTL.value);
const index = utils.getNearestValueIndex(clickValue, currentValue.value);
isDragging.value = true;
dragIndex.value = index;
updateNearestValue(clickValue);
};
const handleLabelClick = (event, value) => {
if (!props.clickableLabels || props.disabled || event.button !== 0)
return;
updateNearestValue(value);
};
const handleMouseMove = (event) => {
if (!isDragging.value || !trackRef.value || props.disabled)
return;
const moveValue = utils.calculateMoveValue(event, trackRef.value, props.min, props.max, props.step, props.vertical, _isRTL.value);
const newCurrentValue = utils.updateValue(moveValue, currentValue.value, props.distance, dragIndex.value);
currentValue.value = newCurrentValue;
emit('change', newCurrentValue);
emit('update:modelValue', newCurrentValue);
};
const handleMouseUp = () => {
isDragging.value = false;
};
return () => vue.h('div', {
class: [
'range-slider',
{
'range-slider-vertical': props.vertical,
disabled: props.disabled,
},
],
ref: rangeSliderRef,
}, [
vue.h('div', {
class: 'range-slider-inputs-container',
onMousedown: handleInputsContainerMouseDown,
}, [
currentValue.value.map((value, index) => [
vue.h('input', {
class: 'range-slider-input',
type: 'range',
min: props.min,
max: props.max,
step: props.step,
value: value,
name: Array.isArray(props.name)
? props.name[index]
: `${props.name || ''}-${index}`,
role: 'slider',
'aria-valuemin': props.min,
'aria-valuemax': props.max,
'aria-valuenow': value,
'aria-orientation': props.vertical ? 'vertical' : 'horizontal',
disabled: props.disabled,
onInput: (e) => handleInputChange(e, index),
ref: (el) => {
inputsRef.value[index] = el;
},
}),
props.tooltips &&
vue.h('div', {
class: 'range-slider-tooltip',
...(thumbSize.value && {
style: utils.calculateTooltipPosition(props.min, props.max, value, thumbSize.value, props.vertical, _isRTL.value),
}),
}, [
vue.h('div', { class: 'range-slider-tooltip-inner' }, [
props.tooltipsFormat ? props.tooltipsFormat(value) : value,
]),
vue.h('div', { class: 'range-slider-tooltip-arrow' }),
]),
]),
vue.h('div', {
class: 'range-slider-track',
...(props.track && {
style: utils.updateGradient(props.min, props.max, currentValue.value, props.vertical, _isRTL.value),
}),
ref: trackRef,
}),
]),
Array.isArray(props.labels) &&
props.labels.length > 0 &&
vue.h('div', {
class: 'range-slider-labels-container',
ref: labelsContainerRef,
}, props.labels.map((label, index) => {
const labelPosition = utils.calculateLabelPosition(props.min, props.max, props.labels, label, index);
const labelValue = utils.getLabelValue(props.min, props.max, props.labels, label, index);
const labelStyle = {
...(props.vertical
? { bottom: labelPosition }
: _isRTL.value
? { right: labelPosition }
: { left: labelPosition }),
...(typeof label === 'object' && 'style' in label ? label.style : {}),
};
return vue.h('div', {
class: [
'range-slider-label',
{
clickable: props.clickableLabels,
},
typeof label === 'object' && 'className' in label ? label.className : '',
],
style: labelStyle,
onMousedown: (event) => handleLabelClick(event, labelValue),
key: index,
ref: (el) => {
labelsRef.value[index] = el;
},
}, typeof label === 'object' && 'label' in label ? label.label : label);
})),
]);
},
});
exports.CRangeSlider = CRangeSlider;
//# sourceMappingURL=CRangeSlider.js.map