reshaped 3.3.12 → 3.4.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.
- package/CHANGELOG.md +13 -0
- package/dist/bundle.css +1 -1
- package/dist/bundle.d.ts +4 -1
- package/dist/bundle.js +11 -11
- package/dist/components/Autocomplete/Autocomplete.js +34 -24
- package/dist/components/Autocomplete/Autocomplete.types.d.ts +1 -1
- package/dist/components/Autocomplete/tests/Autocomplete.stories.js +8 -1
- package/dist/components/Carousel/Carousel.js +53 -4
- package/dist/components/Carousel/Carousel.types.d.ts +5 -0
- package/dist/components/Carousel/tests/Carousel.stories.d.ts +20 -4
- package/dist/components/Carousel/tests/Carousel.stories.js +195 -102
- package/dist/components/Container/Container.module.css +1 -1
- package/dist/components/ContextMenu/ContextMenu.js +2 -2
- package/dist/components/ContextMenu/tests/ContextMenu.test.stories.js +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.js +6 -1
- package/dist/components/DropdownMenu/tests/DropdownMenu.test.stories.js +2 -2
- package/dist/components/Popover/Popover.js +1 -1
- package/dist/components/Popover/tests/Popover.test.stories.js +4 -4
- package/dist/components/ProgressIndicator/ProgressIndicator.d.ts +3 -0
- package/dist/components/ProgressIndicator/ProgressIndicator.js +101 -0
- package/dist/components/ProgressIndicator/ProgressIndicator.module.css +1 -0
- package/dist/components/ProgressIndicator/ProgressIndicator.types.d.ts +9 -0
- package/dist/components/ProgressIndicator/ProgressIndicator.types.js +1 -0
- package/dist/components/ProgressIndicator/index.d.ts +2 -0
- package/dist/components/ProgressIndicator/index.js +1 -0
- package/dist/components/ProgressIndicator/tests/ProgressIndicator.stories.d.ts +19 -0
- package/dist/components/ProgressIndicator/tests/ProgressIndicator.stories.js +85 -0
- package/dist/components/Reshaped/Reshaped.js +4 -5
- package/dist/components/Table/index.d.ts +1 -1
- package/dist/components/Table/tests/Table.stories.d.ts +5 -5
- package/dist/components/Table/tests/Table.test.stories.d.ts +5 -5
- package/dist/components/TextField/TextField.module.css +1 -1
- package/dist/components/Toast/tests/Toast.stories.js +22 -7
- package/dist/components/Tooltip/tests/Tooltip.test.stories.js +1 -1
- package/dist/components/_private/Flyout/Flyout.module.css +1 -1
- package/dist/components/_private/Flyout/Flyout.types.d.ts +14 -3
- package/dist/components/_private/Flyout/FlyoutContent.js +37 -7
- package/dist/components/_private/Flyout/FlyoutControlled.js +12 -11
- package/dist/components/_private/Flyout/FlyoutUncontrolled.js +3 -5
- package/dist/components/_private/Flyout/index.d.ts +1 -1
- package/dist/components/_private/Flyout/tests/Flyout.stories.d.ts +79 -13
- package/dist/components/_private/Flyout/tests/Flyout.stories.js +526 -280
- package/dist/components/_private/Flyout/useFlyout.js +9 -3
- package/dist/components/_private/Flyout/utilities/isFullyVisible.d.ts +3 -1
- package/dist/components/_private/Flyout/utilities/isFullyVisible.js +2 -2
- package/dist/hooks/_private/usePrevious.d.ts +2 -0
- package/dist/hooks/_private/usePrevious.js +17 -0
- package/dist/hooks/_private/useSingletonEnvironment.d.ts +1 -1
- package/dist/hooks/_private/useSingletonEnvironment.js +1 -1
- package/dist/hooks/_private/useSingletonKeyboardMode.d.ts +13 -2
- package/dist/hooks/_private/useSingletonKeyboardMode.js +48 -15
- package/dist/hooks/tests/useKeyboardMode.stories.d.ts +6 -0
- package/dist/hooks/tests/useKeyboardMode.stories.js +37 -0
- package/dist/hooks/useKeyboardMode.d.ts +7 -0
- package/dist/hooks/useKeyboardMode.js +13 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2 -0
- package/dist/utilities/a11y/index.d.ts +1 -1
- package/dist/utilities/a11y/index.js +1 -1
- package/dist/utilities/a11y/keyboardMode.d.ts +2 -2
- package/dist/utilities/a11y/keyboardMode.js +2 -2
- package/dist/utilities/dom/find.d.ts +4 -1
- package/dist/utilities/dom/find.js +4 -4
- package/dist/utilities/scroll/lockStandard.js +1 -1
- package/package.json +34 -35
- package/dist/components/Carousel/tests/Carousel.test.stories.d.ts +0 -17
- package/dist/components/Carousel/tests/Carousel.test.stories.js +0 -52
- package/dist/components/_private/Flyout/tests/Flyout.test.stories.d.ts +0 -28
- package/dist/components/_private/Flyout/tests/Flyout.test.stories.js +0 -205
@@ -1,5 +1,6 @@
|
|
1
1
|
import React from "react";
|
2
2
|
import { createRoot } from "react-dom/client";
|
3
|
+
import { userEvent, waitFor, within, expect, fn } from "@storybook/test";
|
3
4
|
import { Example } from "../../../../utilities/storybook/index.js";
|
4
5
|
import Reshaped from "../../../Reshaped/index.js";
|
5
6
|
import View from "../../../View/index.js";
|
@@ -7,177 +8,442 @@ import Theme from "../../../Theme/index.js";
|
|
7
8
|
import Button from "../../../Button/index.js";
|
8
9
|
import Flyout from "../index.js";
|
9
10
|
import TextField from "../../../TextField/index.js";
|
11
|
+
import MenuItem from "../../../MenuItem/index.js";
|
12
|
+
import { sleep } from "../../../../utilities/helpers.js";
|
10
13
|
export default { title: "Internal/Flyout" };
|
14
|
+
/**
|
15
|
+
* Unit
|
16
|
+
* - groupTimeouts
|
17
|
+
* - id
|
18
|
+
* - contentClassName
|
19
|
+
* - contentAttributes
|
20
|
+
* - content attributes
|
21
|
+
* - content className
|
22
|
+
*/
|
23
|
+
const Content = (props) => (<div style={{
|
24
|
+
background: "var(--rs-color-background-elevation-overlay)",
|
25
|
+
padding: "var(--rs-unit-x4)",
|
26
|
+
height: props.height ?? 150,
|
27
|
+
minWidth: props.width === false ? undefined : props.width || 160,
|
28
|
+
borderRadius: "var(--rs-radius-medium)",
|
29
|
+
border: "1px solid var(--rs-color-border-neutral-faded)",
|
30
|
+
boxSizing: "border-box",
|
31
|
+
}}>
|
32
|
+
{props.children || "Content"}
|
33
|
+
</div>);
|
11
34
|
const Demo = (props) => {
|
12
|
-
const { position = "bottom-start", children, ...rest } = props;
|
13
|
-
return (<Flyout
|
35
|
+
const { position = "bottom-start", children, contentHeight, contentWidth, ...rest } = props;
|
36
|
+
return (<Flyout position={position} {...rest}>
|
14
37
|
<Flyout.Trigger>
|
15
38
|
{(attributes) => <Button attributes={attributes}>{position}</Button>}
|
16
39
|
</Flyout.Trigger>
|
17
40
|
<Flyout.Content>
|
18
|
-
<
|
19
|
-
|
20
|
-
|
21
|
-
height: 150,
|
22
|
-
minWidth: 160,
|
23
|
-
borderRadius: "var(--rs-radius-medium)",
|
24
|
-
border: "1px solid var(--rs-color-border-neutral-faded)",
|
25
|
-
boxSizing: "border-box",
|
26
|
-
}}>
|
27
|
-
{children || "Content"}
|
28
|
-
</div>
|
41
|
+
<Content height={contentHeight} width={contentWidth}>
|
42
|
+
{children}
|
43
|
+
</Content>
|
29
44
|
</Flyout.Content>
|
30
45
|
</Flyout>);
|
31
46
|
};
|
32
|
-
export const position =
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
47
|
+
export const position = {
|
48
|
+
name: "position",
|
49
|
+
render: () => {
|
50
|
+
return (<View gap={4} padding={50} align="center" justify="center">
|
51
|
+
<View gap={4} direction="row">
|
52
|
+
<Demo position="top-start"/>
|
53
|
+
<Demo position="top"/>
|
54
|
+
<Demo position="top-end"/>
|
55
|
+
</View>
|
37
56
|
|
38
|
-
|
39
|
-
|
40
|
-
|
57
|
+
<View gap={4} direction="row">
|
58
|
+
<Demo position="end-top"/>
|
59
|
+
<Demo position="end"/>
|
60
|
+
<Demo position="end-bottom"/>
|
61
|
+
</View>
|
41
62
|
|
42
|
-
|
43
|
-
|
44
|
-
|
63
|
+
<View gap={4} direction="row">
|
64
|
+
<Demo position="start-top"/>
|
65
|
+
<Demo position="start"/>
|
66
|
+
<Demo position="start-bottom"/>
|
67
|
+
</View>
|
45
68
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
</div>);
|
54
|
-
export const originCoordinates = () => {
|
55
|
-
const [coordinates, setCoordinates] = React.useState(null);
|
56
|
-
return (<Example>
|
57
|
-
<Example.Item>
|
58
|
-
<View height={25} width={25} attributes={{
|
59
|
-
onContextMenu: (e) => {
|
60
|
-
e.preventDefault();
|
61
|
-
setCoordinates({ x: e.clientX, y: e.clientY });
|
62
|
-
},
|
63
|
-
}} backgroundColor="neutral-faded" borderRadius="medium"/>
|
64
|
-
<br /> <br />
|
65
|
-
<Demo position="top" originCoordinates={coordinates} active={!!coordinates} onClose={() => setCoordinates(null)}/>
|
66
|
-
</Example.Item>
|
67
|
-
</Example>);
|
69
|
+
<View gap={4} direction="row">
|
70
|
+
<Demo position="bottom-start"/>
|
71
|
+
<Demo position="bottom"/>
|
72
|
+
<Demo position="bottom-end" defaultActive/>
|
73
|
+
</View>
|
74
|
+
</View>);
|
75
|
+
},
|
68
76
|
};
|
69
|
-
export const
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
<
|
80
|
-
<
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
77
|
+
export const defaultActive = {
|
78
|
+
name: "defaultActive, uncontrolled",
|
79
|
+
args: {
|
80
|
+
handleOpen: fn(),
|
81
|
+
handleClose: fn(),
|
82
|
+
},
|
83
|
+
render: (args) => (<Flyout onOpen={args.handleOpen} onClose={args.handleClose} defaultActive>
|
84
|
+
<Flyout.Trigger>
|
85
|
+
{(attributes) => <Button attributes={attributes}>Trigger</Button>}
|
86
|
+
</Flyout.Trigger>
|
87
|
+
<Flyout.Content>
|
88
|
+
<Content />
|
89
|
+
</Flyout.Content>
|
90
|
+
</Flyout>),
|
91
|
+
play: async ({ canvasElement, args }) => {
|
92
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
93
|
+
const trigger = canvas.getAllByRole("button")[0];
|
94
|
+
let item = canvas.getByText("Content");
|
95
|
+
await sleep(500);
|
96
|
+
await userEvent.click(document.body);
|
97
|
+
await waitFor(() => {
|
98
|
+
expect(args.handleClose).toHaveBeenCalledTimes(1);
|
99
|
+
expect(args.handleClose).toHaveBeenCalledWith({ reason: "outside-click" });
|
100
|
+
expect(item).not.toBeInTheDocument();
|
101
|
+
});
|
102
|
+
await userEvent.click(trigger);
|
103
|
+
await waitFor(() => {
|
104
|
+
expect(args.handleOpen).toHaveBeenCalledTimes(1);
|
105
|
+
expect(args.handleOpen).toHaveBeenCalledWith();
|
106
|
+
});
|
107
|
+
item = canvas.getByText("Content");
|
108
|
+
expect(item).toBeInTheDocument();
|
109
|
+
},
|
110
|
+
};
|
111
|
+
export const active = {
|
112
|
+
name: "active, controlled",
|
113
|
+
args: {
|
114
|
+
handleOpen: fn(),
|
115
|
+
handleClose: fn(),
|
116
|
+
},
|
117
|
+
render: (args) => (<Flyout onOpen={args.handleOpen} onClose={args.handleClose} active>
|
118
|
+
<Flyout.Trigger>
|
119
|
+
{(attributes) => <Button attributes={attributes}>Trigger</Button>}
|
120
|
+
</Flyout.Trigger>
|
121
|
+
<Flyout.Content>
|
122
|
+
<Content />
|
123
|
+
</Flyout.Content>
|
124
|
+
</Flyout>),
|
125
|
+
play: async ({ canvasElement, args }) => {
|
126
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
127
|
+
const item = canvas.getByText("Content");
|
128
|
+
await userEvent.click(document.body);
|
129
|
+
await waitFor(() => {
|
130
|
+
expect(args.handleClose).toHaveBeenCalledTimes(1);
|
131
|
+
expect(args.handleClose).toHaveBeenCalledWith({ reason: "outside-click" });
|
132
|
+
});
|
133
|
+
expect(item).toBeInTheDocument();
|
134
|
+
},
|
135
|
+
};
|
136
|
+
export const activeFalse = {
|
137
|
+
name: "active: false, controlled",
|
138
|
+
args: {
|
139
|
+
handleOpen: fn(),
|
140
|
+
handleClose: fn(),
|
141
|
+
},
|
142
|
+
render: (args) => (<Flyout onOpen={args.handleOpen} onClose={args.handleClose} active={false}>
|
143
|
+
<Flyout.Trigger>
|
144
|
+
{(attributes) => <Button attributes={attributes}>Trigger</Button>}
|
145
|
+
</Flyout.Trigger>
|
146
|
+
<Flyout.Content>
|
147
|
+
<Content />
|
148
|
+
</Flyout.Content>
|
149
|
+
</Flyout>),
|
150
|
+
play: async ({ canvasElement, args }) => {
|
151
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
152
|
+
const trigger = canvas.getAllByRole("button")[0];
|
153
|
+
await userEvent.click(trigger);
|
154
|
+
await waitFor(() => {
|
155
|
+
expect(args.handleOpen).toHaveBeenCalledTimes(1);
|
156
|
+
expect(args.handleOpen).toHaveBeenCalledWith();
|
157
|
+
});
|
158
|
+
const item = canvas.queryByText("Content");
|
159
|
+
expect(item).not.toBeInTheDocument();
|
160
|
+
},
|
161
|
+
};
|
162
|
+
export const modes = {
|
163
|
+
name: "triggerType, trapFocusMode",
|
164
|
+
render: () => {
|
165
|
+
return (<Example>
|
166
|
+
<Example.Item title={[
|
167
|
+
"triggerType: click, trapFocusMode: dialog",
|
168
|
+
"tab navigation, completely traps the focus inside",
|
169
|
+
]}>
|
170
|
+
<Demo position="bottom-start" trapFocusMode="dialog">
|
171
|
+
<View direction="row" gap={2}>
|
172
|
+
<Button onClick={() => { }}>Action 1</Button>
|
173
|
+
<Button onClick={() => { }}>Action 2</Button>
|
174
|
+
<Button onClick={() => { }}>Action 3</Button>
|
175
|
+
</View>
|
176
|
+
</Demo>
|
177
|
+
</Example.Item>
|
85
178
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
179
|
+
<Example.Item title={[
|
180
|
+
"triggerType: click, trapFocusMode: action-menu",
|
181
|
+
"arrow navigation, tab closes the content",
|
182
|
+
]}>
|
183
|
+
<Demo position="bottom-start" trapFocusMode="action-menu">
|
184
|
+
<View direction="row" gap={2}>
|
185
|
+
<Button onClick={() => { }}>Action 1</Button>
|
186
|
+
<Button onClick={() => { }}>Action 2</Button>
|
187
|
+
<Button onClick={() => { }}>Action 3</Button>
|
188
|
+
</View>
|
189
|
+
</Demo>
|
190
|
+
</Example.Item>
|
93
191
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
192
|
+
<Example.Item title={[
|
193
|
+
"triggerType: click, trapFocusMode: content-menu",
|
194
|
+
"tab navigation, simulates natural focus order for navigation menus",
|
195
|
+
]}>
|
196
|
+
<Demo position="bottom-start" trapFocusMode="content-menu">
|
197
|
+
<View direction="row" gap={2}>
|
198
|
+
<Button onClick={() => { }}>Action 1</Button>
|
199
|
+
<Button onClick={() => { }}>Action 2</Button>
|
200
|
+
<Button onClick={() => { }}>Action 3</Button>
|
201
|
+
</View>
|
202
|
+
</Demo>
|
203
|
+
</Example.Item>
|
101
204
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
205
|
+
<Example.Item title="triggerType: hover, trapFocusMode: dialog">
|
206
|
+
<Demo position="bottom-start" trapFocusMode="dialog" triggerType="hover">
|
207
|
+
<View direction="row" gap={2}>
|
208
|
+
<Button onClick={() => { }}>Action 1</Button>
|
209
|
+
<Button onClick={() => { }}>Action 2</Button>
|
210
|
+
<Button onClick={() => { }}>Action 3</Button>
|
211
|
+
</View>
|
212
|
+
</Demo>
|
213
|
+
</Example.Item>
|
109
214
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
215
|
+
<Example.Item title="triggerType: hover, trapFocusMode: action-menu">
|
216
|
+
<Demo position="bottom-start" trapFocusMode="action-menu" triggerType="hover">
|
217
|
+
<View direction="row" gap={2}>
|
218
|
+
<Button onClick={() => { }}>Action 1</Button>
|
219
|
+
<Button onClick={() => { }}>Action 2</Button>
|
220
|
+
<Button onClick={() => { }}>Action 3</Button>
|
221
|
+
</View>
|
222
|
+
</Demo>
|
223
|
+
</Example.Item>
|
115
224
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
<Example.Item title="width: 300px">
|
126
|
-
<Demo width="300px" position="bottom"/>
|
127
|
-
</Example.Item>
|
128
|
-
<Example.Item title="width: trigger">
|
129
|
-
<Flyout triggerType="click" width="trigger" position="bottom">
|
130
|
-
<Flyout.Trigger>
|
131
|
-
{(attributes) => <Button attributes={attributes}>Trigger with long text</Button>}
|
132
|
-
</Flyout.Trigger>
|
133
|
-
<Flyout.Content>
|
134
|
-
<div style={{
|
135
|
-
background: "var(--rs-color-background-elevation-overlay)",
|
136
|
-
padding: "var(--rs-unit-x4)",
|
137
|
-
borderRadius: "var(--rs-radius-medium)",
|
138
|
-
border: "1px solid var(--rs-color-border-neutral-faded)",
|
139
|
-
boxSizing: "border-box",
|
140
|
-
}}></div>
|
141
|
-
</Flyout.Content>
|
142
|
-
</Flyout>
|
143
|
-
</Example.Item>
|
144
|
-
</Example>);
|
145
|
-
export const offset = () => (<Example>
|
146
|
-
<Example.Item title="contentGap: x10">
|
147
|
-
<Demo contentGap={10}/>
|
148
|
-
</Example.Item>
|
149
|
-
<Example.Item title="contentShift: x10">
|
150
|
-
<Demo contentShift={10}/>
|
151
|
-
</Example.Item>
|
152
|
-
</Example>);
|
153
|
-
export const disableFlags = () => (<Example>
|
154
|
-
<Example.Item title="disableContentHover">
|
155
|
-
<Demo triggerType="hover" disableContentHover>
|
156
|
-
Content
|
157
|
-
</Demo>
|
158
|
-
</Example.Item>
|
225
|
+
<Example.Item title="triggerType: hover, trapFocusMode: content-menu">
|
226
|
+
<Demo position="bottom-start" trapFocusMode="content-menu" triggerType="hover">
|
227
|
+
<View direction="row" gap={2}>
|
228
|
+
<Button onClick={() => { }}>Action 1</Button>
|
229
|
+
<Button onClick={() => { }}>Action 2</Button>
|
230
|
+
<Button onClick={() => { }}>Action 3</Button>
|
231
|
+
</View>
|
232
|
+
</Demo>
|
233
|
+
</Example.Item>
|
159
234
|
|
160
|
-
|
161
|
-
|
162
|
-
|
235
|
+
<Example.Item title={[
|
236
|
+
"triggerType: hover, trapFocusMode: content-menu, no focusable elements inside",
|
237
|
+
"keeps the focus on trigger",
|
238
|
+
]}>
|
239
|
+
<Demo position="bottom-start" trapFocusMode="content-menu" triggerType="hover"/>
|
240
|
+
</Example.Item>
|
163
241
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
242
|
+
<Example.Item title={[
|
243
|
+
"triggerType: focus, trapFocusMode: selection-menu",
|
244
|
+
"keeps real focus on trigger and simulates arrow key item selection focus on the content",
|
245
|
+
]}>
|
246
|
+
<Demo position="bottom-start" trapFocusMode="selection-menu" triggerType="focus">
|
247
|
+
<View gap={1}>
|
248
|
+
<MenuItem onClick={() => { }} roundedCorners>
|
249
|
+
Action 1
|
250
|
+
</MenuItem>
|
251
|
+
<MenuItem onClick={() => { }} roundedCorners>
|
252
|
+
Action 2
|
253
|
+
</MenuItem>
|
254
|
+
<MenuItem onClick={() => { }} roundedCorners>
|
255
|
+
Action 3
|
256
|
+
</MenuItem>
|
257
|
+
</View>
|
258
|
+
</Demo>
|
259
|
+
</Example.Item>
|
260
|
+
</Example>);
|
261
|
+
},
|
262
|
+
};
|
263
|
+
export const positionFallbacks = {
|
264
|
+
name: "fallbackPositions",
|
265
|
+
render: () => {
|
266
|
+
return (<Example>
|
267
|
+
<Example.Item title="position: top, no fallbacks passed">
|
268
|
+
<View justify="center" align="center">
|
269
|
+
<Demo position="top"/>
|
176
270
|
</View>
|
177
|
-
</
|
271
|
+
</Example.Item>
|
272
|
+
<Example.Item title="position: top, fallbackPositions: [start]">
|
273
|
+
<View justify="center" align="center">
|
274
|
+
<Demo position="top" fallbackPositions={["start"]} contentHeight={200} defaultActive/>
|
275
|
+
</View>
|
276
|
+
</Example.Item>
|
277
|
+
<Example.Item title="position: top, fallbackPositions: false">
|
278
|
+
<View justify="center" align="center">
|
279
|
+
<Demo position="top" fallbackPositions={false} contentHeight={400}/>
|
280
|
+
</View>
|
281
|
+
</Example.Item>
|
282
|
+
</Example>);
|
283
|
+
},
|
284
|
+
};
|
285
|
+
export const originCoordinates = {
|
286
|
+
name: "originCoordinates",
|
287
|
+
render: () => {
|
288
|
+
return (<View gap={4} direction="row">
|
289
|
+
<Demo position="bottom-start" originCoordinates={{ x: 150, y: 150 }} defaultActive/>
|
290
|
+
</View>);
|
291
|
+
},
|
292
|
+
};
|
293
|
+
export const width = {
|
294
|
+
name: "width",
|
295
|
+
render: () => (<Example>
|
296
|
+
<Example.Item title="width: 300px">
|
297
|
+
<Demo width="300px" position="bottom"/>
|
178
298
|
</Example.Item>
|
179
|
-
|
299
|
+
|
300
|
+
<Example.Item title="width: trigger">
|
301
|
+
<Demo width="trigger" contentWidth={false} defaultActive/>
|
302
|
+
</Example.Item>
|
303
|
+
</Example>),
|
304
|
+
};
|
305
|
+
export const contentGap = {
|
306
|
+
name: "contentGap",
|
307
|
+
render: () => <Demo contentGap={10} defaultActive/>,
|
308
|
+
};
|
309
|
+
export const contentShift = {
|
310
|
+
name: "contentShift",
|
311
|
+
render: () => <Demo contentShift={10} defaultActive/>,
|
180
312
|
};
|
313
|
+
export const disableContentHover = {
|
314
|
+
name: "disableContentHover",
|
315
|
+
render: () => <Demo triggerType="hover" disableContentHover/>,
|
316
|
+
};
|
317
|
+
export const disableCloseOnOutsideClick = {
|
318
|
+
name: "disableCloseOnOutsideClick",
|
319
|
+
render: () => <Demo disableCloseOnOutsideClick/>,
|
320
|
+
play: async ({ canvasElement }) => {
|
321
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
322
|
+
const trigger = canvas.getAllByRole("button")[0];
|
323
|
+
await userEvent.click(trigger);
|
324
|
+
await waitFor(() => {
|
325
|
+
const content = canvas.getByText("Content");
|
326
|
+
expect(content).toBeVisible();
|
327
|
+
});
|
328
|
+
await userEvent.click(document.body);
|
329
|
+
await sleep(500);
|
330
|
+
const content = canvas.getByText("Content");
|
331
|
+
expect(content).toBeVisible();
|
332
|
+
},
|
333
|
+
};
|
334
|
+
export const disableHideAnimation = {
|
335
|
+
name: "disableHideAnimation",
|
336
|
+
render: () => <Demo disableHideAnimation defaultActive/>,
|
337
|
+
};
|
338
|
+
export const disabled = {
|
339
|
+
name: "disabled",
|
340
|
+
args: {
|
341
|
+
handleOpen: fn(),
|
342
|
+
},
|
343
|
+
render: () => (<Flyout disabled>
|
344
|
+
<Flyout.Trigger>
|
345
|
+
{(attributes) => <Button attributes={attributes}>Trigger</Button>}
|
346
|
+
</Flyout.Trigger>
|
347
|
+
<Flyout.Content>
|
348
|
+
<Content />
|
349
|
+
</Flyout.Content>
|
350
|
+
</Flyout>),
|
351
|
+
play: async ({ canvasElement, args }) => {
|
352
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
353
|
+
const button = canvas.getAllByRole("button")[0];
|
354
|
+
await userEvent.click(button);
|
355
|
+
expect(args.handleOpen).toHaveBeenCalledTimes(0);
|
356
|
+
},
|
357
|
+
};
|
358
|
+
export const containerRef = {
|
359
|
+
name: "containerRef",
|
360
|
+
render: () => {
|
361
|
+
const portalRef = React.useRef(null);
|
362
|
+
return (<View backgroundColor="neutral-faded" borderRadius="small" height={80} attributes={{ ref: portalRef, "data-testid": "container" }} justify="end" align="start" padding={4}>
|
363
|
+
<Demo containerRef={portalRef} defaultActive position="bottom-start"/>
|
364
|
+
</View>);
|
365
|
+
},
|
366
|
+
play: async ({ canvasElement }) => {
|
367
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
368
|
+
const containerEl = canvas.getByTestId("container");
|
369
|
+
const contentEl = canvas.getByText("Content");
|
370
|
+
expect(containerEl).toContainElement(contentEl);
|
371
|
+
},
|
372
|
+
};
|
373
|
+
export const initialFocusRef = {
|
374
|
+
name: "initialFocusRef",
|
375
|
+
render: () => {
|
376
|
+
const initialFocusRef = React.useRef(null);
|
377
|
+
return (<Demo initialFocusRef={initialFocusRef}>
|
378
|
+
<View gap={4}>
|
379
|
+
<Button onClick={() => { }}>Action 1</Button>
|
380
|
+
<TextField name="foo" inputAttributes={{ ref: initialFocusRef }}/>
|
381
|
+
</View>
|
382
|
+
</Demo>);
|
383
|
+
},
|
384
|
+
play: async ({ canvasElement }) => {
|
385
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
386
|
+
const trigger = canvas.getAllByRole("button")[0];
|
387
|
+
await userEvent.click(trigger);
|
388
|
+
await waitFor(() => {
|
389
|
+
const input = canvas.getByRole("textbox");
|
390
|
+
expect(input).toBe(document.activeElement);
|
391
|
+
});
|
392
|
+
},
|
393
|
+
};
|
394
|
+
export const instanceRef = {
|
395
|
+
name: "instanceRef",
|
396
|
+
args: {
|
397
|
+
handleOpen: fn(),
|
398
|
+
handleClose: fn(),
|
399
|
+
},
|
400
|
+
render: (args) => {
|
401
|
+
const flyoutRef = React.useRef(null);
|
402
|
+
return (<View direction="row" gap={4}>
|
403
|
+
<Demo instanceRef={flyoutRef} disableCloseOnOutsideClick onOpen={args.handleOpen} onClose={args.handleClose}/>
|
404
|
+
|
405
|
+
<Button onClick={() => flyoutRef.current?.open()}>Open</Button>
|
406
|
+
<Button onClick={() => flyoutRef.current?.close()}>Close</Button>
|
407
|
+
</View>);
|
408
|
+
},
|
409
|
+
play: async ({ canvasElement, args }) => {
|
410
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
411
|
+
const openTrigger = canvas.getAllByRole("button")[1];
|
412
|
+
const closeTrigger = canvas.getAllByRole("button")[2];
|
413
|
+
await userEvent.click(openTrigger);
|
414
|
+
await waitFor(() => {
|
415
|
+
expect(args.handleOpen).toHaveBeenCalledTimes(1);
|
416
|
+
expect(args.handleOpen).toHaveBeenCalledWith();
|
417
|
+
});
|
418
|
+
await sleep(500);
|
419
|
+
await userEvent.click(closeTrigger);
|
420
|
+
await waitFor(() => {
|
421
|
+
expect(args.handleClose).toHaveBeenCalledTimes(1);
|
422
|
+
expect(args.handleClose).toHaveBeenCalledWith({});
|
423
|
+
});
|
424
|
+
},
|
425
|
+
};
|
426
|
+
export const contentAttributes = {
|
427
|
+
name: "content: className, attributes",
|
428
|
+
render: () => {
|
429
|
+
return (<Flyout position="bottom" defaultActive>
|
430
|
+
<Flyout.Trigger>
|
431
|
+
{(attributes) => <Button attributes={attributes}>`Trigger</Button>}
|
432
|
+
</Flyout.Trigger>
|
433
|
+
<Flyout.Content attributes={{ "data-testid": "test-id" }} className="test-classname">
|
434
|
+
<Content />
|
435
|
+
</Flyout.Content>
|
436
|
+
</Flyout>);
|
437
|
+
},
|
438
|
+
play: async ({ canvasElement }) => {
|
439
|
+
const canvas = within(canvasElement.ownerDocument.body);
|
440
|
+
const content = canvas.getByTestId("test-id");
|
441
|
+
expect(content).toHaveClass("test-classname");
|
442
|
+
},
|
443
|
+
};
|
444
|
+
/*
|
445
|
+
* Test edge cases
|
446
|
+
*/
|
181
447
|
class CustomElement extends window.HTMLElement {
|
182
448
|
constructor() {
|
183
449
|
super();
|
@@ -185,152 +451,132 @@ class CustomElement extends window.HTMLElement {
|
|
185
451
|
if (!this.shadowRoot)
|
186
452
|
return;
|
187
453
|
const node = (<Reshaped>
|
188
|
-
<
|
189
|
-
|
190
|
-
<
|
191
|
-
</
|
454
|
+
<Demo defaultActive>
|
455
|
+
Content
|
456
|
+
<div id="test-id"/>
|
457
|
+
</Demo>
|
192
458
|
</Reshaped>);
|
193
459
|
const root = createRoot(this.shadowRoot);
|
194
460
|
root.render(node);
|
195
461
|
}
|
196
462
|
}
|
197
|
-
if (!window.customElements.get("custom-element")) {
|
198
|
-
window.customElements.define("custom-element", CustomElement);
|
463
|
+
if (!window.customElements.get("custom-element-flyout")) {
|
464
|
+
window.customElements.define("custom-element-flyout", CustomElement);
|
199
465
|
}
|
200
|
-
export const
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
466
|
+
export const testShadowDom = {
|
467
|
+
name: "test: shadow dom",
|
468
|
+
// @ts-ignore
|
469
|
+
render: () => <custom-element-flyout />,
|
470
|
+
};
|
471
|
+
export const testInsideFixed = {
|
472
|
+
name: "test: inside position fixed",
|
473
|
+
render: () => (<React.Fragment>
|
474
|
+
<View position="fixed" insetTop={2} insetStart={2} insetEnd={2} backgroundColor="elevation-overlay" borderColor="neutral-faded" borderRadius="small" padding={4} zIndex={10} attributes={{ "data-testid": "container" }}>
|
475
|
+
<Demo defaultActive/>
|
476
|
+
</View>
|
477
|
+
<View paddingTop={18} gap={4}>
|
478
|
+
<View height={200} backgroundColor="neutral-faded" borderRadius="small"/>
|
479
|
+
<View height={200} backgroundColor="neutral-faded" borderRadius="small"/>
|
480
|
+
</View>
|
481
|
+
</React.Fragment>),
|
482
|
+
play: ({ canvas }) => {
|
483
|
+
const container = canvas.getByTestId("container");
|
484
|
+
const content = canvas.getByText("Content");
|
485
|
+
expect(container).toContainElement(content);
|
486
|
+
},
|
487
|
+
};
|
488
|
+
export const testInsideSticky = {
|
489
|
+
name: "test: inside position sticky",
|
490
|
+
render: () => (<React.Fragment>
|
491
|
+
<View position="sticky" insetTop={4} insetStart={0} insetEnd={0} backgroundColor="elevation-overlay" borderColor="neutral-faded" borderRadius="small" padding={4} zIndex={10} attributes={{ "data-testid": "container" }}>
|
492
|
+
<Demo defaultActive/>
|
493
|
+
</View>
|
494
|
+
<View gap={4} paddingTop={2}>
|
495
|
+
<View height={200} backgroundColor="neutral-faded" borderRadius="small"/>
|
496
|
+
<View height={200} backgroundColor="neutral-faded" borderRadius="small"/>
|
497
|
+
</View>
|
498
|
+
</React.Fragment>),
|
499
|
+
play: ({ canvas }) => {
|
500
|
+
const container = canvas.getByTestId("container");
|
501
|
+
const content = canvas.getByText("Content");
|
502
|
+
expect(container).toContainElement(content);
|
503
|
+
},
|
504
|
+
};
|
505
|
+
export const testInsideScrollable = {
|
506
|
+
name: "test: inside scrollable",
|
507
|
+
render: () => {
|
508
|
+
const containerRef = React.useRef(null);
|
509
|
+
return (<View padding={50}>
|
510
|
+
<View height={30} overflow="auto" backgroundColor="neutral-faded" borderRadius="small">
|
511
|
+
<View height={50} attributes={{ ref: containerRef }} padding={4} paddingBottom={30}>
|
512
|
+
<Demo position="start"/>
|
513
|
+
</View>
|
514
|
+
</View>
|
515
|
+
</View>);
|
516
|
+
},
|
517
|
+
};
|
518
|
+
export const testDynamicBounds = {
|
519
|
+
name: "test: auto position update",
|
520
|
+
render: () => {
|
521
|
+
const [left, setLeft] = React.useState(50);
|
522
|
+
const [top, setTop] = React.useState(50);
|
523
|
+
const [size, setSize] = React.useState("medium");
|
524
|
+
const flyoutRef = React.useRef(null);
|
525
|
+
React.useEffect(() => {
|
526
|
+
flyoutRef.current?.updatePosition();
|
527
|
+
}, [left, top]);
|
528
|
+
return (<View gap={4}>
|
529
|
+
<View direction="row" gap={2}>
|
530
|
+
<Button onClick={() => setLeft((prev) => prev - 10)}>Left</Button>
|
531
|
+
<Button onClick={() => setLeft((prev) => prev + 10)}>Right</Button>
|
532
|
+
<Button onClick={() => setTop((prev) => prev - 10)}>Up</Button>
|
533
|
+
<Button onClick={() => setTop((prev) => prev + 10)}>Down</Button>
|
534
|
+
<Button onClick={() => {
|
535
|
+
setLeft(50);
|
536
|
+
setTop(50);
|
537
|
+
}}>
|
538
|
+
Center
|
539
|
+
</Button>
|
540
|
+
<Button onClick={() => setSize("large")}>Large button</Button>
|
541
|
+
<Button onClick={() => setSize("medium")}>Small button</Button>
|
542
|
+
</View>
|
543
|
+
<View height={100}>
|
544
|
+
<Flyout position="bottom" instanceRef={flyoutRef} disableCloseOnOutsideClick>
|
545
|
+
<Flyout.Trigger>
|
546
|
+
{(attributes) => (<div style={{ position: "absolute", left: `${left}%`, top: `${top}%` }}>
|
547
|
+
<Button color="primary" attributes={attributes} size={size}>
|
548
|
+
Open
|
549
|
+
</Button>
|
550
|
+
</div>)}
|
551
|
+
</Flyout.Trigger>
|
207
552
|
<Flyout.Content>
|
208
|
-
<
|
209
|
-
background: "var(--rs-color-background-elevation-overlay)",
|
210
|
-
padding: "var(--rs-unit-x4)",
|
211
|
-
height: 200,
|
212
|
-
width: 160,
|
213
|
-
borderRadius: "var(--rs-radius-medium)",
|
214
|
-
border: "1px solid var(--rs-color-border-neutral-faded)",
|
215
|
-
boxSizing: "border-box",
|
216
|
-
}}>
|
217
|
-
{"Content"}
|
218
|
-
</div>
|
553
|
+
<Content />
|
219
554
|
</Flyout.Content>
|
220
555
|
</Flyout>
|
221
|
-
<div style={{ height: 1000 }}/>
|
222
556
|
</View>
|
223
|
-
</
|
224
|
-
|
225
|
-
{/* @ts-ignore */}
|
226
|
-
<custom-element />
|
227
|
-
</Example.Item>
|
228
|
-
</Example>);
|
557
|
+
</View>);
|
558
|
+
},
|
229
559
|
};
|
230
|
-
export const
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
<div style={{
|
237
|
-
background: "var(--rs-color-background-elevation-overlay)",
|
238
|
-
padding: "var(--rs-unit-x4)",
|
239
|
-
height: 100,
|
240
|
-
width: 160,
|
241
|
-
borderRadius: "var(--rs-radius-medium)",
|
242
|
-
border: "1px solid var(--rs-color-border-neutral-faded)",
|
243
|
-
boxSizing: "border-box",
|
244
|
-
}}>
|
245
|
-
{"Content"}
|
246
|
-
</div>
|
247
|
-
</Flyout.Content>
|
248
|
-
</Flyout>
|
249
|
-
</View>
|
250
|
-
<div style={{ height: 2000 }}/>
|
251
|
-
</Example.Item>
|
252
|
-
</Example>);
|
253
|
-
export const testDynamicBounds = () => {
|
254
|
-
const [left, setLeft] = React.useState(50);
|
255
|
-
const [top, setTop] = React.useState(50);
|
256
|
-
const [size, setSize] = React.useState("medium");
|
257
|
-
const flyoutRef = React.useRef(null);
|
258
|
-
React.useEffect(() => {
|
259
|
-
flyoutRef.current?.updatePosition();
|
260
|
-
}, [left, top]);
|
261
|
-
return (<View gap={4}>
|
262
|
-
<View direction="row" gap={2}>
|
263
|
-
<Button onClick={() => setLeft((prev) => prev - 10)}>Left</Button>
|
264
|
-
<Button onClick={() => setLeft((prev) => prev + 10)}>Right</Button>
|
265
|
-
<Button onClick={() => setTop((prev) => prev - 10)}>Up</Button>
|
266
|
-
<Button onClick={() => setTop((prev) => prev + 10)}>Down</Button>
|
267
|
-
<Button onClick={() => {
|
268
|
-
setLeft(50);
|
269
|
-
setTop(50);
|
270
|
-
}}>
|
271
|
-
Center
|
272
|
-
</Button>
|
273
|
-
<Button onClick={() => setSize("large")}>Large button</Button>
|
274
|
-
<Button onClick={() => setSize("medium")}>Small button</Button>
|
275
|
-
</View>
|
276
|
-
<View height={100}>
|
277
|
-
<Flyout position="bottom" instanceRef={flyoutRef} disableCloseOnOutsideClick fallbackPositions={["top", "bottom"]}>
|
560
|
+
export const testScopedTheming = {
|
561
|
+
name: "test: content uses scope theme",
|
562
|
+
render: () => (<View gap={3} align="start">
|
563
|
+
<Button color="primary">Reshaped button</Button>
|
564
|
+
<Theme name="slate">
|
565
|
+
<Flyout triggerType="click" active position="bottom-start">
|
278
566
|
<Flyout.Trigger>
|
279
|
-
{(attributes) => (<
|
280
|
-
|
281
|
-
|
282
|
-
</Button>
|
283
|
-
</div>)}
|
567
|
+
{(attributes) => (<Button color="primary" attributes={attributes}>
|
568
|
+
Slate button
|
569
|
+
</Button>)}
|
284
570
|
</Flyout.Trigger>
|
285
571
|
<Flyout.Content>
|
286
|
-
<
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
border: "1px solid var(--rs-color-border-neutral-faded)",
|
293
|
-
boxSizing: "border-box",
|
294
|
-
}}>
|
295
|
-
Content
|
296
|
-
</div>
|
572
|
+
<Content>
|
573
|
+
<View gap={1}>
|
574
|
+
<View.Item>Portal content, rendered in body</View.Item>
|
575
|
+
<Button color="primary">Slate button</Button>
|
576
|
+
</View>
|
577
|
+
</Content>
|
297
578
|
</Flyout.Content>
|
298
579
|
</Flyout>
|
299
|
-
</
|
300
|
-
</View>)
|
580
|
+
</Theme>
|
581
|
+
</View>),
|
301
582
|
};
|
302
|
-
export const testDisableOutsideClick = () => {
|
303
|
-
return (<Example>
|
304
|
-
<Example.Item title="opening second flyout shouldn't block the first one from closing">
|
305
|
-
<View direction="row" gap={4}>
|
306
|
-
<Demo disableCloseOnOutsideClick/>
|
307
|
-
<Demo />
|
308
|
-
</View>
|
309
|
-
</Example.Item>
|
310
|
-
</Example>);
|
311
|
-
};
|
312
|
-
export const testScopedTheming = () => (<View gap={3} align="start">
|
313
|
-
<Button color="primary">Reshaped button</Button>
|
314
|
-
<Theme name="slate">
|
315
|
-
<Flyout triggerType="click" active position="bottom-start">
|
316
|
-
<Flyout.Trigger>
|
317
|
-
{(attributes) => (<Button color="primary" attributes={attributes}>
|
318
|
-
Slate button
|
319
|
-
</Button>)}
|
320
|
-
</Flyout.Trigger>
|
321
|
-
<Flyout.Content>
|
322
|
-
<div style={{
|
323
|
-
background: "var(--rs-color-background-elevation-overlay)",
|
324
|
-
padding: 8,
|
325
|
-
border: "1px solid var(--rs-color-border-neutral-faded)",
|
326
|
-
boxSizing: "border-box",
|
327
|
-
}}>
|
328
|
-
<View gap={1}>
|
329
|
-
<View.Item>Portal content, rendered in body</View.Item>
|
330
|
-
<Button color="primary">Slate button</Button>
|
331
|
-
</View>
|
332
|
-
</div>
|
333
|
-
</Flyout.Content>
|
334
|
-
</Flyout>
|
335
|
-
</Theme>
|
336
|
-
</View>);
|