@gnome-ui/react-native 1.0.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.
Files changed (63) hide show
  1. package/README.md +714 -0
  2. package/dist/GnomeProvider/GnomeContext.d.ts +36 -0
  3. package/dist/GnomeProvider/GnomeProvider.d.ts +69 -0
  4. package/dist/GnomeProvider/index.d.ts +6 -0
  5. package/dist/GnomeProvider/resolveContext.d.ts +30 -0
  6. package/dist/components/ActionRow/ActionRow.d.ts +51 -0
  7. package/dist/components/ActionRow/index.d.ts +2 -0
  8. package/dist/components/BoxedList/BoxedList.d.ts +36 -0
  9. package/dist/components/BoxedList/index.d.ts +2 -0
  10. package/dist/components/Button/Button.d.ts +47 -0
  11. package/dist/components/Button/index.d.ts +2 -0
  12. package/dist/components/Card/Card.d.ts +34 -0
  13. package/dist/components/Card/index.d.ts +2 -0
  14. package/dist/components/Checkbox/Checkbox.d.ts +44 -0
  15. package/dist/components/Checkbox/index.d.ts +2 -0
  16. package/dist/components/HeaderBar/HeaderBar.d.ts +38 -0
  17. package/dist/components/HeaderBar/index.d.ts +2 -0
  18. package/dist/components/Link/Link.d.ts +33 -0
  19. package/dist/components/Link/index.d.ts +2 -0
  20. package/dist/components/PathBar/PathBar.d.ts +43 -0
  21. package/dist/components/PathBar/index.d.ts +2 -0
  22. package/dist/components/ProgressBar/ProgressBar.d.ts +72 -0
  23. package/dist/components/ProgressBar/index.d.ts +2 -0
  24. package/dist/components/RadioButton/RadioButton.d.ts +36 -0
  25. package/dist/components/RadioButton/index.d.ts +2 -0
  26. package/dist/components/SearchBar/SearchBar.d.ts +51 -0
  27. package/dist/components/SearchBar/index.d.ts +2 -0
  28. package/dist/components/Separator/Separator.d.ts +26 -0
  29. package/dist/components/Separator/index.d.ts +2 -0
  30. package/dist/components/Sidebar/Sidebar.d.ts +45 -0
  31. package/dist/components/Sidebar/SidebarItem.d.ts +37 -0
  32. package/dist/components/Sidebar/SidebarSection.d.ts +42 -0
  33. package/dist/components/Sidebar/filterUtils.d.ts +11 -0
  34. package/dist/components/Sidebar/index.d.ts +6 -0
  35. package/dist/components/Skeleton/Skeleton.d.ts +51 -0
  36. package/dist/components/Skeleton/index.d.ts +2 -0
  37. package/dist/components/Spinner/Spinner.d.ts +44 -0
  38. package/dist/components/Spinner/index.d.ts +2 -0
  39. package/dist/components/Switch/Switch.d.ts +34 -0
  40. package/dist/components/Switch/index.d.ts +2 -0
  41. package/dist/components/Tabs/TabBar.d.ts +35 -0
  42. package/dist/components/Tabs/TabItem.d.ts +54 -0
  43. package/dist/components/Tabs/TabPanel.d.ts +28 -0
  44. package/dist/components/Tabs/index.d.ts +6 -0
  45. package/dist/components/Text/Text.d.ts +26 -0
  46. package/dist/components/Text/index.d.ts +2 -0
  47. package/dist/components/TextField/TextField.d.ts +37 -0
  48. package/dist/components/TextField/index.d.ts +2 -0
  49. package/dist/components/Toast/Toast.d.ts +58 -0
  50. package/dist/components/Toast/Toaster.d.ts +45 -0
  51. package/dist/components/Toast/index.d.ts +4 -0
  52. package/dist/components/ViewSwitcher/ViewSwitcher.d.ts +32 -0
  53. package/dist/components/ViewSwitcher/ViewSwitcherItem.d.ts +27 -0
  54. package/dist/components/ViewSwitcher/index.d.ts +4 -0
  55. package/dist/index.cjs +2 -0
  56. package/dist/index.cjs.map +1 -0
  57. package/dist/index.d.ts +23 -0
  58. package/dist/index.js +2906 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/theme/index.d.ts +4 -0
  61. package/dist/theme/resolveTheme.d.ts +9 -0
  62. package/dist/theme/tokens.generated.d.ts +714 -0
  63. package/package.json +56 -0
@@ -0,0 +1,51 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, TextInput, TextInputProps, TextStyle, ViewStyle } from 'react-native';
3
+ export interface SearchBarProps extends Omit<TextInputProps, 'style'> {
4
+ /** Whether the search bar is rendered. `false` renders nothing. */
5
+ open: boolean;
6
+ /**
7
+ * Renders a trailing "Cancel" button (the RN-idiomatic stand-in for the
8
+ * web version's Escape-to-close — touch keyboards have no reliable
9
+ * Escape key) and calls this when it's pressed.
10
+ */
11
+ onClose?: () => void;
12
+ /** Called when the clear (×) button is pressed. Also clears the input value. */
13
+ onClear?: () => void;
14
+ /**
15
+ * Content rendered below the bar (e.g. filter chips). Only rendered
16
+ * while `open` is true.
17
+ */
18
+ children?: ReactNode;
19
+ /** Removes the header-bar background so the bar blends into any surface. */
20
+ inline?: boolean;
21
+ /** Accessible label for the close button. Defaults to `"Cancel"`. */
22
+ closeLabel?: string;
23
+ /** Style applied to the wrapping `View`. */
24
+ style?: StyleProp<ViewStyle>;
25
+ /** Style applied to the `TextInput` itself. */
26
+ inputStyle?: StyleProp<TextStyle>;
27
+ }
28
+ /**
29
+ * Collapsible search input following the Adwaita `AdwSearchBar` pattern.
30
+ *
31
+ * Rebuilt on RN's `TextInput` rather than ported from `@gnome-ui/react`'s
32
+ * `<input type="search">`: `open` no longer drives a CSS height/opacity
33
+ * transition (no established animated-height pattern exists yet in this
34
+ * package — same trade-off `SidebarSection` made for its collapsible body)
35
+ * — `open={false}` renders nothing at all, and mounting on `open={true}`
36
+ * auto-focuses the input, standing in for the web version's
37
+ * `requestAnimationFrame`-on-open focus effect.
38
+ *
39
+ * Dropped relative to `@gnome-ui/react`'s `SearchBar`: the `suggestions` /
40
+ * `onSuggestionSelect` / `loadingSuggestions` / `renderSuggestion` /
41
+ * `suggestionsLabel` autocomplete popover — it depends on a portal +
42
+ * viewport-anchored positioning primitive (`createPortal` +
43
+ * `getBoundingClientRect`) this package doesn't have yet, the same gap
44
+ * that dropped `SidebarItem`'s `menuItems` context menu — and a `Spinner`
45
+ * component, not yet ported. The search/clear icons are Unicode glyphs
46
+ * (`🔍`/`×`) rather than `@gnome-ui/icons`, matching every other
47
+ * no-SVG-dependency component in this package.
48
+ *
49
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.SearchBar.html
50
+ */
51
+ export declare const SearchBar: import('react').ForwardRefExoticComponent<SearchBarProps & import('react').RefAttributes<TextInput>>;
@@ -0,0 +1,2 @@
1
+ export type { SearchBarProps } from './SearchBar';
2
+ export { SearchBar } from './SearchBar';
@@ -0,0 +1,26 @@
1
+ import { StyleProp, View, ViewProps, ViewStyle } from 'react-native';
2
+ export type SeparatorOrientation = 'horizontal' | 'vertical';
3
+ export interface SeparatorProps extends Omit<ViewProps, 'style'> {
4
+ /** Direction of the dividing line. Defaults to `"horizontal"`. */
5
+ orientation?: SeparatorOrientation;
6
+ style?: StyleProp<ViewStyle>;
7
+ }
8
+ /**
9
+ * Thin dividing line that separates groups of content.
10
+ *
11
+ * Color is driven entirely by `theme.cardShadeColor`, which already
12
+ * resolves correctly per color scheme, so — unlike `Switch`/`Checkbox`/
13
+ * `RadioButton` — there's no `useResolvedColorScheme()` branching needed
14
+ * here.
15
+ *
16
+ * Rebuilt as a plain `View` rather than ported from `@gnome-ui/react`'s
17
+ * `<hr>`/`<div role="separator">`: RN's `AccessibilityRole` union has no
18
+ * `"separator"` value, so — since a divider carries no information a
19
+ * screen reader user needs — it's excluded from the accessibility tree
20
+ * entirely with `accessible={false}`, the RN-idiomatic way to mark a
21
+ * purely decorative element, rather than reaching for a role that doesn't
22
+ * exist.
23
+ *
24
+ * @see https://developer.gnome.org/hig/patterns/containers.html
25
+ */
26
+ export declare const Separator: import('react').ForwardRefExoticComponent<SeparatorProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,2 @@
1
+ export type { SeparatorOrientation, SeparatorProps } from './Separator';
2
+ export { Separator } from './Separator';
@@ -0,0 +1,45 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, View, ViewProps, ViewStyle } from 'react-native';
3
+ /** Provides the collapsed state to all descendant `SidebarSection`/`SidebarItem`. */
4
+ export declare const SidebarCollapsedContext: import('react').Context<boolean>;
5
+ /** Returns `true` when the nearest `Sidebar` is in collapsed (icon-only/rail) mode. */
6
+ export declare function useSidebarCollapsed(): boolean;
7
+ /** Provides the active filter string to all descendant `SidebarItem`/`SidebarSection`. */
8
+ export declare const SidebarFilterContext: import('react').Context<string>;
9
+ export interface SidebarProps extends Omit<ViewProps, 'style'> {
10
+ children?: ReactNode;
11
+ /**
12
+ * When `true`, collapses the sidebar to icon-only (rail) mode. Labels and
13
+ * section titles are hidden.
14
+ */
15
+ collapsed?: boolean;
16
+ /**
17
+ * Controlled filter string. `SidebarItem`s whose `label` does not match
18
+ * (case-insensitive substring) are hidden, and empty `SidebarSection`s are
19
+ * hidden entirely. Unlike the web version this never renders a search
20
+ * input itself — pair it with your own `TextField` (or the future
21
+ * `SearchBar` port) and drive this prop from its value.
22
+ */
23
+ filter?: string;
24
+ style?: StyleProp<ViewStyle>;
25
+ }
26
+ /**
27
+ * Lateral navigation panel following the Adwaita `.navigation-sidebar` style.
28
+ *
29
+ * Compose with `SidebarSection` (named groups) and `SidebarItem` (rows).
30
+ * Consecutive top-level children get a `Separator` inserted between them —
31
+ * same divider-on-index-boundary technique `BoxedList` uses for its rows —
32
+ * standing in for the web version's `.section + .section` adjacent-sibling
33
+ * CSS rule, which RN has no equivalent of.
34
+ *
35
+ * Dropped relative to `@gnome-ui/react`'s `Sidebar`: `searchable` (would
36
+ * pull in a `SearchBar`, not yet ported to this package — use `filter` with
37
+ * your own input instead), `mode`/auto page-layout switch (depends on the
38
+ * web-only `useBreakpoint` hook), `variant` (tinted/blurred backgrounds —
39
+ * the blurred variant needs a native blur view this package doesn't depend
40
+ * on), and the `<nav>` landmark role (RN's `AccessibilityRole` union has no
41
+ * "navigation" value).
42
+ *
43
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Sidebar.html
44
+ */
45
+ export declare const Sidebar: import('react').ForwardRefExoticComponent<SidebarProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,37 @@
1
+ import { ReactNode } from 'react';
2
+ import { PressableProps, StyleProp, View, ViewStyle } from 'react-native';
3
+ export interface SidebarItemProps extends Omit<PressableProps, 'children' | 'style' | 'disabled'> {
4
+ /** Primary label. */
5
+ label: string;
6
+ /**
7
+ * Icon placed at the leading edge. Rendered as-is — size/color it
8
+ * yourself. Web's `icon` takes an `@gnome-ui/icons` `IconDefinition`;
9
+ * this package has no SVG icon system, so it's a plain `ReactNode` here,
10
+ * same as `ActionRow`'s `leading` and `TabItem`'s `icon`.
11
+ */
12
+ icon?: ReactNode;
13
+ /** Marks this item as the currently active view. */
14
+ active?: boolean;
15
+ /** Trailing widget — badge, count, button, icon… */
16
+ suffix?: ReactNode;
17
+ disabled?: boolean;
18
+ style?: StyleProp<ViewStyle>;
19
+ }
20
+ /**
21
+ * Individual navigation row inside a `Sidebar` or `SidebarSection`.
22
+ *
23
+ * Automatically hidden (renders nothing) when the nearest `Sidebar`'s
24
+ * `filter` is active and `label` doesn't match. In collapsed (rail) mode
25
+ * the label and suffix are hidden and the icon centers — `label` still
26
+ * reaches screen readers via `accessibilityLabel`.
27
+ *
28
+ * Dropped relative to `@gnome-ui/react`'s `SidebarItem`: `tooltip` (no
29
+ * `Tooltip` port yet, and RN's touch-first model has no hover to trigger
30
+ * one from), `menuItems` (context menu — no portal/positioning primitive
31
+ * exists in this package yet), and `onDrop`/`acceptTypes` (HTML5
32
+ * drag-and-drop has no RN equivalent without a gesture-handler dependency
33
+ * this package doesn't have).
34
+ *
35
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Sidebar.html
36
+ */
37
+ export declare const SidebarItem: import('react').ForwardRefExoticComponent<SidebarItemProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,42 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, ViewProps, ViewStyle } from 'react-native';
3
+ export interface SidebarSectionHandle {
4
+ expand: () => void;
5
+ collapse: () => void;
6
+ toggle: () => void;
7
+ }
8
+ export interface SidebarSectionProps extends Omit<ViewProps, 'style'> {
9
+ /** Section heading. Omit for an untitled section (e.g. the first group in a sidebar). */
10
+ title?: string;
11
+ /** Icon rendered left of the title. Rendered as-is — size/color it yourself. */
12
+ icon?: ReactNode;
13
+ /** Whether the section body can be toggled open/closed. Defaults to `false`. */
14
+ collapsible?: boolean;
15
+ /** Initial open state when `collapsible` is true. Defaults to `true`. */
16
+ defaultOpen?: boolean;
17
+ /** Controlled open state. */
18
+ open?: boolean;
19
+ /** Called when open state changes. */
20
+ onOpenChange?: (open: boolean) => void;
21
+ children?: ReactNode;
22
+ style?: StyleProp<ViewStyle>;
23
+ }
24
+ /**
25
+ * Named group of `SidebarItem` entries inside a `Sidebar`.
26
+ *
27
+ * When `collapsible`, the body toggles via the header `Pressable` or
28
+ * imperatively via a `ref` (`expand`/`collapse`/`toggle`) — same
29
+ * `useImperativeHandle` shape as the web version's `SidebarSectionHandle`.
30
+ * The body stays mounted and toggles `display: 'none'` rather than
31
+ * unmounting, the same "stays mounted but hidden" approach `TabPanel` uses,
32
+ * instead of porting the web version's animated CSS-grid collapse (no
33
+ * established animated-height pattern exists yet in this package).
34
+ *
35
+ * In rail (`collapsed`) mode the header — and with it the collapse toggle —
36
+ * is hidden and the body is always shown, matching the web version's rail
37
+ * behavior. When a `Sidebar` filter is active and no descendant matches,
38
+ * the whole section renders nothing.
39
+ *
40
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Sidebar.html
41
+ */
42
+ export declare const SidebarSection: import('react').ForwardRefExoticComponent<SidebarSectionProps & import('react').RefAttributes<SidebarSectionHandle>>;
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from 'react';
2
+ /** Recursively count items whose `label` prop matches `filter` (case-insensitive). */
3
+ export declare function countMatchingItems(children: ReactNode, filter: string): number;
4
+ /**
5
+ * Whether a single top-level `Sidebar` child would render something under
6
+ * `filter` — a bare `SidebarItem` if its own `label` matches, a
7
+ * `SidebarSection` (or anything else with `children`) if any descendant
8
+ * matches. Used to decide which children get a `Separator` between them, so
9
+ * a filtered-out (null-rendering) item doesn't still claim a divider slot.
10
+ */
11
+ export declare function isChildVisible(child: ReactNode, filter: string): boolean;
@@ -0,0 +1,6 @@
1
+ export type { SidebarProps } from './Sidebar';
2
+ export { Sidebar, SidebarCollapsedContext, SidebarFilterContext, useSidebarCollapsed, } from './Sidebar';
3
+ export type { SidebarItemProps } from './SidebarItem';
4
+ export { SidebarItem } from './SidebarItem';
5
+ export type { SidebarSectionHandle, SidebarSectionProps } from './SidebarSection';
6
+ export { SidebarSection } from './SidebarSection';
@@ -0,0 +1,51 @@
1
+ import { DimensionValue, StyleProp, ViewProps, ViewStyle } from 'react-native';
2
+ export type SkeletonVariant = 'rect' | 'circle' | 'text';
3
+ export interface SkeletonProps extends Omit<ViewProps, 'style'> {
4
+ /** Shape of the placeholder. Defaults to `"rect"`. */
5
+ variant?: SkeletonVariant;
6
+ /** Width for rectangular placeholders. Defaults to `"100%"`. */
7
+ width?: DimensionValue;
8
+ /** Height for rectangular placeholders. Defaults to `16`. */
9
+ height?: DimensionValue;
10
+ /** Diameter for circular placeholders. Defaults to `40`. */
11
+ size?: number;
12
+ /** Number of rows for text placeholders. Defaults to `3`. */
13
+ lines?: number;
14
+ /** Enables the pulse animation. Respects `useReducedMotion()`. Defaults to `true`. */
15
+ animated?: boolean;
16
+ style?: StyleProp<ViewStyle>;
17
+ }
18
+ /**
19
+ * Loading placeholder for content-shaped skeleton screens.
20
+ *
21
+ * GNOME HIG recommends `Spinner` or `ProgressBar` for loading states; this
22
+ * is a pragmatic web-style extension for layouts that benefit from
23
+ * placeholder shape, ported as-is from `@gnome-ui/react`.
24
+ *
25
+ * The web version's shimmer is a `linear-gradient` swept across the shape
26
+ * via `transform: translateX()`; this package has no gradient dependency
27
+ * (no `expo-linear-gradient`/`react-native-linear-gradient` in its
28
+ * dependency tree, and adding one for a single component would be scope
29
+ * creep), so the animation is a plain opacity pulse instead — animating
30
+ * `theme.skeletonBaseColor`'s own opacity between `1` and `0.5` on a
31
+ * 1.4s round trip, the same cycle length as the web shimmer. This is a
32
+ * common RN-idiomatic substitute for a CSS shimmer (compare Tailwind's own
33
+ * `animate-pulse` utility, which uses the identical technique). Unlike
34
+ * `Spinner` (slows) and `ProgressBar` (stops one state, slows the other),
35
+ * `useReducedMotion()` here fully disables the pulse and shows a static
36
+ * base color — mirroring the source CSS's own
37
+ * `@media (prefers-reduced-motion: reduce) { animation: none }`, which has
38
+ * no partial-motion in-between state to preserve.
39
+ *
40
+ * `theme.skeletonBaseColor` already resolves correctly per color scheme
41
+ * (unlike `Spinner`'s track color, which the source CSS never actually
42
+ * tokenizes), so no `useResolvedColorScheme()` branching is needed here.
43
+ *
44
+ * `accessible={false}` mirrors the web version's `aria-hidden="true"` — a
45
+ * loading placeholder carries no information a screen reader user needs,
46
+ * same reasoning `Separator` already established for a purely decorative
47
+ * element.
48
+ *
49
+ * @see https://developer.gnome.org/hig/patterns/feedback/progress.html
50
+ */
51
+ export declare const Skeleton: ({ variant, width, height, size, lines, animated, style, ...viewProps }: SkeletonProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export type { SkeletonProps, SkeletonVariant } from './Skeleton';
2
+ export { Skeleton } from './Skeleton';
@@ -0,0 +1,44 @@
1
+ import { StyleProp, ViewProps, ViewStyle } from 'react-native';
2
+ export type SpinnerSize = 'sm' | 'md' | 'lg';
3
+ export interface SpinnerProps extends Omit<ViewProps, 'style'> {
4
+ /** Size of the spinner. Defaults to `"md"`. */
5
+ size?: SpinnerSize;
6
+ /**
7
+ * Accessible label announced by screen readers. Defaults to
8
+ * `"Loading…"`. Set to `""` to silence if a sibling label is present.
9
+ */
10
+ label?: string;
11
+ style?: StyleProp<ViewStyle>;
12
+ }
13
+ /**
14
+ * Indeterminate loading indicator following the Adwaita spinner style.
15
+ *
16
+ * Rebuilt on `Animated.View` rather than ported from `@gnome-ui/react`'s
17
+ * pure-CSS `@keyframes spin` animation: the ring itself reuses the same
18
+ * per-side-border trick the CSS does (`borderColor` for the track,
19
+ * `borderTopColor` for the accent-colored "head" of the spinner, on a
20
+ * `borderRadius: 50%` circle) — that part translates directly, since RN's
21
+ * `View` supports independent per-side border colors too. The rotation
22
+ * itself is an `Animated.loop`d `Animated.timing` driving a `rotate`
23
+ * transform, `useNativeDriver: true` since only a transform is animated.
24
+ *
25
+ * `useReducedMotion()` mirrors the source CSS's own
26
+ * `@media (prefers-reduced-motion: reduce) { animation-duration: 2s }` —
27
+ * slowed to 2s, not stopped outright, exactly matching the web behavior
28
+ * rather than dropping the animation entirely.
29
+ *
30
+ * RN's `AccessibilityRole` union has no "status" value (the web version's
31
+ * `role="status"`); `"progressbar"` is the closest match for an
32
+ * indeterminate loading indicator and is what's used here — omitting
33
+ * `accessibilityValue` is RN's equivalent of omitting `aria-valuenow` for
34
+ * an indeterminate progress bar. `@gnome-ui/react`'s two hardcoded
35
+ * per-color-scheme track colors (the `--gnome-spinner-track-color` CSS
36
+ * variable is referenced but never actually defined in `@gnome-ui/core`'s
37
+ * tokens, so the CSS fallback value is always what renders) are ported as
38
+ * the same hardcoded `rgba()` pair, branched on `useResolvedColorScheme()`
39
+ * — the same pattern `Switch`/`Checkbox`/`RadioButton` already use for
40
+ * colors the source CSS hardcodes rather than tokenizes.
41
+ *
42
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/style-classes.html
43
+ */
44
+ export declare const Spinner: ({ size, label, style, ...viewProps }: SpinnerProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export type { SpinnerProps, SpinnerSize } from './Spinner';
2
+ export { Spinner } from './Spinner';
@@ -0,0 +1,34 @@
1
+ import { PressableProps, StyleProp, View, ViewStyle } from 'react-native';
2
+ export interface SwitchProps extends Omit<PressableProps, 'children' | 'style' | 'onPress'> {
3
+ /** Whether the switch is on. */
4
+ value: boolean;
5
+ /** Called with the next value when the switch is pressed. */
6
+ onValueChange?: (value: boolean) => void;
7
+ /** Accessible label. Required when no visible label is associated. */
8
+ accessibilityLabel?: string;
9
+ style?: StyleProp<ViewStyle>;
10
+ }
11
+ /**
12
+ * On/off toggle following the Adwaita switch style.
13
+ *
14
+ * Rebuilt on `Pressable`/`Animated.View` rather than ported from
15
+ * `@gnome-ui/react`'s `<input type="checkbox" role="switch">`: RN has no
16
+ * checkbox primitive to style, and the platform-supplied `Switch` can't be
17
+ * skinned to match Adwaita, so the track and thumb are drawn by hand.
18
+ * `value`/`onValueChange` (not `checked`/`onChange`) mirror RN's own
19
+ * `Switch` API, which is the ecosystem convention this component overlaps
20
+ * with — it's fully controlled, with no `defaultValue` escape hatch.
21
+ *
22
+ * Two of `Switch.module.css`'s colors are hardcoded per color scheme
23
+ * inside a component-level `@media (prefers-color-scheme: dark)` block
24
+ * rather than driven by a semantic token, so — unlike `Button`/`Link`/
25
+ * `TextField`, which read a single token that already resolves correctly
26
+ * per theme — the unchecked track/thumb colors here branch explicitly on
27
+ * `useResolvedColorScheme()` to match. Track background/border color
28
+ * animate (mirroring the CSS `transition` on `.switch`); the thumb's own
29
+ * fill color does not, since the source CSS only transitions its
30
+ * `transform`, not its `background-color`.
31
+ *
32
+ * @see https://developer.gnome.org/hig/patterns/controls/switches.html
33
+ */
34
+ export declare const Switch: import('react').ForwardRefExoticComponent<SwitchProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,2 @@
1
+ export type { SwitchProps } from './Switch';
2
+ export { Switch } from './Switch';
@@ -0,0 +1,35 @@
1
+ import { ReactNode } from 'react';
2
+ import { ScrollView, ScrollViewProps, StyleProp, ViewStyle } from 'react-native';
3
+ export interface TabBarProps extends Omit<ScrollViewProps, 'style' | 'horizontal' | 'children'> {
4
+ children?: ReactNode;
5
+ /** Accessible label for the tab list. */
6
+ accessibilityLabel?: string;
7
+ /**
8
+ * Removes the header-bar background so the tab bar blends into any surface.
9
+ * Use when placing the bar inside a card, content area, or custom container.
10
+ * Mirrors the `.inline` style class.
11
+ */
12
+ inline?: boolean;
13
+ style?: StyleProp<ViewStyle>;
14
+ }
15
+ /**
16
+ * Horizontal, horizontally-scrollable tab bar that holds `TabItem` elements.
17
+ *
18
+ * Rebuilt on a horizontal `ScrollView` rather than ported from
19
+ * `@gnome-ui/react`'s `overflow-x: auto` `<div role="tablist">` — RN's
20
+ * `AccessibilityRole` union does include `"tablist"`, so that semantic
21
+ * carries over directly, but the web version's roving-tabindex ← → / Home /
22
+ * End keyboard navigation doesn't: RN's touch-first focus model has no
23
+ * per-app arrow-key convention to port, so it's dropped here rather than
24
+ * faking it.
25
+ *
26
+ * `style={{ flexGrow: 0 }}` on the `ScrollView` is deliberate, not
27
+ * decorative — a horizontal `ScrollView` with no explicit `flexGrow` can
28
+ * stretch to fill the cross-axis of whatever flex column it's placed in
29
+ * (confirmed the hard way debugging the example app's own tab-like
30
+ * `ControlsBar`), so it's baked in here once rather than left for every
31
+ * consumer to rediscover.
32
+ *
33
+ * @see https://developer.gnome.org/hig/patterns/nav/tabs.html
34
+ */
35
+ export declare const TabBar: import('react').ForwardRefExoticComponent<TabBarProps & import('react').RefAttributes<ScrollView>>;
@@ -0,0 +1,54 @@
1
+ import { ReactNode } from 'react';
2
+ import { PressableProps, View } from 'react-native';
3
+ export interface TabItemProps extends Omit<PressableProps, 'children' | 'style' | 'disabled'> {
4
+ /** Tab label. */
5
+ label: string;
6
+ /**
7
+ * Icon placed before the label. Rendered as-is — size/color it yourself.
8
+ * Web's `icon` takes an `@gnome-ui/icons` `IconDefinition`; this package
9
+ * has no SVG icon system (see [[react-native-port-status]]), so it's a
10
+ * plain `ReactNode` here instead, same as `ActionRow`'s `leading`.
11
+ */
12
+ icon?: ReactNode;
13
+ /** Marks this tab as the currently selected one. */
14
+ active?: boolean;
15
+ /**
16
+ * When provided, a close (×) button is rendered at the trailing edge.
17
+ * Called when the user taps the close button.
18
+ */
19
+ onClose?: () => void;
20
+ /** Accessible label for the close button. Defaults to `"Close tab"`. */
21
+ closeLabel?: string;
22
+ /** Optional count shown as a small badge next to the label. Values above 99 render as "99+". */
23
+ count?: number;
24
+ disabled?: boolean;
25
+ }
26
+ /**
27
+ * Individual tab button inside a `TabBar`.
28
+ *
29
+ * Web's `panelId` (which sets `aria-controls`) is dropped — RN has no ARIA
30
+ * relationship attributes, so there's nothing for it to wire up; keep the
31
+ * tab ↔ panel link in your own state instead. The count badge is a small
32
+ * inline pill rather than the web version's separate `Badge` component,
33
+ * since `Badge` hasn't been ported to this package yet and pulling in a
34
+ * whole new component just for this one pill would be scope creep.
35
+ *
36
+ * The close button is a nested `Pressable` inside the tab's own
37
+ * `Pressable` — unlike the web version, no explicit "stop propagation" is
38
+ * needed: RN's touch responder system grants an in-progress touch to the
39
+ * innermost view that claims it, so pressing the close button never also
40
+ * fires the outer tab's `onPress`. It also gets a `hitSlop` the web
41
+ * version has no equivalent of, since its 18×18 visual size is well under
42
+ * the ~44pt touch target guidance both major mobile platforms recommend.
43
+ *
44
+ * The label `Text` deliberately has no `flex: 1` (unlike the web version's
45
+ * `.tabLabel`) — the outer `Pressable`'s width here is content-driven
46
+ * (`minWidth`/`maxWidth`, not a definite width), and giving a `flex: 1`
47
+ * child to a row whose own width isn't definite collapses that child to a
48
+ * near-zero width in Yoga (confirmed visually: every label truncated to
49
+ * 3-4 characters despite ample room). CSS flexbox resolves this fine
50
+ * because browsers can grow a flex child within an intrinsically-sized
51
+ * container; Yoga can't. `numberOfLines`/`ellipsizeMode` alone are enough
52
+ * to truncate genuinely-too-long labels against `maxWidth`.
53
+ */
54
+ export declare const TabItem: import('react').ForwardRefExoticComponent<TabItemProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,28 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, View, ViewProps, ViewStyle } from 'react-native';
3
+ export interface TabPanelProps extends Omit<ViewProps, 'style'> {
4
+ /** Controls whether this panel is visible. */
5
+ active?: boolean;
6
+ children?: ReactNode;
7
+ style?: StyleProp<ViewStyle>;
8
+ }
9
+ /**
10
+ * Content panel associated with a `TabItem`.
11
+ *
12
+ * Web's `id` (paired with `TabItem`'s `panelId`, together wiring up
13
+ * `aria-controls`) is dropped on both sides here — RN has no ARIA
14
+ * relationship attributes for it to drive, so track which tab is active in
15
+ * your own state (index, key, whatever) and pass the matching panel
16
+ * `active={true}` directly, rather than reaching for an id-matching
17
+ * convention with nothing underneath it.
18
+ *
19
+ * Hidden panels stay mounted with `display: 'none'` rather than being
20
+ * conditionally unmounted — same as the web version keeping them in the
21
+ * DOM via the `hidden` attribute — so a panel's internal state (scroll
22
+ * position, form input, etc.) survives switching tabs away and back. RN
23
+ * has no `"tabpanel"` value in its `AccessibilityRole` union (unlike
24
+ * `TabBar`'s `"tablist"` and `TabItem`'s `"tab"`, both of which do exist),
25
+ * so no role is set here — same reasoning as `Separator` dropping a role
26
+ * RN doesn't have rather than reaching for an inaccurate substitute.
27
+ */
28
+ export declare const TabPanel: import('react').ForwardRefExoticComponent<TabPanelProps & import('react').RefAttributes<View>>;
@@ -0,0 +1,6 @@
1
+ export type { TabBarProps } from './TabBar';
2
+ export { TabBar } from './TabBar';
3
+ export type { TabItemProps } from './TabItem';
4
+ export { TabItem } from './TabItem';
5
+ export type { TabPanelProps } from './TabPanel';
6
+ export { TabPanel } from './TabPanel';
@@ -0,0 +1,26 @@
1
+ import { TextProps as RNTextProps, Text as RNText } from 'react-native';
2
+ export type TextVariant = 'large-title' | 'title-1' | 'title-2' | 'title-3' | 'title-4' | 'heading' | 'body' | 'document' | 'caption' | 'caption-heading' | 'monospace' | 'numeric';
3
+ export type TextColor = 'default' | 'dim' | 'accent' | 'destructive' | 'success' | 'warning' | 'error';
4
+ export interface TextProps extends RNTextProps {
5
+ /** Typography style. Mirrors Adwaita / GNOME HIG text styles. */
6
+ variant?: TextVariant;
7
+ /** Semantic color. */
8
+ color?: TextColor;
9
+ children?: RNTextProps['children'];
10
+ }
11
+ /**
12
+ * Text component following GNOME Human Interface Guidelines typography styles.
13
+ *
14
+ * Variants map directly to Adwaita style classes:
15
+ * `large-title`, `title-1`–`title-4`, `heading`, `body`, `document`,
16
+ * `caption`, `caption-heading`, `monospace`, `numeric`.
17
+ *
18
+ * Rebuilt on RN's `Text` rather than ported from `@gnome-ui/react`'s DOM-based
19
+ * JSX: there is no element to pick, so `@gnome-ui/react`'s `as` prop is
20
+ * replaced by `accessibilityRole`, which the heading variants default to
21
+ * `"header"`.
22
+ *
23
+ * @see https://developer.gnome.org/hig/guidelines/typography.html
24
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/style-classes.html
25
+ */
26
+ export declare const Text: import('react').ForwardRefExoticComponent<TextProps & import('react').RefAttributes<RNText>>;
@@ -0,0 +1,2 @@
1
+ export type { TextColor, TextProps, TextVariant } from './Text';
2
+ export { Text } from './Text';
@@ -0,0 +1,37 @@
1
+ import { StyleProp, TextInput, TextInputProps, TextStyle, ViewStyle } from 'react-native';
2
+ export interface TextFieldProps extends Omit<TextInputProps, 'style'> {
3
+ /** Visible label rendered above the input. */
4
+ label?: string;
5
+ /** Helper text rendered below the input. Hidden when `error` is set. */
6
+ helperText?: string;
7
+ /**
8
+ * Error message rendered below the input in place of `helperText`.
9
+ * Also applies the error visual state to the input border.
10
+ */
11
+ error?: string;
12
+ /** Style applied to the wrapping `View`. */
13
+ style?: StyleProp<ViewStyle>;
14
+ /** Style applied to the `TextInput` itself. */
15
+ inputStyle?: StyleProp<TextStyle>;
16
+ }
17
+ /**
18
+ * Single-line text input with label, helper text, and error state.
19
+ *
20
+ * Follows the Adwaita `GtkEntry` / `.entry` style class.
21
+ *
22
+ * Rebuilt on RN's `TextInput` rather than ported from `@gnome-ui/react`'s
23
+ * `<input>`: there's no `<label htmlFor>`/`aria-describedby` pairing on RN,
24
+ * so `label` doubles as `accessibilityLabel` and `error`/`helperText`
25
+ * double as `accessibilityHint` — announced together with the input the
26
+ * same way `aria-describedby` reads them on the web. `:focus-visible`'s
27
+ * accent border becomes plain `onFocus`/`onBlur` state — RN has no
28
+ * hover/keyboard-vs-pointer focus distinction to mirror, and no outer
29
+ * `box-shadow` ring, so focus is just a border-color change rather than a
30
+ * grown ring. The web version's `disabled` prop is RN's own
31
+ * `editable={false}` — mirrored here as a dimmed wrapper the same way
32
+ * `@gnome-ui/react`'s `.disabled` class dims the label and hint alongside
33
+ * the input.
34
+ *
35
+ * @see https://developer.gnome.org/hig/patterns/controls/text-fields.html
36
+ */
37
+ export declare const TextField: import('react').ForwardRefExoticComponent<TextFieldProps & import('react').RefAttributes<TextInput>>;
@@ -0,0 +1,2 @@
1
+ export type { TextFieldProps } from './TextField';
2
+ export { TextField } from './TextField';
@@ -0,0 +1,58 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, ViewProps, ViewStyle } from 'react-native';
3
+ export interface ToastProps extends Omit<ViewProps, 'style'> {
4
+ /** The notification message. Keep it short — one sentence. */
5
+ title: ReactNode;
6
+ /**
7
+ * Auto-dismiss timeout in milliseconds.
8
+ * - Set to `0` to disable auto-dismiss (user must press action or dismiss).
9
+ * - Defaults to `3000`.
10
+ */
11
+ duration?: number;
12
+ /** Called when the toast should be removed — after timeout or user action. */
13
+ onDismiss?: () => void;
14
+ /** Label for the optional action button. */
15
+ actionLabel?: string;
16
+ /** Called when the user presses the action button. */
17
+ onAction?: () => void;
18
+ /** Whether to show a manual dismiss (×) button. */
19
+ dismissible?: boolean;
20
+ style?: StyleProp<ViewStyle>;
21
+ }
22
+ /**
23
+ * Non-blocking temporary notification following the Adwaita `AdwToast`
24
+ * pattern. Auto-dismisses after `duration` ms (default 3s, `0` disables
25
+ * it); the timer pauses while the toast is pressed and held. Use inside
26
+ * `Toaster` for correct positioning and stacking.
27
+ *
28
+ * The auto-dismiss/pause timer logic (`timerRef`/`remainingRef`/
29
+ * `startedAtRef`) is ported verbatim from `@gnome-ui/react` — it's plain
30
+ * `setTimeout`/`Date.now()` bookkeeping, no DOM API involved, so nothing
31
+ * platform-specific to change. The pause trigger is: RN has no hover, so
32
+ * `onPressIn`/`onPressOut` (touch-down/touch-up) stand in for the web
33
+ * version's `onMouseEnter`/`onMouseLeave` — pausing while the user is
34
+ * actively touching the toast, the closest RN analog to "giving the user
35
+ * time to read it." `onFocus`/`onBlur`-triggered pausing (keyboard
36
+ * accessibility on web) has no port here — the outer card itself isn't a
37
+ * focusable element in RN's touch-first model, only its action/dismiss
38
+ * buttons are, and RN has no "focus-within" primitive to detect that
39
+ * without an extra dependency.
40
+ *
41
+ * The entrance is an `Animated.timing` fading + sliding + scaling in
42
+ * (`opacity`/`translateY`/`scale`, all transform-safe for
43
+ * `useNativeDriver: true`), matching the web version's `@keyframes
44
+ * toast-in`; `useReducedMotion()` skips straight to the settled state,
45
+ * matching the source CSS's `animation: none`. There's no exit animation
46
+ * to port either — the web version doesn't define one, removal is
47
+ * immediate once the consumer drops the `Toast` from its list.
48
+ *
49
+ * RN's `AccessibilityRole` union has no "status" value (the web version's
50
+ * `role="status"`); `"alert"` is the closest available role for content
51
+ * that should interrupt and be announced, paired with
52
+ * `accessibilityLiveRegion="polite"` (Android's live-region API) as the
53
+ * nearest match to the web's `aria-live="polite"` — deliberately not
54
+ * `"assertive"`, matching the same politeness level the source chose.
55
+ *
56
+ * @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Toast.html
57
+ */
58
+ export declare const Toast: ({ title, duration, onDismiss, actionLabel, onAction, dismissible, style, ...viewProps }: ToastProps) => import("react/jsx-runtime").JSX.Element;