| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- import { c as createNamespace, k as isDef, e as extend, s as clamp, n as numericProp, M as makeRequiredProp, o as makeArrayProp, a as useParent, D as useEventListener, p as preventDefault, H as HAPTICS_FEEDBACK, m as makeNumericProp, t as truthProp, z as makeStringProp, u as useChildren, U as unitToPx, x as isSameValue, y as pick, V as BORDER_UNSET_TOP_BOTTOM, w as withInstall } from "./index-487cde8c.js";
- import { u as useExpose } from "./use-scope-id-0b5b8615.js";
- import { L as Loading } from "./index-217c49a0.js";
- import { u as useTouch } from "./index-eef3af38.js";
- import { d as defineComponent, r as ref, a as computed, S as watchEffect, c as createVNode, w as watch, m as mergeProps, z as nextTick } from "./index-5e4623ce.js";
- const [name$3, bem$2, t] = 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, index2) {
- index2 = clamp(index2, 0, options.length);
- for (let i = index2; i < options.length; i++) {
- if (!options[i].disabled)
- return i;
- }
- for (let i = index2 - 1; i >= 0; i--) {
- if (!options[i].disabled)
- return i;
- }
- return 0;
- }
- const isOptionExist = (options, value, fields) => value !== void 0 && !!options.find((option) => option[fields.value] === value);
- function findOptionByValue(options, value, fields) {
- const index2 = options.findIndex((option) => option[fields.value] === value);
- const enabledIndex = findIndexOfEnabledOption(options, index2);
- 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$2, bem$1] = createNamespace("picker-column");
- const PICKER_KEY = Symbol(name$2);
- var stdin_default$2 = defineComponent({
- name: name$2,
- 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(props, {
- emit,
- slots
- }) {
- let moving;
- let startOffset;
- let touchStartTime;
- let momentumOffset;
- let transitionEndTrigger;
- const root = ref();
- const wrapper = ref();
- const currentOffset = ref(0);
- const currentDuration = ref(0);
- const touch = useTouch();
- const count = () => props.options.length;
- const baseOffset = () => props.optionHeight * (+props.visibleOptionNum - 1) / 2;
- const updateValueByIndex = (index2) => {
- let enabledIndex = findIndexOfEnabledOption(props.options, index2);
- const offset = -enabledIndex * props.optionHeight;
- const trigger = () => {
- if (enabledIndex > count() - 1) {
- enabledIndex = findIndexOfEnabledOption(props.options, index2);
- }
- const value = props.options[enabledIndex][props.fields.value];
- if (value !== props.value) {
- emit("change", value);
- }
- };
- if (moving && offset !== currentOffset.value) {
- transitionEndTrigger = trigger;
- } else {
- trigger();
- }
- currentOffset.value = offset;
- };
- const isReadonly = () => props.readonly || !props.options.length;
- const onClickOption = (index2) => {
- if (moving || isReadonly()) {
- return;
- }
- transitionEndTrigger = null;
- currentDuration.value = DEFAULT_DURATION;
- updateValueByIndex(index2);
- emit("clickOption", props.options[index2]);
- };
- const getIndexByOffset = (offset) => clamp(Math.round(-offset / props.optionHeight), 0, count() - 1);
- const currentIndex = 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 index2 = getIndexByOffset(distance);
- currentDuration.value = +props.swipeDuration;
- updateValueByIndex(index2);
- };
- 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 = getElementTranslateY(wrapper.value);
- currentOffset.value = Math.min(0, translateY - baseOffset());
- }
- currentDuration.value = 0;
- startOffset = currentOffset.value;
- touchStartTime = Date.now();
- momentumOffset = startOffset;
- transitionEndTrigger = null;
- };
- const onTouchMove = (event) => {
- if (isReadonly()) {
- return;
- }
- touch.move(event);
- if (touch.isVertical()) {
- moving = true;
- preventDefault(event, true);
- }
- const newOffset = clamp(startOffset + touch.deltaY.value, -(count() * props.optionHeight), props.optionHeight);
- const newIndex = getIndexByOffset(newOffset);
- if (newIndex !== currentIndex.value) {
- emit("scrollInto", props.options[newIndex]);
- }
- currentOffset.value = newOffset;
- const now = Date.now();
- if (now - touchStartTime > MOMENTUM_TIME) {
- touchStartTime = now;
- momentumOffset = newOffset;
- }
- };
- const onTouchEnd = () => {
- if (isReadonly()) {
- return;
- }
- const distance = currentOffset.value - momentumOffset;
- const duration = Date.now() - touchStartTime;
- const startMomentum = duration < MOMENTUM_TIME && Math.abs(distance) > MOMENTUM_DISTANCE;
- if (startMomentum) {
- momentum(distance, duration);
- return;
- }
- const index2 = getIndexByOffset(currentOffset.value);
- currentDuration.value = DEFAULT_DURATION;
- updateValueByIndex(index2);
- setTimeout(() => {
- moving = false;
- }, 0);
- };
- const renderOptions = () => {
- const optionStyle = {
- height: `${props.optionHeight}px`
- };
- return props.options.map((option, index2) => {
- const text = option[props.fields.text];
- const {
- disabled
- } = option;
- const value = option[props.fields.value];
- const data = {
- role: "button",
- style: optionStyle,
- tabindex: disabled ? -1 : 0,
- class: [bem$1("item", {
- disabled,
- selected: value === props.value
- }), option.className],
- onClick: () => onClickOption(index2)
- };
- const childData = {
- class: "van-ellipsis",
- [props.allowHtml ? "innerHTML" : "textContent"]: text
- };
- return createVNode("li", data, [slots.option ? slots.option(option, index2) : createVNode("div", childData, null)]);
- });
- };
- useParent(PICKER_KEY);
- useExpose({
- stopMomentum
- });
- watchEffect(() => {
- const index2 = moving ? Math.floor(-currentOffset.value / props.optionHeight) : props.options.findIndex((option) => option[props.fields.value] === props.value);
- const enabledIndex = findIndexOfEnabledOption(props.options, index2);
- const offset = -enabledIndex * props.optionHeight;
- if (moving && enabledIndex < index2)
- stopMomentum();
- currentOffset.value = offset;
- });
- useEventListener("touchmove", onTouchMove, {
- target: root
- });
- return () => createVNode("div", {
- "ref": root,
- "class": bem$1(),
- "onTouchstartPassive": onTouchStart,
- "onTouchend": onTouchEnd,
- "onTouchcancel": onTouchEnd
- }, [createVNode("ul", {
- "ref": wrapper,
- "style": {
- transform: `translate3d(0, ${currentOffset.value + baseOffset()}px, 0)`,
- transitionDuration: `${currentDuration.value}ms`,
- transitionProperty: currentDuration.value ? "all" : "none"
- },
- "class": bem$1("wrapper"),
- "onTransitionend": stopMomentum
- }, [renderOptions()])]);
- }
- });
- const [name$1] = createNamespace("picker-toolbar");
- const pickerToolbarProps = {
- title: String,
- cancelButtonText: String,
- confirmButtonText: String
- };
- const pickerToolbarSlots = ["cancel", "confirm", "title", "toolbar"];
- const pickerToolbarPropKeys = Object.keys(pickerToolbarProps);
- var stdin_default$1 = defineComponent({
- name: name$1,
- props: pickerToolbarProps,
- emits: ["confirm", "cancel"],
- setup(props, {
- emit,
- slots
- }) {
- const renderTitle = () => {
- if (slots.title) {
- return slots.title();
- }
- if (props.title) {
- return createVNode("div", {
- "class": [bem$2("title"), "van-ellipsis"]
- }, [props.title]);
- }
- };
- const onCancel = () => emit("cancel");
- const onConfirm = () => emit("confirm");
- const renderCancel = () => {
- var _a;
- const text = (_a = props.cancelButtonText) != null ? _a : t("cancel");
- if (!slots.cancel && !text) {
- return;
- }
- return createVNode("button", {
- "type": "button",
- "class": [bem$2("cancel"), HAPTICS_FEEDBACK],
- "onClick": onCancel
- }, [slots.cancel ? slots.cancel() : text]);
- };
- const renderConfirm = () => {
- var _a;
- const text = (_a = props.confirmButtonText) != null ? _a : t("confirm");
- if (!slots.confirm && !text) {
- return;
- }
- return createVNode("button", {
- "type": "button",
- "class": [bem$2("confirm"), HAPTICS_FEEDBACK],
- "onClick": onConfirm
- }, [slots.confirm ? slots.confirm() : text]);
- };
- return () => createVNode("div", {
- "class": bem$2("toolbar")
- }, [slots.toolbar ? slots.toolbar() : [renderCancel(), renderTitle(), renderConfirm()]]);
- }
- });
- const [name, bem] = createNamespace("picker-group");
- const PICKER_GROUP_KEY = Symbol(name);
- extend({
- tabs: makeArrayProp(),
- activeTab: makeNumericProp(0),
- nextStepText: String,
- showToolbar: truthProp
- }, pickerToolbarProps);
- const pickerSharedProps = extend({
- loading: Boolean,
- readonly: Boolean,
- allowHtml: Boolean,
- optionHeight: makeNumericProp(44),
- showToolbar: truthProp,
- swipeDuration: makeNumericProp(1e3),
- visibleOptionNum: makeNumericProp(6)
- }, pickerToolbarProps);
- const pickerProps = extend({}, pickerSharedProps, {
- columns: makeArrayProp(),
- modelValue: makeArrayProp(),
- toolbarPosition: makeStringProp("top"),
- columnsFieldNames: Object
- });
- var stdin_default = defineComponent({
- name: name$3,
- props: pickerProps,
- emits: ["confirm", "cancel", "change", "scrollInto", "clickOption", "update:modelValue"],
- setup(props, {
- emit,
- slots
- }) {
- const columnsRef = ref();
- const selectedValues = ref(props.modelValue.slice(0));
- const {
- parent
- } = useParent(PICKER_GROUP_KEY);
- const {
- children,
- linkChildren
- } = useChildren(PICKER_KEY);
- linkChildren();
- const fields = computed(() => assignDefaultFields(props.columnsFieldNames));
- const optionHeight = computed(() => unitToPx(props.optionHeight));
- const columnsType = computed(() => getColumnsType(props.columns, fields.value));
- const currentColumns = computed(() => {
- const {
- columns
- } = props;
- switch (columnsType.value) {
- case "multiple":
- return columns;
- case "cascade":
- return formatCascadeColumns(columns, fields.value, selectedValues);
- default:
- return [columns];
- }
- });
- const hasOptions = computed(() => currentColumns.value.some((options) => options.length));
- const selectedOptions = computed(() => currentColumns.value.map((options, index2) => findOptionByValue(options, selectedValues.value[index2], fields.value)));
- const selectedIndexes = computed(() => currentColumns.value.map((options, index2) => options.findIndex((option) => option[fields.value.value] === selectedValues.value[index2])));
- const setValue = (index2, value) => {
- if (selectedValues.value[index2] !== value) {
- const newValues = selectedValues.value.slice(0);
- newValues[index2] = value;
- selectedValues.value = newValues;
- }
- };
- const getEventParams = () => ({
- selectedValues: selectedValues.value.slice(0),
- selectedOptions: selectedOptions.value,
- selectedIndexes: selectedIndexes.value
- });
- const onChange = (value, columnIndex) => {
- setValue(columnIndex, value);
- if (columnsType.value === "cascade") {
- selectedValues.value.forEach((value2, index2) => {
- const options = currentColumns.value[index2];
- if (!isOptionExist(options, value2, fields.value)) {
- setValue(index2, options.length ? options[0][fields.value.value] : void 0);
- }
- });
- }
- nextTick(() => {
- emit("change", extend({
- columnIndex
- }, getEventParams()));
- });
- };
- const onClickOption = (currentOption, columnIndex) => {
- const params = {
- columnIndex,
- currentOption
- };
- emit("clickOption", extend(getEventParams(), params));
- emit("scrollInto", params);
- };
- const confirm = () => {
- children.forEach((child) => child.stopMomentum());
- const params = getEventParams();
- nextTick(() => {
- emit("confirm", params);
- });
- return params;
- };
- const cancel = () => emit("cancel", getEventParams());
- const renderColumnItems = () => currentColumns.value.map((options, columnIndex) => createVNode(stdin_default$2, {
- "value": selectedValues.value[columnIndex],
- "fields": fields.value,
- "options": options,
- "readonly": props.readonly,
- "allowHtml": props.allowHtml,
- "optionHeight": optionHeight.value,
- "swipeDuration": props.swipeDuration,
- "visibleOptionNum": props.visibleOptionNum,
- "onChange": (value) => onChange(value, columnIndex),
- "onClickOption": (option) => onClickOption(option, columnIndex),
- "onScrollInto": (option) => {
- emit("scrollInto", {
- currentOption: option,
- columnIndex
- });
- }
- }, {
- option: slots.option
- }));
- const renderMask = (wrapHeight) => {
- if (hasOptions.value) {
- const frameStyle = {
- height: `${optionHeight.value}px`
- };
- const maskStyle = {
- backgroundSize: `100% ${(wrapHeight - optionHeight.value) / 2}px`
- };
- return [createVNode("div", {
- "class": bem$2("mask"),
- "style": maskStyle
- }, null), createVNode("div", {
- "class": [BORDER_UNSET_TOP_BOTTOM, bem$2("frame")],
- "style": frameStyle
- }, null)];
- }
- };
- const renderColumns = () => {
- const wrapHeight = optionHeight.value * +props.visibleOptionNum;
- const columnsStyle = {
- height: `${wrapHeight}px`
- };
- return createVNode("div", {
- "ref": columnsRef,
- "class": bem$2("columns"),
- "style": columnsStyle
- }, [renderColumnItems(), renderMask(wrapHeight)]);
- };
- const renderToolbar = () => {
- if (props.showToolbar && !parent) {
- return createVNode(stdin_default$1, mergeProps(pick(props, pickerToolbarPropKeys), {
- "onConfirm": confirm,
- "onCancel": cancel
- }), pick(slots, pickerToolbarSlots));
- }
- };
- watch(currentColumns, (columns) => {
- columns.forEach((options, index2) => {
- if (options.length && !isOptionExist(options, selectedValues.value[index2], fields.value)) {
- setValue(index2, getFirstEnabledOption(options)[fields.value.value]);
- }
- });
- }, {
- immediate: true
- });
- let lastEmittedModelValue;
- watch(() => props.modelValue, (newValues) => {
- if (!isSameValue(newValues, selectedValues.value) && !isSameValue(newValues, lastEmittedModelValue)) {
- selectedValues.value = newValues.slice(0);
- lastEmittedModelValue = newValues.slice(0);
- }
- }, {
- deep: true
- });
- watch(selectedValues, (newValues) => {
- if (!isSameValue(newValues, props.modelValue)) {
- lastEmittedModelValue = newValues.slice(0);
- emit("update:modelValue", lastEmittedModelValue);
- }
- }, {
- immediate: true
- });
- useEventListener("touchmove", preventDefault, {
- target: columnsRef
- });
- const getSelectedOptions = () => selectedOptions.value;
- useExpose({
- confirm,
- getSelectedOptions
- });
- return () => {
- var _a, _b;
- return createVNode("div", {
- "class": bem$2()
- }, [props.toolbarPosition === "top" ? renderToolbar() : null, props.loading ? createVNode(Loading, {
- "class": bem$2("loading")
- }, null) : null, (_a = slots["columns-top"]) == null ? void 0 : _a.call(slots), renderColumns(), (_b = slots["columns-bottom"]) == null ? void 0 : _b.call(slots), props.toolbarPosition === "bottom" ? renderToolbar() : null]);
- };
- }
- });
- const Picker = withInstall(stdin_default);
- const index$6 = "";
- const index$5 = "";
- const index$4 = "";
- const index$3 = "";
- const index$2 = "";
- const index$1 = "";
- const index = "";
- export {
- Picker as P,
- pickerSharedProps as p
- };
|