@carbon/react 1.89.0-rc.1 → 1.90.0-rc.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.
Files changed (68) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +1152 -849
  2. package/README.md +2 -2
  3. package/es/components/ComposedModal/ComposedModal.js +16 -5
  4. package/es/components/DataTable/DataTable.d.ts +3 -8
  5. package/es/components/DataTable/DataTable.js +10 -3
  6. package/es/components/DataTable/TableExpandRow.d.ts +33 -5
  7. package/es/components/DataTable/TableExpandRow.js +4 -2
  8. package/es/components/DataTable/TableHeader.d.ts +1 -2
  9. package/es/components/DataTable/TableHeader.js +1 -2
  10. package/es/components/DataTable/TableRow.d.ts +3 -6
  11. package/es/components/DataTable/TableRow.js +35 -22
  12. package/es/components/DataTable/state/sorting.d.ts +55 -14
  13. package/es/components/DataTable/state/sorting.js +40 -50
  14. package/es/components/DataTable/tools/sorting.js +4 -0
  15. package/es/components/Dialog/Dialog.d.ts +245 -0
  16. package/es/components/Dialog/Dialog.js +593 -0
  17. package/es/components/Dialog/index.d.ts +3 -251
  18. package/es/components/Dialog/index.js +1 -609
  19. package/es/components/FeatureFlags/index.d.ts +3 -1
  20. package/es/components/FeatureFlags/index.js +5 -2
  21. package/es/components/FileUploader/FileUploader.d.ts +28 -6
  22. package/es/components/FileUploader/FileUploader.js +152 -38
  23. package/es/components/Menu/MenuItem.js +2 -1
  24. package/es/components/Modal/Modal.js +14 -8
  25. package/es/components/NumberInput/NumberInput.js +11 -6
  26. package/es/components/Popover/index.js +6 -2
  27. package/es/components/StructuredList/StructuredList.js +4 -2
  28. package/es/components/Tag/DismissibleTag.d.ts +5 -0
  29. package/es/components/Tag/DismissibleTag.js +6 -1
  30. package/es/components/Toggletip/index.js +20 -8
  31. package/es/components/TreeView/TreeNode.d.ts +28 -0
  32. package/es/components/TreeView/TreeNode.js +6 -5
  33. package/es/index.d.ts +2 -1
  34. package/es/index.js +2 -0
  35. package/lib/components/ComposedModal/ComposedModal.js +16 -5
  36. package/lib/components/DataTable/DataTable.d.ts +3 -8
  37. package/lib/components/DataTable/DataTable.js +10 -3
  38. package/lib/components/DataTable/TableExpandRow.d.ts +33 -5
  39. package/lib/components/DataTable/TableExpandRow.js +4 -2
  40. package/lib/components/DataTable/TableHeader.d.ts +1 -2
  41. package/lib/components/DataTable/TableHeader.js +1 -2
  42. package/lib/components/DataTable/TableRow.d.ts +3 -6
  43. package/lib/components/DataTable/TableRow.js +34 -21
  44. package/lib/components/DataTable/state/sorting.d.ts +55 -14
  45. package/lib/components/DataTable/state/sorting.js +39 -50
  46. package/lib/components/DataTable/tools/sorting.js +4 -0
  47. package/lib/components/Dialog/Dialog.d.ts +245 -0
  48. package/lib/components/Dialog/Dialog.js +602 -0
  49. package/lib/components/Dialog/index.d.ts +3 -251
  50. package/lib/components/Dialog/index.js +9 -614
  51. package/lib/components/FeatureFlags/index.d.ts +3 -1
  52. package/lib/components/FeatureFlags/index.js +5 -2
  53. package/lib/components/FileUploader/FileUploader.d.ts +28 -6
  54. package/lib/components/FileUploader/FileUploader.js +151 -37
  55. package/lib/components/Menu/MenuItem.js +2 -1
  56. package/lib/components/Modal/Modal.js +21 -15
  57. package/lib/components/NumberInput/NumberInput.js +10 -5
  58. package/lib/components/Popover/index.js +6 -2
  59. package/lib/components/StructuredList/StructuredList.js +4 -2
  60. package/lib/components/Tag/DismissibleTag.d.ts +5 -0
  61. package/lib/components/Tag/DismissibleTag.js +6 -1
  62. package/lib/components/Toggletip/index.js +19 -7
  63. package/lib/components/TreeView/TreeNode.d.ts +28 -0
  64. package/lib/components/TreeView/TreeNode.js +6 -5
  65. package/lib/index.d.ts +2 -1
  66. package/lib/index.js +60 -58
  67. package/package.json +15 -15
  68. package/telemetry.yml +16 -0
@@ -0,0 +1,593 @@
1
+ /**
2
+ * Copyright IBM Corp. 2016, 2023
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
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 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
+ Dialog.displayName = 'Dialog';
146
+ 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
+ export { Dialog, DialogBody, DialogCloseButton, DialogControls, DialogFooter, DialogHeader, DialogSubtitle, DialogTitle };