# Positioner
> Utility component to help with positioning an element to an anchor.

<Callout variant="tip">

Positioner is used throughout Vera in components such as
[Tooltip](/components/toolip), [Popover](/components/popover) or [Menu](/components/menu).

</Callout>

## Import

```js
import { Positioner, Placement } from '@gemini-suite/vera-react';

// you may also access Positioner's context via hook:
// import { usePositionerContext } from '@gemini-suite/vera-react';
```

Positioner is a compound component that consists of multiple parts:

- `Positioner.Root`: The wrapper that contains all the parts of a positioner and provides context for its children.
- `Positioner.Anchor`: The reference component, the `Positioner.Box` should be anchored to.
- `Positioner.Box`: The box that positions its content dynamically relative to `Positioner.Anchor`.
- `Positioner.Content`: The content that pops out when the positioner is open.

## Examples

### Basic

```jsx
() => {
  const [isOpen, setIsOpen] = React.useState(false);

  const clickHandler = React.useCallback(() => setIsOpen(prev => !prev), []);

  return (
    <Positioner.Root>
      <Positioner.Anchor as={Button} onClick={clickHandler}>
        {'Open me'}
      </Positioner.Anchor>
      <Positioner.Box isOpen={isOpen} placement={Placement.TOP_RIGHT}>
        <Positioner.Content
          css={{
            border: '1px solid $borderNeutralSubtle',
            padding: '$spacingM',
            borderRadius: '$m',
            backgroundColor: '$backgroundNeutralMinimal'
          }}
        >
          {`Hello, i'm inside positioner!`}
        </Positioner.Content>
      </Positioner.Box>
    </Positioner.Root>
  );
};
```

### Anchoring to any coordinates

`Positioner.Box` can be anchored relative to something that isn't a DOM node, such as mouse position.
This is achieved by passing `virtualRef` property to `Positioner.Anchor`.

<Callout variant="tip">

Read more about the concept of `virtualRef` at <https://floating-ui.com/docs/virtual-elements>.

</Callout>

In the example below, the box is located at the coordinates of a right-click.

```jsx
() => {
  const [isOpen, setIsOpen] = React.useState(false);
  const mousePosRef = React.useRef({ x: 0, y: 0 });
  const virtualRef = React.useRef({
    getBoundingClientRect: () =>
      DOMRect.fromRect({ width: 0, height: 0, ...mousePosRef.current })
  });

  const handleContextMenu = React.useCallback(event => {
    mousePosRef.current = { x: event.clientX, y: event.clientY };
    setIsOpen(true);

    event.preventDefault();
  });

  return (
    <Box
      css={{
        display: 'grid',
        placeItems: 'center',
        height: '7rem',
        border: '2px dashed $borderNeutralSubtle',
        borderRadius: '$m'
      }}
      onContextMenu={handleContextMenu}
    >
      <Box css={{ color: '$foregroundNeutralModerate' }}>
        {'Right click me'}
      </Box>
      <Positioner.Root>
        <Positioner.Anchor virtualRef={virtualRef} />
        <Positioner.Box isOpen={isOpen} placement={Placement.BOTTOM_LEFT}>
          <DismissableLayer
            as={Slot}
            onDismiss={() => {
              setIsOpen(false);
            }}
          >
            <Positioner.Content
              css={{
                border: '1px solid $borderNeutralSubtle',
                padding: '$spacingM',
                borderRadius: '$m',
                backgroundColor: '$backgroundNeutralMinimal'
              }}
            >
              {`Hello, i'm inside positioner!`}
            </Positioner.Content>
          </DismissableLayer>
        </Positioner.Box>
      </Positioner.Root>
    </Box>
  );
};
```

---

## API Reference

### Positioner.Root

| Name       | Type              | Default | Description | Required |
| ---------- | ----------------- | ------- | ----------- | -------- |
| `children` | `React.ReactNode` |         |             |          |

### Positioner.Anchor

| Name         | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ------------ | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`         | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `div`   | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`        | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
| `virtualRef` | `React.RefObject<Measurable>`                             |         | A virtual ref is a plain object that has a `getBoundingClientRect` method, which mimics a real element's one.                                                                                                                                                                                |          |

### Positioner.Box

| Name               | Type                                                                                                     | Default         | Description                                                                                                                                                                                                                                   | Required |
| ------------------ | -------------------------------------------------------------------------------------------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `isOpen`           | `boolean`                                                                                                | `false`         | Open state of the positioner.                                                                                                                                                                                                                 | Yes      |
| `placement`        | `"top" \| "top_left" \| "top_right" \| "bottom" \| "bottom_left" \| "bottom_right" \| "left" \| "right"` | `"bottom_left"` | Placement of the element being positioned on. Smart positioning might override this.                                                                                                                                                          |          |
| `anchorOffset`     | `number`                                                                                                 |                 | Distance from the anchor to the element being positioned.                                                                                                                                                                                     |          |
| `overflowPadding`  | `number`                                                                                                 |                 | The minimum padding between the positioned element and the viewport edge.                                                                                                                                                                     |          |
| `enableAutoUpdate` | `boolean`                                                                                                | `true`          | Controls whether to automatically update the position of the box so it remains anchored to the anchor element.                                                                                                                                |          |
| `onExitComplete`   | `() => void`                                                                                             | `() => void`    | Event handler called when the positioner content has completed animating out.                                                                                                                                                                 |          |
| `css`              | `StitchesCss`                                                                                            |                 | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants. |          |

### Positioner.Content

<Callout variant="tip">

`Positioner.Content` uses [Motion Box](/components/utility/motion-box) under the hood.

</Callout>

| Name  | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ----- | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`  | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `div`   | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css` | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
