@khanacademy/wonder-blocks-popover 3.2.15 → 3.3.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 +26 -0
- package/dist/components/popover.d.ts +6 -0
- package/dist/es/index.js +4 -2
- package/dist/index.js +4 -2
- package/package.json +7 -7
- package/src/components/__tests__/focus-manager.test.tsx +0 -180
- package/src/components/__tests__/initial-focus.test.tsx +0 -73
- package/src/components/__tests__/popover-anchor.test.tsx +0 -61
- package/src/components/__tests__/popover-content.test.tsx +0 -76
- package/src/components/__tests__/popover-content.typestest.tsx +0 -38
- package/src/components/__tests__/popover-dialog.test.tsx +0 -98
- package/src/components/__tests__/popover-event-listener.test.tsx +0 -98
- package/src/components/__tests__/popover.test.tsx +0 -932
- package/src/components/close-button.tsx +0 -61
- package/src/components/focus-manager.tsx +0 -344
- package/src/components/initial-focus.ts +0 -87
- package/src/components/popover-anchor.ts +0 -93
- package/src/components/popover-content-core.tsx +0 -143
- package/src/components/popover-content.tsx +0 -319
- package/src/components/popover-context.ts +0 -40
- package/src/components/popover-dialog.tsx +0 -150
- package/src/components/popover-event-listener.ts +0 -96
- package/src/components/popover.tsx +0 -410
- package/src/index.ts +0 -5
- package/src/util/__tests__/util.test.tsx +0 -38
- package/src/util/util.ts +0 -20
- package/tsconfig-build.json +0 -17
- package/tsconfig-build.tsbuildinfo +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# @khanacademy/wonder-blocks-popover
|
|
2
2
|
|
|
3
|
+
## 3.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- badad6ee: Adds a `viewportPadding` prop to provide spacing between the popper and the viewport edges. If this prop is not provided, default spacing is applied.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- fcab789b: Only show the `TooltipPopper` contents once the popper has positioned itself. This fixes the issue where Tooltips are initially rendered in the top left corner for a brief moment before moving to the correct position (which was causing a flickering effect).
|
|
12
|
+
- Updated dependencies [badad6ee]
|
|
13
|
+
- Updated dependencies [fcab789b]
|
|
14
|
+
- @khanacademy/wonder-blocks-tooltip@2.5.0
|
|
15
|
+
|
|
16
|
+
## 3.2.16
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- 02a1b298: Make sure we don't package tsconfig and tsbuildinfo files
|
|
21
|
+
- Updated dependencies [02a1b298]
|
|
22
|
+
- @khanacademy/wonder-blocks-core@7.0.1
|
|
23
|
+
- @khanacademy/wonder-blocks-icon-button@5.4.1
|
|
24
|
+
- @khanacademy/wonder-blocks-modal@5.1.12
|
|
25
|
+
- @khanacademy/wonder-blocks-tokens@2.0.1
|
|
26
|
+
- @khanacademy/wonder-blocks-tooltip@2.4.3
|
|
27
|
+
- @khanacademy/wonder-blocks-typography@2.1.16
|
|
28
|
+
|
|
3
29
|
## 3.2.15
|
|
4
30
|
|
|
5
31
|
### Patch Changes
|
|
@@ -103,6 +103,12 @@ type Props = AriaProps & Readonly<{
|
|
|
103
103
|
* on where there is available room within the document body.
|
|
104
104
|
*/
|
|
105
105
|
rootBoundary?: RootBoundary;
|
|
106
|
+
/**
|
|
107
|
+
* If `rootBoundary` is `viewport`, this padding value is used to provide
|
|
108
|
+
* spacing between the popper and the viewport. If not provided, default
|
|
109
|
+
* spacing of 12px is applied.
|
|
110
|
+
*/
|
|
111
|
+
viewportPadding?: number;
|
|
106
112
|
}>;
|
|
107
113
|
type State = Readonly<{
|
|
108
114
|
/**
|
package/dist/es/index.js
CHANGED
|
@@ -449,7 +449,8 @@ class Popover extends React.Component {
|
|
|
449
449
|
portal,
|
|
450
450
|
"aria-label": ariaLabel,
|
|
451
451
|
"aria-describedby": ariaDescribedBy,
|
|
452
|
-
rootBoundary
|
|
452
|
+
rootBoundary,
|
|
453
|
+
viewportPadding
|
|
453
454
|
} = this.props;
|
|
454
455
|
const {
|
|
455
456
|
anchorElement
|
|
@@ -459,7 +460,8 @@ class Popover extends React.Component {
|
|
|
459
460
|
const popperContent = React.createElement(TooltipPopper, {
|
|
460
461
|
anchorElement: anchorElement,
|
|
461
462
|
placement: placement,
|
|
462
|
-
rootBoundary: rootBoundary
|
|
463
|
+
rootBoundary: rootBoundary,
|
|
464
|
+
viewportPadding: viewportPadding
|
|
463
465
|
}, props => React.createElement(PopoverDialog, _extends({}, props, {
|
|
464
466
|
"aria-label": ariaLabel,
|
|
465
467
|
"aria-describedby": describedBy,
|
package/dist/index.js
CHANGED
|
@@ -479,7 +479,8 @@ class Popover extends React__namespace.Component {
|
|
|
479
479
|
portal,
|
|
480
480
|
"aria-label": ariaLabel,
|
|
481
481
|
"aria-describedby": ariaDescribedBy,
|
|
482
|
-
rootBoundary
|
|
482
|
+
rootBoundary,
|
|
483
|
+
viewportPadding
|
|
483
484
|
} = this.props;
|
|
484
485
|
const {
|
|
485
486
|
anchorElement
|
|
@@ -489,7 +490,8 @@ class Popover extends React__namespace.Component {
|
|
|
489
490
|
const popperContent = React__namespace.createElement(wonderBlocksTooltip.TooltipPopper, {
|
|
490
491
|
anchorElement: anchorElement,
|
|
491
492
|
placement: placement,
|
|
492
|
-
rootBoundary: rootBoundary
|
|
493
|
+
rootBoundary: rootBoundary,
|
|
494
|
+
viewportPadding: viewportPadding
|
|
493
495
|
}, props => React__namespace.createElement(PopoverDialog, _extends__default["default"]({}, props, {
|
|
494
496
|
"aria-label": ariaLabel,
|
|
495
497
|
"aria-describedby": describedBy,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-popover",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"design": "v1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@babel/runtime": "^7.18.6",
|
|
19
|
-
"@khanacademy/wonder-blocks-core": "^7.0.
|
|
20
|
-
"@khanacademy/wonder-blocks-icon-button": "^5.4.
|
|
21
|
-
"@khanacademy/wonder-blocks-modal": "^5.1.
|
|
22
|
-
"@khanacademy/wonder-blocks-tokens": "^2.0.
|
|
23
|
-
"@khanacademy/wonder-blocks-tooltip": "^2.
|
|
24
|
-
"@khanacademy/wonder-blocks-typography": "^2.1.
|
|
19
|
+
"@khanacademy/wonder-blocks-core": "^7.0.1",
|
|
20
|
+
"@khanacademy/wonder-blocks-icon-button": "^5.4.1",
|
|
21
|
+
"@khanacademy/wonder-blocks-modal": "^5.1.12",
|
|
22
|
+
"@khanacademy/wonder-blocks-tokens": "^2.0.1",
|
|
23
|
+
"@khanacademy/wonder-blocks-tooltip": "^2.5.0",
|
|
24
|
+
"@khanacademy/wonder-blocks-typography": "^2.1.16"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"@phosphor-icons/core": "^2.0.2",
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {render, screen} from "@testing-library/react";
|
|
3
|
-
import {userEvent} from "@testing-library/user-event";
|
|
4
|
-
|
|
5
|
-
import FocusManager from "../focus-manager";
|
|
6
|
-
|
|
7
|
-
describe("FocusManager", () => {
|
|
8
|
-
it("should focus on the first focusable element inside the popover", async () => {
|
|
9
|
-
// Arrange
|
|
10
|
-
const externalNodes = (
|
|
11
|
-
<div>
|
|
12
|
-
<button>Open popover</button>
|
|
13
|
-
<button>Next focusable element outside</button>
|
|
14
|
-
</div>
|
|
15
|
-
);
|
|
16
|
-
render(externalNodes);
|
|
17
|
-
|
|
18
|
-
// get the anchor reference to be able pass it to the FocusManager
|
|
19
|
-
const anchorElementNode = await screen.findByRole("button", {
|
|
20
|
-
name: "Open popover",
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
render(
|
|
24
|
-
<FocusManager anchorElement={anchorElementNode}>
|
|
25
|
-
<div>
|
|
26
|
-
<button>first focusable element inside</button>
|
|
27
|
-
<button>second focusable element inside</button>
|
|
28
|
-
<button>third focusable element inside</button>
|
|
29
|
-
</div>
|
|
30
|
-
</FocusManager>,
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
// Act
|
|
34
|
-
// focus on the previous element before the popover (anchor element)
|
|
35
|
-
anchorElementNode.focus();
|
|
36
|
-
// focus gets automatically moved to be on the first focusable element
|
|
37
|
-
|
|
38
|
-
const firstFocusableElementInside = await screen.findByText(
|
|
39
|
-
"first focusable element inside",
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
// Assert
|
|
43
|
-
expect(firstFocusableElementInside).toHaveFocus();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it("should focus on the last focusable element inside the popover", async () => {
|
|
47
|
-
// Arrange
|
|
48
|
-
const externalNodes = (
|
|
49
|
-
<div>
|
|
50
|
-
<button>Open popover</button>
|
|
51
|
-
<button>Next focusable element outside</button>
|
|
52
|
-
</div>
|
|
53
|
-
);
|
|
54
|
-
render(externalNodes);
|
|
55
|
-
|
|
56
|
-
// get the anchor reference to be able pass it to the FocusManager
|
|
57
|
-
const anchorElementNode = await screen.findByRole("button", {
|
|
58
|
-
name: "Open popover",
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
render(
|
|
62
|
-
<FocusManager anchorElement={anchorElementNode}>
|
|
63
|
-
<div>
|
|
64
|
-
<button>first focusable element inside</button>
|
|
65
|
-
<button>second focusable element inside</button>
|
|
66
|
-
<button>third focusable element inside</button>
|
|
67
|
-
</div>
|
|
68
|
-
</FocusManager>,
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
// Act
|
|
72
|
-
|
|
73
|
-
// find previous focusable element outside the popover
|
|
74
|
-
const nextFocusableElementOutside = await screen.findByRole("button", {
|
|
75
|
-
name: "Next focusable element outside",
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// focus on the next element after the popover
|
|
79
|
-
nextFocusableElementOutside.focus();
|
|
80
|
-
await userEvent.tab({shift: true});
|
|
81
|
-
|
|
82
|
-
const lastFocusableElementInside = await screen.findByText(
|
|
83
|
-
"third focusable element inside",
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
// Assert
|
|
87
|
-
expect(lastFocusableElementInside).toHaveFocus();
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("should allow flowing the focus correctly", async () => {
|
|
91
|
-
// Arrange
|
|
92
|
-
const externalNodes = (
|
|
93
|
-
<div>
|
|
94
|
-
<button>Prev focusable element outside</button>
|
|
95
|
-
<button>Open popover</button>
|
|
96
|
-
<button>Next focusable element outside</button>
|
|
97
|
-
</div>
|
|
98
|
-
);
|
|
99
|
-
render(externalNodes);
|
|
100
|
-
|
|
101
|
-
// get the anchor reference to be able pass it to the FocusManager
|
|
102
|
-
const anchorElementNode = await screen.findByRole("button", {
|
|
103
|
-
name: "Open popover",
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
render(
|
|
107
|
-
<FocusManager anchorElement={anchorElementNode}>
|
|
108
|
-
<div>
|
|
109
|
-
<button>first focusable element inside</button>
|
|
110
|
-
</div>
|
|
111
|
-
</FocusManager>,
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
// Act
|
|
115
|
-
// 1. focus on the Open popover button, this opens the focus manager
|
|
116
|
-
// and focuses the button inside the popover
|
|
117
|
-
await userEvent.tab();
|
|
118
|
-
|
|
119
|
-
// 2. we advance to the next focusable element outside the popover
|
|
120
|
-
await userEvent.tab();
|
|
121
|
-
|
|
122
|
-
// 3. we loop back around to the first focusable element outside the popover
|
|
123
|
-
await userEvent.tab();
|
|
124
|
-
|
|
125
|
-
// find previous focusable element outside the popover
|
|
126
|
-
const prevFocusableElementOutside = await screen.findByRole("button", {
|
|
127
|
-
name: "Prev focusable element outside",
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
// Assert
|
|
131
|
-
expect(prevFocusableElementOutside).toHaveFocus();
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it("should disallow focusability on internal elements if the user focus out of the focus manager", async () => {
|
|
135
|
-
// Arrange
|
|
136
|
-
const externalNodes = (
|
|
137
|
-
<div>
|
|
138
|
-
<button>Prev focusable element outside</button>
|
|
139
|
-
<button>Open popover</button>
|
|
140
|
-
<button>Next focusable element outside</button>
|
|
141
|
-
</div>
|
|
142
|
-
);
|
|
143
|
-
render(externalNodes);
|
|
144
|
-
|
|
145
|
-
// get the anchor reference to be able pass it to the FocusManager
|
|
146
|
-
const anchorElementNode = await screen.findByRole("button", {
|
|
147
|
-
name: "Open popover",
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
render(
|
|
151
|
-
<FocusManager anchorElement={anchorElementNode}>
|
|
152
|
-
<div>
|
|
153
|
-
<button>first focusable element inside</button>
|
|
154
|
-
</div>
|
|
155
|
-
</FocusManager>,
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
// Act
|
|
159
|
-
// 1. focus on the previous element before the popover
|
|
160
|
-
await userEvent.tab();
|
|
161
|
-
|
|
162
|
-
// 2. focus on the anchor element
|
|
163
|
-
await userEvent.tab();
|
|
164
|
-
|
|
165
|
-
// 3. focus on focusable element inside the popover
|
|
166
|
-
await userEvent.tab();
|
|
167
|
-
|
|
168
|
-
// 4. focus on the next focusable element outside the popover (this will
|
|
169
|
-
// be the first focusable element outside the popover)
|
|
170
|
-
await userEvent.tab();
|
|
171
|
-
|
|
172
|
-
// The elements inside the focus manager should not be focusable anymore.
|
|
173
|
-
const focusableElementInside = await screen.findByRole("button", {
|
|
174
|
-
name: "first focusable element inside",
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
// Assert
|
|
178
|
-
expect(focusableElementInside).toHaveAttribute("tabIndex", "-1");
|
|
179
|
-
});
|
|
180
|
-
});
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {render, screen} from "@testing-library/react";
|
|
3
|
-
|
|
4
|
-
import InitialFocus from "../initial-focus";
|
|
5
|
-
|
|
6
|
-
describe("InitialFocus", () => {
|
|
7
|
-
beforeEach(() => {
|
|
8
|
-
jest.useFakeTimers();
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it("should try to focus on a given element by id", () => {
|
|
12
|
-
// Arrange
|
|
13
|
-
render(
|
|
14
|
-
<InitialFocus initialFocusId="initial-focus-id">
|
|
15
|
-
<div data-testid="container">
|
|
16
|
-
<button data-testid="item-0" />
|
|
17
|
-
<button data-testid="item-1" id="initial-focus-id" />
|
|
18
|
-
<button data-testid="item-2" />
|
|
19
|
-
</div>
|
|
20
|
-
</InitialFocus>,
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
// Act
|
|
24
|
-
const firstFocusableElement = screen.getByTestId("item-1");
|
|
25
|
-
// Fast-forward until all timers have been executed
|
|
26
|
-
jest.runAllTimers();
|
|
27
|
-
|
|
28
|
-
// Assert
|
|
29
|
-
expect(firstFocusableElement).toHaveFocus();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("should try to focus on the first focusable element", () => {
|
|
33
|
-
// Arrange
|
|
34
|
-
render(
|
|
35
|
-
<InitialFocus>
|
|
36
|
-
<div data-testid="container">
|
|
37
|
-
<button data-testid="item-0" />
|
|
38
|
-
<button data-testid="item-1" id="initial-focus-id" />
|
|
39
|
-
<button data-testid="item-2" />
|
|
40
|
-
</div>
|
|
41
|
-
</InitialFocus>,
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
// Act
|
|
45
|
-
const firstFocusableElement = screen.getByTestId("item-0");
|
|
46
|
-
|
|
47
|
-
// Fast-forward until all timers have been executed
|
|
48
|
-
jest.runAllTimers();
|
|
49
|
-
|
|
50
|
-
// Assert
|
|
51
|
-
expect(firstFocusableElement).toHaveFocus();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("should try to focus on the container if no focusable elements are found", () => {
|
|
55
|
-
// Arrange
|
|
56
|
-
render(
|
|
57
|
-
<InitialFocus>
|
|
58
|
-
<div data-testid="container">
|
|
59
|
-
<p>no focusable elements here</p>
|
|
60
|
-
</div>
|
|
61
|
-
</InitialFocus>,
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
// Act
|
|
65
|
-
const firstFocusableElement = screen.getByTestId("container");
|
|
66
|
-
|
|
67
|
-
// Fast-forward until all timers have been executed
|
|
68
|
-
jest.runAllTimers();
|
|
69
|
-
|
|
70
|
-
// Assert
|
|
71
|
-
expect(firstFocusableElement).toHaveFocus();
|
|
72
|
-
});
|
|
73
|
-
});
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {render, screen} from "@testing-library/react";
|
|
3
|
-
import {userEvent} from "@testing-library/user-event";
|
|
4
|
-
|
|
5
|
-
import PopoverAnchor from "../popover-anchor";
|
|
6
|
-
|
|
7
|
-
describe("PopoverAnchor", () => {
|
|
8
|
-
it("should set child node as ref", async () => {
|
|
9
|
-
// Arrange
|
|
10
|
-
const updateRef = jest.fn();
|
|
11
|
-
|
|
12
|
-
render(
|
|
13
|
-
<PopoverAnchor anchorRef={updateRef} onClick={jest.fn()}>
|
|
14
|
-
<button>test</button>
|
|
15
|
-
</PopoverAnchor>,
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
// Act
|
|
19
|
-
const triggerElement = await screen.findByRole("button");
|
|
20
|
-
|
|
21
|
-
// Assert
|
|
22
|
-
expect(updateRef).toBeCalledWith(triggerElement);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("should add onClick handler if child is a function", async () => {
|
|
26
|
-
// Arrange
|
|
27
|
-
const onClickMock = jest.fn();
|
|
28
|
-
|
|
29
|
-
render(
|
|
30
|
-
<PopoverAnchor anchorRef={jest.fn()} onClick={onClickMock}>
|
|
31
|
-
{({open}: any) => <button onClick={open}>open</button>}
|
|
32
|
-
</PopoverAnchor>,
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
// Act
|
|
36
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
37
|
-
|
|
38
|
-
// Assert
|
|
39
|
-
expect(onClickMock).toBeCalled();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("should add onClick handler if child is a Node", async () => {
|
|
43
|
-
// Arrange
|
|
44
|
-
const onClickMock = jest.fn();
|
|
45
|
-
const onClickInnerMock = jest.fn();
|
|
46
|
-
|
|
47
|
-
render(
|
|
48
|
-
<PopoverAnchor anchorRef={jest.fn()} onClick={onClickMock}>
|
|
49
|
-
<button onClick={onClickInnerMock}>test</button>
|
|
50
|
-
</PopoverAnchor>,
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
// Act
|
|
54
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
55
|
-
|
|
56
|
-
// Assert
|
|
57
|
-
// both custom and internal click should be called
|
|
58
|
-
expect(onClickInnerMock).toBeCalled();
|
|
59
|
-
expect(onClickMock).toBeCalled();
|
|
60
|
-
});
|
|
61
|
-
});
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {render, screen} from "@testing-library/react";
|
|
3
|
-
import {userEvent} from "@testing-library/user-event";
|
|
4
|
-
|
|
5
|
-
import PopoverContent from "../popover-content";
|
|
6
|
-
import PopoverContext from "../popover-context";
|
|
7
|
-
|
|
8
|
-
describe("PopoverContent", () => {
|
|
9
|
-
it("should close the popover from the actions", async () => {
|
|
10
|
-
// Arrange
|
|
11
|
-
const onCloseMock = jest.fn();
|
|
12
|
-
|
|
13
|
-
render(
|
|
14
|
-
<PopoverContext.Provider
|
|
15
|
-
value={{close: onCloseMock, placement: "left"}}
|
|
16
|
-
>
|
|
17
|
-
<PopoverContent
|
|
18
|
-
title="Title"
|
|
19
|
-
content="content"
|
|
20
|
-
actions={({close}: any) => (
|
|
21
|
-
<button onClick={close}>close popover</button>
|
|
22
|
-
)}
|
|
23
|
-
/>
|
|
24
|
-
</PopoverContext.Provider>,
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
// Act
|
|
28
|
-
await userEvent.click(await screen.findByRole("button"));
|
|
29
|
-
|
|
30
|
-
// Assert
|
|
31
|
-
expect(onCloseMock).toBeCalled();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it("should warn when setting a image and icon at the same time", async () => {
|
|
35
|
-
// Arrange
|
|
36
|
-
const nodes = (
|
|
37
|
-
<PopoverContent
|
|
38
|
-
title="illustration"
|
|
39
|
-
content="content"
|
|
40
|
-
image={<img src="/dummy-image.png" alt="popover image" />}
|
|
41
|
-
icon={<img src="/dummy-icon.png" alt="popover icon" />}
|
|
42
|
-
/>
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
// Act
|
|
46
|
-
const underTest = () => render(nodes);
|
|
47
|
-
|
|
48
|
-
// Assert
|
|
49
|
-
expect(underTest).toThrowErrorMatchingInlineSnapshot(
|
|
50
|
-
`"'image' and 'icon' cannot be used at the same time. You can fix this by either removing 'image' or 'icon' from your instance."`,
|
|
51
|
-
);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("should warn when setting a horizontal placement with an Illustration popover", async () => {
|
|
55
|
-
// Arrange
|
|
56
|
-
const nodes = (
|
|
57
|
-
<PopoverContext.Provider
|
|
58
|
-
value={{close: () => {}, placement: "left"}}
|
|
59
|
-
>
|
|
60
|
-
<PopoverContent
|
|
61
|
-
title="illustration"
|
|
62
|
-
content="content"
|
|
63
|
-
image={<img src="/dummy-image.png" alt="dummy" />}
|
|
64
|
-
/>
|
|
65
|
-
</PopoverContext.Provider>
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
// Act
|
|
69
|
-
const underTest = () => render(nodes);
|
|
70
|
-
|
|
71
|
-
// Assert
|
|
72
|
-
expect(underTest).toThrowErrorMatchingInlineSnapshot(
|
|
73
|
-
`"'image' can only be vertically placed. You can fix this by either changing \`placement\` to \`top\` or \`bottom\` or removing the \`image\` prop inside \`content\`."`,
|
|
74
|
-
);
|
|
75
|
-
});
|
|
76
|
-
});
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
import PopoverContent from "../popover-content";
|
|
4
|
-
|
|
5
|
-
<PopoverContent title="Title" content="Content" />;
|
|
6
|
-
|
|
7
|
-
<PopoverContent title="Title" content="Content" icon="close" />;
|
|
8
|
-
|
|
9
|
-
<PopoverContent
|
|
10
|
-
title="Title"
|
|
11
|
-
content="Content"
|
|
12
|
-
image={<img src="domokun.jpg" alt="domokun" />}
|
|
13
|
-
/>;
|
|
14
|
-
|
|
15
|
-
<PopoverContent
|
|
16
|
-
title="Title"
|
|
17
|
-
content="Content"
|
|
18
|
-
icon="close"
|
|
19
|
-
image={<img src="domokun.jpg" alt="domokun" />}
|
|
20
|
-
/>;
|
|
21
|
-
|
|
22
|
-
<PopoverContent title="Title" content="Content" emphasized={true} />;
|
|
23
|
-
|
|
24
|
-
// @ts-expect-error `emphasized` cannot be used with `icon`
|
|
25
|
-
<PopoverContent
|
|
26
|
-
title="Title"
|
|
27
|
-
content="Content"
|
|
28
|
-
icon="close"
|
|
29
|
-
emphasized={true}
|
|
30
|
-
/>;
|
|
31
|
-
|
|
32
|
-
// @ts-expect-error `emphasized` cannot be used with `img`
|
|
33
|
-
<PopoverContent
|
|
34
|
-
title="Title"
|
|
35
|
-
content="Content"
|
|
36
|
-
image={<img src="domokun.jpg" alt="domokun" />}
|
|
37
|
-
emphasized={true}
|
|
38
|
-
/>;
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {render} from "@testing-library/react";
|
|
3
|
-
import * as Tooltip from "@khanacademy/wonder-blocks-tooltip";
|
|
4
|
-
|
|
5
|
-
import type {Placement} from "@khanacademy/wonder-blocks-tooltip";
|
|
6
|
-
import PopoverDialog from "../popover-dialog";
|
|
7
|
-
import PopoverContentCore from "../popover-content-core";
|
|
8
|
-
|
|
9
|
-
jest.mock("@khanacademy/wonder-blocks-tooltip");
|
|
10
|
-
|
|
11
|
-
describe("PopoverDialog", () => {
|
|
12
|
-
it("should update the tail color to match the content's color", () => {
|
|
13
|
-
// Arrange
|
|
14
|
-
const tooltipTailSpy = jest.spyOn(Tooltip, "TooltipTail");
|
|
15
|
-
|
|
16
|
-
// Act
|
|
17
|
-
render(
|
|
18
|
-
<PopoverDialog showTail={true} placement="top" onUpdate={jest.fn()}>
|
|
19
|
-
<PopoverContentCore color="darkBlue">
|
|
20
|
-
popover content
|
|
21
|
-
</PopoverContentCore>
|
|
22
|
-
</PopoverDialog>,
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
// Assert
|
|
26
|
-
expect(tooltipTailSpy).toHaveBeenCalledWith(
|
|
27
|
-
expect.objectContaining({color: "darkBlue"}),
|
|
28
|
-
{},
|
|
29
|
-
);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("should call onUpdate if placement is changed", () => {
|
|
33
|
-
// Arrange
|
|
34
|
-
const onUpdateMock = jest.fn();
|
|
35
|
-
const UnderTest = ({placement}: {placement: Placement}) => (
|
|
36
|
-
<PopoverDialog
|
|
37
|
-
showTail={true}
|
|
38
|
-
placement={placement}
|
|
39
|
-
onUpdate={onUpdateMock}
|
|
40
|
-
>
|
|
41
|
-
<PopoverContentCore>popover content</PopoverContentCore>
|
|
42
|
-
</PopoverDialog>
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
const {rerender} = render(<UnderTest placement="top" />);
|
|
46
|
-
|
|
47
|
-
// Act
|
|
48
|
-
rerender(<UnderTest placement="bottom" />);
|
|
49
|
-
|
|
50
|
-
// Assert
|
|
51
|
-
expect(onUpdateMock).toBeCalledWith("bottom");
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it("should not call onUpdate if placement remains the same", () => {
|
|
55
|
-
// Arrange
|
|
56
|
-
const onUpdateMock = jest.fn();
|
|
57
|
-
|
|
58
|
-
const UnderTest = ({placement}: {placement: Placement}) => (
|
|
59
|
-
<PopoverDialog
|
|
60
|
-
showTail={true}
|
|
61
|
-
placement={placement}
|
|
62
|
-
onUpdate={onUpdateMock}
|
|
63
|
-
>
|
|
64
|
-
<PopoverContentCore>popover content</PopoverContentCore>
|
|
65
|
-
</PopoverDialog>
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
const {rerender} = render(<UnderTest placement="top" />);
|
|
69
|
-
|
|
70
|
-
// Act
|
|
71
|
-
rerender(<UnderTest placement="top" />);
|
|
72
|
-
|
|
73
|
-
// Assert
|
|
74
|
-
expect(onUpdateMock).not.toBeCalled();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it("should not render a tail if showTail is false", () => {
|
|
78
|
-
// Arrange
|
|
79
|
-
const tooltipTailSpy = jest.spyOn(Tooltip, "TooltipTail");
|
|
80
|
-
|
|
81
|
-
// Act
|
|
82
|
-
render(
|
|
83
|
-
<PopoverDialog
|
|
84
|
-
showTail={false}
|
|
85
|
-
placement="top"
|
|
86
|
-
onUpdate={jest.fn()}
|
|
87
|
-
>
|
|
88
|
-
<PopoverContentCore>popover content</PopoverContentCore>
|
|
89
|
-
</PopoverDialog>,
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
// Assert
|
|
93
|
-
expect(tooltipTailSpy).toHaveBeenCalledWith(
|
|
94
|
-
expect.objectContaining({show: false}),
|
|
95
|
-
{},
|
|
96
|
-
);
|
|
97
|
-
});
|
|
98
|
-
});
|