@gnome-ui/react-native 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,8 +24,9 @@ React Native component library following the [GNOME Human Interface Guidelines](
24
24
  > `SegmentedBar`/`AvatarGroup`/`AvatarRotator`/`CoachMark`/`CoachMarkTour`
25
25
  > (Tier 20), `Chip` (Tier 7), `IconButton`/`Drawer` (Tier 8/Tier 20), and
26
26
  > `Clamp` (Tier 6), `Box` (Tier 20), `WrapBox`/`ToggleGroup` (Tier 7), and
27
- > `InlineViewSwitcher` (Tier 8), and `PreferencesGroup` (Tier 13) also
28
- > shipped. Component ports from
27
+ > `InlineViewSwitcher` (Tier 8), `PreferencesGroup` (Tier 13), and
28
+ > `EntryRow`/`PasswordEntryRow`/`ComboRow` (Tier 12), `ColorPicker`
29
+ > (Tier 20), and `Bin` (Tier 15) also shipped. Component ports from
29
30
  > `@gnome-ui/react` continue tier by tier — see this package's own
30
31
  > [ROADMAP.md](./ROADMAP.md) for full
31
32
  > per-tier status against all 130 `@gnome-ui/react` components, and the
@@ -1868,6 +1869,211 @@ own title. `min-width: 0` on the header text has no port and needs none: it's
1868
1869
  the classic CSS flexbox override for a min-content floor Yoga doesn't apply
1869
1870
  in the first place.
1870
1871
 
1872
+ ### EntryRow
1873
+
1874
+ ```tsx
1875
+ import { EntryRow } from '@gnome-ui/react-native';
1876
+
1877
+ const [name, setName] = useState('');
1878
+
1879
+ <BoxedList>
1880
+ <EntryRow title="Display name" value={name} onValueChange={setName} />
1881
+ <EntryRow
1882
+ title="Email"
1883
+ value={email}
1884
+ onValueChange={setEmail}
1885
+ keyboardType="email-address"
1886
+ leading={<Icon icon={MailRead} />}
1887
+ trailing={<IconButton icon={Delete} label="Clear" onPress={() => setEmail('')} />}
1888
+ />
1889
+ </BoxedList>
1890
+ ```
1891
+
1892
+ Row with an inline text entry field — mirrors `AdwEntryRow` and
1893
+ `@gnome-ui/react`'s own `EntryRow`. The `title` rises above the input as a
1894
+ small label once the field is focused or has content, and stands in for the
1895
+ placeholder until then. Use it inside a `BoxedList` for settings that take
1896
+ free-form text. Controlled (`value`) and uncontrolled (`defaultValue`) modes
1897
+ both work, and every remaining `TextInput` prop passes through.
1898
+
1899
+ The float is one JS-driven `Animated.Value` (`useNativeDriver: false`):
1900
+ `fontSize` is part of the transition and can't be native-driven, and mixing a
1901
+ native with a JS value on one component throws — the same trade-off
1902
+ `Expander` and `InlineViewSwitcher` already accepted. `useReducedMotion()`
1903
+ snaps between the two states instead.
1904
+
1905
+ **The label's travel is measured, not hardcoded.** The web expresses the
1906
+ resting position as `top: 50%; transform: translateY(-50%)` and the floated
1907
+ one as `top: 6px`, but RN can't interpolate between a percentage and a fixed
1908
+ offset — so the field reports its own height through `onLayout` and the
1909
+ distance is derived from it, which also keeps the label centred if you make
1910
+ the row taller than the 56 dp minimum.
1911
+
1912
+ The `:focus` inset ring is dropped rather than approximated. `TextField`'s
1913
+ own precedent — recolor the border on focus — doesn't transfer, because an
1914
+ `EntryRow` has no border of its own: it's a row inside a `BoxedList`, and
1915
+ adding one would shift the list's geometry. On a touch device the state is
1916
+ already unmistakable: the label floats up, the text fades in, and the
1917
+ keyboard opens.
1918
+
1919
+ Two deliberate divergences from the web version. The visible label is hidden
1920
+ from assistive tech and the `title` becomes the input's `accessibilityLabel`
1921
+ — RN has no `<label htmlFor>`, so otherwise the label would be announced as
1922
+ loose text next to an unnamed field (pass `accessibilityLabel` to override).
1923
+ And `testID` lands on the row rather than the input, matching every other
1924
+ component in this package; reach the field itself by its accessible name.
1925
+
1926
+ ### PasswordEntryRow
1927
+
1928
+ ```tsx
1929
+ import { PasswordEntryRow } from '@gnome-ui/react-native';
1930
+
1931
+ <BoxedList>
1932
+ <PasswordEntryRow title="Password" value={password} onValueChange={setPassword} />
1933
+
1934
+ {/* Registration and change-password forms */}
1935
+ <PasswordEntryRow
1936
+ title="New password"
1937
+ value={next}
1938
+ onValueChange={setNext}
1939
+ autoComplete="new-password"
1940
+ />
1941
+ </BoxedList>
1942
+ ```
1943
+
1944
+ Password entry row with a built-in reveal/conceal toggle — mirrors
1945
+ `AdwPasswordEntryRow` and `@gnome-ui/react`'s own `PasswordEntryRow`. It's an
1946
+ `EntryRow` that masks its input and always carries a trailing button to show
1947
+ or hide what's been typed, so don't add your own through `trailing` — that
1948
+ slot is for anything that should sit *before* the reveal button.
1949
+
1950
+ `type={revealed ? 'text' : 'password'}` becomes RN's `secureTextEntry`, and
1951
+ `autoComplete` defaults to `"current-password"`, which is what lets password
1952
+ managers and the platform keyboard offer a saved credential.
1953
+
1954
+ The reveal control is the already-shipped `IconButton` rather than a
1955
+ hand-rolled pressable, which costs one visual detail: `IconButton` is
1956
+ circular (it's `Button` at `shape="circular"`) where the web's
1957
+ `.revealButton` is a 32 dp square with a 6 dp radius. A circular flat icon
1958
+ button is the idiomatic touch control and keeps the row consistent with every
1959
+ other icon action here. The CSS's resting `opacity: 0.55` is dropped too — it
1960
+ exists so the button can brighten on hover, and with no hover on a touch
1961
+ device a permanently dimmed control is just harder to see.
1962
+
1963
+ The web needs `e.stopPropagation()` so pressing the button doesn't also
1964
+ trigger the row's focus-the-input click. RN's responder system routes a touch
1965
+ to the innermost pressable, so there's nothing to stop.
1966
+
1967
+ ### ComboRow
1968
+
1969
+ ```tsx
1970
+ import { ComboRow } from '@gnome-ui/react-native';
1971
+
1972
+ <BoxedList>
1973
+ <ComboRow
1974
+ title="Language"
1975
+ subtitle="Used across the whole app"
1976
+ value={language}
1977
+ onValueChange={setLanguage}
1978
+ options={[
1979
+ { value: 'en', label: 'English' },
1980
+ { value: 'es', label: 'Español' },
1981
+ ]}
1982
+ />
1983
+ </BoxedList>
1984
+ ```
1985
+
1986
+ Settings row with an inline combo selector at the trailing edge — mirrors
1987
+ `AdwComboRow` and `@gnome-ui/react`'s own `ComboRow`. Use it inside a
1988
+ `BoxedList` for a setting that picks one of a set of options. Controlled
1989
+ (`value`) and uncontrolled (`defaultValue`) modes both work; the trigger
1990
+ falls back to `"—"` when nothing is selected.
1991
+
1992
+ **This is a composition of `ActionRow` + `Dropdown`, where the web version
1993
+ hand-rolls its own listbox inline** — around 200 lines re-implementing the
1994
+ trigger, the flip-up placement, outside-click dismissal, roving
1995
+ `aria-activedescendant` and the whole keyboard layer, none of which is
1996
+ meaningfully different from that package's own `Dropdown`. Nothing forced the
1997
+ duplication visually either: `.row` is `ActionRow`'s exact metrics and
1998
+ `.trigger` is `Dropdown`'s exact trigger. Composing the two already-shipped
1999
+ components means the flip-to-fit placement, the tap-outside dismissal and the
2000
+ `Modal`-based list all come along for free rather than being rebuilt.
2001
+
2002
+ `Dropdown` is controlled-only, so the uncontrolled state lives in `ComboRow`
2003
+ — same behaviour as the web version, one level up. The keyboard layer drops
2004
+ as it does everywhere else here.
2005
+
2006
+ ### ColorPicker / ColorSwatch
2007
+
2008
+ ```tsx
2009
+ import { ColorPicker, ColorSwatch, GNOME_PALETTE } from '@gnome-ui/react-native';
2010
+
2011
+ const [color, setColor] = useState('#3584e4');
2012
+
2013
+ <ColorPicker value={color} onChange={setColor} />
2014
+
2015
+ // Custom colors, with your own picker behind the "+"
2016
+ <ColorPicker
2017
+ value={color}
2018
+ onChange={setColor}
2019
+ allowCustom
2020
+ onRequestCustom={() => setPickerOpen(true)}
2021
+ />
2022
+ ```
2023
+
2024
+ Color palette picker following the Adwaita `GtkColorButton` + swatch pattern
2025
+ — mirrors `@gnome-ui/react`'s own `ColorPicker`. Renders a wrapping row of
2026
+ circular `ColorSwatch` items backed by a radio group, defaulting to
2027
+ `GNOME_PALETTE` (the 9 Adwaita named colors, the same set `Avatar` uses).
2028
+ `ColorSwatch` is exported for standalone use; sizes are **22 / 30 / 38 dp**.
2029
+
2030
+ **`allowCustom` is the one prop that changes meaning.** On the web it wires a
2031
+ hidden `<input type="color">` and the browser supplies the whole picker UI;
2032
+ RN has no such control, and an HSV picker is a component in its own right
2033
+ rather than a detail of this one. So the prop keeps its *visible* behaviour —
2034
+ the "+" button, and a `value` outside the palette shown as its own selected
2035
+ swatch — while the press is handed to a new **`onRequestCustom`** callback
2036
+ for your app to answer with whatever picker it has. The result round-trips
2037
+ through `value`/`onChange` exactly as before.
2038
+
2039
+ The web's three `box-shadow` rings collapse into real box-model pieces, since
2040
+ RN gives a `View` one border: the resting `inset 0 0 0 1px` hairline becomes
2041
+ `borderWidth: 1`, the selected `inset 0 0 0 2px rgb(255 255 255 / .9)`
2042
+ becomes a 2 dp white border, and the outer `0 0 0 2px var(--swatch-color)`
2043
+ becomes a wrapper painted in the swatch color. That wrapper is **always**
2044
+ rendered with the same 2 dp padding and only changes color: a box-shadow ring
2045
+ costs no layout space on the web while a real padded wrapper does, so
2046
+ reserving it unconditionally is what keeps the row from reflowing as the
2047
+ selection moves.
2048
+
2049
+ `filter: drop-shadow(...)` on the checkmark has no RN counterpart, so the
2050
+ path is drawn twice — a translucent black copy offset 1 dp down, then the
2051
+ white one on top. That's what the filter renders, and it's why it exists:
2052
+ without it the check disappears on the yellow swatch. The checkmark is
2053
+ hand-drawn with `react-native-svg` rather than taken from `@gnome-ui/icons`,
2054
+ mirroring the web version, which hand-draws it too — it's a stroked path, and
2055
+ `Icon`'s palette has no white to give it. The container is a `WrapBox`, and
2056
+ the "+" button's `border: 1.5px dashed` ports directly.
2057
+
2058
+ ### Bin
2059
+
2060
+ ```tsx
2061
+ import { Bin } from '@gnome-ui/react-native';
2062
+
2063
+ <Bin style={{ maxWidth: 480 }}>
2064
+ <ExpensiveChart data={series} />
2065
+ </Bin>
2066
+ ```
2067
+
2068
+ Single-child container with no visual styling — mirrors `AdwBin` and
2069
+ `@gnome-ui/react`'s own `Bin`. A transparent passthrough `View` forwarding
2070
+ every prop (and a ref to the underlying `View`) straight through, useful as
2071
+ a neutral base for custom components that need to apply layout or size
2072
+ constraints without introducing any chrome of their own. A plain RN `View`
2073
+ already has no default visual styling — no background, no border — so
2074
+ unlike the web port there's no CSS reset to strip; this is a pure
2075
+ passthrough.
2076
+
1871
2077
  ## Installation
1872
2078
 
1873
2079
  ```bash
@@ -0,0 +1,18 @@
1
+ import { View, ViewProps } from 'react-native';
2
+ export type BinProps = ViewProps;
3
+ /**
4
+ * Single-child container with no visual styling.
5
+ *
6
+ * A transparent wrapper that forwards all `View` props (and a ref to the
7
+ * underlying `View`) straight through — useful as a neutral base for custom
8
+ * components that need to apply layout or size constraints without
9
+ * introducing any chrome of their own.
10
+ *
11
+ * Mirrors `AdwBin` and `@gnome-ui/react`'s own `Bin`. A plain RN `View`
12
+ * already has no default visual styling (no background, no border), so
13
+ * unlike the web port there's no CSS reset to strip — this is a pure
14
+ * passthrough.
15
+ *
16
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Bin.html
17
+ */
18
+ export declare const Bin: import('react').ForwardRefExoticComponent<ViewProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,2 @@
1
+ export type { BinProps } from './Bin';
2
+ export { Bin } from './Bin';
@@ -0,0 +1,81 @@
1
+ import { StyleProp, ViewStyle } from 'react-native';
2
+ import { ColorSwatchSize } from './ColorSwatch';
3
+ export interface ColorPickerColor {
4
+ /** Color value (hex recommended). */
5
+ value: string;
6
+ /** Human-readable name, used as the swatch's accessible label. */
7
+ label?: string;
8
+ }
9
+ /** Default Adwaita-named palette (matches the `Avatar` color set). */
10
+ export declare const GNOME_PALETTE: ColorPickerColor[];
11
+ export interface ColorPickerProps {
12
+ /** Currently selected color value. */
13
+ value?: string;
14
+ /** Called when the user selects a color. */
15
+ onChange?: (value: string) => void;
16
+ /** Palette to display. Defaults to `GNOME_PALETTE` (the 9 Adwaita colors). */
17
+ colors?: ColorPickerColor[];
18
+ /**
19
+ * Show a "+" button after the palette, and render any `value` outside the
20
+ * palette as its own selected swatch. Pressing either calls
21
+ * `onRequestCustom` — RN has no `<input type="color">`, so the picker UI
22
+ * itself is the consuming app's to provide. Defaults to `false`.
23
+ */
24
+ allowCustom?: boolean;
25
+ /**
26
+ * Called when the "+" button (or the current custom swatch) is pressed.
27
+ * Open your own color picker here and feed the result back through
28
+ * `value`/`onChange`.
29
+ */
30
+ onRequestCustom?: () => void;
31
+ /** Swatch size. Defaults to `"md"`. */
32
+ size?: ColorSwatchSize;
33
+ /** Accessible name for the group. Defaults to `"Color"`. */
34
+ accessibilityLabel?: string;
35
+ disabled?: boolean;
36
+ style?: StyleProp<ViewStyle>;
37
+ testID?: string;
38
+ }
39
+ /**
40
+ * Color palette picker following the Adwaita `GtkColorButton` + swatch
41
+ * pattern, mirroring `@gnome-ui/react`'s own `ColorPicker`. Renders a
42
+ * wrapping row of circular `ColorSwatch` items backed by a radio group.
43
+ *
44
+ * **`allowCustom` is the one prop that changes meaning.** On the web it
45
+ * wires a hidden `<input type="color">` and the browser supplies the whole
46
+ * picker UI; RN has no such control, and building an HSV picker would be a
47
+ * component in its own right rather than a detail of this one. So the prop
48
+ * keeps its *visible* behaviour — the "+" button, and a `value` outside the
49
+ * palette shown as its own selected swatch — while the press is handed to
50
+ * `onRequestCustom` for the app to answer with whatever picker it has. Round
51
+ * trips through `value`/`onChange` exactly as before.
52
+ *
53
+ * The container is a `WrapBox` (`display: flex; flex-wrap: wrap; gap: 8`
54
+ * with nothing else in `.picker`), and the "+" button's `border: 1.5px
55
+ * dashed` ports directly — `borderStyle: 'dashed'` is one of the few CSS
56
+ * border tricks RN does support. Its plus glyph comes from `@gnome-ui/icons`
57
+ * rather than the web's hand-drawn path, since `Add` is the same mark and
58
+ * already resolves to the foreground color `.customButton` asks for.
59
+ *
60
+ * As in `ToggleGroup`, the group takes `accessibilityRole="radiogroup"` but
61
+ * deliberately not `accessible`, which on iOS would collapse the swatches
62
+ * into one unreachable element. Arrow-key navigation and the roving
63
+ * `tabIndex` drop, as everywhere else here.
64
+ *
65
+ * @example
66
+ * const [color, setColor] = useState('#3584e4');
67
+ *
68
+ * <ColorPicker value={color} onChange={setColor} />
69
+ *
70
+ * @example
71
+ * // Custom colors, with your own picker behind the "+"
72
+ * <ColorPicker
73
+ * value={color}
74
+ * onChange={setColor}
75
+ * allowCustom
76
+ * onRequestCustom={() => setPickerOpen(true)}
77
+ * />
78
+ *
79
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.ColorButton.html
80
+ */
81
+ export declare const ColorPicker: ({ value, onChange, colors, allowCustom, onRequestCustom, size, accessibilityLabel, disabled, style, testID, }: ColorPickerProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,50 @@
1
+ import { PressableProps, StyleProp, View, ViewStyle } from 'react-native';
2
+ export type ColorSwatchSize = 'sm' | 'md' | 'lg';
3
+ /** `.swatch-sm` / `-md` / `-lg`. */
4
+ export declare const SWATCH_DIAMETER: Record<ColorSwatchSize, number>;
5
+ /**
6
+ * Width of the selected state's outer ring. Reserved as padding on every
7
+ * swatch, selected or not, so selecting one never reflows the row — the web
8
+ * gets this for free because `box-shadow` rings don't take up space.
9
+ */
10
+ export declare const RING_WIDTH = 2;
11
+ export interface ColorSwatchProps extends Omit<PressableProps, 'children' | 'style' | 'onPress' | 'disabled'> {
12
+ /** Color value displayed as the swatch background. */
13
+ color: string;
14
+ /** Whether this swatch is the currently selected color. */
15
+ selected?: boolean;
16
+ /** Swatch diameter. Defaults to `"md"`. */
17
+ size?: ColorSwatchSize;
18
+ /** Called with `color` when the swatch is pressed. */
19
+ onSelect?: (color: string) => void;
20
+ /** Accessible name. Defaults to the color value. */
21
+ accessibilityLabel?: string;
22
+ disabled?: boolean;
23
+ style?: StyleProp<ViewStyle>;
24
+ }
25
+ /**
26
+ * Single circular color swatch. Usable standalone or composed inside
27
+ * `ColorPicker`, and shows a white checkmark when `selected`.
28
+ *
29
+ * The web's three `box-shadow` rings collapse into real box-model pieces,
30
+ * since RN gives a `View` exactly one border: the resting
31
+ * `inset 0 0 0 1px` hairline becomes `borderWidth: 1`, the selected state's
32
+ * `inset 0 0 0 2px rgb(255 255 255 / .9)` becomes a 2 dp white border, and
33
+ * the outer `0 0 0 2px var(--swatch-color)` becomes a wrapper painted in the
34
+ * swatch color. That wrapper is always rendered with the same 2 dp padding
35
+ * and only changes color, because a `box-shadow` ring costs no layout space
36
+ * on the web while a real padded wrapper does — reserving it unconditionally
37
+ * is what keeps the row from reflowing as the selection moves.
38
+ *
39
+ * The checkmark is hand-drawn with `react-native-svg` rather than taken from
40
+ * `@gnome-ui/icons`, mirroring the web version, which also hand-draws it:
41
+ * it's a stroked path, and `Icon`'s palette has no white to give it anyway.
42
+ * `filter: drop-shadow(...)` has no RN counterpart, so the path is drawn
43
+ * twice — a translucent black copy offset 1 dp down, then the white one on
44
+ * top — which is what that filter renders and is why it exists: without it
45
+ * the check disappears on a yellow swatch.
46
+ *
47
+ * `:hover { transform: scale(1.12) }` drops with hover; the selected
48
+ * `scale(1.05)` ports as-is.
49
+ */
50
+ export declare const ColorSwatch: import('react').ForwardRefExoticComponent<ColorSwatchProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,4 @@
1
+ export type { ColorPickerColor, ColorPickerProps } from './ColorPicker';
2
+ export { ColorPicker, GNOME_PALETTE } from './ColorPicker';
3
+ export type { ColorSwatchProps, ColorSwatchSize } from './ColorSwatch';
4
+ export { ColorSwatch } from './ColorSwatch';
@@ -0,0 +1,77 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+ import { DropdownOption } from '../Dropdown';
4
+ /** Same shape as `Dropdown`'s own option — re-exported so `ComboRow` reads self-contained. */
5
+ export type ComboRowOption<V extends string = string> = DropdownOption<V>;
6
+ export interface ComboRowProps<V extends string = string> {
7
+ /** Primary label. */
8
+ title: string;
9
+ /** Secondary line below the title. */
10
+ subtitle?: string;
11
+ /** Icon or image placed at the leading edge. */
12
+ leading?: ReactNode;
13
+ /** The list of selectable options. */
14
+ options: ComboRowOption<V>[];
15
+ /** The currently selected value (controlled). */
16
+ value?: V;
17
+ /** Initial value when uncontrolled. */
18
+ defaultValue?: V;
19
+ /** Called when the user selects an option. */
20
+ onValueChange?: (value: V) => void;
21
+ /** Shown in the trigger while nothing is selected. Defaults to `"—"`. */
22
+ placeholder?: string;
23
+ /** Accessible name for the selector. Defaults to `title`. */
24
+ accessibilityLabel?: string;
25
+ /** Disables the row and its selector. */
26
+ disabled?: boolean;
27
+ style?: StyleProp<ViewStyle>;
28
+ testID?: string;
29
+ }
30
+ /**
31
+ * Settings row with an inline combo selector at the trailing edge, mirroring
32
+ * `AdwComboRow` and `@gnome-ui/react`'s own `ComboRow`. Use inside a
33
+ * `BoxedList` for a setting that picks one of a set of options.
34
+ *
35
+ * **This is a composition of `ActionRow` + `Dropdown`, where the web version
36
+ * hand-rolls its own listbox inline** — around 200 lines re-implementing the
37
+ * trigger, the flip-up placement, outside-click dismissal, roving
38
+ * `aria-activedescendant` and the whole keyboard layer, none of which is
39
+ * meaningfully different from that package's own `Dropdown`. Nothing forced
40
+ * the duplication visually either: `.row` is `ActionRow`'s exact metrics
41
+ * (12/24 dp padding, 52 dp min-height) and `.trigger` is `Dropdown`'s exact
42
+ * trigger (card background, 1 px shade border turning accent when open,
43
+ * `radius-md`, chevron). So this port composes the two already-shipped,
44
+ * already-verified components instead — which also means the flip-to-fit
45
+ * placement, the tap-outside dismissal and the `Modal`-based list all come
46
+ * along for free rather than being rebuilt and re-debugged.
47
+ *
48
+ * The web keeps its own `useState` for the uncontrolled case; `Dropdown` is
49
+ * controlled-only, so that state lives here — same behaviour, one level up.
50
+ *
51
+ * The keyboard layer (`↑`/`↓`/`Home`/`End`/`Enter`/`Escape`) drops as it
52
+ * does everywhere else in this package, and `Dropdown` already provides the
53
+ * touch equivalents it was built with.
54
+ *
55
+ * The dimming for `disabled` is applied here rather than left to
56
+ * `ActionRow`, which only dims in its `interactive` branch — on a plain
57
+ * (non-pressable) row its `disabled` prop currently reaches a `View` that
58
+ * does nothing with it. Making this row `interactive` isn't the answer: the
59
+ * `Dropdown` is the control, and the row itself has nothing to press.
60
+ *
61
+ * @example
62
+ * <BoxedList>
63
+ * <ComboRow
64
+ * title="Language"
65
+ * subtitle="Used across the whole app"
66
+ * value={language}
67
+ * onValueChange={setLanguage}
68
+ * options={[
69
+ * { value: 'en', label: 'English' },
70
+ * { value: 'es', label: 'Español' },
71
+ * ]}
72
+ * />
73
+ * </BoxedList>
74
+ *
75
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.ComboRow.html
76
+ */
77
+ export declare const ComboRow: <V extends string = string>({ title, subtitle, leading, options, value: controlledValue, defaultValue, onValueChange, placeholder, accessibilityLabel, disabled, style, testID, }: ComboRowProps<V>) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export type { ComboRowOption, ComboRowProps } from './ComboRow';
2
+ export { ComboRow } from './ComboRow';
@@ -0,0 +1,77 @@
1
+ import { ReactNode } from 'react';
2
+ import { TextInput as RNTextInput, StyleProp, TextInputProps, ViewStyle } from 'react-native';
3
+ export interface EntryRowProps extends Omit<TextInputProps, 'style' | 'value' | 'defaultValue' | 'editable' | 'testID'> {
4
+ /**
5
+ * Acts as a floating label: shown small above the input once the field has
6
+ * content or focus, and as the placeholder while it's empty and unfocused.
7
+ */
8
+ title: string;
9
+ /** Controlled value. Omit for an uncontrolled field. */
10
+ value?: string;
11
+ /** Initial value when uncontrolled. */
12
+ defaultValue?: string;
13
+ /** Called when the input value changes. */
14
+ onValueChange?: (value: string) => void;
15
+ /** Icon or widget placed at the leading edge. */
16
+ leading?: ReactNode;
17
+ /** Icon or widget placed at the trailing edge (e.g. a clear or reveal button). */
18
+ trailing?: ReactNode;
19
+ disabled?: boolean;
20
+ /**
21
+ * Applied to the row, not the input — the convention every other component
22
+ * in this package follows. Reach the field itself with the accessible name
23
+ * (`getByLabelText(title)`).
24
+ */
25
+ testID?: string;
26
+ style?: StyleProp<ViewStyle>;
27
+ }
28
+ /**
29
+ * Row with an inline text entry field, mirroring `AdwEntryRow` and
30
+ * `@gnome-ui/react`'s own `EntryRow`. The `title` rises above the input as a
31
+ * small label once the field is focused or has content, and stands in for
32
+ * the placeholder until then. Use inside a `BoxedList` for settings that
33
+ * take free-form text.
34
+ *
35
+ * The float is one JS-driven `Animated.Value` (`useNativeDriver: false`):
36
+ * `fontSize` is part of the transition and can't be native-driven, and
37
+ * mixing a native with a JS value on one component throws — the same
38
+ * trade-off `Expander` and `InlineViewSwitcher` already accepted.
39
+ * `useReducedMotion()` snaps between the two states instead.
40
+ *
41
+ * **The label's travel is measured, not hardcoded.** The web can express its
42
+ * resting position as `top: 50%; transform: translateY(-50%)` and its
43
+ * floated one as `top: 6px`, but RN can't interpolate between a percentage
44
+ * and a fixed offset, so the row reports its own height through `onLayout`
45
+ * and the distance is derived from it. That also keeps the label centred if
46
+ * a consumer makes the row taller than the 56 dp minimum.
47
+ *
48
+ * The `:focus` inset ring is dropped rather than approximated. `TextField`'s
49
+ * own precedent — recolor the border on focus — doesn't transfer, because an
50
+ * `EntryRow` has no border of its own to recolor: it's a row inside a
51
+ * `BoxedList`, and adding one would shift the list's geometry. On a touch
52
+ * device the state is already unmistakable anyway: the label floats up, the
53
+ * text fades in, and the keyboard opens. The `prefers-contrast: more` block
54
+ * is a variation on that same ring, so it goes with it.
55
+ *
56
+ * Tapping anywhere on the row focuses the field, the same affordance the web
57
+ * version's row-level `onClick` provides.
58
+ *
59
+ * The visible label is hidden from assistive tech and the `title` becomes
60
+ * the input's `accessibilityLabel` instead. On the web the two are bound by
61
+ * `<label htmlFor>`, which RN has no equivalent for — left as-is, the label
62
+ * would be announced as loose text next to an unnamed field. `testID` lands
63
+ * on the row rather than the input (unlike the web version, which spreads
64
+ * every remaining prop onto the `<input>`), matching what every other
65
+ * component in this package does; reach the field itself by its accessible
66
+ * name.
67
+ *
68
+ * @example
69
+ * const [name, setName] = useState('');
70
+ *
71
+ * <BoxedList>
72
+ * <EntryRow title="Display name" value={name} onValueChange={setName} />
73
+ * </BoxedList>
74
+ *
75
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.EntryRow.html
76
+ */
77
+ export declare const EntryRow: import('react').ForwardRefExoticComponent<EntryRowProps & import('react').RefAttributes<RNTextInput>>;
@@ -0,0 +1,2 @@
1
+ export type { EntryRowProps } from './EntryRow';
2
+ export { EntryRow } from './EntryRow';
@@ -0,0 +1,45 @@
1
+ import { ReactNode } from 'react';
2
+ import { TextInput } from 'react-native';
3
+ import { EntryRowProps } from '../EntryRow';
4
+ export interface PasswordEntryRowProps extends Omit<EntryRowProps, 'secureTextEntry' | 'trailing'> {
5
+ /** Additional trailing widgets placed before the reveal button. */
6
+ trailing?: ReactNode;
7
+ }
8
+ /**
9
+ * Password entry row with a built-in reveal/conceal toggle, mirroring
10
+ * `AdwPasswordEntryRow` and `@gnome-ui/react`'s own `PasswordEntryRow`. It's
11
+ * an `EntryRow` that masks its input and always carries a trailing button to
12
+ * show or hide what's been typed. Use inside a `BoxedList` for password
13
+ * settings fields — and don't add your own reveal button through `trailing`,
14
+ * which is for anything that should sit *before* this one.
15
+ *
16
+ * `type={revealed ? 'text' : 'password'}` becomes RN's own
17
+ * `secureTextEntry`, and `autoComplete="current-password"` ports as-is —
18
+ * RN's `autoComplete` accepts the same value and is what lets password
19
+ * managers and the platform keyboard offer a saved credential. Pass
20
+ * `"new-password"` on registration or change-password forms.
21
+ *
22
+ * The reveal control is the already-shipped `IconButton` rather than a
23
+ * hand-rolled pressable, which costs one visual detail: `IconButton` is
24
+ * circular (it's `Button` at `shape="circular"`), where the web's
25
+ * `.revealButton` is a 32 dp square with a 6 dp radius. A circular flat icon
26
+ * button is the idiomatic touch control and keeps this row consistent with
27
+ * every other icon action in the package, so it's the better trade than
28
+ * introducing a fifth flat-pressable implementation. The CSS's resting
29
+ * `opacity: 0.55` is dropped too: it exists so the button can brighten on
30
+ * hover, and with no hover on a touch device a permanently dimmed control is
31
+ * just harder to see — the same reasoning that collapses `:hover` everywhere
32
+ * else here.
33
+ *
34
+ * The web needs `e.stopPropagation()` so pressing the button doesn't also
35
+ * trigger the row's focus-the-input click. RN's responder system routes a
36
+ * touch to the innermost pressable, so there's nothing to stop.
37
+ *
38
+ * @example
39
+ * <BoxedList>
40
+ * <PasswordEntryRow title="Password" value={password} onValueChange={setPassword} />
41
+ * </BoxedList>
42
+ *
43
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.PasswordEntryRow.html
44
+ */
45
+ export declare const PasswordEntryRow: import('react').ForwardRefExoticComponent<PasswordEntryRowProps & import('react').RefAttributes<TextInput>>;
@@ -0,0 +1,2 @@
1
+ export type { PasswordEntryRowProps } from './PasswordEntryRow';
2
+ export { PasswordEntryRow } from './PasswordEntryRow';