playbook_ui 14.7.0.pre.rc.19 → 14.8.0.pre.alpha.PBNTR713dropdowncustomtriggerbug4696

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/_playbook.scss +1 -0
  3. data/app/pb_kits/playbook/pb_card/docs/_card_light.md +1 -1
  4. data/app/pb_kits/playbook/pb_checkbox/checkbox.html.erb +2 -2
  5. data/app/pb_kits/playbook/pb_checkbox/checkbox.rb +0 -4
  6. data/app/pb_kits/playbook/pb_checkbox/docs/_checkbox_indeterminate.html.erb +84 -7
  7. data/app/pb_kits/playbook/pb_date/_date.scss +3 -0
  8. data/app/pb_kits/playbook/pb_date_picker/date_picker_helper.ts +1 -1
  9. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_default_date.html.erb +42 -0
  10. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_default_date.jsx +44 -0
  11. data/app/pb_kits/playbook/pb_date_picker/docs/_date_picker_quick_pick_default_date.md +1 -0
  12. data/app/pb_kits/playbook/pb_date_picker/docs/example.yml +2 -0
  13. data/app/pb_kits/playbook/pb_date_picker/docs/index.js +1 -0
  14. data/app/pb_kits/playbook/pb_date_picker/plugins/quickPick.tsx +17 -1
  15. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default_rails.html.erb +26 -0
  16. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default_rails.md +7 -0
  17. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards_rails.html.erb +38 -0
  18. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards_rails.md +0 -0
  19. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_list_rails.html.erb +19 -0
  20. data/app/pb_kits/playbook/pb_draggable/docs/example.yml +6 -0
  21. data/app/pb_kits/playbook/pb_draggable/draggable.html.erb +3 -0
  22. data/app/pb_kits/playbook/pb_draggable/draggable.rb +18 -0
  23. data/app/pb_kits/playbook/pb_draggable/draggable_container.html.erb +3 -0
  24. data/app/pb_kits/playbook/pb_draggable/draggable_container.rb +15 -0
  25. data/app/pb_kits/playbook/pb_draggable/draggable_item.html.erb +7 -0
  26. data/app/pb_kits/playbook/pb_draggable/draggable_item.rb +18 -0
  27. data/app/pb_kits/playbook/pb_draggable/index.js +125 -0
  28. data/app/pb_kits/playbook/pb_drawer/_drawer.scss +88 -175
  29. data/app/pb_kits/playbook/pb_drawer/_drawer.tsx +79 -47
  30. data/app/pb_kits/playbook/pb_drawer/drawer.test.jsx +20 -16
  31. data/app/pb_kits/playbook/pb_dropdown/_dropdown.scss +1 -0
  32. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.html.erb +0 -1
  33. data/app/pb_kits/playbook/pb_dropdown/dropdown_container.rb +0 -4
  34. data/app/pb_kits/playbook/pb_dropdown/utilities/subComponentHelper.tsx +13 -2
  35. data/app/pb_kits/playbook/pb_form/docs/_form_form_with.html.erb +2 -2
  36. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.html.erb +1 -1
  37. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +63 -12
  38. data/app/pb_kits/playbook/pb_selectable_card/docs/_selectable_card_default.html.erb +2 -1
  39. data/app/pb_kits/playbook/pb_table/_table.tsx +103 -24
  40. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns.jsx +87 -0
  41. data/app/pb_kits/playbook/pb_table/docs/_table_sticky_left_columns_react.md +2 -0
  42. data/app/pb_kits/playbook/pb_table/docs/index.js +1 -0
  43. data/app/pb_kits/playbook/pb_table/styles/_all.scss +2 -0
  44. data/app/pb_kits/playbook/pb_table/styles/_scroll.scss +4 -0
  45. data/app/pb_kits/playbook/pb_table/styles/_sticky_columns.scss +18 -0
  46. data/app/pb_kits/playbook/pb_timeline/_timeline.scss +43 -1
  47. data/app/pb_kits/playbook/pb_timeline/_timeline.tsx +6 -2
  48. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.html.erb +47 -0
  49. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_children.jsx +59 -0
  50. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_gap.html.erb +94 -0
  51. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_gap.jsx +180 -0
  52. data/app/pb_kits/playbook/pb_timeline/docs/_timeline_with_gap.md +1 -0
  53. data/app/pb_kits/playbook/pb_timeline/docs/example.yml +5 -3
  54. data/app/pb_kits/playbook/pb_timeline/docs/index.js +2 -0
  55. data/app/pb_kits/playbook/pb_timeline/timeline.rb +11 -1
  56. data/app/pb_kits/playbook/pb_timeline/timeline.test.js +4 -4
  57. data/app/pb_kits/playbook/pb_typeahead/_typeahead.scss +3 -0
  58. data/app/pb_kits/playbook/pb_typeahead/index.ts +29 -3
  59. data/app/pb_kits/playbook/pb_typeahead/typeahead.html.erb +5 -2
  60. data/app/pb_kits/playbook/pb_typeahead/typeahead.rb +4 -0
  61. data/app/pb_kits/playbook/tokens/_height.scss +19 -0
  62. data/app/pb_kits/playbook/tokens/exports/_height.module.scss +37 -0
  63. data/app/pb_kits/playbook/utilities/_height.scss +33 -0
  64. data/app/pb_kits/playbook/utilities/_hover.scss +40 -27
  65. data/app/pb_kits/playbook/utilities/_max_width.scss +4 -0
  66. data/app/pb_kits/playbook/utilities/_min_width.scss +1 -1
  67. data/app/pb_kits/playbook/utilities/globalPropNames.mjs +0 -1
  68. data/app/pb_kits/playbook/utilities/globalProps.ts +29 -3
  69. data/app/pb_kits/playbook/utilities/test/globalProps/hover.test.js +79 -0
  70. data/dist/chunks/_typeahead-C8Q_fFYF.js +22 -0
  71. data/dist/chunks/_weekday_stacked-CUJfwh5E.js +45 -0
  72. data/dist/chunks/{lib-D-mTv-kp.js → lib-SyD3buPZ.js} +1 -1
  73. data/dist/chunks/{pb_form_validation-BkWGwJsl.js → pb_form_validation-Dt8UJgrJ.js} +1 -1
  74. data/dist/chunks/vendor.js +1 -1
  75. data/dist/menu.yml +322 -1
  76. data/dist/playbook-doc.js +1 -1
  77. data/dist/playbook-rails-react-bindings.js +1 -1
  78. data/dist/playbook-rails.js +1 -1
  79. data/dist/playbook.css +1 -1
  80. data/lib/playbook/classnames.rb +3 -0
  81. data/lib/playbook/forms/builder/typeahead_field.rb +13 -0
  82. data/lib/playbook/height.rb +29 -0
  83. data/lib/playbook/hover.rb +1 -1
  84. data/lib/playbook/kit_base.rb +16 -1
  85. data/lib/playbook/max_height.rb +29 -0
  86. data/lib/playbook/min_height.rb +29 -0
  87. data/lib/playbook/version.rb +2 -2
  88. metadata +35 -6
  89. data/dist/chunks/_typeahead-DhLic2Fe.js +0 -22
  90. data/dist/chunks/_weekday_stacked-Mx8TYP5I.js +0 -45
@@ -7,54 +7,76 @@
7
7
  @import "../tokens/animation-curves";
8
8
  @import "../tokens/positioning";
9
9
 
10
+ $gutter: $space_lg;
11
+ $xsmall: 64px;
12
+ $small: 200px;
13
+ $medium: 250px;
14
+ $large: 300px;
15
+ $xlarge: 365px;
16
+ $animation-duration: 0.4s;
17
+ $z-index: $z_7;
18
+
10
19
  // Drawer animations
11
- // Drawer animations for fading in and out from the center
12
- @keyframes modalFadeIn {
20
+ @keyframes modalFadeInLeft {
13
21
  from {
14
- transform: translate3d(0, -100%, 0);
15
- opacity: 0;
22
+ transform: translateX(-100%);
16
23
  }
17
24
  to {
18
- transform: translate3d(0, 0, 0);
19
- opacity: 1;
25
+ transform: translateX(0);
20
26
  }
21
27
  }
22
28
 
23
- @keyframes modalFadeOut {
29
+ @keyframes modalFadeOutLeft {
24
30
  from {
25
- transform: translate3d(0, 0, 0);
26
- opacity: 1;
31
+ transform: translateX(0);
27
32
  }
28
33
  to {
29
- transform: translate3d(0, -50%, 0);
30
- opacity: 0;
34
+ transform: translateX(-100%);
31
35
  }
32
36
  }
33
37
 
34
- // Drawer animations for fading in and out from the right side
38
+ @keyframes modalFadeInRight {
39
+ from {
40
+ transform: translateX(100%);
41
+ }
42
+ to {
43
+ transform: translateX(0);
44
+ }
45
+ }
35
46
 
36
- @keyframes overlayFade {
47
+ @keyframes modalFadeOutRight {
37
48
  from {
38
- opacity: 0;
39
- transform: translateY(0);
49
+ transform: translateX(0);
50
+ }
51
+ to {
52
+ transform: translateX(100%);
53
+ }
54
+ }
55
+
56
+ @keyframes modalFadeIn {
57
+ from {
58
+ transform: translateY(-100%);
40
59
  }
41
60
  to {
42
- opacity: 1;
43
61
  transform: translateY(0);
44
62
  }
45
63
  }
46
64
 
47
- @keyframes overlayFadeOut {
65
+ @keyframes modalFadeOut {
48
66
  from {
49
- opacity: 1;
67
+ transform: translateY(0);
50
68
  }
51
69
  to {
52
- opacity: 0;
70
+ transform: translateY(-100%);
53
71
  }
54
72
  }
55
73
 
56
- body.ReactModal__Body--open {
57
- transition: margin-left 0.3s ease-in-out, margin-right 0.3s ease-in-out;
74
+ body.PBDrawer__Body--open {
75
+ transition: margin-left $animation-duration ease-in, margin-right $animation-duration ease-in;
76
+ }
77
+
78
+ body.PBDrawer__Body--close {
79
+ transition: margin-left $animation-duration ease-out, margin-right $animation-duration ease-out;
58
80
  }
59
81
 
60
82
  .pb_drawer_lg_left.pb_drawer {
@@ -66,28 +88,21 @@ body.ReactModal__Body--open {
66
88
  }
67
89
 
68
90
  .pb_drawer.pb_drawer_after_open {
69
- transform: translateX(0); /* Slide in */
91
+ transform: translate3d(0, 0, 0);
70
92
  }
93
+
71
94
  // Drawer Styles
72
95
  .pb_drawer {
73
-
74
- // Local Variables
75
- $gutter: $space_lg;
76
- $xsmall: 64px;
77
- $small: 200px;
78
- $medium: 250px;
79
- $large: 300px;
80
- $xlarge: 365px;
81
- $animation-duration: .2s;
82
- $z-index: 100;
83
- $opacity_visible: 1;
84
- $opacity_hidden: 0;
96
+ will-change: transform;
97
+ backface-visibility: hidden;
85
98
 
86
99
  .drawer {
87
100
  position: sticky;
101
+ will-change: transform;
102
+ backface-visibility: hidden;
88
103
  top: 0;
89
104
  background-color: $white;
90
- z-index: $z_8;
105
+ z-index: $z_9;
91
106
  }
92
107
 
93
108
  // @include pb_card;
@@ -97,41 +112,31 @@ body.ReactModal__Body--open {
97
112
  max-height: calc(100vh - #{$gutter * 2});
98
113
  max-width: calc(100vw - #{$gutter * 2});
99
114
  overflow: auto;
100
- animation-name: modalFadeIn;
101
115
  animation-duration: $animation-duration;
102
116
  outline: none;
103
- animation-timing-function: $easeInOutQuint;
104
- transition: transform 0.3s ease-in-out;
105
117
 
106
- &.drawer_border_full {
107
- box-shadow: none;
108
- border: 2px solid #f3f7fb;
109
- }
110
-
111
- &.drawer_border_right {
112
- border-right: 2px solid #f3f7fb;
113
- }
114
-
115
- &.drawer_border_left {
116
- border-left: 2px solid #f3f7fb;
118
+ // General _before_close styles
119
+ &[class*="_before_close"] {
120
+ animation-name: modalFadeOut;
121
+ animation-duration: $animation-duration;
117
122
  }
118
123
 
119
124
  &[class*="_left"] {
120
125
  animation-name: modalFadeInLeft;
121
- &[class*="_before_close"] {
122
- animation-name: modalFadeOutLeft;
123
- animation-duration: $animation-duration;
124
- opacity: $opacity_hidden;
125
- }
126
+ }
127
+
128
+ &[class*="_left"][class*="_before_close"] {
129
+ animation-name: modalFadeOutLeft;
130
+ animation-duration: $animation-duration;
126
131
  }
127
132
 
128
133
  &[class*="_right"] {
129
134
  animation-name: modalFadeInRight;
130
- &[class*="_before_close"] {
131
- animation-name: modalFadeOutRight;
132
- animation-duration: $animation-duration;
133
- opacity: $opacity_hidden;
134
- }
135
+ }
136
+
137
+ &[class*="_right"][class*="_before_close"] {
138
+ animation-name: modalFadeOutRight;
139
+ animation-duration: $animation-duration;
135
140
  }
136
141
 
137
142
  &[class*="_xs_"] {
@@ -164,17 +169,23 @@ body.ReactModal__Body--open {
164
169
  }
165
170
 
166
171
  &_after_open {
167
- opacity: $opacity_visible;
168
172
  }
169
173
 
170
- &.no-background {
171
- background-color: transparent;
174
+ &.drawer_border_full {
175
+ box-shadow: none;
176
+ border: 2px solid #f3f7fb;
172
177
  }
173
178
 
174
- &[class*="_before_close"] {
175
- animation-name: modalFadeOut;
176
- animation-duration: $animation-duration;
177
- opacity: $opacity_hidden;
179
+ &.drawer_border_right {
180
+ border-right: 2px solid #f3f7fb;
181
+ }
182
+
183
+ &.drawer_border_left {
184
+ border-left: 2px solid #f3f7fb;
185
+ }
186
+
187
+ &.no-background {
188
+ background-color: transparent;
178
189
  }
179
190
 
180
191
  &_close_icon {
@@ -196,12 +207,10 @@ body.ReactModal__Body--open {
196
207
  animation-duration: $animation-duration;
197
208
 
198
209
  &_after_open {
199
- opacity: $opacity_visible;
200
210
  }
201
211
  &_before_close {
202
212
  animation-name: overlayFadeOut;
203
213
  animation-duration: $animation-duration;
204
- opacity: $opacity_hidden;
205
214
  }
206
215
  &[class*="full_height"] {
207
216
  &[class*="_left"]{
@@ -258,12 +267,12 @@ body.ReactModal__Body--open {
258
267
  &[class*="_xl_"] {
259
268
  width: $xlarge;
260
269
  .dialog_footer {
261
- width: $xlarge;
270
+ width: $xlarge;
271
+ }
262
272
  }
263
273
  }
264
274
  }
265
275
  }
266
- }
267
276
 
268
277
  &_no_overlay {
269
278
  position: fixed;
@@ -280,20 +289,18 @@ body.ReactModal__Body--open {
280
289
  overflow: none; /* Ensure body remains scrollable */
281
290
  pointer-events: none; /* Allow interaction inside the drawer itself */
282
291
 
283
- body.ReactModal__Body--open {
292
+ body.PBDrawer--open {
284
293
  overflow: none; /* Ensure body remains scrollable */
285
294
  pointer-events: none; /* Allow interaction inside the drawer itself */
286
295
  }
287
296
 
288
297
  &_after_open {
289
- opacity: $opacity_visible;
290
298
  overflow: none; /* Ensure body remains scrollable */
291
299
  pointer-events: none; /* Allow interaction inside the drawer itself */
292
300
  }
293
301
  &_before_close {
294
302
  animation-name: overlayFadeOut;
295
303
  animation-duration: $animation-duration;
296
- opacity: $opacity_hidden;
297
304
  }
298
305
  &[class*="full_height"] {
299
306
  &[class*="_left"]{
@@ -350,116 +357,22 @@ body.ReactModal__Body--open {
350
357
  &[class*="_xl_"] {
351
358
  width: $xlarge;
352
359
  .dialog_footer {
353
- width: $xlarge;
354
- }
355
- }
356
- }
357
- }
358
- }
359
-
360
- [class*="drawer_body"] {
361
- padding: $space_sm;
362
- }
363
-
364
- [class*="drawer_header"] {
365
- padding: $space_sm;
366
- }
367
-
368
- [class*="drawer_footer"] {
369
- padding: $space_sm;
370
- }
371
-
372
- //styles specific to rails version of kit
373
- // rails version has own wrapper because of the way the overlay functions for the HTML drawer used to create this
374
- .pb_drawer_wrapper_rails {
375
- $medium: 500px;
376
- $large: 800px;
377
- $xlarge: 1150px;
378
-
379
- &[class*="full_height"] {
380
- &[class*="_left"]{
381
- .pb_drawer_rails {
382
- margin: unset !important;
383
- margin-right: auto !important;
384
- }
385
- }
386
-
387
- &[class*="_center"]{
388
- justify-content: center;
389
- }
390
-
391
- &[class*="_right"]{
392
- .pb_drawer_rails {
393
- margin: unset !important;
394
- margin-left: auto !important;
395
- }
396
- }
397
-
398
- .pb_drawer {
399
- height: 100% !important;
400
- max-height: 100% !important;
401
- max-width: 100%;
402
- // This empty div only has height when drawer is full height.
403
- // Fix for drawer body content disappearing behind sticky footer
404
- .drawer-pseudo-footer {
405
- height: $space_xl * 2;
406
- }
407
- .drawer_footer {
408
- position:fixed;
409
- bottom: 0;
410
- background-color: $white;
411
- max-width: 100%;
412
- }
413
- &[class*="_sm"] {
414
- width: $medium;
415
- .drawer_footer {
416
- width: $medium;
417
- }
418
- }
419
- &[class*="_md"] {
420
- width: $large;
421
- .drawer_footer {
422
- width: $large;
423
- }
424
- }
425
- &[class*="_lg"] {
426
- width: $xlarge;
427
- .drawer_footer {
428
- width: $xlarge;
360
+ width: $xlarge;
361
+ }
429
362
  }
430
363
  }
431
364
  }
432
365
  }
433
366
 
434
- // Fixes for stylesheets in nitro that were conflicting with our kit. DO NOT REMOVE.
435
- // Conflicts were only apparent in nitro, not in playbook local env
436
- .pb_drawer_rails {
437
- position: fixed !important;
438
- top: 0 !important;
439
- padding: unset !important;
440
- margin: auto;
441
-
367
+ [class*="drawer_body"] {
368
+ padding: $space_sm;
442
369
  }
443
370
 
444
- // Overlay for rails kit
445
- drawer::backdrop {
446
- position: fixed;
447
- top: 0;
448
- left: 0;
449
- right: 0;
450
- bottom: 0;
451
- display: flex;
452
- align-items: center;
453
- justify-content: center;
454
- background-color: rgba($bg_dark, $opacity_4);
455
- animation-name: overlayFade;
456
- animation-duration: 0.2s;
371
+ [class*="drawer_header"] {
372
+ padding: $space_sm;
457
373
  }
458
374
 
459
- .drawer-button-class {
460
- background-color: unset;
461
- border: none;
462
- cursor: pointer;
375
+ [class*="drawer_footer"] {
376
+ padding: $space_sm;
463
377
  }
464
378
  }
465
- }
@@ -1,8 +1,12 @@
1
1
  import React, { useState, useEffect } from "react";
2
2
  import classnames from "classnames";
3
- import Modal from "react-modal";
4
3
 
5
- import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
4
+ import {
5
+ buildAriaProps,
6
+ buildCss,
7
+ buildDataProps,
8
+ buildHtmlProps,
9
+ } from "../utilities/props";
6
10
  import { globalProps } from "../utilities/globalProps";
7
11
 
8
12
  import { DialogContext } from "../pb_dialog/_dialog_context";
@@ -53,13 +57,19 @@ const Drawer = (props: DrawerProps): React.ReactElement => {
53
57
  let globalPropsString: string = globalProps(props);
54
58
 
55
59
  // Check if the string contains any of the prefixes
56
- const containsPrefix = ['p_', 'pb_', 'pt_', 'pl_', 'pr_', 'px_', 'py_'].some((prefix) =>
57
- globalPropsString.includes(prefix)
58
- );
60
+ const containsPrefix = [
61
+ "p_",
62
+ "pb_",
63
+ "pt_",
64
+ "pl_",
65
+ "pr_",
66
+ "px_",
67
+ "py_",
68
+ ].some((prefix) => globalPropsString.includes(prefix));
59
69
 
60
70
  // If none of the prefixes are found, append 'p_sm' to the string
61
71
  if (!containsPrefix) {
62
- globalPropsString += ' p_sm';
72
+ globalPropsString += " p_sm";
63
73
  }
64
74
 
65
75
  const drawerClassNames = {
@@ -67,9 +77,9 @@ const Drawer = (props: DrawerProps): React.ReactElement => {
67
77
  "pb_drawer",
68
78
  buildCss("pb_drawer", size, placement),
69
79
  {
70
- "drawer_border_full": border === "full",
71
- "drawer_border_right": border === "right",
72
- "drawer_border_left": border === "left",
80
+ drawer_border_full: border === "full",
81
+ drawer_border_right: border === "right",
82
+ drawer_border_left: border === "left",
73
83
  }
74
84
  )} ${globalPropsString}`,
75
85
  afterOpen: "pb_drawer_after_open",
@@ -82,19 +92,18 @@ const Drawer = (props: DrawerProps): React.ReactElement => {
82
92
  };
83
93
 
84
94
  const overlayClassNames = {
85
- base: `pb_drawer${overlay ? '_overlay' : '_no_overlay'} ${fullHeight !== null && fullHeightClassNames()} ${!overlay ? 'no-background' : ''}`,
95
+ base: `pb_drawer${overlay ? "_overlay" : "_no_overlay"} ${
96
+ fullHeight !== null && fullHeightClassNames()
97
+ } ${!overlay ? "no-background" : ""}`,
86
98
  afterOpen: "pb_drawer_overlay_after_open",
87
99
  beforeClose: "pb_drawer_overlay_before_close",
88
100
  };
89
101
 
90
- const classes = classnames(
91
- buildCss("pb_drawer_wrapper"),
92
- className
93
- );
102
+ const classes = classnames(buildCss("pb_drawer_wrapper"), className);
94
103
 
95
104
  const [triggerOpened, setTriggerOpened] = useState(false);
96
105
 
97
- const breakpointWidths: Record<DrawerProps['breakpoint'], number> = {
106
+ const breakpointWidths: Record<DrawerProps["breakpoint"], number> = {
98
107
  none: 0,
99
108
  xs: 575,
100
109
  sm: 768,
@@ -107,7 +116,7 @@ const Drawer = (props: DrawerProps): React.ReactElement => {
107
116
  const [isBreakpointOpen, setIsBreakpointOpen] = useState(false);
108
117
 
109
118
  useEffect(() => {
110
- if (breakpoint === 'none') return;
119
+ if (breakpoint === "none") return;
111
120
 
112
121
  const handleResize = () => {
113
122
  const width = window.innerWidth;
@@ -120,39 +129,57 @@ const Drawer = (props: DrawerProps): React.ReactElement => {
120
129
  }
121
130
  };
122
131
 
123
- window.addEventListener('resize', handleResize);
132
+ window.addEventListener("resize", handleResize);
124
133
 
125
134
  // Call handler once on mount to set initial state
126
135
  handleResize();
127
136
 
128
137
  return () => {
129
- window.removeEventListener('resize', handleResize);
138
+ window.removeEventListener("resize", handleResize);
130
139
  };
131
140
  }, [breakpoint]);
132
141
 
133
- const modalIsOpened = trigger ? triggerOpened : (opened || isBreakpointOpen);
142
+ const modalIsOpened = trigger ? triggerOpened : opened || isBreakpointOpen;
143
+
144
+ const [animationState, setAnimationState] = useState("");
145
+
146
+ useEffect(() => {
147
+ if (modalIsOpened) {
148
+ setAnimationState("afterOpen");
149
+ } else if (!modalIsOpened && animationState === "afterOpen") {
150
+ setAnimationState("beforeClose");
151
+ setTimeout(() => {
152
+ setAnimationState("");
153
+ }, 200); // closeTimeoutMS
154
+ }
155
+ }, [modalIsOpened]);
156
+
157
+ const isModalVisible = modalIsOpened || animationState === "beforeClose";
134
158
 
135
159
  useEffect(() => {
136
- const sizeMap: Record<DrawerProps['size'], string> = {
137
- xl: '365px',
138
- lg: '300px',
139
- md: '250px',
140
- sm: '200px',
141
- xs: '64px',
160
+ const sizeMap: Record<DrawerProps["size"], string> = {
161
+ xl: "365px",
162
+ lg: "300px",
163
+ md: "250px",
164
+ sm: "200px",
165
+ xs: "64px",
142
166
  };
143
- const body = document.querySelector('body');
167
+ const body = document.querySelector("body");
144
168
 
145
- if (modalIsOpened && behavior === 'push' && body) {
146
- if (placement === 'left') {
169
+ if (modalIsOpened && behavior === "push" && body) {
170
+ if (placement === "left") {
147
171
  body.style.cssText = `margin-left: ${sizeMap[size]} !important; margin-right: '' !important;`;
148
- } else if (placement === 'right') {
172
+ } else if (placement === "right") {
149
173
  body.style.cssText = `margin-right: ${sizeMap[size]} !important; margin-left: '' !important;`;
150
174
  }
151
175
 
152
- body.classList.add('ReactModal__Body--open');
176
+ body.classList.add("PBDrawer__Body--open");
153
177
  } else if (body) {
154
- body.style.cssText = ''; // Clear the styles when modal is closed or behavior is not 'push'
155
- body.classList.remove('ReactModal__Body--open');
178
+ if (body.classList.contains("PBDrawer__Body--open")) {
179
+ body.classList.add("PBDrawer__Body--close");
180
+ }
181
+ body.style.cssText = ""; // Clear the styles when modal is closed or behavior is not 'push'
182
+ body.classList.remove("PBDrawer__Body--open");
156
183
  }
157
184
  }, [modalIsOpened, behavior, placement, size]);
158
185
 
@@ -172,22 +199,27 @@ const Drawer = (props: DrawerProps): React.ReactElement => {
172
199
  {...htmlProps}
173
200
  className={classes}
174
201
  >
175
- <Modal
176
- ariaHideApp={false}
177
- className={drawerClassNames}
178
- closeTimeoutMS={200}
179
- contentLabel="Minimal Modal Example"
180
- id={id}
181
- isOpen={modalIsOpened}
182
- onRequestClose={onClose}
183
- overlayClassName={overlayClassNames}
184
- shouldCloseOnOverlayClick={overlay}
185
- >
186
- <>
202
+ {isModalVisible && (
203
+ <div
204
+ className={classnames(overlayClassNames.base, {
205
+ [overlayClassNames.afterOpen]: animationState === "afterOpen",
206
+ [overlayClassNames.beforeClose]: animationState === "beforeClose",
207
+ })}
208
+ id={id}
209
+ onClick={overlay ? onClose : undefined}
210
+ >
211
+ <div
212
+ className={classnames(drawerClassNames.base, {
213
+ [drawerClassNames.afterOpen]: animationState === "afterOpen",
214
+ [drawerClassNames.beforeClose]: animationState === "beforeClose",
215
+ })}
216
+ onClick={(e) => e.stopPropagation()}
217
+ >
187
218
  {children}
188
- </>
189
- </Modal>
190
- </div>
219
+ </div>
220
+ </div>
221
+ )}
222
+ </div>
191
223
  </DialogContext.Provider>
192
224
  );
193
225
  };
@@ -1,6 +1,7 @@
1
1
  import React, { useState } from 'react';
2
- import { render, cleanup, fireEvent, screen } from '../utilities/test-utils';
2
+ import { render, fireEvent, screen } from '../utilities/test-utils';
3
3
  import { Drawer, Button } from 'playbook-ui';
4
+ import { waitFor } from '@testing-library/react';
4
5
 
5
6
  const size = 'sm';
6
7
 
@@ -11,9 +12,10 @@ function DrawerTest({ props }) {
11
12
 
12
13
  return (
13
14
  <>
14
- <Button onClick={open}>{'Open Drawer'}</Button>
15
+ <Button onClick={open}>{'Open Drawer'}</Button>
15
16
  <Drawer
16
17
  className="wrapper"
18
+ id="drawer-id"
17
19
  onClose={close}
18
20
  opened={isOpen}
19
21
  placement="left"
@@ -27,24 +29,17 @@ function DrawerTest({ props }) {
27
29
  );
28
30
  }
29
31
 
30
- afterEach(cleanup);
31
-
32
32
  test('renders with the right border class when border prop is right', async () => {
33
33
  render(<DrawerTest props={{ border: 'right' }} />);
34
34
 
35
35
  fireEvent.click(screen.getByText('Open Drawer'));
36
36
 
37
- const drawer = await screen.findByRole('dialog');
38
- expect(drawer).toHaveClass('drawer_border_right');
39
- });
37
+ await waitFor(() => expect(document.getElementById('drawer-id')).toBeInTheDocument());
40
38
 
41
- test('renders with the left border class when border prop is left', async () => {
42
- render(<DrawerTest props={{ border: 'left' }} />);
43
-
44
- fireEvent.click(screen.getByText('Open Drawer'));
39
+ const container = document.getElementById('drawer-id');
40
+ const drawer = container.querySelector('#drawer-id .pb_drawer');
45
41
 
46
- const drawer = await screen.findByRole('dialog');
47
- expect(drawer).toHaveClass('drawer_border_left');
42
+ expect(drawer).toHaveClass('drawer_border_right');
48
43
  });
49
44
 
50
45
  test('renders with the full border class when border prop is full', async () => {
@@ -52,7 +47,10 @@ test('renders with the full border class when border prop is full', async () =>
52
47
 
53
48
  fireEvent.click(screen.getByText('Open Drawer'));
54
49
 
55
- const drawer = await screen.findByRole('dialog');
50
+ await waitFor(() => expect(document.getElementById('drawer-id')).toBeInTheDocument());
51
+
52
+ const container = document.getElementById('drawer-id');
53
+ const drawer = container.querySelector('#drawer-id .pb_drawer');
56
54
  expect(drawer).toHaveClass('drawer_border_full');
57
55
  });
58
56
 
@@ -61,7 +59,10 @@ test('does not have a border class when border prop is none', async () => {
61
59
 
62
60
  fireEvent.click(screen.getByText('Open Drawer'));
63
61
 
64
- const drawer = await screen.findByRole('dialog');
62
+ await waitFor(() => expect(document.getElementById('drawer-id')).toBeInTheDocument());
63
+
64
+ const container = document.getElementById('drawer-id');
65
+ const drawer = container.querySelector('#drawer-id .pb_drawer');
65
66
  expect(drawer).not.toHaveClass('drawer_border_right');
66
67
  expect(drawer).not.toHaveClass('drawer_border_left');
67
68
  expect(drawer).not.toHaveClass('drawer_border_full');
@@ -72,6 +73,9 @@ test('renders the correct size class for a large drawer', async () => {
72
73
 
73
74
  fireEvent.click(screen.getByText('Open Drawer'));
74
75
 
75
- const drawer = await screen.findByRole('dialog');
76
+ await waitFor(() => expect(document.getElementById('drawer-id')).toBeInTheDocument());
77
+
78
+ const container = document.getElementById('drawer-id');
79
+ const drawer = container.querySelector('#drawer-id .pb_drawer');
76
80
  expect(drawer).toHaveClass('pb_drawer pb_drawer_lg_left');
77
81
  });
@@ -53,6 +53,7 @@
53
53
  }
54
54
 
55
55
  .pb_dropdown_container {
56
+ position: absolute;
56
57
  background-color: $white;
57
58
  overflow: hidden;
58
59
  box-shadow: $shadow_deep;