Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add 'translucent' variant to Popover #45

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ import {
Flex,
Grid,
Heading,
IconButton,
Inset,
Popover,
SegmentedControl,
Separator,
Switch,
Text,
TextArea,
popoverContentPropDefs,
Expand All @@ -34,6 +38,7 @@ type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
size: popoverContentPropDefs.size.default,
variant: popoverContentPropDefs.variant.default,
},
render: ({ children, ...args }) => (
<Popover.Root>
Expand Down Expand Up @@ -68,10 +73,108 @@ export const Default: Story = {
),
};

export const Variant: Story = {
args: {
size: popoverContentPropDefs.size.default,
},
render: ({ children, ...args }) => {
type Appearance = 'light' | 'dark';
const [appearance, setAppearance] = React.useState<Appearance>('light');

return (
<Flex gap="5" align="center">
<Popover.Root>
<Popover.Trigger>
<IconButton variant="ghost" color="gray" size="3">
<AppearanceIcon />
</IconButton>
</Popover.Trigger>
<Popover.Content
{...args}
variant="translucent"
align="center"
style={{ width: 292 }}
>
<Heading size="3" mb="2">
Theme
</Heading>
<SegmentedControl.Root
value={appearance}
onValueChange={(appearance) =>
setAppearance(appearance as Appearance)
}
>
<SegmentedControl.List>
<SegmentedControl.Trigger value="light">
<LightModeIcon />
Light
</SegmentedControl.Trigger>
<SegmentedControl.Trigger value="dark">
<DarkModeIcon />
Dark
</SegmentedControl.Trigger>
</SegmentedControl.List>
</SegmentedControl.Root>
<Separator orientation="horizontal" size="4" my="4" />
<Text as="label" size="2">
<Flex gap="2" align="center">
<Switch />
Auto switching
</Flex>
</Text>
</Popover.Content>
</Popover.Root>
<Popover.Root>
<Popover.Trigger>
<IconButton variant="surface" color="gray" size="3">
<AppearanceIcon />
</IconButton>
</Popover.Trigger>
<Popover.Content
{...args}
variant="solid"
align="center"
style={{ width: 292 }}
>
<Heading size="3" mb="2">
Theme
</Heading>
<SegmentedControl.Root
value={appearance}
onValueChange={(appearance) =>
setAppearance(appearance as Appearance)
}
>
<SegmentedControl.List>
<SegmentedControl.Trigger value="light">
<LightModeIcon />
Light
</SegmentedControl.Trigger>
<SegmentedControl.Trigger value="dark">
<DarkModeIcon />
Dark
</SegmentedControl.Trigger>
</SegmentedControl.List>
</SegmentedControl.Root>
<Separator orientation="horizontal" size="4" my="4" />
<Text as="label" size="2">
<Flex gap="2" align="center">
<Switch />
Auto switching
</Flex>
</Text>
</Popover.Content>
</Popover.Root>
</Flex>
);
},
};

export const InsetContent: Story = {
name: 'With inset content',
args: {
size: popoverContentPropDefs.size.default,
variant: popoverContentPropDefs.variant.default,
},
render: ({ children, ...args }) => (
<Popover.Root>
Expand Down Expand Up @@ -108,3 +211,133 @@ export const InsetContent: Story = {
</Popover.Root>
),
};

const LightModeIcon = () => (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_1411_65802)">
<mask id="path-1-inside-1_1411_65802" fill="white">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M8.06396 2.23585C8.83285 2.04475 9.35808 2.9153 9.16128 3.68274C8.65248 5.66684 9.17475 7.86078 10.7281 9.4141C12.2377 10.9238 14.3525 11.4595 16.2916 11.0214C17.0641 10.8468 17.9185 11.3966 17.7052 12.1594C16.7629 15.5287 13.67 18 9.99999 18C5.58171 18 1.99999 14.4183 1.99999 10C1.99999 6.24932 4.58109 3.10149 8.06396 2.23585Z"
/>
</mask>
<path
d="M9.99999 18L9.99999 16.5L9.99999 18ZM1.99999 10H0.499988H1.99999ZM16.2916 11.0214L16.6222 12.4845L16.2916 11.0214ZM17.7052 12.1594L16.2606 11.7554L17.7052 12.1594ZM11.7887 8.35344C10.6255 7.19025 10.2317 5.54719 10.6143 4.05534L7.70829 3.31014C7.07327 5.7865 7.72396 8.53132 9.66741 10.4748L11.7887 8.35344ZM15.961 9.55824C14.5028 9.88772 12.9193 9.48404 11.7887 8.35344L9.66741 10.4748C11.5561 12.3635 14.2021 13.0313 16.6222 12.4845L15.961 9.55824ZM16.2606 11.7554C15.4948 14.4937 12.9798 16.5 9.99999 16.5L9.99999 19.5C14.3603 19.5 18.031 16.5637 19.1497 12.5634L16.2606 11.7554ZM9.99999 16.5C6.41014 16.5 3.49999 13.5899 3.49999 10L0.499988 10C0.499988 15.2467 4.75328 19.5 9.99999 19.5L9.99999 16.5ZM3.49999 10C3.49999 6.95459 5.59578 4.39493 8.42577 3.69156L7.70216 0.78014C3.56641 1.80804 0.499988 5.54405 0.499988 10L3.49999 10ZM16.6222 12.4845C16.5854 12.4928 16.5435 12.4951 16.4725 12.4422C16.4273 12.4086 16.3454 12.3308 16.2894 12.1903C16.228 12.0362 16.2267 11.8764 16.2606 11.7554L19.1497 12.5634C19.455 11.4719 18.9444 10.5422 18.2636 10.0356C17.6256 9.56074 16.7703 9.37539 15.961 9.55824L16.6222 12.4845ZM10.6143 4.05534C10.8204 3.25147 10.6597 2.39102 10.2035 1.73952C9.71686 1.04445 8.80237 0.506692 7.70216 0.78014L8.42577 3.69156C8.30375 3.72189 8.14411 3.71592 7.99201 3.65013C7.85336 3.59017 7.7782 3.50616 7.74599 3.46016C7.69548 3.38802 7.69895 3.34657 7.70829 3.31014L10.6143 4.05534Z"
fill="currentColor"
mask="url(#path-1-inside-1_1411_65802)"
/>
</g>
<defs>
<clipPath id="clip0_1411_65802">
<rect width="20" height="20" fill="white" />
</clipPath>
</defs>
</svg>
);

const DarkModeIcon = () => (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_1411_65816)">
<circle
cx="10"
cy="10"
r="3.25"
stroke="currentColor"
strokeWidth="1.5"
/>
<path
d="M10 3V1"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
<path
d="M17 10H19"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
<path
d="M1 10L3 10"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
<path
d="M10 19V17"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
<path
d="M14.9498 5.0502L16.364 3.63599"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
<path
d="M14.9497 14.9497L16.3639 16.3639"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
<path
d="M3.63599 3.63599L5.0502 5.0502"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
<path
d="M3.63608 16.3639L5.05029 14.9497"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
</g>
<defs>
<clipPath id="clip0_1411_65816">
<rect width="20" height="20" fill="currentColor" />
</clipPath>
</defs>
</svg>
);

const AppearanceIcon = () => (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_1402_143841)">
<path
d="M10 1.25C5 1.25 1.25 5 1.25 10C1.25 14.6939 4.28561 17.0376 6.55714 18.1344C7.89989 18.7827 9.34365 17.9439 9.85683 16.5439C10.9906 13.451 11.4382 13.7412 15.8146 13.7498C15.9355 13.7501 16.0605 13.7564 16.1813 13.7511C16.794 13.724 18.75 13.3734 18.75 10C18.75 5 15 1.25 10 1.25Z"
stroke="currentColor"
strokeWidth="1.5"
/>
<circle cx="5" cy="12" r="1" fill="currentColor" />
<circle cx="6" cy="7" r="1" fill="currentColor" />
<circle cx="11" cy="5" r="1" fill="currentColor" />
<circle cx="15" cy="8" r="1" fill="currentColor" />
</g>
<defs>
<clipPath id="clip0_1402_143841">
<rect width="20" height="20" fill="currentColor" />
</clipPath>
</defs>
</svg>
);
19 changes: 18 additions & 1 deletion packages/frosted-ui/src/components/popover.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.fui-PopoverContent {
background-color: var(--color-panel-solid);
box-shadow: var(--shadow-5);
min-width: var(--radix-popover-trigger-width);
outline: 0;
Expand All @@ -9,6 +8,24 @@
padding: var(--popover-content-padding);

transform-origin: var(--radix-popover-content-transform-origin);

&:where(.fui-variant-translucent) {
background-color: var(--color-panel-translucent);
-webkit-backdrop-filter: var(--backdrop-filter-panel);
backdrop-filter: var(--backdrop-filter-panel);
outline: 0.5px solid var(--color-popover-outline);
}
&:where(.fui-variant-solid) {
background-color: var(--color-panel-solid);
}
}
/* prettier-ignore */
:where(.frosted-ui) {
--color-popover-outline: transparent;
}
:is(.dark, .dark-theme),
:is(.dark, .dark-theme) :where(.frosted-ui:not(.light, .light-theme)) {
--color-popover-outline: black;
}

/***************************************************************************************************
Expand Down
4 changes: 4 additions & 0 deletions packages/frosted-ui/src/components/popover.props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import type { PropDef } from '../helpers';

const contentSizes = ['1', '2', '3', '4'] as const;

const variants = ['solid', 'translucent'] as const;

const popoverContentPropDefs = {
size: { type: 'enum', values: contentSizes, default: '2', responsive: true },
variant: { type: 'enum', values: variants, default: 'translucent' },
} satisfies {
size: PropDef<(typeof contentSizes)[number]>;
variant: PropDef<(typeof variants)[number]>;
};

export { popoverContentPropDefs };
2 changes: 2 additions & 0 deletions packages/frosted-ui/src/components/popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const PopoverContent = React.forwardRef<
forceMount,
container,
size = popoverContentPropDefs.size.default,
variant = popoverContentPropDefs.variant.default,
...contentProps
} = props;
return (
Expand All @@ -63,6 +64,7 @@ const PopoverContent = React.forwardRef<
className={classNames(
'fui-PopperContent',
'fui-PopoverContent',
`fui-variant-${variant}`,
className,
withBreakpoints(size, 'fui-r-size'),
)}
Expand Down