Add popover component
This commit is contained in:
139
components/Popover.tsx
Normal file
139
components/Popover.tsx
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
import React, { ReactNode } from "react";
|
||||||
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
||||||
|
import { styled, keyframes } from "../stitches.config";
|
||||||
|
|
||||||
|
const slideUpAndFade = keyframes({
|
||||||
|
"0%": { opacity: 0, transform: "translateY(2px)" },
|
||||||
|
"100%": { opacity: 1, transform: "translateY(0)" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const slideRightAndFade = keyframes({
|
||||||
|
"0%": { opacity: 0, transform: "translateX(-2px)" },
|
||||||
|
"100%": { opacity: 1, transform: "translateX(0)" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const slideDownAndFade = keyframes({
|
||||||
|
"0%": { opacity: 0, transform: "translateY(-2px)" },
|
||||||
|
"100%": { opacity: 1, transform: "translateY(0)" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const slideLeftAndFade = keyframes({
|
||||||
|
"0%": { opacity: 0, transform: "translateX(2px)" },
|
||||||
|
"100%": { opacity: 1, transform: "translateX(0)" },
|
||||||
|
});
|
||||||
|
const StyledContent = styled(PopoverPrimitive.Content, {
|
||||||
|
borderRadius: 4,
|
||||||
|
padding: "$3 $3",
|
||||||
|
fontSize: 12,
|
||||||
|
lineHeight: 1,
|
||||||
|
color: "$text",
|
||||||
|
boxShadow:
|
||||||
|
"0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2)",
|
||||||
|
"@media (prefers-reduced-motion: no-preference)": {
|
||||||
|
animationDuration: "400ms",
|
||||||
|
animationTimingFunction: "cubic-bezier(0.16, 1, 0.3, 1)",
|
||||||
|
willChange: "transform, opacity",
|
||||||
|
'&[data-state="open"]': {
|
||||||
|
'&[data-side="top"]': { animationName: slideDownAndFade },
|
||||||
|
'&[data-side="right"]': { animationName: slideLeftAndFade },
|
||||||
|
'&[data-side="bottom"]': { animationName: slideUpAndFade },
|
||||||
|
'&[data-side="left"]': { animationName: slideRightAndFade },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
".dark &": {
|
||||||
|
backgroundColor: "$mauve5",
|
||||||
|
boxShadow:
|
||||||
|
"0px 10px 38px -10px rgba(22, 23, 24, 0.85), 0px 10px 20px -15px rgba(22, 23, 24, 0.6)",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledArrow = styled(PopoverPrimitive.Arrow, {
|
||||||
|
fill: "$colors$mauve2",
|
||||||
|
".dark &": {
|
||||||
|
fill: "$mauve5",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledClose = styled(PopoverPrimitive.Close, {
|
||||||
|
all: "unset",
|
||||||
|
fontFamily: "inherit",
|
||||||
|
borderRadius: "100%",
|
||||||
|
height: 25,
|
||||||
|
width: 25,
|
||||||
|
display: "inline-flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
color: "$text",
|
||||||
|
position: "absolute",
|
||||||
|
top: 5,
|
||||||
|
right: 5,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
export const PopoverRoot = PopoverPrimitive.Root;
|
||||||
|
export const PopoverTrigger = PopoverPrimitive.Trigger;
|
||||||
|
export const PopoverContent = StyledContent;
|
||||||
|
export const PopoverArrow = StyledArrow;
|
||||||
|
export const PopoverClose = StyledClose;
|
||||||
|
|
||||||
|
// const PopoverDemo = () => (
|
||||||
|
// <Popover>
|
||||||
|
// <PopoverContent sideOffset={5}>
|
||||||
|
// <Flex css={{ flexDirection: "column", gap: 10 }}>
|
||||||
|
// <Text bold css={{ marginBottom: 10 }}>
|
||||||
|
// Dimensions
|
||||||
|
// </Text>
|
||||||
|
// <Fieldset>
|
||||||
|
// <Label htmlFor="width">Width</Label>
|
||||||
|
// <Input id="width" defaultValue="100%" />
|
||||||
|
// </Fieldset>
|
||||||
|
// <Fieldset>
|
||||||
|
// <Label htmlFor="maxWidth">Max. width</Label>
|
||||||
|
// <Input id="maxWidth" defaultValue="300px" />
|
||||||
|
// </Fieldset>
|
||||||
|
// <Fieldset>
|
||||||
|
// <Label htmlFor="height">Height</Label>
|
||||||
|
// <Input id="height" defaultValue="25px" />
|
||||||
|
// </Fieldset>
|
||||||
|
// <Fieldset>
|
||||||
|
// <Label htmlFor="maxHeight">Max. height</Label>
|
||||||
|
// <Input id="maxHeight" defaultValue="none" />
|
||||||
|
// </Fieldset>
|
||||||
|
// </Flex>
|
||||||
|
// <PopoverArrow />
|
||||||
|
// <PopoverClose aria-label="Close">
|
||||||
|
// <Cross2Icon />
|
||||||
|
// </PopoverClose>
|
||||||
|
// </PopoverContent>
|
||||||
|
// </Popover>
|
||||||
|
// );
|
||||||
|
|
||||||
|
// export default PopoverDemo;
|
||||||
|
|
||||||
|
interface IPopover {
|
||||||
|
content: string | ReactNode;
|
||||||
|
open?: boolean;
|
||||||
|
defaultOpen?: boolean;
|
||||||
|
onOpenChange?: (open: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Popover: React.FC<IPopover> = ({
|
||||||
|
children,
|
||||||
|
content,
|
||||||
|
open,
|
||||||
|
defaultOpen = false,
|
||||||
|
onOpenChange,
|
||||||
|
}) => (
|
||||||
|
<PopoverRoot
|
||||||
|
open={open}
|
||||||
|
defaultOpen={defaultOpen}
|
||||||
|
onOpenChange={onOpenChange}
|
||||||
|
>
|
||||||
|
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
||||||
|
<PopoverContent sideOffset={5}>
|
||||||
|
{content} <PopoverArrow />
|
||||||
|
</PopoverContent>
|
||||||
|
</PopoverRoot>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Popover;
|
||||||
Reference in New Issue
Block a user