From 20267f081a69fa5252360344eb1177336ba5fb8d Mon Sep 17 00:00:00 2001 From: brendanlaschke Date: Fri, 22 Sep 2023 11:44:42 +0200 Subject: [PATCH] Fix command menu keyboard input & refactor group (#1706) * - fix command menu keyboard shortcuts - refactor command groups * - refactor the MenuItemCommand to use cmdk * - fixed matching commands multiple displays * - fixed array count problems react with boolean --- .../command-menu/components/CommandGroup.tsx | 31 +++++ .../command-menu/components/CommandMenu.tsx | 118 ++++++++---------- .../components/CommandMenuItem.tsx | 1 - .../components/CommandMenuStyles.tsx | 89 ------------- .../menu-item/components/MenuItemCommand.tsx | 49 +++++++- 5 files changed, 130 insertions(+), 158 deletions(-) create mode 100644 front/src/modules/command-menu/components/CommandGroup.tsx diff --git a/front/src/modules/command-menu/components/CommandGroup.tsx b/front/src/modules/command-menu/components/CommandGroup.tsx new file mode 100644 index 000000000..793c17c36 --- /dev/null +++ b/front/src/modules/command-menu/components/CommandGroup.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import styled from '@emotion/styled'; +import { Command } from 'cmdk'; + +const StyledGroup = styled(Command.Group)` + [cmdk-group-heading] { + align-items: center; + color: ${({ theme }) => theme.font.color.light}; + display: flex; + font-size: ${({ theme }) => theme.font.size.xs}; + font-weight: ${({ theme }) => theme.font.weight.semiBold}; + padding-bottom: ${({ theme }) => theme.spacing(2)}; + padding-left: ${({ theme }) => theme.spacing(2)}; + padding-right: ${({ theme }) => theme.spacing(1)}; + padding-top: ${({ theme }) => theme.spacing(2)}; + text-transform: uppercase; + user-select: none; + } +`; + +type OwnProps = { + heading: string; + children: React.ReactNode | React.ReactNode[]; +}; + +export const CommandGroup = ({ heading, children }: OwnProps) => { + if (!children || !React.Children.count(children)) { + return null; + } + return {children}; +}; diff --git a/front/src/modules/command-menu/components/CommandMenu.tsx b/front/src/modules/command-menu/components/CommandMenu.tsx index 80e6def7e..5f0c123d3 100644 --- a/front/src/modules/command-menu/components/CommandMenu.tsx +++ b/front/src/modules/command-menu/components/CommandMenu.tsx @@ -19,11 +19,11 @@ import { commandMenuCommandsState } from '../states/commandMenuCommandsState'; import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState'; import { Command, CommandType } from '../types/Command'; +import { CommandGroup } from './CommandGroup'; import { CommandMenuItem } from './CommandMenuItem'; import { StyledDialog, StyledEmpty, - StyledGroup, StyledInput, StyledList, } from './CommandMenuStyles'; @@ -130,14 +130,10 @@ export const CommandMenu = () => { onValueChange={setSearch} /> - {matchingCreateCommand.length < 1 && - matchingNavigateCommand.length < 1 && - people.length < 1 && - companies.length < 1 && - activities.length < 1 && No results found.} - {matchingCreateCommand.length > 0 && ( - - {matchingCreateCommand.map((cmd) => ( + No results found. + + {matchingCreateCommand.length === 1 && + matchingCreateCommand.map((cmd) => ( { shortcuts={cmd.shortcuts || []} /> ))} - - )} - {matchingNavigateCommand.length > 0 && ( - - {matchingNavigateCommand.map((cmd) => ( + + + {matchingNavigateCommand.length === 1 && + matchingNavigateCommand.map((cmd) => ( { shortcuts={cmd.shortcuts || []} /> ))} - - )} - {people.length > 0 && ( - - {people.map((person) => ( - ( - - )} - /> - ))} - - )} - {companies.length > 0 && ( - - {companies.map((company) => ( - ( - - )} - /> - ))} - - )} - {activities.length > 0 && ( - - {activities.map((activity) => ( - openActivityRightDrawer(activity.id)} - /> - ))} - - )} + + + {people.map((person) => ( + ( + + )} + /> + ))} + + + {companies.map((company) => ( + ( + + )} + /> + ))} + + + {activities.map((activity) => ( + openActivityRightDrawer(activity.id)} + /> + ))} + ); diff --git a/front/src/modules/command-menu/components/CommandMenuItem.tsx b/front/src/modules/command-menu/components/CommandMenuItem.tsx index d994a2bfa..ad5c9baa2 100644 --- a/front/src/modules/command-menu/components/CommandMenuItem.tsx +++ b/front/src/modules/command-menu/components/CommandMenuItem.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { useNavigate } from 'react-router-dom'; import { IconArrowUpRight } from '@/ui/icon'; diff --git a/front/src/modules/command-menu/components/CommandMenuStyles.tsx b/front/src/modules/command-menu/components/CommandMenuStyles.tsx index 071cfa8f5..1e26491d9 100644 --- a/front/src/modules/command-menu/components/CommandMenuStyles.tsx +++ b/front/src/modules/command-menu/components/CommandMenuStyles.tsx @@ -37,48 +37,6 @@ export const StyledInput = styled(Command.Input)` } `; -export const StyledMenuItem = styled(Command.Item)` - align-items: center; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ theme }) => theme.font.color.primary}; - cursor: pointer; - display: flex; - font-size: ${({ theme }) => theme.font.size.md}; - gap: ${({ theme }) => theme.spacing(3)}; - height: 40px; - justify-content: space-between; - padding: 0 ${({ theme }) => theme.spacing(1)}; - position: relative; - transition: all 150ms ease; - transition-property: none; - user-select: none; - &:hover { - background: ${({ theme }) => theme.background.transparent.light}; - } - &[data-selected='true'] { - background: ${({ theme }) => theme.background.tertiary}; - /* Could be nice to add a caret like this for better accessibility in the future - But it needs to be consistend with other picker dropdown (e.g. company) - &:after { - background: ${({ theme }) => theme.background.quaternary}; - content: ''; - height: 100%; - left: 0; - position: absolute; - width: 3px; - z-index: ${({ theme }) => theme.lastLayerZIndex}; - } */ - } - &[data-disabled='true'] { - color: ${({ theme }) => theme.font.color.light}; - cursor: not-allowed; - } - svg { - height: 16px; - width: 16px; - } -`; - export const StyledList = styled(Command.List)` background: ${({ theme }) => theme.background.secondary}; height: min(300px, var(--cmdk-list-height)); @@ -89,22 +47,6 @@ export const StyledList = styled(Command.List)` transition-property: height; `; -export const StyledGroup = styled(Command.Group)` - [cmdk-group-heading] { - align-items: center; - color: ${({ theme }) => theme.font.color.light}; - display: flex; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - padding-bottom: ${({ theme }) => theme.spacing(2)}; - padding-left: ${({ theme }) => theme.spacing(2)}; - padding-right: ${({ theme }) => theme.spacing(1)}; - padding-top: ${({ theme }) => theme.spacing(2)}; - text-transform: uppercase; - user-select: none; - } -`; - export const StyledEmpty = styled(Command.Empty)` align-items: center; color: ${({ theme }) => theme.font.color.light}; @@ -114,34 +56,3 @@ export const StyledEmpty = styled(Command.Empty)` justify-content: center; white-space: pre-wrap; `; - -export const StyledSeparator = styled(Command.Separator)``; - -export const StyledIconAndLabelContainer = styled.div` - align-items: center; - display: flex; - gap: ${({ theme }) => theme.spacing(2)}; -`; -export const StyledIconContainer = styled.div` - align-items: center; - background: ${({ theme }) => theme.background.transparent.light}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ theme }) => theme.font.color.secondary}; - display: flex; - padding: ${({ theme }) => theme.spacing(1)}; -`; -export const StyledShortCut = styled.div` - background-color: ${({ theme }) => theme.background.transparent.light}; - border-radius: ${({ theme }) => theme.border.radius.sm}; - color: ${({ theme }) => theme.font.color.light}; - margin-left: ${({ theme }) => theme.spacing(1)}; - margin-right: ${({ theme }) => theme.spacing(1)}; - padding: ${({ theme }) => theme.spacing(1)}; -`; - -export const StyledShortcutsContainer = styled.div` - align-items: center; - color: ${({ theme }) => theme.font.color.light}; - display: flex; - font-size: ${({ theme }) => theme.font.size.sm}; -`; diff --git a/front/src/modules/ui/menu-item/components/MenuItemCommand.tsx b/front/src/modules/ui/menu-item/components/MenuItemCommand.tsx index 266f368b4..38562125f 100644 --- a/front/src/modules/ui/menu-item/components/MenuItemCommand.tsx +++ b/front/src/modules/ui/menu-item/components/MenuItemCommand.tsx @@ -1,10 +1,10 @@ import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; +import { Command } from 'cmdk'; import { IconComponent } from '@/ui/icon/types/IconComponent'; import { - StyledMenuItemBase, StyledMenuItemLabel, StyledMenuItemLeftContent, } from '../internals/components/StyledMenuItemBase'; @@ -32,8 +32,51 @@ const StyledCommandText = styled.div` padding-right: ${({ theme }) => theme.spacing(2)}; `; -const StyledMenuItemCommandContainer = styled(StyledMenuItemBase)` +const StyledMenuItemCommandContainer = styled(Command.Item)` + --horizontal-padding: ${({ theme }) => theme.spacing(1)}; + --vertical-padding: ${({ theme }) => theme.spacing(2)}; + align-items: center; + border-radius: ${({ theme }) => theme.border.radius.sm}; + color: ${({ theme }) => theme.font.color.secondary}; + cursor: pointer; + display: flex; + flex-direction: row; + font-size: ${({ theme }) => theme.font.size.sm}; + gap: ${({ theme }) => theme.spacing(2)}; + height: calc(32px - 2 * var(--vertical-padding)); height: 24px; + justify-content: space-between; + padding: var(--vertical-padding) var(--horizontal-padding); + position: relative; + transition: all 150ms ease; + transition-property: none; + user-select: none; + width: calc(100% - 2 * var(--horizontal-padding)); + &:hover { + background: ${({ theme }) => theme.background.transparent.light}; + } + &[data-selected='true'] { + background: ${({ theme }) => theme.background.tertiary}; + /* Could be nice to add a caret like this for better accessibility in the future + But it needs to be consistend with other picker dropdown (e.g. company) + &:after { + background: ${({ theme }) => theme.background.quaternary}; + content: ''; + height: 100%; + left: 0; + position: absolute; + width: 3px; + z-index: ${({ theme }) => theme.lastLayerZIndex}; + } */ + } + &[data-disabled='true'] { + color: ${({ theme }) => theme.font.color.light}; + cursor: not-allowed; + } + svg { + height: 16px; + width: 16px; + } `; export type MenuItemProps = { @@ -54,7 +97,7 @@ export const MenuItemCommand = ({ const theme = useTheme(); return ( - + {LeftIcon && (