@gnome-ui/react-native 1.5.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.
Files changed (43) hide show
  1. package/README.md +647 -3
  2. package/dist/components/AvatarGroup/AvatarGroup.d.ts +47 -0
  3. package/dist/components/AvatarGroup/index.d.ts +2 -0
  4. package/dist/components/AvatarRotator/AvatarRotator.d.ts +65 -0
  5. package/dist/components/AvatarRotator/index.d.ts +2 -0
  6. package/dist/components/Bin/Bin.d.ts +18 -0
  7. package/dist/components/Bin/index.d.ts +2 -0
  8. package/dist/components/Box/Box.d.ts +87 -0
  9. package/dist/components/Box/index.d.ts +2 -0
  10. package/dist/components/Clamp/Clamp.d.ts +61 -0
  11. package/dist/components/Clamp/index.d.ts +2 -0
  12. package/dist/components/CoachMark/CoachMark.d.ts +92 -0
  13. package/dist/components/CoachMark/CoachMarkTour.d.ts +54 -0
  14. package/dist/components/CoachMark/coachMarkUtils.d.ts +42 -0
  15. package/dist/components/CoachMark/index.d.ts +5 -0
  16. package/dist/components/ColorPicker/ColorPicker.d.ts +81 -0
  17. package/dist/components/ColorPicker/ColorSwatch.d.ts +50 -0
  18. package/dist/components/ColorPicker/index.d.ts +4 -0
  19. package/dist/components/ComboRow/ComboRow.d.ts +77 -0
  20. package/dist/components/ComboRow/index.d.ts +2 -0
  21. package/dist/components/EntryRow/EntryRow.d.ts +77 -0
  22. package/dist/components/EntryRow/index.d.ts +2 -0
  23. package/dist/components/InlineViewSwitcher/InlineViewSwitcher.d.ts +93 -0
  24. package/dist/components/InlineViewSwitcher/InlineViewSwitcherItem.d.ts +25 -0
  25. package/dist/components/InlineViewSwitcher/index.d.ts +4 -0
  26. package/dist/components/InlineViewSwitcher/variants.d.ts +30 -0
  27. package/dist/components/PasswordEntryRow/PasswordEntryRow.d.ts +45 -0
  28. package/dist/components/PasswordEntryRow/index.d.ts +2 -0
  29. package/dist/components/PreferencesGroup/PreferencesGroup.d.ts +52 -0
  30. package/dist/components/PreferencesGroup/index.d.ts +2 -0
  31. package/dist/components/StatusPage/StatusPage.d.ts +79 -0
  32. package/dist/components/StatusPage/index.d.ts +2 -0
  33. package/dist/components/ToggleGroup/ToggleGroup.d.ts +70 -0
  34. package/dist/components/ToggleGroup/ToggleGroupItem.d.ts +49 -0
  35. package/dist/components/ToggleGroup/index.d.ts +4 -0
  36. package/dist/components/WrapBox/WrapBox.d.ts +67 -0
  37. package/dist/components/WrapBox/index.d.ts +2 -0
  38. package/dist/index.cjs +1 -1
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.ts +15 -0
  41. package/dist/index.js +2057 -645
  42. package/dist/index.js.map +1 -1
  43. package/package.json +1 -1
@@ -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,93 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, View, ViewProps, ViewStyle } from 'react-native';
3
+ import { InlineViewSwitcherVariant, VariantStyles } from './variants';
4
+ export type { InlineViewSwitcherVariant } from './variants';
5
+ export type InlineViewSwitcherOverflow = 'wrap' | 'scroll' | 'compact' | 'menu';
6
+ /** Measured position of one item inside the switcher row. */
7
+ export interface ItemLayout {
8
+ x: number;
9
+ width: number;
10
+ }
11
+ interface InlineViewSwitcherContextValue {
12
+ value: string;
13
+ onValueChange: (value: string) => void;
14
+ compact: boolean;
15
+ styles: VariantStyles;
16
+ onItemLayout: (name: string, layout: ItemLayout) => void;
17
+ }
18
+ export declare function useInlineViewSwitcher(): InlineViewSwitcherContextValue;
19
+ export interface InlineViewSwitcherProps extends Omit<ViewProps, 'style'> {
20
+ /** Currently active view name. */
21
+ value: string;
22
+ /** Called with the new value when a view is selected. */
23
+ onValueChange: (value: string) => void;
24
+ /**
25
+ * Visual style of the switcher.
26
+ * - `default` — card background with border (same shape as `ToggleGroup`).
27
+ * - `flat` — no background or border; active indicator only.
28
+ * - `round` — pill-shaped container and items, solid accent indicator.
29
+ * - `pill` — segmented-control style; active item appears lifted, no accent color.
30
+ */
31
+ variant?: InlineViewSwitcherVariant;
32
+ /**
33
+ * Overflow strategy when the container is too narrow for all items.
34
+ * - `wrap` — default; items simply overflow.
35
+ * - `scroll` — horizontal scroll, snapping each item to the start edge.
36
+ * - `compact` — collapses item labels to icons-only when overflowing (needs icons on all items).
37
+ * - `menu` — shows the active item and a chevron; all items open in a `BottomSheet`.
38
+ */
39
+ overflow?: InlineViewSwitcherOverflow;
40
+ /** Accessible label for the group. */
41
+ accessibilityLabel?: string;
42
+ children?: ReactNode;
43
+ style?: StyleProp<ViewStyle>;
44
+ }
45
+ /**
46
+ * Compact inline view switcher for content areas, cards, and toolbars —
47
+ * wherever `ViewSwitcher` (header-bar sized) would be too heavy. Mirrors
48
+ * `AdwInlineViewSwitcher` (libadwaita 1.7 / GNOME 48) and
49
+ * `@gnome-ui/react`'s own `InlineViewSwitcher`.
50
+ *
51
+ * All four variants and all four overflow strategies port, but almost none
52
+ * of the *mechanism* does — this is a rebuild, not a transliteration:
53
+ *
54
+ * - **The sliding indicator** is measured, not laid out. The web reads the
55
+ * active button's `offsetLeft`/`offsetWidth` in a `useLayoutEffect`; here
56
+ * each item reports its own `onLayout` up through the context, and the
57
+ * indicator animates `translateX` + `width` to the active entry. Both run
58
+ * on **one JS-driven animation** (`useNativeDriver: false`): `width` can't
59
+ * be native-driven, and mixing a native and a JS value on one component
60
+ * throws — the same trade-off `Expander` accepted for its own animated
61
+ * height. `scaleX` would have been native-driveable but distorts the
62
+ * indicator's corner radii, which is exactly what the variants shape.
63
+ * `useReducedMotion()` snaps it into place instead, per this package's
64
+ * per-component convention.
65
+ * - **Overflow detection** replaces `ResizeObserver` + `scrollWidth` vs
66
+ * `clientWidth` with the item measurements already being collected: their
67
+ * summed natural widths (RN defaults `flexShrink` to 0, so an overflowing
68
+ * row reports each item's *natural* width rather than a squeezed one)
69
+ * against the row's own `onLayout` width. The web's `naturalWidthRef`
70
+ * capture and 30 px hysteresis port verbatim — without them, collapsing
71
+ * the labels shrinks the content and would immediately re-expand it.
72
+ * - **`overflow="scroll"`** becomes a horizontal `ScrollView` with the
73
+ * scrollbar hidden. `scroll-snap-align: start` has no RN style, but the
74
+ * measured item offsets feed `snapToOffsets`, which reproduces it exactly.
75
+ * - **`overflow="menu"`** reuses the already-shipped `BottomSheet`, the same
76
+ * component the web version reaches for.
77
+ *
78
+ * The ←/→/Home/End keyboard layer drops, as everywhere else in this package.
79
+ * As in `ToggleGroup`, the group takes `accessibilityRole="radiogroup"` but
80
+ * deliberately not `accessible`, which on iOS would collapse the items into
81
+ * a single unreachable element.
82
+ *
83
+ * @example
84
+ * const [view, setView] = useState('grid');
85
+ *
86
+ * <InlineViewSwitcher value={view} onValueChange={setView} variant="pill">
87
+ * <InlineViewSwitcherItem name="grid" label="Grid" />
88
+ * <InlineViewSwitcherItem name="list" label="List" />
89
+ * </InlineViewSwitcher>
90
+ *
91
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.InlineViewSwitcher.html
92
+ */
93
+ export declare const InlineViewSwitcher: import('react').ForwardRefExoticComponent<InlineViewSwitcherProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,25 @@
1
+ import { IconDefinition } from '@gnome-ui/icons';
2
+ import { PressableProps, View } from 'react-native';
3
+ export interface InlineViewSwitcherItemProps extends Omit<PressableProps, 'children' | 'style' | 'disabled' | 'onPress'> {
4
+ /** String identifier — becomes the switcher's `value` when this item is active. */
5
+ name: string;
6
+ /** Visible label. */
7
+ label?: string;
8
+ /** Icon from `@gnome-ui/icons`. */
9
+ icon?: IconDefinition;
10
+ /** Accessible name. Required for icon-only items; defaults to `label`. */
11
+ accessibilityLabel?: string;
12
+ disabled?: boolean;
13
+ }
14
+ /**
15
+ * Individual view option inside an `InlineViewSwitcher`. Can be icon-only,
16
+ * label-only, or icon + label — for icon-only items always pass an
17
+ * `accessibilityLabel` so screen readers can identify the view.
18
+ *
19
+ * The item paints no background of its own for the active state: that's the
20
+ * parent's sliding indicator, which this component feeds by reporting its
21
+ * `onLayout` position and width up through the context. Only the label's
22
+ * color and weight change, exactly as in the web version — where the
23
+ * `.active` class also sets nothing but `color` and `font-weight`.
24
+ */
25
+ export declare const InlineViewSwitcherItem: import('react').ForwardRefExoticComponent<InlineViewSwitcherItemProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,4 @@
1
+ export type { InlineViewSwitcherOverflow, InlineViewSwitcherProps, InlineViewSwitcherVariant, } from './InlineViewSwitcher';
2
+ export { InlineViewSwitcher } from './InlineViewSwitcher';
3
+ export type { InlineViewSwitcherItemProps } from './InlineViewSwitcherItem';
4
+ export { InlineViewSwitcherItem } from './InlineViewSwitcherItem';
@@ -0,0 +1,30 @@
1
+ import { TextStyle, ViewStyle } from 'react-native';
2
+ import { GnomeThemeTokens } from '../../theme';
3
+ export type InlineViewSwitcherVariant = 'default' | 'flat' | 'round' | 'pill';
4
+ export interface VariantStyles {
5
+ container: ViewStyle;
6
+ /** Same values as `container.gap`/`container.padding`, kept as plain
7
+ * numbers so the overflow math can add them up — `ViewStyle` types them
8
+ * as `DimensionValue`, which may be a percentage string. */
9
+ gap: number;
10
+ padding: number;
11
+ item: ViewStyle;
12
+ iconOnlyItem: ViewStyle;
13
+ indicator: ViewStyle;
14
+ /** Inset of the indicator from the container's top/bottom edge. */
15
+ indicatorInset: number;
16
+ activeTextColor: string;
17
+ idleTextColor: string;
18
+ }
19
+ /**
20
+ * The four `.default`/`.flat`/`.round`/`.pill` CSS blocks, resolved against
21
+ * the theme. Every `color-mix(in srgb, accent N%, transparent)` becomes an
22
+ * 8-digit `#RRGGBBAA` hex off `theme.accentBgColor` (the `Chip`/`ToggleGroup`
23
+ * precedent, which keeps the tint following the app's configurable accent),
24
+ * and every `box-shadow` is dropped — the theme generator keeps shadow
25
+ * tokens in `raw` only and `Card` already settled that a border, or the
26
+ * surface contrast itself, carries the same separation on RN.
27
+ */
28
+ export declare function getVariantStyles(theme: GnomeThemeTokens, variant: InlineViewSwitcherVariant, isDark: boolean): VariantStyles;
29
+ /** Shared by the item label and the menu-sheet rows. */
30
+ export declare function labelTextStyle(theme: GnomeThemeTokens, active: boolean, color: string): TextStyle;
@@ -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';
@@ -0,0 +1,52 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, View, ViewProps, ViewStyle } from 'react-native';
3
+ export interface PreferencesGroupProps extends Omit<ViewProps, 'style'> {
4
+ /** Group heading. */
5
+ title?: string;
6
+ /** Optional description rendered below the title. */
7
+ description?: string;
8
+ /** Widget placed at the trailing edge of the title row (e.g. a reset `Button`). */
9
+ headerSuffix?: ReactNode;
10
+ /** `BoxedList` rows or any row-shaped content. */
11
+ children?: ReactNode;
12
+ style?: StyleProp<ViewStyle>;
13
+ }
14
+ /**
15
+ * Titled section that wraps a `BoxedList` with an optional description,
16
+ * mirroring `AdwPreferencesGroup` and `@gnome-ui/react`'s own
17
+ * `PreferencesGroup`.
18
+ *
19
+ * Use it to group related settings under a named heading. The group is
20
+ * purely a layout and labelling wrapper — it doesn't render the `BoxedList`
21
+ * itself; pass one as `children`.
22
+ *
23
+ * The web's empty `.content` wrapper looks like dead markup but is
24
+ * load-bearing, so it's kept: the group is a 12 dp-gap flex column, and
25
+ * without that wrapper every child would become a flex item of the group and
26
+ * pick up a 12 dp gap between the rows themselves, instead of one gap
27
+ * between the header and the content as a whole.
28
+ *
29
+ * The title is `Text variant="body"` with an explicit semibold weight rather
30
+ * than `variant="heading"`, which is body-sized but **bold** and on the
31
+ * tighter heading line-height — the CSS `.title` is specifically semibold at
32
+ * the body line-height. It keeps the `header` accessibility role anyway
33
+ * (passed explicitly), since a settings-group heading is exactly the kind of
34
+ * landmark a screen reader rotor should list — the same call `StatusPage`
35
+ * makes for its own title.
36
+ *
37
+ * `min-width: 0` on the header text has no port and needs none: it's the
38
+ * classic CSS flexbox override for a min-content floor that Yoga doesn't
39
+ * apply in the first place.
40
+ *
41
+ * @example
42
+ * <PreferencesGroup
43
+ * title="Appearance"
44
+ * description="How the app looks on this device."
45
+ * headerSuffix={<Button variant="flat" onPress={reset}>Reset</Button>}
46
+ * >
47
+ * <BoxedList>{rows}</BoxedList>
48
+ * </PreferencesGroup>
49
+ *
50
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.PreferencesGroup.html
51
+ */
52
+ export declare const PreferencesGroup: import('react').ForwardRefExoticComponent<PreferencesGroupProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,2 @@
1
+ export type { PreferencesGroupProps } from './PreferencesGroup';
2
+ export { PreferencesGroup } from './PreferencesGroup';
@@ -0,0 +1,79 @@
1
+ import { IconDefinition } from '@gnome-ui/icons';
2
+ import { ReactNode } from 'react';
3
+ import { StyleProp, View, ViewProps, ViewStyle } from 'react-native';
4
+ export interface StatusPageProps extends Omit<ViewProps, 'style'> {
5
+ /**
6
+ * Large icon displayed above the title.
7
+ * Use an icon from `@gnome-ui/icons` or omit for a text-only page.
8
+ */
9
+ icon?: IconDefinition;
10
+ /**
11
+ * Custom icon node. Use when you need an image, emoji, or a rendered
12
+ * SVG that is not part of `@gnome-ui/icons`.
13
+ * Ignored when `icon` is also provided.
14
+ */
15
+ iconNode?: ReactNode;
16
+ /** Main heading. Keep it short — one noun phrase. */
17
+ title: string;
18
+ /** Supporting description rendered below the title. */
19
+ description?: string;
20
+ /**
21
+ * Optional action area — typically one or two `Button`s.
22
+ * Rendered below the description, wrapping onto a second line if needed.
23
+ */
24
+ children?: ReactNode;
25
+ /**
26
+ * Reduces padding, icon size, and title scale for use in compact
27
+ * contexts such as sidebars, popovers, and small panels.
28
+ */
29
+ compact?: boolean;
30
+ style?: StyleProp<ViewStyle>;
31
+ }
32
+ /**
33
+ * Empty-state / status page following the Adwaita `AdwStatusPage` pattern,
34
+ * mirroring `@gnome-ui/react`'s own `StatusPage`.
35
+ *
36
+ * Use to fill a view with no content yet, an error state, or a completion
37
+ * confirmation. Always explain *why* the view is empty and *what the user
38
+ * can do* about it — don't use it for loading states, where `Spinner` or
39
+ * `ProgressBar` belong instead.
40
+ *
41
+ * Centres its content on both axes, but — exactly as in the web version —
42
+ * the vertical centring only does anything once a parent gives it height:
43
+ * put it in a `flex: 1` container to fill the view.
44
+ *
45
+ * The title renders through this package's `Text` at `variant="title-1"`
46
+ * (`"title-4"` when `compact`), which means it also picks up `Text`'s
47
+ * automatic `header` accessibility role — a deliberate divergence from the
48
+ * web version's `<p class="title">`. That `<p>` exists because HTML forces
49
+ * you to pick a concrete `h1`–`h6` level for a component that has no idea
50
+ * where it sits in the document outline; RN's `header` role carries no
51
+ * level, so the dilemma disappears and the title can be what it actually
52
+ * is. On a touch device the rotor is the only structural navigation a
53
+ * screen reader user has, so this is worth having.
54
+ *
55
+ * The icon is dimmed by its wrapper's `opacity` (0.55 light / 0.45 dark,
56
+ * the two values the web version's own `@media (prefers-color-scheme)`
57
+ * block hardcodes) and hidden from assistive tech with the
58
+ * `accessibilityElementsHidden` + `importantForAccessibility="no"` pair
59
+ * this package already uses in place of `aria-hidden`. Its color needs no
60
+ * handling at all: `Icon` already defaults to the theme foreground, which
61
+ * is what `.iconWrap`'s `color` sets.
62
+ *
63
+ * The action area is a `WrapBox` rather than a hand-rolled row — `.actions`
64
+ * is `display: flex; flex-wrap: wrap; justify-content: center; gap` and
65
+ * nothing else, which is exactly what that component already is.
66
+ *
67
+ * @example
68
+ * <StatusPage
69
+ * icon={StarOutline}
70
+ * title="No favorites yet"
71
+ * description="Packages you star will show up here."
72
+ * >
73
+ * <Button variant="suggested" onPress={onAdd}>Add a package</Button>
74
+ * </StatusPage>
75
+ *
76
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.StatusPage.html
77
+ * @see https://developer.gnome.org/hig/patterns/feedback/empty-states.html
78
+ */
79
+ export declare const StatusPage: import('react').ForwardRefExoticComponent<StatusPageProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,2 @@
1
+ export type { StatusPageProps } from './StatusPage';
2
+ export { StatusPage } from './StatusPage';
@@ -0,0 +1,70 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, View, ViewProps, ViewStyle } from 'react-native';
3
+ interface ToggleGroupContextValue {
4
+ value: string;
5
+ onValueChange: (value: string) => void;
6
+ }
7
+ /** Internal — `ToggleGroupItem` reads the selected value and setter from here. */
8
+ export declare function useToggleGroup(): ToggleGroupContextValue;
9
+ export interface ToggleGroupProps extends Omit<ViewProps, 'style'> {
10
+ /** Name of the currently active toggle. */
11
+ value: string;
12
+ /** Called with the new value when a toggle is selected. */
13
+ onValueChange: (value: string) => void;
14
+ /** Accessible label for the group. */
15
+ accessibilityLabel?: string;
16
+ children?: ReactNode;
17
+ style?: StyleProp<ViewStyle>;
18
+ }
19
+ /**
20
+ * Mutually-exclusive group of toggle buttons for in-place option selection.
21
+ * Mirrors `AdwToggleGroup` (libadwaita 1.7 / GNOME 48) and
22
+ * `@gnome-ui/react`'s own `ToggleGroup`.
23
+ *
24
+ * Use for formatting controls, view-mode selectors, and toolbar options —
25
+ * wherever a `ViewSwitcher` would be too heavy or doesn't belong in a
26
+ * `HeaderBar`. Compose with `ToggleGroupItem`.
27
+ *
28
+ * The context and its `value`/`onValueChange` shape port 1:1 — pure React,
29
+ * no DOM involved. What doesn't port is the keyboard layer: the web version
30
+ * owns an `onKeyDown` handler implementing ← / → cycling and Home / End
31
+ * jumps over a roving `tabIndex`, none of which has a touch counterpart.
32
+ * That's this package's standing convention, already set by `ViewSwitcher`
33
+ * and `TabBar`; the `radiogroup`/`radio` + `checked` accessibility pairing
34
+ * that VoiceOver and TalkBack actually announce is what carries the
35
+ * semantics here instead.
36
+ *
37
+ * The group carries `accessibilityRole="radiogroup"` but deliberately
38
+ * **not** `accessible` — on iOS, `accessible` on a container collapses the
39
+ * whole subtree into one accessibility element, which would make the
40
+ * individual toggles unreachable for VoiceOver and defeat the point of the
41
+ * role. Without it the role still groups on Android while every item stays
42
+ * individually focusable. (`ViewSwitcher`, built earlier, does set
43
+ * `accessible` alongside the same role — see this package's ROADMAP note;
44
+ * worth revisiting there.) The visible trade-off is that the group won't
45
+ * match a `getByRole('radiogroup')` query, since Testing Library only
46
+ * matches roles on accessible elements — the items are what matter to a
47
+ * screen reader, and they each match `getByRole('radio')`.
48
+ *
49
+ * `display: inline-flex` becomes `alignSelf: 'flex-start'` (the same
50
+ * hug-your-content trick `ViewSwitcher` uses), and `box-shadow:
51
+ * var(--gnome-shadow-sm)` is dropped rather than approximated — the theme
52
+ * generator deliberately keeps the shadow tokens in `raw` only, and `Card`
53
+ * already established that a border carries the same separation on RN.
54
+ * The dark-mode border color is hardcoded per scheme (`rgba(255,255,255,
55
+ * 0.12)`) exactly as the source CSS hardcodes it, rather than read from
56
+ * `theme.light3`, which stays `#deddda` in every theme.
57
+ *
58
+ * @example
59
+ * const [align, setAlign] = useState('left');
60
+ *
61
+ * <ToggleGroup value={align} onValueChange={setAlign} accessibilityLabel="Alignment">
62
+ * <ToggleGroupItem name="left" icon={FormatJustifyLeft} accessibilityLabel="Left" />
63
+ * <ToggleGroupItem name="center" icon={FormatJustifyCenter} accessibilityLabel="Center" />
64
+ * <ToggleGroupItem name="right" icon={FormatJustifyRight} accessibilityLabel="Right" />
65
+ * </ToggleGroup>
66
+ *
67
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.ToggleGroup.html
68
+ */
69
+ export declare const ToggleGroup: import('react').ForwardRefExoticComponent<ToggleGroupProps & import('react').RefAttributes<View>>;
70
+ export {};
@@ -0,0 +1,49 @@
1
+ import { IconDefinition } from '@gnome-ui/icons';
2
+ import { PressableProps, View } from 'react-native';
3
+ export interface ToggleGroupItemProps extends Omit<PressableProps, 'children' | 'style' | 'disabled' | 'onPress'> {
4
+ /** String identifier — becomes the group's `value` when this item is selected. */
5
+ name: string;
6
+ /** Visible label. Omit for icon-only items (pass `accessibilityLabel` instead). */
7
+ label?: string;
8
+ /** Icon from `@gnome-ui/icons`. */
9
+ icon?: IconDefinition;
10
+ /** Accessible name. Required for icon-only items; defaults to `label`. */
11
+ accessibilityLabel?: string;
12
+ disabled?: boolean;
13
+ }
14
+ /**
15
+ * Individual toggle inside a `ToggleGroup`. Can be icon-only, label-only, or
16
+ * icon + label — for icon-only items always pass an `accessibilityLabel` so
17
+ * screen readers can identify the option.
18
+ *
19
+ * The active state's three `color-mix(in srgb, accent N%, transparent)`
20
+ * values resolve to 8-digit `#RRGGBBAA` hexes off `theme.accentBgColor`
21
+ * (always a plain 6-digit hex), the technique `Chip` already established for
22
+ * exactly this selected-tint problem — `26` for 15% and `66` for 40% in
23
+ * light, `40` for 25% and `80` for 50% in dark. The CSS paints its active
24
+ * ring as an `inset 0 0 0 1px` box-shadow, which RN has no equivalent for;
25
+ * it becomes a real `borderWidth: 1` that every item carries at all times
26
+ * (transparent when inactive) so selecting one never shifts the row's
27
+ * layout — the same substitution `AvatarGroup` made for its own ring.
28
+ *
29
+ * `:hover` has no touch counterpart and collapses away; `:active` maps to
30
+ * `Pressable`'s `pressed` state using `theme.activeOverlay`, whose light
31
+ * (`rgba(0, 0, 0, 0.12)`) and dark (`rgba(255, 255, 255, 0.14)`) values are
32
+ * character-for-character the CSS's own `:active` colors — the same
33
+ * coincidence `ViewSwitcherItem` documented and reused. The
34
+ * `background-color`/`box-shadow` transition is dropped rather than
35
+ * rebuilt on `Animated`: `ViewSwitcherItem`, the closest sibling, doesn't
36
+ * animate its own selection either, so there is no reduced-motion handling
37
+ * to wire up here.
38
+ *
39
+ * The icon keeps the default foreground color instead of tracking the
40
+ * active accent text: `Icon` has no `currentColor` equivalent, and its
41
+ * `color` prop is a fixed GNOME palette (`blue`, `green`, …) with no
42
+ * `accent` member — which couldn't follow the app's configurable accent
43
+ * anyway. Same call, same reason, as `Chip`.
44
+ *
45
+ * `icon` is an `IconDefinition` rather than the `ReactNode` the older
46
+ * `ViewSwitcherItem` takes; that component predates `Icon` shipping in this
47
+ * package, while `Chip` and the web version both type it this way.
48
+ */
49
+ export declare const ToggleGroupItem: import('react').ForwardRefExoticComponent<ToggleGroupItemProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,4 @@
1
+ export type { ToggleGroupProps } from './ToggleGroup';
2
+ export { ToggleGroup } from './ToggleGroup';
3
+ export type { ToggleGroupItemProps } from './ToggleGroupItem';
4
+ export { ToggleGroupItem } from './ToggleGroupItem';