mirror of
https://github.com/lingble/twenty.git
synced 2025-11-01 13:17:57 +00:00
8172 update the right drawer action menu to open with command o (#8375)
Closes #8172 - Added a shortcut property to the button component - Displays the actions inside a dropdown - The dropdown is toggled either by clicking on the button or with the `command + O` shortcut https://github.com/user-attachments/assets/4c4c88fa-85dc-404e-bb42-f2b0d57c8960
This commit is contained in:
@@ -1,56 +0,0 @@
|
|||||||
import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry';
|
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
import { MOBILE_VIEWPORT, MenuItemAccent } from 'twenty-ui';
|
|
||||||
|
|
||||||
type RecordShowActionMenuBarEntryProps = {
|
|
||||||
entry: ActionMenuEntry;
|
|
||||||
};
|
|
||||||
|
|
||||||
const StyledButton = styled.div<{ accent: MenuItemAccent }>`
|
|
||||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
|
||||||
color: ${(props) =>
|
|
||||||
props.accent === 'danger'
|
|
||||||
? props.theme.color.red
|
|
||||||
: props.theme.font.color.secondary};
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
padding: ${({ theme }) => theme.spacing(2)};
|
|
||||||
transition: background 0.1s ease;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: ${({ theme, accent }) =>
|
|
||||||
accent === 'danger'
|
|
||||||
? theme.background.danger
|
|
||||||
: theme.background.transparent.light};
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: ${MOBILE_VIEWPORT}px) {
|
|
||||||
padding: ${({ theme }) => theme.spacing(1)};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledButtonLabel = styled.div`
|
|
||||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
|
||||||
margin-left: ${({ theme }) => theme.spacing(1)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
// For now, this component is the same as RecordIndexActionMenuBarEntry but they
|
|
||||||
// will probably diverge in the future
|
|
||||||
export const RecordShowActionMenuBarEntry = ({
|
|
||||||
entry,
|
|
||||||
}: RecordShowActionMenuBarEntryProps) => {
|
|
||||||
const theme = useTheme();
|
|
||||||
return (
|
|
||||||
<StyledButton
|
|
||||||
accent={entry.accent ?? 'default'}
|
|
||||||
onClick={() => entry.onClick?.()}
|
|
||||||
>
|
|
||||||
{entry.Icon && <entry.Icon size={theme.icon.size.md} />}
|
|
||||||
<StyledButtonLabel>{entry.label}</StyledButtonLabel>
|
|
||||||
</StyledButton>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { GlobalActionMenuEntriesSetter } from '@/action-menu/actions/global-actions/components/GlobalActionMenuEntriesSetter';
|
import { GlobalActionMenuEntriesSetter } from '@/action-menu/actions/global-actions/components/GlobalActionMenuEntriesSetter';
|
||||||
import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter';
|
import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter';
|
||||||
import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals';
|
import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals';
|
||||||
import { RecordShowRightDrawerActionMenuBar } from '@/action-menu/components/RecordShowRightDrawerActionMenuBar';
|
import { RightDrawerActionMenuDropdown } from '@/action-menu/components/RightDrawerActionMenuDropdown';
|
||||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
|
||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||||
@@ -21,7 +21,7 @@ export const RecordShowRightDrawerActionMenu = () => {
|
|||||||
onActionExecutedCallback: () => {},
|
onActionExecutedCallback: () => {},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RecordShowRightDrawerActionMenuBar />
|
<RightDrawerActionMenuDropdown />
|
||||||
<ActionMenuConfirmationModals />
|
<ActionMenuConfirmationModals />
|
||||||
<RecordActionMenuEntriesSetter />
|
<RecordActionMenuEntriesSetter />
|
||||||
<GlobalActionMenuEntriesSetter />
|
<GlobalActionMenuEntriesSetter />
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import { RecordShowActionMenuBarEntry } from '@/action-menu/components/RecordShowActionMenuBarEntry';
|
|
||||||
import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector';
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
|
||||||
|
|
||||||
export const RecordShowRightDrawerActionMenuBar = () => {
|
|
||||||
const actionMenuEntries = useRecoilComponentValueV2(
|
|
||||||
actionMenuEntriesComponentSelector,
|
|
||||||
);
|
|
||||||
|
|
||||||
const standardActionMenuEntries = actionMenuEntries.filter(
|
|
||||||
(actionMenuEntry) => actionMenuEntry.type === 'standard',
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{standardActionMenuEntries.map((actionMenuEntry) => (
|
|
||||||
<RecordShowActionMenuBarEntry entry={actionMenuEntry} />
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector';
|
||||||
|
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||||
|
import { RightDrawerActionMenuDropdownHotkeyScope } from '@/action-menu/types/RightDrawerActionMenuDropdownHotkeyScope';
|
||||||
|
import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '@/action-menu/utils/getRightDrawerActionMenuDropdownIdFromActionMenuId';
|
||||||
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||||
|
import { RightDrawerHotkeyScope } from '@/ui/layout/right-drawer/types/RightDrawerHotkeyScope';
|
||||||
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
|
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import { Key } from 'ts-key-enum';
|
||||||
|
import { Button, MenuItem } from 'twenty-ui';
|
||||||
|
|
||||||
|
export const RightDrawerActionMenuDropdown = () => {
|
||||||
|
const actionMenuEntries = useRecoilComponentValueV2(
|
||||||
|
actionMenuEntriesComponentSelector,
|
||||||
|
);
|
||||||
|
|
||||||
|
const actionMenuId = useAvailableComponentInstanceIdOrThrow(
|
||||||
|
ActionMenuComponentInstanceContext,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { closeDropdown, openDropdown } = useDropdownV2();
|
||||||
|
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
useScopedHotkeys(
|
||||||
|
[Key.Escape, 'ctrl+o,meta+o'],
|
||||||
|
() => {
|
||||||
|
closeDropdown(
|
||||||
|
getRightDrawerActionMenuDropdownIdFromActionMenuId(actionMenuId),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
RightDrawerActionMenuDropdownHotkeyScope.RightDrawerActionMenuDropdown,
|
||||||
|
[closeDropdown],
|
||||||
|
);
|
||||||
|
|
||||||
|
useScopedHotkeys(
|
||||||
|
['ctrl+o,meta+o'],
|
||||||
|
() => {
|
||||||
|
openDropdown(
|
||||||
|
getRightDrawerActionMenuDropdownIdFromActionMenuId(actionMenuId),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
RightDrawerHotkeyScope.RightDrawer,
|
||||||
|
[openDropdown],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
dropdownId={getRightDrawerActionMenuDropdownIdFromActionMenuId(
|
||||||
|
actionMenuId,
|
||||||
|
)}
|
||||||
|
dropdownHotkeyScope={{
|
||||||
|
scope:
|
||||||
|
RightDrawerActionMenuDropdownHotkeyScope.RightDrawerActionMenuDropdown,
|
||||||
|
}}
|
||||||
|
data-select-disable
|
||||||
|
clickableComponent={<Button title="Actions" shortcut="⌘O" />}
|
||||||
|
dropdownPlacement="top-end"
|
||||||
|
dropdownOffset={{
|
||||||
|
y: parseInt(theme.spacing(2)),
|
||||||
|
}}
|
||||||
|
dropdownComponents={
|
||||||
|
<DropdownMenuItemsContainer>
|
||||||
|
{actionMenuEntries.map((item, index) => (
|
||||||
|
<MenuItem
|
||||||
|
key={index}
|
||||||
|
LeftIcon={item.Icon}
|
||||||
|
onClick={() => {
|
||||||
|
closeDropdown(
|
||||||
|
getRightDrawerActionMenuDropdownIdFromActionMenuId(
|
||||||
|
actionMenuId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
item.onClick?.();
|
||||||
|
}}
|
||||||
|
text={item.label}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -2,7 +2,7 @@ import { expect, jest } from '@storybook/jest';
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
import { RecoilRoot } from 'recoil';
|
import { RecoilRoot } from 'recoil';
|
||||||
|
|
||||||
import { RecordShowRightDrawerActionMenuBar } from '@/action-menu/components/RecordShowRightDrawerActionMenuBar';
|
import { RightDrawerActionMenuDropdown } from '@/action-menu/components/RightDrawerActionMenuDropdown';
|
||||||
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
|
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
|
||||||
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
|
||||||
import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry';
|
import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry';
|
||||||
@@ -21,9 +21,9 @@ const deleteMock = jest.fn();
|
|||||||
const addToFavoritesMock = jest.fn();
|
const addToFavoritesMock = jest.fn();
|
||||||
const exportMock = jest.fn();
|
const exportMock = jest.fn();
|
||||||
|
|
||||||
const meta: Meta<typeof RecordShowRightDrawerActionMenuBar> = {
|
const meta: Meta<typeof RightDrawerActionMenuDropdown> = {
|
||||||
title: 'Modules/ActionMenu/RecordShowRightDrawerActionMenuBar',
|
title: 'Modules/ActionMenu/RightDrawerActionMenuDropdown',
|
||||||
component: RecordShowRightDrawerActionMenuBar,
|
component: RightDrawerActionMenuDropdown,
|
||||||
decorators: [
|
decorators: [
|
||||||
(Story) => (
|
(Story) => (
|
||||||
<RecoilRoot
|
<RecoilRoot
|
||||||
@@ -98,7 +98,7 @@ const meta: Meta<typeof RecordShowRightDrawerActionMenuBar> = {
|
|||||||
|
|
||||||
export default meta;
|
export default meta;
|
||||||
|
|
||||||
type Story = StoryObj<typeof RecordShowRightDrawerActionMenuBar>;
|
type Story = StoryObj<typeof RightDrawerActionMenuDropdown>;
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args: {
|
args: {
|
||||||
@@ -113,12 +113,21 @@ export const WithButtonClicks: Story = {
|
|||||||
play: async ({ canvasElement }) => {
|
play: async ({ canvasElement }) => {
|
||||||
const canvas = within(canvasElement);
|
const canvas = within(canvasElement);
|
||||||
|
|
||||||
|
let actionButton = await canvas.findByText('Actions');
|
||||||
|
await userEvent.click(actionButton);
|
||||||
|
|
||||||
const deleteButton = await canvas.findByText('Delete');
|
const deleteButton = await canvas.findByText('Delete');
|
||||||
await userEvent.click(deleteButton);
|
await userEvent.click(deleteButton);
|
||||||
|
|
||||||
|
actionButton = await canvas.findByText('Actions');
|
||||||
|
await userEvent.click(actionButton);
|
||||||
|
|
||||||
const addToFavoritesButton = await canvas.findByText('Add to favorites');
|
const addToFavoritesButton = await canvas.findByText('Add to favorites');
|
||||||
await userEvent.click(addToFavoritesButton);
|
await userEvent.click(addToFavoritesButton);
|
||||||
|
|
||||||
|
actionButton = await canvas.findByText('Actions');
|
||||||
|
await userEvent.click(actionButton);
|
||||||
|
|
||||||
const exportButton = await canvas.findByText('Export');
|
const exportButton = await canvas.findByText('Export');
|
||||||
await userEvent.click(exportButton);
|
await userEvent.click(exportButton);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export enum RightDrawerActionMenuDropdownHotkeyScope {
|
||||||
|
RightDrawerActionMenuDropdown = 'right-drawer-action-menu-dropdown',
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { getRightDrawerActionMenuDropdownIdFromActionMenuId } from '../getRightDrawerActionMenuDropdownIdFromActionMenuId';
|
||||||
|
|
||||||
|
describe('getRightDrawerActionMenuDropdownIdFromActionMenuId', () => {
|
||||||
|
it('should return the right drawer action menu dropdown id', () => {
|
||||||
|
expect(
|
||||||
|
getRightDrawerActionMenuDropdownIdFromActionMenuId('action-menu-id'),
|
||||||
|
).toBe('right-drawer-action-menu-dropdown-action-menu-id');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export const getRightDrawerActionMenuDropdownIdFromActionMenuId = (
|
||||||
|
actionMenuId: string,
|
||||||
|
) => {
|
||||||
|
return `right-drawer-action-menu-dropdown-${actionMenuId}`;
|
||||||
|
};
|
||||||
@@ -350,6 +350,10 @@ export const RichTextEditor = ({
|
|||||||
editor.focus();
|
editor.focus();
|
||||||
},
|
},
|
||||||
RightDrawerHotkeyScope.RightDrawer,
|
RightDrawerHotkeyScope.RightDrawer,
|
||||||
|
[],
|
||||||
|
{
|
||||||
|
preventDefault: false,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleBlockEditorFocus = () => {
|
const handleBlockEditorFocus = () => {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export type ButtonProps = {
|
|||||||
to?: string;
|
to?: string;
|
||||||
target?: string;
|
target?: string;
|
||||||
dataTestId?: string;
|
dataTestId?: string;
|
||||||
|
shortcut?: string;
|
||||||
} & React.ComponentProps<'button'>;
|
} & React.ComponentProps<'button'>;
|
||||||
|
|
||||||
const StyledButton = styled('button', {
|
const StyledButton = styled('button', {
|
||||||
@@ -358,6 +359,19 @@ const StyledSoonPill = styled(Pill)`
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const StyledShortcutLabel = styled.div`
|
||||||
|
color: ${({ theme }) => theme.font.color.light};
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledSeparator = styled.div<{ buttonSize: ButtonSize }>`
|
||||||
|
background: ${({ theme }) => theme.border.color.light};
|
||||||
|
height: ${({ theme, buttonSize }) =>
|
||||||
|
theme.spacing(buttonSize === 'small' ? 3 : 4)};
|
||||||
|
margin: 0 ${({ theme }) => theme.spacing(1)};
|
||||||
|
width: 1px;
|
||||||
|
`;
|
||||||
|
|
||||||
export const Button = ({
|
export const Button = ({
|
||||||
className,
|
className,
|
||||||
Icon,
|
Icon,
|
||||||
@@ -376,6 +390,7 @@ export const Button = ({
|
|||||||
to,
|
to,
|
||||||
target,
|
target,
|
||||||
dataTestId,
|
dataTestId,
|
||||||
|
shortcut,
|
||||||
}: ButtonProps) => {
|
}: ButtonProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
@@ -399,6 +414,12 @@ export const Button = ({
|
|||||||
>
|
>
|
||||||
{Icon && <Icon size={theme.icon.size.sm} />}
|
{Icon && <Icon size={theme.icon.size.sm} />}
|
||||||
{title}
|
{title}
|
||||||
|
{shortcut && (
|
||||||
|
<>
|
||||||
|
<StyledSeparator buttonSize={size} />
|
||||||
|
<StyledShortcutLabel>{shortcut}</StyledShortcutLabel>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{soon && <StyledSoonPill label="Soon" />}
|
{soon && <StyledSoonPill label="Soon" />}
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type Story = StoryObj<typeof Button>;
|
|||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
argTypes: {
|
argTypes: {
|
||||||
|
shortcut: { control: false },
|
||||||
Icon: { control: false },
|
Icon: { control: false },
|
||||||
},
|
},
|
||||||
args: {
|
args: {
|
||||||
@@ -54,6 +55,7 @@ export const Catalog: CatalogStory<Story, typeof Button> = {
|
|||||||
soon: { control: false },
|
soon: { control: false },
|
||||||
position: { control: false },
|
position: { control: false },
|
||||||
className: { control: false },
|
className: { control: false },
|
||||||
|
shortcut: { control: false },
|
||||||
},
|
},
|
||||||
parameters: {
|
parameters: {
|
||||||
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
||||||
@@ -126,6 +128,7 @@ export const SoonCatalog: CatalogStory<Story, typeof Button> = {
|
|||||||
soon: { control: false },
|
soon: { control: false },
|
||||||
position: { control: false },
|
position: { control: false },
|
||||||
className: { control: false },
|
className: { control: false },
|
||||||
|
shortcut: { control: false },
|
||||||
},
|
},
|
||||||
parameters: {
|
parameters: {
|
||||||
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
||||||
@@ -197,6 +200,7 @@ export const PositionCatalog: CatalogStory<Story, typeof Button> = {
|
|||||||
fullWidth: { control: false },
|
fullWidth: { control: false },
|
||||||
soon: { control: false },
|
soon: { control: false },
|
||||||
position: { control: false },
|
position: { control: false },
|
||||||
|
shortcut: { control: false },
|
||||||
},
|
},
|
||||||
parameters: {
|
parameters: {
|
||||||
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
||||||
@@ -262,6 +266,34 @@ export const PositionCatalog: CatalogStory<Story, typeof Button> = {
|
|||||||
decorators: [CatalogDecorator],
|
decorators: [CatalogDecorator],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ShortcutCatalog: CatalogStory<Story, typeof Button> = {
|
||||||
|
args: { title: 'Actions', shortcut: '⌘O' },
|
||||||
|
argTypes: {
|
||||||
|
size: { control: false },
|
||||||
|
variant: { control: false },
|
||||||
|
accent: { control: false },
|
||||||
|
disabled: { control: false },
|
||||||
|
focus: { control: false },
|
||||||
|
fullWidth: { control: false },
|
||||||
|
soon: { control: false },
|
||||||
|
position: { control: false },
|
||||||
|
shortcut: { control: false },
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
|
||||||
|
catalog: {
|
||||||
|
dimensions: [
|
||||||
|
{
|
||||||
|
name: 'sizes',
|
||||||
|
values: ['small', 'medium'] satisfies ButtonSize[],
|
||||||
|
props: (size: ButtonSize) => ({ size }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
decorators: [CatalogDecorator],
|
||||||
|
};
|
||||||
|
|
||||||
export const FullWidth: Story = {
|
export const FullWidth: Story = {
|
||||||
args: { title: 'Filter', Icon: IconSearch, fullWidth: true },
|
args: { title: 'Filter', Icon: IconSearch, fullWidth: true },
|
||||||
argTypes: {
|
argTypes: {
|
||||||
|
|||||||
Reference in New Issue
Block a user