@carbon/react 1.89.0-rc.0 → 1.89.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 +1113 -851
- package/es/components/AILabel/index.d.ts +2 -5
- package/es/components/AILabel/index.js +2 -42
- package/es/components/ComposedModal/ComposedModal.js +2 -2
- package/es/components/Copy/Copy.js +1 -0
- package/es/components/DataTable/DataTable.js +10 -3
- package/es/components/Dialog/Dialog.d.ts +245 -0
- package/es/components/Dialog/Dialog.js +593 -0
- package/es/components/Dialog/index.d.ts +3 -251
- package/es/components/Dialog/index.js +1 -609
- package/es/components/FeatureFlags/index.d.ts +3 -1
- package/es/components/FeatureFlags/index.js +5 -2
- package/es/components/FileUploader/FileUploader.d.ts +28 -6
- package/es/components/FileUploader/FileUploader.js +152 -38
- package/es/components/Link/Link.js +15 -1
- package/es/components/Menu/MenuContext.d.ts +1 -1
- package/es/components/Menu/MenuContext.js +11 -4
- package/es/components/Menu/MenuItem.js +4 -10
- package/es/components/Modal/Modal.js +17 -9
- package/es/components/MultiSelect/FilterableMultiSelect.js +1 -5
- package/es/components/MultiSelect/MultiSelect.js +3 -7
- package/es/components/Popover/index.d.ts +4 -0
- package/es/components/Popover/index.js +8 -2
- package/es/components/StructuredList/StructuredList.d.ts +16 -0
- package/es/components/StructuredList/StructuredList.js +23 -11
- package/es/components/Toggletip/index.d.ts +13 -36
- package/es/components/Toggletip/index.js +12 -51
- package/es/index.d.ts +2 -1
- package/es/index.js +2 -0
- package/es/internal/Selection.js +1 -1
- package/es/internal/useMergedRefs.js +4 -3
- package/lib/components/AILabel/index.d.ts +2 -5
- package/lib/components/AILabel/index.js +1 -41
- package/lib/components/ComposedModal/ComposedModal.js +2 -2
- package/lib/components/Copy/Copy.js +1 -0
- package/lib/components/DataTable/DataTable.js +10 -3
- package/lib/components/Dialog/Dialog.d.ts +245 -0
- package/lib/components/Dialog/Dialog.js +602 -0
- package/lib/components/Dialog/index.d.ts +3 -251
- package/lib/components/Dialog/index.js +9 -614
- package/lib/components/FeatureFlags/index.d.ts +3 -1
- package/lib/components/FeatureFlags/index.js +5 -2
- package/lib/components/FileUploader/FileUploader.d.ts +28 -6
- package/lib/components/FileUploader/FileUploader.js +151 -37
- package/lib/components/Link/Link.js +15 -1
- package/lib/components/Menu/MenuContext.d.ts +1 -1
- package/lib/components/Menu/MenuContext.js +11 -4
- package/lib/components/Menu/MenuItem.js +4 -10
- package/lib/components/Modal/Modal.js +24 -16
- package/lib/components/MultiSelect/FilterableMultiSelect.js +1 -5
- package/lib/components/MultiSelect/MultiSelect.js +3 -7
- package/lib/components/Popover/index.d.ts +4 -0
- package/lib/components/Popover/index.js +8 -2
- package/lib/components/StructuredList/StructuredList.d.ts +16 -0
- package/lib/components/StructuredList/StructuredList.js +23 -11
- package/lib/components/Toggletip/index.d.ts +13 -36
- package/lib/components/Toggletip/index.js +11 -50
- package/lib/index.d.ts +2 -1
- package/lib/index.js +60 -58
- package/lib/internal/Selection.js +1 -1
- package/lib/internal/useMergedRefs.js +3 -2
- package/package.json +15 -16
- package/telemetry.yml +5 -2
|
@@ -5,6 +5,21 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
import React, { type HTMLAttributes } from 'react';
|
|
8
|
+
interface FileItem {
|
|
9
|
+
name: string;
|
|
10
|
+
uuid: string;
|
|
11
|
+
file: File;
|
|
12
|
+
}
|
|
13
|
+
export interface FileChangeData {
|
|
14
|
+
addedFiles: FileItem[];
|
|
15
|
+
removedFiles: FileItem[];
|
|
16
|
+
currentFiles: FileItem[];
|
|
17
|
+
action: 'add' | 'remove' | 'clear';
|
|
18
|
+
}
|
|
19
|
+
export interface FileDeleteData {
|
|
20
|
+
deletedFile: FileItem;
|
|
21
|
+
remainingFiles: FileItem[];
|
|
22
|
+
}
|
|
8
23
|
export interface FileUploaderProps extends HTMLAttributes<HTMLSpanElement> {
|
|
9
24
|
/**
|
|
10
25
|
* Specify the types of files that this input should be able to receive
|
|
@@ -52,20 +67,23 @@ export interface FileUploaderProps extends HTMLAttributes<HTMLSpanElement> {
|
|
|
52
67
|
*/
|
|
53
68
|
name?: string;
|
|
54
69
|
/**
|
|
55
|
-
* Provide an optional `onChange` hook that is called each time the input is
|
|
56
|
-
*
|
|
70
|
+
* Provide an optional `onChange` hook that is called each time the input is changed.
|
|
71
|
+
* When 'enable-enhanced-file-uploader' feature flag is enabled:
|
|
72
|
+
* - Also fires for file deletions and clearFiles operations
|
|
73
|
+
* - Event includes enhanced file information in event.target
|
|
57
74
|
*/
|
|
58
|
-
onChange?: (event: any) => void;
|
|
75
|
+
onChange?: (event: any, data?: FileChangeData) => void;
|
|
59
76
|
/**
|
|
60
77
|
* Provide an optional `onClick` hook that is called each time the
|
|
61
78
|
* FileUploader is clicked
|
|
62
79
|
*/
|
|
63
80
|
onClick?: (event: any) => void;
|
|
64
81
|
/**
|
|
65
|
-
* Provide an optional `onDelete` hook that is called when an uploaded item
|
|
66
|
-
* is
|
|
82
|
+
* Provide an optional `onDelete` hook that is called when an uploaded item is removed.
|
|
83
|
+
* When 'enable-enhanced-file-uploader' feature flag is enabled:
|
|
84
|
+
* - Event includes deleted file information in event.target
|
|
67
85
|
*/
|
|
68
|
-
onDelete?: (event: any) => void;
|
|
86
|
+
onDelete?: (event: any, data?: FileDeleteData) => void;
|
|
69
87
|
/**
|
|
70
88
|
* Specify the size of the FileUploaderButton, from a list of available
|
|
71
89
|
* sizes.
|
|
@@ -77,6 +95,10 @@ export interface FileUploaderHandle {
|
|
|
77
95
|
* Clear internal state
|
|
78
96
|
*/
|
|
79
97
|
clearFiles: () => void;
|
|
98
|
+
/**
|
|
99
|
+
* Get current files (only available when 'enable-enhanced-file-uploader' feature flag is enabled)
|
|
100
|
+
*/
|
|
101
|
+
getCurrentFiles?: () => FileItem[];
|
|
80
102
|
}
|
|
81
103
|
declare const FileUploader: {
|
|
82
104
|
<ItemType>(props: FileUploaderProps): React.ReactElement<any>;
|
|
@@ -21,6 +21,7 @@ var match = require('../../internal/keyboard/match.js');
|
|
|
21
21
|
var usePrefix = require('../../internal/usePrefix.js');
|
|
22
22
|
require('../Text/index.js');
|
|
23
23
|
var useId = require('../../internal/useId.js');
|
|
24
|
+
var index = require('../FeatureFlags/index.js');
|
|
24
25
|
var Text = require('../Text/Text.js');
|
|
25
26
|
|
|
26
27
|
const FileUploader = /*#__PURE__*/React.forwardRef(({
|
|
@@ -42,45 +43,149 @@ const FileUploader = /*#__PURE__*/React.forwardRef(({
|
|
|
42
43
|
...other
|
|
43
44
|
}, ref) => {
|
|
44
45
|
const fileUploaderInstanceId = useId.useId('file-uploader');
|
|
45
|
-
const [state, updateState] = React.useState({
|
|
46
|
-
fileNames: []
|
|
47
|
-
});
|
|
48
|
-
const nodes = [];
|
|
49
46
|
const prefix = usePrefix.usePrefix();
|
|
50
|
-
const
|
|
47
|
+
const enhancedFileUploaderEnabled = index.useFeatureFlag('enable-enhanced-file-uploader');
|
|
48
|
+
const [fileItems, setFileItems] = React.useState([]);
|
|
49
|
+
const [legacyFileNames, setLegacyFileNames] = React.useState([]);
|
|
50
|
+
const [fileObjects, setFileObjects] = React.useState(new Map());
|
|
51
|
+
const nodes = [];
|
|
52
|
+
const createFileItem = file => ({
|
|
53
|
+
name: file.name,
|
|
54
|
+
uuid: `${fileUploaderInstanceId}-${Date.now()}-${Array.from(crypto.getRandomValues(new Uint8Array(8))).map(b => b.toString(36)).join('')}`,
|
|
55
|
+
file
|
|
56
|
+
});
|
|
57
|
+
const handleChange = React.useCallback(evt => {
|
|
51
58
|
evt.stopPropagation();
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
const newFiles = Array.from(evt.target.files);
|
|
60
|
+
if (enhancedFileUploaderEnabled) {
|
|
61
|
+
const newFileItems = newFiles.map(createFileItem);
|
|
62
|
+
let updatedFileItems;
|
|
63
|
+
if (multiple) {
|
|
64
|
+
const existingNames = new Set(fileItems.map(item => item.name));
|
|
65
|
+
const uniqueNewItems = newFileItems.filter(item => !existingNames.has(item.name));
|
|
66
|
+
updatedFileItems = [...fileItems, ...uniqueNewItems];
|
|
67
|
+
} else {
|
|
68
|
+
updatedFileItems = newFileItems;
|
|
69
|
+
}
|
|
70
|
+
setFileItems(updatedFileItems);
|
|
71
|
+
if (onChange) {
|
|
72
|
+
const allFiles = updatedFileItems.map(item => item.file);
|
|
73
|
+
const enhancedEvent = {
|
|
74
|
+
...evt,
|
|
75
|
+
target: {
|
|
76
|
+
...evt.target,
|
|
77
|
+
files: Object.assign(allFiles, {
|
|
78
|
+
item: index => allFiles[index] || null
|
|
79
|
+
}),
|
|
80
|
+
addedFiles: newFileItems,
|
|
81
|
+
currentFiles: updatedFileItems,
|
|
82
|
+
action: 'add'
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
onChange(enhancedEvent);
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
const filenames = newFiles.map(file => file.name);
|
|
89
|
+
const updatedFileNames = multiple ? [...new Set([...legacyFileNames, ...filenames])] : filenames;
|
|
90
|
+
setLegacyFileNames(updatedFileNames);
|
|
91
|
+
setFileObjects(prevMap => {
|
|
92
|
+
const newMap = multiple ? new Map(prevMap) : new Map();
|
|
93
|
+
newFiles.forEach(file => {
|
|
94
|
+
newMap.set(file.name, file);
|
|
95
|
+
});
|
|
96
|
+
return newMap;
|
|
97
|
+
});
|
|
98
|
+
if (onChange) {
|
|
99
|
+
onChange(evt);
|
|
100
|
+
}
|
|
58
101
|
}
|
|
59
|
-
};
|
|
60
|
-
const handleClick = (evt, {
|
|
102
|
+
}, [enhancedFileUploaderEnabled, fileItems, legacyFileNames, multiple, onChange]);
|
|
103
|
+
const handleClick = React.useCallback((evt, {
|
|
61
104
|
index,
|
|
62
105
|
filenameStatus
|
|
63
106
|
}) => {
|
|
64
107
|
if (filenameStatus === 'edit') {
|
|
65
108
|
evt.stopPropagation();
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
109
|
+
if (enhancedFileUploaderEnabled) {
|
|
110
|
+
const deletedItem = fileItems[index];
|
|
111
|
+
if (!deletedItem) return;
|
|
112
|
+
const remainingItems = fileItems.filter((_, i) => i !== index);
|
|
113
|
+
setFileItems(remainingItems);
|
|
114
|
+
const remainingFiles = remainingItems.map(item => item.file);
|
|
115
|
+
const enhancedEvent = {
|
|
116
|
+
...evt,
|
|
117
|
+
target: {
|
|
118
|
+
...evt.target,
|
|
119
|
+
files: Object.assign(remainingFiles, {
|
|
120
|
+
item: index => remainingFiles[index] || null
|
|
121
|
+
}),
|
|
122
|
+
deletedFile: deletedItem,
|
|
123
|
+
deletedFileName: deletedItem.name,
|
|
124
|
+
remainingFiles: remainingItems,
|
|
125
|
+
currentFiles: remainingItems,
|
|
126
|
+
action: 'remove'
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
if (onDelete) {
|
|
130
|
+
onDelete(enhancedEvent);
|
|
131
|
+
}
|
|
132
|
+
if (onChange) {
|
|
133
|
+
onChange(enhancedEvent);
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
const deletedFileName = legacyFileNames[index];
|
|
137
|
+
const filteredArray = legacyFileNames.filter(filename => filename !== deletedFileName);
|
|
138
|
+
setLegacyFileNames(filteredArray);
|
|
139
|
+
|
|
140
|
+
// Update File objects
|
|
141
|
+
setFileObjects(prevMap => {
|
|
142
|
+
const newMap = new Map(prevMap);
|
|
143
|
+
if (deletedFileName) {
|
|
144
|
+
newMap.delete(deletedFileName);
|
|
145
|
+
}
|
|
146
|
+
return newMap;
|
|
147
|
+
});
|
|
148
|
+
if (onDelete) {
|
|
149
|
+
onDelete(evt);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (onClick) {
|
|
153
|
+
onClick(evt);
|
|
73
154
|
}
|
|
74
|
-
|
|
155
|
+
uploaderButton.current?.focus?.();
|
|
75
156
|
}
|
|
76
|
-
};
|
|
157
|
+
}, [enhancedFileUploaderEnabled, fileItems, legacyFileNames, onDelete, onChange, onClick]);
|
|
77
158
|
React.useImperativeHandle(ref, () => ({
|
|
78
159
|
clearFiles() {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
160
|
+
if (enhancedFileUploaderEnabled) {
|
|
161
|
+
const previousItems = [...fileItems];
|
|
162
|
+
setFileItems([]);
|
|
163
|
+
if (onChange && previousItems.length > 0) {
|
|
164
|
+
const enhancedEvent = {
|
|
165
|
+
target: {
|
|
166
|
+
files: Object.assign([], {
|
|
167
|
+
item: () => null
|
|
168
|
+
}),
|
|
169
|
+
clearedFiles: previousItems,
|
|
170
|
+
currentFiles: [],
|
|
171
|
+
action: 'clear'
|
|
172
|
+
},
|
|
173
|
+
preventDefault: () => {},
|
|
174
|
+
stopPropagation: () => {}
|
|
175
|
+
};
|
|
176
|
+
onChange(enhancedEvent);
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
setLegacyFileNames([]);
|
|
180
|
+
setFileObjects(new Map());
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
...(enhancedFileUploaderEnabled && {
|
|
184
|
+
getCurrentFiles() {
|
|
185
|
+
return [...fileItems];
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
}), [enhancedFileUploaderEnabled, fileItems, onChange]);
|
|
84
189
|
const uploaderButton = /*#__PURE__*/React.createRef();
|
|
85
190
|
const classes = cx({
|
|
86
191
|
[`${prefix}--form-item`]: true,
|
|
@@ -93,6 +198,15 @@ const FileUploader = /*#__PURE__*/React.forwardRef(({
|
|
|
93
198
|
[`${prefix}--file__selected-file--md`]: size === 'field' || size === 'md',
|
|
94
199
|
[`${prefix}--file__selected-file--sm`]: size === 'small' || size === 'sm'
|
|
95
200
|
});
|
|
201
|
+
const displayFiles = enhancedFileUploaderEnabled ? fileItems.map((item, index) => ({
|
|
202
|
+
name: item.name,
|
|
203
|
+
key: item.uuid,
|
|
204
|
+
index
|
|
205
|
+
})) : legacyFileNames.map((name, index) => ({
|
|
206
|
+
name,
|
|
207
|
+
key: index,
|
|
208
|
+
index
|
|
209
|
+
}));
|
|
96
210
|
return /*#__PURE__*/React.createElement("div", _rollupPluginBabelHelpers.extends({
|
|
97
211
|
className: classes
|
|
98
212
|
}, other), !labelTitle ? null : /*#__PURE__*/React.createElement(Text.Text, {
|
|
@@ -116,32 +230,32 @@ const FileUploader = /*#__PURE__*/React.forwardRef(({
|
|
|
116
230
|
"aria-describedby": fileUploaderInstanceId
|
|
117
231
|
}), /*#__PURE__*/React.createElement("div", {
|
|
118
232
|
className: `${prefix}--file-container`
|
|
119
|
-
},
|
|
120
|
-
key:
|
|
233
|
+
}, displayFiles.length === 0 ? null : displayFiles.map(file => /*#__PURE__*/React.createElement("span", _rollupPluginBabelHelpers.extends({
|
|
234
|
+
key: file.key,
|
|
121
235
|
className: selectedFileClasses,
|
|
122
236
|
ref: node => {
|
|
123
|
-
nodes[index] = node;
|
|
124
|
-
}
|
|
237
|
+
nodes[file.index] = node;
|
|
238
|
+
}
|
|
125
239
|
}, other), /*#__PURE__*/React.createElement(Text.Text, {
|
|
126
240
|
as: "p",
|
|
127
241
|
className: `${prefix}--file-filename`,
|
|
128
|
-
id:
|
|
129
|
-
}, name), /*#__PURE__*/React.createElement("span", {
|
|
242
|
+
id: enhancedFileUploaderEnabled ? `${fileUploaderInstanceId}-file-${fileItems[file.index]?.uuid || file.index}` : `${fileUploaderInstanceId}-file-${file.index}`
|
|
243
|
+
}, file.name), /*#__PURE__*/React.createElement("span", {
|
|
130
244
|
className: `${prefix}--file__state-container`
|
|
131
245
|
}, /*#__PURE__*/React.createElement(Filename.default, {
|
|
132
|
-
name: name,
|
|
246
|
+
name: file.name,
|
|
133
247
|
iconDescription: iconDescription,
|
|
134
248
|
status: filenameStatus,
|
|
135
249
|
onKeyDown: evt => {
|
|
136
250
|
if (match.matches(evt, [keys.Enter, keys.Space])) {
|
|
137
251
|
handleClick(evt, {
|
|
138
|
-
index,
|
|
252
|
+
index: file.index,
|
|
139
253
|
filenameStatus
|
|
140
254
|
});
|
|
141
255
|
}
|
|
142
256
|
},
|
|
143
257
|
onClick: evt => handleClick(evt, {
|
|
144
|
-
index,
|
|
258
|
+
index: file.index,
|
|
145
259
|
filenameStatus
|
|
146
260
|
})
|
|
147
261
|
}))))));
|
|
@@ -211,7 +325,7 @@ FileUploader.propTypes = {
|
|
|
211
325
|
* Specify the size of the FileUploaderButton, from a list of available
|
|
212
326
|
* sizes.
|
|
213
327
|
*/
|
|
214
|
-
size: PropTypes.oneOf(['sm', 'md', 'lg'])
|
|
328
|
+
size: PropTypes.oneOf(['sm', 'small', 'md', 'field', 'lg'])
|
|
215
329
|
};
|
|
216
330
|
|
|
217
331
|
exports.default = FileUploader;
|
|
@@ -52,9 +52,23 @@ const LinkBase = /*#__PURE__*/React.forwardRef(({
|
|
|
52
52
|
linkProps['aria-disabled'] = true;
|
|
53
53
|
}
|
|
54
54
|
const BaseComponentAsAny = BaseComponent ?? 'a';
|
|
55
|
+
const handleOnClick = event => {
|
|
56
|
+
if (disabled) {
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
event.stopPropagation();
|
|
59
|
+
} else {
|
|
60
|
+
// If the link is not disabled, we allow the onClick event to propagate
|
|
61
|
+
// so that any parent handlers can also respond to the click.
|
|
62
|
+
if (rest.onClick) {
|
|
63
|
+
rest.onClick(event);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
55
67
|
return /*#__PURE__*/React.createElement(BaseComponentAsAny, _rollupPluginBabelHelpers.extends({
|
|
56
68
|
ref: ref
|
|
57
|
-
}, linkProps, rest
|
|
69
|
+
}, linkProps, rest, {
|
|
70
|
+
onClick: handleOnClick
|
|
71
|
+
}), children, !inline && Icon && /*#__PURE__*/React.createElement("div", {
|
|
58
72
|
className: `${prefix}--link__icon`
|
|
59
73
|
}, /*#__PURE__*/React.createElement(Icon, null)));
|
|
60
74
|
});
|
|
@@ -30,10 +30,17 @@ function menuReducer(state, action) {
|
|
|
30
30
|
hasSelectableItems: true
|
|
31
31
|
};
|
|
32
32
|
case 'registerItem':
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
items
|
|
36
|
-
|
|
33
|
+
{
|
|
34
|
+
const newItem = action.payload;
|
|
35
|
+
const items = state.items.filter(item => item.ref.current);
|
|
36
|
+
const next = newItem.ref.current?.nextElementSibling;
|
|
37
|
+
const idx = items.findIndex(item => item.ref.current === next);
|
|
38
|
+
items.splice(idx < 0 ? items.length : idx, 0, newItem);
|
|
39
|
+
return {
|
|
40
|
+
...state,
|
|
41
|
+
items
|
|
42
|
+
};
|
|
43
|
+
}
|
|
37
44
|
}
|
|
38
45
|
}
|
|
39
46
|
const MenuContext = /*#__PURE__*/React.createContext({
|
|
@@ -51,7 +51,8 @@ const MenuItem = /*#__PURE__*/React.forwardRef(function MenuItem({
|
|
|
51
51
|
middleware: [react.offset({
|
|
52
52
|
mainAxis: -6,
|
|
53
53
|
crossAxis: -6
|
|
54
|
-
})]
|
|
54
|
+
})],
|
|
55
|
+
strategy: 'fixed'
|
|
55
56
|
});
|
|
56
57
|
const {
|
|
57
58
|
getReferenceProps,
|
|
@@ -130,18 +131,11 @@ const MenuItem = /*#__PURE__*/React.forwardRef(function MenuItem({
|
|
|
130
131
|
[`${prefix}--menu-item--disabled`]: isDisabled,
|
|
131
132
|
[`${prefix}--menu-item--danger`]: isDanger
|
|
132
133
|
});
|
|
133
|
-
|
|
134
|
+
|
|
134
135
|
// on first render, register this menuitem in the context's state
|
|
135
136
|
// (used for keyboard navigation)
|
|
136
137
|
React.useEffect(() => {
|
|
137
138
|
registerItem();
|
|
138
|
-
|
|
139
|
-
// Detects if this is the first focusable item
|
|
140
|
-
const currentItems = context.state.items;
|
|
141
|
-
if (!disabled && menuItem.current && currentItems.length === 0) {
|
|
142
|
-
setIsFocusable(true);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
139
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
146
140
|
}, []);
|
|
147
141
|
|
|
@@ -180,7 +174,7 @@ const MenuItem = /*#__PURE__*/React.forwardRef(function MenuItem({
|
|
|
180
174
|
}, rest, {
|
|
181
175
|
ref: ref,
|
|
182
176
|
className: classNames,
|
|
183
|
-
tabIndex:
|
|
177
|
+
tabIndex: !disabled ? 0 : -1,
|
|
184
178
|
"aria-disabled": isDisabled ?? undefined,
|
|
185
179
|
"aria-haspopup": hasChildren ?? undefined,
|
|
186
180
|
"aria-expanded": hasChildren ? submenuOpen : undefined,
|
|
@@ -19,7 +19,7 @@ var Button = require('../Button/Button.js');
|
|
|
19
19
|
require('../Button/Button.Skeleton.js');
|
|
20
20
|
var ButtonSet = require('../ButtonSet/ButtonSet.js');
|
|
21
21
|
var InlineLoading = require('../InlineLoading/InlineLoading.js');
|
|
22
|
-
var index$
|
|
22
|
+
var index$3 = require('../Layer/index.js');
|
|
23
23
|
var requiredIfGivenPropIsTruthy = require('../../prop-types/requiredIfGivenPropIsTruthy.js');
|
|
24
24
|
var wrapFocus = require('../../internal/wrapFocus.js');
|
|
25
25
|
var useIsomorphicEffect = require('../../internal/useIsomorphicEffect.js');
|
|
@@ -28,13 +28,13 @@ var usePrefix = require('../../internal/usePrefix.js');
|
|
|
28
28
|
var usePreviousValue = require('../../internal/usePreviousValue.js');
|
|
29
29
|
var keys = require('../../internal/keyboard/keys.js');
|
|
30
30
|
var match = require('../../internal/keyboard/match.js');
|
|
31
|
-
var index$
|
|
31
|
+
var index$2 = require('../IconButton/index.js');
|
|
32
32
|
var noopFn = require('../../internal/noopFn.js');
|
|
33
33
|
require('../Text/index.js');
|
|
34
34
|
var index = require('../FeatureFlags/index.js');
|
|
35
35
|
var events = require('../../tools/events.js');
|
|
36
36
|
var deprecate = require('../../prop-types/deprecate.js');
|
|
37
|
-
var
|
|
37
|
+
var Dialog = require('../Dialog/Dialog.js');
|
|
38
38
|
var index$1 = require('../AILabel/index.js');
|
|
39
39
|
var utils = require('../../internal/utils.js');
|
|
40
40
|
var warning = require('../../internal/warning.js');
|
|
@@ -85,6 +85,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
|
|
|
85
85
|
const innerModal = React.useRef(null);
|
|
86
86
|
const startTrap = React.useRef(null);
|
|
87
87
|
const endTrap = React.useRef(null);
|
|
88
|
+
const wrapFocusTimeout = React.useRef(null);
|
|
88
89
|
const [isScrollable, setIsScrollable] = React.useState(false);
|
|
89
90
|
const prevOpen = usePreviousValue.usePreviousValue(open);
|
|
90
91
|
const modalInstanceId = `modal-${useId.useId()}`;
|
|
@@ -146,13 +147,20 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
|
|
|
146
147
|
const {
|
|
147
148
|
current: endTrapNode
|
|
148
149
|
} = endTrap;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
150
|
+
// use setTimeout to ensure focus is set after all browser default focus behavior. Fixes issue of
|
|
151
|
+
// focus not wrapping in Firefox
|
|
152
|
+
wrapFocusTimeout.current = setTimeout(() => {
|
|
153
|
+
wrapFocus.wrapFocus({
|
|
154
|
+
bodyNode,
|
|
155
|
+
startTrapNode,
|
|
156
|
+
endTrapNode,
|
|
157
|
+
currentActiveNode,
|
|
158
|
+
oldActiveNode,
|
|
159
|
+
selectorsFloatingMenus
|
|
160
|
+
});
|
|
161
|
+
if (wrapFocusTimeout.current) {
|
|
162
|
+
clearTimeout(wrapFocusTimeout.current);
|
|
163
|
+
}
|
|
156
164
|
});
|
|
157
165
|
}
|
|
158
166
|
|
|
@@ -293,7 +301,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
|
|
|
293
301
|
}) : null;
|
|
294
302
|
const modalButton = /*#__PURE__*/React.createElement("div", {
|
|
295
303
|
className: `${prefix}--modal-close-button`
|
|
296
|
-
}, /*#__PURE__*/React.createElement(index$
|
|
304
|
+
}, /*#__PURE__*/React.createElement(index$2.IconButton, {
|
|
297
305
|
className: modalCloseButtonClass,
|
|
298
306
|
label: closeButtonLabel,
|
|
299
307
|
onClick: onRequestClose,
|
|
@@ -310,7 +318,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
|
|
|
310
318
|
// alertdialog is the only permitted aria role for a native dialog element
|
|
311
319
|
// https://www.w3.org/TR/html-aria/#docconformance:~:text=Role%3A-,alertdialog,-.%20(dialog%20is
|
|
312
320
|
const isAlertDialog = alert && !passiveModal;
|
|
313
|
-
const modalBody = enableDialogElement ? /*#__PURE__*/React.createElement(
|
|
321
|
+
const modalBody = enableDialogElement ? /*#__PURE__*/React.createElement(Dialog.Dialog, {
|
|
314
322
|
open: open,
|
|
315
323
|
focusAfterCloseRef: launcherButtonRef,
|
|
316
324
|
modal: true,
|
|
@@ -333,7 +341,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
|
|
|
333
341
|
className: `${prefix}--modal--inner__decorator`
|
|
334
342
|
}, normalizedDecorator) : '', /*#__PURE__*/React.createElement("div", {
|
|
335
343
|
className: `${prefix}--modal-close-button`
|
|
336
|
-
}, /*#__PURE__*/React.createElement(index$
|
|
344
|
+
}, /*#__PURE__*/React.createElement(index$2.IconButton, {
|
|
337
345
|
className: modalCloseButtonClass,
|
|
338
346
|
label: closeButtonLabel,
|
|
339
347
|
onClick: onRequestClose,
|
|
@@ -345,7 +353,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
|
|
|
345
353
|
"aria-hidden": "true",
|
|
346
354
|
tabIndex: "-1",
|
|
347
355
|
className: `${modalCloseButtonClass}__icon`
|
|
348
|
-
})))), /*#__PURE__*/React.createElement(index$
|
|
356
|
+
})))), /*#__PURE__*/React.createElement(index$3.Layer, _rollupPluginBabelHelpers.extends({
|
|
349
357
|
ref: contentRef,
|
|
350
358
|
id: modalBodyId,
|
|
351
359
|
className: contentClasses
|
|
@@ -401,7 +409,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
|
|
|
401
409
|
className: `${prefix}--modal-header__heading`
|
|
402
410
|
}, modalHeading), slug ? normalizedDecorator : decorator ? /*#__PURE__*/React.createElement("div", {
|
|
403
411
|
className: `${prefix}--modal--inner__decorator`
|
|
404
|
-
}, normalizedDecorator) : '', !passiveModal && modalButton), /*#__PURE__*/React.createElement(index$
|
|
412
|
+
}, normalizedDecorator) : '', !passiveModal && modalButton), /*#__PURE__*/React.createElement(index$3.Layer, _rollupPluginBabelHelpers.extends({
|
|
405
413
|
ref: contentRef,
|
|
406
414
|
id: modalBodyId,
|
|
407
415
|
className: contentClasses
|
|
@@ -438,7 +446,7 @@ const Modal = /*#__PURE__*/React.forwardRef(function Modal({
|
|
|
438
446
|
role: "link",
|
|
439
447
|
className: `${prefix}--visually-hidden`
|
|
440
448
|
}, "Focus sentinel"));
|
|
441
|
-
return /*#__PURE__*/React.createElement(index$
|
|
449
|
+
return /*#__PURE__*/React.createElement(index$3.Layer, _rollupPluginBabelHelpers.extends({}, rest, {
|
|
442
450
|
level: 0,
|
|
443
451
|
onKeyDown: handleKeyDown,
|
|
444
452
|
onClick: events.composeEventHandlers([rest?.onClick, handleOnClick]),
|
|
@@ -124,11 +124,7 @@ const FilterableMultiSelect = /*#__PURE__*/React.forwardRef(function FilterableM
|
|
|
124
124
|
inputValue
|
|
125
125
|
}), [items, inputValue, itemToString$1, filterItems]);
|
|
126
126
|
const nonSelectAllItems = React.useMemo(() => filteredItems.filter(item => !item.isSelectAll), [filteredItems]);
|
|
127
|
-
|
|
128
|
-
if ((selected ?? []).length > 0 && selectAll) {
|
|
129
|
-
console.warn('Warning: `selectAll` should not be used when `selectedItems` is provided. Please pass either `selectAll` or `selectedItems`, not both.');
|
|
130
|
-
selectAll = false;
|
|
131
|
-
}
|
|
127
|
+
const selectAll = filteredItems.some(item => item.isSelectAll);
|
|
132
128
|
const {
|
|
133
129
|
selectedItems: controlledSelectedItems,
|
|
134
130
|
onItemChange,
|
|
@@ -113,11 +113,7 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
113
113
|
return true; // Return true if item is not an object with undefined values
|
|
114
114
|
});
|
|
115
115
|
}, [items]);
|
|
116
|
-
|
|
117
|
-
if ((selected ?? []).length > 0 && selectAll) {
|
|
118
|
-
console.warn('Warning: `selectAll` should not be used when `selectedItems` is provided. Please pass either `selectAll` or `selectedItems`, not both.');
|
|
119
|
-
selectAll = false;
|
|
120
|
-
}
|
|
116
|
+
const selectAll = filteredItems.some(item => item.isSelectAll);
|
|
121
117
|
const prefix = usePrefix.usePrefix();
|
|
122
118
|
const {
|
|
123
119
|
isFluid
|
|
@@ -491,13 +487,13 @@ const MultiSelect = /*#__PURE__*/React.forwardRef(({
|
|
|
491
487
|
})), slug ? normalizedDecorator : decorator ? /*#__PURE__*/React.createElement("div", {
|
|
492
488
|
className: `${prefix}--list-box__inner-wrapper--decorator`
|
|
493
489
|
}, normalizedDecorator) : ''), /*#__PURE__*/React.createElement(index$2.default.Menu, menuProps, isOpen && sortItems(filteredItems, sortOptions).map((item, index) => {
|
|
494
|
-
const isChecked = selectedItems.filter(selected => isEqual(selected, item)).length > 0;
|
|
495
490
|
const {
|
|
496
491
|
hasIndividualSelections,
|
|
497
492
|
nonSelectAllSelectedCount,
|
|
498
493
|
totalSelectableCount
|
|
499
494
|
} = getSelectionStats(selectedItems, filteredItems);
|
|
500
|
-
const
|
|
495
|
+
const isChecked = item.isSelectAll ? nonSelectAllSelectedCount === totalSelectableCount && totalSelectableCount > 0 : selectedItems.some(selected => isEqual(selected, item));
|
|
496
|
+
const isIndeterminate = item.isSelectAll && hasIndividualSelections && nonSelectAllSelectedCount < totalSelectableCount;
|
|
501
497
|
const itemProps = getItemProps({
|
|
502
498
|
item,
|
|
503
499
|
// we don't want Downshift to set aria-selected for us
|
|
@@ -25,6 +25,10 @@ export interface PopoverBaseProps {
|
|
|
25
25
|
* Specify how the popover should align with the trigger element.
|
|
26
26
|
*/
|
|
27
27
|
align?: PopoverAlignment;
|
|
28
|
+
/**
|
|
29
|
+
* **Experimental:** Provide an offset value for alignment axis. Only takes effect when `autoalign` is enabled.
|
|
30
|
+
*/
|
|
31
|
+
alignmentAxisOffset?: number;
|
|
28
32
|
/**
|
|
29
33
|
* Will auto-align the popover on first render if it is not visible. This prop
|
|
30
34
|
* is currently experimental and is subject to future changes. Requires
|
|
@@ -19,7 +19,6 @@ var useEvent = require('../../internal/useEvent.js');
|
|
|
19
19
|
var mapPopoverAlign = require('../../tools/mapPopoverAlign.js');
|
|
20
20
|
var react = require('@floating-ui/react');
|
|
21
21
|
var index = require('../FeatureFlags/index.js');
|
|
22
|
-
var index$1 = require('../Toggletip/index.js');
|
|
23
22
|
|
|
24
23
|
const PopoverContext = /*#__PURE__*/React.createContext({
|
|
25
24
|
setFloating: {
|
|
@@ -64,7 +63,10 @@ forwardRef) {
|
|
|
64
63
|
// The `Popover` should close whenever it and its children loses focus
|
|
65
64
|
useEvent.useEvent(popover, 'focusout', event => {
|
|
66
65
|
const relatedTarget = event.relatedTarget;
|
|
66
|
+
|
|
67
|
+
// No relatedTarget, focus moved to nowhere, so close the popover
|
|
67
68
|
if (!relatedTarget) {
|
|
69
|
+
onRequestClose?.();
|
|
68
70
|
return;
|
|
69
71
|
}
|
|
70
72
|
const isOutsideMainContainer = !popover.current?.contains(relatedTarget);
|
|
@@ -237,7 +239,7 @@ forwardRef) {
|
|
|
237
239
|
// For a toggletip there is a specific trigger component, ToggletipButton.
|
|
238
240
|
// In either of these cases we want to set this as the reference node for floating-ui autoAlign
|
|
239
241
|
// positioning.
|
|
240
|
-
if (enableFloatingStyles && item?.type !== PopoverContent || enableFloatingStyles && item?.type ===
|
|
242
|
+
if (enableFloatingStyles && item?.type !== PopoverContent || enableFloatingStyles && item?.type['displayName'] === 'ToggletipButton') {
|
|
241
243
|
// Set the reference element for floating-ui
|
|
242
244
|
refs.setReference(node);
|
|
243
245
|
}
|
|
@@ -294,6 +296,10 @@ Popover.propTypes = {
|
|
|
294
296
|
|
|
295
297
|
// new values to match floating-ui
|
|
296
298
|
'top-start', 'top-end', 'bottom-start', 'bottom-end', 'left-end', 'left-start', 'right-end', 'right-start']), ['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end', 'right', 'right-start', 'right-end'], mapPopoverAlign.mapPopoverAlign),
|
|
299
|
+
/**
|
|
300
|
+
* **Experimental:** Provide an offset value for alignment axis. Only takes effect when `autoalign` is enabled.
|
|
301
|
+
*/
|
|
302
|
+
alignmentAxisOffset: PropTypes.number,
|
|
297
303
|
/**
|
|
298
304
|
* Provide a custom element or component to render the top-level node for the
|
|
299
305
|
* component.
|
|
@@ -32,6 +32,10 @@ export interface StructuredListWrapperProps extends DivAttrs {
|
|
|
32
32
|
* Specify whether your StructuredListWrapper should have selections
|
|
33
33
|
*/
|
|
34
34
|
selection?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Specify which row will be selected initially
|
|
37
|
+
*/
|
|
38
|
+
selectedInitialRow?: string;
|
|
35
39
|
}
|
|
36
40
|
export declare function StructuredListWrapper(props: StructuredListWrapperProps): import("react/jsx-runtime").JSX.Element;
|
|
37
41
|
export declare namespace StructuredListWrapper {
|
|
@@ -65,6 +69,10 @@ export declare namespace StructuredListWrapper {
|
|
|
65
69
|
* Specify whether your StructuredListWrapper should have selections
|
|
66
70
|
*/
|
|
67
71
|
selection: PropTypes.Requireable<boolean>;
|
|
72
|
+
/**
|
|
73
|
+
* Specify which row will be selected initially
|
|
74
|
+
*/
|
|
75
|
+
selectedInitialRow: PropTypes.Requireable<string>;
|
|
68
76
|
};
|
|
69
77
|
}
|
|
70
78
|
export interface StructuredListHeadProps extends DivAttrs {
|
|
@@ -148,6 +156,10 @@ export interface StructuredListRowProps extends DivAttrs {
|
|
|
148
156
|
* Mark if this row should be selectable
|
|
149
157
|
*/
|
|
150
158
|
selection?: boolean;
|
|
159
|
+
/**
|
|
160
|
+
* Specify row id so that it can be used for initial selection
|
|
161
|
+
*/
|
|
162
|
+
id?: string;
|
|
151
163
|
}
|
|
152
164
|
export declare function StructuredListRow(props: StructuredListRowProps): import("react/jsx-runtime").JSX.Element;
|
|
153
165
|
export declare namespace StructuredListRow {
|
|
@@ -180,6 +192,10 @@ export declare namespace StructuredListRow {
|
|
|
180
192
|
* Mark if this row should be selectable
|
|
181
193
|
*/
|
|
182
194
|
selection: PropTypes.Requireable<boolean>;
|
|
195
|
+
/**
|
|
196
|
+
* Specify row id so that it can be used for initial selection
|
|
197
|
+
*/
|
|
198
|
+
id: PropTypes.Requireable<string>;
|
|
183
199
|
};
|
|
184
200
|
}
|
|
185
201
|
export interface StructuredListInputProps extends DivAttrs {
|