Option-menu-imporovements (#11309)
- icon switching : if switching layout from table to kanban and if icon is the table icon (the default one) then automatically update the icon to the kanban icon - add tooltip on Layout default view to better explain why it's unavaialble Fixes [#689](https://github.com/twentyhq/core-team-issues/issues/689) Fixes [#688](https://github.com/twentyhq/core-team-issues/issues/688) Fixes [#686](https://github.com/twentyhq/core-team-issues/issues/686)
This commit is contained in:
@ -1,7 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
IconBaselineDensitySmall,
|
IconBaselineDensitySmall,
|
||||||
IconChevronLeft,
|
IconChevronLeft,
|
||||||
IconLayoutKanban,
|
|
||||||
IconLayoutList,
|
IconLayoutList,
|
||||||
IconLayoutNavbar,
|
IconLayoutNavbar,
|
||||||
IconLayoutSidebarRight,
|
IconLayoutSidebarRight,
|
||||||
@ -9,6 +8,7 @@ import {
|
|||||||
MenuItem,
|
MenuItem,
|
||||||
MenuItemSelect,
|
MenuItemSelect,
|
||||||
MenuItemToggle,
|
MenuItemToggle,
|
||||||
|
OverflowingTextWithTooltip,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
import { useObjectOptionsForBoard } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsForBoard';
|
||||||
@ -24,7 +24,7 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
|||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||||
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
import { ViewOpenRecordInType } from '@/views/types/ViewOpenRecordInType';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType';
|
||||||
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
@ -75,6 +75,7 @@ export const ObjectOptionsDropdownLayoutContent = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isDefaultView = currentView?.key === 'INDEX';
|
const isDefaultView = currentView?.key === 'INDEX';
|
||||||
|
const nbsp = '\u00A0';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -101,15 +102,20 @@ export const ObjectOptionsDropdownLayoutContent = () => {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<MenuItemSelect
|
<MenuItemSelect
|
||||||
LeftIcon={IconLayoutKanban}
|
LeftIcon={viewTypeIconMapping(ViewType.Kanban)}
|
||||||
text={t`Kanban`}
|
text={t`Kanban`}
|
||||||
disabled={isDefaultView}
|
disabled={isDefaultView}
|
||||||
contextualText={
|
contextualText={
|
||||||
isDefaultView
|
isDefaultView ? (
|
||||||
? t`Not available for default view`
|
<>
|
||||||
: availableFieldsForKanban.length === 0
|
{nbsp}·{nbsp}
|
||||||
? t`Create Select...`
|
<OverflowingTextWithTooltip
|
||||||
: undefined
|
text={t`Not available for default view`}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : availableFieldsForKanban.length === 0 ? (
|
||||||
|
t`Create Select...`
|
||||||
|
) : undefined
|
||||||
}
|
}
|
||||||
selected={currentView?.type === ViewType.Kanban}
|
selected={currentView?.type === ViewType.Kanban}
|
||||||
onClick={handleSelectKanbanViewType}
|
onClick={handleSelectKanbanViewType}
|
||||||
|
|||||||
@ -2,10 +2,8 @@ import { Key } from 'ts-key-enum';
|
|||||||
import {
|
import {
|
||||||
AppTooltip,
|
AppTooltip,
|
||||||
IconCopy,
|
IconCopy,
|
||||||
IconLayoutKanban,
|
|
||||||
IconLayoutList,
|
IconLayoutList,
|
||||||
IconListDetails,
|
IconListDetails,
|
||||||
IconTable,
|
|
||||||
IconTrash,
|
IconTrash,
|
||||||
MenuItem,
|
MenuItem,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
@ -23,7 +21,7 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
|||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType';
|
||||||
import { useDeleteViewFromCurrentState } from '@/views/view-picker/hooks/useDeleteViewFromCurrentState';
|
import { useDeleteViewFromCurrentState } from '@/views/view-picker/hooks/useDeleteViewFromCurrentState';
|
||||||
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
|
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
@ -85,9 +83,7 @@ export const ObjectOptionsDropdownMenuContent = () => {
|
|||||||
<DropdownMenuItemsContainer scrollable={false}>
|
<DropdownMenuItemsContainer scrollable={false}>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => onContentChange('layout')}
|
onClick={() => onContentChange('layout')}
|
||||||
LeftIcon={
|
LeftIcon={viewTypeIconMapping(currentView?.type ?? ViewType.Table)}
|
||||||
currentView?.type === ViewType.Table ? IconTable : IconLayoutKanban
|
|
||||||
}
|
|
||||||
text={t`Layout`}
|
text={t`Layout`}
|
||||||
contextualText={`${capitalize(currentView?.type ?? '')}`}
|
contextualText={`${capitalize(currentView?.type ?? '')}`}
|
||||||
hasSubMenu
|
hasSubMenu
|
||||||
|
|||||||
@ -61,6 +61,8 @@ export const ObjectOptionsDropdownMenuViewName = ({
|
|||||||
const [viewPickerSelectedIcon, setViewPickerSelectedIcon] =
|
const [viewPickerSelectedIcon, setViewPickerSelectedIcon] =
|
||||||
useRecoilComponentStateV2(viewPickerSelectedIconComponentState);
|
useRecoilComponentStateV2(viewPickerSelectedIconComponentState);
|
||||||
|
|
||||||
|
setViewPickerSelectedIcon(currentView.icon);
|
||||||
|
|
||||||
const viewPickerIsPersisting = useRecoilComponentValueV2(
|
const viewPickerIsPersisting = useRecoilComponentValueV2(
|
||||||
viewPickerIsPersistingComponentState,
|
viewPickerIsPersistingComponentState,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import { usePersistViewGroupRecords } from '@/views/hooks/internal/usePersistVie
|
|||||||
import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView';
|
import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView';
|
||||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||||
import { ViewGroup } from '@/views/types/ViewGroup';
|
import { ViewGroup } from '@/views/types/ViewGroup';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType';
|
||||||
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||||
@ -122,13 +122,20 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
setRecordIndexViewType(viewType);
|
setRecordIndexViewType(viewType);
|
||||||
await updateCurrentView(updateCurrentViewParams);
|
|
||||||
break;
|
if (shouldChangeIcon(currentView.icon, currentView.type)) {
|
||||||
|
updateCurrentViewParams.icon =
|
||||||
|
viewTypeIconMapping(viewType).displayName;
|
||||||
|
}
|
||||||
|
return await updateCurrentView(updateCurrentViewParams);
|
||||||
}
|
}
|
||||||
case ViewType.Table:
|
case ViewType.Table:
|
||||||
setRecordIndexViewType(viewType);
|
setRecordIndexViewType(viewType);
|
||||||
await updateCurrentView(updateCurrentViewParams);
|
if (shouldChangeIcon(currentView.icon, currentView.type)) {
|
||||||
break;
|
updateCurrentViewParams.icon =
|
||||||
|
viewTypeIconMapping(viewType).displayName;
|
||||||
|
}
|
||||||
|
return await updateCurrentView(updateCurrentViewParams);
|
||||||
default: {
|
default: {
|
||||||
return assertUnreachable(viewType);
|
return assertUnreachable(viewType);
|
||||||
}
|
}
|
||||||
@ -144,6 +151,25 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const shouldChangeIcon = (
|
||||||
|
oldIcon: string,
|
||||||
|
oldViewType: ViewType,
|
||||||
|
): boolean => {
|
||||||
|
if (
|
||||||
|
oldViewType === ViewType.Kanban &&
|
||||||
|
oldIcon === viewTypeIconMapping(ViewType.Kanban).displayName
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
oldViewType === ViewType.Table &&
|
||||||
|
oldIcon === viewTypeIconMapping(ViewType.Table).displayName
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setAndPersistViewType,
|
setAndPersistViewType,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,21 @@
|
|||||||
|
import { IconComponent, IconLayoutKanban, IconTable } from 'twenty-ui';
|
||||||
|
|
||||||
export enum ViewType {
|
export enum ViewType {
|
||||||
Table = 'table',
|
Table = 'table',
|
||||||
Kanban = 'kanban',
|
Kanban = 'kanban',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VIEW_TYPE_ICON_MAPPING = [
|
||||||
|
{ icon: IconLayoutKanban, value: ViewType.Kanban },
|
||||||
|
{ icon: IconTable, value: ViewType.Table },
|
||||||
|
] as const satisfies {
|
||||||
|
icon: IconComponent;
|
||||||
|
value: ViewType;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
export const viewTypeIconMapping = (viewType?: ViewType) => {
|
||||||
|
return (
|
||||||
|
VIEW_TYPE_ICON_MAPPING.find((type) => type.value === viewType)?.icon ??
|
||||||
|
IconTable
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
import { IconLayoutKanban, IconTable, IconX } from 'twenty-ui';
|
import { IconX } from 'twenty-ui';
|
||||||
|
|
||||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||||
import { IconPicker } from '@/ui/input/components/IconPicker';
|
import { IconPicker } from '@/ui/input/components/IconPicker';
|
||||||
import { Select } from '@/ui/input/components/Select';
|
import { Select } from '@/ui/input/components/Select';
|
||||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
||||||
|
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
||||||
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 { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
@ -16,7 +17,7 @@ import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/
|
|||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState';
|
import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState';
|
||||||
import { ViewsHotkeyScope } from '@/views/types/ViewsHotkeyScope';
|
import { ViewsHotkeyScope } from '@/views/types/ViewsHotkeyScope';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType';
|
||||||
import { ViewPickerCreateButton } from '@/views/view-picker/components/ViewPickerCreateButton';
|
import { ViewPickerCreateButton } from '@/views/view-picker/components/ViewPickerCreateButton';
|
||||||
import { ViewPickerIconAndNameContainer } from '@/views/view-picker/components/ViewPickerIconAndNameContainer';
|
import { ViewPickerIconAndNameContainer } from '@/views/view-picker/components/ViewPickerIconAndNameContainer';
|
||||||
import { ViewPickerSaveButtonContainer } from '@/views/view-picker/components/ViewPickerSaveButtonContainer';
|
import { ViewPickerSaveButtonContainer } from '@/views/view-picker/components/ViewPickerSaveButtonContainer';
|
||||||
@ -32,9 +33,8 @@ import { viewPickerIsPersistingComponentState } from '@/views/view-picker/states
|
|||||||
import { viewPickerKanbanFieldMetadataIdComponentState } from '@/views/view-picker/states/viewPickerKanbanFieldMetadataIdComponentState';
|
import { viewPickerKanbanFieldMetadataIdComponentState } from '@/views/view-picker/states/viewPickerKanbanFieldMetadataIdComponentState';
|
||||||
import { viewPickerSelectedIconComponentState } from '@/views/view-picker/states/viewPickerSelectedIconComponentState';
|
import { viewPickerSelectedIconComponentState } from '@/views/view-picker/states/viewPickerSelectedIconComponentState';
|
||||||
import { viewPickerTypeComponentState } from '@/views/view-picker/states/viewPickerTypeComponentState';
|
import { viewPickerTypeComponentState } from '@/views/view-picker/states/viewPickerTypeComponentState';
|
||||||
import { useMemo, useState } from 'react';
|
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
const StyledNoKanbanFieldAvailableContainer = styled.div`
|
const StyledNoKanbanFieldAvailableContainer = styled.div`
|
||||||
color: ${({ theme }) => theme.font.color.light};
|
color: ${({ theme }) => theme.font.color.light};
|
||||||
@ -101,8 +101,7 @@ export const ViewPickerContentCreateMode = () => {
|
|||||||
ViewsHotkeyScope.ListDropdown,
|
ViewsHotkeyScope.ListDropdown,
|
||||||
);
|
);
|
||||||
|
|
||||||
const defaultIcon =
|
const defaultIcon = viewTypeIconMapping(viewPickerType).displayName;
|
||||||
viewPickerType === ViewType.Kanban ? 'IconLayoutKanban' : 'IconTable';
|
|
||||||
|
|
||||||
const selectedIcon = useMemo(() => {
|
const selectedIcon = useMemo(() => {
|
||||||
if (hasManuallySelectedIcon) {
|
if (hasManuallySelectedIcon) {
|
||||||
@ -165,11 +164,15 @@ export const ViewPickerContentCreateMode = () => {
|
|||||||
setViewPickerType(value);
|
setViewPickerType(value);
|
||||||
}}
|
}}
|
||||||
options={[
|
options={[
|
||||||
{ value: ViewType.Table, label: t`Table`, Icon: IconTable },
|
{
|
||||||
|
value: ViewType.Table,
|
||||||
|
label: t`Table`,
|
||||||
|
Icon: viewTypeIconMapping(ViewType.Table),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: ViewType.Kanban,
|
value: ViewType.Kanban,
|
||||||
label: t`Kanban`,
|
label: t`Kanban`,
|
||||||
Icon: IconLayoutKanban,
|
Icon: viewTypeIconMapping(ViewType.Kanban),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
dropdownId={VIEW_PICKER_VIEW_TYPE_DROPDOWN_ID}
|
dropdownId={VIEW_PICKER_VIEW_TYPE_DROPDOWN_ID}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { prefetchViewsFromObjectMetadataItemFamilySelector } from '@/prefetch/st
|
|||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
import { viewTypeIconMapping } from '@/views/types/ViewType';
|
||||||
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
||||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||||
import { viewPickerInputNameComponentState } from '@/views/view-picker/states/viewPickerInputNameComponentState';
|
import { viewPickerInputNameComponentState } from '@/views/view-picker/states/viewPickerInputNameComponentState';
|
||||||
@ -66,7 +66,8 @@ export const ViewPickerContentEffect = () => {
|
|||||||
!viewPickerIsDirty
|
!viewPickerIsDirty
|
||||||
) {
|
) {
|
||||||
const defaultIcon =
|
const defaultIcon =
|
||||||
viewPickerType === ViewType.Kanban ? 'IconLayoutKanban' : 'IconTable';
|
viewTypeIconMapping(viewPickerType).displayName ?? 'IconTable';
|
||||||
|
|
||||||
if (viewPickerMode === 'create-empty') {
|
if (viewPickerMode === 'create-empty') {
|
||||||
setViewPickerSelectedIcon(defaultIcon);
|
setViewPickerSelectedIcon(defaultIcon);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { css, useTheme } from '@emotion/react';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { IconCheck, IconChevronRight, IconComponent } from '@ui/display';
|
import { IconCheck, IconChevronRight, IconComponent } from '@ui/display';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
import { MenuItemLeftContent } from '../internals/components/MenuItemLeftContent';
|
import { MenuItemLeftContent } from '../internals/components/MenuItemLeftContent';
|
||||||
import { StyledMenuItemBase } from '../internals/components/StyledMenuItemBase';
|
import { StyledMenuItemBase } from '../internals/components/StyledMenuItemBase';
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ type MenuItemSelectProps = {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
hovered?: boolean;
|
hovered?: boolean;
|
||||||
hasSubMenu?: boolean;
|
hasSubMenu?: boolean;
|
||||||
contextualText?: string;
|
contextualText?: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MenuItemSelect = ({
|
export const MenuItemSelect = ({
|
||||||
|
|||||||
Reference in New Issue
Block a user