diff --git a/.changeset/shy-falcons-shout.md b/.changeset/shy-falcons-shout.md new file mode 100644 index 00000000000..6c8dfbaf48c --- /dev/null +++ b/.changeset/shy-falcons-shout.md @@ -0,0 +1,5 @@ +--- +"@primer/react": minor +--- + +feat(SelectPanel): display selected items at the top under FF diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-colorblind-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-colorblind-linux.png index 9a290b87dc0..ada92291786 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-colorblind-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-colorblind-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-colorblind-modern-action-list--true-linux.png index 1aa16bd2eae..32d7a32c7a3 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-colorblind-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-colorblind-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-dimmed-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-dimmed-linux.png index 637868b208f..f4962bbb75d 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-dimmed-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-dimmed-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-dimmed-modern-action-list--true-linux.png index f2015f8b2f1..c0dc62549a4 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-dimmed-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-dimmed-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-high-contrast-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-high-contrast-linux.png index eeb165b5065..d77f6e57b39 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-high-contrast-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-high-contrast-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-high-contrast-modern-action-list--true-linux.png index 7f3f1b65b24..992d4874570 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-high-contrast-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-high-contrast-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-linux.png index 9a290b87dc0..ada92291786 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-modern-action-list--true-linux.png index 1aa16bd2eae..32d7a32c7a3 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-tritanopia-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-tritanopia-linux.png index 8217adbb639..ada92291786 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-tritanopia-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-tritanopia-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-tritanopia-modern-action-list--true-linux.png index 1aa16bd2eae..32d7a32c7a3 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-tritanopia-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-dark-tritanopia-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-colorblind-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-colorblind-linux.png index e1f3402361f..fcc971dc102 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-colorblind-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-colorblind-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-colorblind-modern-action-list--true-linux.png index 5954c396f77..8d331a708da 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-colorblind-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-colorblind-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-high-contrast-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-high-contrast-linux.png index 0642ff3ce41..7eac7eb5fed 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-high-contrast-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-high-contrast-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-high-contrast-modern-action-list--true-linux.png index afa5c0e9f55..8ec3eb7e27f 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-high-contrast-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-high-contrast-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-linux.png index e1f3402361f..fcc971dc102 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-modern-action-list--true-linux.png index 5954c396f77..8d331a708da 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-tritanopia-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-tritanopia-linux.png index e1f3402361f..fcc971dc102 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-tritanopia-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-tritanopia-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-tritanopia-modern-action-list--true-linux.png index 5954c396f77..8d331a708da 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-tritanopia-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-External-Anchor-light-tritanopia-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-colorblind-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-colorblind-linux.png index 5851ce58425..d425aed52fb 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-colorblind-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-colorblind-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-colorblind-modern-action-list--true-linux.png index 3cb951d7182..35b44d9acca 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-colorblind-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-colorblind-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-dimmed-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-dimmed-linux.png index 8b2c5b450c2..616fdfff733 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-dimmed-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-dimmed-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-dimmed-modern-action-list--true-linux.png index 199c244801e..87a91a92c48 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-dimmed-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-dimmed-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-high-contrast-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-high-contrast-linux.png index 2ed88973f93..2732ebfc85c 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-high-contrast-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-high-contrast-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-high-contrast-modern-action-list--true-linux.png index 9a4ce9d8033..ba37d272c1a 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-high-contrast-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-high-contrast-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-linux.png index ee85762acdf..852c023c9d2 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-modern-action-list--true-linux.png index 9cbfe1f3e6e..52c894e2a25 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-tritanopia-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-tritanopia-linux.png index 5851ce58425..d425aed52fb 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-tritanopia-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-tritanopia-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-tritanopia-modern-action-list--true-linux.png index 3cb951d7182..35b44d9acca 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-tritanopia-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-dark-tritanopia-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-colorblind-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-colorblind-linux.png index 5e73aee7c18..b97df8cd27c 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-colorblind-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-colorblind-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-colorblind-modern-action-list--true-linux.png index 6b173758ab4..77b75fde570 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-colorblind-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-colorblind-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-high-contrast-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-high-contrast-linux.png index fb0c85d3a8b..1779b95fde2 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-high-contrast-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-high-contrast-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-high-contrast-modern-action-list--true-linux.png index fcc1ff2bff6..ebd80213f14 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-high-contrast-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-high-contrast-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-linux.png index 11e9acc1961..cbcd1d25302 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-modern-action-list--true-linux.png index da7ff48b40f..390b7a99a40 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-tritanopia-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-tritanopia-linux.png index 5e73aee7c18..b97df8cd27c 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-tritanopia-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-tritanopia-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-tritanopia-modern-action-list--true-linux.png index 6b173758ab4..77b75fde570 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-tritanopia-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-Multi-Select-Modal-light-tritanopia-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-colorblind-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-colorblind-linux.png index 9ac90673201..8d2bab43f7c 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-colorblind-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-colorblind-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-colorblind-modern-action-list--true-linux.png index 42e27e9fbf6..ab60656309a 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-colorblind-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-colorblind-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-dimmed-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-dimmed-linux.png index de323640591..75f26cd8e32 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-dimmed-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-dimmed-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-dimmed-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-dimmed-modern-action-list--true-linux.png index 9ea0165009e..9c6168f0fa9 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-dimmed-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-dimmed-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-high-contrast-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-high-contrast-linux.png index 17b60b0f99b..df2b190e3e2 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-high-contrast-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-high-contrast-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-high-contrast-modern-action-list--true-linux.png index bdc41d673fe..0f2cb369c91 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-high-contrast-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-high-contrast-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-linux.png index 9ac90673201..8d2bab43f7c 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-modern-action-list--true-linux.png index 42e27e9fbf6..ab60656309a 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-tritanopia-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-tritanopia-linux.png index 9ac90673201..8d2bab43f7c 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-tritanopia-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-tritanopia-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-tritanopia-modern-action-list--true-linux.png index 42e27e9fbf6..ab60656309a 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-tritanopia-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-dark-tritanopia-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-colorblind-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-colorblind-linux.png index 2bab09971aa..974e87766d1 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-colorblind-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-colorblind-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-colorblind-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-colorblind-modern-action-list--true-linux.png index 9b1ca05637c..ad6ecc35ddf 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-colorblind-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-colorblind-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-high-contrast-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-high-contrast-linux.png index aa88dca757a..08a8b8a338e 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-high-contrast-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-high-contrast-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-high-contrast-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-high-contrast-modern-action-list--true-linux.png index 7ec337e6482..9789556682e 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-high-contrast-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-high-contrast-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-linux.png index 2bab09971aa..974e87766d1 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-modern-action-list--true-linux.png index 9b1ca05637c..ad6ecc35ddf 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-modern-action-list--true-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-tritanopia-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-tritanopia-linux.png index 2bab09971aa..974e87766d1 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-tritanopia-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-tritanopia-linux.png differ diff --git a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-tritanopia-modern-action-list--true-linux.png b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-tritanopia-modern-action-list--true-linux.png index 9b1ca05637c..ad6ecc35ddf 100644 Binary files a/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-tritanopia-modern-action-list--true-linux.png and b/.playwright/snapshots/components/SelectPanel.test.ts-snapshots/SelectPanel-With-Footer-light-tritanopia-modern-action-list--true-linux.png differ diff --git a/packages/react/src/FeatureFlags/DefaultFeatureFlags.ts b/packages/react/src/FeatureFlags/DefaultFeatureFlags.ts index 6b33404ce39..278ecbfc72e 100644 --- a/packages/react/src/FeatureFlags/DefaultFeatureFlags.ts +++ b/packages/react/src/FeatureFlags/DefaultFeatureFlags.ts @@ -7,4 +7,5 @@ export const DefaultFeatureFlags = FeatureFlagScope.create({ primer_react_overlay_overflow: false, primer_react_segmented_control_tooltip: false, primer_react_select_panel_fullscreen_on_narrow: false, + primer_react_select_panel_order_selected_at_top: true, }) diff --git a/packages/react/src/SelectPanel/SelectPanel.docs.json b/packages/react/src/SelectPanel/SelectPanel.docs.json index d1dd32e4dd0..e6f903cecba 100644 --- a/packages/react/src/SelectPanel/SelectPanel.docs.json +++ b/packages/react/src/SelectPanel/SelectPanel.docs.json @@ -177,6 +177,12 @@ "type": "React.ReactElement", "defaultValue": "null", "description": "Secondary action, it will be rendered in the footer of the panel. Use `SecondaryActionButton` or `SecondaryActionLink` for the action." + }, + { + "name": "showSelectedOptionsFirst", + "type": "boolean", + "description": "Whether to display the selected items at the top of the list", + "default": "true" } ], "subcomponents": [] diff --git a/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx b/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx index 52113395b59..5d30bb6505c 100644 --- a/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.examples.stories.tsx @@ -57,14 +57,7 @@ export const HeightInitialWithOverflowingItemsStory = () => { const [selected, setSelected] = useState(items.slice(1, 3)) const [filter, setFilter] = useState('') const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) return ( @@ -79,12 +72,12 @@ export const HeightInitialWithOverflowingItemsStory = () => { placeholder="Select labels" // button text when no items are selected open={open} onOpenChange={setOpen} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} overlayProps={{width: 'small', height: 'initial', maxHeight: 'xsmall'}} - message={selectedItemsSortedFirst.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItems.length === 0 ? NoResultsMessage(filter) : undefined} /> ) @@ -96,14 +89,7 @@ export const HeightInitialWithUnderflowingItemsStory = () => { const [selected, setSelected] = useState([underflowingItems[0]]) const [filter, setFilter] = useState('') const filteredItems = underflowingItems.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) return ( @@ -118,13 +104,13 @@ export const HeightInitialWithUnderflowingItemsStory = () => { placeholder="Select labels" // button text when no items are selected open={open} onOpenChange={setOpen} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} showItemDividers={true} overlayProps={{width: 'small', height: 'initial', maxHeight: 'xsmall'}} - message={selectedItemsSortedFirst.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItems.length === 0 ? NoResultsMessage(filter) : undefined} /> ) @@ -139,14 +125,7 @@ export const HeightInitialWithUnderflowingItemsAfterFetch = () => { () => fetchedItems.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())), [fetchedItems, filter], ) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) const [height, setHeight] = useState('auto') @@ -171,13 +150,13 @@ export const HeightInitialWithUnderflowingItemsAfterFetch = () => { open={open} onOpenChange={onOpenChange} loading={filteredItems.length === 0 && !filter} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} showItemDividers={true} overlayProps={{width: 'small', height, maxHeight: 'xsmall'}} - message={selectedItemsSortedFirst.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItems.length === 0 ? NoResultsMessage(filter) : undefined} /> ) @@ -188,14 +167,7 @@ export const AboveTallBody = () => { const [selected, setSelected] = useState(items.slice(1, 3)) const [filter, setFilter] = useState('') const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) return ( @@ -209,12 +181,12 @@ export const AboveTallBody = () => { placeholder="Select labels" // button text when no items are selected open={open} onOpenChange={setOpen} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} showItemDividers={true} - message={selectedItemsSortedFirst.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItems.length === 0 ? NoResultsMessage(filter) : undefined} />
{ // Example A const [selectedA, setSelectedA] = React.useState(longItems[0]) const filteredItemsA = longItems.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirstA = filteredItemsA.sort((a, b) => { - if (a.text === selectedA?.text) return -1 - if (b.text === selectedA?.text) return 1 - return 0 - }) + const [openA, setOpenA] = useState(false) // Example B const [selectedB, setSelectedB] = React.useState(longItems[0]) const filteredItemsB = longItems.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirstB = filteredItemsB.sort((a, b) => { - if (a.text === selectedB?.text) return -1 - if (b.text === selectedB?.text) return 1 - return 0 - }) + const [openB, setOpenB] = useState(false) return ( @@ -270,13 +232,13 @@ export const HeightVariationsAndScroll = () => { placeholder="Select labels" // button text when no items are selected open={openA} onOpenChange={setOpenA} - items={selectedItemsSortedFirstA} + items={filteredItemsA} selected={selectedA} onSelectedChange={setSelectedA} onFilterChange={setFilter} showItemDividers={true} overlayProps={{height: 'medium'}} - message={selectedItemsSortedFirstA.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItemsA.length === 0 ? NoResultsMessage(filter) : undefined} />
@@ -291,7 +253,7 @@ export const HeightVariationsAndScroll = () => { placeholder="Select labels" // button text when no items are selected open={openB} onOpenChange={setOpenB} - items={selectedItemsSortedFirstB} + items={filteredItemsB} selected={selectedB} onSelectedChange={setSelectedB} onFilterChange={setFilter} @@ -300,7 +262,7 @@ export const HeightVariationsAndScroll = () => { height: 'auto', maxHeight: 'medium', }} - message={selectedItemsSortedFirstB.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItemsB.length === 0 ? NoResultsMessage(filter) : undefined} /> @@ -317,14 +279,7 @@ export const CustomItemRenderer = () => { const [selected, setSelected] = useState(items.slice(1, 3)) const [filter, setFilter] = useState('') const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) return ( @@ -339,7 +294,7 @@ export const CustomItemRenderer = () => { )} open={open} onOpenChange={setOpen} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} @@ -369,7 +324,7 @@ export const CustomItemRenderer = () => { )} - message={selectedItemsSortedFirst.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItems.length === 0 ? NoResultsMessage(filter) : undefined} /> ) @@ -392,14 +347,7 @@ export const ItemsInScope = () => { const [selected, setSelected] = useState(items.slice(1, 3)) const [filter, setFilter] = useState('') const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) return ( @@ -409,11 +357,11 @@ export const ItemsInScope = () => { placeholder="Select labels" // button text when no items are selected open={open} onOpenChange={setOpen} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} - message={selectedItemsSortedFirst.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItems.length === 0 ? NoResultsMessage(filter) : undefined} /> ) diff --git a/packages/react/src/SelectPanel/SelectPanel.features.stories.tsx b/packages/react/src/SelectPanel/SelectPanel.features.stories.tsx index 707ae6b98b0..084bd7690ed 100644 --- a/packages/react/src/SelectPanel/SelectPanel.features.stories.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.features.stories.tsx @@ -87,14 +87,7 @@ export const WithItemDividers = () => { const [selected, setSelected] = useState(items.slice(1, 3)) const [filter, setFilter] = useState('') const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) return ( @@ -111,13 +104,13 @@ export const WithItemDividers = () => { )} open={open} onOpenChange={setOpen} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} showItemDividers={true} width="medium" - message={selectedItemsSortedFirst.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItems.length === 0 ? NoResultsMessage(filter) : undefined} /> ) @@ -127,14 +120,7 @@ export const WithPlaceholderForSearchInput = () => { const [selected, setSelected] = useState(items.slice(1, 3)) const [filter, setFilter] = useState('') const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) return ( @@ -152,12 +138,12 @@ export const WithPlaceholderForSearchInput = () => { placeholderText="Filter labels" open={open} onOpenChange={setOpen} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} width="medium" - message={selectedItemsSortedFirst.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItems.length === 0 ? NoResultsMessage(filter) : undefined} /> ) @@ -227,14 +213,7 @@ export const WithExternalAnchor = () => { const [selected, setSelected] = useState(items.slice(1, 3)) const [filter, setFilter] = useState('') const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) const buttonRef = useRef(null) @@ -250,7 +229,7 @@ export const WithExternalAnchor = () => { open={open} onOpenChange={setOpen} items={filteredItems} - selected={selectedItemsSortedFirst} + selected={filteredItems} onSelectedChange={setSelected} onFilterChange={setFilter} width="medium" @@ -326,14 +305,7 @@ export const WithNotice = () => { const [selected, setSelected] = useState(items.slice(1, 3)) const [filter, setFilter] = useState('') const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) const [noticeVariant, setNoticeVariant] = useState(0) @@ -389,7 +361,7 @@ export const WithNotice = () => { placeholder="Select labels" // button text when no items are selected open={open} onOpenChange={setOpen} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} @@ -451,16 +423,7 @@ export const WithGroups = () => { const [selected, setSelected] = useState([]) const [filter, setFilter] = useState('') const filteredItems = listOfItems.filter(item => item.text?.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - if (a.groupId === b.groupId) { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - } - return 0 - }) + const [open, setOpen] = useState(false) return ( @@ -478,13 +441,13 @@ export const WithGroups = () => { groupMetadata={groupMetadata} open={open} onOpenChange={setOpen} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} overlayProps={{width: 'large', height: 'xlarge'}} width="medium" - message={selectedItemsSortedFirst.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItems.length === 0 ? NoResultsMessage(filter) : undefined} /> ) @@ -494,14 +457,7 @@ export const WithLabelVisuallyHidden = () => { const [selected, setSelected] = useState(items.slice(1, 3)) const [filter, setFilter] = useState('') const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) return ( @@ -518,12 +474,12 @@ export const WithLabelVisuallyHidden = () => { )} open={open} onOpenChange={setOpen} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} width="medium" - message={selectedItemsSortedFirst.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItems.length === 0 ? NoResultsMessage(filter) : undefined} /> ) @@ -533,14 +489,7 @@ export const WithLabelInternally = () => { const [selected, setSelected] = useState(items.slice(1, 3)) const [filter, setFilter] = useState('') const filteredItems = items.filter(item => item.text.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) return ( @@ -560,12 +509,12 @@ export const WithLabelInternally = () => { )} open={open} onOpenChange={setOpen} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} width="medium" - message={selectedItemsSortedFirst.length === 0 ? NoResultsMessage(filter) : undefined} + message={filteredItems.length === 0 ? NoResultsMessage(filter) : undefined} /> ) } diff --git a/packages/react/src/SelectPanel/SelectPanel.stories.tsx b/packages/react/src/SelectPanel/SelectPanel.stories.tsx index fac495cda3c..d8a32211f57 100644 --- a/packages/react/src/SelectPanel/SelectPanel.stories.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.stories.tsx @@ -66,14 +66,7 @@ export const Default = () => { const [selected, setSelected] = useState(items.slice(1, 3)) const [filter, setFilter] = useState('') const filteredItems = items.filter(item => item.text?.toLowerCase().startsWith(filter.toLowerCase())) - // design guidelines say to sort selected items first - const selectedItemsSortedFirst = filteredItems.sort((a, b) => { - const aIsSelected = selected.some(selectedItem => selectedItem.text === a.text) - const bIsSelected = selected.some(selectedItem => selectedItem.text === b.text) - if (aIsSelected && !bIsSelected) return -1 - if (!aIsSelected && bIsSelected) return 1 - return 0 - }) + const [open, setOpen] = useState(false) return ( @@ -90,13 +83,13 @@ export const Default = () => { )} open={open} onOpenChange={setOpen} - items={selectedItemsSortedFirst} + items={filteredItems} selected={selected} onSelectedChange={setSelected} onFilterChange={setFilter} width="medium" message={ - selectedItemsSortedFirst.length === 0 + filteredItems.length === 0 ? { variant: 'empty', title: `No language found for \`${filter}\``, diff --git a/packages/react/src/SelectPanel/SelectPanel.test.tsx b/packages/react/src/SelectPanel/SelectPanel.test.tsx index b36dcee132a..17efc043b25 100644 --- a/packages/react/src/SelectPanel/SelectPanel.test.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.test.tsx @@ -998,6 +998,74 @@ for (const useModernActionList of [false, true]) { expect(screen.getByRole('button', {name: 'Cancel'})).toBeVisible() }) }) + + describe('sorting', () => { + const items = [ + { + text: 'item one', + id: '3', + }, + { + text: 'item two', + id: '1', + selected: true, + }, + { + text: 'item three', + id: '2', + }, + ] + + it('should render selected items at the top by default when FF on', async () => { + const user = userEvent.setup() + + renderWithFlag( + + + , + useModernActionList, + ) + + await user.click(screen.getByText('item two')) // item two is selected so that's what the anchor text is + + const options = screen.getAllByRole('option') + expect(options[0]).toHaveTextContent('item two') // item two is selected + expect(options[1]).toHaveTextContent('item one') + expect(options[2]).toHaveTextContent('item three') + }) + it('should not render selected items at the top by default when FF off', async () => { + const user = userEvent.setup() + + renderWithFlag( + + + , + useModernActionList, + ) + + await user.click(screen.getByText('item two')) // item two is selected so that's what the anchor text is + + const options = screen.getAllByRole('option') + expect(options[0]).toHaveTextContent('item one') + expect(options[1]).toHaveTextContent('item two') // item two is selected + expect(options[2]).toHaveTextContent('item three') + }) + it('should not render selected items at the top when showSelectedOptionsFirst set to false', async () => { + const user = userEvent.setup() + + renderWithFlag( + , + useModernActionList, + ) + + await user.click(screen.getByText('item two')) // item two is selected so that's what the anchor text is + + const options = screen.getAllByRole('option') + expect(options[0]).toHaveTextContent('item one') + expect(options[1]).toHaveTextContent('item two') // item two is selected + expect(options[2]).toHaveTextContent('item three') + }) + }) }) }) } diff --git a/packages/react/src/SelectPanel/SelectPanel.tsx b/packages/react/src/SelectPanel/SelectPanel.tsx index b78d3638b3b..fefc930ae6c 100644 --- a/packages/react/src/SelectPanel/SelectPanel.tsx +++ b/packages/react/src/SelectPanel/SelectPanel.tsx @@ -100,6 +100,7 @@ interface SelectPanelBaseProps { * @deprecated Use `secondaryAction` instead. */ footer?: string | React.ReactElement + showSelectedOptionsFirst?: boolean } // onCancel is optional with variant=anchored, but required with variant=modal @@ -170,6 +171,7 @@ function Panel({ onCancel, variant = 'anchored', secondaryAction, + showSelectedOptionsFirst = true, ...listProps }: SelectPanelProps): JSX.Element { const titleId = useId() @@ -185,9 +187,14 @@ function Panel({ const [listContainerElement, setListContainerElement] = useState(null) const [needsNoItemsAnnouncement, setNeedsNoItemsAnnouncement] = useState(false) const isNarrowScreenSize = useResponsiveValue({narrow: true, regular: false, wide: false}, false) + const [selectedOnSort, setSelectedOnSort] = useState([]) + const [prevItems, setPrevItems] = useState([]) + const [prevOpen, setPrevOpen] = useState(open) const usingModernActionList = useFeatureFlag('primer_react_select_panel_with_modern_action_list') const usingFullScreenOnNarrow = useFeatureFlag('primer_react_select_panel_fullscreen_on_narrow') + const shouldOrderSelectedFirst = + useFeatureFlag('primer_react_select_panel_order_selected_at_top') && showSelectedOptionsFirst // Single select modals work differently, they have an intermediate state where the user has selected an item but // has not yet confirmed the selection. This is the only time the user can cancel the selection. @@ -219,6 +226,16 @@ function Panel({ [setInputRef], ) + const resetSort = useCallback(() => { + if (isMultiSelectVariant(selected)) { + setSelectedOnSort(selected) + } else if (selected) { + setSelectedOnSort([selected]) + } else { + setSelectedOnSort([]) + } + }, [selected]) + const onFilterChange: FilteredActionListProps['onFilterChange'] = useCallback( (value, e) => { if (loadingManagedInternally) { @@ -252,6 +269,9 @@ function Panel({ externalOnFilterChange(value, e) setInternalFilterValue(value) + if (!value) { + resetSort() + } }, [ loadingManagedInternally, @@ -261,6 +281,7 @@ function Panel({ safeSetTimeout, safeClearTimeout, items.length, + resetSort, ], ) @@ -403,46 +424,101 @@ function Panel({ ) const itemsToRender = useMemo(() => { - return items.map(item => { - return { - ...item, - role: 'option', - selected: 'selected' in item && item.selected === undefined ? undefined : isItemCurrentlySelected(item), - onAction: (itemFromAction, event) => { - item.onAction?.(itemFromAction, event) - - if (event.defaultPrevented) { - return - } + return items + .map(item => { + return { + ...item, + role: 'option', + selected: 'selected' in item && item.selected === undefined ? undefined : isItemCurrentlySelected(item), + onAction: (itemFromAction, event) => { + item.onAction?.(itemFromAction, event) + + if (event.defaultPrevented) { + return + } - if (isMultiSelectVariant(selected)) { - const otherSelectedItems = selected.filter(selectedItem => !areItemsEqual(selectedItem, item)) - const newSelectedItems = doesItemsIncludeItem(selected, item) - ? otherSelectedItems - : [...otherSelectedItems, item] + if (isMultiSelectVariant(selected)) { + const otherSelectedItems = selected.filter(selectedItem => !areItemsEqual(selectedItem, item)) + const newSelectedItems = doesItemsIncludeItem(selected, item) + ? otherSelectedItems + : [...otherSelectedItems, item] - const multiSelectOnChange = onSelectedChange as SelectPanelMultiSelection['onSelectedChange'] - multiSelectOnChange(newSelectedItems) - return - } + const multiSelectOnChange = onSelectedChange as SelectPanelMultiSelection['onSelectedChange'] + multiSelectOnChange(newSelectedItems) + return + } - if (isSingleSelectModal) { - if (intermediateSelected?.id === item.id) { - // if the item is already selected, we need to unselect it - setIntermediateSelected(undefined) - } else { - setIntermediateSelected(item) + if (isSingleSelectModal) { + if (intermediateSelected?.id === item.id) { + // if the item is already selected, we need to unselect it + setIntermediateSelected(undefined) + } else { + setIntermediateSelected(item) + } + return } - return + // single select anchored, direct save on click + const singleSelectOnChange = onSelectedChange as SelectPanelSingleSelection['onSelectedChange'] + singleSelectOnChange(item === selected ? undefined : item) + onClose('selection') + }, + } as ItemProps + }) + .sort((itemA, itemB) => { + if (shouldOrderSelectedFirst) { + // itemA is selected (for sorting purposes) if an object in selectedOnSort matches every property of itemA, except for the selected property + const itemASelected = selectedOnSort.some(item => + Object.entries(item).every(([key, value]) => { + if (key === 'selected') { + return true + } + return itemA[key as keyof ItemProps] === value + }), + ) + + // itemB is selected (for sorting purposes) if an object in selectedOnSort matches every property of itemA, except for the selected property + const itemBSelected = selectedOnSort.some(item => + Object.entries(item).every(([key, value]) => { + if (key === 'selected') { + return true + } + return itemB[key as keyof ItemProps] === value + }), + ) + + // order selected items first + if (itemASelected > itemBSelected) { + return -1 + } else if (itemASelected < itemBSelected) { + return 1 } - // single select anchored, direct save on click - const singleSelectOnChange = onSelectedChange as SelectPanelSingleSelection['onSelectedChange'] - singleSelectOnChange(item === selected ? undefined : item) - onClose('selection') - }, - } as ItemProps - }) - }, [onClose, onSelectedChange, items, selected, isItemCurrentlySelected, isSingleSelectModal, intermediateSelected]) + } + + return 0 + }) + }, [ + onClose, + onSelectedChange, + items, + selected, + isItemCurrentlySelected, + isSingleSelectModal, + intermediateSelected, + shouldOrderSelectedFirst, + selectedOnSort, + ]) + + if (prevItems !== items) { + setPrevItems(items) + if (prevItems.length === 0 && items.length > 0) { + resetSort() + } + } + + if (open !== prevOpen) { + setPrevOpen(open) + resetSort() + } const focusTrapSettings = { initialFocusRef: inputRef || undefined, diff --git a/results.json b/results.json new file mode 100644 index 00000000000..0637a088a01 --- /dev/null +++ b/results.json @@ -0,0 +1 @@ +[] \ No newline at end of file