UNPKG

16.4 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4var _typeof = require("@babel/runtime/helpers/typeof");
5Object.defineProperty(exports, "__esModule", {
6 value: true
7});
8exports.default = void 0;
9var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
10var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
11var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
12var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
13var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
14var _classnames = _interopRequireDefault(require("classnames"));
15var _KeyCode = _interopRequireDefault(require("rc-util/lib/KeyCode"));
16var _useMemo = _interopRequireDefault(require("rc-util/lib/hooks/useMemo"));
17var _omit = _interopRequireDefault(require("rc-util/lib/omit"));
18var _pickAttrs = _interopRequireDefault(require("rc-util/lib/pickAttrs"));
19var _rcVirtualList = _interopRequireDefault(require("rc-virtual-list"));
20var _react = _interopRequireWildcard(require("react"));
21var React = _react;
22var _SelectContext = _interopRequireDefault(require("./SelectContext"));
23var _TransBtn = _interopRequireDefault(require("./TransBtn"));
24var _useBaseProps2 = _interopRequireDefault(require("./hooks/useBaseProps"));
25var _platformUtil = require("./utils/platformUtil");
26var _valueUtil = require("./utils/valueUtil");
27var _excluded = ["disabled", "title", "children", "style", "className"];
28function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
29function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
30// export interface OptionListProps<OptionsType extends object[]> {
31
32function isTitleType(content) {
33 return typeof content === 'string' || typeof content === 'number';
34}
35
36/**
37 * Using virtual list of option display.
38 * Will fallback to dom if use customize render.
39 */
40var OptionList = function OptionList(_, ref) {
41 var _useBaseProps = (0, _useBaseProps2.default)(),
42 prefixCls = _useBaseProps.prefixCls,
43 id = _useBaseProps.id,
44 open = _useBaseProps.open,
45 multiple = _useBaseProps.multiple,
46 mode = _useBaseProps.mode,
47 searchValue = _useBaseProps.searchValue,
48 toggleOpen = _useBaseProps.toggleOpen,
49 notFoundContent = _useBaseProps.notFoundContent,
50 onPopupScroll = _useBaseProps.onPopupScroll;
51 var _React$useContext = React.useContext(_SelectContext.default),
52 maxCount = _React$useContext.maxCount,
53 flattenOptions = _React$useContext.flattenOptions,
54 onActiveValue = _React$useContext.onActiveValue,
55 defaultActiveFirstOption = _React$useContext.defaultActiveFirstOption,
56 onSelect = _React$useContext.onSelect,
57 menuItemSelectedIcon = _React$useContext.menuItemSelectedIcon,
58 rawValues = _React$useContext.rawValues,
59 fieldNames = _React$useContext.fieldNames,
60 virtual = _React$useContext.virtual,
61 direction = _React$useContext.direction,
62 listHeight = _React$useContext.listHeight,
63 listItemHeight = _React$useContext.listItemHeight,
64 optionRender = _React$useContext.optionRender;
65 var itemPrefixCls = "".concat(prefixCls, "-item");
66 var memoFlattenOptions = (0, _useMemo.default)(function () {
67 return flattenOptions;
68 }, [open, flattenOptions], function (prev, next) {
69 return next[0] && prev[1] !== next[1];
70 });
71
72 // =========================== List ===========================
73 var listRef = React.useRef(null);
74 var overMaxCount = React.useMemo(function () {
75 return multiple && (0, _valueUtil.isValidCount)(maxCount) && (rawValues === null || rawValues === void 0 ? void 0 : rawValues.size) >= maxCount;
76 }, [multiple, maxCount, rawValues === null || rawValues === void 0 ? void 0 : rawValues.size]);
77 var onListMouseDown = function onListMouseDown(event) {
78 event.preventDefault();
79 };
80 var scrollIntoView = function scrollIntoView(args) {
81 var _listRef$current;
82 (_listRef$current = listRef.current) === null || _listRef$current === void 0 || _listRef$current.scrollTo(typeof args === 'number' ? {
83 index: args
84 } : args);
85 };
86
87 // ========================== Active ==========================
88 var getEnabledActiveIndex = function getEnabledActiveIndex(index) {
89 var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
90 var len = memoFlattenOptions.length;
91 for (var i = 0; i < len; i += 1) {
92 var current = (index + i * offset + len) % len;
93 var _ref = memoFlattenOptions[current] || {},
94 group = _ref.group,
95 data = _ref.data;
96 if (!group && !(data !== null && data !== void 0 && data.disabled) && !overMaxCount) {
97 return current;
98 }
99 }
100 return -1;
101 };
102 var _React$useState = React.useState(function () {
103 return getEnabledActiveIndex(0);
104 }),
105 _React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2),
106 activeIndex = _React$useState2[0],
107 setActiveIndex = _React$useState2[1];
108 var setActive = function setActive(index) {
109 var fromKeyboard = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
110 setActiveIndex(index);
111 var info = {
112 source: fromKeyboard ? 'keyboard' : 'mouse'
113 };
114
115 // Trigger active event
116 var flattenItem = memoFlattenOptions[index];
117 if (!flattenItem) {
118 onActiveValue(null, -1, info);
119 return;
120 }
121 onActiveValue(flattenItem.value, index, info);
122 };
123
124 // Auto active first item when list length or searchValue changed
125 (0, _react.useEffect)(function () {
126 setActive(defaultActiveFirstOption !== false ? getEnabledActiveIndex(0) : -1);
127 }, [memoFlattenOptions.length, searchValue]);
128
129 // https://github.com/ant-design/ant-design/issues/34975
130 var isSelected = React.useCallback(function (value) {
131 if (mode === 'combobox') {
132 return false;
133 }
134 return rawValues.has(value);
135 }, [mode, (0, _toConsumableArray2.default)(rawValues).toString(), rawValues.size]);
136
137 // https://github.com/ant-design/ant-design/issues/48036
138 var isAriaSelected = React.useCallback(function (value) {
139 if (mode === 'combobox') {
140 return String(value).toLowerCase() === searchValue.toLowerCase();
141 }
142 return rawValues.has(value);
143 }, [mode, searchValue, (0, _toConsumableArray2.default)(rawValues).toString(), rawValues.size]);
144
145 // Auto scroll to item position in single mode
146 (0, _react.useEffect)(function () {
147 /**
148 * React will skip `onChange` when component update.
149 * `setActive` function will call root accessibility state update which makes re-render.
150 * So we need to delay to let Input component trigger onChange first.
151 */
152 var timeoutId = setTimeout(function () {
153 if (!multiple && open && rawValues.size === 1) {
154 var value = Array.from(rawValues)[0];
155 var index = memoFlattenOptions.findIndex(function (_ref2) {
156 var data = _ref2.data;
157 return data.value === value;
158 });
159 if (index !== -1) {
160 setActive(index);
161 scrollIntoView(index);
162 }
163 }
164 });
165
166 // Force trigger scrollbar visible when open
167 if (open) {
168 var _listRef$current2;
169 (_listRef$current2 = listRef.current) === null || _listRef$current2 === void 0 || _listRef$current2.scrollTo(undefined);
170 }
171 return function () {
172 return clearTimeout(timeoutId);
173 };
174 }, [open, searchValue]);
175
176 // ========================== Values ==========================
177 var onSelectValue = function onSelectValue(value) {
178 if (value !== undefined) {
179 onSelect(value, {
180 selected: !rawValues.has(value)
181 });
182 }
183
184 // Single mode should always close by select
185 if (!multiple) {
186 toggleOpen(false);
187 }
188 };
189
190 // ========================= Keyboard =========================
191 React.useImperativeHandle(ref, function () {
192 return {
193 onKeyDown: function onKeyDown(event) {
194 var which = event.which,
195 ctrlKey = event.ctrlKey;
196 switch (which) {
197 // >>> Arrow keys & ctrl + n/p on Mac
198 case _KeyCode.default.N:
199 case _KeyCode.default.P:
200 case _KeyCode.default.UP:
201 case _KeyCode.default.DOWN:
202 {
203 var offset = 0;
204 if (which === _KeyCode.default.UP) {
205 offset = -1;
206 } else if (which === _KeyCode.default.DOWN) {
207 offset = 1;
208 } else if ((0, _platformUtil.isPlatformMac)() && ctrlKey) {
209 if (which === _KeyCode.default.N) {
210 offset = 1;
211 } else if (which === _KeyCode.default.P) {
212 offset = -1;
213 }
214 }
215 if (offset !== 0) {
216 var nextActiveIndex = getEnabledActiveIndex(activeIndex + offset, offset);
217 scrollIntoView(nextActiveIndex);
218 setActive(nextActiveIndex, true);
219 }
220 break;
221 }
222
223 // >>> Select (Tab / Enter)
224 case _KeyCode.default.TAB:
225 case _KeyCode.default.ENTER:
226 {
227 var _item$data;
228 // value
229 var item = memoFlattenOptions[activeIndex];
230 if (item && !(item !== null && item !== void 0 && (_item$data = item.data) !== null && _item$data !== void 0 && _item$data.disabled) && !overMaxCount) {
231 onSelectValue(item.value);
232 } else {
233 onSelectValue(undefined);
234 }
235 if (open) {
236 event.preventDefault();
237 }
238 break;
239 }
240
241 // >>> Close
242 case _KeyCode.default.ESC:
243 {
244 toggleOpen(false);
245 if (open) {
246 event.stopPropagation();
247 }
248 }
249 }
250 },
251 onKeyUp: function onKeyUp() {},
252 scrollTo: function scrollTo(index) {
253 scrollIntoView(index);
254 }
255 };
256 });
257
258 // ========================== Render ==========================
259 if (memoFlattenOptions.length === 0) {
260 return /*#__PURE__*/React.createElement("div", {
261 role: "listbox",
262 id: "".concat(id, "_list"),
263 className: "".concat(itemPrefixCls, "-empty"),
264 onMouseDown: onListMouseDown
265 }, notFoundContent);
266 }
267 var omitFieldNameList = Object.keys(fieldNames).map(function (key) {
268 return fieldNames[key];
269 });
270 var getLabel = function getLabel(item) {
271 return item.label;
272 };
273 function getItemAriaProps(item, index) {
274 var group = item.group;
275 return {
276 role: group ? 'presentation' : 'option',
277 id: "".concat(id, "_list_").concat(index)
278 };
279 }
280 var renderItem = function renderItem(index) {
281 var item = memoFlattenOptions[index];
282 if (!item) {
283 return null;
284 }
285 var itemData = item.data || {};
286 var value = itemData.value;
287 var group = item.group;
288 var attrs = (0, _pickAttrs.default)(itemData, true);
289 var mergedLabel = getLabel(item);
290 return item ? /*#__PURE__*/React.createElement("div", (0, _extends2.default)({
291 "aria-label": typeof mergedLabel === 'string' && !group ? mergedLabel : null
292 }, attrs, {
293 key: index
294 }, getItemAriaProps(item, index), {
295 "aria-selected": isAriaSelected(value)
296 }), value) : null;
297 };
298 var a11yProps = {
299 role: 'listbox',
300 id: "".concat(id, "_list")
301 };
302 return /*#__PURE__*/React.createElement(React.Fragment, null, virtual && /*#__PURE__*/React.createElement("div", (0, _extends2.default)({}, a11yProps, {
303 style: {
304 height: 0,
305 width: 0,
306 overflow: 'hidden'
307 }
308 }), renderItem(activeIndex - 1), renderItem(activeIndex), renderItem(activeIndex + 1)), /*#__PURE__*/React.createElement(_rcVirtualList.default, {
309 itemKey: "key",
310 ref: listRef,
311 data: memoFlattenOptions,
312 height: listHeight,
313 itemHeight: listItemHeight,
314 fullHeight: false,
315 onMouseDown: onListMouseDown,
316 onScroll: onPopupScroll,
317 virtual: virtual,
318 direction: direction,
319 innerProps: virtual ? null : a11yProps
320 }, function (item, itemIndex) {
321 var group = item.group,
322 groupOption = item.groupOption,
323 data = item.data,
324 label = item.label,
325 value = item.value;
326 var key = data.key;
327
328 // Group
329 if (group) {
330 var _data$title;
331 var groupTitle = (_data$title = data.title) !== null && _data$title !== void 0 ? _data$title : isTitleType(label) ? label.toString() : undefined;
332 return /*#__PURE__*/React.createElement("div", {
333 className: (0, _classnames.default)(itemPrefixCls, "".concat(itemPrefixCls, "-group"), data.className),
334 title: groupTitle
335 }, label !== undefined ? label : key);
336 }
337 var disabled = data.disabled,
338 title = data.title,
339 children = data.children,
340 style = data.style,
341 className = data.className,
342 otherProps = (0, _objectWithoutProperties2.default)(data, _excluded);
343 var passedProps = (0, _omit.default)(otherProps, omitFieldNameList);
344
345 // Option
346 var selected = isSelected(value);
347 var mergedDisabled = disabled || !selected && overMaxCount;
348 var optionPrefixCls = "".concat(itemPrefixCls, "-option");
349 var optionClassName = (0, _classnames.default)(itemPrefixCls, optionPrefixCls, className, (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({}, "".concat(optionPrefixCls, "-grouped"), groupOption), "".concat(optionPrefixCls, "-active"), activeIndex === itemIndex && !mergedDisabled), "".concat(optionPrefixCls, "-disabled"), mergedDisabled), "".concat(optionPrefixCls, "-selected"), selected));
350 var mergedLabel = getLabel(item);
351 var iconVisible = !menuItemSelectedIcon || typeof menuItemSelectedIcon === 'function' || selected;
352
353 // https://github.com/ant-design/ant-design/issues/34145
354 var content = typeof mergedLabel === 'number' ? mergedLabel : mergedLabel || value;
355 // https://github.com/ant-design/ant-design/issues/26717
356 var optionTitle = isTitleType(content) ? content.toString() : undefined;
357 if (title !== undefined) {
358 optionTitle = title;
359 }
360 return /*#__PURE__*/React.createElement("div", (0, _extends2.default)({}, (0, _pickAttrs.default)(passedProps), !virtual ? getItemAriaProps(item, itemIndex) : {}, {
361 "aria-selected": isAriaSelected(value),
362 className: optionClassName,
363 title: optionTitle,
364 onMouseMove: function onMouseMove() {
365 if (activeIndex === itemIndex || mergedDisabled) {
366 return;
367 }
368 setActive(itemIndex);
369 },
370 onClick: function onClick() {
371 if (!mergedDisabled) {
372 onSelectValue(value);
373 }
374 },
375 style: style
376 }), /*#__PURE__*/React.createElement("div", {
377 className: "".concat(optionPrefixCls, "-content")
378 }, typeof optionRender === 'function' ? optionRender(item, {
379 index: itemIndex
380 }) : content), /*#__PURE__*/React.isValidElement(menuItemSelectedIcon) || selected, iconVisible && /*#__PURE__*/React.createElement(_TransBtn.default, {
381 className: "".concat(itemPrefixCls, "-option-state"),
382 customizeIcon: menuItemSelectedIcon,
383 customizeIconProps: {
384 value: value,
385 disabled: mergedDisabled,
386 isSelected: selected
387 }
388 }, selected ? '✓' : null));
389 }));
390};
391var RefOptionList = /*#__PURE__*/React.forwardRef(OptionList);
392if (process.env.NODE_ENV !== 'production') {
393 RefOptionList.displayName = 'OptionList';
394}
395var _default = exports.default = RefOptionList;
\No newline at end of file