Skip to content

Commit

Permalink
Merge pull request #364 from andriishupta/feat/dropdown-menu
Browse files Browse the repository at this point in the history
feature: add DropdownMenu
  • Loading branch information
e-roy authored Jul 25, 2022
2 parents 7c88810 + f3511c9 commit cea3b21
Show file tree
Hide file tree
Showing 12 changed files with 1,516 additions and 36 deletions.
2 changes: 2 additions & 0 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
"@babel/runtime": "^7.16.7",
"@radix-ui/colors": "^0.1.8",
"@radix-ui/react-checkbox": "^1.0.0",
"@radix-ui/react-dropdown-menu": "^1.0.0",
"@radix-ui/react-icons": "^1.1.1",
"@radix-ui/react-menu": "^1.0.0",
"@stitches/react": "^1.2.8",
"framer-motion": "^6.3.15",
"wagmi": "^0.5.5"
Expand Down
124 changes: 124 additions & 0 deletions packages/components/src/common/Menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React from 'react';

import * as MenuPrimitive from '@radix-ui/react-menu';
import { CheckIcon } from '@radix-ui/react-icons';

import { styled, css, CSS } from '../theme/stitches.config';
import { Box } from './Box';
import { Flex } from './Flex';
import { panelStyles } from './Panel';

export const baseItemCss = css({
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
fontFamily: '$untitled',
fontSize: '$1',
fontVariantNumeric: 'tabular-nums',
lineHeight: '1',
cursor: 'default',
userSelect: 'none',
whiteSpace: 'nowrap',
height: '$5',
px: '$5',
});

export const itemCss = css(baseItemCss, {
position: 'relative',
color: '$hiContrast',

'&[data-highlighted]': {
outline: 'none',
backgroundColor: '$blue9',
color: 'white',
},

'&[data-disabled]': {
color: '$slate9',
},
});

export const labelCss = css(baseItemCss, {
color: '$slate11',
});

export const menuCss = css({
boxSizing: 'border-box',
minWidth: 120,
py: '$1',
});

export const separatorCss = css({
height: 1,
my: '$1',
backgroundColor: '$slate6',
});

export const Menu = styled(MenuPrimitive.Root, menuCss);
export const MenuContent = styled(MenuPrimitive.Content, panelStyles);

export const MenuSeparator = styled(MenuPrimitive.Separator, separatorCss);

export const MenuItem = styled(MenuPrimitive.Item, itemCss);

const StyledMenuRadioItem = styled(MenuPrimitive.RadioItem, itemCss);

type MenuRadioItemPrimitiveProps = React.ComponentProps<
typeof MenuPrimitive.RadioItem
>;
type MenuRadioItemProps = MenuRadioItemPrimitiveProps & { css?: CSS };

export const MenuRadioItem = React.forwardRef<
React.ElementRef<typeof StyledMenuRadioItem>,
MenuRadioItemProps
>(({ children, ...props }, forwardedRef) => (
<StyledMenuRadioItem {...props} ref={forwardedRef}>
<Box as="span" css={{ position: 'absolute', left: '$1' }}>
<MenuPrimitive.ItemIndicator>
<Flex
css={{
width: '$3',
height: '$3',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Box
css={{
width: '$1',
height: '$1',
backgroundColor: 'currentColor',
borderRadius: '$DEFAULT',
}}
></Box>
</Flex>
</MenuPrimitive.ItemIndicator>
</Box>
{children}
</StyledMenuRadioItem>
));

const StyledMenuCheckboxItem = styled(MenuPrimitive.CheckboxItem, itemCss);

type MenuCheckboxItemPrimitiveProps = React.ComponentProps<
typeof MenuPrimitive.CheckboxItem
>;
type MenuCheckboxItemProps = MenuCheckboxItemPrimitiveProps & { css?: CSS };

export const MenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof StyledMenuCheckboxItem>,
MenuCheckboxItemProps
>(({ children, ...props }, forwardedRef) => (
<StyledMenuCheckboxItem {...props} ref={forwardedRef}>
<Box as="span" css={{ position: 'absolute', left: '$1' }}>
<MenuPrimitive.ItemIndicator>
<CheckIcon />
</MenuPrimitive.ItemIndicator>
</Box>
{children}
</StyledMenuCheckboxItem>
));

export const MenuLabel = styled(MenuPrimitive.Label, labelCss);
export const MenuRadioGroup = styled(MenuPrimitive.RadioGroup, {});
export const MenuGroup = styled(MenuPrimitive.Group, {});
10 changes: 10 additions & 0 deletions packages/components/src/common/Panel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { styled, css } from '../theme/stitches.config';

export const panelStyles = css({
backgroundColor: '$panel',
borderRadius: '$DEFAULT',
boxShadow:
'$colors$shadowLight 0px 10px 38px -10px, $colors$shadowDark 0px 10px 20px -15px',
});

export const Panel = styled('div', panelStyles);
2 changes: 2 additions & 0 deletions packages/components/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ export * from './Box';
export * from './Container';
export * from './Flex';
export * from './Grid';
export * from './Menu';
export * from './Panel';
export * from './Text';
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';

import { ComponentStory, ComponentMeta } from '@storybook/react';

import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuCheckboxItem,
DropdownMenuLabel,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
} from './DropdownMenu';

import { Button } from '../Button';

export default {
title: 'Elements/DropdownMenu',
component: DropdownMenu,
} as ComponentMeta<typeof DropdownMenu>;

const Template: ComponentStory<typeof DropdownMenu> = (args) => (
<DropdownMenu {...args}>
<DropdownMenuTrigger asChild>
<Button>Dropdown</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuGroup>
<DropdownMenuItem>Item</DropdownMenuItem>
<DropdownMenuItem>Item</DropdownMenuItem>
<DropdownMenuItem>Item</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuCheckboxItem>Item</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem checked>Item</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem>Item</DropdownMenuCheckboxItem>
<DropdownMenuSeparator />
<DropdownMenuLabel>Choose one</DropdownMenuLabel>
<DropdownMenuRadioGroup value="one">
<DropdownMenuRadioItem value="one">Item</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="two">Item</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="three">Item</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
);

export const Default = Template.bind({});
Default.args = {
children: 'DropdownMenu',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import { render } from '@testing-library/react';

import { DropdownMenu } from './DropdownMenu';

describe('DropdownMenu', () => {
it('renders without throwing', () => {
const { container } = render(<DropdownMenu />);
expect(container).toBeInTheDocument();
});
});
131 changes: 131 additions & 0 deletions packages/components/src/elements/DropdownMenu/DropdownMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import React from 'react';

import { CheckIcon } from '@radix-ui/react-icons';
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';

import { styled, CSS } from '../../theme/stitches.config';

import {
Box,
Flex,
panelStyles,
menuCss,
separatorCss,
itemCss,
labelCss,
} from '../../common';

const DropdownMenu = DropdownMenuPrimitive.Root;
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;

const StyledContent = styled(
DropdownMenuPrimitive.Content,
menuCss,
panelStyles
);

type DropdownMenuContentPrimitiveProps = React.ComponentProps<
typeof DropdownMenuPrimitive.Content
>;
type DropdownMenuContentProps = DropdownMenuContentPrimitiveProps & {
css?: CSS;
};

const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof StyledContent>,
DropdownMenuContentProps
>((props, forwardedRef) => (
<DropdownMenuPrimitive.Portal>
<StyledContent {...props} ref={forwardedRef} />
</DropdownMenuPrimitive.Portal>
));

const DropdownMenuItem = styled(DropdownMenuPrimitive.Item, itemCss);
const DropdownMenuGroup = styled(DropdownMenuPrimitive.Group, {});
const DropdownMenuLabel = styled(DropdownMenuPrimitive.Label, labelCss);
const DropdownMenuSeparator = styled(
DropdownMenuPrimitive.Separator,
separatorCss
);

const StyledDropdownMenuCheckboxItem = styled(
DropdownMenuPrimitive.CheckboxItem,
itemCss
);

type DialogMenuCheckboxItemPrimitiveProps = React.ComponentProps<
typeof DropdownMenuPrimitive.CheckboxItem
>;
type DialogMenuCheckboxItemProps = DialogMenuCheckboxItemPrimitiveProps & {
css?: CSS;
};

const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof StyledDropdownMenuCheckboxItem>,
DialogMenuCheckboxItemProps
>(({ children, ...props }, forwardedRef) => (
<StyledDropdownMenuCheckboxItem {...props} ref={forwardedRef}>
<Box as="span" css={{ position: 'absolute', left: '$1' }}>
<DropdownMenuPrimitive.ItemIndicator>
<CheckIcon />
</DropdownMenuPrimitive.ItemIndicator>
</Box>
{children}
</StyledDropdownMenuCheckboxItem>
));

const DropdownMenuRadioGroup = styled(DropdownMenuPrimitive.RadioGroup, {});
const StyledDropdownMenuRadioItem = styled(
DropdownMenuPrimitive.RadioItem,
itemCss
);

type DialogMenuRadioItemPrimitiveProps = React.ComponentProps<
typeof DropdownMenuPrimitive.RadioItem
>;
type DialogMenuRadioItemProps = DialogMenuRadioItemPrimitiveProps & {
css?: CSS;
};

const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef<typeof StyledDropdownMenuRadioItem>,
DialogMenuRadioItemProps
>(({ children, ...props }, forwardedRef) => (
<StyledDropdownMenuRadioItem {...props} ref={forwardedRef}>
<Box as="span" css={{ position: 'absolute', left: '$1' }}>
<DropdownMenuPrimitive.ItemIndicator>
<Flex
css={{
width: '$3',
height: '$3',
alignItems: 'center',
justifyContent: 'center',
}}
>
<Box
css={{
width: '$1',
height: '$1',
backgroundColor: 'currentColor',
borderRadius: '$DEFAULT',
}}
/>
</Flex>
</DropdownMenuPrimitive.ItemIndicator>
</Box>
{children}
</StyledDropdownMenuRadioItem>
));

export {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuGroup,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuCheckboxItem,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
};
1 change: 1 addition & 0 deletions packages/components/src/elements/DropdownMenu/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './DropdownMenu';
8 changes: 8 additions & 0 deletions packages/components/src/elements/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Elements

Elements are basic blocks of `@web3-ui/components`.

They are build with [@radix-ui](https://radix-ui.com/) and [stitches](http://stitches.dev/)
with a base of [@radix-ui/design-system](https://github.com/radix-ui/design-system).

Design, theme and elements themselves are subject to change
1 change: 1 addition & 0 deletions packages/components/src/elements/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './Button';
export * from './Badge';
export * from './Checkbox';
export * from './DropdownMenu';
Loading

2 comments on commit cea3b21

@vercel
Copy link

@vercel vercel bot commented on cea3b21 Jul 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

web3ui – ./

web3ui-git-main-developdao.vercel.app
web3ui-developdao.vercel.app
web3-ui.vercel.app

@vercel
Copy link

@vercel vercel bot commented on cea3b21 Jul 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

web3-ui-docs – ./

web3-ui-docs-git-main-developdao.vercel.app
web3-ui-docs.vercel.app
web3-ui-docs-developdao.vercel.app

Please sign in to comment.