Feat/hide board fields (#1271)
* Renamed AuthAutoRouter * Moved RecoilScope * Refactored old WithTopBarContainer to make it less transclusive * Created new add opportunity button and refactored DropdownButton * Added tests * Deactivated new eslint rule * Refactored Table options with new dropdown * Started BoardDropdown * Fix lint * Refactor dropdown openstate * Fix according to PR * Fix tests --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -1,10 +1,16 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { Keys } from 'react-hotkeys-hook';
|
||||
import styled from '@emotion/styled';
|
||||
import { flip, offset, useFloating } from '@floating-ui/react';
|
||||
import { flip, offset, Placement, useFloating } from '@floating-ui/react';
|
||||
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { useRecoilScopedFamilyState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
import { useDropdownButton } from '../hooks/useDropdownButton';
|
||||
import { dropdownButtonCustomHotkeyScopeScopedFamilyState } from '../states/dropdownButtonCustomHotkeyScopeScopedFamilyState';
|
||||
import { DropdownRecoilScopeContext } from '../states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
||||
|
||||
import { HotkeyEffect } from './HotkeyEffect';
|
||||
|
||||
@ -16,38 +22,74 @@ const StyledContainer = styled.div`
|
||||
type OwnProps = {
|
||||
buttonComponents: JSX.Element | JSX.Element[];
|
||||
dropdownComponents: JSX.Element | JSX.Element[];
|
||||
dropdownKey: string;
|
||||
hotkey?: {
|
||||
key: Keys;
|
||||
scope: string;
|
||||
};
|
||||
dropdownScopeToSet?: HotkeyScope;
|
||||
dropdownHotkeyScope?: HotkeyScope;
|
||||
dropdownPlacement?: Placement;
|
||||
};
|
||||
|
||||
export function DropdownButton({
|
||||
buttonComponents,
|
||||
dropdownComponents,
|
||||
dropdownKey,
|
||||
hotkey,
|
||||
dropdownScopeToSet,
|
||||
dropdownHotkeyScope,
|
||||
dropdownPlacement = 'bottom-end',
|
||||
}: OwnProps) {
|
||||
const { isDropdownButtonOpen, toggleDropdownButton } = useDropdownButton();
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { isDropdownButtonOpen, toggleDropdownButton, closeDropdownButton } =
|
||||
useDropdownButton({
|
||||
key: dropdownKey,
|
||||
});
|
||||
|
||||
const { refs, floatingStyles } = useFloating({
|
||||
placement: 'bottom-end',
|
||||
placement: dropdownPlacement,
|
||||
middleware: [flip(), offset()],
|
||||
});
|
||||
|
||||
function handleButtonClick() {
|
||||
toggleDropdownButton(dropdownScopeToSet);
|
||||
function handleHotkeyTriggered() {
|
||||
toggleDropdownButton();
|
||||
}
|
||||
|
||||
useListenClickOutside({
|
||||
refs: [containerRef],
|
||||
callback: () => {
|
||||
if (isDropdownButtonOpen) {
|
||||
closeDropdownButton();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const [dropdownButtonCustomHotkeyScope, setDropdownButtonCustomHotkeyScope] =
|
||||
useRecoilScopedFamilyState(
|
||||
dropdownButtonCustomHotkeyScopeScopedFamilyState,
|
||||
dropdownKey,
|
||||
DropdownRecoilScopeContext,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDeeplyEqual(dropdownButtonCustomHotkeyScope, dropdownHotkeyScope)) {
|
||||
setDropdownButtonCustomHotkeyScope(dropdownHotkeyScope);
|
||||
}
|
||||
}, [
|
||||
setDropdownButtonCustomHotkeyScope,
|
||||
dropdownHotkeyScope,
|
||||
dropdownButtonCustomHotkeyScope,
|
||||
]);
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<StyledContainer ref={containerRef}>
|
||||
{hotkey && (
|
||||
<HotkeyEffect hotkey={hotkey} onHotkeyTriggered={handleButtonClick} />
|
||||
<HotkeyEffect
|
||||
hotkey={hotkey}
|
||||
onHotkeyTriggered={handleHotkeyTriggered}
|
||||
/>
|
||||
)}
|
||||
<div ref={refs.setReference} onClick={handleButtonClick}>
|
||||
{buttonComponents}
|
||||
</div>
|
||||
<div ref={refs.setReference}>{buttonComponents}</div>
|
||||
{isDropdownButtonOpen && (
|
||||
<div ref={refs.setFloating} style={floatingStyles}>
|
||||
{dropdownComponents}
|
||||
|
||||
@ -44,15 +44,19 @@ type DropdownMenuHeaderProps = ComponentProps<'li'> & {
|
||||
endIcon?: ReactElement;
|
||||
};
|
||||
|
||||
export const DropdownMenuHeader = ({
|
||||
export function DropdownMenuHeader({
|
||||
children,
|
||||
startIcon,
|
||||
endIcon,
|
||||
...props
|
||||
}: DropdownMenuHeaderProps) => (
|
||||
<StyledHeader {...props}>
|
||||
{startIcon && <StyledStartIconWrapper>{startIcon}</StyledStartIconWrapper>}
|
||||
{children}
|
||||
{endIcon && <StyledEndIconWrapper>{endIcon}</StyledEndIconWrapper>}
|
||||
</StyledHeader>
|
||||
);
|
||||
}: DropdownMenuHeaderProps) {
|
||||
return (
|
||||
<StyledHeader {...props}>
|
||||
{startIcon && (
|
||||
<StyledStartIconWrapper>{startIcon}</StyledStartIconWrapper>
|
||||
)}
|
||||
{children}
|
||||
{endIcon && <StyledEndIconWrapper>{endIcon}</StyledEndIconWrapper>}
|
||||
</StyledHeader>
|
||||
);
|
||||
}
|
||||
|
||||
@ -58,22 +58,24 @@ export type DropdownMenuItemProps = ComponentProps<'li'> & {
|
||||
accent?: DropdownMenuItemAccent;
|
||||
};
|
||||
|
||||
export const DropdownMenuItem = ({
|
||||
export function DropdownMenuItem({
|
||||
actions,
|
||||
children,
|
||||
accent = 'regular',
|
||||
...props
|
||||
}: DropdownMenuItemProps) => (
|
||||
<StyledItem {...props} accent={accent}>
|
||||
{children}
|
||||
{actions && (
|
||||
<StyledActions
|
||||
className={styledIconButtonGroupClassName}
|
||||
variant="transparent"
|
||||
size="small"
|
||||
>
|
||||
{actions}
|
||||
</StyledActions>
|
||||
)}
|
||||
</StyledItem>
|
||||
);
|
||||
}: DropdownMenuItemProps) {
|
||||
return (
|
||||
<StyledItem {...props} accent={accent}>
|
||||
{children}
|
||||
{actions && (
|
||||
<StyledActions
|
||||
className={styledIconButtonGroupClassName}
|
||||
variant="transparent"
|
||||
size="small"
|
||||
>
|
||||
{actions}
|
||||
</StyledActions>
|
||||
)}
|
||||
</StyledItem>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
/* eslint-disable twenty/styled-components-prefixed-with-styled */
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export const DropdownMenu = styled.div<{
|
||||
export const StyledDropdownMenu = styled.div<{
|
||||
disableBlur?: boolean;
|
||||
width?: number;
|
||||
}>`
|
||||
@ -1,7 +1,6 @@
|
||||
/* eslint-disable twenty/styled-components-prefixed-with-styled */
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export const DropdownMenuItemsContainer = styled.div<{
|
||||
export const StyledDropdownMenuItemsContainer = styled.div<{
|
||||
hasMaxHeight?: boolean;
|
||||
}>`
|
||||
--padding: ${({ theme }) => theme.spacing(1)};
|
||||
@ -1,7 +1,6 @@
|
||||
/* eslint-disable twenty/styled-components-prefixed-with-styled */
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export const DropdownMenuSeparator = styled.div`
|
||||
export const StyledDropdownMenuSeparator = styled.div`
|
||||
background-color: ${({ theme }) => theme.border.color.light};
|
||||
height: 1px;
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
/* eslint-disable twenty/styled-components-prefixed-with-styled */
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export const DropdownMenuSubheader = styled.div`
|
||||
export const StyledDropdownMenuSubheader = styled.div`
|
||||
background-color: ${({ theme }) => theme.background.transparent.lighter};
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
font-size: ${({ theme }) => theme.font.size.xxs};
|
||||
@ -0,0 +1,27 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
type StyledDropdownButtonProps = {
|
||||
isUnfolded?: boolean;
|
||||
isActive?: boolean;
|
||||
};
|
||||
|
||||
export const StyledHeaderDropdownButton = styled.div<StyledDropdownButtonProps>`
|
||||
align-items: center;
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
color: ${({ isActive, theme, color }) =>
|
||||
color ?? (isActive ? theme.color.blue : 'none')};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
filter: ${(props) => (props.isUnfolded ? 'brightness(0.95)' : 'none')};
|
||||
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
padding-right: ${({ theme }) => theme.spacing(2)};
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
filter: brightness(0.95);
|
||||
}
|
||||
`;
|
||||
@ -8,19 +8,19 @@ import { DropdownMenuSkeletonItem } from '@/ui/input/relation-picker/components/
|
||||
import { Avatar } from '@/users/components/Avatar';
|
||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||
|
||||
import { DropdownMenu } from '../DropdownMenu';
|
||||
import { DropdownMenuCheckableItem } from '../DropdownMenuCheckableItem';
|
||||
import { DropdownMenuHeader } from '../DropdownMenuHeader';
|
||||
import { DropdownMenuInput } from '../DropdownMenuInput';
|
||||
import { DropdownMenuItem } from '../DropdownMenuItem';
|
||||
import { DropdownMenuItemsContainer } from '../DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSelectableItem } from '../DropdownMenuSelectableItem';
|
||||
import { DropdownMenuSeparator } from '../DropdownMenuSeparator';
|
||||
import { DropdownMenuSubheader } from '../DropdownMenuSubheader';
|
||||
import { StyledDropdownMenu } from '../StyledDropdownMenu';
|
||||
import { StyledDropdownMenuItemsContainer } from '../StyledDropdownMenuItemsContainer';
|
||||
import { StyledDropdownMenuSeparator } from '../StyledDropdownMenuSeparator';
|
||||
import { StyledDropdownMenuSubheader } from '../StyledDropdownMenuSubheader';
|
||||
|
||||
const meta: Meta<typeof DropdownMenu> = {
|
||||
const meta: Meta<typeof StyledDropdownMenu> = {
|
||||
title: 'UI/Dropdown/DropdownMenu',
|
||||
component: DropdownMenu,
|
||||
component: StyledDropdownMenu,
|
||||
decorators: [ComponentDecorator],
|
||||
argTypes: {
|
||||
as: { table: { disable: true } },
|
||||
@ -29,7 +29,7 @@ const meta: Meta<typeof DropdownMenu> = {
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof DropdownMenu>;
|
||||
type Story = StoryObj<typeof StyledDropdownMenu>;
|
||||
|
||||
const FakeContentBelow = () => (
|
||||
<div style={{ position: 'absolute' }}>
|
||||
@ -156,9 +156,9 @@ const FakeCheckableMenuItemList = ({ hasAvatar }: { hasAvatar?: boolean }) => {
|
||||
|
||||
export const Empty: Story = {
|
||||
render: (args) => (
|
||||
<DropdownMenu {...args}>
|
||||
<StyledDropdownMenu {...args}>
|
||||
<StyledFakeMenuContent />
|
||||
</DropdownMenu>
|
||||
</StyledDropdownMenu>
|
||||
),
|
||||
};
|
||||
|
||||
@ -179,60 +179,60 @@ export const WithContentBelow: Story = {
|
||||
export const SimpleMenuItem: Story = {
|
||||
...WithContentBelow,
|
||||
render: (args) => (
|
||||
<DropdownMenu {...args}>
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
<StyledDropdownMenu {...args}>
|
||||
<StyledDropdownMenuItemsContainer hasMaxHeight>
|
||||
{mockSelectArray.map(({ name }) => (
|
||||
<DropdownMenuItem>{name}</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
</StyledDropdownMenu>
|
||||
),
|
||||
};
|
||||
|
||||
export const WithHeaders: Story = {
|
||||
...WithContentBelow,
|
||||
render: (args) => (
|
||||
<DropdownMenu {...args}>
|
||||
<StyledDropdownMenu {...args}>
|
||||
<DropdownMenuHeader>Header</DropdownMenuHeader>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuSubheader>Subheader 1</DropdownMenuSubheader>
|
||||
<DropdownMenuItemsContainer>
|
||||
<StyledDropdownMenuSeparator />
|
||||
<StyledDropdownMenuSubheader>Subheader 1</StyledDropdownMenuSubheader>
|
||||
<StyledDropdownMenuItemsContainer>
|
||||
{mockSelectArray.slice(0, 3).map(({ name }) => (
|
||||
<DropdownMenuItem>{name}</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuSubheader>Subheader 2</DropdownMenuSubheader>
|
||||
<DropdownMenuItemsContainer>
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
<StyledDropdownMenuSeparator />
|
||||
<StyledDropdownMenuSubheader>Subheader 2</StyledDropdownMenuSubheader>
|
||||
<StyledDropdownMenuItemsContainer>
|
||||
{mockSelectArray.slice(3).map(({ name }) => (
|
||||
<DropdownMenuItem>{name}</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
</StyledDropdownMenu>
|
||||
),
|
||||
};
|
||||
|
||||
export const WithIcons: Story = {
|
||||
...WithContentBelow,
|
||||
render: (args) => (
|
||||
<DropdownMenu {...args}>
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
<StyledDropdownMenu {...args}>
|
||||
<StyledDropdownMenuItemsContainer hasMaxHeight>
|
||||
{mockSelectArray.map(({ name }) => (
|
||||
<DropdownMenuItem>
|
||||
<IconUser size={16} />
|
||||
{name}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
</StyledDropdownMenu>
|
||||
),
|
||||
};
|
||||
|
||||
export const WithActions: Story = {
|
||||
...WithContentBelow,
|
||||
render: (args) => (
|
||||
<DropdownMenu {...args}>
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
<StyledDropdownMenu {...args}>
|
||||
<StyledDropdownMenuItemsContainer hasMaxHeight>
|
||||
{mockSelectArray.map(({ name }, index) => (
|
||||
<DropdownMenuItem
|
||||
className={index === 0 ? 'hover' : undefined}
|
||||
@ -244,8 +244,8 @@ export const WithActions: Story = {
|
||||
{name}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
</StyledDropdownMenu>
|
||||
),
|
||||
parameters: {
|
||||
pseudo: { hover: ['.hover'] },
|
||||
@ -255,71 +255,71 @@ export const WithActions: Story = {
|
||||
export const LoadingMenu: Story = {
|
||||
...WithContentBelow,
|
||||
render: () => (
|
||||
<DropdownMenu>
|
||||
<StyledDropdownMenu>
|
||||
<DropdownMenuInput value={'query'} autoFocus />
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
<StyledDropdownMenuSeparator />
|
||||
<StyledDropdownMenuItemsContainer hasMaxHeight>
|
||||
<DropdownMenuSkeletonItem />
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
</StyledDropdownMenu>
|
||||
),
|
||||
};
|
||||
|
||||
export const Search: Story = {
|
||||
...WithContentBelow,
|
||||
render: (args) => (
|
||||
<DropdownMenu {...args}>
|
||||
<StyledDropdownMenu {...args}>
|
||||
<DropdownMenuInput />
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
<StyledDropdownMenuSeparator />
|
||||
<StyledDropdownMenuItemsContainer hasMaxHeight>
|
||||
{mockSelectArray.map(({ name }) => (
|
||||
<DropdownMenuItem>{name}</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
</StyledDropdownMenu>
|
||||
),
|
||||
};
|
||||
|
||||
export const SelectableMenuItem: Story = {
|
||||
...WithContentBelow,
|
||||
render: (args) => (
|
||||
<DropdownMenu {...args}>
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
<StyledDropdownMenu {...args}>
|
||||
<StyledDropdownMenuItemsContainer hasMaxHeight>
|
||||
<FakeSelectableMenuItemList />
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
</StyledDropdownMenu>
|
||||
),
|
||||
};
|
||||
|
||||
export const SelectableMenuItemWithAvatar: Story = {
|
||||
...WithContentBelow,
|
||||
render: (args) => (
|
||||
<DropdownMenu {...args}>
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
<StyledDropdownMenu {...args}>
|
||||
<StyledDropdownMenuItemsContainer hasMaxHeight>
|
||||
<FakeSelectableMenuItemList hasAvatar />
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
</StyledDropdownMenu>
|
||||
),
|
||||
};
|
||||
|
||||
export const CheckableMenuItem: Story = {
|
||||
...WithContentBelow,
|
||||
render: (args) => (
|
||||
<DropdownMenu {...args}>
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
<StyledDropdownMenu {...args}>
|
||||
<StyledDropdownMenuItemsContainer hasMaxHeight>
|
||||
<FakeCheckableMenuItemList />
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
</StyledDropdownMenu>
|
||||
),
|
||||
};
|
||||
|
||||
export const CheckableMenuItemWithAvatar: Story = {
|
||||
...WithContentBelow,
|
||||
render: (args) => (
|
||||
<DropdownMenu {...args}>
|
||||
<DropdownMenuItemsContainer hasMaxHeight>
|
||||
<StyledDropdownMenu {...args}>
|
||||
<StyledDropdownMenuItemsContainer hasMaxHeight>
|
||||
<FakeCheckableMenuItemList hasAvatar />
|
||||
</DropdownMenuItemsContainer>
|
||||
</DropdownMenu>
|
||||
</StyledDropdownMenuItemsContainer>
|
||||
</StyledDropdownMenu>
|
||||
),
|
||||
};
|
||||
|
||||
@ -1,17 +1,27 @@
|
||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { useRecoilScopedFamilyState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedFamilyState';
|
||||
|
||||
import { isDropdownButtonOpenScopedState } from '../states/isDropdownButtonOpenScopedState';
|
||||
import { dropdownButtonCustomHotkeyScopeScopedFamilyState } from '../states/dropdownButtonCustomHotkeyScopeScopedFamilyState';
|
||||
import { isDropdownButtonOpenScopedFamilyState } from '../states/isDropdownButtonOpenScopedFamilyState';
|
||||
import { DropdownRecoilScopeContext } from '../states/recoil-scope-contexts/DropdownRecoilScopeContext';
|
||||
|
||||
export function useDropdownButton() {
|
||||
export function useDropdownButton({ key }: { key: string }) {
|
||||
const {
|
||||
setHotkeyScopeAndMemorizePreviousScope,
|
||||
goBackToPreviousHotkeyScope,
|
||||
} = usePreviousHotkeyScope();
|
||||
|
||||
const [isDropdownButtonOpen, setIsDropdownButtonOpen] = useRecoilScopedState(
|
||||
isDropdownButtonOpenScopedState,
|
||||
const [isDropdownButtonOpen, setIsDropdownButtonOpen] =
|
||||
useRecoilScopedFamilyState(
|
||||
isDropdownButtonOpenScopedFamilyState,
|
||||
key,
|
||||
DropdownRecoilScopeContext,
|
||||
);
|
||||
|
||||
const [dropdownButtonCustomHotkeyScope] = useRecoilScopedFamilyState(
|
||||
dropdownButtonCustomHotkeyScopeScopedFamilyState,
|
||||
key,
|
||||
DropdownRecoilScopeContext,
|
||||
);
|
||||
|
||||
function closeDropdownButton() {
|
||||
@ -19,22 +29,22 @@ export function useDropdownButton() {
|
||||
setIsDropdownButtonOpen(false);
|
||||
}
|
||||
|
||||
function openDropdownButton(hotkeyScopeToSet?: HotkeyScope) {
|
||||
function openDropdownButton() {
|
||||
setIsDropdownButtonOpen(true);
|
||||
|
||||
if (hotkeyScopeToSet) {
|
||||
if (dropdownButtonCustomHotkeyScope) {
|
||||
setHotkeyScopeAndMemorizePreviousScope(
|
||||
hotkeyScopeToSet.scope,
|
||||
hotkeyScopeToSet.customScopes,
|
||||
dropdownButtonCustomHotkeyScope.scope,
|
||||
dropdownButtonCustomHotkeyScope.customScopes,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleDropdownButton(hotkeyScopeToSet?: HotkeyScope) {
|
||||
function toggleDropdownButton() {
|
||||
if (isDropdownButtonOpen) {
|
||||
closeDropdownButton();
|
||||
} else {
|
||||
openDropdownButton(hotkeyScopeToSet);
|
||||
openDropdownButton();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
|
||||
export const dropdownButtonCustomHotkeyScopeScopedFamilyState = atomFamily<
|
||||
HotkeyScope | null | undefined,
|
||||
string
|
||||
>({
|
||||
key: 'dropdownButtonCustomHotkeyScopeScopedState',
|
||||
default: null,
|
||||
});
|
||||
@ -1,6 +1,9 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
export const isDropdownButtonOpenScopedState = atomFamily<boolean, string>({
|
||||
export const isDropdownButtonOpenScopedFamilyState = atomFamily<
|
||||
boolean,
|
||||
string
|
||||
>({
|
||||
key: 'isDropdownButtonOpenScopedState',
|
||||
default: false,
|
||||
});
|
||||
@ -0,0 +1,3 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export const DropdownRecoilScopeContext = createContext<string | null>(null);
|
||||
Reference in New Issue
Block a user