From d7d991669bc8845537d6e35e1f21405559dab141 Mon Sep 17 00:00:00 2001 From: Sofiya Huts Date: Thu, 23 Aug 2018 18:24:07 +0200 Subject: [PATCH 1/5] Add possibility to render submenus for menu --- .../MenuExampleWithSubmenu.shorthand.tsx | 45 +++++++++++++++++++ .../examples/components/Menu/Types/index.tsx | 5 +++ src/components/Menu/Menu.tsx | 9 +++- src/components/Menu/MenuItem.tsx | 45 +++++++++++++++++-- .../teams/components/Menu/menuItemStyles.ts | 6 +++ .../teams/components/Menu/menuStyles.ts | 2 +- .../teams/components/Menu/menuVariables.ts | 2 + test/specs/components/Menu/MenuItem-test.tsx | 18 +++++++- 8 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 docs/src/examples/components/Menu/Types/MenuExampleWithSubmenu.shorthand.tsx diff --git a/docs/src/examples/components/Menu/Types/MenuExampleWithSubmenu.shorthand.tsx b/docs/src/examples/components/Menu/Types/MenuExampleWithSubmenu.shorthand.tsx new file mode 100644 index 0000000000..41afe299c2 --- /dev/null +++ b/docs/src/examples/components/Menu/Types/MenuExampleWithSubmenu.shorthand.tsx @@ -0,0 +1,45 @@ +import React from 'react' +import { Menu } from '@stardust-ui/react' + +const menuWidthVariable = { + menuItemWidth: '100px', +} + +const fileSubmenu = { + vertical: true, + items: [ + { key: 'new', content: 'New' }, + { key: 'open', content: 'Open' }, + { key: 'edit', content: 'Edit' }, + ], + variables: menuWidthVariable, +} +const editSubmenu = { + vertical: true, + items: [ + { key: 'undo', content: 'Undo' }, + { key: 'redo', content: 'Redo' }, + { key: 'cut', content: 'Cut' }, + , + { key: 'copy', content: 'Copy' }, + ], + variables: menuWidthVariable, +} +const formatSubmenu = { + vertical: true, + items: [{ key: 'font', content: 'Font' }, { key: 'text', content: 'Text' }], + variables: menuWidthVariable, +} + +const items = [ + { key: 'file', content: File ▾, submenu: fileSubmenu }, + { key: 'edit', content: Edit ▾, submenu: editSubmenu }, + { key: 'format', content: Format ▾, submenu: formatSubmenu }, + { key: 'help', content: 'Help' }, +] + +const MenuExampleWithSubmenu = () => ( + +) + +export default MenuExampleWithSubmenu diff --git a/docs/src/examples/components/Menu/Types/index.tsx b/docs/src/examples/components/Menu/Types/index.tsx index 8ce62a8f8d..f3a4b4097c 100644 --- a/docs/src/examples/components/Menu/Types/index.tsx +++ b/docs/src/examples/components/Menu/Types/index.tsx @@ -19,6 +19,11 @@ const Types = () => ( description="A vertical menu displays elements vertically." examplePath="components/Menu/Types/MenuExampleVertical" /> + ) diff --git a/src/components/Menu/Menu.tsx b/src/components/Menu/Menu.tsx index e14419b76d..d7277f4873 100644 --- a/src/components/Menu/Menu.tsx +++ b/src/components/Menu/Menu.tsx @@ -2,7 +2,12 @@ import * as _ from 'lodash' import * as PropTypes from 'prop-types' import * as React from 'react' -import { AutoControlledComponent, childrenExist, customPropTypes } from '../../lib' +import { + AutoControlledComponent, + childrenExist, + customPropTypes, + createShorthandFactory, +} from '../../lib' import MenuItem from './MenuItem' import { MenuBehavior } from '../../lib/accessibility' import { Accessibility } from '../../lib/accessibility/interfaces' @@ -135,4 +140,6 @@ class Menu extends AutoControlledComponent { } } +Menu.create = createShorthandFactory(Menu, {}) + export default Menu diff --git a/src/components/Menu/MenuItem.tsx b/src/components/Menu/MenuItem.tsx index dc39e76a0f..ce0a7069dd 100644 --- a/src/components/Menu/MenuItem.tsx +++ b/src/components/Menu/MenuItem.tsx @@ -3,12 +3,22 @@ import * as cx from 'classnames' import * as PropTypes from 'prop-types' import * as React from 'react' -import { childrenExist, createShorthandFactory, customPropTypes, UIComponent } from '../../lib' +import { + childrenExist, + createShorthandFactory, + customPropTypes, + AutoControlledComponent, +} from '../../lib' import Icon from '../Icon' +import Menu from '../Menu' import { MenuItemBehavior } from '../../lib/accessibility' import { Accessibility } from '../../lib/accessibility/interfaces' -class MenuItem extends UIComponent { +interface MenuItemState { + submenuOpened: boolean +} + +class MenuItem extends AutoControlledComponent { static displayName = 'MenuItem' static className = 'ui-menu__item' @@ -31,6 +41,9 @@ class MenuItem extends UIComponent { /** Shorthand for primary content. */ content: customPropTypes.contentShorthand, + /** Initial submenuOpened value. */ + defaultSubmenuOpened: PropTypes.bool, + /** Name or shorthand for Menu Item Icon */ icon: customPropTypes.itemShorthand, @@ -70,6 +83,12 @@ class MenuItem extends UIComponent { /** Custom styles to be applied for component. */ styles: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), + /** Shorthand for Menu Item submenu */ + submenu: customPropTypes.itemShorthand, + + /** Auto controlled prop that defines if submenu is opened */ + submenuOpened: PropTypes.bool, + /** Custom variables to be applied for component. */ variables: PropTypes.oneOfType([PropTypes.object, PropTypes.func]), } @@ -79,6 +98,8 @@ class MenuItem extends UIComponent { accessibility: MenuItemBehavior as Accessibility, } + static autoControlledProps = ['submenuOpened'] + static handledProps = [ 'accessibility', 'active', @@ -86,6 +107,7 @@ class MenuItem extends UIComponent { 'children', 'className', 'content', + 'defaultSubmenuOpened', 'icon', 'iconOnly', 'index', @@ -93,18 +115,28 @@ class MenuItem extends UIComponent { 'pills', 'pointing', 'styles', + 'submenu', + 'submenuOpened', 'type', 'underlined', 'variables', 'vertical', ] + getInitialAutoControlledState() { + return { submenuOpened: false } + } + handleClick = e => { + if (this.props.submenu) { + this.setState({ submenuOpened: !this.state.submenuOpened }) + } + _.invoke(this.props, 'onClick', e, this.props) } renderComponent({ ElementType, classes, accessibility, rest }) { - const { children, content, icon } = this.props + const { children, content, icon, submenu } = this.props return ( @@ -123,6 +155,13 @@ class MenuItem extends UIComponent { {content} )} + + {this.state.submenuOpened && + Menu.create(submenu, { + overrideProps: { + className: classes.submenu, + }, + })} ) } diff --git a/src/themes/teams/components/Menu/menuItemStyles.ts b/src/themes/teams/components/Menu/menuItemStyles.ts index 813e4081cd..9ddc5a5989 100644 --- a/src/themes/teams/components/Menu/menuItemStyles.ts +++ b/src/themes/teams/components/Menu/menuItemStyles.ts @@ -52,6 +52,7 @@ const menuItemStyles = { : { marginLeft: iconsMenuItemSpacing }), }, }), + ...(!vertical && { width: variables.menuItemWidth }), ...(pills && { ...(vertical ? { margin: `0 0 ${pxToRem(5)} 0` } : { margin: `0 ${pxToRem(8)} 0 0` }), borderRadius: pxToRem(5), @@ -173,6 +174,11 @@ const menuItemStyles = { }), } }, + submenu: { + position: 'absolute', + borderTopLeftRadius: 0, + borderTopRightRadius: 0, + }, } export default menuItemStyles diff --git a/src/themes/teams/components/Menu/menuStyles.ts b/src/themes/teams/components/Menu/menuStyles.ts index 67558a2eed..fc5b7da46e 100644 --- a/src/themes/teams/components/Menu/menuStyles.ts +++ b/src/themes/teams/components/Menu/menuStyles.ts @@ -12,7 +12,7 @@ export default { display: 'flex', ...(vertical && { flexDirection: 'column', - ...(!fluid && { width: pxToRem(200) }), + ...(!fluid && { width: variables.menuItemWidth || pxToRem(200) }), ...(iconOnly && { display: 'inline-block', width: 'auto', diff --git a/src/themes/teams/components/Menu/menuVariables.ts b/src/themes/teams/components/Menu/menuVariables.ts index 5b3365b7a8..9291c9f5de 100644 --- a/src/themes/teams/components/Menu/menuVariables.ts +++ b/src/themes/teams/components/Menu/menuVariables.ts @@ -16,6 +16,7 @@ export interface IMenuVariables { iconsMenuItemSize: string iconsMenuItemSpacing: number | string + menuItemWidth: string } export default (siteVars: any): IMenuVariables => { @@ -35,5 +36,6 @@ export default (siteVars: any): IMenuVariables => { iconsMenuItemSize: undefined, iconsMenuItemSpacing: 0, + menuItemWidth: undefined, } } diff --git a/test/specs/components/Menu/MenuItem-test.tsx b/test/specs/components/Menu/MenuItem-test.tsx index b58fb28ca9..86bef879a7 100644 --- a/test/specs/components/Menu/MenuItem-test.tsx +++ b/test/specs/components/Menu/MenuItem-test.tsx @@ -1,7 +1,8 @@ import * as React from 'react' import { isConformant, handlesAccessibility } from 'test/specs/commonTests' -import { getTestingRenderedComponent } from 'test/utils' +import { getTestingRenderedComponent, mountWithProvider } from 'test/utils' + import MenuItem from 'src/components/Menu/MenuItem' describe('MenuItem', () => { @@ -29,4 +30,19 @@ describe('MenuItem', () => { expect(menuItem.find('.ui-menu__item').is('li')).toBe(true) expect(menuItem.text()).toBe('Home') }) + + it('menu item renders submenu after click on it', () => { + const submenu = { + vertical: true, + items: [ + { key: 'new', content: 'New' }, + { key: 'open', content: 'Open' }, + { key: 'edit', content: 'Edit' }, + ], + } + const menuItem = mountWithProvider() + expect(menuItem.find('.ui-menu').length).toBe(0) + menuItem.find('a').simulate('click') + expect(menuItem.find('.ui-menu').is('ul')).toBe(true) + }) }) From bdfaa0b3cd4b94aa21cf27a950ce5528c86f13cd Mon Sep 17 00:00:00 2001 From: Sofiya Huts Date: Thu, 23 Aug 2018 20:08:44 +0200 Subject: [PATCH 2/5] Made minor improvements --- .../Menu/Types/MenuExampleWithSubmenu.shorthand.tsx | 9 +-------- src/components/Menu/MenuItem.tsx | 4 +++- src/themes/teams/components/Menu/menuItemStyles.ts | 2 +- src/themes/teams/components/Menu/menuStyles.ts | 2 +- src/themes/teams/components/Menu/menuVariables.ts | 2 +- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/docs/src/examples/components/Menu/Types/MenuExampleWithSubmenu.shorthand.tsx b/docs/src/examples/components/Menu/Types/MenuExampleWithSubmenu.shorthand.tsx index 41afe299c2..36879d0f8c 100644 --- a/docs/src/examples/components/Menu/Types/MenuExampleWithSubmenu.shorthand.tsx +++ b/docs/src/examples/components/Menu/Types/MenuExampleWithSubmenu.shorthand.tsx @@ -2,33 +2,26 @@ import React from 'react' import { Menu } from '@stardust-ui/react' const menuWidthVariable = { - menuItemWidth: '100px', + menuItemWidth: 100, } const fileSubmenu = { - vertical: true, items: [ { key: 'new', content: 'New' }, { key: 'open', content: 'Open' }, { key: 'edit', content: 'Edit' }, ], - variables: menuWidthVariable, } const editSubmenu = { - vertical: true, items: [ { key: 'undo', content: 'Undo' }, { key: 'redo', content: 'Redo' }, { key: 'cut', content: 'Cut' }, - , { key: 'copy', content: 'Copy' }, ], - variables: menuWidthVariable, } const formatSubmenu = { - vertical: true, items: [{ key: 'font', content: 'Font' }, { key: 'text', content: 'Text' }], - variables: menuWidthVariable, } const items = [ diff --git a/src/components/Menu/MenuItem.tsx b/src/components/Menu/MenuItem.tsx index ce0a7069dd..5bbfc1e3fc 100644 --- a/src/components/Menu/MenuItem.tsx +++ b/src/components/Menu/MenuItem.tsx @@ -136,7 +136,7 @@ class MenuItem extends AutoControlledComponent { } renderComponent({ ElementType, classes, accessibility, rest }) { - const { children, content, icon, submenu } = this.props + const { children, content, icon, submenu, variables } = this.props return ( @@ -160,6 +160,8 @@ class MenuItem extends AutoControlledComponent { Menu.create(submenu, { overrideProps: { className: classes.submenu, + variables, + vertical: true, }, })} diff --git a/src/themes/teams/components/Menu/menuItemStyles.ts b/src/themes/teams/components/Menu/menuItemStyles.ts index 9ddc5a5989..777e4e5f66 100644 --- a/src/themes/teams/components/Menu/menuItemStyles.ts +++ b/src/themes/teams/components/Menu/menuItemStyles.ts @@ -52,7 +52,7 @@ const menuItemStyles = { : { marginLeft: iconsMenuItemSpacing }), }, }), - ...(!vertical && { width: variables.menuItemWidth }), + ...(!vertical && { width: pxToRem(variables.menuItemWidth) }), ...(pills && { ...(vertical ? { margin: `0 0 ${pxToRem(5)} 0` } : { margin: `0 ${pxToRem(8)} 0 0` }), borderRadius: pxToRem(5), diff --git a/src/themes/teams/components/Menu/menuStyles.ts b/src/themes/teams/components/Menu/menuStyles.ts index fc5b7da46e..7171410a97 100644 --- a/src/themes/teams/components/Menu/menuStyles.ts +++ b/src/themes/teams/components/Menu/menuStyles.ts @@ -12,7 +12,7 @@ export default { display: 'flex', ...(vertical && { flexDirection: 'column', - ...(!fluid && { width: variables.menuItemWidth || pxToRem(200) }), + ...(!fluid && { width: pxToRem(variables.menuItemWidth) || pxToRem(200) }), ...(iconOnly && { display: 'inline-block', width: 'auto', diff --git a/src/themes/teams/components/Menu/menuVariables.ts b/src/themes/teams/components/Menu/menuVariables.ts index 9291c9f5de..69e4265119 100644 --- a/src/themes/teams/components/Menu/menuVariables.ts +++ b/src/themes/teams/components/Menu/menuVariables.ts @@ -16,7 +16,7 @@ export interface IMenuVariables { iconsMenuItemSize: string iconsMenuItemSpacing: number | string - menuItemWidth: string + menuItemWidth: number } export default (siteVars: any): IMenuVariables => { From e1bae9bc01c90a4f49599abda67866a806696b87 Mon Sep 17 00:00:00 2001 From: Sofiya Huts Date: Thu, 23 Aug 2018 20:15:43 +0200 Subject: [PATCH 3/5] Made minor improvements --- src/components/Menu/MenuItem.tsx | 2 +- src/themes/teams/components/Menu/menuItemStyles.ts | 2 +- src/themes/teams/components/Menu/menuStyles.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/Menu/MenuItem.tsx b/src/components/Menu/MenuItem.tsx index 5bbfc1e3fc..4c1bdd0c62 100644 --- a/src/components/Menu/MenuItem.tsx +++ b/src/components/Menu/MenuItem.tsx @@ -160,8 +160,8 @@ class MenuItem extends AutoControlledComponent { Menu.create(submenu, { overrideProps: { className: classes.submenu, - variables, vertical: true, + variables, }, })} diff --git a/src/themes/teams/components/Menu/menuItemStyles.ts b/src/themes/teams/components/Menu/menuItemStyles.ts index 777e4e5f66..408b3c23b4 100644 --- a/src/themes/teams/components/Menu/menuItemStyles.ts +++ b/src/themes/teams/components/Menu/menuItemStyles.ts @@ -52,7 +52,7 @@ const menuItemStyles = { : { marginLeft: iconsMenuItemSpacing }), }, }), - ...(!vertical && { width: pxToRem(variables.menuItemWidth) }), + ...(!vertical && variables.menuItemWidth && { width: pxToRem(variables.menuItemWidth) }), ...(pills && { ...(vertical ? { margin: `0 0 ${pxToRem(5)} 0` } : { margin: `0 ${pxToRem(8)} 0 0` }), borderRadius: pxToRem(5), diff --git a/src/themes/teams/components/Menu/menuStyles.ts b/src/themes/teams/components/Menu/menuStyles.ts index 7171410a97..afff37bd65 100644 --- a/src/themes/teams/components/Menu/menuStyles.ts +++ b/src/themes/teams/components/Menu/menuStyles.ts @@ -12,7 +12,7 @@ export default { display: 'flex', ...(vertical && { flexDirection: 'column', - ...(!fluid && { width: pxToRem(variables.menuItemWidth) || pxToRem(200) }), + ...(!fluid && { width: pxToRem(variables.menuItemWidth || 200) }), ...(iconOnly && { display: 'inline-block', width: 'auto', From 01810169eb8ae0ec9c17e84f86bf3772a5b86345 Mon Sep 17 00:00:00 2001 From: Sofiya Huts <8460706+sophieH29@users.noreply.github.com> Date: Fri, 24 Aug 2018 10:27:32 +0200 Subject: [PATCH 4/5] Update index.tsx --- docs/src/examples/components/Menu/Types/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/examples/components/Menu/Types/index.tsx b/docs/src/examples/components/Menu/Types/index.tsx index f3a4b4097c..dbf7fcc014 100644 --- a/docs/src/examples/components/Menu/Types/index.tsx +++ b/docs/src/examples/components/Menu/Types/index.tsx @@ -20,8 +20,8 @@ const Types = () => ( examplePath="components/Menu/Types/MenuExampleVertical" /> From 1701079889676e6d0aa5ead3ae9e0977f28690a3 Mon Sep 17 00:00:00 2001 From: Sofiya Huts Date: Tue, 4 Sep 2018 11:26:42 +0200 Subject: [PATCH 5/5] Minor improbements --- src/components/Menu/MenuItem.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/Menu/MenuItem.tsx b/src/components/Menu/MenuItem.tsx index aa79c4a1dc..78cd03d960 100644 --- a/src/components/Menu/MenuItem.tsx +++ b/src/components/Menu/MenuItem.tsx @@ -40,6 +40,9 @@ export interface IMenuItemProps { vertical?: boolean styles?: IComponentPartStylesInput variables?: ComponentVariablesInput + submenu?: ItemShorthand + submenuOpened?: boolean + defaultSubmenuOpened?: boolean } interface MenuItemState {