921 lines
29 KiB
JavaScript
921 lines
29 KiB
JavaScript
import { h, ref, computed, toRef, defineComponent, watch, Transition, withDirectives, vShow, watchEffect } from 'vue';
|
|
import { getPreciseEventTarget, happensIn } from 'seemly';
|
|
import { createTreeMate } from 'treemate';
|
|
import { VBinder, VFollower, VTarget } from 'vueuc';
|
|
import { useIsMounted, useMergedState, useCompitable } from 'vooks';
|
|
import { clickoutside } from 'vdirs';
|
|
import { useTheme, useConfig, useLocale, useFormItem, useThemeClass } from "../../_mixins/index.mjs";
|
|
import { call, markEventEffectPerformed, useAdjustedTo, warnOnce } from "../../_utils/index.mjs";
|
|
import { NInternalSelectMenu, NInternalSelection } from "../../_internal/index.mjs";
|
|
import { selectLight } from "../styles/index.mjs";
|
|
import { createValOptMap, filterOptions, createTmOptions, patternMatched } from "./utils.mjs";
|
|
import style from "./styles/index.cssr.mjs";
|
|
export const selectProps = Object.assign(Object.assign({}, useTheme.props), {
|
|
to: useAdjustedTo.propTo,
|
|
bordered: {
|
|
type: Boolean,
|
|
default: undefined
|
|
},
|
|
clearable: Boolean,
|
|
clearFilterAfterSelect: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
options: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
defaultValue: {
|
|
type: [String, Number, Array],
|
|
default: null
|
|
},
|
|
keyboard: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
value: [String, Number, Array],
|
|
placeholder: String,
|
|
menuProps: Object,
|
|
multiple: Boolean,
|
|
size: String,
|
|
filterable: Boolean,
|
|
disabled: {
|
|
type: Boolean,
|
|
default: undefined
|
|
},
|
|
remote: Boolean,
|
|
loading: Boolean,
|
|
filter: Function,
|
|
placement: {
|
|
type: String,
|
|
default: 'bottom-start'
|
|
},
|
|
widthMode: {
|
|
type: String,
|
|
default: 'trigger'
|
|
},
|
|
tag: Boolean,
|
|
onCreate: Function,
|
|
fallbackOption: {
|
|
type: [Function, Boolean],
|
|
default: undefined
|
|
},
|
|
show: {
|
|
type: Boolean,
|
|
default: undefined
|
|
},
|
|
showArrow: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
maxTagCount: [Number, String],
|
|
ellipsisTagPopoverProps: Object,
|
|
consistentMenuWidth: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
virtualScroll: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
labelField: {
|
|
type: String,
|
|
default: 'label'
|
|
},
|
|
valueField: {
|
|
type: String,
|
|
default: 'value'
|
|
},
|
|
childrenField: {
|
|
type: String,
|
|
default: 'children'
|
|
},
|
|
renderLabel: Function,
|
|
renderOption: Function,
|
|
renderTag: Function,
|
|
'onUpdate:value': [Function, Array],
|
|
inputProps: Object,
|
|
nodeProps: Function,
|
|
ignoreComposition: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
showOnFocus: Boolean,
|
|
// for jsx
|
|
onUpdateValue: [Function, Array],
|
|
onBlur: [Function, Array],
|
|
onClear: [Function, Array],
|
|
onFocus: [Function, Array],
|
|
onScroll: [Function, Array],
|
|
onSearch: [Function, Array],
|
|
onUpdateShow: [Function, Array],
|
|
'onUpdate:show': [Function, Array],
|
|
displayDirective: {
|
|
type: String,
|
|
default: 'show'
|
|
},
|
|
resetMenuOnOptionsChange: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
status: String,
|
|
showCheckmark: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
/** deprecated */
|
|
onChange: [Function, Array],
|
|
items: Array
|
|
});
|
|
export default defineComponent({
|
|
name: 'Select',
|
|
props: selectProps,
|
|
setup(props) {
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
watchEffect(() => {
|
|
if (props.items !== undefined) {
|
|
warnOnce('select', '`items` is deprecated, please use `options` instead.');
|
|
}
|
|
if (props.onChange !== undefined) {
|
|
warnOnce('select', '`on-change` is deprecated, please use `on-update:value` instead.');
|
|
}
|
|
});
|
|
}
|
|
const {
|
|
mergedClsPrefixRef,
|
|
mergedBorderedRef,
|
|
namespaceRef,
|
|
inlineThemeDisabled
|
|
} = useConfig(props);
|
|
const themeRef = useTheme('Select', '-select', style, selectLight, props, mergedClsPrefixRef);
|
|
const uncontrolledValueRef = ref(props.defaultValue);
|
|
const controlledValueRef = toRef(props, 'value');
|
|
const mergedValueRef = useMergedState(controlledValueRef, uncontrolledValueRef);
|
|
const focusedRef = ref(false);
|
|
const patternRef = ref('');
|
|
const treeMateRef = computed(() => {
|
|
const {
|
|
valueField,
|
|
childrenField
|
|
} = props;
|
|
const options = createTmOptions(valueField, childrenField);
|
|
return createTreeMate(filteredOptionsRef.value, options);
|
|
});
|
|
const valOptMapRef = computed(() => createValOptMap(localOptionsRef.value, props.valueField, props.childrenField));
|
|
const uncontrolledShowRef = ref(false);
|
|
const mergedShowRef = useMergedState(toRef(props, 'show'), uncontrolledShowRef);
|
|
const triggerRef = ref(null);
|
|
const followerRef = ref(null);
|
|
const menuRef = ref(null);
|
|
const {
|
|
localeRef
|
|
} = useLocale('Select');
|
|
const localizedPlaceholderRef = computed(() => {
|
|
var _a;
|
|
return (_a = props.placeholder) !== null && _a !== void 0 ? _a : localeRef.value.placeholder;
|
|
});
|
|
const compitableOptionsRef = useCompitable(props, ['items', 'options']);
|
|
const emptyArray = [];
|
|
const createdOptionsRef = ref([]);
|
|
const beingCreatedOptionsRef = ref([]);
|
|
const memoValOptMapRef = ref(new Map());
|
|
const wrappedFallbackOptionRef = computed(() => {
|
|
const {
|
|
fallbackOption
|
|
} = props;
|
|
if (fallbackOption === undefined) {
|
|
const {
|
|
labelField,
|
|
valueField
|
|
} = props;
|
|
return value => ({
|
|
[labelField]: String(value),
|
|
[valueField]: value
|
|
});
|
|
}
|
|
if (fallbackOption === false) return false;
|
|
return value => {
|
|
return Object.assign(fallbackOption(value), {
|
|
value
|
|
});
|
|
};
|
|
});
|
|
const localOptionsRef = computed(() => {
|
|
return beingCreatedOptionsRef.value.concat(createdOptionsRef.value).concat(compitableOptionsRef.value);
|
|
});
|
|
const resolvedFilterRef = computed(() => {
|
|
const {
|
|
filter
|
|
} = props;
|
|
if (filter) return filter;
|
|
const {
|
|
labelField,
|
|
valueField
|
|
} = props;
|
|
return (pattern, option) => {
|
|
if (!option) return false;
|
|
const label = option[labelField];
|
|
if (typeof label === 'string') {
|
|
return patternMatched(pattern, label);
|
|
}
|
|
const value = option[valueField];
|
|
if (typeof value === 'string') {
|
|
return patternMatched(pattern, value);
|
|
}
|
|
if (typeof value === 'number') {
|
|
return patternMatched(pattern, String(value));
|
|
}
|
|
return false;
|
|
};
|
|
});
|
|
const filteredOptionsRef = computed(() => {
|
|
if (props.remote) {
|
|
return compitableOptionsRef.value;
|
|
} else {
|
|
const {
|
|
value: localOptions
|
|
} = localOptionsRef;
|
|
const {
|
|
value: pattern
|
|
} = patternRef;
|
|
if (!pattern.length || !props.filterable) {
|
|
return localOptions;
|
|
} else {
|
|
return filterOptions(localOptions, resolvedFilterRef.value, pattern, props.childrenField);
|
|
}
|
|
}
|
|
});
|
|
function getMergedOptions(values) {
|
|
const remote = props.remote;
|
|
const {
|
|
value: memoValOptMap
|
|
} = memoValOptMapRef;
|
|
const {
|
|
value: valOptMap
|
|
} = valOptMapRef;
|
|
const {
|
|
value: wrappedFallbackOption
|
|
} = wrappedFallbackOptionRef;
|
|
const options = [];
|
|
values.forEach(value => {
|
|
if (valOptMap.has(value)) {
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
options.push(valOptMap.get(value));
|
|
} else if (remote && memoValOptMap.has(value)) {
|
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
options.push(memoValOptMap.get(value));
|
|
} else if (wrappedFallbackOption) {
|
|
const option = wrappedFallbackOption(value);
|
|
if (option) {
|
|
options.push(option);
|
|
}
|
|
}
|
|
});
|
|
return options;
|
|
}
|
|
const selectedOptionsRef = computed(() => {
|
|
if (props.multiple) {
|
|
const {
|
|
value: values
|
|
} = mergedValueRef;
|
|
if (!Array.isArray(values)) return [];
|
|
return getMergedOptions(values);
|
|
}
|
|
return null;
|
|
});
|
|
const selectedOptionRef = computed(() => {
|
|
const {
|
|
value: mergedValue
|
|
} = mergedValueRef;
|
|
if (!props.multiple && !Array.isArray(mergedValue)) {
|
|
if (mergedValue === null) return null;
|
|
return getMergedOptions([mergedValue])[0] || null;
|
|
}
|
|
return null;
|
|
});
|
|
const formItem = useFormItem(props);
|
|
const {
|
|
mergedSizeRef,
|
|
mergedDisabledRef,
|
|
mergedStatusRef
|
|
} = formItem;
|
|
function doUpdateValue(value, option) {
|
|
const {
|
|
onChange,
|
|
'onUpdate:value': _onUpdateValue,
|
|
onUpdateValue
|
|
} = props;
|
|
const {
|
|
nTriggerFormChange,
|
|
nTriggerFormInput
|
|
} = formItem;
|
|
if (onChange) call(onChange, value, option);
|
|
if (onUpdateValue) call(onUpdateValue, value, option);
|
|
if (_onUpdateValue) {
|
|
call(_onUpdateValue, value, option);
|
|
}
|
|
uncontrolledValueRef.value = value;
|
|
nTriggerFormChange();
|
|
nTriggerFormInput();
|
|
}
|
|
function doBlur(e) {
|
|
const {
|
|
onBlur
|
|
} = props;
|
|
const {
|
|
nTriggerFormBlur
|
|
} = formItem;
|
|
if (onBlur) call(onBlur, e);
|
|
nTriggerFormBlur();
|
|
}
|
|
function doClear() {
|
|
const {
|
|
onClear
|
|
} = props;
|
|
if (onClear) call(onClear);
|
|
}
|
|
function doFocus(e) {
|
|
const {
|
|
onFocus,
|
|
showOnFocus
|
|
} = props;
|
|
const {
|
|
nTriggerFormFocus
|
|
} = formItem;
|
|
if (onFocus) call(onFocus, e);
|
|
nTriggerFormFocus();
|
|
if (showOnFocus) {
|
|
openMenu();
|
|
}
|
|
}
|
|
function doSearch(value) {
|
|
const {
|
|
onSearch
|
|
} = props;
|
|
if (onSearch) call(onSearch, value);
|
|
}
|
|
function doScroll(e) {
|
|
const {
|
|
onScroll
|
|
} = props;
|
|
if (onScroll) call(onScroll, e);
|
|
}
|
|
// remote related methods
|
|
function updateMemorizedOptions() {
|
|
var _a;
|
|
const {
|
|
remote,
|
|
multiple
|
|
} = props;
|
|
if (remote) {
|
|
const {
|
|
value: memoValOptMap
|
|
} = memoValOptMapRef;
|
|
if (multiple) {
|
|
const {
|
|
valueField
|
|
} = props;
|
|
(_a = selectedOptionsRef.value) === null || _a === void 0 ? void 0 : _a.forEach(option => {
|
|
memoValOptMap.set(option[valueField], option);
|
|
});
|
|
} else {
|
|
const option = selectedOptionRef.value;
|
|
if (option) {
|
|
memoValOptMap.set(option[props.valueField], option);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// menu related methods
|
|
function doUpdateShow(value) {
|
|
const {
|
|
onUpdateShow,
|
|
'onUpdate:show': _onUpdateShow
|
|
} = props;
|
|
if (onUpdateShow) call(onUpdateShow, value);
|
|
if (_onUpdateShow) call(_onUpdateShow, value);
|
|
uncontrolledShowRef.value = value;
|
|
}
|
|
function openMenu() {
|
|
if (!mergedDisabledRef.value) {
|
|
doUpdateShow(true);
|
|
uncontrolledShowRef.value = true;
|
|
if (props.filterable) {
|
|
focusSelectionInput();
|
|
}
|
|
}
|
|
}
|
|
function closeMenu() {
|
|
doUpdateShow(false);
|
|
}
|
|
function handleMenuAfterLeave() {
|
|
patternRef.value = '';
|
|
beingCreatedOptionsRef.value = emptyArray;
|
|
}
|
|
const activeWithoutMenuOpenRef = ref(false);
|
|
function onTriggerInputFocus() {
|
|
if (props.filterable) {
|
|
activeWithoutMenuOpenRef.value = true;
|
|
}
|
|
}
|
|
function onTriggerInputBlur() {
|
|
if (props.filterable) {
|
|
activeWithoutMenuOpenRef.value = false;
|
|
if (!mergedShowRef.value) {
|
|
handleMenuAfterLeave();
|
|
}
|
|
}
|
|
}
|
|
function handleTriggerClick() {
|
|
if (mergedDisabledRef.value) return;
|
|
if (!mergedShowRef.value) {
|
|
openMenu();
|
|
} else {
|
|
if (!props.filterable) {
|
|
// already focused, don't need to return focus
|
|
closeMenu();
|
|
} else {
|
|
focusSelectionInput();
|
|
}
|
|
}
|
|
}
|
|
function handleTriggerBlur(e) {
|
|
var _a, _b;
|
|
if ((_b = (_a = menuRef.value) === null || _a === void 0 ? void 0 : _a.selfRef) === null || _b === void 0 ? void 0 : _b.contains(e.relatedTarget)) {
|
|
return;
|
|
}
|
|
focusedRef.value = false;
|
|
doBlur(e);
|
|
// outside select, don't need to return focus
|
|
closeMenu();
|
|
}
|
|
function handleTriggerFocus(e) {
|
|
doFocus(e);
|
|
focusedRef.value = true;
|
|
}
|
|
function handleMenuFocus(e) {
|
|
focusedRef.value = true;
|
|
}
|
|
function handleMenuBlur(e) {
|
|
var _a;
|
|
if ((_a = triggerRef.value) === null || _a === void 0 ? void 0 : _a.$el.contains(e.relatedTarget)) return;
|
|
focusedRef.value = false;
|
|
doBlur(e);
|
|
// outside select, don't need to return focus
|
|
closeMenu();
|
|
}
|
|
function handleMenuTabOut() {
|
|
var _a;
|
|
(_a = triggerRef.value) === null || _a === void 0 ? void 0 : _a.focus();
|
|
closeMenu();
|
|
}
|
|
function handleMenuClickOutside(e) {
|
|
var _a;
|
|
if (mergedShowRef.value) {
|
|
if (!((_a = triggerRef.value) === null || _a === void 0 ? void 0 : _a.$el.contains(getPreciseEventTarget(e)))) {
|
|
// outside select, don't need to return focus
|
|
closeMenu();
|
|
}
|
|
}
|
|
}
|
|
function createClearedMultipleSelectValue(value) {
|
|
if (!Array.isArray(value)) return [];
|
|
if (wrappedFallbackOptionRef.value) {
|
|
// if option has a fallback, I can't help user to clear some unknown value
|
|
return Array.from(value);
|
|
} else {
|
|
// if there's no option fallback, unappeared options are treated as invalid
|
|
const {
|
|
remote
|
|
} = props;
|
|
const {
|
|
value: valOptMap
|
|
} = valOptMapRef;
|
|
if (remote) {
|
|
const {
|
|
value: memoValOptMap
|
|
} = memoValOptMapRef;
|
|
return value.filter(v => valOptMap.has(v) || memoValOptMap.has(v));
|
|
} else {
|
|
return value.filter(v => valOptMap.has(v));
|
|
}
|
|
}
|
|
}
|
|
function handleToggleByTmNode(tmNode) {
|
|
handleToggleByOption(tmNode.rawNode);
|
|
}
|
|
function handleToggleByOption(option) {
|
|
if (mergedDisabledRef.value) return;
|
|
const {
|
|
tag,
|
|
remote,
|
|
clearFilterAfterSelect,
|
|
valueField
|
|
} = props;
|
|
if (tag && !remote) {
|
|
const {
|
|
value: beingCreatedOptions
|
|
} = beingCreatedOptionsRef;
|
|
const beingCreatedOption = beingCreatedOptions[0] || null;
|
|
if (beingCreatedOption) {
|
|
const createdOptions = createdOptionsRef.value;
|
|
if (!createdOptions.length) {
|
|
createdOptionsRef.value = [beingCreatedOption];
|
|
} else {
|
|
createdOptions.push(beingCreatedOption);
|
|
}
|
|
beingCreatedOptionsRef.value = emptyArray;
|
|
}
|
|
}
|
|
if (remote) {
|
|
memoValOptMapRef.value.set(option[valueField], option);
|
|
}
|
|
if (props.multiple) {
|
|
const changedValue = createClearedMultipleSelectValue(mergedValueRef.value);
|
|
const index = changedValue.findIndex(value => value === option[valueField]);
|
|
if (~index) {
|
|
changedValue.splice(index, 1);
|
|
if (tag && !remote) {
|
|
const createdOptionIndex = getCreatedOptionIndex(option[valueField]);
|
|
if (~createdOptionIndex) {
|
|
createdOptionsRef.value.splice(createdOptionIndex, 1);
|
|
if (clearFilterAfterSelect) patternRef.value = '';
|
|
}
|
|
}
|
|
} else {
|
|
changedValue.push(option[valueField]);
|
|
if (clearFilterAfterSelect) patternRef.value = '';
|
|
}
|
|
doUpdateValue(changedValue, getMergedOptions(changedValue));
|
|
} else {
|
|
if (tag && !remote) {
|
|
const createdOptionIndex = getCreatedOptionIndex(option[valueField]);
|
|
if (~createdOptionIndex) {
|
|
createdOptionsRef.value = [createdOptionsRef.value[createdOptionIndex]];
|
|
} else {
|
|
createdOptionsRef.value = emptyArray;
|
|
}
|
|
}
|
|
focusSelection();
|
|
closeMenu();
|
|
doUpdateValue(option[valueField], option);
|
|
}
|
|
}
|
|
function getCreatedOptionIndex(optionValue) {
|
|
const createdOptions = createdOptionsRef.value;
|
|
return createdOptions.findIndex(createdOption => createdOption[props.valueField] === optionValue);
|
|
}
|
|
function handlePatternInput(e) {
|
|
if (!mergedShowRef.value) {
|
|
openMenu();
|
|
}
|
|
const {
|
|
value
|
|
} = e.target;
|
|
patternRef.value = value;
|
|
const {
|
|
tag,
|
|
remote
|
|
} = props;
|
|
doSearch(value);
|
|
if (tag && !remote) {
|
|
if (!value) {
|
|
beingCreatedOptionsRef.value = emptyArray;
|
|
return;
|
|
}
|
|
const {
|
|
onCreate
|
|
} = props;
|
|
const optionBeingCreated = onCreate ? onCreate(value) : {
|
|
[props.labelField]: value,
|
|
[props.valueField]: value
|
|
};
|
|
const {
|
|
valueField,
|
|
labelField
|
|
} = props;
|
|
if (compitableOptionsRef.value.some(option => {
|
|
return option[valueField] === optionBeingCreated[valueField] || option[labelField] === optionBeingCreated[labelField];
|
|
}) || createdOptionsRef.value.some(option => {
|
|
return option[valueField] === optionBeingCreated[valueField] || option[labelField] === optionBeingCreated[labelField];
|
|
})) {
|
|
beingCreatedOptionsRef.value = emptyArray;
|
|
} else {
|
|
beingCreatedOptionsRef.value = [optionBeingCreated];
|
|
}
|
|
}
|
|
}
|
|
function handleClear(e) {
|
|
e.stopPropagation();
|
|
const {
|
|
multiple
|
|
} = props;
|
|
if (!multiple && props.filterable) {
|
|
closeMenu();
|
|
}
|
|
doClear();
|
|
if (multiple) {
|
|
doUpdateValue([], []);
|
|
} else {
|
|
doUpdateValue(null, null);
|
|
}
|
|
}
|
|
function handleMenuMousedown(e) {
|
|
if (!happensIn(e, 'action') && !happensIn(e, 'empty')) e.preventDefault();
|
|
}
|
|
// scroll events on menu
|
|
function handleMenuScroll(e) {
|
|
doScroll(e);
|
|
}
|
|
// keyboard events
|
|
// also for menu keydown
|
|
function handleKeydown(e) {
|
|
var _a, _b, _c, _d, _e;
|
|
if (!props.keyboard) {
|
|
e.preventDefault();
|
|
return;
|
|
}
|
|
switch (e.key) {
|
|
case ' ':
|
|
if (props.filterable) break;else {
|
|
e.preventDefault();
|
|
}
|
|
// eslint-disable-next-line no-fallthrough
|
|
case 'Enter':
|
|
if (!((_a = triggerRef.value) === null || _a === void 0 ? void 0 : _a.isComposing)) {
|
|
if (mergedShowRef.value) {
|
|
const pendingTmNode = (_b = menuRef.value) === null || _b === void 0 ? void 0 : _b.getPendingTmNode();
|
|
if (pendingTmNode) {
|
|
handleToggleByTmNode(pendingTmNode);
|
|
} else if (!props.filterable) {
|
|
closeMenu();
|
|
focusSelection();
|
|
}
|
|
} else {
|
|
openMenu();
|
|
if (props.tag && activeWithoutMenuOpenRef.value) {
|
|
const beingCreatedOption = beingCreatedOptionsRef.value[0];
|
|
if (beingCreatedOption) {
|
|
const optionValue = beingCreatedOption[props.valueField];
|
|
const {
|
|
value: mergedValue
|
|
} = mergedValueRef;
|
|
if (props.multiple) {
|
|
if (Array.isArray(mergedValue) && mergedValue.some(value => value === optionValue)) {
|
|
// do nothing
|
|
} else {
|
|
handleToggleByOption(beingCreatedOption);
|
|
}
|
|
} else {
|
|
handleToggleByOption(beingCreatedOption);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
e.preventDefault();
|
|
break;
|
|
case 'ArrowUp':
|
|
e.preventDefault();
|
|
if (props.loading) return;
|
|
if (mergedShowRef.value) {
|
|
(_c = menuRef.value) === null || _c === void 0 ? void 0 : _c.prev();
|
|
}
|
|
break;
|
|
case 'ArrowDown':
|
|
e.preventDefault();
|
|
if (props.loading) return;
|
|
if (mergedShowRef.value) {
|
|
(_d = menuRef.value) === null || _d === void 0 ? void 0 : _d.next();
|
|
} else {
|
|
openMenu();
|
|
}
|
|
break;
|
|
case 'Escape':
|
|
if (mergedShowRef.value) {
|
|
markEventEffectPerformed(e);
|
|
closeMenu();
|
|
}
|
|
(_e = triggerRef.value) === null || _e === void 0 ? void 0 : _e.focus();
|
|
break;
|
|
}
|
|
}
|
|
function focusSelection() {
|
|
var _a;
|
|
(_a = triggerRef.value) === null || _a === void 0 ? void 0 : _a.focus();
|
|
}
|
|
function focusSelectionInput() {
|
|
var _a;
|
|
(_a = triggerRef.value) === null || _a === void 0 ? void 0 : _a.focusInput();
|
|
}
|
|
function handleTriggerOrMenuResize() {
|
|
var _a;
|
|
if (!mergedShowRef.value) return;
|
|
(_a = followerRef.value) === null || _a === void 0 ? void 0 : _a.syncPosition();
|
|
}
|
|
updateMemorizedOptions();
|
|
watch(toRef(props, 'options'), updateMemorizedOptions);
|
|
const exposedMethods = {
|
|
focus: () => {
|
|
var _a;
|
|
(_a = triggerRef.value) === null || _a === void 0 ? void 0 : _a.focus();
|
|
},
|
|
focusInput: () => {
|
|
var _a;
|
|
(_a = triggerRef.value) === null || _a === void 0 ? void 0 : _a.focusInput();
|
|
},
|
|
blur: () => {
|
|
var _a;
|
|
(_a = triggerRef.value) === null || _a === void 0 ? void 0 : _a.blur();
|
|
},
|
|
blurInput: () => {
|
|
var _a;
|
|
(_a = triggerRef.value) === null || _a === void 0 ? void 0 : _a.blurInput();
|
|
}
|
|
};
|
|
const cssVarsRef = computed(() => {
|
|
const {
|
|
self: {
|
|
menuBoxShadow
|
|
}
|
|
} = themeRef.value;
|
|
return {
|
|
'--n-menu-box-shadow': menuBoxShadow
|
|
};
|
|
});
|
|
const themeClassHandle = inlineThemeDisabled ? useThemeClass('select', undefined, cssVarsRef, props) : undefined;
|
|
return Object.assign(Object.assign({}, exposedMethods), {
|
|
mergedStatus: mergedStatusRef,
|
|
mergedClsPrefix: mergedClsPrefixRef,
|
|
mergedBordered: mergedBorderedRef,
|
|
namespace: namespaceRef,
|
|
treeMate: treeMateRef,
|
|
isMounted: useIsMounted(),
|
|
triggerRef,
|
|
menuRef,
|
|
pattern: patternRef,
|
|
uncontrolledShow: uncontrolledShowRef,
|
|
mergedShow: mergedShowRef,
|
|
adjustedTo: useAdjustedTo(props),
|
|
uncontrolledValue: uncontrolledValueRef,
|
|
mergedValue: mergedValueRef,
|
|
followerRef,
|
|
localizedPlaceholder: localizedPlaceholderRef,
|
|
selectedOption: selectedOptionRef,
|
|
selectedOptions: selectedOptionsRef,
|
|
mergedSize: mergedSizeRef,
|
|
mergedDisabled: mergedDisabledRef,
|
|
focused: focusedRef,
|
|
activeWithoutMenuOpen: activeWithoutMenuOpenRef,
|
|
inlineThemeDisabled,
|
|
onTriggerInputFocus,
|
|
onTriggerInputBlur,
|
|
handleTriggerOrMenuResize,
|
|
handleMenuFocus,
|
|
handleMenuBlur,
|
|
handleMenuTabOut,
|
|
handleTriggerClick,
|
|
handleToggle: handleToggleByTmNode,
|
|
handleDeleteOption: handleToggleByOption,
|
|
handlePatternInput,
|
|
handleClear,
|
|
handleTriggerBlur,
|
|
handleTriggerFocus,
|
|
handleKeydown,
|
|
handleMenuAfterLeave,
|
|
handleMenuClickOutside,
|
|
handleMenuScroll,
|
|
handleMenuKeydown: handleKeydown,
|
|
handleMenuMousedown,
|
|
mergedTheme: themeRef,
|
|
cssVars: inlineThemeDisabled ? undefined : cssVarsRef,
|
|
themeClass: themeClassHandle === null || themeClassHandle === void 0 ? void 0 : themeClassHandle.themeClass,
|
|
onRender: themeClassHandle === null || themeClassHandle === void 0 ? void 0 : themeClassHandle.onRender
|
|
});
|
|
},
|
|
render() {
|
|
return h("div", {
|
|
class: `${this.mergedClsPrefix}-select`
|
|
}, h(VBinder, null, {
|
|
default: () => [h(VTarget, null, {
|
|
default: () => h(NInternalSelection, {
|
|
ref: "triggerRef",
|
|
inlineThemeDisabled: this.inlineThemeDisabled,
|
|
status: this.mergedStatus,
|
|
inputProps: this.inputProps,
|
|
clsPrefix: this.mergedClsPrefix,
|
|
showArrow: this.showArrow,
|
|
maxTagCount: this.maxTagCount,
|
|
ellipsisTagPopoverProps: this.ellipsisTagPopoverProps,
|
|
bordered: this.mergedBordered,
|
|
active: this.activeWithoutMenuOpen || this.mergedShow,
|
|
pattern: this.pattern,
|
|
placeholder: this.localizedPlaceholder,
|
|
selectedOption: this.selectedOption,
|
|
selectedOptions: this.selectedOptions,
|
|
multiple: this.multiple,
|
|
renderTag: this.renderTag,
|
|
renderLabel: this.renderLabel,
|
|
filterable: this.filterable,
|
|
clearable: this.clearable,
|
|
disabled: this.mergedDisabled,
|
|
size: this.mergedSize,
|
|
theme: this.mergedTheme.peers.InternalSelection,
|
|
labelField: this.labelField,
|
|
valueField: this.valueField,
|
|
themeOverrides: this.mergedTheme.peerOverrides.InternalSelection,
|
|
loading: this.loading,
|
|
focused: this.focused,
|
|
onClick: this.handleTriggerClick,
|
|
onDeleteOption: this.handleDeleteOption,
|
|
onPatternInput: this.handlePatternInput,
|
|
onClear: this.handleClear,
|
|
onBlur: this.handleTriggerBlur,
|
|
onFocus: this.handleTriggerFocus,
|
|
onKeydown: this.handleKeydown,
|
|
onPatternBlur: this.onTriggerInputBlur,
|
|
onPatternFocus: this.onTriggerInputFocus,
|
|
onResize: this.handleTriggerOrMenuResize,
|
|
ignoreComposition: this.ignoreComposition
|
|
}, {
|
|
arrow: () => {
|
|
var _a, _b;
|
|
return [(_b = (_a = this.$slots).arrow) === null || _b === void 0 ? void 0 : _b.call(_a)];
|
|
}
|
|
})
|
|
}), h(VFollower, {
|
|
ref: "followerRef",
|
|
show: this.mergedShow,
|
|
to: this.adjustedTo,
|
|
teleportDisabled: this.adjustedTo === useAdjustedTo.tdkey,
|
|
containerClass: this.namespace,
|
|
width: this.consistentMenuWidth ? 'target' : undefined,
|
|
minWidth: "target",
|
|
placement: this.placement
|
|
}, {
|
|
default: () => h(Transition, {
|
|
name: "fade-in-scale-up-transition",
|
|
appear: this.isMounted,
|
|
onAfterLeave: this.handleMenuAfterLeave
|
|
}, {
|
|
default: () => {
|
|
var _a, _b, _c;
|
|
if (!(this.mergedShow || this.displayDirective === 'show')) {
|
|
return null;
|
|
}
|
|
(_a = this.onRender) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
return withDirectives(h(NInternalSelectMenu, Object.assign({}, this.menuProps, {
|
|
ref: "menuRef",
|
|
onResize: this.handleTriggerOrMenuResize,
|
|
inlineThemeDisabled: this.inlineThemeDisabled,
|
|
virtualScroll: this.consistentMenuWidth && this.virtualScroll,
|
|
class: [`${this.mergedClsPrefix}-select-menu`, this.themeClass, (_b = this.menuProps) === null || _b === void 0 ? void 0 : _b.class],
|
|
clsPrefix: this.mergedClsPrefix,
|
|
focusable: true,
|
|
labelField: this.labelField,
|
|
valueField: this.valueField,
|
|
autoPending: true,
|
|
nodeProps: this.nodeProps,
|
|
theme: this.mergedTheme.peers.InternalSelectMenu,
|
|
themeOverrides: this.mergedTheme.peerOverrides.InternalSelectMenu,
|
|
treeMate: this.treeMate,
|
|
multiple: this.multiple,
|
|
size: "medium",
|
|
renderOption: this.renderOption,
|
|
renderLabel: this.renderLabel,
|
|
value: this.mergedValue,
|
|
style: [(_c = this.menuProps) === null || _c === void 0 ? void 0 : _c.style, this.cssVars],
|
|
onToggle: this.handleToggle,
|
|
onScroll: this.handleMenuScroll,
|
|
onFocus: this.handleMenuFocus,
|
|
onBlur: this.handleMenuBlur,
|
|
onKeydown: this.handleMenuKeydown,
|
|
onTabOut: this.handleMenuTabOut,
|
|
onMousedown: this.handleMenuMousedown,
|
|
show: this.mergedShow,
|
|
showCheckmark: this.showCheckmark,
|
|
resetMenuOnOptionsChange: this.resetMenuOnOptionsChange
|
|
}), {
|
|
empty: () => {
|
|
var _a, _b;
|
|
return [(_b = (_a = this.$slots).empty) === null || _b === void 0 ? void 0 : _b.call(_a)];
|
|
},
|
|
header: () => {
|
|
var _a, _b;
|
|
return [(_b = (_a = this.$slots).header) === null || _b === void 0 ? void 0 : _b.call(_a)];
|
|
},
|
|
action: () => {
|
|
var _a, _b;
|
|
return [(_b = (_a = this.$slots).action) === null || _b === void 0 ? void 0 : _b.call(_a)];
|
|
}
|
|
}), this.displayDirective === 'show' ? [[vShow, this.mergedShow], [clickoutside, this.handleMenuClickOutside, undefined, {
|
|
capture: true
|
|
}]] : [[clickoutside, this.handleMenuClickOutside, undefined, {
|
|
capture: true
|
|
}]]);
|
|
}
|
|
})
|
|
})]
|
|
}));
|
|
}
|
|
}); |