UNPKG

@opensig/opendesign

Version:

352 lines (351 loc) 12.8 kB
import { defineComponent, mergeModels, useModel, toRefs, computed, ref, provide, watch, nextTick, createBlock, openBlock, unref, mergeProps, createSlots, withCtx, createVNode, withKeys, normalizeClass, createCommentVNode, renderSlot } from "vue"; import { useDebounceFn } from "@vueuse/core"; import dayjs from "dayjs"; import _sfc_main$1 from "../_components/in-box/InBox.vue.mjs"; import _sfc_main$2 from "../_components/in-input/InInput.vue.mjs"; import { isEmptySlot } from "../_utils/vue-utils.mjs"; import { useFormField } from "../_composables/use-form-field.mjs"; import "../_utils/is.mjs"; import "../hooks/use-theme.mjs"; import { useScreen } from "../hooks/use-screen.mjs"; import { useI18n } from "../locale/index.mjs"; import { IconTime } from "../_utils/icons.mjs"; import { useClickOutside } from "../date-picker/composables/use-click-outside.mjs"; import { timePickerProps } from "./types.mjs"; import { timePickerInjectKey } from "./provide.mjs"; import { useTimePickerOptions } from "./use-time-picker-options.mjs"; import { findNearestTime } from "./find-nearest-time.mjs"; import { isValidTimeUnit } from "./use-time-range-input-validation.mjs"; import _sfc_main$3 from "./components/TimePanel.vue.mjs"; const _sfc_main = /* @__PURE__ */ defineComponent({ __name: "OTimePicker", props: /* @__PURE__ */ mergeModels(timePickerProps, { "modelValue": { default: void 0 }, "modelModifiers": {} }), emits: /* @__PURE__ */ mergeModels(["change", "blur", "focus", "clear", "pressEnter"], ["update:modelValue"]), setup(__props, { expose: __expose, emit: __emit }) { const props = __props; const emits = __emit; const modelValue = useModel(__props, "modelValue"); const { effectiveColor: color, inputId, isFocus, onFocus: formOnFocus, onBlur: formOnBlur, onClear: formOnClear, onPressEnter: formOnPressEnter, notifyChange } = useFormField(props, emits); const propsRefs = toRefs(props); const { format, hourStep, minuteStep, secondStep, disabled, readonly, noResponsive } = propsRefs; const { t } = useI18n(); const { isPhonePad } = useScreen(); const isResponding = computed(() => !(noResponsive == null ? void 0 : noResponsive.value) && isPhonePad.value); const inBoxRef = ref(); const inInputRef = ref(); const panelRef = ref(); const tempInputValue = ref(); const tempParsed = computed(() => { var _a; const [hour, minute, second] = ((_a = tempInputValue.value) == null ? void 0 : _a.split(":").map((v) => Number.parseInt(v))) ?? []; return { hour, minute, second }; }); const tempSelectedHour = computed(() => Number.isNaN(tempParsed.value.hour) ? null : tempParsed.value.hour); const tempSelectedMinute = computed(() => Number.isNaN(tempParsed.value.minute) ? null : tempParsed.value.minute); const { hourOptions, minuteOptions, secondOptions, disabledHourOptions, disabledMinuteOptions, disabledSecondOptions } = useTimePickerOptions({ hourStep, minuteStep, secondStep, disabledHours: propsRefs.disabledHours, disabledMinutes: propsRefs.disabledMinutes, disabledSeconds: propsRefs.disabledSeconds, minTime: propsRefs.minTime, maxTime: propsRefs.maxTime, selectedHour: tempSelectedHour, selectedMinute: tempSelectedMinute }); provide(timePickerInjectKey, { ...propsRefs, computedOptions: { hourOptions, minuteOptions, secondOptions, disabledHourOptions } }); const isTempInputValueValid = computed(() => { const { hour, minute, second } = tempParsed.value; if (!isValidTimeUnit(hour, hourOptions.value, disabledHourOptions.value)) return false; if (!isValidTimeUnit(minute, minuteOptions.value, disabledMinuteOptions.value)) return false; if (!isValidTimeUnit(second, secondOptions.value, disabledSecondOptions.value)) return false; return true; }); watch( modelValue, (newValue) => { tempInputValue.value = newValue ?? ""; }, { immediate: true } ); watch(isFocus, (newVal, oldVal) => { var _a; if (!newVal && oldVal) { tempInputValue.value = modelValue.value ?? ""; if (!isResponding.value) { (_a = panelRef.value) == null ? void 0 : _a.close(); } } }); useClickOutside({ targets: [() => { var _a; return (_a = inBoxRef.value) == null ? void 0 : _a.$el; }, () => { var _a; return (_a = panelRef.value) == null ? void 0 : _a.getPopupEl(); }], onOutside: () => { formOnBlur(); }, disabled: isResponding }); const getNearestAvailableTime = () => { const now = dayjs(); return findNearestTime({ hourOptions: hourOptions.value, minuteOptions: minuteOptions.value, secondOptions: secondOptions.value, minTime: props.minTime, maxTime: props.maxTime, disabledHours: props.disabledHours, disabledMinutes: props.disabledMinutes, disabledSeconds: props.disabledSeconds, target: { hour: now.hour(), minute: now.minute(), second: now.second() }, format: format.value }); }; let skipOpenPanel = false; const onFocus = (e) => { var _a; if (readonly.value) return; if (!skipOpenPanel) { let valueToOpen = tempInputValue.value; if (!valueToOpen) { const nearest = getNearestAvailableTime(); if (nearest) { tempInputValue.value = nearest; valueToOpen = nearest; } } (_a = panelRef.value) == null ? void 0 : _a.open(valueToOpen); } skipOpenPanel = false; if (isFocus.value) return; formOnFocus(e); }; let prevValue = modelValue.value; let internalChangePending = false; watch(modelValue, (_, old) => { if (internalChangePending) { internalChangePending = false; } else { prevValue = old; } }); const handleChange = () => { var _a; internalChangePending = true; modelValue.value = isTempInputValueValid.value ? tempInputValue.value : (_a = panelRef.value) == null ? void 0 : _a.getValue(); emits("change", modelValue.value, prevValue); prevValue = modelValue.value; notifyChange(); }; const handleInput = useDebounceFn(async () => { var _a; await nextTick(); if (isTempInputValueValid.value) { (_a = panelRef.value) == null ? void 0 : _a.setValue(tempInputValue.value); } }); const blurAndClose = () => { var _a, _b; (_a = inInputRef.value) == null ? void 0 : _a.blur(); (_b = panelRef.value) == null ? void 0 : _b.close(); formOnBlur(); }; const cancelEdit = () => { tempInputValue.value = modelValue.value ?? ""; blurAndClose(); }; const handlePanelChange = (newVal) => { tempInputValue.value = newVal; }; const onPressEnter = () => { if (!isTempInputValueValid.value) { cancelEdit(); return; } handleChange(); blurAndClose(); formOnPressEnter(); }; const handleConfirm = () => { handleChange(); formOnBlur(); formOnPressEnter(); }; const handleCancel = () => { cancelEdit(); }; const onClear = (e) => { e == null ? void 0 : e.stopPropagation(); const oldVal = prevValue; internalChangePending = true; modelValue.value = void 0; tempInputValue.value = ""; prevValue = void 0; emits("change", void 0, oldVal); formOnClear(e); notifyChange(); blurAndClose(); }; __expose({ /** * @zh-CN 使输入框获取焦点,open 为 false 时仅聚焦不打开面板 * @en-US Focus the input. Pass false to focus without opening the panel. */ focus: (open = true) => { var _a; if (!open) skipOpenPanel = true; (_a = inInputRef.value) == null ? void 0 : _a.focus(); }, /** * @zh-CN 使输入框失去焦点,校验合法则应用当前值,否则回滚 * @en-US Blur the input. Applies the current value if valid, otherwise rolls back. */ blur: () => { if (isTempInputValueValid.value) { handleChange(); blurAndClose(); } else { cancelEdit(); } }, /** * @zh-CN 清除输入值 * @en-US Clear the input value */ clear: () => { var _a; return (_a = inInputRef.value) == null ? void 0 : _a.clear(); }, /** * @zh-CN 获取输入框 DOM 元素 * @en-US Get the input DOM element */ inputEl: () => { var _a; return (_a = inInputRef.value) == null ? void 0 : _a.inputEl; } }); return (_ctx, _cache) => { return openBlock(), createBlock( unref(_sfc_main$1), mergeProps({ ref_key: "inBoxRef", ref: inBoxRef }, { size: props.size, variant: props.variant, color: unref(color), disabled: props.disabled, readonly: props.readonly, round: props.round, focused: unref(isFocus) }, { class: ["o-time-picker", "o-input"] }), createSlots({ default: withCtx(() => { var _a; return [ createVNode(unref(_sfc_main$2), { ref_key: "inInputRef", ref: inInputRef, modelValue: tempInputValue.value, "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => tempInputValue.value = $event), class: normalizeClass(["o-input-wrap", { "o-input-wrap-focused": unref(isFocus), "o-input-wrap-touch": isResponding.value }]), disabled: unref(disabled), clearable: props.clearable && !!tempInputValue.value, placeholder: props.placeholder ?? unref(t)("timePicker.placeholder"), "input-id": unref(inputId), "max-length": ((_a = unref(format)) == null ? void 0 : _a.length) ?? 8, "input-on-outlimit": false, "show-length": "never", readonly: unref(readonly), "no-keyboard": "", onKeydown: withKeys(handleCancel, ["esc"]), onInput: unref(handleInput), onFocus, onClear, onPressEnter }, createSlots({ extra: withCtx(() => { var _a2; return [ !unref(disabled) && !unref(readonly) ? (openBlock(), createBlock(_sfc_main$3, { key: 0, ref_key: "panelRef", ref: panelRef, target: (_a2 = inBoxRef.value) == null ? void 0 : _a2.$el, "option-title": props.optionTitle, onChange: handlePanelChange, onCancel: handleCancel, onConfirm: handleConfirm }, { shortcut: withCtx(({ setValue: panelSetValue, emitChange }) => [ renderSlot(_ctx.$slots, "shortcut", { setValue: panelSetValue, emitChange }) ]), _: 3 /* FORWARDED */ }, 8, ["target", "option-title"])) : createCommentVNode("v-if", true) ]; }), _: 2 /* DYNAMIC */ }, [ !isResponding.value || !tempInputValue.value ? { name: "suffix", fn: withCtx(() => [ createVNode(unref(IconTime)) ]), key: "0" } : void 0 ]), 1032, ["modelValue", "class", "disabled", "clearable", "placeholder", "input-id", "max-length", "readonly", "onInput"]) ]; }), _: 2 /* DYNAMIC */ }, [ !unref(isEmptySlot)(_ctx.$slots.prepend) ? { name: "prepend", fn: withCtx(() => [ renderSlot(_ctx.$slots, "prepend") ]), key: "0" } : void 0, !unref(isEmptySlot)(_ctx.$slots.append) ? { name: "append", fn: withCtx(() => [ renderSlot(_ctx.$slots, "append") ]), key: "1" } : void 0 ]), 1040 /* FULL_PROPS, DYNAMIC_SLOTS */ ); }; } }); export { _sfc_main as default };