OptionList.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. "use strict";
  2. var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
  3. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
  4. Object.defineProperty(exports, "__esModule", {
  5. value: true
  6. });
  7. exports.default = void 0;
  8. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  9. var _createForOfIteratorHelper2 = _interopRequireDefault(require("@babel/runtime/helpers/createForOfIteratorHelper"));
  10. var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
  11. var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
  12. var _rcSelect = require("rc-select");
  13. var _rcTree = _interopRequireWildcard(require("rc-tree"));
  14. var _KeyCode = _interopRequireDefault(require("rc-util/lib/KeyCode"));
  15. var _useMemo = _interopRequireDefault(require("rc-util/lib/hooks/useMemo"));
  16. var React = _interopRequireWildcard(require("react"));
  17. var _LegacyContext = _interopRequireDefault(require("./LegacyContext"));
  18. var _TreeSelectContext = _interopRequireDefault(require("./TreeSelectContext"));
  19. var _valueUtil = require("./utils/valueUtil");
  20. var _rcUtil = require("rc-util");
  21. var HIDDEN_STYLE = {
  22. width: 0,
  23. height: 0,
  24. display: 'flex',
  25. overflow: 'hidden',
  26. opacity: 0,
  27. border: 0,
  28. padding: 0,
  29. margin: 0
  30. };
  31. var OptionList = function OptionList(_, ref) {
  32. var _useBaseProps = (0, _rcSelect.useBaseProps)(),
  33. prefixCls = _useBaseProps.prefixCls,
  34. multiple = _useBaseProps.multiple,
  35. searchValue = _useBaseProps.searchValue,
  36. toggleOpen = _useBaseProps.toggleOpen,
  37. open = _useBaseProps.open,
  38. notFoundContent = _useBaseProps.notFoundContent;
  39. var _React$useContext = React.useContext(_TreeSelectContext.default),
  40. virtual = _React$useContext.virtual,
  41. listHeight = _React$useContext.listHeight,
  42. listItemHeight = _React$useContext.listItemHeight,
  43. listItemScrollOffset = _React$useContext.listItemScrollOffset,
  44. treeData = _React$useContext.treeData,
  45. fieldNames = _React$useContext.fieldNames,
  46. onSelect = _React$useContext.onSelect,
  47. dropdownMatchSelectWidth = _React$useContext.dropdownMatchSelectWidth,
  48. treeExpandAction = _React$useContext.treeExpandAction,
  49. treeTitleRender = _React$useContext.treeTitleRender,
  50. onPopupScroll = _React$useContext.onPopupScroll,
  51. leftMaxCount = _React$useContext.leftMaxCount,
  52. leafCountOnly = _React$useContext.leafCountOnly,
  53. valueEntities = _React$useContext.valueEntities;
  54. var _React$useContext2 = React.useContext(_LegacyContext.default),
  55. checkable = _React$useContext2.checkable,
  56. checkedKeys = _React$useContext2.checkedKeys,
  57. halfCheckedKeys = _React$useContext2.halfCheckedKeys,
  58. treeExpandedKeys = _React$useContext2.treeExpandedKeys,
  59. treeDefaultExpandAll = _React$useContext2.treeDefaultExpandAll,
  60. treeDefaultExpandedKeys = _React$useContext2.treeDefaultExpandedKeys,
  61. onTreeExpand = _React$useContext2.onTreeExpand,
  62. treeIcon = _React$useContext2.treeIcon,
  63. showTreeIcon = _React$useContext2.showTreeIcon,
  64. switcherIcon = _React$useContext2.switcherIcon,
  65. treeLine = _React$useContext2.treeLine,
  66. treeNodeFilterProp = _React$useContext2.treeNodeFilterProp,
  67. loadData = _React$useContext2.loadData,
  68. treeLoadedKeys = _React$useContext2.treeLoadedKeys,
  69. treeMotion = _React$useContext2.treeMotion,
  70. onTreeLoad = _React$useContext2.onTreeLoad,
  71. keyEntities = _React$useContext2.keyEntities;
  72. var treeRef = React.useRef();
  73. var memoTreeData = (0, _useMemo.default)(function () {
  74. return treeData;
  75. },
  76. // eslint-disable-next-line react-hooks/exhaustive-deps
  77. [open, treeData], function (prev, next) {
  78. return next[0] && prev[1] !== next[1];
  79. });
  80. // ========================== Values ==========================
  81. var mergedCheckedKeys = React.useMemo(function () {
  82. if (!checkable) {
  83. return null;
  84. }
  85. return {
  86. checked: checkedKeys,
  87. halfChecked: halfCheckedKeys
  88. };
  89. }, [checkable, checkedKeys, halfCheckedKeys]);
  90. // ========================== Scroll ==========================
  91. React.useEffect(function () {
  92. // Single mode should scroll to current key
  93. if (open && !multiple && checkedKeys.length) {
  94. var _treeRef$current;
  95. (_treeRef$current = treeRef.current) === null || _treeRef$current === void 0 || _treeRef$current.scrollTo({
  96. key: checkedKeys[0]
  97. });
  98. }
  99. // eslint-disable-next-line react-hooks/exhaustive-deps
  100. }, [open]);
  101. // ========================== Events ==========================
  102. var onListMouseDown = function onListMouseDown(event) {
  103. event.preventDefault();
  104. };
  105. var onInternalSelect = function onInternalSelect(__, info) {
  106. var node = info.node;
  107. if (checkable && (0, _valueUtil.isCheckDisabled)(node)) {
  108. return;
  109. }
  110. onSelect(node.key, {
  111. selected: !checkedKeys.includes(node.key)
  112. });
  113. if (!multiple) {
  114. toggleOpen(false);
  115. }
  116. };
  117. // =========================== Keys ===========================
  118. var _React$useState = React.useState(treeDefaultExpandedKeys),
  119. _React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2),
  120. expandedKeys = _React$useState2[0],
  121. setExpandedKeys = _React$useState2[1];
  122. var _React$useState3 = React.useState(null),
  123. _React$useState4 = (0, _slicedToArray2.default)(_React$useState3, 2),
  124. searchExpandedKeys = _React$useState4[0],
  125. setSearchExpandedKeys = _React$useState4[1];
  126. var mergedExpandedKeys = React.useMemo(function () {
  127. if (treeExpandedKeys) {
  128. return (0, _toConsumableArray2.default)(treeExpandedKeys);
  129. }
  130. return searchValue ? searchExpandedKeys : expandedKeys;
  131. }, [expandedKeys, searchExpandedKeys, treeExpandedKeys, searchValue]);
  132. var onInternalExpand = function onInternalExpand(keys) {
  133. setExpandedKeys(keys);
  134. setSearchExpandedKeys(keys);
  135. if (onTreeExpand) {
  136. onTreeExpand(keys);
  137. }
  138. };
  139. // ========================== Search ==========================
  140. var lowerSearchValue = String(searchValue).toLowerCase();
  141. var filterTreeNode = function filterTreeNode(treeNode) {
  142. if (!lowerSearchValue) {
  143. return false;
  144. }
  145. return String(treeNode[treeNodeFilterProp]).toLowerCase().includes(lowerSearchValue);
  146. };
  147. React.useEffect(function () {
  148. if (searchValue) {
  149. setSearchExpandedKeys((0, _valueUtil.getAllKeys)(treeData, fieldNames));
  150. }
  151. // eslint-disable-next-line react-hooks/exhaustive-deps
  152. }, [searchValue]);
  153. // ========================= Disabled =========================
  154. // Cache disabled states in React state to ensure re-render when cache updates
  155. var _React$useState5 = React.useState(function () {
  156. return new Map();
  157. }),
  158. _React$useState6 = (0, _slicedToArray2.default)(_React$useState5, 2),
  159. disabledCache = _React$useState6[0],
  160. setDisabledCache = _React$useState6[1];
  161. React.useEffect(function () {
  162. if (leftMaxCount) {
  163. setDisabledCache(new Map());
  164. }
  165. }, [leftMaxCount]);
  166. function getDisabledWithCache(node) {
  167. var value = node[fieldNames.value];
  168. if (!disabledCache.has(value)) {
  169. var entity = valueEntities.get(value);
  170. var isLeaf = (entity.children || []).length === 0;
  171. if (!isLeaf) {
  172. var checkableChildren = entity.children.filter(function (childTreeNode) {
  173. return !childTreeNode.node.disabled && !childTreeNode.node.disableCheckbox && !checkedKeys.includes(childTreeNode.node[fieldNames.value]);
  174. });
  175. var checkableChildrenCount = checkableChildren.length;
  176. disabledCache.set(value, checkableChildrenCount > leftMaxCount);
  177. } else {
  178. disabledCache.set(value, false);
  179. }
  180. }
  181. return disabledCache.get(value);
  182. }
  183. var nodeDisabled = (0, _rcUtil.useEvent)(function (node) {
  184. var nodeValue = node[fieldNames.value];
  185. if (checkedKeys.includes(nodeValue)) {
  186. return false;
  187. }
  188. if (leftMaxCount === null) {
  189. return false;
  190. }
  191. if (leftMaxCount <= 0) {
  192. return true;
  193. }
  194. // This is a low performance calculation
  195. if (leafCountOnly && leftMaxCount) {
  196. return getDisabledWithCache(node);
  197. }
  198. return false;
  199. });
  200. // ========================== Get First Selectable Node ==========================
  201. var getFirstMatchingNode = function getFirstMatchingNode(nodes) {
  202. var _iterator = (0, _createForOfIteratorHelper2.default)(nodes),
  203. _step;
  204. try {
  205. for (_iterator.s(); !(_step = _iterator.n()).done;) {
  206. var node = _step.value;
  207. if (node.disabled || node.selectable === false) {
  208. continue;
  209. }
  210. if (searchValue) {
  211. if (filterTreeNode(node)) {
  212. return node;
  213. }
  214. } else {
  215. return node;
  216. }
  217. if (node[fieldNames.children]) {
  218. var matchInChildren = getFirstMatchingNode(node[fieldNames.children]);
  219. if (matchInChildren) {
  220. return matchInChildren;
  221. }
  222. }
  223. }
  224. } catch (err) {
  225. _iterator.e(err);
  226. } finally {
  227. _iterator.f();
  228. }
  229. return null;
  230. };
  231. // ========================== Active ==========================
  232. var _React$useState7 = React.useState(null),
  233. _React$useState8 = (0, _slicedToArray2.default)(_React$useState7, 2),
  234. activeKey = _React$useState8[0],
  235. setActiveKey = _React$useState8[1];
  236. var activeEntity = keyEntities[activeKey];
  237. React.useEffect(function () {
  238. if (!open) {
  239. return;
  240. }
  241. var nextActiveKey = null;
  242. var getFirstNode = function getFirstNode() {
  243. var firstNode = getFirstMatchingNode(memoTreeData);
  244. return firstNode ? firstNode[fieldNames.value] : null;
  245. };
  246. // single mode active first checked node
  247. if (!multiple && checkedKeys.length && !searchValue) {
  248. nextActiveKey = checkedKeys[0];
  249. } else {
  250. nextActiveKey = getFirstNode();
  251. }
  252. setActiveKey(nextActiveKey);
  253. }, [open, searchValue]);
  254. // ========================= Keyboard =========================
  255. React.useImperativeHandle(ref, function () {
  256. var _treeRef$current2;
  257. return {
  258. scrollTo: (_treeRef$current2 = treeRef.current) === null || _treeRef$current2 === void 0 ? void 0 : _treeRef$current2.scrollTo,
  259. onKeyDown: function onKeyDown(event) {
  260. var _treeRef$current3;
  261. var which = event.which;
  262. switch (which) {
  263. // >>> Arrow keys
  264. case _KeyCode.default.UP:
  265. case _KeyCode.default.DOWN:
  266. case _KeyCode.default.LEFT:
  267. case _KeyCode.default.RIGHT:
  268. (_treeRef$current3 = treeRef.current) === null || _treeRef$current3 === void 0 || _treeRef$current3.onKeyDown(event);
  269. break;
  270. // >>> Select item
  271. case _KeyCode.default.ENTER:
  272. {
  273. if (activeEntity) {
  274. var isNodeDisabled = nodeDisabled(activeEntity.node);
  275. var _ref = (activeEntity === null || activeEntity === void 0 ? void 0 : activeEntity.node) || {},
  276. selectable = _ref.selectable,
  277. value = _ref.value,
  278. disabled = _ref.disabled;
  279. if (selectable !== false && !disabled && !isNodeDisabled) {
  280. onInternalSelect(null, {
  281. node: {
  282. key: activeKey
  283. },
  284. selected: !checkedKeys.includes(value)
  285. });
  286. }
  287. }
  288. break;
  289. }
  290. // >>> Close
  291. case _KeyCode.default.ESC:
  292. {
  293. toggleOpen(false);
  294. }
  295. }
  296. },
  297. onKeyUp: function onKeyUp() {}
  298. };
  299. });
  300. var hasLoadDataFn = (0, _useMemo.default)(function () {
  301. return searchValue ? false : true;
  302. }, [searchValue, treeExpandedKeys || expandedKeys], function (_ref2, _ref3) {
  303. var _ref4 = (0, _slicedToArray2.default)(_ref2, 1),
  304. preSearchValue = _ref4[0];
  305. var _ref5 = (0, _slicedToArray2.default)(_ref3, 2),
  306. nextSearchValue = _ref5[0],
  307. nextExcludeSearchExpandedKeys = _ref5[1];
  308. return preSearchValue !== nextSearchValue && !!(nextSearchValue || nextExcludeSearchExpandedKeys);
  309. });
  310. var syncLoadData = hasLoadDataFn ? loadData : null;
  311. // ========================== Render ==========================
  312. if (memoTreeData.length === 0) {
  313. return /*#__PURE__*/React.createElement("div", {
  314. role: "listbox",
  315. className: "".concat(prefixCls, "-empty"),
  316. onMouseDown: onListMouseDown
  317. }, notFoundContent);
  318. }
  319. var treeProps = {
  320. fieldNames: fieldNames
  321. };
  322. if (treeLoadedKeys) {
  323. treeProps.loadedKeys = treeLoadedKeys;
  324. }
  325. if (mergedExpandedKeys) {
  326. treeProps.expandedKeys = mergedExpandedKeys;
  327. }
  328. return /*#__PURE__*/React.createElement("div", {
  329. onMouseDown: onListMouseDown
  330. }, activeEntity && open && /*#__PURE__*/React.createElement("span", {
  331. style: HIDDEN_STYLE,
  332. "aria-live": "assertive"
  333. }, activeEntity.node.value), /*#__PURE__*/React.createElement(_rcTree.UnstableContext.Provider, {
  334. value: {
  335. nodeDisabled: nodeDisabled
  336. }
  337. }, /*#__PURE__*/React.createElement(_rcTree.default, (0, _extends2.default)({
  338. ref: treeRef,
  339. focusable: false,
  340. prefixCls: "".concat(prefixCls, "-tree"),
  341. treeData: memoTreeData,
  342. height: listHeight,
  343. itemHeight: listItemHeight,
  344. itemScrollOffset: listItemScrollOffset,
  345. virtual: virtual !== false && dropdownMatchSelectWidth !== false,
  346. multiple: multiple,
  347. icon: treeIcon,
  348. showIcon: showTreeIcon,
  349. switcherIcon: switcherIcon,
  350. showLine: treeLine,
  351. loadData: syncLoadData,
  352. motion: treeMotion,
  353. activeKey: activeKey
  354. // We handle keys by out instead tree self
  355. ,
  356. checkable: checkable,
  357. checkStrictly: true,
  358. checkedKeys: mergedCheckedKeys,
  359. selectedKeys: !checkable ? checkedKeys : [],
  360. defaultExpandAll: treeDefaultExpandAll,
  361. titleRender: treeTitleRender
  362. }, treeProps, {
  363. // Proxy event out
  364. onActiveChange: setActiveKey,
  365. onSelect: onInternalSelect,
  366. onCheck: onInternalSelect,
  367. onExpand: onInternalExpand,
  368. onLoad: onTreeLoad,
  369. filterTreeNode: filterTreeNode,
  370. expandAction: treeExpandAction,
  371. onScroll: onPopupScroll
  372. }))));
  373. };
  374. var RefOptionList = /*#__PURE__*/React.forwardRef(OptionList);
  375. if (process.env.NODE_ENV !== 'production') {
  376. RefOptionList.displayName = 'OptionList';
  377. }
  378. var _default = exports.default = RefOptionList;