UNPKG

@fesjs/fes-design

Version:
410 lines (403 loc) 13.6 kB
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty'; import { defineComponent, computed, ref, watch, resolveComponent, openBlock, createBlock, withCtx, normalizeClass, normalizeStyle, renderSlot, createVNode } from 'vue'; import { isValid, format } from 'date-fns'; import { isNil, isEqual, isArray } from 'lodash-es'; import InputInner from '../input/inputInner.js'; import Popper from '../popper'; import useFormAdaptor from '../_util/use/useFormAdaptor'; import { useNormalModel } from '../_util/use/useModel'; import getPrefixCls from '../_util/getPrefixCls'; import { useTheme } from '../_theme/useTheme'; import { DateOutlined, SwapRightOutlined } from '../icon'; import { useLocale } from '../config-provider/useLocale'; import { COMMON_PROPS, RANGE_PROPS } from './const'; import { strictParse, isEmptyValue } from './helper'; import Calendars from './calendars.js'; import RangeInput from './rangeInput.js'; import { pickerFactory, PickerType } from './pickerHandler'; import { useDisable } from './use'; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const prefixCls = getPrefixCls('date-picker'); const datePickerProps = _objectSpread(_objectSpread({ open: { type: Boolean, default: false }, disabled: { type: Boolean, default: false }, clearable: { type: Boolean, default: false }, placeholder: { type: [String, Array] }, appendToContainer: { type: Boolean, default: true }, getContainer: { type: Function }, popperClass: [String, Array, Object], control: Boolean, shortcuts: Object, disabledDate: Function }, COMMON_PROPS), RANGE_PROPS); const useTmpSelectedDates = () => { const tmpSelectedDates = ref(); const tmpSelectedDateChange = val => { tmpSelectedDates.value = val; }; return { tmpSelectedDates, tmpSelectedDateChange }; }; const useInput = _ref => { let { props, visibleValue, picker, changeDateByInput } = _ref; const dateText = ref(); const { innerDisabledDate } = useDisable(props); let cacheValidInputDate = ''; const getFormatDate = () => { if (isEmptyValue(visibleValue.value)) { return ''; } if (!picker.value.isRange) { if (isArray(visibleValue.value)) { return visibleValue.value.map(item => { return format(item, props.format || picker.value.format); }).join('; '); } return format(visibleValue.value, props.format || picker.value.format); } return ''; }; const resetDateText = () => { dateText.value = getFormatDate(); cacheValidInputDate = dateText.value; }; watch([visibleValue, () => props.format], resetDateText, { immediate: true }); const handleDateInput = val => { dateText.value = val; const date = strictParse(val, props.format || picker.value.format, new Date()); if (isValid(date) && !innerDisabledDate(date, props.format || picker.value.format)) { cacheValidInputDate = val; changeDateByInput(date.getTime()); } }; const handleDateInputBlur = () => { if (dateText.value !== cacheValidInputDate && cacheValidInputDate) { dateText.value = cacheValidInputDate; } }; return { resetDateText, dateText, handleDateInput, handleDateInputBlur }; }; const usePlaceholder = (props, picker) => { const { t } = useLocale(); const innerPlaceHolder = computed(() => { if (props.placeholder) { return props.placeholder; } const placeholderLang = picker.value.placeholderLang; if (Array.isArray(placeholderLang)) { return placeholderLang.map(item => t(item)); } return t(placeholderLang); }); const singlePlaceHolder = computed(() => { return Array.isArray(innerPlaceHolder.value) ? innerPlaceHolder.value[0] : innerPlaceHolder.value; }); return { innerPlaceHolder, singlePlaceHolder }; }; var script = defineComponent({ name: 'FDatePicker', components: { Calendars, InputInner, Popper, DateOutlined, RangeInput, SwapRightOutlined }, props: datePickerProps, emits: ['update:modelValue', 'update:open', 'change', 'clear', 'blur', 'focus'], setup(props, _ref2) { let { emit, attrs } = _ref2; useTheme(); const [isOpened, updatePopperOpen] = useNormalModel(props, emit, { prop: 'open' }); const [currentValue, updateCurrentValue] = useNormalModel(props, emit); /** * props.format 是最终给用户展示的格式,不必和 picker.value.format 一致 * picker.value.format 用于内部处理 */ const pickerRef = computed(() => { return pickerFactory(props.type); }); const inputRefEl = ref(); const inputRangeRefEL = ref(); const calendarsRef = ref(); const activeInputRefEL = computed(() => { if (pickerRef.value.isRange) { return inputRangeRefEL.value; } return inputRefEl.value; }); const { validate, isError, isFormDisabled } = useFormAdaptor({ valueType: computed(() => pickerRef.value.isRange ? 'array' : 'number'), forbidChildValidate: true }); const innerDisabled = computed(() => props.disabled || isFormDisabled.value); const { innerPlaceHolder, singlePlaceHolder } = usePlaceholder(props, pickerRef); const { tmpSelectedDates, tmpSelectedDateChange } = useTmpSelectedDates(); const visibleValue = computed(() => { if (isOpened.value) { return isNil(tmpSelectedDates.value) ? currentValue.value : tmpSelectedDates.value; } return currentValue.value; }); const handleChange = val => { if (!isEqual(val, currentValue.value)) { updateCurrentValue(val); emit('change', val); validate('change'); } }; // 输入框里的变更,直接更新 currentValue const changeDateByInput = val => { tmpSelectedDateChange(null); handleChange(val); }; const { resetDateText, dateText, handleDateInput, handleDateInputBlur } = useInput({ props, visibleValue, changeDateByInput, picker: pickerRef }); // 事件 const clear = () => { const initValue = pickerRef.value.isRange || pickerRef.value.name === PickerType.datemultiple ? [] : null; tmpSelectedDateChange(null); handleChange(initValue); emit('clear'); }; const changeDateBycalendars = val => { handleChange(val); // 选择完后重新聚焦 activeInputRefEL.value.focus(); updatePopperOpen(false); }; const inputIsFocus = ref(false); const handleFocus = e => { // 防止重复聚焦 if (!inputIsFocus.value) { inputIsFocus.value = true; emit('focus', e); } }; let cacheEvent = null; const checkBlur = () => { if (!isOpened.value && cacheEvent) { emit('blur', cacheEvent); validate('blur'); // 重置输入框内容 resetDateText(); cacheEvent = null; inputIsFocus.value = false; } }; const handleBlur = e => { var _calendarsRef$value; cacheEvent = e; // 非弹窗内容点击导致的失焦,进行 blur 的校验 // 兼容禁用状态,选择框不展示的情况 if (!((_calendarsRef$value = calendarsRef.value) !== null && _calendarsRef$value !== void 0 && _calendarsRef$value.$el.contains(e.relatedTarget))) { if (isOpened.value) { updatePopperOpen(false); } checkBlur(); } }; watch(isOpened, () => { if (!isOpened.value) { // 重置临时输入 tmpSelectedDateChange(null); } }); const handlePopperVisible = val => { if (val === false) { checkBlur(); } }; return { prefixCls, isOpened, currentValue, visibleValue, isError, innerDisabled, dateText, handleDateInput, handleDateInputBlur: event => { handleDateInputBlur(); handleBlur(event); }, PickerType, pickerRef, changeDateByInput, clear, changeDateBycalendars, inputIsFocus, handleFocus, handleBlur, tmpSelectedDateChange, innerPlaceHolder, singlePlaceHolder, handlePopperVisible, inputRefEl, inputRangeRefEL, calendarsRef, attrs }; } }); function render(_ctx, _cache, $props, $setup, $data, $options) { const _component_SwapRightOutlined = resolveComponent("SwapRightOutlined"); const _component_DateOutlined = resolveComponent("DateOutlined"); const _component_RangeInput = resolveComponent("RangeInput"); const _component_InputInner = resolveComponent("InputInner"); const _component_calendars = resolveComponent("calendars"); const _component_Popper = resolveComponent("Popper"); return openBlock(), createBlock(_component_Popper, { modelValue: _ctx.isOpened, "onUpdate:modelValue": [_cache[0] || (_cache[0] = $event => _ctx.isOpened = $event), _ctx.handlePopperVisible], disabled: _ctx.innerDisabled, appendToContainer: _ctx.appendToContainer, getContainer: _ctx.getContainer, popperClass: [_ctx.popperClass, `${_ctx.prefixCls}-popper`], trigger: "click", hideAfter: 0, placement: "bottom-start", offset: 4, onlyShowTrigger: "" }, { trigger: withCtx(() => [_ctx.pickerRef.isRange ? (openBlock(), createBlock(_component_RangeInput, { key: 0, ref: "inputRangeRefEL", format: _ctx.format || _ctx.pickerRef.format, selectedDates: _ctx.visibleValue, placeholder: _ctx.innerPlaceHolder, clearable: _ctx.clearable, disabled: _ctx.innerDisabled, innerIsFocus: _ctx.inputIsFocus, innerIsError: _ctx.isError, class: normalizeClass(_ctx.attrs.class), style: normalizeStyle(_ctx.attrs.style), changeSelectedDates: _ctx.changeDateByInput, maxRange: _ctx.maxRange, onFocus: _ctx.handleFocus, onBlur: _ctx.handleBlur, onClear: _ctx.clear }, { separator: withCtx(() => [_ctx.$slots.separator ? renderSlot(_ctx.$slots, "separator", { key: 0 }) : (openBlock(), createBlock(_component_SwapRightOutlined, { key: 1 }))]), suffix: withCtx(() => [_ctx.$slots.suffixIcon ? renderSlot(_ctx.$slots, "suffixIcon", { key: 0 }) : (openBlock(), createBlock(_component_DateOutlined, { key: 1 }))]), _: 3 /* FORWARDED */ }, 8 /* PROPS */, ["format", "selectedDates", "placeholder", "clearable", "disabled", "innerIsFocus", "innerIsError", "class", "style", "changeSelectedDates", "maxRange", "onFocus", "onBlur", "onClear"])) : (openBlock(), createBlock(_component_InputInner, { key: 1, ref: "inputRefEl", modelValue: _ctx.dateText, placeholder: _ctx.singlePlaceHolder, disabled: _ctx.innerDisabled, canEdit: _ctx.pickerRef.name !== _ctx.PickerType.datemultiple, clearable: _ctx.clearable, innerIsFocus: _ctx.inputIsFocus, innerIsError: _ctx.isError, class: normalizeClass(_ctx.attrs.class), style: normalizeStyle(_ctx.attrs.style), onFocus: _ctx.handleFocus, onInput: _ctx.handleDateInput, onBlur: _ctx.handleDateInputBlur, onClear: _ctx.clear }, { suffix: withCtx(() => [_ctx.$slots.suffixIcon ? renderSlot(_ctx.$slots, "suffixIcon", { key: 0 }) : (openBlock(), createBlock(_component_DateOutlined, { key: 1 }))]), _: 3 /* FORWARDED */ }, 8 /* PROPS */, ["modelValue", "placeholder", "disabled", "canEdit", "clearable", "innerIsFocus", "innerIsError", "class", "style", "onFocus", "onInput", "onBlur", "onClear"]))]), default: withCtx(() => [createVNode(_component_calendars, { ref: "calendarsRef", visible: _ctx.isOpened, modelValue: _ctx.currentValue, type: _ctx.type, control: _ctx.control, shortcuts: _ctx.shortcuts, minDate: _ctx.minDate, maxDate: _ctx.maxDate, maxRange: _ctx.maxRange, hourStep: _ctx.hourStep, minuteStep: _ctx.minuteStep, secondStep: _ctx.secondStep, disabledDate: _ctx.disabledDate, disabledTime: _ctx.disabledTime, defaultTime: _ctx.defaultTime, onChange: _ctx.changeDateBycalendars, onTmpSelectedDateChange: _ctx.tmpSelectedDateChange }, null, 8 /* PROPS */, ["visible", "modelValue", "type", "control", "shortcuts", "minDate", "maxDate", "maxRange", "hourStep", "minuteStep", "secondStep", "disabledDate", "disabledTime", "defaultTime", "onChange", "onTmpSelectedDateChange"])]), _: 3 /* FORWARDED */ }, 8 /* PROPS */, ["modelValue", "disabled", "appendToContainer", "getContainer", "popperClass", "onUpdate:modelValue"]); } script.render = render; script.__file = "components/date-picker/datePicker.vue"; export { datePickerProps, script as default };