@opensig/opendesign
Version:
<p align="center"><img src="../docs/public/opendesign-logo-light.png"/></p> <h1 align="center">opendesign</h1> <p align="center">一个 Vue 3 组件库</p> <p align="center"><b>皮肤可定制,使用 TypeScript</b></p>
600 lines (599 loc) • 22.8 kB
JavaScript
import { defineComponent, ref, computed, watch, inject, watchEffect, provide, createElementBlock, openBlock, normalizeStyle, normalizeClass, unref, createBlock, createElementVNode, createVNode, withCtx, createCommentVNode, Fragment, renderList, createTextVNode, toDisplayString, renderSlot, Teleport, withDirectives, vShow, createSlots } from "vue";
import { defaultSize } from "../_utils/global.mjs";
import { IconClose, IconLoading, IconChevronDown } from "../_utils/icons.mjs";
import { OPopup } from "../popup/index.mjs";
import { OPopover } from "../popover/index.mjs";
import { ODialog } from "../dialog/index.mjs";
import { selectOptionInjectKey } from "./provide.mjs";
import { selectProps } from "./types.mjs";
import { getRoundClass } from "../_utils/style-class.mjs";
import ClientOnly from "../_components/client-only.mjs";
import { OScroller } from "../scrollbar/index.mjs";
import { isArray, isUndefined, isArrayEqual, isFunction } from "../_utils/is.mjs";
import _sfc_main$1 from "./SelectOption.vue.mjs";
import slot from "./slot.mjs";
import { filterSlots } from "../_utils/vue-utils.mjs";
import { formItemInjectKey } from "../form/provide.mjs";
import { useI18n } from "../locale/index.mjs";
import { OButton } from "../button/index.mjs";
import { useScreen } from "../hooks/use-screen.mjs";
const _hoisted_1 = ["value", "placeholder"];
const _hoisted_2 = { class: "o-select-tags-wrap" };
const _hoisted_3 = ["onClick"];
const _hoisted_4 = { class: "o-select-tags" };
const _hoisted_5 = ["onClick"];
const _hoisted_6 = { class: "o-select-suffix" };
const _hoisted_7 = { class: "o-select-suffix-icon" };
const _hoisted_8 = {
key: 0,
class: "o-select-loading"
};
const _hoisted_9 = { class: "o-select-option-wrap" };
const _hoisted_10 = { class: "o-select-empty" };
const _hoisted_11 = { class: "o-select-options-head" };
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "OSelect",
props: selectProps,
emits: ["update:modelValue", "change", "options-visible-change", "clear"],
setup(__props, { emit: __emit }) {
const props = __props;
const emits = __emit;
const { isPhonePad } = useScreen();
const { t } = useI18n();
const selectRef = ref();
const optionsRef = ref(null);
const isSelecting = ref(false);
const isResponding = computed(() => {
return !props.noResponsive && isPhonePad.value;
});
const tagPopoverVisible = ref(false);
watch(
() => isSelecting.value,
() => {
if (isSelecting.value) {
tagPopoverVisible.value = false;
}
}
);
const formItemInjection = inject(formItemInjectKey, null);
const color = computed(() => {
var _a;
if (formItemInjection == null ? void 0 : formItemInjection.fieldResult.value) {
return (_a = formItemInjection == null ? void 0 : formItemInjection.fieldResult.value) == null ? void 0 : _a.type;
} else {
return props.color;
}
});
const optionLabels = ref({});
const valueList = ref([]);
const finalValueList = ref([]);
if (isArray(props.modelValue)) {
valueList.value = [...props.modelValue];
} else if (isArray(props.defaultValue)) {
valueList.value = [...props.defaultValue];
} else {
const mrValue = props.modelValue ?? props.defaultValue;
if (!isUndefined(mrValue)) {
valueList.value = [mrValue];
} else {
valueList.value = [];
}
}
finalValueList.value = [...valueList.value];
const valueListDisplay = computed(() => {
if (!props.maxTagCount) {
return finalValueList.value;
}
return finalValueList.value.slice(0, props.maxTagCount);
});
const valueListFold = computed(() => {
if (!props.maxTagCount) {
return [];
}
return finalValueList.value.slice(props.maxTagCount);
});
const foldLabel = computed(() => {
if (props.foldLabel) {
const tags = valueListFold.value.map((item) => ({
value: item,
label: optionLabels.value[item]
}));
return props.foldLabel(tags);
}
return `+${valueListFold.value.length}...`;
});
const foldTrigger = typeof props.showFoldTags === "string" ? props.showFoldTags : "hover";
const round = getRoundClass(props, "select");
watch(
() => props.modelValue,
(v) => {
if (props.multiple) {
if (isArray(v)) {
if (!isArrayEqual(v, valueList.value)) {
valueList.value = [...v];
}
} else {
valueList.value = [];
}
} else if (valueList.value[0] !== v) {
valueList.value = [v];
}
finalValueList.value = [...valueList.value];
}
);
watchEffect(() => {
if (!isResponding.value) {
finalValueList.value = [...valueList.value];
}
});
const isClearable = computed(() => props.clearable && !props.disabled && valueList.value.length > 0);
const emitChange = (value) => {
var _a, _b;
if (props.multiple) {
emits("change", [...value]);
} else {
emits("change", value[0]);
}
(_b = formItemInjection == null ? void 0 : (_a = formItemInjection.fieldHandlers).onChange) == null ? void 0 : _b.call(_a);
};
const emitUpdateValue = (value) => {
if (props.multiple) {
emits("update:modelValue", [...value]);
} else {
emits("update:modelValue", value[0]);
}
};
const clearClick = (e) => {
e.stopPropagation();
valueList.value = [];
emits("clear", e);
emitChange(valueList.value);
emitUpdateValue(valueList.value);
};
const beforeSelect = async (value) => {
if (isFunction(props.beforeSelect)) {
const rlt = await props.beforeSelect(value, props.multiple ? valueList.value : valueList.value[0]);
return rlt;
}
return true;
};
provide(selectOptionInjectKey, {
multiple: props.multiple,
selectValue: valueList,
select: async (option, userSelect) => {
if (userSelect) {
let toValue = option.value;
const rlt = await beforeSelect(option.value);
if (rlt === false) {
return;
}
if (typeof rlt !== "boolean") {
toValue = rlt;
}
if (!props.multiple) {
isSelecting.value = false;
if (valueList.value[0] !== toValue) {
valueList.value[0] = toValue;
emitUpdateValue(valueList.value);
emitChange(valueList.value);
}
} else {
const idx = valueList.value.indexOf(toValue);
if (idx > -1) {
valueList.value.splice(idx, 1);
} else {
valueList.value.push(toValue);
}
if (!isResponding.value) {
emitUpdateValue(valueList.value);
emitChange(valueList.value);
}
}
} else {
if (optionLabels.value[option.value] !== option.label) {
optionLabels.value[option.value] = option.label;
}
}
}
});
const onOptionVisibleChange = (visible) => {
emits("options-visible-change", visible);
};
const onRemoveTag = (value, e) => {
e.stopPropagation();
const idx = valueList.value.indexOf(value);
if (idx > -1) {
valueList.value.splice(idx, 1);
emitChange(valueList.value);
emitUpdateValue(valueList.value);
}
};
const onFoldTagClick = (e) => {
if (foldTrigger === "click") {
e.stopPropagation();
}
};
const beforeTagPopoverShow = () => {
if (isSelecting.value) {
return false;
}
return true;
};
const onSelectClick = () => {
if (isResponding.value) {
if (!props.disabled) {
isSelecting.value = true;
}
}
};
const onSelectDlgChange = (visible) => {
onOptionVisibleChange(visible);
};
const onselectDlgCancelClick = () => {
isSelecting.value = false;
valueList.value = [...finalValueList.value];
};
const onselectDlgOkClick = () => {
isSelecting.value = false;
finalValueList.value = [...valueList.value];
emitChange(valueList.value);
emitUpdateValue(valueList.value);
};
return (_ctx, _cache) => {
return openBlock(), createElementBlock(
"div",
{
ref_key: "selectRef",
ref: selectRef,
class: normalizeClass(["o-select", [
`o-select-${color.value}`,
`o-select-${props.variant}`,
`o-select-${props.size || unref(defaultSize)}`,
unref(round).class.value,
{
"is-selecting": isSelecting.value,
"is-multiple": props.multiple && valueList.value.length > 0,
"o-select-disabled": props.disabled,
"o-select-clearable": isClearable.value,
"o-select-is-loading": props.loading
}
]]),
style: normalizeStyle(unref(round).style.value),
onClick: onSelectClick
},
[
!props.multiple || props.multiple && valueList.value.length === 0 ? (openBlock(), createElementBlock("input", {
key: 0,
value: optionLabels.value[valueList.value[0]],
type: "text",
placeholder: props.placeholder,
class: "o-select-input",
readonly: ""
}, null, 8, _hoisted_1)) : (openBlock(), createBlock(unref(OScroller), {
key: 1,
class: "o-select-tags-scroller",
"wrap-class": "o-select-value-list",
"show-type": "hover",
size: "small",
"disabled-x": ""
}, {
default: withCtx(() => [
createElementVNode("div", _hoisted_2, [
(openBlock(true), createElementBlock(
Fragment,
null,
renderList(valueListDisplay.value, (item) => {
return openBlock(), createElementBlock("div", {
key: item,
class: "o-select-tag"
}, [
createTextVNode(
toDisplayString(optionLabels.value[item]) + " ",
1
/* TEXT */
),
createElementVNode("div", {
class: "o-select-tag-remove",
onClick: (e) => onRemoveTag(item, e)
}, [
createVNode(unref(IconClose))
], 8, _hoisted_3)
]);
}),
128
/* KEYED_FRAGMENT */
)),
_ctx.showFoldTags && valueListFold.value.length > 0 ? (openBlock(), createBlock(unref(OPopover), {
key: 0,
visible: tagPopoverVisible.value,
"onUpdate:visible": _cache[0] || (_cache[0] = ($event) => tagPopoverVisible.value = $event),
trigger: unref(foldTrigger),
class: "o-select-tag-popover",
position: "bottom",
"before-show": beforeTagPopoverShow
}, {
target: withCtx(() => [
createElementVNode("div", {
class: "o-select-tag",
onClick: onFoldTagClick
}, [
renderSlot(_ctx.$slots, "tag-fold", {}, () => [
createTextVNode(
toDisplayString(foldLabel.value),
1
/* TEXT */
)
])
])
]),
default: withCtx(() => [
createElementVNode("div", _hoisted_4, [
(openBlock(true), createElementBlock(
Fragment,
null,
renderList(valueListFold.value, (item) => {
return openBlock(), createElementBlock("div", {
key: item,
class: "o-select-tag"
}, [
createTextVNode(
toDisplayString(optionLabels.value[item]) + " ",
1
/* TEXT */
),
createElementVNode("div", {
class: "o-select-tag-remove",
onClick: (e) => onRemoveTag(item, e)
}, [
createVNode(unref(IconClose))
], 8, _hoisted_5)
]);
}),
128
/* KEYED_FRAGMENT */
))
])
]),
_: 3
/* FORWARDED */
}, 8, ["visible", "trigger"])) : createCommentVNode("v-if", true)
])
]),
_: 3
/* FORWARDED */
})),
createElementVNode("div", _hoisted_6, [
createElementVNode("div", _hoisted_7, [
props.loading ? (openBlock(), createElementBlock("div", _hoisted_8, [
createVNode(unref(IconLoading), { class: "o-rotating" })
])) : isClearable.value ? (openBlock(), createElementBlock("div", {
key: 1,
class: "o-select-clear",
onClick: clearClick
}, [
createVNode(unref(IconClose), { class: "o-select-clear-icon" })
])) : createCommentVNode("v-if", true),
createElementVNode(
"div",
{
class: normalizeClass(["o-select-arrow", { active: isSelecting.value }])
},
[
renderSlot(_ctx.$slots, "arrow", { active: isSelecting.value }, () => [
createVNode(unref(IconChevronDown))
])
],
2
/* CLASS */
)
]),
renderSlot(_ctx.$slots, "suffix", { active: isSelecting.value })
]),
createVNode(unref(ClientOnly), null, {
default: withCtx(() => [
(openBlock(), createBlock(Teleport, {
to: optionsRef.value,
disabled: !optionsRef.value
}, [
withDirectives(createElementVNode(
"div",
_hoisted_9,
[
renderSlot(_ctx.$slots, "default", {}, () => [
createElementVNode("div", _hoisted_10, [
renderSlot(_ctx.$slots, "empty", {}, () => [
createElementVNode(
"span",
null,
toDisplayString(unref(t)("common.empty")),
1
/* TEXT */
)
])
])
])
],
512
/* NEED_PATCH */
), [
[vShow, optionsRef.value]
])
], 8, ["to", "disabled"])),
isResponding.value ? (openBlock(), createBlock(unref(ODialog), {
key: 0,
visible: isSelecting.value,
"onUpdate:visible": _cache[1] || (_cache[1] = ($event) => isSelecting.value = $event),
"before-show": props.beforeOptionsShow,
"before-hide": props.beforeOptionsHide,
"hide-close": "",
class: normalizeClass(["o-select-dlg", {
"is-loading": props.loading
}]),
"mask-close": !props.multiple,
size: "small",
scrollbar: false,
onChange: onSelectDlgChange
}, createSlots({
default: withCtx(() => [
createVNode(_sfc_main$1, {
size: props.size,
"wrap-class": props.optionWrapClass,
loading: props.loading,
class: "o-select-options-dlg",
"option-title": props.optionTitle,
multiple: props.multiple
}, createSlots({
"option-target": withCtx(() => [
createElementVNode(
"div",
{
ref_key: "optionsRef",
ref: optionsRef
},
null,
512
/* NEED_PATCH */
)
]),
_: 2
/* DYNAMIC */
}, [
renderList(unref(filterSlots)(_ctx.$slots, unref(slot).option.names), (name) => {
return {
name,
fn: withCtx(() => [
renderSlot(_ctx.$slots, name)
])
};
})
]), 1032, ["size", "wrap-class", "loading", "option-title", "multiple"])
]),
_: 2
/* DYNAMIC */
}, [
props.optionTitle ? {
name: "header",
fn: withCtx(() => [
createElementVNode(
"div",
_hoisted_11,
toDisplayString(props.optionTitle),
1
/* TEXT */
)
]),
key: "0"
} : void 0,
props.multiple ? {
name: "actions",
fn: withCtx(() => [
createVNode(unref(OButton), {
class: "o-dlg-btn",
variant: "text",
size: "large",
onClick: onselectDlgCancelClick
}, {
default: withCtx(() => [
createTextVNode(
toDisplayString(unref(t)("select.cancel")),
1
/* TEXT */
)
]),
_: 1
/* STABLE */
}),
createVNode(unref(OButton), {
class: "o-dlg-btn",
variant: "text",
size: "large",
onClick: onselectDlgOkClick
}, {
default: withCtx(() => [
createTextVNode(
toDisplayString(unref(t)("select.confirm")),
1
/* TEXT */
)
]),
_: 1
/* STABLE */
})
]),
key: "1"
} : void 0
]), 1032, ["visible", "before-show", "before-hide", "mask-close", "class"])) : (openBlock(), createElementBlock(
Fragment,
{ key: 1 },
[
!props.disabled ? (openBlock(), createBlock(unref(OPopup), {
key: 0,
visible: isSelecting.value,
"onUpdate:visible": _cache[2] || (_cache[2] = ($event) => isSelecting.value = $event),
"wrap-class": "o-options-popup",
transition: props.transition,
"unmount-on-hide": props.unmountOnHide,
position: props.optionPosition,
wrapper: props.optionsWrapper,
target: selectRef.value,
trigger: props.trigger,
offset: 4,
"adjust-min-width": props.optionWidthMode === "min-width",
"adjust-width": props.optionWidthMode === "width",
"before-show": props.beforeOptionsShow,
"before-hide": props.beforeOptionsHide,
onChange: onOptionVisibleChange
}, {
default: withCtx(() => [
createVNode(_sfc_main$1, {
size: props.size,
"wrap-class": props.optionWrapClass,
loading: props.loading,
multiple: props.multiple
}, createSlots({
"option-target": withCtx(() => [
createElementVNode(
"div",
{
ref_key: "optionsRef",
ref: optionsRef
},
null,
512
/* NEED_PATCH */
)
]),
_: 2
/* DYNAMIC */
}, [
renderList(unref(filterSlots)(_ctx.$slots, unref(slot).option.names), (name) => {
return {
name,
fn: withCtx(() => [
renderSlot(_ctx.$slots, name)
])
};
})
]), 1032, ["size", "wrap-class", "loading", "multiple"])
]),
_: 3
/* FORWARDED */
}, 8, ["visible", "transition", "unmount-on-hide", "position", "wrapper", "target", "trigger", "adjust-min-width", "adjust-width", "before-show", "before-hide"])) : createCommentVNode("v-if", true)
],
64
/* STABLE_FRAGMENT */
))
]),
_: 3
/* FORWARDED */
})
],
6
/* CLASS, STYLE */
);
};
}
});
export {
_sfc_main as default
};