@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.
- package/README.md +714 -0
- package/dist/GnomeProvider/GnomeContext.d.ts +36 -0
- package/dist/GnomeProvider/GnomeProvider.d.ts +69 -0
- package/dist/GnomeProvider/index.d.ts +6 -0
- package/dist/GnomeProvider/resolveContext.d.ts +30 -0
- package/dist/components/ActionRow/ActionRow.d.ts +51 -0
- package/dist/components/ActionRow/index.d.ts +2 -0
- package/dist/components/BoxedList/BoxedList.d.ts +36 -0
- package/dist/components/BoxedList/index.d.ts +2 -0
- package/dist/components/Button/Button.d.ts +47 -0
- package/dist/components/Button/index.d.ts +2 -0
- package/dist/components/Card/Card.d.ts +34 -0
- package/dist/components/Card/index.d.ts +2 -0
- package/dist/components/Checkbox/Checkbox.d.ts +44 -0
- package/dist/components/Checkbox/index.d.ts +2 -0
- package/dist/components/HeaderBar/HeaderBar.d.ts +38 -0
- package/dist/components/HeaderBar/index.d.ts +2 -0
- package/dist/components/Link/Link.d.ts +33 -0
- package/dist/components/Link/index.d.ts +2 -0
- package/dist/components/PathBar/PathBar.d.ts +43 -0
- package/dist/components/PathBar/index.d.ts +2 -0
- package/dist/components/ProgressBar/ProgressBar.d.ts +72 -0
- package/dist/components/ProgressBar/index.d.ts +2 -0
- package/dist/components/RadioButton/RadioButton.d.ts +36 -0
- package/dist/components/RadioButton/index.d.ts +2 -0
- package/dist/components/SearchBar/SearchBar.d.ts +51 -0
- package/dist/components/SearchBar/index.d.ts +2 -0
- package/dist/components/Separator/Separator.d.ts +26 -0
- package/dist/components/Separator/index.d.ts +2 -0
- package/dist/components/Sidebar/Sidebar.d.ts +45 -0
- package/dist/components/Sidebar/SidebarItem.d.ts +37 -0
- package/dist/components/Sidebar/SidebarSection.d.ts +42 -0
- package/dist/components/Sidebar/filterUtils.d.ts +11 -0
- package/dist/components/Sidebar/index.d.ts +6 -0
- package/dist/components/Skeleton/Skeleton.d.ts +51 -0
- package/dist/components/Skeleton/index.d.ts +2 -0
- package/dist/components/Spinner/Spinner.d.ts +44 -0
- package/dist/components/Spinner/index.d.ts +2 -0
- package/dist/components/Switch/Switch.d.ts +34 -0
- package/dist/components/Switch/index.d.ts +2 -0
- package/dist/components/Tabs/TabBar.d.ts +35 -0
- package/dist/components/Tabs/TabItem.d.ts +54 -0
- package/dist/components/Tabs/TabPanel.d.ts +28 -0
- package/dist/components/Tabs/index.d.ts +6 -0
- package/dist/components/Text/Text.d.ts +26 -0
- package/dist/components/Text/index.d.ts +2 -0
- package/dist/components/TextField/TextField.d.ts +37 -0
- package/dist/components/TextField/index.d.ts +2 -0
- package/dist/components/Toast/Toast.d.ts +58 -0
- package/dist/components/Toast/Toaster.d.ts +45 -0
- package/dist/components/Toast/index.d.ts +4 -0
- package/dist/components/ViewSwitcher/ViewSwitcher.d.ts +32 -0
- package/dist/components/ViewSwitcher/ViewSwitcherItem.d.ts +27 -0
- package/dist/components/ViewSwitcher/index.d.ts +4 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +2906 -0
- package/dist/index.js.map +1 -0
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/resolveTheme.d.ts +9 -0
- package/dist/theme/tokens.generated.d.ts +714 -0
- 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,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,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,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,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,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,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,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,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;
|