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 22:19:43 +03:00
committed by GitHub
parent eea7470571
commit dee9807eb3
41 changed files with 634 additions and 674 deletions

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>

View File

@ -181,4 +181,4 @@
"msw": { "msw": {
"workerDirectory": "public" "workerDirectory": "public"
} }
} }

View File

@ -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>
); );
}; };

View File

@ -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>
)} )}

View File

@ -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>
); );
}; };

View File

@ -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',

View File

@ -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,
)} )}

View File

@ -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

View File

@ -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>
); );
}; };

View File

@ -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};
`; `;

View File

@ -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>
); );
}; };

View File

@ -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> </>
); );
}; };

View File

@ -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>

View File

@ -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>
); );
}; };

View File

@ -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>
); );
}; };

View File

@ -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>

View File

@ -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>
); );
}; };

View File

@ -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>
); );

View File

@ -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>
);
};

View File

@ -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>
}
/>
); );
}; };

View File

@ -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>
); );
}; };

View File

@ -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}>

View File

@ -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>
</> </>
); );

View File

@ -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>
); );
}; };

View File

@ -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>
); );
}; };

View File

@ -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}

View File

@ -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}

View File

@ -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>
); );
}; };

View File

@ -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>
); );
}; };

View File

@ -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> </>
); );
}; };

View File

@ -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>
);
};

View File

@ -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>
);
};

View File

@ -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>
);
};

View File

@ -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>
);
});

View File

@ -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 };

View File

@ -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;

View File

@ -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'};
`;

View File

@ -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,

View File

@ -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;

View File

@ -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>
); );
}; };

View File

@ -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>
); );
}; };