@pingux/astro 1.1.0-alpha.15 → 1.1.0-alpha.16
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/lib/cjs/components/OverlayPanel/OverlayPanel.js +53 -6
- package/lib/cjs/components/OverlayPanel/OverlayPanel.stories.js +59 -47
- package/lib/cjs/components/OverlayPanel/OverlayPanel.test.js +84 -0
- package/lib/cjs/hooks/useOverlayPanelState/useOverlayPanelState.js +20 -1
- package/lib/cjs/hooks/useOverlayPanelState/useOverlayPanelState.test.js +7 -3
- package/lib/components/OverlayPanel/OverlayPanel.js +52 -8
- package/lib/components/OverlayPanel/OverlayPanel.stories.js +59 -49
- package/lib/components/OverlayPanel/OverlayPanel.test.js +73 -1
- package/lib/hooks/useOverlayPanelState/useOverlayPanelState.js +20 -1
- package/lib/hooks/useOverlayPanelState/useOverlayPanelState.test.js +7 -3
- package/package.json +2 -2
@@ -18,12 +18,16 @@ var _extends2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/e
|
|
18
18
|
|
19
19
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/defineProperty"));
|
20
20
|
|
21
|
+
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/slicedToArray"));
|
22
|
+
|
21
23
|
var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/objectWithoutProperties"));
|
22
24
|
|
23
25
|
var _react = _interopRequireWildcard(require("react"));
|
24
26
|
|
25
27
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
26
28
|
|
29
|
+
var _focus = require("@react-aria/focus");
|
30
|
+
|
27
31
|
var _Box = _interopRequireDefault(require("../Box"));
|
28
32
|
|
29
33
|
var _hooks = require("../../hooks");
|
@@ -37,12 +41,25 @@ var OverlayPanel = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
|
|
37
41
|
|
38
42
|
var children = props.children,
|
39
43
|
isOpen = props.isOpen,
|
44
|
+
onCloseProp = props.onClose,
|
40
45
|
className = props.className,
|
46
|
+
state = props.state,
|
41
47
|
size = props.size,
|
42
|
-
|
48
|
+
triggerRef = props.triggerRef,
|
49
|
+
others = (0, _objectWithoutProperties2["default"])(props, ["children", "isOpen", "onClose", "className", "state", "size", "triggerRef"]);
|
50
|
+
|
51
|
+
var _useOverlayPanelState = (0, _hooks.useOverlayPanelState)(),
|
52
|
+
onClose = _useOverlayPanelState.onClose;
|
53
|
+
|
43
54
|
var overlayPanelRef = (0, _react.useRef)();
|
55
|
+
|
56
|
+
var _useState = (0, _react.useState)(true),
|
57
|
+
_useState2 = (0, _slicedToArray2["default"])(_useState, 2),
|
58
|
+
contain = _useState2[0],
|
59
|
+
setIsContained = _useState2[1];
|
44
60
|
/* istanbul ignore next */
|
45
61
|
|
62
|
+
|
46
63
|
(0, _react.useImperativeHandle)(ref, function () {
|
47
64
|
return overlayPanelRef.current;
|
48
65
|
});
|
@@ -52,14 +69,32 @@ var OverlayPanel = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
|
|
52
69
|
}, "is-".concat((props === null || props === void 0 ? void 0 : (_props$sx = props.sx) === null || _props$sx === void 0 ? void 0 : _props$sx.width) ? 'custom' : size), size)),
|
53
70
|
classNames = _useStatusClasses.classNames;
|
54
71
|
|
55
|
-
|
56
|
-
|
72
|
+
var handleClose = function handleClose(e) {
|
73
|
+
e.stopPropagation();
|
74
|
+
|
75
|
+
if (e.key === 'Escape') {
|
76
|
+
setIsContained(false);
|
77
|
+
}
|
78
|
+
};
|
79
|
+
|
80
|
+
(0, _react.useEffect)(function () {
|
81
|
+
if (!contain && onClose) {
|
82
|
+
onClose(state, triggerRef, onCloseProp);
|
83
|
+
}
|
84
|
+
}, [contain]);
|
85
|
+
return (0, _react2.jsx)(_focus.FocusScope, {
|
86
|
+
autoFocus: true,
|
87
|
+
contain: contain
|
88
|
+
}, (0, _react2.jsx)(_Box["default"], (0, _extends2["default"])({
|
89
|
+
variant: "overlayPanel.overlayPanel",
|
90
|
+
ref: overlayPanelRef
|
57
91
|
}, others, {
|
58
|
-
className: classNames
|
92
|
+
className: classNames,
|
93
|
+
onKeyUp: handleClose
|
59
94
|
}), (0, _react2.jsx)(_Box["default"], {
|
60
95
|
variant: "overlayPanel.overlayPanelBody",
|
61
96
|
className: classNames
|
62
|
-
}, children));
|
97
|
+
}, children)));
|
63
98
|
});
|
64
99
|
OverlayPanel.propTypes = {
|
65
100
|
/** Sets the open state of the menu. */
|
@@ -71,7 +106,19 @@ OverlayPanel.propTypes = {
|
|
71
106
|
/** JSX styling that is passed into the component. */
|
72
107
|
sx: _propTypes["default"].shape({
|
73
108
|
width: _propTypes["default"].string
|
74
|
-
})
|
109
|
+
}),
|
110
|
+
|
111
|
+
/** State object that is passed in from the useOverlayPanelState hook */
|
112
|
+
state: _propTypes["default"].shape({
|
113
|
+
close: _propTypes["default"].func
|
114
|
+
}),
|
115
|
+
|
116
|
+
/** Callback function that runs when the esc key is used to close the OverlayPanel. */
|
117
|
+
onClose: _propTypes["default"].func,
|
118
|
+
|
119
|
+
/** Ref that is connected to the button that triggers the overlay state.
|
120
|
+
Focus will return to this ref when the keyboard is used to close the OverlayPanel. */
|
121
|
+
triggerRef: _propTypes["default"].shape({})
|
75
122
|
};
|
76
123
|
OverlayPanel.defaultProps = {
|
77
124
|
size: 'medium'
|
@@ -61,21 +61,29 @@ exports["default"] = _default;
|
|
61
61
|
|
62
62
|
var Default = function Default(_ref) {
|
63
63
|
var args = (0, _extends2["default"])({}, _ref);
|
64
|
-
|
64
|
+
|
65
|
+
var _useOverlayPanelState = (0, _hooks.useOverlayPanelState)(),
|
66
|
+
state = _useOverlayPanelState.state,
|
67
|
+
onClose = _useOverlayPanelState.onClose;
|
68
|
+
|
69
|
+
var triggerRef = (0, _react.useRef)();
|
65
70
|
return (// Application must be wrapped in an OverlayProvider so that it can be hidden from screen
|
66
|
-
// readers when an overlay
|
71
|
+
// readers when an overlay is open.
|
67
72
|
(0, _react2.jsx)(_index.OverlayProvider, null, (0, _react2.jsx)(_index.Text, null, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."), (0, _react2.jsx)("br", null), (0, _react2.jsx)(_index.Button, {
|
73
|
+
ref: triggerRef,
|
68
74
|
onPress: state.open
|
69
|
-
}, "Open Panel"), (0, _react2.jsx)(_OverlayPanel["default"], (0, _extends2["default"])({
|
70
|
-
isOpen: state.isOpen
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
}, (0, _react2.jsx)(_index.Text,
|
75
|
+
}, "Open Panel"), state.isOpen && (0, _react2.jsx)(_OverlayPanel["default"], (0, _extends2["default"])({
|
76
|
+
isOpen: state.isOpen,
|
77
|
+
state: state
|
78
|
+
}, args, {
|
79
|
+
triggerRef: triggerRef
|
80
|
+
}), (0, _react2.jsx)(_index.Box, null, (0, _react2.jsx)(_index.Button, {
|
81
|
+
onPress: function onPress() {
|
82
|
+
onClose(state, triggerRef);
|
83
|
+
}
|
84
|
+
}, "Close Panel"), (0, _react2.jsx)(_index.Text, {
|
85
|
+
pt: "md"
|
86
|
+
}, "Children render here."))))
|
79
87
|
);
|
80
88
|
};
|
81
89
|
|
@@ -83,8 +91,17 @@ exports.Default = Default;
|
|
83
91
|
|
84
92
|
var InnerPanel = function InnerPanel(_ref2) {
|
85
93
|
var args = (0, _extends2["default"])({}, _ref2);
|
86
|
-
|
87
|
-
var
|
94
|
+
|
95
|
+
var _useOverlayPanelState2 = (0, _hooks.useOverlayPanelState)(),
|
96
|
+
state = _useOverlayPanelState2.state,
|
97
|
+
onClose = _useOverlayPanelState2.onClose;
|
98
|
+
|
99
|
+
var _useOverlayPanelState3 = (0, _hooks.useOverlayPanelState)(),
|
100
|
+
innerState = _useOverlayPanelState3.state,
|
101
|
+
onCloseInner = _useOverlayPanelState3.onClose;
|
102
|
+
|
103
|
+
var outerTriggerRef = (0, _react.useRef)();
|
104
|
+
var innerTriggerRef = (0, _react.useRef)();
|
88
105
|
|
89
106
|
var _useState = (0, _react.useState)(false),
|
90
107
|
_useState2 = (0, _slicedToArray2["default"])(_useState, 2),
|
@@ -100,15 +117,22 @@ var InnerPanel = function InnerPanel(_ref2) {
|
|
100
117
|
innerState.close();
|
101
118
|
}
|
102
119
|
|
103
|
-
state
|
120
|
+
onClose(state, outerTriggerRef);
|
121
|
+
};
|
122
|
+
|
123
|
+
var closeInnerPanel = function closeInnerPanel() {
|
124
|
+
onCloseInner(innerState, innerTriggerRef);
|
104
125
|
};
|
105
126
|
|
106
127
|
var inner = (0, _react2.jsx)(_react["default"].Fragment, null, innerState.isOpen && (0, _react2.jsx)(_OverlayPanel["default"], (0, _extends2["default"])({
|
107
128
|
variant: "overlayPanel.overlayPanelInner" // applies higher z-index
|
108
129
|
,
|
109
130
|
isOpen: innerState.isOpen
|
110
|
-
}, args
|
111
|
-
|
131
|
+
}, args, {
|
132
|
+
state: innerState,
|
133
|
+
triggerRef: innerTriggerRef
|
134
|
+
}), (0, _react2.jsx)(_index.Box, null, (0, _react2.jsx)(_index.Button, {
|
135
|
+
onPress: closeInnerPanel
|
112
136
|
}, "Close Inner Panel"), (0, _react2.jsx)(_index.Text, {
|
113
137
|
pt: "md"
|
114
138
|
}, "Children render here."))));
|
@@ -118,7 +142,10 @@ var InnerPanel = function InnerPanel(_ref2) {
|
|
118
142
|
sx: {
|
119
143
|
p: '0px'
|
120
144
|
}
|
121
|
-
}, args
|
145
|
+
}, args, {
|
146
|
+
state: state,
|
147
|
+
triggerRef: outerTriggerRef
|
148
|
+
}), (0, _react2.jsx)(_index.Box, {
|
122
149
|
sx: {
|
123
150
|
p: '12px'
|
124
151
|
}
|
@@ -141,38 +168,16 @@ var InnerPanel = function InnerPanel(_ref2) {
|
|
141
168
|
mr: "auto"
|
142
169
|
}, "Form 2")), (0, _react2.jsx)(_index.Separator, {
|
143
170
|
margin: "0"
|
144
|
-
}), (0, _react2.jsx)(_index.ListItem, {
|
145
|
-
title: "Form 3"
|
146
|
-
}, (0, _react2.jsx)(_index.Text, {
|
147
|
-
variant: "itemTitle",
|
148
|
-
alignSelf: "center",
|
149
|
-
mr: "auto"
|
150
|
-
}, "Form 3")), (0, _react2.jsx)(_index.Separator, {
|
151
|
-
margin: "0"
|
152
|
-
}), (0, _react2.jsx)(_index.ListItem, {
|
153
|
-
title: "Form 4"
|
154
|
-
}, (0, _react2.jsx)(_index.Text, {
|
155
|
-
variant: "itemTitle",
|
156
|
-
alignSelf: "center",
|
157
|
-
mr: "auto"
|
158
|
-
}, "Form 4")), (0, _react2.jsx)(_index.Separator, {
|
159
|
-
margin: "0"
|
160
|
-
}), (0, _react2.jsx)(_index.ListItem, {
|
161
|
-
title: "Form 5"
|
162
|
-
}, (0, _react2.jsx)(_index.Text, {
|
163
|
-
variant: "itemTitle",
|
164
|
-
alignSelf: "center",
|
165
|
-
mr: "auto"
|
166
|
-
}, "Form 5")), (0, _react2.jsx)(_index.Separator, {
|
167
|
-
margin: "0"
|
168
171
|
})), (0, _react2.jsx)("br", null), (0, _react2.jsx)(_index.Button, {
|
169
172
|
onPress: toggleMessagesOpen
|
170
173
|
}, "Toggle Messages"), (0, _react2.jsx)("br", null), (0, _react2.jsx)(_index.Button, {
|
174
|
+
ref: innerTriggerRef,
|
171
175
|
onPress: innerState.open
|
172
176
|
}, "Open Inner Panel"), inner)));
|
173
177
|
return (// Application must be wrapped in an OverlayProvider so that it can be hidden from screen
|
174
178
|
// readers when an overlay opens.
|
175
179
|
(0, _react2.jsx)(_react["default"].Fragment, null, (0, _react2.jsx)(_index.OverlayProvider, null, (0, _react2.jsx)(_index.Button, {
|
180
|
+
ref: outerTriggerRef,
|
176
181
|
onPress: state.open
|
177
182
|
}, "Open Panel"), outer), messagesOpen && (0, _react2.jsx)(_index.Messages, {
|
178
183
|
sx: {
|
@@ -188,20 +193,27 @@ var InnerPanel = function InnerPanel(_ref2) {
|
|
188
193
|
exports.InnerPanel = InnerPanel;
|
189
194
|
|
190
195
|
var CustomWidth = function CustomWidth() {
|
191
|
-
var
|
196
|
+
var _useOverlayPanelState4 = (0, _hooks.useOverlayPanelState)(),
|
197
|
+
state = _useOverlayPanelState4.state,
|
198
|
+
onClose = _useOverlayPanelState4.onClose;
|
199
|
+
|
200
|
+
var triggerRef = (0, _react.useRef)();
|
192
201
|
return (// Application must be wrapped in an OverlayProvider so that it can be hidden from screen
|
193
202
|
// readers when an overlay opens.
|
194
|
-
//
|
195
|
-
// For a custom width, provide the width via the 'sx' prop
|
196
203
|
(0, _react2.jsx)(_index.OverlayProvider, null, (0, _react2.jsx)(_index.Text, null, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."), (0, _react2.jsx)("br", null), (0, _react2.jsx)(_index.Button, {
|
204
|
+
ref: triggerRef,
|
197
205
|
onPress: state.open
|
198
|
-
}, "Open Panel"), (0, _react2.jsx)(_OverlayPanel["default"], {
|
206
|
+
}, "Open Panel"), state.isOpen && (0, _react2.jsx)(_OverlayPanel["default"], {
|
199
207
|
isOpen: state.isOpen,
|
208
|
+
state: state,
|
209
|
+
triggerRef: triggerRef,
|
200
210
|
sx: {
|
201
211
|
width: '720px'
|
202
212
|
}
|
203
213
|
}, (0, _react2.jsx)(_index.Box, null, (0, _react2.jsx)(_index.Button, {
|
204
|
-
onPress:
|
214
|
+
onPress: function onPress() {
|
215
|
+
onClose(state, triggerRef);
|
216
|
+
}
|
205
217
|
}, "Close Panel"), (0, _react2.jsx)(_index.Text, {
|
206
218
|
pt: "md"
|
207
219
|
}, "Children render here."))))
|
@@ -53,4 +53,88 @@ test('custom overlayPanel gets custom width', function () {
|
|
53
53
|
|
54
54
|
expect(overlayPanel).toBeInTheDocument();
|
55
55
|
expect(overlayPanel).toHaveStyleRule('width', '240px');
|
56
|
+
});
|
57
|
+
test('onClose callback fires when provided', function () {
|
58
|
+
var onClose = jest.fn();
|
59
|
+
getComponent({
|
60
|
+
onClose: onClose,
|
61
|
+
children: (0, _react2.jsx)("div", null, "Test")
|
62
|
+
});
|
63
|
+
|
64
|
+
var overlayPanel = _testWrapper.screen.getByTestId(testId);
|
65
|
+
|
66
|
+
_testWrapper.fireEvent.keyDown(overlayPanel, {
|
67
|
+
key: 'Escape',
|
68
|
+
code: 'Escape',
|
69
|
+
keyCode: 27,
|
70
|
+
charCode: 27
|
71
|
+
});
|
72
|
+
|
73
|
+
_testWrapper.fireEvent.keyUp(overlayPanel, {
|
74
|
+
key: 'Escape',
|
75
|
+
code: 'Escape',
|
76
|
+
keyCode: 27,
|
77
|
+
charCode: 27
|
78
|
+
});
|
79
|
+
|
80
|
+
expect(onClose).toHaveBeenCalled();
|
81
|
+
});
|
82
|
+
test('neither callback fires when not provided', function () {
|
83
|
+
var onClose = jest.fn();
|
84
|
+
getComponent({
|
85
|
+
children: (0, _react2.jsx)("div", null, "Test")
|
86
|
+
});
|
87
|
+
|
88
|
+
var overlayPanel = _testWrapper.screen.getByTestId(testId);
|
89
|
+
|
90
|
+
_testWrapper.fireEvent.keyDown(overlayPanel, {
|
91
|
+
key: 'Escape',
|
92
|
+
code: 'Escape',
|
93
|
+
keyCode: 27,
|
94
|
+
charCode: 27
|
95
|
+
});
|
96
|
+
|
97
|
+
_testWrapper.fireEvent.keyUp(overlayPanel, {
|
98
|
+
key: 'Escape',
|
99
|
+
code: 'Escape',
|
100
|
+
keyCode: 27,
|
101
|
+
charCode: 27
|
102
|
+
});
|
103
|
+
|
104
|
+
expect(onClose).not.toHaveBeenCalled();
|
105
|
+
});
|
106
|
+
test('triggerRef.current.focus() fires when provided', function () {
|
107
|
+
var onClose = jest.fn();
|
108
|
+
var focusFunction = jest.fn();
|
109
|
+
var state = {
|
110
|
+
close: onClose
|
111
|
+
};
|
112
|
+
var triggerRef = {
|
113
|
+
current: {
|
114
|
+
focus: focusFunction
|
115
|
+
}
|
116
|
+
};
|
117
|
+
getComponent({
|
118
|
+
state: state,
|
119
|
+
children: (0, _react2.jsx)("div", null, "Test"),
|
120
|
+
triggerRef: triggerRef
|
121
|
+
});
|
122
|
+
|
123
|
+
var overlayPanel = _testWrapper.screen.getByTestId(testId);
|
124
|
+
|
125
|
+
_testWrapper.fireEvent.keyDown(overlayPanel, {
|
126
|
+
key: 'Escape',
|
127
|
+
code: 'Escape',
|
128
|
+
keyCode: 27,
|
129
|
+
charCode: 27
|
130
|
+
});
|
131
|
+
|
132
|
+
_testWrapper.fireEvent.keyUp(overlayPanel, {
|
133
|
+
key: 'Escape',
|
134
|
+
code: 'Escape',
|
135
|
+
keyCode: 27,
|
136
|
+
charCode: 27
|
137
|
+
});
|
138
|
+
|
139
|
+
expect(focusFunction).toHaveBeenCalled();
|
56
140
|
});
|
@@ -24,11 +24,30 @@ var useOverlayPanelState = function useOverlayPanelState() {
|
|
24
24
|
var isDefaultOpen = props.isDefaultOpen,
|
25
25
|
isOpen = props.isOpen,
|
26
26
|
onOpenChange = props.onOpenChange;
|
27
|
-
|
27
|
+
var state = (0, _overlays.useOverlayTriggerState)({
|
28
28
|
defaultOpen: isDefaultOpen,
|
29
29
|
isOpen: isOpen,
|
30
30
|
onOpenChange: onOpenChange
|
31
31
|
});
|
32
|
+
|
33
|
+
var onClose = function onClose(stateProp, triggerRef, onCloseProp) {
|
34
|
+
if (stateProp) {
|
35
|
+
stateProp.close();
|
36
|
+
}
|
37
|
+
|
38
|
+
if (triggerRef === null || triggerRef === void 0 ? void 0 : triggerRef.current) {
|
39
|
+
triggerRef.current.focus();
|
40
|
+
}
|
41
|
+
|
42
|
+
if (onCloseProp) {
|
43
|
+
onCloseProp();
|
44
|
+
}
|
45
|
+
};
|
46
|
+
|
47
|
+
return {
|
48
|
+
state: state,
|
49
|
+
onClose: onClose
|
50
|
+
};
|
32
51
|
};
|
33
52
|
|
34
53
|
var _default = useOverlayPanelState;
|
@@ -13,8 +13,12 @@ test('default useOverlayPanelState', function () {
|
|
13
13
|
result = _renderHook.result;
|
14
14
|
|
15
15
|
expect(result.current).toEqual(expect.objectContaining({
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
state: {
|
17
|
+
open: expect.any(Function),
|
18
|
+
close: expect.any(Function),
|
19
|
+
toggle: expect.any(Function),
|
20
|
+
isOpen: expect.any(Boolean)
|
21
|
+
},
|
22
|
+
onClose: expect.any(Function)
|
19
23
|
}));
|
20
24
|
});
|
@@ -1,11 +1,13 @@
|
|
1
1
|
import _Object$values from "@babel/runtime-corejs3/core-js-stable/object/values";
|
2
2
|
import _extends from "@babel/runtime-corejs3/helpers/esm/extends";
|
3
3
|
import _defineProperty from "@babel/runtime-corejs3/helpers/esm/defineProperty";
|
4
|
+
import _slicedToArray from "@babel/runtime-corejs3/helpers/esm/slicedToArray";
|
4
5
|
import _objectWithoutProperties from "@babel/runtime-corejs3/helpers/esm/objectWithoutProperties";
|
5
|
-
import React, { forwardRef, useRef, useImperativeHandle } from 'react';
|
6
|
+
import React, { forwardRef, useRef, useImperativeHandle, useEffect, useState } from 'react';
|
6
7
|
import PropTypes from 'prop-types';
|
8
|
+
import { FocusScope } from '@react-aria/focus';
|
7
9
|
import Box from '../Box';
|
8
|
-
import { useStatusClasses } from '../../hooks';
|
10
|
+
import { useStatusClasses, useOverlayPanelState } from '../../hooks';
|
9
11
|
import { panelSizes } from '../../utils/devUtils/constants/panelSizes';
|
10
12
|
import { jsx as ___EmotionJSX } from "@emotion/react";
|
11
13
|
var OverlayPanel = /*#__PURE__*/forwardRef(function (props, ref) {
|
@@ -13,13 +15,25 @@ var OverlayPanel = /*#__PURE__*/forwardRef(function (props, ref) {
|
|
13
15
|
|
14
16
|
var children = props.children,
|
15
17
|
isOpen = props.isOpen,
|
18
|
+
onCloseProp = props.onClose,
|
16
19
|
className = props.className,
|
20
|
+
state = props.state,
|
17
21
|
size = props.size,
|
18
|
-
|
22
|
+
triggerRef = props.triggerRef,
|
23
|
+
others = _objectWithoutProperties(props, ["children", "isOpen", "onClose", "className", "state", "size", "triggerRef"]);
|
24
|
+
|
25
|
+
var _useOverlayPanelState = useOverlayPanelState(),
|
26
|
+
onClose = _useOverlayPanelState.onClose;
|
19
27
|
|
20
28
|
var overlayPanelRef = useRef();
|
29
|
+
|
30
|
+
var _useState = useState(true),
|
31
|
+
_useState2 = _slicedToArray(_useState, 2),
|
32
|
+
contain = _useState2[0],
|
33
|
+
setIsContained = _useState2[1];
|
21
34
|
/* istanbul ignore next */
|
22
35
|
|
36
|
+
|
23
37
|
useImperativeHandle(ref, function () {
|
24
38
|
return overlayPanelRef.current;
|
25
39
|
});
|
@@ -29,14 +43,32 @@ var OverlayPanel = /*#__PURE__*/forwardRef(function (props, ref) {
|
|
29
43
|
}, "is-".concat((props === null || props === void 0 ? void 0 : (_props$sx = props.sx) === null || _props$sx === void 0 ? void 0 : _props$sx.width) ? 'custom' : size), size)),
|
30
44
|
classNames = _useStatusClasses.classNames;
|
31
45
|
|
32
|
-
|
33
|
-
|
46
|
+
var handleClose = function handleClose(e) {
|
47
|
+
e.stopPropagation();
|
48
|
+
|
49
|
+
if (e.key === 'Escape') {
|
50
|
+
setIsContained(false);
|
51
|
+
}
|
52
|
+
};
|
53
|
+
|
54
|
+
useEffect(function () {
|
55
|
+
if (!contain && onClose) {
|
56
|
+
onClose(state, triggerRef, onCloseProp);
|
57
|
+
}
|
58
|
+
}, [contain]);
|
59
|
+
return ___EmotionJSX(FocusScope, {
|
60
|
+
autoFocus: true,
|
61
|
+
contain: contain
|
62
|
+
}, ___EmotionJSX(Box, _extends({
|
63
|
+
variant: "overlayPanel.overlayPanel",
|
64
|
+
ref: overlayPanelRef
|
34
65
|
}, others, {
|
35
|
-
className: classNames
|
66
|
+
className: classNames,
|
67
|
+
onKeyUp: handleClose
|
36
68
|
}), ___EmotionJSX(Box, {
|
37
69
|
variant: "overlayPanel.overlayPanelBody",
|
38
70
|
className: classNames
|
39
|
-
}, children));
|
71
|
+
}, children)));
|
40
72
|
});
|
41
73
|
OverlayPanel.propTypes = {
|
42
74
|
/** Sets the open state of the menu. */
|
@@ -48,7 +80,19 @@ OverlayPanel.propTypes = {
|
|
48
80
|
/** JSX styling that is passed into the component. */
|
49
81
|
sx: PropTypes.shape({
|
50
82
|
width: PropTypes.string
|
51
|
-
})
|
83
|
+
}),
|
84
|
+
|
85
|
+
/** State object that is passed in from the useOverlayPanelState hook */
|
86
|
+
state: PropTypes.shape({
|
87
|
+
close: PropTypes.func
|
88
|
+
}),
|
89
|
+
|
90
|
+
/** Callback function that runs when the esc key is used to close the OverlayPanel. */
|
91
|
+
onClose: PropTypes.func,
|
92
|
+
|
93
|
+
/** Ref that is connected to the button that triggers the overlay state.
|
94
|
+
Focus will return to this ref when the keyboard is used to close the OverlayPanel. */
|
95
|
+
triggerRef: PropTypes.shape({})
|
52
96
|
};
|
53
97
|
OverlayPanel.defaultProps = {
|
54
98
|
size: 'medium'
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import _slicedToArray from "@babel/runtime-corejs3/helpers/esm/slicedToArray";
|
2
2
|
import _extends from "@babel/runtime-corejs3/helpers/esm/extends";
|
3
|
-
import React, { useState } from 'react';
|
3
|
+
import React, { useState, useRef } from 'react';
|
4
4
|
import { Item } from '@react-stately/collections';
|
5
5
|
import { useOverlayPanelState } from '../../hooks';
|
6
6
|
import OverlayPanel from './OverlayPanel';
|
7
|
-
import { OverlayProvider, Box, Text, List, ListItem, Separator, Messages, Button
|
7
|
+
import { OverlayProvider, Box, Text, List, ListItem, Separator, Messages, Button } from '../../index';
|
8
8
|
import { panelSizes } from '../../utils/devUtils/constants/panelSizes';
|
9
9
|
import { jsx as ___EmotionJSX } from "@emotion/react";
|
10
10
|
export default {
|
@@ -37,28 +37,43 @@ export default {
|
|
37
37
|
export var Default = function Default(_ref) {
|
38
38
|
var args = _extends({}, _ref);
|
39
39
|
|
40
|
-
var
|
40
|
+
var _useOverlayPanelState = useOverlayPanelState(),
|
41
|
+
state = _useOverlayPanelState.state,
|
42
|
+
onClose = _useOverlayPanelState.onClose;
|
43
|
+
|
44
|
+
var triggerRef = useRef();
|
41
45
|
return (// Application must be wrapped in an OverlayProvider so that it can be hidden from screen
|
42
|
-
// readers when an overlay
|
46
|
+
// readers when an overlay is open.
|
43
47
|
___EmotionJSX(OverlayProvider, null, ___EmotionJSX(Text, null, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."), ___EmotionJSX("br", null), ___EmotionJSX(Button, {
|
48
|
+
ref: triggerRef,
|
44
49
|
onPress: state.open
|
45
|
-
}, "Open Panel"), ___EmotionJSX(OverlayPanel, _extends({
|
46
|
-
isOpen: state.isOpen
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
}, ___EmotionJSX(Text,
|
50
|
+
}, "Open Panel"), state.isOpen && ___EmotionJSX(OverlayPanel, _extends({
|
51
|
+
isOpen: state.isOpen,
|
52
|
+
state: state
|
53
|
+
}, args, {
|
54
|
+
triggerRef: triggerRef
|
55
|
+
}), ___EmotionJSX(Box, null, ___EmotionJSX(Button, {
|
56
|
+
onPress: function onPress() {
|
57
|
+
onClose(state, triggerRef);
|
58
|
+
}
|
59
|
+
}, "Close Panel"), ___EmotionJSX(Text, {
|
60
|
+
pt: "md"
|
61
|
+
}, "Children render here."))))
|
55
62
|
);
|
56
63
|
};
|
57
64
|
export var InnerPanel = function InnerPanel(_ref2) {
|
58
65
|
var args = _extends({}, _ref2);
|
59
66
|
|
60
|
-
var
|
61
|
-
|
67
|
+
var _useOverlayPanelState2 = useOverlayPanelState(),
|
68
|
+
state = _useOverlayPanelState2.state,
|
69
|
+
onClose = _useOverlayPanelState2.onClose;
|
70
|
+
|
71
|
+
var _useOverlayPanelState3 = useOverlayPanelState(),
|
72
|
+
innerState = _useOverlayPanelState3.state,
|
73
|
+
onCloseInner = _useOverlayPanelState3.onClose;
|
74
|
+
|
75
|
+
var outerTriggerRef = useRef();
|
76
|
+
var innerTriggerRef = useRef();
|
62
77
|
|
63
78
|
var _useState = useState(false),
|
64
79
|
_useState2 = _slicedToArray(_useState, 2),
|
@@ -74,15 +89,22 @@ export var InnerPanel = function InnerPanel(_ref2) {
|
|
74
89
|
innerState.close();
|
75
90
|
}
|
76
91
|
|
77
|
-
state
|
92
|
+
onClose(state, outerTriggerRef);
|
93
|
+
};
|
94
|
+
|
95
|
+
var closeInnerPanel = function closeInnerPanel() {
|
96
|
+
onCloseInner(innerState, innerTriggerRef);
|
78
97
|
};
|
79
98
|
|
80
99
|
var inner = ___EmotionJSX(React.Fragment, null, innerState.isOpen && ___EmotionJSX(OverlayPanel, _extends({
|
81
100
|
variant: "overlayPanel.overlayPanelInner" // applies higher z-index
|
82
101
|
,
|
83
102
|
isOpen: innerState.isOpen
|
84
|
-
}, args
|
85
|
-
|
103
|
+
}, args, {
|
104
|
+
state: innerState,
|
105
|
+
triggerRef: innerTriggerRef
|
106
|
+
}), ___EmotionJSX(Box, null, ___EmotionJSX(Button, {
|
107
|
+
onPress: closeInnerPanel
|
86
108
|
}, "Close Inner Panel"), ___EmotionJSX(Text, {
|
87
109
|
pt: "md"
|
88
110
|
}, "Children render here."))));
|
@@ -93,7 +115,10 @@ export var InnerPanel = function InnerPanel(_ref2) {
|
|
93
115
|
sx: {
|
94
116
|
p: '0px'
|
95
117
|
}
|
96
|
-
}, args
|
118
|
+
}, args, {
|
119
|
+
state: state,
|
120
|
+
triggerRef: outerTriggerRef
|
121
|
+
}), ___EmotionJSX(Box, {
|
97
122
|
sx: {
|
98
123
|
p: '12px'
|
99
124
|
}
|
@@ -116,39 +141,17 @@ export var InnerPanel = function InnerPanel(_ref2) {
|
|
116
141
|
mr: "auto"
|
117
142
|
}, "Form 2")), ___EmotionJSX(Separator, {
|
118
143
|
margin: "0"
|
119
|
-
}), ___EmotionJSX(ListItem, {
|
120
|
-
title: "Form 3"
|
121
|
-
}, ___EmotionJSX(Text, {
|
122
|
-
variant: "itemTitle",
|
123
|
-
alignSelf: "center",
|
124
|
-
mr: "auto"
|
125
|
-
}, "Form 3")), ___EmotionJSX(Separator, {
|
126
|
-
margin: "0"
|
127
|
-
}), ___EmotionJSX(ListItem, {
|
128
|
-
title: "Form 4"
|
129
|
-
}, ___EmotionJSX(Text, {
|
130
|
-
variant: "itemTitle",
|
131
|
-
alignSelf: "center",
|
132
|
-
mr: "auto"
|
133
|
-
}, "Form 4")), ___EmotionJSX(Separator, {
|
134
|
-
margin: "0"
|
135
|
-
}), ___EmotionJSX(ListItem, {
|
136
|
-
title: "Form 5"
|
137
|
-
}, ___EmotionJSX(Text, {
|
138
|
-
variant: "itemTitle",
|
139
|
-
alignSelf: "center",
|
140
|
-
mr: "auto"
|
141
|
-
}, "Form 5")), ___EmotionJSX(Separator, {
|
142
|
-
margin: "0"
|
143
144
|
})), ___EmotionJSX("br", null), ___EmotionJSX(Button, {
|
144
145
|
onPress: toggleMessagesOpen
|
145
146
|
}, "Toggle Messages"), ___EmotionJSX("br", null), ___EmotionJSX(Button, {
|
147
|
+
ref: innerTriggerRef,
|
146
148
|
onPress: innerState.open
|
147
149
|
}, "Open Inner Panel"), inner)));
|
148
150
|
|
149
151
|
return (// Application must be wrapped in an OverlayProvider so that it can be hidden from screen
|
150
152
|
// readers when an overlay opens.
|
151
153
|
___EmotionJSX(React.Fragment, null, ___EmotionJSX(OverlayProvider, null, ___EmotionJSX(Button, {
|
154
|
+
ref: outerTriggerRef,
|
152
155
|
onPress: state.open
|
153
156
|
}, "Open Panel"), outer), messagesOpen && ___EmotionJSX(Messages, {
|
154
157
|
sx: {
|
@@ -161,20 +164,27 @@ export var InnerPanel = function InnerPanel(_ref2) {
|
|
161
164
|
);
|
162
165
|
};
|
163
166
|
export var CustomWidth = function CustomWidth() {
|
164
|
-
var
|
167
|
+
var _useOverlayPanelState4 = useOverlayPanelState(),
|
168
|
+
state = _useOverlayPanelState4.state,
|
169
|
+
onClose = _useOverlayPanelState4.onClose;
|
170
|
+
|
171
|
+
var triggerRef = useRef();
|
165
172
|
return (// Application must be wrapped in an OverlayProvider so that it can be hidden from screen
|
166
173
|
// readers when an overlay opens.
|
167
|
-
//
|
168
|
-
// For a custom width, provide the width via the 'sx' prop
|
169
174
|
___EmotionJSX(OverlayProvider, null, ___EmotionJSX(Text, null, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."), ___EmotionJSX("br", null), ___EmotionJSX(Button, {
|
175
|
+
ref: triggerRef,
|
170
176
|
onPress: state.open
|
171
|
-
}, "Open Panel"), ___EmotionJSX(OverlayPanel, {
|
177
|
+
}, "Open Panel"), state.isOpen && ___EmotionJSX(OverlayPanel, {
|
172
178
|
isOpen: state.isOpen,
|
179
|
+
state: state,
|
180
|
+
triggerRef: triggerRef,
|
173
181
|
sx: {
|
174
182
|
width: '720px'
|
175
183
|
}
|
176
184
|
}, ___EmotionJSX(Box, null, ___EmotionJSX(Button, {
|
177
|
-
onPress:
|
185
|
+
onPress: function onPress() {
|
186
|
+
onClose(state, triggerRef);
|
187
|
+
}
|
178
188
|
}, "Close Panel"), ___EmotionJSX(Text, {
|
179
189
|
pt: "md"
|
180
190
|
}, "Children render here."))))
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import _extends from "@babel/runtime-corejs3/helpers/esm/extends";
|
2
2
|
import React from 'react';
|
3
3
|
import axeTest from '../../utils/testUtils/testAxe';
|
4
|
-
import { render, screen } from '../../utils/testUtils/testWrapper';
|
4
|
+
import { fireEvent, render, screen } from '../../utils/testUtils/testWrapper';
|
5
5
|
import OverlayPanel from './OverlayPanel';
|
6
6
|
import { jsx as ___EmotionJSX } from "@emotion/react";
|
7
7
|
var testId = 'test-overlayPanel';
|
@@ -38,4 +38,76 @@ test('custom overlayPanel gets custom width', function () {
|
|
38
38
|
var overlayPanel = screen.getByTestId(testId);
|
39
39
|
expect(overlayPanel).toBeInTheDocument();
|
40
40
|
expect(overlayPanel).toHaveStyleRule('width', '240px');
|
41
|
+
});
|
42
|
+
test('onClose callback fires when provided', function () {
|
43
|
+
var onClose = jest.fn();
|
44
|
+
getComponent({
|
45
|
+
onClose: onClose,
|
46
|
+
children: ___EmotionJSX("div", null, "Test")
|
47
|
+
});
|
48
|
+
var overlayPanel = screen.getByTestId(testId);
|
49
|
+
fireEvent.keyDown(overlayPanel, {
|
50
|
+
key: 'Escape',
|
51
|
+
code: 'Escape',
|
52
|
+
keyCode: 27,
|
53
|
+
charCode: 27
|
54
|
+
});
|
55
|
+
fireEvent.keyUp(overlayPanel, {
|
56
|
+
key: 'Escape',
|
57
|
+
code: 'Escape',
|
58
|
+
keyCode: 27,
|
59
|
+
charCode: 27
|
60
|
+
});
|
61
|
+
expect(onClose).toHaveBeenCalled();
|
62
|
+
});
|
63
|
+
test('neither callback fires when not provided', function () {
|
64
|
+
var onClose = jest.fn();
|
65
|
+
getComponent({
|
66
|
+
children: ___EmotionJSX("div", null, "Test")
|
67
|
+
});
|
68
|
+
var overlayPanel = screen.getByTestId(testId);
|
69
|
+
fireEvent.keyDown(overlayPanel, {
|
70
|
+
key: 'Escape',
|
71
|
+
code: 'Escape',
|
72
|
+
keyCode: 27,
|
73
|
+
charCode: 27
|
74
|
+
});
|
75
|
+
fireEvent.keyUp(overlayPanel, {
|
76
|
+
key: 'Escape',
|
77
|
+
code: 'Escape',
|
78
|
+
keyCode: 27,
|
79
|
+
charCode: 27
|
80
|
+
});
|
81
|
+
expect(onClose).not.toHaveBeenCalled();
|
82
|
+
});
|
83
|
+
test('triggerRef.current.focus() fires when provided', function () {
|
84
|
+
var onClose = jest.fn();
|
85
|
+
var focusFunction = jest.fn();
|
86
|
+
var state = {
|
87
|
+
close: onClose
|
88
|
+
};
|
89
|
+
var triggerRef = {
|
90
|
+
current: {
|
91
|
+
focus: focusFunction
|
92
|
+
}
|
93
|
+
};
|
94
|
+
getComponent({
|
95
|
+
state: state,
|
96
|
+
children: ___EmotionJSX("div", null, "Test"),
|
97
|
+
triggerRef: triggerRef
|
98
|
+
});
|
99
|
+
var overlayPanel = screen.getByTestId(testId);
|
100
|
+
fireEvent.keyDown(overlayPanel, {
|
101
|
+
key: 'Escape',
|
102
|
+
code: 'Escape',
|
103
|
+
keyCode: 27,
|
104
|
+
charCode: 27
|
105
|
+
});
|
106
|
+
fireEvent.keyUp(overlayPanel, {
|
107
|
+
key: 'Escape',
|
108
|
+
code: 'Escape',
|
109
|
+
keyCode: 27,
|
110
|
+
charCode: 27
|
111
|
+
});
|
112
|
+
expect(focusFunction).toHaveBeenCalled();
|
41
113
|
});
|
@@ -14,11 +14,30 @@ var useOverlayPanelState = function useOverlayPanelState() {
|
|
14
14
|
var isDefaultOpen = props.isDefaultOpen,
|
15
15
|
isOpen = props.isOpen,
|
16
16
|
onOpenChange = props.onOpenChange;
|
17
|
-
|
17
|
+
var state = useOverlayTriggerState({
|
18
18
|
defaultOpen: isDefaultOpen,
|
19
19
|
isOpen: isOpen,
|
20
20
|
onOpenChange: onOpenChange
|
21
21
|
});
|
22
|
+
|
23
|
+
var onClose = function onClose(stateProp, triggerRef, onCloseProp) {
|
24
|
+
if (stateProp) {
|
25
|
+
stateProp.close();
|
26
|
+
}
|
27
|
+
|
28
|
+
if (triggerRef === null || triggerRef === void 0 ? void 0 : triggerRef.current) {
|
29
|
+
triggerRef.current.focus();
|
30
|
+
}
|
31
|
+
|
32
|
+
if (onCloseProp) {
|
33
|
+
onCloseProp();
|
34
|
+
}
|
35
|
+
};
|
36
|
+
|
37
|
+
return {
|
38
|
+
state: state,
|
39
|
+
onClose: onClose
|
40
|
+
};
|
22
41
|
};
|
23
42
|
|
24
43
|
export default useOverlayPanelState;
|
@@ -7,8 +7,12 @@ test('default useOverlayPanelState', function () {
|
|
7
7
|
result = _renderHook.result;
|
8
8
|
|
9
9
|
expect(result.current).toEqual(expect.objectContaining({
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
state: {
|
11
|
+
open: expect.any(Function),
|
12
|
+
close: expect.any(Function),
|
13
|
+
toggle: expect.any(Function),
|
14
|
+
isOpen: expect.any(Boolean)
|
15
|
+
},
|
16
|
+
onClose: expect.any(Function)
|
13
17
|
}));
|
14
18
|
});
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@pingux/astro",
|
3
|
-
"version": "1.1.0-alpha.
|
3
|
+
"version": "1.1.0-alpha.16",
|
4
4
|
"description": "PingUX themeable React component library",
|
5
5
|
"author": "uxdev@pingidentity.com",
|
6
6
|
"license": "Apache-2.0",
|
@@ -78,7 +78,7 @@
|
|
78
78
|
"@react-aria/color": "^3.0.0-beta.2",
|
79
79
|
"@react-aria/combobox": "^3.0.0",
|
80
80
|
"@react-aria/dialog": "^3.1.2",
|
81
|
-
"@react-aria/focus": "^3.
|
81
|
+
"@react-aria/focus": "^3.5.0",
|
82
82
|
"@react-aria/grid": "^3.0.0-beta.1",
|
83
83
|
"@react-aria/i18n": "^3.3.0",
|
84
84
|
"@react-aria/interactions": "^3.5.0",
|