import { type ReactNode } from "react"; import { type TextStyle } from "./primitives.js"; import { type ColorTokens } from "./tokens.js"; import type { AnatomyTarget } from "./anatomy.js"; /** * The label-placement slice a filled-field skin fulfills. iOS + web render the * label ABOVE the field (`floatingLabel: false`), Android floats the M3 * in-container label (`floatingLabel: true`, supplying the rest/floated/reserve * types). The label's COLOR (muted at rest, `primary-text` on focus, `destructive-text` * on error) is animated by `FloatingLabel` from the active tokens, so it is not * described here. */ export interface FloatingLabelStyles { /** true on the Android skin (floating label); false on iOS/web (label above). */ floatingLabel: boolean; /** The static above-field label's whole type and ink, colour included: the skin * supplies all of it and the shell adds none. iOS and web always place the label * here; an Android skin supplies it for a field that cannot float its label. */ labelAbove?: (t: ColorTokens, size: S) => TextStyle; /** Android: the resting (unfocused, empty) label type, body-large, centered like a placeholder. */ labelRest?: (t: ColorTokens, size: S) => TextStyle; /** Android: the floated label type, body-small at the top. Only its `fontSize` is * used, for the transform's scale (floated over rest): the label is rendered at * `labelRest` and scaled, never re-sized, so the float stays on the transform, which * the native driver and react-native-web both move. */ labelFloated?: (t: ColorTokens, size: S) => TextStyle; /** Android: the state-independent top padding the field's value takes to clear the * floated label at the skin's text size (`useFloatingLabelRoom` grows it with a larger * one), spread by the shell so the skin's field/trigger signature (and the * active-indicator invariant it is tested against) stays intact. */ labelReserve?: (size: S) => TextStyle; } /** The room a floating-label field gives its label (`useFloatingLabelRoom`). */ export interface FloatingLabelRoom { /** The value's top padding, clearing the floated label: spread where the skin's `labelReserve` went. */ reserve: TextStyle; /** How much taller the rendered label makes a fixed-height field than the skin's numbers: 0 at the skin's text size or smaller. */ growth: number; /** Hand to FloatingLabel's `onLine`: the label reports its rendered resting line through it. */ onLine: (line: number) => void; } /** * The room a field gives its floating label, which follows the user's text size: the * value's top padding (the skin's `labelReserve` until the label has measured its rendered * line, and more once a larger text size needs it) and, for a field of fixed height, how * much taller it grows. A field that floats its label calls it unconditionally, spreads * `reserve` on its value and hands `onLine` to its FloatingLabel. One commit when the label * first measures a line that differs from the skin's, and on a text-size change; none at * the skin's own text size. */ export declare function useFloatingLabelRoom(styles: FloatingLabelStyles, tokens: ColorTokens, size: S): FloatingLabelRoom; /** The accessibility props `labelA11y` gives a field's visible label Text. */ export interface LabelA11y { accessibilityLabel?: string; accessibilityElementsHidden?: boolean; importantForAccessibility?: "no-hide-descendants"; } /** * The accessibility props of a field's visible label: the Text that holds LabelContent, * above a field or floating in it. * * On iOS and Android the label Text takes `name` as its accessible name, so the required * star is never spoken: React Native renders the star, a Text nested in the label, as a * span of the label's paragraph, which its own hiding props cannot reach. `name` is the * bare label, or `requiredName(label, required)` for a label that is the required field's * only cue (Field's heading over a control that names itself). The web keeps its markup as * it is: the star's `aria-hidden` already keeps it out of the field's name through * `aria-labelledby`, and an `aria-label` on the label's generic element is one ARIA * prohibits. * * With `names` (the control takes its accessible name from this label) the label is also * hidden from VoiceOver and TalkBack, which would otherwise stop on it and then on the * field with the same name. Both props are native only (react-native-web drops them), so * the label stays in the web DOM, where it is the node the field's `aria-labelledby` * names. Leave `names` off where the label heads a control that names itself (Field around * a Switch): there the label is a stop of its own. * * `os` is the platform to resolve for; it defaults to the running one. */ export declare function labelA11y(name: string, names: boolean, os?: string): LabelA11y; /** * A required field's accessible name: `", required"` on iOS and Android, and the name * itself on the web and wherever `required` is off. React Native has no native required * state (its `aria-required` reaches the web alone) and the label's star is never spoken * (`labelA11y`), so natively the word in the name is the only required cue VoiceOver and * TalkBack hear, as they hear it in Select's trigger name. The web keeps the bare name, * since the field's `aria-required` announces it there and the word would say it twice. * Give it to the field's `accessibilityLabel` and `aria-label` both: React Native takes * `aria-label` over `accessibilityLabel`. An absent name stays absent. * * `os` is the platform to resolve for; it defaults to the running one. */ export declare function requiredName(name: N, required: boolean | undefined, os?: string): N; /** * The label text plus, when required, a trailing destructive "*". Used for BOTH the * above-field label and the floated label so every field family renders the required * affordance identically. The star is decorative: `aria-hidden` keeps it out of the * field's name on the web, and on iOS and Android the label Text that holds this content * names itself with the bare label (`labelA11y`), since the star is part of its paragraph * there. */ export declare function LabelContent({ label, required, starColor, starPart }: { label: string; required?: boolean; starColor: string; /** The docs anatomy "Required mark" on the star (src/style/anatomy.tsx), inside an AnatomyProvider only. */ starPart?: AnatomyTarget; }): ReactNode; /** * The Material 3 in-container floating label, which the Android skins of Input, Textarea, * Select and Autocomplete render inside their field (the iOS and web skins title the field * from above). It overlays the field, pinned to the leading edge and bounded on both sides, * and moves between its resting place (centered like a placeholder, or on the first line of * a multiline field) and its floated one (small, at the top, its bottom edge where the value * begins). It never takes a tap (taps reach the field beneath), never paints a material of * its own, and never wraps: a label longer than the field truncates on one line while the * field's accessible name stays the whole label. * * Two values drive it, each a one-shot timing from the motion tunables (`FLOAT`): * - `pos` (0 to 1, its target focused or populated) drives only the transform, translateY * and a scale from 1 to floated/rest, on the native driver where there is one and the JS * driver on the web. It never animates fontSize, top or width, which the native driver * cannot move. * - `tint` (0 to 1, its target focused or in error) drives only the colour, from * `muted-foreground` to `primary-text` (or `destructive-text`), so a filled, valid, * unfocused field floats yet stays muted. It runs on the JS driver on every platform, * the one exception motion.ts states to its native-driver gate: React Native 0.86's * native driver, with its default feature flags, writes a frame onto the native view's * props, and Android's text view takes its colour only through the paragraph's * attributed text, so read from React Native's source (not yet confirmed on a device) it * would not repaint the label. Natively each of its frames is a setNativeProps Fabric * commit, with a single React render after the last frame; on the web both values run * on the JS driver, and each frame updates the label through react-native-web's Animated * for the length of the float. * Under Reduce Motion both values jump to their target in one write: the label still floats. * Each value is seeded at its target, so a field that mounts filled (or in error) is floated * (or tinted) from its first frame, the server's included, and a mount starts no timing. * * The label is pinned to the logical `start` edge, and its transform origin pins that edge * while it scales (no measurement, no translateX): the origin follows the layout direction * from `isRTL()`, "0% 50%" or "100% 50%", because transform origins are physical while * `start` is the right edge in a right-to-left layout. * * Geometry: translateY carries the label's resting vertical center to its floated one. The * floated center lands the scaled label's bottom edge on the reserve, where the value * begins, so the value always clears it; the resting center is the field's middle, or the * first value line of a multiline field (the reserve plus half a line). The numbers are the * skin's at the skin's own text size and the rendered label's at any other, the reserve * handed back to the field through `onLine` (`useFloatingLabelRoom`). * * To assistive technology the label is the field's name, never a second stop beside it: * natively it names itself with the bare label and, while `names`, is hidden (`labelA11y`); * on the web it stays in the DOM, the node the field's `aria-labelledby` names. */ export declare function FloatingLabel({ styles, size, tokens, label, required, labelId, focused, populated, isError, height, inset, end, multiline, names, edges, onLine, part, starPart, }: { styles: FloatingLabelStyles; size: S; tokens: ColorTokens; label: string; required?: boolean; labelId: string; focused: boolean; populated: boolean; isError: boolean; /** * The single-line field's height, from its skin, which centers the resting label at the * skin's text size; once a different text size changes the rendered line, the field's * measured height takes over. Ignored in `multiline` mode. */ height: number; /** Leading inset that matches the field's horizontal content padding (default 16dp). */ inset?: number; /** * How far from the field's end edge the label stays: the field's end padding, `inset` * by default, or the width of the trailing chevron or toggle where one sits there. A * label longer than the room between the two ends truncates with an ellipsis, and the * field's accessible name stays the whole label. */ end?: number; /** Multiline field (Textarea): rest the label at the top text line, not the box middle. */ multiline?: boolean; /** * The field takes its accessible name from this label (default true), so VoiceOver and * TalkBack skip the label and stop on the field alone (`labelA11y`). */ names?: boolean; /** Told the label's rendered resting line height whenever it changes: a field's `useFloatingLabelRoom` `onLine`. */ onLine?: (line: number) => void; /** * How far the field's padding box reaches over its border on each side, which the label's * bounds step back from to keep their place: a field box that turns its resting border * into padding under glass (the text-entry material's `edges`). None by default. */ edges?: { top: number; bottom: number; start: number; end: number; }; /** * The docs anatomy "Label" on the label text (src/style/anatomy.tsx), inside an * AnatomyProvider only. Its rectangle is the label's resting box: a part is measured in * layout space, which the float's transform does not move. */ part?: AnatomyTarget; /** The docs anatomy "Required mark" on the label's star, as LabelContent's `starPart`. */ starPart?: AnatomyTarget; }): import("react").JSX.Element; //# sourceMappingURL=floating-label.d.ts.map