@khanacademy/wonder-blocks-link 3.8.13 → 3.8.15

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,22 @@
1
1
  # @khanacademy/wonder-blocks-link
2
2
 
3
+ ## 3.8.15
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [b561425a]
8
+ - Updated dependencies [a566e232]
9
+ - Updated dependencies [d2b21a6e]
10
+ - @khanacademy/wonder-blocks-core@4.6.0
11
+ - @khanacademy/wonder-blocks-clickable@2.4.2
12
+
13
+ ## 3.8.14
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [4c682709]
18
+ - @khanacademy/wonder-blocks-clickable@2.4.1
19
+
3
20
  ## 3.8.13
4
21
 
5
22
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-link",
3
- "version": "3.8.13",
3
+ "version": "3.8.15",
4
4
  "design": "v1",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -16,9 +16,9 @@
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
18
  "@babel/runtime": "^7.18.6",
19
- "@khanacademy/wonder-blocks-clickable": "^2.4.0",
19
+ "@khanacademy/wonder-blocks-clickable": "^2.4.2",
20
20
  "@khanacademy/wonder-blocks-color": "^1.2.0",
21
- "@khanacademy/wonder-blocks-core": "^4.5.0"
21
+ "@khanacademy/wonder-blocks-core": "^4.6.0"
22
22
  },
23
23
  "peerDependencies": {
24
24
  "aphrodite": "^1.2.5",
@@ -27,6 +27,6 @@
27
27
  "react-router-dom": "5.3.0"
28
28
  },
29
29
  "devDependencies": {
30
- "wb-dev-build-settings": "^0.4.0"
30
+ "wb-dev-build-settings": "^0.5.0"
31
31
  }
32
32
  }
@@ -6,7 +6,6 @@ exports[`Link <Link tabIndex={-1}> 1`] = `
6
6
  href="#"
7
7
  onBlur={[Function]}
8
8
  onClick={[Function]}
9
- onDragStart={[Function]}
10
9
  onFocus={[Function]}
11
10
  onKeyDown={[Function]}
12
11
  onKeyUp={[Function]}
@@ -37,7 +36,6 @@ exports[`Link <Link tabIndex={0}> 1`] = `
37
36
  href="#"
38
37
  onBlur={[Function]}
39
38
  onClick={[Function]}
40
- onDragStart={[Function]}
41
39
  onFocus={[Function]}
42
40
  onKeyDown={[Function]}
43
41
  onKeyUp={[Function]}
@@ -68,7 +66,6 @@ exports[`Link <Link tabIndex={1}> 1`] = `
68
66
  href="#"
69
67
  onBlur={[Function]}
70
68
  onClick={[Function]}
71
- onDragStart={[Function]}
72
69
  onFocus={[Function]}
73
70
  onKeyDown={[Function]}
74
71
  onKeyUp={[Function]}
@@ -99,7 +96,6 @@ exports[`LinkCore kind:primary href:# light:false visitable:false focused 1`] =
99
96
  href="#"
100
97
  onBlur={[Function]}
101
98
  onClick={[Function]}
102
- onDragStart={[Function]}
103
99
  onFocus={[Function]}
104
100
  onKeyDown={[Function]}
105
101
  onKeyUp={[Function]}
@@ -130,7 +126,6 @@ exports[`LinkCore kind:primary href:# light:false visitable:false hovered 1`] =
130
126
  href="#"
131
127
  onBlur={[Function]}
132
128
  onClick={[Function]}
133
- onDragStart={[Function]}
134
129
  onFocus={[Function]}
135
130
  onKeyDown={[Function]}
136
131
  onKeyUp={[Function]}
@@ -161,7 +156,6 @@ exports[`LinkCore kind:primary href:# light:false visitable:false pressed 1`] =
161
156
  href="#"
162
157
  onBlur={[Function]}
163
158
  onClick={[Function]}
164
- onDragStart={[Function]}
165
159
  onFocus={[Function]}
166
160
  onKeyDown={[Function]}
167
161
  onKeyUp={[Function]}
@@ -192,7 +186,6 @@ exports[`LinkCore kind:primary href:# light:false visitable:true focused 1`] = `
192
186
  href="#"
193
187
  onBlur={[Function]}
194
188
  onClick={[Function]}
195
- onDragStart={[Function]}
196
189
  onFocus={[Function]}
197
190
  onKeyDown={[Function]}
198
191
  onKeyUp={[Function]}
@@ -226,7 +219,6 @@ exports[`LinkCore kind:primary href:# light:false visitable:true hovered 1`] = `
226
219
  href="#"
227
220
  onBlur={[Function]}
228
221
  onClick={[Function]}
229
- onDragStart={[Function]}
230
222
  onFocus={[Function]}
231
223
  onKeyDown={[Function]}
232
224
  onKeyUp={[Function]}
@@ -260,7 +252,6 @@ exports[`LinkCore kind:primary href:# light:false visitable:true pressed 1`] = `
260
252
  href="#"
261
253
  onBlur={[Function]}
262
254
  onClick={[Function]}
263
- onDragStart={[Function]}
264
255
  onFocus={[Function]}
265
256
  onKeyDown={[Function]}
266
257
  onKeyUp={[Function]}
@@ -294,7 +285,6 @@ exports[`LinkCore kind:primary href:# light:true visitable:false focused 1`] = `
294
285
  href="#"
295
286
  onBlur={[Function]}
296
287
  onClick={[Function]}
297
- onDragStart={[Function]}
298
288
  onFocus={[Function]}
299
289
  onKeyDown={[Function]}
300
290
  onKeyUp={[Function]}
@@ -325,7 +315,6 @@ exports[`LinkCore kind:primary href:# light:true visitable:false hovered 1`] = `
325
315
  href="#"
326
316
  onBlur={[Function]}
327
317
  onClick={[Function]}
328
- onDragStart={[Function]}
329
318
  onFocus={[Function]}
330
319
  onKeyDown={[Function]}
331
320
  onKeyUp={[Function]}
@@ -356,7 +345,6 @@ exports[`LinkCore kind:primary href:# light:true visitable:false pressed 1`] = `
356
345
  href="#"
357
346
  onBlur={[Function]}
358
347
  onClick={[Function]}
359
- onDragStart={[Function]}
360
348
  onFocus={[Function]}
361
349
  onKeyDown={[Function]}
362
350
  onKeyUp={[Function]}
@@ -387,7 +375,6 @@ exports[`LinkCore kind:primary href:#non-existent-link light:false visitable:fal
387
375
  href="#"
388
376
  onBlur={[Function]}
389
377
  onClick={[Function]}
390
- onDragStart={[Function]}
391
378
  onFocus={[Function]}
392
379
  onKeyDown={[Function]}
393
380
  onKeyUp={[Function]}
@@ -418,7 +405,6 @@ exports[`LinkCore kind:primary href:#non-existent-link light:false visitable:fal
418
405
  href="#"
419
406
  onBlur={[Function]}
420
407
  onClick={[Function]}
421
- onDragStart={[Function]}
422
408
  onFocus={[Function]}
423
409
  onKeyDown={[Function]}
424
410
  onKeyUp={[Function]}
@@ -449,7 +435,6 @@ exports[`LinkCore kind:primary href:#non-existent-link light:false visitable:fal
449
435
  href="#"
450
436
  onBlur={[Function]}
451
437
  onClick={[Function]}
452
- onDragStart={[Function]}
453
438
  onFocus={[Function]}
454
439
  onKeyDown={[Function]}
455
440
  onKeyUp={[Function]}
@@ -480,7 +465,6 @@ exports[`LinkCore kind:primary href:#non-existent-link light:false visitable:tru
480
465
  href="#"
481
466
  onBlur={[Function]}
482
467
  onClick={[Function]}
483
- onDragStart={[Function]}
484
468
  onFocus={[Function]}
485
469
  onKeyDown={[Function]}
486
470
  onKeyUp={[Function]}
@@ -514,7 +498,6 @@ exports[`LinkCore kind:primary href:#non-existent-link light:false visitable:tru
514
498
  href="#"
515
499
  onBlur={[Function]}
516
500
  onClick={[Function]}
517
- onDragStart={[Function]}
518
501
  onFocus={[Function]}
519
502
  onKeyDown={[Function]}
520
503
  onKeyUp={[Function]}
@@ -548,7 +531,6 @@ exports[`LinkCore kind:primary href:#non-existent-link light:false visitable:tru
548
531
  href="#"
549
532
  onBlur={[Function]}
550
533
  onClick={[Function]}
551
- onDragStart={[Function]}
552
534
  onFocus={[Function]}
553
535
  onKeyDown={[Function]}
554
536
  onKeyUp={[Function]}
@@ -582,7 +564,6 @@ exports[`LinkCore kind:primary href:#non-existent-link light:true visitable:fals
582
564
  href="#"
583
565
  onBlur={[Function]}
584
566
  onClick={[Function]}
585
- onDragStart={[Function]}
586
567
  onFocus={[Function]}
587
568
  onKeyDown={[Function]}
588
569
  onKeyUp={[Function]}
@@ -613,7 +594,6 @@ exports[`LinkCore kind:primary href:#non-existent-link light:true visitable:fals
613
594
  href="#"
614
595
  onBlur={[Function]}
615
596
  onClick={[Function]}
616
- onDragStart={[Function]}
617
597
  onFocus={[Function]}
618
598
  onKeyDown={[Function]}
619
599
  onKeyUp={[Function]}
@@ -644,7 +624,6 @@ exports[`LinkCore kind:primary href:#non-existent-link light:true visitable:fals
644
624
  href="#"
645
625
  onBlur={[Function]}
646
626
  onClick={[Function]}
647
- onDragStart={[Function]}
648
627
  onFocus={[Function]}
649
628
  onKeyDown={[Function]}
650
629
  onKeyUp={[Function]}
@@ -675,7 +654,6 @@ exports[`LinkCore kind:secondary href:# light:false visitable:false focused 1`]
675
654
  href="#"
676
655
  onBlur={[Function]}
677
656
  onClick={[Function]}
678
- onDragStart={[Function]}
679
657
  onFocus={[Function]}
680
658
  onKeyDown={[Function]}
681
659
  onKeyUp={[Function]}
@@ -706,7 +684,6 @@ exports[`LinkCore kind:secondary href:# light:false visitable:false hovered 1`]
706
684
  href="#"
707
685
  onBlur={[Function]}
708
686
  onClick={[Function]}
709
- onDragStart={[Function]}
710
687
  onFocus={[Function]}
711
688
  onKeyDown={[Function]}
712
689
  onKeyUp={[Function]}
@@ -737,7 +714,6 @@ exports[`LinkCore kind:secondary href:# light:false visitable:false pressed 1`]
737
714
  href="#"
738
715
  onBlur={[Function]}
739
716
  onClick={[Function]}
740
- onDragStart={[Function]}
741
717
  onFocus={[Function]}
742
718
  onKeyDown={[Function]}
743
719
  onKeyUp={[Function]}
@@ -768,7 +744,6 @@ exports[`LinkCore kind:secondary href:#non-existent-link light:false visitable:f
768
744
  href="#"
769
745
  onBlur={[Function]}
770
746
  onClick={[Function]}
771
- onDragStart={[Function]}
772
747
  onFocus={[Function]}
773
748
  onKeyDown={[Function]}
774
749
  onKeyUp={[Function]}
@@ -799,7 +774,6 @@ exports[`LinkCore kind:secondary href:#non-existent-link light:false visitable:f
799
774
  href="#"
800
775
  onBlur={[Function]}
801
776
  onClick={[Function]}
802
- onDragStart={[Function]}
803
777
  onFocus={[Function]}
804
778
  onKeyDown={[Function]}
805
779
  onKeyUp={[Function]}
@@ -830,7 +804,6 @@ exports[`LinkCore kind:secondary href:#non-existent-link light:false visitable:f
830
804
  href="#"
831
805
  onBlur={[Function]}
832
806
  onClick={[Function]}
833
- onDragStart={[Function]}
834
807
  onFocus={[Function]}
835
808
  onKeyDown={[Function]}
836
809
  onKeyUp={[Function]}
@@ -11,7 +11,6 @@ const defaultHandlers = {
11
11
  onMouseLeave: () => void 0,
12
12
  onMouseDown: () => void 0,
13
13
  onMouseUp: () => void 0,
14
- onDragStart: () => void 0,
15
14
  onTouchStart: () => void 0,
16
15
  onTouchEnd: () => void 0,
17
16
  onTouchCancel: () => void 0,
@@ -1,17 +1,11 @@
1
1
  // @flow
2
2
  import * as React from "react";
3
3
  import {MemoryRouter, Route, Switch} from "react-router-dom";
4
- import {mount} from "enzyme";
5
- import "jest-enzyme";
4
+ import {fireEvent, render, screen, waitFor} from "@testing-library/react";
5
+ import userEvent from "@testing-library/user-event";
6
6
 
7
7
  import Link from "../link.js";
8
8
 
9
- const wait = (delay: number = 0) =>
10
- new Promise((resolve, reject) => {
11
- // eslint-disable-next-line no-restricted-syntax
12
- return setTimeout(resolve, delay);
13
- });
14
-
15
9
  describe("Link", () => {
16
10
  beforeEach(() => {
17
11
  // Note: window.location.assign needs a mock function in the testing
@@ -22,12 +16,13 @@ describe("Link", () => {
22
16
 
23
17
  afterEach(() => {
24
18
  window.location.assign.mockClear();
19
+ jest.clearAllMocks();
25
20
  });
26
21
 
27
22
  describe("client-side navigation", () => {
28
23
  test("works for known URLs", () => {
29
24
  // Arrange
30
- const wrapper = mount(
25
+ render(
31
26
  <MemoryRouter>
32
27
  <div>
33
28
  <Link href="/foo">Click me!</Link>
@@ -41,16 +36,16 @@ describe("Link", () => {
41
36
  );
42
37
 
43
38
  // Act
44
- const linkWrapper = wrapper.find("Link").first();
45
- linkWrapper.simulate("click", {button: 0});
39
+ const link = screen.getByText("Click me!");
40
+ userEvent.click(link);
46
41
 
47
42
  // Assert
48
- expect(wrapper.find("#foo").exists()).toBe(true);
43
+ expect(screen.getByText("Hello, world!")).toBeInTheDocument();
49
44
  });
50
45
 
51
46
  test("navigation to without route does not render", () => {
52
47
  // Arrange
53
- const wrapper = mount(
48
+ render(
54
49
  <MemoryRouter>
55
50
  <div>
56
51
  <Link href="/unknown">Click me!</Link>
@@ -64,16 +59,16 @@ describe("Link", () => {
64
59
  );
65
60
 
66
61
  // Act
67
- const linkWrapper = wrapper.find("Link").first();
68
- linkWrapper.simulate("click", {button: 0});
62
+ const link = screen.getByText("Click me!");
63
+ userEvent.click(link);
69
64
 
70
65
  // Assert
71
- expect(wrapper.find("#foo").exists()).toBe(false);
66
+ expect(screen.queryByText("Hello, world!")).not.toBeInTheDocument();
72
67
  });
73
68
 
74
- test("waits until beforeNav resolves before navigating", async () => {
69
+ test("waits until beforeNav resolves before navigating", () => {
75
70
  // Arrange
76
- const wrapper = mount(
71
+ render(
77
72
  <MemoryRouter>
78
73
  <div>
79
74
  <Link href="/foo" beforeNav={() => Promise.resolve()}>
@@ -89,20 +84,16 @@ describe("Link", () => {
89
84
  );
90
85
 
91
86
  // Act
92
- const linkWrapper = wrapper.find("Link").first();
93
- linkWrapper.simulate("click", {
94
- button: 0,
95
- });
96
- await wait(0);
97
- wrapper.update();
87
+ const link = screen.getByText("Click me!");
88
+ userEvent.click(link);
98
89
 
99
90
  // Assert
100
- expect(wrapper.find("#foo")).toExist();
91
+ expect(screen.queryByText("Hello, world!")).not.toBeInTheDocument();
101
92
  });
102
93
 
103
- test("doesn't navigate before beforeNav resolves", async () => {
94
+ test("doesn't navigate before beforeNav resolves", () => {
104
95
  // Arrange
105
- const wrapper = mount(
96
+ render(
106
97
  <MemoryRouter>
107
98
  <div>
108
99
  <Link href="/foo" beforeNav={() => Promise.resolve()}>
@@ -118,18 +109,16 @@ describe("Link", () => {
118
109
  );
119
110
 
120
111
  // Act
121
- const linkWrapper = wrapper.find("Link").first();
122
- linkWrapper.simulate("click", {
123
- button: 0,
124
- });
112
+ const link = screen.getByText("Click me!");
113
+ userEvent.click(link);
125
114
 
126
115
  // Assert
127
- expect(wrapper.find("#foo")).not.toExist();
116
+ expect(screen.queryByText("Hello, world!")).not.toBeInTheDocument();
128
117
  });
129
118
 
130
- test("does not navigate if beforeNav rejects", async () => {
119
+ test("does not navigate if beforeNav rejects", () => {
131
120
  // Arrange
132
- const wrapper = mount(
121
+ render(
133
122
  <MemoryRouter>
134
123
  <div>
135
124
  <Link href="/foo" beforeNav={() => Promise.reject()}>
@@ -145,21 +134,17 @@ describe("Link", () => {
145
134
  );
146
135
 
147
136
  // Act
148
- const linkWrapper = wrapper.find("Link").first();
149
- linkWrapper.simulate("click", {
150
- button: 0,
151
- });
152
- await wait(0);
153
- wrapper.update();
137
+ const link = screen.getByText("Click me!");
138
+ userEvent.click(link);
154
139
 
155
140
  // Assert
156
- expect(wrapper.find("#foo")).not.toExist();
141
+ expect(screen.queryByText("Hello, world!")).not.toBeInTheDocument();
157
142
  });
158
143
 
159
144
  test("runs safeWithNav if set", async () => {
160
145
  // Arrange
161
146
  const safeWithNavMock = jest.fn();
162
- const wrapper = mount(
147
+ render(
163
148
  <MemoryRouter>
164
149
  <div>
165
150
  <Link
@@ -179,21 +164,19 @@ describe("Link", () => {
179
164
  );
180
165
 
181
166
  // Act
182
- const linkWrapper = wrapper.find("Link").first();
183
- linkWrapper.simulate("click", {
184
- button: 0,
185
- });
186
- await wait(0);
187
- wrapper.update();
167
+ const link = screen.getByText("Click me!");
168
+ userEvent.click(link);
188
169
 
189
170
  // Assert
190
- expect(safeWithNavMock).toHaveBeenCalled();
171
+ await waitFor(() => {
172
+ expect(safeWithNavMock).toHaveBeenCalled();
173
+ });
191
174
  });
192
175
 
193
176
  test("doesn't run safeWithNav until beforeNav resolves", () => {
194
177
  // Arrange
195
178
  const safeWithNavMock = jest.fn();
196
- const wrapper = mount(
179
+ render(
197
180
  <MemoryRouter>
198
181
  <div>
199
182
  <Link
@@ -213,10 +196,8 @@ describe("Link", () => {
213
196
  );
214
197
 
215
198
  // Act
216
- const linkWrapper = wrapper.find("Link").first();
217
- linkWrapper.simulate("click", {
218
- button: 0,
219
- });
199
+ const link = screen.getByText("Click me!");
200
+ userEvent.click(link);
220
201
 
221
202
  // Assert
222
203
  expect(safeWithNavMock).not.toHaveBeenCalled();
@@ -227,7 +208,7 @@ describe("Link", () => {
227
208
  test("doesn't redirect if safeWithNav hasn't resolved yet when skipClientNav=true", () => {
228
209
  // Arrange
229
210
  jest.spyOn(window.location, "assign").mockImplementation(() => {});
230
- const wrapper = mount(
211
+ render(
231
212
  <Link
232
213
  href="/foo"
233
214
  safeWithNav={() => Promise.resolve()}
@@ -238,10 +219,8 @@ describe("Link", () => {
238
219
  );
239
220
 
240
221
  // Act
241
- const linkWrapper = wrapper.find("Link").first();
242
- linkWrapper.simulate("click", {
243
- button: 0,
244
- });
222
+ const link = screen.getByText("Click me!");
223
+ userEvent.click(link);
245
224
 
246
225
  // Assert
247
226
  expect(window.location.assign).not.toHaveBeenCalled();
@@ -250,7 +229,7 @@ describe("Link", () => {
250
229
  test("redirects after safeWithNav resolves when skipClientNav=true", async () => {
251
230
  // Arrange
252
231
  jest.spyOn(window.location, "assign").mockImplementation(() => {});
253
- const wrapper = mount(
232
+ render(
254
233
  <Link
255
234
  href="/foo"
256
235
  safeWithNav={() => Promise.resolve()}
@@ -261,21 +240,19 @@ describe("Link", () => {
261
240
  );
262
241
 
263
242
  // Act
264
- const linkWrapper = wrapper.find("Link").first();
265
- linkWrapper.simulate("click", {
266
- button: 0,
267
- });
268
- await wait(0);
269
- wrapper.update();
243
+ const link = screen.getByText("Click me!");
244
+ userEvent.click(link);
270
245
 
271
246
  // Assert
272
- expect(window.location.assign).toHaveBeenCalledWith("/foo");
247
+ await waitFor(() => {
248
+ expect(window.location.assign).toHaveBeenCalledWith("/foo");
249
+ });
273
250
  });
274
251
 
275
252
  test("redirects after beforeNav and safeWithNav resolve when skipClientNav=true", async () => {
276
253
  // Arrange
277
254
  jest.spyOn(window.location, "assign").mockImplementation(() => {});
278
- const wrapper = mount(
255
+ render(
279
256
  <Link
280
257
  href="/foo"
281
258
  beforeNav={() => Promise.resolve()}
@@ -287,21 +264,19 @@ describe("Link", () => {
287
264
  );
288
265
 
289
266
  // Act
290
- const linkWrapper = wrapper.find("Link").first();
291
- linkWrapper.simulate("click", {
292
- button: 0,
293
- });
294
- await wait(0);
295
- wrapper.update();
267
+ const link = screen.getByText("Click me!");
268
+ userEvent.click(link);
296
269
 
297
270
  // Assert
298
- expect(window.location.assign).toHaveBeenCalledWith("/foo");
271
+ await waitFor(() => {
272
+ expect(window.location.assign).toHaveBeenCalledWith("/foo");
273
+ });
299
274
  });
300
275
 
301
276
  test("doesn't redirect before beforeNav resolves when skipClientNav=true", () => {
302
277
  // Arrange
303
278
  jest.spyOn(window.location, "assign").mockImplementation(() => {});
304
- const wrapper = mount(
279
+ render(
305
280
  <Link
306
281
  href="/foo"
307
282
  beforeNav={() => Promise.resolve()}
@@ -312,10 +287,8 @@ describe("Link", () => {
312
287
  );
313
288
 
314
289
  // Act
315
- const linkWrapper = wrapper.find("Link").first();
316
- linkWrapper.simulate("click", {
317
- button: 0,
318
- });
290
+ const link = screen.getByText("Click me!");
291
+ userEvent.click(link);
319
292
 
320
293
  // Assert
321
294
  expect(window.location.assign).not.toHaveBeenCalled();
@@ -325,38 +298,38 @@ describe("Link", () => {
325
298
  describe("raw events", () => {
326
299
  test("onKeyDown", () => {
327
300
  // Arrange
328
- const keyMock = jest.fn();
329
- const wrapper = mount(
330
- <Link href="/" onKeyDown={keyMock}>
301
+ let keyCode;
302
+ render(
303
+ <Link href="/" onKeyDown={(e) => (keyCode = e.keyCode)}>
331
304
  Click me!
332
305
  </Link>,
333
306
  );
334
307
 
335
308
  // Act
336
- wrapper.find(Link).simulate("keydown", {keyCode: 32});
309
+ const link = screen.getByText("Click me!");
310
+ // eslint-disable-next-line testing-library/prefer-user-event
311
+ fireEvent.keyDown(link, {keyCode: 32});
337
312
 
338
313
  // Assert
339
- expect(keyMock).toHaveBeenCalledWith(
340
- expect.objectContaining({keyCode: 32}),
341
- );
314
+ expect(keyCode).toEqual(32);
342
315
  });
343
316
 
344
317
  test("onKeyUp", () => {
345
318
  // Arrange
346
- const keyMock = jest.fn();
347
- const wrapper = mount(
348
- <Link href="/" onKeyDown={keyMock}>
319
+ let keyCode;
320
+ render(
321
+ <Link href="/" onKeyUp={(e) => (keyCode = e.keyCode)}>
349
322
  Click me!
350
323
  </Link>,
351
324
  );
352
325
 
353
326
  // Act
354
- wrapper.find(Link).simulate("keydown", {keyCode: 32});
327
+ const link = screen.getByText("Click me!");
328
+ // eslint-disable-next-line testing-library/prefer-user-event
329
+ fireEvent.keyUp(link, {keyCode: 32});
355
330
 
356
331
  // Assert
357
- expect(keyMock).toHaveBeenCalledWith(
358
- expect.objectContaining({keyCode: 32}),
359
- );
332
+ expect(keyCode).toEqual(32);
360
333
  });
361
334
  });
362
335
  });
package/dist/index.js DELETED
@@ -1,409 +0,0 @@
1
- module.exports =
2
- /******/ (function(modules) { // webpackBootstrap
3
- /******/ // The module cache
4
- /******/ var installedModules = {};
5
- /******/
6
- /******/ // The require function
7
- /******/ function __webpack_require__(moduleId) {
8
- /******/
9
- /******/ // Check if module is in cache
10
- /******/ if(installedModules[moduleId]) {
11
- /******/ return installedModules[moduleId].exports;
12
- /******/ }
13
- /******/ // Create a new module (and put it into the cache)
14
- /******/ var module = installedModules[moduleId] = {
15
- /******/ i: moduleId,
16
- /******/ l: false,
17
- /******/ exports: {}
18
- /******/ };
19
- /******/
20
- /******/ // Execute the module function
21
- /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
22
- /******/
23
- /******/ // Flag the module as loaded
24
- /******/ module.l = true;
25
- /******/
26
- /******/ // Return the exports of the module
27
- /******/ return module.exports;
28
- /******/ }
29
- /******/
30
- /******/
31
- /******/ // expose the modules object (__webpack_modules__)
32
- /******/ __webpack_require__.m = modules;
33
- /******/
34
- /******/ // expose the module cache
35
- /******/ __webpack_require__.c = installedModules;
36
- /******/
37
- /******/ // define getter function for harmony exports
38
- /******/ __webpack_require__.d = function(exports, name, getter) {
39
- /******/ if(!__webpack_require__.o(exports, name)) {
40
- /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
41
- /******/ }
42
- /******/ };
43
- /******/
44
- /******/ // define __esModule on exports
45
- /******/ __webpack_require__.r = function(exports) {
46
- /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
47
- /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
48
- /******/ }
49
- /******/ Object.defineProperty(exports, '__esModule', { value: true });
50
- /******/ };
51
- /******/
52
- /******/ // create a fake namespace object
53
- /******/ // mode & 1: value is a module id, require it
54
- /******/ // mode & 2: merge all properties of value into the ns
55
- /******/ // mode & 4: return value when already ns object
56
- /******/ // mode & 8|1: behave like require
57
- /******/ __webpack_require__.t = function(value, mode) {
58
- /******/ if(mode & 1) value = __webpack_require__(value);
59
- /******/ if(mode & 8) return value;
60
- /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
61
- /******/ var ns = Object.create(null);
62
- /******/ __webpack_require__.r(ns);
63
- /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
64
- /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
65
- /******/ return ns;
66
- /******/ };
67
- /******/
68
- /******/ // getDefaultExport function for compatibility with non-harmony modules
69
- /******/ __webpack_require__.n = function(module) {
70
- /******/ var getter = module && module.__esModule ?
71
- /******/ function getDefault() { return module['default']; } :
72
- /******/ function getModuleExports() { return module; };
73
- /******/ __webpack_require__.d(getter, 'a', getter);
74
- /******/ return getter;
75
- /******/ };
76
- /******/
77
- /******/ // Object.prototype.hasOwnProperty.call
78
- /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
79
- /******/
80
- /******/ // __webpack_public_path__
81
- /******/ __webpack_require__.p = "";
82
- /******/
83
- /******/
84
- /******/ // Load entry module and return exports
85
- /******/ return __webpack_require__(__webpack_require__.s = 10);
86
- /******/ })
87
- /************************************************************************/
88
- /******/ ([
89
- /* 0 */
90
- /***/ (function(module, exports) {
91
-
92
- module.exports = require("react");
93
-
94
- /***/ }),
95
- /* 1 */
96
- /***/ (function(module, exports) {
97
-
98
- module.exports = require("@khanacademy/wonder-blocks-color");
99
-
100
- /***/ }),
101
- /* 2 */
102
- /***/ (function(module, exports) {
103
-
104
- function _extends() {
105
- module.exports = _extends = Object.assign ? Object.assign.bind() : function (target) {
106
- for (var i = 1; i < arguments.length; i++) {
107
- var source = arguments[i];
108
-
109
- for (var key in source) {
110
- if (Object.prototype.hasOwnProperty.call(source, key)) {
111
- target[key] = source[key];
112
- }
113
- }
114
- }
115
-
116
- return target;
117
- }, module.exports.__esModule = true, module.exports["default"] = module.exports;
118
- return _extends.apply(this, arguments);
119
- }
120
-
121
- module.exports = _extends, module.exports.__esModule = true, module.exports["default"] = module.exports;
122
-
123
- /***/ }),
124
- /* 3 */
125
- /***/ (function(module, exports) {
126
-
127
- module.exports = require("react-router");
128
-
129
- /***/ }),
130
- /* 4 */
131
- /***/ (function(module, exports) {
132
-
133
- module.exports = require("@khanacademy/wonder-blocks-clickable");
134
-
135
- /***/ }),
136
- /* 5 */
137
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
138
-
139
- "use strict";
140
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return LinkCore; });
141
- /* harmony import */ var _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
142
- /* harmony import */ var _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0__);
143
- /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
144
- /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
145
- /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
146
- /* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_2__);
147
- /* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
148
- /* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(react_router_dom__WEBPACK_IMPORTED_MODULE_3__);
149
- /* harmony import */ var react_router__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(3);
150
- /* harmony import */ var react_router__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(react_router__WEBPACK_IMPORTED_MODULE_4__);
151
- /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(7);
152
- /* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_5__);
153
- /* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(1);
154
- /* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_6__);
155
- /* harmony import */ var _khanacademy_wonder_blocks_clickable__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(4);
156
- /* harmony import */ var _khanacademy_wonder_blocks_clickable__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_clickable__WEBPACK_IMPORTED_MODULE_7__);
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
- const StyledAnchor = Object(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_5__["addStyle"])("a");
166
- const StyledLink = Object(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_5__["addStyle"])(react_router_dom__WEBPACK_IMPORTED_MODULE_3__["Link"]);
167
- class LinkCore extends react__WEBPACK_IMPORTED_MODULE_1__["Component"] {
168
- renderInner(router) {
169
- const {
170
- children,
171
- skipClientNav,
172
- focused,
173
- hovered,
174
- href,
175
- kind,
176
- light,
177
- visitable,
178
- pressed,
179
- style,
180
- testId,
181
- waiting: _,
182
- ...restProps
183
- } = this.props;
184
-
185
- const linkStyles = _generateStyles(kind, light, visitable);
186
-
187
- const defaultStyles = [sharedStyles.shared, !(hovered || focused || pressed) && linkStyles.default, pressed ? linkStyles.active : (hovered || focused) && linkStyles.focus];
188
- const commonProps = {
189
- "data-test-id": testId,
190
- style: [defaultStyles, style],
191
- ...restProps
192
- };
193
- return router && !skipClientNav && Object(_khanacademy_wonder_blocks_clickable__WEBPACK_IMPORTED_MODULE_7__["isClientSideUrl"])(href) ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](StyledLink, _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0___default()({}, commonProps, {
194
- to: href
195
- }), children) : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](StyledAnchor, _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0___default()({}, commonProps, {
196
- href: href
197
- }), children);
198
- }
199
-
200
- render() {
201
- return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](react_router__WEBPACK_IMPORTED_MODULE_4__["__RouterContext"].Consumer, null, router => this.renderInner(router));
202
- }
203
-
204
- }
205
- const styles = {};
206
- const sharedStyles = aphrodite__WEBPACK_IMPORTED_MODULE_2__["StyleSheet"].create({
207
- shared: {
208
- cursor: "pointer",
209
- textDecoration: "none",
210
- outline: "none"
211
- }
212
- });
213
-
214
- const _generateStyles = (kind, light, visitable) => {
215
- const buttonType = kind + light.toString() + visitable.toString();
216
-
217
- if (styles[buttonType]) {
218
- return styles[buttonType];
219
- }
220
-
221
- if (kind === "secondary" && light) {
222
- throw new Error("Secondary Light links are not supported");
223
- }
224
-
225
- if (visitable && (kind !== "primary" || kind === "primary" && light)) {
226
- throw new Error("Only primary (not light) link is visitable");
227
- }
228
-
229
- const {
230
- blue,
231
- purple,
232
- white,
233
- offBlack,
234
- offBlack32
235
- } = _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_6___default.a;
236
- const linkPurple = Object(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_6__["mix"])(Object(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_6__["fade"])(offBlack, 0.08), purple);
237
- const defaultTextColor = kind === "primary" ? light ? white : blue : offBlack;
238
- const focusColor = light ? white : blue;
239
- const activeColor = light ? Object(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_6__["mix"])(Object(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_6__["fade"])(blue, 0.32), white) : Object(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_6__["mix"])(offBlack32, blue);
240
- const defaultVisited = visitable ? {
241
- ":visited": {
242
- color: linkPurple
243
- }
244
- } : Object.freeze({});
245
- const activeVisited = visitable ? {
246
- ":visited": {
247
- color: Object(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_6__["mix"])(offBlack32, linkPurple)
248
- }
249
- } : Object.freeze({});
250
- const newStyles = {
251
- default: {
252
- color: defaultTextColor,
253
- ...defaultVisited
254
- },
255
- focus: {
256
- textDecoration: "underline currentcolor solid",
257
- color: focusColor,
258
- ...defaultVisited
259
- },
260
- active: {
261
- color: activeColor,
262
- textDecoration: "underline currentcolor solid",
263
- ...activeVisited
264
- }
265
- };
266
- styles[buttonType] = aphrodite__WEBPACK_IMPORTED_MODULE_2__["StyleSheet"].create(newStyles);
267
- return styles[buttonType];
268
- };
269
-
270
- /***/ }),
271
- /* 6 */
272
- /***/ (function(module, exports) {
273
-
274
- module.exports = require("aphrodite");
275
-
276
- /***/ }),
277
- /* 7 */
278
- /***/ (function(module, exports) {
279
-
280
- module.exports = require("@khanacademy/wonder-blocks-core");
281
-
282
- /***/ }),
283
- /* 8 */
284
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
285
-
286
- "use strict";
287
- /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Link; });
288
- /* harmony import */ var _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
289
- /* harmony import */ var _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0__);
290
- /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
291
- /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
292
- /* harmony import */ var react_router__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
293
- /* harmony import */ var react_router__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(react_router__WEBPACK_IMPORTED_MODULE_2__);
294
- /* harmony import */ var _khanacademy_wonder_blocks_clickable__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
295
- /* harmony import */ var _khanacademy_wonder_blocks_clickable__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_clickable__WEBPACK_IMPORTED_MODULE_3__);
296
- /* harmony import */ var _link_core_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(5);
297
-
298
-
299
-
300
-
301
-
302
-
303
- /**
304
- * Reusable link component.
305
- *
306
- * Consisting of a [`ClickableBehavior`](#clickablebehavior) surrounding a
307
- * `LinkCore`. `ClickableBehavior` handles interactions and state changes.
308
- * `LinkCore` is a stateless component which displays the different states
309
- * the `Link` can take.
310
- *
311
- * ### Usage
312
- *
313
- * ```jsx
314
- * <Link
315
- * href="https://khanacademy.org/"
316
- * >
317
- * Label
318
- * </Link>
319
- * ```
320
- */
321
- class Link extends react__WEBPACK_IMPORTED_MODULE_1__["Component"] {
322
- renderClickableBehavior(router) {
323
- const {
324
- onClick,
325
- beforeNav = undefined,
326
- safeWithNav,
327
- href,
328
- skipClientNav,
329
- children,
330
- tabIndex,
331
- onKeyDown,
332
- onKeyUp,
333
- target = undefined,
334
- ...sharedProps
335
- } = this.props;
336
- const ClickableBehavior = Object(_khanacademy_wonder_blocks_clickable__WEBPACK_IMPORTED_MODULE_3__["getClickableBehavior"])(href, skipClientNav, router);
337
-
338
- if (beforeNav) {
339
- return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](ClickableBehavior, {
340
- disabled: false,
341
- href: href,
342
- role: "link",
343
- onClick: onClick,
344
- beforeNav: beforeNav,
345
- safeWithNav: safeWithNav,
346
- onKeyDown: onKeyDown,
347
- onKeyUp: onKeyUp
348
- }, (state, { ...childrenProps
349
- }) => {
350
- return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_link_core_js__WEBPACK_IMPORTED_MODULE_4__[/* default */ "a"], _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0___default()({}, sharedProps, state, childrenProps, {
351
- skipClientNav: skipClientNav,
352
- href: href,
353
- target: target,
354
- tabIndex: tabIndex
355
- }), children);
356
- });
357
- } else {
358
- return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](ClickableBehavior, {
359
- disabled: false,
360
- href: href,
361
- role: "link",
362
- onClick: onClick,
363
- safeWithNav: safeWithNav,
364
- target: target,
365
- onKeyDown: onKeyDown,
366
- onKeyUp: onKeyUp
367
- }, (state, { ...childrenProps
368
- }) => {
369
- return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_link_core_js__WEBPACK_IMPORTED_MODULE_4__[/* default */ "a"], _babel_runtime_helpers_extends__WEBPACK_IMPORTED_MODULE_0___default()({}, sharedProps, state, childrenProps, {
370
- skipClientNav: skipClientNav,
371
- href: href,
372
- target: target,
373
- tabIndex: tabIndex
374
- }), children);
375
- });
376
- }
377
- }
378
-
379
- render() {
380
- return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](react_router__WEBPACK_IMPORTED_MODULE_2__["__RouterContext"].Consumer, null, router => this.renderClickableBehavior(router));
381
- }
382
-
383
- }
384
- Link.defaultProps = {
385
- kind: "primary",
386
- light: false,
387
- visitable: false
388
- };
389
-
390
- /***/ }),
391
- /* 9 */
392
- /***/ (function(module, exports) {
393
-
394
- module.exports = require("react-router-dom");
395
-
396
- /***/ }),
397
- /* 10 */
398
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
399
-
400
- "use strict";
401
- __webpack_require__.r(__webpack_exports__);
402
- /* harmony import */ var _components_link_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8);
403
- /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "default", function() { return _components_link_js__WEBPACK_IMPORTED_MODULE_0__["a"]; });
404
-
405
-
406
-
407
-
408
- /***/ })
409
- /******/ ]);
@@ -1,2 +0,0 @@
1
- // @flow
2
- export * from "../src/index.js";
package/docs.md DELETED
@@ -1,5 +0,0 @@
1
- Documentation for `@khanacademy/wonder-blocks-link` is now in Storybook.
2
-
3
- Visit the [Storybook
4
- Link](https://khan.github.io/wonder-blocks/?path=/docs/link) docs on GitHub
5
- Pages.