@via-profit/ui-kit 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,116 +32,105 @@ const MenuList_1 = __importDefault(require("./MenuList"));
32
32
  const Popper_1 = __importDefault(require("../Popper"));
33
33
  const ClickOutside_1 = __importDefault(require("../ClickOutside"));
34
34
  const onRequestCloseDefault = () => undefined;
35
+ const isEqual = (a, b) => {
36
+ if (a === b) {
37
+ return true;
38
+ }
39
+ if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) {
40
+ return false;
41
+ }
42
+ const keysA = Object.keys(a);
43
+ const keysB = Object.keys(b);
44
+ if (keysA.length !== keysB.length)
45
+ return false;
46
+ return keysA.every(key => Object.prototype.hasOwnProperty.call(b, key) && a[key] === b[key]);
47
+ };
35
48
  const MenuContainer = react_1.default.forwardRef((props, ref) => {
36
- const { items, value, anchorElement = null, overrides, children, closeOutsideClick = true, isOpen = false, anchorPos = 'bottom', positionStrategy, autoFlip, viewportMargin, offset, multiple = false, autofocus = true, closeOnSelect = !multiple, onRequestClose = onRequestCloseDefault, onAnchorPosChanged, zIndex, onSelectItem, getOptionSelected, } = props;
37
- const [actualPlacement, setActualPlacement] = react_1.default.useState(anchorPos);
49
+ const { items, value, anchorElement = null, overrides, children, closeOutsideClick = true, isOpen = false, anchorPos = 'bottom', alternativePlacements = ['bottom', 'top'], positionStrategy, autoFlip, viewportMargin, offset, multiple = false, autofocus = true, closeOnSelect = !multiple, onRequestClose = onRequestCloseDefault, onAnchorPosChanged, zIndex, onSelectItem, getOptionSelected, maxWidth, } = props;
50
+ // const [actualPlacement, setActualPlacement] = React.useState(anchorPos);
51
+ const [currentAnchorElement, setAnchorElement] = react_1.default.useState(anchorElement);
38
52
  const overridesMap = react_1.default.useMemo(() => ({
39
53
  List: (overrides === null || overrides === void 0 ? void 0 : overrides.List) || MenuList_1.default,
40
54
  Popper: (overrides === null || overrides === void 0 ? void 0 : overrides.Popper) || Popper_1.default,
41
- }), [overrides]);
42
- const getSelectedIndexes = react_1.default.useCallback(() => {
43
- const idx = new Set();
44
- if (value !== null) {
45
- if (typeof getOptionSelected === 'function') {
46
- if (multiple) {
47
- value.forEach(v => {
48
- idx.add(items.findIndex(item => getOptionSelected({ item, value: v })));
49
- });
50
- }
51
- else {
52
- idx.add(items.findIndex(item => getOptionSelected({ item, value: value })));
53
- }
54
- }
55
- else {
56
- if (multiple) {
57
- value.forEach(v => {
58
- idx.add(items.findIndex(item => JSON.stringify(item) === JSON.stringify(v)));
59
- });
60
- }
61
- else {
62
- idx.add(items.findIndex(item => JSON.stringify(item) === JSON.stringify(value)));
63
- }
64
- }
65
- }
66
- return [...idx];
67
- }, [getOptionSelected, items, multiple, value]);
68
- const [currentAnchorElement, setAnchorElement] = react_1.default.useState(anchorElement);
69
- const isOpenRef = react_1.default.useRef(isOpen);
55
+ }), [overrides === null || overrides === void 0 ? void 0 : overrides.List, overrides === null || overrides === void 0 ? void 0 : overrides.Popper]);
70
56
  const menuListRef = react_1.default.useRef(null);
71
57
  const menuPopperRef = react_1.default.useRef(null);
58
+ const isOpenRef = react_1.default.useRef(isOpen);
59
+ const focusTimeoutRef = react_1.default.useRef();
72
60
  const { dispatch, state: { selectedIndexes, markedIndex, hoveredIndex }, } = (0, context_1.default)();
73
61
  const selectedIndexesRef = react_1.default.useRef(selectedIndexes);
74
- const timeoutRef = react_1.default.useRef(null);
62
+ // Оптимизированная функция получения выбранных индексов
63
+ const getSelectedIndexes = react_1.default.useCallback(() => {
64
+ if (value === null || (multiple && value.length === 0)) {
65
+ return [];
66
+ }
67
+ const indexes = [];
68
+ const compareFunc = getOptionSelected
69
+ ? (item, val) => getOptionSelected({ item, value: val })
70
+ : (item, val) => isEqual(item, val);
71
+ if (multiple) {
72
+ const valueArray = value;
73
+ items.forEach((item, index) => {
74
+ if (valueArray.some(val => compareFunc(item, val))) {
75
+ indexes.push(index);
76
+ }
77
+ });
78
+ }
79
+ else {
80
+ const singleValue = value;
81
+ const index = items.findIndex(item => compareFunc(item, singleValue));
82
+ if (index !== -1) {
83
+ indexes.push(index);
84
+ }
85
+ }
86
+ return indexes;
87
+ }, [items, value, multiple, getOptionSelected]);
75
88
  const scrollToIndex = react_1.default.useCallback((index) => {
76
- var _a;
77
- const option = (_a = menuListRef === null || menuListRef === void 0 ? void 0 : menuListRef.current) === null || _a === void 0 ? void 0 : _a.children[index];
78
- if (option) {
79
- option.scrollIntoView({
80
- behavior: 'auto',
81
- block: 'nearest',
89
+ if (index === -1) {
90
+ return;
91
+ }
92
+ const container = menuListRef.current;
93
+ const option = container === null || container === void 0 ? void 0 : container.children[index];
94
+ if (container && option) {
95
+ const containerRect = container.getBoundingClientRect();
96
+ const optionRect = option.getBoundingClientRect();
97
+ const scrollOffset = optionRect.top - containerRect.top + container.scrollTop;
98
+ container.scrollTo({
99
+ top: scrollOffset,
100
+ behavior: 'instant'
82
101
  });
83
102
  }
84
103
  }, []);
85
- react_1.default.useEffect(() => {
86
- let timeout;
87
- const recalc = () => {
88
- if (timeout) {
89
- clearTimeout(timeout);
90
- }
91
- timeout = setTimeout(() => {
92
- if (anchorElement) {
93
- // calculateElementPos();
94
- }
95
- }, 300);
96
- };
97
- window.addEventListener('resize', recalc);
98
- window.addEventListener('scroll', recalc);
99
- recalc();
100
- return () => {
101
- window.removeEventListener('resize', recalc);
102
- window.removeEventListener('scroll', recalc);
103
- };
104
- }, [anchorElement, isOpen]);
105
- /**
106
- * Scroll to first of selected item
107
- */
108
104
  const scrollToFirstSelected = react_1.default.useCallback(() => {
109
- const indexes = [...selectedIndexes];
110
- // Sort array of indexes by DESC and get the index
111
- const index = indexes.length ? [...indexes.sort()][0] : -1;
112
- dispatch({
113
- type: 'setMenuState',
114
- payload: {
115
- markedIndex: index,
116
- },
117
- });
118
- scrollToIndex(index);
105
+ if (selectedIndexes.length === 0)
106
+ return;
107
+ const firstSelectedIndex = Math.min(...selectedIndexes);
108
+ dispatch((0, context_1.actionSetmenuState)({ markedIndex: firstSelectedIndex }));
109
+ scrollToIndex(firstSelectedIndex);
119
110
  }, [dispatch, selectedIndexes, scrollToIndex]);
120
- /**
121
- * Select specified item by index
122
- */
123
111
  const selectItem = react_1.default.useCallback((index) => {
112
+ if (index < 0 || index >= items.length)
113
+ return;
124
114
  const item = items[index];
125
- if (!item) {
115
+ if (!item)
126
116
  return;
127
- }
128
117
  if (typeof onSelectItem === 'function') {
129
- // For multiple
130
118
  if (multiple) {
131
- const selectedMap = new Map();
119
+ // Для multiple режима
120
+ const selectedSet = new Set();
132
121
  if (value !== null) {
133
- value.forEach(v => selectedMap.set(JSON.stringify(v), v));
122
+ value.forEach(v => selectedSet.add(v));
134
123
  }
135
124
  if (selectedIndexes.includes(index)) {
136
- selectedMap.delete(JSON.stringify(item));
125
+ selectedSet.delete(item);
137
126
  }
138
- if (!selectedIndexes.includes(index)) {
139
- selectedMap.set(JSON.stringify(item), item);
127
+ else {
128
+ selectedSet.add(item);
140
129
  }
141
- onSelectItem(Array.from(selectedMap, ([_key, v]) => v));
130
+ onSelectItem(Array.from(selectedSet));
142
131
  }
143
132
  else {
144
- // For single
133
+ // Для single режима
145
134
  onSelectItem(item);
146
135
  }
147
136
  if (closeOnSelect) {
@@ -149,232 +138,194 @@ const MenuContainer = react_1.default.forwardRef((props, ref) => {
149
138
  }
150
139
  }
151
140
  }, [onSelectItem, onRequestClose, selectedIndexes, closeOnSelect, items, value, multiple]);
152
- /**
153
- * Highlight specified item by index
154
- */
155
141
  const highlightIndex = react_1.default.useCallback((index) => {
156
- dispatch((0, context_1.actionSetmenuState)({ markedIndex: items[index] ? index : -1 }));
157
- scrollToIndex(index);
158
- }, [dispatch, items, scrollToIndex]);
159
- const hightlightPrevItem = react_1.default.useCallback(() => {
160
- const index = Math.max(markedIndex - 1, 0);
161
- highlightIndex(index);
162
- scrollToIndex(index);
163
- }, [markedIndex, highlightIndex, scrollToIndex]);
164
- const hightlightNextItem = react_1.default.useCallback(() => {
165
- const index = Math.min(markedIndex + 1, items.length);
166
- highlightIndex(index);
167
- scrollToIndex(index);
168
- }, [markedIndex, items.length, highlightIndex, scrollToIndex]);
169
- const hightlightFirstItem = react_1.default.useCallback(() => {
170
- const index = 0;
171
- highlightIndex(index);
172
- scrollToIndex(index);
173
- }, [highlightIndex, scrollToIndex]);
174
- const hightlightLastItem = react_1.default.useCallback(() => {
175
- const index = items.length - 1;
176
- highlightIndex(index);
177
- scrollToIndex(index);
178
- }, [highlightIndex, scrollToIndex, items.length]);
179
- const selectHightlightedItem = react_1.default.useCallback(() => {
180
- if (markedIndex > -1) {
142
+ const validIndex = Math.max(-1, Math.min(index, items.length - 1));
143
+ if (validIndex !== markedIndex) {
144
+ dispatch((0, context_1.actionSetmenuState)({ markedIndex: validIndex }));
145
+ scrollToIndex(validIndex);
146
+ }
147
+ }, [dispatch, items.length, markedIndex, scrollToIndex]);
148
+ const highlightPrevItem = react_1.default.useCallback(() => {
149
+ const newIndex = markedIndex - 1;
150
+ highlightIndex(newIndex >= 0 ? newIndex : 0);
151
+ }, [markedIndex, highlightIndex]);
152
+ const highlightNextItem = react_1.default.useCallback(() => {
153
+ const newIndex = markedIndex + 1;
154
+ highlightIndex(newIndex < items.length ? newIndex : items.length - 1);
155
+ }, [markedIndex, items.length, highlightIndex]);
156
+ const highlightFirstItem = react_1.default.useCallback(() => {
157
+ highlightIndex(0);
158
+ }, [highlightIndex]);
159
+ const highlightLastItem = react_1.default.useCallback(() => {
160
+ highlightIndex(items.length - 1);
161
+ }, [highlightIndex, items.length]);
162
+ const selectHighlightedItem = react_1.default.useCallback(() => {
163
+ if (markedIndex > -1 && markedIndex < items.length) {
181
164
  selectItem(markedIndex);
182
165
  }
183
- }, [markedIndex, selectItem]);
184
- /**
185
- * API
186
- */
166
+ }, [markedIndex, selectItem, items.length]);
167
+ // API ref
187
168
  react_1.default.useImperativeHandle(ref, () => ({
188
169
  focus: () => { var _a; return (_a = menuListRef.current) === null || _a === void 0 ? void 0 : _a.focus(); },
189
170
  scrollToIndex: (idx) => scrollToIndex(idx),
190
171
  highlightIndex: (idx) => highlightIndex(idx),
191
- highlightPrevItem: () => hightlightPrevItem(),
192
- highlightNextItem: () => hightlightNextItem(),
193
- highlightFirstItem: () => hightlightFirstItem(),
194
- highlightLastItem: () => hightlightLastItem(),
172
+ highlightPrevItem: () => highlightPrevItem(),
173
+ highlightNextItem: () => highlightNextItem(),
174
+ highlightFirstItem: () => highlightFirstItem(),
175
+ highlightLastItem: () => highlightLastItem(),
195
176
  scrollToFirstSelected: () => scrollToFirstSelected(),
196
- selectHighlightedItem: () => selectHightlightedItem(),
177
+ selectHighlightedItem: () => selectHighlightedItem(),
197
178
  selectItem: (idx) => selectItem(idx),
198
179
  getListElement: () => menuListRef.current,
199
- setActualPlacement: placement => setActualPlacement(placement),
180
+ // setActualPlacement: placement => setActualPlacement(placement),
200
181
  }), [
201
182
  scrollToIndex,
202
183
  highlightIndex,
203
- hightlightPrevItem,
204
- hightlightNextItem,
205
- hightlightFirstItem,
206
- hightlightLastItem,
207
- selectHightlightedItem,
184
+ highlightPrevItem,
185
+ highlightNextItem,
186
+ highlightFirstItem,
187
+ highlightLastItem,
188
+ selectHighlightedItem,
208
189
  scrollToFirstSelected,
209
190
  selectItem,
210
191
  ]);
211
- /**
212
- * Update achnor
213
- */
192
+ // Обновление anchor элемента
214
193
  react_1.default.useEffect(() => {
215
194
  if (anchorElement !== currentAnchorElement) {
216
195
  setAnchorElement(anchorElement);
217
196
  }
218
197
  }, [anchorElement, currentAnchorElement]);
219
- /**
220
- * Keyboard events of menu list container.
221
- * Note: Moved selection up and down while keys pressed
222
- */
198
+ // Обработчик клавиатуры
223
199
  const listKeydownEvent = react_1.default.useCallback((event) => {
224
200
  switch (event.code) {
225
201
  case 'Enter':
226
202
  case 'NumpadEnter':
227
- case 'Tab':
228
203
  event.preventDefault();
229
- if (markedIndex > -1) {
204
+ if (markedIndex > -1 && markedIndex < items.length) {
230
205
  selectItem(markedIndex);
231
206
  }
232
207
  break;
233
208
  case 'ArrowUp':
234
- {
235
- event.preventDefault();
236
- hightlightPrevItem();
237
- }
209
+ event.preventDefault();
210
+ highlightPrevItem();
238
211
  break;
239
212
  case 'ArrowDown':
240
- {
241
- event.preventDefault();
242
- hightlightNextItem();
243
- }
213
+ event.preventDefault();
214
+ highlightNextItem();
244
215
  break;
245
216
  case 'Home':
246
- {
247
- event.preventDefault();
248
- hightlightFirstItem();
249
- }
217
+ event.preventDefault();
218
+ highlightFirstItem();
250
219
  break;
251
220
  case 'End':
252
- {
253
- event.preventDefault();
254
- hightlightLastItem();
255
- }
256
- break;
257
- case 'PageUp':
258
- case 'PageDown':
259
- case 'Space':
260
221
  event.preventDefault();
222
+ highlightLastItem();
261
223
  break;
262
224
  case 'Escape':
263
225
  event.preventDefault();
264
226
  onRequestClose(event);
265
227
  break;
266
228
  default:
267
- // do nothing
268
229
  break;
269
230
  }
270
231
  }, [
271
232
  markedIndex,
272
- onRequestClose,
233
+ items.length,
273
234
  selectItem,
274
- hightlightPrevItem,
275
- hightlightNextItem,
276
- hightlightFirstItem,
277
- hightlightLastItem,
235
+ highlightPrevItem,
236
+ highlightNextItem,
237
+ highlightFirstItem,
238
+ highlightLastItem,
239
+ onRequestClose,
278
240
  ]);
241
+ // Управление открытием/закрытием меню
279
242
  react_1.default.useEffect(() => {
280
- const timeoutID = timeoutRef.current;
281
- return () => {
282
- if (timeoutID) {
283
- clearTimeout(timeoutID);
284
- }
285
- };
286
- }, []);
287
- react_1.default.useEffect(() => {
288
- const windowResizeEvent = (_event) => {
289
- if (timeoutRef.current) {
290
- clearTimeout(timeoutRef.current);
291
- }
292
- };
293
- window.document.addEventListener('resize', windowResizeEvent);
294
- return () => {
295
- window.document.removeEventListener('resize', windowResizeEvent);
296
- };
297
- }, [isOpen, onRequestClose, anchorElement, closeOutsideClick]);
298
- /**
299
- * Toggle menu open
300
- */
301
- react_1.default.useEffect(() => {
302
- if (isOpenRef.current !== isOpen) {
303
- isOpenRef.current = Boolean(isOpen);
304
- // setMenuOpen(Boolean(isOpen));
305
- if (!isOpen) {
306
- onRequestClose();
307
- }
308
- if (isOpen) {
309
- scrollToFirstSelected();
310
- if (autofocus) {
311
- setTimeout(() => {
312
- var _a;
313
- (_a = menuListRef.current) === null || _a === void 0 ? void 0 : _a.focus();
314
- }, 15);
315
- }
316
- }
317
- // Reset indexes
318
- if (!isOpen) {
319
- // listVirtRef.current?.scrollToIndex(0);
320
- dispatch((0, context_1.actionSetmenuState)({ markedIndex: -1, hoveredIndex: -1 }));
243
+ if (isOpenRef.current === isOpen)
244
+ return;
245
+ isOpenRef.current = isOpen;
246
+ if (!isOpen) {
247
+ onRequestClose();
248
+ dispatch((0, context_1.actionSetmenuState)({ markedIndex: -1, hoveredIndex: -1 }));
249
+ return;
250
+ }
251
+ // При открытии
252
+ scrollToFirstSelected();
253
+ if (autofocus) {
254
+ // Очищаем предыдущий таймаут
255
+ if (focusTimeoutRef.current) {
256
+ clearTimeout(focusTimeoutRef.current);
321
257
  }
258
+ focusTimeoutRef.current = setTimeout(() => {
259
+ var _a;
260
+ (_a = menuListRef.current) === null || _a === void 0 ? void 0 : _a.focus();
261
+ }, 15);
322
262
  }
323
- }, [getSelectedIndexes, scrollToFirstSelected, isOpen, autofocus, dispatch, onRequestClose]);
324
- /**
325
- * Mark selected items by values
326
- */
263
+ }, [isOpen, autofocus, dispatch, onRequestClose, scrollToFirstSelected]);
264
+ // Обновление выбранных индексов
327
265
  react_1.default.useEffect(() => {
328
266
  const indexes = getSelectedIndexes();
329
- // If elements in selectedIndexesRef and indexes are not equal
330
- if (!(selectedIndexesRef.current.length === indexes.length &&
331
- selectedIndexesRef.current.every(value => indexes.includes(value)))) {
267
+ // Сравниваем массивы эффективно
268
+ const hasChanged = selectedIndexesRef.current.length !== indexes.length ||
269
+ selectedIndexesRef.current.some((value, idx) => value !== indexes[idx]);
270
+ if (hasChanged) {
332
271
  selectedIndexesRef.current = indexes;
333
272
  dispatch({
334
273
  type: 'setMenuState',
335
- payload: {
336
- selectedIndexes: indexes,
337
- },
274
+ payload: { selectedIndexes: indexes },
338
275
  });
339
276
  }
340
- }, [value, getSelectedIndexes, dispatch]);
341
- const itemClickHandler = react_1.default.useCallback((index) => () => {
342
- selectItem(index);
343
- }, [selectItem]);
344
- const itemMouseLeaveHandler = react_1.default.useCallback((index, hoveredIndex) => () => {
345
- if (index === hoveredIndex) {
277
+ }, [getSelectedIndexes, dispatch]);
278
+ const itemClickHandler = react_1.default.useCallback((index) => () => selectItem(index), [selectItem]);
279
+ const itemMouseEnterHandler = react_1.default.useCallback((index) => () => {
280
+ if (index !== hoveredIndex) {
346
281
  dispatch((0, context_1.actionSetmenuState)({
347
- hoveredIndex: -1,
282
+ hoveredIndex: index,
348
283
  markedIndex: -1,
349
284
  }));
350
285
  }
351
- }, [dispatch]);
352
- const itemMouseEnterHandler = react_1.default.useCallback((index, hoveredIndex) => () => {
353
- if (index !== hoveredIndex) {
286
+ }, [dispatch, hoveredIndex]);
287
+ const itemMouseLeaveHandler = react_1.default.useCallback((index) => () => {
288
+ if (index === hoveredIndex) {
354
289
  dispatch((0, context_1.actionSetmenuState)({
355
- hoveredIndex: index,
290
+ hoveredIndex: -1,
356
291
  markedIndex: -1,
357
292
  }));
358
293
  }
359
- }, [dispatch]);
294
+ }, [dispatch, hoveredIndex]);
295
+ const onAnchorPosChangedMemo = react_1.default.useCallback((newPlacement) => {
296
+ if (typeof onAnchorPosChanged === 'function') {
297
+ onAnchorPosChanged(newPlacement);
298
+ }
299
+ }, [onAnchorPosChanged]);
300
+ const renderedChildren = react_1.default.useMemo(() => items.map((item, index) => children({ item, index }, {
301
+ key: index,
302
+ onMouseEnter: itemMouseEnterHandler(index),
303
+ onMouseLeave: itemMouseLeaveHandler(index),
304
+ onClick: itemClickHandler(index),
305
+ selected: selectedIndexes.includes(index),
306
+ hovered: hoveredIndex === index || markedIndex === index,
307
+ })), [
308
+ items,
309
+ children,
310
+ selectedIndexes,
311
+ hoveredIndex,
312
+ markedIndex,
313
+ itemMouseEnterHandler,
314
+ itemMouseLeaveHandler,
315
+ itemClickHandler,
316
+ ]);
317
+ // Cleanup on unmount
318
+ react_1.default.useEffect(() => () => {
319
+ if (focusTimeoutRef.current) {
320
+ clearTimeout(focusTimeoutRef.current);
321
+ }
322
+ }, []);
323
+ // Мемоизация компонентов
324
+ const PopperComponent = overridesMap.Popper;
325
+ const ListComponent = overridesMap.List;
360
326
  return (react_1.default.createElement(ClickOutside_1.default, { onOutsideClick: onRequestClose, mouseEvent: isOpen && closeOutsideClick ? 'onMouseDown' : false },
361
- react_1.default.createElement(overridesMap.Popper, { isOpen: Boolean(isOpen), ref: menuPopperRef, zIndex: zIndex, anchorPos: actualPlacement, anchorElement: anchorElement, onAnchorPosChanged: newPlacement => {
362
- setActualPlacement(newPlacement);
363
- if (typeof onAnchorPosChanged === 'function') {
364
- onAnchorPosChanged(newPlacement);
365
- }
366
- }, positionStrategy: positionStrategy, autoFlip: autoFlip, viewportMargin: viewportMargin, offset: offset },
367
- react_1.default.createElement(overridesMap.List, { anchorPos: actualPlacement, isOpen: Boolean(isOpen), ref: menuListRef, onKeyDown: listKeydownEvent }, items.map((item, index) => children({
368
- item,
369
- index,
370
- }, {
371
- key: index,
372
- onMouseEnter: itemMouseEnterHandler(index, hoveredIndex),
373
- onMouseLeave: itemMouseLeaveHandler(index, hoveredIndex),
374
- onClick: itemClickHandler(index),
375
- selected: selectedIndexes.includes(index),
376
- hovered: hoveredIndex === index || markedIndex === index,
377
- }))))));
327
+ react_1.default.createElement(PopperComponent, { isOpen: Boolean(isOpen), ref: menuPopperRef, zIndex: zIndex, anchorPos: anchorPos, alternativePlacements: alternativePlacements, anchorElement: anchorElement, onAnchorPosChanged: onAnchorPosChangedMemo, positionStrategy: positionStrategy, autoFlip: autoFlip, viewportMargin: viewportMargin, offset: offset },
328
+ react_1.default.createElement(ListComponent, { anchorPos: anchorPos, isOpen: Boolean(isOpen), ref: menuListRef, maxWidth: maxWidth, onKeyDown: listKeydownEvent }, renderedChildren))));
378
329
  });
379
330
  MenuContainer.displayName = 'MenuContainer';
380
331
  exports.default = MenuContainer;
@@ -3,6 +3,7 @@ import { AnchorPos } from '../Popper';
3
3
  export interface MenuListProps extends React.HTMLAttributes<HTMLDivElement> {
4
4
  readonly isOpen: boolean;
5
5
  readonly anchorPos: AnchorPos;
6
+ readonly maxWidth?: number | string;
6
7
  }
7
8
  export declare const MenuList: React.ForwardRefExoticComponent<MenuListProps & React.RefAttributes<HTMLDivElement>>;
8
9
  export default MenuList;
package/Menu/MenuList.js CHANGED
@@ -27,6 +27,19 @@ const StyledMenuList = styled_1.default.div `
27
27
  border-radius: ${({ theme }) => theme.shape.radiusFactor * 2}em;
28
28
  box-shadow: 0 0.5em 1.5em ${({ theme }) => theme.color.surface.darken(50).alpha(0.6).toString()};
29
29
 
30
+ ${({ $maxWidth }) => {
31
+ if (typeof $maxWidth === 'number') {
32
+ return (0, react_2.css) `
33
+ max-width: ${$maxWidth}px;
34
+ `;
35
+ }
36
+ if (typeof $maxWidth === 'string') {
37
+ return (0, react_2.css) `
38
+ max-width: ${$maxWidth};
39
+ `;
40
+ }
41
+ return undefined;
42
+ }};
30
43
  &:focus {
31
44
  outline-style: solid;
32
45
  outline-width: 0.14em;
@@ -64,24 +77,10 @@ const StyledMenuList = styled_1.default.div `
64
77
  overflow-y: auto;
65
78
  padding: 0.4em;
66
79
  max-height: 18em;
67
- min-width: 10em;
68
-
69
- max-width: 100%;
70
-
71
- ${({ $fixedWidth }) => $fixedWidth &&
72
- (0, react_2.css) `
73
- min-width: 10em;
74
- max-width: 16em;
75
- `}
76
-
77
- ${({ $anchorPos, theme }) => $anchorPos === 'top-fill' &&
78
- (0, react_2.css) `
79
- box-shadow: 0 -0.5em 1.5em ${theme.color.surface.darken(50).alpha(0.6).toString()};
80
- `};
81
80
  `;
82
81
  exports.MenuList = react_1.default.forwardRef((props, ref) => {
83
- const { isOpen, anchorPos, children } = props, nativeProps = __rest(props, ["isOpen", "anchorPos", "children"]);
84
- return (react_1.default.createElement(StyledMenuList, Object.assign({ tabIndex: -1, "$isOpen": isOpen, "$anchorPos": anchorPos, "$fixedWidth": !['bottom-fill', 'top-fill'].includes(anchorPos) }, nativeProps, { ref: ref }), children));
82
+ const { isOpen, anchorPos, maxWidth, children } = props, nativeProps = __rest(props, ["isOpen", "anchorPos", "maxWidth", "children"]);
83
+ return (react_1.default.createElement(StyledMenuList, Object.assign({ tabIndex: -1, "$isOpen": isOpen, "$maxWidth": maxWidth, "$anchorPos": anchorPos }, nativeProps, { ref: ref }), children));
85
84
  });
86
85
  exports.MenuList.displayName = 'MenuList';
87
86
  exports.default = exports.MenuList;
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { PopperContainerProps, PositionStrategy } from './PopperContainer';
3
- import { AnchorPos } from './usePopprer';
4
- export * from './usePopprer';
3
+ import { AnchorPos } from './usePopper';
4
+ export * from './usePopper';
5
5
  export interface PopperProps extends React.HTMLAttributes<HTMLDivElement> {
6
6
  /**
7
7
  * Controls the visibility of the popper.
@@ -38,6 +38,7 @@ export interface PopperProps extends React.HTMLAttributes<HTMLDivElement> {
38
38
  * ```
39
39
  */
40
40
  readonly anchorPos?: AnchorPos;
41
+ readonly alternativePlacements?: readonly AnchorPos[];
41
42
  readonly onAnchorPosChanged?: (anchorPos: AnchorPos) => void;
42
43
  /**
43
44
  * The z-index value for the popper container.