@khanacademy/wonder-blocks-popover 3.2.15 → 3.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @khanacademy/wonder-blocks-popover
2
2
 
3
+ ## 3.2.16
4
+
5
+ ### Patch Changes
6
+
7
+ - 02a1b298: Make sure we don't package tsconfig and tsbuildinfo files
8
+ - Updated dependencies [02a1b298]
9
+ - @khanacademy/wonder-blocks-core@7.0.1
10
+ - @khanacademy/wonder-blocks-icon-button@5.4.1
11
+ - @khanacademy/wonder-blocks-modal@5.1.12
12
+ - @khanacademy/wonder-blocks-tokens@2.0.1
13
+ - @khanacademy/wonder-blocks-tooltip@2.4.3
14
+ - @khanacademy/wonder-blocks-typography@2.1.16
15
+
3
16
  ## 3.2.15
4
17
 
5
18
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-popover",
3
- "version": "3.2.15",
3
+ "version": "3.2.16",
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.0",
20
- "@khanacademy/wonder-blocks-icon-button": "^5.4.0",
21
- "@khanacademy/wonder-blocks-modal": "^5.1.11",
22
- "@khanacademy/wonder-blocks-tokens": "^2.0.0",
23
- "@khanacademy/wonder-blocks-tooltip": "^2.4.2",
24
- "@khanacademy/wonder-blocks-typography": "^2.1.15"
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.4.3",
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
- });
@@ -1,98 +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 {View} from "@khanacademy/wonder-blocks-core";
6
- import PopoverEventListener from "../popover-event-listener";
7
- import PopoverContent from "../popover-content";
8
-
9
- describe("PopoverKeypressListener", () => {
10
- // TODO(FEI-5533): Key press events aren't working correctly with
11
- // user-event v14. We need to investigate and fix this.
12
- it.skip("should call onClose if Escape is pressed", async () => {
13
- // Arrange
14
- const onCloseMock = jest.fn();
15
-
16
- render(<PopoverEventListener onClose={onCloseMock} />);
17
-
18
- // Act
19
- await userEvent.keyboard("{esc}");
20
-
21
- // Assert
22
- expect(onCloseMock).toHaveBeenCalled();
23
- });
24
-
25
- it("should call onClose if clicked outside content ref", async () => {
26
- // Arrange
27
- const onCloseMock = jest.fn();
28
- const contentRef: React.RefObject<PopoverContent> = React.createRef();
29
-
30
- render(
31
- <View>
32
- <PopoverContent
33
- ref={contentRef}
34
- title="Title"
35
- content="Content"
36
- />
37
- <PopoverEventListener
38
- onClose={onCloseMock}
39
- contentRef={contentRef}
40
- />
41
- </View>,
42
- );
43
-
44
- // Act
45
- const event = new MouseEvent("click", {view: window, bubbles: true});
46
- const node = document.body;
47
- if (node) {
48
- // First click is ignored by PopoverEventListener
49
- // because it is triggered when opening the popover.
50
- node.dispatchEvent(event);
51
- node.dispatchEvent(event);
52
- } else {
53
- // Signal that body was never found
54
- expect(node).not.toBe(null);
55
- }
56
-
57
- // Assert
58
- expect(onCloseMock).toHaveBeenCalled();
59
- });
60
-
61
- it("should not call onClose if clicked inside content ref", async () => {
62
- // Arrange
63
- const onCloseMock = jest.fn();
64
- const contentRef: React.RefObject<PopoverContent> = React.createRef();
65
-
66
- render(
67
- <View>
68
- <PopoverContent
69
- ref={contentRef}
70
- title="Title"
71
- content="Content"
72
- testId="popover-content"
73
- />
74
- <PopoverEventListener
75
- onClose={onCloseMock}
76
- contentRef={contentRef}
77
- />
78
- </View>,
79
- );
80
-
81
- // Act
82
- const event = new MouseEvent("click", {view: window, bubbles: true});
83
- const node = await screen.findByTestId("popover-content");
84
-
85
- if (node) {
86
- // First click is ignored by PopoverEventListener
87
- // because it is triggered when opening the popover.
88
- node.dispatchEvent(event);
89
- node.dispatchEvent(event);
90
- } else {
91
- // Signal that PopoverContent was never found
92
- expect(node).not.toBe(null);
93
- }
94
-
95
- // Assert
96
- expect(onCloseMock).not.toHaveBeenCalled();
97
- });
98
- });