/**
* SectionProgress — a floating pill saying how far through a screen you are,
* and which part of it you are in.
*
* A ring filled to the scroll position, and beside it the title of the section
* being read. Pressed, it opens into the list of sections and jumps to any of
* them.
*
* ```tsx
* const sections = useScrollSections({ ids: SECTIONS.map((s) => s.id) });
*
*
* Introduction
* Setup
*
* ```
*
* ## Two readings, one control
*
* The ring is continuous and the label is not, and that is the point: a
* percentage says how much is left, a section name says what is being read.
* Either on its own leaves the other question open — a bar at 60% of an
* unfamiliar page means nothing in particular, and a heading with no sense of
* depth is a position without a scale.
*
* ## It arrives, and then it stays
*
* Nothing is drawn on the first screen. Past `revealAt` the pill fades in and
* remains for the rest of the scroll — it does not hide again on the way back
* up. A label that comes and goes with the scroll direction is one the reader
* has to catch rather than read.
*
* ## One surface, not a card above a button
*
* Open, the list and the pill are a single bordered box: the pill's row is the
* end of the card rather than a control sitting under a panel of its own. Two
* boxes would draw two outlines a few points apart, and the pill would read as
* something the list had landed on top of rather than as the thing it grew
* out of.
*
* The card is the only thing carrying a border, a background and a shadow.
* Everything inside it is a row.
*
* ## The section, and the colour it brings
*
* An `Item` may carry a `color`, and the active one's colour is taken by the
* ring, the label and a wash across the pill, crossfading as the reader moves
* between sections. It turns the pill into a second, peripheral signal — the
* part of the page you are in, readable without the words.
*/
import { type ReactNode } from 'react';
import { type ViewProps } from 'react-native';
import { type SharedValue } from 'react-native-reanimated';
export type SectionProgressPlacement = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
/** The colour an `Item` can bring with it. */
export type SectionProgressColor = 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'foreground';
/**
* Where the scroller is.
*
* Three values rather than one fraction, because the fraction is not the only
* thing that is wanted: the reveal threshold is a distance in points, and a
* distance cannot be recovered from a percentage.
*
* Both `useScrollSections().scroll` and the `ScrollProgress` primitive's
* context satisfy this shape.
*/
export interface SectionProgressScroll {
/** Distance scrolled, in points. */
offset: SharedValue;
/** Height of the visible area. */
viewport: SharedValue;
/** Total height of the content. */
content: SharedValue;
}
export interface SectionProgressProps extends Omit {
className?: string;
/**
* The scroll position the ring is filled from. `useScrollSections` returns
* one as `scroll`; without it the component falls back to the nearest
* `ScrollProgress`, and with neither the ring stays empty.
*/
scroll?: SectionProgressScroll;
/**
* Fill the ring from a value of your own, between 0 and 1. Nothing is
* derived when this is passed.
*/
progress?: SharedValue | number;
/** Active section id. Controlled — usually driven by a scroll handler. */
value?: string;
/** Starting section when uncontrolled. */
defaultValue?: string;
/** Fires when a section is chosen from the panel. Scroll there. */
onValueChange?: (value: string) => void;
/** Controlled expansion of the panel. */
open?: boolean;
/** Whether the panel starts open when uncontrolled. */
defaultOpen?: boolean;
/** Fires when the panel opens or closes, however it was done. */
onOpenChange?: (open: boolean) => void;
/** Which corner or edge the pill floats in. */
placement?: SectionProgressPlacement;
/** Gap between the pill and the edge of the safe area. */
offset?: number;
/**
* How far the reader must scroll, in points, before the pill appears. `0`
* shows it from the first frame. It never hides again.
*/
revealAt?: number;
/**
* Tick under the finger on every change of section, however it was made.
* Nothing between a tap in the panel and its arrival counts as a change.
* Needs the optional `expo-haptics` package; without it this does nothing.
*/
haptics?: boolean;
/**
* What the pill is called to a screen reader. The section being read and
* the percentage are announced after it, so this names the control rather
* than describing the state.
*/
label?: string;
/** One `SectionProgress.Item` per section, in the order they appear. */
children: ReactNode;
}
declare function SectionProgressRoot({ className, scroll, progress, value: valueProp, defaultValue, onValueChange, open: openProp, defaultOpen, onOpenChange, placement, offset, revealAt, haptics, label, children, ...props }: SectionProgressProps): import("react").JSX.Element;
declare namespace SectionProgressRoot {
var displayName: string;
}
export interface SectionProgressItemProps {
className?: string;
/** Section this row jumps to. Matches the root's `value`. */
value: string;
/**
* The colour this section brings to the pill. Left out, the section takes
* the foreground colour like every other.
*/
color?: SectionProgressColor;
/** The section's title. It is what the collapsed pill shows. */
children: ReactNode;
}
/**
* One section: a row in the panel, and the label the pill shows while that
* section is the one being read.
*/
declare function SectionProgressItem({ className, value, children }: SectionProgressItemProps): import("react").JSX.Element;
declare namespace SectionProgressItem {
var displayName: string;
}
export declare const SectionProgress: typeof SectionProgressRoot & {
Item: typeof SectionProgressItem;
};
export {};
//# sourceMappingURL=index.d.ts.map