import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { type ReactNode, lazy, Suspense, useState } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { type IconComponent } from 'twenty-ui/icon'; import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem'; import { addToNavPayloadRegistryState } from '@/navigation-menu-item/common/states/addToNavPayloadRegistryState'; import { navigationMenuItemEditSectionState } from '@/navigation-menu-item/common/states/navigationMenuItemEditSectionState'; import type { AddToNavigationDragPayload } from '@/navigation-menu-item/common/types/add-to-navigation-drag-payload'; import { AddToNavigationDragHandle } from '@/navigation-menu-item/display/dnd/components/AddToNavigationDragHandle'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; const CommandMenuItemWithAddToNavigationDragDndKit = lazy(() => import('@/command-menu/components/CommandMenuItemWithAddToNavigationDragDndKit').then( (m) => ({ default: m.CommandMenuItemWithAddToNavigationDragDndKit, }), ), ); type SidePanelItemWithAddToNavigationDragProps = { icon?: IconComponent; customIconContent?: ReactNode; label: string; description?: string; id: string; onClick: () => void; payload: AddToNavigationDragPayload; dragIndex?: number; disabled?: boolean; disableDrag?: boolean; }; const StyledDraggableMenuItem = styled.div<{ $disabled?: boolean; $disableDrag?: boolean; }>` cursor: ${({ $disabled, $disableDrag }) => $disabled || $disableDrag ? 'default' : 'grab'}; pointer-events: ${({ $disabled }) => ($disabled ? 'none' : 'auto')}; width: 100%; &:active { cursor: ${({ $disabled, $disableDrag }) => $disabled || $disableDrag ? 'default' : 'grabbing'}; } `; export const SidePanelItemWithAddToNavigationDrag = ({ icon, customIconContent, label, description, id, onClick, payload, dragIndex, disabled = false, disableDrag = false, }: SidePanelItemWithAddToNavigationDragProps) => { const { t } = useLingui(); const setAddToNavPayloadRegistry = useSetAtomState( addToNavPayloadRegistryState, ); const navigationMenuItemEditSection = useAtomStateValue( navigationMenuItemEditSectionState, ); const [isHovered, setIsHovered] = useState(false); // Favorites are added by click only; drag-to-add targets the workspace // sidebar and runs through layout-customization mode. const effectiveDisableDrag = disableDrag || navigationMenuItemEditSection === 'favorite'; const showDragAffordance = !disabled && !effectiveDisableDrag && isHovered; const contextualDescription = showDragAffordance ? t`Drag to add to navbar` : description; const DragHandleIcon = () => ( ); const registerPayload = () => { if (!disabled && !effectiveDisableDrag && isDefined(dragIndex)) { setAddToNavPayloadRegistry((prev) => new Map(prev).set(id, payload)); } }; const menuItemContent = ( { if (!disabled && !effectiveDisableDrag) { setIsHovered(true); registerPayload(); } }} onMouseLeave={() => { if (!disabled && !effectiveDisableDrag) setIsHovered(false); }} onMouseDown={registerPayload} > ); if (!isDefined(dragIndex) || effectiveDisableDrag) { return menuItemContent; } return ( ); };