winbox-ui-next
Version:
We Design Vue 2.0: A Vue.js 3 UI Library
321 lines (320 loc) • 10.6 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var vue = require("vue");
var index = require("../textarea/index.js");
var index$2 = require("../input/index.js");
var index$1 = require("../trigger/index.js");
var dropdownPanel = require("../_components/dropdown/dropdown-panel.js");
var dropdownOption = require("../_components/dropdown/dropdown-option.js");
require("../_components/dropdown/dropdown-optgroup.js");
var useOptions = require("../_hooks/use-options.js");
var utils$1 = require("./utils.js");
var keyboard = require("../_utils/keyboard.js");
var globalConfig = require("../_utils/global-config.js");
var utils = require("../textarea/utils.js");
var resizeObserver = require("../_components/resize-observer.js");
var is = require("../_utils/is.js");
function _isSlot(s) {
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !vue.isVNode(s);
}
var _Mention = vue.defineComponent({
name: "Mention",
inheritAttrs: false,
props: {
modelValue: String,
defaultValue: {
type: String,
default: ""
},
data: {
type: Array,
default: () => []
},
prefix: {
type: [String, Array],
default: "@"
},
split: {
type: String,
default: " "
},
type: {
type: String,
default: "input"
},
onChange: {
type: [Function, Array]
},
onSelect: {
type: [Function, Array]
}
},
emits: [
"update:modelValue",
"change",
"search",
"select"
],
setup(props, {
emit,
attrs,
slots
}) {
const prefixCls = globalConfig.getPrefixCls("mention");
let styleDeclaration;
const {
data
} = vue.toRefs(props);
const dropdownRef = vue.ref();
const optionRefs = vue.ref({});
const _value = vue.ref(props.defaultValue);
const computeValue = vue.computed(() => {
var _a;
return (_a = props.modelValue) != null ? _a : _value.value;
});
const measureInfo = vue.ref({
measuring: false,
location: -1,
prefix: "",
text: ""
});
const resetMeasureInfo = () => {
measureInfo.value = {
measuring: false,
location: -1,
prefix: "",
text: ""
};
};
const inputRef = vue.ref();
const measureText = vue.computed(() => measureInfo.value.text);
const filterOption = vue.ref(true);
const handleInput = (value, e) => {
const text = utils$1.getTextBeforeSelection(e.target);
const lastMeasure = utils$1.getLastMeasureIndex(text, props.prefix);
if (lastMeasure.location > -1) {
const measureText2 = text.slice(lastMeasure.location + lastMeasure.prefix.length);
if (utils$1.isValidSearch(measureText2, props.split)) {
_popupVisible.value = true;
measureInfo.value = __spreadValues({
measuring: true,
text: measureText2
}, lastMeasure);
emit("search", measureText2);
} else if (measureInfo.value.location > -1) {
resetMeasureInfo();
}
} else if (measureInfo.value.location > -1) {
resetMeasureInfo();
}
_value.value = value;
emit("update:modelValue", value);
emit("change", value);
};
const _popupVisible = vue.ref(false);
const computedPopupVisible = vue.computed(() => _popupVisible.value && measureInfo.value.measuring && nodes.value.length > 0);
const handleResize = () => {
mirrorStyle.value = utils.getSizeStyles(styleDeclaration);
};
const handlePopupVisibleChange = (popupVisible) => {
_popupVisible.value = popupVisible;
};
const extraOptions = vue.ref([]);
const {
nodes,
activeOption,
getNextActiveOption,
scrollIntoView,
enabledOptionSet,
optionInfoMap
} = useOptions.useOptions({
options: data,
extraOptions,
inputValue: measureText,
filterOption,
dropdownRef,
optionRefs
});
const handleSelect = (value, e) => {
const measureStart = measureInfo.value.location;
const measureEnd = measureInfo.value.location + measureInfo.value.text.length;
let head = _value.value.slice(0, measureStart);
let tail = _value.value.slice(measureEnd + 1);
head += !head || head.endsWith(props.split) || head.endsWith("\n") ? "" : props.split;
tail = (!tail || tail.startsWith(props.split) || tail.startsWith("\n") ? "" : props.split) + tail;
const match = `${measureInfo.value.prefix}${value}`;
const nextValue = `${head}${match}${tail}`;
_value.value = nextValue;
emit("select", value);
emit("update:modelValue", value);
emit("change", nextValue);
resetMeasureInfo();
};
const handleMouseEnter = (value, e) => {
const optionInfo = optionInfoMap.get(value);
if (optionInfo) {
activeOption.value = optionInfo;
}
};
const handleMouseLeave = (e) => {
activeOption.value = void 0;
};
const mirrorStyle = vue.ref();
vue.onMounted(() => {
var _a;
if (props.type === "textarea" && ((_a = inputRef.value) == null ? void 0 : _a.textareaRef)) {
styleDeclaration = window.getComputedStyle(inputRef.value.textareaRef);
mirrorStyle.value = utils.getSizeStyles(styleDeclaration);
}
});
const handleKeyDown = keyboard.getKeyDownHandler(new Map([[keyboard.CODE.ENTER, (e) => {
if (computedPopupVisible.value) {
if (activeOption.value) {
handleSelect(activeOption.value.value);
}
e.preventDefault();
}
}], [keyboard.CODE.ESC, (e) => {
handlePopupVisibleChange(false);
e.preventDefault();
}], [keyboard.CODE.ARROW_DOWN, (e) => {
if (computedPopupVisible.value) {
const next = getNextActiveOption("down");
if (next) {
activeOption.value = next;
scrollIntoView(next.value);
}
e.preventDefault();
}
}], [keyboard.CODE.ARROW_UP, (e) => {
if (computedPopupVisible.value) {
const next = getNextActiveOption("up");
if (next) {
activeOption.value = next;
scrollIntoView(next.value);
}
e.preventDefault();
}
}]]));
const getOptionContentFunc = (item) => {
if (is.isFunction(slots.option) && item.value) {
const optionInfo = optionInfoMap.get(item.value);
const optionSlot = slots.option;
return () => optionSlot({
data: optionInfo
});
}
return () => item.label;
};
const renderOption = (item) => {
const {
value = ""
} = item;
return vue.createVNode(dropdownOption, {
"ref": (ref) => {
if (ref == null ? void 0 : ref.$el) {
optionRefs.value[value] = ref.$el;
}
},
"key": item.key,
"value": value,
"disabled": item.disabled,
"isActive": activeOption.value && value === activeOption.value.value,
"onClick": handleSelect,
"onMouseenter": handleMouseEnter,
"onMouseleave": handleMouseLeave
}, {
default: getOptionContentFunc(item)
});
};
const renderDropdown = () => {
if (!measureInfo.value.measuring || nodes.value.length === 0) {
return null;
}
const _children = nodes.value.map((node) => renderOption(node));
return vue.createVNode(dropdownPanel, {
"ref": dropdownRef
}, _isSlot(_children) ? _children : {
default: () => [_children]
});
};
const mirrorRef = vue.ref();
vue.watch(computedPopupVisible, (visible) => {
if (props.type === "textarea" && visible) {
vue.nextTick(() => {
var _a, _b;
if (((_a = inputRef.value) == null ? void 0 : _a.textareaRef) && inputRef.value.textareaRef.scrollTop > 0) {
(_b = mirrorRef.value) == null ? void 0 : _b.scrollTo(0, inputRef.value.textareaRef.scrollTop);
}
});
}
});
const render = () => {
var _a;
if (props.type === "textarea") {
return vue.createVNode("div", {
"class": prefixCls
}, [vue.createVNode(resizeObserver, {
"onResize": handleResize
}, {
default: () => [vue.createVNode(index, vue.mergeProps(attrs, {
"ref": inputRef,
"modelValue": computeValue.value,
"onInput": handleInput,
"onKeydown": handleKeyDown
}), null)]
}), measureInfo.value.measuring && nodes.value.length > 0 && vue.createVNode("div", {
"ref": mirrorRef,
"style": mirrorStyle.value,
"class": `${prefixCls}-measure`
}, [(_a = computeValue.value) == null ? void 0 : _a.slice(0, measureInfo.value.location), vue.createVNode(index$1, {
"trigger": "focus",
"position": "bl",
"popupOffset": 4,
"preventFocus": true,
"popupVisible": computedPopupVisible.value,
"clickToClose": false,
"onPopupVisibleChange": handlePopupVisibleChange
}, {
default: () => [vue.createVNode("span", null, [vue.createTextVNode("@")])],
content: renderDropdown
})])]);
}
return vue.createVNode(index$1, {
"trigger": "focus",
"position": "bl",
"popupOffset": 4,
"preventFocus": true,
"popupVisible": computedPopupVisible.value,
"clickToClose": false,
"autoFitPopupWidth": true,
"onPopupVisibleChange": handlePopupVisibleChange
}, {
default: () => [vue.createVNode(index$2["default"], vue.mergeProps(attrs, {
"ref": inputRef,
"modelValue": computeValue.value,
"onInput": handleInput,
"onKeydown": handleKeyDown
}), slots)],
content: renderDropdown
});
};
return render;
}
});
module.exports = _Mention;