UNPKG

@varlet/ui

Version:

A Vue3 component library based on Material Design 2 and 3, supporting mobile and desktop.

486 lines (485 loc) • 16.8 kB
import { computed, defineComponent, reactive, ref, watch } from "vue"; import { call, getRect, preventDefault, toNumber } from "@varlet/shared"; import dayjs from "dayjs/esm/index.js"; import { t } from "../locale/index.mjs"; import { injectLocaleProvider } from "../locale-provider/provide.mjs"; import { createNamespace, formatElevation } from "../utils/components.mjs"; import { padStart } from "../utils/shared.mjs"; import Clock from "./clock.mjs"; import { hours24, hoursAmpm, props } from "./props.mjs"; import { getIsDisableMinute, getIsDisableSecond, getNumberTime } from "./utils.mjs"; const { name, n, classes } = createNamespace("time-picker"); import { toDisplayString as _toDisplayString, normalizeClass as _normalizeClass, createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, createCommentVNode as _createCommentVNode, normalizeStyle as _normalizeStyle, resolveComponent as _resolveComponent, createBlock as _createBlock, Transition as _Transition, withCtx as _withCtx, createVNode as _createVNode, renderSlot as _renderSlot } from "vue"; function __render__(_ctx, _cache) { var _a; const _component_clock = _resolveComponent("clock"); return _openBlock(), _createElementBlock( "div", { ref: "picker", class: _normalizeClass(_ctx.classes(_ctx.n(), _ctx.formatElevation(_ctx.elevation, 2))) }, [ _createElementVNode( "div", { class: _normalizeClass(_ctx.n("title")), style: _normalizeStyle({ background: _ctx.titleColor || _ctx.color }) }, [ _createElementVNode( "div", { class: _normalizeClass(_ctx.n("title-hint")) }, _toDisplayString((_a = _ctx.hint) != null ? _a : (_ctx.pt ? _ctx.pt : _ctx.t)("timePickerHint")), 3 /* TEXT, CLASS */ ), _createElementVNode( "div", { class: _normalizeClass(_ctx.n("title-time-container")) }, [ _createElementVNode( "div", { class: _normalizeClass(_ctx.n("title-time")) }, [ _createElementVNode( "div", { class: _normalizeClass(_ctx.classes(_ctx.n("title-btn"), [_ctx.type === "hour", _ctx.n("title-btn--active")])), onClick: _cache[0] || (_cache[0] = ($event) => _ctx.checkPanel("hour")) }, _toDisplayString(_ctx.time.hour), 3 /* TEXT, CLASS */ ), _createElementVNode( "span", { class: _normalizeClass(_ctx.n("title-splitter")) }, ":", 2 /* CLASS */ ), _createElementVNode( "div", { class: _normalizeClass(_ctx.classes(_ctx.n("title-btn"), [_ctx.type === "minute", _ctx.n("title-btn--active")])), onClick: _cache[1] || (_cache[1] = ($event) => _ctx.checkPanel("minute")) }, _toDisplayString(_ctx.time.minute), 3 /* TEXT, CLASS */ ), _ctx.useSeconds ? (_openBlock(), _createElementBlock( "span", { key: 0, class: _normalizeClass(_ctx.n("title-splitter")) }, ":", 2 /* CLASS */ )) : _createCommentVNode("v-if", true), _ctx.useSeconds ? (_openBlock(), _createElementBlock( "div", { key: 1, class: _normalizeClass(_ctx.classes(_ctx.n("title-btn"), [_ctx.type === "second", _ctx.n("title-btn--active")])), onClick: _cache[2] || (_cache[2] = ($event) => _ctx.checkPanel("second")) }, _toDisplayString(_ctx.time.second), 3 /* TEXT, CLASS */ )) : _createCommentVNode("v-if", true) ], 2 /* CLASS */ ), _ctx.format === "ampm" ? (_openBlock(), _createElementBlock( "div", { key: 0, class: _normalizeClass(_ctx.n("title-ampm")) }, [ _createElementVNode( "div", { class: _normalizeClass(_ctx.classes(_ctx.n("title-btn"), [_ctx.ampm === "am", _ctx.n("title-btn--active")])), onClick: _cache[3] || (_cache[3] = ($event) => _ctx.checkAmpm("am")) }, " AM ", 2 /* CLASS */ ), _createElementVNode( "div", { class: _normalizeClass(_ctx.classes(_ctx.n("title-btn"), [_ctx.ampm === "pm", _ctx.n("title-btn--active")])), onClick: _cache[4] || (_cache[4] = ($event) => _ctx.checkAmpm("pm")) }, " PM ", 2 /* CLASS */ ) ], 2 /* CLASS */ )) : _createCommentVNode("v-if", true) ], 2 /* CLASS */ ) ], 6 /* CLASS, STYLE */ ), _createElementVNode( "div", { class: _normalizeClass(_ctx.n("body")) }, [ _createElementVNode( "div", { ref: "container", class: _normalizeClass(_ctx.n("clock-container")), onTouchstart: _cache[5] || (_cache[5] = (...args) => _ctx.moveHand && _ctx.moveHand(...args)), onTouchmove: _cache[6] || (_cache[6] = (...args) => _ctx.moveHand && _ctx.moveHand(...args)), onTouchend: _cache[7] || (_cache[7] = (...args) => _ctx.end && _ctx.end(...args)) }, [ _createVNode(_Transition, { name: `${_ctx.n()}-panel-fade` }, { default: _withCtx(() => [ (_openBlock(), _createBlock(_component_clock, { key: _ctx.type, ref: "inner", type: _ctx.type, ampm: _ctx.ampm, color: _ctx.color, "is-inner": _ctx.isInner, format: _ctx.format, "allowed-time": _ctx.allowedTime, rad: _ctx.getRad, time: _ctx.time, "prevent-next-update": _ctx.isPreventNextUpdate, "use-seconds": _ctx.useSeconds, max: _ctx.max, min: _ctx.min, onUpdate: _ctx.update, onChangePreventUpdate: _ctx.changePreventUpdate }, null, 8, ["type", "ampm", "color", "is-inner", "format", "allowed-time", "rad", "time", "prevent-next-update", "use-seconds", "max", "min", "onUpdate", "onChangePreventUpdate"])) ]), _: 1 /* STABLE */ }, 8, ["name"]) ], 34 /* CLASS, NEED_HYDRATION */ ) ], 2 /* CLASS */ ), _ctx.$slots.actions ? (_openBlock(), _createElementBlock( "div", { key: 0, class: _normalizeClass(_ctx.n("actions")) }, [ _renderSlot(_ctx.$slots, "actions") ], 2 /* CLASS */ )) : _createCommentVNode("v-if", true) ], 2 /* CLASS */ ); } const __sfc__ = defineComponent({ name, components: { Clock }, props, setup(props2) { const container = ref(null); const picker = ref(null); const inner = ref(null); const isInner = ref(false); const isPreventNextUpdate = ref(false); const isActualInner = ref(false); const isChosenUsableHour = ref(false); const isChosenUsableMinute = ref(false); const isDisableHour = ref(false); const isDisableMinute = ref(false); const minuteRad = ref(0); const secondRad = ref(0); const hourRad = ref(); const type = ref("hour"); const ampm = ref("am"); const time = ref({ hour: "00", minute: "00", second: "00" }); const center = reactive({ x: 0, y: 0 }); const innerRange = reactive({ x: [], y: [] }); const getRad = computed(() => { if (type.value === "hour") { return hourRad.value; } if (type.value === "minute") { return minuteRad.value; } return secondRad.value; }); const { t: pt } = injectLocaleProvider(); watch( () => props2.modelValue, (value) => { if (value === void 0 || value === "") { resetTime(); return; } const { hour, minute, second } = getNumberTime(value); const formatHour12 = dayjs().hour(hour).format("hh"); const formatHour24 = dayjs().hour(hour).format("HH"); const formatMinute = dayjs().minute(minute).format("mm"); const formatSecond = dayjs().second(second).format("ss"); hourRad.value = (formatHour12 === "12" ? 0 : toNumber(formatHour12)) * 30; minuteRad.value = toNumber(formatMinute) * 6; secondRad.value = toNumber(formatSecond) * 6; time.value = getTime(value); if (props2.format !== "24hr") { ampm.value = padStart(`${hour}`, 2, "0") === formatHour24 && hours24.includes(formatHour24) ? "pm" : "am"; } isInner.value = props2.format === "24hr" && hours24.includes(formatHour24); }, { immediate: true } ); function resetTime() { hourRad.value = void 0; minuteRad.value = 0; secondRad.value = 0; time.value = { hour: "00", minute: "00", second: "00" }; ampm.value = "am"; } function update(newTime) { call(props2["onUpdate:modelValue"], newTime); call(props2.onChange, newTime); } function rad2deg(rad) { return rad * 57.29577951308232; } function checkPanel(panelType) { isChosenUsableHour.value = false; isDisableMinute.value = false; type.value = panelType; } function findAvailableHour(ampm2) { const { disableHour } = inner.value; const index = hoursAmpm.findIndex((hour) => toNumber(hour) === toNumber(time.value.hour)); const hours = ampm2 === "am" ? hoursAmpm : hours24; const realignmentHours = [...hours.slice(index), ...hours.slice(0, index)]; return realignmentHours.find((hour, index2) => { isPreventNextUpdate.value = index2 !== 0; return !disableHour.includes(hour); }); } function checkAmpm(ampmType) { if (props2.readonly) { return; } ampm.value = ampmType; const newHour = findAvailableHour(ampmType); if (!newHour) { return; } const second = props2.useSeconds ? `:${time.value.second}` : ""; const newTime = `${padStart(newHour, 2, "0")}:${time.value.minute}${second}`; update(newTime); } function getInner(clientX, clientY) { const xIsInRange = clientX >= innerRange.x[0] && clientX <= innerRange.x[1]; const yIsInRange = clientY >= innerRange.y[0] && clientY <= innerRange.y[1]; return xIsInRange && yIsInRange; } function getTime(value) { const hourFormat = props2.format === "24hr" ? "HH" : "hh"; const { hour, minute, second } = getNumberTime(value); return { hour: dayjs().hour(hour).format(hourFormat), minute: dayjs().minute(minute).format("mm"), second: dayjs().second(second).format("ss") }; } function getHourIndex(rad) { const value = rad / 30; return value >= 0 ? value : value + 12; } function getRangeSize() { const { width: innerWidth, height: innerHeight } = inner.value.getSize(); const rangeXMin = center.x - innerWidth / 2 - 8; const rangeXMax = center.x + innerWidth / 2 + 8; const rangeYMin = center.y - innerHeight / 2 - 8; const rangeYMax = center.y + innerHeight / 2 + 8; return { rangeXMin, rangeXMax, rangeYMin, rangeYMax }; } function setHourRad(clientX, clientY, roundDeg) { const { disableHour } = inner.value; isActualInner.value = getInner(clientX, clientY); const rad = Math.round(roundDeg / 30) * 30 + 90; const index = getHourIndex(rad); const anotherHour = isInner.value ? hoursAmpm[index] : hours24[index]; if (!disableHour.includes(anotherHour)) { isInner.value = props2.format === "24hr" ? getInner(clientX, clientY) : false; } if (isInner.value !== isActualInner.value) { return; } const newHour = isInner.value || ampm.value === "pm" ? hours24[index] : hoursAmpm[index]; isDisableHour.value = disableHour.includes(newHour); if (isDisableHour.value) { return; } hourRad.value = rad; isChosenUsableHour.value = true; } function setMinuteRad(roundDeg) { const { disableHour } = inner.value; const rad = Math.round(roundDeg / 6) * 6 + 90; const radToMin = rad / 6 >= 0 ? rad / 6 : rad / 6 + 60; const values = { time: radToMin, format: props2.format, ampm: ampm.value, hour: time.value.hour, max: props2.max, min: props2.min, disableHour, allowedTime: props2.allowedTime }; isDisableMinute.value = getIsDisableMinute(values); if (isDisableMinute.value) { return; } minuteRad.value = rad; isChosenUsableMinute.value = true; } function setSecondRad(roundDeg) { const { disableHour } = inner.value; const rad = Math.round(roundDeg / 6) * 6 + 90; const radToSec = rad / 6 >= 0 ? rad / 6 : rad / 6 + 60; const values = { time: radToSec, format: props2.format, ampm: ampm.value, hour: time.value.hour, minute: toNumber(time.value.minute), max: props2.max, min: props2.min, disableHour, allowedTime: props2.allowedTime }; if (!getIsDisableSecond(values)) { secondRad.value = rad; } } function setCenterAndRange() { const { left, top, width, height } = getRect(container.value); center.x = left + width / 2; center.y = top + height / 2; if (type.value === "hour" && props2.format === "24hr") { const { rangeXMin, rangeXMax, rangeYMin, rangeYMax } = getRangeSize(); innerRange.x = [rangeXMin, rangeXMax]; innerRange.y = [rangeYMin, rangeYMax]; } } function moveHand(event) { preventDefault(event); if (props2.readonly) { return; } setCenterAndRange(); const { clientX, clientY } = event.touches[0]; const x = clientX - center.x; const y = clientY - center.y; const roundDeg = Math.round(rad2deg(Math.atan2(y, x))); if (type.value === "hour") { setHourRad(clientX, clientY, roundDeg); } else if (type.value === "minute") { setMinuteRad(roundDeg); } else { setSecondRad(roundDeg); } } function end() { if (props2.readonly) { return; } if (type.value === "hour" && isChosenUsableHour.value) { type.value = "minute"; return; } if (type.value === "minute" && props2.useSeconds && isChosenUsableMinute.value) { type.value = "second"; } } function changePreventUpdate() { isPreventNextUpdate.value = false; } return { getRad, time, container, inner, picker, isInner, type, ampm, isPreventNextUpdate, n, classes, t, pt, moveHand, checkPanel, checkAmpm, end, update, changePreventUpdate, formatElevation }; } }); __sfc__.render = __render__; var stdin_default = __sfc__; export { stdin_default as default };