Chore(front): Create Storybook tests for the DropdownMenu component (#2157)

* Chore(front): Create Storybook tests for the DropdownMenu component

Co-authored-by: Benjamin Mayanja V <vibenjamin6@gmail.com>
Co-authored-by: FellipeMTX <fellipefacdir@gmail.com>

* Fix the tests

Co-authored-by: Benjamin Mayanja V <vibenjamin6@gmail.com>
Co-authored-by: FellipeMTX <fellipefacdir@gmail.com>

* Simplify Dropdown

* Remove console.log

---------

Co-authored-by: Benjamin Mayanja V <vibenjamin6@gmail.com>
Co-authored-by: FellipeMTX <fellipefacdir@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
gitstart-twenty
2023-10-20 21:19:43 +02:00
committed by GitHub
co-authored by Benjamin Mayanja V FellipeMTX Charles Bochet
parent eea7470571
commit dee9807eb3
41 changed files with 634 additions and 674 deletions
+13
View File
@@ -16,4 +16,17 @@ html {
.sbdocs-wrapper { .sbdocs-wrapper {
padding: 0 !important; padding: 0 !important;
} }
*::-webkit-scrollbar {
height: 4px;
width: 4px;
}
*::-webkit-scrollbar-corner {
background-color: transparent;
}
*::-webkit-scrollbar-thumb {
background-color: transparent;
border-radius: 2px;
}
</style> </style>
+1 -1
View File
@@ -181,4 +181,4 @@
"msw": { "msw": {
"workerDirectory": "public" "workerDirectory": "public"
} }
} }
@@ -6,11 +6,11 @@ import { IconChevronDown } from '@/ui/display/icon';
import { SingleEntitySelectBase } from '@/ui/input/relation-picker/components/SingleEntitySelectBase'; import { SingleEntitySelectBase } from '@/ui/input/relation-picker/components/SingleEntitySelectBase';
import { useEntitySelectSearch } from '@/ui/input/relation-picker/hooks/useEntitySelectSearch'; import { useEntitySelectSearch } from '@/ui/input/relation-picker/hooks/useEntitySelectSearch';
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect'; import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader'; import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
@@ -79,7 +79,7 @@ export const CompanyProgressPicker = ({
); );
return ( return (
<StyledDropdownMenu <DropdownMenu
ref={containerRef} ref={containerRef}
data-testid={`company-progress-dropdown-menu`} data-testid={`company-progress-dropdown-menu`}
> >
@@ -105,13 +105,13 @@ export const CompanyProgressPicker = ({
> >
{selectedPipelineStage?.name} {selectedPipelineStage?.name}
</DropdownMenuHeader> </DropdownMenuHeader>
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuSearchInput <DropdownMenuSearchInput
value={searchFilter} value={searchFilter}
onChange={handleSearchFilterChange} onChange={handleSearchFilterChange}
autoFocus autoFocus
/> />
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<RecoilScope> <RecoilScope>
<SingleEntitySelectBase <SingleEntitySelectBase
entitiesToSelect={companies.entitiesToSelect} entitiesToSelect={companies.entitiesToSelect}
@@ -123,6 +123,6 @@ export const CompanyProgressPicker = ({
</RecoilScope> </RecoilScope>
</> </>
)} )}
</StyledDropdownMenu> </DropdownMenu>
); );
}; };
@@ -6,8 +6,8 @@ import { autoUpdate, flip, offset, useFloating } from '@floating-ui/react';
import { IconDotsVertical, IconLinkOff, IconTrash } from '@/ui/display/icon'; import { IconDotsVertical, IconLinkOff, IconTrash } from '@/ui/display/icon';
import { FloatingIconButton } from '@/ui/input/button/components/FloatingIconButton'; import { FloatingIconButton } from '@/ui/input/button/components/FloatingIconButton';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { Avatar } from '@/users/components/Avatar'; import { Avatar } from '@/users/components/Avatar';
@@ -164,7 +164,7 @@ export const PeopleCard = ({
Icon={IconDotsVertical} Icon={IconDotsVertical}
/> />
{isOptionsOpen && ( {isOptionsOpen && (
<StyledDropdownMenu <DropdownMenu
data-select-disable data-select-disable
ref={refs.setFloating} ref={refs.setFloating}
style={floatingStyles} style={floatingStyles}
@@ -182,7 +182,7 @@ export const PeopleCard = ({
accent="danger" accent="danger"
/> />
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</StyledDropdownMenu> </DropdownMenu>
)} )}
</div> </div>
)} )}
@@ -1,13 +1,14 @@
import { CompanyProgressPicker } from '@/companies/components/CompanyProgressPicker'; import { CompanyProgressPicker } from '@/companies/components/CompanyProgressPicker';
import { useCreateCompanyProgress } from '@/companies/hooks/useCreateCompanyProgress'; import { useCreateCompanyProgress } from '@/companies/hooks/useCreateCompanyProgress';
import { PageHotkeyScope } from '@/types/PageHotkeyScope'; import { PageHotkeyScope } from '@/types/PageHotkeyScope';
import { ViewBarDropdownButton } from '@/ui/data/view-bar/components/ViewBarDropdownButton';
import { IconPlus } from '@/ui/display/icon/index'; import { IconPlus } from '@/ui/display/icon/index';
import { useSnackBar } from '@/ui/feedback/snack-bar/hooks/useSnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar/hooks/useSnackBar';
import { IconButton } from '@/ui/input/button/components/IconButton'; import { IconButton } from '@/ui/input/button/components/IconButton';
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect'; import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope'; import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { logError } from '~/utils/logError'; import { logError } from '~/utils/logError';
export const PipelineAddButton = () => { export const PipelineAddButton = () => {
@@ -51,32 +52,33 @@ export const PipelineAddButton = () => {
}; };
return ( return (
<ViewBarDropdownButton <DropdownScope dropdownScopeId="add-pipeline-progress">
dropdownId="add-pipeline-progress" <Dropdown
buttonComponent={ clickableComponent={
<IconButton <IconButton
Icon={IconPlus} Icon={IconPlus}
size="medium" size="medium"
dataTestId="add-company-progress-button" dataTestId="add-company-progress-button"
accent="default" accent="default"
variant="secondary" variant="secondary"
onClick={toggleDropdown} onClick={toggleDropdown}
/> />
} }
dropdownComponents={ dropdownComponents={
<CompanyProgressPicker <CompanyProgressPicker
companyId={null} companyId={null}
onSubmit={handleCompanySelected} onSubmit={handleCompanySelected}
onCancel={closeDropdown} onCancel={closeDropdown}
/> />
} }
hotkey={{ hotkey={{
key: 'c', key: 'c',
scope: PageHotkeyScope.OpportunitiesPage, scope: PageHotkeyScope.OpportunitiesPage,
}} }}
dropdownHotkeyScope={{ dropdownHotkeyScope={{
scope: RelationPickerHotkeyScope.RelationPicker, scope: RelationPickerHotkeyScope.RelationPicker,
}} }}
/> />
</DropdownScope>
); );
}; };
@@ -1,9 +1,9 @@
import { IconDotsVertical, IconTrash } from '@/ui/display/icon'; import { IconDotsVertical, IconTrash } from '@/ui/display/icon';
import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
import { IconArchiveOff } from '@/ui/input/constants/icons'; import { IconArchiveOff } from '@/ui/input/constants/icons';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu'; import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope'; import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
@@ -22,12 +22,12 @@ export const SettingsObjectDisabledMenuDropDown = ({
<DropdownScope <DropdownScope
dropdownScopeId={scopeKey + '-settings-object-disabled-menu-dropdown'} dropdownScopeId={scopeKey + '-settings-object-disabled-menu-dropdown'}
> >
<DropdownMenu <Dropdown
clickableComponent={ clickableComponent={
<LightIconButton Icon={IconDotsVertical} accent="tertiary" /> <LightIconButton Icon={IconDotsVertical} accent="tertiary" />
} }
dropdownComponents={ dropdownComponents={
<StyledDropdownMenu width="160px"> <DropdownMenu width="160px">
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
<MenuItem <MenuItem
text="Activate" text="Activate"
@@ -41,7 +41,7 @@ export const SettingsObjectDisabledMenuDropDown = ({
onClick={handleErase} onClick={handleErase}
/> />
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</StyledDropdownMenu> </DropdownMenu>
} }
dropdownHotkeyScope={{ dropdownHotkeyScope={{
scope: scopeKey + '-settings-object-disabled-menu-dropdown', scope: scopeKey + '-settings-object-disabled-menu-dropdown',
@@ -14,10 +14,10 @@ import { ReadonlyDeep } from 'type-fest';
import { SelectOption } from '@/spreadsheet-import/types'; import { SelectOption } from '@/spreadsheet-import/types';
import { AppTooltip } from '@/ui/display/tooltip/AppTooltip'; import { AppTooltip } from '@/ui/display/tooltip/AppTooltip';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { MenuItemSelect } from '@/ui/navigation/menu-item/components/MenuItemSelect'; import { MenuItemSelect } from '@/ui/navigation/menu-item/components/MenuItemSelect';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
@@ -116,7 +116,7 @@ export const MatchColumnSelect = ({
{isOpen && {isOpen &&
createPortal( createPortal(
<StyledFloatingDropdown ref={refs.setFloating} style={floatingStyles}> <StyledFloatingDropdown ref={refs.setFloating} style={floatingStyles}>
<StyledDropdownMenu <DropdownMenu
data-select-disable data-select-disable
ref={dropdownContainerRef} ref={dropdownContainerRef}
width={refs.domReference.current?.clientWidth} width={refs.domReference.current?.clientWidth}
@@ -126,7 +126,7 @@ export const MatchColumnSelect = ({
onChange={handleFilterChange} onChange={handleFilterChange}
autoFocus autoFocus
/> />
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItemsContainer hasMaxHeight> <DropdownMenuItemsContainer hasMaxHeight>
{options?.map((option) => ( {options?.map((option) => (
<> <>
@@ -156,7 +156,7 @@ export const MatchColumnSelect = ({
))} ))}
{options?.length === 0 && <MenuItem text="No result" />} {options?.length === 0 && <MenuItem text="No result" />}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</StyledDropdownMenu> </DropdownMenu>
</StyledFloatingDropdown>, </StyledFloatingDropdown>,
document.body, document.body,
)} )}
@@ -1,5 +1,5 @@
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata'; import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope'; import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { ColumnDefinition } from '../types/ColumnDefinition'; import { ColumnDefinition } from '../types/ColumnDefinition';
@@ -22,7 +22,7 @@ export const ColumnHeadWithDropdown = ({
}: ColumnHeadWithDropdownProps) => { }: ColumnHeadWithDropdownProps) => {
return ( return (
<DropdownScope dropdownScopeId={column.key + '-header'}> <DropdownScope dropdownScopeId={column.key + '-header'}>
<DropdownMenu <Dropdown
clickableComponent={<ColumnHead column={column} />} clickableComponent={<ColumnHead column={column} />}
dropdownComponents={ dropdownComponents={
<DataTableColumnDropdownMenu <DataTableColumnDropdownMenu
@@ -1,7 +1,7 @@
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata'; import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { IconArrowLeft, IconArrowRight, IconEyeOff } from '@/ui/display/icon'; import { IconArrowLeft, IconArrowRight, IconEyeOff } from '@/ui/display/icon';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
@@ -52,7 +52,7 @@ export const DataTableColumnDropdownMenu = ({
return column.key === primaryColumnKey ? ( return column.key === primaryColumnKey ? (
<></> <></>
) : ( ) : (
<StyledDropdownMenu> <DropdownMenu>
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
{!isFirstColumn && ( {!isFirstColumn && (
<MenuItem <MenuItem
@@ -74,6 +74,6 @@ export const DataTableColumnDropdownMenu = ({
text="Hide" text="Hide"
/> />
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</StyledDropdownMenu> </DropdownMenu>
); );
}; };
@@ -3,8 +3,8 @@ import styled from '@emotion/styled';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata'; import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { IconPlus } from '@/ui/display/icon'; import { IconPlus } from '@/ui/display/icon';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
@@ -14,7 +14,7 @@ import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRe
import { hiddenTableColumnsScopedSelector } from '../states/selectors/hiddenTableColumnsScopedSelector'; import { hiddenTableColumnsScopedSelector } from '../states/selectors/hiddenTableColumnsScopedSelector';
import { ColumnDefinition } from '../types/ColumnDefinition'; import { ColumnDefinition } from '../types/ColumnDefinition';
const StyledHeaderPlusButton = styled(StyledDropdownMenu)` const StyledHeaderPlusButton = styled(DropdownMenu)`
font-weight: ${({ theme }) => theme.font.weight.regular}; font-weight: ${({ theme }) => theme.font.weight.regular};
`; `;
@@ -1,7 +1,8 @@
import { useResetRecoilState } from 'recoil'; import { useResetRecoilState } from 'recoil';
import { ViewBarDropdownButton } from '@/ui/data/view-bar/components/ViewBarDropdownButton';
import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState'; import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId'; import { TableOptionsDropdownId } from '../../constants/TableOptionsDropdownId';
@@ -19,12 +20,14 @@ export const TableOptionsDropdown = ({
const resetViewEditMode = useResetRecoilState(viewEditModeState); const resetViewEditMode = useResetRecoilState(viewEditModeState);
return ( return (
<ViewBarDropdownButton <DropdownScope dropdownScopeId={TableOptionsDropdownId}>
buttonComponent={<TableOptionsDropdownButton />} <Dropdown
dropdownHotkeyScope={customHotkeyScope} clickableComponent={<TableOptionsDropdownButton />}
dropdownId={TableOptionsDropdownId} dropdownHotkeyScope={customHotkeyScope}
dropdownComponents={<TableOptionsDropdownContent />} dropdownOffset={{ y: 8 }}
onClickOutside={resetViewEditMode} dropdownComponents={<TableOptionsDropdownContent />}
/> onClickOutside={resetViewEditMode}
/>
</DropdownScope>
); );
}; };
@@ -12,10 +12,8 @@ import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState';
import { IconChevronLeft, IconFileImport, IconTag } from '@/ui/display/icon'; import { IconChevronLeft, IconFileImport, IconTag } from '@/ui/display/icon';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader'; import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput'; import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput';
import { DropdownMenuInputContainer } from '@/ui/layout/dropdown/components/DropdownMenuInputContainer';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
@@ -128,28 +126,23 @@ export const TableOptionsDropdownContent = () => {
); );
return ( return (
<StyledDropdownMenu> <>
{!currentMenu && ( {!currentMenu && (
<> <>
<DropdownMenuInputContainer> <DropdownMenuInput
<DropdownMenuInput autoFocus={viewEditMode.mode === 'create' || !!viewEditMode.viewId}
ref={viewEditInputRef} placeholder={
autoFocus={ viewEditMode.mode === 'create' ? 'New view' : 'View name'
viewEditMode.mode === 'create' || !!viewEditMode.viewId }
} defaultValue={
placeholder={ viewEditMode.mode === 'create'
viewEditMode.mode === 'create' ? 'New view' : 'View name' ? ''
} : viewEditMode.viewId
defaultValue={ ? viewsById[viewEditMode.viewId]?.name
viewEditMode.mode === 'create' : currentView?.name
? '' }
: viewEditMode.viewId />
? viewsById[viewEditMode.viewId]?.name <DropdownMenuSeparator />
: currentView?.name
}
/>
</DropdownMenuInputContainer>
<StyledDropdownMenuSeparator />
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
<MenuItem <MenuItem
onClick={() => handleSelectMenu('fields')} onClick={() => handleSelectMenu('fields')}
@@ -171,7 +164,7 @@ export const TableOptionsDropdownContent = () => {
<DropdownMenuHeader StartIcon={IconChevronLeft} onClick={resetMenu}> <DropdownMenuHeader StartIcon={IconChevronLeft} onClick={resetMenu}>
Fields Fields
</DropdownMenuHeader> </DropdownMenuHeader>
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<ViewFieldsVisibilityDropdownSection <ViewFieldsVisibilityDropdownSection
title="Visible" title="Visible"
fields={visibleTableColumns} fields={visibleTableColumns}
@@ -181,7 +174,7 @@ export const TableOptionsDropdownContent = () => {
/> />
{hiddenTableColumns.length > 0 && ( {hiddenTableColumns.length > 0 && (
<> <>
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<ViewFieldsVisibilityDropdownSection <ViewFieldsVisibilityDropdownSection
title="Hidden" title="Hidden"
fields={hiddenTableColumns} fields={hiddenTableColumns}
@@ -192,6 +185,6 @@ export const TableOptionsDropdownContent = () => {
)} )}
</> </>
)} )}
</StyledDropdownMenu> </>
); );
}; };
@@ -1,4 +1,4 @@
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope'; import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
@@ -19,7 +19,7 @@ export const FilterDropdownEntitySelect = () => {
return ( return (
<> <>
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<RecoilScope> <RecoilScope>
{filterDefinitionUsedInDropdown.entitySelectComponent} {filterDefinitionUsedInDropdown.entitySelectComponent}
</RecoilScope> </RecoilScope>
@@ -1,10 +1,11 @@
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { FilterDropdownId } from '../constants/FilterDropdownId'; import { FilterDropdownId } from '../constants/FilterDropdownId';
import { MultipleFiltersButton } from './MultipleFiltersButton'; import { MultipleFiltersButton } from './MultipleFiltersButton';
import { MultipleFiltersDropdownContent } from './MultipleFiltersDropdownContent'; import { MultipleFiltersDropdownContent } from './MultipleFiltersDropdownContent';
import { ViewBarDropdownButton } from './ViewBarDropdownButton';
type MultipleFiltersDropdownButtonProps = { type MultipleFiltersDropdownButtonProps = {
hotkeyScope: HotkeyScope; hotkeyScope: HotkeyScope;
@@ -14,11 +15,13 @@ export const MultipleFiltersDropdownButton = ({
hotkeyScope, hotkeyScope,
}: MultipleFiltersDropdownButtonProps) => { }: MultipleFiltersDropdownButtonProps) => {
return ( return (
<ViewBarDropdownButton <DropdownScope dropdownScopeId={FilterDropdownId}>
dropdownId={FilterDropdownId} <Dropdown
buttonComponent={<MultipleFiltersButton />} clickableComponent={<MultipleFiltersButton />}
dropdownComponents={<MultipleFiltersDropdownContent />} dropdownComponents={<MultipleFiltersDropdownContent />}
dropdownHotkeyScope={hotkeyScope} dropdownHotkeyScope={hotkeyScope}
/> dropdownOffset={{ y: 8 }}
/>
</DropdownScope>
); );
}; };
@@ -1,5 +1,4 @@
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
import { useViewBarContext } from '../hooks/useViewBarContext'; import { useViewBarContext } from '../hooks/useViewBarContext';
@@ -35,36 +34,34 @@ export const MultipleFiltersDropdownContent = () => {
); );
return ( return (
<StyledDropdownMenu> <>
<> {!filterDefinitionUsedInDropdown ? (
{!filterDefinitionUsedInDropdown ? ( <FilterDropdownFilterSelect />
<FilterDropdownFilterSelect /> ) : isFilterDropdownOperandSelectUnfolded ? (
) : isFilterDropdownOperandSelectUnfolded ? ( <FilterDropdownOperandSelect />
<FilterDropdownOperandSelect /> ) : (
) : ( selectedOperandInDropdown && (
selectedOperandInDropdown && ( <>
<> <FilterDropdownOperandButton />
<FilterDropdownOperandButton /> <DropdownMenuSeparator />
<StyledDropdownMenuSeparator /> {filterDefinitionUsedInDropdown.type === 'text' && (
{filterDefinitionUsedInDropdown.type === 'text' && ( <FilterDropdownTextSearchInput />
<FilterDropdownTextSearchInput /> )}
)} {filterDefinitionUsedInDropdown.type === 'number' && (
{filterDefinitionUsedInDropdown.type === 'number' && ( <FilterDropdownNumberSearchInput />
<FilterDropdownNumberSearchInput /> )}
)} {filterDefinitionUsedInDropdown.type === 'date' && (
{filterDefinitionUsedInDropdown.type === 'date' && ( <FilterDropdownDateSearchInput />
<FilterDropdownDateSearchInput /> )}
)} {filterDefinitionUsedInDropdown.type === 'entity' && (
{filterDefinitionUsedInDropdown.type === 'entity' && ( <FilterDropdownEntitySearchInput />
<FilterDropdownEntitySearchInput /> )}
)} {filterDefinitionUsedInDropdown.type === 'entity' && (
{filterDefinitionUsedInDropdown.type === 'entity' && ( <FilterDropdownEntitySelect />
<FilterDropdownEntitySelect /> )}
)} </>
</> )
) )}
)} </>
</>
</StyledDropdownMenu>
); );
}; };
@@ -2,8 +2,7 @@ import React from 'react';
import { useTheme } from '@emotion/react'; import { useTheme } from '@emotion/react';
import { IconChevronDown } from '@/ui/display/icon/index'; import { IconChevronDown } from '@/ui/display/icon/index';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuContainer } from '@/ui/layout/dropdown/components/DropdownMenuContainer';
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton'; import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope'; import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
@@ -63,7 +62,7 @@ export const SingleEntityFilterDropdownButton = ({
return ( return (
<DropdownScope dropdownScopeId="single-entity-filter-dropdown"> <DropdownScope dropdownScopeId="single-entity-filter-dropdown">
<DropdownMenu <Dropdown
dropdownHotkeyScope={hotkeyScope} dropdownHotkeyScope={hotkeyScope}
dropdownOffset={{ x: 0, y: -28 }} dropdownOffset={{ x: 0, y: -28 }}
clickableComponent={ clickableComponent={
@@ -84,10 +83,10 @@ export const SingleEntityFilterDropdownButton = ({
</StyledHeaderDropdownButton> </StyledHeaderDropdownButton>
} }
dropdownComponents={ dropdownComponents={
<DropdownMenuContainer> <>
<FilterDropdownEntitySearchInput /> <FilterDropdownEntitySearchInput />
<FilterDropdownEntitySelect /> <FilterDropdownEntitySelect />
</DropdownMenuContainer> </>
} }
/> />
</DropdownScope> </DropdownScope>
@@ -3,11 +3,12 @@ import { produce } from 'immer';
import { IconChevronDown } from '@/ui/display/icon'; import { IconChevronDown } from '@/ui/display/icon';
import { LightButton } from '@/ui/input/button/components/LightButton'; import { LightButton } from '@/ui/input/button/components/LightButton';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader'; import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
@@ -19,8 +20,6 @@ import { sortsScopedState } from '../states/sortsScopedState';
import { SortDefinition } from '../types/SortDefinition'; import { SortDefinition } from '../types/SortDefinition';
import { SORT_DIRECTIONS, SortDirection } from '../types/SortDirection'; import { SORT_DIRECTIONS, SortDirection } from '../types/SortDirection';
import { ViewBarDropdownButton } from './ViewBarDropdownButton';
export type SortDropdownButtonProps = { export type SortDropdownButtonProps = {
hotkeyScope: HotkeyScope; hotkeyScope: HotkeyScope;
isPrimaryButton?: boolean; isPrimaryButton?: boolean;
@@ -91,56 +90,58 @@ export const SortDropdownButton = ({
}; };
return ( return (
<ViewBarDropdownButton <DropdownScope dropdownScopeId={SortDropdownId}>
dropdownId={SortDropdownId} <Dropdown
dropdownHotkeyScope={hotkeyScope} dropdownHotkeyScope={hotkeyScope}
buttonComponent={ dropdownOffset={{ y: 8 }}
<LightButton clickableComponent={
title="Sort" <LightButton
active={isSortSelected} title="Sort"
onClick={handleButtonClick} active={isSortSelected}
/> onClick={handleButtonClick}
} />
dropdownComponents={ }
<StyledDropdownMenu> dropdownComponents={
{isSortDirectionMenuUnfolded ? ( <>
<DropdownMenuItemsContainer> {isSortDirectionMenuUnfolded ? (
{SORT_DIRECTIONS.map((sortOrder, index) => (
<MenuItem
key={index}
onClick={() => {
setSelectedSortDirection(sortOrder);
setIsSortDirectionMenuUnfolded(false);
}}
text={sortOrder === 'asc' ? 'Ascending' : 'Descending'}
/>
))}
</DropdownMenuItemsContainer>
) : (
<>
<DropdownMenuHeader
EndIcon={IconChevronDown}
onClick={() => setIsSortDirectionMenuUnfolded(true)}
>
{selectedSortDirection === 'asc' ? 'Ascending' : 'Descending'}
</DropdownMenuHeader>
<StyledDropdownMenuSeparator />
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
{availableSorts.map((availableSort, index) => ( {SORT_DIRECTIONS.map((sortOrder, index) => (
<MenuItem <MenuItem
testId={`select-sort-${index}`}
key={index} key={index}
onClick={() => handleAddSort(availableSort)} onClick={() => {
LeftIcon={availableSort.Icon} setSelectedSortDirection(sortOrder);
text={availableSort.label} setIsSortDirectionMenuUnfolded(false);
}}
text={sortOrder === 'asc' ? 'Ascending' : 'Descending'}
/> />
))} ))}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</> ) : (
)} <>
</StyledDropdownMenu> <DropdownMenuHeader
} EndIcon={IconChevronDown}
onClose={handleDropdownButtonClose} onClick={() => setIsSortDirectionMenuUnfolded(true)}
></ViewBarDropdownButton> >
{selectedSortDirection === 'asc' ? 'Ascending' : 'Descending'}
</DropdownMenuHeader>
<DropdownMenuSeparator />
<DropdownMenuItemsContainer>
{availableSorts.map((availableSort, index) => (
<MenuItem
testId={`select-sort-${index}`}
key={index}
onClick={() => handleAddSort(availableSort)}
LeftIcon={availableSort.Icon}
text={availableSort.label}
/>
))}
</DropdownMenuItemsContainer>
</>
)}
</>
}
onClose={handleDropdownButtonClose}
/>
</DropdownScope>
); );
}; };
@@ -14,7 +14,6 @@ import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState';
import { IconChevronDown, IconPlus } from '@/ui/display/icon'; import { IconChevronDown, IconPlus } from '@/ui/display/icon';
import { Button } from '@/ui/input/button/components/Button'; import { Button } from '@/ui/input/button/components/Button';
import { ButtonGroup } from '@/ui/input/button/components/ButtonGroup'; import { ButtonGroup } from '@/ui/input/button/components/ButtonGroup';
import { DropdownMenuContainer } from '@/ui/layout/dropdown/components/DropdownMenuContainer';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
@@ -126,15 +125,13 @@ export const UpdateViewButtonGroup = ({
</ButtonGroup> </ButtonGroup>
{isDropdownOpen && ( {isDropdownOpen && (
<DropdownMenuContainer onClose={handleDropdownClose}> <DropdownMenuItemsContainer>
<DropdownMenuItemsContainer> <MenuItem
<MenuItem onClick={handleCreateViewButtonClick}
onClick={handleCreateViewButtonClick} LeftIcon={IconPlus}
LeftIcon={IconPlus} text="Create view"
text="Create view" />
/> </DropdownMenuItemsContainer>
</DropdownMenuItemsContainer>
</DropdownMenuContainer>
)} )}
</StyledContainer> </StyledContainer>
); );
@@ -1,49 +0,0 @@
import { Keys } from 'react-hotkeys-hook';
import { Placement } from '@floating-ui/react';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
type ViewBarDropdownButtonProps = {
buttonComponent: JSX.Element | JSX.Element[];
dropdownComponents: JSX.Element | JSX.Element[];
dropdownId: string;
hotkey?: {
key: Keys;
scope: string;
};
dropdownHotkeyScope: HotkeyScope;
dropdownPlacement?: Placement;
onClickOutside?: () => void;
onClose?: () => void;
onOpen?: () => void;
};
export const ViewBarDropdownButton = ({
buttonComponent,
dropdownComponents,
dropdownId,
hotkey,
dropdownHotkeyScope,
dropdownPlacement = 'bottom-end',
onClickOutside,
onClose,
onOpen,
}: ViewBarDropdownButtonProps) => {
return (
<DropdownScope dropdownScopeId={dropdownId}>
<DropdownMenu
clickableComponent={buttonComponent}
dropdownComponents={dropdownComponents}
hotkey={hotkey}
dropdownHotkeyScope={dropdownHotkeyScope}
dropdownOffset={{ x: 0, y: 8 }}
dropdownPlacement={dropdownPlacement}
onClickOutside={onClickOutside}
onClose={onClose}
onOpen={onOpen}
/>
</DropdownScope>
);
};
@@ -24,11 +24,12 @@ import {
IconPlus, IconPlus,
IconTrash, IconTrash,
} from '@/ui/display/icon'; } from '@/ui/display/icon';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer'; import { StyledDropdownButtonContainer } from '@/ui/layout/dropdown/components/StyledDropdownButtonContainer';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { MOBILE_VIEWPORT } from '@/ui/theme/constants/theme'; import { MOBILE_VIEWPORT } from '@/ui/theme/constants/theme';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
@@ -41,8 +42,6 @@ import { ViewsDropdownId } from '../constants/ViewsDropdownId';
import { ViewBarContext } from '../contexts/ViewBarContext'; import { ViewBarContext } from '../contexts/ViewBarContext';
import { useRemoveView } from '../hooks/useRemoveView'; import { useRemoveView } from '../hooks/useRemoveView';
import { ViewBarDropdownButton } from './ViewBarDropdownButton';
const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)` const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
font-weight: ${({ theme }) => theme.font.weight.regular}; font-weight: ${({ theme }) => theme.font.weight.regular};
`; `;
@@ -159,56 +158,57 @@ export const ViewsDropdownButton = ({
}; };
return ( return (
<ViewBarDropdownButton <DropdownScope dropdownScopeId={ViewsDropdownId}>
dropdownId={ViewsDropdownId} <Dropdown
dropdownHotkeyScope={hotkeyScope} dropdownHotkeyScope={hotkeyScope}
buttonComponent={ clickableComponent={
<StyledDropdownButtonContainer isUnfolded={isDropdownOpen}> <StyledDropdownButtonContainer isUnfolded={isDropdownOpen}>
<StyledViewIcon size={theme.icon.size.md} /> <StyledViewIcon size={theme.icon.size.md} />
<StyledViewName> <StyledViewName>
{currentView?.name || defaultViewName} {currentView?.name || defaultViewName}
</StyledViewName> </StyledViewName>
<StyledDropdownLabelAdornments> <StyledDropdownLabelAdornments>
· {entityCount} <IconChevronDown size={theme.icon.size.sm} /> · {entityCount} <IconChevronDown size={theme.icon.size.sm} />
</StyledDropdownLabelAdornments> </StyledDropdownLabelAdornments>
</StyledDropdownButtonContainer> </StyledDropdownButtonContainer>
} }
dropdownComponents={ dropdownComponents={
<StyledDropdownMenu width={200}> <>
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
{views.map((view) => ( {views.map((view) => (
<MenuItem
key={view.id}
iconButtons={[
{
Icon: IconPencil,
onClick: (event: MouseEvent<HTMLButtonElement>) =>
handleEditViewButtonClick(event, view.id),
},
views.length > 1
? {
Icon: IconTrash,
onClick: (event: MouseEvent<HTMLButtonElement>) =>
handleDeleteViewButtonClick(event, view.id),
}
: null,
].filter(assertNotNull)}
onClick={() => handleViewSelect(view.id)}
LeftIcon={IconList}
text={view.name}
/>
))}
</DropdownMenuItemsContainer>
<DropdownMenuSeparator />
<StyledBoldDropdownMenuItemsContainer>
<MenuItem <MenuItem
key={view.id} onClick={handleAddViewButtonClick}
iconButtons={[ LeftIcon={IconPlus}
{ text="Add view"
Icon: IconPencil,
onClick: (event: MouseEvent<HTMLButtonElement>) =>
handleEditViewButtonClick(event, view.id),
},
views.length > 1
? {
Icon: IconTrash,
onClick: (event: MouseEvent<HTMLButtonElement>) =>
handleDeleteViewButtonClick(event, view.id),
}
: null,
].filter(assertNotNull)}
onClick={() => handleViewSelect(view.id)}
LeftIcon={IconList}
text={view.name}
/> />
))} </StyledBoldDropdownMenuItemsContainer>
</DropdownMenuItemsContainer> </>
<StyledDropdownMenuSeparator /> }
<StyledBoldDropdownMenuItemsContainer> />
<MenuItem </DropdownScope>
onClick={handleAddViewButtonClick}
LeftIcon={IconPlus}
text="Add view"
/>
</StyledBoldDropdownMenuItemsContainer>
</StyledDropdownMenu>
}
/>
); );
}; };
@@ -2,11 +2,11 @@ import { useMemo, useState } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { IconComponent } from '@/ui/display/icon/types/IconComponent'; import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu'; import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope'; import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
@@ -73,7 +73,7 @@ export const IconPicker = ({
return ( return (
<DropdownScope dropdownScopeId="icon-picker"> <DropdownScope dropdownScopeId="icon-picker">
<DropdownMenu <Dropdown
dropdownHotkeyScope={{ scope: IconPickerHotkeyScope.IconPicker }} dropdownHotkeyScope={{ scope: IconPickerHotkeyScope.IconPicker }}
clickableComponent={ clickableComponent={
<IconButton <IconButton
@@ -83,13 +83,13 @@ export const IconPicker = ({
/> />
} }
dropdownComponents={ dropdownComponents={
<StyledDropdownMenu width={168}> <DropdownMenu width={168}>
<DropdownMenuSearchInput <DropdownMenuSearchInput
placeholder="Search icon" placeholder="Search icon"
autoFocus autoFocus
onChange={(event) => setSearchString(event.target.value)} onChange={(event) => setSearchString(event.target.value)}
/> />
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
{isLoading ? ( {isLoading ? (
<DropdownMenuSkeletonItem /> <DropdownMenuSkeletonItem />
@@ -111,7 +111,7 @@ export const IconPicker = ({
</StyledMenuIconItemsContainer> </StyledMenuIconItemsContainer>
)} )}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</StyledDropdownMenu> </DropdownMenu>
} }
onClickOutside={onClickOutside} onClickOutside={onClickOutside}
onClose={() => { onClose={() => {
@@ -119,7 +119,7 @@ export const IconPicker = ({
setSearchString(''); setSearchString('');
}} }}
onOpen={onOpen} onOpen={onOpen}
></DropdownMenu> ></Dropdown>
</DropdownScope> </DropdownScope>
); );
}; };
@@ -8,7 +8,7 @@ import { CountryCallingCode } from 'libphonenumber-js';
import { IconChevronDown } from '@/ui/display/icon'; import { IconChevronDown } from '@/ui/display/icon';
import { IconWorld } from '@/ui/input/constants/icons'; import { IconWorld } from '@/ui/input/constants/icons';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope'; import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
@@ -123,7 +123,7 @@ export const CountryPickerDropdownButton = ({
return ( return (
<DropdownScope dropdownScopeId="country-picker"> <DropdownScope dropdownScopeId="country-picker">
<DropdownMenu <Dropdown
dropdownHotkeyScope={{ scope: CountryPickerHotkeyScope.CountryPicker }} dropdownHotkeyScope={{ scope: CountryPickerHotkeyScope.CountryPicker }}
clickableComponent={ clickableComponent={
<StyledDropdownButtonContainer isUnfolded={isDropdownOpen}> <StyledDropdownButtonContainer isUnfolded={isDropdownOpen}>
@@ -1,10 +1,10 @@
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { MenuItemSelectAvatar } from '@/ui/navigation/menu-item/components/MenuItemSelectAvatar'; import { MenuItemSelectAvatar } from '@/ui/navigation/menu-item/components/MenuItemSelectAvatar';
@@ -58,13 +58,13 @@ export const CountryPickerDropdownSelect = ({
return ( return (
<> <>
<StyledDropdownMenuContainer data-select-disable> <StyledDropdownMenuContainer data-select-disable>
<StyledDropdownMenu width="240px" disableBlur> <DropdownMenu width="240px" disableBlur>
<DropdownMenuSearchInput <DropdownMenuSearchInput
value={searchFilter} value={searchFilter}
onChange={(event) => setSearchFilter(event.currentTarget.value)} onChange={(event) => setSearchFilter(event.currentTarget.value)}
autoFocus autoFocus
/> />
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItemsContainer hasMaxHeight> <DropdownMenuItemsContainer hasMaxHeight>
{filteredCountries?.length === 0 ? ( {filteredCountries?.length === 0 ? (
<MenuItem text="No result" /> <MenuItem text="No result" />
@@ -102,7 +102,7 @@ export const CountryPickerDropdownSelect = ({
</> </>
)} )}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</StyledDropdownMenu> </DropdownMenu>
</StyledDropdownMenuContainer> </StyledDropdownMenuContainer>
</> </>
); );
@@ -1,10 +1,10 @@
import { useRef } from 'react'; import { useRef } from 'react';
import debounce from 'lodash.debounce'; import debounce from 'lodash.debounce';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { MenuItemMultiSelectAvatar } from '@/ui/navigation/menu-item/components/MenuItemMultiSelectAvatar'; import { MenuItemMultiSelectAvatar } from '@/ui/navigation/menu-item/components/MenuItemMultiSelectAvatar';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
@@ -72,13 +72,13 @@ export const MultipleEntitySelect = <
}); });
return ( return (
<StyledDropdownMenu ref={containerRef} data-select-disable> <DropdownMenu ref={containerRef} data-select-disable>
<DropdownMenuSearchInput <DropdownMenuSearchInput
value={searchFilter} value={searchFilter}
onChange={handleFilterChange} onChange={handleFilterChange}
autoFocus autoFocus
/> />
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItemsContainer hasMaxHeight> <DropdownMenuItemsContainer hasMaxHeight>
{entitiesInDropdown?.map((entity) => ( {entitiesInDropdown?.map((entity) => (
<MenuItemMultiSelectAvatar <MenuItemMultiSelectAvatar
@@ -101,6 +101,6 @@ export const MultipleEntitySelect = <
))} ))}
{entitiesInDropdown?.length === 0 && <MenuItem text="No result" />} {entitiesInDropdown?.length === 0 && <MenuItem text="No result" />}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</StyledDropdownMenu> </DropdownMenu>
); );
}; };
@@ -1,8 +1,8 @@
import { useRef } from 'react'; import { useRef } from 'react';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { isDefined } from '~/utils/isDefined'; import { isDefined } from '~/utils/isDefined';
@@ -61,7 +61,7 @@ export const SingleEntitySelect = <
}); });
return ( return (
<StyledDropdownMenu <DropdownMenu
disableBlur={disableBackgroundBlur} disableBlur={disableBackgroundBlur}
ref={containerRef} ref={containerRef}
width={width} width={width}
@@ -72,7 +72,7 @@ export const SingleEntitySelect = <
onChange={handleSearchFilterChange} onChange={handleSearchFilterChange}
autoFocus autoFocus
/> />
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<SingleEntitySelectBase <SingleEntitySelectBase
{...{ {...{
EmptyIcon, EmptyIcon,
@@ -86,6 +86,6 @@ export const SingleEntitySelect = <
showCreateButton, showCreateButton,
}} }}
/> />
</StyledDropdownMenu> </DropdownMenu>
); );
}; };
@@ -4,7 +4,7 @@ import { Key } from 'ts-key-enum';
import { IconPlus } from '@/ui/display/icon'; import { IconPlus } from '@/ui/display/icon';
import { IconComponent } from '@/ui/display/icon/types/IconComponent'; import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { MenuItemSelect } from '@/ui/navigation/menu-item/components/MenuItemSelect'; import { MenuItemSelect } from '@/ui/navigation/menu-item/components/MenuItemSelect';
import { MenuItemSelectAvatar } from '@/ui/navigation/menu-item/components/MenuItemSelectAvatar'; import { MenuItemSelectAvatar } from '@/ui/navigation/menu-item/components/MenuItemSelectAvatar';
@@ -155,7 +155,7 @@ export const SingleEntitySelectBase = <
{showCreateButton && ( {showCreateButton && (
<> <>
<DropdownMenuItemsContainer hasMaxHeight> <DropdownMenuItemsContainer hasMaxHeight>
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<CreateNewButton <CreateNewButton
onClick={onCreate} onClick={onCreate}
LeftIcon={IconPlus} LeftIcon={IconPlus}
@@ -4,7 +4,7 @@ import { useRecoilState } from 'recoil';
import { IconTrash } from '@/ui/display/icon'; import { IconTrash } from '@/ui/display/icon';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { MenuItemSelectColor } from '@/ui/navigation/menu-item/components/MenuItemSelectColor'; import { MenuItemSelectColor } from '@/ui/navigation/menu-item/components/MenuItemSelectColor';
import { ThemeColor } from '@/ui/theme/constants/colors'; import { ThemeColor } from '@/ui/theme/constants/colors';
@@ -123,7 +123,7 @@ export const BoardColumnEditTitleMenu = ({
autoFocus autoFocus
/> />
</StyledEditTitleContainer> </StyledEditTitleContainer>
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
{COLUMN_COLOR_OPTIONS.map((colorOption) => ( {COLUMN_COLOR_OPTIONS.map((colorOption) => (
<MenuItemSelectColor <MenuItemSelectColor
key={colorOption.name} key={colorOption.name}
@@ -135,7 +135,7 @@ export const BoardColumnEditTitleMenu = ({
text={colorOption.name} text={colorOption.name}
/> />
))} ))}
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<MenuItem <MenuItem
onClick={handleDelete} onClick={handleDelete}
LeftIcon={IconTrash} LeftIcon={IconTrash}
@@ -15,8 +15,8 @@ import { SingleEntitySelect } from '@/ui/input/relation-picker/components/Single
import { relationPickerSearchFilterScopedState } from '@/ui/input/relation-picker/states/relationPickerSearchFilterScopedState'; import { relationPickerSearchFilterScopedState } from '@/ui/input/relation-picker/states/relationPickerSearchFilterScopedState';
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect'; import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope'; import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
@@ -138,7 +138,7 @@ export const BoardColumnMenu = ({
return ( return (
<StyledMenuContainer ref={boardColumnMenuRef}> <StyledMenuContainer ref={boardColumnMenuRef}>
<StyledDropdownMenu data-select-disable> <DropdownMenu data-select-disable>
{currentMenu === 'actions' && ( {currentMenu === 'actions' && (
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
<MenuItem <MenuItem
@@ -183,7 +183,7 @@ export const BoardColumnMenu = ({
selectedEntity={companies.selectedEntities[0]} selectedEntity={companies.selectedEntities[0]}
/> />
)} )}
</StyledDropdownMenu> </DropdownMenu>
</StyledMenuContainer> </StyledMenuContainer>
); );
}; };
@@ -1,8 +1,9 @@
import { useResetRecoilState } from 'recoil'; import { useResetRecoilState } from 'recoil';
import { ViewBarDropdownButton } from '@/ui/data/view-bar/components/ViewBarDropdownButton';
import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState'; import { viewEditModeState } from '@/ui/data/view-bar/states/viewEditModeState';
import { Dropdown } from '../../dropdown/components/Dropdown';
import { DropdownScope } from '../../dropdown/scopes/DropdownScope';
import { BoardScopeIds } from '../types/enums/BoardScopeIds'; import { BoardScopeIds } from '../types/enums/BoardScopeIds';
import { BoardOptionsDropdownButton } from './BoardOptionsDropdownButton'; import { BoardOptionsDropdownButton } from './BoardOptionsDropdownButton';
@@ -23,17 +24,18 @@ export const BoardOptionsDropdown = ({
const resetViewEditMode = useResetRecoilState(viewEditModeState); const resetViewEditMode = useResetRecoilState(viewEditModeState);
return ( return (
<ViewBarDropdownButton <DropdownScope dropdownScopeId={BoardScopeIds.OptionsDropdown}>
buttonComponent={<BoardOptionsDropdownButton />} <Dropdown
dropdownComponents={ clickableComponent={<BoardOptionsDropdownButton />}
<BoardOptionsDropdownContent dropdownComponents={
customHotkeyScope={customHotkeyScope} <BoardOptionsDropdownContent
onStageAdd={onStageAdd} customHotkeyScope={customHotkeyScope}
/> onStageAdd={onStageAdd}
} />
dropdownHotkeyScope={customHotkeyScope} }
dropdownId={BoardScopeIds.OptionsDropdown} dropdownHotkeyScope={customHotkeyScope}
onClickOutside={resetViewEditMode} onClickOutside={resetViewEditMode}
/> />
</DropdownScope>
); );
}; };
@@ -22,11 +22,9 @@ import {
} from '@/ui/display/icon'; } from '@/ui/display/icon';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader'; import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader';
import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput'; import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput';
import { DropdownMenuInputContainer } from '@/ui/layout/dropdown/components/DropdownMenuInputContainer';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { StyledDropdownMenuSeparator } from '@/ui/layout/dropdown/components/StyledDropdownMenuSeparator';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { MenuItemNavigate } from '@/ui/navigation/menu-item/components/MenuItemNavigate'; import { MenuItemNavigate } from '@/ui/navigation/menu-item/components/MenuItemNavigate';
@@ -166,28 +164,24 @@ export const BoardOptionsDropdownContent = ({
); );
return ( return (
<StyledDropdownMenu> <>
{!currentMenu && ( {!currentMenu && (
<> <>
<DropdownMenuInputContainer> <DropdownMenuInput
<DropdownMenuInput ref={viewEditInputRef}
ref={viewEditInputRef} autoFocus={viewEditMode.mode === 'create' || !!viewEditMode.viewId}
autoFocus={ placeholder={
viewEditMode.mode === 'create' || !!viewEditMode.viewId viewEditMode.mode === 'create' ? 'New view' : 'View name'
} }
placeholder={ defaultValue={
viewEditMode.mode === 'create' ? 'New view' : 'View name' viewEditMode.mode === 'create'
} ? ''
defaultValue={ : viewEditMode.viewId
viewEditMode.mode === 'create' ? viewsById[viewEditMode.viewId]?.name
? '' : currentView?.name
: viewEditMode.viewId }
? viewsById[viewEditMode.viewId]?.name />
: currentView?.name <DropdownMenuSeparator />
}
/>
</DropdownMenuInputContainer>
<StyledDropdownMenuSeparator />
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
<MenuItemNavigate <MenuItemNavigate
onClick={() => handleMenuNavigate('fields')} onClick={() => handleMenuNavigate('fields')}
@@ -207,7 +201,7 @@ export const BoardOptionsDropdownContent = ({
<DropdownMenuHeader StartIcon={IconChevronLeft} onClick={resetMenu}> <DropdownMenuHeader StartIcon={IconChevronLeft} onClick={resetMenu}>
Stages Stages
</DropdownMenuHeader> </DropdownMenuHeader>
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
<MenuItem <MenuItem
onClick={() => setCurrentMenu('stage-creation')} onClick={() => setCurrentMenu('stage-creation')}
@@ -229,7 +223,7 @@ export const BoardOptionsDropdownContent = ({
<DropdownMenuHeader StartIcon={IconChevronLeft} onClick={resetMenu}> <DropdownMenuHeader StartIcon={IconChevronLeft} onClick={resetMenu}>
Fields Fields
</DropdownMenuHeader> </DropdownMenuHeader>
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
{hasVisibleFields && ( {hasVisibleFields && (
<ViewFieldsVisibilityDropdownSection <ViewFieldsVisibilityDropdownSection
title="Visible" title="Visible"
@@ -238,9 +232,7 @@ export const BoardOptionsDropdownContent = ({
isDraggable={true} isDraggable={true}
/> />
)} )}
{hasVisibleFields && hasHiddenFields && ( {hasVisibleFields && hasHiddenFields && <DropdownMenuSeparator />}
<StyledDropdownMenuSeparator />
)}
{hasHiddenFields && ( {hasHiddenFields && (
<ViewFieldsVisibilityDropdownSection <ViewFieldsVisibilityDropdownSection
title="Hidden" title="Hidden"
@@ -251,6 +243,6 @@ export const BoardOptionsDropdownContent = ({
)} )}
</> </>
)} )}
</StyledDropdownMenu> </>
); );
}; };
@@ -0,0 +1,117 @@
import { useRef } from 'react';
import { Keys } from 'react-hotkeys-hook';
import { flip, offset, Placement, useFloating } from '@floating-ui/react';
import { Key } from 'ts-key-enum';
import { HotkeyEffect } from '@/ui/utilities/hotkey/components/HotkeyEffect';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { useDropdown } from '../hooks/useDropdown';
import { useInternalHotkeyScopeManagement } from '../hooks/useInternalHotkeyScopeManagement';
import { DropdownMenu } from './DropdownMenu';
import { DropdownToggleEffect } from './DropdownToggleEffect';
type DropdownProps = {
clickableComponent?: JSX.Element | JSX.Element[];
dropdownComponents: JSX.Element | JSX.Element[];
hotkey?: {
key: Keys;
scope: string;
};
dropdownHotkeyScope: HotkeyScope;
dropdownPlacement?: Placement;
dropdownMenuWidth?: number;
dropdownOffset?: { x?: number; y?: number };
onClickOutside?: () => void;
onClose?: () => void;
onOpen?: () => void;
};
export const Dropdown = ({
clickableComponent,
dropdownComponents,
dropdownMenuWidth = 160,
hotkey,
dropdownHotkeyScope,
dropdownPlacement = 'bottom-end',
dropdownOffset = { x: 0, y: 0 },
onClickOutside,
onClose,
onOpen,
}: DropdownProps) => {
const containerRef = useRef<HTMLDivElement>(null);
const { isDropdownOpen, toggleDropdown, closeDropdown } = useDropdown();
const offsetMiddlewares = [];
if (dropdownOffset.x) {
offsetMiddlewares.push(offset({ crossAxis: dropdownOffset.x }));
}
if (dropdownOffset.y) {
offsetMiddlewares.push(offset({ mainAxis: dropdownOffset.y }));
}
const { refs, floatingStyles } = useFloating({
placement: dropdownPlacement,
middleware: [flip(), ...offsetMiddlewares],
});
const handleHotkeyTriggered = () => {
toggleDropdown();
};
useListenClickOutside({
refs: [containerRef],
callback: () => {
onClickOutside?.();
if (isDropdownOpen) {
closeDropdown();
}
},
});
useInternalHotkeyScopeManagement({
dropdownHotkeyScopeFromParent: dropdownHotkeyScope,
});
useScopedHotkeys(
Key.Escape,
() => {
closeDropdown();
},
dropdownHotkeyScope.scope,
[closeDropdown],
);
return (
<div ref={containerRef}>
{clickableComponent && (
<div ref={refs.setReference} onClick={toggleDropdown}>
{clickableComponent}
</div>
)}
{hotkey && (
<HotkeyEffect
hotkey={hotkey}
onHotkeyTriggered={handleHotkeyTriggered}
/>
)}
{isDropdownOpen && (
<DropdownMenu
width={dropdownMenuWidth}
data-select-disable
ref={refs.setFloating}
style={floatingStyles}
>
{dropdownComponents}
</DropdownMenu>
)}
<DropdownToggleEffect onDropdownClose={onClose} onDropdownOpen={onOpen} />
</div>
);
};
@@ -1,103 +1,25 @@
import { useRef } from 'react'; import styled from '@emotion/styled';
import { Keys } from 'react-hotkeys-hook';
import { flip, offset, Placement, useFloating } from '@floating-ui/react';
import { Key } from 'ts-key-enum';
import { HotkeyEffect } from '@/ui/utilities/hotkey/components/HotkeyEffect'; const StyledDropdownMenu = styled.div<{
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; disableBlur?: boolean;
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; width?: `${string}px` | 'auto' | number;
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; }>`
backdrop-filter: ${({ disableBlur }) =>
disableBlur ? 'none' : 'blur(20px)'};
import { useDropdown } from '../hooks/useDropdown'; background: ${({ theme }) => theme.background.secondary};
import { useInternalHotkeyScopeManagement } from '../hooks/useInternalHotkeyScopeManagement'; border: 1px solid ${({ theme }) => theme.border.color.medium};
border-radius: ${({ theme }) => theme.border.radius.md};
box-shadow: ${({ theme }) => theme.boxShadow.strong};
import { DropdownToggleEffect } from './DropdownToggleEffect'; display: flex;
type DropdownMenuProps = { flex-direction: column;
clickableComponent?: JSX.Element | JSX.Element[];
dropdownComponents: JSX.Element | JSX.Element[];
hotkey?: {
key: Keys;
scope: string;
};
dropdownHotkeyScope: HotkeyScope;
dropdownPlacement?: Placement;
dropdownOffset?: { x: number; y: number };
onClickOutside?: () => void;
onClose?: () => void;
onOpen?: () => void;
};
export const DropdownMenu = ({ overflow: hidden;
clickableComponent,
dropdownComponents,
hotkey,
dropdownHotkeyScope,
dropdownPlacement = 'bottom-end',
dropdownOffset = { x: 0, y: 0 },
onClickOutside,
onClose,
onOpen,
}: DropdownMenuProps) => {
const containerRef = useRef<HTMLDivElement>(null);
const { isDropdownOpen, toggleDropdown, closeDropdown } = useDropdown(); width: ${({ width }) =>
width ? `${typeof width === 'number' ? `${width}px` : width}` : '160px'};
`;
const { refs, floatingStyles } = useFloating({ export const DropdownMenu = StyledDropdownMenu;
placement: dropdownPlacement,
middleware: [
flip(),
offset({ mainAxis: dropdownOffset.y, crossAxis: dropdownOffset.x }),
],
});
const handleHotkeyTriggered = () => {
toggleDropdown();
};
useListenClickOutside({
refs: [containerRef],
callback: () => {
onClickOutside?.();
if (isDropdownOpen) {
closeDropdown();
}
},
});
useInternalHotkeyScopeManagement({
dropdownHotkeyScopeFromParent: dropdownHotkeyScope,
});
useScopedHotkeys(
Key.Escape,
() => {
closeDropdown();
},
dropdownHotkeyScope.scope,
[closeDropdown],
);
return (
<div ref={containerRef}>
{clickableComponent && (
<div ref={refs.setReference} onClick={toggleDropdown}>
{clickableComponent}
</div>
)}
{hotkey && (
<HotkeyEffect
hotkey={hotkey}
onHotkeyTriggered={handleHotkeyTriggered}
/>
)}
{isDropdownOpen && (
<div data-select-disable ref={refs.setFloating} style={floatingStyles}>
{dropdownComponents}
</div>
)}
<DropdownToggleEffect onDropdownClose={onClose} onDropdownOpen={onOpen} />
</div>
);
};
@@ -1,47 +0,0 @@
import { HTMLAttributes, useRef } from 'react';
import styled from '@emotion/styled';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
const StyledDropdownMenuContainer = styled.ul<{
anchor: 'left' | 'right';
}>`
padding: 0;
position: absolute;
${({ anchor }) => {
if (anchor === 'right') return 'right: 0';
}};
top: 14px;
`;
export type DropdownMenuContainerProps = {
anchor?: 'left' | 'right';
children: React.ReactNode;
onClose?: () => void;
width?: `${string}px` | 'auto' | number;
} & HTMLAttributes<HTMLUListElement>;
export const DropdownMenuContainer = ({
anchor = 'right',
children,
onClose,
width,
}: DropdownMenuContainerProps) => {
const dropdownRef = useRef<HTMLDivElement>(null);
useListenClickOutside({
refs: [dropdownRef],
callback: () => {
onClose?.();
},
});
return (
<StyledDropdownMenuContainer data-select-disable anchor={anchor}>
<StyledDropdownMenu ref={dropdownRef} width={width}>
{children}
</StyledDropdownMenu>
</StyledDropdownMenuContainer>
);
};
@@ -1,9 +1,10 @@
import { forwardRef, InputHTMLAttributes } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { rgba } from '@/ui/theme/constants/colors'; import { rgba } from '@/ui/theme/constants/colors';
import { textInputStyle } from '@/ui/theme/constants/effects'; import { textInputStyle } from '@/ui/theme/constants/effects';
const StyledViewNameInput = styled.input` const StyledInput = styled.input`
${textInputStyle} ${textInputStyle}
border: 1px solid ${({ theme }) => theme.border.color.medium}; border: 1px solid ${({ theme }) => theme.border.color.medium};
@@ -20,4 +21,24 @@ const StyledViewNameInput = styled.input`
} }
`; `;
export { StyledViewNameInput as DropdownMenuInput }; const StyledInputContainer = styled.div`
box-sizing: border-box;
padding: ${({ theme }) => theme.spacing(1)};
width: 100%;
`;
export const DropdownMenuInput = forwardRef<
HTMLInputElement,
InputHTMLAttributes<HTMLInputElement>
>(({ autoFocus, defaultValue, placeholder }, ref) => {
return (
<StyledInputContainer>
<StyledInput
autoFocus={autoFocus}
defaultValue={defaultValue}
placeholder={placeholder}
ref={ref}
/>
</StyledInputContainer>
);
});
@@ -1,9 +0,0 @@
import styled from '@emotion/styled';
const StyledInputContainer = styled.div`
box-sizing: border-box;
padding: ${({ theme }) => theme.spacing(1)};
width: 100%;
`;
export { StyledInputContainer as DropdownMenuInputContainer };
@@ -1,8 +1,10 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
export const StyledDropdownMenuSeparator = styled.div` const StyledDropdownMenuSeparator = styled.div`
background-color: ${({ theme }) => theme.border.color.light}; background-color: ${({ theme }) => theme.border.color.light};
height: 1px; height: 1px;
width: 100%; width: 100%;
`; `;
export const DropdownMenuSeparator = StyledDropdownMenuSeparator;
@@ -1,23 +0,0 @@
import styled from '@emotion/styled';
export const StyledDropdownMenu = styled.div<{
disableBlur?: boolean;
width?: `${string}px` | 'auto' | number;
}>`
backdrop-filter: ${({ disableBlur }) =>
disableBlur ? 'none' : 'blur(20px)'};
background: ${({ theme }) => theme.background.secondary};
border: 1px solid ${({ theme }) => theme.border.color.medium};
border-radius: ${({ theme }) => theme.border.radius.md};
box-shadow: ${({ theme }) => theme.boxShadow.strong};
display: flex;
flex-direction: column;
overflow: hidden;
width: ${({ width }) =>
width ? `${typeof width === 'number' ? `${width}px` : width}` : '160px'};
`;
@@ -1,7 +1,8 @@
import { useState } from 'react'; import { useState } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { expect } from '@storybook/jest';
import { Decorator, Meta, StoryObj } from '@storybook/react'; import { Decorator, Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library'; import { userEvent, waitFor, within } from '@storybook/testing-library';
import { PlayFunction } from '@storybook/types'; import { PlayFunction } from '@storybook/types';
import { Button } from '@/ui/input/button/components/Button'; import { Button } from '@/ui/input/button/components/Button';
@@ -13,19 +14,17 @@ import { Avatar } from '@/users/components/Avatar';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator'; import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { DropdownScope } from '../../scopes/DropdownScope'; import { DropdownScope } from '../../scopes/DropdownScope';
import { DropdownMenu } from '../DropdownMenu'; import { Dropdown } from '../Dropdown';
import { DropdownMenuHeader } from '../DropdownMenuHeader'; import { DropdownMenuHeader } from '../DropdownMenuHeader';
import { DropdownMenuInput } from '../DropdownMenuInput'; import { DropdownMenuInput } from '../DropdownMenuInput';
import { DropdownMenuInputContainer } from '../DropdownMenuInputContainer';
import { DropdownMenuItemsContainer } from '../DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '../DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '../DropdownMenuSearchInput'; import { DropdownMenuSearchInput } from '../DropdownMenuSearchInput';
import { StyledDropdownMenu } from '../StyledDropdownMenu'; import { DropdownMenuSeparator } from '../DropdownMenuSeparator';
import { StyledDropdownMenuSeparator } from '../StyledDropdownMenuSeparator';
import { StyledDropdownMenuSubheader } from '../StyledDropdownMenuSubheader'; import { StyledDropdownMenuSubheader } from '../StyledDropdownMenuSubheader';
const meta: Meta<typeof DropdownMenu> = { const meta: Meta<typeof Dropdown> = {
title: 'UI/Layout/Dropdown/DropdownMenu', title: 'UI/Layout/Dropdown/Dropdown',
component: DropdownMenu, component: Dropdown,
decorators: [ decorators: [
ComponentDecorator, ComponentDecorator,
@@ -38,7 +37,7 @@ const meta: Meta<typeof DropdownMenu> = {
args: { args: {
clickableComponent: <Button title="Open Dropdown" />, clickableComponent: <Button title="Open Dropdown" />,
dropdownHotkeyScope: { scope: 'testDropdownMenu' }, dropdownHotkeyScope: { scope: 'testDropdownMenu' },
dropdownOffset: { x: 0, y: -8 }, dropdownOffset: { x: 0, y: 8 },
}, },
argTypes: { argTypes: {
clickableComponent: { control: false }, clickableComponent: { control: false },
@@ -49,26 +48,9 @@ const meta: Meta<typeof DropdownMenu> = {
}; };
export default meta; export default meta;
type Story = StoryObj<typeof DropdownMenu>; type Story = StoryObj<typeof Dropdown>;
const FakeContentBelow = () => ( const StyledContainer = styled.div`
<div style={{ position: 'absolute' }}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</div>
);
const avatarUrl =
'https://s3-alpha-sig.figma.com/img/bbb5/4905/f0a52cc2b9aaeb0a82a360d478dae8bf?Expires=1687132800&Signature=iVBr0BADa3LHoFVGbwqO-wxC51n1o~ZyFD-w7nyTyFP4yB-Y6zFawL-igewaFf6PrlumCyMJThDLAAc-s-Cu35SBL8BjzLQ6HymzCXbrblUADMB208PnMAvc1EEUDq8TyryFjRO~GggLBk5yR0EXzZ3zenqnDEGEoQZR~TRqS~uDF-GwQB3eX~VdnuiU2iittWJkajIDmZtpN3yWtl4H630A3opQvBnVHZjXAL5YPkdh87-a-H~6FusWvvfJxfNC2ZzbrARzXofo8dUFtH7zUXGCC~eUk~hIuLbLuz024lFQOjiWq2VKyB7dQQuGFpM-OZQEV8tSfkViP8uzDLTaCg__&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4';
const StyledFakeMenuContent = styled.div`
height: 400px;
width: 100%;
`;
const StyledFakeBelowContainer = styled.div`
height: 600px; height: 600px;
position: relative; position: relative;
@@ -77,12 +59,62 @@ const StyledFakeBelowContainer = styled.div`
const StyledMenuAbsolutePositionWrapper = styled.div` const StyledMenuAbsolutePositionWrapper = styled.div`
height: fit-content; height: fit-content;
position: absolute;
width: fit-content; width: fit-content;
`; `;
const mockSelectArray = [ const WithContentBelowDecorator: Decorator = (Story) => (
<StyledContainer>
<StyledMenuAbsolutePositionWrapper>
<Story />
</StyledMenuAbsolutePositionWrapper>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</StyledContainer>
);
const StyledEmptyDropdownContent = styled.div`
height: 400px;
width: 100%;
`;
export const Empty: Story = {
args: {
dropdownComponents: (
<StyledEmptyDropdownContent data-testid="dropdown-content" />
),
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const button = await canvas.findByRole('button');
userEvent.click(button);
await waitFor(async () => {
const fakeMenu = await canvas.findByTestId('dropdown-content');
expect(fakeMenu).toBeInTheDocument();
});
userEvent.click(button);
await waitFor(async () => {
const fakeMenu = await canvas.findByTestId('dropdown-content');
expect(fakeMenu).not.toBeInTheDocument();
});
userEvent.click(button);
await waitFor(async () => {
const fakeMenu = await canvas.findByTestId('dropdown-content');
expect(fakeMenu).toBeInTheDocument();
});
},
};
const avatarUrl =
'https://s3-alpha-sig.figma.com/img/bbb5/4905/f0a52cc2b9aaeb0a82a360d478dae8bf?Expires=1687132800&Signature=iVBr0BADa3LHoFVGbwqO-wxC51n1o~ZyFD-w7nyTyFP4yB-Y6zFawL-igewaFf6PrlumCyMJThDLAAc-s-Cu35SBL8BjzLQ6HymzCXbrblUADMB208PnMAvc1EEUDq8TyryFjRO~GggLBk5yR0EXzZ3zenqnDEGEoQZR~TRqS~uDF-GwQB3eX~VdnuiU2iittWJkajIDmZtpN3yWtl4H630A3opQvBnVHZjXAL5YPkdh87-a-H~6FusWvvfJxfNC2ZzbrARzXofo8dUFtH7zUXGCC~eUk~hIuLbLuz024lFQOjiWq2VKyB7dQQuGFpM-OZQEV8tSfkViP8uzDLTaCg__&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4';
const optionsMock = [
{ {
id: '1', id: '1',
name: 'Company A', name: 'Company A',
@@ -120,7 +152,7 @@ const FakeSelectableMenuItemList = ({ hasAvatar }: { hasAvatar?: boolean }) => {
return ( return (
<> <>
{mockSelectArray.map((item) => ( {optionsMock.map((item) => (
<MenuItemSelectAvatar <MenuItemSelectAvatar
key={item.id} key={item.id}
selected={selectedItem === item.id} selected={selectedItem === item.id}
@@ -149,7 +181,7 @@ const FakeCheckableMenuItemList = ({ hasAvatar }: { hasAvatar?: boolean }) => {
return ( return (
<> <>
{mockSelectArray.map((item) => ( {optionsMock.map((item) => (
<MenuItemMultiSelectAvatar <MenuItemMultiSelectAvatar
key={item.id} key={item.id}
selected={selectedItemsById[item.id]} selected={selectedItemsById[item.id]}
@@ -176,55 +208,40 @@ const FakeCheckableMenuItemList = ({ hasAvatar }: { hasAvatar?: boolean }) => {
); );
}; };
const WithContentBelowDecorator: Decorator = (Story) => (
<StyledFakeBelowContainer>
<FakeContentBelow />
<StyledMenuAbsolutePositionWrapper>
<Story />
</StyledMenuAbsolutePositionWrapper>
</StyledFakeBelowContainer>
);
const playInteraction: PlayFunction<any, any> = async ({ canvasElement }) => { const playInteraction: PlayFunction<any, any> = async ({ canvasElement }) => {
const canvas = within(canvasElement); const canvas = within(canvasElement);
const button = await canvas.findByRole('button'); const button = await canvas.findByRole('button');
userEvent.click(button); userEvent.click(button);
};
export const Empty: Story = { await waitFor(async () => {
args: { expect(canvas.getByText('Company A')).toBeInTheDocument();
dropdownComponents: ( });
<StyledDropdownMenu>
<StyledFakeMenuContent />
</StyledDropdownMenu>
),
},
play: playInteraction,
}; };
export const WithHeaders: Story = { export const WithHeaders: Story = {
decorators: [WithContentBelowDecorator], decorators: [WithContentBelowDecorator],
args: { args: {
dropdownComponents: ( dropdownComponents: (
<StyledDropdownMenu> <>
<DropdownMenuHeader>Header</DropdownMenuHeader> <DropdownMenuHeader>Header</DropdownMenuHeader>
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<StyledDropdownMenuSubheader>Subheader 1</StyledDropdownMenuSubheader> <StyledDropdownMenuSubheader>Subheader 1</StyledDropdownMenuSubheader>
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer hasMaxHeight>
{mockSelectArray.slice(0, 3).map(({ name }) => ( <>
<MenuItem text={name} /> {optionsMock.slice(0, 3).map(({ name }) => (
))} <MenuItem text={name} />
))}
</>
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<StyledDropdownMenuSubheader>Subheader 2</StyledDropdownMenuSubheader> <StyledDropdownMenuSubheader>Subheader 2</StyledDropdownMenuSubheader>
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
{mockSelectArray.slice(3).map(({ name }) => ( {optionsMock.slice(3).map(({ name }) => (
<MenuItem text={name} /> <MenuItem text={name} />
))} ))}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</StyledDropdownMenu> </>
), ),
}, },
play: playInteraction, play: playInteraction,
@@ -234,33 +251,45 @@ export const SearchWithLoadingMenu: Story = {
decorators: [WithContentBelowDecorator], decorators: [WithContentBelowDecorator],
args: { args: {
dropdownComponents: ( dropdownComponents: (
<StyledDropdownMenu> <>
<DropdownMenuSearchInput value="query" autoFocus /> <DropdownMenuSearchInput value="query" autoFocus />
<StyledDropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItemsContainer hasMaxHeight> <DropdownMenuItemsContainer hasMaxHeight>
<DropdownMenuSkeletonItem /> <DropdownMenuSkeletonItem />
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</StyledDropdownMenu> </>
), ),
}, },
play: playInteraction, play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const button = await canvas.findByRole('button');
await waitFor(() => {
userEvent.click(button);
expect(canvas.getByDisplayValue('query')).toBeInTheDocument();
});
await waitFor(() => {
userEvent.click(button);
expect(canvas.queryByDisplayValue('query')).not.toBeInTheDocument();
});
},
}; };
export const WithInput: Story = { export const WithInput: Story = {
decorators: [WithContentBelowDecorator], decorators: [WithContentBelowDecorator],
args: { args: {
dropdownComponents: ( dropdownComponents: (
<StyledDropdownMenu> <>
<DropdownMenuInputContainer> <DropdownMenuInput defaultValue="Lorem ipsum" autoFocus />
<DropdownMenuInput defaultValue="Lorem ipsum" autoFocus /> <DropdownMenuSeparator />
</DropdownMenuInputContainer>
<StyledDropdownMenuSeparator />
<DropdownMenuItemsContainer hasMaxHeight> <DropdownMenuItemsContainer hasMaxHeight>
{mockSelectArray.map(({ name }) => ( {optionsMock.map(({ name }) => (
<MenuItem text={name} /> <MenuItem text={name} />
))} ))}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</StyledDropdownMenu> </>
), ),
}, },
play: playInteraction, play: playInteraction,
@@ -270,11 +299,9 @@ export const SelectableMenuItemWithAvatar: Story = {
decorators: [WithContentBelowDecorator], decorators: [WithContentBelowDecorator],
args: { args: {
dropdownComponents: ( dropdownComponents: (
<StyledDropdownMenu> <DropdownMenuItemsContainer hasMaxHeight>
<DropdownMenuItemsContainer hasMaxHeight> <FakeSelectableMenuItemList hasAvatar />
<FakeSelectableMenuItemList hasAvatar /> </DropdownMenuItemsContainer>
</DropdownMenuItemsContainer>
</StyledDropdownMenu>
), ),
}, },
play: playInteraction, play: playInteraction,
@@ -284,11 +311,9 @@ export const CheckableMenuItemWithAvatar: Story = {
decorators: [WithContentBelowDecorator], decorators: [WithContentBelowDecorator],
args: { args: {
dropdownComponents: ( dropdownComponents: (
<StyledDropdownMenu> <DropdownMenuItemsContainer hasMaxHeight>
<DropdownMenuItemsContainer hasMaxHeight> <FakeCheckableMenuItemList hasAvatar />
<FakeCheckableMenuItemList hasAvatar /> </DropdownMenuItemsContainer>
</DropdownMenuItemsContainer>
</StyledDropdownMenu>
), ),
}, },
play: playInteraction, play: playInteraction,
@@ -9,10 +9,6 @@ const meta: Meta<typeof DropdownMenuInput> = {
component: DropdownMenuInput, component: DropdownMenuInput,
decorators: [ComponentDecorator], decorators: [ComponentDecorator],
args: { defaultValue: 'Lorem ipsum' }, args: { defaultValue: 'Lorem ipsum' },
argTypes: {
as: { table: { disable: true } },
theme: { table: { disable: true } },
},
}; };
export default meta; export default meta;
@@ -3,15 +3,17 @@ import styled from '@emotion/styled';
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer'; import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity'; import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity';
import { PageHotkeyScope } from '@/types/PageHotkeyScope'; import { PageHotkeyScope } from '@/types/PageHotkeyScope';
import { ViewBarDropdownButton } from '@/ui/data/view-bar/components/ViewBarDropdownButton';
import { IconCheckbox, IconNotes, IconPlus } from '@/ui/display/icon/index'; import { IconCheckbox, IconNotes, IconPlus } from '@/ui/display/icon/index';
import { IconButton } from '@/ui/input/button/components/IconButton'; import { IconButton } from '@/ui/input/button/components/IconButton';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { ActivityType } from '~/generated/graphql'; import { ActivityType } from '~/generated/graphql';
import { Dropdown } from '../../dropdown/components/Dropdown';
import { DropdownMenu } from '../../dropdown/components/DropdownMenu';
import { DropdownScope } from '../../dropdown/scopes/DropdownScope';
const StyledContainer = styled.div` const StyledContainer = styled.div`
z-index: 1; z-index: 1;
`; `;
@@ -33,40 +35,41 @@ export const ShowPageAddButton = ({
return ( return (
<StyledContainer> <StyledContainer>
<ViewBarDropdownButton <DropdownScope dropdownScopeId="add-show-page">
dropdownId="add-show-page" <Dropdown
buttonComponent={ clickableComponent={
<IconButton <IconButton
Icon={IconPlus} Icon={IconPlus}
size="medium" size="medium"
dataTestId="add-showpage-button" dataTestId="add-showpage-button"
accent="default" accent="default"
variant="secondary" variant="secondary"
onClick={toggleDropdown} onClick={toggleDropdown}
/> />
} }
dropdownComponents={ dropdownComponents={
<StyledDropdownMenu> <DropdownMenu>
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
<MenuItem <MenuItem
onClick={() => handleSelect(ActivityType.Note)} onClick={() => handleSelect(ActivityType.Note)}
accent="default" accent="default"
LeftIcon={IconNotes} LeftIcon={IconNotes}
text="Note" text="Note"
/> />
<MenuItem <MenuItem
onClick={() => handleSelect(ActivityType.Task)} onClick={() => handleSelect(ActivityType.Task)}
accent="default" accent="default"
LeftIcon={IconCheckbox} LeftIcon={IconCheckbox}
text="Task" text="Task"
/> />
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</StyledDropdownMenu> </DropdownMenu>
} }
dropdownHotkeyScope={{ dropdownHotkeyScope={{
scope: PageHotkeyScope.ShowPage, scope: PageHotkeyScope.ShowPage,
}} }}
/> />
</DropdownScope>
</StyledContainer> </StyledContainer>
); );
}; };
@@ -2,8 +2,8 @@ import React, { useRef } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useRecoilValue, useSetRecoilState } from 'recoil'; import { useRecoilValue, useSetRecoilState } from 'recoil';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { StyledDropdownMenu } from '@/ui/layout/dropdown/components/StyledDropdownMenu';
import { actionBarOpenState } from '@/ui/navigation/action-bar/states/actionBarIsOpenState'; import { actionBarOpenState } from '@/ui/navigation/action-bar/states/actionBarIsOpenState';
import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState'; import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
@@ -73,7 +73,7 @@ export const ContextMenu = ({ selectedIds }: ContextMenuProps) => {
ref={wrapperRef} ref={wrapperRef}
position={contextMenuPosition} position={contextMenuPosition}
> >
<StyledDropdownMenu data-select-disable width={width}> <DropdownMenu data-select-disable width={width}>
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
{contextMenuEntries.map((item) => ( {contextMenuEntries.map((item) => (
<ContextMenuItem <ContextMenuItem
@@ -85,7 +85,7 @@ export const ContextMenu = ({ selectedIds }: ContextMenuProps) => {
/> />
))} ))}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</StyledDropdownMenu> </DropdownMenu>
</StyledContainerContextMenu> </StyledContainerContextMenu>
); );
}; };