@ishitatsuyuki/oruga-next
Version:
UI components for Vue.js and CSS framework agnostic
719 lines (705 loc) • 25.3 kB
JavaScript
import { defineComponent, resolveComponent, openBlock, createBlock, createVNode, withCtx, mergeProps, withKeys, withModifiers, toDisplayString, createCommentVNode, renderSlot, Fragment, renderList } from 'vue';
import { getValueByPath } from './helpers.mjs';
import { getOptions } from './config.mjs';
import { B as BaseComponentMixin } from './BaseComponentMixin-d78ed3dc.mjs';
import { s as script$3 } from './Tooltip-741497a7.mjs';
var script = defineComponent({
name: 'OSliderThumb',
components: {
[script$3.name]: script$3
},
configField: 'slider',
inheritAttrs: false,
inject: ['$slider'],
emits: ['update:modelValue', 'dragstart', 'dragend'],
props: {
modelValue: {
type: Number,
default: 0
},
variant: {
type: String,
default: ''
},
tooltip: {
type: Boolean,
default: true
},
indicator: {
type: Boolean,
default: false
},
customFormatter: Function,
format: {
type: String,
default: 'raw',
validator: (value) => {
return [
'raw',
'percent'
].indexOf(value) >= 0;
}
},
locale: {
type: [String, Array],
default: () => {
return getValueByPath(getOptions(), 'locale');
}
},
tooltipAlways: {
type: Boolean,
default: false
}
},
data() {
return {
isFocused: false,
dragging: false,
startX: 0,
startPosition: 0,
newPosition: null,
oldValue: this.modelValue
};
},
computed: {
disabled() {
return this.$parent.disabled;
},
max() {
return this.$parent.max;
},
min() {
return this.$parent.min;
},
step() {
return this.$parent.step;
},
precision() {
return this.$parent.precision;
},
currentPosition() {
return `${(this.modelValue - this.min) / (this.max - this.min) * 100}%`;
},
wrapperStyle() {
return { left: this.currentPosition };
},
formattedValue() {
if (typeof this.customFormatter !== 'undefined') {
return this.customFormatter(this.modelValue);
}
if (this.format === 'percent') {
return new Intl.NumberFormat(this.locale, {
style: 'percent'
}).format(((this.modelValue - this.min)) / (this.max - this.min));
}
return new Intl.NumberFormat(this.locale).format(this.modelValue);
}
},
methods: {
onFocus() {
this.isFocused = true;
},
onBlur() {
this.isFocused = false;
},
onButtonDown(event) {
if (this.disabled)
return;
event.preventDefault();
this.onDragStart(event);
if (typeof window !== 'undefined') {
document.addEventListener('mousemove', this.onDragging);
document.addEventListener('touchmove', this.onDragging);
document.addEventListener('mouseup', this.onDragEnd);
document.addEventListener('touchend', this.onDragEnd);
document.addEventListener('contextmenu', this.onDragEnd);
}
},
onLeftKeyDown() {
if (this.disabled || this.modelvalue === this.min)
return;
this.newPosition = parseFloat(this.currentPosition) -
this.step / (this.max - this.min) * 100;
this.setPosition(this.newPosition);
this.$parent.emitValue('change');
},
onRightKeyDown() {
if (this.disabled || this.modelvalue === this.max)
return;
this.newPosition = parseFloat(this.currentPosition) +
this.step / (this.max - this.min) * 100;
this.setPosition(this.newPosition);
this.$parent.emitValue('change');
},
onHomeKeyDown() {
if (this.disabled || this.modelvalue === this.min)
return;
this.newPosition = 0;
this.setPosition(this.newPosition);
this.$parent.emitValue('change');
},
onEndKeyDown() {
if (this.disabled || this.modelvalue === this.max)
return;
this.newPosition = 100;
this.setPosition(this.newPosition);
this.$parent.emitValue('change');
},
onDragStart(event) {
this.dragging = true;
this.$emit('dragstart');
if (event.type === 'touchstart') {
event.clientX = event.touches[0].clientX;
}
this.startX = event.clientX;
this.startPosition = parseFloat(this.currentPosition);
this.newPosition = this.startPosition;
},
onDragging(event) {
if (this.dragging) {
if (event.type === 'touchmove') {
event.clientX = event.touches[0].clientX;
}
const diff = (event.clientX - this.startX) / this.$parent.sliderSize() * 100;
this.newPosition = this.startPosition + diff;
this.setPosition(this.newPosition);
}
},
onDragEnd() {
this.dragging = false;
this.$emit('dragend');
if (this.modelvalue !== this.oldValue) {
this.$parent.emitValue('change');
}
this.setPosition(this.newPosition);
if (typeof window !== 'undefined') {
document.removeEventListener('mousemove', this.onDragging);
document.removeEventListener('touchmove', this.onDragging);
document.removeEventListener('mouseup', this.onDragEnd);
document.removeEventListener('touchend', this.onDragEnd);
document.removeEventListener('contextmenu', this.onDragEnd);
}
},
setPosition(percent) {
if (percent === null || isNaN(percent))
return;
if (percent < 0) {
percent = 0;
}
else if (percent > 100) {
percent = 100;
}
const stepLength = 100 / ((this.max - this.min) / this.step);
const steps = Math.round(percent / stepLength);
let value = steps * stepLength / 100 * (this.max - this.min) + this.min;
value = parseFloat(value.toFixed(this.precision));
this.$emit('update:modelValue', value);
if (!this.dragging && value !== this.oldValue) {
this.oldValue = value;
}
}
}
});
const _hoisted_1 = {
key: 0
};
function render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_o_tooltip = resolveComponent("o-tooltip");
return openBlock(), createBlock("div", {
class: _ctx.$slider.thumbWrapperClasses,
style: _ctx.wrapperStyle
}, [createVNode(_component_o_tooltip, {
label: _ctx.formattedValue,
variant: _ctx.variant,
always: _ctx.dragging || _ctx.isFocused || _ctx.tooltipAlways,
active: !_ctx.disabled && _ctx.tooltip
}, {
default: withCtx(() => [createVNode("div", mergeProps(_ctx.$attrs, {
class: _ctx.$slider.thumbClasses,
tabindex: _ctx.disabled ? false : 0,
onMousedown: _cache[1] || (_cache[1] = (...args) => _ctx.onButtonDown(...args)),
onTouchstart: _cache[2] || (_cache[2] = (...args) => _ctx.onButtonDown(...args)),
onFocus: _cache[3] || (_cache[3] = (...args) => _ctx.onFocus(...args)),
onBlur: _cache[4] || (_cache[4] = (...args) => _ctx.onBlur(...args)),
onKeydown: [_cache[5] || (_cache[5] = withKeys(withModifiers((...args) => _ctx.onLeftKeyDown(...args), ["prevent"]), ["left"])), _cache[6] || (_cache[6] = withKeys(withModifiers((...args) => _ctx.onRightKeyDown(...args), ["prevent"]), ["right"])), _cache[7] || (_cache[7] = withKeys(withModifiers((...args) => _ctx.onLeftKeyDown(...args), ["prevent"]), ["down"])), _cache[8] || (_cache[8] = withKeys(withModifiers((...args) => _ctx.onRightKeyDown(...args), ["prevent"]), ["up"])), _cache[9] || (_cache[9] = withKeys(withModifiers((...args) => _ctx.onHomeKeyDown(...args), ["prevent"]), ["home"])), _cache[10] || (_cache[10] = withKeys(withModifiers((...args) => _ctx.onEndKeyDown(...args), ["prevent"]), ["end"]))]
}), [_ctx.indicator ? (openBlock(), createBlock("span", _hoisted_1, toDisplayString(_ctx.formattedValue), 1
/* TEXT */
)) : createCommentVNode("v-if", true)], 16
/* FULL_PROPS */
, ["tabindex"])]),
_: 1
}, 8
/* PROPS */
, ["label", "variant", "always", "active"])], 6
/* CLASS, STYLE */
);
}
script.render = render;
script.__file = "src/components/slider/SliderThumb.vue";
/**
* @displayName Slider Tick
*/
var script$1 = defineComponent({
name: 'OSliderTick',
mixins: [BaseComponentMixin],
configField: 'slider',
inject: ['$slider'],
props: {
/** Value of single tick */
value: {
variant: Number,
default: 0
},
tickClass: [String, Function, Array],
tickHiddenClass: [String, Function, Array],
tickLabelClass: [String, Function, Array]
},
computed: {
rootClasses() {
return [
this.computedClass('tickClass', 'o-slide__tick'),
{ [this.computedClass('tickHiddenClass', 'o-slide__tick--hidden')]: this.hidden },
];
},
tickLabelClasses() {
return [
this.computedClass('tickLabelClass', 'o-slide__tick-label')
];
},
position() {
const pos = (this.value - this.$parent.min) /
(this.$parent.max - this.$parent.min) * 100;
return (pos >= 0 && pos <= 100) ? pos : 0;
},
hidden() {
return this.value === this.$parent.min || this.value === this.$parent.max;
},
tickStyle() {
return { 'left': this.position + '%' };
}
},
created() {
if (!this.$slider) {
throw new Error('You should wrap oSliderTick on a oSlider');
}
}
});
function render$1(_ctx, _cache, $props, $setup, $data, $options) {
return openBlock(), createBlock("div", {
class: _ctx.rootClasses,
style: _ctx.tickStyle
}, [_ctx.$slots.default ? (openBlock(), createBlock("span", {
key: 0,
class: _ctx.tickLabelClasses
}, [renderSlot(_ctx.$slots, "default")], 2
/* CLASS */
)) : createCommentVNode("v-if", true)], 6
/* CLASS, STYLE */
);
}
script$1.render = render$1;
script$1.__file = "src/components/slider/SliderTick.vue";
/**
* A slider to select a value or range from a given range
* @displayName Slider
* @requires ./SliderTick.vue
* @style _slider.scss
*/
var script$2 = defineComponent({
name: 'OSlider',
components: {
[script.name]: script,
[script$1.name]: script$1
},
configField: 'slider',
mixins: [BaseComponentMixin],
provide() {
return {
$slider: this
};
},
emits: ['update:modelValue', 'change', 'dragging', 'dragstart', 'dragend'],
props: {
/** @model */
modelValue: {
type: [Number, Array],
default: 0
},
/** Minimum value */
min: {
type: Number,
default: 0
},
/** Maximum value */
max: {
type: Number,
default: 100
},
/** Step interval of ticks */
step: {
type: Number,
default: 1
},
/**
* Color of the slider
* @values primary, info, success, warning, danger, and any other custom color
*/
variant: {
type: String
},
/**
* Vertical size of slider, optional
* @values small, medium, large
*/
size: String,
/** Show tick marks */
ticks: {
type: Boolean,
default: false
},
/** Show tooltip when thumb is being dragged */
tooltip: {
type: Boolean,
default: () => {
return getValueByPath(getOptions(), 'slider.tooltip', true);
}
},
/**
* Color of the tooltip
* @values primary, info, success, warning, danger, and any other custom color
*/
tooltipVariant: String,
/** Rounded thumb */
rounded: {
type: Boolean,
default: () => {
return getValueByPath(getOptions(), 'slider.rounded', false);
}
},
disabled: {
type: Boolean,
default: false
},
/** Update v-model only when dragging is finished */
lazy: {
type: Boolean,
default: false
},
/** Function to format the tooltip label for display */
customFormatter: Function,
ariaLabel: [String, Array],
/** Increases slider size on focus */
biggerSliderFocus: {
type: Boolean,
default: false
},
indicator: {
type: Boolean,
default: false
},
format: {
type: String,
default: 'raw',
validator: (value) => {
return [
'raw',
'percent'
].indexOf(value) >= 0;
}
},
locale: {
type: [String, Array],
default: () => {
return getValueByPath(getOptions(), 'locale');
}
},
/** Tooltip displays always */
tooltipAlways: {
type: Boolean,
default: false
},
rootClass: [String, Function, Array],
sizeClass: [String, Function, Array],
trackClass: [String, Function, Array],
fillClass: [String, Function, Array],
thumbRoundedClass: [String, Function, Array],
thumbDraggingClass: [String, Function, Array],
disabledClass: [String, Function, Array],
thumbWrapperClass: [String, Function, Array],
thumbClass: [String, Function, Array],
variantClass: [String, Function, Array]
},
data() {
return {
value1: null,
value2: null,
dragging: false,
isRange: false
};
},
computed: {
rootClasses() {
return [
this.computedClass('rootClass', 'o-slide'),
{ [this.computedClass('sizeClass', 'o-slide--', this.size)]: this.size },
{ [this.computedClass('disabledClass', 'o-slide--disabled')]: this.disabled },
];
},
trackClasses() {
return [
this.computedClass('trackClass', 'o-slide__track'),
];
},
fillClasses() {
return [
this.computedClass('fillClass', 'o-slide__fill'),
{ [this.computedClass('variantClass', 'o-slide__fill--', this.variant)]: this.variant },
];
},
thumbClasses() {
return [
this.computedClass('thumbClass', 'o-slide__thumb'),
{ [this.computedClass('thumbDraggingClass', 'o-slide__thumb--dragging')]: this.dragging },
{ [this.computedClass('thumbRoundedClass', 'o-slide__thumb--rounded')]: this.rounded },
];
},
thumbWrapperClasses() {
return [
this.computedClass('thumbWrapperClass', 'o-slide__thumb-wrapper'),
];
},
newTooltipVariant() {
return this.tooltipVariant ? this.tooltipVariant : this.variant;
},
tickValues() {
if (!this.ticks || this.min > this.max || this.step === 0)
return [];
const result = [];
for (let i = this.min + this.step; i < this.max; i = i + this.step) {
result.push(i);
}
return result;
},
minValue() {
return Math.min(this.value1, this.value2);
},
maxValue() {
return Math.max(this.value1, this.value2);
},
barSize() {
return this.isRange
? `${100 * (this.maxValue - this.minValue) / (this.max - this.min)}%`
: `${100 * (this.value1 - this.min) / (this.max - this.min)}%`;
},
barStart() {
return this.isRange
? `${100 * (this.minValue - this.min) / (this.max - this.min)}%`
: '0%';
},
precision() {
const precisions = [this.min, this.max, this.step].map((item) => {
const decimal = ('' + item).split('.')[1];
return decimal ? decimal.length : 0;
});
return Math.max(...precisions);
},
barStyle() {
return {
width: this.barSize,
left: this.barStart
};
}
},
watch: {
value1() {
this.onInternalValueUpdate();
},
value2() {
this.onInternalValueUpdate();
},
min() {
this.setValues(this.value);
},
max() {
this.setValues(this.value);
},
/**
* When v-model is changed set the new active step.
*/
modelValue(value) {
this.setValues(value);
}
},
methods: {
setValues(newValue) {
if (this.min > this.max) {
return;
}
if (Array.isArray(newValue)) {
this.isRange = true;
const smallValue = typeof newValue[0] !== 'number' || isNaN(newValue[0])
? this.min
: Math.min(Math.max(this.min, newValue[0]), this.max);
const largeValue = typeof newValue[1] !== 'number' || isNaN(newValue[1])
? this.max
: Math.max(Math.min(this.max, newValue[1]), this.min);
this.value1 = this.isThumbReversed ? largeValue : smallValue;
this.value2 = this.isThumbReversed ? smallValue : largeValue;
}
else {
this.isRange = false;
this.value1 = isNaN(newValue)
? this.min
: Math.min(this.max, Math.max(this.min, newValue));
this.value2 = null;
}
},
onInternalValueUpdate() {
if (this.isRange) {
this.isThumbReversed = this.value1 > this.value2;
}
if (!this.lazy || !this.dragging) {
this.emitValue('update:modelValue');
}
if (this.dragging) {
this.emitValue('dragging');
}
},
sliderSize() {
return this.$refs.slider.getBoundingClientRect().width;
},
onSliderClick(event) {
if (this.disabled || this.isTrackClickDisabled)
return;
const sliderOffsetLeft = this.$refs.slider.getBoundingClientRect().left;
const percent = (event.clientX - sliderOffsetLeft) / this.sliderSize() * 100;
const targetValue = this.min + percent * (this.max - this.min) / 100;
const diffFirst = Math.abs(targetValue - this.value1);
if (!this.isRange) {
if (diffFirst < this.step / 2)
return;
this.$refs.button1.setPosition(percent);
}
else {
const diffSecond = Math.abs(targetValue - this.value2);
if (diffFirst <= diffSecond) {
if (diffFirst < this.step / 2)
return;
this.$refs['button1'].setPosition(percent);
}
else {
if (diffSecond < this.step / 2)
return;
this.$refs['button2'].setPosition(percent);
}
}
this.emitValue('change');
},
onDragStart() {
this.dragging = true;
this.$emit('dragstart');
},
onDragEnd() {
this.isTrackClickDisabled = true;
setTimeout(() => {
// avoid triggering onSliderClick after dragend
this.isTrackClickDisabled = false;
}, 0);
this.dragging = false;
this.$emit('dragend');
if (this.lazy) {
this.emitValue('update:modelValue');
}
},
emitValue(event) {
const val = this.isRange
? [this.minValue, this.maxValue]
: this.value1;
this.$emit(event, val);
}
},
created() {
this.isThumbReversed = false;
this.isTrackClickDisabled = false;
this.setValues(this.modelValue);
}
});
function render$2(_ctx, _cache, $props, $setup, $data, $options) {
const _component_o_slider_tick = resolveComponent("o-slider-tick");
const _component_o_slider_thumb = resolveComponent("o-slider-thumb");
return openBlock(), createBlock("div", {
onClick: _cache[3] || (_cache[3] = (...args) => _ctx.onSliderClick(...args)),
class: _ctx.rootClasses
}, [createVNode("div", {
class: _ctx.trackClasses,
ref: "slider"
}, [createVNode("div", {
class: _ctx.fillClasses,
style: _ctx.barStyle
}, null, 6
/* CLASS, STYLE */
), _ctx.ticks ? (openBlock(true), createBlock(Fragment, {
key: 0
}, renderList(_ctx.tickValues, (val, key) => {
return openBlock(), createBlock(_component_o_slider_tick, {
key: key,
value: val
}, null, 8
/* PROPS */
, ["value"]);
}), 128
/* KEYED_FRAGMENT */
)) : createCommentVNode("v-if", true), renderSlot(_ctx.$slots, "default"), createVNode(_component_o_slider_thumb, {
modelValue: _ctx.value1,
"onUpdate:modelValue": _cache[1] || (_cache[1] = $event => _ctx.value1 = $event),
variant: _ctx.newTooltipVariant,
tooltip: _ctx.tooltip,
"custom-formatter": _ctx.customFormatter,
indicator: _ctx.indicator,
ref: "button1",
role: "slider",
format: _ctx.format,
locale: _ctx.locale,
"tooltip-always": _ctx.tooltipAlways,
"aria-valuenow": _ctx.value1,
"aria-valuemin": _ctx.min,
"aria-valuemax": _ctx.max,
"aria-orientation": "horizontal",
"aria-label": Array.isArray(_ctx.ariaLabel) ? _ctx.ariaLabel[0] : _ctx.ariaLabel,
"aria-disabled": _ctx.disabled,
onDragstart: _ctx.onDragStart,
onDragend: _ctx.onDragEnd
}, null, 8
/* PROPS */
, ["modelValue", "variant", "tooltip", "custom-formatter", "indicator", "format", "locale", "tooltip-always", "aria-valuenow", "aria-valuemin", "aria-valuemax", "aria-label", "aria-disabled", "onDragstart", "onDragend"]), _ctx.isRange ? createVNode(_component_o_slider_thumb, {
key: 1,
modelValue: _ctx.value2,
"onUpdate:modelValue": _cache[2] || (_cache[2] = $event => _ctx.value2 = $event),
variant: _ctx.newTooltipVariant,
tooltip: _ctx.tooltip,
"custom-formatter": _ctx.customFormatter,
indicator: _ctx.indicator,
ref: "button2",
role: "slider",
format: _ctx.format,
locale: _ctx.locale,
"tooltip-always": _ctx.tooltipAlways,
"aria-valuenow": _ctx.value2,
"aria-valuemin": _ctx.min,
"aria-valuemax": _ctx.max,
"aria-orientation": "horizontal",
"aria-label": Array.isArray(_ctx.ariaLabel) ? _ctx.ariaLabel[1] : '',
"aria-disabled": _ctx.disabled,
onDragstart: _ctx.onDragStart,
onDragend: _ctx.onDragEnd
}, null, 8
/* PROPS */
, ["modelValue", "variant", "tooltip", "custom-formatter", "indicator", "format", "locale", "tooltip-always", "aria-valuenow", "aria-valuemin", "aria-valuemax", "aria-label", "aria-disabled", "onDragstart", "onDragend"]) : createCommentVNode("v-if", true)], 2
/* CLASS */
)], 2
/* CLASS */
);
}
script$2.render = render$2;
script$2.__file = "src/components/slider/Slider.vue";
export { script$1 as a, script$2 as s };