Cascader.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. import _extends from "@babel/runtime/helpers/esm/extends";
  2. import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
  3. import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
  4. import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
  5. import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
  6. var _excluded = ["id", "prefixCls", "fieldNames", "defaultValue", "value", "changeOnSelect", "onChange", "displayRender", "checkable", "autoClearSearchValue", "searchValue", "onSearch", "showSearch", "expandTrigger", "options", "dropdownPrefixCls", "loadData", "popupVisible", "open", "popupClassName", "dropdownClassName", "dropdownMenuColumnStyle", "dropdownStyle", "popupPlacement", "placement", "onDropdownVisibleChange", "onPopupVisibleChange", "onOpenChange", "expandIcon", "loadingIcon", "children", "dropdownMatchSelectWidth", "showCheckedStrategy", "optionRender"];
  7. import { BaseSelect } from 'rc-select';
  8. import useId from "rc-select/es/hooks/useId";
  9. import useEvent from "rc-util/es/hooks/useEvent";
  10. import useMergedState from "rc-util/es/hooks/useMergedState";
  11. import * as React from 'react';
  12. import CascaderContext from "./context";
  13. import useDisplayValues from "./hooks/useDisplayValues";
  14. import useMissingValues from "./hooks/useMissingValues";
  15. import useOptions from "./hooks/useOptions";
  16. import useSearchConfig from "./hooks/useSearchConfig";
  17. import useSearchOptions from "./hooks/useSearchOptions";
  18. import useSelect from "./hooks/useSelect";
  19. import useValues from "./hooks/useValues";
  20. import OptionList from "./OptionList";
  21. import Panel from "./Panel";
  22. import { fillFieldNames, SHOW_CHILD, SHOW_PARENT, toPathKeys, toRawValues } from "./utils/commonUtil";
  23. import { formatStrategyValues, toPathOptions } from "./utils/treeUtil";
  24. import warningProps, { warningNullOptions } from "./utils/warningPropsUtil";
  25. var Cascader = /*#__PURE__*/React.forwardRef(function (props, ref) {
  26. var id = props.id,
  27. _props$prefixCls = props.prefixCls,
  28. prefixCls = _props$prefixCls === void 0 ? 'rc-cascader' : _props$prefixCls,
  29. fieldNames = props.fieldNames,
  30. defaultValue = props.defaultValue,
  31. value = props.value,
  32. changeOnSelect = props.changeOnSelect,
  33. onChange = props.onChange,
  34. displayRender = props.displayRender,
  35. checkable = props.checkable,
  36. _props$autoClearSearc = props.autoClearSearchValue,
  37. autoClearSearchValue = _props$autoClearSearc === void 0 ? true : _props$autoClearSearc,
  38. searchValue = props.searchValue,
  39. onSearch = props.onSearch,
  40. showSearch = props.showSearch,
  41. expandTrigger = props.expandTrigger,
  42. options = props.options,
  43. dropdownPrefixCls = props.dropdownPrefixCls,
  44. loadData = props.loadData,
  45. popupVisible = props.popupVisible,
  46. open = props.open,
  47. popupClassName = props.popupClassName,
  48. dropdownClassName = props.dropdownClassName,
  49. dropdownMenuColumnStyle = props.dropdownMenuColumnStyle,
  50. customDropdownStyle = props.dropdownStyle,
  51. popupPlacement = props.popupPlacement,
  52. placement = props.placement,
  53. onDropdownVisibleChange = props.onDropdownVisibleChange,
  54. onPopupVisibleChange = props.onPopupVisibleChange,
  55. onOpenChange = props.onOpenChange,
  56. _props$expandIcon = props.expandIcon,
  57. expandIcon = _props$expandIcon === void 0 ? '>' : _props$expandIcon,
  58. loadingIcon = props.loadingIcon,
  59. children = props.children,
  60. _props$dropdownMatchS = props.dropdownMatchSelectWidth,
  61. dropdownMatchSelectWidth = _props$dropdownMatchS === void 0 ? false : _props$dropdownMatchS,
  62. _props$showCheckedStr = props.showCheckedStrategy,
  63. showCheckedStrategy = _props$showCheckedStr === void 0 ? SHOW_PARENT : _props$showCheckedStr,
  64. optionRender = props.optionRender,
  65. restProps = _objectWithoutProperties(props, _excluded);
  66. var mergedId = useId(id);
  67. var multiple = !!checkable;
  68. // =========================== Values ===========================
  69. var _useMergedState = useMergedState(defaultValue, {
  70. value: value,
  71. postState: toRawValues
  72. }),
  73. _useMergedState2 = _slicedToArray(_useMergedState, 2),
  74. rawValues = _useMergedState2[0],
  75. setRawValues = _useMergedState2[1];
  76. // ========================= FieldNames =========================
  77. var mergedFieldNames = React.useMemo(function () {
  78. return fillFieldNames(fieldNames);
  79. }, /* eslint-disable react-hooks/exhaustive-deps */
  80. [JSON.stringify(fieldNames)]
  81. /* eslint-enable react-hooks/exhaustive-deps */);
  82. // =========================== Option ===========================
  83. var _useOptions = useOptions(mergedFieldNames, options),
  84. _useOptions2 = _slicedToArray(_useOptions, 3),
  85. mergedOptions = _useOptions2[0],
  86. getPathKeyEntities = _useOptions2[1],
  87. getValueByKeyPath = _useOptions2[2];
  88. // =========================== Search ===========================
  89. var _useMergedState3 = useMergedState('', {
  90. value: searchValue,
  91. postState: function postState(search) {
  92. return search || '';
  93. }
  94. }),
  95. _useMergedState4 = _slicedToArray(_useMergedState3, 2),
  96. mergedSearchValue = _useMergedState4[0],
  97. setSearchValue = _useMergedState4[1];
  98. var onInternalSearch = function onInternalSearch(searchText, info) {
  99. setSearchValue(searchText);
  100. if (info.source !== 'blur' && onSearch) {
  101. onSearch(searchText);
  102. }
  103. };
  104. var _useSearchConfig = useSearchConfig(showSearch),
  105. _useSearchConfig2 = _slicedToArray(_useSearchConfig, 2),
  106. mergedShowSearch = _useSearchConfig2[0],
  107. searchConfig = _useSearchConfig2[1];
  108. var searchOptions = useSearchOptions(mergedSearchValue, mergedOptions, mergedFieldNames, dropdownPrefixCls || prefixCls, searchConfig, changeOnSelect || multiple);
  109. // =========================== Values ===========================
  110. var getMissingValues = useMissingValues(mergedOptions, mergedFieldNames);
  111. // Fill `rawValues` with checked conduction values
  112. var _useValues = useValues(multiple, rawValues, getPathKeyEntities, getValueByKeyPath, getMissingValues),
  113. _useValues2 = _slicedToArray(_useValues, 3),
  114. checkedValues = _useValues2[0],
  115. halfCheckedValues = _useValues2[1],
  116. missingCheckedValues = _useValues2[2];
  117. var deDuplicatedValues = React.useMemo(function () {
  118. var checkedKeys = toPathKeys(checkedValues);
  119. var deduplicateKeys = formatStrategyValues(checkedKeys, getPathKeyEntities, showCheckedStrategy);
  120. return [].concat(_toConsumableArray(missingCheckedValues), _toConsumableArray(getValueByKeyPath(deduplicateKeys)));
  121. }, [checkedValues, getPathKeyEntities, getValueByKeyPath, missingCheckedValues, showCheckedStrategy]);
  122. var displayValues = useDisplayValues(deDuplicatedValues, mergedOptions, mergedFieldNames, multiple, displayRender);
  123. // =========================== Change ===========================
  124. var triggerChange = useEvent(function (nextValues) {
  125. setRawValues(nextValues);
  126. // Save perf if no need trigger event
  127. if (onChange) {
  128. var nextRawValues = toRawValues(nextValues);
  129. var valueOptions = nextRawValues.map(function (valueCells) {
  130. return toPathOptions(valueCells, mergedOptions, mergedFieldNames).map(function (valueOpt) {
  131. return valueOpt.option;
  132. });
  133. });
  134. var triggerValues = multiple ? nextRawValues : nextRawValues[0];
  135. var triggerOptions = multiple ? valueOptions : valueOptions[0];
  136. onChange(triggerValues, triggerOptions);
  137. }
  138. });
  139. // =========================== Select ===========================
  140. var handleSelection = useSelect(multiple, triggerChange, checkedValues, halfCheckedValues, missingCheckedValues, getPathKeyEntities, getValueByKeyPath, showCheckedStrategy);
  141. var onInternalSelect = useEvent(function (valuePath) {
  142. if (!multiple || autoClearSearchValue) {
  143. setSearchValue('');
  144. }
  145. handleSelection(valuePath);
  146. });
  147. // Display Value change logic
  148. var onDisplayValuesChange = function onDisplayValuesChange(_, info) {
  149. if (info.type === 'clear') {
  150. triggerChange([]);
  151. return;
  152. }
  153. // Cascader do not support `add` type. Only support `remove`
  154. var _ref = info.values[0],
  155. valueCells = _ref.valueCells;
  156. onInternalSelect(valueCells);
  157. };
  158. // ============================ Open ============================
  159. var mergedOpen = open !== undefined ? open : popupVisible;
  160. var mergedDropdownClassName = dropdownClassName || popupClassName;
  161. var mergedPlacement = placement || popupPlacement;
  162. var onInternalDropdownVisibleChange = function onInternalDropdownVisibleChange(nextVisible) {
  163. onOpenChange === null || onOpenChange === void 0 || onOpenChange(nextVisible);
  164. onDropdownVisibleChange === null || onDropdownVisibleChange === void 0 || onDropdownVisibleChange(nextVisible);
  165. onPopupVisibleChange === null || onPopupVisibleChange === void 0 || onPopupVisibleChange(nextVisible);
  166. };
  167. // ========================== Warning ===========================
  168. if (process.env.NODE_ENV !== 'production') {
  169. warningProps(props);
  170. warningNullOptions(mergedOptions, mergedFieldNames);
  171. }
  172. // ========================== Context ===========================
  173. var cascaderContext = React.useMemo(function () {
  174. return {
  175. options: mergedOptions,
  176. fieldNames: mergedFieldNames,
  177. values: checkedValues,
  178. halfValues: halfCheckedValues,
  179. changeOnSelect: changeOnSelect,
  180. onSelect: onInternalSelect,
  181. checkable: checkable,
  182. searchOptions: searchOptions,
  183. dropdownPrefixCls: dropdownPrefixCls,
  184. loadData: loadData,
  185. expandTrigger: expandTrigger,
  186. expandIcon: expandIcon,
  187. loadingIcon: loadingIcon,
  188. dropdownMenuColumnStyle: dropdownMenuColumnStyle,
  189. optionRender: optionRender
  190. };
  191. }, [mergedOptions, mergedFieldNames, checkedValues, halfCheckedValues, changeOnSelect, onInternalSelect, checkable, searchOptions, dropdownPrefixCls, loadData, expandTrigger, expandIcon, loadingIcon, dropdownMenuColumnStyle, optionRender]);
  192. // ==============================================================
  193. // == Render ==
  194. // ==============================================================
  195. var emptyOptions = !(mergedSearchValue ? searchOptions : mergedOptions).length;
  196. var dropdownStyle =
  197. // Search to match width
  198. mergedSearchValue && searchConfig.matchInputWidth ||
  199. // Empty keep the width
  200. emptyOptions ? {} : {
  201. minWidth: 'auto'
  202. };
  203. return /*#__PURE__*/React.createElement(CascaderContext.Provider, {
  204. value: cascaderContext
  205. }, /*#__PURE__*/React.createElement(BaseSelect, _extends({}, restProps, {
  206. // MISC
  207. ref: ref,
  208. id: mergedId,
  209. prefixCls: prefixCls,
  210. autoClearSearchValue: autoClearSearchValue,
  211. dropdownMatchSelectWidth: dropdownMatchSelectWidth,
  212. dropdownStyle: _objectSpread(_objectSpread({}, dropdownStyle), customDropdownStyle)
  213. // Value
  214. ,
  215. displayValues: displayValues,
  216. onDisplayValuesChange: onDisplayValuesChange,
  217. mode: multiple ? 'multiple' : undefined
  218. // Search
  219. ,
  220. searchValue: mergedSearchValue,
  221. onSearch: onInternalSearch,
  222. showSearch: mergedShowSearch
  223. // Options
  224. ,
  225. OptionList: OptionList,
  226. emptyOptions: emptyOptions
  227. // Open
  228. ,
  229. open: mergedOpen,
  230. dropdownClassName: mergedDropdownClassName,
  231. placement: mergedPlacement,
  232. onDropdownVisibleChange: onInternalDropdownVisibleChange
  233. // Children
  234. ,
  235. getRawInputElement: function getRawInputElement() {
  236. return children;
  237. }
  238. })));
  239. });
  240. if (process.env.NODE_ENV !== 'production') {
  241. Cascader.displayName = 'Cascader';
  242. }
  243. Cascader.SHOW_PARENT = SHOW_PARENT;
  244. Cascader.SHOW_CHILD = SHOW_CHILD;
  245. Cascader.Panel = Panel;
  246. export default Cascader;