diff --git a/.changeset/rare-geese-melt.md b/.changeset/rare-geese-melt.md new file mode 100644 index 00000000000..bd324284689 --- /dev/null +++ b/.changeset/rare-geese-melt.md @@ -0,0 +1,5 @@ +--- +"@primer/react": minor +--- + +Dialog: `full-screen` and `action-sheet` variants diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-colorblind-linux.png new file mode 100644 index 00000000000..91a733129c3 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-dimmed-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-dimmed-linux.png new file mode 100644 index 00000000000..543cf54eee1 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-high-contrast-linux.png new file mode 100644 index 00000000000..6032c0df663 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-linux.png new file mode 100644 index 00000000000..d16e3f2b42a Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-tritanopia-linux.png new file mode 100644 index 00000000000..91a733129c3 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-light-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-light-colorblind-linux.png new file mode 100644 index 00000000000..ad243dec84b Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-light-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-light-high-contrast-linux.png new file mode 100644 index 00000000000..80a330b1d8b Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-light-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-light-linux.png new file mode 100644 index 00000000000..de151d68807 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-light-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-light-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-light-tritanopia-linux.png new file mode 100644 index 00000000000..ad243dec84b Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Bottom-Sheet-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-colorblind-linux.png new file mode 100644 index 00000000000..27ed70d5b20 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-dimmed-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-dimmed-linux.png new file mode 100644 index 00000000000..76bb9f88386 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-high-contrast-linux.png new file mode 100644 index 00000000000..c86b0e30691 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-linux.png new file mode 100644 index 00000000000..8b4cece3666 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-tritanopia-linux.png new file mode 100644 index 00000000000..27ed70d5b20 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-light-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-light-colorblind-linux.png new file mode 100644 index 00000000000..e3736f47f9e Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-light-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-light-high-contrast-linux.png new file mode 100644 index 00000000000..231d37e7374 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-light-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-light-linux.png new file mode 100644 index 00000000000..768f747fe4f Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-light-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-light-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-light-tritanopia-linux.png new file mode 100644 index 00000000000..e3736f47f9e Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Full-Screen-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-colorblind-linux.png new file mode 100644 index 00000000000..0ffc13b0934 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-dimmed-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-dimmed-linux.png new file mode 100644 index 00000000000..a995b84d36a Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-high-contrast-linux.png new file mode 100644 index 00000000000..b736c80aa33 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-linux.png new file mode 100644 index 00000000000..dfb81e8d203 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-tritanopia-linux.png new file mode 100644 index 00000000000..0ffc13b0934 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-light-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-light-colorblind-linux.png new file mode 100644 index 00000000000..00c205cbe95 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-light-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-light-high-contrast-linux.png new file mode 100644 index 00000000000..ff327982da5 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-light-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-light-linux.png new file mode 100644 index 00000000000..4ac2ccd9dfa Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-light-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-light-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-light-tritanopia-linux.png new file mode 100644 index 00000000000..00c205cbe95 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Non-Declaritve-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-colorblind-linux.png new file mode 100644 index 00000000000..f403eded856 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-dimmed-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-dimmed-linux.png new file mode 100644 index 00000000000..8f6a4104383 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-high-contrast-linux.png new file mode 100644 index 00000000000..3c617a56918 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-linux.png new file mode 100644 index 00000000000..a3238bd9333 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-tritanopia-linux.png new file mode 100644 index 00000000000..f403eded856 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-light-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-light-colorblind-linux.png new file mode 100644 index 00000000000..231d5f5177f Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-light-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-light-high-contrast-linux.png new file mode 100644 index 00000000000..334e7b96773 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-light-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-light-linux.png new file mode 100644 index 00000000000..e61d5b15617 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-light-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-light-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-light-tritanopia-linux.png new file mode 100644 index 00000000000..231d5f5177f Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Responsive-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-colorblind-linux.png new file mode 100644 index 00000000000..edc921a7a81 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-dimmed-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-dimmed-linux.png new file mode 100644 index 00000000000..440d8323c34 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-high-contrast-linux.png new file mode 100644 index 00000000000..dc7417125f0 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-linux.png new file mode 100644 index 00000000000..c4439d9948c Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-tritanopia-linux.png new file mode 100644 index 00000000000..edc921a7a81 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-light-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-light-colorblind-linux.png new file mode 100644 index 00000000000..8fcec487947 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-light-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-light-high-contrast-linux.png new file mode 100644 index 00000000000..e8db146f3aa Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-light-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-light-linux.png new file mode 100644 index 00000000000..53e57eefd33 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-light-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-light-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-light-tritanopia-linux.png new file mode 100644 index 00000000000..8fcec487947 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Large-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-colorblind-linux.png new file mode 100644 index 00000000000..0738abb6f2b Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-dimmed-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-dimmed-linux.png new file mode 100644 index 00000000000..d17944dac1f Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-high-contrast-linux.png new file mode 100644 index 00000000000..6e777648b74 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-linux.png new file mode 100644 index 00000000000..cf8ff570cb5 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-tritanopia-linux.png new file mode 100644 index 00000000000..0738abb6f2b Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-light-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-light-colorblind-linux.png new file mode 100644 index 00000000000..f813063ae14 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-light-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-light-high-contrast-linux.png new file mode 100644 index 00000000000..c8489e63bdb Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-light-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-light-linux.png new file mode 100644 index 00000000000..77a124ee3f7 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-light-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-light-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-light-tritanopia-linux.png new file mode 100644 index 00000000000..f813063ae14 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-Small-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-colorblind-linux.png new file mode 100644 index 00000000000..6357e78a63e Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-dimmed-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-dimmed-linux.png new file mode 100644 index 00000000000..36e43711f68 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-high-contrast-linux.png new file mode 100644 index 00000000000..d058b93a977 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-linux.png new file mode 100644 index 00000000000..31a130f51f5 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-tritanopia-linux.png new file mode 100644 index 00000000000..6357e78a63e Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-light-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-light-colorblind-linux.png new file mode 100644 index 00000000000..24ab03f71c8 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-light-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-light-high-contrast-linux.png new file mode 100644 index 00000000000..c46ceb930cf Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-light-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-light-linux.png new file mode 100644 index 00000000000..469a747efb2 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-light-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-light-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-light-tritanopia-linux.png new file mode 100644 index 00000000000..24ab03f71c8 Binary files /dev/null and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Size-X-Large-Test-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-colorblind-linux.png index 304040711a8..e9054a40acb 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-colorblind-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-dimmed-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-dimmed-linux.png index f72ac7b90bb..2c06f9402a5 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-dimmed-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-high-contrast-linux.png index f748f336d71..e89b487a252 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-high-contrast-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-linux.png index 95832458825..dad20b634f9 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-tritanopia-linux.png index e345db8a985..0b299534e34 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-tritanopia-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-colorblind-linux.png index 9451f77c8b8..d8d05d004b3 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-colorblind-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-high-contrast-linux.png index d76e58cc8e8..c63aebdd0a0 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-high-contrast-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-linux.png index 260a68b1361..a970c3d47fa 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-tritanopia-linux.png index c09b6919eda..e82c292a81d 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-tritanopia-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-Stress-Test-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-colorblind-linux.png index ca50e1e1c1a..4b3371ae092 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-colorblind-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-dimmed-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-dimmed-linux.png index f2a27d6486a..6103b498919 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-dimmed-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-high-contrast-linux.png index f8d6c5a27cc..f3d717da7df 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-high-contrast-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-linux.png index d1134be3719..367ef1a9eda 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-tritanopia-linux.png index d90d3360b40..2c5504b3ef1 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-tritanopia-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-colorblind-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-colorblind-linux.png index 76f93cb515f..c1e26568351 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-colorblind-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-high-contrast-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-high-contrast-linux.png index e9dba1a061b..e4c92b589aa 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-high-contrast-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-linux.png index f2a7e6f4563..1233f3bf253 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-linux.png differ diff --git a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-tritanopia-linux.png b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-tritanopia-linux.png index b3c5ecde99c..7dde2ed7efa 100644 Binary files a/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-tritanopia-linux.png and b/.playwright/snapshots/components/Dialog.test.ts-snapshots/Dialog-With-Custom-Renderers-light-tritanopia-linux.png differ diff --git a/e2e/components/Dialog.test.ts b/e2e/components/Dialog.test.ts index 82255b03545..81d8426ec22 100644 --- a/e2e/components/Dialog.test.ts +++ b/e2e/components/Dialog.test.ts @@ -32,6 +32,190 @@ test.describe('Dialog', () => { } }) + test.describe('Bottom Sheet', () => { + for (const theme of themes) { + test.describe(theme, () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--bottom-sheet', + globals: { + colorScheme: theme, + }, + }) + expect(await page.screenshot({animations: 'disabled'})).toMatchSnapshot(`Dialog.Bottom Sheet.${theme}.png`) + }) + + test('axe @aat', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--bottom-sheet', + globals: { + colorScheme: theme, + }, + }) + await expect(page).toHaveNoViolations() + }) + }) + } + }) + + test.describe('Full Screen', () => { + for (const theme of themes) { + test.describe(theme, () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--full-screen', + globals: { + colorScheme: theme, + }, + }) + expect(await page.screenshot({animations: 'disabled'})).toMatchSnapshot(`Dialog.Full Screen.${theme}.png`) + }) + + test('axe @aat', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--full-screen', + globals: { + colorScheme: theme, + }, + }) + await expect(page).toHaveNoViolations() + }) + }) + } + }) + + test.describe('Non Declaritive', () => { + for (const theme of themes) { + test.describe(theme, () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--non-declaritive', + globals: { + colorScheme: theme, + }, + }) + expect(await page.screenshot({animations: 'disabled'})).toMatchSnapshot(`Dialog.Non Declaritve.${theme}.png`) + }) + + test('axe @aat', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--non-declaritive', + globals: { + colorScheme: theme, + }, + }) + await expect(page).toHaveNoViolations() + }) + }) + } + }) + + test.describe('Responsive', () => { + for (const theme of themes) { + test.describe(theme, () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--responsive', + globals: { + colorScheme: theme, + }, + }) + expect(await page.screenshot({animations: 'disabled'})).toMatchSnapshot(`Dialog.Responsive.${theme}.png`) + }) + + test('axe @aat', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--responsive', + globals: { + colorScheme: theme, + }, + }) + await expect(page).toHaveNoViolations() + }) + }) + } + }) + + test.describe('Size Large', () => { + for (const theme of themes) { + test.describe(theme, () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--size-large', + globals: { + colorScheme: theme, + }, + }) + expect(await page.screenshot({animations: 'disabled'})).toMatchSnapshot(`Dialog.Size Large.${theme}.png`) + }) + + test('axe @aat', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--size-large', + globals: { + colorScheme: theme, + }, + }) + await expect(page).toHaveNoViolations() + }) + }) + } + }) + + test.describe('Size Small', () => { + for (const theme of themes) { + test.describe(theme, () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--size-small', + globals: { + colorScheme: theme, + }, + }) + expect(await page.screenshot({animations: 'disabled'})).toMatchSnapshot(`Dialog.Size Small.${theme}.png`) + }) + + test('axe @aat', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--size-small', + globals: { + colorScheme: theme, + }, + }) + await expect(page).toHaveNoViolations() + }) + }) + } + }) + + test.describe('Size X Dialog', () => { + for (const theme of themes) { + test.describe(theme, () => { + test('default @vrt', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--size-x-large', + globals: { + colorScheme: theme, + }, + }) + expect(await page.screenshot({animations: 'disabled'})).toMatchSnapshot( + `Dialog.Size X Large Test.${theme}.png`, + ) + }) + + test('axe @aat', async ({page}) => { + await visit(page, { + id: 'components-dialog-features--size-x-large', + globals: { + colorScheme: theme, + }, + }) + await expect(page).toHaveNoViolations() + }) + }) + } + }) + test.describe('Stress Test', () => { for (const theme of themes) { test.describe(theme, () => { @@ -42,8 +226,6 @@ test.describe('Dialog', () => { colorScheme: theme, }, }) - - await page.getByRole('button', {name: 'Show dialog'}).click() expect(await page.screenshot({animations: 'disabled'})).toMatchSnapshot(`Dialog.Stress Test.${theme}.png`) }) @@ -71,7 +253,6 @@ test.describe('Dialog', () => { }, }) - await page.getByRole('button', {name: 'Show dialog'}).click() expect(await page.screenshot({animations: 'disabled'})).toMatchSnapshot( `Dialog.With Custom Renderers.${theme}.png`, ) diff --git a/package-lock.json b/package-lock.json index 4dbc6c7c7c5..92db1eef488 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@primer/react", - "version": "36.5.0", + "version": "36.4.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@primer/react", - "version": "36.5.0", + "version": "36.4.0", "license": "MIT", "dependencies": { "@github/combobox-nav": "^2.1.5", diff --git a/src/ConfirmationDialog/ConfirmationDialog.test.tsx b/src/ConfirmationDialog/ConfirmationDialog.test.tsx index 37792d8153c..b334b4044e0 100644 --- a/src/ConfirmationDialog/ConfirmationDialog.test.tsx +++ b/src/ConfirmationDialog/ConfirmationDialog.test.tsx @@ -12,6 +12,22 @@ import {ThemeProvider} from '../ThemeProvider' import {SSRProvider} from '../utils/ssr' import {behavesAsComponent, checkExports} from '../utils/testing' +// The Dialog uses `matchMedia` to determine whether or not to reduce motion. + +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // deprecated + removeListener: jest.fn(), // deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), +}) + const Basic = ({confirmButtonType}: Pick, 'confirmButtonType'>) => { const [isOpen, setIsOpen] = useState(false) const buttonRef = useRef(null) diff --git a/src/ConfirmationDialog/ConfirmationDialog.tsx b/src/ConfirmationDialog/ConfirmationDialog.tsx index fa951fd6962..1477ccb79fa 100644 --- a/src/ConfirmationDialog/ConfirmationDialog.tsx +++ b/src/ConfirmationDialog/ConfirmationDialog.tsx @@ -17,8 +17,7 @@ export interface ConfirmationDialogProps { * Required. This callback is invoked when a gesture to close the dialog * is performed. The first argument indicates the gesture. */ - onClose: (gesture: 'confirm' | 'close-button' | 'cancel' | 'escape') => void - + onClose: (gesture: 'confirm' | 'cancel' | 'close-button' | 'escape') => void /** * Required. The title of the ConfirmationDialog. This is usually a brief * question. diff --git a/src/DataTable/__tests__/ErrorDialog.test.tsx b/src/DataTable/__tests__/ErrorDialog.test.tsx index f15164e4748..cb0fe0ab1da 100644 --- a/src/DataTable/__tests__/ErrorDialog.test.tsx +++ b/src/DataTable/__tests__/ErrorDialog.test.tsx @@ -3,6 +3,22 @@ import {render, screen} from '@testing-library/react' import React from 'react' import {ErrorDialog} from '../ErrorDialog' +// The ErrorDialog uses `matchMedia` because the ConfirmationDialog uses it to determine whether or not to reduce motion. + +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // deprecated + removeListener: jest.fn(), // deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), +}) + describe('Table.ErrorDialog', () => { it('should use a default title of "Error" if `title` is not provided', () => { render() diff --git a/src/Dialog/Dialog.docs.json b/src/Dialog/Dialog.docs.json index 5b803588341..ca21a3b1669 100644 --- a/src/Dialog/Dialog.docs.json +++ b/src/Dialog/Dialog.docs.json @@ -37,14 +37,19 @@ }, { "name": "onClose", - "type": "(gesture: 'close-button' | 'escape') => void", - "description": "This method is invoked when a gesture to close the dialog is used (either an Escape key press or clicking the 'X' in the top-right corner). The gesture argument indicates the gesture that was used to close the dialog (either 'close-button' or 'escape')." + "type": "(gesture: 'close-button' | 'escape' | 'drag' | 'overlay') => void", + "description": "This method is invoked when a gesture to close the dialog is used (either an Escape key press, clicking/tapping on the backdrop, clicking/tapping the 'X' in the top-right corner or dragging away a bottom sheet). The gesture argument indicates the gesture that was used to close the dialog." }, { "name": "role", "type": "'dialog' | 'alertdialog'", "description": "The ARIA role to assign to this dialog." }, + { + "name": "type", + "type": "'default' | 'full-screen' | 'bottom-sheet'", + "description": "The type of dialog to render. 'default' renders a dialog in the center of the screen. 'full-screen' renders the dialog full screen and ignored the width and height. 'full-screen' is often used for mobile breakpoints." + }, { "name": "width", "type": "'small' | 'medium' | 'large' | 'xlarge'" diff --git a/src/Dialog/Dialog.features.stories.tsx b/src/Dialog/Dialog.features.stories.tsx index 33331260526..5cfc52c357b 100644 --- a/src/Dialog/Dialog.features.stories.tsx +++ b/src/Dialog/Dialog.features.stories.tsx @@ -3,7 +3,8 @@ import {Meta} from '@storybook/react' import {BaseStyles, ThemeProvider, Box, TextInput} from '..' import {Button} from '../Button' -import {Dialog, DialogProps, DialogWidth, DialogHeight} from './Dialog' +import Text from '../Text' +import {Dialog, DialogProps} from './Dialog' /* Dialog Version 2 */ @@ -23,45 +24,10 @@ export default { ) }, ], - args: { - width: 'xlarge', - height: 'auto', - subtitle: true, - }, - argTypes: { - width: { - control: { - type: 'radio', - }, - options: ['small', 'medium', 'large', 'xlarge'], - }, - height: { - control: { - type: 'radio', - }, - options: ['small', 'large', 'auto'], - }, - subtitle: { - name: 'show subtitle', - control: { - type: 'boolean', - }, - }, - title: {table: {disable: true}}, - - renderHeader: {table: {disable: true}}, - renderBody: {table: {disable: true}}, - renderFooter: {table: {disable: true}}, - onClose: {table: {disable: true}}, - role: {table: {disable: true}}, - ref: {table: {disable: true}}, - key: {table: {disable: true}}, - footerButtons: {table: {disable: true}}, - }, } as Meta const lipsum = ( -
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sollicitudin mauris maximus elit sagittis, nec lobortis ligula elementum. Nam iaculis, urna nec lobortis posuere, eros urna venenatis eros, vel accumsan turpis @@ -100,63 +66,55 @@ const lipsum = ( pharetra dolor at dictum tempor. Quisque ut est a ligula hendrerit sodales. Curabitur ornare a nulla in laoreet. Maecenas semper mi egestas, dignissim nisi et, elementum neque.

-
+ ) -interface DialogStoryProps { - width: DialogWidth - height: DialogHeight - subtitle: boolean -} -function CustomHeader({ - title, - subtitle, - dialogLabelId, - dialogDescriptionId, - onClose, -}: React.PropsWithChildren) { - const onCloseClick = useCallback(() => { - onClose('close-button') - }, [onClose]) - if (typeof title === 'string' && typeof subtitle === 'string') { - return ( - -

{title.toUpperCase()}

-

{subtitle.toLowerCase()}

- -
- ) +export const WithCustomRenderers = () => { + const [isOpen, setIsOpen] = useState(true) + + const CustomHeader = ({ + title, + subtitle, + dialogLabelId, + dialogDescriptionId, + onClose, + }: React.PropsWithChildren) => { + const onCloseClick = useCallback(() => { + onClose('close-button') + }, [onClose]) + if (typeof title === 'string' && typeof subtitle === 'string') { + return ( + +

{title.toUpperCase()}

+

{subtitle.toLowerCase()}

+ +
+ ) + } + return null } - return null -} -function CustomBody({children}: React.PropsWithChildren) { - return {children} -} -function CustomFooter({footerButtons}: React.PropsWithChildren) { - return ( + + const CustomBody = () => {lipsum} + + const CustomFooter = ({footerButtons}: React.PropsWithChildren) => ( {footerButtons ? : null} ) -} -export const WithCustomRenderers = ({width, height, subtitle}: DialogStoryProps) => { - const [isOpen, setIsOpen] = useState(false) - const onDialogClose = useCallback(() => setIsOpen(false), []) + return ( <> - + {isOpen && ( setIsOpen(false)} footerButtons={[ - {buttonType: 'danger', content: 'Delete the universe', onClick: onDialogClose}, + {buttonType: 'danger', content: 'Delete the universe'}, {buttonType: 'primary', content: 'Proceed'}, ]} > @@ -167,8 +125,8 @@ export const WithCustomRenderers = ({width, height, subtitle}: DialogStoryProps) ) } -export const StressTest = ({width, height, subtitle}: DialogStoryProps) => { - const [isOpen, setIsOpen] = useState(false) +export const StressTest = () => { + const [isOpen, setIsOpen] = useState(true) const [secondOpen, setSecondOpen] = useState(false) const buttonRef = useRef(null) const onDialogClose = useCallback(() => setIsOpen(false), []) @@ -177,20 +135,14 @@ export const StressTest = ({width, height, subtitle}: DialogStoryProps) => { const manyButtons = new Array(10).fill(undefined).map((_, i) => ({content: `Button ${i}`})) return ( <> - {isOpen && ( { ) } +export const NonDeclaritive = () => { + const [isOpen, setIsOpen] = useState(true) + + return ( + <> + + {isOpen && ( + setIsOpen(false)}> + + It's a common scenario, to show a dialog that's just informational and therefore doesn't have + footers in the button + + + )} + + ) +} + +export const SizeSmall = () => { + const [isOpen, setIsOpen] = useState(true) + + return ( + <> + + {isOpen && ( + setIsOpen(false)}> + {lipsum} + + )} + + ) +} + +export const SizeXLarge = () => { + const [isOpen, setIsOpen] = useState(true) + + return ( + <> + + {isOpen && ( + setIsOpen(false)}> + {lipsum} + + )} + + ) +} + +export const SizeLarge = () => { + const [isOpen, setIsOpen] = useState(true) + + return ( + <> + + {isOpen && ( + setIsOpen(false)}> + {lipsum} + + )} + + ) +} + +export const Responsive = () => { + const [isOpen, setIsOpen] = useState(true) + + return ( + <> + + {isOpen && ( + {}} + type={{narrow: 'full-screen', regular: 'default', wide: 'default'}} + footerButtons={[ + {buttonType: 'normal', content: 'Cancel', onClick: () => {}}, + {buttonType: 'primary', content: 'Submit', autoFocus: true}, + ]} + > + {lipsum} + + )} + + ) +} + +export const FullScreen = () => { + const [isOpen, setIsOpen] = useState(true) + + return ( + <> + + {isOpen && ( + setIsOpen(false)} + type="full-screen" + footerButtons={[ + {buttonType: 'normal', content: 'Cancel', onClick: () => {}}, + {buttonType: 'primary', content: 'Submit', autoFocus: true}, + ]} + > + {lipsum} + + )} + + ) +} + +export const BottomSheet = () => { + const [isOpen, setIsOpen] = useState(true) + + return ( + <> + + {isOpen && ( + setIsOpen(false)}> + {lipsum} + + )} + + ) +} + // repro for https://github.com/github/primer/issues/2480 -export const ReproMultistepDialogWithConditionalFooter = ({width, height}: DialogStoryProps) => { - const [isOpen, setIsOpen] = useState(false) +export const ReproMultistepDialogWithConditionalFooter = () => { const onDialogClose = useCallback(() => setIsOpen(false), []) + const [isOpen, setIsOpen] = useState(true) const [step, setStep] = React.useState(1) const renderFooterConditionally = () => { @@ -227,12 +303,10 @@ export const ReproMultistepDialogWithConditionalFooter = ({width, height}: Dialo return ( <> - + {isOpen && ( { const [isOpen, setIsOpen] = useState(false) @@ -106,7 +106,7 @@ export const Default = () => { ) } -export const Playground = ({width, height, subtitle}: DialogStoryProps) => { +export const Playground = ({width, height, subtitle, type}: DialogStoryProps) => { const [isOpen, setIsOpen] = useState(false) const [secondOpen, setSecondOpen] = useState(false) const buttonRef = useRef(null) @@ -123,6 +123,7 @@ export const Playground = ({width, height, subtitle}: DialogStoryProps) => { title="My Dialog" subtitle={subtitle ? 'This is a subtitle!' : undefined} onClose={onDialogClose} + type={type} width={width} height={height} footerButtons={[ @@ -146,8 +147,15 @@ Playground.args = { width: 'xlarge', height: 'auto', subtitle: true, + type: 'default', } Playground.argTypes = { + type: { + control: { + type: 'radio', + }, + options: ['default', 'full-screen', 'bottom-sheet'], + }, width: { control: { type: 'radio', diff --git a/src/Dialog/Dialog.tsx b/src/Dialog/Dialog.tsx index aa00fed479f..98a17b2eba8 100644 --- a/src/Dialog/Dialog.tsx +++ b/src/Dialog/Dialog.tsx @@ -1,19 +1,24 @@ import React, {useCallback, useEffect, useRef, useState} from 'react' import styled from 'styled-components' -import {Button, ButtonProps} from '../Button' -import Box from '../Box' -import {get} from '../constants' -import {useOnEscapePress, useProvidedRefOrCreate} from '../hooks' -import {useFocusTrap} from '../hooks/useFocusTrap' -import sx, {SxProp} from '../sx' -import Octicon from '../Octicon' -import {XIcon} from '@primer/octicons-react' -import {useFocusZone} from '../hooks/useFocusZone' import {FocusKeys} from '@primer/behaviors' -import Portal from '../Portal' +import {XIcon} from '@primer/octicons-react' + +import {useOnEscapePress, useProvidedRefOrCreate} from '../hooks' import {useRefObjectAsForwardedRef} from '../hooks/useRefObjectAsForwardedRef' +import {ResponsiveValue, useResponsiveValue} from '../hooks/useResponsiveValue' +import {useFocusZone} from '../hooks/useFocusZone' +import {useFocusTrap} from '../hooks/useFocusTrap' import {useId} from '../hooks/useId' + import {ScrollableRegion} from '../internal/components/ScrollableRegion' +import sx, {SxProp} from '../sx' +import {get} from '../constants' +import {Button, ButtonProps} from '../Button' +import Box from '../Box' +import Portal from '../Portal' +import Octicon from '../Octicon' + +import DialogBottomSheet from './DialogBottomSheet' /* Dialog Version 2 */ @@ -96,11 +101,13 @@ export interface DialogProps extends SxProp { footerButtons?: DialogButtonProps[] /** - * This method is invoked when a gesture to close the dialog is used (either - * an Escape key press or clicking the "X" in the top-right corner). The - * gesture argument indicates the gesture that was used to close the dialog - * (either 'close-button' or 'escape'). + * This method is invoked when a gesture to close the dialog is used + * (either an Escape key press, clicking/tapping on the backdrop, + * clicking/tapping the 'X' in the top-right corner or dragging away a + * bottom sheet). The gesture argument indicates the gesture that was + * used to close the dialog. */ + onClose: (gesture: 'close-button' | 'escape') => void /** @@ -110,6 +117,14 @@ export interface DialogProps extends SxProp { */ role?: 'dialog' | 'alertdialog' + /** + * Normally a dialog is display in the center of a viewport but sometimes + * it is useful to display this full screen or as an bottom sheet on mobile viewports + * to allow for more space for content. When full-screen or bottom sheet the width + * and height is ignored. + */ + type?: DialogType | ResponsiveValue + /** * The width of the dialog. * small: 296px @@ -143,29 +158,12 @@ export interface DialogHeaderProps extends DialogProps { * dialog. This ID should be set to the element that renders the dialog's subtitle. */ dialogDescriptionId: string -} -const Backdrop = styled('div')` - position: fixed; - top: 0; - left: 0; - bottom: 0; - right: 0; - display: flex; - align-items: center; - justify-content: center; - background-color: ${get('colors.primer.canvas.backdrop')}; - animation: dialog-backdrop-appear ${ANIMATION_DURATION} ${get('animation.easeOutCubic')}; - - @keyframes dialog-backdrop-appear { - 0% { - opacity: 0; - } - 100% { - opacity: 1; - } - } -` + /** + * A reference to the close button DOM node + */ + closeButtonRef?: React.RefObject +} const heightMap = { small: '480px', @@ -182,46 +180,20 @@ const widthMap = { export type DialogWidth = keyof typeof widthMap export type DialogHeight = keyof typeof heightMap +export type DialogType = 'default' | 'full-screen' | 'bottom-sheet' type StyledDialogProps = { width?: DialogWidth height?: DialogHeight } & SxProp -const StyledDialog = styled.div` - display: flex; - flex-direction: column; - background-color: ${get('colors.canvas.overlay')}; - box-shadow: ${get('shadows.overlay.shadow')}; - min-width: 296px; - max-width: calc(100vw - 64px); - max-height: calc(100vh - 64px); - width: ${props => widthMap[props.width ?? ('xlarge' as const)]}; - height: ${props => heightMap[props.height ?? ('auto' as const)]}; - border-radius: 12px; - opacity: 1; - animation: overlay--dialog-appear ${ANIMATION_DURATION} ${get('animation.easeOutCubic')}; - - @keyframes overlay--dialog-appear { - 0% { - opacity: 0; - transform: scale(0.5); - } - 100% { - opacity: 1; - transform: scale(1); - } - } - - ${sx}; -` - const DefaultHeader: React.FC> = ({ dialogLabelId, title, subtitle, dialogDescriptionId, onClose, + closeButtonRef, }) => { const onCloseClick = useCallback(() => { onClose('close-button') @@ -233,7 +205,17 @@ const DefaultHeader: React.FC> = ({ {title ?? 'Dialog'} {subtitle && {subtitle}} - + + + ) @@ -264,23 +246,30 @@ const _Dialog = React.forwardRef(null) + const closeButtonRef = useRef(null) for (const footerButton of footerButtons) { if (footerButton.autoFocus) { footerButton.ref = autoFocusedFooterButtonRef } } - const defaultedProps = {...props, title, subtitle, role, dialogLabelId, dialogDescriptionId} + + const defaultedProps = {...props, title, subtitle, role, dialogLabelId, dialogDescriptionId, closeButtonRef} + const responsiveType = useResponsiveValue(type, 'default') const dialogRef = useRef(null) useRefObjectAsForwardedRef(forwardedRef, dialogRef) - const backdropRef = useRef(null) - useFocusTrap({containerRef: dialogRef, restoreFocusOnCleanUp: true, initialFocusRef: autoFocusedFooterButtonRef}) + useFocusTrap({ + containerRef: dialogRef, + restoreFocusOnCleanUp: true, + initialFocusRef: footerButtons.length > 0 ? autoFocusedFooterButtonRef : closeButtonRef, + }) useOnEscapePress( (event: KeyboardEvent) => { @@ -310,53 +299,204 @@ const _Dialog = React.forwardRef + if (responsiveType === 'full-screen') { + return ( - - - {header} - - {body} - - {footer} - - + + {header} + + {body} + + {footer} + - + ) + } + + if (responsiveType === 'bottom-sheet') { + return ( + + onClose('close-button')} + ariaLabelledby={dialogLabelId} + ariaDescribedby={dialogDescriptionId} + ariaModal + header={header} + sx={sx} + > + + {body} + + {footer} + + + ) + } + + return ( + + + + {header} + + {body} + + {footer} + + + ) }) _Dialog.displayName = 'Dialog' +const Buttons: React.FC> = ({buttons}) => { + const autoFocusRef = useProvidedRefOrCreate(buttons.find(button => button.autoFocus)?.ref) + let autoFocusCount = 0 + const [hasRendered, setHasRendered] = useState(0) + useEffect(() => { + // hack to work around dialogs originating from other focus traps. + if (hasRendered === 1) { + autoFocusRef.current?.focus() + } else { + setHasRendered(hasRendered + 1) + } + }, [autoFocusRef, hasRendered]) + + return ( + <> + {buttons.map((dialogButtonProps, index) => { + const {content, buttonType = 'default', autoFocus = false, ...buttonProps} = dialogButtonProps + return ( + + ) + })} + + ) +} + +/** + * Styled wrappers + */ + +const Backdrop = styled('div')` + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + display: flex; + align-items: center; + justify-content: center; + background-color: ${get('colors.primer.canvas.backdrop')}; + animation: dialog-backdrop-appear ${ANIMATION_DURATION} ${get('animation.easeOutCubic')}; + + @keyframes dialog-backdrop-appear { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } + } +` + +const NormalDialog = styled.div` + display: flex; + flex-direction: column; + background-color: ${get('colors.canvas.overlay')}; + box-shadow: ${get('shadows.overlay.shadow')}; + min-width: 296px; + max-width: calc(100vw - 64px); + max-height: calc(100vh - 64px); + width: ${props => widthMap[props.width ?? ('xlarge' as const)]}; + height: ${props => heightMap[props.height ?? ('auto' as const)]}; + border-radius: 12px; + opacity: 1; + animation: overlay--dialog-appear ${ANIMATION_DURATION} ${get('animation.easeOutCubic')}; + + @keyframes overlay--dialog-appear { + 0% { + opacity: 0; + transform: scale(0.5); + } + 100% { + opacity: 1; + transform: scale(1); + } + } + + ${sx}; +` + +const FullScreenDialog = styled.div` + display: flex; + flex-direction: column; + background-color: ${get('colors.canvas.overlay')}; + width: 100vw; + height: 100vh; + opacity: 1; + animation: overlay--dialog-appear ${ANIMATION_DURATION} ${get('animation.easeOutCubic')}; + @keyframes overlay--dialog-appear { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } + } + ${sx}; +` + const Header = styled.div` box-shadow: 0 1px 0 ${get('colors.border.default')}; padding: ${get('space.2')}; z-index: 1; + pointer-events: none ${/* Allows clicks to pass through the header in bottom sheets */ ''}; flex-shrink: 0; + position: relative; ` const Title = styled.h1` font-size: ${get('fontSizes.1')}; font-weight: ${get('fontWeights.bold')}; margin: 0; /* override default margin */ + width: calc(100% - ${get('space.4')}); ${sx}; ` const Subtitle = styled.h2` font-size: ${get('fontSizes.0')}; + font-weight: ${get('fontWeights.normal')}; color: ${get('colors.fg.muted')}; margin: 0; /* override default margin */ margin-top: ${get('space.1')}; - + width: fit-content; ${sx}; ` @@ -364,7 +504,6 @@ const Body = styled.div` flex-grow: 1; overflow: auto; padding: ${get('space.3')}; - ${sx}; ` @@ -377,42 +516,9 @@ const Footer = styled.div` gap: ${get('space.2')}; z-index: 1; flex-shrink: 0; - ${sx}; ` -const Buttons: React.FC> = ({buttons}) => { - const autoFocusRef = useProvidedRefOrCreate(buttons.find(button => button.autoFocus)?.ref) - let autoFocusCount = 0 - const [hasRendered, setHasRendered] = useState(0) - useEffect(() => { - // hack to work around dialogs originating from other focus traps. - if (hasRendered === 1) { - autoFocusRef.current?.focus() - } else { - setHasRendered(hasRendered + 1) - } - }, [autoFocusRef, hasRendered]) - - return ( - <> - {buttons.map((dialogButtonProps, index) => { - const {content, buttonType = 'default', autoFocus = false, ...buttonProps} = dialogButtonProps - return ( - - ) - })} - - ) -} const DialogCloseButton = styled(Button)` border-radius: 4px; background: transparent; @@ -424,13 +530,19 @@ const DialogCloseButton = styled(Button)` line-height: normal; box-shadow: none; ` -const CloseButton: React.FC void}>> = ({onClose}) => { + +export interface CloseButtonProps extends SxProp { + onClose: () => void +} + +const CloseButton = React.forwardRef((props, ref) => { + const {onClose} = props return ( - + ) -} +}) /** * A dialog is a type of overlay that can be used for confirming actions, asking diff --git a/src/Dialog/DialogBottomSheet.test.tsx b/src/Dialog/DialogBottomSheet.test.tsx new file mode 100644 index 00000000000..aafb909ee28 --- /dev/null +++ b/src/Dialog/DialogBottomSheet.test.tsx @@ -0,0 +1,157 @@ +import React from 'react' +import {fireEvent, render, waitFor} from '@testing-library/react' +import {Dialog} from './Dialog' +import MatchMediaMock from 'jest-matchmedia-mock' +import {behavesAsComponent} from '../utils/testing' +import {FULL_HEIGHT, HALF_HEIGHT} from './DialogBottomSheet' +import {axe} from 'jest-axe' + +let matchMedia: MatchMediaMock + +describe('Dialog', () => { + beforeEach(() => { + matchMedia = new MatchMediaMock() + }) + + afterEach(() => { + matchMedia.clear() + }) + + behavesAsComponent({ + Component: Dialog, + options: {skipAs: true, skipSx: true, htmlRenderer: true}, + toRender: () => ( + {}} type="bottom-sheet"> +
Hello World
+
+ ), + }) + + // Arrow keys support in the testing library is currently not implemented and therefore can't be tested + // https://github.com/testing-library/user-event/issues/871 + + it('expands/contracts when using the range slider', async () => { + const onClose = jest.fn() + + const {getByRole} = render( + +
Hello World
+
, + ) + + const slider = getByRole('slider') + slider.focus() + + expect(slider).toHaveFocus() + + fireEvent.change(slider, {target: {value: 2}}) + + const dialog = getByRole('dialog') + + expect(dialog).toHaveStyle(`height: ${FULL_HEIGHT}dvh)`) + + fireEvent.change(slider, {target: {value: 1}}) + + expect(dialog).toHaveStyle(`height: ${HALF_HEIGHT}dvh)`) + }) + + it('automatically focuses the footer button when `autoFocus` is true', async () => { + const {getByRole} = render( + {}} + footerButtons={[{buttonType: 'primary', content: 'Footer button', autoFocus: true}]} + type={'bottom-sheet'} + > + Pay attention to me + , + ) + + await waitFor(() => expect(getByRole('button', {name: 'Footer button'})).toHaveFocus()) + }) + + it('changes the style for `overflow` if it is not set to "hidden"', () => { + document.body.style.overflow = 'scroll' + + const {container} = render( + {}} type="bottom-sheet"> + Pay attention to me + , + ) + + expect(container.ownerDocument.body.style.overflow).toBe('hidden') + }) + + it('should have no axe violations', async () => { + const {container} = render( + {}}> + Pay attention to me + , + ) + const results = await axe(container) + expect(results).toHaveNoViolations() + }) + + it('opens the bottom sheet on mount', () => { + const {getByRole} = render( + {}} type="bottom-sheet"> + My dialog content + , + ) + + expect(getByRole('dialog')).toHaveStyle(`height: ${HALF_HEIGHT}dvh)`) + }) + + it('calls `onClose` when keying "Escape"', () => { + const onClose = jest.fn() + const {container} = render( + + Pay attention to me + , + ) + + expect(onClose).not.toHaveBeenCalled() + + fireEvent.keyDown(container, {key: 'Escape'}) + + expect(onClose).toHaveBeenCalled() + }) + + it('`onClose` is called when clicking close', async () => { + const onClose = jest.fn() + const {getByLabelText} = render( + +
Hello World
+
, + ) + + expect(onClose).not.toHaveBeenCalled() + + fireEvent.click(getByLabelText('Close')) + + expect(onClose).toHaveBeenCalled() + }) + + it('is dialog and has the aria-model attribute', () => { + const {getByRole} = render( + {}} type="bottom-sheet"> + My dialog content + , + ) + + const dialog = getByRole('dialog') + expect(dialog).toHaveAttribute('aria-modal', 'true') + }) + + it('`onClose` is called when clicking the overlay', async () => { + const mockOnClose = jest.fn() + + const {getByTestId} = render( + + My dialog content + , + ) + expect(mockOnClose).not.toHaveBeenCalled() + fireEvent.click(getByTestId('overlay')) + expect(mockOnClose).toHaveBeenCalled() + }) +}) diff --git a/src/Dialog/DialogBottomSheet.tsx b/src/Dialog/DialogBottomSheet.tsx new file mode 100644 index 00000000000..5b12803186b --- /dev/null +++ b/src/Dialog/DialogBottomSheet.tsx @@ -0,0 +1,319 @@ +import React, {useEffect, useRef, useState, PropsWithChildren, MouseEvent, TouchEvent, ChangeEvent} from 'react' +import styled from 'styled-components' +import {SxProp} from '../sx' +import {useRefObjectAsForwardedRef} from '../hooks/useRefObjectAsForwardedRef' +import Box from '../Box' +import {get} from '../constants' +import {useMedia} from '../hooks/useMedia' + +export const ANIMATION_DURATION = 300 +export const FULL_HEIGHT = 95 +export const HALF_HEIGHT = 50 + +/** + * Props to customize the rendering of the Dialog. + */ +export interface DialogBottomSheetProps extends SxProp { + /** + * This method is invoked when a gesture to close the dialog is used + */ + onClose: () => void + + /** + * Content that appears in the draggable header area. + */ + header: React.ReactNode + + /** + * Default: "dialog". The ARIA role to assign to this dialog. + * @see https://www.w3.org/TR/wai-aria-practices-1.1/#dialog_modal + * @see https://www.w3.org/TR/wai-aria-practices-1.1/#alertdialog + */ + role?: 'dialog' | 'alertdialog' + + /** + * Identifies the element (or elements) that labels the element it is applied to. + */ + ariaLabelledby: string + + /** + * Identifies the element (or elements) that describes the element on which the attribute is set. + */ + ariaDescribedby: string + + /** + * Indicates whether an element is modal when displayed. + */ + ariaModal: boolean +} + +export default React.forwardRef>((props, forwardedRef) => { + const {onClose, children, role, ariaLabelledby, ariaDescribedby, ariaModal, header, sx} = props + + // 🔄 STATES + + const [open, setIsOpen] = useState(false) + const [snappedHeight, setSnappedHeight] = useState(HALF_HEIGHT) + const [fireDelayedOnClose, setFireDelayedOnClose] = useState(false) + + // 📎 REFERENCES + + const dialogRef = useRef(null) + const startY = useRef(0) + const startHeight = useRef(0) + const isDragging = useRef(false) + + useRefObjectAsForwardedRef(forwardedRef, dialogRef) + + // 🧑‍🦽 ACCESSIBILITY + + const isReduced = useMedia('(prefers-reduced-motion: no-preference)', false) === false + + // 🥊 ACTIONS + + const showBottomSheet = () => { + setIsOpen(true) + updateSheetHeight(HALF_HEIGHT) + } + + const hideBottomSheet = async () => { + setIsOpen(false) + if (isReduced) { + onClose() + } else { + setFireDelayedOnClose(true) + } + } + + const updateSheetHeight = (height: number) => { + if (!dialogRef.current) return + dialogRef.current.style.height = `${height}dvh` + setSnappedHeight(height) + } + + // 🎪 EVENTS + + const dragStop = (e: MouseEvent | TouchEvent) => { + if (!dialogRef.current) return + + e.preventDefault() + + isDragging.current = false + const sheetHeight = parseInt(dialogRef.current.style.height) + + dialogRef.current.style.transition = isReduced ? 'none' : '0.3s ease' + + if (sheetHeight < 10) return hideBottomSheet() + if (sheetHeight > 75) return updateSheetHeight(FULL_HEIGHT) + + updateSheetHeight(HALF_HEIGHT) + } + + const dragStart = (e: MouseEvent | TouchEvent) => { + if (!dialogRef.current) return + + e.preventDefault() + + if (e.type === 'touchstart' && 'touches' in e) { + startY.current = e.touches[0].pageY + } else if ('clientX' in e) { + startY.current = e.pageY + } + + startHeight.current = parseInt(dialogRef.current.style.height) + isDragging.current = true + dialogRef.current.style.transition = 'none' + } + + const dragging = (e: MouseEvent | TouchEvent) => { + if (!dialogRef.current || !isDragging.current) return + + e.preventDefault() + + let pageY + if (e.type === 'touchmove' && 'touches' in e) { + pageY = e.touches[0].pageY + } else if ('clientX' in e) { + pageY = e.pageY + } + + const delta = startY.current - (pageY || 0) + const newHeight = startHeight.current + (delta / window.innerHeight) * 100 + updateSheetHeight(newHeight) + } + + const onSliderChange = (e: ChangeEvent) => { + if (!isDragging.current) { + const value = parseInt(e.target.value) + if (value === 1) { + updateSheetHeight(HALF_HEIGHT) + } else if (value === 2) { + updateSheetHeight(FULL_HEIGHT) + } + } + } + + // 🪝 HOOKS + + // Ensures an animation upon closing the component + useEffect(() => { + if (!fireDelayedOnClose) return + setIsOpen(false) + const timer = setTimeout(() => { + onClose() + }, ANIMATION_DURATION) + return () => clearTimeout(timer) + }, [fireDelayedOnClose, onClose]) + + // Animates the bottom sheet in on mount + useEffect(() => { + showBottomSheet() + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + const currentSliderValue = snappedHeight === HALF_HEIGHT ? 1 : 2 + + return ( + + hideBottomSheet()}> + + + + + {header} + + {children} + + + ) +}) + +// 🖌️ Styles + +const FullScreenContainer = styled.div<{open: boolean}>` + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + opacity: ${props => (props.open ? 1 : 0)}; + pointerevents: ${props => (props.open ? 'auto' : 'none')}; + flex-direction: column; + justify-content: flex-end; + align-items: center; + transition: ${ANIMATION_DURATION / 3}ms linear; + @media (prefers-reduced-motion) { + transition: none; + } +` +const Overlay = styled.div` + position: fixed; + top: 0; + left: 0; + z-index: -1; + width: 100%; + height: 100%; + background-color: ${get('colors.primer.canvas.backdrop')}; +` + +const DraggableRegionPill = styled.div` + height: 6px; + width: 70px; + display: block; + background-color: ${get('colors.border.muted')}; + border-radius: 3px; + top: ${get('space.2')}; + position: absolute; + pointer-events: none; + left: 50%; + margin-left: -35px; +` + +const DraggableRegion = styled.input` + appearance: none; + display: flex; + justify-content: center; + border: none; + position: absolute; + background: transparent; + top: 0; + width: 100%; + right: 0; + left: 0; + bottom: 0; + padding-top: ${get('space.2')}; + padding-bottom: ${get('space.1')}; + cursor: grab; + user-select: none; + min-height: 50px; + &:hover ~ ${DraggableRegionPill} { + background-color: ${get('colors.border.default')}; + } + &:focus { + outline: none; + opacity: 0; + } + &:focus-visible:not([disabled]) ~ ${DraggableRegionPill} { + background-color: ${get('colors.accent.emphasis')}; + } + ::-moz-range-thumb { + appearance: none; + visibility: hidden; + } + ::-webkit-slider-thumb { + appearance: none; + } +` +const Content = styled.div< + { + open: boolean + } & SxProp +>` + display: flex; + flex-direction: column; + background-color: ${get('colors.canvas.default')}; + width: 100vw; + max-width: 100dvh; + max-width: 480px; + border-radius: 12px 12px 0 0; + position: relative; + height: 50vh; + height: 50dvh; + box-shadow: ${get('shadows.overlay.shadow')}; + max-height: 100vh; + max-height: 100dvh; + overflow-x: hidden; + overflow-y: auto; + transform: ${props => (props.open ? 'translateY(0%)' : 'translateY(100%)')}; + transition: ${ANIMATION_DURATION}ms ease; +` diff --git a/src/Dialog/__snapshots__/DialogBottomSheet.test.tsx.snap b/src/Dialog/__snapshots__/DialogBottomSheet.test.tsx.snap new file mode 100644 index 00000000000..e245e89212a --- /dev/null +++ b/src/Dialog/__snapshots__/DialogBottomSheet.test.tsx.snap @@ -0,0 +1,655 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Dialog renders consistently 1`] = ` +{ + "asFragment": [Function], + "baseElement": .c3 { + position: relative; +} + +.c7 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.c8 { + padding-left: 8px; + padding-right: 8px; + padding-top: 6px; + padding-bottom: 6px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +.c10 { + z-index: 2; + right: 0; + padding-right: 8px; + position: absolute; + pointer-events: auto; +} + +.c13 { + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; +} + +.c14 { + overflow: auto; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.c11 { + border-radius: 2; + border: 1px solid; + border-color: var(--button-default-borderColor-rest,undefined); + font-family: inherit; + font-weight: semibold; + font-size: 14px; + cursor: pointer; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-text-decoration: none; + text-decoration: none; + text-align: center; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; + height: 32px; + padding: 0 12px; + gap: 8px; + min-width: -webkit-max-content; + min-width: -moz-max-content; + min-width: max-content; + -webkit-transition: 80ms cubic-bezier(0.65,0,0.35,1); + transition: 80ms cubic-bezier(0.65,0,0.35,1); + -webkit-transition-property: color,fill,background-color,border-color; + transition-property: color,fill,background-color,border-color; + color: btn.text; + background-color: btn.bg; + box-shadow: undefined,undefined; +} + +.c11:focus:not(:disabled) { + box-shadow: none; + outline: 2px solid; + outline-offset: -2px; +} + +.c11:focus:not(:disabled):not(:focus-visible) { + outline: solid 1px transparent; +} + +.c11:focus-visible:not(:disabled) { + box-shadow: none; + outline: 2px solid; + outline-offset: -2px; +} + +.c11[href] { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; +} + +.c11[href]:hover { + -webkit-text-decoration: none; + text-decoration: none; +} + +.c11:hover { + -webkit-transition-duration: 80ms; + transition-duration: 80ms; +} + +.c11:active { + -webkit-transition: none; + transition: none; +} + +.c11[data-inactive] { + cursor: auto; +} + +.c11:disabled { + cursor: not-allowed; + box-shadow: none; + color: primer.fg.disabled; +} + +.c11:disabled [data-component=ButtonCounter] { + color: inherit; +} + +.c11 [data-component=ButtonCounter] { + font-size: 12px; +} + +.c11[data-component=IconButton] { + display: inline-grid; + padding: unset; + place-content: center; + width: 32px; + min-width: unset; +} + +.c11[data-size="small"] { + padding: 0 8px; + height: 28px; + gap: 4px; + font-size: 12px; +} + +.c11[data-size="small"] [data-component="text"] { + line-height: calc(20 / 12); +} + +.c11[data-size="small"] [data-component=ButtonCounter] { + font-size: 12px; +} + +.c11[data-size="small"] [data-component="buttonContent"] > :not(:last-child) { + margin-right: 4px; +} + +.c11[data-size="small"][data-component=IconButton] { + width: 28px; + padding: unset; +} + +.c11[data-size="large"] { + padding: 0 16px; + height: 40px; + gap: 8px; +} + +.c11[data-size="large"] [data-component="buttonContent"] > :not(:last-child) { + margin-right: 8px; +} + +.c11[data-size="large"][data-component=IconButton] { + width: 40px; + padding: unset; +} + +.c11[data-block="block"] { + width: 100%; +} + +.c11[data-inactive]:not([disabled]) { + background-color: var(--button-inactive-bgColor,undefined); + border-color: var(--button-inactive-bgColor,undefined); + color: var(--button-inactive-fgColor,undefined); +} + +.c11[data-inactive]:not([disabled]):focus-visible { + box-shadow: none; +} + +.c11 [data-component="leadingVisual"] { + grid-area: leadingVisual; +} + +.c11 [data-component="text"] { + grid-area: text; + line-height: calc(20/14); + white-space: nowrap; +} + +.c11 [data-component="trailingVisual"] { + grid-area: trailingVisual; +} + +.c11 [data-component="trailingAction"] { + margin-right: -4px; +} + +.c11 [data-component="buttonContent"] { + -webkit-flex: 1 0 auto; + -ms-flex: 1 0 auto; + flex: 1 0 auto; + display: grid; + grid-template-areas: "leadingVisual text trailingVisual"; + grid-template-columns: min-content minmax(0,auto) min-content; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-align-content: center; + -ms-flex-line-pack: center; + align-content: center; +} + +.c11 [data-component="buttonContent"] > :not(:last-child) { + margin-right: 8px; +} + +.c11:hover:not([disabled]):not([data-inactive]) { + background-color: btn.hoverBg; + border-color: var(--button-default-borderColor-hover,undefined); +} + +.c11:active:not([disabled]):not([data-inactive]) { + background-color: btn.activeBg; + border-color: var(--button-default-borderColor-active,undefined); +} + +.c11[aria-expanded=true] { + background-color: btn.activeBg; + border-color: var(--button-default-borderColor-active,undefined); +} + +.c11 [data-component="leadingVisual"], +.c11 [data-component="trailingVisual"], +.c11 [data-component="trailingAction"] { + color: var(--button-color,undefined); +} + +.c0 { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + opacity: 1; + pointerevents: auto; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + -ms-flex-pack: end; + justify-content: flex-end; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-transition: 100ms linear; + transition: 100ms linear; +} + +.c1 { + position: fixed; + top: 0; + left: 0; + z-index: -1; + width: 100%; + height: 100%; +} + +.c5 { + height: 6px; + width: 70px; + display: block; + border-radius: 3px; + top: 8px; + position: absolute; + pointer-events: none; + left: 50%; + margin-left: -35px; +} + +.c4 { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + border: none; + position: absolute; + background: transparent; + top: 0; + width: 100%; + right: 0; + left: 0; + bottom: 0; + padding-top: 8px; + padding-bottom: 4px; + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + min-height: 50px; +} + +.c4:focus { + outline: none; + opacity: 0; +} + +.c4::-moz-range-thumb { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + visibility: hidden; +} + +.c4::-webkit-slider-thumb { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + +.c2 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: 100vw; + max-width: 100dvh; + max-width: 480px; + border-radius: 12px 12px 0 0; + position: relative; + height: 50vh; + height: 50dvh; + max-height: 100vh; + max-height: 100dvh; + overflow-x: hidden; + overflow-y: auto; + -webkit-transform: translateY(0%); + -ms-transform: translateY(0%); + transform: translateY(0%); + -webkit-transition: 300ms ease; + transition: 300ms ease; +} + +.c6 { + box-shadow: 0 1px 0; + padding: 8px; + z-index: 1; + pointer-events: none; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + position: relative; +} + +.c9 { + font-size: 14px; + font-weight: 600; + margin: 0; + width: calc(100% - 24px); +} + +.c15 { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; + overflow: auto; + padding: 16px; +} + +.c12 { + border-radius: 4px; + background: transparent; + border: 0; + vertical-align: middle; + padding: 8px; + -webkit-align-self: flex-start; + -ms-flex-item-align: start; + align-self: flex-start; + line-height: normal; + box-shadow: none; +} + +@media (forced-colors:active) { + .c11:focus { + outline: solid 1px transparent; + } +} + +@media (prefers-reduced-motion) { + +} + +@media (prefers-reduced-motion) { + .c0 { + -webkit-transition: none; + transition: none; + } +} + + +
+
+
+
+
+ +
+
+ , + "container": @media (forced-colors:active) { + +} + +@media (prefers-reduced-motion) { + +} + +@media (prefers-reduced-motion) { + +} + +
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/src/TreeView/TreeView.test.tsx b/src/TreeView/TreeView.test.tsx index 881d35bfcca..8a07a8923f8 100644 --- a/src/TreeView/TreeView.test.tsx +++ b/src/TreeView/TreeView.test.tsx @@ -6,6 +6,22 @@ import {SubTreeState, TreeView} from './TreeView' jest.useFakeTimers() +// The TreeView.ErrorDialog uses `matchMedia` because the ConfirmationDialog uses it to determine whether or not to reduce motion. + +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // deprecated + removeListener: jest.fn(), // deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), +}) + // TODO: Move this function into a shared location function renderWithTheme( ui: Parameters[0], diff --git a/src/__tests__/Dialog.test.tsx b/src/__tests__/Dialog.test.tsx index 1d636d591cf..70b0a501a5f 100644 --- a/src/__tests__/Dialog.test.tsx +++ b/src/__tests__/Dialog.test.tsx @@ -6,7 +6,7 @@ import {axe, toHaveNoViolations} from 'jest-axe' import {behavesAsComponent, checkExports} from '../utils/testing' expect.extend(toHaveNoViolations) -/* Dialog Version 2 */ +/* Dialog Version 1 */ const comp = ( null} aria-labelledby="header"> diff --git a/src/__tests__/__snapshots__/exports.test.ts.snap b/src/__tests__/__snapshots__/exports.test.ts.snap index e3584fc6957..dbe19dcd203 100644 --- a/src/__tests__/__snapshots__/exports.test.ts.snap +++ b/src/__tests__/__snapshots__/exports.test.ts.snap @@ -242,6 +242,7 @@ exports[`@primer/react/drafts should not update exports without a semver change "callbackCancelledResult", "type CallbackCancelledResult", "type ChildrenPropTypes", + "type CloseButtonProps", "type Column", "type ComboboxCommitEvent", "createColumnHelper", @@ -254,6 +255,7 @@ exports[`@primer/react/drafts should not update exports without a semver change "type DialogHeaderProps", "type DialogHeight", "type DialogProps", + "type DialogType", "type DialogWidth", "type Emoji", "type FileType", @@ -322,6 +324,7 @@ exports[`@primer/react/experimental should not update exports without a semver c "callbackCancelledResult", "type CallbackCancelledResult", "type ChildrenPropTypes", + "type CloseButtonProps", "type Column", "type ComboboxCommitEvent", "createColumnHelper", @@ -334,6 +337,7 @@ exports[`@primer/react/experimental should not update exports without a semver c "type DialogHeaderProps", "type DialogHeight", "type DialogProps", + "type DialogType", "type DialogWidth", "type Emoji", "type FileType", diff --git a/src/internal/components/ScrollableRegion.tsx b/src/internal/components/ScrollableRegion.tsx index 0600f5cba92..46537324db0 100644 --- a/src/internal/components/ScrollableRegion.tsx +++ b/src/internal/components/ScrollableRegion.tsx @@ -1,13 +1,15 @@ import React from 'react' import Box from '../../Box' import {useOverflow} from '../hooks/useOverflow' +import {SxProp} from '../../sx' type ScrollableRegionProps = React.PropsWithChildren<{ 'aria-labelledby'?: string className?: string -}> +}> & + SxProp -export function ScrollableRegion({'aria-labelledby': labelledby, children, ...rest}: ScrollableRegionProps) { +export function ScrollableRegion({'aria-labelledby': labelledby, children, sx, ...rest}: ScrollableRegionProps) { const ref = React.useRef(null) const hasOverflow = useOverflow(ref) const regionProps = hasOverflow @@ -19,7 +21,7 @@ export function ScrollableRegion({'aria-labelledby': labelledby, children, ...re : {} return ( - + {children} ) diff --git a/src/utils/testing.tsx b/src/utils/testing.tsx index 9321f698d96..b941a7467bb 100644 --- a/src/utils/testing.tsx +++ b/src/utils/testing.tsx @@ -190,6 +190,7 @@ export function unloadCSS(path: string) { interface Options { skipAs?: boolean skipSx?: boolean + htmlRenderer?: boolean } interface BehavesAsComponent { @@ -223,7 +224,11 @@ export function behavesAsComponent({Component, toRender, options}: BehavesAsComp }) it('renders consistently', () => { - expect(render(getElement())).toMatchSnapshot() + if (options?.htmlRenderer) { + expect(HTMLRender(getElement())).toMatchSnapshot() + } else { + expect(render(getElement())).toMatchSnapshot() + } }) }