@carbon/react 1.89.0-rc.1 → 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 +1099 -837
- package/es/components/ComposedModal/ComposedModal.js +2 -2
- 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/Menu/MenuItem.js +2 -1
- package/es/components/Modal/Modal.js +2 -2
- package/es/components/StructuredList/StructuredList.js +4 -2
- package/es/components/Toggletip/index.js +1 -0
- package/es/index.d.ts +2 -1
- package/es/index.js +2 -0
- package/lib/components/ComposedModal/ComposedModal.js +2 -2
- 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/Menu/MenuItem.js +2 -1
- package/lib/components/Modal/Modal.js +9 -9
- package/lib/components/StructuredList/StructuredList.js +4 -2
- package/lib/components/Toggletip/index.js +1 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.js +60 -58
- package/package.json +13 -13
- package/telemetry.yml +2 -0
|
@@ -5,612 +5,4 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
import PropTypes from 'prop-types';
|
|
10
|
-
import React, { useRef, useEffect, createContext, useContext, useState } from 'react';
|
|
11
|
-
import useIsomorphicEffect from '../../internal/useIsomorphicEffect.js';
|
|
12
|
-
import { usePrefix } from '../../internal/usePrefix.js';
|
|
13
|
-
import cx from 'classnames';
|
|
14
|
-
import { Close } from '@carbon/icons-react';
|
|
15
|
-
import { IconButton } from '../IconButton/index.js';
|
|
16
|
-
import { noopFn } from '../../internal/noopFn.js';
|
|
17
|
-
import '../Text/index.js';
|
|
18
|
-
import { Layer } from '../Layer/index.js';
|
|
19
|
-
import ButtonSet from '../ButtonSet/ButtonSet.js';
|
|
20
|
-
import Button from '../Button/Button.js';
|
|
21
|
-
import '../Button/Button.Skeleton.js';
|
|
22
|
-
import { useId } from '../../internal/useId.js';
|
|
23
|
-
import InlineLoading from '../InlineLoading/InlineLoading.js';
|
|
24
|
-
import { debounce } from '../../node_modules/es-toolkit/dist/compat/function/debounce.js';
|
|
25
|
-
import { Text } from '../Text/Text.js';
|
|
26
|
-
|
|
27
|
-
const DialogContext = /*#__PURE__*/createContext({});
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* ----------
|
|
31
|
-
* Dialog
|
|
32
|
-
* ----------
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
const unstable__Dialog = /*#__PURE__*/React.forwardRef(({
|
|
36
|
-
children,
|
|
37
|
-
className,
|
|
38
|
-
focusAfterCloseRef,
|
|
39
|
-
modal,
|
|
40
|
-
onCancel = noopFn,
|
|
41
|
-
onClick = noopFn,
|
|
42
|
-
onClose = noopFn,
|
|
43
|
-
onRequestClose = noopFn,
|
|
44
|
-
open = false,
|
|
45
|
-
role,
|
|
46
|
-
ariaLabel,
|
|
47
|
-
ariaLabelledBy,
|
|
48
|
-
ariaDescribedBy,
|
|
49
|
-
...rest
|
|
50
|
-
}, forwardRef) => {
|
|
51
|
-
const prefix = usePrefix();
|
|
52
|
-
const dialogId = useId();
|
|
53
|
-
const titleId = `${prefix}--dialog-header__heading--${dialogId}`;
|
|
54
|
-
const subtitleId = `${prefix}--dialog-header__label--${dialogId}`;
|
|
55
|
-
|
|
56
|
-
// This component needs access to a ref, placed on the dialog, to call the
|
|
57
|
-
// various imperative dialog functions (show(), close(), etc.).
|
|
58
|
-
// If the parent component has not passed a ref for forwardRef, forwardRef
|
|
59
|
-
// will be null. A "backup" ref is needed to ensure the dialog's instance
|
|
60
|
-
// methods can always be called within this component.
|
|
61
|
-
const backupRef = useRef(null);
|
|
62
|
-
const ref = forwardRef ?? backupRef;
|
|
63
|
-
|
|
64
|
-
// Clicks on the backdrop of an open modal dialog should request the consuming component to close
|
|
65
|
-
// the dialog. Clicks elsewhere, or on non-modal dialogs should not request
|
|
66
|
-
// to close the dialog.
|
|
67
|
-
function handleModalBackdropClick(e) {
|
|
68
|
-
if (open && modal && e.target === ref.current) {
|
|
69
|
-
onRequestClose(e);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function handleClick(e) {
|
|
73
|
-
handleModalBackdropClick(e);
|
|
74
|
-
|
|
75
|
-
// onClick should always be called, no matter if the target is a modal
|
|
76
|
-
// dialog, modal dialog backdrop, or non-modal dialog.
|
|
77
|
-
onClick(e);
|
|
78
|
-
}
|
|
79
|
-
useEffect(() => {
|
|
80
|
-
if (ref.current) {
|
|
81
|
-
if (open) {
|
|
82
|
-
if (modal) {
|
|
83
|
-
// Display the dialog as a modal, over the top of any other dialogs
|
|
84
|
-
// that might be present. Everything outside the dialog are inert
|
|
85
|
-
// with interactions outside the dialog being blocked.
|
|
86
|
-
ref.current.showModal();
|
|
87
|
-
} else {
|
|
88
|
-
// Display the dialog modelessly, i.e. still allowing interaction
|
|
89
|
-
// with content outside of the dialog.
|
|
90
|
-
ref.current.show();
|
|
91
|
-
}
|
|
92
|
-
} else {
|
|
93
|
-
ref.current.close();
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}, [modal, open]);
|
|
97
|
-
useEffect(() => {
|
|
98
|
-
if (!open && focusAfterCloseRef) {
|
|
99
|
-
// use setTimeout to ensure focus is set after all other default focus behavior
|
|
100
|
-
const moveFocus = setTimeout(() => {
|
|
101
|
-
focusAfterCloseRef.current?.focus();
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
//component did unmount equivalent
|
|
105
|
-
return () => {
|
|
106
|
-
clearTimeout(moveFocus);
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
}, [open, focusAfterCloseRef]);
|
|
110
|
-
const containerClasses = cx(`${prefix}--dialog-container`);
|
|
111
|
-
const contextValue = {
|
|
112
|
-
dialogId,
|
|
113
|
-
titleId,
|
|
114
|
-
subtitleId,
|
|
115
|
-
isOpen: open
|
|
116
|
-
};
|
|
117
|
-
useEffect(() => {
|
|
118
|
-
if (ref.current && open && !ariaLabel && !ariaLabelledBy) {
|
|
119
|
-
const title = ref.current.querySelector(`.${prefix}--dialog-header__heading`);
|
|
120
|
-
|
|
121
|
-
// Set aria-labelledby to the title's ID if it exists
|
|
122
|
-
if (title && title.id) {
|
|
123
|
-
ref.current.setAttribute('aria-labelledby', title.id);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}, [open, ariaLabel, ariaLabelledBy, prefix]);
|
|
127
|
-
return /*#__PURE__*/React.createElement(DialogContext.Provider, {
|
|
128
|
-
value: contextValue
|
|
129
|
-
}, /*#__PURE__*/React.createElement("dialog", _extends({}, rest, {
|
|
130
|
-
className: cx(`${prefix}--dialog`, {
|
|
131
|
-
[`${prefix}--dialog--modal`]: modal
|
|
132
|
-
}, className),
|
|
133
|
-
ref: ref,
|
|
134
|
-
onCancel: onCancel,
|
|
135
|
-
onClick: handleClick,
|
|
136
|
-
onClose: onClose,
|
|
137
|
-
role: role,
|
|
138
|
-
"aria-label": ariaLabel,
|
|
139
|
-
"aria-labelledby": !ariaLabel ? ariaLabelledBy || titleId : undefined,
|
|
140
|
-
"aria-describedby": ariaDescribedBy
|
|
141
|
-
}), /*#__PURE__*/React.createElement("div", {
|
|
142
|
-
className: containerClasses
|
|
143
|
-
}, children)));
|
|
144
|
-
});
|
|
145
|
-
unstable__Dialog.displayName = 'Dialog';
|
|
146
|
-
unstable__Dialog.propTypes = {
|
|
147
|
-
/**
|
|
148
|
-
* Provide children to be rendered inside of the Dialog
|
|
149
|
-
*/
|
|
150
|
-
children: PropTypes.node,
|
|
151
|
-
/**
|
|
152
|
-
* Specify an optional className to be applied to the modal root node
|
|
153
|
-
*/
|
|
154
|
-
className: PropTypes.string,
|
|
155
|
-
/**
|
|
156
|
-
* Provide a ref to return focus to once the dialog is closed.
|
|
157
|
-
*/
|
|
158
|
-
focusAfterCloseRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({
|
|
159
|
-
current: PropTypes.any
|
|
160
|
-
})]),
|
|
161
|
-
/**
|
|
162
|
-
* Modal specifies whether the Dialog is modal or non-modal. This cannot be
|
|
163
|
-
* changed while open=true
|
|
164
|
-
*/
|
|
165
|
-
modal: PropTypes.bool,
|
|
166
|
-
/**
|
|
167
|
-
* Specify a handler for closing Dialog.
|
|
168
|
-
* The handler should care of closing Dialog, e.g. changing `open` prop.
|
|
169
|
-
*/
|
|
170
|
-
onRequestClose: PropTypes.func,
|
|
171
|
-
/**
|
|
172
|
-
* open initial state
|
|
173
|
-
*/
|
|
174
|
-
open: PropTypes.bool,
|
|
175
|
-
/**
|
|
176
|
-
* Specify the role of the dialog for accessibility
|
|
177
|
-
*/
|
|
178
|
-
role: PropTypes.oneOf(['dialog', 'alertdialog']),
|
|
179
|
-
/**
|
|
180
|
-
* Specify a label for screen readers
|
|
181
|
-
*/
|
|
182
|
-
'aria-label': PropTypes.string,
|
|
183
|
-
/**
|
|
184
|
-
* Specify the ID of an element that labels this dialog
|
|
185
|
-
*/
|
|
186
|
-
'aria-labelledby': PropTypes.string,
|
|
187
|
-
/**
|
|
188
|
-
* Specify the ID of an element that describes this dialog
|
|
189
|
-
*/
|
|
190
|
-
ariaDescribedBy: PropTypes.string
|
|
191
|
-
};
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* -------------
|
|
195
|
-
* DialogHeader
|
|
196
|
-
* -------------
|
|
197
|
-
*/
|
|
198
|
-
|
|
199
|
-
const DialogHeader = /*#__PURE__*/React.forwardRef(({
|
|
200
|
-
children,
|
|
201
|
-
...rest
|
|
202
|
-
}, ref) => {
|
|
203
|
-
const prefix = usePrefix();
|
|
204
|
-
return /*#__PURE__*/React.createElement("div", _extends({
|
|
205
|
-
className: `${prefix}--dialog__header`,
|
|
206
|
-
ref: ref
|
|
207
|
-
}, rest), children);
|
|
208
|
-
});
|
|
209
|
-
DialogHeader.displayName = 'DialogHeader';
|
|
210
|
-
DialogHeader.propTypes = {
|
|
211
|
-
/**
|
|
212
|
-
* Provide the contents to be rendered inside of this component
|
|
213
|
-
*/
|
|
214
|
-
children: PropTypes.node
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* ---------------
|
|
219
|
-
* DialogControls
|
|
220
|
-
* ---------------
|
|
221
|
-
*/
|
|
222
|
-
|
|
223
|
-
const DialogControls = /*#__PURE__*/React.forwardRef(({
|
|
224
|
-
children,
|
|
225
|
-
...rest
|
|
226
|
-
}, ref) => {
|
|
227
|
-
const prefix = usePrefix();
|
|
228
|
-
return (
|
|
229
|
-
/*#__PURE__*/
|
|
230
|
-
// @ts-ignore
|
|
231
|
-
React.createElement("div", _extends({
|
|
232
|
-
className: `${prefix}--dialog__header-controls`,
|
|
233
|
-
ref: ref
|
|
234
|
-
}, rest), children)
|
|
235
|
-
);
|
|
236
|
-
});
|
|
237
|
-
DialogControls.displayName = 'DialogControls';
|
|
238
|
-
DialogControls.propTypes = {
|
|
239
|
-
/**
|
|
240
|
-
* Provide children to be rendered inside of this component
|
|
241
|
-
*/
|
|
242
|
-
children: PropTypes.node
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* -------------------
|
|
247
|
-
* DialogCloseButton
|
|
248
|
-
* -------------------
|
|
249
|
-
*/
|
|
250
|
-
|
|
251
|
-
const DialogCloseButton = /*#__PURE__*/React.forwardRef(({
|
|
252
|
-
onClick,
|
|
253
|
-
...rest
|
|
254
|
-
}, ref) => {
|
|
255
|
-
const prefix = usePrefix();
|
|
256
|
-
return (
|
|
257
|
-
/*#__PURE__*/
|
|
258
|
-
// @ts-ignore
|
|
259
|
-
React.createElement(IconButton, _extends({
|
|
260
|
-
kind: "ghost",
|
|
261
|
-
className: `${prefix}--dialog__close`,
|
|
262
|
-
label: "Close",
|
|
263
|
-
title: "Close",
|
|
264
|
-
"aria-label": "Close",
|
|
265
|
-
align: "left",
|
|
266
|
-
onClick: onClick,
|
|
267
|
-
ref: ref
|
|
268
|
-
}, rest), /*#__PURE__*/React.createElement(Close, {
|
|
269
|
-
size: 20,
|
|
270
|
-
"aria-hidden": "true",
|
|
271
|
-
tabIndex: -1,
|
|
272
|
-
className: `${prefix}--icon__close`
|
|
273
|
-
}))
|
|
274
|
-
);
|
|
275
|
-
});
|
|
276
|
-
DialogCloseButton.displayName = 'DialogCloseButton';
|
|
277
|
-
DialogCloseButton.propTypes = {
|
|
278
|
-
/**
|
|
279
|
-
* Specify a click handler applied to the IconButton
|
|
280
|
-
*/
|
|
281
|
-
onClick: PropTypes.func
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* ------------
|
|
286
|
-
* DialogTitle
|
|
287
|
-
* ------------
|
|
288
|
-
*/
|
|
289
|
-
|
|
290
|
-
const DialogTitle = /*#__PURE__*/React.forwardRef(({
|
|
291
|
-
children,
|
|
292
|
-
className,
|
|
293
|
-
id,
|
|
294
|
-
...rest
|
|
295
|
-
}, ref) => {
|
|
296
|
-
const prefix = usePrefix();
|
|
297
|
-
const {
|
|
298
|
-
titleId
|
|
299
|
-
} = useContext(DialogContext);
|
|
300
|
-
const headingId = id || titleId;
|
|
301
|
-
return /*#__PURE__*/React.createElement(Text, _extends({
|
|
302
|
-
as: "h2",
|
|
303
|
-
id: headingId,
|
|
304
|
-
className: cx(`${prefix}--dialog-header__heading`, className),
|
|
305
|
-
ref: ref
|
|
306
|
-
}, rest), children);
|
|
307
|
-
});
|
|
308
|
-
DialogTitle.displayName = 'DialogTitle';
|
|
309
|
-
DialogTitle.propTypes = {
|
|
310
|
-
/**
|
|
311
|
-
* Provide the contents to be rendered inside of this component
|
|
312
|
-
*/
|
|
313
|
-
children: PropTypes.node,
|
|
314
|
-
/**
|
|
315
|
-
* Specify an optional className to be applied to the title node
|
|
316
|
-
*/
|
|
317
|
-
className: PropTypes.string,
|
|
318
|
-
/**
|
|
319
|
-
* Specify an optional id for the title element
|
|
320
|
-
*/
|
|
321
|
-
id: PropTypes.string
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* ---------------
|
|
326
|
-
* DialogSubtitle
|
|
327
|
-
* ---------------
|
|
328
|
-
*/
|
|
329
|
-
|
|
330
|
-
const DialogSubtitle = /*#__PURE__*/React.forwardRef(({
|
|
331
|
-
children,
|
|
332
|
-
className,
|
|
333
|
-
id,
|
|
334
|
-
...rest
|
|
335
|
-
}, ref) => {
|
|
336
|
-
const prefix = usePrefix();
|
|
337
|
-
const {
|
|
338
|
-
subtitleId
|
|
339
|
-
} = useContext(DialogContext);
|
|
340
|
-
const labelId = id || subtitleId;
|
|
341
|
-
return /*#__PURE__*/React.createElement(Text, _extends({
|
|
342
|
-
as: "h2",
|
|
343
|
-
id: labelId,
|
|
344
|
-
className: cx(`${prefix}--dialog-header__label`, className),
|
|
345
|
-
ref: ref
|
|
346
|
-
}, rest), children);
|
|
347
|
-
});
|
|
348
|
-
DialogSubtitle.displayName = 'DialogSubtitle';
|
|
349
|
-
DialogSubtitle.propTypes = {
|
|
350
|
-
/**
|
|
351
|
-
* Provide the contents to be rendered inside of this component
|
|
352
|
-
*/
|
|
353
|
-
children: PropTypes.node,
|
|
354
|
-
/**
|
|
355
|
-
* Specify an optional className to be applied to the subtitle node
|
|
356
|
-
*/
|
|
357
|
-
className: PropTypes.string,
|
|
358
|
-
/**
|
|
359
|
-
* Specify an optional id for the subtitle element
|
|
360
|
-
*/
|
|
361
|
-
id: PropTypes.string
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* -----------
|
|
366
|
-
* DialogBody
|
|
367
|
-
* -----------
|
|
368
|
-
*/
|
|
369
|
-
|
|
370
|
-
const DialogBody = /*#__PURE__*/React.forwardRef(({
|
|
371
|
-
children,
|
|
372
|
-
className,
|
|
373
|
-
hasScrollingContent,
|
|
374
|
-
...rest
|
|
375
|
-
}, ref) => {
|
|
376
|
-
const prefix = usePrefix();
|
|
377
|
-
const contentRef = useRef(null);
|
|
378
|
-
const [isScrollable, setIsScrollable] = useState(false);
|
|
379
|
-
const dialogId = useId();
|
|
380
|
-
const dialogBodyId = `${prefix}--dialog-body--${dialogId}`;
|
|
381
|
-
useIsomorphicEffect(() => {
|
|
382
|
-
if (contentRef.current) {
|
|
383
|
-
setIsScrollable(contentRef.current.scrollHeight > contentRef.current.clientHeight);
|
|
384
|
-
}
|
|
385
|
-
function handler() {
|
|
386
|
-
if (contentRef.current) {
|
|
387
|
-
setIsScrollable(contentRef.current.scrollHeight > contentRef.current.clientHeight);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
const debouncedHandler = debounce(handler, 200);
|
|
391
|
-
window.addEventListener('resize', debouncedHandler);
|
|
392
|
-
return () => {
|
|
393
|
-
debouncedHandler.cancel();
|
|
394
|
-
window.removeEventListener('resize', debouncedHandler);
|
|
395
|
-
};
|
|
396
|
-
}, []);
|
|
397
|
-
const contentClasses = cx(`${prefix}--dialog-content`, {
|
|
398
|
-
[`${prefix}--dialog-scroll-content`]: hasScrollingContent || isScrollable
|
|
399
|
-
}, className);
|
|
400
|
-
const hasScrollingContentProps = hasScrollingContent || isScrollable ? {
|
|
401
|
-
tabIndex: 0,
|
|
402
|
-
role: 'region'
|
|
403
|
-
} : {};
|
|
404
|
-
const combinedRef = el => {
|
|
405
|
-
if (typeof ref === 'function') {
|
|
406
|
-
ref(el);
|
|
407
|
-
} else if (ref) {
|
|
408
|
-
ref.current = el;
|
|
409
|
-
}
|
|
410
|
-
contentRef.current = el;
|
|
411
|
-
};
|
|
412
|
-
return /*#__PURE__*/React.createElement(Layer, _extends({
|
|
413
|
-
ref: combinedRef,
|
|
414
|
-
id: dialogBodyId,
|
|
415
|
-
className: contentClasses
|
|
416
|
-
}, hasScrollingContentProps, rest), children);
|
|
417
|
-
});
|
|
418
|
-
DialogBody.displayName = 'DialogBody';
|
|
419
|
-
DialogBody.propTypes = {
|
|
420
|
-
/**
|
|
421
|
-
* Provide the contents to be rendered inside of this component
|
|
422
|
-
*/
|
|
423
|
-
children: PropTypes.node,
|
|
424
|
-
/**
|
|
425
|
-
* Specify an optional className to be applied to the body node
|
|
426
|
-
*/
|
|
427
|
-
className: PropTypes.string,
|
|
428
|
-
/**
|
|
429
|
-
* Specify whether the content has overflow that should be scrollable
|
|
430
|
-
*/
|
|
431
|
-
hasScrollingContent: PropTypes.bool
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
* -------------
|
|
436
|
-
* DialogFooter
|
|
437
|
-
* -------------
|
|
438
|
-
*/
|
|
439
|
-
|
|
440
|
-
const DialogFooter = /*#__PURE__*/React.forwardRef(({
|
|
441
|
-
children,
|
|
442
|
-
className,
|
|
443
|
-
onRequestClose = noopFn,
|
|
444
|
-
onSecondarySubmit,
|
|
445
|
-
onRequestSubmit = noopFn,
|
|
446
|
-
primaryButtonText = 'Save',
|
|
447
|
-
primaryButtonDisabled = false,
|
|
448
|
-
secondaryButtonText = 'Cancel',
|
|
449
|
-
secondaryButtons,
|
|
450
|
-
loadingStatus = 'inactive',
|
|
451
|
-
loadingDescription,
|
|
452
|
-
loadingIconDescription,
|
|
453
|
-
onLoadingSuccess = noopFn,
|
|
454
|
-
danger = false,
|
|
455
|
-
...rest
|
|
456
|
-
}, ref) => {
|
|
457
|
-
const prefix = usePrefix();
|
|
458
|
-
const button = useRef(null);
|
|
459
|
-
const {
|
|
460
|
-
isOpen
|
|
461
|
-
} = useContext(DialogContext);
|
|
462
|
-
const [secondaryButtonRef, setSecondaryButtonRef] = useState(null);
|
|
463
|
-
useEffect(() => {
|
|
464
|
-
if (danger && secondaryButtonRef) {
|
|
465
|
-
const focusFrame = requestAnimationFrame(() => {
|
|
466
|
-
secondaryButtonRef.focus();
|
|
467
|
-
});
|
|
468
|
-
return () => cancelAnimationFrame(focusFrame);
|
|
469
|
-
}
|
|
470
|
-
}, [danger, secondaryButtonRef, isOpen]);
|
|
471
|
-
const classes = cx(`${prefix}--dialog-footer`, className, {
|
|
472
|
-
[`${prefix}--dialog-footer--three-button`]: Array.isArray(secondaryButtons) && secondaryButtons.length === 2
|
|
473
|
-
});
|
|
474
|
-
const loadingActive = loadingStatus !== 'inactive';
|
|
475
|
-
const primaryButtonClass = cx({
|
|
476
|
-
[`${prefix}--btn--loading`]: loadingStatus !== 'inactive'
|
|
477
|
-
});
|
|
478
|
-
const onSecondaryButtonClick = onSecondarySubmit ? onSecondarySubmit : onRequestClose;
|
|
479
|
-
if (children) {
|
|
480
|
-
return /*#__PURE__*/React.createElement(ButtonSet, _extends({
|
|
481
|
-
className: classes,
|
|
482
|
-
ref: ref
|
|
483
|
-
}, rest), children);
|
|
484
|
-
}
|
|
485
|
-
return /*#__PURE__*/React.createElement(ButtonSet, _extends({
|
|
486
|
-
className: classes,
|
|
487
|
-
"aria-busy": loadingActive,
|
|
488
|
-
ref: ref
|
|
489
|
-
}, rest), Array.isArray(secondaryButtons) && secondaryButtons.length <= 2 ? secondaryButtons.map(({
|
|
490
|
-
buttonText,
|
|
491
|
-
onClick: onButtonClick
|
|
492
|
-
}, i) => /*#__PURE__*/React.createElement(Button, {
|
|
493
|
-
key: `${buttonText}-${i}`,
|
|
494
|
-
autoFocus: danger,
|
|
495
|
-
kind: "secondary",
|
|
496
|
-
ref: i === 0 && danger ? setSecondaryButtonRef : undefined,
|
|
497
|
-
onClick: onButtonClick
|
|
498
|
-
}, buttonText)) : secondaryButtonText && /*#__PURE__*/React.createElement(Button, {
|
|
499
|
-
ref: danger ? setSecondaryButtonRef : undefined,
|
|
500
|
-
disabled: loadingActive,
|
|
501
|
-
kind: "secondary",
|
|
502
|
-
autoFocus: danger,
|
|
503
|
-
onClick: onSecondaryButtonClick
|
|
504
|
-
}, secondaryButtonText), /*#__PURE__*/React.createElement(Button, {
|
|
505
|
-
className: primaryButtonClass,
|
|
506
|
-
kind: danger ? 'danger' : 'primary',
|
|
507
|
-
disabled: loadingActive || primaryButtonDisabled,
|
|
508
|
-
onClick: onRequestSubmit,
|
|
509
|
-
ref: button
|
|
510
|
-
}, loadingStatus === 'inactive' ? primaryButtonText : /*#__PURE__*/React.createElement(InlineLoading, {
|
|
511
|
-
status: loadingStatus,
|
|
512
|
-
description: loadingDescription,
|
|
513
|
-
iconDescription: loadingIconDescription,
|
|
514
|
-
className: `${prefix}--inline-loading--btn`,
|
|
515
|
-
onSuccess: onLoadingSuccess
|
|
516
|
-
})));
|
|
517
|
-
});
|
|
518
|
-
DialogFooter.displayName = 'DialogFooter';
|
|
519
|
-
DialogFooter.propTypes = {
|
|
520
|
-
/**
|
|
521
|
-
* Provide the contents to be rendered inside of this component
|
|
522
|
-
*/
|
|
523
|
-
children: PropTypes.node,
|
|
524
|
-
/**
|
|
525
|
-
* Specify an optional className to be applied to the footer node
|
|
526
|
-
*/
|
|
527
|
-
className: PropTypes.string,
|
|
528
|
-
/**
|
|
529
|
-
* Specify a handler for closing dialog.
|
|
530
|
-
*/
|
|
531
|
-
onRequestClose: PropTypes.func,
|
|
532
|
-
/**
|
|
533
|
-
* Specify a handler for the secondary button.
|
|
534
|
-
*/
|
|
535
|
-
onSecondarySubmit: PropTypes.func,
|
|
536
|
-
/**
|
|
537
|
-
* Specify a handler for submitting dialog.
|
|
538
|
-
*/
|
|
539
|
-
onRequestSubmit: PropTypes.func,
|
|
540
|
-
/**
|
|
541
|
-
* Specify the text for the primary button
|
|
542
|
-
*/
|
|
543
|
-
primaryButtonText: PropTypes.node,
|
|
544
|
-
/**
|
|
545
|
-
* Specify whether the Button should be disabled, or not
|
|
546
|
-
*/
|
|
547
|
-
primaryButtonDisabled: PropTypes.bool,
|
|
548
|
-
/**
|
|
549
|
-
* Specify the text for the secondary button
|
|
550
|
-
*/
|
|
551
|
-
secondaryButtonText: PropTypes.node,
|
|
552
|
-
/**
|
|
553
|
-
* Specify an array of config objects for secondary buttons
|
|
554
|
-
*/
|
|
555
|
-
secondaryButtons: (props, propName, componentName) => {
|
|
556
|
-
if (props.secondaryButtons) {
|
|
557
|
-
if (!Array.isArray(props.secondaryButtons) || props.secondaryButtons.length !== 2) {
|
|
558
|
-
return new Error(`${propName} needs to be an array of two button config objects`);
|
|
559
|
-
}
|
|
560
|
-
const shape = {
|
|
561
|
-
buttonText: PropTypes.node,
|
|
562
|
-
onClick: PropTypes.func
|
|
563
|
-
};
|
|
564
|
-
props[propName].forEach(secondaryButton => {
|
|
565
|
-
PropTypes.checkPropTypes(shape, secondaryButton, propName, componentName);
|
|
566
|
-
});
|
|
567
|
-
}
|
|
568
|
-
return null;
|
|
569
|
-
},
|
|
570
|
-
/**
|
|
571
|
-
* Specify whether the Dialog is for dangerous actions
|
|
572
|
-
*/
|
|
573
|
-
danger: PropTypes.bool,
|
|
574
|
-
/**
|
|
575
|
-
* Specify loading status
|
|
576
|
-
*/
|
|
577
|
-
loadingStatus: PropTypes.oneOf(['inactive', 'active', 'finished', 'error']),
|
|
578
|
-
/**
|
|
579
|
-
* Specify the description for the loading text
|
|
580
|
-
*/
|
|
581
|
-
loadingDescription: PropTypes.string,
|
|
582
|
-
/**
|
|
583
|
-
* Specify the description for the loading icon
|
|
584
|
-
*/
|
|
585
|
-
loadingIconDescription: PropTypes.string,
|
|
586
|
-
/**
|
|
587
|
-
* Provide an optional handler to be invoked when loading is
|
|
588
|
-
* successful
|
|
589
|
-
*/
|
|
590
|
-
onLoadingSuccess: PropTypes.func
|
|
591
|
-
};
|
|
592
|
-
/**
|
|
593
|
-
* -------
|
|
594
|
-
* Exports
|
|
595
|
-
* -------
|
|
596
|
-
*/
|
|
597
|
-
|
|
598
|
-
const Dialog = unstable__Dialog;
|
|
599
|
-
Dialog.Root = unstable__Dialog;
|
|
600
|
-
Dialog.Root.displayName = 'Dialog.Root';
|
|
601
|
-
Dialog.Header = DialogHeader;
|
|
602
|
-
Dialog.Header.displayName = 'Dialog.Header';
|
|
603
|
-
Dialog.Controls = DialogControls;
|
|
604
|
-
Dialog.Controls.displayName = 'Dialog.Controls';
|
|
605
|
-
Dialog.CloseButton = DialogCloseButton;
|
|
606
|
-
Dialog.CloseButton.displayName = 'Dialog.CloseButton';
|
|
607
|
-
Dialog.Title = DialogTitle;
|
|
608
|
-
Dialog.Title.displayName = 'Dialog.Title';
|
|
609
|
-
Dialog.Subtitle = DialogSubtitle;
|
|
610
|
-
Dialog.Subtitle.displayName = 'Dialog.Subtitle';
|
|
611
|
-
Dialog.Body = DialogBody;
|
|
612
|
-
Dialog.Body.displayName = 'Dialog.Body';
|
|
613
|
-
Dialog.Footer = DialogFooter;
|
|
614
|
-
Dialog.Footer.displayName = 'Dialog.Footer';
|
|
615
|
-
|
|
616
|
-
export { Dialog, DialogBody, DialogCloseButton, DialogControls, DialogFooter, DialogHeader, DialogSubtitle, DialogTitle, unstable__Dialog };
|
|
8
|
+
export { Dialog, DialogBody, DialogCloseButton, DialogControls, DialogFooter, DialogHeader, DialogSubtitle, DialogTitle } from './Dialog.js';
|
|
@@ -16,6 +16,7 @@ export interface FeatureFlagsProps {
|
|
|
16
16
|
enableExperimentalFocusWrapWithoutSentinels?: boolean;
|
|
17
17
|
enableDialogElement?: boolean;
|
|
18
18
|
enableV12DynamicFloatingStyles?: boolean;
|
|
19
|
+
enableEnhancedFileUploader?: boolean;
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
22
|
* Our FeatureFlagContext is used alongside the FeatureFlags component to enable
|
|
@@ -27,7 +28,7 @@ declare const FeatureFlagContext: React.Context<any>;
|
|
|
27
28
|
* along with the current `FeatureFlagContext` to provide consumers to check if
|
|
28
29
|
* a feature flag is enabled or disabled in a given React tree
|
|
29
30
|
*/
|
|
30
|
-
declare function FeatureFlags({ children, flags, enableV12TileDefaultIcons, enableV12TileRadioIcons, enableV12Overflowmenu, enableTreeviewControllable, enableExperimentalFocusWrapWithoutSentinels, enableDialogElement, enableV12DynamicFloatingStyles, }: FeatureFlagsProps): JSX.Element;
|
|
31
|
+
declare function FeatureFlags({ children, flags, enableV12TileDefaultIcons, enableV12TileRadioIcons, enableV12Overflowmenu, enableTreeviewControllable, enableExperimentalFocusWrapWithoutSentinels, enableDialogElement, enableV12DynamicFloatingStyles, enableEnhancedFileUploader, }: FeatureFlagsProps): JSX.Element;
|
|
31
32
|
declare namespace FeatureFlags {
|
|
32
33
|
var propTypes: {
|
|
33
34
|
children: PropTypes.Requireable<PropTypes.ReactNodeLike>;
|
|
@@ -42,6 +43,7 @@ declare namespace FeatureFlags {
|
|
|
42
43
|
enableExperimentalFocusWrapWithoutSentinels: PropTypes.Requireable<boolean>;
|
|
43
44
|
enableDialogElement: PropTypes.Requireable<boolean>;
|
|
44
45
|
enableV12DynamicFloatingStyles: PropTypes.Requireable<boolean>;
|
|
46
|
+
enableEnhancedFileUploader: PropTypes.Requireable<boolean>;
|
|
45
47
|
};
|
|
46
48
|
}
|
|
47
49
|
/**
|
|
@@ -30,7 +30,8 @@ function FeatureFlags({
|
|
|
30
30
|
enableTreeviewControllable = false,
|
|
31
31
|
enableExperimentalFocusWrapWithoutSentinels = false,
|
|
32
32
|
enableDialogElement = false,
|
|
33
|
-
enableV12DynamicFloatingStyles = false
|
|
33
|
+
enableV12DynamicFloatingStyles = false,
|
|
34
|
+
enableEnhancedFileUploader = false
|
|
34
35
|
}) {
|
|
35
36
|
const parentScope = useContext(FeatureFlagContext);
|
|
36
37
|
const [prevParentScope, setPrevParentScope] = useState(parentScope);
|
|
@@ -42,6 +43,7 @@ function FeatureFlags({
|
|
|
42
43
|
'enable-experimental-focus-wrap-without-sentinels': enableExperimentalFocusWrapWithoutSentinels,
|
|
43
44
|
'enable-dialog-element': enableDialogElement,
|
|
44
45
|
'enable-v12-dynamic-floating-styles': enableV12DynamicFloatingStyles,
|
|
46
|
+
'enable-enhanced-file-uploader': enableEnhancedFileUploader,
|
|
45
47
|
...flags
|
|
46
48
|
};
|
|
47
49
|
const [scope, updateScope] = useState(() => {
|
|
@@ -80,7 +82,8 @@ FeatureFlags.propTypes = {
|
|
|
80
82
|
enableTreeviewControllable: PropTypes.bool,
|
|
81
83
|
enableExperimentalFocusWrapWithoutSentinels: PropTypes.bool,
|
|
82
84
|
enableDialogElement: PropTypes.bool,
|
|
83
|
-
enableV12DynamicFloatingStyles: PropTypes.bool
|
|
85
|
+
enableV12DynamicFloatingStyles: PropTypes.bool,
|
|
86
|
+
enableEnhancedFileUploader: PropTypes.bool
|
|
84
87
|
};
|
|
85
88
|
|
|
86
89
|
/**
|