@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.
- package/.storybook/main.js +1 -0
- package/build/system/NewConfirmationDialog/NewConfirmationDialog.js +120 -0
- package/build/system/NewConfirmationDialog/NewConfirmationDialog.stories.js +52 -0
- package/build/system/NewConfirmationDialog/NewConfirmationDialog.test.js +82 -0
- package/build/system/NewConfirmationDialog/index.js +7 -0
- package/build/system/NewDialog/DialogDescription.js +3 -2
- package/build/system/NewDialog/DialogTitle.js +4 -2
- package/build/system/NewDialog/NewDialog.js +32 -7
- package/build/system/NewDialog/NewDialog.stories.js +44 -8
- package/build/system/index.js +4 -0
- package/package.json +2 -1
- package/src/system/NewConfirmationDialog/NewConfirmationDialog.js +93 -0
- package/src/system/NewConfirmationDialog/NewConfirmationDialog.stories.jsx +32 -0
- package/src/system/NewConfirmationDialog/NewConfirmationDialog.test.js +39 -0
- package/src/system/NewConfirmationDialog/index.js +6 -0
- package/src/system/NewDialog/DialogDescription.js +6 -2
- package/src/system/NewDialog/DialogTitle.js +6 -2
- package/src/system/NewDialog/NewDialog.js +26 -6
- package/src/system/NewDialog/NewDialog.stories.jsx +33 -3
- package/src/system/index.js +2 -0
package/.storybook/main.js
CHANGED
|
@@ -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
|
+
});
|
|
@@ -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"].
|
|
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"].
|
|
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:
|
|
69
|
-
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"].
|
|
98
|
-
description: _propTypes["default"].
|
|
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:
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
children:
|
|
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;
|
package/build/system/index.js
CHANGED
|
@@ -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.
|
|
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‘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
|
+
} );
|
|
@@ -21,7 +21,11 @@ export const DialogDescription = React.forwardRef(
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
return (
|
|
24
|
-
<DialogPrimitive.Description
|
|
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.
|
|
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
|
|
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.
|
|
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={
|
|
41
|
-
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">
|
|
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.
|
|
68
|
-
description: PropTypes.
|
|
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={
|
|
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
|
-
<
|
|
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
|
+
};
|
package/src/system/index.js
CHANGED
|
@@ -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,
|