@primer/components 30.3.0-rc.2010c7d4 → 31.0.0-rc.15aa0a10

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.
Files changed (180) hide show
  1. package/.eslintrc.json +2 -1
  2. package/.storybook/preview.js +4 -4
  3. package/CHANGELOG.md +12 -2
  4. package/codemods/deprecateUtilityComponents.js +1 -1
  5. package/contributor-docs/adrs/adr-003-prop-norms.md +72 -0
  6. package/dist/browser.esm.js +798 -794
  7. package/dist/browser.esm.js.map +1 -1
  8. package/dist/browser.umd.js +801 -797
  9. package/dist/browser.umd.js.map +1 -1
  10. package/docs/content/Autocomplete.mdx +627 -0
  11. package/docs/content/TextInputTokens.mdx +89 -0
  12. package/docs/content/getting-started.md +1 -1
  13. package/docs/content/overriding-styles.mdx +7 -6
  14. package/docs/content/theming.md +5 -5
  15. package/docs/package-lock.json +288 -511
  16. package/docs/package.json +1 -1
  17. package/docs/src/@primer/gatsby-theme-doctocat/components/hero.js +14 -12
  18. package/docs/src/@primer/gatsby-theme-doctocat/nav.yml +2 -0
  19. package/docs/src/@primer/gatsby-theme-doctocat/primer-components-hero.svg +7 -7
  20. package/lib/ActionList/Item.js +1 -1
  21. package/lib/AnchoredOverlay/AnchoredOverlay.d.ts +2 -1
  22. package/lib/AnchoredOverlay/AnchoredOverlay.js +11 -3
  23. package/lib/Autocomplete/Autocomplete.d.ts +304 -0
  24. package/lib/Autocomplete/Autocomplete.js +145 -0
  25. package/lib/Autocomplete/AutocompleteContext.d.ts +17 -0
  26. package/lib/Autocomplete/AutocompleteContext.js +11 -0
  27. package/lib/Autocomplete/AutocompleteInput.d.ts +292 -0
  28. package/lib/Autocomplete/AutocompleteInput.js +157 -0
  29. package/lib/Autocomplete/AutocompleteMenu.d.ts +72 -0
  30. package/lib/Autocomplete/AutocompleteMenu.js +224 -0
  31. package/lib/Autocomplete/AutocompleteOverlay.d.ts +20 -0
  32. package/lib/Autocomplete/AutocompleteOverlay.js +80 -0
  33. package/lib/Autocomplete/index.d.ts +2 -0
  34. package/lib/Autocomplete/index.js +15 -0
  35. package/lib/BaseStyles.js +1 -1
  36. package/lib/BorderBox.js +1 -1
  37. package/lib/Button/ButtonInvisible.js +1 -1
  38. package/lib/Caret.js +2 -2
  39. package/lib/Dialog.js +1 -1
  40. package/lib/FilteredActionList/FilteredActionList.js +5 -31
  41. package/lib/Flash.js +16 -16
  42. package/lib/Label.js +1 -1
  43. package/lib/Overlay.d.ts +1 -0
  44. package/lib/Overlay.js +3 -1
  45. package/lib/ProgressBar.js +1 -1
  46. package/lib/StateLabel.js +13 -19
  47. package/lib/Token/_RemoveTokenButton.js +1 -1
  48. package/lib/__tests__/Autocomplete.test.d.ts +1 -0
  49. package/lib/__tests__/Autocomplete.test.js +528 -0
  50. package/lib/__tests__/BorderBox.test.js +1 -1
  51. package/lib/__tests__/CircleOcticon.test.js +1 -1
  52. package/lib/__tests__/CounterLabel.test.js +4 -4
  53. package/lib/__tests__/Flash.test.js +4 -4
  54. package/lib/__tests__/Link.test.js +1 -1
  55. package/lib/__tests__/behaviors/scrollIntoViewingArea.test.d.ts +1 -0
  56. package/lib/__tests__/behaviors/scrollIntoViewingArea.test.js +226 -0
  57. package/lib/behaviors/scrollIntoViewingArea.d.ts +1 -0
  58. package/lib/behaviors/scrollIntoViewingArea.js +39 -0
  59. package/lib/hooks/useOpenAndCloseFocus.d.ts +2 -1
  60. package/lib/hooks/useOpenAndCloseFocus.js +7 -2
  61. package/lib/hooks/useOverlay.d.ts +2 -1
  62. package/lib/hooks/useOverlay.js +4 -2
  63. package/lib/index.d.ts +2 -0
  64. package/lib/index.js +8 -0
  65. package/lib/stories/Autocomplete.stories.js +608 -0
  66. package/lib/stories/Dialog.stories.js +3 -3
  67. package/lib/stories/IssueLabelToken.stories.js +1 -1
  68. package/lib/stories/ProfileToken.stories.js +1 -1
  69. package/lib/theme-preval.js +370 -3100
  70. package/lib/utils/testing.d.ts +50 -493
  71. package/lib/utils/types/MandateProps.d.ts +3 -0
  72. package/lib/utils/types/MandateProps.js +1 -0
  73. package/lib/utils/types/index.d.ts +1 -0
  74. package/lib/utils/types/index.js +13 -0
  75. package/lib-esm/ActionList/Item.js +1 -1
  76. package/lib-esm/AnchoredOverlay/AnchoredOverlay.d.ts +2 -1
  77. package/lib-esm/AnchoredOverlay/AnchoredOverlay.js +11 -3
  78. package/lib-esm/Autocomplete/Autocomplete.d.ts +304 -0
  79. package/lib-esm/Autocomplete/Autocomplete.js +123 -0
  80. package/lib-esm/Autocomplete/AutocompleteContext.d.ts +17 -0
  81. package/lib-esm/Autocomplete/AutocompleteContext.js +2 -0
  82. package/lib-esm/Autocomplete/AutocompleteInput.d.ts +292 -0
  83. package/lib-esm/Autocomplete/AutocompleteInput.js +138 -0
  84. package/lib-esm/Autocomplete/AutocompleteMenu.d.ts +72 -0
  85. package/lib-esm/Autocomplete/AutocompleteMenu.js +205 -0
  86. package/lib-esm/Autocomplete/AutocompleteOverlay.d.ts +20 -0
  87. package/lib-esm/Autocomplete/AutocompleteOverlay.js +62 -0
  88. package/lib-esm/Autocomplete/index.d.ts +2 -0
  89. package/lib-esm/Autocomplete/index.js +1 -0
  90. package/lib-esm/BaseStyles.js +1 -1
  91. package/lib-esm/BorderBox.js +1 -1
  92. package/lib-esm/Button/ButtonInvisible.js +1 -1
  93. package/lib-esm/Caret.js +2 -2
  94. package/lib-esm/Dialog.js +1 -1
  95. package/lib-esm/FilteredActionList/FilteredActionList.js +3 -31
  96. package/lib-esm/Flash.js +16 -16
  97. package/lib-esm/Label.js +1 -1
  98. package/lib-esm/Overlay.d.ts +1 -0
  99. package/lib-esm/Overlay.js +3 -1
  100. package/lib-esm/ProgressBar.js +1 -1
  101. package/lib-esm/StateLabel.js +13 -19
  102. package/lib-esm/Token/_RemoveTokenButton.js +1 -1
  103. package/lib-esm/__tests__/Autocomplete.test.d.ts +1 -0
  104. package/lib-esm/__tests__/Autocomplete.test.js +494 -0
  105. package/lib-esm/__tests__/BorderBox.test.js +1 -1
  106. package/lib-esm/__tests__/CircleOcticon.test.js +1 -1
  107. package/lib-esm/__tests__/CounterLabel.test.js +4 -4
  108. package/lib-esm/__tests__/Flash.test.js +4 -4
  109. package/lib-esm/__tests__/Link.test.js +1 -1
  110. package/lib-esm/__tests__/behaviors/scrollIntoViewingArea.test.d.ts +1 -0
  111. package/lib-esm/__tests__/behaviors/scrollIntoViewingArea.test.js +224 -0
  112. package/lib-esm/behaviors/scrollIntoViewingArea.d.ts +1 -0
  113. package/lib-esm/behaviors/scrollIntoViewingArea.js +30 -0
  114. package/lib-esm/hooks/useOpenAndCloseFocus.d.ts +2 -1
  115. package/lib-esm/hooks/useOpenAndCloseFocus.js +7 -2
  116. package/lib-esm/hooks/useOverlay.d.ts +2 -1
  117. package/lib-esm/hooks/useOverlay.js +4 -2
  118. package/lib-esm/index.d.ts +2 -0
  119. package/lib-esm/index.js +1 -0
  120. package/lib-esm/stories/Autocomplete.stories.js +549 -0
  121. package/lib-esm/stories/Dialog.stories.js +3 -3
  122. package/lib-esm/stories/IssueLabelToken.stories.js +1 -1
  123. package/lib-esm/stories/ProfileToken.stories.js +1 -1
  124. package/lib-esm/theme-preval.js +370 -3100
  125. package/lib-esm/utils/testing.d.ts +50 -493
  126. package/lib-esm/utils/types/MandateProps.d.ts +3 -0
  127. package/lib-esm/utils/types/MandateProps.js +1 -0
  128. package/lib-esm/utils/types/index.d.ts +1 -0
  129. package/lib-esm/utils/types/index.js +2 -1
  130. package/package-lock.json +11 -8
  131. package/package.json +3 -3
  132. package/src/ActionList/Item.tsx +1 -1
  133. package/src/AnchoredOverlay/AnchoredOverlay.tsx +14 -3
  134. package/src/Autocomplete/Autocomplete.tsx +103 -0
  135. package/src/Autocomplete/AutocompleteContext.tsx +19 -0
  136. package/src/Autocomplete/AutocompleteInput.tsx +179 -0
  137. package/src/Autocomplete/AutocompleteMenu.tsx +341 -0
  138. package/src/Autocomplete/AutocompleteOverlay.tsx +68 -0
  139. package/src/Autocomplete/index.ts +2 -0
  140. package/src/BaseStyles.tsx +1 -1
  141. package/src/BorderBox.tsx +1 -1
  142. package/src/Button/ButtonInvisible.tsx +7 -2
  143. package/src/Caret.tsx +2 -2
  144. package/src/Dialog.tsx +1 -1
  145. package/src/FilteredActionList/FilteredActionList.tsx +10 -25
  146. package/src/Flash.tsx +16 -16
  147. package/src/Label.tsx +1 -1
  148. package/src/Overlay.tsx +4 -1
  149. package/src/ProgressBar.tsx +1 -1
  150. package/src/StateLabel.tsx +12 -20
  151. package/src/Token/_RemoveTokenButton.tsx +4 -2
  152. package/src/__tests__/Autocomplete.test.tsx +444 -0
  153. package/src/__tests__/BorderBox.test.tsx +1 -1
  154. package/src/__tests__/CircleOcticon.test.tsx +1 -1
  155. package/src/__tests__/CounterLabel.test.tsx +4 -4
  156. package/src/__tests__/Flash.test.tsx +4 -4
  157. package/src/__tests__/Link.test.tsx +1 -1
  158. package/src/__tests__/__snapshots__/AnchoredOverlay.test.tsx.snap +3 -3
  159. package/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap +3414 -0
  160. package/src/__tests__/__snapshots__/Button.test.tsx.snap +9 -1
  161. package/src/__tests__/__snapshots__/ConfirmationDialog.test.tsx.snap +1 -1
  162. package/src/__tests__/__snapshots__/SelectPanel.test.tsx.snap +1 -1
  163. package/src/__tests__/__snapshots__/StateLabel.test.tsx.snap +0 -21
  164. package/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap +16 -16
  165. package/src/__tests__/__snapshots__/Token.test.tsx.snap +34 -34
  166. package/src/__tests__/behaviors/scrollIntoViewingArea.test.ts +195 -0
  167. package/src/behaviors/scrollIntoViewingArea.ts +27 -0
  168. package/src/hooks/useOpenAndCloseFocus.ts +7 -2
  169. package/src/hooks/useOverlay.tsx +4 -2
  170. package/src/index.ts +2 -0
  171. package/src/stories/Autocomplete.stories.tsx +572 -0
  172. package/src/stories/Dialog.stories.tsx +3 -3
  173. package/src/stories/IssueLabelToken.stories.tsx +1 -1
  174. package/src/stories/ProfileToken.stories.tsx +1 -1
  175. package/src/utils/types/MandateProps.ts +19 -0
  176. package/src/utils/types/index.ts +1 -0
  177. package/stats.html +1 -1
  178. package/docs/src/@primer/gatsby-theme-doctocat/components/live-code.js +0 -84
  179. package/docs/src/@primer/gatsby-theme-doctocat/components/nav-dropdown.js +0 -48
  180. package/docs/src/@primer/gatsby-theme-doctocat/components/wrap-page-element.js +0 -25
@@ -472,13 +472,21 @@ exports[`ButtonInvisible renders correct disabled styles 1`] = `
472
472
  }
473
473
 
474
474
  .c0:disabled {
475
- color: #57606a;
475
+ color: #8c959f;
476
476
  }
477
477
 
478
478
  .c0:focus {
479
479
  box-shadow: 0 0 0 3px rgba(9,105,218,0.3);
480
480
  }
481
481
 
482
+ .c0:hover {
483
+ background-color: #f3f4f6;
484
+ }
485
+
486
+ .c0:active {
487
+ background-color: hsla(220,14%,94%,1);
488
+ }
489
+
482
490
  <button
483
491
  className="c0"
484
492
  disabled={true}
@@ -75,7 +75,7 @@ exports[`ConfirmationDialog renders consistently 1`] = `
75
75
 
76
76
  <div
77
77
  className="c0"
78
- color="text.primary"
78
+ color="fg.default"
79
79
  data-portal-root={true}
80
80
  fontFamily="normal"
81
81
  >
@@ -79,7 +79,7 @@ exports[`SelectPanel renders consistently 1`] = `
79
79
 
80
80
  <div
81
81
  className="c0"
82
- color="text.primary"
82
+ color="fg.default"
83
83
  data-portal-root={true}
84
84
  fontFamily="normal"
85
85
  >
@@ -19,11 +19,8 @@ exports[`StateLabel renders children 1`] = `
19
19
  color: #ffffff;
20
20
  text-align: center;
21
21
  border-radius: 100px;
22
- border-width: 1px;
23
- border-style: solid;
24
22
  background-color: #2da44e;
25
23
  color: #ffffff;
26
- border-color: rgba(0,0,0,0);
27
24
  padding-left: 12px;
28
25
  padding-right: 12px;
29
26
  padding-top: 8px;
@@ -78,11 +75,8 @@ exports[`StateLabel renders consistently 1`] = `
78
75
  color: #ffffff;
79
76
  text-align: center;
80
77
  border-radius: 100px;
81
- border-width: 1px;
82
- border-style: solid;
83
78
  background-color: #2da44e;
84
79
  color: #ffffff;
85
- border-color: rgba(0,0,0,0);
86
80
  padding-left: 12px;
87
81
  padding-right: 12px;
88
82
  padding-top: 8px;
@@ -137,11 +131,8 @@ exports[`StateLabel respects the status prop 1`] = `
137
131
  color: #ffffff;
138
132
  text-align: center;
139
133
  border-radius: 100px;
140
- border-width: 1px;
141
- border-style: solid;
142
134
  background-color: #2da44e;
143
135
  color: #ffffff;
144
- border-color: rgba(0,0,0,0);
145
136
  padding-left: 12px;
146
137
  padding-right: 12px;
147
138
  padding-top: 8px;
@@ -195,11 +186,8 @@ exports[`StateLabel respects the status prop 2`] = `
195
186
  color: #ffffff;
196
187
  text-align: center;
197
188
  border-radius: 100px;
198
- border-width: 1px;
199
- border-style: solid;
200
189
  background-color: #cf222e;
201
190
  color: #ffffff;
202
- border-color: rgba(0,0,0,0);
203
191
  padding-left: 12px;
204
192
  padding-right: 12px;
205
193
  padding-top: 8px;
@@ -253,11 +241,8 @@ exports[`StateLabel respects the status prop 3`] = `
253
241
  color: #ffffff;
254
242
  text-align: center;
255
243
  border-radius: 100px;
256
- border-width: 1px;
257
- border-style: solid;
258
244
  background-color: #8250df;
259
245
  color: #ffffff;
260
- border-color: rgba(0,0,0,0);
261
246
  padding-left: 12px;
262
247
  padding-right: 12px;
263
248
  padding-top: 8px;
@@ -311,11 +296,8 @@ exports[`StateLabel respects the variant prop 1`] = `
311
296
  color: #ffffff;
312
297
  text-align: center;
313
298
  border-radius: 100px;
314
- border-width: 1px;
315
- border-style: solid;
316
299
  background-color: #2da44e;
317
300
  color: #ffffff;
318
- border-color: rgba(0,0,0,0);
319
301
  padding-left: 8px;
320
302
  padding-right: 8px;
321
303
  padding-top: 4px;
@@ -369,11 +351,8 @@ exports[`StateLabel respects the variant prop 2`] = `
369
351
  color: #ffffff;
370
352
  text-align: center;
371
353
  border-radius: 100px;
372
- border-width: 1px;
373
- border-style: solid;
374
354
  background-color: #2da44e;
375
355
  color: #ffffff;
376
- border-color: rgba(0,0,0,0);
377
356
  padding-left: 12px;
378
357
  padding-right: 12px;
379
358
  padding-top: 8px;
@@ -232,11 +232,11 @@ exports[`TextInputWithTokens renders at a maximum height when specified 1`] = `
232
232
 
233
233
  .c5:hover,
234
234
  .c5:focus {
235
- background-color: rgba(27,31,36,0.1);
235
+ background-color: rgba(175,184,193,0.2);
236
236
  }
237
237
 
238
238
  .c5:active {
239
- background-color: rgba(27,31,36,0.15);
239
+ background-color: rgba(234,238,242,0.5);
240
240
  }
241
241
 
242
242
  .c4 {
@@ -829,11 +829,11 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 1`] = `
829
829
 
830
830
  .c5:hover,
831
831
  .c5:focus {
832
- background-color: rgba(27,31,36,0.1);
832
+ background-color: rgba(175,184,193,0.2);
833
833
  }
834
834
 
835
835
  .c5:active {
836
- background-color: rgba(27,31,36,0.15);
836
+ background-color: rgba(234,238,242,0.5);
837
837
  }
838
838
 
839
839
  .c4 {
@@ -1426,11 +1426,11 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 2`] = `
1426
1426
 
1427
1427
  .c5:hover,
1428
1428
  .c5:focus {
1429
- background-color: rgba(27,31,36,0.1);
1429
+ background-color: rgba(175,184,193,0.2);
1430
1430
  }
1431
1431
 
1432
1432
  .c5:active {
1433
- background-color: rgba(27,31,36,0.15);
1433
+ background-color: rgba(234,238,242,0.5);
1434
1434
  }
1435
1435
 
1436
1436
  .c4 {
@@ -2023,11 +2023,11 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 3`] = `
2023
2023
 
2024
2024
  .c5:hover,
2025
2025
  .c5:focus {
2026
- background-color: rgba(27,31,36,0.1);
2026
+ background-color: rgba(175,184,193,0.2);
2027
2027
  }
2028
2028
 
2029
2029
  .c5:active {
2030
- background-color: rgba(27,31,36,0.15);
2030
+ background-color: rgba(234,238,242,0.5);
2031
2031
  }
2032
2032
 
2033
2033
  .c4 {
@@ -2620,11 +2620,11 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 4`] = `
2620
2620
 
2621
2621
  .c5:hover,
2622
2622
  .c5:focus {
2623
- background-color: rgba(27,31,36,0.1);
2623
+ background-color: rgba(175,184,193,0.2);
2624
2624
  }
2625
2625
 
2626
2626
  .c5:active {
2627
- background-color: rgba(27,31,36,0.15);
2627
+ background-color: rgba(234,238,242,0.5);
2628
2628
  }
2629
2629
 
2630
2630
  .c4 {
@@ -3218,11 +3218,11 @@ exports[`TextInputWithTokens renders tokens on a single line when specified 1`]
3218
3218
 
3219
3219
  .c5:hover,
3220
3220
  .c5:focus {
3221
- background-color: rgba(27,31,36,0.1);
3221
+ background-color: rgba(175,184,193,0.2);
3222
3222
  }
3223
3223
 
3224
3224
  .c5:active {
3225
- background-color: rgba(27,31,36,0.15);
3225
+ background-color: rgba(234,238,242,0.5);
3226
3226
  }
3227
3227
 
3228
3228
  .c4 {
@@ -4129,11 +4129,11 @@ exports[`TextInputWithTokens renders with tokens 1`] = `
4129
4129
 
4130
4130
  .c5:hover,
4131
4131
  .c5:focus {
4132
- background-color: rgba(27,31,36,0.1);
4132
+ background-color: rgba(175,184,193,0.2);
4133
4133
  }
4134
4134
 
4135
4135
  .c5:active {
4136
- background-color: rgba(27,31,36,0.15);
4136
+ background-color: rgba(234,238,242,0.5);
4137
4137
  }
4138
4138
 
4139
4139
  .c4 {
@@ -4770,11 +4770,11 @@ exports[`TextInputWithTokens renders with tokens using a custom token component
4770
4770
 
4771
4771
  .c5:hover,
4772
4772
  .c5:focus {
4773
- background-color: rgba(27,31,36,0.1);
4773
+ background-color: rgba(175,184,193,0.2);
4774
4774
  }
4775
4775
 
4776
4776
  .c5:active {
4777
- background-color: rgba(27,31,36,0.15);
4777
+ background-color: rgba(234,238,242,0.5);
4778
4778
  }
4779
4779
 
4780
4780
  .c4 {
@@ -52,11 +52,11 @@ exports[`Token components AvatarToken renders all sizes 1`] = `
52
52
 
53
53
  .c5:hover,
54
54
  .c5:focus {
55
- background-color: rgba(27,31,36,0.1);
55
+ background-color: rgba(175,184,193,0.2);
56
56
  }
57
57
 
58
58
  .c5:active {
59
- background-color: rgba(27,31,36,0.15);
59
+ background-color: rgba(234,238,242,0.5);
60
60
  }
61
61
 
62
62
  .c4 {
@@ -260,11 +260,11 @@ exports[`Token components AvatarToken renders all sizes 2`] = `
260
260
 
261
261
  .c5:hover,
262
262
  .c5:focus {
263
- background-color: rgba(27,31,36,0.1);
263
+ background-color: rgba(175,184,193,0.2);
264
264
  }
265
265
 
266
266
  .c5:active {
267
- background-color: rgba(27,31,36,0.15);
267
+ background-color: rgba(234,238,242,0.5);
268
268
  }
269
269
 
270
270
  .c4 {
@@ -468,11 +468,11 @@ exports[`Token components AvatarToken renders all sizes 3`] = `
468
468
 
469
469
  .c5:hover,
470
470
  .c5:focus {
471
- background-color: rgba(27,31,36,0.1);
471
+ background-color: rgba(175,184,193,0.2);
472
472
  }
473
473
 
474
474
  .c5:active {
475
- background-color: rgba(27,31,36,0.15);
475
+ background-color: rgba(234,238,242,0.5);
476
476
  }
477
477
 
478
478
  .c4 {
@@ -676,11 +676,11 @@ exports[`Token components AvatarToken renders all sizes 4`] = `
676
676
 
677
677
  .c5:hover,
678
678
  .c5:focus {
679
- background-color: rgba(27,31,36,0.1);
679
+ background-color: rgba(175,184,193,0.2);
680
680
  }
681
681
 
682
682
  .c5:active {
683
- background-color: rgba(27,31,36,0.15);
683
+ background-color: rgba(234,238,242,0.5);
684
684
  }
685
685
 
686
686
  .c4 {
@@ -1096,11 +1096,11 @@ exports[`Token components AvatarToken renders with a remove button 1`] = `
1096
1096
 
1097
1097
  .c5:hover,
1098
1098
  .c5:focus {
1099
- background-color: rgba(27,31,36,0.1);
1099
+ background-color: rgba(175,184,193,0.2);
1100
1100
  }
1101
1101
 
1102
1102
  .c5:active {
1103
- background-color: rgba(27,31,36,0.15);
1103
+ background-color: rgba(234,238,242,0.5);
1104
1104
  }
1105
1105
 
1106
1106
  .c4 {
@@ -1338,11 +1338,11 @@ exports[`Token components IssueLabelToken renders all sizes 1`] = `
1338
1338
 
1339
1339
  .c2:hover,
1340
1340
  .c2:focus {
1341
- background-color: rgba(27,31,36,0.1);
1341
+ background-color: rgba(175,184,193,0.2);
1342
1342
  }
1343
1343
 
1344
1344
  .c2:active {
1345
- background-color: rgba(27,31,36,0.15);
1345
+ background-color: rgba(234,238,242,0.5);
1346
1346
  }
1347
1347
 
1348
1348
  .c1 {
@@ -1514,11 +1514,11 @@ exports[`Token components IssueLabelToken renders all sizes 2`] = `
1514
1514
 
1515
1515
  .c2:hover,
1516
1516
  .c2:focus {
1517
- background-color: rgba(27,31,36,0.1);
1517
+ background-color: rgba(175,184,193,0.2);
1518
1518
  }
1519
1519
 
1520
1520
  .c2:active {
1521
- background-color: rgba(27,31,36,0.15);
1521
+ background-color: rgba(234,238,242,0.5);
1522
1522
  }
1523
1523
 
1524
1524
  .c1 {
@@ -1690,11 +1690,11 @@ exports[`Token components IssueLabelToken renders all sizes 3`] = `
1690
1690
 
1691
1691
  .c2:hover,
1692
1692
  .c2:focus {
1693
- background-color: rgba(27,31,36,0.1);
1693
+ background-color: rgba(175,184,193,0.2);
1694
1694
  }
1695
1695
 
1696
1696
  .c2:active {
1697
- background-color: rgba(27,31,36,0.15);
1697
+ background-color: rgba(234,238,242,0.5);
1698
1698
  }
1699
1699
 
1700
1700
  .c1 {
@@ -1866,11 +1866,11 @@ exports[`Token components IssueLabelToken renders all sizes 4`] = `
1866
1866
 
1867
1867
  .c2:hover,
1868
1868
  .c2:focus {
1869
- background-color: rgba(27,31,36,0.1);
1869
+ background-color: rgba(175,184,193,0.2);
1870
1870
  }
1871
1871
 
1872
1872
  .c2:active {
1873
- background-color: rgba(27,31,36,0.15);
1873
+ background-color: rgba(234,238,242,0.5);
1874
1874
  }
1875
1875
 
1876
1876
  .c1 {
@@ -2126,11 +2126,11 @@ exports[`Token components IssueLabelToken renders custom fill color 1`] = `
2126
2126
 
2127
2127
  .c2:hover,
2128
2128
  .c2:focus {
2129
- background-color: rgba(27,31,36,0.1);
2129
+ background-color: rgba(175,184,193,0.2);
2130
2130
  }
2131
2131
 
2132
2132
  .c2:active {
2133
- background-color: rgba(27,31,36,0.15);
2133
+ background-color: rgba(234,238,242,0.5);
2134
2134
  }
2135
2135
 
2136
2136
  .c1 {
@@ -2302,11 +2302,11 @@ exports[`Token components IssueLabelToken renders default fill color 1`] = `
2302
2302
 
2303
2303
  .c2:hover,
2304
2304
  .c2:focus {
2305
- background-color: rgba(27,31,36,0.1);
2305
+ background-color: rgba(175,184,193,0.2);
2306
2306
  }
2307
2307
 
2308
2308
  .c2:active {
2309
- background-color: rgba(27,31,36,0.15);
2309
+ background-color: rgba(234,238,242,0.5);
2310
2310
  }
2311
2311
 
2312
2312
  .c1 {
@@ -2592,11 +2592,11 @@ exports[`Token components IssueLabelToken renders with a remove button 1`] = `
2592
2592
 
2593
2593
  .c2:hover,
2594
2594
  .c2:focus {
2595
- background-color: rgba(27,31,36,0.1);
2595
+ background-color: rgba(175,184,193,0.2);
2596
2596
  }
2597
2597
 
2598
2598
  .c2:active {
2599
- background-color: rgba(27,31,36,0.15);
2599
+ background-color: rgba(234,238,242,0.5);
2600
2600
  }
2601
2601
 
2602
2602
  .c1 {
@@ -2724,11 +2724,11 @@ exports[`Token components Token renders all sizes 1`] = `
2724
2724
 
2725
2725
  .c2:hover,
2726
2726
  .c2:focus {
2727
- background-color: rgba(27,31,36,0.1);
2727
+ background-color: rgba(175,184,193,0.2);
2728
2728
  }
2729
2729
 
2730
2730
  .c2:active {
2731
- background-color: rgba(27,31,36,0.15);
2731
+ background-color: rgba(234,238,242,0.5);
2732
2732
  }
2733
2733
 
2734
2734
  .c1 {
@@ -2890,11 +2890,11 @@ exports[`Token components Token renders all sizes 2`] = `
2890
2890
 
2891
2891
  .c2:hover,
2892
2892
  .c2:focus {
2893
- background-color: rgba(27,31,36,0.1);
2893
+ background-color: rgba(175,184,193,0.2);
2894
2894
  }
2895
2895
 
2896
2896
  .c2:active {
2897
- background-color: rgba(27,31,36,0.15);
2897
+ background-color: rgba(234,238,242,0.5);
2898
2898
  }
2899
2899
 
2900
2900
  .c1 {
@@ -3056,11 +3056,11 @@ exports[`Token components Token renders all sizes 3`] = `
3056
3056
 
3057
3057
  .c2:hover,
3058
3058
  .c2:focus {
3059
- background-color: rgba(27,31,36,0.1);
3059
+ background-color: rgba(175,184,193,0.2);
3060
3060
  }
3061
3061
 
3062
3062
  .c2:active {
3063
- background-color: rgba(27,31,36,0.15);
3063
+ background-color: rgba(234,238,242,0.5);
3064
3064
  }
3065
3065
 
3066
3066
  .c1 {
@@ -3222,11 +3222,11 @@ exports[`Token components Token renders all sizes 4`] = `
3222
3222
 
3223
3223
  .c2:hover,
3224
3224
  .c2:focus {
3225
- background-color: rgba(27,31,36,0.1);
3225
+ background-color: rgba(175,184,193,0.2);
3226
3226
  }
3227
3227
 
3228
3228
  .c2:active {
3229
- background-color: rgba(27,31,36,0.15);
3229
+ background-color: rgba(234,238,242,0.5);
3230
3230
  }
3231
3231
 
3232
3232
  .c1 {
@@ -3662,11 +3662,11 @@ exports[`Token components Token renders with a remove button 1`] = `
3662
3662
 
3663
3663
  .c2:hover,
3664
3664
  .c2:focus {
3665
- background-color: rgba(27,31,36,0.1);
3665
+ background-color: rgba(175,184,193,0.2);
3666
3666
  }
3667
3667
 
3668
3668
  .c2:active {
3669
- background-color: rgba(27,31,36,0.15);
3669
+ background-color: rgba(234,238,242,0.5);
3670
3670
  }
3671
3671
 
3672
3672
  .c1 {
@@ -0,0 +1,195 @@
1
+ import {scrollIntoViewingArea} from '../../behaviors/scrollIntoViewingArea'
2
+
3
+ function scrollPositionFormula(
4
+ positionData: {viewingAreaEdgePosition: number; childEdgePosition: number; margin: number},
5
+ isChildAboveViewingArea: boolean
6
+ ) {
7
+ const {viewingAreaEdgePosition, childEdgePosition, margin} = positionData
8
+ const marginOffset = margin * (isChildAboveViewingArea ? -1 : 1)
9
+
10
+ return childEdgePosition - viewingAreaEdgePosition + marginOffset
11
+ }
12
+
13
+ // The DOMRect constructor isn't available in JSDOM, so we improvise here.
14
+ function makeDOMRect(x: number, y: number, width: number, height: number): DOMRect {
15
+ return {
16
+ x,
17
+ y,
18
+ width,
19
+ height,
20
+ top: y,
21
+ left: x,
22
+ right: x + width,
23
+ bottom: y + height,
24
+ toJSON() {
25
+ return this
26
+ }
27
+ }
28
+ }
29
+
30
+ // Since Jest/JSDOM doesn't support layout, we can stub out getBoundingClientRect if we know the
31
+ // correct dimensions. JSDOM will handle the rest of the DOM API used by getAnchoredPosition.
32
+ function createVirtualDOM(viewingAreaRect: DOMRect, childRect: DOMRect) {
33
+ const viewingArea = document.createElement('div')
34
+ viewingArea.style.overflow = 'auto'
35
+ viewingArea.id = 'viewingArea'
36
+ // eslint-disable-next-line github/unescaped-html-literal
37
+ viewingArea.innerHTML = '<div id="child"></div>'
38
+ const child = viewingArea.querySelector('#child')!
39
+ child.getBoundingClientRect = () => childRect
40
+ viewingArea.getBoundingClientRect = () => viewingAreaRect
41
+ return {viewingArea, child}
42
+ }
43
+
44
+ describe('scrollIntoViewingArea', () => {
45
+ it('scrolls the expected amount when only the viewingArea element and child element are passed to the function', () => {
46
+ const scrollToMock = jest.fn()
47
+ Object.defineProperty(window.Element.prototype, 'scrollTo', {
48
+ writable: true,
49
+ value: scrollToMock
50
+ })
51
+ const childHeight = 50
52
+ const viewAreaHeight = 100
53
+ const childStart = viewAreaHeight + 10
54
+ const expectedScrollPosition = scrollPositionFormula(
55
+ {viewingAreaEdgePosition: viewAreaHeight, childEdgePosition: childStart + childHeight, margin: 8},
56
+ false
57
+ )
58
+
59
+ const viewingAreaRect = makeDOMRect(0, 0, 100, viewAreaHeight)
60
+ const childRect = makeDOMRect(0, childStart, 100, childHeight)
61
+ const {viewingArea, child} = createVirtualDOM(viewingAreaRect, childRect)
62
+
63
+ viewingArea.getBoundingClientRect = () => viewingAreaRect
64
+ viewingArea.scrollTop = 0
65
+ child.getBoundingClientRect = () => childRect
66
+
67
+ scrollIntoViewingArea(child as HTMLDivElement, viewingArea)
68
+ expect(scrollToMock).toHaveBeenCalledWith({
69
+ behavior: 'smooth',
70
+ top: expectedScrollPosition
71
+ })
72
+ })
73
+
74
+ describe('y-axis', () => {
75
+ it('scrolls the child into the viewing area when it is AFTER the overflow cutoff point', () => {
76
+ const scrollToMock = jest.fn()
77
+ Object.defineProperty(window.Element.prototype, 'scrollTo', {
78
+ writable: true,
79
+ value: scrollToMock
80
+ })
81
+ const childHeight = 50
82
+ const viewAreaHeight = 100
83
+ const childStart = viewAreaHeight + 10
84
+ const scrollMargin = 10
85
+ const expectedScrollPosition = scrollPositionFormula(
86
+ {viewingAreaEdgePosition: viewAreaHeight, childEdgePosition: childStart + childHeight, margin: scrollMargin},
87
+ false
88
+ )
89
+
90
+ const viewingAreaRect = makeDOMRect(0, 0, 100, viewAreaHeight)
91
+ const childRect = makeDOMRect(0, childStart, 100, childHeight)
92
+ const {viewingArea, child} = createVirtualDOM(viewingAreaRect, childRect)
93
+
94
+ viewingArea.getBoundingClientRect = () => viewingAreaRect
95
+ viewingArea.scrollTop = 0
96
+ child.getBoundingClientRect = () => childRect
97
+
98
+ scrollIntoViewingArea(child as HTMLDivElement, viewingArea, 'vertical', scrollMargin, scrollMargin, 'auto')
99
+ expect(scrollToMock).toHaveBeenCalledWith({
100
+ behavior: 'auto',
101
+ top: expectedScrollPosition
102
+ })
103
+ })
104
+
105
+ it('scrolls the child into the viewing area when it is BEFORE the overflow cutoff point', () => {
106
+ const scrollToMock = jest.fn()
107
+ Object.defineProperty(window.Element.prototype, 'scrollTo', {
108
+ writable: true,
109
+ value: scrollToMock
110
+ })
111
+ const childHeight = 50
112
+ const childStart = childHeight * -1 - 10
113
+ const scrollMargin = 10
114
+ const expectedScrollPosition = scrollPositionFormula(
115
+ {viewingAreaEdgePosition: 0, childEdgePosition: childStart, margin: scrollMargin},
116
+ true
117
+ )
118
+
119
+ const viewingAreaRect = makeDOMRect(0, 0, 100, 100)
120
+ const childRect = makeDOMRect(0, childStart, 100, childHeight)
121
+ const {viewingArea, child} = createVirtualDOM(viewingAreaRect, childRect)
122
+
123
+ viewingArea.getBoundingClientRect = () => viewingAreaRect
124
+ viewingArea.scrollTop = 0
125
+ child.getBoundingClientRect = () => childRect
126
+
127
+ scrollIntoViewingArea(child as HTMLDivElement, viewingArea, 'vertical', scrollMargin, scrollMargin, 'auto')
128
+ expect(scrollToMock).toHaveBeenCalledWith({
129
+ behavior: 'auto',
130
+ top: expectedScrollPosition
131
+ })
132
+ })
133
+ })
134
+
135
+ describe('x-axis', () => {
136
+ it('scrolls the child into the viewing area when it is AFTER the overflow cutoff point', () => {
137
+ const scrollToMock = jest.fn()
138
+ Object.defineProperty(window.Element.prototype, 'scrollTo', {
139
+ writable: true,
140
+ value: scrollToMock
141
+ })
142
+ const childWidth = 50
143
+ const viewAreaWidth = 100
144
+ const childStart = viewAreaWidth + 10
145
+ const scrollMargin = 10
146
+ const expectedScrollPosition = scrollPositionFormula(
147
+ {viewingAreaEdgePosition: viewAreaWidth, childEdgePosition: childStart + childWidth, margin: scrollMargin},
148
+ false
149
+ )
150
+
151
+ const viewingAreaRect = makeDOMRect(0, 0, 100, viewAreaWidth)
152
+ const childRect = makeDOMRect(childStart, 0, childWidth, 100)
153
+ const {viewingArea, child} = createVirtualDOM(viewingAreaRect, childRect)
154
+
155
+ viewingArea.getBoundingClientRect = () => viewingAreaRect
156
+ viewingArea.scrollLeft = 0
157
+ child.getBoundingClientRect = () => childRect
158
+
159
+ scrollIntoViewingArea(child as HTMLDivElement, viewingArea, 'horizontal', scrollMargin, scrollMargin, 'auto')
160
+ expect(scrollToMock).toHaveBeenCalledWith({
161
+ behavior: 'auto',
162
+ left: expectedScrollPosition
163
+ })
164
+ })
165
+
166
+ it('scrolls the child into the viewing area when it is BEFORE the overflow cutoff point', () => {
167
+ const scrollToMock = jest.fn()
168
+ Object.defineProperty(window.Element.prototype, 'scrollTo', {
169
+ writable: true,
170
+ value: scrollToMock
171
+ })
172
+ const childWidth = 50
173
+ const childStart = childWidth * -1 - 10
174
+ const scrollMargin = 10
175
+ const expectedScrollPosition = scrollPositionFormula(
176
+ {viewingAreaEdgePosition: 0, childEdgePosition: childStart, margin: scrollMargin},
177
+ true
178
+ )
179
+
180
+ const viewingAreaRect = makeDOMRect(0, 0, 100, 100)
181
+ const childRect = makeDOMRect(childStart, 0, childWidth, 100)
182
+ const {viewingArea, child} = createVirtualDOM(viewingAreaRect, childRect)
183
+
184
+ viewingArea.getBoundingClientRect = () => viewingAreaRect
185
+ viewingArea.scrollTop = 0
186
+ child.getBoundingClientRect = () => childRect
187
+
188
+ scrollIntoViewingArea(child as HTMLDivElement, viewingArea, 'horizontal', scrollMargin, scrollMargin, 'auto')
189
+ expect(scrollToMock).toHaveBeenCalledWith({
190
+ behavior: 'auto',
191
+ left: expectedScrollPosition
192
+ })
193
+ })
194
+ })
195
+ })
@@ -0,0 +1,27 @@
1
+ export const scrollIntoViewingArea = (
2
+ child: HTMLElement,
3
+ viewingArea: HTMLElement,
4
+ direction: 'horizontal' | 'vertical' = 'vertical',
5
+ startMargin = 8,
6
+ endMargin = 0,
7
+ behavior: ScrollBehavior = 'smooth'
8
+ ) => {
9
+ const startSide = direction === 'vertical' ? 'top' : 'left'
10
+ const endSide = direction === 'vertical' ? 'bottom' : 'right'
11
+ const scrollSide = direction === 'vertical' ? 'scrollTop' : 'scrollLeft'
12
+ const {[startSide]: childStart, [endSide]: childEnd} = child.getBoundingClientRect()
13
+ const {[startSide]: viewingAreaStart, [endSide]: viewingAreaEnd} = viewingArea.getBoundingClientRect()
14
+
15
+ const isChildStartAboveViewingArea = childStart < viewingAreaStart + endMargin
16
+ const isChildBottomBelowViewingArea = childEnd > viewingAreaEnd - startMargin
17
+
18
+ if (isChildStartAboveViewingArea) {
19
+ const scrollHeightToChildStart = childStart - viewingAreaStart + viewingArea[scrollSide]
20
+ viewingArea.scrollTo({behavior, [startSide]: scrollHeightToChildStart - endMargin})
21
+ } else if (isChildBottomBelowViewingArea) {
22
+ const scrollHeightToChildBottom = childEnd - viewingAreaEnd + viewingArea[scrollSide]
23
+ viewingArea.scrollTo({behavior, [startSide]: scrollHeightToChildBottom + startMargin})
24
+ }
25
+
26
+ // either completely in view or outside viewing area on both ends, don't scroll
27
+ }