UNPKG

15.9 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 return rawValues.has(value) && mode !== 'combobox';
132 }, [mode, (0, _toConsumableArray2.default)(rawValues).toString(), rawValues.size]);
133
134 // Auto scroll to item position in single mode
135 (0, _react.useEffect)(function () {
136 /**
137 * React will skip `onChange` when component update.
138 * `setActive` function will call root accessibility state update which makes re-render.
139 * So we need to delay to let Input component trigger onChange first.
140 */
141 var timeoutId = setTimeout(function () {
142 if (!multiple && open && rawValues.size === 1) {
143 var value = Array.from(rawValues)[0];
144 var index = memoFlattenOptions.findIndex(function (_ref2) {
145 var data = _ref2.data;
146 return data.value === value;
147 });
148 if (index !== -1) {
149 setActive(index);
150 scrollIntoView(index);
151 }
152 }
153 });
154
155 // Force trigger scrollbar visible when open
156 if (open) {
157 var _listRef$current2;
158 (_listRef$current2 = listRef.current) === null || _listRef$current2 === void 0 || _listRef$current2.scrollTo(undefined);
159 }
160 return function () {
161 return clearTimeout(timeoutId);
162 };
163 }, [open, searchValue]);
164
165 // ========================== Values ==========================
166 var onSelectValue = function onSelectValue(value) {
167 if (value !== undefined) {
168 onSelect(value, {
169 selected: !rawValues.has(value)
170 });
171 }
172
173 // Single mode should always close by select
174 if (!multiple) {
175 toggleOpen(false);
176 }
177 };
178
179 // ========================= Keyboard =========================
180 React.useImperativeHandle(ref, function () {
181 return {
182 onKeyDown: function onKeyDown(event) {
183 var which = event.which,
184 ctrlKey = event.ctrlKey;
185 switch (which) {
186 // >>> Arrow keys & ctrl + n/p on Mac
187 case _KeyCode.default.N:
188 case _KeyCode.default.P:
189 case _KeyCode.default.UP:
190 case _KeyCode.default.DOWN:
191 {
192 var offset = 0;
193 if (which === _KeyCode.default.UP) {
194 offset = -1;
195 } else if (which === _KeyCode.default.DOWN) {
196 offset = 1;
197 } else if ((0, _platformUtil.isPlatformMac)() && ctrlKey) {
198 if (which === _KeyCode.default.N) {
199 offset = 1;
200 } else if (which === _KeyCode.default.P) {
201 offset = -1;
202 }
203 }
204 if (offset !== 0) {
205 var nextActiveIndex = getEnabledActiveIndex(activeIndex + offset, offset);
206 scrollIntoView(nextActiveIndex);
207 setActive(nextActiveIndex, true);
208 }
209 break;
210 }
211
212 // >>> Select
213 case _KeyCode.default.ENTER:
214 {
215 var _item$data;
216 // value
217 var item = memoFlattenOptions[activeIndex];
218 if (item && !(item !== null && item !== void 0 && (_item$data = item.data) !== null && _item$data !== void 0 && _item$data.disabled) && !overMaxCount) {
219 onSelectValue(item.value);
220 } else {
221 onSelectValue(undefined);
222 }
223 if (open) {
224 event.preventDefault();
225 }
226 break;
227 }
228
229 // >>> Close
230 case _KeyCode.default.ESC:
231 {
232 toggleOpen(false);
233 if (open) {
234 event.stopPropagation();
235 }
236 }
237 }
238 },
239 onKeyUp: function onKeyUp() {},
240 scrollTo: function scrollTo(index) {
241 scrollIntoView(index);
242 }
243 };
244 });
245
246 // ========================== Render ==========================
247 if (memoFlattenOptions.length === 0) {
248 return /*#__PURE__*/React.createElement("div", {
249 role: "listbox",
250 id: "".concat(id, "_list"),
251 className: "".concat(itemPrefixCls, "-empty"),
252 onMouseDown: onListMouseDown
253 }, notFoundContent);
254 }
255 var omitFieldNameList = Object.keys(fieldNames).map(function (key) {
256 return fieldNames[key];
257 });
258 var getLabel = function getLabel(item) {
259 return item.label;
260 };
261 function getItemAriaProps(item, index) {
262 var group = item.group;
263 return {
264 role: group ? 'presentation' : 'option',
265 id: "".concat(id, "_list_").concat(index)
266 };
267 }
268 var renderItem = function renderItem(index) {
269 var item = memoFlattenOptions[index];
270 if (!item) {
271 return null;
272 }
273 var itemData = item.data || {};
274 var value = itemData.value;
275 var group = item.group;
276 var attrs = (0, _pickAttrs.default)(itemData, true);
277 var mergedLabel = getLabel(item);
278 return item ? /*#__PURE__*/React.createElement("div", (0, _extends2.default)({
279 "aria-label": typeof mergedLabel === 'string' && !group ? mergedLabel : null
280 }, attrs, {
281 key: index
282 }, getItemAriaProps(item, index), {
283 "aria-selected": isSelected(value)
284 }), value) : null;
285 };
286 var a11yProps = {
287 role: 'listbox',
288 id: "".concat(id, "_list")
289 };
290 return /*#__PURE__*/React.createElement(React.Fragment, null, virtual && /*#__PURE__*/React.createElement("div", (0, _extends2.default)({}, a11yProps, {
291 style: {
292 height: 0,
293 width: 0,
294 overflow: 'hidden'
295 }
296 }), renderItem(activeIndex - 1), renderItem(activeIndex), renderItem(activeIndex + 1)), /*#__PURE__*/React.createElement(_rcVirtualList.default, {
297 itemKey: "key",
298 ref: listRef,
299 data: memoFlattenOptions,
300 height: listHeight,
301 itemHeight: listItemHeight,
302 fullHeight: false,
303 onMouseDown: onListMouseDown,
304 onScroll: onPopupScroll,
305 virtual: virtual,
306 direction: direction,
307 innerProps: virtual ? null : a11yProps
308 }, function (item, itemIndex) {
309 var group = item.group,
310 groupOption = item.groupOption,
311 data = item.data,
312 label = item.label,
313 value = item.value;
314 var key = data.key;
315
316 // Group
317 if (group) {
318 var _data$title;
319 var groupTitle = (_data$title = data.title) !== null && _data$title !== void 0 ? _data$title : isTitleType(label) ? label.toString() : undefined;
320 return /*#__PURE__*/React.createElement("div", {
321 className: (0, _classnames.default)(itemPrefixCls, "".concat(itemPrefixCls, "-group"), data.className),
322 title: groupTitle
323 }, label !== undefined ? label : key);
324 }
325 var disabled = data.disabled,
326 title = data.title,
327 children = data.children,
328 style = data.style,
329 className = data.className,
330 otherProps = (0, _objectWithoutProperties2.default)(data, _excluded);
331 var passedProps = (0, _omit.default)(otherProps, omitFieldNameList);
332
333 // Option
334 var selected = isSelected(value);
335 var mergedDisabled = disabled || !selected && overMaxCount;
336 var optionPrefixCls = "".concat(itemPrefixCls, "-option");
337 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));
338 var mergedLabel = getLabel(item);
339 var iconVisible = !menuItemSelectedIcon || typeof menuItemSelectedIcon === 'function' || selected;
340
341 // https://github.com/ant-design/ant-design/issues/34145
342 var content = typeof mergedLabel === 'number' ? mergedLabel : mergedLabel || value;
343 // https://github.com/ant-design/ant-design/issues/26717
344 var optionTitle = isTitleType(content) ? content.toString() : undefined;
345 if (title !== undefined) {
346 optionTitle = title;
347 }
348 return /*#__PURE__*/React.createElement("div", (0, _extends2.default)({}, (0, _pickAttrs.default)(passedProps), !virtual ? getItemAriaProps(item, itemIndex) : {}, {
349 "aria-selected": selected,
350 className: optionClassName,
351 title: optionTitle,
352 onMouseMove: function onMouseMove() {
353 if (activeIndex === itemIndex || mergedDisabled) {
354 return;
355 }
356 setActive(itemIndex);
357 },
358 onClick: function onClick() {
359 if (!mergedDisabled) {
360 onSelectValue(value);
361 }
362 },
363 style: style
364 }), /*#__PURE__*/React.createElement("div", {
365 className: "".concat(optionPrefixCls, "-content")
366 }, typeof optionRender === 'function' ? optionRender(item, {
367 index: itemIndex
368 }) : content), /*#__PURE__*/React.isValidElement(menuItemSelectedIcon) || selected, iconVisible && /*#__PURE__*/React.createElement(_TransBtn.default, {
369 className: "".concat(itemPrefixCls, "-option-state"),
370 customizeIcon: menuItemSelectedIcon,
371 customizeIconProps: {
372 value: value,
373 disabled: mergedDisabled,
374 isSelected: selected
375 }
376 }, selected ? '✓' : null));
377 }));
378};
379var RefOptionList = /*#__PURE__*/React.forwardRef(OptionList);
380if (process.env.NODE_ENV !== 'production') {
381 RefOptionList.displayName = 'OptionList';
382}
383var _default = exports.default = RefOptionList;
\No newline at end of file