Migrate dropdown to scope map (#3338)
* Migrate dropdown to scope map * Run lintr * Move Dropdown Scope internally * Fix * Fix lint --------- Co-authored-by: Thomas Trompette <thomast@twenty.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -11,7 +11,6 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
@ -23,7 +22,7 @@ import { IconPickerHotkeyScope } from '../types/IconPickerHotkeyScope';
|
||||
|
||||
type IconPickerProps = {
|
||||
disabled?: boolean;
|
||||
dropdownScopeId?: string;
|
||||
dropdownId?: string;
|
||||
onChange: (params: { iconKey: string; Icon: IconComponent }) => void;
|
||||
selectedIconKey?: string;
|
||||
onClickOutside?: () => void;
|
||||
@ -80,7 +79,7 @@ const IconPickerIcon = ({
|
||||
|
||||
export const IconPicker = ({
|
||||
disabled,
|
||||
dropdownScopeId = 'icon-picker',
|
||||
dropdownId = 'icon-picker',
|
||||
onChange,
|
||||
selectedIconKey,
|
||||
onClickOutside,
|
||||
@ -95,7 +94,7 @@ export const IconPicker = ({
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
|
||||
const { closeDropdown } = useDropdown(dropdownScopeId);
|
||||
const { closeDropdown } = useDropdown(dropdownId);
|
||||
|
||||
const { getIcons, getIcon } = useIcons();
|
||||
const icons = getIcons();
|
||||
@ -126,71 +125,70 @@ export const IconPicker = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<DropdownScope dropdownScopeId={dropdownScopeId}>
|
||||
<div className={className}>
|
||||
<Dropdown
|
||||
dropdownHotkeyScope={{ scope: IconPickerHotkeyScope.IconPicker }}
|
||||
clickableComponent={
|
||||
<IconButton
|
||||
disabled={disabled}
|
||||
Icon={selectedIconKey ? getIcon(selectedIconKey) : IconApps}
|
||||
variant={variant}
|
||||
/>
|
||||
}
|
||||
dropdownMenuWidth={176}
|
||||
dropdownComponents={
|
||||
<SelectableList
|
||||
selectableListId="icon-list"
|
||||
selectableItemIdMatrix={iconKeys2d}
|
||||
hotkeyScope={IconPickerHotkeyScope.IconPicker}
|
||||
onEnter={(iconKey) => {
|
||||
onChange({ iconKey, Icon: getIcon(iconKey) });
|
||||
closeDropdown();
|
||||
}}
|
||||
>
|
||||
<DropdownMenu width={176}>
|
||||
<DropdownMenuSearchInput
|
||||
placeholder="Search icon"
|
||||
autoFocus
|
||||
onChange={(event) => setSearchString(event.target.value)}
|
||||
/>
|
||||
<DropdownMenuSeparator />
|
||||
<div
|
||||
onMouseEnter={() => {
|
||||
setHotkeyScopeAndMemorizePreviousScope(
|
||||
IconPickerHotkeyScope.IconPicker,
|
||||
);
|
||||
}}
|
||||
onMouseLeave={goBackToPreviousHotkeyScope}
|
||||
>
|
||||
<DropdownMenuItemsContainer>
|
||||
<StyledMenuIconItemsContainer>
|
||||
{iconKeys.map((iconKey) => (
|
||||
<IconPickerIcon
|
||||
key={iconKey}
|
||||
iconKey={iconKey}
|
||||
onClick={() => {
|
||||
onChange({ iconKey, Icon: getIcon(iconKey) });
|
||||
closeDropdown();
|
||||
}}
|
||||
selectedIconKey={selectedIconKey}
|
||||
Icon={getIcon(iconKey)}
|
||||
/>
|
||||
))}
|
||||
</StyledMenuIconItemsContainer>
|
||||
</DropdownMenuItemsContainer>
|
||||
</div>
|
||||
</DropdownMenu>
|
||||
</SelectableList>
|
||||
}
|
||||
onClickOutside={onClickOutside}
|
||||
onClose={() => {
|
||||
onClose?.();
|
||||
setSearchString('');
|
||||
}}
|
||||
onOpen={onOpen}
|
||||
/>
|
||||
</div>
|
||||
</DropdownScope>
|
||||
<div className={className}>
|
||||
<Dropdown
|
||||
dropdownId={dropdownId}
|
||||
dropdownHotkeyScope={{ scope: IconPickerHotkeyScope.IconPicker }}
|
||||
clickableComponent={
|
||||
<IconButton
|
||||
disabled={disabled}
|
||||
Icon={selectedIconKey ? getIcon(selectedIconKey) : IconApps}
|
||||
variant={variant}
|
||||
/>
|
||||
}
|
||||
dropdownMenuWidth={176}
|
||||
dropdownComponents={
|
||||
<SelectableList
|
||||
selectableListId="icon-list"
|
||||
selectableItemIdMatrix={iconKeys2d}
|
||||
hotkeyScope={IconPickerHotkeyScope.IconPicker}
|
||||
onEnter={(iconKey) => {
|
||||
onChange({ iconKey, Icon: getIcon(iconKey) });
|
||||
closeDropdown();
|
||||
}}
|
||||
>
|
||||
<DropdownMenu width={176}>
|
||||
<DropdownMenuSearchInput
|
||||
placeholder="Search icon"
|
||||
autoFocus
|
||||
onChange={(event) => setSearchString(event.target.value)}
|
||||
/>
|
||||
<DropdownMenuSeparator />
|
||||
<div
|
||||
onMouseEnter={() => {
|
||||
setHotkeyScopeAndMemorizePreviousScope(
|
||||
IconPickerHotkeyScope.IconPicker,
|
||||
);
|
||||
}}
|
||||
onMouseLeave={goBackToPreviousHotkeyScope}
|
||||
>
|
||||
<DropdownMenuItemsContainer>
|
||||
<StyledMenuIconItemsContainer>
|
||||
{iconKeys.map((iconKey) => (
|
||||
<IconPickerIcon
|
||||
key={iconKey}
|
||||
iconKey={iconKey}
|
||||
onClick={() => {
|
||||
onChange({ iconKey, Icon: getIcon(iconKey) });
|
||||
closeDropdown();
|
||||
}}
|
||||
selectedIconKey={selectedIconKey}
|
||||
Icon={getIcon(iconKey)}
|
||||
/>
|
||||
))}
|
||||
</StyledMenuIconItemsContainer>
|
||||
</DropdownMenuItemsContainer>
|
||||
</div>
|
||||
</DropdownMenu>
|
||||
</SelectableList>
|
||||
}
|
||||
onClickOutside={onClickOutside}
|
||||
onClose={() => {
|
||||
onClose?.();
|
||||
setSearchString('');
|
||||
}}
|
||||
onOpen={onOpen}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -6,7 +6,6 @@ import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
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 { SelectHotkeyScope } from '../types/SelectHotkeyScope';
|
||||
@ -98,31 +97,30 @@ export const Select = <Value extends string | number | null>({
|
||||
{selectControl}
|
||||
</div>
|
||||
) : (
|
||||
<DropdownScope dropdownScopeId={dropdownScopeId}>
|
||||
<div className={className}>
|
||||
{!!label && <StyledLabel>{label}</StyledLabel>}
|
||||
<Dropdown
|
||||
dropdownMenuWidth={176}
|
||||
dropdownPlacement="bottom-start"
|
||||
clickableComponent={selectControl}
|
||||
dropdownComponents={
|
||||
<DropdownMenuItemsContainer>
|
||||
{options.map((option) => (
|
||||
<MenuItem
|
||||
key={option.value}
|
||||
LeftIcon={option.Icon}
|
||||
text={option.label}
|
||||
onClick={() => {
|
||||
onChange?.(option.value);
|
||||
closeDropdown();
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }}
|
||||
/>
|
||||
</div>
|
||||
</DropdownScope>
|
||||
<div className={className}>
|
||||
{!!label && <StyledLabel>{label}</StyledLabel>}
|
||||
<Dropdown
|
||||
dropdownId="select"
|
||||
dropdownMenuWidth={176}
|
||||
dropdownPlacement="bottom-start"
|
||||
clickableComponent={selectControl}
|
||||
dropdownComponents={
|
||||
<DropdownMenuItemsContainer>
|
||||
{options.map((option) => (
|
||||
<MenuItem
|
||||
key={option.value}
|
||||
LeftIcon={option.Icon}
|
||||
text={option.label}
|
||||
onClick={() => {
|
||||
onChange?.(option.value);
|
||||
closeDropdown();
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
}
|
||||
dropdownHotkeyScope={{ scope: SelectHotkeyScope.Select }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -9,7 +9,6 @@ import { CountryCallingCode } from 'libphonenumber-js';
|
||||
import { IconChevronDown, IconWorld } from '@/ui/display/icon';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
|
||||
import { CountryPickerHotkeyScope } from '../types/CountryPickerHotkeyScope';
|
||||
|
||||
@ -119,27 +118,26 @@ export const CountryPickerDropdownButton = ({
|
||||
}, [countries, value]);
|
||||
|
||||
return (
|
||||
<DropdownScope dropdownScopeId="country-picker">
|
||||
<Dropdown
|
||||
dropdownHotkeyScope={{ scope: CountryPickerHotkeyScope.CountryPicker }}
|
||||
clickableComponent={
|
||||
<StyledDropdownButtonContainer isUnfolded={isDropdownOpen}>
|
||||
<StyledIconContainer>
|
||||
{selectedCountry ? <selectedCountry.Flag /> : <IconWorld />}
|
||||
<IconChevronDown size={theme.icon.size.sm} />
|
||||
</StyledIconContainer>
|
||||
</StyledDropdownButtonContainer>
|
||||
}
|
||||
dropdownComponents={
|
||||
<CountryPickerDropdownSelect
|
||||
countries={countries}
|
||||
selectedCountry={selectedCountry}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
}
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownOffset={{ x: 0, y: 4 }}
|
||||
/>
|
||||
</DropdownScope>
|
||||
<Dropdown
|
||||
dropdownId="country-picker-dropdown-id"
|
||||
dropdownHotkeyScope={{ scope: CountryPickerHotkeyScope.CountryPicker }}
|
||||
clickableComponent={
|
||||
<StyledDropdownButtonContainer isUnfolded={isDropdownOpen}>
|
||||
<StyledIconContainer>
|
||||
{selectedCountry ? <selectedCountry.Flag /> : <IconWorld />}
|
||||
<IconChevronDown size={theme.icon.size.sm} />
|
||||
</StyledIconContainer>
|
||||
</StyledDropdownButtonContainer>
|
||||
}
|
||||
dropdownComponents={
|
||||
<CountryPickerDropdownSelect
|
||||
countries={countries}
|
||||
selectedCountry={selectedCountry}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
}
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownOffset={{ x: 0, y: 4 }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -9,6 +9,7 @@ import {
|
||||
} from '@floating-ui/react';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
import { HotkeyEffect } from '@/ui/utilities/hotkey/components/HotkeyEffect';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
@ -29,6 +30,7 @@ type DropdownProps = {
|
||||
scope: string;
|
||||
};
|
||||
dropdownHotkeyScope: HotkeyScope;
|
||||
dropdownId: string;
|
||||
dropdownPlacement?: Placement;
|
||||
dropdownMenuWidth?: number;
|
||||
dropdownOffset?: { x?: number; y?: number };
|
||||
@ -43,6 +45,7 @@ export const Dropdown = ({
|
||||
dropdownComponents,
|
||||
dropdownMenuWidth,
|
||||
hotkey,
|
||||
dropdownId,
|
||||
dropdownHotkeyScope,
|
||||
dropdownPlacement = 'bottom-end',
|
||||
dropdownOffset = { x: 0, y: 0 },
|
||||
@ -53,8 +56,7 @@ export const Dropdown = ({
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { isDropdownOpen, toggleDropdown, closeDropdown, dropdownWidth } =
|
||||
useDropdown();
|
||||
|
||||
useDropdown(dropdownId);
|
||||
const offsetMiddlewares = [];
|
||||
|
||||
if (dropdownOffset.x) {
|
||||
@ -87,6 +89,7 @@ export const Dropdown = ({
|
||||
});
|
||||
|
||||
useInternalHotkeyScopeManagement({
|
||||
dropdownScopeId: `${dropdownId}-scope`,
|
||||
dropdownHotkeyScopeFromParent: dropdownHotkeyScope,
|
||||
});
|
||||
|
||||
@ -100,36 +103,38 @@ export const Dropdown = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className={className}>
|
||||
{clickableComponent && (
|
||||
<div
|
||||
ref={refs.setReference}
|
||||
onClick={toggleDropdown}
|
||||
className={className}
|
||||
>
|
||||
{clickableComponent}
|
||||
</div>
|
||||
)}
|
||||
{hotkey && (
|
||||
<HotkeyEffect
|
||||
hotkey={hotkey}
|
||||
onHotkeyTriggered={handleHotkeyTriggered}
|
||||
<DropdownScope dropdownScopeId={`${dropdownId}-scope`}>
|
||||
<div ref={containerRef} className={className}>
|
||||
{clickableComponent && (
|
||||
<div
|
||||
ref={refs.setReference}
|
||||
onClick={toggleDropdown}
|
||||
className={className}
|
||||
>
|
||||
{clickableComponent}
|
||||
</div>
|
||||
)}
|
||||
{hotkey && (
|
||||
<HotkeyEffect
|
||||
hotkey={hotkey}
|
||||
onHotkeyTriggered={handleHotkeyTriggered}
|
||||
/>
|
||||
)}
|
||||
{isDropdownOpen && (
|
||||
<DropdownMenu
|
||||
width={dropdownMenuWidth ?? dropdownWidth}
|
||||
data-select-disable
|
||||
ref={refs.setFloating}
|
||||
style={floatingStyles}
|
||||
>
|
||||
{dropdownComponents}
|
||||
</DropdownMenu>
|
||||
)}
|
||||
<DropdownOnToggleEffect
|
||||
onDropdownClose={onClose}
|
||||
onDropdownOpen={onOpen}
|
||||
/>
|
||||
)}
|
||||
{isDropdownOpen && (
|
||||
<DropdownMenu
|
||||
width={dropdownMenuWidth ?? dropdownWidth}
|
||||
data-select-disable
|
||||
ref={refs.setFloating}
|
||||
style={floatingStyles}
|
||||
>
|
||||
{dropdownComponents}
|
||||
</DropdownMenu>
|
||||
)}
|
||||
<DropdownOnToggleEffect
|
||||
onDropdownClose={onClose}
|
||||
onDropdownOpen={onOpen}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DropdownScope>
|
||||
);
|
||||
};
|
||||
|
||||
@ -12,7 +12,6 @@ import { MenuItemSelectAvatar } from '@/ui/navigation/menu-item/components/MenuI
|
||||
import { Avatar } from '@/users/components/Avatar';
|
||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||
|
||||
import { DropdownScope } from '../../scopes/DropdownScope';
|
||||
import { Dropdown } from '../Dropdown';
|
||||
import { DropdownMenuHeader } from '../DropdownMenuHeader';
|
||||
import { DropdownMenuInput } from '../DropdownMenuInput';
|
||||
@ -25,18 +24,12 @@ const meta: Meta<typeof Dropdown> = {
|
||||
title: 'UI/Layout/Dropdown/Dropdown',
|
||||
component: Dropdown,
|
||||
|
||||
decorators: [
|
||||
ComponentDecorator,
|
||||
(Story) => (
|
||||
<DropdownScope dropdownScopeId="testDropdownMenu">
|
||||
<Story />
|
||||
</DropdownScope>
|
||||
),
|
||||
],
|
||||
decorators: [ComponentDecorator, (Story) => <Story />],
|
||||
args: {
|
||||
clickableComponent: <Button title="Open Dropdown" />,
|
||||
dropdownHotkeyScope: { scope: 'testDropdownMenu' },
|
||||
dropdownOffset: { x: 0, y: 8 },
|
||||
dropdownId: 'test-dropdown-id',
|
||||
},
|
||||
argTypes: {
|
||||
clickableComponent: { control: false },
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
import { DropdownScopeInternalContext } from '@/ui/layout/dropdown/scopes/scope-internal-context/DropdownScopeInternalContext';
|
||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||
import { useScopedState } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useScopedState';
|
||||
|
||||
type UseDropdownScopedStatesProps = {
|
||||
dropdownScopeId?: string;
|
||||
};
|
||||
|
||||
export const useDropdownScopedStates = ({
|
||||
dropdownScopeId,
|
||||
}: UseDropdownScopedStatesProps) => {
|
||||
const scopeId = useAvailableScopeIdOrThrow(
|
||||
DropdownScopeInternalContext,
|
||||
dropdownScopeId,
|
||||
);
|
||||
|
||||
const {
|
||||
getScopedState,
|
||||
getScopedFamilyState,
|
||||
getScopedSnapshotValue,
|
||||
getScopedFamilySnapshotValue,
|
||||
} = useScopedState(scopeId);
|
||||
|
||||
return {
|
||||
scopeId,
|
||||
injectStateWithDropdownScopeId: getScopedState,
|
||||
injectFamilyStateWithDropdownScopeId: getScopedFamilyState,
|
||||
injectSnapshotValueWithDropdownScopeId: getScopedSnapshotValue,
|
||||
injectFamilySnapshotValueWithDropdownScopeId: getScopedFamilySnapshotValue,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,26 @@
|
||||
import { DropdownScopeInternalContext } from '@/ui/layout/dropdown/scopes/scope-internal-context/DropdownScopeInternalContext';
|
||||
import { dropdownHotkeyStateScopeMap } from '@/ui/layout/dropdown/states/dropdownHotkeyStateScopeMap';
|
||||
import { dropdownWidthStateScopeMap } from '@/ui/layout/dropdown/states/dropdownWidthStateScopeMap';
|
||||
import { isDropdownOpenStateScopeMap } from '@/ui/layout/dropdown/states/isDropdownOpenStateScopeMap';
|
||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||
import { getState } from '@/ui/utilities/recoil-scope/utils/getState';
|
||||
|
||||
type UseDropdownStatesProps = {
|
||||
dropdownScopeId?: string;
|
||||
};
|
||||
|
||||
export const useDropdownStates = ({
|
||||
dropdownScopeId,
|
||||
}: UseDropdownStatesProps) => {
|
||||
const scopeId = useAvailableScopeIdOrThrow(
|
||||
DropdownScopeInternalContext,
|
||||
dropdownScopeId,
|
||||
);
|
||||
|
||||
return {
|
||||
scopeId,
|
||||
dropdownHotkeyScopeState: getState(dropdownHotkeyStateScopeMap, scopeId),
|
||||
dropdownWidthState: getState(dropdownWidthStateScopeMap, scopeId),
|
||||
isDropdownOpenState: getState(isDropdownOpenStateScopeMap, scopeId),
|
||||
};
|
||||
};
|
||||
@ -1,36 +1,29 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useDropdownScopedStates } from '@/ui/layout/dropdown/hooks/internal/useDropdownScopedStates';
|
||||
import { getDropdownScopeInjectors } from '@/ui/layout/dropdown/utils/internal/getDropdownScopeInjectors';
|
||||
import { useDropdownStates } from '@/ui/layout/dropdown/hooks/internal/useDropdownStates';
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
|
||||
export const useDropdown = (dropdownId?: string) => {
|
||||
const { injectStateWithDropdownScopeId, scopeId } = useDropdownScopedStates({
|
||||
dropdownScopeId: dropdownId,
|
||||
});
|
||||
|
||||
const {
|
||||
dropdownHotkeyScopeScopeInjector,
|
||||
dropdownWidthScopeInjector,
|
||||
isDropdownOpenScopeInjector,
|
||||
} = getDropdownScopeInjectors();
|
||||
scopeId,
|
||||
dropdownHotkeyScopeState,
|
||||
dropdownWidthState,
|
||||
isDropdownOpenState,
|
||||
} = useDropdownStates({
|
||||
dropdownScopeId: `${dropdownId}-scope`,
|
||||
});
|
||||
|
||||
const {
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeyScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
|
||||
const [dropdownHotkeyScope, setDropdownHotkeyScope] = useRecoilState(
|
||||
injectStateWithDropdownScopeId(dropdownHotkeyScopeScopeInjector),
|
||||
);
|
||||
const [dropdownHotkeyScope] = useRecoilState(dropdownHotkeyScopeState);
|
||||
|
||||
const [dropdownWidth, setDropdownWidth] = useRecoilState(
|
||||
injectStateWithDropdownScopeId(dropdownWidthScopeInjector),
|
||||
);
|
||||
const [dropdownWidth, setDropdownWidth] = useRecoilState(dropdownWidthState);
|
||||
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useRecoilState(
|
||||
injectStateWithDropdownScopeId(isDropdownOpenScopeInjector),
|
||||
);
|
||||
const [isDropdownOpen, setIsDropdownOpen] =
|
||||
useRecoilState(isDropdownOpenState);
|
||||
|
||||
const closeDropdown = () => {
|
||||
goBackToPreviousHotkeyScope();
|
||||
@ -61,8 +54,6 @@ export const useDropdown = (dropdownId?: string) => {
|
||||
closeDropdown,
|
||||
toggleDropdown,
|
||||
openDropdown,
|
||||
dropdownHotkeyScope,
|
||||
setDropdownHotkeyScope,
|
||||
dropdownWidth,
|
||||
setDropdownWidth,
|
||||
};
|
||||
|
||||
@ -1,16 +1,22 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useDropdownStates } from '@/ui/layout/dropdown/hooks/internal/useDropdownStates';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
import { useDropdown } from './useDropdown';
|
||||
|
||||
export const useInternalHotkeyScopeManagement = ({
|
||||
dropdownScopeId,
|
||||
dropdownHotkeyScopeFromParent,
|
||||
}: {
|
||||
dropdownScopeId: string;
|
||||
dropdownHotkeyScopeFromParent?: HotkeyScope;
|
||||
}) => {
|
||||
const { dropdownHotkeyScope, setDropdownHotkeyScope } = useDropdown();
|
||||
const { dropdownHotkeyScopeState } = useDropdownStates({ dropdownScopeId });
|
||||
|
||||
const [dropdownHotkeyScope, setDropdownHotkeyScope] = useRecoilState(
|
||||
dropdownHotkeyScopeState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDeeplyEqual(dropdownHotkeyScopeFromParent, dropdownHotkeyScope)) {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
|
||||
|
||||
export const dropdownHotkeyScopeScopedState = createStateScopeMap<
|
||||
export const dropdownHotkeyStateScopeMap = createStateScopeMap<
|
||||
HotkeyScope | null | undefined
|
||||
>({
|
||||
key: 'dropdownHotkeyScopeScopedState',
|
||||
key: 'dropdownHotkeyStateScopeMap',
|
||||
defaultValue: null,
|
||||
});
|
||||
@ -1,8 +0,0 @@
|
||||
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
|
||||
|
||||
export const dropdownWidthScopedState = createStateScopeMap<number | undefined>(
|
||||
{
|
||||
key: 'dropdownWidthScopedState',
|
||||
defaultValue: 160,
|
||||
},
|
||||
);
|
||||
@ -0,0 +1,8 @@
|
||||
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
|
||||
|
||||
export const dropdownWidthStateScopeMap = createStateScopeMap<
|
||||
number | undefined
|
||||
>({
|
||||
key: 'dropdownWidthStateScopeMap',
|
||||
defaultValue: 160,
|
||||
});
|
||||
@ -1,6 +1,6 @@
|
||||
import { createStateScopeMap } from '@/ui/utilities/recoil-scope/utils/createStateScopeMap';
|
||||
|
||||
export const isDropdownOpenScopedState = createStateScopeMap<boolean>({
|
||||
key: 'isDropdownOpenScopedState',
|
||||
export const isDropdownOpenStateScopeMap = createStateScopeMap<boolean>({
|
||||
key: 'isDropdownOpenStateScopeMap',
|
||||
defaultValue: false,
|
||||
});
|
||||
@ -1,22 +0,0 @@
|
||||
import { dropdownHotkeyScopeScopedState } from '@/ui/layout/dropdown/states/dropdownHotkeyScopeScopedState';
|
||||
import { dropdownWidthScopedState } from '@/ui/layout/dropdown/states/dropdownWidthScopedState';
|
||||
import { isDropdownOpenScopedState } from '@/ui/layout/dropdown/states/isDropdownOpenScopedState';
|
||||
import { getScopeInjector } from '@/ui/utilities/recoil-scope/utils/getScopeInjector';
|
||||
|
||||
export const getDropdownScopeInjectors = () => {
|
||||
const dropdownHotkeyScopeScopeInjector = getScopeInjector(
|
||||
dropdownHotkeyScopeScopedState,
|
||||
);
|
||||
|
||||
const dropdownWidthScopeInjector = getScopeInjector(dropdownWidthScopedState);
|
||||
|
||||
const isDropdownOpenScopeInjector = getScopeInjector(
|
||||
isDropdownOpenScopedState,
|
||||
);
|
||||
|
||||
return {
|
||||
dropdownHotkeyScopeScopeInjector,
|
||||
dropdownWidthScopeInjector,
|
||||
isDropdownOpenScopeInjector,
|
||||
};
|
||||
};
|
||||
@ -12,7 +12,6 @@ import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||
|
||||
import { Dropdown } from '../../dropdown/components/Dropdown';
|
||||
import { DropdownMenu } from '../../dropdown/components/DropdownMenu';
|
||||
import { DropdownScope } from '../../dropdown/scopes/DropdownScope';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
z-index: 1;
|
||||
@ -33,41 +32,40 @@ export const ShowPageAddButton = ({
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<DropdownScope dropdownScopeId="add-show-page">
|
||||
<Dropdown
|
||||
clickableComponent={
|
||||
<IconButton
|
||||
Icon={IconPlus}
|
||||
size="medium"
|
||||
dataTestId="add-showpage-button"
|
||||
accent="default"
|
||||
variant="secondary"
|
||||
onClick={toggleDropdown}
|
||||
/>
|
||||
}
|
||||
dropdownComponents={
|
||||
<DropdownMenu>
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
onClick={() => handleSelect('Note')}
|
||||
accent="default"
|
||||
LeftIcon={IconNotes}
|
||||
text="Note"
|
||||
/>
|
||||
<MenuItem
|
||||
onClick={() => handleSelect('Task')}
|
||||
accent="default"
|
||||
LeftIcon={IconCheckbox}
|
||||
text="Task"
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
}
|
||||
dropdownHotkeyScope={{
|
||||
scope: PageHotkeyScope.ShowPage,
|
||||
}}
|
||||
/>
|
||||
</DropdownScope>
|
||||
<Dropdown
|
||||
dropdownId="show-page-add-button-dropdown-id"
|
||||
clickableComponent={
|
||||
<IconButton
|
||||
Icon={IconPlus}
|
||||
size="medium"
|
||||
dataTestId="add-showpage-button"
|
||||
accent="default"
|
||||
variant="secondary"
|
||||
onClick={toggleDropdown}
|
||||
/>
|
||||
}
|
||||
dropdownComponents={
|
||||
<DropdownMenu>
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
onClick={() => handleSelect('Note')}
|
||||
accent="default"
|
||||
LeftIcon={IconNotes}
|
||||
text="Note"
|
||||
/>
|
||||
<MenuItem
|
||||
onClick={() => handleSelect('Task')}
|
||||
accent="default"
|
||||
LeftIcon={IconCheckbox}
|
||||
text="Task"
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
}
|
||||
dropdownHotkeyScope={{
|
||||
scope: PageHotkeyScope.ShowPage,
|
||||
}}
|
||||
/>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@ -13,7 +13,6 @@ import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMe
|
||||
|
||||
import { Dropdown } from '../../dropdown/components/Dropdown';
|
||||
import { DropdownMenu } from '../../dropdown/components/DropdownMenu';
|
||||
import { DropdownScope } from '../../dropdown/scopes/DropdownScope';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
z-index: 1;
|
||||
@ -42,35 +41,34 @@ export const ShowPageMoreButton = ({
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<DropdownScope dropdownScopeId="more-show-page">
|
||||
<Dropdown
|
||||
clickableComponent={
|
||||
<IconButton
|
||||
Icon={IconDotsVertical}
|
||||
size="medium"
|
||||
dataTestId="more-showpage-button"
|
||||
accent="default"
|
||||
variant="secondary"
|
||||
onClick={toggleDropdown}
|
||||
/>
|
||||
}
|
||||
dropdownComponents={
|
||||
<DropdownMenu>
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
onClick={handleDelete}
|
||||
accent="danger"
|
||||
LeftIcon={IconTrash}
|
||||
text="Delete"
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
}
|
||||
dropdownHotkeyScope={{
|
||||
scope: PageHotkeyScope.ShowPage,
|
||||
}}
|
||||
/>
|
||||
</DropdownScope>
|
||||
<Dropdown
|
||||
dropdownId="more-show-page"
|
||||
clickableComponent={
|
||||
<IconButton
|
||||
Icon={IconDotsVertical}
|
||||
size="medium"
|
||||
dataTestId="more-showpage-button"
|
||||
accent="default"
|
||||
variant="secondary"
|
||||
onClick={toggleDropdown}
|
||||
/>
|
||||
}
|
||||
dropdownComponents={
|
||||
<DropdownMenu>
|
||||
<DropdownMenuItemsContainer>
|
||||
<MenuItem
|
||||
onClick={handleDelete}
|
||||
accent="danger"
|
||||
LeftIcon={IconTrash}
|
||||
text="Delete"
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
}
|
||||
dropdownHotkeyScope={{
|
||||
scope: PageHotkeyScope.ShowPage,
|
||||
}}
|
||||
/>
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user