@gnome-ui/react-native 1.5.0 → 1.6.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 +441 -3
- package/dist/components/AvatarGroup/AvatarGroup.d.ts +47 -0
- package/dist/components/AvatarGroup/index.d.ts +2 -0
- package/dist/components/AvatarRotator/AvatarRotator.d.ts +65 -0
- package/dist/components/AvatarRotator/index.d.ts +2 -0
- package/dist/components/Box/Box.d.ts +87 -0
- package/dist/components/Box/index.d.ts +2 -0
- package/dist/components/Clamp/Clamp.d.ts +61 -0
- package/dist/components/Clamp/index.d.ts +2 -0
- package/dist/components/CoachMark/CoachMark.d.ts +92 -0
- package/dist/components/CoachMark/CoachMarkTour.d.ts +54 -0
- package/dist/components/CoachMark/coachMarkUtils.d.ts +42 -0
- package/dist/components/CoachMark/index.d.ts +5 -0
- package/dist/components/InlineViewSwitcher/InlineViewSwitcher.d.ts +93 -0
- package/dist/components/InlineViewSwitcher/InlineViewSwitcherItem.d.ts +25 -0
- package/dist/components/InlineViewSwitcher/index.d.ts +4 -0
- package/dist/components/InlineViewSwitcher/variants.d.ts +30 -0
- package/dist/components/PreferencesGroup/PreferencesGroup.d.ts +52 -0
- package/dist/components/PreferencesGroup/index.d.ts +2 -0
- package/dist/components/StatusPage/StatusPage.d.ts +79 -0
- package/dist/components/StatusPage/index.d.ts +2 -0
- package/dist/components/ToggleGroup/ToggleGroup.d.ts +70 -0
- package/dist/components/ToggleGroup/ToggleGroupItem.d.ts +49 -0
- package/dist/components/ToggleGroup/index.d.ts +4 -0
- package/dist/components/WrapBox/WrapBox.d.ts +67 -0
- package/dist/components/WrapBox/index.d.ts +2 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +1487 -393
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { StyleProp, View, ViewProps, ViewStyle } from 'react-native';
|
|
3
|
+
export interface ClampProps extends Omit<ViewProps, 'style'> {
|
|
4
|
+
/**
|
|
5
|
+
* Maximum content width in density-independent pixels.
|
|
6
|
+
* The container shrinks freely below this value.
|
|
7
|
+
* Defaults to `600` — the Adwaita recommended narrow-content width.
|
|
8
|
+
*/
|
|
9
|
+
maximumSize?: number;
|
|
10
|
+
/**
|
|
11
|
+
* Fractional width (`0`–`1`) of the available space to use while that
|
|
12
|
+
* space is narrower than `maximumSize` — useful for keeping a
|
|
13
|
+
* comfortable margin on medium-width screens. Defaults to `1` (always
|
|
14
|
+
* fill the width).
|
|
15
|
+
*/
|
|
16
|
+
tighteningThreshold?: number;
|
|
17
|
+
children?: ReactNode;
|
|
18
|
+
style?: StyleProp<ViewStyle>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Constrains its children to a maximum width while letting them shrink
|
|
22
|
+
* freely, mirroring the Adwaita `AdwClamp` widget and `@gnome-ui/react`'s
|
|
23
|
+
* own `Clamp`.
|
|
24
|
+
*
|
|
25
|
+
* Use it on settings pages and forms so content never becomes too wide to
|
|
26
|
+
* read comfortably on a tablet or a landscape phone, while still filling
|
|
27
|
+
* the available width on a narrow one.
|
|
28
|
+
*
|
|
29
|
+
* The web version's `margin-inline: auto` centering becomes
|
|
30
|
+
* `alignSelf: 'center'` here rather than `marginHorizontal: 'auto'` —
|
|
31
|
+
* RN auto-margin support was left unverified for this Yoga version when
|
|
32
|
+
* `Drawer` needed the same trick, so this follows `Drawer`'s resolution of
|
|
33
|
+
* using flex alignment instead. The one consequence is that `Clamp`
|
|
34
|
+
* expects a column-direction parent (RN's default): `alignSelf` acts on
|
|
35
|
+
* the cross axis, so inside a `flexDirection: 'row'` parent it would
|
|
36
|
+
* centre vertically instead. Wrap it in a plain `View` there.
|
|
37
|
+
*
|
|
38
|
+
* `tighteningThreshold` is a real percentage width here, unlike in
|
|
39
|
+
* `@gnome-ui/react` where the prop is declared and documented but never
|
|
40
|
+
* reaches the DOM — implementing it exactly as that package documents it
|
|
41
|
+
* (a fraction of the available width, still capped by `maximumSize`)
|
|
42
|
+
* costs nothing on RN and avoids shipping a dead prop.
|
|
43
|
+
*
|
|
44
|
+
* Adds no padding of its own — wrap the content in its own padded
|
|
45
|
+
* container as needed.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // Settings page — content never wider than 600 dp
|
|
49
|
+
* <Clamp>
|
|
50
|
+
* <BoxedList>…</BoxedList>
|
|
51
|
+
* </Clamp>
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* // Leave a 10% margin while the screen is narrower than 480 dp
|
|
55
|
+
* <Clamp maximumSize={480} tighteningThreshold={0.9}>
|
|
56
|
+
* <Text>…</Text>
|
|
57
|
+
* </Clamp>
|
|
58
|
+
*
|
|
59
|
+
* @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Clamp.html
|
|
60
|
+
*/
|
|
61
|
+
export declare const Clamp: import('react').ForwardRefExoticComponent<ClampProps & import('react').RefAttributes<View>>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { ReactNode, RefObject } from 'react';
|
|
2
|
+
import { StyleProp, ViewStyle, View } from 'react-native';
|
|
3
|
+
import { CoachMarkPlacement } from './coachMarkUtils';
|
|
4
|
+
export interface CoachMarkAction {
|
|
5
|
+
label: string;
|
|
6
|
+
onPress: () => void;
|
|
7
|
+
}
|
|
8
|
+
export interface CoachMarkProps {
|
|
9
|
+
/** Whether the coach mark is shown. */
|
|
10
|
+
open: boolean;
|
|
11
|
+
/** The element to highlight and anchor to. */
|
|
12
|
+
targetRef: RefObject<View | null>;
|
|
13
|
+
/** Heading text. */
|
|
14
|
+
title?: ReactNode;
|
|
15
|
+
/** Body copy explaining the highlighted element. */
|
|
16
|
+
description?: ReactNode;
|
|
17
|
+
/** Preferred side of the target for the bubble. Flips to stay on-screen. Defaults to `'bottom'`. */
|
|
18
|
+
placement?: CoachMarkPlacement;
|
|
19
|
+
/** Dim the rest of the screen and cut a spotlight around the target. Defaults to `true`. */
|
|
20
|
+
spotlight?: boolean;
|
|
21
|
+
/** Extra px around the target inside the spotlight cutout. Defaults to `8`. */
|
|
22
|
+
spotlightPadding?: number;
|
|
23
|
+
/** Close when the dimmed backdrop is pressed. Defaults to `false` (guided). */
|
|
24
|
+
dismissOnBackdrop?: boolean;
|
|
25
|
+
/** 1-based index of this step within a tour, for the "X of N" counter. */
|
|
26
|
+
step?: number;
|
|
27
|
+
/** Total number of steps in the tour. */
|
|
28
|
+
stepCount?: number;
|
|
29
|
+
/** Primary (suggested) action, e.g. Next / Got it. */
|
|
30
|
+
primaryAction?: CoachMarkAction;
|
|
31
|
+
/** Secondary (flat) action, e.g. Back. */
|
|
32
|
+
secondaryAction?: CoachMarkAction;
|
|
33
|
+
/** Called when the Android back button is pressed, or the backdrop is dismissed. */
|
|
34
|
+
onDismiss?: () => void;
|
|
35
|
+
style?: StyleProp<ViewStyle>;
|
|
36
|
+
testID?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A single onboarding coach mark: it spotlights a target element and
|
|
40
|
+
* anchors a callout bubble (title, description, step counter, actions)
|
|
41
|
+
* beside it, guiding a user to one feature. Compose several with
|
|
42
|
+
* `CoachMarkTour`, or drive one directly with `open`. Mirrors
|
|
43
|
+
* `@gnome-ui/react`'s `CoachMark` — not a GNOME HIG widget, a pragmatic
|
|
44
|
+
* feature-discovery pattern.
|
|
45
|
+
*
|
|
46
|
+
* Rebuilt on RN's own `Modal` rather than the web version's DOM `Portal` —
|
|
47
|
+
* no `container` prop, the same `Overlay`/`Drawer` precedent for "no RN
|
|
48
|
+
* portal-target concept." Positions with the same two-pass viewport-aware
|
|
49
|
+
* flip as the web version (`coachMarkUtils.ts`, duplicated verbatim — pure
|
|
50
|
+
* math, no DOM), resolved from `targetRef.current?.measureInWindow(...)`
|
|
51
|
+
* and the bubble's own `onLayout` size, combined once both arrive — the
|
|
52
|
+
* same "resolve two independent async things, then combine" shape
|
|
53
|
+
* `Tooltip`/`Popover`/`Dropdown` already established. No focus trap (no
|
|
54
|
+
* DOM `Tab` concept in RN) and no scroll/resize re-positioning (RN has no
|
|
55
|
+
* global scroll event, the same `Tooltip` precedent for a transient
|
|
56
|
+
* floating element).
|
|
57
|
+
*
|
|
58
|
+
* **The spotlight cutout has no CSS `box-shadow: 0 0 0 100vmax` port** —
|
|
59
|
+
* that trick paints an opaque scrim everywhere *except* inside a rounded
|
|
60
|
+
* rect by using a huge spread shadow, which RN's `shadow*` props (real OS
|
|
61
|
+
* shadows, not a scrim generator) can't reproduce. Rebuilt as four plain
|
|
62
|
+
* `View` bands (top/bottom/left/right of the padded target rect) filling
|
|
63
|
+
* the screen minus a rectangular hole, plus a separate rounded
|
|
64
|
+
* `accentColor`-bordered ring `View` drawn on top at the target rect —
|
|
65
|
+
* visually equivalent (dims everything but the target, with an accent
|
|
66
|
+
* ring around it), just assembled from ordinary rects instead of one
|
|
67
|
+
* masked shape. The whole overlay (bands + ring) sits inside a single
|
|
68
|
+
* full-screen `Pressable`, so — matching the web version exactly — a tap
|
|
69
|
+
* anywhere within it (including visually "in the hole," since the web
|
|
70
|
+
* version's backdrop is one full-bleed element with the spotlight only
|
|
71
|
+
* painted on top, `pointer-events: none`) triggers `dismissOnBackdrop`,
|
|
72
|
+
* never the real content underneath.
|
|
73
|
+
*
|
|
74
|
+
* **`dismissOnBackdrop` has no effect when `spotlight` is `false`** —
|
|
75
|
+
* ported faithfully, not fixed: the web source only renders a backdrop
|
|
76
|
+
* element at all when `spotlight` is true, so with `spotlight={false}`
|
|
77
|
+
* there is nothing to press to dismiss via backdrop either way, on both
|
|
78
|
+
* platforms.
|
|
79
|
+
*
|
|
80
|
+
* The arrow reuses `Popover`/`Tooltip`'s transparent-border-triangle trick
|
|
81
|
+
* rather than the web CSS's rotated-45°-square, the same established RN
|
|
82
|
+
* substitution for every floating-bubble arrow in this package — offset
|
|
83
|
+
* along the bubble's edge by `arrowOffset` (from `computeBubblePosition`,
|
|
84
|
+
* unlike `Tooltip`/`Popover`'s simpler always-centered arrow).
|
|
85
|
+
*
|
|
86
|
+
* `role="dialog"` + `accessibilityViewIsModal` port 1:1 from `Dialog`'s
|
|
87
|
+
* own precedent. `BackHandler`'s `hardwareBackPress` is the Android analog
|
|
88
|
+
* of the web version's Escape listener.
|
|
89
|
+
*
|
|
90
|
+
* @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Window.html
|
|
91
|
+
*/
|
|
92
|
+
export declare const CoachMark: ({ open, targetRef, title, description, placement, spotlight, spotlightPadding, dismissOnBackdrop, step, stepCount, primaryAction, secondaryAction, onDismiss, style, testID, }: CoachMarkProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ReactNode, RefObject } from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { CoachMarkPlacement } from './coachMarkUtils';
|
|
4
|
+
export interface CoachMarkStep {
|
|
5
|
+
/** The element this step highlights. */
|
|
6
|
+
targetRef: RefObject<View | null>;
|
|
7
|
+
/** Heading for the step. */
|
|
8
|
+
title?: ReactNode;
|
|
9
|
+
/** Body copy for the step. */
|
|
10
|
+
description?: ReactNode;
|
|
11
|
+
/** Preferred bubble side for this step. Defaults to the tour's placement. */
|
|
12
|
+
placement?: CoachMarkPlacement;
|
|
13
|
+
}
|
|
14
|
+
export interface CoachMarkTourProps {
|
|
15
|
+
/** Ordered steps of the tour. */
|
|
16
|
+
steps: CoachMarkStep[];
|
|
17
|
+
/** Whether the tour is running. */
|
|
18
|
+
open: boolean;
|
|
19
|
+
/** Step to start on when the tour opens. Defaults to `0`. */
|
|
20
|
+
startIndex?: number;
|
|
21
|
+
/** Called after the primary action on the final step. */
|
|
22
|
+
onFinish?: () => void;
|
|
23
|
+
/** Called when the user skips (Skip button or Android back) before finishing. */
|
|
24
|
+
onSkip?: () => void;
|
|
25
|
+
/** Called with the new index whenever the active step changes. */
|
|
26
|
+
onStepChange?: (index: number) => void;
|
|
27
|
+
/** Default preferred bubble side for steps that don't set their own. Defaults to `'bottom'`. */
|
|
28
|
+
placement?: CoachMarkPlacement;
|
|
29
|
+
/** Spotlight the target. Defaults to `true`. */
|
|
30
|
+
spotlight?: boolean;
|
|
31
|
+
/** Close the tour when the dimmed backdrop is pressed. Defaults to `false`. */
|
|
32
|
+
dismissOnBackdrop?: boolean;
|
|
33
|
+
/** Override the action-button labels (for i18n). */
|
|
34
|
+
labels?: Partial<{
|
|
35
|
+
next: string;
|
|
36
|
+
back: string;
|
|
37
|
+
skip: string;
|
|
38
|
+
finish: string;
|
|
39
|
+
}>;
|
|
40
|
+
testID?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Sequential onboarding tour built from `CoachMark` steps. Renders the
|
|
44
|
+
* mark for the active step, wires Next/Back/Skip/Done and the "X of N"
|
|
45
|
+
* counter, and advances through `steps` until finished or skipped.
|
|
46
|
+
* Mirrors `@gnome-ui/react`'s `CoachMarkTour` verbatim — pure state
|
|
47
|
+
* orchestration on top of `CoachMark`, nothing platform-specific to
|
|
48
|
+
* change.
|
|
49
|
+
*
|
|
50
|
+
* Uncontrolled step index: the tour tracks its own position and resets to
|
|
51
|
+
* `startIndex` each time it opens. Drive visibility with `open`; react to
|
|
52
|
+
* completion with `onFinish`/`onSkip`.
|
|
53
|
+
*/
|
|
54
|
+
export declare const CoachMarkTour: ({ steps, open, startIndex, onFinish, onSkip, onStepChange, placement, spotlight, dismissOnBackdrop, labels, testID, }: CoachMarkTourProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Positioning helpers for `CoachMark`. Kept pure and measurement-free so
|
|
3
|
+
* they can be unit-tested directly; the component feeds them real rects
|
|
4
|
+
* (from `measureInWindow` instead of the web version's
|
|
5
|
+
* `getBoundingClientRect`, but the shape is identical either way).
|
|
6
|
+
*
|
|
7
|
+
* Duplicated verbatim from `@gnome-ui/react` rather than imported
|
|
8
|
+
* cross-package — the same `fileType.ts`/`Icon.tsx` precedent for
|
|
9
|
+
* DOM-free logic that isn't worth a shared package for one file's worth
|
|
10
|
+
* of code.
|
|
11
|
+
*
|
|
12
|
+
* The algorithm mirrors `Popover`'s viewport-aware flip: try the preferred
|
|
13
|
+
* side, then its opposite, then the rest, picking the first that fits;
|
|
14
|
+
* clamp the cross-axis and shift the arrow when nothing fits perfectly.
|
|
15
|
+
*/
|
|
16
|
+
export type CoachMarkPlacement = 'top' | 'bottom' | 'left' | 'right';
|
|
17
|
+
export interface Rect {
|
|
18
|
+
top: number;
|
|
19
|
+
left: number;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
}
|
|
23
|
+
export interface BubblePosition {
|
|
24
|
+
top: number;
|
|
25
|
+
left: number;
|
|
26
|
+
placement: CoachMarkPlacement;
|
|
27
|
+
/** Arrow centre offset in px from the near edge of the bubble. */
|
|
28
|
+
arrowOffset: number;
|
|
29
|
+
}
|
|
30
|
+
/** Grow a rect outward by `pad` on every side, e.g. the spotlight cutout. */
|
|
31
|
+
export declare const padRect: (rect: Rect, pad: number) => Rect;
|
|
32
|
+
/**
|
|
33
|
+
* Place the callout bubble around `target`, flipping to stay inside a
|
|
34
|
+
* `viewport` (width × height). `bubble` is the measured bubble size.
|
|
35
|
+
*/
|
|
36
|
+
export declare const computeBubblePosition: (target: Rect, bubble: {
|
|
37
|
+
width: number;
|
|
38
|
+
height: number;
|
|
39
|
+
}, viewport: {
|
|
40
|
+
width: number;
|
|
41
|
+
height: number;
|
|
42
|
+
}, preferred: CoachMarkPlacement) => BubblePosition;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { CoachMarkAction, CoachMarkProps } from './CoachMark';
|
|
2
|
+
export { CoachMark } from './CoachMark';
|
|
3
|
+
export type { CoachMarkStep, CoachMarkTourProps } from './CoachMarkTour';
|
|
4
|
+
export { CoachMarkTour } from './CoachMarkTour';
|
|
5
|
+
export type { CoachMarkPlacement } from './coachMarkUtils';
|
|
@@ -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,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,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,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 {};
|