UNPKG

element-plus

Version:

A Component Library for Vue 3

636 lines (633 loc) 23.7 kB
import { defineComponent, inject, ref, watch, nextTick, computed, unref, provide, resolveComponent, openBlock, createBlock, mergeProps, withCtx, normalizeClass, normalizeStyle, withModifiers, resolveDynamicComponent, createCommentVNode, createElementBlock, createElementVNode, renderSlot, toDisplayString } from 'vue'; import dayjs from 'dayjs'; import { isEqual } from 'lodash-unified'; import { onClickOutside } from '@vueuse/core'; import '../../../../hooks/index.mjs'; import '../../../../tokens/index.mjs'; import { ElInput } from '../../../input/index.mjs'; import { ElIcon } from '../../../icon/index.mjs'; import { ElTooltip } from '../../../tooltip/index.mjs'; import '../../../../utils/index.mjs'; import '../../../../constants/index.mjs'; import { Clock, Calendar } from '@element-plus/icons-vue'; import { timePickerDefaultProps } from './props.mjs'; import _export_sfc from '../../../../_virtual/plugin-vue_export-helper.mjs'; import { isEmpty } from '../../../../utils/types.mjs'; import { useLocale } from '../../../../hooks/use-locale/index.mjs'; import { useNamespace } from '../../../../hooks/use-namespace/index.mjs'; import { formContextKey, formItemContextKey } from '../../../../tokens/form.mjs'; import { debugWarn } from '../../../../utils/error.mjs'; import { useSize } from '../../../../hooks/use-common-props/index.mjs'; import { EVENT_CODE } from '../../../../constants/aria.mjs'; const dateEquals = function(a, b) { const aIsDate = a instanceof Date; const bIsDate = b instanceof Date; if (aIsDate && bIsDate) { return a.getTime() === b.getTime(); } if (!aIsDate && !bIsDate) { return a === b; } return false; }; const valueEquals = function(a, b) { const aIsArray = Array.isArray(a); const bIsArray = Array.isArray(b); if (aIsArray && bIsArray) { if (a.length !== b.length) { return false; } return a.every((item, index) => dateEquals(item, b[index])); } if (!aIsArray && !bIsArray) { return dateEquals(a, b); } return false; }; const parser = function(date, format, lang) { const day = isEmpty(format) || format === "x" ? dayjs(date).locale(lang) : dayjs(date, format).locale(lang); return day.isValid() ? day : void 0; }; const formatter = function(date, format, lang) { if (isEmpty(format)) return date; if (format === "x") return +date; return dayjs(date).locale(lang).format(format); }; const _sfc_main = defineComponent({ name: "Picker", components: { ElInput, ElTooltip, ElIcon }, props: timePickerDefaultProps, emits: [ "update:modelValue", "change", "focus", "blur", "calendar-change", "panel-change", "visible-change" ], setup(props, ctx) { const { lang } = useLocale(); const nsDate = useNamespace("date"); const nsInput = useNamespace("input"); const nsRange = useNamespace("range"); const elForm = inject(formContextKey, {}); const elFormItem = inject(formItemContextKey, {}); const elPopperOptions = inject("ElPopperOptions", {}); const refPopper = ref(); const inputRef = ref(); const pickerVisible = ref(false); const pickerActualVisible = ref(false); const valueOnOpen = ref(null); watch(pickerVisible, (val) => { var _a; if (!val) { userInput.value = null; nextTick(() => { emitChange(props.modelValue); }); ctx.emit("blur"); blurInput(); props.validateEvent && ((_a = elFormItem.validate) == null ? void 0 : _a.call(elFormItem, "blur").catch((err) => debugWarn(err))); } else { valueOnOpen.value = props.modelValue; } }); const emitChange = (val, isClear) => { var _a; if (isClear || !valueEquals(val, valueOnOpen.value)) { ctx.emit("change", val); props.validateEvent && ((_a = elFormItem.validate) == null ? void 0 : _a.call(elFormItem, "change").catch((err) => debugWarn(err))); } }; const emitInput = (val) => { if (!valueEquals(props.modelValue, val)) { let formatValue; if (Array.isArray(val)) { formatValue = val.map((_) => formatter(_, props.valueFormat, lang.value)); } else if (val) { formatValue = formatter(val, props.valueFormat, lang.value); } ctx.emit("update:modelValue", val ? formatValue : val, lang.value); } }; const refInput = computed(() => { if (inputRef.value) { const _r = isRangeInput.value ? inputRef.value : inputRef.value.$el; return Array.from(_r.querySelectorAll("input")); } return []; }); const refStartInput = computed(() => { return refInput == null ? void 0 : refInput.value[0]; }); const refEndInput = computed(() => { return refInput == null ? void 0 : refInput.value[1]; }); const setSelectionRange = (start, end, pos) => { const _inputs = refInput.value; if (!_inputs.length) return; if (!pos || pos === "min") { _inputs[0].setSelectionRange(start, end); _inputs[0].focus(); } else if (pos === "max") { _inputs[1].setSelectionRange(start, end); _inputs[1].focus(); } }; const onPick = (date = "", visible = false) => { pickerVisible.value = visible; let result; if (Array.isArray(date)) { result = date.map((_) => _.toDate()); } else { result = date ? date.toDate() : date; } userInput.value = null; emitInput(result); }; const onBeforeShow = () => { pickerActualVisible.value = true; }; const onShow = () => { ctx.emit("visible-change", true); }; const onHide = () => { pickerActualVisible.value = false; ctx.emit("visible-change", false); }; const focus = (focusStartInput = true) => { let input = refStartInput.value; if (!focusStartInput && isRangeInput.value) { input = refEndInput.value; } if (input) { input.focus(); } }; const handleFocus = (e) => { if (props.readonly || pickerDisabled.value || pickerVisible.value) return; pickerVisible.value = true; ctx.emit("focus", e); }; const handleBlur = () => { var _a; (_a = refPopper.value) == null ? void 0 : _a.onClose(); blurInput(); }; const pickerDisabled = computed(() => { return props.disabled || elForm.disabled; }); const parsedValue = computed(() => { let result; if (valueIsEmpty.value) { if (pickerOptions.value.getDefaultValue) { result = pickerOptions.value.getDefaultValue(); } } else { if (Array.isArray(props.modelValue)) { result = props.modelValue.map((_) => parser(_, props.valueFormat, lang.value)); } else { result = parser(props.modelValue, props.valueFormat, lang.value); } } if (pickerOptions.value.getRangeAvailableTime) { const availableResult = pickerOptions.value.getRangeAvailableTime(result); if (!isEqual(availableResult, result)) { result = availableResult; emitInput(Array.isArray(result) ? result.map((_) => _.toDate()) : result.toDate()); } } if (Array.isArray(result) && result.some((_) => !_)) { result = []; } return result; }); const displayValue = computed(() => { if (!pickerOptions.value.panelReady) return; const formattedValue = formatDayjsToString(parsedValue.value); if (Array.isArray(userInput.value)) { return [ userInput.value[0] || formattedValue && formattedValue[0] || "", userInput.value[1] || formattedValue && formattedValue[1] || "" ]; } else if (userInput.value !== null) { return userInput.value; } if (!isTimePicker.value && valueIsEmpty.value) return; if (!pickerVisible.value && valueIsEmpty.value) return; if (formattedValue) { return isDatesPicker.value ? formattedValue.join(", ") : formattedValue; } return ""; }); const isTimeLikePicker = computed(() => props.type.includes("time")); const isTimePicker = computed(() => props.type.startsWith("time")); const isDatesPicker = computed(() => props.type === "dates"); const triggerIcon = computed(() => props.prefixIcon || (isTimeLikePicker.value ? Clock : Calendar)); const showClose = ref(false); const onClearIconClick = (event) => { if (props.readonly || pickerDisabled.value) return; if (showClose.value) { event.stopPropagation(); emitInput(null); emitChange(null, true); showClose.value = false; pickerVisible.value = false; pickerOptions.value.handleClear && pickerOptions.value.handleClear(); } }; const valueIsEmpty = computed(() => { return !props.modelValue || Array.isArray(props.modelValue) && !props.modelValue.length; }); const onMouseEnter = () => { if (props.readonly || pickerDisabled.value) return; if (!valueIsEmpty.value && props.clearable) { showClose.value = true; } }; const onMouseLeave = () => { showClose.value = false; }; const isRangeInput = computed(() => { return props.type.includes("range"); }); const pickerSize = useSize(); const popperPaneRef = computed(() => { var _a, _b; return (_b = (_a = refPopper.value) == null ? void 0 : _a.popperRef) == null ? void 0 : _b.contentRef; }); const popperEl = computed(() => { var _a, _b; return (_b = (_a = unref(refPopper)) == null ? void 0 : _a.popperRef) == null ? void 0 : _b.contentRef; }); const actualInputRef = computed(() => { var _a; if (unref(isRangeInput)) { return unref(inputRef); } return (_a = unref(inputRef)) == null ? void 0 : _a.$el; }); onClickOutside(actualInputRef, (e) => { const unrefedPopperEl = unref(popperEl); const inputEl = unref(actualInputRef); if (unrefedPopperEl && (e.target === unrefedPopperEl || e.composedPath().includes(unrefedPopperEl)) || e.target === inputEl || e.composedPath().includes(inputEl)) return; pickerVisible.value = false; }); const userInput = ref(null); const handleChange = () => { if (userInput.value) { const value = parseUserInputToDayjs(displayValue.value); if (value) { if (isValidValue(value)) { emitInput(Array.isArray(value) ? value.map((_) => _.toDate()) : value.toDate()); userInput.value = null; } } } if (userInput.value === "") { emitInput(null); emitChange(null); userInput.value = null; } }; const blurInput = () => { refInput.value.forEach((input) => input.blur()); }; const parseUserInputToDayjs = (value) => { if (!value) return null; return pickerOptions.value.parseUserInput(value); }; const formatDayjsToString = (value) => { if (!value) return null; return pickerOptions.value.formatToString(value); }; const isValidValue = (value) => { return pickerOptions.value.isValidValue(value); }; const handleKeydown = (event) => { const code = event.code; if (code === EVENT_CODE.esc) { pickerVisible.value = false; event.stopPropagation(); return; } if (code === EVENT_CODE.tab) { if (!isRangeInput.value) { handleChange(); pickerVisible.value = false; event.stopPropagation(); } else { setTimeout(() => { if (!refInput.value.includes(document.activeElement)) { pickerVisible.value = false; blurInput(); } }, 0); } return; } if (code === EVENT_CODE.enter || code === EVENT_CODE.numpadEnter) { if (userInput.value === null || userInput.value === "" || isValidValue(parseUserInputToDayjs(displayValue.value))) { handleChange(); pickerVisible.value = false; } event.stopPropagation(); return; } if (userInput.value) { event.stopPropagation(); return; } if (pickerOptions.value.handleKeydown) { pickerOptions.value.handleKeydown(event); } }; const onUserInput = (e) => { userInput.value = e; }; const handleStartInput = (event) => { if (userInput.value) { userInput.value = [event.target.value, userInput.value[1]]; } else { userInput.value = [event.target.value, null]; } }; const handleEndInput = (event) => { if (userInput.value) { userInput.value = [userInput.value[0], event.target.value]; } else { userInput.value = [null, event.target.value]; } }; const handleStartChange = () => { const value = parseUserInputToDayjs(userInput.value && userInput.value[0]); if (value && value.isValid()) { userInput.value = [formatDayjsToString(value), displayValue.value[1]]; const newValue = [value, parsedValue.value && parsedValue.value[1]]; if (isValidValue(newValue)) { emitInput(newValue); userInput.value = null; } } }; const handleEndChange = () => { const value = parseUserInputToDayjs(userInput.value && userInput.value[1]); if (value && value.isValid()) { userInput.value = [displayValue.value[0], formatDayjsToString(value)]; const newValue = [parsedValue.value && parsedValue.value[0], value]; if (isValidValue(newValue)) { emitInput(newValue); userInput.value = null; } } }; const pickerOptions = ref({}); const onSetPickerOption = (e) => { pickerOptions.value[e[0]] = e[1]; pickerOptions.value.panelReady = true; }; const onCalendarChange = (e) => { ctx.emit("calendar-change", e); }; const onPanelChange = (value, mode, view) => { ctx.emit("panel-change", value, mode, view); }; provide("EP_PICKER_BASE", { props }); return { nsDate, nsInput, nsRange, elPopperOptions, isDatesPicker, handleEndChange, handleStartChange, handleStartInput, handleEndInput, onUserInput, handleChange, handleKeydown, popperPaneRef, onClickOutside, pickerSize, isRangeInput, onMouseLeave, onMouseEnter, onClearIconClick, showClose, triggerIcon, onPick, handleFocus, handleBlur, pickerVisible, pickerActualVisible, displayValue, parsedValue, setSelectionRange, refPopper, inputRef, pickerDisabled, onSetPickerOption, onCalendarChange, onPanelChange, focus, onShow, onBeforeShow, onHide }; } }); const _hoisted_1 = ["id", "name", "placeholder", "value", "disabled", "readonly"]; const _hoisted_2 = ["id", "name", "placeholder", "value", "disabled", "readonly"]; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { const _component_el_icon = resolveComponent("el-icon"); const _component_el_input = resolveComponent("el-input"); const _component_el_tooltip = resolveComponent("el-tooltip"); return openBlock(), createBlock(_component_el_tooltip, mergeProps({ ref: "refPopper", visible: _ctx.pickerVisible, "onUpdate:visible": _cache[17] || (_cache[17] = ($event) => _ctx.pickerVisible = $event), effect: "light", pure: "", trigger: "click" }, _ctx.$attrs, { "append-to-body": "", transition: `${_ctx.nsDate.namespace.value}-zoom-in-top`, "popper-class": [`${_ctx.nsDate.namespace.value}-picker__popper`, _ctx.popperClass], "popper-options": _ctx.elPopperOptions, "fallback-placements": ["bottom", "top", "right", "left"], "gpu-acceleration": false, "stop-popper-mouse-event": false, "hide-after": 0, persistent: "", onBeforeShow: _ctx.onBeforeShow, onShow: _ctx.onShow, onHide: _ctx.onHide }), { default: withCtx(() => [ !_ctx.isRangeInput ? (openBlock(), createBlock(_component_el_input, { key: 0, id: _ctx.id, ref: "inputRef", "model-value": _ctx.displayValue, name: _ctx.name, size: _ctx.pickerSize, disabled: _ctx.pickerDisabled, placeholder: _ctx.placeholder, class: normalizeClass([_ctx.nsDate.b("editor"), _ctx.nsDate.bm("editor", _ctx.type), _ctx.$attrs.class]), style: normalizeStyle(_ctx.$attrs.style), readonly: !_ctx.editable || _ctx.readonly || _ctx.isDatesPicker || _ctx.type === "week", onInput: _ctx.onUserInput, onFocus: _ctx.handleFocus, onKeydown: _ctx.handleKeydown, onChange: _ctx.handleChange, onMouseenter: _ctx.onMouseEnter, onMouseleave: _ctx.onMouseLeave, onClick: _cache[0] || (_cache[0] = withModifiers(() => { }, ["stop"])) }, { prefix: withCtx(() => [ _ctx.triggerIcon ? (openBlock(), createBlock(_component_el_icon, { key: 0, class: normalizeClass(_ctx.nsInput.e("icon")), onClick: _ctx.handleFocus }, { default: withCtx(() => [ (openBlock(), createBlock(resolveDynamicComponent(_ctx.triggerIcon))) ]), _: 1 }, 8, ["class", "onClick"])) : createCommentVNode("v-if", true) ]), suffix: withCtx(() => [ _ctx.showClose && _ctx.clearIcon ? (openBlock(), createBlock(_component_el_icon, { key: 0, class: normalizeClass(`${_ctx.nsInput.e("icon")} clear-icon`), onClick: _ctx.onClearIconClick }, { default: withCtx(() => [ (openBlock(), createBlock(resolveDynamicComponent(_ctx.clearIcon))) ]), _: 1 }, 8, ["class", "onClick"])) : createCommentVNode("v-if", true) ]), _: 1 }, 8, ["id", "model-value", "name", "size", "disabled", "placeholder", "class", "style", "readonly", "onInput", "onFocus", "onKeydown", "onChange", "onMouseenter", "onMouseleave"])) : (openBlock(), createElementBlock("div", { key: 1, ref: "inputRef", class: normalizeClass([ _ctx.nsDate.b("editor"), _ctx.nsDate.bm("editor", _ctx.type), _ctx.nsInput.e("inner"), _ctx.nsDate.is("disabled", _ctx.pickerDisabled), _ctx.nsDate.is("active", _ctx.pickerVisible), _ctx.nsRange.b("editor"), _ctx.pickerSize ? _ctx.nsRange.bm("editor", _ctx.pickerSize) : "", _ctx.$attrs.class ]), style: normalizeStyle(_ctx.$attrs.style), onClick: _cache[7] || (_cache[7] = (...args) => _ctx.handleFocus && _ctx.handleFocus(...args)), onMouseenter: _cache[8] || (_cache[8] = (...args) => _ctx.onMouseEnter && _ctx.onMouseEnter(...args)), onMouseleave: _cache[9] || (_cache[9] = (...args) => _ctx.onMouseLeave && _ctx.onMouseLeave(...args)), onKeydown: _cache[10] || (_cache[10] = (...args) => _ctx.handleKeydown && _ctx.handleKeydown(...args)) }, [ _ctx.triggerIcon ? (openBlock(), createBlock(_component_el_icon, { key: 0, class: normalizeClass([_ctx.nsInput.e("icon"), _ctx.nsRange.e("icon")]), onClick: _ctx.handleFocus }, { default: withCtx(() => [ (openBlock(), createBlock(resolveDynamicComponent(_ctx.triggerIcon))) ]), _: 1 }, 8, ["class", "onClick"])) : createCommentVNode("v-if", true), createElementVNode("input", { id: _ctx.id && _ctx.id[0], autocomplete: "off", name: _ctx.name && _ctx.name[0], placeholder: _ctx.startPlaceholder, value: _ctx.displayValue && _ctx.displayValue[0], disabled: _ctx.pickerDisabled, readonly: !_ctx.editable || _ctx.readonly, class: normalizeClass(_ctx.nsRange.b("input")), onInput: _cache[1] || (_cache[1] = (...args) => _ctx.handleStartInput && _ctx.handleStartInput(...args)), onChange: _cache[2] || (_cache[2] = (...args) => _ctx.handleStartChange && _ctx.handleStartChange(...args)), onFocus: _cache[3] || (_cache[3] = (...args) => _ctx.handleFocus && _ctx.handleFocus(...args)) }, null, 42, _hoisted_1), renderSlot(_ctx.$slots, "range-separator", {}, () => [ createElementVNode("span", { class: normalizeClass(_ctx.nsRange.b("separator")) }, toDisplayString(_ctx.rangeSeparator), 3) ]), createElementVNode("input", { id: _ctx.id && _ctx.id[1], autocomplete: "off", name: _ctx.name && _ctx.name[1], placeholder: _ctx.endPlaceholder, value: _ctx.displayValue && _ctx.displayValue[1], disabled: _ctx.pickerDisabled, readonly: !_ctx.editable || _ctx.readonly, class: normalizeClass(_ctx.nsRange.b("input")), onFocus: _cache[4] || (_cache[4] = (...args) => _ctx.handleFocus && _ctx.handleFocus(...args)), onInput: _cache[5] || (_cache[5] = (...args) => _ctx.handleEndInput && _ctx.handleEndInput(...args)), onChange: _cache[6] || (_cache[6] = (...args) => _ctx.handleEndChange && _ctx.handleEndChange(...args)) }, null, 42, _hoisted_2), _ctx.clearIcon ? (openBlock(), createBlock(_component_el_icon, { key: 1, class: normalizeClass([ _ctx.nsInput.e("icon"), _ctx.nsRange.e("close-icon"), { [_ctx.nsRange.e("close-icon--hidden")]: !_ctx.showClose } ]), onClick: _ctx.onClearIconClick }, { default: withCtx(() => [ (openBlock(), createBlock(resolveDynamicComponent(_ctx.clearIcon))) ]), _: 1 }, 8, ["class", "onClick"])) : createCommentVNode("v-if", true) ], 38)) ]), content: withCtx(() => [ renderSlot(_ctx.$slots, "default", { visible: _ctx.pickerVisible, actualVisible: _ctx.pickerActualVisible, parsedValue: _ctx.parsedValue, format: _ctx.format, unlinkPanels: _ctx.unlinkPanels, type: _ctx.type, defaultValue: _ctx.defaultValue, onPick: _cache[11] || (_cache[11] = (...args) => _ctx.onPick && _ctx.onPick(...args)), onSelectRange: _cache[12] || (_cache[12] = (...args) => _ctx.setSelectionRange && _ctx.setSelectionRange(...args)), onSetPickerOption: _cache[13] || (_cache[13] = (...args) => _ctx.onSetPickerOption && _ctx.onSetPickerOption(...args)), onCalendarChange: _cache[14] || (_cache[14] = (...args) => _ctx.onCalendarChange && _ctx.onCalendarChange(...args)), onPanelChange: _cache[15] || (_cache[15] = (...args) => _ctx.onPanelChange && _ctx.onPanelChange(...args)), onMousedown: _cache[16] || (_cache[16] = withModifiers(() => { }, ["stop"])) }) ]), _: 3 }, 16, ["visible", "transition", "popper-class", "popper-options", "onBeforeShow", "onShow", "onHide"]); } var CommonPicker = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__file", "/home/runner/work/element-plus/element-plus/packages/components/time-picker/src/common/picker.vue"]]); export { CommonPicker as default }; //# sourceMappingURL=picker.mjs.map