@gnome-ui/react-native 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +441 -3
- package/dist/components/AvatarGroup/AvatarGroup.d.ts +47 -0
- package/dist/components/AvatarGroup/index.d.ts +2 -0
- package/dist/components/AvatarRotator/AvatarRotator.d.ts +65 -0
- package/dist/components/AvatarRotator/index.d.ts +2 -0
- package/dist/components/Box/Box.d.ts +87 -0
- package/dist/components/Box/index.d.ts +2 -0
- package/dist/components/Clamp/Clamp.d.ts +61 -0
- package/dist/components/Clamp/index.d.ts +2 -0
- package/dist/components/CoachMark/CoachMark.d.ts +92 -0
- package/dist/components/CoachMark/CoachMarkTour.d.ts +54 -0
- package/dist/components/CoachMark/coachMarkUtils.d.ts +42 -0
- package/dist/components/CoachMark/index.d.ts +5 -0
- package/dist/components/InlineViewSwitcher/InlineViewSwitcher.d.ts +93 -0
- package/dist/components/InlineViewSwitcher/InlineViewSwitcherItem.d.ts +25 -0
- package/dist/components/InlineViewSwitcher/index.d.ts +4 -0
- package/dist/components/InlineViewSwitcher/variants.d.ts +30 -0
- package/dist/components/PreferencesGroup/PreferencesGroup.d.ts +52 -0
- package/dist/components/PreferencesGroup/index.d.ts +2 -0
- package/dist/components/StatusPage/StatusPage.d.ts +79 -0
- package/dist/components/StatusPage/index.d.ts +2 -0
- package/dist/components/ToggleGroup/ToggleGroup.d.ts +70 -0
- package/dist/components/ToggleGroup/ToggleGroupItem.d.ts +49 -0
- package/dist/components/ToggleGroup/index.d.ts +4 -0
- package/dist/components/WrapBox/WrapBox.d.ts +67 -0
- package/dist/components/WrapBox/index.d.ts +2 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +1487 -393
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,12 +17,15 @@ React Native component library following the [GNOME Human Interface Guidelines](
|
|
|
17
17
|
> `PathBar`) fully ported. Tier 4 Feedback: `Spinner`, `ProgressBar`,
|
|
18
18
|
> `Skeleton`, `Toast`/`Toaster`, `Banner`, `Dialog`, `Tooltip`, and
|
|
19
19
|
> `AnimatedIcon` (which brought a new `Icon` component along with it, as its
|
|
20
|
-
> own public component) shipped —
|
|
20
|
+
> own public component) and `StatusPage` shipped — Tier 4 complete. Tier 5
|
|
21
21
|
> Advanced Controls fully ported: `Dropdown`, `Slider`, `SpinButton`,
|
|
22
22
|
> `Avatar`, `Badge`, and `Popover`. Beyond Tier 5, `BottomSheet` (Tier 14)
|
|
23
23
|
> and `Overlay`/`LevelBar`/`Expander`/`Divider`/`Highlight`/`FileTypeIcon`/
|
|
24
|
-
> `SegmentedBar
|
|
25
|
-
> (Tier
|
|
24
|
+
> `SegmentedBar`/`AvatarGroup`/`AvatarRotator`/`CoachMark`/`CoachMarkTour`
|
|
25
|
+
> (Tier 20), `Chip` (Tier 7), `IconButton`/`Drawer` (Tier 8/Tier 20), and
|
|
26
|
+
> `Clamp` (Tier 6), `Box` (Tier 20), `WrapBox`/`ToggleGroup` (Tier 7), and
|
|
27
|
+
> `InlineViewSwitcher` (Tier 8), and `PreferencesGroup` (Tier 13) also
|
|
28
|
+
> shipped. Component ports from
|
|
26
29
|
> `@gnome-ui/react` continue tier by tier — see this package's own
|
|
27
30
|
> [ROADMAP.md](./ROADMAP.md) for full
|
|
28
31
|
> per-tier status against all 130 `@gnome-ui/react` components, and the
|
|
@@ -1430,6 +1433,441 @@ no exit keyframes at all, so this follows `Dialog`'s simpler animation
|
|
|
1430
1433
|
shape instead. `backdrop-filter: blur(4px)` has no port (no native blur
|
|
1431
1434
|
dependency in this package).
|
|
1432
1435
|
|
|
1436
|
+
### AvatarGroup
|
|
1437
|
+
|
|
1438
|
+
```tsx
|
|
1439
|
+
import { AvatarGroup } from '@gnome-ui/react-native';
|
|
1440
|
+
|
|
1441
|
+
<AvatarGroup
|
|
1442
|
+
avatars={[{ name: 'Alice Martin' }, { name: 'Bob Smith' }, { name: 'Carol White' }]}
|
|
1443
|
+
max={5}
|
|
1444
|
+
/>
|
|
1445
|
+
```
|
|
1446
|
+
|
|
1447
|
+
Overlapping stack of `Avatar`s with a "+N" overflow indicator. Mirrors
|
|
1448
|
+
`@gnome-ui/react`'s `AvatarGroup`. The web version's separating ring
|
|
1449
|
+
around each overlapping avatar is two layered `box-shadow`s (an inset 1px
|
|
1450
|
+
dark/light border plus an outset 2px window-colored ring) — RN can only
|
|
1451
|
+
give a `View` one border, so this keeps just the outer window-colored
|
|
1452
|
+
ring (overriding `Avatar`'s own subtle 1px ring via its `style` prop),
|
|
1453
|
+
since that's the ring doing the actual "stay visually distinct from the
|
|
1454
|
+
avatar behind you" work. The overflow chip reuses `Avatar`'s own per-size
|
|
1455
|
+
box dimensions so it lines up exactly with the avatars beside it.
|
|
1456
|
+
`role="group"` + an auto-generated `accessibilityLabel` (joined names,
|
|
1457
|
+
plus "and N more" when overflowing) port 1:1 from RN's newer web-aligned
|
|
1458
|
+
`Role` union.
|
|
1459
|
+
|
|
1460
|
+
### AvatarRotator
|
|
1461
|
+
|
|
1462
|
+
```tsx
|
|
1463
|
+
import { AvatarRotator } from '@gnome-ui/react-native';
|
|
1464
|
+
|
|
1465
|
+
<AvatarRotator name="Alice Martin" avatars={[url1, url2, url3]} />
|
|
1466
|
+
```
|
|
1467
|
+
|
|
1468
|
+
Single avatar surface that crossfades through multiple image sources.
|
|
1469
|
+
Mirrors `@gnome-ui/react`'s `AvatarRotator`. Keeps `Avatar` focused on
|
|
1470
|
+
rendering one identity, while this component owns timing, crossfade
|
|
1471
|
+
animation, and pause behavior.
|
|
1472
|
+
|
|
1473
|
+
Each source renders as its own absolutely-positioned `Avatar`, crossfaded
|
|
1474
|
+
with `Animated.timing` (`useNativeDriver: true`) — a `RotatorLayer`
|
|
1475
|
+
sub-component owns each layer's own `Animated.Value` rather than the
|
|
1476
|
+
parent tracking an array of them, the same "each item animates itself"
|
|
1477
|
+
shape `Toast`/`Toaster` already established for independently
|
|
1478
|
+
transitioning list items. `prefers-reduced-motion` stops the rotation
|
|
1479
|
+
outright, not just the fade — ported exactly from the web version's own
|
|
1480
|
+
auto-advance effect, which bails out early on both `isPaused` and reduced
|
|
1481
|
+
motion alike. `pauseOnHover` becomes `pauseOnPress`
|
|
1482
|
+
(`onPressIn`/`onPressOut`) — the same touch substitution `Toast`'s own
|
|
1483
|
+
press-and-hold pause already established, kept as a real toggleable prop
|
|
1484
|
+
here (defaults `true`).
|
|
1485
|
+
|
|
1486
|
+
### CoachMark / CoachMarkTour
|
|
1487
|
+
|
|
1488
|
+
```tsx
|
|
1489
|
+
import { CoachMark, CoachMarkTour } from '@gnome-ui/react-native';
|
|
1490
|
+
|
|
1491
|
+
<CoachMark
|
|
1492
|
+
open={open}
|
|
1493
|
+
targetRef={target}
|
|
1494
|
+
title="Sync your files"
|
|
1495
|
+
description="Press this to keep every device up to date."
|
|
1496
|
+
primaryAction={{ label: 'Got it', onPress: () => setOpen(false) }}
|
|
1497
|
+
onDismiss={() => setOpen(false)}
|
|
1498
|
+
/>
|
|
1499
|
+
|
|
1500
|
+
<CoachMarkTour
|
|
1501
|
+
open={running}
|
|
1502
|
+
steps={[
|
|
1503
|
+
{ targetRef: searchRef, title: 'Search', description: 'Find anything fast.' },
|
|
1504
|
+
{ targetRef: addRef, title: 'Add', description: 'Create a new item here.', placement: 'left' },
|
|
1505
|
+
]}
|
|
1506
|
+
onFinish={() => setRunning(false)}
|
|
1507
|
+
onSkip={() => setRunning(false)}
|
|
1508
|
+
/>
|
|
1509
|
+
```
|
|
1510
|
+
|
|
1511
|
+
Spotlights a target element and anchors a callout bubble (title,
|
|
1512
|
+
description, step counter, actions) beside it, guiding a user to one
|
|
1513
|
+
feature. Compose several with `CoachMarkTour`, or drive one directly with
|
|
1514
|
+
`open`. Mirrors `@gnome-ui/react`'s `CoachMark`/`CoachMarkTour` — not a
|
|
1515
|
+
GNOME HIG widget, a pragmatic feature-discovery pattern.
|
|
1516
|
+
|
|
1517
|
+
Positions with the same two-pass viewport-aware flip as the web version
|
|
1518
|
+
(`coachMarkUtils.ts`, duplicated verbatim — pure math, no DOM), resolved
|
|
1519
|
+
from `targetRef.current?.measureInWindow(...)` and the bubble's own
|
|
1520
|
+
`onLayout` size. **The measurement is deliberately delayed (a real
|
|
1521
|
+
`setTimeout`, not just one `requestAnimationFrame`)** — confirmed
|
|
1522
|
+
on-device that measuring too early catches a stale rect when the target
|
|
1523
|
+
sits below sibling content whose own size isn't final on the first commit
|
|
1524
|
+
(e.g. a multi-line description `Text` above it); a single rAF still
|
|
1525
|
+
landed before the follow-up layout pass accounted for it.
|
|
1526
|
+
|
|
1527
|
+
The spotlight cutout has no CSS `box-shadow: 0 0 0 100vmax` port — that
|
|
1528
|
+
trick paints an opaque scrim everywhere except inside a rounded rect via a
|
|
1529
|
+
huge spread shadow, which RN's real OS shadows can't reproduce. Rebuilt as
|
|
1530
|
+
four plain `View` bands around the padded target rect, plus a separate
|
|
1531
|
+
rounded `accentColor`-bordered ring on top — the whole overlay sits inside
|
|
1532
|
+
one full-screen `Pressable`, so a tap anywhere within it (including
|
|
1533
|
+
visually "in the hole") triggers `dismissOnBackdrop`, matching the web
|
|
1534
|
+
version exactly. `dismissOnBackdrop` has no effect when `spotlight` is
|
|
1535
|
+
`false` — ported faithfully, not fixed: the web source only renders a
|
|
1536
|
+
backdrop element at all when `spotlight` is true. The arrow reuses
|
|
1537
|
+
`Popover`/`Tooltip`'s transparent-border-triangle trick rather than the
|
|
1538
|
+
web CSS's rotated-45°-square, offset along the bubble's edge by
|
|
1539
|
+
`arrowOffset` from the position math (unlike `Tooltip`/`Popover`'s simpler
|
|
1540
|
+
always-centered arrow). No focus trap and no scroll/resize
|
|
1541
|
+
re-positioning, the same established gaps for a transient RN floating
|
|
1542
|
+
element. `CoachMarkTour` is pure state orchestration on top of
|
|
1543
|
+
`CoachMark`, ported verbatim.
|
|
1544
|
+
|
|
1545
|
+
### Clamp
|
|
1546
|
+
|
|
1547
|
+
```tsx
|
|
1548
|
+
import { Clamp } from '@gnome-ui/react-native';
|
|
1549
|
+
|
|
1550
|
+
<Clamp>
|
|
1551
|
+
<BoxedList>{/* … */}</BoxedList>
|
|
1552
|
+
</Clamp>
|
|
1553
|
+
|
|
1554
|
+
<Clamp maximumSize={480} tighteningThreshold={0.9}>
|
|
1555
|
+
<Text>Never wider than 480 dp, and never edge-to-edge below it</Text>
|
|
1556
|
+
</Clamp>
|
|
1557
|
+
```
|
|
1558
|
+
|
|
1559
|
+
Constrains its children to a maximum width while letting them shrink freely
|
|
1560
|
+
— mirrors `@gnome-ui/react`'s `Clamp` and the Adwaita `AdwClamp` widget. Use
|
|
1561
|
+
it on settings pages and forms so content never becomes too wide to read
|
|
1562
|
+
comfortably on a tablet or a landscape phone, while still filling the width
|
|
1563
|
+
on a narrow one. `maximumSize` defaults to **600** (the Adwaita recommended
|
|
1564
|
+
narrow-content width) and is in density-independent pixels, not CSS px.
|
|
1565
|
+
Adds no padding of its own.
|
|
1566
|
+
|
|
1567
|
+
The web version's `margin-inline: auto` centering becomes
|
|
1568
|
+
`alignSelf: 'center'` rather than `marginHorizontal: 'auto'` — RN
|
|
1569
|
+
auto-margin support was left unverified for this Yoga version back when
|
|
1570
|
+
`Drawer` needed the same trick, so this follows `Drawer`'s resolution of
|
|
1571
|
+
using flex alignment instead. The one consequence is that `Clamp` expects a
|
|
1572
|
+
column-direction parent (RN's default): `alignSelf` acts on the cross axis,
|
|
1573
|
+
so inside a `flexDirection: 'row'` parent it would centre vertically. Wrap
|
|
1574
|
+
it in a plain `View` there.
|
|
1575
|
+
|
|
1576
|
+
`tighteningThreshold` is a real percentage width here, unlike in
|
|
1577
|
+
`@gnome-ui/react`, where the prop is declared and documented but never
|
|
1578
|
+
reaches the DOM — implementing it exactly as that package documents it (a
|
|
1579
|
+
fraction of the available width, still capped by `maximumSize`) costs
|
|
1580
|
+
nothing on RN and avoids shipping a dead prop.
|
|
1581
|
+
|
|
1582
|
+
### Box
|
|
1583
|
+
|
|
1584
|
+
```tsx
|
|
1585
|
+
import { Box } from '@gnome-ui/react-native';
|
|
1586
|
+
|
|
1587
|
+
// Vertical section (heading + content)
|
|
1588
|
+
<Box spacing={12}>
|
|
1589
|
+
<Text variant="caption-heading" color="dim">Devices</Text>
|
|
1590
|
+
<BoxedList>{/* … */}</BoxedList>
|
|
1591
|
+
</Box>
|
|
1592
|
+
|
|
1593
|
+
// Horizontal icon + label
|
|
1594
|
+
<Box orientation="horizontal" spacing={6} align="center">
|
|
1595
|
+
<Icon icon={Folder} size="sm" />
|
|
1596
|
+
<Text>Documents</Text>
|
|
1597
|
+
</Box>
|
|
1598
|
+
```
|
|
1599
|
+
|
|
1600
|
+
Fundamental flex layout primitive — the RN equivalent of `GtkBox`, and a 1:1
|
|
1601
|
+
mirror of `@gnome-ui/react`'s own `Box`. Arranges children in a row or
|
|
1602
|
+
column with consistent spacing from the GNOME HIG scale: **3** (tight) ·
|
|
1603
|
+
**6** (standard, the default) · **12** (medium) · **18** (large) · **24**
|
|
1604
|
+
(section) · **32** (loose) · **48** (jumbo), all in dp. `align` defaults to
|
|
1605
|
+
`"stretch"` when vertical and `"center"` when horizontal, `justify` to
|
|
1606
|
+
`"start"`.
|
|
1607
|
+
|
|
1608
|
+
`BoxSpacing` keeps the web package's exact seven values rather than being
|
|
1609
|
+
remapped onto this package's own `theme.space1`–`space6` scale — the two
|
|
1610
|
+
overlap at 6/12/18/24/48 but not at 3 or 32/36, and `BoxSpacing` is a
|
|
1611
|
+
published type consumers may already be importing, so it ports verbatim.
|
|
1612
|
+
|
|
1613
|
+
Two things the web version accepts don't survive the platform. `spacing`
|
|
1614
|
+
and `padding` are numbers only — RN's `gap`/`padding` take dp, not CSS
|
|
1615
|
+
strings like `"1rem"`. And `align`/`justify`, which the web hands straight
|
|
1616
|
+
to CSS, are mapped internally from their bare `start`/`end` keywords onto
|
|
1617
|
+
Yoga's `flex-start`/`flex-end`; the prop values stay the web ones, so the
|
|
1618
|
+
API reads identically across both packages. `display: 'flex'` needs no port
|
|
1619
|
+
at all — every RN `View` is already a flex container.
|
|
1620
|
+
|
|
1621
|
+
### WrapBox
|
|
1622
|
+
|
|
1623
|
+
```tsx
|
|
1624
|
+
import { WrapBox } from '@gnome-ui/react-native';
|
|
1625
|
+
|
|
1626
|
+
// Tag list
|
|
1627
|
+
<WrapBox>
|
|
1628
|
+
{tags.map((tag) => <Chip key={tag} label={tag} />)}
|
|
1629
|
+
</WrapBox>
|
|
1630
|
+
|
|
1631
|
+
// Tight between items, loose between lines
|
|
1632
|
+
<WrapBox childSpacing={6} lineSpacing={18} justify="center">
|
|
1633
|
+
{filters.map((filter) => <Chip key={filter} label={filter} />)}
|
|
1634
|
+
</WrapBox>
|
|
1635
|
+
```
|
|
1636
|
+
|
|
1637
|
+
Flexible wrapping layout container — children flow horizontally and wrap to
|
|
1638
|
+
new lines when they don't fit, like words in a paragraph, without locking
|
|
1639
|
+
them into a grid. Mirrors `AdwWrapBox` (libadwaita 1.7 / GNOME 48) and
|
|
1640
|
+
`@gnome-ui/react`'s own `WrapBox`. Pair with `Chip` for tag lists and filter
|
|
1641
|
+
rows.
|
|
1642
|
+
|
|
1643
|
+
`childSpacing` (default **6**) is the gap between items on a line;
|
|
1644
|
+
`lineSpacing` is the gap between lines and falls back to `childSpacing` when
|
|
1645
|
+
omitted — passing `0` really means zero, not "fall back". `justify` defaults
|
|
1646
|
+
to `"start"` and `align` to `"center"`; `wrapReverse` stacks lines bottom to
|
|
1647
|
+
top.
|
|
1648
|
+
|
|
1649
|
+
The web version ships its values as CSS custom properties consumed by a
|
|
1650
|
+
stylesheet (`--wrapbox-gap`, `--wrapbox-justify`, …) because a CSS module
|
|
1651
|
+
can't take runtime values any other way — RN has no such indirection, so
|
|
1652
|
+
they're written straight onto the style object. `flex-flow: row wrap`
|
|
1653
|
+
becomes `flexDirection: 'row'` + `flexWrap`, and the CSS shorthand
|
|
1654
|
+
`gap: <row> <column>` splits into RN's separate `rowGap`/`columnGap`; the
|
|
1655
|
+
single `gap` property would set both, which is precisely what this component
|
|
1656
|
+
has to be able to avoid. As in `Box`, the spacing props are numbers only
|
|
1657
|
+
(dp, not CSS strings) and `align`/`justify` keep the web's bare `start`/`end`
|
|
1658
|
+
keywords while mapping internally onto Yoga's `flex-start`/`flex-end`.
|
|
1659
|
+
|
|
1660
|
+
`alignContent: 'stretch'` is set explicitly even though neither package
|
|
1661
|
+
exposes an `alignContent` prop: **CSS defaults it to `stretch`, Yoga defaults
|
|
1662
|
+
it to `flex-start`**, so without it `align="stretch"` silently does nothing
|
|
1663
|
+
whenever the children have no cross-size of their own — the line collapses to
|
|
1664
|
+
zero height before `alignItems` gets to stretch anything into it. Caught
|
|
1665
|
+
on-device; it's a no-op in the ordinary case where the container hugs its
|
|
1666
|
+
content rather than having a fixed height.
|
|
1667
|
+
|
|
1668
|
+
### StatusPage
|
|
1669
|
+
|
|
1670
|
+
```tsx
|
|
1671
|
+
import { StatusPage } from '@gnome-ui/react-native';
|
|
1672
|
+
|
|
1673
|
+
<StatusPage
|
|
1674
|
+
icon={StarOutline}
|
|
1675
|
+
title="No favorites yet"
|
|
1676
|
+
description="Packages you star will show up here."
|
|
1677
|
+
>
|
|
1678
|
+
<Button variant="suggested" onPress={onAdd}>Add a package</Button>
|
|
1679
|
+
</StatusPage>
|
|
1680
|
+
|
|
1681
|
+
// For sidebars, popovers, and small panels
|
|
1682
|
+
<StatusPage compact icon={Search} title="No results" />
|
|
1683
|
+
```
|
|
1684
|
+
|
|
1685
|
+
Empty-state / status page following the Adwaita `AdwStatusPage` pattern —
|
|
1686
|
+
mirrors `@gnome-ui/react`'s `StatusPage`. Use it to fill a view with no
|
|
1687
|
+
content yet, an error state, or a completion confirmation. Always explain
|
|
1688
|
+
*why* the view is empty and *what the user can do* about it; don't use it
|
|
1689
|
+
for loading states, where `Spinner` or `ProgressBar` belong instead.
|
|
1690
|
+
`compact` scales padding, icon size, title variant, description
|
|
1691
|
+
variant/measure and both action-area gaps down together.
|
|
1692
|
+
|
|
1693
|
+
It centres its content on both axes, but — exactly as in the web version —
|
|
1694
|
+
the vertical centring only does anything once a parent gives it height: put
|
|
1695
|
+
it in a `flex: 1` container to fill the view.
|
|
1696
|
+
|
|
1697
|
+
The title renders through this package's `Text` at `variant="title-1"`
|
|
1698
|
+
(`"title-4"` when `compact`), so it also picks up `Text`'s automatic
|
|
1699
|
+
`header` accessibility role — a deliberate divergence from the web
|
|
1700
|
+
version's `<p class="title">`. That `<p>` exists because HTML forces you to
|
|
1701
|
+
pick a concrete `h1`–`h6` level for a component that can't know where it
|
|
1702
|
+
sits in the document outline; RN's `header` role carries no level, so the
|
|
1703
|
+
dilemma disappears. On a touch device the rotor is the only structural
|
|
1704
|
+
navigation a screen reader user has, which makes the role worth having.
|
|
1705
|
+
|
|
1706
|
+
`max-width: 36ch` on the description has no RN unit to port to. `ch` is the
|
|
1707
|
+
advance width of "0", ≈ 0.5em in the sans faces Adwaita uses, so the cap is
|
|
1708
|
+
resolved against the description's own font size — 288 dp at body size, 216
|
|
1709
|
+
dp at caption size — keeping the measure font-relative the way the CSS is,
|
|
1710
|
+
rather than freezing one pixel value that `compact` would get wrong. The
|
|
1711
|
+
icon is dimmed by its wrapper's opacity (0.55 light / 0.45 dark, the two
|
|
1712
|
+
values the web's own `prefers-color-scheme` block hardcodes) and hidden
|
|
1713
|
+
from assistive tech with the `accessibilityElementsHidden` +
|
|
1714
|
+
`importantForAccessibility="no"` pair used in place of `aria-hidden`. The
|
|
1715
|
+
action area is a `WrapBox` rather than a hand-rolled row — `.actions` is a
|
|
1716
|
+
centred wrapping flex row with a gap and nothing else.
|
|
1717
|
+
|
|
1718
|
+
### ToggleGroup / ToggleGroupItem
|
|
1719
|
+
|
|
1720
|
+
```tsx
|
|
1721
|
+
import { ToggleGroup, ToggleGroupItem } from '@gnome-ui/react-native';
|
|
1722
|
+
|
|
1723
|
+
const [align, setAlign] = useState('left');
|
|
1724
|
+
|
|
1725
|
+
<ToggleGroup value={align} onValueChange={setAlign} accessibilityLabel="Alignment">
|
|
1726
|
+
<ToggleGroupItem name="left" icon={FormatJustifyLeft} accessibilityLabel="Left" />
|
|
1727
|
+
<ToggleGroupItem name="center" icon={FormatJustifyCenter} accessibilityLabel="Center" />
|
|
1728
|
+
<ToggleGroupItem name="right" icon={FormatJustifyRight} accessibilityLabel="Right" />
|
|
1729
|
+
</ToggleGroup>
|
|
1730
|
+
|
|
1731
|
+
// Items can be icon-only, label-only, or icon + label
|
|
1732
|
+
<ToggleGroupItem name="grid" icon={Applications} label="Grid" />
|
|
1733
|
+
```
|
|
1734
|
+
|
|
1735
|
+
Mutually-exclusive group of toggle buttons for in-place option selection —
|
|
1736
|
+
mirrors `AdwToggleGroup` (libadwaita 1.7 / GNOME 48) and
|
|
1737
|
+
`@gnome-ui/react`'s own `ToggleGroup`. Use it for formatting controls,
|
|
1738
|
+
view-mode selectors and toolbar options, wherever a `ViewSwitcher` would be
|
|
1739
|
+
too heavy or doesn't belong in a `HeaderBar`. For icon-only items always
|
|
1740
|
+
pass an `accessibilityLabel`.
|
|
1741
|
+
|
|
1742
|
+
The context and its `value`/`onValueChange` shape port 1:1 — pure React. The
|
|
1743
|
+
keyboard layer doesn't: the web version owns an `onKeyDown` implementing
|
|
1744
|
+
← / → cycling and Home / End jumps over a roving `tabIndex`, none of which
|
|
1745
|
+
has a touch counterpart, so it drops per this package's standing convention
|
|
1746
|
+
(set by `ViewSwitcher` and `TabBar`). The `radiogroup`/`radio` + `checked`
|
|
1747
|
+
pairing that VoiceOver and TalkBack actually announce carries the semantics
|
|
1748
|
+
instead.
|
|
1749
|
+
|
|
1750
|
+
The group sets `accessibilityRole="radiogroup"` but deliberately **not**
|
|
1751
|
+
`accessible` — on iOS, `accessible` on a container collapses the whole
|
|
1752
|
+
subtree into a single accessibility element, which would make the individual
|
|
1753
|
+
toggles unreachable for VoiceOver. Without it the role still groups on
|
|
1754
|
+
Android while every item stays focusable on its own.
|
|
1755
|
+
|
|
1756
|
+
Three `color-mix(in srgb, accent N%, transparent)` values resolve to 8-digit
|
|
1757
|
+
`#RRGGBBAA` hexes off `theme.accentBgColor` (the `Chip` precedent for the
|
|
1758
|
+
same selected-tint problem), so the tint follows the app's configurable
|
|
1759
|
+
accent color. The CSS paints its active ring as an `inset` box-shadow, which
|
|
1760
|
+
RN has no equivalent for — it becomes a real `borderWidth: 1` that every
|
|
1761
|
+
item carries at all times (transparent when inactive) so selecting one never
|
|
1762
|
+
shifts the row's layout, the substitution `AvatarGroup` already made for its
|
|
1763
|
+
own ring. `box-shadow: var(--gnome-shadow-sm)` on the group is dropped
|
|
1764
|
+
rather than approximated: the theme generator keeps shadow tokens in `raw`
|
|
1765
|
+
only, and `Card` already established that a border carries the same
|
|
1766
|
+
separation here. `:hover` collapses away and `:active` maps to `Pressable`'s
|
|
1767
|
+
`pressed` using `theme.activeOverlay`, whose light/dark values match the
|
|
1768
|
+
CSS's own `:active` colors exactly.
|
|
1769
|
+
|
|
1770
|
+
The icon keeps the default foreground color instead of tracking the active
|
|
1771
|
+
accent text — `Icon` has no `currentColor` equivalent and its `color` prop
|
|
1772
|
+
is a fixed GNOME palette with no `accent` member, which couldn't follow a
|
|
1773
|
+
configurable accent anyway. Same call, same reason, as `Chip`.
|
|
1774
|
+
|
|
1775
|
+
### InlineViewSwitcher / InlineViewSwitcherItem
|
|
1776
|
+
|
|
1777
|
+
```tsx
|
|
1778
|
+
import { InlineViewSwitcher, InlineViewSwitcherItem } from '@gnome-ui/react-native';
|
|
1779
|
+
|
|
1780
|
+
const [view, setView] = useState('grid');
|
|
1781
|
+
|
|
1782
|
+
<InlineViewSwitcher value={view} onValueChange={setView} variant="pill">
|
|
1783
|
+
<InlineViewSwitcherItem name="grid" label="Grid" icon={Applications} />
|
|
1784
|
+
<InlineViewSwitcherItem name="list" label="List" icon={ViewSidebar} />
|
|
1785
|
+
</InlineViewSwitcher>
|
|
1786
|
+
|
|
1787
|
+
// Collapse to a BottomSheet picker when the items stop fitting
|
|
1788
|
+
<InlineViewSwitcher value={view} onValueChange={setView} overflow="menu">
|
|
1789
|
+
{/* … */}
|
|
1790
|
+
</InlineViewSwitcher>
|
|
1791
|
+
```
|
|
1792
|
+
|
|
1793
|
+
Compact inline view switcher for content areas, cards and toolbars —
|
|
1794
|
+
wherever `ViewSwitcher` (header-bar sized) would be too heavy. Mirrors
|
|
1795
|
+
`AdwInlineViewSwitcher` (libadwaita 1.7 / GNOME 48) and `@gnome-ui/react`'s
|
|
1796
|
+
own `InlineViewSwitcher`. Four variants — `default` (card surface + border),
|
|
1797
|
+
`flat` (indicator only), `round` (pill container, solid accent indicator),
|
|
1798
|
+
`pill` (segmented-control look, no accent) — and four overflow strategies:
|
|
1799
|
+
`wrap`, `scroll`, `compact`, `menu`.
|
|
1800
|
+
|
|
1801
|
+
Almost none of the *mechanism* ports, so this is a rebuild rather than a
|
|
1802
|
+
transliteration:
|
|
1803
|
+
|
|
1804
|
+
- **The sliding indicator** is measured, not laid out. The web reads the
|
|
1805
|
+
active button's `offsetLeft`/`offsetWidth`; here each item reports its own
|
|
1806
|
+
`onLayout` up through the context and the indicator animates `translateX` +
|
|
1807
|
+
`width` on **one JS-driven animation** (`useNativeDriver: false`). `width`
|
|
1808
|
+
can't be native-driven and mixing a native with a JS value on one component
|
|
1809
|
+
throws — the trade-off `Expander` already accepted for its animated height.
|
|
1810
|
+
`scaleX` would have been native-driveable but distorts the corner radii the
|
|
1811
|
+
variants are defined by. `useReducedMotion()` snaps it into place instead.
|
|
1812
|
+
- **Overflow detection** replaces `ResizeObserver` + `scrollWidth` vs
|
|
1813
|
+
`clientWidth` with the item measurements already being collected: their
|
|
1814
|
+
summed natural widths (RN leaves `flexShrink` at 0, so an overflowing row
|
|
1815
|
+
still reports each item at full width) against the row's own `onLayout`.
|
|
1816
|
+
The web's `naturalWidthRef` capture and 30 px hysteresis port verbatim —
|
|
1817
|
+
without them, collapsing the labels shrinks the content and immediately
|
|
1818
|
+
re-expands it.
|
|
1819
|
+
- **`overflow="scroll"`** becomes a horizontal `ScrollView` with the
|
|
1820
|
+
scrollbar hidden; `scroll-snap-align: start` has no RN style, but the
|
|
1821
|
+
measured item offsets feed `snapToOffsets`, which reproduces it exactly.
|
|
1822
|
+
- **`overflow="menu"`** reuses the already-shipped `BottomSheet`.
|
|
1823
|
+
|
|
1824
|
+
The ←/→/Home/End keyboard layer drops as everywhere else here, and — as in
|
|
1825
|
+
`ToggleGroup` — the group takes `accessibilityRole="radiogroup"` but
|
|
1826
|
+
deliberately not `accessible`, which on iOS would collapse the items into one
|
|
1827
|
+
unreachable element.
|
|
1828
|
+
|
|
1829
|
+
One divergence is a fix, not a port: the web applies its `.active` class to
|
|
1830
|
+
the menu trigger even though menu mode hides the indicator, which paints
|
|
1831
|
+
`round`'s trigger label in `accent-fg` (#fff) on a plain card — white on
|
|
1832
|
+
white. The RN trigger uses the idle color.
|
|
1833
|
+
|
|
1834
|
+
### PreferencesGroup
|
|
1835
|
+
|
|
1836
|
+
```tsx
|
|
1837
|
+
import { PreferencesGroup } from '@gnome-ui/react-native';
|
|
1838
|
+
|
|
1839
|
+
<PreferencesGroup
|
|
1840
|
+
title="Appearance"
|
|
1841
|
+
description="How the app looks on this device."
|
|
1842
|
+
headerSuffix={<Button variant="flat" onPress={reset}>Reset</Button>}
|
|
1843
|
+
>
|
|
1844
|
+
<BoxedList>{rows}</BoxedList>
|
|
1845
|
+
</PreferencesGroup>
|
|
1846
|
+
```
|
|
1847
|
+
|
|
1848
|
+
Titled section that wraps a `BoxedList` with an optional description —
|
|
1849
|
+
mirrors `AdwPreferencesGroup` and `@gnome-ui/react`'s own
|
|
1850
|
+
`PreferencesGroup`. Use it to group related settings under a named heading.
|
|
1851
|
+
It's purely a layout and labelling wrapper: it doesn't render the
|
|
1852
|
+
`BoxedList` itself, you pass one as `children`. All three header parts are
|
|
1853
|
+
optional; with none of them the header row is omitted entirely.
|
|
1854
|
+
|
|
1855
|
+
The web's empty `.content` wrapper looks like dead markup but is
|
|
1856
|
+
load-bearing, so it's kept. The group is a 12 dp-gap flex column — without
|
|
1857
|
+
that wrapper every child would become a flex item of the group and pick up a
|
|
1858
|
+
12 dp gap between the rows themselves, instead of one gap between the header
|
|
1859
|
+
and the content as a whole.
|
|
1860
|
+
|
|
1861
|
+
The title renders as `Text variant="body"` with an explicit semibold weight
|
|
1862
|
+
rather than `variant="heading"`, which is body-sized but **bold** and on the
|
|
1863
|
+
tighter heading line-height; the CSS `.title` is specifically semibold at the
|
|
1864
|
+
body line-height. It keeps the `header` accessibility role anyway (passed
|
|
1865
|
+
explicitly), since a settings-group heading is exactly the kind of landmark a
|
|
1866
|
+
screen reader rotor should list — the same call `StatusPage` makes for its
|
|
1867
|
+
own title. `min-width: 0` on the header text has no port and needs none: it's
|
|
1868
|
+
the classic CSS flexbox override for a min-content floor Yoga doesn't apply
|
|
1869
|
+
in the first place.
|
|
1870
|
+
|
|
1433
1871
|
## Installation
|
|
1434
1872
|
|
|
1435
1873
|
```bash
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
import { AvatarColor, AvatarSize } from '../Avatar';
|
|
3
|
+
export interface AvatarGroupItem {
|
|
4
|
+
name?: string;
|
|
5
|
+
src?: string;
|
|
6
|
+
alt?: string;
|
|
7
|
+
color?: AvatarColor;
|
|
8
|
+
}
|
|
9
|
+
export interface AvatarGroupProps {
|
|
10
|
+
avatars: AvatarGroupItem[];
|
|
11
|
+
/** Max visible avatars before showing the overflow chip. Defaults to `5`. */
|
|
12
|
+
max?: number;
|
|
13
|
+
/** Size applied to all avatars and the overflow chip. Defaults to `"md"`. */
|
|
14
|
+
size?: AvatarSize;
|
|
15
|
+
/** Accessible label for the group. Auto-generated from names when omitted. */
|
|
16
|
+
accessibilityLabel?: string;
|
|
17
|
+
style?: StyleProp<ViewStyle>;
|
|
18
|
+
testID?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Overlapping stack of `Avatar`s with a "+N" overflow indicator. Mirrors
|
|
22
|
+
* `@gnome-ui/react`'s `AvatarGroup`.
|
|
23
|
+
*
|
|
24
|
+
* The web version's separating ring around each overlapping avatar is two
|
|
25
|
+
* layered `box-shadow`s (an inset 1px dark/light border plus an outset 2px
|
|
26
|
+
* window-colored ring) — RN can only give a `View` one border, so this
|
|
27
|
+
* keeps just the outer window-colored ring (`borderWidth: 2,
|
|
28
|
+
* borderColor: theme.windowBgColor`, overriding `Avatar`'s own subtle 1px
|
|
29
|
+
* ring via its `style` prop), since that's the ring doing the actual
|
|
30
|
+
* "stay visually distinct from the avatar behind you" work — the inner
|
|
31
|
+
* hairline is a decorative nicety, not a behavior gap. The overflow chip
|
|
32
|
+
* reuses `Avatar`'s own per-size box dimensions (`sm`/`md`/`lg`/`xl` →
|
|
33
|
+
* 24/32/48/64) so it lines up exactly with the avatars beside it.
|
|
34
|
+
*
|
|
35
|
+
* `role="group"` + `accessibilityLabel` ports 1:1 from RN's newer
|
|
36
|
+
* web-aligned `Role` union (the same `Avatar`/`Badge`/`LevelBar`
|
|
37
|
+
* precedent) — the label is auto-generated from `avatars[].name` (joined,
|
|
38
|
+
* plus "and N more" when overflowing) exactly like the web version, unless
|
|
39
|
+
* overridden. The overflow chip's `+N` text is hidden from the
|
|
40
|
+
* accessibility tree (`accessibilityElementsHidden`/
|
|
41
|
+
* `importantForAccessibility="no"`) in favor of the chip's own
|
|
42
|
+
* `accessibilityLabel="+N more"` — the same one-stop-not-two reasoning
|
|
43
|
+
* `SpinButton`/`Avatar` already established for a decorative inner glyph.
|
|
44
|
+
*
|
|
45
|
+
* @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Avatar.html
|
|
46
|
+
*/
|
|
47
|
+
export declare const AvatarGroup: ({ avatars, max, size, accessibilityLabel, style, testID, }: AvatarGroupProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
import { AvatarColor, AvatarSize } from '../Avatar';
|
|
3
|
+
export interface AvatarRotatorProps {
|
|
4
|
+
/** Full name used for the accessible label and initials fallback. */
|
|
5
|
+
name?: string;
|
|
6
|
+
/** Image URLs to rotate through. */
|
|
7
|
+
avatars?: string[];
|
|
8
|
+
/** Accessible label. Defaults to `name`. */
|
|
9
|
+
alt?: string;
|
|
10
|
+
/** Size of the avatar. Defaults to `"md"`. */
|
|
11
|
+
size?: AvatarSize;
|
|
12
|
+
/** Fallback initials color when no avatar image is available. */
|
|
13
|
+
color?: AvatarColor;
|
|
14
|
+
/** Time between avatar changes in milliseconds. Defaults to `3000`. */
|
|
15
|
+
interval?: number;
|
|
16
|
+
/** Crossfade duration in milliseconds. Defaults to `240`. */
|
|
17
|
+
transitionDuration?: number;
|
|
18
|
+
/** Pause automatic rotation while pressed and held. Defaults to `true`. */
|
|
19
|
+
pauseOnPress?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Controlled active avatar index.
|
|
22
|
+
* When omitted the rotator manages index state internally.
|
|
23
|
+
*/
|
|
24
|
+
activeIndex?: number;
|
|
25
|
+
/** Initial active avatar index for uncontrolled usage. Defaults to `0`. */
|
|
26
|
+
defaultActiveIndex?: number;
|
|
27
|
+
/** Called when the active avatar changes. */
|
|
28
|
+
onIndexChange?: (index: number) => void;
|
|
29
|
+
style?: StyleProp<ViewStyle>;
|
|
30
|
+
testID?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Single avatar surface that crossfades through multiple image sources.
|
|
34
|
+
* Mirrors `@gnome-ui/react`'s `AvatarRotator`. Keeps `Avatar` focused on
|
|
35
|
+
* rendering one identity, while this component owns timing, crossfade
|
|
36
|
+
* animation, and pause behavior.
|
|
37
|
+
*
|
|
38
|
+
* Each source renders as its own absolutely-positioned `Avatar`, layered
|
|
39
|
+
* via `StyleSheet.absoluteFill` and crossfaded with `Animated.timing` on
|
|
40
|
+
* `useNativeDriver: true` — an exact reproduction of the web version's
|
|
41
|
+
* stacked-`.layer`-elements-with-opacity-transition technique, just with
|
|
42
|
+
* `RotatorLayer` (see above) owning each layer's own `Animated.Value`
|
|
43
|
+
* instead of a single shared CSS custom property driving them all.
|
|
44
|
+
*
|
|
45
|
+
* **`prefers-reduced-motion` stops the rotation outright, not just the
|
|
46
|
+
* fade** — ported exactly: the web source's own auto-advance `useEffect`
|
|
47
|
+
* bails out early when reduced motion is on, the same as when paused, so
|
|
48
|
+
* this isn't merely an instant-swap-instead-of-crossfade case like
|
|
49
|
+
* `ProgressBar`'s determinate transitions.
|
|
50
|
+
*
|
|
51
|
+
* The web version's `pauseOnHover` (mouseEnter/mouseLeave, focus/blur)
|
|
52
|
+
* becomes `pauseOnPress` (`onPressIn`/`onPressOut`) — the same touch
|
|
53
|
+
* substitution `Toast`'s own press-and-hold pause already established,
|
|
54
|
+
* kept as a real toggleable prop here (unlike `Toast`, where the web
|
|
55
|
+
* source bakes the behavior in without an escape hatch).
|
|
56
|
+
* `usePrefersReducedMotion` (the web version's `@gnome-ui/hooks` import)
|
|
57
|
+
* has no bearing here — this package's own `useReducedMotion()` from
|
|
58
|
+
* `GnomeProvider` is the correct, already-established source for this.
|
|
59
|
+
*
|
|
60
|
+
* `role="img"` + `accessibilityLabel` ports 1:1 from RN's newer
|
|
61
|
+
* web-aligned `Role` union (the same `Avatar`/`AvatarGroup` precedent).
|
|
62
|
+
*
|
|
63
|
+
* @see https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Avatar.html
|
|
64
|
+
*/
|
|
65
|
+
export declare const AvatarRotator: ({ name, avatars, alt, size, color, interval, transitionDuration, pauseOnPress, activeIndex, defaultActiveIndex, onIndexChange, style, testID, }: AvatarRotatorProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { StyleProp, View, ViewProps, ViewStyle } from 'react-native';
|
|
3
|
+
/** GNOME HIG standard spacing values (matches `GtkBox` spacing tokens). */
|
|
4
|
+
export type BoxSpacing = 3 | 6 | 12 | 18 | 24 | 32 | 48;
|
|
5
|
+
/** Alias of `BoxSpacing` for use as a padding scale. */
|
|
6
|
+
export type BoxPadding = BoxSpacing;
|
|
7
|
+
export type BoxOrientation = 'horizontal' | 'vertical';
|
|
8
|
+
export type BoxAlign = 'start' | 'center' | 'end' | 'stretch' | 'baseline';
|
|
9
|
+
export type BoxJustify = 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly';
|
|
10
|
+
export interface BoxProps extends Omit<ViewProps, 'style'> {
|
|
11
|
+
/**
|
|
12
|
+
* Direction children are arranged.
|
|
13
|
+
* `"vertical"` → `flexDirection: 'column'` (default).
|
|
14
|
+
* `"horizontal"` → `flexDirection: 'row'`.
|
|
15
|
+
*/
|
|
16
|
+
orientation?: BoxOrientation;
|
|
17
|
+
/**
|
|
18
|
+
* Gap between children, in density-independent pixels.
|
|
19
|
+
* Accepts any of the GNOME HIG standard spacing values or any number.
|
|
20
|
+
* Defaults to `6` (the HIG "standard" inner spacing).
|
|
21
|
+
*/
|
|
22
|
+
spacing?: BoxSpacing | number;
|
|
23
|
+
/**
|
|
24
|
+
* Cross-axis alignment (`alignItems`).
|
|
25
|
+
* Defaults to `"stretch"` for vertical, `"center"` for horizontal.
|
|
26
|
+
*/
|
|
27
|
+
align?: BoxAlign;
|
|
28
|
+
/**
|
|
29
|
+
* Main-axis distribution (`justifyContent`).
|
|
30
|
+
* Defaults to `"start"`.
|
|
31
|
+
*/
|
|
32
|
+
justify?: BoxJustify;
|
|
33
|
+
/** Inner padding applied to all sides, in density-independent pixels. */
|
|
34
|
+
padding?: BoxPadding | number;
|
|
35
|
+
children?: ReactNode;
|
|
36
|
+
style?: StyleProp<ViewStyle>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Fundamental flex layout primitive — the RN equivalent of `GtkBox`, and a
|
|
40
|
+
* 1:1 mirror of `@gnome-ui/react`'s own `Box`.
|
|
41
|
+
*
|
|
42
|
+
* Arranges children in a single row or column with consistent spacing
|
|
43
|
+
* following the GNOME Human Interface Guidelines spacing scale:
|
|
44
|
+
*
|
|
45
|
+
* | Token | dp | Use |
|
|
46
|
+
* |-------|----|-----|
|
|
47
|
+
* | tight | 3 | Dense UI, icon + label pairs |
|
|
48
|
+
* | standard | 6 | Default inner spacing |
|
|
49
|
+
* | medium | 12 | Between related groups |
|
|
50
|
+
* | large | 18 | Between loosely related sections |
|
|
51
|
+
* | section | 24 | Page-level section gaps |
|
|
52
|
+
* | loose | 32 | Large content separation |
|
|
53
|
+
* | jumbo | 48 | Hero / splash spacing |
|
|
54
|
+
*
|
|
55
|
+
* `BoxSpacing` keeps the web package's exact seven values rather than being
|
|
56
|
+
* remapped onto this package's own `theme.space1`–`space6` scale — the two
|
|
57
|
+
* overlap at 6/12/18/24/48 but not at 3 or 32/36, and `BoxSpacing` is a
|
|
58
|
+
* published type consumers may already be importing, so it ports verbatim.
|
|
59
|
+
*
|
|
60
|
+
* Two things the web version accepts don't survive the platform: `spacing`
|
|
61
|
+
* and `padding` are numbers only (RN's `gap`/`padding` take dp, not CSS
|
|
62
|
+
* strings like `"1rem"`), and `align`/`justify` — which the web passes
|
|
63
|
+
* straight through to CSS — are mapped from their bare `start`/`end`
|
|
64
|
+
* keywords onto Yoga's `flex-start`/`flex-end`. The prop values stay the
|
|
65
|
+
* web ones so the API reads identically across both packages; only the
|
|
66
|
+
* internal translation differs.
|
|
67
|
+
*
|
|
68
|
+
* `display: 'flex'` has no port and needs none — every RN `View` is already
|
|
69
|
+
* a flex container.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* // Vertical section (heading + content)
|
|
73
|
+
* <Box spacing={12}>
|
|
74
|
+
* <Text variant="caption-heading" color="dim">Devices</Text>
|
|
75
|
+
* <BoxedList>…</BoxedList>
|
|
76
|
+
* </Box>
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* // Horizontal icon + label
|
|
80
|
+
* <Box orientation="horizontal" spacing={6} align="center">
|
|
81
|
+
* <Icon icon={Folder} />
|
|
82
|
+
* <Text>Documents</Text>
|
|
83
|
+
* </Box>
|
|
84
|
+
*
|
|
85
|
+
* @see https://developer.gnome.org/hig/guidelines/spacing.html
|
|
86
|
+
*/
|
|
87
|
+
export declare const Box: import('react').ForwardRefExoticComponent<BoxProps & import('react').RefAttributes<View>>;
|