@gnome-ui/react-native 1.3.0 → 1.5.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 +463 -4
- package/dist/components/Avatar/Avatar.d.ts +53 -0
- package/dist/components/Avatar/index.d.ts +2 -0
- package/dist/components/Badge/Badge.d.ts +48 -0
- package/dist/components/Badge/index.d.ts +2 -0
- package/dist/components/BottomSheet/BottomSheet.d.ts +82 -0
- package/dist/components/BottomSheet/index.d.ts +2 -0
- package/dist/components/Chip/Chip.d.ts +63 -0
- package/dist/components/Chip/index.d.ts +2 -0
- package/dist/components/Divider/Divider.d.ts +36 -0
- package/dist/components/Divider/index.d.ts +2 -0
- package/dist/components/Drawer/Drawer.d.ts +117 -0
- package/dist/components/Drawer/index.d.ts +2 -0
- package/dist/components/Expander/Expander.d.ts +64 -0
- package/dist/components/Expander/index.d.ts +2 -0
- package/dist/components/FileTypeIcon/FileTypeIcon.d.ts +45 -0
- package/dist/components/FileTypeIcon/fileType.d.ts +8 -0
- package/dist/components/FileTypeIcon/index.d.ts +3 -0
- package/dist/components/Highlight/Highlight.d.ts +42 -0
- package/dist/components/Highlight/index.d.ts +2 -0
- package/dist/components/IconButton/IconButton.d.ts +34 -0
- package/dist/components/IconButton/index.d.ts +2 -0
- package/dist/components/LevelBar/LevelBar.d.ts +72 -0
- package/dist/components/LevelBar/index.d.ts +2 -0
- package/dist/components/Overlay/Overlay.d.ts +41 -0
- package/dist/components/Overlay/index.d.ts +2 -0
- package/dist/components/Popover/Popover.d.ts +91 -0
- package/dist/components/Popover/index.d.ts +2 -0
- package/dist/components/SegmentedBar/SegmentedBar.d.ts +64 -0
- package/dist/components/SegmentedBar/index.d.ts +2 -0
- package/dist/components/SpinButton/SpinButton.d.ts +57 -0
- package/dist/components/SpinButton/index.d.ts +2 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +15 -0
- package/dist/index.js +2089 -662
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
export interface BottomSheetProps {
|
|
4
|
+
/** Whether the sheet is visible. */
|
|
5
|
+
open: boolean;
|
|
6
|
+
/** Optional heading shown below the drag handle. */
|
|
7
|
+
title?: ReactNode;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
/** Called when the user dismisses the sheet (backdrop press, Android back button, or drag down). */
|
|
10
|
+
onClose?: () => void;
|
|
11
|
+
/** Whether pressing the backdrop closes the sheet. Defaults to `true`. */
|
|
12
|
+
closeOnBackdrop?: boolean;
|
|
13
|
+
style?: StyleProp<ViewStyle>;
|
|
14
|
+
/** Applied to the backdrop, mirroring `Dialog`'s own `testID`. */
|
|
15
|
+
testID?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Slide-up panel that overlays content from the bottom edge, mirroring
|
|
19
|
+
* `AdwBottomSheet` (libadwaita 1.6+) and `@gnome-ui/react`'s `BottomSheet`.
|
|
20
|
+
*
|
|
21
|
+
* Rebuilt with `View`/`Modal`/`PanResponder` rather than ported from the web
|
|
22
|
+
* version's DOM `Portal` + manual focus trap + raw pointer events —
|
|
23
|
+
* reusing this package's own established pieces: `Dialog`'s backdrop-
|
|
24
|
+
* opacity-on-an-`AnimatedPressable` + no-op-`Pressable`-around-the-card
|
|
25
|
+
* (so a tap on the card never bubbles to the backdrop) recipe, and
|
|
26
|
+
* `BackHandler`'s `hardwareBackPress` as the Android analog of the web
|
|
27
|
+
* version's Escape listener (same pattern `Dialog`/`Popover` already use).
|
|
28
|
+
* Focus-trapping and focus-restore-on-close have no port — no DOM
|
|
29
|
+
* `document.activeElement`/`querySelector` equivalent exists in RN, the
|
|
30
|
+
* same gap already present in every other floating component here.
|
|
31
|
+
*
|
|
32
|
+
* **Real drag-to-dismiss, not a fixed-panel simplification**: unlike the
|
|
33
|
+
* web version's raw `PointerEvent` handlers directly mutating
|
|
34
|
+
* `style.transform`, this uses `PanResponder` (the same core RN API
|
|
35
|
+
* `Slider` already proved handles a threshold-based drag gesture) driving
|
|
36
|
+
* a single `Animated.Value` — the *same* value used for the slide-in/
|
|
37
|
+
* slide-out entrance animation. `PanResponder`'s `gestureState.dy` is the
|
|
38
|
+
* cumulative vertical delta since the gesture started, so a plain
|
|
39
|
+
* `translateY.setValue(Math.max(0, gestureState.dy))` during
|
|
40
|
+
* `onPanResponderMove` reproduces the web version's own
|
|
41
|
+
* `Math.max(0, e.clientY - dragStartY.current)` clamp exactly, and a
|
|
42
|
+
* release past `DRAG_CLOSE_THRESHOLD` (150 px, same constant as the web
|
|
43
|
+
* version) animates the rest of the way down before calling `onClose`,
|
|
44
|
+
* otherwise it springs back to `0`. The gesture responder is attached only
|
|
45
|
+
* to the handle bar `View`, not the whole sheet, mirroring the web
|
|
46
|
+
* version's `onPointerDown` being scoped to `.handle` alone.
|
|
47
|
+
*
|
|
48
|
+
* **A real slide-up needs the sheet's own height first** — RN's
|
|
49
|
+
* `transform` has no percentage-of-self units (the same `Slider`/`Avatar`
|
|
50
|
+
* pitfall), unlike the web version's `translateY(100%)`. The sheet renders
|
|
51
|
+
* once off-screen (measured via `onLayout`, starting `translateY` at that
|
|
52
|
+
* measured height) before animating to `0` — the same "resolve own
|
|
53
|
+
* rendered size, then animate" two-step every other sized-on-open
|
|
54
|
+
* component in this package (`Dialog`, `Dropdown`, `Popover`) already
|
|
55
|
+
* needs, just for a transform offset instead of a floating position.
|
|
56
|
+
*
|
|
57
|
+
* **Real, timed exit animation, unlike `Dialog`**: `Dialog`'s web source
|
|
58
|
+
* has no exit keyframes at all (`Modal`'s `visible={false}` unmounts
|
|
59
|
+
* immediately, matching the web version's plain `return null`) — but
|
|
60
|
+
* `BottomSheet`'s web source explicitly animates both the backdrop fade
|
|
61
|
+
* and the sheet's slide-out before removing it. Ported with a local
|
|
62
|
+
* `visible` state that lags one animation behind the `open` prop: closing
|
|
63
|
+
* starts the exit `Animated.timing`s and only flips `visible` to `false`
|
|
64
|
+
* (unmounting the `Modal`'s content) in the animation's own completion
|
|
65
|
+
* callback — not a `setTimeout` racing a hardcoded duration like the web
|
|
66
|
+
* version, since `Animated`'s callback already fires exactly when the
|
|
67
|
+
* animation actually finishes.
|
|
68
|
+
*
|
|
69
|
+
* The web version's `backdrop-filter: blur(4px)` has no port — this
|
|
70
|
+
* package has no native blur view dependency, the same reasoning that
|
|
71
|
+
* already dropped `Sidebar`'s blurred `variant`. `useBodyScrollLock` has no
|
|
72
|
+
* RN equivalent needed: `Modal` already blocks all interaction with
|
|
73
|
+
* whatever's behind it, there is no scrollable "body" to lock separately.
|
|
74
|
+
*
|
|
75
|
+
* `role="dialog"` + `accessibilityViewIsModal` port 1:1 from `Dialog`'s own
|
|
76
|
+
* precedent. `children`, when a plain string, must be wrapped in `Text`
|
|
77
|
+
* before rendering — RN throws if a raw string is a `View`'s child, unlike
|
|
78
|
+
* the web version's `<div>{children}</div>`, which needed no such check.
|
|
79
|
+
*
|
|
80
|
+
* @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.BottomSheet.html
|
|
81
|
+
*/
|
|
82
|
+
export declare const BottomSheet: ({ open, title, children, onClose, closeOnBackdrop, style, testID, }: BottomSheetProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { IconDefinition } from '@gnome-ui/icons';
|
|
2
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
export interface ChipProps {
|
|
4
|
+
/** Text label displayed inside the chip. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Leading icon from `@gnome-ui/icons`. */
|
|
7
|
+
icon?: IconDefinition;
|
|
8
|
+
/**
|
|
9
|
+
* When provided, renders a remove (×) button and calls this handler.
|
|
10
|
+
* The chip root becomes a plain `View`; only the remove button is
|
|
11
|
+
* interactive.
|
|
12
|
+
*/
|
|
13
|
+
onRemove?: () => void;
|
|
14
|
+
/**
|
|
15
|
+
* When true the chip renders as a toggle button.
|
|
16
|
+
* Use `selected` + `onToggle` to control its state.
|
|
17
|
+
*/
|
|
18
|
+
selectable?: boolean;
|
|
19
|
+
/** Active/selected state. Only relevant when `selectable` is true. */
|
|
20
|
+
selected?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Called when a selectable chip is pressed.
|
|
23
|
+
* Only relevant when `selectable` is true.
|
|
24
|
+
*/
|
|
25
|
+
onToggle?: () => void;
|
|
26
|
+
/** Disabled state — applies to both selectable chips and the remove button. */
|
|
27
|
+
disabled?: boolean;
|
|
28
|
+
style?: StyleProp<ViewStyle>;
|
|
29
|
+
testID?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Compact pill-shaped label for tags, filters, and selection states.
|
|
33
|
+
* Mirrors `@gnome-ui/react`'s `Chip`.
|
|
34
|
+
*
|
|
35
|
+
* Three usage modes:
|
|
36
|
+
* - **Static** — just a visual label (no `onRemove`, no `selectable`).
|
|
37
|
+
* - **Removable** — add `onRemove` to show a × button.
|
|
38
|
+
* - **Selectable** — add `selectable` + `selected` + `onToggle` for toggle
|
|
39
|
+
* behavior. Same `isInteractive = selectable && !onRemove` precedence as
|
|
40
|
+
* the web version: passing both `selectable` and `onRemove` renders the
|
|
41
|
+
* remove button, not a toggle.
|
|
42
|
+
*
|
|
43
|
+
* Pair with `WrapBox` for multi-chip layouts.
|
|
44
|
+
*
|
|
45
|
+
* Rebuilt with `Pressable`/`View`/`Text` rather than ported from
|
|
46
|
+
* `@gnome-ui/react`'s `<button>`/`<span>`: the selected background/border
|
|
47
|
+
* tint (`color-mix(in srgb, accent 15%/50%, transparent)`) has no RN
|
|
48
|
+
* equivalent, resolved to a literal 8-digit `#RRGGBBAA` hex instead — the
|
|
49
|
+
* same `Highlight` precedent, since `accentBgColor` is always a plain
|
|
50
|
+
* 6-digit hex. The `:hover`/`:active` background transitions collapse into
|
|
51
|
+
* a single pressed-state overlay tinted by `theme.activeOverlay` (the same
|
|
52
|
+
* `ActionRow`/`Card` recipe), since touch has no hover. The leading icon
|
|
53
|
+
* and remove (×) icon don't recolor to match the selected accent text
|
|
54
|
+
* (`color: inherit` on the web) — RN's `Icon` has no `currentColor`
|
|
55
|
+
* equivalent and only accepts a fixed named-swatch palette, none of which
|
|
56
|
+
* tracks the app's configurable accent color, so both icons stay in the
|
|
57
|
+
* default foreground color; a decorative nicety dropped, not a behavior
|
|
58
|
+
* gap. `accessibilityRole="checkbox"` on the selectable form ports 1:1
|
|
59
|
+
* (the same `Checkbox` precedent).
|
|
60
|
+
*
|
|
61
|
+
* @see https://developer.gnome.org/hig/patterns/selection.html
|
|
62
|
+
*/
|
|
63
|
+
export declare const Chip: ({ label, icon, onRemove, selectable, selected, onToggle, disabled, style, testID, }: ChipProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
export interface DividerProps {
|
|
4
|
+
/** Optional centered label (e.g. `"OR"`, `"Continue with"`). */
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
/** Accessible name. Defaults to `children` when it's a string. */
|
|
7
|
+
accessibilityLabel?: string;
|
|
8
|
+
style?: StyleProp<ViewStyle>;
|
|
9
|
+
testID?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Horizontal rule with an optional centered label — common auth/login-form
|
|
13
|
+
* pattern ("Sign in" / **OR** / "Continue with Google"). Mirrors
|
|
14
|
+
* `@gnome-ui/react`'s `Divider`.
|
|
15
|
+
*
|
|
16
|
+
* For a bare dividing line with no label, use `Separator` instead — it also
|
|
17
|
+
* supports a vertical orientation, which `Divider` does not.
|
|
18
|
+
*
|
|
19
|
+
* `role="separator"` ports 1:1 from RN's newer web-aligned `Role` union
|
|
20
|
+
* (the same one `Avatar`/`Badge`/`LevelBar` already reach for), unlike
|
|
21
|
+
* `Separator`'s own choice to render as `accessible={false}` — that
|
|
22
|
+
* component is purely decorative with nothing for a screen reader to
|
|
23
|
+
* announce, while a labelled `Divider` ("OR") is exactly the kind of
|
|
24
|
+
* content a screen reader user needs read aloud, so it stays in the
|
|
25
|
+
* accessibility tree instead. The label reuses `Text`'s `variant="caption"
|
|
26
|
+
* color="dim"` verbatim rather than hand-rolled styles, since that
|
|
27
|
+
* combination already resolves to the same font-size/weight/dim-opacity
|
|
28
|
+
* the web version's `.label` class hard-codes.
|
|
29
|
+
*
|
|
30
|
+
* The web version's `aria-orientation="horizontal"` has no port — `Divider`
|
|
31
|
+
* has no `orientation` prop at all (unlike `Separator`), so there is only
|
|
32
|
+
* ever one orientation to announce.
|
|
33
|
+
*
|
|
34
|
+
* @see https://developer.gnome.org/hig/patterns/containers.html
|
|
35
|
+
*/
|
|
36
|
+
export declare const Divider: ({ children, accessibilityLabel, style, testID }: DividerProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { IconDefinition } from '@gnome-ui/icons';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
4
|
+
export type DrawerSide = 'left' | 'right';
|
|
5
|
+
export type DrawerSize = 'classic' | 'wide';
|
|
6
|
+
export interface DrawerRailItem {
|
|
7
|
+
/** Stable unique identifier. */
|
|
8
|
+
id: string;
|
|
9
|
+
/** Icon shown for this rail entry. */
|
|
10
|
+
icon: IconDefinition;
|
|
11
|
+
/** Accessible name, also used as the tooltip. */
|
|
12
|
+
label: string;
|
|
13
|
+
/** Whether this entry represents the currently visible drawer/panel. */
|
|
14
|
+
active?: boolean;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
onPress: () => void;
|
|
17
|
+
}
|
|
18
|
+
export interface DrawerProps {
|
|
19
|
+
/** Whether the drawer is visible. */
|
|
20
|
+
open: boolean;
|
|
21
|
+
/** Edge that the drawer slides in from. Defaults to `"right"`. */
|
|
22
|
+
side?: DrawerSide;
|
|
23
|
+
/** Preset drawer width. Defaults to `"classic"`. */
|
|
24
|
+
size?: DrawerSize;
|
|
25
|
+
/** Optional drawer heading. */
|
|
26
|
+
title?: ReactNode;
|
|
27
|
+
/** Drawer content when a prop is preferred over `children`. */
|
|
28
|
+
content?: ReactNode;
|
|
29
|
+
/** Drawer content. Used when `content` is not provided. */
|
|
30
|
+
children?: ReactNode;
|
|
31
|
+
/** Called when the user dismisses the drawer with the Android back button or the backdrop. */
|
|
32
|
+
onClose?: () => void;
|
|
33
|
+
/** Whether pressing the backdrop closes the drawer. Defaults to `true`. */
|
|
34
|
+
closeOnBackdrop?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Narrow icon rail rendered on the drawer's inner edge (the edge facing
|
|
37
|
+
* the backdrop), for switching between related drawers or panels without
|
|
38
|
+
* closing the drawer. Purely presentational — pressing an entry only
|
|
39
|
+
* calls its `onPress`; the caller decides what happens (swap `content`,
|
|
40
|
+
* open a different drawer, etc).
|
|
41
|
+
*/
|
|
42
|
+
rail?: DrawerRailItem[];
|
|
43
|
+
style?: StyleProp<ViewStyle>;
|
|
44
|
+
/** Forwarded to the backdrop — useful for testing. */
|
|
45
|
+
testID?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Slide-in panel for supplementary content, anchored to the left or right
|
|
49
|
+
* edge. Mirrors `@gnome-ui/react`'s `Drawer`.
|
|
50
|
+
*
|
|
51
|
+
* Rebuilt with `View`/`Modal` rather than ported from the web version's
|
|
52
|
+
* `createPortal(document.body)` + manual focus trap + Escape listener:
|
|
53
|
+
* `Modal` already floats above everything with no portal target needed,
|
|
54
|
+
* and `BackHandler`'s `hardwareBackPress` is the Android analog of the
|
|
55
|
+
* Escape listener (the same `Dialog`/`BottomSheet` precedent). Focus
|
|
56
|
+
* trapping has no port — no DOM `Tab`/`document.activeElement` concept in
|
|
57
|
+
* RN's touch-first model.
|
|
58
|
+
*
|
|
59
|
+
* **Floats with a margin on every side, all four corners rounded** — the
|
|
60
|
+
* backdrop `Pressable` carries `padding: theme.space3` (matching the
|
|
61
|
+
* `@gnome-ui/react` source's own recent update to the same floating-card
|
|
62
|
+
* look, not a divergence), and the drawer itself gets a uniform
|
|
63
|
+
* `borderRadius` instead of the flat-edge-on-the-anchored-side look a
|
|
64
|
+
* flush-to-the-screen-edge panel would need. Positioning within that
|
|
65
|
+
* padded backdrop uses `justifyContent: 'flex-end'`/`'flex-start'` on the
|
|
66
|
+
* backdrop (not the web CSS's `margin-left/right: auto` on the drawer
|
|
67
|
+
* itself) — confirmed empirically (a throwaway build with saturated debug
|
|
68
|
+
* colors standing in for the real theme colors, screenshotted on-device)
|
|
69
|
+
* that `justifyContent` renders correctly while auto-margins were, at
|
|
70
|
+
* best, unverified for this RN/Yoga version; `BottomSheet` already proves
|
|
71
|
+
* the same `justifyContent: 'flex-end'` mechanism works on this exact
|
|
72
|
+
* setup, just on the vertical axis instead of horizontal. On a phone-width
|
|
73
|
+
* screen the `classic`/`wide` presets (420/640, sized for wider viewports)
|
|
74
|
+
* get capped to fill essentially the entire available width after the
|
|
75
|
+
* margin either way, so the anchored side becomes visually obvious mainly
|
|
76
|
+
* on tablets — the same responsive behavior the web version would show at
|
|
77
|
+
* an equally narrow browser width, not an RN-specific gap.
|
|
78
|
+
*
|
|
79
|
+
* **No drag-to-dismiss, unlike `BottomSheet`**: the web source only
|
|
80
|
+
* defines entrance keyframes for both the backdrop and the panel, so this
|
|
81
|
+
* follows `Dialog`'s simpler shape (a single `progress` `Animated.Value`
|
|
82
|
+
* replayed via `useEffect` keyed on `open`, no separate exit animation or
|
|
83
|
+
* lagging `visible` state) rather than `BottomSheet`'s
|
|
84
|
+
* `PanResponder`-plus-timed-exit machinery.
|
|
85
|
+
*
|
|
86
|
+
* **The slide distance needs no `onLayout` measurement**, unlike
|
|
87
|
+
* `BottomSheet`'s content-driven height: the drawer's width is a value
|
|
88
|
+
* this component already computes in JS (`size`'s preset, scaled down by
|
|
89
|
+
* `DrawerDepthContext` depth, capped by the available space after the
|
|
90
|
+
* backdrop's margin) — RN's `transform` has no percentage-of-self units
|
|
91
|
+
* (the same `BottomSheet`/`Avatar`/`Slider` pitfall), but since the exact
|
|
92
|
+
* pixel width is already known synchronously, `translateX` can animate
|
|
93
|
+
* from that known offset to `0` immediately, with no first-frame
|
|
94
|
+
* imprecision to accept.
|
|
95
|
+
*
|
|
96
|
+
* **`DrawerDepthContext` (nested-drawer width auto-scaling) ports 1:1** —
|
|
97
|
+
* pure React Context state, no DOM dependency at all. A `Drawer` opened
|
|
98
|
+
* from within another drawer's `content`/`children` is detected via
|
|
99
|
+
* context and scales its own preset width down (`0.85^depth`, floored at
|
|
100
|
+
* `DRAWER_MIN_WIDTH`) so stacked drawers read as a drill-in hierarchy
|
|
101
|
+
* instead of identical overlapping panels.
|
|
102
|
+
*
|
|
103
|
+
* **`rail` reuses the newly-added `IconButton`** (itself just `Button` +
|
|
104
|
+
* `Icon` + optional `Tooltip`, the same composition `@gnome-ui/react`'s own
|
|
105
|
+
* `IconButton` already is) — `aria-pressed` becomes
|
|
106
|
+
* `accessibilityState={{ selected: item.active }}`, the closest RN
|
|
107
|
+
* equivalent for a toggleable icon button with no dedicated visual
|
|
108
|
+
* "pressed" style on either platform's source.
|
|
109
|
+
*
|
|
110
|
+
* `backdrop-filter: blur(4px)` has no port — no native blur view
|
|
111
|
+
* dependency exists in this package, the same gap already dropped from
|
|
112
|
+
* `Sidebar`'s blurred `variant`/`BottomSheet`'s backdrop. `role="dialog"` +
|
|
113
|
+
* `accessibilityViewIsModal` port 1:1 from `Dialog`'s own precedent.
|
|
114
|
+
*
|
|
115
|
+
* @see https://developer.gnome.org/hig/patterns/containers.html
|
|
116
|
+
*/
|
|
117
|
+
export declare const Drawer: ({ open, side, size, title, content, children, onClose, closeOnBackdrop, rail, style, testID, }: DrawerProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
export interface ExpanderProps {
|
|
4
|
+
/** Clickable header label. String children render as a themed `Text` label; other nodes render as-is. */
|
|
5
|
+
label: ReactNode;
|
|
6
|
+
/** Content revealed when expanded. */
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
/** Controlled expanded state. */
|
|
9
|
+
expanded?: boolean;
|
|
10
|
+
/** Initial expanded state when uncontrolled. Defaults to `false`. */
|
|
11
|
+
defaultExpanded?: boolean;
|
|
12
|
+
/** Called when the expanded state changes. */
|
|
13
|
+
onExpandedChange?: (expanded: boolean) => void;
|
|
14
|
+
/** Disables the toggle. */
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
style?: StyleProp<ViewStyle>;
|
|
17
|
+
testID?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Standalone disclosure triangle + collapsible content — mirrors
|
|
21
|
+
* `GtkExpander` and `@gnome-ui/react`'s `Expander`.
|
|
22
|
+
*
|
|
23
|
+
* A bare, unstyled counterpart to `ExpanderRow`. Use `Expander` outside a
|
|
24
|
+
* settings-row context, e.g. "Show advanced options" in a form, or "Show
|
|
25
|
+
* details" under an error message.
|
|
26
|
+
*
|
|
27
|
+
* The web version clips the panel with a CSS grid-height animation and
|
|
28
|
+
* rides the content's `padding-top` on a second, separate transition (so a
|
|
29
|
+
* collapsed expander doesn't reserve blank space for padding that belongs
|
|
30
|
+
* to hidden content). RN has no CSS grid to lean on, so the panel is a
|
|
31
|
+
* single `Animated.View` whose numeric `height` is driven directly —
|
|
32
|
+
* `useNativeDriver: false`, the same accepted (and documented) trade-off
|
|
33
|
+
* `Checkbox`/`RadioButton`/`Switch`/`AnimatedIcon` already make for
|
|
34
|
+
* non-transform properties. Because the inner content `View`'s `onLayout`
|
|
35
|
+
* measurement already includes its own `paddingTop`, animating that single
|
|
36
|
+
* height value reproduces the web version's two-transition result with one
|
|
37
|
+
* `Animated.Value` instead of two. Content stays mounted while collapsed
|
|
38
|
+
* (matching the web version's `inert`, unmounted-from-the-tab-order-only
|
|
39
|
+
* behavior) — `accessibilityElementsHidden` / `importantForAccessibility`
|
|
40
|
+
* is RN's closest equivalent, applied to the panel wrapper.
|
|
41
|
+
*
|
|
42
|
+
* On first mount with `defaultExpanded`, the panel briefly renders at its
|
|
43
|
+
* natural (unmeasured) height instead of the animated value, so the initial
|
|
44
|
+
* reveal doesn't start from a wrong, pre-measurement `0` and pop once
|
|
45
|
+
* `onLayout` resolves — the same "let layout report the truth once, then
|
|
46
|
+
* hand control to `Animated`" shape `Dropdown`/`Tooltip` use for their own
|
|
47
|
+
* `onLayout`-measured dimensions.
|
|
48
|
+
*
|
|
49
|
+
* The chevron is `PanEnd` (GNOME's own `pan-end-symbolic` disclosure
|
|
50
|
+
* triangle) rather than a chevron glyph, matching the web version's
|
|
51
|
+
* hand-drawn arrow shape. It rotates 0deg → 90deg on an `Animated.Value`
|
|
52
|
+
* (the same `interpolate`-to-`rotate` recipe `Spinner` uses for its own
|
|
53
|
+
* indeterminate spin), unlike `Dropdown`'s chevron, which snaps instantly
|
|
54
|
+
* since that panel's own reveal has no comparable "settle" affordance.
|
|
55
|
+
*
|
|
56
|
+
* `role="region"` on the panel and `accessibilityState={{ expanded }}` on
|
|
57
|
+
* the header port 1:1 from the web version's `aria-controls`/`aria-expanded`
|
|
58
|
+
* pair — RN has no DOM ids, so the id-based `aria-labelledby`/`aria-controls`
|
|
59
|
+
* relationship itself has no port, the same `ProgressBar`/`LevelBar`
|
|
60
|
+
* precedent for dropping id-relationship-only ARIA props.
|
|
61
|
+
*
|
|
62
|
+
* @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Expander.html
|
|
63
|
+
*/
|
|
64
|
+
export declare const Expander: ({ label, children, expanded: controlledExpanded, defaultExpanded, onExpandedChange, disabled, style, testID, }: ExpanderProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
import { IconSize } from '../Icon';
|
|
3
|
+
export interface FileTypeIconProps {
|
|
4
|
+
/** File name (e.g. `"report.pdf"`) — resolves the icon from its extension. */
|
|
5
|
+
name?: string;
|
|
6
|
+
/**
|
|
7
|
+
* MIME type (e.g. `"application/pdf"`, `"inode/directory"`).
|
|
8
|
+
* Takes precedence over `name` when both are provided.
|
|
9
|
+
*/
|
|
10
|
+
mimeType?: string;
|
|
11
|
+
/** Renders the folder icon regardless of `name`/`mimeType`. */
|
|
12
|
+
isFolder?: boolean;
|
|
13
|
+
/** Thumbnail image URL. When provided, renders the image instead of the resolved icon. */
|
|
14
|
+
thumbnail?: string;
|
|
15
|
+
/** Accessible label. Defaults to a generated description (e.g. `"PDF document"`). */
|
|
16
|
+
label?: string;
|
|
17
|
+
/** Icon size. Defaults to `"md"`. */
|
|
18
|
+
size?: IconSize;
|
|
19
|
+
style?: StyleProp<ViewStyle>;
|
|
20
|
+
testID?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Small icon — optionally a thumbnail — resolved from a file's MIME type
|
|
24
|
+
* or name extension. Useful for file-manager-style listings. Mirrors
|
|
25
|
+
* `@gnome-ui/react`'s `FileTypeIcon`.
|
|
26
|
+
*
|
|
27
|
+
* Falls back to the generic file icon (mirrors freedesktop's
|
|
28
|
+
* `text-x-generic`) when the type can't be resolved.
|
|
29
|
+
*
|
|
30
|
+
* `fileType.ts`'s category-resolution logic (MIME type / extension → one of
|
|
31
|
+
* 13 categories, plus the freedesktop icon and generated label per
|
|
32
|
+
* category) is pure, DOM-free TS — duplicated verbatim from
|
|
33
|
+
* `@gnome-ui/react` rather than imported cross-package, the same
|
|
34
|
+
* `isIconDefinition`/`Icon.tsx` precedent already established for
|
|
35
|
+
* DOM-independent logic that still isn't worth a shared package for one
|
|
36
|
+
* function's worth of code.
|
|
37
|
+
*
|
|
38
|
+
* `role="img"` + `accessibilityLabel` ports 1:1 (the same `Avatar`/
|
|
39
|
+
* `LevelBar` precedent for RN's newer web-aligned `Role` union). The
|
|
40
|
+
* thumbnail reuses `Avatar`'s own `Image`/`resizeMode="cover"` recipe,
|
|
41
|
+
* sized from `Icon`'s own `ICON_SIZE_MAP` so swapping between the resolved
|
|
42
|
+
* icon and a thumbnail never shifts layout — the same reasoning the web
|
|
43
|
+
* version's `.sm`/`.md`/`.lg` classes document.
|
|
44
|
+
*/
|
|
45
|
+
export declare const FileTypeIcon: ({ name, mimeType, isFolder, thumbnail, label, size, style, testID, }: FileTypeIconProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { IconDefinition } from '@gnome-ui/icons';
|
|
2
|
+
export type FileTypeCategory = 'folder' | 'image' | 'audio' | 'video' | 'text' | 'pdf' | 'archive' | 'document' | 'spreadsheet' | 'presentation' | 'font' | 'executable' | 'unknown';
|
|
3
|
+
/** Resolves a file-type category from a MIME type (e.g. `"image/png"`). */
|
|
4
|
+
export declare function categoryFromMimeType(mimeType: string): FileTypeCategory | null;
|
|
5
|
+
/** Resolves a file-type category from a file name's extension (e.g. `"report.pdf"`). */
|
|
6
|
+
export declare function categoryFromName(name: string): FileTypeCategory | null;
|
|
7
|
+
export declare function getFileTypeIcon(category: FileTypeCategory): IconDefinition;
|
|
8
|
+
export declare function getFileTypeLabel(category: FileTypeCategory): string;
|
|
@@ -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,34 @@
|
|
|
1
|
+
import { IconDefinition } from '@gnome-ui/icons';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { ButtonProps, ButtonSize, ButtonVariant } from '../Button';
|
|
4
|
+
import { IconSize } from '../Icon';
|
|
5
|
+
import { TooltipPlacement } from '../Tooltip';
|
|
6
|
+
export type IconButtonVariant = ButtonVariant | 'osd';
|
|
7
|
+
export type IconButtonSize = ButtonSize;
|
|
8
|
+
export interface IconButtonProps extends Omit<ButtonProps, 'accessibilityLabel' | 'children' | 'leadingIcon' | 'osd' | 'shape' | 'trailingIcon' | 'variant'> {
|
|
9
|
+
/** Icon definition imported from `@gnome-ui/icons`. */
|
|
10
|
+
icon: IconDefinition;
|
|
11
|
+
/** Accessible name for the icon-only button. */
|
|
12
|
+
label: string;
|
|
13
|
+
/** Visual style of the button. Use `"osd"` for media overlay controls. */
|
|
14
|
+
variant?: IconButtonVariant;
|
|
15
|
+
/** Size of the button. */
|
|
16
|
+
size?: IconButtonSize;
|
|
17
|
+
/** Override the rendered icon size. Defaults to a size matched to `size`. */
|
|
18
|
+
iconSize?: IconSize;
|
|
19
|
+
/** Optional tooltip label shown on long-press/hover/focus. */
|
|
20
|
+
tooltip?: string;
|
|
21
|
+
/** Preferred tooltip placement. */
|
|
22
|
+
tooltipPlacement?: TooltipPlacement;
|
|
23
|
+
/** Tooltip delay in milliseconds. */
|
|
24
|
+
tooltipDelay?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Icon-only action button composed from `Button`, `Icon`, and optionally
|
|
28
|
+
* `Tooltip` — mirrors `@gnome-ui/react`'s `IconButton`, itself already just
|
|
29
|
+
* a thin composition of those same three pieces (its own JSDoc example
|
|
30
|
+
* shows the identical `<Tooltip><Button><Icon /></Button></Tooltip>`
|
|
31
|
+
* nesting `IconButton` here just formalizes into a named, reusable export).
|
|
32
|
+
* `label` is required since the button has no visible text.
|
|
33
|
+
*/
|
|
34
|
+
export declare const IconButton: import('react').ForwardRefExoticComponent<IconButtonProps & import('react').RefAttributes<View>>;
|
|
@@ -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;
|