/** * Frame — a widget shell: a card of rows sitting in a tray, with the tray's * one exposed strip along the top carrying the title. * * The two surfaces are nested rather than stacked, and only one edge of the * outer one is ever visible. The panel is flush to the shell's left, right and * bottom, so the shell reads as something the card is *sitting in* rather than * as a border around it — and the strip left at the top is the header, which * is why the header needs no rule under it and no background of its own. * * The shell's radius is the larger of the two, and the panel's top corners are * tighter. That is the reverse of the usual nested-radius rule, and it is * deliberate: with only the top corners free, matching them would make the two * surfaces read as one misdrawn shape. The panel's bottom corners are not set * at all — the shell clips them, so they take its radius exactly. * * That clip follows the shell's *border box*, not the box inside its border. * Along the straight edges the panel is held off by the border width and the * edge shows through, but at the corner arcs the panel's square corner is * clipped to the outer radius and paints across the border. At the default * hairline that is a sliver nobody sees. Give the shell a thicker border and * the corners visibly eat it, so a Frame with `border-2` or more needs the * panel told where to stop: * * ```tsx * * … * * ``` * * The radius to use is the shell's less its border width. It is on the caller * because both arrive as `className` strings, which the component cannot read. * * ```tsx * * * Agent monitor * All agents under 25% token limit * * * * * * opus-4.6 * Indexing the repository * * Running * * * * ``` * * `inset` is the other way to nest the two. The panel floats clear of the * shell on all four sides rather than sitting flush against three, and the band * left around it carries `Frame.Footer`. The band is a recess: the shell is the * popover surface with `--color-inset` laid over it rather than a colour of its * own, so it always comes out darker than the panel it holds. The surface * ladder cannot do that job — it runs darker in a light theme and lighter in a * dark one, and a recess has to read the same way in both. * * There is no shadow under it. A recessed band and a drop shadow are opposite * claims about where a surface sits, and this one is set into the page. * * The panel draws the hairlines between its own rows. React Native has no * `:first-child`, so the alternative is every caller writing * `divided={index > 0}` on every row and getting it wrong once. * * A row is three slots, and they exist because of one React Native detail: * Yoga defaults `flexShrink` to `0`, the opposite of the web. A child that is * not told to shrink never does, so a fourth thing in a row pushes the others * past the edge — where the frame's `overflow-hidden` silently cuts them off * rather than wrapping or truncating. `Frame.Media` and `Frame.Actions` hold * their size, `Frame.Content` takes what is left and is allowed to shrink to * nothing, and the row fits at any width without the caller measuring anything. */ import { type ReactNode } from 'react'; import { View, type PressableProps, type Text as RNText, type ViewProps } from 'react-native'; import { type TextProps } from '../../primitives/text.js'; export type FrameVariant = 'default' | 'plain' | 'inset'; export interface FrameProps extends ViewProps { className?: string; } export interface FrameRootProps extends FrameProps { /** * `plain` drops the outer shell so the panel is the widget — for a Frame * inside a container that already draws its own border. `inset` sets the * panel into a recessed band on all four sides instead, and gives * `Frame.Footer` somewhere to sit. */ variant?: FrameVariant; } export interface FrameHeaderProps extends FrameProps { children?: ReactNode; } export interface FrameActionProps extends FrameProps { children?: ReactNode; } export interface FrameMediaProps extends FrameProps { children?: ReactNode; } export interface FrameContentProps extends FrameProps { children?: ReactNode; } export interface FrameActionsProps extends FrameProps { children?: ReactNode; } /** * Marks the parts that take part in the panel's own divider bookkeeping — * a Row draws a line above itself, a Section draws one above its heading. * Anything else the panel is given is left alone. */ interface Dividable { divided?: boolean; } export interface FramePanelProps extends FrameProps { /** * Set false to place the hairlines by hand instead — for a panel whose rows * are generated somewhere the divider order is not obvious. */ dividers?: boolean; children?: ReactNode; } export interface FrameRowProps extends Omit, Dividable { className?: string; /** * Draw a hairline above this row. `Frame.Panel` sets it for you; pass it * explicitly to override the panel's decision either way. */ divided?: boolean; /** Trailing chevron marking the row as leading somewhere. */ chevron?: boolean; /** * Let the row run onto a second line instead of holding one. For a cluster * of chips or tags, where the alternative is the last ones being clipped. */ wrap?: boolean; /** * Where the row's slots sit against each other. `start` for a row two or * three lines tall, where centring an icon against a tall text column leaves * it floating in the middle. */ align?: 'center' | 'start'; children?: ReactNode; } export interface FrameSectionProps extends FrameProps, Dividable { /** Heading above the rows. Strings are wrapped for you. */ title?: ReactNode; divided?: boolean; children?: ReactNode; } export interface FrameFooterProps extends FrameProps { children?: ReactNode; } export declare const Frame: import("react").ForwardRefExoticComponent> & { Header: import("react").ForwardRefExoticComponent>; Title: import("react").ForwardRefExoticComponent>; Action: import("react").ForwardRefExoticComponent>; Description: import("react").ForwardRefExoticComponent>; Panel: import("react").ForwardRefExoticComponent>; Footer: import("react").ForwardRefExoticComponent>; Section: import("react").ForwardRefExoticComponent>; Row: import("react").ForwardRefExoticComponent>; Media: import("react").ForwardRefExoticComponent>; Content: import("react").ForwardRefExoticComponent>; Actions: import("react").ForwardRefExoticComponent>; }; export {}; //# sourceMappingURL=index.d.ts.map