@arco-design/web-vue
Version:
Arco Design Vue 2.0: A Vue.js 3 UI Library
768 lines (767 loc) • 25 kB
JavaScript
import { defineComponent, toRefs, inject, watchEffect, computed, reactive, ref, watch, nextTick, onUnmounted, resolveComponent, openBlock, createBlock, mergeProps, withCtx, createVNode, normalizeProps, guardReactiveProps, renderSlot, createSlots, createTextVNode, toDisplayString } from "vue";
import { getPrefixCls } from "../_utils/global-config.js";
import { isArray, isBoolean } from "../_utils/is.js";
import pick from "../_utils/pick.js";
import { getFormattedValue, isValidInputValue } from "../time-picker/utils/index.js";
import { initializeDateLocale, getDateValue, getNow, dayjs, isValueChange, getSortedDayjsArray } from "../_utils/date.js";
import useState from "../_hooks/use-state.js";
import { isCompleteRangeValue, isValidRangeValue, mergeValueWithTime } from "./utils/index.js";
import useFormat from "./hooks/use-format.js";
import useRangePickerState from "./hooks/use-range-picker-state.js";
import useRangeHeaderValue from "./hooks/use-range-header-value.js";
import Trigger from "../trigger/index.js";
import DateRangeInput from "../_components/picker/input-range.js";
import RangePickerPanel from "./range-picker-panel.js";
import useRangeTimePickerValue from "./hooks/use-range-time-picker-value.js";
import useIsDisabledDate from "./hooks/use-is-disabled-date.js";
import { omit } from "../_utils/omit.js";
import useMergeState from "../_hooks/use-merge-state.js";
import IconCalendar from "../icon/icon-calendar/index.js";
import useDatePickerTransform from "./hooks/use-provide-datepicker-transform.js";
import { getReturnRangeValue } from "./hooks/use-value-format.js";
import { useFormItem } from "../_hooks/use-form-item.js";
import { useI18n } from "../locale/index.js";
import { configProviderInjectionKey } from "../config-provider/context.js";
import _export_sfc from "../_virtual/plugin-vue_export-helper.js";
const _sfc_main = defineComponent({
name: "RangePicker",
components: {
RangePickerPanel,
DateRangeInput,
Trigger,
IconCalendar
},
inheritAttrs: false,
props: {
mode: {
type: String,
default: "date"
},
modelValue: {
type: Array
},
defaultValue: {
type: Array
},
pickerValue: {
type: Array
},
defaultPickerValue: {
type: Array
},
disabled: {
type: [Boolean, Array],
default: false
},
dayStartOfWeek: {
type: Number,
default: 0
},
format: {
type: String
},
valueFormat: {
type: String
},
showTime: {
type: Boolean
},
timePickerProps: {
type: Object
},
placeholder: {
type: Array
},
disabledDate: {
type: Function
},
disabledTime: {
type: Function
},
separator: {
type: String
},
exchangeTime: {
type: Boolean,
default: true
},
popupContainer: {
type: [String, Object]
},
locale: {
type: Object
},
hideTrigger: {
type: Boolean
},
allowClear: {
type: Boolean,
default: true
},
readonly: {
type: Boolean
},
error: {
type: Boolean
},
size: {
type: String
},
shortcuts: {
type: Array,
default: () => []
},
shortcutsPosition: {
type: String,
default: "bottom"
},
position: {
type: String,
default: "bl"
},
popupVisible: {
type: Boolean,
default: void 0
},
defaultPopupVisible: {
type: Boolean
},
triggerProps: {
type: Object
},
unmountOnClose: {
type: Boolean
},
previewShortcut: {
type: Boolean,
default: true
},
showConfirmBtn: {
type: Boolean
},
disabledInput: {
type: Boolean,
default: false
},
abbreviation: {
type: Boolean,
default: true
}
},
emits: {
"change": (value, date, dateString) => {
return true;
},
"update:modelValue": (value) => {
return true;
},
"select": (value, date, dateString) => {
return true;
},
"popup-visible-change": (visible) => {
return true;
},
"update:popupVisible": (visible) => {
return true;
},
"ok": (value, date, dateString) => {
return true;
},
"clear": () => {
return true;
},
"select-shortcut": (shortcut) => {
return true;
},
"picker-value-change": (value, date, dateString) => {
return true;
},
"update:pickerValue": (value) => {
return true;
}
},
setup(props, { emit, slots }) {
const {
mode,
showTime,
format,
modelValue,
defaultValue,
popupVisible,
defaultPopupVisible,
placeholder,
timePickerProps,
disabled,
disabledDate,
disabledTime,
locale,
pickerValue,
defaultPickerValue,
valueFormat,
size,
error,
dayStartOfWeek,
exchangeTime,
previewShortcut,
showConfirmBtn
} = toRefs(props);
const { locale: globalLocal } = useI18n();
const configCtx = inject(configProviderInjectionKey, void 0);
watchEffect(() => {
initializeDateLocale(globalLocal.value, dayStartOfWeek.value);
});
const mergedExchangeTime = computed(() => {
var _a;
return !(!exchangeTime.value || !((_a = configCtx == null ? void 0 : configCtx.exchangeTime) != null ? _a : true));
});
const {
mergedSize,
mergedDisabled: formDisabled,
mergedError,
eventHandlers
} = useFormItem({
size,
error
});
const datePickerT = useDatePickerTransform(
reactive({
locale
})
);
const prefixCls = getPrefixCls("picker");
const computedPlaceholder = computed(
() => (placeholder == null ? void 0 : placeholder.value) || {
date: datePickerT("datePicker.rangePlaceholder.date"),
month: datePickerT("datePicker.rangePlaceholder.month"),
year: datePickerT("datePicker.rangePlaceholder.year"),
week: datePickerT("datePicker.rangePlaceholder.week"),
quarter: datePickerT("datePicker.rangePlaceholder.quarter")
}[mode.value] || datePickerT("datePicker.rangePlaceholder.date")
);
const {
format: computedFormat,
valueFormat: returnValueFormat,
parseValueFormat
} = useFormat(
reactive({
mode,
format,
showTime,
valueFormat
})
);
const disabledArray = computed(() => {
const disabled0 = disabled.value === true || formDisabled.value || isArray(disabled.value) && disabled.value[0] === true;
const disabled1 = disabled.value === true || formDisabled.value || isArray(disabled.value) && disabled.value[1] === true;
return [disabled0, disabled1];
});
const triggerDisabled = computed(
() => disabledArray.value[0] && disabledArray.value[1]
);
function getFocusedIndex(cur = 0) {
return disabledArray.value[cur] ? cur ^ 1 : cur;
}
const refInput = ref();
const focusedIndex = ref(getFocusedIndex());
const nextFocusedIndex = computed(() => {
const cur = focusedIndex.value;
const next = cur ^ 1;
return disabledArray.value[next] ? cur : next;
});
const isNextDisabled = computed(
() => disabledArray.value[focusedIndex.value ^ 1]
);
const { value: selectedValue, setValue: setSelectedValue } = useRangePickerState(
reactive({
modelValue,
defaultValue,
format: parseValueFormat
})
);
const [processValue, setProcessValue] = useState();
const [previewValue, setPreviewValue] = useState();
const forSelectedValue = computed(
() => {
var _a;
return (_a = processValue.value) != null ? _a : selectedValue.value;
}
);
const panelValue = computed(
() => {
var _a, _b;
return (_b = (_a = previewValue.value) != null ? _a : processValue.value) != null ? _b : selectedValue.value;
}
);
const [inputValue, setInputValue] = useState();
const startHeaderMode = ref();
const endHeaderMode = ref();
const [panelVisible, setLocalPanelVisible] = useMergeState(
defaultPopupVisible.value,
reactive({ value: popupVisible })
);
const setPanelVisible = (newVisible) => {
if (panelVisible.value !== newVisible) {
setLocalPanelVisible(newVisible);
emit("popup-visible-change", newVisible);
emit("update:popupVisible", newVisible);
}
};
const {
startHeaderValue,
endHeaderValue,
startHeaderOperations,
endHeaderOperations,
resetHeaderValue,
setHeaderValue
} = useRangeHeaderValue(
reactive({
mode,
startHeaderMode,
endHeaderMode,
value: pickerValue,
defaultValue: defaultPickerValue,
selectedValue: panelValue,
format: parseValueFormat,
onChange: (newVal) => {
const returnValue = getReturnRangeValue(
newVal,
returnValueFormat.value
);
const formattedValue = getFormattedValue(
newVal,
parseValueFormat.value
);
const dateValue = getDateValue(newVal);
emit("picker-value-change", returnValue, dateValue, formattedValue);
emit("update:pickerValue", returnValue);
}
})
);
function onStartPanelHeaderLabelClick(type) {
startHeaderMode.value = type;
}
function onEndPanelHeaderLabelClick(type) {
endHeaderMode.value = type;
}
function onStartPanelHeaderSelect(date) {
let newStartValue = startHeaderValue.value;
newStartValue = newStartValue.set("year", date.year());
if (startHeaderMode.value === "month") {
newStartValue = newStartValue.set("month", date.month());
}
setHeaderValue([newStartValue, endHeaderValue.value]);
startHeaderMode.value = void 0;
}
function onEndPanelHeaderSelect(date) {
let newEndValue = endHeaderValue.value;
newEndValue = newEndValue.set("year", date.year());
if (endHeaderMode.value === "month") {
newEndValue = newEndValue.set("month", date.month());
}
setHeaderValue([startHeaderValue.value, newEndValue]);
endHeaderMode.value = void 0;
}
const footerValue = ref([
panelValue.value[0] || getNow(),
panelValue.value[1] || getNow()
]);
watch(panelValue, () => {
const [value0, value1] = panelValue.value;
footerValue.value[0] = value0 || footerValue.value[0];
footerValue.value[1] = value1 || footerValue.value[1];
});
const [timePickerValue, setTimePickerValue, resetTimePickerValue] = useRangeTimePickerValue(
reactive({
timePickerProps,
selectedValue: panelValue
})
);
const isDateTime = computed(() => mode.value === "date" && showTime.value);
const hasTime = computed(() => isDateTime.value || timePickerProps.value);
const isDisabledDate = useIsDisabledDate(
reactive({
mode,
isRange: true,
showTime,
disabledDate,
disabledTime
})
);
const needConfirm = computed(
() => isDateTime.value || showConfirmBtn.value
);
const confirmBtnDisabled = computed(
() => needConfirm.value && (!isCompleteRangeValue(forSelectedValue.value) || isDisabledDate(forSelectedValue.value[0], "start") || isDisabledDate(forSelectedValue.value[1], "end"))
);
watch(panelVisible, (newVisible) => {
startHeaderMode.value = void 0;
endHeaderMode.value = void 0;
setProcessValue(void 0);
setPreviewValue(void 0);
if (newVisible) {
resetHeaderValue();
resetTimePickerValue();
focusedIndex.value = getFocusedIndex(focusedIndex.value);
nextTick(() => focusInput(focusedIndex.value));
}
if (!newVisible) {
setInputValue(void 0);
}
});
watch(focusedIndex, () => {
if (props.disabledInput) {
focusInput(focusedIndex.value);
setInputValue(void 0);
}
});
function emitChange(value, emitOk) {
var _a, _b;
const returnValue = value ? getReturnRangeValue(value, returnValueFormat.value) : void 0;
const formattedValue = getFormattedValue(value, parseValueFormat.value);
const dateValue = getDateValue(value);
if (isValueChange(value, selectedValue.value)) {
emit("update:modelValue", returnValue);
emit("change", returnValue, dateValue, formattedValue);
(_b = (_a = eventHandlers.value) == null ? void 0 : _a.onChange) == null ? void 0 : _b.call(_a);
}
if (emitOk) {
emit("ok", returnValue, dateValue, formattedValue);
}
}
function getSortedDayjsArrayByExchangeTimeOrNot(newValue) {
let sortedValue = getSortedDayjsArray(newValue);
if (hasTime.value && !mergedExchangeTime.value) {
sortedValue = [
getMergedOpValue(sortedValue[0], newValue[0]),
getMergedOpValue(sortedValue[1], newValue[1])
];
}
return sortedValue;
}
function confirm(value, showPanel, emitOk) {
if (isDisabledDate(value == null ? void 0 : value[0], "start") || isDisabledDate(value == null ? void 0 : value[1], "end")) {
return;
}
let newValue = value ? [...value] : void 0;
if (isCompleteRangeValue(newValue)) {
newValue = getSortedDayjsArrayByExchangeTimeOrNot(newValue);
}
emitChange(newValue, emitOk);
setSelectedValue(newValue || []);
setProcessValue(void 0);
setPreviewValue(void 0);
setInputValue(void 0);
startHeaderMode.value = void 0;
endHeaderMode.value = void 0;
if (isBoolean(showPanel)) {
setPanelVisible(showPanel);
}
}
function emitSelectEvent(value) {
const returnValue = getReturnRangeValue(value, returnValueFormat.value);
const formattedValue = getFormattedValue(value, parseValueFormat.value);
const dateValue = getDateValue(value);
emit("select", returnValue, dateValue, formattedValue);
}
function select(value, options) {
const { emitSelect = false, updateHeader = false } = options || {};
let newValue = [...value];
if (isCompleteRangeValue(newValue)) {
newValue = getSortedDayjsArrayByExchangeTimeOrNot(newValue);
}
setProcessValue(newValue);
setPreviewValue(void 0);
setInputValue(void 0);
startHeaderMode.value = void 0;
endHeaderMode.value = void 0;
if (emitSelect) {
emitSelectEvent(newValue);
}
if (updateHeader) {
resetHeaderValue();
}
}
function preview(value, options) {
const { updateHeader = false } = options || {};
setPreviewValue(value);
setInputValue(void 0);
if (updateHeader) {
resetHeaderValue();
}
}
function focusInput(index) {
refInput.value && refInput.value.focus && refInput.value.focus(index);
}
function getMergedOpValue(date, time) {
if (!hasTime.value)
return date;
return mergeValueWithTime(getNow(), date, time);
}
function onPanelVisibleChange(visible) {
setPanelVisible(visible);
}
function onPanelCellMouseEnter(date) {
if (processValue.value && panelValue.value[nextFocusedIndex.value] && (!needConfirm.value || !isCompleteRangeValue(processValue.value))) {
const newValue = [...panelValue.value];
const mergedOpValue = getMergedOpValue(
date,
timePickerValue.value[focusedIndex.value]
);
newValue[focusedIndex.value] = mergedOpValue;
preview(newValue);
}
}
function getValueToModify(isTime = false) {
if (isNextDisabled.value)
return [...selectedValue.value];
if (processValue.value) {
return isTime || !isCompleteRangeValue(processValue.value) ? [...processValue.value] : [];
}
return isTime ? [...selectedValue.value] : [];
}
function onPanelCellClick(date) {
const newValue = getValueToModify();
const mergedOpValue = getMergedOpValue(
date,
timePickerValue.value[focusedIndex.value]
);
newValue[focusedIndex.value] = mergedOpValue;
emitSelectEvent(newValue);
if (!needConfirm.value && isCompleteRangeValue(newValue)) {
confirm(newValue, false);
} else {
select(newValue);
if (!isCompleteRangeValue(newValue)) {
focusedIndex.value = nextFocusedIndex.value;
} else {
focusedIndex.value = 0;
}
}
}
function onTimePickerSelect(time, type) {
const updateIndex = type === "start" ? 0 : 1;
const mergedOpValue = getMergedOpValue(
timePickerValue.value[updateIndex],
time
);
const newTimeValue = [...timePickerValue.value];
newTimeValue[updateIndex] = mergedOpValue;
setTimePickerValue(newTimeValue);
const newValue = getValueToModify(true);
if (newValue[updateIndex]) {
newValue[updateIndex] = mergedOpValue;
select(newValue, { emitSelect: true });
}
}
let clearShortcutPreviewTimer;
onUnmounted(() => {
clearTimeout(clearShortcutPreviewTimer);
});
function onPanelShortcutMouseEnter(value) {
clearTimeout(clearShortcutPreviewTimer);
preview(value, { updateHeader: true });
}
function onPanelShortcutMouseLeave() {
clearTimeout(clearShortcutPreviewTimer);
clearShortcutPreviewTimer = setTimeout(() => {
setPreviewValue(void 0);
setInputValue(void 0);
resetHeaderValue();
}, 100);
}
function onPanelShortcutClick(value, shortcut) {
emit("select-shortcut", shortcut);
confirm(value, false);
}
function onPanelConfirm() {
confirm(panelValue.value, false, true);
}
function onInputClear(e) {
e.stopPropagation();
confirm(void 0);
emit("clear");
}
function onInputChange(e) {
setPanelVisible(true);
const targetValue = e.target.value;
if (!targetValue) {
setInputValue(void 0);
return;
}
const formattedPanelValue = getFormattedValue(
panelValue.value,
computedFormat.value
);
const newInputValue = isArray(inputValue.value) ? [...inputValue.value] : formattedPanelValue || [];
newInputValue[focusedIndex.value] = targetValue;
setInputValue(newInputValue);
if (!isValidInputValue(targetValue, computedFormat.value))
return;
const targetValueDayjs = dayjs(targetValue, computedFormat.value);
if (isDisabledDate(
targetValueDayjs,
focusedIndex.value === 0 ? "start" : "end"
))
return;
const newValue = isArray(panelValue.value) ? [...panelValue.value] : [];
newValue[focusedIndex.value] = targetValueDayjs;
select(newValue, { updateHeader: true });
}
function onInputPressEnter() {
if (isValidRangeValue(panelValue.value)) {
confirm(panelValue.value, false);
} else {
focusedIndex.value = nextFocusedIndex.value;
}
}
const computedTimePickerProps = computed(() => ({
format: computedFormat.value,
...omit((timePickerProps == null ? void 0 : timePickerProps.value) || {}, ["defaultValue"]),
visible: panelVisible.value
}));
const headerIcons = computed(() => ({
prev: slots["icon-prev"],
prevDouble: slots["icon-prev-double"],
next: slots["icon-next"],
nextDouble: slots["icon-next-double"]
}));
const startHeaderProps = reactive({
headerValue: startHeaderValue,
headerOperations: startHeaderOperations,
headerIcons
});
const endHeaderProps = reactive({
headerValue: endHeaderValue,
headerOperations: endHeaderOperations,
headerIcons
});
const rangePanelProps = computed(() => ({
...pick(props, [
"mode",
"showTime",
"shortcuts",
"shortcutsPosition",
"dayStartOfWeek",
"disabledDate",
"disabledTime",
"hideTrigger",
"abbreviation"
]),
prefixCls,
format: parseValueFormat.value,
value: panelValue.value,
showConfirmBtn: needConfirm.value,
confirmBtnDisabled: confirmBtnDisabled.value,
timePickerValue: timePickerValue.value,
timePickerProps: computedTimePickerProps.value,
extra: slots.extra,
dateRender: slots.cell,
startHeaderProps,
endHeaderProps,
footerValue: footerValue.value,
disabled: disabledArray.value,
visible: panelVisible.value,
onCellClick: onPanelCellClick,
onCellMouseEnter: onPanelCellMouseEnter,
onShortcutClick: onPanelShortcutClick,
onShortcutMouseEnter: previewShortcut.value ? onPanelShortcutMouseEnter : void 0,
onShortcutMouseLeave: previewShortcut.value ? onPanelShortcutMouseLeave : void 0,
onConfirm: onPanelConfirm,
onTimePickerSelect,
startHeaderMode: startHeaderMode.value,
endHeaderMode: endHeaderMode.value,
onStartHeaderLabelClick: onStartPanelHeaderLabelClick,
onEndHeaderLabelClick: onEndPanelHeaderLabelClick,
onStartHeaderSelect: onStartPanelHeaderSelect,
onEndHeaderSelect: onEndPanelHeaderSelect
}));
return {
prefixCls,
refInput,
computedFormat,
computedPlaceholder,
panelVisible,
panelValue,
inputValue,
focusedIndex,
triggerDisabled,
mergedSize,
mergedError,
onPanelVisibleChange,
onInputClear,
onInputChange,
onInputPressEnter,
rangePanelProps
};
}
});
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
const _component_IconCalendar = resolveComponent("IconCalendar");
const _component_DateRangeInput = resolveComponent("DateRangeInput");
const _component_RangePickerPanel = resolveComponent("RangePickerPanel");
const _component_Trigger = resolveComponent("Trigger");
return !_ctx.hideTrigger ? (openBlock(), createBlock(_component_Trigger, mergeProps({
key: 0,
trigger: "click",
"animation-name": "slide-dynamic-origin",
"auto-fit-transform-origin": "",
"click-to-close": false,
"popup-offset": 4
}, _ctx.triggerProps, {
"unmount-on-close": _ctx.unmountOnClose,
position: _ctx.position,
disabled: _ctx.triggerDisabled || _ctx.readonly,
"popup-visible": _ctx.panelVisible,
"popup-container": _ctx.popupContainer,
onPopupVisibleChange: _ctx.onPanelVisibleChange
}), {
content: withCtx(() => [
createVNode(_component_RangePickerPanel, normalizeProps(guardReactiveProps(_ctx.rangePanelProps)), null, 16)
]),
default: withCtx(() => [
renderSlot(_ctx.$slots, "default", {}, () => [
createVNode(_component_DateRangeInput, mergeProps({ ref: "refInput" }, _ctx.$attrs, {
focusedIndex: _ctx.focusedIndex,
"onUpdate:focusedIndex": _cache[0] || (_cache[0] = ($event) => _ctx.focusedIndex = $event),
size: _ctx.size,
focused: _ctx.panelVisible,
visible: _ctx.panelVisible,
error: _ctx.error,
disabled: _ctx.disabled,
readonly: _ctx.readonly || _ctx.disabledInput,
"allow-clear": _ctx.allowClear && !_ctx.readonly,
placeholder: _ctx.computedPlaceholder,
"input-value": _ctx.inputValue,
value: _ctx.panelValue,
format: _ctx.computedFormat,
onClear: _ctx.onInputClear,
onChange: _ctx.onInputChange,
onPressEnter: _ctx.onInputPressEnter
}), createSlots({
"suffix-icon": withCtx(() => [
renderSlot(_ctx.$slots, "suffix-icon", {}, () => [
createVNode(_component_IconCalendar)
])
]),
separator: withCtx(() => [
renderSlot(_ctx.$slots, "separator", {}, () => [
createTextVNode(toDisplayString(_ctx.separator || "-"), 1)
])
]),
_: 2
}, [
_ctx.$slots.prefix ? {
name: "prefix",
fn: withCtx(() => [
renderSlot(_ctx.$slots, "prefix")
]),
key: "0"
} : void 0
]), 1040, ["focusedIndex", "size", "focused", "visible", "error", "disabled", "readonly", "allow-clear", "placeholder", "input-value", "value", "format", "onClear", "onChange", "onPressEnter"])
])
]),
_: 3
}, 16, ["unmount-on-close", "position", "disabled", "popup-visible", "popup-container", "onPopupVisibleChange"])) : (openBlock(), createBlock(_component_RangePickerPanel, normalizeProps(mergeProps({ key: 1 }, { ..._ctx.$attrs, ..._ctx.rangePanelProps })), null, 16));
}
var RangePicker = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
export { RangePicker as default };