UNPKG

ant-design-vue

Version:

An enterprise-class UI design language and Vue-based implementation

446 lines (388 loc) 14.6 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray"; import { createVNode as _createVNode } from "vue"; var __rest = this && this.__rest || function (s, e) { var t = {}; for (var p in s) { if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; } if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import { getComponent, getSlot } from '../_util/props-util'; import PropTypes from '../_util/vue-types'; import Trigger from '../vc-trigger'; import Menus from './Menus'; import KeyCode from '../_util/KeyCode'; import arrayTreeFilter from 'array-tree-filter'; import shallowEqualArrays from 'shallow-equal/arrays'; import { hasProp, getEvents } from '../_util/props-util'; import BaseMixin from '../_util/BaseMixin'; import { cloneElement } from '../_util/vnode'; import { defineComponent } from 'vue'; import isEqual from 'lodash-es/isEqual'; var BUILT_IN_PLACEMENTS = { bottomLeft: { points: ['tl', 'bl'], offset: [0, 4], overflow: { adjustX: 1, adjustY: 1 } }, topLeft: { points: ['bl', 'tl'], offset: [0, -4], overflow: { adjustX: 1, adjustY: 1 } }, bottomRight: { points: ['tr', 'br'], offset: [0, 4], overflow: { adjustX: 1, adjustY: 1 } }, topRight: { points: ['br', 'tr'], offset: [0, -4], overflow: { adjustX: 1, adjustY: 1 } } }; export default defineComponent({ name: 'Cascader', mixins: [BaseMixin], inheritAttrs: false, // model: { // prop: 'value', // event: 'change', // }, props: { value: PropTypes.array, defaultValue: PropTypes.array, options: PropTypes.array, // onChange: PropTypes.func, // onPopupVisibleChange: PropTypes.func, popupVisible: PropTypes.looseBool, disabled: PropTypes.looseBool.def(false), transitionName: PropTypes.string.def(''), popupClassName: PropTypes.string.def(''), popupStyle: PropTypes.object.def(function () { return {}; }), popupPlacement: PropTypes.string.def('bottomLeft'), prefixCls: PropTypes.string.def('rc-cascader'), dropdownMenuColumnStyle: PropTypes.object, builtinPlacements: PropTypes.object.def(BUILT_IN_PLACEMENTS), loadData: PropTypes.func, changeOnSelect: PropTypes.looseBool, // onKeyDown: PropTypes.func, expandTrigger: PropTypes.string.def('click'), fieldNames: PropTypes.object.def(function () { return { label: 'label', value: 'value', children: 'children' }; }), expandIcon: PropTypes.any, loadingIcon: PropTypes.any, getPopupContainer: PropTypes.func }, data: function data() { var initialValue = []; var value = this.value, defaultValue = this.defaultValue, popupVisible = this.popupVisible; if (hasProp(this, 'value')) { initialValue = value || []; } else if (hasProp(this, 'defaultValue')) { initialValue = defaultValue || []; } this.children = undefined; // warning(!('filedNames' in props), // '`filedNames` of Cascader is a typo usage and deprecated, please use `fieldNames` instead.'); this.defaultFieldNames = { label: 'label', value: 'value', children: 'children' }; return { sPopupVisible: popupVisible, sActiveValue: initialValue, sValue: initialValue }; }, watch: { value: function value(val, oldValue) { if (!shallowEqualArrays(val, oldValue)) { var newValues = { sValue: val || [] }; // allow activeValue diff from value // https://github.com/ant-design/ant-design/issues/2767 if (!hasProp(this, 'loadData')) { newValues.sActiveValue = val || []; } this.setState(newValues); } }, popupVisible: function popupVisible(val) { this.setState({ sPopupVisible: val }); } }, methods: { getPopupDOMNode: function getPopupDOMNode() { return this.trigger.getPopupDomNode(); }, getFieldName: function getFieldName(name) { var defaultFieldNames = this.defaultFieldNames, fieldNames = this.fieldNames; return fieldNames[name] || defaultFieldNames[name]; }, getFieldNames: function getFieldNames() { return this.fieldNames; }, getCurrentLevelOptions: function getCurrentLevelOptions() { var _this = this; var _this$options = this.options, options = _this$options === void 0 ? [] : _this$options, _this$sActiveValue = this.sActiveValue, sActiveValue = _this$sActiveValue === void 0 ? [] : _this$sActiveValue; var result = arrayTreeFilter(options, function (o, level) { return isEqual(o[_this.getFieldName('value')], sActiveValue[level]); }, { childrenKeyName: this.getFieldName('children') }); if (result[result.length - 2]) { return result[result.length - 2][this.getFieldName('children')]; } return _toConsumableArray(options).filter(function (o) { return !o.disabled; }); }, getActiveOptions: function getActiveOptions(activeValue) { var _this2 = this; return arrayTreeFilter(this.options || [], function (o, level) { return isEqual(o[_this2.getFieldName('value')], activeValue[level]); }, { childrenKeyName: this.getFieldName('children') }); }, setPopupVisible: function setPopupVisible(popupVisible) { if (!hasProp(this, 'popupVisible')) { this.setState({ sPopupVisible: popupVisible }); } // sync activeValue with value when panel open if (popupVisible && !this.sPopupVisible) { this.setState({ sActiveValue: this.sValue }); } this.__emit('popupVisibleChange', popupVisible); }, handleChange: function handleChange(options, setProps, e) { var _this3 = this; if (e.type !== 'keydown' || e.keyCode === KeyCode.ENTER) { var value = options.map(function (o) { return o[_this3.getFieldName('value')]; }); this.__emit('change', value, options); this.setPopupVisible(setProps.visible); } }, handlePopupVisibleChange: function handlePopupVisibleChange(popupVisible) { this.setPopupVisible(popupVisible); }, handleMenuSelect: function handleMenuSelect(targetOption, menuIndex, e) { // Keep focused state for keyboard support var triggerNode = this.trigger.getRootDomNode(); if (triggerNode && triggerNode.focus) { triggerNode.focus(); } var changeOnSelect = this.changeOnSelect, loadData = this.loadData, expandTrigger = this.expandTrigger; if (!targetOption || targetOption.disabled) { return; } var sActiveValue = this.sActiveValue; sActiveValue = sActiveValue.slice(0, menuIndex + 1); sActiveValue[menuIndex] = targetOption[this.getFieldName('value')]; var activeOptions = this.getActiveOptions(sActiveValue); if (targetOption.isLeaf === false && !targetOption[this.getFieldName('children')] && loadData) { if (changeOnSelect) { this.handleChange(activeOptions, { visible: true }, e); } this.setState({ sActiveValue: sActiveValue }); loadData(activeOptions); return; } var newState = {}; if (!targetOption[this.getFieldName('children')] || !targetOption[this.getFieldName('children')].length) { this.handleChange(activeOptions, { visible: false }, e); // set value to activeValue when select leaf option newState.sValue = sActiveValue; // add e.type judgement to prevent `onChange` being triggered by mouseEnter } else if (changeOnSelect && (e.type === 'click' || e.type === 'keydown')) { if (expandTrigger === 'hover') { this.handleChange(activeOptions, { visible: false }, e); } else { this.handleChange(activeOptions, { visible: true }, e); } // set value to activeValue on every select newState.sValue = sActiveValue; } newState.sActiveValue = sActiveValue; // not change the value by keyboard if (hasProp(this, 'value') || e.type === 'keydown' && e.keyCode !== KeyCode.ENTER) { delete newState.sValue; } this.setState(newState); }, handleItemDoubleClick: function handleItemDoubleClick() { var changeOnSelect = this.$props.changeOnSelect; if (changeOnSelect) { this.setPopupVisible(false); } }, handleKeyDown: function handleKeyDown(e) { var _this4 = this; var children = this.children; // https://github.com/ant-design/ant-design/issues/6717 // Don't bind keyboard support when children specify the onKeyDown if (children) { var keydown = getEvents(children).onKeydown; if (keydown) { keydown(e); return; } } var activeValue = _toConsumableArray(this.sActiveValue); var currentLevel = activeValue.length - 1 < 0 ? 0 : activeValue.length - 1; var currentOptions = this.getCurrentLevelOptions(); var currentIndex = currentOptions.map(function (o) { return o[_this4.getFieldName('value')]; }).findIndex(function (val) { return isEqual(activeValue[currentLevel], val); }); if (e.keyCode !== KeyCode.DOWN && e.keyCode !== KeyCode.UP && e.keyCode !== KeyCode.LEFT && e.keyCode !== KeyCode.RIGHT && e.keyCode !== KeyCode.ENTER && e.keyCode !== KeyCode.SPACE && e.keyCode !== KeyCode.BACKSPACE && e.keyCode !== KeyCode.ESC && e.keyCode !== KeyCode.TAB) { return; } // Press any keys above to reopen menu if (!this.sPopupVisible && e.keyCode !== KeyCode.BACKSPACE && e.keyCode !== KeyCode.LEFT && e.keyCode !== KeyCode.RIGHT && e.keyCode !== KeyCode.ESC && e.keyCode !== KeyCode.TAB) { this.setPopupVisible(true); return; } if (e.keyCode === KeyCode.DOWN || e.keyCode === KeyCode.UP) { e.preventDefault(); var nextIndex = currentIndex; if (nextIndex !== -1) { if (e.keyCode === KeyCode.DOWN) { nextIndex += 1; nextIndex = nextIndex >= currentOptions.length ? 0 : nextIndex; } else { nextIndex -= 1; nextIndex = nextIndex < 0 ? currentOptions.length - 1 : nextIndex; } } else { nextIndex = 0; } activeValue[currentLevel] = currentOptions[nextIndex][this.getFieldName('value')]; } else if (e.keyCode === KeyCode.LEFT || e.keyCode === KeyCode.BACKSPACE) { e.preventDefault(); activeValue.splice(activeValue.length - 1, 1); } else if (e.keyCode === KeyCode.RIGHT) { e.preventDefault(); if (currentOptions[currentIndex] && currentOptions[currentIndex][this.getFieldName('children')]) { activeValue.push(currentOptions[currentIndex][this.getFieldName('children')][0][this.getFieldName('value')]); } } else if (e.keyCode === KeyCode.ESC || e.keyCode === KeyCode.TAB) { this.setPopupVisible(false); return; } if (!activeValue || activeValue.length === 0) { this.setPopupVisible(false); } var activeOptions = this.getActiveOptions(activeValue); var targetOption = activeOptions[activeOptions.length - 1]; this.handleMenuSelect(targetOption, activeOptions.length - 1, e); this.__emit('keydown', e); }, saveTrigger: function saveTrigger(node) { this.trigger = node; } }, render: function render() { var $props = this.$props, sActiveValue = this.sActiveValue, handleMenuSelect = this.handleMenuSelect, sPopupVisible = this.sPopupVisible, handlePopupVisibleChange = this.handlePopupVisibleChange, handleKeyDown = this.handleKeyDown; var prefixCls = $props.prefixCls, transitionName = $props.transitionName, popupClassName = $props.popupClassName, _$props$options = $props.options, options = _$props$options === void 0 ? [] : _$props$options, disabled = $props.disabled, builtinPlacements = $props.builtinPlacements, popupPlacement = $props.popupPlacement, restProps = __rest($props, ["prefixCls", "transitionName", "popupClassName", "options", "disabled", "builtinPlacements", "popupPlacement"]); // Did not show popup when there is no options var menus = _createVNode("div", null, null); var emptyMenuClassName = ''; if (options && options.length > 0) { var loadingIcon = getComponent(this, 'loadingIcon'); var expandIcon = getComponent(this, 'expandIcon') || '>'; var menusProps = _extends(_extends(_extends({}, $props), this.$attrs), { fieldNames: this.getFieldNames(), defaultFieldNames: this.defaultFieldNames, activeValue: sActiveValue, visible: sPopupVisible, loadingIcon: loadingIcon, expandIcon: expandIcon, onSelect: handleMenuSelect, onItemDoubleClick: this.handleItemDoubleClick }); menus = _createVNode(Menus, menusProps, null); } else { emptyMenuClassName = " ".concat(prefixCls, "-menus-empty"); } var triggerProps = _extends(_extends(_extends({}, restProps), this.$attrs), { disabled: disabled, popupPlacement: popupPlacement, builtinPlacements: builtinPlacements, popupTransitionName: transitionName, action: disabled ? [] : ['click'], popupVisible: disabled ? false : sPopupVisible, prefixCls: "".concat(prefixCls, "-menus"), popupClassName: popupClassName + emptyMenuClassName, popup: menus, onPopupVisibleChange: handlePopupVisibleChange, ref: this.saveTrigger }); var children = getSlot(this); this.children = children; return _createVNode(Trigger, triggerProps, { default: function _default() { return [children && cloneElement(children[0], { onKeydown: handleKeyDown, tabindex: disabled ? undefined : 0 })]; } }); } });