index.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. import _extends from 'babel-runtime/helpers/extends';
  2. import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
  3. import _defineProperty from 'babel-runtime/helpers/defineProperty';
  4. import PropTypes from '../_util/vue-types';
  5. import VcCascader from '../vc-cascader';
  6. import arrayTreeFilter from 'array-tree-filter';
  7. import classNames from 'classnames';
  8. import omit from 'omit.js';
  9. import KeyCode from '../_util/KeyCode';
  10. import Input from '../input';
  11. import Icon from '../icon';
  12. import { hasProp, filterEmpty, getOptionProps, getStyle, getClass, getAttrs, getComponentFromProp, isValidElement, getListeners } from '../_util/props-util';
  13. import BaseMixin from '../_util/BaseMixin';
  14. import { cloneElement } from '../_util/vnode';
  15. import warning from '../_util/warning';
  16. import { ConfigConsumerProps } from '../config-provider/configConsumerProps';
  17. import Base from '../base';
  18. var CascaderOptionType = PropTypes.shape({
  19. value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  20. label: PropTypes.any,
  21. disabled: PropTypes.bool,
  22. children: PropTypes.array,
  23. key: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
  24. }).loose;
  25. var FieldNamesType = PropTypes.shape({
  26. value: PropTypes.string.isRequired,
  27. label: PropTypes.string.isRequired,
  28. children: PropTypes.string
  29. }).loose;
  30. var CascaderExpandTrigger = PropTypes.oneOf(['click', 'hover']);
  31. var ShowSearchType = PropTypes.shape({
  32. filter: PropTypes.func,
  33. render: PropTypes.func,
  34. sort: PropTypes.func,
  35. matchInputWidth: PropTypes.bool,
  36. limit: PropTypes.oneOfType([Boolean, Number])
  37. }).loose;
  38. function noop() {}
  39. var CascaderProps = {
  40. /** 可选项数据源 */
  41. options: PropTypes.arrayOf(CascaderOptionType).def([]),
  42. /** 默认的选中项 */
  43. defaultValue: PropTypes.array,
  44. /** 指定选中项 */
  45. value: PropTypes.array,
  46. /** 选择完成后的回调 */
  47. // onChange?: (value: string[], selectedOptions?: CascaderOptionType[]) => void;
  48. /** 选择后展示的渲染函数 */
  49. displayRender: PropTypes.func,
  50. transitionName: PropTypes.string.def('slide-up'),
  51. popupStyle: PropTypes.object.def(function () {
  52. return {};
  53. }),
  54. /** 自定义浮层类名 */
  55. popupClassName: PropTypes.string,
  56. /** 浮层预设位置:`bottomLeft` `bottomRight` `topLeft` `topRight` */
  57. popupPlacement: PropTypes.oneOf(['bottomLeft', 'bottomRight', 'topLeft', 'topRight']).def('bottomLeft'),
  58. /** 输入框占位文本*/
  59. placeholder: PropTypes.string.def('Please select'),
  60. /** 输入框大小,可选 `large` `default` `small` */
  61. size: PropTypes.oneOf(['large', 'default', 'small']),
  62. /** 禁用*/
  63. disabled: PropTypes.bool.def(false),
  64. /** 是否支持清除*/
  65. allowClear: PropTypes.bool.def(true),
  66. showSearch: PropTypes.oneOfType([Boolean, ShowSearchType]),
  67. notFoundContent: PropTypes.any,
  68. loadData: PropTypes.func,
  69. /** 次级菜单的展开方式,可选 'click' 和 'hover' */
  70. expandTrigger: CascaderExpandTrigger,
  71. /** 当此项为 true 时,点选每级菜单选项值都会发生变化 */
  72. changeOnSelect: PropTypes.bool,
  73. /** 浮层可见变化时回调 */
  74. // onPopupVisibleChange?: (popupVisible: boolean) => void;
  75. prefixCls: PropTypes.string,
  76. inputPrefixCls: PropTypes.string,
  77. getPopupContainer: PropTypes.func,
  78. popupVisible: PropTypes.bool,
  79. fieldNames: FieldNamesType,
  80. autoFocus: PropTypes.bool,
  81. suffixIcon: PropTypes.any
  82. };
  83. // We limit the filtered item count by default
  84. var defaultLimit = 50;
  85. function defaultFilterOption(inputValue, path, names) {
  86. return path.some(function (option) {
  87. return option[names.label].indexOf(inputValue) > -1;
  88. });
  89. }
  90. function defaultSortFilteredOption(a, b, inputValue, names) {
  91. function callback(elem) {
  92. return elem[names.label].indexOf(inputValue) > -1;
  93. }
  94. return a.findIndex(callback) - b.findIndex(callback);
  95. }
  96. function getFilledFieldNames(_ref) {
  97. var _ref$fieldNames = _ref.fieldNames,
  98. fieldNames = _ref$fieldNames === undefined ? {} : _ref$fieldNames;
  99. var names = {
  100. children: fieldNames.children || 'children',
  101. label: fieldNames.label || 'label',
  102. value: fieldNames.value || 'value'
  103. };
  104. return names;
  105. }
  106. function flattenTree() {
  107. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  108. var props = arguments[1];
  109. var ancestor = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
  110. var names = getFilledFieldNames(props);
  111. var flattenOptions = [];
  112. var childrenName = names.children;
  113. options.forEach(function (option) {
  114. var path = ancestor.concat(option);
  115. if (props.changeOnSelect || !option[childrenName] || !option[childrenName].length) {
  116. flattenOptions.push(path);
  117. }
  118. if (option[childrenName]) {
  119. flattenOptions = flattenOptions.concat(flattenTree(option[childrenName], props, path));
  120. }
  121. });
  122. return flattenOptions;
  123. }
  124. var defaultDisplayRender = function defaultDisplayRender(_ref2) {
  125. var labels = _ref2.labels;
  126. return labels.join(' / ');
  127. };
  128. var Cascader = {
  129. inheritAttrs: false,
  130. name: 'ACascader',
  131. mixins: [BaseMixin],
  132. props: CascaderProps,
  133. model: {
  134. prop: 'value',
  135. event: 'change'
  136. },
  137. provide: function provide() {
  138. return {
  139. savePopupRef: this.savePopupRef
  140. };
  141. },
  142. inject: {
  143. configProvider: { 'default': function _default() {
  144. return ConfigConsumerProps;
  145. } },
  146. localeData: { 'default': function _default() {
  147. return {};
  148. } }
  149. },
  150. data: function data() {
  151. this.cachedOptions = [];
  152. var value = this.value,
  153. defaultValue = this.defaultValue,
  154. popupVisible = this.popupVisible,
  155. showSearch = this.showSearch,
  156. options = this.options;
  157. return {
  158. sValue: value || defaultValue || [],
  159. inputValue: '',
  160. inputFocused: false,
  161. sPopupVisible: popupVisible,
  162. flattenOptions: showSearch ? flattenTree(options, this.$props) : undefined
  163. };
  164. },
  165. mounted: function mounted() {
  166. var _this = this;
  167. this.$nextTick(function () {
  168. if (_this.autoFocus && !_this.showSearch && !_this.disabled) {
  169. _this.$refs.picker.focus();
  170. }
  171. });
  172. },
  173. watch: {
  174. value: function value(val) {
  175. this.setState({ sValue: val || [] });
  176. },
  177. popupVisible: function popupVisible(val) {
  178. this.setState({ sPopupVisible: val });
  179. },
  180. options: function options(val) {
  181. if (this.showSearch) {
  182. this.setState({ flattenOptions: flattenTree(val, this.$props) });
  183. }
  184. }
  185. },
  186. methods: {
  187. savePopupRef: function savePopupRef(ref) {
  188. this.popupRef = ref;
  189. },
  190. highlightKeyword: function highlightKeyword(str, keyword, prefixCls) {
  191. var h = this.$createElement;
  192. return str.split(keyword).map(function (node, index) {
  193. return index === 0 ? node : [h(
  194. 'span',
  195. { 'class': prefixCls + '-menu-item-keyword' },
  196. [keyword]
  197. ), node];
  198. });
  199. },
  200. defaultRenderFilteredOption: function defaultRenderFilteredOption(_ref3) {
  201. var _this2 = this;
  202. var inputValue = _ref3.inputValue,
  203. path = _ref3.path,
  204. prefixCls = _ref3.prefixCls,
  205. names = _ref3.names;
  206. return path.map(function (option, index) {
  207. var label = option[names.label];
  208. var node = label.indexOf(inputValue) > -1 ? _this2.highlightKeyword(label, inputValue, prefixCls) : label;
  209. return index === 0 ? node : [' / ', node];
  210. });
  211. },
  212. handleChange: function handleChange(value, selectedOptions) {
  213. this.setState({ inputValue: '' });
  214. if (selectedOptions[0].__IS_FILTERED_OPTION) {
  215. var unwrappedValue = value[0];
  216. var unwrappedSelectedOptions = selectedOptions[0].path;
  217. this.setValue(unwrappedValue, unwrappedSelectedOptions);
  218. return;
  219. }
  220. this.setValue(value, selectedOptions);
  221. },
  222. handlePopupVisibleChange: function handlePopupVisibleChange(popupVisible) {
  223. if (!hasProp(this, 'popupVisible')) {
  224. this.setState(function (state) {
  225. return {
  226. sPopupVisible: popupVisible,
  227. inputFocused: popupVisible,
  228. inputValue: popupVisible ? state.inputValue : ''
  229. };
  230. });
  231. }
  232. this.$emit('popupVisibleChange', popupVisible);
  233. },
  234. handleInputFocus: function handleInputFocus(e) {
  235. this.$emit('focus', e);
  236. },
  237. handleInputBlur: function handleInputBlur(e) {
  238. this.setState({
  239. inputFocused: false
  240. });
  241. this.$emit('blur', e);
  242. },
  243. handleInputClick: function handleInputClick(e) {
  244. var inputFocused = this.inputFocused,
  245. sPopupVisible = this.sPopupVisible;
  246. // Prevent `Trigger` behaviour.
  247. if (inputFocused || sPopupVisible) {
  248. e.stopPropagation();
  249. if (e.nativeEvent && e.nativeEvent.stopImmediatePropagation) {
  250. e.nativeEvent.stopImmediatePropagation();
  251. }
  252. }
  253. },
  254. handleKeyDown: function handleKeyDown(e) {
  255. if (e.keyCode === KeyCode.BACKSPACE || e.keyCode === KeyCode.SPACE) {
  256. e.stopPropagation();
  257. }
  258. },
  259. handleInputChange: function handleInputChange(e) {
  260. var inputValue = e.target.value;
  261. this.setState({ inputValue: inputValue });
  262. this.$emit('search', inputValue);
  263. },
  264. setValue: function setValue(value, selectedOptions) {
  265. if (!hasProp(this, 'value')) {
  266. this.setState({ sValue: value });
  267. }
  268. this.$emit('change', value, selectedOptions);
  269. },
  270. getLabel: function getLabel() {
  271. var options = this.options,
  272. $scopedSlots = this.$scopedSlots;
  273. var names = getFilledFieldNames(this.$props);
  274. var displayRender = this.displayRender || $scopedSlots.displayRender || defaultDisplayRender;
  275. var value = this.sValue;
  276. var unwrappedValue = Array.isArray(value[0]) ? value[0] : value;
  277. var selectedOptions = arrayTreeFilter(options, function (o, level) {
  278. return o[names.value] === unwrappedValue[level];
  279. }, { childrenKeyName: names.children });
  280. var labels = selectedOptions.map(function (o) {
  281. return o[names.label];
  282. });
  283. return displayRender({ labels: labels, selectedOptions: selectedOptions });
  284. },
  285. clearSelection: function clearSelection(e) {
  286. e.preventDefault();
  287. e.stopPropagation();
  288. if (!this.inputValue) {
  289. this.setValue([]);
  290. this.handlePopupVisibleChange(false);
  291. } else {
  292. this.setState({ inputValue: '' });
  293. }
  294. },
  295. generateFilteredOptions: function generateFilteredOptions(prefixCls, renderEmpty) {
  296. var _ref5;
  297. var h = this.$createElement;
  298. var showSearch = this.showSearch,
  299. notFoundContent = this.notFoundContent,
  300. $scopedSlots = this.$scopedSlots;
  301. var names = getFilledFieldNames(this.$props);
  302. var _showSearch$filter = showSearch.filter,
  303. filter = _showSearch$filter === undefined ? defaultFilterOption : _showSearch$filter,
  304. _showSearch$sort = showSearch.sort,
  305. sort = _showSearch$sort === undefined ? defaultSortFilteredOption : _showSearch$sort,
  306. _showSearch$limit = showSearch.limit,
  307. limit = _showSearch$limit === undefined ? defaultLimit : _showSearch$limit;
  308. var render = showSearch.render || $scopedSlots.showSearchRender || this.defaultRenderFilteredOption;
  309. var _$data = this.$data,
  310. _$data$flattenOptions = _$data.flattenOptions,
  311. flattenOptions = _$data$flattenOptions === undefined ? [] : _$data$flattenOptions,
  312. inputValue = _$data.inputValue;
  313. // Limit the filter if needed
  314. var filtered = void 0;
  315. if (limit > 0) {
  316. filtered = [];
  317. var matchCount = 0;
  318. // Perf optimization to filter items only below the limit
  319. flattenOptions.some(function (path) {
  320. var match = filter(inputValue, path, names);
  321. if (match) {
  322. filtered.push(path);
  323. matchCount += 1;
  324. }
  325. return matchCount >= limit;
  326. });
  327. } else {
  328. warning(typeof limit !== 'number', 'Cascader', "'limit' of showSearch in Cascader should be positive number or false.");
  329. filtered = flattenOptions.filter(function (path) {
  330. return filter(inputValue, path, names);
  331. });
  332. }
  333. filtered.sort(function (a, b) {
  334. return sort(a, b, inputValue, names);
  335. });
  336. if (filtered.length > 0) {
  337. return filtered.map(function (path) {
  338. var _ref4;
  339. return _ref4 = {
  340. __IS_FILTERED_OPTION: true,
  341. path: path
  342. }, _defineProperty(_ref4, names.label, render({ inputValue: inputValue, path: path, prefixCls: prefixCls, names: names })), _defineProperty(_ref4, names.value, path.map(function (o) {
  343. return o[names.value];
  344. })), _defineProperty(_ref4, 'disabled', path.some(function (o) {
  345. return !!o.disabled;
  346. })), _ref4;
  347. });
  348. }
  349. return [(_ref5 = {}, _defineProperty(_ref5, names.label, notFoundContent || renderEmpty(h, 'Cascader')), _defineProperty(_ref5, names.value, 'ANT_CASCADER_NOT_FOUND'), _defineProperty(_ref5, 'disabled', true), _ref5)];
  350. },
  351. focus: function focus() {
  352. if (this.showSearch) {
  353. this.$refs.input.focus();
  354. } else {
  355. this.$refs.picker.focus();
  356. }
  357. },
  358. blur: function blur() {
  359. if (this.showSearch) {
  360. this.$refs.input.blur();
  361. } else {
  362. this.$refs.picker.blur();
  363. }
  364. }
  365. },
  366. render: function render() {
  367. var _classNames, _classNames2, _classNames3;
  368. var h = arguments[0];
  369. var $slots = this.$slots,
  370. sPopupVisible = this.sPopupVisible,
  371. inputValue = this.inputValue,
  372. configProvider = this.configProvider,
  373. localeData = this.localeData;
  374. var _$data2 = this.$data,
  375. value = _$data2.sValue,
  376. inputFocused = _$data2.inputFocused;
  377. var props = getOptionProps(this);
  378. var suffixIcon = getComponentFromProp(this, 'suffixIcon');
  379. suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon;
  380. var getContextPopupContainer = configProvider.getPopupContainer;
  381. var customizePrefixCls = props.prefixCls,
  382. customizeInputPrefixCls = props.inputPrefixCls,
  383. _props$placeholder = props.placeholder,
  384. placeholder = _props$placeholder === undefined ? localeData.placeholder : _props$placeholder,
  385. size = props.size,
  386. disabled = props.disabled,
  387. allowClear = props.allowClear,
  388. _props$showSearch = props.showSearch,
  389. showSearch = _props$showSearch === undefined ? false : _props$showSearch,
  390. notFoundContent = props.notFoundContent,
  391. otherProps = _objectWithoutProperties(props, ['prefixCls', 'inputPrefixCls', 'placeholder', 'size', 'disabled', 'allowClear', 'showSearch', 'notFoundContent']);
  392. var getPrefixCls = this.configProvider.getPrefixCls;
  393. var renderEmpty = this.configProvider.renderEmpty;
  394. var prefixCls = getPrefixCls('cascader', customizePrefixCls);
  395. var inputPrefixCls = getPrefixCls('input', customizeInputPrefixCls);
  396. var sizeCls = classNames((_classNames = {}, _defineProperty(_classNames, inputPrefixCls + '-lg', size === 'large'), _defineProperty(_classNames, inputPrefixCls + '-sm', size === 'small'), _classNames));
  397. var clearIcon = allowClear && !disabled && value.length > 0 || inputValue ? h(Icon, {
  398. attrs: {
  399. type: 'close-circle',
  400. theme: 'filled'
  401. },
  402. 'class': prefixCls + '-picker-clear',
  403. on: {
  404. 'click': this.clearSelection
  405. },
  406. key: 'clear-icon'
  407. }) : null;
  408. var arrowCls = classNames((_classNames2 = {}, _defineProperty(_classNames2, prefixCls + '-picker-arrow', true), _defineProperty(_classNames2, prefixCls + '-picker-arrow-expand', sPopupVisible), _classNames2));
  409. var pickerCls = classNames(getClass(this), prefixCls + '-picker', (_classNames3 = {}, _defineProperty(_classNames3, prefixCls + '-picker-with-value', inputValue), _defineProperty(_classNames3, prefixCls + '-picker-disabled', disabled), _defineProperty(_classNames3, prefixCls + '-picker-' + size, !!size), _defineProperty(_classNames3, prefixCls + '-picker-show-search', !!showSearch), _defineProperty(_classNames3, prefixCls + '-picker-focused', inputFocused), _classNames3));
  410. // Fix bug of https://github.com/facebook/react/pull/5004
  411. // and https://fb.me/react-unknown-prop
  412. var tempInputProps = omit(otherProps, ['options', 'popupPlacement', 'transitionName', 'displayRender', 'changeOnSelect', 'expandTrigger', 'popupVisible', 'getPopupContainer', 'loadData', 'popupClassName', 'filterOption', 'renderFilteredOption', 'sortFilteredOption', 'notFoundContent', 'defaultValue', 'fieldNames']);
  413. var options = props.options;
  414. var names = getFilledFieldNames(this.$props);
  415. if (options && options.length > 0) {
  416. if (inputValue) {
  417. options = this.generateFilteredOptions(prefixCls, renderEmpty);
  418. }
  419. } else {
  420. var _ref6;
  421. options = [(_ref6 = {}, _defineProperty(_ref6, names.label, notFoundContent || renderEmpty(h, 'Cascader')), _defineProperty(_ref6, names.value, 'ANT_CASCADER_NOT_FOUND'), _defineProperty(_ref6, 'disabled', true), _ref6)];
  422. }
  423. // Dropdown menu should keep previous status until it is fully closed.
  424. if (!sPopupVisible) {
  425. options = this.cachedOptions;
  426. } else {
  427. this.cachedOptions = options;
  428. }
  429. var dropdownMenuColumnStyle = {};
  430. var isNotFound = (options || []).length === 1 && options[0].value === 'ANT_CASCADER_NOT_FOUND';
  431. if (isNotFound) {
  432. dropdownMenuColumnStyle.height = 'auto'; // Height of one row.
  433. }
  434. // The default value of `matchInputWidth` is `true`
  435. var resultListMatchInputWidth = showSearch.matchInputWidth !== false;
  436. if (resultListMatchInputWidth && (inputValue || isNotFound) && this.$refs.input) {
  437. dropdownMenuColumnStyle.width = this.$refs.input.$el.offsetWidth + 'px';
  438. }
  439. // showSearch时,focus、blur在input上触发,反之在ref='picker'上触发
  440. var inputProps = {
  441. props: _extends({}, tempInputProps, {
  442. prefixCls: inputPrefixCls,
  443. placeholder: value && value.length > 0 ? undefined : placeholder,
  444. value: inputValue,
  445. disabled: disabled,
  446. readOnly: !showSearch,
  447. autoComplete: 'off'
  448. }),
  449. 'class': prefixCls + '-input ' + sizeCls,
  450. ref: 'input',
  451. on: {
  452. focus: showSearch ? this.handleInputFocus : noop,
  453. click: showSearch ? this.handleInputClick : noop,
  454. blur: showSearch ? this.handleInputBlur : noop,
  455. keydown: this.handleKeyDown,
  456. change: showSearch ? this.handleInputChange : noop
  457. },
  458. attrs: getAttrs(this)
  459. };
  460. var children = filterEmpty($slots['default']);
  461. var inputIcon = suffixIcon && (isValidElement(suffixIcon) ? cloneElement(suffixIcon, {
  462. 'class': _defineProperty({}, prefixCls + '-picker-arrow', true)
  463. }) : h(
  464. 'span',
  465. { 'class': prefixCls + '-picker-arrow' },
  466. [suffixIcon]
  467. )) || h(Icon, {
  468. attrs: { type: 'down' },
  469. 'class': arrowCls });
  470. var input = children.length ? children : h(
  471. 'span',
  472. { 'class': pickerCls, style: getStyle(this), ref: 'picker' },
  473. [showSearch ? h(
  474. 'span',
  475. { 'class': prefixCls + '-picker-label' },
  476. [this.getLabel()]
  477. ) : null, h(Input, inputProps), !showSearch ? h(
  478. 'span',
  479. { 'class': prefixCls + '-picker-label' },
  480. [this.getLabel()]
  481. ) : null, clearIcon, inputIcon]
  482. );
  483. var expandIcon = h(Icon, {
  484. attrs: { type: 'right' }
  485. });
  486. var loadingIcon = h(
  487. 'span',
  488. { 'class': prefixCls + '-menu-item-loading-icon' },
  489. [h(Icon, {
  490. attrs: { type: 'redo', spin: true }
  491. })]
  492. );
  493. var getPopupContainer = props.getPopupContainer || getContextPopupContainer;
  494. var cascaderProps = {
  495. props: _extends({}, props, {
  496. getPopupContainer: getPopupContainer,
  497. options: options,
  498. prefixCls: prefixCls,
  499. value: value,
  500. popupVisible: sPopupVisible,
  501. dropdownMenuColumnStyle: dropdownMenuColumnStyle,
  502. expandIcon: expandIcon,
  503. loadingIcon: loadingIcon
  504. }),
  505. on: _extends({}, getListeners(this), {
  506. popupVisibleChange: this.handlePopupVisibleChange,
  507. change: this.handleChange
  508. })
  509. };
  510. return h(
  511. VcCascader,
  512. cascaderProps,
  513. [input]
  514. );
  515. }
  516. };
  517. /* istanbul ignore next */
  518. Cascader.install = function (Vue) {
  519. Vue.use(Base);
  520. Vue.component(Cascader.name, Cascader);
  521. };
  522. export default Cascader;