Skip to content
This repository was archived by the owner on Mar 25, 2025. It is now read-only.

Commit f9305c1

Browse files
boilundTigge
authored andcommitted
feat(basemenu)!: refactors BaseMenu to use ReactNode for menu button
BREAKING CHANGE: - Refactors `BaseMenu` to use `ReactNode instead of `icon` prop to allow customization of the menu button. - Adds `MenuButtonIconContainer` and exports `MenuButtonIcon` and `MenuButtonHalo` in order to create icon button component as before.
1 parent 5384d07 commit f9305c1

File tree

4 files changed

+300
-169
lines changed

4 files changed

+300
-169
lines changed

packages/core/src/Icon/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export type IconType =
4949

5050
export type IconSize = 'small' | 'medium' | 'large' | 'extraLarge'
5151

52-
interface IconProps extends BaseProps {
52+
export interface IconProps extends BaseProps {
5353
/**
5454
* `class` to be passed to the component.
5555
*/

packages/core/src/Menu/BaseMenu.tsx

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@ import React, {
88
} from 'react'
99
import styled, { css } from 'styled-components'
1010

11-
import { spacing, componentSize, opacity, shape } from '../designparams'
12-
import { remainder } from '../utils/math'
13-
14-
import { Icon, IconType } from '../Icon'
15-
import { MoreVertIcon } from 'practical-react-components-icons'
16-
import { PopOver, PopOverProps } from '../PopOver'
1711
import {
1812
useBoolean,
1913
useVisibleFocus,
2014
useClickOutside,
2115
} from 'react-hooks-shareable'
16+
17+
import { spacing, componentSize, opacity, shape } from '../designparams'
18+
import { remainder } from '../utils/math'
19+
import { Icon } from '../Icon'
20+
import { PopOver, PopOverProps } from '../PopOver'
2221
import { useEscapeListenerStack } from '../Modal/hooks/useEscapeListenerStack'
2322

2423
type BaseElement = HTMLDivElement
@@ -35,12 +34,24 @@ const Anchor = styled.div`
3534
height: fit-content;
3635
`
3736

38-
const MenuIcon = styled(Icon).attrs({ className: 'sc-ButtonIcon' })`
37+
export const MenuButtonIconContainer = styled.div`
38+
position: relative;
39+
height: ${componentSize.small};
40+
width: ${componentSize.small};
41+
border-radius: ${shape.radius.circle};
42+
display: flex;
43+
align-items: center;
44+
justify-content: center;
45+
`
46+
47+
export const MenuButtonIcon = styled(Icon).attrs({
48+
className: 'sc-ButtonIcon',
49+
})`
3950
fill: inherit;
4051
flex: none;
4152
`
4253

43-
const MenuButtonHalo = styled.div`
54+
export const MenuButtonHalo = styled.div`
4455
position: absolute;
4556
top: 0;
4657
right: 0;
@@ -53,27 +64,30 @@ const MenuButtonHalo = styled.div`
5364
transition: transform 100ms;
5465
`
5566

56-
const MenuNativeButton = styled.button<{ readonly visibleFocus: boolean }>`
57-
position: relative;
67+
const MenuNativeButton = styled.button<{
68+
readonly visibleFocus: boolean
69+
}>`
5870
flex: none;
59-
height: ${componentSize.small};
60-
width: ${componentSize.small};
61-
border-radius: ${shape.radius.circle};
6271
min-width: unset;
6372
padding: unset;
6473
outline: none;
65-
border: 2px solid transparent;
6674
cursor: pointer;
75+
border: 0;
6776
&::-moz-focus-inner {
6877
border: 0;
6978
}
7079
color: ${({ theme }) => theme.color.text04()};
7180
fill: ${({ theme }) => theme.color.text04()};
7281
background-color: transparent;
7382
transition: all 200ms;
83+
${MenuButtonIconContainer} {
84+
border: 2px solid transparent;
85+
}
7486
7587
&:hover {
76-
border: 0 solid transparent;
88+
${MenuButtonIconContainer} {
89+
border: 0 solid transparent;
90+
}
7791
${MenuButtonHalo} {
7892
background-color: ${({ theme }) => theme.color.element11(opacity[16])};
7993
transform: scale(1);
@@ -85,7 +99,9 @@ const MenuNativeButton = styled.button<{ readonly visibleFocus: boolean }>`
8599
visibleFocus
86100
? css`
87101
&:focus {
88-
border: 2px solid ${({ theme }) => theme.color.elementBorder()};
102+
${MenuButtonIconContainer} {
103+
border: 2px solid ${({ theme }) => theme.color.elementBorder()};
104+
}
89105
${MenuButtonHalo} {
90106
background-color: ${({ theme }) =>
91107
theme.color.element11(opacity[16])};
@@ -177,27 +193,23 @@ interface MenuButtonProps extends BaseButtonProps {
177193
* `class` to be passed to the component.
178194
*/
179195
readonly className?: string
180-
/**
181-
* Icon that shows inside Button.
182-
*/
183-
readonly icon: IconType
184196
/**
185197
* The title attribute specifies extra information about an element.
186198
*/
187199
readonly title?: string
188200
}
189201

190-
export const MenuButton = React.forwardRef<BaseButtonElement, MenuButtonProps>(
202+
const MenuButton = React.forwardRef<BaseButtonElement, MenuButtonProps>(
191203
(
192204
{
193205
disabled,
194206
name,
195207
onClick,
196208
className,
197-
icon,
198209
onPointerDown,
199210
onPointerUp,
200211
onFocus,
212+
children,
201213
...props
202214
},
203215
ref
@@ -249,8 +261,7 @@ export const MenuButton = React.forwardRef<BaseButtonElement, MenuButtonProps>(
249261
visibleFocus={visibleFocus}
250262
{...props}
251263
>
252-
<MenuIcon icon={icon} />
253-
<MenuButtonHalo />
264+
{children}
254265
</MenuNativeButton>
255266
)
256267
}
@@ -378,9 +389,9 @@ const BaseItem: React.FunctionComponent<BaseItemProps> = ({
378389

379390
export interface BaseMenuProps extends Omit<PopOverProps, 'anchorEl'> {
380391
/**
381-
* The icon element.
392+
* React element that will appear as menu button
382393
*/
383-
readonly icon?: IconType
394+
readonly button: ReactNode
384395
/**
385396
* Aligns the menu either left or right.
386397
*/
@@ -403,7 +414,7 @@ export interface BaseMenuProps extends Omit<PopOverProps, 'anchorEl'> {
403414
*/
404415
export const BaseMenu = memo<BaseMenuProps>(
405416
({
406-
icon = MoreVertIcon,
417+
button,
407418
align = 'left',
408419
disabled = false,
409420
components,
@@ -537,7 +548,9 @@ export const BaseMenu = memo<BaseMenuProps>(
537548
onBlur={handleBlur}
538549
{...props}
539550
>
540-
<MenuButton icon={icon} onClick={mouseToggleMenu} disabled={disabled} />
551+
<MenuButton onClick={mouseToggleMenu} disabled={disabled}>
552+
{button}
553+
</MenuButton>
541554
{menuVisible ? (
542555
<PopOver
543556
horizontalPosition={align}

packages/core/src/Menu/Menu.tsx

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
import React, { memo, useMemo } from 'react'
22
import styled, { css, useTheme } from 'styled-components'
33

4+
import { MoreVertIcon } from 'practical-react-components-icons'
5+
46
import { componentSize, spacing } from '../designparams'
57
import { Typography } from '../Typography'
68
import { Icon, IconType } from '../Icon'
7-
import { BaseMenu, BaseItemProps, BaseMenuProps } from './BaseMenu'
9+
import {
10+
BaseMenu,
11+
BaseItemProps,
12+
BaseMenuProps,
13+
MenuButtonIcon,
14+
MenuButtonHalo,
15+
MenuButtonIconContainer,
16+
} from './BaseMenu'
817

918
export const MenuItem = styled.div<{
1019
readonly divider?: boolean
@@ -49,13 +58,18 @@ export interface MenuItemProps
4958
}
5059

5160
interface MenuProps extends Omit<BaseMenuProps, 'components'> {
61+
/**
62+
* The icon element for menu button.
63+
*
64+
* Default: `MoreVertIcon`
65+
*/
66+
readonly icon?: IconType
5267
/**
5368
* An array of items in the drop down menu.
5469
*/
5570
readonly items: ReadonlyArray<MenuItemProps>
5671
/**
5772
* Override theme's default setting for `compact` if set.
58-
5973
*/
6074
readonly compact?: boolean
6175
}
@@ -66,10 +80,22 @@ interface MenuProps extends Omit<BaseMenuProps, 'components'> {
6680
* Forwards props to BaseMenu
6781
*/
6882
export const Menu = memo<MenuProps>(
69-
({ items, compact: compactFromProps, ...props }) => {
83+
({
84+
icon: buttonIcon = MoreVertIcon,
85+
items,
86+
compact: compactFromProps,
87+
...props
88+
}) => {
7089
const { compact: compactFromTheme } = useTheme()
7190
const compact = compactFromProps ?? compactFromTheme
7291

92+
const button = (
93+
<MenuButtonIconContainer>
94+
<MenuButtonIcon icon={buttonIcon} />
95+
<MenuButtonHalo />
96+
</MenuButtonIconContainer>
97+
)
98+
7399
/**
74100
* Creates array of components using MenuItem to
75101
* forward to Base Menu
@@ -97,7 +123,7 @@ export const Menu = memo<MenuProps>(
97123
[compact, items]
98124
)
99125

100-
return <BaseMenu components={components} {...props} />
126+
return <BaseMenu button={button} components={components} {...props} />
101127
}
102128
)
103129

0 commit comments

Comments
 (0)