@gnome-ui/react-native 1.3.0 → 1.4.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.
@@ -0,0 +1,42 @@
1
+ import { TextProps } from '../Text';
2
+ export interface HighlightProps extends Omit<TextProps, 'children'> {
3
+ /** Full text to render. */
4
+ text: string;
5
+ /**
6
+ * Term or terms to highlight within `text`. Pass an array to highlight
7
+ * multiple distinct terms at once (e.g. each word of a multi-word search
8
+ * query). Empty or whitespace-only terms are ignored.
9
+ */
10
+ query: string | string[];
11
+ /** Match case-sensitively. Defaults to `false`. */
12
+ caseSensitive?: boolean;
13
+ }
14
+ /**
15
+ * Wraps every occurrence of `query` within `text` in a highlighted inline
16
+ * run — mirrors `@gnome-ui/react`'s `Highlight`, which wraps matches in a
17
+ * `<mark>`. Pairs with `SearchBar`'s suggestion list and any filterable
18
+ * list to show users which part of a result matched what they typed.
19
+ *
20
+ * The outer span is the themed `Text` component (so callers get the same
21
+ * `variant`/`color` API as everywhere else), but each matched run is a
22
+ * plain, unthemed RN `Text` carrying only the highlight's own overrides —
23
+ * RN's `Text` is the one primitive that inherits ambient `fontSize`/
24
+ * `color`/`fontFamily` from a parent `Text` when nested, the same way the
25
+ * web version's `<mark>` inherits from its surrounding text and only
26
+ * overrides `background-color`/`font-weight`. Reaching for the themed
27
+ * `Text` for the marked runs too would reset them to its own default
28
+ * `variant="body"` sizing instead of inheriting whatever variant the
29
+ * caller chose for the whole string.
30
+ *
31
+ * The web version's translucent `color-mix(in srgb, accent 30%,
32
+ * transparent)` background has no RN equivalent (`color-mix` is CSS-only)
33
+ * — resolved to a literal 8-digit `#RRGGBBAA` hex instead, since
34
+ * `accentBgColor` is always a plain 6-digit hex across all four theme
35
+ * variants. `border-radius` on the `<mark>` has no reliable port either:
36
+ * RN only paints `backgroundColor` on an inline (nested) `Text` run, not
37
+ * `borderRadius` — a decorative nicety dropped here, not a behavior gap.
38
+ * `prefers-contrast: more`'s solid-background/white-text swap ports via
39
+ * `useResolvedContrast()`, the same hook `Button` already uses for its own
40
+ * high-contrast branching.
41
+ */
42
+ export declare const Highlight: ({ text, query, caseSensitive, ...textProps }: HighlightProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export type { HighlightProps } from './Highlight';
2
+ export { Highlight } from './Highlight';
@@ -0,0 +1,72 @@
1
+ import { StyleProp, ViewStyle } from 'react-native';
2
+ export type LevelBarVariant = 'accent' | 'success' | 'warning' | 'error';
3
+ export interface LevelBarProps {
4
+ /** Current value, between `min` and `max`. */
5
+ value: number;
6
+ /** Minimum value. Defaults to `0`. */
7
+ min?: number;
8
+ /** Maximum value. Defaults to `1`. */
9
+ max?: number;
10
+ /** Threshold at or below which the bar renders in `lowVariant`. */
11
+ low?: number;
12
+ /** Color used when `value <= low`. Defaults to `"warning"`. */
13
+ lowVariant?: LevelBarVariant;
14
+ /** Threshold at or above which the bar renders in `highVariant`. */
15
+ high?: number;
16
+ /** Color used when `value >= high`. Defaults to `"error"`. */
17
+ highVariant?: LevelBarVariant;
18
+ /** Color used between `low` and `high`. Defaults to `"accent"`. */
19
+ variant?: LevelBarVariant;
20
+ /**
21
+ * Render as a row of discrete blocks instead of a continuous fill —
22
+ * mirrors `GtkLevelBar`'s discrete mode (e.g. signal-strength indicators).
23
+ */
24
+ discrete?: boolean;
25
+ /** Number of blocks when `discrete` is true. Defaults to `10`. */
26
+ numBlocks?: number;
27
+ /** Accessible label describing what the level represents. */
28
+ accessibilityLabel?: string;
29
+ style?: StyleProp<ViewStyle>;
30
+ testID?: string;
31
+ }
32
+ /**
33
+ * Discrete level indicator with color-coded low/high offset zones —
34
+ * mirrors `GtkLevelBar` and `@gnome-ui/react`'s `LevelBar`. Use for a
35
+ * gauge/measurement display (disk usage, battery, signal strength), not
36
+ * for task progress (see `ProgressBar`) or a proportional category
37
+ * breakdown (see `SegmentedBar`).
38
+ *
39
+ * The continuous fill reuses `ProgressBar`'s exact animation technique
40
+ * rather than animating `width` directly: a fixed `width: '100%'` fill
41
+ * with `transformOrigin: 'left'` and an animated `transform: [{ scaleX }]`,
42
+ * so the whole thing runs on `useNativeDriver: true` — a JS-driven
43
+ * (`useNativeDriver: false`) `width` animation schedules its next frame via
44
+ * a plain `setTimeout` that routinely fires after a test's `render()`
45
+ * returns but before unmount, producing a real "update not wrapped in
46
+ * act()" warning, the same reasoning `ProgressBar`'s own docstring
47
+ * documents. `useReducedMotion()` mirrors `ProgressBar`'s determinate
48
+ * behavior: the transition duration drops to `0` (an immediate jump)
49
+ * rather than the animation being skipped in some other way.
50
+ *
51
+ * Discrete mode's per-block `background-color` transition has no port —
52
+ * unlike the continuous fill's width change, a value change in discrete
53
+ * mode is a binary color swap per block with no established `Animated`
54
+ * color-interpolation precedent elsewhere in this package, so it's a
55
+ * plain, unanimated style swap; a decorative nicety, not a behavior gap.
56
+ * Discrete blocks are hidden from the accessibility tree
57
+ * (`accessibilityElementsHidden`/`importantForAccessibility="no"`,
58
+ * mirroring the web version's `aria-hidden`) since the meter's value is
59
+ * already exposed once via `accessibilityValue` on the container.
60
+ *
61
+ * `role="meter"` ports 1:1 from RN's newer web-aligned `Role` union (unlike
62
+ * `AccessibilityRole`, which has no `"meter"` value at all) — the same
63
+ * precedent `Dialog`/`Avatar`/`Badge` already established for reaching for
64
+ * `role` over `accessibilityRole` when only the newer union has the value
65
+ * needed. Web's `aria-labelledby` (an id-relationship prop) has no RN
66
+ * equivalent — RN has no DOM ids — so only `aria-label`
67
+ * (`accessibilityLabel`) is ported, the same `ProgressBar`/`Slider`
68
+ * precedent.
69
+ *
70
+ * @see https://developer.gnome.org/hig/patterns/feedback/progress.html
71
+ */
72
+ export declare const LevelBar: ({ value, min, max, low, lowVariant, high, highVariant, variant, discrete, numBlocks, accessibilityLabel, style, testID, }: LevelBarProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export type { LevelBarProps, LevelBarVariant } from './LevelBar';
2
+ export { LevelBar } from './LevelBar';
@@ -0,0 +1,41 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+ export interface OverlayProps {
4
+ /** Whether the overlay is visible. */
5
+ open: boolean;
6
+ /** Called when the backdrop itself (not its content) is pressed. */
7
+ onDismiss?: () => void;
8
+ children?: ReactNode;
9
+ style?: StyleProp<ViewStyle>;
10
+ testID?: string;
11
+ }
12
+ /**
13
+ * Standalone backdrop/scrim layer with a fade transition and
14
+ * press-to-dismiss — the shared building block behind `Dialog`,
15
+ * `Dropdown`, `Popover`, and `BottomSheet`'s backdrops, extracted here for
16
+ * building custom overlay UI, mirroring `@gnome-ui/react`'s `Overlay`.
17
+ *
18
+ * Deliberately minimal, same as the web version: no focus trap, no
19
+ * `BackHandler`/Escape handling, no `role`. Use `Dialog`/`Popover`/
20
+ * `BottomSheet` directly when you need those — this is only the fade +
21
+ * dismiss-on-backdrop-tap primitive underneath them.
22
+ *
23
+ * Built on `Modal` rather than the web version's `createPortal` — no
24
+ * `container` prop exists here, since RN's `Modal` has no equivalent
25
+ * mount-target concept (it always renders at the top of the native view
26
+ * hierarchy). Reuses `Dialog`'s exact backdrop recipe: an
27
+ * `AnimatedPressable` backdrop whose `onPress` fires `onDismiss`, wrapping
28
+ * `children` in a no-op `Pressable` so a tap on the content itself never
29
+ * bubbles to the backdrop and dismisses it — the RN analog of the web
30
+ * version's `e.target === e.currentTarget` check, which has no meaning in
31
+ * RN's touch-responder model.
32
+ *
33
+ * **Real, timed exit animation, same technique as `BottomSheet`**: a local
34
+ * `visible` state lags one animation behind the `open` prop, flipping to
35
+ * `false` only in the fade-out `Animated.timing`'s own completion callback
36
+ * — not a `setTimeout` racing a hardcoded duration like the web version,
37
+ * since `Animated`'s callback already fires exactly when the animation
38
+ * actually finishes. `useBodyScrollLock` has no RN equivalent needed —
39
+ * `Modal` already blocks all interaction with whatever's behind it.
40
+ */
41
+ export declare const Overlay: ({ open, onDismiss, children, style, testID }: OverlayProps) => import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,2 @@
1
+ export type { OverlayProps } from './Overlay';
2
+ export { Overlay } from './Overlay';
@@ -0,0 +1,91 @@
1
+ import { ReactElement, ReactNode, Ref } from 'react';
2
+ import { PressableProps, StyleProp, ViewStyle, View } from 'react-native';
3
+ export type PopoverPlacement = 'top' | 'bottom' | 'left' | 'right';
4
+ export interface PopoverProps {
5
+ /**
6
+ * The rich content rendered inside the popover panel.
7
+ * Can include interactive elements (buttons, links, forms).
8
+ */
9
+ content: ReactNode;
10
+ /**
11
+ * Preferred placement relative to the trigger.
12
+ * Flips automatically when there is not enough viewport space.
13
+ * Defaults to `"bottom"`.
14
+ */
15
+ placement?: PopoverPlacement;
16
+ /**
17
+ * Whether the popover is open (controlled mode).
18
+ * Omit to use uncontrolled mode where the trigger toggles it.
19
+ */
20
+ open?: boolean;
21
+ /** Called when open state should change. */
22
+ onOpenChange?: (open: boolean) => void;
23
+ /** Extra style on the popover panel itself. */
24
+ panelStyle?: StyleProp<ViewStyle>;
25
+ /**
26
+ * The trigger element. Must be a single element built on `Pressable`
27
+ * (e.g. `Button`, `Card`) that forwards its `ref` to the underlying `View`.
28
+ */
29
+ children: ReactElement<PressableProps & {
30
+ ref?: Ref<View>;
31
+ }>;
32
+ }
33
+ /**
34
+ * Floating panel anchored to a trigger element, following the Adwaita
35
+ * `GtkPopover` pattern. Unlike `Tooltip`, a popover can contain rich
36
+ * interactive content (buttons, links, forms).
37
+ *
38
+ * Rebuilt with `View`/`Pressable`/`Modal` rather than ported from
39
+ * `@gnome-ui/react`'s DOM `Portal` + manual focus trap, reusing this
40
+ * package's own established pieces rather than re-deriving them: `Tooltip`'s
41
+ * `cloneElement`-onto-an-arbitrary-trigger architecture and 4-placement
42
+ * fallback-cascade positioning (`computePosition`, same shape, no arrow-
43
+ * offset-shift-when-clamped complexity — same simplification `Tooltip`
44
+ * already accepted), and `Dropdown`'s toggle-on-press + full-screen backdrop
45
+ * `Pressable` that closes on an outside tap (the RN analog of the web
46
+ * version's document-level "click outside" listener) plus reduced-motion
47
+ * fade-in.
48
+ *
49
+ * **Deliberate divergence from `Dropdown`'s backdrop structure**: `Dropdown`
50
+ * nests its panel directly inside the backdrop `Pressable` and gets away
51
+ * with it because almost every pixel of its panel is itself a `Pressable`
52
+ * option row, which claims the touch responder before it can bubble to the
53
+ * backdrop. A popover's `content` is arbitrary — likely to have inert
54
+ * padding/whitespace/text with no `Pressable` of its own — so nesting the
55
+ * same way would let a tap on inert panel space fall through to the
56
+ * backdrop and close the popover, unlike the web version's `.contains()`
57
+ * check (which never closes on *any* tap inside the panel). Fixed with
58
+ * `onStartShouldSetResponder={() => true}` on the panel itself: it claims
59
+ * the touch responder for any touch RN's negotiation hasn't already given to
60
+ * a deeper `Pressable` inside `content`, without making the panel itself
61
+ * behave like a button.
62
+ *
63
+ * `BackHandler`'s `hardwareBackPress` (wired the same way `Dialog` already
64
+ * does) is the Android analog of the web version's document-level Escape
65
+ * listener — there is no keyboard `Escape` to catch on a touch-first device.
66
+ * Focus-trapping and focus-restore-on-close have no port: there is no DOM
67
+ * `document.activeElement`/`querySelector` equivalent in RN, the same gap
68
+ * that already left every other floating component in this package (
69
+ * `Dialog`, `Tooltip`, `Dropdown`) without them.
70
+ *
71
+ * The web version's rotated-square-with-matching-background arrow (relying
72
+ * on same-color blending across a straddled panel edge and CSS stacking
73
+ * order) is replaced with `Tooltip`'s simpler transparent-border-triangle
74
+ * technique — same visual affordance (a pointer toward the trigger), a much
75
+ * simpler RN-native primitive.
76
+ *
77
+ * `role="dialog"` on the panel ports 1:1 from RN's newer web-aligned `Role`
78
+ * union (the same one `Dialog`/`Tooltip` already use) — no substitution
79
+ * needed. `aria-haspopup`/`aria-controls` have no RN equivalent (no
80
+ * cross-platform relationship-attribute prop); only `accessibilityState.
81
+ * expanded` is wired on the trigger, the same subset `Dropdown`'s own
82
+ * trigger already exposes.
83
+ *
84
+ * @example
85
+ * <Popover content={<Text>Rich content here</Text>}>
86
+ * <Button>Open</Button>
87
+ * </Popover>
88
+ *
89
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Popover.html
90
+ */
91
+ export declare const Popover: ({ content, placement: preferredPlacement, open: controlledOpen, onOpenChange, panelStyle, children, }: PopoverProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export type { PopoverPlacement, PopoverProps } from './Popover';
2
+ export { Popover } from './Popover';
@@ -0,0 +1,57 @@
1
+ import { StyleProp, ViewStyle } from 'react-native';
2
+ export interface SpinButtonProps {
3
+ /** Current value. */
4
+ value: number;
5
+ /** Called when the value changes. */
6
+ onChange: (value: number) => void;
7
+ /** Minimum allowed value. Defaults to `0`. */
8
+ min?: number;
9
+ /** Maximum allowed value. Defaults to `100`. */
10
+ max?: number;
11
+ /** Amount to increment/decrement per step. Defaults to `1`. */
12
+ step?: number;
13
+ /** Number of decimal places shown. Derived from `step` when omitted. */
14
+ decimals?: number;
15
+ /**
16
+ * Wrap around instead of clamping at the edges — stepping past `max` returns
17
+ * to `min` and vice versa, and the −/+ buttons never disable. Mirrors
18
+ * `GtkSpinButton:wrap`; used for cyclic values like hours and minutes.
19
+ */
20
+ wrap?: boolean;
21
+ /**
22
+ * Custom display formatter for the current value (e.g. zero-padding, or
23
+ * mapping a numeric value to `AM`/`PM`). Defaults to fixed-decimal text. When
24
+ * provided, its result is also exposed as the accessibility value's `text`.
25
+ */
26
+ format?: (value: number) => string;
27
+ /** Disables the control. */
28
+ disabled?: boolean;
29
+ /** Accessible label. Required — RN has no visible-label association to fall back on. */
30
+ accessibilityLabel?: string;
31
+ style?: StyleProp<ViewStyle>;
32
+ }
33
+ /**
34
+ * Numeric input with − and + buttons following the Adwaita `GtkSpinButton` style.
35
+ *
36
+ * Rebuilt with `View`/`Pressable`/`Text` rather than ported from
37
+ * `@gnome-ui/react`'s DOM-based JSX, but mirrors its prop API and clamp/wrap/
38
+ * decimal math (pure JS, ported verbatim).
39
+ *
40
+ * The primary interaction is tapping the visible −/+ buttons, same as a
41
+ * sighted mouse user on the web version. The web version's keyboard
42
+ * interaction (↑/↓ one step, Page Up/Down ten steps, Home/End to bounds) has
43
+ * no RN equivalent — a touch-first device has no keyboard to drive it, the
44
+ * same reasoning `Slider` already applied. Rather than dropping value
45
+ * adjustment accessibility entirely, single-step increment/decrement is
46
+ * wired through `accessibilityRole="adjustable"` + `onAccessibilityAction`
47
+ * (VoiceOver's swipe-up/down, TalkBack's local-context menu), reusing the
48
+ * exact recipe `Slider` already proved works — the bigger Page Up/Down and
49
+ * Home/End jumps have no equivalent screen-reader gesture on either
50
+ * platform, so those alone are dropped, same as `Slider`. The visible
51
+ * buttons are hidden from the accessibility tree (mirrors the web version's
52
+ * `aria-hidden`/`tabIndex={-1}` on both `<button>`s) so a screen reader user
53
+ * gets one adjustable stop, not three.
54
+ *
55
+ * @see https://developer.gnome.org/hig/patterns/controls/spin-buttons.html
56
+ */
57
+ export declare const SpinButton: ({ value, onChange, min, max, step, decimals, wrap, format, disabled, accessibilityLabel, style, }: SpinButtonProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export type { SpinButtonProps } from './SpinButton';
2
+ export { SpinButton } from './SpinButton';