Truncate long country lists with a popover
AWS-scale region lists blew out subprocessor cards. Cap the visible labels and open the rest from a +N trigger using a new Base UI Popover in the v2 kit. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
44
packages/ui/src/v2/Popover/Popover.stories.tsx
Normal file
44
packages/ui/src/v2/Popover/Popover.stories.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import { Button } from "../Button/Button";
|
||||
import { Text } from "../typography/Text";
|
||||
|
||||
import { Popover } from "./Popover";
|
||||
import { PopoverPopup } from "./PopoverPopup";
|
||||
import { PopoverTrigger } from "./PopoverTrigger";
|
||||
|
||||
export default {
|
||||
title: "v2/Popover",
|
||||
component: Popover,
|
||||
};
|
||||
|
||||
export function Default() {
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger render={<Button variant="soft" color="neutral">Open popover</Button>} />
|
||||
<PopoverPopup>
|
||||
<Text size={2} color="neutral" highContrast>
|
||||
Popover content goes here.
|
||||
</Text>
|
||||
</PopoverPopup>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
30
packages/ui/src/v2/Popover/Popover.tsx
Normal file
30
packages/ui/src/v2/Popover/Popover.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import { Popover as BasePopover } from "@base-ui/react/popover";
|
||||
import type { ComponentProps } from "react";
|
||||
|
||||
// Root of the popover (Radix "Popover"). Controlled the same way as Base UI's
|
||||
// Popover: `open` / `onOpenChange`, or left uncontrolled. See contrib/claude/ui.md.
|
||||
export type PopoverProps = ComponentProps<typeof BasePopover.Root>;
|
||||
|
||||
export function Popover(props: PopoverProps) {
|
||||
return <BasePopover.Root {...props} />;
|
||||
}
|
||||
54
packages/ui/src/v2/Popover/PopoverPopup.tsx
Normal file
54
packages/ui/src/v2/Popover/PopoverPopup.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import { Popover as BasePopover } from "@base-ui/react/popover";
|
||||
import type { ComponentProps } from "react";
|
||||
|
||||
import { popoverPopup } from "./variants";
|
||||
|
||||
export type PopoverPopupProps
|
||||
= & Omit<ComponentProps<typeof BasePopover.Popup>, "className">
|
||||
& {
|
||||
className?: string;
|
||||
// Positioner placement passthrough.
|
||||
side?: ComponentProps<typeof BasePopover.Positioner>["side"];
|
||||
align?: ComponentProps<typeof BasePopover.Positioner>["align"];
|
||||
sideOffset?: ComponentProps<typeof BasePopover.Positioner>["sideOffset"];
|
||||
};
|
||||
|
||||
// Portal + positioner + styled popup. Content-agnostic — callers compose children.
|
||||
export function PopoverPopup(props: PopoverPopupProps) {
|
||||
const {
|
||||
className, children,
|
||||
side = "bottom", align = "start", sideOffset = 4,
|
||||
...popupProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<BasePopover.Portal>
|
||||
{/* z-3 on the Positioner so the portaled root wins over in-page z-1. */}
|
||||
<BasePopover.Positioner className="z-3" side={side} align={align} sideOffset={sideOffset}>
|
||||
<BasePopover.Popup className={popoverPopup({ className })} {...popupProps}>
|
||||
{children}
|
||||
</BasePopover.Popup>
|
||||
</BasePopover.Positioner>
|
||||
</BasePopover.Portal>
|
||||
);
|
||||
}
|
||||
30
packages/ui/src/v2/Popover/PopoverTrigger.tsx
Normal file
30
packages/ui/src/v2/Popover/PopoverTrigger.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import { Popover as BasePopover } from "@base-ui/react/popover";
|
||||
import type { ComponentProps } from "react";
|
||||
|
||||
// The element that opens the popover. Compose a Button via `render` to style it,
|
||||
// or pass className/children for a native button trigger.
|
||||
export type PopoverTriggerProps = ComponentProps<typeof BasePopover.Trigger>;
|
||||
|
||||
export function PopoverTrigger(props: PopoverTriggerProps) {
|
||||
return <BasePopover.Trigger {...props} />;
|
||||
}
|
||||
32
packages/ui/src/v2/Popover/variants.ts
Normal file
32
packages/ui/src/v2/Popover/variants.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import { tv } from "tailwind-variants/lite";
|
||||
|
||||
// Floating popover surface (Radix "Popover" over Base UI). Same panel look as
|
||||
// DropdownPopup; content-agnostic so callers compose arbitrary children.
|
||||
|
||||
export const popoverPopup = tv({
|
||||
base: [
|
||||
"max-w-sm origin-(--transform-origin) rounded-3 bg-sand-1 p-3 shadow-5 outline-none",
|
||||
"transition-[scale,opacity] duration-150 ease-out data-starting-style:scale-95 data-starting-style:opacity-0",
|
||||
"data-ending-style:scale-95 data-ending-style:opacity-0",
|
||||
],
|
||||
});
|
||||
Reference in New Issue
Block a user