# `useContextMenu` Hook

## Purpose

`useContextMenu` is a React hook that enables components to display context menus (like `Menu` or `CommandMenu`) at the exact cursor position where the user right-clicked or triggered a context action. Unlike [`useAnchoredMenu`](./use-anchored-menu.md) which anchors menus to specific elements, `useContextMenu` positions menus at cursor coordinates or centers them on the target element, making it perfect for traditional right-click context menus and programmatic menu opening.

The hook automatically handles `onContextMenu` event binding and provides a clean API for both automatic (right-click) and programmatic menu opening.

## Related Components

- [`useAnchoredMenu`](./use-anchored-menu.md) - For menus anchored to specific elements
- [`MenuTrigger`](./MenuTrigger.md) - The underlying trigger component used for positioning
- [`Menu`](./Menu.md) - The menu component typically used with this hook
- [`CommandMenu`](./CommandMenu.md) - Command palette component that can be used with this hook

## API

```ts
function useContextMenu<P, T = ComponentProps<typeof MenuTrigger>>(
  Component: ComponentType<P>,
  defaultTriggerProps?: Omit<
    ComponentProps<typeof MenuTrigger>,
    'children' | 'isOpen' | 'onOpenChange' | 'targetRef'
  >,
  defaultMenuProps?: P,
): {
  /** Container element that receives context menu events. Attach this ref to your target element. */
  targetRef: RefObject<HTMLElement>;

  /**
   * Programmatically opens the menu at the specified coordinates or element center.
   * Runtime props are merged with defaultMenuProps (runtime props take precedence).
   *
   * @param props - Props to pass to the menu component (optional, defaults to defaultMenuProps)
   * @param triggerProps - Additional props for MenuTrigger (merged with defaultTriggerProps)
   * @param event - The pointer/mouse event containing coordinates for positioning (optional, centers on element if not provided)
   */
  open(
    props?: P,
    triggerProps?: T,
    event?: MouseEvent | PointerEvent,
  ): void;

  /**
   * Updates the props of the currently open menu without repositioning.
   * Props are merged with defaultMenuProps.
   */
  update(props: P, triggerProps?: T): void;

  /** Closes the menu programmatically. */
  close(): void;

  /** Current open/closed state of the menu. */
  isOpen: boolean;

  /**
   * JSX element that must be rendered in your component tree.
   * Contains the MenuTrigger and positioning logic.
   * IMPORTANT: Must be placed directly inside the target container (the element with targetRef).
   */
  get rendered(): ReactElement | null;
};
```

### Parameters

- **`Component`** - The menu component to render (`Menu`, `CommandMenu`, etc.)
- **`defaultTriggerProps`** - Default props passed to `MenuTrigger` for positioning and behavior
- **`defaultMenuProps`** - Default props passed to the menu component (used for automatic right-click opening)

## Key Features

### Automatic Context Menu Binding

The hook automatically binds `onContextMenu` events to the `targetRef` element:

- **Right-click** automatically opens the menu using `defaultMenuProps`
- **`event.preventDefault()`** is called automatically to suppress the browser's native context menu
- **No manual event binding required** in most cases

### Flexible Positioning

`useContextMenu` supports two positioning modes:

1. **Coordinate-Based Positioning** (when event is provided):
   - Creates an **invisible anchor element** at click coordinates
   - Supports **collision detection** and automatic repositioning
   - **Clamps coordinates** to stay within the container bounds
   - Works with **scrollable containers** by accounting for scroll offset

2. **Center Positioning** (when no event is provided):
   - Positions the menu at the **center of the target element**
   - Useful for **programmatic menu opening** from buttons or keyboard shortcuts
   - Respects **element padding and borders** for accurate centering

### Props Merging Strategy

The hook provides flexible prop management:

- **`defaultMenuProps`** - Used for automatic right-click opening
- **Runtime props** (via `open()`) - Merged with defaults, taking precedence
- **Trigger props** - Merged with `defaultTriggerProps` for positioning control

### Menu Synchronization

Integrates with the global menu synchronization system:

- **Only one menu open** at a time across the entire application
- **Automatic closing** when other menus open
- **Works with** `MenuTrigger`, `useAnchoredMenu`, `Select`, `ComboBox`, etc.

## Basic Usage

```tsx
import { useContextMenu, Menu } from '@cube-dev/ui-kit';

function FileItem({ file }) {
  const handleAction = (key) => {
    console.log(`Action ${key} on ${file.name}`);
  };

  const { targetRef, rendered } = useContextMenu(
    Menu,
    { placement: 'bottom start' },     // trigger props
    { 
      onAction: handleAction,
      children: (
        <>
          <Menu.Item key="open">Open</Menu.Item>
          <Menu.Item key="rename">Rename</Menu.Item>
          <Menu.Item key="delete">Delete</Menu.Item>
        </>
      )
    }
  );

  return (
    <div ref={targetRef} className="file-item">
      {/* IMPORTANT: rendered must be placed directly inside the target container */}
      {rendered}
      <span>{file.name}</span>
    </div>
  );
}
```

> **Important:** The `{rendered}` element must be placed **directly inside** the element that has the `targetRef` attached. This ensures proper coordinate calculation and positioning for the context menu.

## Comparison with Related Hooks

- **`Positioning`** — useContextMenu: Cursor coordinates or element center; useAnchoredMenu: Element-anchored
- **`Trigger`** — useContextMenu: Right-click (automatic) + programmatic; useAnchoredMenu: Manual (button click)
- **`Event Binding`** — useContextMenu: Automatic `onContextMenu`; useAnchoredMenu: Manual event handling
- **`Use Cases`** — useContextMenu: Context menus, right-click actions, toolbar dropdowns; useAnchoredMenu: Dropdown menus, action buttons
- **`Default Placement`** — Both: `"bottom start"`
- **`Setup Complexity`** — useContextMenu: Minimal (auto-binding); useAnchoredMenu: Manual event handling

## Implementation Notes

### Coordinate Calculation

The hook calculates menu position differently based on whether an event is provided:

**With Event (Coordinate-Based):**
1. **Getting viewport coordinates** from the pointer event
2. **Converting to container-relative coordinates** accounting for borders and scroll
3. **Clamping to container bounds** to ensure the menu stays visible
4. **Creating an invisible anchor** at the calculated position
5. **Delegating to MenuTrigger** for collision detection and final positioning

**Without Event (Center-Based):**
1. **Calculating element center** using `clientWidth/2` and `clientHeight/2`
2. **Accounting for scroll offset** to position relative to content area
3. **Clamping to container bounds** to ensure proper positioning
4. **Creating an invisible anchor** at the center position

### Event Handling

- **Automatic binding** occurs via `useEffect` on the `targetRef`
- **Event listeners** are properly cleaned up on unmount
- **`preventDefault()`** is called automatically for context menu events
- **Manual `open()` calls** can still prevent default if an event is provided

### Memory Management

- **Event listeners** are bound/unbound automatically
- **Menu content** is only rendered when needed
- **Position calculations** are performed only when opening
- **No memory leaks** from uncleaned event handlers

### Rendered Element Placement

The `{rendered}` element contains the invisible anchor and MenuTrigger components needed for positioning. It **must** be placed directly inside the element with `targetRef` because:

- **Coordinate calculations** are relative to the target container
- **Scroll offset handling** requires the rendered element to be within the scrollable area
- **CSS positioning context** needs to be established correctly
- **Event coordinate mapping** depends on the proper parent-child relationship

```tsx
// ✅ Correct placement
<div ref={targetRef}>
  {rendered}
  <content />
</div>

// ❌ Incorrect placement
<div>
  <div ref={targetRef}>
    <content />
  </div>
  {rendered}
</div>
```

---

*Last updated: 2025-01-16* 

### Style Properties

These properties allow direct style application without using the `styles` prop:

- **Base:** `display`, `font`, `preset`, `hide`, `whiteSpace`, `opacity`, `transition`
- **Position:** `gridArea`, `order`, `gridColumn`, `gridRow`, `placeSelf`, `alignSelf`, `justifySelf`, `zIndex`, `margin`, `inset`, `position`
- **Dimension:** `width`, `height`, `flexBasis`, `flexGrow`, `flexShrink`, `flex`
- **Block:** `border`, `radius`, `shadow`, `outline`, `padding`, `paddingInline`, `paddingBlock`, `overflow`, `scrollbar`, `textAlign`
- **Color:** `color`, `fill`, `fade`, `image`
- **Flow:** `flow`, `placeItems`, `placeContent`, `alignItems`, `alignContent`, `justifyItems`, `justifyContent`, `align`, `justify`, `gap`, `columnGap`, `rowGap`, `gridColumns`, `gridRows`, `gridTemplate`, `gridAreas`
