UNPKG

vant

Version:

Mobile UI Components built on Vue

1,820 lines 513 kB
"use strict"; Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } }); const vue = require("vue"); const use = require("@vant/use"); const shared = require("@vue/shared"); const popperjs = require("@vant/popperjs"); function noop() { } const extend = Object.assign; const inBrowser = typeof window !== "undefined"; const isObject = (val) => val !== null && typeof val === "object"; const isDef = (val) => val !== void 0 && val !== null; const isFunction = (val) => typeof val === "function"; const isPromise = (val) => isObject(val) && isFunction(val.then) && isFunction(val.catch); const isDate = (val) => Object.prototype.toString.call(val) === "[object Date]" && !Number.isNaN(val.getTime()); function isMobile(value) { value = value.replace(/[^-|\d]/g, ""); return /^((\+86)|(86))?(1)\d{10}$/.test(value) || /^0[0-9-]{10,13}$/.test(value); } const isNumeric = (val) => typeof val === "number" || /^\d+(\.\d+)?$/.test(val); const isIOS$1 = () => inBrowser ? /ios|iphone|ipad|ipod/.test(navigator.userAgent.toLowerCase()) : false; function get(object, path) { const keys = path.split("."); let result = object; keys.forEach((key) => { var _a; result = isObject(result) ? (_a = result[key]) != null ? _a : "" : ""; }); return result; } function pick(obj, keys, ignoreUndefined) { return keys.reduce( (ret, key) => { if (!ignoreUndefined || obj[key] !== void 0) { ret[key] = obj[key]; } return ret; }, {} ); } const isSameValue = (newValue, oldValue) => JSON.stringify(newValue) === JSON.stringify(oldValue); const toArray = (item) => Array.isArray(item) ? item : [item]; const flat = (arr) => arr.reduce((acc, val) => acc.concat(val), []); const unknownProp = null; const numericProp = [Number, String]; const truthProp = { type: Boolean, default: true }; const makeRequiredProp = (type) => ({ type, required: true }); const makeArrayProp = () => ({ type: Array, default: () => [] }); const makeNumberProp = (defaultVal) => ({ type: Number, default: defaultVal }); const makeNumericProp = (defaultVal) => ({ type: numericProp, default: defaultVal }); const makeStringProp = (defaultVal) => ({ type: String, default: defaultVal }); function getScrollTop(el) { const top = "scrollTop" in el ? el.scrollTop : el.pageYOffset; return Math.max(top, 0); } function setScrollTop(el, value) { if ("scrollTop" in el) { el.scrollTop = value; } else { el.scrollTo(el.scrollX, value); } } function getRootScrollTop() { return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; } function setRootScrollTop(value) { setScrollTop(window, value); setScrollTop(document.body, value); } function getElementTop(el, scroller) { if (el === window) { return 0; } const scrollTop = scroller ? getScrollTop(scroller) : getRootScrollTop(); return use.useRect(el).top + scrollTop; } const isIOS = isIOS$1(); function resetScroll() { if (isIOS) { setRootScrollTop(getRootScrollTop()); } } const stopPropagation = (event) => event.stopPropagation(); function preventDefault(event, isStopPropagation) { if (typeof event.cancelable !== "boolean" || event.cancelable) { event.preventDefault(); } if (isStopPropagation) { stopPropagation(event); } } function isHidden(elementRef) { const el = vue.unref(elementRef); if (!el) { return false; } const style = window.getComputedStyle(el); const hidden = style.display === "none"; const parentHidden = el.offsetParent === null && style.position !== "fixed"; return hidden || parentHidden; } const { width: windowWidth, height: windowHeight } = use.useWindowSize(); function isContainingBlock(el) { const css = window.getComputedStyle(el); return css.transform !== "none" || css.perspective !== "none" || ["transform", "perspective", "filter"].some( (value) => (css.willChange || "").includes(value) ); } function getContainingBlock(el) { let node = el.parentElement; while (node) { if (node && node.tagName !== "HTML" && node.tagName !== "BODY" && isContainingBlock(node)) { return node; } node = node.parentElement; } return null; } function addUnit(value) { if (isDef(value)) { return isNumeric(value) ? `${value}px` : String(value); } return void 0; } function getSizeStyle(originSize) { if (isDef(originSize)) { if (Array.isArray(originSize)) { return { width: addUnit(originSize[0]), height: addUnit(originSize[1]) }; } const size = addUnit(originSize); return { width: size, height: size }; } } function getZIndexStyle(zIndex) { const style = {}; if (zIndex !== void 0) { style.zIndex = +zIndex; } return style; } let rootFontSize; function getRootFontSize() { if (!rootFontSize) { const doc = document.documentElement; const fontSize = doc.style.fontSize || window.getComputedStyle(doc).fontSize; rootFontSize = parseFloat(fontSize); } return rootFontSize; } function convertRem(value) { value = value.replace(/rem/g, ""); return +value * getRootFontSize(); } function convertVw(value) { value = value.replace(/vw/g, ""); return +value * windowWidth.value / 100; } function convertVh(value) { value = value.replace(/vh/g, ""); return +value * windowHeight.value / 100; } function unitToPx(value) { if (typeof value === "number") { return value; } if (inBrowser) { if (value.includes("rem")) { return convertRem(value); } if (value.includes("vw")) { return convertVw(value); } if (value.includes("vh")) { return convertVh(value); } } return parseFloat(value); } const camelizeRE = /-(\w)/g; const camelize = (str) => str.replace(camelizeRE, (_, c) => c.toUpperCase()); const kebabCase = (str) => str.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, ""); function padZero(num, targetLength = 2) { let str = num + ""; while (str.length < targetLength) { str = "0" + str; } return str; } const clamp = (num, min, max) => Math.min(Math.max(num, min), max); function trimExtraChar(value, char, regExp) { const index = value.indexOf(char); if (index === -1) { return value; } if (char === "-" && index !== 0) { return value.slice(0, index); } return value.slice(0, index + 1) + value.slice(index).replace(regExp, ""); } function formatNumber(value, allowDot = true, allowMinus = true) { if (allowDot) { value = trimExtraChar(value, ".", /\./g); } else { value = value.split(".")[0]; } if (allowMinus) { value = trimExtraChar(value, "-", /-/g); } else { value = value.replace(/-/, ""); } const regExp = allowDot ? /[^-0-9.]/g : /[^-0-9]/g; return value.replace(regExp, ""); } function addNumber(num1, num2) { const cardinal = 10 ** 10; return Math.round((num1 + num2) * cardinal) / cardinal; } const { hasOwnProperty } = Object.prototype; function assignKey(to, from, key) { const val = from[key]; if (!isDef(val)) { return; } if (!hasOwnProperty.call(to, key) || !isObject(val)) { to[key] = val; } else { to[key] = deepAssign(Object(to[key]), val); } } function deepAssign(to, from) { Object.keys(from).forEach((key) => { assignKey(to, from, key); }); return to; } var stdin_default$1W = { name: "姓名", tel: "电话", save: "保存", clear: "清空", cancel: "取消", confirm: "确认", delete: "删除", loading: "加载中...", noCoupon: "暂无优惠券", nameEmpty: "请填写姓名", addContact: "添加联系人", telInvalid: "请填写正确的电话", vanCalendar: { end: "结束", start: "开始", title: "日期选择", weekdays: ["日", "一", "二", "三", "四", "五", "六"], monthTitle: (year, month) => `${year}年${month}月`, rangePrompt: (maxRange) => `最多选择 ${maxRange} 天` }, vanCascader: { select: "请选择" }, vanPagination: { prev: "上一页", next: "下一页" }, vanPullRefresh: { pulling: "下拉即可刷新...", loosing: "释放即可刷新..." }, vanSubmitBar: { label: "合计:" }, vanCoupon: { unlimited: "无门槛", discount: (discount) => `${discount}折`, condition: (condition) => `满${condition}元可用` }, vanCouponCell: { title: "优惠券", count: (count) => `${count}张可用` }, vanCouponList: { exchange: "兑换", close: "不使用", enable: "可用", disabled: "不可用", placeholder: "输入优惠码" }, vanAddressEdit: { area: "地区", areaEmpty: "请选择地区", addressEmpty: "请填写详细地址", addressDetail: "详细地址", defaultAddress: "设为默认收货地址" }, vanAddressList: { add: "新增地址" } }; const lang = vue.ref("zh-CN"); const messages = vue.reactive({ "zh-CN": stdin_default$1W }); const Locale = { messages() { return messages[lang.value]; }, use(newLang, newMessages) { lang.value = newLang; this.add({ [newLang]: newMessages }); }, add(newMessages = {}) { deepAssign(messages, newMessages); } }; const useCurrentLang = () => lang; var stdin_default$1V = Locale; function createTranslate(name2) { const prefix = camelize(name2) + "."; return (path, ...args) => { const messages2 = stdin_default$1V.messages(); const message = get(messages2, prefix + path) || get(messages2, path); return isFunction(message) ? message(...args) : message; }; } function genBem(name2, mods) { if (!mods) { return ""; } if (typeof mods === "string") { return ` ${name2}--${mods}`; } if (Array.isArray(mods)) { return mods.reduce( (ret, item) => ret + genBem(name2, item), "" ); } return Object.keys(mods).reduce( (ret, key) => ret + (mods[key] ? genBem(name2, key) : ""), "" ); } function createBEM(name2) { return (el, mods) => { if (el && typeof el !== "string") { mods = el; el = ""; } el = el ? `${name2}__${el}` : name2; return `${el}${genBem(el, mods)}`; }; } function createNamespace(name2) { const prefixedName = `van-${name2}`; return [ prefixedName, createBEM(prefixedName), createTranslate(prefixedName) ]; } const BORDER = "van-hairline"; const BORDER_TOP = `${BORDER}--top`; const BORDER_LEFT = `${BORDER}--left`; const BORDER_RIGHT = `${BORDER}--right`; const BORDER_BOTTOM = `${BORDER}--bottom`; const BORDER_SURROUND = `${BORDER}--surround`; const BORDER_TOP_BOTTOM = `${BORDER}--top-bottom`; const BORDER_UNSET_TOP_BOTTOM = `${BORDER}-unset--top-bottom`; const HAPTICS_FEEDBACK = "van-haptics-feedback"; const FORM_KEY = Symbol("van-form"); const LONG_PRESS_START_TIME = 500; const TAP_OFFSET = 5; function callInterceptor(interceptor, { args = [], done, canceled, error }) { if (interceptor) { const returnVal = interceptor.apply(null, args); if (isPromise(returnVal)) { returnVal.then((value) => { if (value) { done(); } else if (canceled) { canceled(); } }).catch(error || noop); } else if (returnVal) { done(); } else if (canceled) { canceled(); } } else { done(); } } function withInstall(options) { options.install = (app) => { const { name: name2 } = options; if (name2) { app.component(name2, options); app.component(camelize(`-${name2}`), options); } }; return options; } function closest(arr, target) { return arr.reduce( (pre, cur) => Math.abs(pre - target) < Math.abs(cur - target) ? pre : cur ); } const POPUP_TOGGLE_KEY = Symbol(); function onPopupReopen(callback) { const popupToggleStatus = vue.inject(POPUP_TOGGLE_KEY, null); if (popupToggleStatus) { vue.watch(popupToggleStatus, (show) => { if (show) { callback(); } }); } } const useHeight = (element, withSafeArea) => { const height = vue.ref(); const setHeight = () => { height.value = use.useRect(element).height; }; vue.onMounted(() => { vue.nextTick(setHeight); if (withSafeArea) { for (let i = 1; i <= 3; i++) { setTimeout(setHeight, 100 * i); } } }); onPopupReopen(() => vue.nextTick(setHeight)); vue.watch([windowWidth, windowHeight], setHeight); return height; }; function usePlaceholder(contentRef, bem2) { const height = useHeight(contentRef, true); return (renderContent) => vue.createVNode("div", { "class": bem2("placeholder"), "style": { height: height.value ? `${height.value}px` : void 0 } }, [renderContent()]); } const [name$1K, bem$1F] = createNamespace("action-bar"); const ACTION_BAR_KEY = Symbol(name$1K); const actionBarProps = { placeholder: Boolean, safeAreaInsetBottom: truthProp }; var stdin_default$1U = vue.defineComponent({ name: name$1K, props: actionBarProps, setup(props2, { slots }) { const root = vue.ref(); const renderPlaceholder = usePlaceholder(root, bem$1F); const { linkChildren } = use.useChildren(ACTION_BAR_KEY); linkChildren(); const renderActionBar = () => { var _a; return vue.createVNode("div", { "ref": root, "class": [bem$1F(), { "van-safe-area-bottom": props2.safeAreaInsetBottom }] }, [(_a = slots.default) == null ? void 0 : _a.call(slots)]); }; return () => { if (props2.placeholder) { return renderPlaceholder(renderActionBar); } return renderActionBar(); }; } }); const ActionBar = withInstall(stdin_default$1U); function useExpose(apis) { const instance2 = vue.getCurrentInstance(); if (instance2) { extend(instance2.proxy, apis); } } const routeProps = { to: [String, Object], url: String, replace: Boolean }; function route({ to, url, replace, $router: router }) { if (to && router) { router[replace ? "replace" : "push"](to); } else if (url) { replace ? location.replace(url) : location.href = url; } } function useRoute() { const vm = vue.getCurrentInstance().proxy; return () => route(vm); } const [name$1J, bem$1E] = createNamespace("badge"); const badgeProps = { dot: Boolean, max: numericProp, tag: makeStringProp("div"), color: String, offset: Array, content: numericProp, showZero: truthProp, position: makeStringProp("top-right") }; var stdin_default$1T = vue.defineComponent({ name: name$1J, props: badgeProps, setup(props2, { slots }) { const hasContent = () => { if (slots.content) { return true; } const { content, showZero } = props2; return isDef(content) && content !== "" && (showZero || content !== 0 && content !== "0"); }; const renderContent = () => { const { dot, max, content } = props2; if (!dot && hasContent()) { if (slots.content) { return slots.content(); } if (isDef(max) && isNumeric(content) && +content > +max) { return `${max}+`; } return content; } }; const getOffsetWithMinusString = (val) => val.startsWith("-") ? val.replace("-", "") : `-${val}`; const style = vue.computed(() => { const style2 = { background: props2.color }; if (props2.offset) { const [x, y] = props2.offset; const { position } = props2; const [offsetY, offsetX] = position.split("-"); if (slots.default) { if (typeof y === "number") { style2[offsetY] = addUnit(offsetY === "top" ? y : -y); } else { style2[offsetY] = offsetY === "top" ? addUnit(y) : getOffsetWithMinusString(y); } if (typeof x === "number") { style2[offsetX] = addUnit(offsetX === "left" ? x : -x); } else { style2[offsetX] = offsetX === "left" ? addUnit(x) : getOffsetWithMinusString(x); } } else { style2.marginTop = addUnit(y); style2.marginLeft = addUnit(x); } } return style2; }); const renderBadge = () => { if (hasContent() || props2.dot) { return vue.createVNode("div", { "class": bem$1E([props2.position, { dot: props2.dot, fixed: !!slots.default }]), "style": style.value }, [renderContent()]); } }; return () => { if (slots.default) { const { tag } = props2; return vue.createVNode(tag, { "class": bem$1E("wrapper") }, { default: () => [slots.default(), renderBadge()] }); } return renderBadge(); }; } }); const Badge = withInstall(stdin_default$1T); let globalZIndex = 2e3; const useGlobalZIndex = () => ++globalZIndex; const setGlobalZIndex = (val) => { globalZIndex = val; }; const [name$1I, bem$1D] = createNamespace("config-provider"); const CONFIG_PROVIDER_KEY = Symbol(name$1I); const configProviderProps = { tag: makeStringProp("div"), theme: makeStringProp("light"), zIndex: Number, themeVars: Object, themeVarsDark: Object, themeVarsLight: Object, themeVarsScope: makeStringProp("local"), iconPrefix: String }; function insertDash(str) { return str.replace(/([a-zA-Z])(\d)/g, "$1-$2"); } function mapThemeVarsToCSSVars(themeVars) { const cssVars = {}; Object.keys(themeVars).forEach((key) => { const formattedKey = insertDash(kebabCase(key)); cssVars[`--van-${formattedKey}`] = themeVars[key]; }); return cssVars; } function syncThemeVarsOnRoot(newStyle = {}, oldStyle = {}) { Object.keys(newStyle).forEach((key) => { if (newStyle[key] !== oldStyle[key]) { document.documentElement.style.setProperty(key, newStyle[key]); } }); Object.keys(oldStyle).forEach((key) => { if (!newStyle[key]) { document.documentElement.style.removeProperty(key); } }); } var stdin_default$1S = vue.defineComponent({ name: name$1I, props: configProviderProps, setup(props2, { slots }) { const style = vue.computed(() => mapThemeVarsToCSSVars(extend({}, props2.themeVars, props2.theme === "dark" ? props2.themeVarsDark : props2.themeVarsLight))); if (inBrowser) { const addTheme = () => { document.documentElement.classList.add(`van-theme-${props2.theme}`); }; const removeTheme = (theme = props2.theme) => { document.documentElement.classList.remove(`van-theme-${theme}`); }; vue.watch(() => props2.theme, (newVal, oldVal) => { if (oldVal) { removeTheme(oldVal); } addTheme(); }, { immediate: true }); vue.onActivated(addTheme); vue.onDeactivated(removeTheme); vue.onBeforeUnmount(removeTheme); vue.watch(style, (newStyle, oldStyle) => { if (props2.themeVarsScope === "global") { syncThemeVarsOnRoot(newStyle, oldStyle); } }); vue.watch(() => props2.themeVarsScope, (newScope, oldScope) => { if (oldScope === "global") { syncThemeVarsOnRoot({}, style.value); } if (newScope === "global") { syncThemeVarsOnRoot(style.value, {}); } }); if (props2.themeVarsScope === "global") { syncThemeVarsOnRoot(style.value, {}); } } vue.provide(CONFIG_PROVIDER_KEY, props2); vue.watchEffect(() => { if (props2.zIndex !== void 0) { setGlobalZIndex(props2.zIndex); } }); return () => vue.createVNode(props2.tag, { "class": bem$1D(), "style": props2.themeVarsScope === "local" ? style.value : void 0 }, { default: () => { var _a; return [(_a = slots.default) == null ? void 0 : _a.call(slots)]; } }); } }); const [name$1H, bem$1C] = createNamespace("icon"); const isImage$1 = (name2) => name2 == null ? void 0 : name2.includes("/"); const iconProps = { dot: Boolean, tag: makeStringProp("i"), name: String, size: numericProp, badge: numericProp, color: String, badgeProps: Object, classPrefix: String }; var stdin_default$1R = vue.defineComponent({ name: name$1H, props: iconProps, setup(props2, { slots }) { const config = vue.inject(CONFIG_PROVIDER_KEY, null); const classPrefix = vue.computed(() => props2.classPrefix || (config == null ? void 0 : config.iconPrefix) || bem$1C()); return () => { const { tag, dot, name: name2, size, badge, color } = props2; const isImageIcon = isImage$1(name2); return vue.createVNode(Badge, vue.mergeProps({ "dot": dot, "tag": tag, "class": [classPrefix.value, isImageIcon ? "" : `${classPrefix.value}-${name2}`], "style": { color, fontSize: addUnit(size) }, "content": badge }, props2.badgeProps), { default: () => { var _a; return [(_a = slots.default) == null ? void 0 : _a.call(slots), isImageIcon && vue.createVNode("img", { "class": bem$1C("image"), "src": name2 }, null)]; } }); }; } }); const Icon = withInstall(stdin_default$1R); var stdin_default$1Q = Icon; const [name$1G, bem$1B] = createNamespace("loading"); const SpinIcon = Array(12).fill(null).map((_, index) => vue.createVNode("i", { "class": bem$1B("line", String(index + 1)) }, null)); const CircularIcon = vue.createVNode("svg", { "class": bem$1B("circular"), "viewBox": "25 25 50 50" }, [vue.createVNode("circle", { "cx": "50", "cy": "50", "r": "20", "fill": "none" }, null)]); const loadingProps = { size: numericProp, type: makeStringProp("circular"), color: String, vertical: Boolean, textSize: numericProp, textColor: String }; var stdin_default$1P = vue.defineComponent({ name: name$1G, props: loadingProps, setup(props2, { slots }) { const spinnerStyle = vue.computed(() => extend({ color: props2.color }, getSizeStyle(props2.size))); const renderIcon = () => { const DefaultIcon = props2.type === "spinner" ? SpinIcon : CircularIcon; return vue.createVNode("span", { "class": bem$1B("spinner", props2.type), "style": spinnerStyle.value }, [slots.icon ? slots.icon() : DefaultIcon]); }; const renderText = () => { var _a; if (slots.default) { return vue.createVNode("span", { "class": bem$1B("text"), "style": { fontSize: addUnit(props2.textSize), color: (_a = props2.textColor) != null ? _a : props2.color } }, [slots.default()]); } }; return () => { const { type, vertical } = props2; return vue.createVNode("div", { "class": bem$1B([type, { vertical }]), "aria-live": "polite", "aria-busy": true }, [renderIcon(), renderText()]); }; } }); const Loading = withInstall(stdin_default$1P); const [name$1F, bem$1A] = createNamespace("button"); const buttonProps = extend({}, routeProps, { tag: makeStringProp("button"), text: String, icon: String, type: makeStringProp("default"), size: makeStringProp("normal"), color: String, block: Boolean, plain: Boolean, round: Boolean, square: Boolean, loading: Boolean, hairline: Boolean, disabled: Boolean, iconPrefix: String, nativeType: makeStringProp("button"), loadingSize: numericProp, loadingText: String, loadingType: String, iconPosition: makeStringProp("left") }); var stdin_default$1O = vue.defineComponent({ name: name$1F, props: buttonProps, emits: ["click"], setup(props2, { emit, slots }) { const route2 = useRoute(); const renderLoadingIcon = () => { if (slots.loading) { return slots.loading(); } return vue.createVNode(Loading, { "size": props2.loadingSize, "type": props2.loadingType, "class": bem$1A("loading") }, null); }; const renderIcon = () => { if (props2.loading) { return renderLoadingIcon(); } if (slots.icon) { return vue.createVNode("div", { "class": bem$1A("icon") }, [slots.icon()]); } if (props2.icon) { return vue.createVNode(Icon, { "name": props2.icon, "class": bem$1A("icon"), "classPrefix": props2.iconPrefix }, null); } }; const renderText = () => { let text; if (props2.loading) { text = props2.loadingText; } else { text = slots.default ? slots.default() : props2.text; } if (text) { return vue.createVNode("span", { "class": bem$1A("text") }, [text]); } }; const getStyle = () => { const { color, plain } = props2; if (color) { const style = { color: plain ? color : "white" }; if (!plain) { style.background = color; } if (color.includes("gradient")) { style.border = 0; } else { style.borderColor = color; } return style; } }; const onClick = (event) => { if (props2.loading) { preventDefault(event); } else if (!props2.disabled) { emit("click", event); route2(); } }; return () => { const { tag, type, size, block, round, plain, square, loading, disabled, hairline, nativeType, iconPosition } = props2; const classes = [bem$1A([type, size, { plain, block, round, square, loading, disabled, hairline }]), { [BORDER_SURROUND]: hairline }]; return vue.createVNode(tag, { "type": nativeType, "class": classes, "style": getStyle(), "disabled": disabled, "onClick": onClick }, { default: () => [vue.createVNode("div", { "class": bem$1A("content") }, [iconPosition === "left" && renderIcon(), renderText(), iconPosition === "right" && renderIcon()])] }); }; } }); const Button = withInstall(stdin_default$1O); const [name$1E, bem$1z] = createNamespace("action-bar-button"); const actionBarButtonProps = extend({}, routeProps, { type: String, text: String, icon: String, color: String, loading: Boolean, disabled: Boolean }); var stdin_default$1N = vue.defineComponent({ name: name$1E, props: actionBarButtonProps, setup(props2, { slots }) { const route2 = useRoute(); const { parent, index } = use.useParent(ACTION_BAR_KEY); const isFirst = vue.computed(() => { if (parent) { const prev = parent.children[index.value - 1]; return !(prev && "isButton" in prev); } }); const isLast = vue.computed(() => { if (parent) { const next = parent.children[index.value + 1]; return !(next && "isButton" in next); } }); useExpose({ isButton: true }); return () => { const { type, icon, text, color, loading, disabled } = props2; return vue.createVNode(Button, { "class": bem$1z([type, { last: isLast.value, first: isFirst.value }]), "size": "large", "type": type, "icon": icon, "color": color, "loading": loading, "disabled": disabled, "onClick": route2 }, { default: () => [slots.default ? slots.default() : text] }); }; } }); const ActionBarButton = withInstall(stdin_default$1N); const [name$1D, bem$1y] = createNamespace("action-bar-icon"); const actionBarIconProps = extend({}, routeProps, { dot: Boolean, text: String, icon: String, color: String, badge: numericProp, iconClass: unknownProp, badgeProps: Object, iconPrefix: String }); var stdin_default$1M = vue.defineComponent({ name: name$1D, props: actionBarIconProps, setup(props2, { slots }) { const route2 = useRoute(); use.useParent(ACTION_BAR_KEY); const renderIcon = () => { const { dot, badge, icon, color, iconClass, badgeProps: badgeProps2, iconPrefix } = props2; if (slots.icon) { return vue.createVNode(Badge, vue.mergeProps({ "dot": dot, "class": bem$1y("icon"), "content": badge }, badgeProps2), { default: slots.icon }); } return vue.createVNode(Icon, { "tag": "div", "dot": dot, "name": icon, "badge": badge, "color": color, "class": [bem$1y("icon"), iconClass], "badgeProps": badgeProps2, "classPrefix": iconPrefix }, null); }; return () => vue.createVNode("div", { "role": "button", "class": bem$1y(), "tabindex": 0, "onClick": route2 }, [renderIcon(), slots.default ? slots.default() : props2.text]); } }); const ActionBarIcon = withInstall(stdin_default$1M); const popupSharedProps = { // whether to show popup show: Boolean, // z-index zIndex: numericProp, // whether to show overlay overlay: truthProp, // transition duration duration: numericProp, // teleport teleport: [String, Object], // prevent body scroll lockScroll: truthProp, // whether to lazy render lazyRender: truthProp, // callback function before close beforeClose: Function, // overlay custom style overlayStyle: Object, // overlay custom class name overlayClass: unknownProp, // Initial rendering animation transitionAppear: Boolean, // whether to close popup when overlay is clicked closeOnClickOverlay: truthProp }; const popupSharedPropKeys = Object.keys( popupSharedProps ); function getDirection(x, y) { if (x > y) { return "horizontal"; } if (y > x) { return "vertical"; } return ""; } function useTouch() { const startX = vue.ref(0); const startY = vue.ref(0); const deltaX = vue.ref(0); const deltaY = vue.ref(0); const offsetX = vue.ref(0); const offsetY = vue.ref(0); const direction = vue.ref(""); const isTap = vue.ref(true); const isVertical = () => direction.value === "vertical"; const isHorizontal = () => direction.value === "horizontal"; const reset = () => { deltaX.value = 0; deltaY.value = 0; offsetX.value = 0; offsetY.value = 0; direction.value = ""; isTap.value = true; }; const start = (event) => { reset(); startX.value = event.touches[0].clientX; startY.value = event.touches[0].clientY; }; const move = (event) => { const touch = event.touches[0]; deltaX.value = (touch.clientX < 0 ? 0 : touch.clientX) - startX.value; deltaY.value = touch.clientY - startY.value; offsetX.value = Math.abs(deltaX.value); offsetY.value = Math.abs(deltaY.value); const LOCK_DIRECTION_DISTANCE = 10; if (!direction.value || offsetX.value < LOCK_DIRECTION_DISTANCE && offsetY.value < LOCK_DIRECTION_DISTANCE) { direction.value = getDirection(offsetX.value, offsetY.value); } if (isTap.value && (offsetX.value > TAP_OFFSET || offsetY.value > TAP_OFFSET)) { isTap.value = false; } }; return { move, start, reset, startX, startY, deltaX, deltaY, offsetX, offsetY, direction, isVertical, isHorizontal, isTap }; } let totalLockCount = 0; const BODY_LOCK_CLASS = "van-overflow-hidden"; function useLockScroll(rootRef, shouldLock) { const touch = useTouch(); const DIRECTION_UP = "01"; const DIRECTION_DOWN = "10"; const onTouchMove = (event) => { touch.move(event); const direction = touch.deltaY.value > 0 ? DIRECTION_DOWN : DIRECTION_UP; const el = use.getScrollParent( event.target, rootRef.value ); const { scrollHeight, offsetHeight, scrollTop } = el; let status = "11"; if (scrollTop === 0) { status = offsetHeight >= scrollHeight ? "00" : "01"; } else if (scrollTop + offsetHeight >= scrollHeight) { status = "10"; } if (status !== "11" && touch.isVertical() && !(parseInt(status, 2) & parseInt(direction, 2))) { preventDefault(event, true); } }; const lock = () => { document.addEventListener("touchstart", touch.start); document.addEventListener("touchmove", onTouchMove, { passive: false }); if (!totalLockCount) { document.body.classList.add(BODY_LOCK_CLASS); } totalLockCount++; }; const unlock = () => { if (totalLockCount) { document.removeEventListener("touchstart", touch.start); document.removeEventListener("touchmove", onTouchMove); totalLockCount--; if (!totalLockCount) { document.body.classList.remove(BODY_LOCK_CLASS); } } }; const init = () => shouldLock() && lock(); const destroy = () => shouldLock() && unlock(); use.onMountedOrActivated(init); vue.onDeactivated(destroy); vue.onBeforeUnmount(destroy); vue.watch(shouldLock, (value) => { value ? lock() : unlock(); }); } function useLazyRender(show) { const inited = vue.ref(false); vue.watch( show, (value) => { if (value) { inited.value = value; } }, { immediate: true } ); return (render) => () => inited.value ? render() : null; } const useScopeId = () => { var _a; const { scopeId } = ((_a = vue.getCurrentInstance()) == null ? void 0 : _a.vnode) || {}; return scopeId ? { [scopeId]: "" } : null; }; const [name$1C, bem$1x] = createNamespace("overlay"); const overlayProps = { show: Boolean, zIndex: numericProp, duration: numericProp, className: unknownProp, lockScroll: truthProp, lazyRender: truthProp, customStyle: Object, teleport: [String, Object] }; var stdin_default$1L = vue.defineComponent({ name: name$1C, inheritAttrs: false, props: overlayProps, setup(props2, { attrs, slots }) { const root = vue.ref(); const lazyRender = useLazyRender(() => props2.show || !props2.lazyRender); const onTouchMove = (event) => { if (props2.lockScroll) { preventDefault(event, true); } }; const renderOverlay = lazyRender(() => { var _a; const style = extend(getZIndexStyle(props2.zIndex), props2.customStyle); if (isDef(props2.duration)) { style.animationDuration = `${props2.duration}s`; } return vue.withDirectives(vue.createVNode("div", vue.mergeProps({ "ref": root, "style": style, "class": [bem$1x(), props2.className] }, attrs), [(_a = slots.default) == null ? void 0 : _a.call(slots)]), [[vue.vShow, props2.show]]); }); use.useEventListener("touchmove", onTouchMove, { target: root }); return () => { const Content = vue.createVNode(vue.Transition, { "name": "van-fade", "appear": true }, { default: renderOverlay }); if (props2.teleport) { return vue.createVNode(vue.Teleport, { "to": props2.teleport }, { default: () => [Content] }); } return Content; }; } }); const Overlay = withInstall(stdin_default$1L); const popupProps$2 = extend({}, popupSharedProps, { round: Boolean, position: makeStringProp("center"), closeIcon: makeStringProp("cross"), closeable: Boolean, transition: String, iconPrefix: String, closeOnPopstate: Boolean, closeIconPosition: makeStringProp("top-right"), destroyOnClose: Boolean, safeAreaInsetTop: Boolean, safeAreaInsetBottom: Boolean }); const [name$1B, bem$1w] = createNamespace("popup"); var stdin_default$1K = vue.defineComponent({ name: name$1B, inheritAttrs: false, props: popupProps$2, emits: ["open", "close", "opened", "closed", "keydown", "update:show", "clickOverlay", "clickCloseIcon"], setup(props2, { emit, attrs, slots }) { let opened; let shouldReopen; const zIndex = vue.ref(); const popupRef = vue.ref(); const lazyRender = useLazyRender(() => props2.show || !props2.lazyRender); const style = vue.computed(() => { const style2 = { zIndex: zIndex.value }; if (isDef(props2.duration)) { const key = props2.position === "center" ? "animationDuration" : "transitionDuration"; style2[key] = `${props2.duration}s`; } return style2; }); const open = () => { if (!opened) { opened = true; zIndex.value = props2.zIndex !== void 0 ? +props2.zIndex : useGlobalZIndex(); emit("open"); } }; const close = () => { if (opened) { callInterceptor(props2.beforeClose, { done() { opened = false; emit("close"); emit("update:show", false); } }); } }; const onClickOverlay = (event) => { emit("clickOverlay", event); if (props2.closeOnClickOverlay) { close(); } }; const renderOverlay = () => { if (props2.overlay) { return vue.createVNode(Overlay, vue.mergeProps({ "show": props2.show, "class": props2.overlayClass, "zIndex": zIndex.value, "duration": props2.duration, "customStyle": props2.overlayStyle, "role": props2.closeOnClickOverlay ? "button" : void 0, "tabindex": props2.closeOnClickOverlay ? 0 : void 0 }, useScopeId(), { "onClick": onClickOverlay }), { default: slots["overlay-content"] }); } }; const onClickCloseIcon = (event) => { emit("clickCloseIcon", event); close(); }; const renderCloseIcon = () => { if (props2.closeable) { return vue.createVNode(Icon, { "role": "button", "tabindex": 0, "name": props2.closeIcon, "class": [bem$1w("close-icon", props2.closeIconPosition), HAPTICS_FEEDBACK], "classPrefix": props2.iconPrefix, "onClick": onClickCloseIcon }, null); } }; let timer2; const onOpened = () => { if (timer2) clearTimeout(timer2); timer2 = setTimeout(() => { emit("opened"); }); }; const onClosed = () => emit("closed"); const onKeydown = (event) => emit("keydown", event); const renderPopup = lazyRender(() => { var _a; const { destroyOnClose, round, position, safeAreaInsetTop, safeAreaInsetBottom, show } = props2; if (!show && destroyOnClose) { return; } return vue.withDirectives(vue.createVNode("div", vue.mergeProps({ "ref": popupRef, "style": style.value, "role": "dialog", "tabindex": 0, "class": [bem$1w({ round, [position]: position }), { "van-safe-area-top": safeAreaInsetTop, "van-safe-area-bottom": safeAreaInsetBottom }], "onKeydown": onKeydown }, attrs, useScopeId()), [(_a = slots.default) == null ? void 0 : _a.call(slots), renderCloseIcon()]), [[vue.vShow, show]]); }); const renderTransition = () => { const { position, transition, transitionAppear } = props2; const name2 = position === "center" ? "van-fade" : `van-popup-slide-${position}`; return vue.createVNode(vue.Transition, { "name": transition || name2, "appear": transitionAppear, "onAfterEnter": onOpened, "onAfterLeave": onClosed }, { default: renderPopup }); }; vue.watch(() => props2.show, (show) => { if (show && !opened) { open(); if (attrs.tabindex === 0) { vue.nextTick(() => { var _a; (_a = popupRef.value) == null ? void 0 : _a.focus(); }); } } if (!show && opened) { opened = false; emit("close"); } }); useExpose({ popupRef }); useLockScroll(popupRef, () => props2.show && props2.lockScroll); use.useEventListener("popstate", () => { if (props2.closeOnPopstate) { close(); shouldReopen = false; } }); vue.onMounted(() => { if (props2.show) { open(); } }); vue.onActivated(() => { if (shouldReopen) { emit("update:show", true); shouldReopen = false; } }); vue.onDeactivated(() => { if (props2.show && props2.teleport) { close(); shouldReopen = true; } }); vue.provide(POPUP_TOGGLE_KEY, () => props2.show); return () => { if (props2.teleport) { return vue.createVNode(vue.Teleport, { "to": props2.teleport }, { default: () => [renderOverlay(), renderTransition()] }); } return vue.createVNode(vue.Fragment, null, [renderOverlay(), renderTransition()]); }; } }); const Popup = withInstall(stdin_default$1K); const [name$1A, bem$1v] = createNamespace("action-sheet"); const actionSheetProps = extend({}, popupSharedProps, { title: String, round: truthProp, actions: makeArrayProp(), closeIcon: makeStringProp("cross"), closeable: truthProp, cancelText: String, description: String, closeOnPopstate: truthProp, closeOnClickAction: Boolean, safeAreaInsetBottom: truthProp }); const popupInheritKeys$2 = [...popupSharedPropKeys, "round", "closeOnPopstate", "safeAreaInsetBottom"]; var stdin_default$1J = vue.defineComponent({ name: name$1A, props: actionSheetProps, emits: ["select", "cancel", "update:show"], setup(props2, { slots, emit }) { const updateShow = (show) => emit("update:show", show); const onCancel = () => { updateShow(false); emit("cancel"); }; const renderHeader = () => { if (props2.title) { return vue.createVNode("div", { "class": bem$1v("header") }, [props2.title, props2.closeable && vue.createVNode(Icon, { "name": props2.closeIcon, "class": [bem$1v("close"), HAPTICS_FEEDBACK], "onClick": onCancel }, null)]); } }; const renderCancel = () => { if (slots.cancel || props2.cancelText) { return [vue.createVNode("div", { "class": bem$1v("gap") }, null), vue.createVNode("button", { "type": "button", "class": bem$1v("cancel"), "onClick": onCancel }, [slots.cancel ? slots.cancel() : props2.cancelText])]; } }; const renderIcon = (action) => { if (action.icon) { return vue.createVNode(Icon, { "class": bem$1v("item-icon"), "name": action.icon }, null); } }; const renderActionContent = (action, index) => { if (action.loading) { return vue.createVNode(Loading, { "class": bem$1v("loading-icon") }, null); } if (slots.action) { return slots.action({ action, index }); } return [vue.createVNode("span", { "class": bem$1v("name") }, [action.name]), action.subname && vue.createVNode("div", { "class": bem$1v("subname") }, [action.subname])]; }; const renderAction = (action, index) => { const { color, loading, callback, disabled, className } = action; const onClick = () => { if (disabled || loading) { return; } if (callback) { callback(action); } if (props2.closeOnClickAction) { updateShow(false); } vue.nextTick(() => emit("select", action, index)); }; return vue.createVNode("button", { "type": "button", "style": { color }, "class": [bem$1v("item", { loading, disabled }), className], "onClick": onClick }, [renderIcon(action), renderActionContent(action, index)]); }; const renderDescription = () => { if (props2.description || slots.description) { const content = slots.description ? slots.description() : props2.description; return vue.createVNode("div", { "class": bem$1v("description") }, [content]); } }; return () => vue.createVNode(Popup, vue.mergeProps({ "class": bem$1v(), "position": "bottom", "onUpdate:show": updateShow }, pick(props2, popupInheritKeys$2)), { default: () => { var _a; return [renderHeader(), renderDescription(), vue.createVNode("div", { "class": bem$1v("content") }, [props2.actions.map(renderAction), (_a = slots.default) == null ? void 0 : _a.call(slots)]), renderCancel()]; } }); } }); const ActionSheet = withInstall(stdin_default$1J); const [name$1z, bem$1u, t$k] = createNamespace("picker"); const getFirstEnabledOption = (options) => options.find((option) => !option.disabled) || options[0]; function getColumnsType(columns, fields) { const firstColumn = columns[0]; if (firstColumn) { if (Array.isArray(firstColumn)) { return "multiple"; } if (fields.children in firstColumn) { return "cascade"; } } return "default"; } function findIndexOfEnabledOption(options, index) { index = clamp(index, 0, options.length); for (let i = index; i < options.length; i++) { if (!options[i].disabled) return i; } for (let i = index - 1; i >= 0; i--) { if (!options[i].disabled) return i; } return 0; } const isOptionExist = (options, value, fields) => value !== void 0 && options.some((option) => option[fields.value] === value); function findOptionByValue(options, value, fields) { const index = options.findIndex((option) => option[fields.value] === value); const enabledIndex = findIndexOfEnabledOption(options, index); return options[enabledIndex]; } function formatCascadeColumns(columns, fields, selectedValues) { const formatted = []; let cursor = { [fields.children]: columns }; let columnIndex = 0; while (cursor && cursor[fields.children]) { const options = cursor[fields.children]; const value = selectedValues.value[columnIndex]; cursor = isDef(value) ? findOptionByValue(options, value, fields) : void 0; if (!cursor && options.length) { const firstValue = getFirstEnabledOption(options)[fields.value]; cursor = findOptionByValue(options, firstValue, fields); } columnIndex++; formatted.push(options); } return formatted; } function getElementTranslateY(element) { const { transform } = window.getComputedStyle(element); const translateY = transform.slice(7, transform.length - 1).split(", ")[5]; return Number(translateY); } function assignDefaultFields(fields) { return extend( { text: "text", value: "value", children: "children" }, fields ); } const DEFAULT_DURATION = 200; const MOMENTUM_TIME = 300; const MOMENTUM_DISTANCE = 15; const [name$1y, bem$1t] = createNamespace("picker-column"); const PICKER_KEY = Symbol(name$1y); var stdin_default$1I = vue.defineComponent({ name: name$1y, props: { value: numericProp, fields: makeRequiredProp(Object), options: makeArrayProp(), readonly: Boolean, allowHtml: Boolean, optionHeight: makeRequiredProp(Number), swipeDuration: makeRequiredProp(numericProp), visibleOptionNum: makeRequiredProp(numericProp) }, emits: ["change", "clickOption", "scrollInto"], setup(props2, { emit, slots }) { let moving; let startOffset; let touchStartTime; let momentumOffset; let transitionEndTrigger; const root = vue.ref(); const wrapper = vue.ref(); const currentOffset = vue.ref(0); const currentDuration = vue.ref(0); const touch = useTouch(); const count = () => props2.options.length; const baseOffset = () => props2.optionHeight * (+props2.visibleOptionNum - 1) / 2; const updateValueByIndex = (index) => { let enabledIndex = findIndexOfEnabledOption(props2.options, index); const offset = -enabledIndex * props2.optionHeight; const trigger = () => { if (enabledIndex > count() - 1) { enabledIndex = findIndexOfEnabledOption(props2.options, index); } const value = props2.options[enabledIndex][props2.fields.value]; if (value !== props2.value) { emit("change", value); } }; if (moving && offset !== currentOffset.value) { transitionEndTrigger = trigger; } else { trigger(); } currentOffset.value = offset; }; const isReadonly = () => props2.readonly || !props2.options.length; const onClickOption = (index) => { if (moving || isReadonly()) { return; } transitionEndTrigger = null; currentDuration.value = DEFAULT_DURATION; updateValueByIndex(index); emit("clickOption", props2.options[index]); }; const getIndexByOffset = (offset) => clamp(Math.round(-offset / props2.optionHeight), 0, count() - 1); const currentIndex = vue.computed(() => getIndexByOffset(currentOffset.value)); const momentum = (distance, duration) => { const speed = Math.abs(distance / duration); distance = currentOffset.value + speed / 3e-3 * (distance < 0 ? -1 : 1); const index = getIndexByOffset(distance); currentDuration.value = +props2.swipeDuration; updateValueByIndex(index); }; const stopMomentum = () => { moving = false; currentDuration.value = 0; if (transitionEndTrigger) { transitionEndTrigger(); transitionEndTrigger = null; } }; const onTouchStart = (event) => { if (isReadonly()) { return; } touch.start(event); if (moving) { const translateY = getElementT