@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 +258 -0
- package/dist/components/CopyButton/CopyButton.d.ts +44 -0
- package/dist/components/CopyButton/index.d.ts +2 -0
- package/dist/components/ScrollToTop/ScrollToTop.d.ts +105 -0
- package/dist/components/ScrollToTop/index.d.ts +2 -0
- package/dist/components/Spacer/Spacer.d.ts +25 -0
- package/dist/components/Spacer/index.d.ts +2 -0
- package/dist/components/StepIndicator/StepIndicator.d.ts +56 -0
- package/dist/components/StepIndicator/index.d.ts +2 -0
- package/dist/components/SwitchRow/SwitchRow.d.ts +43 -0
- package/dist/components/SwitchRow/index.d.ts +2 -0
- package/dist/components/Timeline/Timeline.d.ts +87 -0
- package/dist/components/Timeline/index.d.ts +2 -0
- package/dist/components/Toolbar/Toolbar.d.ts +25 -0
- package/dist/components/Toolbar/index.d.ts +2 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js +1203 -698
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
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,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,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,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,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>>;
|