ant-design-vue
Version:
An enterprise-class UI design language and Vue-based implementation
433 lines • 18.2 kB
JavaScript
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import { createVNode as _createVNode, resolveDirective as _resolveDirective } from "vue";
import { computed, defineComponent, ref, toRef, toRefs, watchEffect } from 'vue';
import { baseSelectPropsWithoutPrivate } from '../vc-select/BaseSelect';
import omit from '../_util/omit';
import PropTypes from '../_util/vue-types';
import { initDefaultProps } from '../_util/props-util';
import useId from '../vc-select/hooks/useId';
import useMergedState from '../_util/hooks/useMergedState';
import { fillFieldNames, toPathKey, toPathKeys, SHOW_PARENT, SHOW_CHILD } from './utils/commonUtil';
import useEntities from './hooks/useEntities';
import useSearchConfig from './hooks/useSearchConfig';
import useSearchOptions from './hooks/useSearchOptions';
import useMissingValues from './hooks/useMissingValues';
import { formatStrategyValues, toPathOptions } from './utils/treeUtil';
import { conductCheck } from '../vc-tree/utils/conductUtil';
import useDisplayValues from './hooks/useDisplayValues';
import { useProvideCascader } from './context';
import OptionList from './OptionList';
import { BaseSelect } from '../vc-select';
import devWarning from '../vc-util/devWarning';
import useMaxLevel from '../vc-tree/useMaxLevel';
export { SHOW_PARENT, SHOW_CHILD };
function baseCascaderProps() {
return _objectSpread(_objectSpread({}, omit(baseSelectPropsWithoutPrivate(), ['tokenSeparators', 'mode', 'showSearch'])), {}, {
// MISC
id: String,
prefixCls: String,
fieldNames: Object,
children: Array,
// Value
value: {
type: [String, Number, Array]
},
defaultValue: {
type: [String, Number, Array]
},
changeOnSelect: {
type: Boolean,
default: undefined
},
displayRender: Function,
checkable: {
type: Boolean,
default: undefined
},
showCheckedStrategy: {
type: String,
default: SHOW_PARENT
},
// Search
showSearch: {
type: [Boolean, Object],
default: undefined
},
searchValue: String,
onSearch: Function,
// Trigger
expandTrigger: String,
// Options
options: Array,
/** @private Internal usage. Do not use in your production. */
dropdownPrefixCls: String,
loadData: Function,
// Open
/** @deprecated Use `open` instead */
popupVisible: {
type: Boolean,
default: undefined
},
/** @deprecated Use `dropdownClassName` instead */
popupClassName: String,
dropdownClassName: String,
dropdownMenuColumnStyle: {
type: Object,
default: undefined
},
/** @deprecated Use `dropdownStyle` instead */
popupStyle: {
type: Object,
default: undefined
},
dropdownStyle: {
type: Object,
default: undefined
},
/** @deprecated Use `placement` instead */
popupPlacement: String,
placement: String,
/** @deprecated Use `onDropdownVisibleChange` instead */
onPopupVisibleChange: Function,
onDropdownVisibleChange: Function,
// Icon
expandIcon: PropTypes.any,
loadingIcon: PropTypes.any
});
}
export function singleCascaderProps() {
return _objectSpread(_objectSpread({}, baseCascaderProps()), {}, {
checkable: Boolean,
onChange: Function
});
}
export function multipleCascaderProps() {
return _objectSpread(_objectSpread({}, baseCascaderProps()), {}, {
checkable: Boolean,
onChange: Function
});
}
export function internalCascaderProps() {
return _objectSpread(_objectSpread({}, baseCascaderProps()), {}, {
onChange: Function,
customSlots: Object
});
}
function isMultipleValue(value) {
return Array.isArray(value) && Array.isArray(value[0]);
}
function toRawValues(value) {
if (!value) {
return [];
}
if (isMultipleValue(value)) {
return value;
}
return (value.length === 0 ? [] : [value]).map(function (val) {
return Array.isArray(val) ? val : [val];
});
}
export default defineComponent({
compatConfig: {
MODE: 3
},
name: 'Cascader',
inheritAttrs: false,
props: initDefaultProps(internalCascaderProps(), {}),
setup: function setup(props, _ref) {
var attrs = _ref.attrs,
expose = _ref.expose,
slots = _ref.slots;
var mergedId = useId(toRef(props, 'id'));
var multiple = computed(function () {
return !!props.checkable;
});
// =========================== Values ===========================
var _useMergedState = useMergedState(props.defaultValue, {
value: computed(function () {
return props.value;
}),
postState: toRawValues
}),
_useMergedState2 = _slicedToArray(_useMergedState, 2),
rawValues = _useMergedState2[0],
setRawValues = _useMergedState2[1];
// ========================= FieldNames =========================
var mergedFieldNames = computed(function () {
return fillFieldNames(props.fieldNames);
});
// =========================== Option ===========================
var mergedOptions = computed(function () {
return props.options || [];
});
// Only used in multiple mode, this fn will not call in single mode
var pathKeyEntities = useEntities(mergedOptions, mergedFieldNames);
/** Convert path key back to value format */
var getValueByKeyPath = function getValueByKeyPath(pathKeys) {
var keyPathEntities = pathKeyEntities.value;
return pathKeys.map(function (pathKey) {
var nodes = keyPathEntities[pathKey].nodes;
return nodes.map(function (node) {
return node[mergedFieldNames.value.value];
});
});
};
// =========================== Search ===========================
var _useMergedState3 = useMergedState('', {
value: computed(function () {
return props.searchValue;
}),
postState: function postState(search) {
return search || '';
}
}),
_useMergedState4 = _slicedToArray(_useMergedState3, 2),
mergedSearchValue = _useMergedState4[0],
setSearchValue = _useMergedState4[1];
var onInternalSearch = function onInternalSearch(searchText, info) {
setSearchValue(searchText);
if (info.source !== 'blur' && props.onSearch) {
props.onSearch(searchText);
}
};
var _useSearchConfig = useSearchConfig(toRef(props, 'showSearch')),
mergedShowSearch = _useSearchConfig.showSearch,
mergedSearchConfig = _useSearchConfig.searchConfig;
var searchOptions = useSearchOptions(mergedSearchValue, mergedOptions, mergedFieldNames, computed(function () {
return props.dropdownPrefixCls || props.prefixCls;
}), mergedSearchConfig, toRef(props, 'changeOnSelect'));
// =========================== Values ===========================
var missingValuesInfo = useMissingValues(mergedOptions, mergedFieldNames, rawValues);
// Fill `rawValues` with checked conduction values
var _ref2 = [ref([]), ref([]), ref([])],
checkedValues = _ref2[0],
halfCheckedValues = _ref2[1],
missingCheckedValues = _ref2[2];
var _useMaxLevel = useMaxLevel(pathKeyEntities),
maxLevel = _useMaxLevel.maxLevel,
levelEntities = _useMaxLevel.levelEntities;
watchEffect(function () {
var _missingValuesInfo$va = _slicedToArray(missingValuesInfo.value, 2),
existValues = _missingValuesInfo$va[0],
missingValues = _missingValuesInfo$va[1];
if (!multiple.value || !rawValues.value.length) {
var _ref3 = [existValues, [], missingValues];
checkedValues.value = _ref3[0];
halfCheckedValues.value = _ref3[1];
missingCheckedValues.value = _ref3[2];
return;
}
var keyPathValues = toPathKeys(existValues);
var keyPathEntities = pathKeyEntities.value;
var _conductCheck = conductCheck(keyPathValues, true, keyPathEntities, maxLevel.value, levelEntities.value),
checkedKeys = _conductCheck.checkedKeys,
halfCheckedKeys = _conductCheck.halfCheckedKeys;
// Convert key back to value cells
var _ref4 = [getValueByKeyPath(checkedKeys), getValueByKeyPath(halfCheckedKeys), missingValues];
checkedValues.value = _ref4[0];
halfCheckedValues.value = _ref4[1];
missingCheckedValues.value = _ref4[2];
});
var deDuplicatedValues = computed(function () {
var checkedKeys = toPathKeys(checkedValues.value);
var deduplicateKeys = formatStrategyValues(checkedKeys, pathKeyEntities.value, props.showCheckedStrategy);
return [].concat(_toConsumableArray(missingCheckedValues.value), _toConsumableArray(getValueByKeyPath(deduplicateKeys)));
});
var displayValues = useDisplayValues(deDuplicatedValues, mergedOptions, mergedFieldNames, multiple, toRef(props, 'displayRender'));
// =========================== Change ===========================
var triggerChange = function triggerChange(nextValues) {
setRawValues(nextValues);
// Save perf if no need trigger event
if (props.onChange) {
var nextRawValues = toRawValues(nextValues);
var valueOptions = nextRawValues.map(function (valueCells) {
return toPathOptions(valueCells, mergedOptions.value, mergedFieldNames.value).map(function (valueOpt) {
return valueOpt.option;
});
});
var triggerValues = multiple.value ? nextRawValues : nextRawValues[0];
var triggerOptions = multiple.value ? valueOptions : valueOptions[0];
props.onChange(triggerValues, triggerOptions);
}
};
// =========================== Select ===========================
var onInternalSelect = function onInternalSelect(valuePath) {
setSearchValue('');
if (!multiple.value) {
triggerChange(valuePath);
} else {
// Prepare conduct required info
var pathKey = toPathKey(valuePath);
var checkedPathKeys = toPathKeys(checkedValues.value);
var halfCheckedPathKeys = toPathKeys(halfCheckedValues.value);
var existInChecked = checkedPathKeys.includes(pathKey);
var existInMissing = missingCheckedValues.value.some(function (valueCells) {
return toPathKey(valueCells) === pathKey;
});
// Do update
var nextCheckedValues = checkedValues.value;
var nextMissingValues = missingCheckedValues.value;
if (existInMissing && !existInChecked) {
// Missing value only do filter
nextMissingValues = missingCheckedValues.value.filter(function (valueCells) {
return toPathKey(valueCells) !== pathKey;
});
} else {
// Update checked key first
var nextRawCheckedKeys = existInChecked ? checkedPathKeys.filter(function (key) {
return key !== pathKey;
}) : [].concat(_toConsumableArray(checkedPathKeys), [pathKey]);
// Conduction by selected or not
var checkedKeys;
if (existInChecked) {
var _conductCheck2 = conductCheck(nextRawCheckedKeys, {
checked: false,
halfCheckedKeys: halfCheckedPathKeys
}, pathKeyEntities.value, maxLevel.value, levelEntities.value);
checkedKeys = _conductCheck2.checkedKeys;
} else {
var _conductCheck3 = conductCheck(nextRawCheckedKeys, true, pathKeyEntities.value, maxLevel.value, levelEntities.value);
checkedKeys = _conductCheck3.checkedKeys;
}
// Roll up to parent level keys
var deDuplicatedKeys = formatStrategyValues(checkedKeys, pathKeyEntities.value, props.showCheckedStrategy);
nextCheckedValues = getValueByKeyPath(deDuplicatedKeys);
}
triggerChange([].concat(_toConsumableArray(nextMissingValues), _toConsumableArray(nextCheckedValues)));
}
};
// Display Value change logic
var onDisplayValuesChange = function onDisplayValuesChange(_, info) {
if (info.type === 'clear') {
triggerChange([]);
return;
}
// Cascader do not support `add` type. Only support `remove`
var valueCells = info.values[0].valueCells;
onInternalSelect(valueCells);
};
// ============================ Open ============================
if (process.env.NODE_ENV !== 'production') {
watchEffect(function () {
devWarning(!props.onPopupVisibleChange, 'Cascader', '`popupVisibleChange` is deprecated. Please use `dropdownVisibleChange` instead.');
devWarning(props.popupVisible === undefined, 'Cascader', '`popupVisible` is deprecated. Please use `open` instead.');
devWarning(props.popupClassName === undefined, 'Cascader', '`popupClassName` is deprecated. Please use `dropdownClassName` instead.');
devWarning(props.popupPlacement === undefined, 'Cascader', '`popupPlacement` is deprecated. Please use `placement` instead.');
devWarning(props.popupStyle === undefined, 'Cascader', '`popupStyle` is deprecated. Please use `dropdownStyle` instead.');
});
}
var mergedOpen = computed(function () {
return props.open !== undefined ? props.open : props.popupVisible;
});
var mergedDropdownClassName = computed(function () {
return props.dropdownClassName || props.popupClassName;
});
var mergedDropdownStyle = computed(function () {
return props.dropdownStyle || props.popupStyle || {};
});
var mergedPlacement = computed(function () {
return props.placement || props.popupPlacement;
});
var onInternalDropdownVisibleChange = function onInternalDropdownVisibleChange(nextVisible) {
var _props$onDropdownVisi, _props$onPopupVisible;
(_props$onDropdownVisi = props.onDropdownVisibleChange) === null || _props$onDropdownVisi === void 0 ? void 0 : _props$onDropdownVisi.call(props, nextVisible);
(_props$onPopupVisible = props.onPopupVisibleChange) === null || _props$onPopupVisible === void 0 ? void 0 : _props$onPopupVisible.call(props, nextVisible);
};
var _toRefs = toRefs(props),
changeOnSelect = _toRefs.changeOnSelect,
checkable = _toRefs.checkable,
dropdownPrefixCls = _toRefs.dropdownPrefixCls,
loadData = _toRefs.loadData,
expandTrigger = _toRefs.expandTrigger,
expandIcon = _toRefs.expandIcon,
loadingIcon = _toRefs.loadingIcon,
dropdownMenuColumnStyle = _toRefs.dropdownMenuColumnStyle,
customSlots = _toRefs.customSlots;
useProvideCascader({
options: mergedOptions,
fieldNames: mergedFieldNames,
values: checkedValues,
halfValues: halfCheckedValues,
changeOnSelect: changeOnSelect,
onSelect: onInternalSelect,
checkable: checkable,
searchOptions: searchOptions,
dropdownPrefixCls: dropdownPrefixCls,
loadData: loadData,
expandTrigger: expandTrigger,
expandIcon: expandIcon,
loadingIcon: loadingIcon,
dropdownMenuColumnStyle: dropdownMenuColumnStyle,
customSlots: customSlots
});
var selectRef = ref();
expose({
focus: function focus() {
var _selectRef$value;
(_selectRef$value = selectRef.value) === null || _selectRef$value === void 0 ? void 0 : _selectRef$value.focus();
},
blur: function blur() {
var _selectRef$value2;
(_selectRef$value2 = selectRef.value) === null || _selectRef$value2 === void 0 ? void 0 : _selectRef$value2.blur();
},
scrollTo: function scrollTo(arg) {
var _selectRef$value3;
(_selectRef$value3 = selectRef.value) === null || _selectRef$value3 === void 0 ? void 0 : _selectRef$value3.scrollTo(arg);
}
});
var pickProps = computed(function () {
return omit(props, ['id', 'prefixCls', 'fieldNames',
// Value
'defaultValue', 'value', 'changeOnSelect', 'onChange', 'displayRender', 'checkable',
// Search
'searchValue', 'onSearch', 'showSearch',
// Trigger
'expandTrigger',
// Options
'options', 'dropdownPrefixCls', 'loadData',
// Open
'popupVisible', 'open', 'popupClassName', 'dropdownClassName', 'dropdownMenuColumnStyle', 'popupPlacement', 'placement', 'onDropdownVisibleChange', 'onPopupVisibleChange',
// Icon
'expandIcon', 'loadingIcon', 'customSlots', 'showCheckedStrategy',
// Children
'children']);
});
return function () {
var emptyOptions = !(mergedSearchValue.value ? searchOptions.value : mergedOptions.value).length;
var _props$dropdownMatchS = props.dropdownMatchSelectWidth,
dropdownMatchSelectWidth = _props$dropdownMatchS === void 0 ? false : _props$dropdownMatchS;
var dropdownStyle =
// Search to match width
mergedSearchValue.value && mergedSearchConfig.value.matchInputWidth ||
// Empty keep the width
emptyOptions ? {} : {
minWidth: 'auto'
};
return _createVNode(BaseSelect, _objectSpread(_objectSpread(_objectSpread({}, pickProps.value), attrs), {}, {
"ref": selectRef,
"id": mergedId,
"prefixCls": props.prefixCls,
"dropdownMatchSelectWidth": dropdownMatchSelectWidth,
"dropdownStyle": _objectSpread(_objectSpread({}, mergedDropdownStyle.value), dropdownStyle),
"displayValues": displayValues.value,
"onDisplayValuesChange": onDisplayValuesChange,
"mode": multiple.value ? 'multiple' : undefined,
"searchValue": mergedSearchValue.value,
"onSearch": onInternalSearch,
"showSearch": mergedShowSearch.value,
"OptionList": OptionList,
"emptyOptions": emptyOptions,
"open": mergedOpen.value,
"dropdownClassName": mergedDropdownClassName.value,
"placement": mergedPlacement.value,
"onDropdownVisibleChange": onInternalDropdownVisibleChange,
"getRawInputElement": function getRawInputElement() {
var _slots$default;
return (_slots$default = slots.default) === null || _slots$default === void 0 ? void 0 : _slots$default.call(slots);
}
}), slots);
};
}
});