@gnome-ui/react-native 1.10.0 → 1.11.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
@@ -1464,6 +1464,41 @@ thin composition of those same three pieces. `label` is required since the
1464
1464
  button has no visible text. Built as a genuine prerequisite for `Drawer`'s
1465
1465
  `rail`, not scope creep — every piece it composes already existed.
1466
1466
 
1467
+ ### CopyButton
1468
+
1469
+ ```tsx
1470
+ import { CopyButton } from '@gnome-ui/react-native';
1471
+
1472
+ <CopyButton value="CVE-2024-3094" />
1473
+ <CopyButton value={installCommand} label="Copy install command" copiedLabel="Added to clipboard" />
1474
+ ```
1475
+
1476
+ Icon button that copies `value` to the clipboard, swapping to a checkmark
1477
+ and a "Copied!" tooltip for `resetDelay` ms (default 2000) as confirmation
1478
+ — mirrors `@gnome-ui/react`'s `CopyButton`. RN has no `navigator.clipboard`,
1479
+ so this is built on `@react-native-clipboard/clipboard` (a new peer
1480
+ dependency, deliberately chosen over `expo-clipboard` so this package
1481
+ works the same in bare RN and Expo, not just this repo's own Expo example
1482
+ app — the same "no new peer dependency without a deliberate decision"
1483
+ standard `AnimatedIcon`'s `react-native-svg` addition was held to).
1484
+
1485
+ **Real environment finding**: `@react-native-clipboard/clipboard`'s native
1486
+ module isn't part of Expo Go's preinstalled module set, so any app using
1487
+ this component needs a custom dev client (`npx expo prebuild` +
1488
+ `expo run:ios`/`run:android`) rather than plain Expo Go — confirmed by
1489
+ hitting `TurboModuleRegistry.getEnforcing(...): 'RNCClipboard' could not
1490
+ be found` in Expo Go before building this repo's own example app a dev
1491
+ client to verify the component on-device.
1492
+
1493
+ Its `setString` is synchronous and void — unlike the web version's
1494
+ `navigator.clipboard.writeText`, which returns a `Promise` that can
1495
+ reject, there's no error channel to observe under normal operation.
1496
+ `onCopyError` is kept for API parity (and wraps the native call in a
1497
+ `try`/`catch` defensively) but in practice won't fire the way it can on
1498
+ web. The live-region announcement uses `role="status"` directly — RN's
1499
+ newer `Role` union does include `"status"`, unlike the older
1500
+ `AccessibilityRole` enum `Toast` had to substitute `"alert"` for.
1501
+
1467
1502
  ### Drawer
1468
1503
 
1469
1504
  ```tsx
@@ -1494,6 +1529,44 @@ no exit keyframes at all, so this follows `Dialog`'s simpler animation
1494
1529
  shape instead. `backdrop-filter: blur(4px)` has no port (no native blur
1495
1530
  dependency in this package).
1496
1531
 
1532
+ ### Toolbar
1533
+
1534
+ ```tsx
1535
+ import { Button, Spacer, Toolbar } from '@gnome-ui/react-native';
1536
+
1537
+ <Toolbar>
1538
+ <Button variant="flat">Cancel</Button>
1539
+ <Spacer />
1540
+ <Button variant="flat">Done</Button>
1541
+ </Toolbar>
1542
+ ```
1543
+
1544
+ Horizontal action bar following the libadwaita `.toolbar` pattern —
1545
+ mirrors `@gnome-ui/react`'s `Toolbar`. Directly portable, no web-only APIs
1546
+ — a flex row with `theme.space1` (6 dp) padding and gap, the standard
1547
+ spacing for rows of flat buttons in header bars, action bars, and tool
1548
+ rows. Use `Button variant="flat"` for buttons that blend into the bar, or
1549
+ `variant="raised"` for one that needs explicit elevation within a flat
1550
+ context. The web CSS's `color`/`font-family` on `.toolbar` are dropped —
1551
+ RN has no style inheritance from a parent `View` down to child `Text`
1552
+ the way CSS `color` cascades, so a value there would reach nothing (every
1553
+ child, e.g. `Button`, already sets its own explicit colors).
1554
+
1555
+ ### Spacer
1556
+
1557
+ ```tsx
1558
+ import { Spacer } from '@gnome-ui/react-native';
1559
+ ```
1560
+
1561
+ Invisible `flex: 1` filler for `Toolbar` and `HeaderBar` — mirrors
1562
+ `@gnome-ui/react`'s `Spacer`. Place between leading and trailing groups to
1563
+ push trailing items to the end. `accessible={false}` mirrors the web
1564
+ version's `aria-hidden="true"` — the same "purely decorative, exclude
1565
+ from the accessibility tree entirely" call `Separator` already made,
1566
+ rather than reaching for `role`'s newer `"separator"` value (which
1567
+ exists, but implies a divider a screen reader user might care about — a
1568
+ plain flex filler has no such meaning).
1569
+
1497
1570
  ### AvatarGroup
1498
1571
 
1499
1572
  ```tsx
@@ -2330,6 +2403,36 @@ nesting one `Pressable` inside another would create two overlapping tap
2330
2403
  targets. `aria-labelledby` has no RN equivalent, so `accessibilityLabel`
2331
2404
  combines the title and subtitle instead.
2332
2405
 
2406
+ ### SwitchRow
2407
+
2408
+ ```tsx
2409
+ import { BoxedList, SwitchRow } from '@gnome-ui/react-native';
2410
+
2411
+ <BoxedList>
2412
+ <SwitchRow
2413
+ title="Wi-Fi"
2414
+ subtitle="Home Network"
2415
+ checked={wifi}
2416
+ onCheckedChange={setWifi}
2417
+ />
2418
+ </BoxedList>
2419
+ ```
2420
+
2421
+ Activatable row with an integrated switch, for use inside a `BoxedList`
2422
+ — mirrors `@gnome-ui/react`'s `SwitchRow`. The entire row is a single
2423
+ pressable; pressing anywhere toggles the switch, which is why this isn't
2424
+ `ActionRow` + a trailing `Switch` — `AdwSwitchRow` makes the whole row the
2425
+ interactive element, the same shape `CheckRow` already established for its
2426
+ checkbox. Use for a single on/off setting; prefer `CheckRow` for
2427
+ multi-select scenarios. Supports both controlled (`checked`) and
2428
+ uncontrolled (`defaultChecked`) modes, the same `isControlled`/internal-
2429
+ state-fallback shape already used by `Expander`/`ComboRow`/`Popover`/
2430
+ `CheckRow`. The switch visual reuses `Switch`'s exact track/thumb animation
2431
+ recipe, but as plain non-interactive `Animated.View`s rather than the real
2432
+ `Switch` component — nesting one `Pressable` inside another would create
2433
+ two overlapping tap targets. `aria-labelledby` has no RN equivalent, so
2434
+ `accessibilityLabel` combines the title and subtitle instead.
2435
+
2333
2436
  ### ExpanderRow
2334
2437
 
2335
2438
  ```tsx
@@ -2504,6 +2607,112 @@ counter. Six variants (`success`/`warning`/`error`/`new`/`accent`/
2504
2607
  `neutral`) reuse `Badge`'s exact color-mapping shape, plus a `new` (purple)
2505
2608
  variant `Badge` doesn't have.
2506
2609
 
2610
+ ### StepIndicator
2611
+
2612
+ ```tsx
2613
+ import { StepIndicator } from '@gnome-ui/react-native';
2614
+
2615
+ <StepIndicator steps={5} currentStep={1} />
2616
+
2617
+ <StepIndicator
2618
+ steps={['Account', 'Profile', 'Payment', 'Confirm']}
2619
+ currentStep={2}
2620
+ onStepClick={setCurrentStep}
2621
+ />
2622
+
2623
+ <StepIndicator steps={4} currentStep={2} orientation="vertical" />
2624
+ ```
2625
+
2626
+ Numbered "Step X of Y" progress indicator for onboarding/wizard flows —
2627
+ mirrors `@gnome-ui/react`'s `StepIndicator`. Directly portable, no web-only
2628
+ APIs involved: each step's circle derives its state (upcoming/current/
2629
+ completed) purely from `currentStep`. Each circle animates its own
2630
+ border/background color (an independent pair of 0/1 `Animated.Value`s,
2631
+ one for "accented border" and one for "filled background", since they
2632
+ flip on different transitions) — the content swap between number and
2633
+ checkmark and the connector-line recolor are instant, matching the source
2634
+ CSS exactly (only `background-color`/`border-color` transition there).
2635
+
2636
+ The connecting line between circles reuses the CSS trick verbatim —
2637
+ `position: absolute; left: '50%'; width: '100%'` inside each equal-width
2638
+ flex item, so the line runs from one circle's center to the next's;
2639
+ `left`/`width` percentages are valid RN position/dimension values, unlike
2640
+ the `transform: translateX('50%')` trick this package avoids elsewhere.
2641
+ The checkmark uses `tintColor` rather than `color`, since RN icons have no
2642
+ `currentColor` to inherit — the same call `BottomTabBar`'s active-tab icon
2643
+ already made for tracking the *configurable* accent.
2644
+
2645
+ The outer container sets `role="navigation"` **without** `accessible` —
2646
+ the `ToggleGroup`-established pattern for a grouping role over multiple
2647
+ independently-focusable children (each step circle): `accessible` here
2648
+ would collapse the whole indicator into one VoiceOver stop on iOS. Assert
2649
+ `element.props.role` on a `testID` in tests instead of
2650
+ `getByRole('navigation')`. A completed step's circle becomes a `Pressable`
2651
+ only when `onStepClick` is provided — the current and upcoming steps are
2652
+ never pressable, matching the web version.
2653
+
2654
+ ### Timeline
2655
+
2656
+ ```tsx
2657
+ import { Timeline } from '@gnome-ui/react-native';
2658
+
2659
+ <Timeline
2660
+ items={[
2661
+ { leading: <Text color="dim">10:00</Text>, icon: <Icon icon={Check} tintColor={theme.accentFgColor} />, content: <Text>Approved</Text> },
2662
+ { content: <Text>Pending review</Text> },
2663
+ ]}
2664
+ />
2665
+
2666
+ <Timeline orientation="horizontal" variant="dotted" items={steps} />
2667
+ ```
2668
+
2669
+ Ordered sequence of events connected by a visual timeline — mirrors
2670
+ `@gnome-ui/react`'s `Timeline`. An original composition (no direct
2671
+ libadwaita widget), following GNOME HIG activity-feed/stepper patterns.
2672
+
2673
+ The web version aligns every item's `leading` column (vertical) or row
2674
+ (horizontal) via CSS subgrid, so timestamps/labels line up across items
2675
+ regardless of how wide/tall any single one of them is. RN/Yoga has no
2676
+ grid or subgrid at all, so that alignment is reproduced by measurement
2677
+ instead — the same `onLayout` + `Record<index, size>` +
2678
+ "largest-so-far wins" technique `Slider`'s mark labels already
2679
+ established. The node track itself additionally gets a fixed width
2680
+ (vertical, 24 dp, matching the source CSS's literal grid column) or
2681
+ height (horizontal, 28 dp, the larger of the dot/icon node sizes) so
2682
+ `content` starts at the same position across items even when dot and
2683
+ icon nodes are mixed in the same list.
2684
+
2685
+ `orientation="horizontal"` wraps itself in a horizontal `ScrollView`,
2686
+ reimagining the web CSS's `overflow-x: auto`. The web version's
2687
+ `grid-auto-columns: minmax(72px, 1fr)` also grows items to fill leftover
2688
+ space when the row doesn't overflow; that half doesn't port (a
2689
+ `ScrollView`'s content isn't bounded the way a CSS grid track is) — each
2690
+ item gets a flat 72 dp `minWidth` instead, unconditionally scrollable.
2691
+
2692
+ **Real, on-device-confirmed platform bug found while building `variant="dotted"`**:
2693
+ RN's `borderStyle: 'dotted'` renders nothing at all — no error, just
2694
+ invisible — unless *every* side shares the same width and color; the
2695
+ direct 1:1 port of the web CSS's single-side `border-left`/`border-top`
2696
+ dotted line (one bordered side, the other three left unset) silently
2697
+ produced no line whatsoever. Confirmed via the iOS Simulator with
2698
+ saturated debug colors: a uniform four-side `borderWidth`/`borderColor`
2699
+ renders the dotted pattern correctly, but reintroducing even three
2700
+ `transparent` sides (uniform width, per-side color) suppresses it again.
2701
+ Fixed by drawing the dotted connector as a narrow (6 dp) box with a
2702
+ uniform dotted border on all four sides instead of a single bordered
2703
+ edge — visually indistinguishable from a single dotted line at this
2704
+ thickness. **Any future dotted/dashed RN border needs all sides
2705
+ width-and-color-uniform — a single-side border in that style silently
2706
+ renders invisible.**
2707
+
2708
+ `icon`/`leading`/`content` are plain `ReactNode`, the same as `PathBar`'s
2709
+ segment `icon` — the consumer sizes and colors their own icon (e.g.
2710
+ `tintColor={theme.accentFgColor}`), since RN has no `currentColor` for
2711
+ this component to tint an arbitrary child with. `role="list"`/
2712
+ `role="listitem"` are set without `accessible`, the same
2713
+ `ToggleGroup`/`StepIndicator`-established pattern for a grouping role
2714
+ over children that may themselves contain focusable content.
2715
+
2507
2716
  ### WidgetManager
2508
2717
 
2509
2718
  ```tsx
@@ -2647,6 +2856,55 @@ threshold. Unlike the web version there's no `data-breakpoint` attribute
2647
2856
  to expose for CSS targeting (RN has no attribute selectors) — branch on
2648
2857
  `activeBreakpoint` directly inside the render prop instead.
2649
2858
 
2859
+ ### ScrollToTop
2860
+
2861
+ ```tsx
2862
+ import { ScrollToTop } from '@gnome-ui/react-native';
2863
+
2864
+ const scrollRef = useRef<ScrollView>(null);
2865
+ const [scrollY, setScrollY] = useState(0);
2866
+
2867
+ <View style={{ flex: 1 }}>
2868
+ <ScrollView
2869
+ ref={scrollRef}
2870
+ onScroll={(e) => setScrollY(e.nativeEvent.contentOffset.y)}
2871
+ scrollEventThrottle={16}
2872
+ >
2873
+ {/* ... */}
2874
+ </ScrollView>
2875
+ <ScrollToTop
2876
+ scrollY={scrollY}
2877
+ onPress={() => scrollRef.current?.scrollTo({ y: 0, animated: true })}
2878
+ />
2879
+ </View>;
2880
+ ```
2881
+
2882
+ Absolutely-positioned OSD button that scrolls a `ScrollView`/`FlatList`
2883
+ back to the top — mirrors `@gnome-ui/react`'s `ScrollToTop`, reimagined
2884
+ rather than ported 1:1: RN has no page-level scroll event to observe
2885
+ internally, so the web version's `useScrollToTopVisibility` (a `window`/
2886
+ element `scroll` listener) doesn't port at all. `visible="auto"` (the
2887
+ default) is instead a pure function of a `scrollY` number prop the
2888
+ consumer feeds from their own `ScrollView`'s `onScroll` — no internal
2889
+ state or listener needed. There's likewise no way for this component to
2890
+ scroll a `ScrollView`/`FlatList` on the consumer's behalf the way the web
2891
+ version calls `scrollTarget.scrollTo(...)` itself, so pressing the button
2892
+ calls the required `onPress` instead — typically
2893
+ `scrollRef.current?.scrollTo({ y: 0, animated: true })`.
2894
+
2895
+ Same "no `document.body`/portal target" gap `Toaster` already documents —
2896
+ mount this yourself as the last child of the `View` wrapping your
2897
+ scrollable content so it paints on top; `pointerEvents="box-none"` (the
2898
+ same technique `Toaster` uses) keeps the empty space around the button
2899
+ from intercepting touches meant for the content underneath. The web
2900
+ version's resting `opacity: 0.5`-until-hover/focus is dropped, the same
2901
+ call `PasswordEntryRow`'s reveal button already made — that effect exists
2902
+ purely so the control can brighten on hover, and touch has no hover.
2903
+ `topInset`/`bottomInset` let you thread in your own
2904
+ `useSafeAreaInsets()` values for a `"top-*"`/`"bottom-*"` position, same
2905
+ as `BottomTabBar`'s `bottomInset` — this package takes no dependency on
2906
+ `react-native-safe-area-context` itself.
2907
+
2650
2908
  ## Installation
2651
2909
 
2652
2910
  ```bash
@@ -0,0 +1,44 @@
1
+ import { IconButtonProps } from '../IconButton';
2
+ export interface CopyButtonProps extends Omit<IconButtonProps, 'icon' | 'label' | 'onPress' | 'tooltip'> {
3
+ /** The text copied to the clipboard when the button is activated. */
4
+ value: string;
5
+ /** Accessible label and tooltip shown before copying. Defaults to `"Copy"`. */
6
+ label?: string;
7
+ /** Accessible label and tooltip shown briefly after a successful copy. Defaults to `"Copied!"`. */
8
+ copiedLabel?: string;
9
+ /** How long the "copied" confirmation state is shown, in milliseconds. Defaults to `2000`. */
10
+ resetDelay?: number;
11
+ /**
12
+ * Called after `value` is written to the clipboard.
13
+ * Named `onCopied` (not `onCopy`), mirroring the web version's own naming.
14
+ */
15
+ onCopied?: (value: string) => void;
16
+ /**
17
+ * Called if the copy attempt throws. Kept for API parity with the web
18
+ * version's `onCopyError` (whose `navigator.clipboard.writeText` can
19
+ * reject, e.g. on permission denial) — but `@react-native-clipboard/
20
+ * clipboard`'s `setString` is a synchronous, void-returning native call
21
+ * with no error channel at all, so in normal operation this won't fire
22
+ * the way it can on web. Kept as a defensive catch around the native
23
+ * call (a real, if unlikely, synchronous throw) rather than removed.
24
+ */
25
+ onCopyError?: (error: unknown) => void;
26
+ }
27
+ /**
28
+ * Icon button that copies `value` to the clipboard, swapping to a checkmark
29
+ * and a "Copied!" tooltip for `resetDelay` ms as confirmation — mirrors
30
+ * `@gnome-ui/react`'s `CopyButton`.
31
+ *
32
+ * RN has no `navigator.clipboard`, so this is built on
33
+ * `@react-native-clipboard/clipboard` (the community-standard clipboard
34
+ * module, not `expo-clipboard` — chosen so this package works the same in
35
+ * bare RN and Expo, not just this repo's own Expo example app). Its
36
+ * `setString` is synchronous and void — see `onCopyError`'s doc for what
37
+ * that means for error handling.
38
+ *
39
+ * The live-region announcement uses `role="status"` directly (RN's newer
40
+ * `Role` union does include `"status"`, unlike the older
41
+ * `AccessibilityRole` enum `Toast` had to substitute `"alert"` for) plus
42
+ * `accessibilityLiveRegion="polite"` for Android's announcement mechanism.
43
+ */
44
+ export declare const CopyButton: ({ value, label, copiedLabel, resetDelay, onCopied, onCopyError, ...props }: CopyButtonProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export type { CopyButtonProps } from './CopyButton';
2
+ export { CopyButton } from './CopyButton';
@@ -0,0 +1,105 @@
1
+ import { StyleProp, View, ViewStyle } from 'react-native';
2
+ /**
3
+ * Controls when the button is rendered.
4
+ *
5
+ * - `"auto"` — hidden until `scrollY` exceeds `threshold` (default).
6
+ * - `"always"` — always rendered regardless of scroll position.
7
+ */
8
+ export type ScrollToTopVisible = 'always' | 'auto';
9
+ /**
10
+ * Anchor corner or edge for the absolutely-positioned container.
11
+ * The button is inset `theme.space4` (24 dp) from each named edge.
12
+ */
13
+ export type ScrollToTopPosition = 'bottom-right' | 'bottom-left' | 'bottom-center' | 'top-right' | 'top-left' | 'top-center';
14
+ export interface ScrollToTopProps {
15
+ /**
16
+ * Controls when the button is visible.
17
+ *
18
+ * - `"auto"` (default) — shown only once `scrollY` exceeds `threshold`.
19
+ * - `"always"` — permanently visible.
20
+ */
21
+ visible?: ScrollToTopVisible;
22
+ /**
23
+ * Corner or edge where the button is anchored. Default: `"bottom-right"`.
24
+ */
25
+ position?: ScrollToTopPosition;
26
+ /**
27
+ * Offset the user must scroll past before the button appears.
28
+ * Only relevant when `visible="auto"`. Default: `300`.
29
+ */
30
+ threshold?: number;
31
+ /**
32
+ * The observed `ScrollView`/`FlatList`'s current vertical scroll offset —
33
+ * pass `nativeEvent.contentOffset.y` from its `onScroll` handler. Only
34
+ * relevant when `visible="auto"`; ignored (and safe to omit) otherwise.
35
+ * Default: `0`.
36
+ */
37
+ scrollY?: number;
38
+ /**
39
+ * Called when the button is pressed. There's no RN equivalent of the web
40
+ * version's own `scrollTarget.scrollTo({ top: 0, behavior: 'smooth' })` —
41
+ * `ScrollView`/`FlatList` are scrolled through a ref's imperative
42
+ * `scrollTo`/`scrollToOffset`, which this component has no way to hold on
43
+ * a consumer's behalf. Typically
44
+ * `() => scrollViewRef.current?.scrollTo({ y: 0, animated: true })`.
45
+ */
46
+ onPress: () => void;
47
+ /**
48
+ * Extra inset added on top of the base edge spacing when anchored to a
49
+ * `"top-*"` position — pass your own `useSafeAreaInsets().top` so the
50
+ * button clears a notch/status bar. Same "no new peer dependency" call
51
+ * `BottomTabBar`'s `bottomInset` already made. Default: `0`.
52
+ */
53
+ topInset?: number;
54
+ /** Same as `topInset`, for a `"bottom-*"` position. Default: `0`. */
55
+ bottomInset?: number;
56
+ style?: StyleProp<ViewStyle>;
57
+ testID?: string;
58
+ }
59
+ /**
60
+ * Absolutely-positioned OSD button that scrolls a `ScrollView`/`FlatList`
61
+ * back to the top — mirrors `@gnome-ui/react`'s `ScrollToTop`, reimagined
62
+ * rather than ported 1:1 per this package's own ROADMAP note: RN has no
63
+ * page-level scroll event to observe internally the way the web version's
64
+ * `useScrollToTopVisibility` attaches a `window`/element `scroll` listener,
65
+ * so that hook doesn't port at all — `visible="auto"` is instead a pure
66
+ * function of a `scrollY` prop the consumer feeds from their own
67
+ * `ScrollView`'s `onScroll`, re-evaluated on every render with no internal
68
+ * state or listener needed.
69
+ *
70
+ * Same "no `document.body`/portal target" gap `Toaster` already
71
+ * documents — mount this yourself as the last child of the `View` wrapping
72
+ * your scrollable content (left at its default relative positioning) so it
73
+ * paints on top; `pointerEvents="box-none"` (the same technique `Toaster`
74
+ * uses) keeps the empty space around the button from intercepting touches
75
+ * meant for the content underneath.
76
+ *
77
+ * The web version's resting `opacity: 0.5`-until-hover/focus is dropped —
78
+ * the same call `PasswordEntryRow`'s reveal button already made: that
79
+ * effect exists purely so the control can brighten on hover, and touch has
80
+ * no hover, so a permanently dimmed control would just be harder to see.
81
+ *
82
+ * Forwards `ref` to the root positioning `View`, not the inner button —
83
+ * matching the web version's own `forwardRef` target.
84
+ *
85
+ * @example
86
+ * // Minimal — appears once `scrollY` exceeds 300, anchored bottom-right
87
+ * const [scrollY, setScrollY] = useState(0);
88
+ * const scrollRef = useRef<ScrollView>(null);
89
+ * <View style={{ flex: 1 }}>
90
+ * <ScrollView
91
+ * ref={scrollRef}
92
+ * onScroll={(e) => setScrollY(e.nativeEvent.contentOffset.y)}
93
+ * scrollEventThrottle={16}
94
+ * >
95
+ * ...
96
+ * </ScrollView>
97
+ * <ScrollToTop
98
+ * scrollY={scrollY}
99
+ * onPress={() => scrollRef.current?.scrollTo({ y: 0, animated: true })}
100
+ * />
101
+ * </View>
102
+ *
103
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.ScrollToTop.html
104
+ */
105
+ export declare const ScrollToTop: import('react').ForwardRefExoticComponent<ScrollToTopProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,2 @@
1
+ export type { ScrollToTopPosition, ScrollToTopProps, ScrollToTopVisible } from './ScrollToTop';
2
+ export { ScrollToTop } from './ScrollToTop';
@@ -0,0 +1,25 @@
1
+ import { StyleProp, View, ViewProps, ViewStyle } from 'react-native';
2
+ export interface SpacerProps extends Omit<ViewProps, 'style'> {
3
+ style?: StyleProp<ViewStyle>;
4
+ }
5
+ /**
6
+ * Invisible `flex: 1` filler for `Toolbar` and `HeaderBar` — mirrors
7
+ * `@gnome-ui/react`'s `Spacer`. Place between leading and trailing groups
8
+ * to push trailing items to the end.
9
+ *
10
+ * `accessible={false}` mirrors the web version's `aria-hidden="true"` —
11
+ * same "purely decorative, exclude from the accessibility tree entirely"
12
+ * call `Separator` already made, rather than reaching for `role`'s newer
13
+ * `"separator"` value (which exists but implies a divider a screen
14
+ * reader user might care about; a plain flex filler has no such meaning).
15
+ *
16
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/1-latest/style-classes.html#spacer
17
+ *
18
+ * @example
19
+ * <Toolbar>
20
+ * <Button variant="flat">Back</Button>
21
+ * <Spacer />
22
+ * <Button variant="flat">Done</Button>
23
+ * </Toolbar>
24
+ */
25
+ export declare const Spacer: import('react').ForwardRefExoticComponent<SpacerProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,2 @@
1
+ export type { SpacerProps } from './Spacer';
2
+ export { Spacer } from './Spacer';
@@ -0,0 +1,56 @@
1
+ import { StyleProp, ViewStyle } from 'react-native';
2
+ export type StepIndicatorOrientation = 'horizontal' | 'vertical';
3
+ export interface StepIndicatorProps {
4
+ /**
5
+ * Total number of steps, or an array of per-step labels rendered beside
6
+ * (vertical) or beneath (horizontal) each circle. Pass a plain number for
7
+ * an unlabelled sequence (only the "Step X of Y" caption is shown); pass
8
+ * an array of strings to label each step.
9
+ */
10
+ steps: number | string[];
11
+ /** Zero-based index of the current/active step. */
12
+ currentStep: number;
13
+ /** Layout direction. Default: `"horizontal"`. */
14
+ orientation?: StepIndicatorOrientation;
15
+ /**
16
+ * Called when a completed step's circle is pressed, letting the user jump
17
+ * back to a step they've already finished. Omit to make steps
18
+ * non-interactive. The current and upcoming steps are never pressable.
19
+ */
20
+ onStepClick?: (index: number) => void;
21
+ /** Accessible label for the indicator. Default: `"Progress"`. */
22
+ label?: string;
23
+ style?: StyleProp<ViewStyle>;
24
+ testID?: string;
25
+ }
26
+ /**
27
+ * Numbered "Step X of Y" progress indicator for onboarding/wizard flows —
28
+ * mirrors `@gnome-ui/react`'s `StepIndicator`. Directly portable per this
29
+ * package's own ROADMAP note: no web-only APIs are involved, just derived
30
+ * dot/number state from `currentStep`.
31
+ *
32
+ * The outer container sets `role="navigation"` **without** `accessible` —
33
+ * the corrected pattern `ToggleGroup` established over the earlier
34
+ * `BoxedList`/`ViewSwitcher` precedent: `accessible` on a *grouping*
35
+ * container with multiple independently-focusable children (each step
36
+ * circle here) collapses the whole subtree into one VoiceOver stop on iOS.
37
+ * The role still groups on Android, and every step stays individually
38
+ * reachable; assert `element.props.role` on a `testID` in tests instead of
39
+ * `getByRole('navigation')`.
40
+ *
41
+ * The connecting line between circles reuses the exact CSS trick verbatim
42
+ * (`position: absolute; left: 50%; width: 100%` inside each equal-width
43
+ * flex item, so the line runs from one circle's center to the next's) —
44
+ * `left`/`width` percentages are supported for RN position/dimension
45
+ * props, unlike the `transform: translateX('50%')` trick this package has
46
+ * hit real bugs with elsewhere (that limitation is specific to `transform`).
47
+ *
48
+ * The web version's checkmark/number content swap and connector-line color
49
+ * change have no CSS `transition` at all (only `.circle`'s own
50
+ * `background-color`/`border-color` do), so only those two colors animate
51
+ * here — the content swap and connector recolor are instant, matching the
52
+ * source exactly rather than adding an unrequested fade.
53
+ *
54
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.StepIndicator.html
55
+ */
56
+ export declare const StepIndicator: ({ steps, currentStep, orientation, onStepClick, label, style, testID, }: StepIndicatorProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export type { StepIndicatorOrientation, StepIndicatorProps } from './StepIndicator';
2
+ export { StepIndicator } from './StepIndicator';
@@ -0,0 +1,43 @@
1
+ import { ReactNode } from 'react';
2
+ import { PressableProps, StyleProp, View, ViewStyle } from 'react-native';
3
+ export interface SwitchRowProps extends Omit<PressableProps, 'children' | 'style' | 'onPress'> {
4
+ /** Primary label. */
5
+ title: string;
6
+ /** Secondary line below the title. */
7
+ subtitle?: string;
8
+ /** Icon or image placed at the leading edge. */
9
+ leading?: ReactNode;
10
+ /** Controlled checked state. */
11
+ checked?: boolean;
12
+ /** Initial checked state when uncontrolled. Defaults to `false`. */
13
+ defaultChecked?: boolean;
14
+ /** Called with the next value when the row is pressed. */
15
+ onCheckedChange?: (checked: boolean) => void;
16
+ style?: StyleProp<ViewStyle>;
17
+ }
18
+ /**
19
+ * Activatable row with an integrated switch, mirroring `@gnome-ui/react`'s
20
+ * `SwitchRow`. The entire row is a single pressable — pressing anywhere
21
+ * toggles the switch, which is why this isn't `ActionRow` + a trailing
22
+ * `Switch` (the ROADMAP's own guess): `AdwSwitchRow` makes the whole row the
23
+ * interactive element, the same shape `CheckRow` already established for
24
+ * its checkbox. Prefer this over `CheckRow` for a single on/off setting,
25
+ * and `CheckRow` for selecting/deselecting individual items in a list.
26
+ *
27
+ * The switch visual reuses `Switch`'s exact track/thumb `Animated.Value`
28
+ * interpolation, but as plain non-interactive `Animated.View`s rather than
29
+ * importing the real `Switch` component — `Switch` is itself a `Pressable`,
30
+ * and nesting one touchable inside another (the row's own `Pressable`)
31
+ * would create two overlapping tap targets, the same reasoning `CheckRow`
32
+ * already applied to `Checkbox`. `aria-labelledby` (pointing the web
33
+ * button's `role="switch"` at the title/subtitle content) has no RN
34
+ * equivalent — `accessibilityLabel` combining title and subtitle is the
35
+ * substitution, same as `CheckRow`.
36
+ *
37
+ * Supports both controlled (`checked`) and uncontrolled (`defaultChecked`)
38
+ * modes, the same `isControlled`/internal-state-fallback shape already
39
+ * established by `Expander`/`ComboRow`/`Popover`/`CheckRow`.
40
+ *
41
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.SwitchRow.html
42
+ */
43
+ export declare const SwitchRow: import('react').ForwardRefExoticComponent<SwitchRowProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,2 @@
1
+ export type { SwitchRowProps } from './SwitchRow';
2
+ export { SwitchRow } from './SwitchRow';