/**
* ContextMenu — the actions that belong to a piece of content, opened on it.
*
* A `Menu` hangs off a control that exists to be pressed: a ⋯ button, a toolbar
* item, something whose whole job is to open the menu. A context menu has no
* such control. The target is the content itself — a message, a note, a photo,
* a row — and the actions are reached by holding it, by a named accessibility
* action, or from the keyboard.
*
* ```tsx
*
*
* Would you like an interactive todo list?
*
*
* }>Share
* }>Copy
*
* }>
* Report
*
*
*
* ```
*
* ## It is a Menu, and deliberately so
*
* The rows here *are* `Menu`'s rows — the same components, not a second set
* styled to match. `ContextMenu.Item` and `Menu.Item` are one implementation,
* so the destructive colour, the press-in scale, the indicator column and the
* dismiss-on-select rule cannot drift apart between the two ways of reaching
* them. The panel is `Menu`'s panel, which is `Popover`'s, so `presentation`,
* submenus and edge-flipping all arrive already working.
*
* What this component owns is what a menu opened on content needs and a menu
* opened from a button does not: alternate invocation paths, and where the
* panel goes.
*
* ## Anchored to the finger, not to the target
*
* A toolbar menu is placed against its trigger, because the trigger is small
* and its position is the only sensible answer. A context menu's target is
* often most of the screen — a whole message, a whole card — and the middle of
* it is not where the finger was. So the anchor is the press point by default,
* and the panel unfolds from it the way a popover unfolds from a button.
*
* `anchor="target"` places it against the target's bounds instead, which is the
* better answer for something small and list-shaped, where the panel lining up
* with the row reads as belonging to it.
*
* ## Why the gesture is not a Pressable
*
* The target usually has a press of its own — open the thread, play the video,
* follow the link — and the two must not both fire. React Native's `Pressable`
* decides between them after the fact, and the tap can still get through on the
* way to a long press; the recogniser here is asked for the arbitration up
* front instead, so a hold that opens the menu never also counts as a press.
*
* It is also what lets the target be anything at all. A cloned `onLongPress`
* needs a child that takes one, which rules out exactly the plain views —
* bubbles, cards, images — that content-native actions are usually attached to.
*/
import { type ReactNode } from 'react';
import { type ViewProps } from 'react-native';
import { type MenuCheckboxItemProps, type MenuContentProps, type MenuItemProps, type MenuProps } from '../menu/index.js';
import { type ContextMenuKeyDownEvent } from './context-menu-invocation.js';
/**
* The root takes exactly what `Menu`'s root takes — `open`, `onOpenChange`,
* `defaultOpen`, `presentation` and `haptics` — because it *is* that root.
*/
export type ContextMenuProps = MenuProps;
/**
* The root. Provides the menu's own context and the popover underneath it.
*
* It renders a `Menu`, which is not a shortcut — it is the point. Everything a
* menu is, this is, and the parts below are the only difference.
*/
declare function ContextMenuRoot({ children, ...props }: ContextMenuProps): import("react").JSX.Element;
/** Which rectangle the panel is placed against. */
export type ContextMenuAnchor = 'point' | 'target';
export interface ContextMenuTriggerProps extends Omit {
/**
* Classes on the wrapper the content sits in, which lays out like any other
* view — it does not shrink to its child, because the things held are usually
* meant to fill their place in the layout. It is also the rect
* `anchor="target"` measures.
*/
className?: string;
/**
* The content the actions belong to. Anything at all — it is not required to
* be pressable, and is not cloned or altered.
*/
children: ReactNode;
/**
* `point` anchors the panel where the finger landed, `target` against the
* bounds of the whole trigger.
*
* Point is the default because a context menu's target is usually large, and
* the middle of a whole message is not where the press was. Reach for
* `target` when the target is small and list-shaped and the panel should read
* as lining up with it. Keyboard and accessibility opens always use the target
* bounds, because those modalities have no pointer coordinate.
*/
anchor?: ContextMenuAnchor;
/** How long the hold has to last, in milliseconds. 350 by default. */
delay?: number;
/**
* How far the finger may move during the hold before it stops being one, in
* points. 12 by default.
*
* Loose rather than tight, because the target is usually inside a scroller: a
* threshold small enough to feel precise cancels the menu for anyone whose
* thumb drifts while holding still, and a scroll has travelled much further
* than this by the time the two need telling apart. Tighten it only for a
* target that cannot be scrolled.
*/
slop?: number;
/** A short press on the target, which the hold never also counts as. */
onPress?: () => void;
/**
* Tick the haptic engine as the menu opens. Needs the optional
* `expo-haptics`, and is silent without it.
*
* Worth setting more often than not. A hold has no edge to it the way a press
* does — nothing moves under the finger at the moment it takes — so the tick
* is what tells someone the hold has been long enough, before the panel has
* had time to say so.
*/
haptics?: boolean;
/** Nothing opens the menu, and the short press stops firing too. */
disabled?: boolean;
/**
* Called first for keyboard events. Prevent the event to keep ContextMenu
* from handling it. Context Menu and Shift+F10 open the menu; Enter and Space
* mirror the trigger's accessible activation.
*/
onKeyDown?: (event: ContextMenuKeyDownEvent) => void;
}
/**
* Wraps the content and opens the menu when held, through accessibility
* actions, or from the keyboard.
*
* The wrapper is a plain view and lays out like one, stretching as a view does
* rather than shrinking to its child. That is the opposite of what a tooltip's
* trigger wants, and for the opposite reason: a tooltip names a control and
* belongs over it, while the things held here — a bubble, a card, a row — are
* usually meant to fill their place in the layout, and a wrapper that collapsed
* around them would change it.
*
* It is also the rect measured under `anchor="target"`, which is why that
* anchoring lines the panel up with the row rather than with the text in it.
*/
declare function ContextMenuTrigger({ className, children, anchor, delay, slop, onPress, haptics, disabled, accessible, accessibilityActions, onAccessibilityAction, accessibilityRole, accessibilityState, focusable, tabIndex, onKeyDown, ...props }: ContextMenuTriggerProps): import("react").JSX.Element;
export interface ContextMenuPreviewProps {
/**
* Drawn instead of the target itself. For a target that would be wrong to
* repeat — one carrying a video, a live map, a text field with a cursor in
* it — or one that should show more of itself once it has the screen.
*
* Left out, the target is drawn again as it stands, which is what makes the
* lift read as the content coming forward rather than as a picture of it
* appearing.
*/
children?: ReactNode;
/** Extra classes on the lifted copy. */
className?: string;
}
/**
* The target, lifted off the page while its actions are up.
*
* Declared inside `ContextMenu.Content`, but not drawn there — it floats over
* the dimmed screen at the place the target was measured, and the panel is
* anchored to that same rectangle so the two never overlap. Its presence is
* what switches the anchor: a panel placed at the press point would open across
* the very content the preview exists to hold up.
*
* What it draws is the trigger's own children, rendered a second time. That
* keeps the lift honest — it is the content itself coming forward, at the size
* and in the place it already occupied — and it is why a target that should not
* simply be repeated can pass its own `children` instead.
*
* It takes no touches. The actions are in the panel; the lifted content is
* there to say what they are about, and a second live copy of a pressable card
* would be a second place to press.
*/
declare function ContextMenuPreview({ children, className }: ContextMenuPreviewProps): import("react").JSX.Element | null;
declare namespace ContextMenuPreview {
var displayName: string;
}
export interface ContextMenuItemProps extends MenuItemProps {
/**
* The row's glyph, drawn at the trailing edge rather than in front of the
* label. Painted to match the label unless it carries a colour of its own.
*/
icon?: ReactNode;
}
/**
* One row: the verb at the leading edge, its glyph at the trailing one.
*
* The other way round is right for a menu dropped from a button, where the
* glyphs form a column the eye runs down to find the row it wants. A context
* menu is not read that way. It appears under the hand that opened it, already
* over the content, and what is being scanned is the *words* — so the words
* start at the edge, flush with one another, and the glyph sits at the far side
* confirming the row rather than introducing it.
*
* It is still `Menu.Item` underneath, handed the glyph as its trailing slot. So
* the press-in fill, the destructive colour and the dismiss-on-select rule are
* one implementation shared with `Menu`, and only the arrangement differs.
*/
declare function ContextMenuItem({ className, icon, variant, ...props }: ContextMenuItemProps): import("react").JSX.Element;
declare namespace ContextMenuItem {
var displayName: string;
}
/**
* A row carrying a state. Its tick stays at the leading edge, where `Menu` puts
* it, because a tick is not a glyph naming the row — it is the answer to it,
* and a column of them is what makes a set of choices readable as one.
*/
declare function ContextMenuCheckboxItem({ className, ...props }: MenuCheckboxItemProps): import("react").JSX.Element;
declare namespace ContextMenuCheckboxItem {
var displayName: string;
}
/**
* Everything `Menu.Content` takes. The four listed here are the ones whose
* defaults differ, and they are listed so the difference is visible.
*/
export interface ContextMenuContentProps extends MenuContentProps {
/** Which side of the anchor the panel opens on. Down from the press, flipping
* above it near the bottom of the screen. */
placement?: MenuContentProps['placement'];
/** Where it sits along the other axis. From the press, not centred on it. */
align?: MenuContentProps['align'];
/** Gap between the anchor and the panel. Small, so it reads as coming out of
* the press rather than floating near it. */
offset?: number;
/**
* Floor for the panel's width. A context menu has no trigger to take its
* width from, and a column of one-word verbs is too narrow to aim at.
*/
minWidth?: number;
/** Dim the screen behind the panel. On here, unlike a plain popover. */
scrim?: boolean;
}
/**
* The panel, with the defaults a context menu wants rather than a popover's.
*
* It unfolds down and from the press rather than being centred on it —
* centring is right for a panel under a button, and wrong for one at a
* fingertip, where it would put half the panel back under the hand that opened
* it. Near the bottom of the screen `Popover` flips it above the press and
* clamps it into the safe area, so the one case where down does not work
* answers itself.
*
* The gap to the anchor is small, so the panel reads as coming out of the press
* rather than floating near it.
*
* The screen dims behind it, which a popover does not do. A context menu is
* modal in practice — the content underneath is what the actions are *about*,
* so nothing else on the screen is available while it is up, and the dim is
* what says so.
*/
declare function ContextMenuContent({ placement, align, offset, minWidth, scrim, children, ...props }: ContextMenuContentProps): import("react").JSX.Element;
export declare const ContextMenu: typeof ContextMenuRoot & {
Trigger: typeof ContextMenuTrigger;
Content: typeof ContextMenuContent;
Preview: typeof ContextMenuPreview;
Background: typeof import("../menu/index.js").MenuBackground;
Label: typeof import("../menu/index.js").MenuLabel;
Item: typeof ContextMenuItem;
CheckboxItem: typeof ContextMenuCheckboxItem;
RadioGroup: typeof import("../menu/index.js").MenuRadioGroup;
RadioItem: typeof import("../menu/index.js").MenuRadioItem;
Separator: typeof import("../menu/index.js").MenuSeparator;
Sub: typeof import("../menu/index.js").MenuSub;
SubTrigger: typeof import("../menu/index.js").MenuSubTrigger;
SubContent: typeof import("../menu/index.js").MenuSubContent;
};
export {};
//# sourceMappingURL=index.d.ts.map