/** * Compare — two versions of one picture, with a seam the reader drags across * it. * * ```tsx * * * * * * * * * * ``` * * ## What it is for * * Showing that two images differ, when they differ in a way a pair of * thumbnails side by side will not carry. Retouching, a filter, a render at two * quality settings, a map at two dates: the change is spread across the frame * rather than gathered in one place, and the eye cannot hold one image well * enough to spot it in the other. * * The seam works because both versions are in the same place on the screen at * the same scale. Every pixel the reader is comparing is a pixel that was just * under the one beside it, so the difference arrives as movement rather than as * something to be remembered. * * ## It clips, it does not resize * * The revealed side is a window onto a full-size copy of its content, not a * copy of the content squeezed into the window. That distinction is the whole * implementation: a view whose width is animated will lay its children out * again at every new width, so an image inside one is an image being squashed * and stretched as the seam moves, and the two halves stop lining up — which * is the one thing this component exists to guarantee. * * It follows that the content has to be told how big to be, and the only thing * that knows is the container once it has been measured. So nothing is drawn * until the first layout pass has run, and `Compare.Before` sizes its child to * the measured box rather than to itself. * * ## It needs a height * * Everything inside is positioned absolutely, so the box has no height of its * own to take from its content. `height` is what gives it one. An image told to * fill the box will fill whatever height is set here, and cropping is * `resizeMode` on the image rather than anything this component does. * * ## Dragging, and the two ways round it * * The whole frame is the drag target, not just the knob — a knob is a small * thing to hit on a phone and the reader's finger is already over the picture. * The gesture only claims horizontal movement, so a Compare inside a scrolling * page still scrolls. * * A drag is not available to everyone, so the seam is also `adjustable`: a * screen reader moves it a `step` at a time without one, and `value` drives it * from anywhere else — a button that snaps to the ends, an animation, a slider * somewhere else on the screen. */ import { type ReactNode } from 'react'; import { type ViewProps } from 'react-native'; export type CompareOrientation = 'horizontal' | 'vertical'; export interface CompareProps extends Omit { className?: string; /** * How tall the frame is, in points. * * Required in practice rather than in the types: both sides are positioned * absolutely, so there is no content left to give the box a height of its own. */ height?: number; /** Where the seam sits, `0` to `1`. Leave unset to let the frame track it. */ value?: number; /** Where it starts when the frame is tracking it itself. */ defaultValue?: number; /** Fires while the seam moves, with its new position. */ onValueChange?: (value: number) => void; /** Fires once, when the finger is lifted. The one to persist. */ onValueCommit?: (value: number) => void; /** Which way the seam runs. */ orientation?: CompareOrientation; /** Freezes the seam where it is and takes it out of the accessibility tree. */ disabled?: boolean; /** How far one screen-reader increment moves the seam, `0` to `1`. */ step?: number; /** A tick when the seam reaches either end. */ haptics?: boolean; children?: ReactNode; } declare function CompareRoot({ className, height, value, defaultValue, onValueChange, onValueCommit, orientation, disabled, step, haptics, children, ...props }: CompareProps): import("react").JSX.Element; declare namespace CompareRoot { var displayName: string; } export interface CompareAfterProps extends ViewProps { className?: string; children?: ReactNode; } /** * The side the seam uncovers as it travels: the whole frame, underneath. * * It is drawn at full size and never clipped, so it is the one that decides * what the frame looks like at either end of the travel. */ declare function CompareAfter({ className, children, ...props }: CompareAfterProps): import("react").JSX.Element; declare namespace CompareAfter { var displayName: string; var layer: "base"; } export interface CompareBeforeProps extends ViewProps { className?: string; children?: ReactNode; } /** * The side on the near edge of the seam: a window onto the content, sized to * the frame. * * The child is given the frame's measured size in points rather than a * percentage. A percentage would be a percentage *of the window*, which shrinks * as the seam closes — so the image would slide and scale under the seam * instead of standing still behind it, and the two halves would no longer be * the same picture in the same place. */ declare function CompareBefore({ className, children, ...props }: CompareBeforeProps): import("react").JSX.Element; declare namespace CompareBefore { var displayName: string; var layer: "clip"; } export interface CompareHandleProps extends ViewProps { className?: string; /** Hide the two grip bars inside the knob. */ withGrip?: boolean; /** Spoken name. */ accessibilityLabel?: string; /** Replaces the knob. The line behind it is kept. */ children?: ReactNode; } /** * The seam: a line across the frame with a knob on it. * * The knob is a marker rather than the target — the drag is on the whole frame, * and a 36-point circle is not something to ask a thumb to find. What it is * for is saying where the seam is and that it is the thing that moves, which a * bare line does not. * * It carries the accessibility wiring for the same reason a splitter's handle * does: it is the one part of this that is a control, so it is the part that is * `adjustable` and takes the increment and decrement a screen reader sends * instead of a drag. */ declare function CompareHandle({ className, withGrip, accessibilityLabel, children, style, ...props }: CompareHandleProps): import("react").JSX.Element; declare namespace CompareHandle { var displayName: string; var layer: "over"; } export interface CompareLabelProps extends ViewProps { className?: string; /** Which side of the frame it sits on. */ side?: 'start' | 'end'; children?: ReactNode; } /** * A caption pinned to one corner, for saying which side is which. * * Worth adding wherever the two versions are not obviously an original and an * edit — two dates, two settings, two models. Where they are, it is one more * thing over the picture and the picture is the point. */ declare function CompareLabel({ className, side, children, ...props }: CompareLabelProps): import("react").JSX.Element; declare namespace CompareLabel { var displayName: string; var layer: "over"; } export declare const Compare: typeof CompareRoot & { Before: typeof CompareBefore; After: typeof CompareAfter; Handle: typeof CompareHandle; Label: typeof CompareLabel; }; export {}; //# sourceMappingURL=index.d.ts.map