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: Sub menu #12

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
39 changes: 29 additions & 10 deletions docs/component/menu.mdx
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ route: /component/menu
menu: Component
---

import { Menu, Text } from 'fiber'
import { Menu, Text, Divider, Heading } from 'fiber'
import { Playground } from 'docz'

# Menu
@@ -14,16 +14,35 @@ import { Playground } from 'docz'
<Playground>
{() => {
return (
<div>
<Menu style={{ width: 300 }}>
<Menu.Item>
<Text> Item 1 </Text>
</Menu.Item>
<div style={{ width: 300 }}>
<Menu>
<Menu.Sub title={ <span> Sub Menu 1 </span> }>
<Menu.Sub title={ <span> Sub Menu 1.1 </span> }>
<Menu.Item>
Item 1
</Menu.Item>
<Menu.Item>
Item 2
</Menu.Item>
</Menu.Sub>
<Menu.Item>
Item 3
</Menu.Item>
</Menu.Sub>
<Menu.Sub title={ <span> Sub Menu 2 </span> }>
<Menu.Item>
Item 4
</Menu.Item>
<Menu.Item>
Item 5
</Menu.Item>
<Menu.Item>
Item 6
</Menu.Item>
</Menu.Sub>
<Divider />
<Menu.Item>
<Text> Item 2 </Text>
</Menu.Item>
<Menu.Item>
<Text> Item 3 </Text>
Item 3
</Menu.Item>
</Menu>
</div>
2 changes: 1 addition & 1 deletion src/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ const DropdownWrapper = styled.div<any>`
const useDropdownStatus = (trigger: TriggerType) => {
const node = useRef<
HTMLDivElement & { contains: (e: EventTarget) => Boolean }
// eslint-disable-next-line indent
// eslint-disable-next-line indent
>(null)
const [expand, setExpand] = useState(false)

4 changes: 2 additions & 2 deletions src/Dropdown/__tests__/__snapshots__/Dropdown.spec.tsx.snap
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

exports[`Menu & Menu Items renders correctly 1`] = `
<div
className="sc-fzozJi cvaiIV"
className="sc-fznyAO hWrpzu"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
@@ -13,7 +13,7 @@ exports[`Menu & Menu Items renders correctly 1`] = `
Hover Me
</span>
<div
className="sc-fzoLsD iJVoRQ"
className="sc-fznKkj cBTFzs"
/>
</div>
`;
4 changes: 4 additions & 0 deletions src/Menu/Menu.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { styleComposition } from '../utils/styles'

import { SubMenu } from './SubMenu'
import { MenuItem } from './MenuItem'
import { MenuProps, MenuContext } from './useMenu'

@@ -8,6 +9,7 @@ import styled from 'styled-components'

type MenuFC<P> = FC<P> & {
Item: FC
Sub: FC<any>
}

const MenuWrapper = styled.ul<MenuProps>`
@@ -18,6 +20,7 @@ const MenuWrapper = styled.ul<MenuProps>`
padding: 0;
overflow: auto;
list-style-type: none;
border-right: solid 1px ${(props) => props.theme.colors.gray3};
`

const Menu: MenuFC<MenuProps> = ({ children, inline }) => {
@@ -29,5 +32,6 @@ const Menu: MenuFC<MenuProps> = ({ children, inline }) => {
}

Menu.Item = MenuItem
Menu.Sub = SubMenu

export { Menu }
21 changes: 14 additions & 7 deletions src/Menu/MenuItem.tsx
Original file line number Diff line number Diff line change
@@ -2,39 +2,46 @@ import { StyleProps, styleComposition } from '../utils/styles'

import { useMenu } from './useMenu'

import styled from 'styled-components'
import React, { FC } from 'react'
import styled, { css } from 'styled-components'
import React, { FC, useState } from 'react'

export interface MenuItemProps extends StyleProps {}
export interface MenuItemProps extends StyleProps { }

const selectedItem = css`
color: white;
background: ${(props) => props.theme.colors.lightest};
border-right: solid 3.5px ${(props) => props.theme.colors.light};
`
const BlockMenuItem = styled.li<any>`
${styleComposition}
display: block;
padding: 8px 10px;
float: none;
border-right: solid ${(props) => props.theme.colors.gray3} 0.5px;
color: ${(props) => props.color};
text-align: left;
text-decoration: none;
&:hover {
background: ${(props) => props.theme.colors.gray3};
color: ${(props) => props.theme.colors.light};
cursor: pointer;
}
${(props) => props.selected ? selectedItem : null};
`

const InlineMenuItem = styled(BlockMenuItem)<any>`
const InlineMenuItem = styled(BlockMenuItem) <any>`
display: inline-block;
float: left;
`

const MenuItem: FC<MenuItemProps> = ({ children, ...props }) => {
const { inline } = useMenu()
const [selected, setSelected] = useState<boolean>(false)

const Item = inline ? InlineMenuItem : BlockMenuItem

return <Item {...props}>{children}</Item>
return <Item {...props} selected={selected} onClick={() => setSelected(!selected)}>{children}</Item>
}

export { MenuItem }
31 changes: 31 additions & 0 deletions src/Menu/SubMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { StyleProps } from '../utils/styles'

import { Arrow, TitleWrapper, SubMenuWrapper, ItemWrapper } from './styles'

import React, { FC, ReactElement, useState } from 'react'

export type TitleFunc = () => React.ReactElement

export interface SubMenuProps extends StyleProps {
title: ReactElement | TitleFunc;
}

const SubMenu: FC<SubMenuProps> = ({ children, title }) => {
const [expand, setExpand] = useState<boolean>(false)

const titleNode = typeof title === 'function' ? (title as TitleFunc)() : title

return (
<SubMenuWrapper>
<TitleWrapper expand={expand} onClick={() => setExpand(!expand)}>
{titleNode}
<Arrow expand={expand} />
</TitleWrapper>
<ItemWrapper>
{expand ? children : null}
</ItemWrapper>
</SubMenuWrapper>
)
}

export { SubMenu }
35 changes: 27 additions & 8 deletions src/Menu/__tests__/Menu.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Menu, Text } from '../../'
import { Menu, Text, Divider } from '../../'

import React from 'react'
import { render } from 'test/utils'
@@ -7,14 +7,33 @@ describe('Block Menu & Menu Items', () => {
it('renders correctly', () => {
const block = render(
<Menu>
<Menu.Sub title={<span> Sub Menu 1 </span>}>
<Menu.Sub title={<span> Sub Menu 1.1 </span>}>
<Menu.Item>
Item 1
</Menu.Item>
<Menu.Item>
Item 2
</Menu.Item>
</Menu.Sub>
<Menu.Item>
Item 3
</Menu.Item>
</Menu.Sub>
<Menu.Sub title={<span> Sub Menu 2 </span>}>
<Menu.Item>
Item 4
</Menu.Item>
<Menu.Item>
Item 5
</Menu.Item>
<Menu.Item>
Item 6
</Menu.Item>
</Menu.Sub>
<Divider />
<Menu.Item>
<Text> Item 1 </Text>
</Menu.Item>
<Menu.Item>
<Text> Item 2 </Text>
</Menu.Item>
<Menu.Item>
<Text> Item 3 </Text>
Item 3
</Menu.Item>
</Menu>
)
79 changes: 53 additions & 26 deletions src/Menu/__tests__/__snapshots__/Menu.spec.tsx.snap
Original file line number Diff line number Diff line change
@@ -2,47 +2,70 @@

exports[`Block Menu & Menu Items renders correctly 1`] = `
<ul
className="sc-AxmLO enoELj"
className="sc-fzplWN kCYiUw"
>
<li
className="sc-AxheI bBCLtC"
<div
className="sc-Axmtr icUvKO"
>
<span
className="sc-AxiKw ioUFXk"
size={4}
<div
className="sc-AxheI kokSYy"
onClick={[Function]}
>
Item 1
</span>
</li>
<li
className="sc-AxheI bBCLtC"
<span>
Sub Menu 1
</span>
<i
className="sc-fzozJi grUWqN"
/>
</div>
<ul
className="sc-AxmLO hAqXzN"
/>
</div>
<div
className="sc-Axmtr icUvKO"
>
<span
className="sc-AxiKw ioUFXk"
size={4}
<div
className="sc-AxheI kokSYy"
onClick={[Function]}
>
Item 2
</span>
</li>
<li
className="sc-AxheI bBCLtC"
<span>
Sub Menu 2
</span>
<i
className="sc-fzozJi grUWqN"
/>
</div>
<ul
className="sc-AxmLO hAqXzN"
/>
</div>
<div
className="sc-fznZeY bCvFKa"
>
<span
className="sc-AxiKw ioUFXk"
size={4}
>
Item 3
</span>
/>
</div>
<li
className="sc-fzoLsD ePTHqD"
onClick={[Function]}
selected={false}
>
Item 3
</li>
</ul>
`;

exports[`Inline Menu & Menu Items renders correctly 1`] = `
<ul
className="sc-AxmLO enoELj"
className="sc-fzplWN kCYiUw"
>
<li
className="sc-AxheI sc-Axmtr gCqhiy"
className="sc-fzoLsD sc-fzpans cPjyk"
onClick={[Function]}
selected={false}
>
<span
className="sc-AxiKw ioUFXk"
@@ -52,7 +75,9 @@ exports[`Inline Menu & Menu Items renders correctly 1`] = `
</span>
</li>
<li
className="sc-AxheI sc-Axmtr gCqhiy"
className="sc-fzoLsD sc-fzpans cPjyk"
onClick={[Function]}
selected={false}
>
<span
className="sc-AxiKw ioUFXk"
@@ -62,7 +87,9 @@ exports[`Inline Menu & Menu Items renders correctly 1`] = `
</span>
</li>
<li
className="sc-AxheI sc-Axmtr gCqhiy"
className="sc-fzoLsD sc-fzpans cPjyk"
onClick={[Function]}
selected={false}
>
<span
className="sc-AxiKw ioUFXk"
54 changes: 54 additions & 0 deletions src/Menu/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { styleComposition } from '../utils/styles'

import styled, { css } from 'styled-components'

export interface ExpandProps {
expand: boolean
}

export const TitleWrapper = styled.div<ExpandProps>`
display: block;
padding: 8px 10px;
color: ${(props) => (props.expand ? props.theme.colors.light : null)};
&:hover {
color: ${(props) => props.theme.colors.light};
cursor: pointer;
}
`

export const SubMenuWrapper = styled.div<any>`
display: block;
`

export const ItemWrapper = styled.ul`
${styleComposition}
height: 100%;
margin: 0;
overflow: auto;
`

const ArrowDown = css`
transform: rotate(45deg);
`

const ArrowUp = css`
transform: rotate(-135deg);
`

export const Arrow = styled.i<ExpandProps>`
display: inline-block;
margin: 10px;
padding: 3px;
float: right;
border: solid ${(props) => (props.expand ? props.theme.colors.light : null)};
border-width: 0 3px 3px 0;
${(props) => (props.expand ? ArrowUp : ArrowDown)};
${TitleWrapper}:hover & {
border: solid ${(props) => props.theme.colors.light};
border-width: 0 3px 3px 0;
}
`