# Upgrading usePopupMenu to 0.13.0

[Back to usePopupMenu](https://github.com/NantHealth/featherk/blob/integration/packages/composables/docs/menu/usePopupMenu.md)

This guide covers migration from `@featherk/composables` 0.12.x to 0.13.0.

## Required Changes

Version 0.13.0 renames three returned handlers so their names apply equally to button and row triggers.

| 0.12.x                      | 0.13.0                 |
| --------------------------- | ---------------------- |
| `handleActionButtonClick`   | `handleTriggerClick`   |
| `handleActionButtonKeydown` | `handleTriggerKeydown` |
| `handleActionMenuEscape`    | `handleMenuEscape`     |

Before:

```vue
<button
  @click="menu.handleActionButtonClick"
  @keydown="menu.handleActionButtonKeydown"
/>
<Menu @keydown.escape="menu.handleActionMenuEscape" />
```

After:

```vue
<button @click="menu.handleTriggerClick" @keydown="menu.handleTriggerKeydown" />
<Menu @keydown.escape="menu.handleMenuEscape" />
```

Search all consumer source for:

```text
handleActionButtonClick
handleActionButtonKeydown
handleActionMenuEscape
```

The old properties are removed rather than retained as aliases.

## Optional: Replace Manual Activation Geometry

Custom `getRect(trigger)` remains supported. Consumers that manually store pointer coordinates relative to a trigger can remove that state and use activation-point anchoring.

Before:

```ts
const point = ref<{ x: number; y: number } | null>(null);

const menu = usePopupMenu({
  // Other required options omitted.
  anchor: {
    intersectionThreshold: 0,
    getRect: (trigger) => {
      const rect = trigger.getBoundingClientRect();
      return point.value
        ? new DOMRect(rect.left + point.value.x, rect.top + point.value.y, 0, 0)
        : null;
    },
  },
});
```

After:

```ts
const menu = usePopupMenu({
  // Other required options omitted.
  anchor: {
    activationPoint: { pointerOffset: { x: -12, y: -12 } },
  },
});

const trigger = registry.resolve(id);
if (trigger && menu.setAnchorActivation(trigger, context)) {
  registry.activate(id);
}
```

Capture before activating a shared registry id. Pointer coordinates become trigger-relative automatically; keyboard activation defaults to 8px from the left and vertically centered. Internal activation state clears when the menu closes.

## Optional: Simplify Focus Restoration

Before:

```ts
resolveFocusTarget: () =>
  registry.activeElement.value?.closest(".k-table-row") ?? null,
```

After:

```ts
focusTargetContainerSelector: ".k-table-row",
```

Keep `resolveFocusTarget` when the target cannot be expressed as the trigger's closest matching ancestor. Its precedence remains higher than `focusTargetRef` and `focusTargetContainerSelector`.

## Unchanged Contracts

- The consumer owns `isOpen`, `requestShow`, and `requestHide`.
- The consumer provides static `aria-haspopup="menu"` and baseline `aria-expanded="false"`.
- `usePopupMenu` updates only `aria-expanded` unless ARIA management is disabled.
- `anchor: true` continues to follow the trigger's bottom-left corner.
- Custom `getRect(trigger)` remains supported and is source-compatible with zero-argument callbacks.
- Intersection dismissal and the `"anchor-hidden"` close reason are unchanged.
- `useActiveIdRegistry`, `useExclusiveGroup`, and `useGridRowAction` remain independent composables.
- Package root and `@featherk/composables/menu` imports remain supported.

## Custom Geometry Fallback

Activation-point anchoring is optional. Retain `getRect(trigger)` when the popup must follow geometry that is not derived from a pointer or keyboard activation, such as a selection rectangle or a domain-specific virtual anchor.
