-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ContextMenu): Create base component
- Loading branch information
Showing
7 changed files
with
268 additions
and
0 deletions.
There are no files selected for viewing
39 changes: 39 additions & 0 deletions
39
packages/react-component-library/src/components/ContextMenu/ContextMenu.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import React from 'react' | ||
import { Meta } from '@storybook/react/types-6-0' | ||
|
||
import { IconEdit, IconDelete, IconAdd } from '@royalnavy/icon-library' | ||
|
||
import { ContextMenu, ContextMenuItem, ContextMenuDivider } from '.' | ||
import { Link } from '../Link' | ||
|
||
export default { component: ContextMenu, title: 'ContextMenu' } as Meta | ||
|
||
export const Default = () => ( | ||
<ContextMenu> | ||
<ContextMenuItem | ||
icon={<IconEdit />} | ||
link={<Link href="/edit">Edit</Link>} | ||
/> | ||
<ContextMenuItem | ||
icon={<IconDelete />} | ||
link={<Link href="/delete">Delete</Link>} | ||
/> | ||
<ContextMenuItem link={<Link href="/delete">Action</Link>} /> | ||
<ContextMenuDivider /> | ||
<ContextMenuItem icon={<IconAdd />} link={<Link href="/add">Add</Link>} /> | ||
<ContextMenuDivider /> | ||
<ContextMenuItem | ||
link={<Link href="/something-else">Do something else</Link>} | ||
/> | ||
<ContextMenuDivider /> | ||
<ContextMenuItem | ||
link={( | ||
<Link href="/something-else"> | ||
This is too much text to put into a context menu item | ||
</Link> | ||
)} | ||
/> | ||
</ContextMenu> | ||
) | ||
|
||
Default.storyName = 'Default' |
94 changes: 94 additions & 0 deletions
94
packages/react-component-library/src/components/ContextMenu/ContextMenu.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import React from 'react' | ||
import '@testing-library/jest-dom/extend-expect' | ||
import { RenderResult, render } from '@testing-library/react' | ||
import { IconSettings } from '@royalnavy/icon-library' | ||
|
||
import { ContextMenu, ContextMenuItem, ContextMenuDivider } from '.' | ||
import { Link } from '../Link' | ||
|
||
const CustomLink = ({ children, onClick }: any) => { | ||
return ( | ||
<button onClick={onClick} data-testid="context-menu-custom-link"> | ||
{children} | ||
</button> | ||
) | ||
} | ||
|
||
describe('ContextMenu', () => { | ||
let wrapper: RenderResult | ||
let onClickSpy: (e: React.MouseEvent<HTMLElement>) => void | ||
|
||
describe('With link', () => { | ||
beforeEach(() => { | ||
wrapper = render( | ||
<ContextMenu> | ||
<ContextMenuItem link={<Link href="/hello-foo">Hello, Foo!</Link>} /> | ||
<ContextMenuItem link={<Link href="/hello-bar">Hello, Bar!</Link>} /> | ||
</ContextMenu> | ||
) | ||
}) | ||
|
||
it('renders the links', () => { | ||
expect(wrapper.queryByText('Hello, Foo!')).toBeInTheDocument() | ||
expect(wrapper.queryByText('Hello, Bar!')).toBeInTheDocument() | ||
}) | ||
}) | ||
|
||
describe('With custom link', () => { | ||
beforeEach(() => { | ||
onClickSpy = jest.fn() | ||
|
||
wrapper = render( | ||
<ContextMenu> | ||
<ContextMenuItem | ||
link={<CustomLink onClick={onClickSpy}>Click me!</CustomLink>} | ||
/> | ||
</ContextMenu> | ||
) | ||
|
||
wrapper.getByTestId('context-menu-custom-link').click() | ||
}) | ||
|
||
it('invokes the onClick event when the custom link is clicked', () => { | ||
expect(onClickSpy).toHaveBeenCalledTimes(1) | ||
}) | ||
}) | ||
|
||
describe('With icons', () => { | ||
beforeEach(() => { | ||
wrapper = render( | ||
<ContextMenu> | ||
<ContextMenuItem | ||
icon={<IconSettings data-testid="context-menu-item-icon" />} | ||
link={<Link href="/hello-foo">Hello, Foo!</Link>} | ||
/> | ||
</ContextMenu> | ||
) | ||
}) | ||
|
||
it('renders the icons', () => { | ||
expect( | ||
wrapper.queryByTestId('context-menu-item-icon') | ||
).toBeInTheDocument() | ||
}) | ||
}) | ||
|
||
describe('With dividers', () => { | ||
beforeEach(() => { | ||
wrapper = render( | ||
<ContextMenu> | ||
<ContextMenuDivider /> | ||
<ContextMenuItem | ||
icon={IconSettings} | ||
link={<Link href="/hello-foo">Hello, Foo!</Link>} | ||
/> | ||
<ContextMenuDivider /> | ||
</ContextMenu> | ||
) | ||
}) | ||
|
||
it('renders the dividers', () => { | ||
expect(wrapper.queryAllByTestId('context-menu-divider')).toHaveLength(2) | ||
}) | ||
}) | ||
}) |
26 changes: 26 additions & 0 deletions
26
packages/react-component-library/src/components/ContextMenu/ContextMenu.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import React from 'react' | ||
import styled from 'styled-components' | ||
import { selectors } from '@royalnavy/design-tokens' | ||
|
||
import { ComponentWithClass } from '../../common/ComponentWithClass' | ||
|
||
const { color } = selectors | ||
|
||
const StyledContextMenu = styled.ol` | ||
width: 12rem; | ||
padding: 0; | ||
list-style-type: none; | ||
background-color: ${color('neutral', 'white')}; | ||
border-radius: 4px; | ||
border: 1px solid ${color('neutral', '200')}; | ||
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.07); | ||
` | ||
|
||
export const ContextMenu: React.FC<ComponentWithClass> = ({ | ||
className, | ||
children, | ||
}) => { | ||
return <StyledContextMenu className={className}>{children}</StyledContextMenu> | ||
} | ||
|
||
ContextMenu.displayName = 'ContextMenu' |
18 changes: 18 additions & 0 deletions
18
packages/react-component-library/src/components/ContextMenu/ContextMenuDivider.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import React from 'react' | ||
import styled from 'styled-components' | ||
import { selectors } from '@royalnavy/design-tokens' | ||
|
||
const { color, spacing } = selectors | ||
|
||
const StyledContextMenuDivider = styled.div` | ||
width: 100%; | ||
height: 1px; | ||
background-color: ${color('neutral', '100')}; | ||
margin: ${spacing('2')} 0; | ||
` | ||
|
||
export const ContextMenuDivider: React.FC = () => { | ||
return <StyledContextMenuDivider data-testid="context-menu-divider" /> | ||
} | ||
|
||
ContextMenuDivider.displayName = 'ContextMenuDivider' |
87 changes: 87 additions & 0 deletions
87
packages/react-component-library/src/components/ContextMenu/ContextMenuItem.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import React from 'react' | ||
import styled from 'styled-components' | ||
import { selectors } from '@royalnavy/design-tokens' | ||
|
||
import { NavItem } from '../../common/Nav' | ||
|
||
interface ContextMenuItemProps extends NavItem { | ||
icon?: React.ReactNode | ||
} | ||
|
||
const { color, fontSize, spacing } = selectors | ||
|
||
const StyledContextMenuItem = styled.li` | ||
overflow: hidden; | ||
&:first-of-type { | ||
border-top-left-radius: 4px; | ||
border-top-right-radius: 4px; | ||
} | ||
&:last-of-type { | ||
border-bottom-left-radius: 4px; | ||
border-bottom-right-radius: 4px; | ||
} | ||
> * { | ||
display: flex; | ||
padding: ${spacing('4')} ${spacing('6')}; | ||
overflow: hidden; | ||
text-overflow: ellipsis; | ||
text-wrap: none; | ||
} | ||
&:hover { | ||
background-color: ${color('neutral', '000')}; | ||
> * { | ||
text-decoration: none; | ||
} | ||
} | ||
` | ||
|
||
const StyledIcon = styled.div` | ||
display: inline-flex; | ||
align-items: center; | ||
margin-right: ${spacing('4')}; | ||
svg { | ||
color: ${color('neutral', '500')}; | ||
} | ||
` | ||
|
||
interface StyledTextProps { | ||
hasIcon?: boolean | ||
} | ||
|
||
const StyledText = styled.div<StyledTextProps>` | ||
color: ${color('neutral', '300')}; | ||
font-weight: 600; | ||
font-size: ${fontSize('s')}; | ||
${({ hasIcon }) => !hasIcon && `margin-left: 1.5rem;`} | ||
${StyledContextMenuItem}:hover & { | ||
color: ${color('neutral', '400')}; | ||
} | ||
` | ||
|
||
export const ContextMenuItem: React.FC<ContextMenuItemProps> = ({ | ||
icon, | ||
link, | ||
}) => { | ||
const linkElement = link as React.ReactElement | ||
|
||
const item = React.cloneElement(linkElement, { | ||
...link.props, | ||
children: ( | ||
<> | ||
{icon && <StyledIcon>{icon}</StyledIcon>} | ||
<StyledText hasIcon={!!icon}>{linkElement.props.children}</StyledText> | ||
</> | ||
), | ||
}) | ||
|
||
return <StyledContextMenuItem>{item}</StyledContextMenuItem> | ||
} | ||
|
||
ContextMenuItem.displayName = 'ContextMenuItem' |
3 changes: 3 additions & 0 deletions
3
packages/react-component-library/src/components/ContextMenu/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './ContextMenu' | ||
export * from './ContextMenuItem' | ||
export * from './ContextMenuDivider' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters