From aab15b2014c72c1bd1f9cb99f776cff5c7a234bb Mon Sep 17 00:00:00 2001 From: Nikolay Kost Date: Mon, 4 Jul 2022 21:26:57 +0200 Subject: [PATCH 1/5] fix: use param to display checkboxes --- src/components/pickers/Menu/Menu.stories.tsx | 15 ++++++++++++ src/components/pickers/Menu/Menu.tsx | 7 ++++-- src/components/pickers/Menu/MenuButton.tsx | 24 +++++++++++++++++--- src/components/pickers/Menu/MenuItem.tsx | 6 +++-- src/components/pickers/Menu/MenuSection.tsx | 2 ++ 5 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/components/pickers/Menu/Menu.stories.tsx b/src/components/pickers/Menu/Menu.stories.tsx index a98c63e7..4060db3e 100644 --- a/src/components/pickers/Menu/Menu.stories.tsx +++ b/src/components/pickers/Menu/Menu.stories.tsx @@ -199,6 +199,21 @@ export const MenuSelectableMultiple = (props) => { }); }; +export const MenuSelectableCheckboxes = (props) => { + const [selectedKeys, setSelectedKeys] = useState(['1']); + const onSelectionChange = (key) => { + setSelectedKeys(key); + }; + + return MenuTemplate({ + ...props, + selectionType: 'checkbox', + selectionMode: 'single', + selectedKeys, + onSelectionChange, + }); +}; + export const PaymentDetails = (props) => { return ( diff --git a/src/components/pickers/Menu/Menu.tsx b/src/components/pickers/Menu/Menu.tsx index 7b72236e..1ec708f6 100644 --- a/src/components/pickers/Menu/Menu.tsx +++ b/src/components/pickers/Menu/Menu.tsx @@ -17,7 +17,7 @@ import { Styles, } from '../../../tasty'; import { StyledMenu, StyledMenuHeader } from './styled'; -import { MenuItem } from './MenuItem'; +import { MenuItem, MenuSelectionType } from './MenuItem'; import { MenuSection } from './MenuSection'; import { MenuButtonProps } from './MenuButton'; import { useMenuContext } from './context'; @@ -26,6 +26,7 @@ import { useContextStyles } from '../../../providers/StyleProvider'; export interface CubeMenuProps extends ContainerStyleProps, AriaMenuProps { + selectionType?: MenuSelectionType; header?: ReactNode; footer?: ReactNode; styles?: Styles; @@ -35,7 +36,7 @@ function Menu( props: CubeMenuProps, ref: DOMRef, ) { - const { header, footer, styles } = props; + const { header, footer, styles, selectionType } = props; const domRef = useDOMRef(ref); const contextProps = useMenuContext(); const completeProps = mergeProps(contextProps, props); @@ -76,6 +77,7 @@ function Menu( key={item.key} item={item} state={state} + selectionType={selectionType} onAction={completeProps.onAction} /> ); @@ -86,6 +88,7 @@ function Menu( key={item.key} item={item} state={state} + selectionType={selectionType} onAction={completeProps.onAction} /> ); diff --git a/src/components/pickers/Menu/MenuButton.tsx b/src/components/pickers/Menu/MenuButton.tsx index 9a2c0340..91cf1aa7 100644 --- a/src/components/pickers/Menu/MenuButton.tsx +++ b/src/components/pickers/Menu/MenuButton.tsx @@ -3,7 +3,7 @@ import { Button, CubeButtonProps } from '../../actions'; import { Text } from '../../content/Text'; import { Styles } from '../../../tasty'; import { Space } from '../../layout/Space'; -import { CheckOutlined } from '@ant-design/icons'; +import { CheckOutlined, CheckCircleOutlined } from '@ant-design/icons'; const ACTION_BUTTON: Styles = { border: { @@ -30,6 +30,8 @@ const ACTION_BUTTON: Styles = { padding: { '': '(0.75x - 1px) (1.5x - 1px)', 'selectable & !selected': + '(0.75x - 1px) (1.5x - 1px) (0.75x - 1px) (1.5x - 1px)', + 'selectionType & selectable & !selected': '(0.75x - 1px) (1.5x - 1px) (0.75x - 1px) (1.5x - 1px + 22px)', }, display: 'flex', @@ -54,22 +56,38 @@ const getPostfix = (postfix) => postfix ); +export type MenuSelectionType = 'checkbox' | 'radio'; + export type MenuButtonProps = { postfix: ReactNode; + selectionType?: MenuSelectionType; isSelectable?: boolean; disabled?: boolean; } & CubeButtonProps; +const getSelectionTypeIcon = (selectionType?: MenuSelectionType) => { + switch (selectionType) { + case 'checkbox': + return ; + case 'radio': + return ; + default: + return null; + } +}; + export function MenuButton({ children, icon, postfix, ...props }: MenuButtonProps) { - const { isSelected, isSelectable } = props; - const checkIcon = isSelectable && isSelected ? : null; + const { selectionType, isSelected, isSelectable } = props; + const checkIcon = + isSelectable && isSelected ? getSelectionTypeIcon(selectionType) : null; const mods = { ...props.mods, + selectionType: !!selectionType, selectable: isSelectable, selected: isSelected, }; diff --git a/src/components/pickers/Menu/MenuItem.tsx b/src/components/pickers/Menu/MenuItem.tsx index fcd42fb1..b862b603 100644 --- a/src/components/pickers/Menu/MenuItem.tsx +++ b/src/components/pickers/Menu/MenuItem.tsx @@ -7,18 +7,19 @@ import { useMenuItem } from '@react-aria/menu'; import { mergeProps, ClearSlots, SlotProvider } from '../../../utils/react'; import { useMenuContext } from './context'; import { StyledMenuItem } from './styled'; -import { MenuButton } from './MenuButton'; +import { MenuButton, MenuSelectionType } from './MenuButton'; interface MenuItemProps { item: Node; state: TreeState; + selectionType?: MenuSelectionType; isVirtualized?: boolean; onAction?: (key: Key) => void; } /** @private */ export function MenuItem(props: MenuItemProps) { - const { item, state, isVirtualized, onAction } = props; + const { item, state, selectionType, isVirtualized, onAction } = props; const { onClose, closeOnSelect } = useMenuContext(); const { rendered, key, props: itemProps } = item; @@ -48,6 +49,7 @@ export function MenuItem(props: MenuItemProps) { typeof rendered === 'string' ? ( { item: Node; state: TreeState; + selectionType?: MenuSelectionType; onAction?: (key: Key) => void; } From f5b3bdbc72e74e9b7fe8ab3ccdeeb740bc3425cd Mon Sep 17 00:00:00 2001 From: Nikolay Kost Date: Mon, 4 Jul 2022 21:42:52 +0200 Subject: [PATCH 2/5] fix: after merge --- src/components/pickers/Menu/Menu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/pickers/Menu/Menu.tsx b/src/components/pickers/Menu/Menu.tsx index 7ee93dce..0c71a097 100644 --- a/src/components/pickers/Menu/Menu.tsx +++ b/src/components/pickers/Menu/Menu.tsx @@ -17,9 +17,9 @@ import { Styles, } from '../../../tasty'; import { StyledMenu, StyledMenuHeader } from './styled'; -import { MenuItem, MenuSelectionType } from './MenuItem'; +import { MenuItem } from './MenuItem'; import { MenuSection } from './MenuSection'; -import { MenuButtonProps } from './MenuButton'; +import { MenuButtonProps, MenuSelectionType } from './MenuButton'; import { useMenuContext } from './context'; export interface CubeMenuProps From cde44690d74743917b30f3877ce9a5b9c7741061 Mon Sep 17 00:00:00 2001 From: Nikolay Kost <105391768+nikolaykost@users.noreply.github.com> Date: Mon, 4 Jul 2022 21:46:50 +0200 Subject: [PATCH 3/5] chore: add changeset --- .changeset/stupid-rockets-clap.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .changeset/stupid-rockets-clap.md diff --git a/.changeset/stupid-rockets-clap.md b/.changeset/stupid-rockets-clap.md new file mode 100644 index 00000000..afafc082 --- /dev/null +++ b/.changeset/stupid-rockets-clap.md @@ -0,0 +1,13 @@ +--- +"@cube-dev/ui-kit": patch +--- + +Adds prop `selectionType` for `Menu` component. That stands for values `checkbox` or `radio`. + +```jsx + + Item 1 + Item 2 + +``` + From 8f7276570162183669c881df3a1c262be372ec18 Mon Sep 17 00:00:00 2001 From: Andrey Yamanov Date: Thu, 7 Jul 2022 11:50:42 +0300 Subject: [PATCH 4/5] fix(Menu): change icon and selectionType -> selectionIcon --- src/components/pickers/Menu/Menu.stories.tsx | 17 +++++++++- src/components/pickers/Menu/Menu.tsx | 8 ++--- src/components/pickers/Menu/MenuButton.tsx | 35 +++++++++++++++----- src/components/pickers/Menu/MenuItem.tsx | 6 ++-- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/components/pickers/Menu/Menu.stories.tsx b/src/components/pickers/Menu/Menu.stories.tsx index cd1ea943..30e909bf 100644 --- a/src/components/pickers/Menu/Menu.stories.tsx +++ b/src/components/pickers/Menu/Menu.stories.tsx @@ -207,7 +207,22 @@ export const MenuSelectableCheckboxes = (props) => { return MenuTemplate({ ...props, - selectionType: 'checkbox', + selectionIcon: 'checkbox', + selectionMode: 'multiple', + selectedKeys, + onSelectionChange, + }); +}; + +export const MenuSelectableRadio = (props) => { + const [selectedKeys, setSelectedKeys] = useState(['1']); + const onSelectionChange = (key) => { + setSelectedKeys(key); + }; + + return MenuTemplate({ + ...props, + selectionIcon: 'radio', selectionMode: 'single', selectedKeys, onSelectionChange, diff --git a/src/components/pickers/Menu/Menu.tsx b/src/components/pickers/Menu/Menu.tsx index 0c71a097..5e54470c 100644 --- a/src/components/pickers/Menu/Menu.tsx +++ b/src/components/pickers/Menu/Menu.tsx @@ -25,7 +25,7 @@ import { useMenuContext } from './context'; export interface CubeMenuProps extends ContainerStyleProps, AriaMenuProps { - selectionType?: MenuSelectionType; + selectionIcon?: MenuSelectionType; header?: ReactNode; footer?: ReactNode; styles?: Styles; @@ -35,7 +35,7 @@ function Menu( props: CubeMenuProps, ref: DOMRef, ) { - const { header, footer, selectionType } = props; + const { header, footer, selectionIcon } = props; const domRef = useDOMRef(ref); const contextProps = useMenuContext(); const completeProps = mergeProps(contextProps, props); @@ -71,7 +71,7 @@ function Menu( key={item.key} item={item} state={state} - selectionType={selectionType} + selectionIcon={selectionIcon} onAction={completeProps.onAction} /> ); @@ -82,7 +82,7 @@ function Menu( key={item.key} item={item} state={state} - selectionType={selectionType} + selectionIcon={selectionIcon} onAction={completeProps.onAction} /> ); diff --git a/src/components/pickers/Menu/MenuButton.tsx b/src/components/pickers/Menu/MenuButton.tsx index 91cf1aa7..099a76ba 100644 --- a/src/components/pickers/Menu/MenuButton.tsx +++ b/src/components/pickers/Menu/MenuButton.tsx @@ -1,7 +1,7 @@ import { ReactNode } from 'react'; import { Button, CubeButtonProps } from '../../actions'; import { Text } from '../../content/Text'; -import { Styles } from '../../../tasty'; +import { Styles, tasty } from '../../../tasty'; import { Space } from '../../layout/Space'; import { CheckOutlined, CheckCircleOutlined } from '@ant-design/icons'; @@ -31,7 +31,7 @@ const ACTION_BUTTON: Styles = { '': '(0.75x - 1px) (1.5x - 1px)', 'selectable & !selected': '(0.75x - 1px) (1.5x - 1px) (0.75x - 1px) (1.5x - 1px)', - 'selectionType & selectable & !selected': + 'selectionIcon & selectable & !selected': '(0.75x - 1px) (1.5x - 1px) (0.75x - 1px) (1.5x - 1px + 22px)', }, display: 'flex', @@ -47,6 +47,23 @@ const ACTION_BUTTON: Styles = { }, }; +const RadioIcon = tasty({ + styles: { + display: 'flex', + width: '1.875x', + placeContent: 'center', + + '&::before': { + display: 'block', + content: '""', + width: '1x', + height: '1x', + radius: 'round', + fill: '#current', + }, + }, +}); + const getPostfix = (postfix) => typeof postfix === 'string' ? ( @@ -60,17 +77,17 @@ export type MenuSelectionType = 'checkbox' | 'radio'; export type MenuButtonProps = { postfix: ReactNode; - selectionType?: MenuSelectionType; + selectionIcon?: MenuSelectionType; isSelectable?: boolean; disabled?: boolean; } & CubeButtonProps; -const getSelectionTypeIcon = (selectionType?: MenuSelectionType) => { - switch (selectionType) { +const getSelectionTypeIcon = (selectionIcon?: MenuSelectionType) => { + switch (selectionIcon) { case 'checkbox': return ; case 'radio': - return ; + return ; default: return null; } @@ -82,12 +99,12 @@ export function MenuButton({ postfix, ...props }: MenuButtonProps) { - const { selectionType, isSelected, isSelectable } = props; + const { selectionIcon, isSelected, isSelectable } = props; const checkIcon = - isSelectable && isSelected ? getSelectionTypeIcon(selectionType) : null; + isSelectable && isSelected ? getSelectionTypeIcon(selectionIcon) : null; const mods = { ...props.mods, - selectionType: !!selectionType, + selectionIcon: !!selectionIcon, selectable: isSelectable, selected: isSelected, }; diff --git a/src/components/pickers/Menu/MenuItem.tsx b/src/components/pickers/Menu/MenuItem.tsx index a634b588..1fbbe314 100644 --- a/src/components/pickers/Menu/MenuItem.tsx +++ b/src/components/pickers/Menu/MenuItem.tsx @@ -12,14 +12,14 @@ import { MenuButton, MenuSelectionType } from './MenuButton'; export interface MenuItemProps { item: Node; state: TreeState; - selectionType?: MenuSelectionType; + selectionIcon?: MenuSelectionType; isVirtualized?: boolean; onAction?: (key: Key) => void; } /** @private */ export function MenuItem(props: MenuItemProps) { - const { item, state, selectionType, isVirtualized, onAction } = props; + const { item, state, selectionIcon, isVirtualized, onAction } = props; const { onClose, closeOnSelect } = useMenuContext(); const { rendered, key, props: itemProps } = item; @@ -49,7 +49,7 @@ export function MenuItem(props: MenuItemProps) { typeof rendered === 'string' ? ( Date: Thu, 7 Jul 2022 12:15:04 +0300 Subject: [PATCH 5/5] fix(Menu): change checkbox story --- src/components/pickers/Menu/Menu.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/pickers/Menu/Menu.stories.tsx b/src/components/pickers/Menu/Menu.stories.tsx index 30e909bf..f9a360bc 100644 --- a/src/components/pickers/Menu/Menu.stories.tsx +++ b/src/components/pickers/Menu/Menu.stories.tsx @@ -200,7 +200,7 @@ export const MenuSelectableMultiple = (props) => { }; export const MenuSelectableCheckboxes = (props) => { - const [selectedKeys, setSelectedKeys] = useState(['1']); + const [selectedKeys, setSelectedKeys] = useState(['1', '2']); const onSelectionChange = (key) => { setSelectedKeys(key); };