@automattic/vip-design-system 0.16.0 → 0.18.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.
@@ -6,5 +6,6 @@ module.exports = {
6
6
  '@storybook/addon-essentials',
7
7
  '@storybook/addon-links',
8
8
  '@storybook/addon-controls',
9
+ '@storybook/addon-storysource',
9
10
  ],
10
11
  };
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ exports.__esModule = true;
6
+ exports.NewConfirmationDialog = void 0;
7
+
8
+ var _classnames = _interopRequireDefault(require("classnames"));
9
+
10
+ var _propTypes = _interopRequireDefault(require("prop-types"));
11
+
12
+ var _react = _interopRequireDefault(require("react"));
13
+
14
+ var _ = require("..");
15
+
16
+ var _jsxRuntime = require("theme-ui/jsx-runtime");
17
+
18
+ /** @jsxImportSource theme-ui */
19
+
20
+ /**
21
+ * External dependencies
22
+ */
23
+
24
+ /**
25
+ * Internal dependencies
26
+ */
27
+ var NewConfirmationDialogContent = function NewConfirmationDialogContent(_ref) {
28
+ var _ref$label = _ref.label,
29
+ label = _ref$label === void 0 ? 'Confirm' : _ref$label,
30
+ onConfirm = _ref.onConfirm,
31
+ onClose = _ref.onClose,
32
+ _ref$className = _ref.className,
33
+ className = _ref$className === void 0 ? null : _ref$className;
34
+ return (0, _jsxRuntime.jsx)(_.Box, {
35
+ className: (0, _classnames["default"])('vip-confirmation-dialog-component', className),
36
+ children: (0, _jsxRuntime.jsxs)(_.Flex, {
37
+ sx: {
38
+ justifyContent: 'flex-end',
39
+ mt: 4
40
+ },
41
+ children: [(0, _jsxRuntime.jsx)(_.Button, {
42
+ variant: "secondary",
43
+ sx: {
44
+ mr: 2
45
+ },
46
+ onClick: onClose,
47
+ children: "Cancel"
48
+ }), (0, _jsxRuntime.jsx)(_.NewDialog.Close, {
49
+ children: (0, _jsxRuntime.jsx)(_.Button, {
50
+ variant: "danger",
51
+ onClick: function onClick() {
52
+ onConfirm();
53
+ onClose();
54
+ },
55
+ children: label
56
+ })
57
+ })]
58
+ })
59
+ });
60
+ };
61
+
62
+ NewConfirmationDialogContent.propTypes = {
63
+ body: _propTypes["default"].node,
64
+ label: _propTypes["default"].string,
65
+ onClose: _propTypes["default"].func,
66
+ onConfirm: _propTypes["default"].func,
67
+ className: _propTypes["default"].any
68
+ };
69
+
70
+ var NewConfirmationDialog = function NewConfirmationDialog(_ref2) {
71
+ var trigger = _ref2.trigger,
72
+ onConfirm = _ref2.onConfirm,
73
+ _ref2$needsConfirm = _ref2.needsConfirm,
74
+ needsConfirm = _ref2$needsConfirm === void 0 ? true : _ref2$needsConfirm,
75
+ label = _ref2.label,
76
+ title = _ref2.title,
77
+ _ref2$body = _ref2.body,
78
+ body = _ref2$body === void 0 ? '' : _ref2$body;
79
+
80
+ var _React$useState = _react["default"].useState(false),
81
+ open = _React$useState[0],
82
+ setOpen = _React$useState[1];
83
+
84
+ var directTrigger = /*#__PURE__*/_react["default"].cloneElement(trigger, {
85
+ onClick: onConfirm
86
+ });
87
+
88
+ if (!needsConfirm) {
89
+ return directTrigger;
90
+ }
91
+
92
+ return (0, _jsxRuntime.jsx)(_.NewDialog.Root, {
93
+ open: open,
94
+ onOpenChange: setOpen,
95
+ sx: {
96
+ maxWidth: 680
97
+ },
98
+ title: title,
99
+ description: body,
100
+ content: (0, _jsxRuntime.jsx)(NewConfirmationDialogContent, {
101
+ onClose: function onClose() {
102
+ return setOpen(false);
103
+ },
104
+ onConfirm: onConfirm,
105
+ body: body,
106
+ label: label
107
+ }),
108
+ trigger: trigger
109
+ });
110
+ };
111
+
112
+ exports.NewConfirmationDialog = NewConfirmationDialog;
113
+ NewConfirmationDialog.propTypes = {
114
+ needsConfirm: _propTypes["default"].bool,
115
+ trigger: _propTypes["default"].node,
116
+ onConfirm: _propTypes["default"].func,
117
+ title: _propTypes["default"].node.isRequired,
118
+ body: _propTypes["default"].node,
119
+ label: _propTypes["default"].node
120
+ };
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ exports.__esModule = true;
6
+ exports["default"] = exports.Default = void 0;
7
+
8
+ var _react = _interopRequireDefault(require("react"));
9
+
10
+ var _ = require("..");
11
+
12
+ var _jsxRuntime = require("theme-ui/jsx-runtime");
13
+
14
+ /**
15
+ * Internal dependencies
16
+ */
17
+ var _default = {
18
+ title: 'NewConfirmationDialog',
19
+ component: _.NewConfirmationDialog
20
+ };
21
+ exports["default"] = _default;
22
+ var ConfirmationTrigger = (0, _jsxRuntime.jsx)(_.Button, {
23
+ sx: {
24
+ mr: 3
25
+ },
26
+ children: "Click to answer"
27
+ });
28
+
29
+ var Default = function Default() {
30
+ var _React$useState = _react["default"].useState('🤔'),
31
+ answer = _React$useState[0],
32
+ setAnswer = _React$useState[1];
33
+
34
+ return (0, _jsxRuntime.jsxs)(_.Box, {
35
+ children: [(0, _jsxRuntime.jsx)("p", {
36
+ children: "Confirm that your name is John doe?"
37
+ }), (0, _jsxRuntime.jsx)(_.NewConfirmationDialog, {
38
+ title: 'Are you John Doe?',
39
+ description: 'Please confirm that your name is John Doe.',
40
+ trigger: ConfirmationTrigger,
41
+ body: "A modal is used to perform more detailed actions that don\u2018t necessarily need the context behind.",
42
+ onConfirm: function onConfirm() {
43
+ return setAnswer('👍');
44
+ },
45
+ needsConfirm: true
46
+ }), (0, _jsxRuntime.jsxs)("p", {
47
+ children: ["Answer: ", answer]
48
+ })]
49
+ });
50
+ };
51
+
52
+ exports.Default = Default;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
6
+
7
+ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
8
+
9
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
+
11
+ var _react = require("@testing-library/react");
12
+
13
+ var _jestAxe = require("jest-axe");
14
+
15
+ var _NewConfirmationDialog = require("./NewConfirmationDialog");
16
+
17
+ var _jsxRuntime = require("theme-ui/jsx-runtime");
18
+
19
+ /**
20
+ * External dependencies
21
+ */
22
+
23
+ /**
24
+ * Internal dependencies
25
+ */
26
+ var defaultProps = {
27
+ needsConfirm: true,
28
+ title: 'My Custom Title',
29
+ body: 'My Custom Text',
30
+ label: 'Submit this!',
31
+ trigger: (0, _jsxRuntime.jsx)("button", {
32
+ children: "Trigger"
33
+ })
34
+ };
35
+
36
+ var getButton = function getButton() {
37
+ return _react.screen.getByText('Trigger');
38
+ };
39
+
40
+ var getConfirmButton = function getConfirmButton() {
41
+ return _react.screen.getByText(defaultProps.label);
42
+ };
43
+
44
+ var getTitle = function getTitle() {
45
+ return _react.screen.getByRole('heading', {
46
+ level: 2
47
+ });
48
+ };
49
+
50
+ describe('<NewConfirmationDialog />', function () {
51
+ it('renders the NewConfirmationDialog component', /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() {
52
+ var _render, container;
53
+
54
+ return _regenerator["default"].wrap(function _callee$(_context) {
55
+ while (1) {
56
+ switch (_context.prev = _context.next) {
57
+ case 0:
58
+ _render = (0, _react.render)((0, _jsxRuntime.jsx)(_NewConfirmationDialog.NewConfirmationDialog, (0, _extends2["default"])({}, defaultProps))), container = _render.container;
59
+ expect(getButton()).toBeInTheDocument();
60
+
61
+ _react.fireEvent.click(getButton());
62
+
63
+ expect(getTitle()).toHaveTextContent(defaultProps.title);
64
+ expect(getConfirmButton()).toBeInTheDocument(); // Check for accessibility issues
65
+
66
+ _context.t0 = expect;
67
+ _context.next = 8;
68
+ return (0, _jestAxe.axe)(container);
69
+
70
+ case 8:
71
+ _context.t1 = _context.sent;
72
+ _context.next = 11;
73
+ return (0, _context.t0)(_context.t1).toHaveNoViolations();
74
+
75
+ case 11:
76
+ case "end":
77
+ return _context.stop();
78
+ }
79
+ }
80
+ }, _callee);
81
+ })));
82
+ });
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+
5
+ var _NewConfirmationDialog = require("./NewConfirmationDialog");
6
+
7
+ exports.NewConfirmationDialog = _NewConfirmationDialog.NewConfirmationDialog;
@@ -43,7 +43,8 @@ var DialogDescription = /*#__PURE__*/_react["default"].forwardRef(function (_ref
43
43
  return (0, _jsxRuntime.jsx)(DialogPrimitive.Description, (0, _extends2["default"])({}, rest, {
44
44
  ref: forwardedRef,
45
45
  sx: {
46
- margin: 0
46
+ margin: 0,
47
+ color: 'text'
47
48
  },
48
49
  children: text
49
50
  }));
@@ -52,6 +53,6 @@ var DialogDescription = /*#__PURE__*/_react["default"].forwardRef(function (_ref
52
53
  exports.DialogDescription = DialogDescription;
53
54
  DialogDescription.displayName = 'DialogDescription';
54
55
  DialogDescription.propTypes = {
55
- description: _propTypes["default"].string,
56
+ description: _propTypes["default"].node,
56
57
  hidden: _propTypes["default"].bool
57
58
  };
@@ -40,7 +40,9 @@ var DialogTitle = function DialogTitle(_ref) {
40
40
 
41
41
  return (0, _jsxRuntime.jsx)(DialogPrimitive.Title, {
42
42
  sx: {
43
- margin: 0
43
+ margin: 0,
44
+ fontSize: 3,
45
+ fontWeight: 500
44
46
  },
45
47
  children: titleNode
46
48
  });
@@ -48,6 +50,6 @@ var DialogTitle = function DialogTitle(_ref) {
48
50
 
49
51
  exports.DialogTitle = DialogTitle;
50
52
  DialogTitle.propTypes = {
51
- title: _propTypes["default"].string,
53
+ title: _propTypes["default"].node,
52
54
  hidden: _propTypes["default"].bool
53
55
  };
@@ -7,6 +7,8 @@ exports.NewDialog = void 0;
7
7
 
8
8
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
9
 
10
+ var _react = _interopRequireDefault(require("react"));
11
+
10
12
  var _propTypes = _interopRequireDefault(require("prop-types"));
11
13
 
12
14
  var DialogPrimitive = _interopRequireWildcard(require("@radix-ui/react-dialog"));
@@ -59,14 +61,33 @@ var NewDialog = function NewDialog(_ref) {
59
61
  _ref$id = _ref.id,
60
62
  id = _ref$id === void 0 ? undefined : _ref$id;
61
63
 
64
+ var _React$useState = _react["default"].useState(open || defaultOpen),
65
+ isOpen = _React$useState[0],
66
+ setIsOpen = _React$useState[1];
67
+
62
68
  if (disabled) {
63
69
  return;
64
- }
70
+ } // if content is a function, pass in onClose
71
+
72
+
73
+ var isContentFunction = typeof content === 'function';
74
+
75
+ var handleOnOpenChange = function handleOnOpenChange(status) {
76
+ setIsOpen(status);
77
+
78
+ if (onOpenChange) {
79
+ onOpenChange(status);
80
+ }
81
+ };
82
+
83
+ _react["default"].useEffect(function () {
84
+ handleOnOpenChange(open);
85
+ }, [open]);
65
86
 
66
87
  return (0, _jsxRuntime.jsxs)(DialogPrimitive.Root, {
67
88
  id: id,
68
- open: open,
69
- onOpenChange: onOpenChange,
89
+ open: isOpen,
90
+ onOpenChange: handleOnOpenChange,
70
91
  defaultOpen: defaultOpen,
71
92
  allowPinchZoom: allowPinchZoom,
72
93
  children: [trigger && (0, _jsxRuntime.jsx)(DialogPrimitive.Trigger, {
@@ -84,7 +105,11 @@ var NewDialog = function NewDialog(_ref) {
84
105
  hidden: !showHeading
85
106
  }), (0, _jsxRuntime.jsx)("div", {
86
107
  role: "document",
87
- children: content
108
+ children: isContentFunction ? content({
109
+ onClose: function onClose() {
110
+ return setIsOpen(false);
111
+ }
112
+ }) : content
88
113
  })]
89
114
  })]
90
115
  })]
@@ -94,9 +119,9 @@ var NewDialog = function NewDialog(_ref) {
94
119
  exports.NewDialog = NewDialog;
95
120
  NewDialog.propTypes = {
96
121
  trigger: _propTypes["default"].node.isRequired,
97
- title: _propTypes["default"].string.isRequired,
98
- description: _propTypes["default"].string.isRequired,
99
- content: _propTypes["default"].node,
122
+ title: _propTypes["default"].node.isRequired,
123
+ description: _propTypes["default"].node.isRequired,
124
+ content: _propTypes["default"].oneOfType([_propTypes["default"].node, _propTypes["default"].func]),
100
125
  showHeading: _propTypes["default"].bool,
101
126
  disabled: _propTypes["default"].bool,
102
127
  style: _propTypes["default"].oneOfType([_propTypes["default"].object, _propTypes["default"].func]),
@@ -3,7 +3,7 @@
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
4
 
5
5
  exports.__esModule = true;
6
- exports["default"] = exports.HiddenHeadings = exports.Default = exports.CustomStyling = exports.CustomStateManagement = exports.CustomClose = exports.AutoOpen = void 0;
6
+ exports["default"] = exports.HiddenHeadings = exports.Default = exports.CustomStyling = exports.CustomStateManagement = exports.CustomOnClose = exports.CustomClose = exports.AutoOpen = void 0;
7
7
 
8
8
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
9
 
@@ -222,20 +222,56 @@ var CustomStateManagement = function CustomStateManagement() {
222
222
  }), " attribute."]
223
223
  }), (0, _jsxRuntime.jsx)(NewDialog.Root, (0, _extends2["default"])({}, defaultProps, {
224
224
  open: open,
225
- onOpenChange: setOpen,
225
+ onOpenChange: function onOpenChange(status) {
226
+ // eslint-disable-next-line no-console
227
+ console.log('New status changed', status);
228
+ setOpen(!!open);
229
+ },
226
230
  trigger: (0, _jsxRuntime.jsx)(_system.Button, {
227
231
  children: "Trigger Dialog"
228
232
  }),
229
233
  content: (0, _jsxRuntime.jsx)("div", {
230
- children: (0, _jsxRuntime.jsx)(_system.Button, {
231
- onClick: function onClick() {
232
- return setOpen(false);
233
- },
234
- children: "Close here instead"
234
+ sx: {
235
+ mt: 2
236
+ },
237
+ children: (0, _jsxRuntime.jsx)(NewDialog.Close, {
238
+ children: (0, _jsxRuntime.jsx)(_system.Button, {
239
+ children: "Close here instead"
240
+ })
235
241
  })
236
242
  })
237
243
  }))]
238
244
  });
239
245
  };
240
246
 
241
- exports.CustomStateManagement = CustomStateManagement;
247
+ exports.CustomStateManagement = CustomStateManagement;
248
+
249
+ var CustomOnClose = function CustomOnClose() {
250
+ return (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
251
+ children: [(0, _jsxRuntime.jsx)(_system.Text, {
252
+ sx: {
253
+ fontSize: 3,
254
+ mb: 3
255
+ },
256
+ children: "This example shows how you can use the content as a function to use the onClose method (same behavior as the original Dialog component)."
257
+ }), (0, _jsxRuntime.jsx)(NewDialog.Root, (0, _extends2["default"])({}, defaultProps, {
258
+ trigger: (0, _jsxRuntime.jsx)(_system.Button, {
259
+ children: "Trigger Dialog"
260
+ }),
261
+ content: function content(_ref) {
262
+ var onClose = _ref.onClose;
263
+ return (0, _jsxRuntime.jsx)("div", {
264
+ sx: {
265
+ mt: 2
266
+ },
267
+ children: (0, _jsxRuntime.jsx)(_system.Button, {
268
+ onClick: onClose,
269
+ children: "Close here instead"
270
+ })
271
+ });
272
+ }
273
+ }))]
274
+ });
275
+ };
276
+
277
+ exports.CustomOnClose = CustomOnClose;
@@ -51,6 +51,10 @@ var _ConfirmationDialog = require("./ConfirmationDialog");
51
51
 
52
52
  exports.ConfirmationDialog = _ConfirmationDialog.ConfirmationDialog;
53
53
 
54
+ var _NewConfirmationDialog = require("./NewConfirmationDialog");
55
+
56
+ exports.NewConfirmationDialog = _NewConfirmationDialog.NewConfirmationDialog;
57
+
54
58
  var _Flex = require("./Flex");
55
59
 
56
60
  exports.Flex = _Flex.Flex;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/vip-design-system",
3
- "version": "0.16.0",
3
+ "version": "0.18.0",
4
4
  "main": "build/system/index.js",
5
5
  "scripts": {
6
6
  "build-storybook": "build-storybook",
@@ -25,6 +25,7 @@
25
25
  "@radix-ui/react-switch": "^0.1.5",
26
26
  "@radix-ui/react-tooltip": "^0.1.7",
27
27
  "@radix-ui/react-visually-hidden": "^0.1.4",
28
+ "@storybook/addon-storysource": "^6.5.10",
28
29
  "babel-loader": "^8.2.2",
29
30
  "classnames": "^2.3.1",
30
31
  "framer-motion": "^3.9.1",
@@ -0,0 +1,93 @@
1
+ /** @jsxImportSource theme-ui */
2
+
3
+ /**
4
+ * External dependencies
5
+ */
6
+ import classNames from 'classnames';
7
+ import PropTypes from 'prop-types';
8
+ import React from 'react';
9
+
10
+ /**
11
+ * Internal dependencies
12
+ */
13
+ import { NewDialog, Box, Flex, Button } from '..';
14
+
15
+ const NewConfirmationDialogContent = ( {
16
+ label = 'Confirm',
17
+ onConfirm,
18
+ onClose,
19
+ className = null,
20
+ } ) => (
21
+ <Box className={ classNames( 'vip-confirmation-dialog-component', className ) }>
22
+ <Flex sx={ { justifyContent: 'flex-end', mt: 4 } }>
23
+ <Button variant="secondary" sx={ { mr: 2 } } onClick={ onClose }>
24
+ Cancel
25
+ </Button>
26
+ <NewDialog.Close>
27
+ <Button
28
+ variant="danger"
29
+ onClick={ () => {
30
+ onConfirm();
31
+ onClose();
32
+ } }
33
+ >
34
+ { label }
35
+ </Button>
36
+ </NewDialog.Close>
37
+ </Flex>
38
+ </Box>
39
+ );
40
+
41
+ NewConfirmationDialogContent.propTypes = {
42
+ body: PropTypes.node,
43
+ label: PropTypes.string,
44
+ onClose: PropTypes.func,
45
+ onConfirm: PropTypes.func,
46
+ className: PropTypes.any,
47
+ };
48
+
49
+ const NewConfirmationDialog = ( {
50
+ trigger,
51
+ onConfirm,
52
+ needsConfirm = true,
53
+ label,
54
+ title,
55
+ body = '',
56
+ } ) => {
57
+ const [ open, setOpen ] = React.useState( false );
58
+ const directTrigger = React.cloneElement( trigger, { onClick: onConfirm } );
59
+
60
+ if ( ! needsConfirm ) {
61
+ return directTrigger;
62
+ }
63
+
64
+ return (
65
+ <NewDialog.Root
66
+ open={ open }
67
+ onOpenChange={ setOpen }
68
+ sx={ { maxWidth: 680 } }
69
+ title={ title }
70
+ description={ body }
71
+ content={
72
+ <NewConfirmationDialogContent
73
+ onClose={ () => setOpen( false ) }
74
+ onConfirm={ onConfirm }
75
+ body={ body }
76
+ label={ label }
77
+ />
78
+ }
79
+ trigger={ trigger }
80
+ />
81
+ );
82
+ };
83
+
84
+ NewConfirmationDialog.propTypes = {
85
+ needsConfirm: PropTypes.bool,
86
+ trigger: PropTypes.node,
87
+ onConfirm: PropTypes.func,
88
+ title: PropTypes.node.isRequired,
89
+ body: PropTypes.node,
90
+ label: PropTypes.node,
91
+ };
92
+
93
+ export { NewConfirmationDialog };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import React from 'react';
5
+ import { Box, NewConfirmationDialog, Button } from '..';
6
+
7
+ export default {
8
+ title: 'NewConfirmationDialog',
9
+ component: NewConfirmationDialog,
10
+ };
11
+
12
+ const ConfirmationTrigger = <Button sx={ { mr: 3 } }>Click to answer</Button>;
13
+
14
+ export const Default = () => {
15
+ const [ answer, setAnswer ] = React.useState( '🤔' );
16
+ return (
17
+ <Box>
18
+ <p>Confirm that your name is John doe?</p>
19
+ <NewConfirmationDialog
20
+ title={ 'Are you John Doe?' }
21
+ description={ 'Please confirm that your name is John Doe.' }
22
+ trigger={ ConfirmationTrigger }
23
+ body="A modal is used to perform more detailed actions that don&lsquo;t necessarily need the context
24
+ behind."
25
+ onConfirm={ () => setAnswer( '👍' ) }
26
+ needsConfirm={ true }
27
+ />
28
+
29
+ <p>Answer: { answer }</p>
30
+ </Box>
31
+ );
32
+ };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { fireEvent, render, screen } from '@testing-library/react';
5
+ import { axe } from 'jest-axe';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import { NewConfirmationDialog } from './NewConfirmationDialog';
11
+
12
+ const defaultProps = {
13
+ needsConfirm: true,
14
+ title: 'My Custom Title',
15
+ body: 'My Custom Text',
16
+ label: 'Submit this!',
17
+ trigger: <button>Trigger</button>,
18
+ };
19
+
20
+ const getButton = () => screen.getByText( 'Trigger' );
21
+ const getConfirmButton = () => screen.getByText( defaultProps.label );
22
+ const getTitle = () => screen.getByRole( 'heading', { level: 2 } );
23
+
24
+ describe( '<NewConfirmationDialog />', () => {
25
+ it( 'renders the NewConfirmationDialog component', async () => {
26
+ const { container } = render( <NewConfirmationDialog { ...defaultProps } /> );
27
+
28
+ expect( getButton() ).toBeInTheDocument();
29
+
30
+ fireEvent.click( getButton() );
31
+
32
+ expect( getTitle() ).toHaveTextContent( defaultProps.title );
33
+
34
+ expect( getConfirmButton() ).toBeInTheDocument();
35
+
36
+ // Check for accessibility issues
37
+ await expect( await axe( container ) ).toHaveNoViolations();
38
+ } );
39
+ } );
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { NewConfirmationDialog } from './NewConfirmationDialog';
5
+
6
+ export { NewConfirmationDialog };
@@ -21,7 +21,11 @@ export const DialogDescription = React.forwardRef(
21
21
  }
22
22
 
23
23
  return (
24
- <DialogPrimitive.Description { ...rest } ref={ forwardedRef } sx={ { margin: 0 } }>
24
+ <DialogPrimitive.Description
25
+ { ...rest }
26
+ ref={ forwardedRef }
27
+ sx={ { margin: 0, color: 'text' } }
28
+ >
25
29
  { text }
26
30
  </DialogPrimitive.Description>
27
31
  );
@@ -31,6 +35,6 @@ export const DialogDescription = React.forwardRef(
31
35
  DialogDescription.displayName = 'DialogDescription';
32
36
 
33
37
  DialogDescription.propTypes = {
34
- description: PropTypes.string,
38
+ description: PropTypes.node,
35
39
  hidden: PropTypes.bool,
36
40
  };
@@ -18,10 +18,14 @@ export const DialogTitle = ( { title, hidden = false } ) => {
18
18
  titleNode = <ScreenReaderText>{ titleNode }</ScreenReaderText>;
19
19
  }
20
20
 
21
- return <DialogPrimitive.Title sx={ { margin: 0 } }>{ titleNode }</DialogPrimitive.Title>;
21
+ return (
22
+ <DialogPrimitive.Title sx={ { margin: 0, fontSize: 3, fontWeight: 500 } }>
23
+ { titleNode }
24
+ </DialogPrimitive.Title>
25
+ );
22
26
  };
23
27
 
24
28
  DialogTitle.propTypes = {
25
- title: PropTypes.string,
29
+ title: PropTypes.node,
26
30
  hidden: PropTypes.bool,
27
31
  };
@@ -3,6 +3,7 @@
3
3
  /**
4
4
  * External dependencies
5
5
  */
6
+ import React from 'react';
6
7
  import PropTypes from 'prop-types';
7
8
  import * as DialogPrimitive from '@radix-ui/react-dialog';
8
9
  /**
@@ -30,15 +31,32 @@ export const NewDialog = ( {
30
31
  open = undefined,
31
32
  id = undefined,
32
33
  } ) => {
34
+ const [ isOpen, setIsOpen ] = React.useState( open || defaultOpen );
35
+
33
36
  if ( disabled ) {
34
37
  return;
35
38
  }
36
39
 
40
+ // if content is a function, pass in onClose
41
+ const isContentFunction = typeof content === 'function';
42
+
43
+ const handleOnOpenChange = status => {
44
+ setIsOpen( status );
45
+
46
+ if ( onOpenChange ) {
47
+ onOpenChange( status );
48
+ }
49
+ };
50
+
51
+ React.useEffect( () => {
52
+ handleOnOpenChange( open );
53
+ }, [ open ] );
54
+
37
55
  return (
38
56
  <DialogPrimitive.Root
39
57
  id={ id }
40
- open={ open }
41
- onOpenChange={ onOpenChange }
58
+ open={ isOpen }
59
+ onOpenChange={ handleOnOpenChange }
42
60
  defaultOpen={ defaultOpen }
43
61
  allowPinchZoom={ allowPinchZoom }
44
62
  >
@@ -55,7 +73,9 @@ export const NewDialog = ( {
55
73
  <DialogTitle title={ title } hidden={ ! showHeading } />
56
74
  <DialogDescription description={ description } hidden={ ! showHeading } />
57
75
 
58
- <div role="document">{ content }</div>
76
+ <div role="document">
77
+ { isContentFunction ? content( { onClose: () => setIsOpen( false ) } ) : content }
78
+ </div>
59
79
  </DialogPrimitive.Content>
60
80
  </DialogPrimitive.Portal>
61
81
  </DialogPrimitive.Root>
@@ -64,9 +84,9 @@ export const NewDialog = ( {
64
84
 
65
85
  NewDialog.propTypes = {
66
86
  trigger: PropTypes.node.isRequired,
67
- title: PropTypes.string.isRequired,
68
- description: PropTypes.string.isRequired,
69
- content: PropTypes.node,
87
+ title: PropTypes.node.isRequired,
88
+ description: PropTypes.node.isRequired,
89
+ content: PropTypes.oneOfType( [ PropTypes.node, PropTypes.func ] ),
70
90
  showHeading: PropTypes.bool,
71
91
  disabled: PropTypes.bool,
72
92
  style: PropTypes.oneOfType( [ PropTypes.object, PropTypes.func ] ),
@@ -89,6 +89,7 @@ export const HiddenHeadings = () => (
89
89
  />
90
90
  </>
91
91
  );
92
+
92
93
  export const CustomStyling = () => (
93
94
  <>
94
95
  <Text sx={ { fontSize: 3, mb: 3 } }>Custom Styling on Dialog Content</Text>
@@ -136,6 +137,7 @@ export const CustomClose = () => (
136
137
  />
137
138
  </>
138
139
  );
140
+
139
141
  export const CustomStateManagement = () => {
140
142
  const [ open, setOpen ] = useState( false );
141
143
  return (
@@ -149,14 +151,42 @@ export const CustomStateManagement = () => {
149
151
  <NewDialog.Root
150
152
  { ...defaultProps }
151
153
  open={ open }
152
- onOpenChange={ setOpen }
154
+ onOpenChange={ status => {
155
+ // eslint-disable-next-line no-console
156
+ console.log( 'New status changed', status );
157
+
158
+ setOpen( !! open );
159
+ } }
153
160
  trigger={ <Button>Trigger Dialog</Button> }
154
161
  content={
155
- <div>
156
- <Button onClick={ () => setOpen( false ) }>Close here instead</Button>
162
+ <div sx={ { mt: 2 } }>
163
+ <NewDialog.Close>
164
+ <Button>Close here instead</Button>
165
+ </NewDialog.Close>
157
166
  </div>
158
167
  }
159
168
  />
160
169
  </>
161
170
  );
162
171
  };
172
+
173
+ export const CustomOnClose = () => {
174
+ return (
175
+ <>
176
+ <Text sx={ { fontSize: 3, mb: 3 } }>
177
+ This example shows how you can use the content as a function to use the onClose method (same
178
+ behavior as the original Dialog component).
179
+ </Text>
180
+
181
+ <NewDialog.Root
182
+ { ...defaultProps }
183
+ trigger={ <Button>Trigger Dialog</Button> }
184
+ content={ ( { onClose } ) => (
185
+ <div sx={ { mt: 2 } }>
186
+ <Button onClick={ onClose }>Close here instead</Button>
187
+ </div>
188
+ ) }
189
+ />
190
+ </>
191
+ );
192
+ };
@@ -20,6 +20,7 @@ import {
20
20
 
21
21
  import * as NewDialog from './NewDialog';
22
22
  import { ConfirmationDialog } from './ConfirmationDialog';
23
+ import { NewConfirmationDialog } from './NewConfirmationDialog';
23
24
  import { Flex } from './Flex';
24
25
  import {
25
26
  Input,
@@ -70,6 +71,7 @@ export {
70
71
  DialogContent,
71
72
  DialogTrigger,
72
73
  ConfirmationDialog,
74
+ NewConfirmationDialog,
73
75
  Grid,
74
76
  Flex,
75
77
  Notice,