@carbon/react 1.78.0-rc.0 → 1.78.0
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.
- package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +877 -842
- package/es/components/ComboBox/ComboBox.js +6 -6
- package/es/components/ComboButton/index.js +0 -1
- package/es/components/ContextMenu/useContextMenu.d.ts +0 -1
- package/es/components/ContextMenu/useContextMenu.js +1 -2
- package/es/components/Menu/Menu.d.ts +1 -0
- package/es/components/Menu/Menu.js +5 -7
- package/es/components/Menu/MenuContext.d.ts +4 -4
- package/es/components/Menu/MenuContext.js +6 -1
- package/es/components/Menu/MenuItem.d.ts +1 -1
- package/es/components/Menu/MenuItem.js +14 -22
- package/es/components/MenuButton/index.js +14 -2
- package/es/components/Notification/Notification.js +4 -5
- package/lib/components/ComboBox/ComboBox.js +6 -6
- package/lib/components/ComboButton/index.js +0 -1
- package/lib/components/ContextMenu/useContextMenu.d.ts +0 -1
- package/lib/components/ContextMenu/useContextMenu.js +1 -2
- package/lib/components/Menu/Menu.d.ts +1 -0
- package/lib/components/Menu/Menu.js +5 -7
- package/lib/components/Menu/MenuContext.d.ts +4 -4
- package/lib/components/Menu/MenuContext.js +6 -1
- package/lib/components/Menu/MenuItem.d.ts +1 -1
- package/lib/components/Menu/MenuItem.js +13 -21
- package/lib/components/MenuButton/index.js +14 -2
- package/lib/components/Notification/Notification.js +4 -5
- package/package.json +5 -5
|
@@ -215,7 +215,7 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
215
215
|
const textInput = useRef(null);
|
|
216
216
|
const comboBoxInstanceId = useId();
|
|
217
217
|
const [isFocused, setIsFocused] = useState(false);
|
|
218
|
-
const
|
|
218
|
+
const prevInputValue = useRef(inputValue);
|
|
219
219
|
const prevSelectedItemProp = useRef(selectedItemProp);
|
|
220
220
|
|
|
221
221
|
// fully controlled combobox: handle changes to selectedItemProp
|
|
@@ -246,12 +246,12 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
246
246
|
itemToString,
|
|
247
247
|
inputValue
|
|
248
248
|
}) : defaultShouldFilterItem());
|
|
249
|
+
|
|
250
|
+
// call onInputChange whenever inputValue is updated
|
|
249
251
|
useEffect(() => {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if (savedOnInputChange.current) {
|
|
254
|
-
savedOnInputChange.current(inputValue);
|
|
252
|
+
if (prevInputValue.current !== inputValue) {
|
|
253
|
+
prevInputValue.current = inputValue;
|
|
254
|
+
onInputChange && onInputChange(inputValue);
|
|
255
255
|
}
|
|
256
256
|
}, [inputValue]);
|
|
257
257
|
const handleSelectionClear = () => {
|
|
@@ -27,6 +27,7 @@ export interface MenuProps extends React.HTMLAttributes<HTMLUListElement> {
|
|
|
27
27
|
*/
|
|
28
28
|
menuAlignment?: string;
|
|
29
29
|
/**
|
|
30
|
+
* @deprecated Menus now always support both icons as well as selectable items and nesting.
|
|
30
31
|
* The mode of this menu. Defaults to full.
|
|
31
32
|
* `full` supports nesting and selectable menu items, but no icons.
|
|
32
33
|
* `basic` supports icons but no nesting or selectable menu items.
|
|
@@ -12,7 +12,7 @@ import React__default, { forwardRef, useRef, useContext, useReducer, useMemo, us
|
|
|
12
12
|
import { createPortal } from 'react-dom';
|
|
13
13
|
import { useMergedRefs } from '../../internal/useMergedRefs.js';
|
|
14
14
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
15
|
-
import
|
|
15
|
+
import deprecate from '../../prop-types/deprecate.js';
|
|
16
16
|
import { MenuContext, menuReducer } from './MenuContext.js';
|
|
17
17
|
import { canUseDOM } from '../../internal/environment.js';
|
|
18
18
|
import { useLayoutDirection } from '../LayoutDirection/useLayoutDirection.js';
|
|
@@ -28,7 +28,7 @@ const Menu = /*#__PURE__*/forwardRef(function Menu(_ref, forwardRef) {
|
|
|
28
28
|
containerRef,
|
|
29
29
|
label,
|
|
30
30
|
menuAlignment,
|
|
31
|
-
mode
|
|
31
|
+
mode,
|
|
32
32
|
onClose,
|
|
33
33
|
onOpen,
|
|
34
34
|
open,
|
|
@@ -44,14 +44,10 @@ const Menu = /*#__PURE__*/forwardRef(function Menu(_ref, forwardRef) {
|
|
|
44
44
|
const focusReturn = useRef(null);
|
|
45
45
|
const context = useContext(MenuContext);
|
|
46
46
|
const isRoot = context.state.isRoot;
|
|
47
|
-
if (context.state.mode === 'basic' && !isRoot) {
|
|
48
|
-
process.env.NODE_ENV !== "production" ? warning(false, 'Nested menus are not supported when the menu is in "basic" mode.') : void 0;
|
|
49
|
-
}
|
|
50
47
|
const menuSize = isRoot ? size : context.state.size;
|
|
51
48
|
const [childState, childDispatch] = useReducer(menuReducer, {
|
|
52
49
|
...context.state,
|
|
53
50
|
isRoot: false,
|
|
54
|
-
mode,
|
|
55
51
|
size,
|
|
56
52
|
requestCloseRoot: isRoot ? handleClose : context.state.requestCloseRoot
|
|
57
53
|
});
|
|
@@ -283,6 +279,7 @@ const Menu = /*#__PURE__*/forwardRef(function Menu(_ref, forwardRef) {
|
|
|
283
279
|
[`${prefix}--menu--open`]: open,
|
|
284
280
|
[`${prefix}--menu--shown`]: open && !legacyAutoalign || position[0] >= 0 && position[1] >= 0,
|
|
285
281
|
[`${prefix}--menu--with-icons`]: childContext.state.hasIcons,
|
|
282
|
+
[`${prefix}--menu--with-selectable-items`]: childContext.state.hasSelectableItems,
|
|
286
283
|
[`${prefix}--autoalign`]: !legacyAutoalign
|
|
287
284
|
});
|
|
288
285
|
const rendered = /*#__PURE__*/React__default.createElement(MenuContext.Provider, {
|
|
@@ -320,13 +317,14 @@ Menu.propTypes = {
|
|
|
320
317
|
*/
|
|
321
318
|
menuAlignment: PropTypes.string,
|
|
322
319
|
/**
|
|
320
|
+
* **Deprecated**: Menus now always support both icons as well as selectable items and nesting.
|
|
323
321
|
* The mode of this menu. Defaults to full.
|
|
324
322
|
* `full` supports nesting and selectable menu items, but no icons.
|
|
325
323
|
* `basic` supports icons but no nesting or selectable menu items.
|
|
326
324
|
*
|
|
327
325
|
* **This prop is not intended for use and will be set by the respective implementation (like useContextMenu, MenuButton, and ComboButton).**
|
|
328
326
|
*/
|
|
329
|
-
mode: PropTypes.oneOf(['full', 'basic']),
|
|
327
|
+
mode: deprecate(PropTypes.oneOf(['full', 'basic']), 'Menus now always support both icons as well as selectable items and nesting.'),
|
|
330
328
|
/**
|
|
331
329
|
* Provide an optional function to be called when the Menu should be closed.
|
|
332
330
|
*/
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { KeyboardEvent, RefObject } from 'react';
|
|
8
8
|
type ActionType = {
|
|
9
|
-
type: 'enableIcons' | 'registerItem';
|
|
9
|
+
type: 'enableIcons' | 'enableSelectableItems' | 'registerItem';
|
|
10
10
|
payload: any;
|
|
11
11
|
};
|
|
12
12
|
type StateType = {
|
|
13
13
|
isRoot: boolean;
|
|
14
|
-
mode: 'full' | 'basic';
|
|
15
14
|
hasIcons: boolean;
|
|
15
|
+
hasSelectableItems: boolean;
|
|
16
16
|
size: 'xs' | 'sm' | 'md' | 'lg' | null;
|
|
17
17
|
items: any[];
|
|
18
18
|
requestCloseRoot: (e: Pick<KeyboardEvent<HTMLUListElement>, 'type'>) => void;
|
|
@@ -20,13 +20,13 @@ type StateType = {
|
|
|
20
20
|
declare function menuReducer(state: StateType, action: ActionType): {
|
|
21
21
|
hasIcons: boolean;
|
|
22
22
|
isRoot: boolean;
|
|
23
|
-
|
|
23
|
+
hasSelectableItems: boolean;
|
|
24
24
|
size: "xs" | "sm" | "md" | "lg" | null;
|
|
25
25
|
items: any[];
|
|
26
26
|
requestCloseRoot: (e: Pick<KeyboardEvent<HTMLUListElement>, "type">) => void;
|
|
27
27
|
};
|
|
28
28
|
type DispatchFuncProps = {
|
|
29
|
-
type: '
|
|
29
|
+
type: ActionType['type'];
|
|
30
30
|
payload: {
|
|
31
31
|
ref: RefObject<HTMLLIElement>;
|
|
32
32
|
disabled: boolean;
|
|
@@ -9,8 +9,8 @@ import { createContext } from 'react';
|
|
|
9
9
|
|
|
10
10
|
const menuDefaultState = {
|
|
11
11
|
isRoot: true,
|
|
12
|
-
mode: 'full',
|
|
13
12
|
hasIcons: false,
|
|
13
|
+
hasSelectableItems: false,
|
|
14
14
|
size: null,
|
|
15
15
|
items: [],
|
|
16
16
|
requestCloseRoot: () => {}
|
|
@@ -22,6 +22,11 @@ function menuReducer(state, action) {
|
|
|
22
22
|
...state,
|
|
23
23
|
hasIcons: true
|
|
24
24
|
};
|
|
25
|
+
case 'enableSelectableItems':
|
|
26
|
+
return {
|
|
27
|
+
...state,
|
|
28
|
+
hasSelectableItems: true
|
|
29
|
+
};
|
|
25
30
|
case 'registerItem':
|
|
26
31
|
return {
|
|
27
32
|
...state,
|
|
@@ -31,7 +31,7 @@ export interface MenuItemProps extends LiHTMLAttributes<HTMLLIElement> {
|
|
|
31
31
|
*/
|
|
32
32
|
onClick?: (event: KeyboardEvent<HTMLLIElement> | MouseEvent<HTMLLIElement>) => void;
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* Sets the menu item's icon.
|
|
35
35
|
*/
|
|
36
36
|
renderIcon?: FC;
|
|
37
37
|
/**
|
|
@@ -10,11 +10,10 @@ import cx from 'classnames';
|
|
|
10
10
|
import PropTypes from 'prop-types';
|
|
11
11
|
import React__default, { forwardRef, useState, useContext, useRef, useEffect } from 'react';
|
|
12
12
|
import { useFloating, autoUpdate, offset, useInteractions, useHover, safePolygon, FloatingFocusManager } from '@floating-ui/react';
|
|
13
|
-
import { CaretLeft, CaretRight
|
|
13
|
+
import { Checkmark, CaretLeft, CaretRight } from '@carbon/icons-react';
|
|
14
14
|
import { useControllableState } from '../../internal/useControllableState.js';
|
|
15
15
|
import { useMergedRefs } from '../../internal/useMergedRefs.js';
|
|
16
16
|
import { usePrefix } from '../../internal/usePrefix.js';
|
|
17
|
-
import { warning } from '../../internal/warning.js';
|
|
18
17
|
import { Menu } from './Menu.js';
|
|
19
18
|
import { MenuContext } from './MenuContext.js';
|
|
20
19
|
import '../Text/index.js';
|
|
@@ -23,7 +22,7 @@ import { match } from '../../internal/keyboard/match.js';
|
|
|
23
22
|
import { Text } from '../Text/Text.js';
|
|
24
23
|
import { ArrowRight, Enter, Space } from '../../internal/keyboard/keys.js';
|
|
25
24
|
|
|
26
|
-
var _CaretLeft, _CaretRight;
|
|
25
|
+
var _Checkmark, _CaretLeft, _CaretRight;
|
|
27
26
|
const MenuItem = /*#__PURE__*/forwardRef(function MenuItem(_ref, forwardRef) {
|
|
28
27
|
let {
|
|
29
28
|
children,
|
|
@@ -134,15 +133,14 @@ const MenuItem = /*#__PURE__*/forwardRef(function MenuItem(_ref, forwardRef) {
|
|
|
134
133
|
setRtl(false);
|
|
135
134
|
}
|
|
136
135
|
}, [direction]);
|
|
137
|
-
const iconsAllowed = context.state.mode === 'basic' || rest.role === 'menuitemcheckbox' || rest.role === 'menuitemradio';
|
|
138
136
|
useEffect(() => {
|
|
139
|
-
if (
|
|
137
|
+
if (IconElement && !context.state.hasIcons) {
|
|
140
138
|
// @ts-ignore - TODO: Should we be passing payload?
|
|
141
139
|
context.dispatch({
|
|
142
140
|
type: 'enableIcons'
|
|
143
141
|
});
|
|
144
142
|
}
|
|
145
|
-
}, [
|
|
143
|
+
}, [IconElement, context.state.hasIcons, context]);
|
|
146
144
|
useEffect(() => {
|
|
147
145
|
Object.keys(floatingStyles).forEach(style => {
|
|
148
146
|
if (refs.floating.current && style !== 'position') {
|
|
@@ -166,8 +164,10 @@ const MenuItem = /*#__PURE__*/forwardRef(function MenuItem(_ref, forwardRef) {
|
|
|
166
164
|
onClick: handleClick,
|
|
167
165
|
onKeyDown: handleKeyDown
|
|
168
166
|
}, getReferenceProps()), /*#__PURE__*/React__default.createElement("div", {
|
|
167
|
+
className: `${prefix}--menu-item__selection-icon`
|
|
168
|
+
}, rest['aria-checked'] && (_Checkmark || (_Checkmark = /*#__PURE__*/React__default.createElement(Checkmark, null)))), /*#__PURE__*/React__default.createElement("div", {
|
|
169
169
|
className: `${prefix}--menu-item__icon`
|
|
170
|
-
},
|
|
170
|
+
}, IconElement && /*#__PURE__*/React__default.createElement(IconElement, null)), /*#__PURE__*/React__default.createElement(Text, {
|
|
171
171
|
as: "div",
|
|
172
172
|
className: `${prefix}--menu-item__label`,
|
|
173
173
|
title: label
|
|
@@ -212,7 +212,7 @@ MenuItem.propTypes = {
|
|
|
212
212
|
// @ts-ignore-next-line -- avoid spurious (?) TS2322 error
|
|
213
213
|
onClick: PropTypes.func,
|
|
214
214
|
/**
|
|
215
|
-
*
|
|
215
|
+
* Sets the menu item's icon.
|
|
216
216
|
*/
|
|
217
217
|
// @ts-ignore-next-line -- avoid spurious (?) TS2322 error
|
|
218
218
|
renderIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
@@ -233,9 +233,6 @@ const MenuItemSelectable = /*#__PURE__*/forwardRef(function MenuItemSelectable(_
|
|
|
233
233
|
} = _ref2;
|
|
234
234
|
const prefix = usePrefix();
|
|
235
235
|
const context = useContext(MenuContext);
|
|
236
|
-
if (context.state.mode === 'basic') {
|
|
237
|
-
process.env.NODE_ENV !== "production" ? warning(false, 'MenuItemSelectable is not supported when the menu is in "basic" mode.') : void 0;
|
|
238
|
-
}
|
|
239
236
|
const [checked, setChecked] = useControllableState({
|
|
240
237
|
value: selected,
|
|
241
238
|
onChange,
|
|
@@ -245,13 +242,13 @@ const MenuItemSelectable = /*#__PURE__*/forwardRef(function MenuItemSelectable(_
|
|
|
245
242
|
setChecked(!checked);
|
|
246
243
|
}
|
|
247
244
|
useEffect(() => {
|
|
248
|
-
if (!context.state.
|
|
245
|
+
if (!context.state.hasSelectableItems) {
|
|
249
246
|
// @ts-ignore - TODO: Should we be passing payload?
|
|
250
247
|
context.dispatch({
|
|
251
|
-
type: '
|
|
248
|
+
type: 'enableSelectableItems'
|
|
252
249
|
});
|
|
253
250
|
}
|
|
254
|
-
}, [context.state.
|
|
251
|
+
}, [context.state.hasSelectableItems, context]);
|
|
255
252
|
const classNames = cx(className, `${prefix}--menu-item-selectable--selected`);
|
|
256
253
|
return /*#__PURE__*/React__default.createElement(MenuItem, _extends({}, rest, {
|
|
257
254
|
ref: forwardRef,
|
|
@@ -259,7 +256,6 @@ const MenuItemSelectable = /*#__PURE__*/forwardRef(function MenuItemSelectable(_
|
|
|
259
256
|
className: classNames,
|
|
260
257
|
role: "menuitemcheckbox",
|
|
261
258
|
"aria-checked": checked,
|
|
262
|
-
renderIcon: checked ? Checkmark : undefined,
|
|
263
259
|
onClick: handleClick
|
|
264
260
|
}));
|
|
265
261
|
});
|
|
@@ -334,9 +330,6 @@ const MenuItemRadioGroup = /*#__PURE__*/forwardRef(function MenuItemRadioGroup(_
|
|
|
334
330
|
} = _ref4;
|
|
335
331
|
const prefix = usePrefix();
|
|
336
332
|
const context = useContext(MenuContext);
|
|
337
|
-
if (context.state.mode === 'basic') {
|
|
338
|
-
process.env.NODE_ENV !== "production" ? warning(false, 'MenuItemRadioGroup is not supported when the menu is in "basic" mode.') : void 0;
|
|
339
|
-
}
|
|
340
333
|
const [selection, setSelection] = useControllableState({
|
|
341
334
|
value: selectedItem,
|
|
342
335
|
onChange,
|
|
@@ -346,13 +339,13 @@ const MenuItemRadioGroup = /*#__PURE__*/forwardRef(function MenuItemRadioGroup(_
|
|
|
346
339
|
setSelection(item);
|
|
347
340
|
}
|
|
348
341
|
useEffect(() => {
|
|
349
|
-
if (!context.state.
|
|
342
|
+
if (!context.state.hasSelectableItems) {
|
|
350
343
|
// @ts-ignore - TODO: Should we be passing payload?
|
|
351
344
|
context.dispatch({
|
|
352
|
-
type: '
|
|
345
|
+
type: 'enableSelectableItems'
|
|
353
346
|
});
|
|
354
347
|
}
|
|
355
|
-
}, [context.state.
|
|
348
|
+
}, [context.state.hasSelectableItems, context]);
|
|
356
349
|
const classNames = cx(className, `${prefix}--menu-item-radio-group`);
|
|
357
350
|
return /*#__PURE__*/React__default.createElement("li", {
|
|
358
351
|
className: classNames,
|
|
@@ -366,7 +359,6 @@ const MenuItemRadioGroup = /*#__PURE__*/forwardRef(function MenuItemRadioGroup(_
|
|
|
366
359
|
label: itemToString(item),
|
|
367
360
|
role: "menuitemradio",
|
|
368
361
|
"aria-checked": item === selection,
|
|
369
|
-
renderIcon: item === selection ? Checkmark : undefined,
|
|
370
362
|
onClick: e => {
|
|
371
363
|
handleClick(item);
|
|
372
364
|
}
|
|
@@ -73,6 +73,15 @@ const MenuButton = /*#__PURE__*/forwardRef(function MenuButton(_ref, forwardRef)
|
|
|
73
73
|
// “break” the floating element out of a clipping ancestor.
|
|
74
74
|
// https://floating-ui.com/docs/misc#clipping
|
|
75
75
|
strategy: 'fixed',
|
|
76
|
+
// Submenus are using a fixed position to break out of the parent menu's
|
|
77
|
+
// box avoiding clipping while allowing for vertical scroll. When an
|
|
78
|
+
// element is using transform it establishes a new containing block
|
|
79
|
+
// block for all of its descendants. Therefore, its padding box will be
|
|
80
|
+
// used for fixed-positioned descendants. This would cause the submenu
|
|
81
|
+
// to be clipped by its parent menu.
|
|
82
|
+
// Reference: https://www.w3.org/TR/2019/CR-css-transforms-1-20190214/#current-transformation-matrix-computation
|
|
83
|
+
// Reference: https://github.com/carbon-design-system/carbon/pull/18153#issuecomment-2498548835
|
|
84
|
+
transform: false,
|
|
76
85
|
// Middleware order matters, arrow should be last
|
|
77
86
|
middleware: middlewares,
|
|
78
87
|
whileElementsMounted: autoUpdate
|
|
@@ -87,7 +96,11 @@ const MenuButton = /*#__PURE__*/forwardRef(function MenuButton(_ref, forwardRef)
|
|
|
87
96
|
useLayoutEffect(() => {
|
|
88
97
|
Object.keys(floatingStyles).forEach(style => {
|
|
89
98
|
if (refs.floating.current) {
|
|
90
|
-
|
|
99
|
+
let value = floatingStyles[style];
|
|
100
|
+
if (['top', 'right', 'bottom', 'left'].includes(style) && Number(value)) {
|
|
101
|
+
value += 'px';
|
|
102
|
+
}
|
|
103
|
+
refs.floating.current.style[style] = value;
|
|
91
104
|
}
|
|
92
105
|
});
|
|
93
106
|
}, [floatingStyles, refs.floating, middlewareData, placement, open]);
|
|
@@ -126,7 +139,6 @@ const MenuButton = /*#__PURE__*/forwardRef(function MenuButton(_ref, forwardRef)
|
|
|
126
139
|
id: id,
|
|
127
140
|
legacyAutoalign: false,
|
|
128
141
|
label: label,
|
|
129
|
-
mode: "basic",
|
|
130
142
|
size: size$1,
|
|
131
143
|
open: open,
|
|
132
144
|
onClose: handleClose,
|
|
@@ -730,11 +730,9 @@ function Callout(_ref8) {
|
|
|
730
730
|
[`${prefix}--actionable-notification--${kind}`]: kind,
|
|
731
731
|
[`${prefix}--actionable-notification--hide-close-button`]: true
|
|
732
732
|
});
|
|
733
|
-
const
|
|
734
|
-
useInteractiveChildrenNeedDescription(
|
|
735
|
-
return /*#__PURE__*/React__default.createElement("div", _extends({
|
|
736
|
-
ref: ref
|
|
737
|
-
}, rest, {
|
|
733
|
+
const childrenContainer = useRef(null);
|
|
734
|
+
useInteractiveChildrenNeedDescription(childrenContainer, `interactive child node(s) should have an \`aria-describedby\` property with a value matching the value of \`titleId\``);
|
|
735
|
+
return /*#__PURE__*/React__default.createElement("div", _extends({}, rest, {
|
|
738
736
|
className: containerClassName
|
|
739
737
|
}), /*#__PURE__*/React__default.createElement("div", {
|
|
740
738
|
className: `${prefix}--actionable-notification__details`
|
|
@@ -743,6 +741,7 @@ function Callout(_ref8) {
|
|
|
743
741
|
kind: kind,
|
|
744
742
|
iconDescription: statusIconDescription || `${kind} icon`
|
|
745
743
|
}), /*#__PURE__*/React__default.createElement("div", {
|
|
744
|
+
ref: childrenContainer,
|
|
746
745
|
className: `${prefix}--actionable-notification__text-wrapper`
|
|
747
746
|
}, title && /*#__PURE__*/React__default.createElement(Text, {
|
|
748
747
|
as: "div",
|
|
@@ -226,7 +226,7 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
226
226
|
const textInput = React.useRef(null);
|
|
227
227
|
const comboBoxInstanceId = useId.useId();
|
|
228
228
|
const [isFocused, setIsFocused] = React.useState(false);
|
|
229
|
-
const
|
|
229
|
+
const prevInputValue = React.useRef(inputValue);
|
|
230
230
|
const prevSelectedItemProp = React.useRef(selectedItemProp);
|
|
231
231
|
|
|
232
232
|
// fully controlled combobox: handle changes to selectedItemProp
|
|
@@ -257,12 +257,12 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
257
257
|
itemToString,
|
|
258
258
|
inputValue
|
|
259
259
|
}) : defaultShouldFilterItem());
|
|
260
|
+
|
|
261
|
+
// call onInputChange whenever inputValue is updated
|
|
260
262
|
React.useEffect(() => {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (savedOnInputChange.current) {
|
|
265
|
-
savedOnInputChange.current(inputValue);
|
|
263
|
+
if (prevInputValue.current !== inputValue) {
|
|
264
|
+
prevInputValue.current = inputValue;
|
|
265
|
+
onInputChange && onInputChange(inputValue);
|
|
266
266
|
}
|
|
267
267
|
}, [inputValue]);
|
|
268
268
|
const handleSelectionClear = () => {
|
|
@@ -27,6 +27,7 @@ export interface MenuProps extends React.HTMLAttributes<HTMLUListElement> {
|
|
|
27
27
|
*/
|
|
28
28
|
menuAlignment?: string;
|
|
29
29
|
/**
|
|
30
|
+
* @deprecated Menus now always support both icons as well as selectable items and nesting.
|
|
30
31
|
* The mode of this menu. Defaults to full.
|
|
31
32
|
* `full` supports nesting and selectable menu items, but no icons.
|
|
32
33
|
* `basic` supports icons but no nesting or selectable menu items.
|
|
@@ -16,7 +16,7 @@ var React = require('react');
|
|
|
16
16
|
var ReactDOM = require('react-dom');
|
|
17
17
|
var useMergedRefs = require('../../internal/useMergedRefs.js');
|
|
18
18
|
var usePrefix = require('../../internal/usePrefix.js');
|
|
19
|
-
var
|
|
19
|
+
var deprecate = require('../../prop-types/deprecate.js');
|
|
20
20
|
var MenuContext = require('./MenuContext.js');
|
|
21
21
|
var environment = require('../../internal/environment.js');
|
|
22
22
|
var useLayoutDirection = require('../LayoutDirection/useLayoutDirection.js');
|
|
@@ -38,7 +38,7 @@ const Menu = /*#__PURE__*/React.forwardRef(function Menu(_ref, forwardRef) {
|
|
|
38
38
|
containerRef,
|
|
39
39
|
label,
|
|
40
40
|
menuAlignment,
|
|
41
|
-
mode
|
|
41
|
+
mode,
|
|
42
42
|
onClose,
|
|
43
43
|
onOpen,
|
|
44
44
|
open,
|
|
@@ -54,14 +54,10 @@ const Menu = /*#__PURE__*/React.forwardRef(function Menu(_ref, forwardRef) {
|
|
|
54
54
|
const focusReturn = React.useRef(null);
|
|
55
55
|
const context = React.useContext(MenuContext.MenuContext);
|
|
56
56
|
const isRoot = context.state.isRoot;
|
|
57
|
-
if (context.state.mode === 'basic' && !isRoot) {
|
|
58
|
-
process.env.NODE_ENV !== "production" ? warning.warning(false, 'Nested menus are not supported when the menu is in "basic" mode.') : void 0;
|
|
59
|
-
}
|
|
60
57
|
const menuSize = isRoot ? size : context.state.size;
|
|
61
58
|
const [childState, childDispatch] = React.useReducer(MenuContext.menuReducer, {
|
|
62
59
|
...context.state,
|
|
63
60
|
isRoot: false,
|
|
64
|
-
mode,
|
|
65
61
|
size,
|
|
66
62
|
requestCloseRoot: isRoot ? handleClose : context.state.requestCloseRoot
|
|
67
63
|
});
|
|
@@ -293,6 +289,7 @@ const Menu = /*#__PURE__*/React.forwardRef(function Menu(_ref, forwardRef) {
|
|
|
293
289
|
[`${prefix}--menu--open`]: open,
|
|
294
290
|
[`${prefix}--menu--shown`]: open && !legacyAutoalign || position[0] >= 0 && position[1] >= 0,
|
|
295
291
|
[`${prefix}--menu--with-icons`]: childContext.state.hasIcons,
|
|
292
|
+
[`${prefix}--menu--with-selectable-items`]: childContext.state.hasSelectableItems,
|
|
296
293
|
[`${prefix}--autoalign`]: !legacyAutoalign
|
|
297
294
|
});
|
|
298
295
|
const rendered = /*#__PURE__*/React__default["default"].createElement(MenuContext.MenuContext.Provider, {
|
|
@@ -330,13 +327,14 @@ Menu.propTypes = {
|
|
|
330
327
|
*/
|
|
331
328
|
menuAlignment: PropTypes__default["default"].string,
|
|
332
329
|
/**
|
|
330
|
+
* **Deprecated**: Menus now always support both icons as well as selectable items and nesting.
|
|
333
331
|
* The mode of this menu. Defaults to full.
|
|
334
332
|
* `full` supports nesting and selectable menu items, but no icons.
|
|
335
333
|
* `basic` supports icons but no nesting or selectable menu items.
|
|
336
334
|
*
|
|
337
335
|
* **This prop is not intended for use and will be set by the respective implementation (like useContextMenu, MenuButton, and ComboButton).**
|
|
338
336
|
*/
|
|
339
|
-
mode: PropTypes__default["default"].oneOf(['full', 'basic']),
|
|
337
|
+
mode: deprecate["default"](PropTypes__default["default"].oneOf(['full', 'basic']), 'Menus now always support both icons as well as selectable items and nesting.'),
|
|
340
338
|
/**
|
|
341
339
|
* Provide an optional function to be called when the Menu should be closed.
|
|
342
340
|
*/
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { KeyboardEvent, RefObject } from 'react';
|
|
8
8
|
type ActionType = {
|
|
9
|
-
type: 'enableIcons' | 'registerItem';
|
|
9
|
+
type: 'enableIcons' | 'enableSelectableItems' | 'registerItem';
|
|
10
10
|
payload: any;
|
|
11
11
|
};
|
|
12
12
|
type StateType = {
|
|
13
13
|
isRoot: boolean;
|
|
14
|
-
mode: 'full' | 'basic';
|
|
15
14
|
hasIcons: boolean;
|
|
15
|
+
hasSelectableItems: boolean;
|
|
16
16
|
size: 'xs' | 'sm' | 'md' | 'lg' | null;
|
|
17
17
|
items: any[];
|
|
18
18
|
requestCloseRoot: (e: Pick<KeyboardEvent<HTMLUListElement>, 'type'>) => void;
|
|
@@ -20,13 +20,13 @@ type StateType = {
|
|
|
20
20
|
declare function menuReducer(state: StateType, action: ActionType): {
|
|
21
21
|
hasIcons: boolean;
|
|
22
22
|
isRoot: boolean;
|
|
23
|
-
|
|
23
|
+
hasSelectableItems: boolean;
|
|
24
24
|
size: "xs" | "sm" | "md" | "lg" | null;
|
|
25
25
|
items: any[];
|
|
26
26
|
requestCloseRoot: (e: Pick<KeyboardEvent<HTMLUListElement>, "type">) => void;
|
|
27
27
|
};
|
|
28
28
|
type DispatchFuncProps = {
|
|
29
|
-
type: '
|
|
29
|
+
type: ActionType['type'];
|
|
30
30
|
payload: {
|
|
31
31
|
ref: RefObject<HTMLLIElement>;
|
|
32
32
|
disabled: boolean;
|
|
@@ -13,8 +13,8 @@ var React = require('react');
|
|
|
13
13
|
|
|
14
14
|
const menuDefaultState = {
|
|
15
15
|
isRoot: true,
|
|
16
|
-
mode: 'full',
|
|
17
16
|
hasIcons: false,
|
|
17
|
+
hasSelectableItems: false,
|
|
18
18
|
size: null,
|
|
19
19
|
items: [],
|
|
20
20
|
requestCloseRoot: () => {}
|
|
@@ -26,6 +26,11 @@ function menuReducer(state, action) {
|
|
|
26
26
|
...state,
|
|
27
27
|
hasIcons: true
|
|
28
28
|
};
|
|
29
|
+
case 'enableSelectableItems':
|
|
30
|
+
return {
|
|
31
|
+
...state,
|
|
32
|
+
hasSelectableItems: true
|
|
33
|
+
};
|
|
29
34
|
case 'registerItem':
|
|
30
35
|
return {
|
|
31
36
|
...state,
|
|
@@ -31,7 +31,7 @@ export interface MenuItemProps extends LiHTMLAttributes<HTMLLIElement> {
|
|
|
31
31
|
*/
|
|
32
32
|
onClick?: (event: KeyboardEvent<HTMLLIElement> | MouseEvent<HTMLLIElement>) => void;
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* Sets the menu item's icon.
|
|
35
35
|
*/
|
|
36
36
|
renderIcon?: FC;
|
|
37
37
|
/**
|