@olympusoss/canvas 3.2.1 → 5.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 +75 -65
- package/package.json +11 -5
- package/src/atoms/avatar/avatar.md +185 -0
- package/src/atoms/avatar/avatar.styles.ts +48 -0
- package/src/atoms/avatar/avatar.tsx +99 -0
- package/src/atoms/badge/badge.md +237 -0
- package/src/atoms/badge/badge.styles.ts +79 -0
- package/src/atoms/badge/badge.tsx +86 -0
- package/src/atoms/breadcrumb/breadcrumb.md +233 -0
- package/src/atoms/breadcrumb/breadcrumb.styles.ts +40 -0
- package/src/atoms/breadcrumb/breadcrumb.tsx +130 -0
- package/src/atoms/button/button.android.tsx +6 -0
- package/src/atoms/button/button.ios.tsx +6 -0
- package/src/atoms/button/button.md +184 -0
- package/src/atoms/button/button.shared.tsx +79 -0
- package/src/atoms/button/button.styles.ts +152 -0
- package/src/atoms/button/button.tsx +6 -0
- package/src/atoms/button-group/button-group.android.tsx +6 -0
- package/src/atoms/button-group/button-group.ios.tsx +6 -0
- package/src/atoms/button-group/button-group.md +120 -0
- package/src/atoms/button-group/button-group.shared.tsx +398 -0
- package/src/atoms/button-group/button-group.styles.ts +483 -0
- package/src/atoms/button-group/button-group.tsx +6 -0
- package/src/atoms/checkbox/checkbox.android.tsx +6 -0
- package/src/atoms/checkbox/checkbox.ios.tsx +6 -0
- package/src/atoms/checkbox/checkbox.md +150 -0
- package/src/atoms/checkbox/checkbox.shared.tsx +103 -0
- package/src/atoms/checkbox/checkbox.styles.ts +106 -0
- package/src/atoms/checkbox/checkbox.tsx +6 -0
- package/src/atoms/combobox/combobox.android.tsx +6 -0
- package/src/atoms/combobox/combobox.ios.tsx +6 -0
- package/src/atoms/combobox/combobox.md +213 -0
- package/src/atoms/combobox/combobox.shared.tsx +160 -0
- package/src/atoms/combobox/combobox.styles.ts +270 -0
- package/src/atoms/combobox/combobox.tsx +6 -0
- package/src/atoms/divider/divider.md +140 -0
- package/src/atoms/divider/divider.styles.ts +35 -0
- package/src/atoms/divider/divider.tsx +67 -0
- package/src/atoms/dropdown/dropdown.android.tsx +6 -0
- package/src/atoms/dropdown/dropdown.ios.tsx +6 -0
- package/src/atoms/dropdown/dropdown.md +221 -0
- package/src/atoms/dropdown/dropdown.shared.tsx +190 -0
- package/src/atoms/dropdown/dropdown.styles.ts +233 -0
- package/src/atoms/dropdown/dropdown.tsx +6 -0
- package/src/atoms/icon/icon.md +131 -0
- package/src/atoms/icon/icon.styles.ts +30 -0
- package/src/atoms/icon/icon.tsx +328 -0
- package/src/atoms/index.ts +24 -0
- package/src/atoms/input/input.android.tsx +6 -0
- package/src/atoms/input/input.ios.tsx +6 -0
- package/src/atoms/input/input.md +118 -0
- package/src/atoms/input/input.shared.tsx +203 -0
- package/src/atoms/input/input.styles.ts +286 -0
- package/src/atoms/input/input.tsx +6 -0
- package/src/atoms/kbd/kbd.md +91 -0
- package/src/atoms/kbd/kbd.styles.ts +33 -0
- package/src/atoms/kbd/kbd.tsx +27 -0
- package/src/atoms/listbox/listbox.md +177 -0
- package/src/atoms/listbox/listbox.styles.ts +60 -0
- package/src/atoms/listbox/listbox.tsx +113 -0
- package/src/atoms/pagination/pagination.android.tsx +6 -0
- package/src/atoms/pagination/pagination.ios.tsx +6 -0
- package/src/atoms/pagination/pagination.md +133 -0
- package/src/atoms/pagination/pagination.shared.tsx +289 -0
- package/src/atoms/pagination/pagination.styles.ts +245 -0
- package/src/atoms/pagination/pagination.tsx +6 -0
- package/src/atoms/popover/popover.android.tsx +8 -0
- package/src/atoms/popover/popover.ios.tsx +6 -0
- package/src/atoms/popover/popover.md +87 -0
- package/src/atoms/popover/popover.shared.tsx +124 -0
- package/src/atoms/popover/popover.styles.ts +144 -0
- package/src/atoms/popover/popover.tsx +6 -0
- package/src/atoms/radio/radio.android.tsx +6 -0
- package/src/atoms/radio/radio.ios.tsx +6 -0
- package/src/atoms/radio/radio.md +173 -0
- package/src/atoms/radio/radio.shared.tsx +98 -0
- package/src/atoms/radio/radio.styles.ts +109 -0
- package/src/atoms/radio/radio.tsx +6 -0
- package/src/atoms/select/select.android.tsx +6 -0
- package/src/atoms/select/select.ios.tsx +6 -0
- package/src/atoms/select/select.md +156 -0
- package/src/atoms/select/select.shared.tsx +143 -0
- package/src/atoms/select/select.styles.ts +310 -0
- package/src/atoms/select/select.tsx +6 -0
- package/src/atoms/skeleton/skeleton.md +135 -0
- package/src/atoms/skeleton/skeleton.styles.ts +117 -0
- package/src/atoms/skeleton/skeleton.tsx +145 -0
- package/src/atoms/spinner/spinner.android.tsx +7 -0
- package/src/atoms/spinner/spinner.ios.tsx +7 -0
- package/src/atoms/spinner/spinner.md +94 -0
- package/src/atoms/spinner/spinner.shared.tsx +92 -0
- package/src/atoms/spinner/spinner.styles.tsx +115 -0
- package/src/atoms/spinner/spinner.tsx +7 -0
- package/src/atoms/switch/switch.android.tsx +6 -0
- package/src/atoms/switch/switch.ios.tsx +6 -0
- package/src/atoms/switch/switch.md +91 -0
- package/src/atoms/switch/switch.shared.tsx +97 -0
- package/src/atoms/switch/switch.styles.ts +79 -0
- package/src/atoms/switch/switch.tsx +6 -0
- package/src/atoms/textarea/textarea.android.tsx +6 -0
- package/src/atoms/textarea/textarea.ios.tsx +6 -0
- package/src/atoms/textarea/textarea.md +140 -0
- package/src/atoms/textarea/textarea.shared.tsx +74 -0
- package/src/atoms/textarea/textarea.styles.ts +116 -0
- package/src/atoms/textarea/textarea.tsx +6 -0
- package/src/atoms/tooltip/tooltip.android.tsx +6 -0
- package/src/atoms/tooltip/tooltip.ios.tsx +7 -0
- package/src/atoms/tooltip/tooltip.md +122 -0
- package/src/atoms/tooltip/tooltip.shared.tsx +113 -0
- package/src/atoms/tooltip/tooltip.styles.ts +113 -0
- package/src/atoms/tooltip/tooltip.tsx +6 -0
- package/src/atoms/typography/typography.md +330 -0
- package/src/atoms/typography/typography.styles.ts +95 -0
- package/src/atoms/typography/typography.tsx +76 -0
- package/src/index.ts +12 -2
- package/src/molecules/action-panels/action-panels.md +133 -0
- package/src/molecules/action-panels/action-panels.styles.ts +39 -0
- package/src/molecules/action-panels/action-panels.tsx +113 -0
- package/src/molecules/alert/alert.md +119 -0
- package/src/molecules/alert/alert.styles.ts +88 -0
- package/src/molecules/alert/alert.tsx +74 -0
- package/src/molecules/alert-dialog/alert-dialog.android.tsx +6 -0
- package/src/molecules/alert-dialog/alert-dialog.ios.tsx +6 -0
- package/src/molecules/alert-dialog/alert-dialog.md +177 -0
- package/src/molecules/alert-dialog/alert-dialog.shared.tsx +187 -0
- package/src/molecules/alert-dialog/alert-dialog.styles.ts +248 -0
- package/src/molecules/alert-dialog/alert-dialog.tsx +6 -0
- package/src/molecules/card/card.md +190 -0
- package/src/molecules/card/card.styles.ts +67 -0
- package/src/molecules/card/card.tsx +176 -0
- package/src/molecules/code-block/code-block.md +159 -0
- package/src/molecules/code-block/code-block.styles.ts +167 -0
- package/src/molecules/code-block/code-block.tsx +176 -0
- package/src/molecules/description-lists/description-lists.md +129 -0
- package/src/molecules/description-lists/description-lists.styles.ts +102 -0
- package/src/molecules/description-lists/description-lists.tsx +133 -0
- package/src/molecules/empty-state/empty-state.md +218 -0
- package/src/molecules/empty-state/empty-state.styles.ts +63 -0
- package/src/molecules/empty-state/empty-state.tsx +77 -0
- package/src/molecules/feeds/feeds.md +102 -0
- package/src/molecules/feeds/feeds.styles.ts +120 -0
- package/src/molecules/feeds/feeds.tsx +167 -0
- package/src/molecules/field/field.md +117 -0
- package/src/molecules/field/field.styles.ts +85 -0
- package/src/molecules/field/field.tsx +175 -0
- package/src/molecules/fieldset/fieldset.md +141 -0
- package/src/molecules/fieldset/fieldset.styles.ts +79 -0
- package/src/molecules/fieldset/fieldset.tsx +182 -0
- package/src/molecules/form/form.md +137 -0
- package/src/molecules/form/form.styles.ts +39 -0
- package/src/molecules/form/form.tsx +246 -0
- package/src/molecules/grid-lists/grid-lists.md +114 -0
- package/src/molecules/grid-lists/grid-lists.styles.ts +79 -0
- package/src/molecules/grid-lists/grid-lists.tsx +157 -0
- package/src/molecules/index.ts +16 -0
- package/src/molecules/media-objects/media-objects.md +87 -0
- package/src/molecules/media-objects/media-objects.styles.ts +94 -0
- package/src/molecules/media-objects/media-objects.tsx +128 -0
- package/src/molecules/stacked-lists/stacked-lists.md +116 -0
- package/src/molecules/stacked-lists/stacked-lists.styles.ts +111 -0
- package/src/molecules/stacked-lists/stacked-lists.tsx +195 -0
- package/src/molecules/stats/stats.md +166 -0
- package/src/molecules/stats/stats.styles.ts +91 -0
- package/src/molecules/stats/stats.tsx +88 -0
- package/src/organisms/calendar/calendar.android.tsx +6 -0
- package/src/organisms/calendar/calendar.ios.tsx +6 -0
- package/src/organisms/calendar/calendar.md +114 -0
- package/src/organisms/calendar/calendar.shared.tsx +146 -0
- package/src/organisms/calendar/calendar.styles.ts +315 -0
- package/src/organisms/calendar/calendar.tsx +6 -0
- package/src/organisms/charts/charts.md +326 -0
- package/src/organisms/charts/charts.styles.ts +135 -0
- package/src/organisms/charts/charts.tsx +124 -0
- package/src/organisms/command/command.md +117 -0
- package/src/organisms/command/command.styles.ts +179 -0
- package/src/organisms/command/command.tsx +164 -0
- package/src/organisms/data-table/data-table.md +182 -0
- package/src/organisms/data-table/data-table.styles.ts +103 -0
- package/src/organisms/data-table/data-table.tsx +105 -0
- package/src/organisms/dialog/dialog.android.tsx +6 -0
- package/src/organisms/dialog/dialog.ios.tsx +6 -0
- package/src/organisms/dialog/dialog.md +271 -0
- package/src/organisms/dialog/dialog.shared.tsx +230 -0
- package/src/organisms/dialog/dialog.styles.ts +272 -0
- package/src/organisms/dialog/dialog.tsx +6 -0
- package/src/organisms/filter-panel/filter-panel.md +116 -0
- package/src/organisms/filter-panel/filter-panel.styles.ts +83 -0
- package/src/organisms/filter-panel/filter-panel.tsx +91 -0
- package/src/organisms/index.ts +13 -0
- package/src/organisms/navbars/navbars.android.tsx +6 -0
- package/src/organisms/navbars/navbars.ios.tsx +6 -0
- package/src/organisms/navbars/navbars.md +144 -0
- package/src/organisms/navbars/navbars.shared.tsx +137 -0
- package/src/organisms/navbars/navbars.styles.ts +251 -0
- package/src/organisms/navbars/navbars.tsx +6 -0
- package/src/organisms/overlays/overlays.android.tsx +6 -0
- package/src/organisms/overlays/overlays.ios.tsx +6 -0
- package/src/organisms/overlays/overlays.md +123 -0
- package/src/organisms/overlays/overlays.shared.tsx +175 -0
- package/src/organisms/overlays/overlays.styles.ts +309 -0
- package/src/organisms/overlays/overlays.tsx +6 -0
- package/src/organisms/row-menu/row-menu.android.tsx +6 -0
- package/src/organisms/row-menu/row-menu.ios.tsx +6 -0
- package/src/organisms/row-menu/row-menu.md +102 -0
- package/src/organisms/row-menu/row-menu.shared.tsx +105 -0
- package/src/organisms/row-menu/row-menu.styles.ts +262 -0
- package/src/organisms/row-menu/row-menu.tsx +6 -0
- package/src/organisms/sidebar/sidebar.android.tsx +6 -0
- package/src/organisms/sidebar/sidebar.ios.tsx +6 -0
- package/src/organisms/sidebar/sidebar.md +188 -0
- package/src/organisms/sidebar/sidebar.shared.tsx +167 -0
- package/src/organisms/sidebar/sidebar.styles.ts +262 -0
- package/src/organisms/sidebar/sidebar.tsx +6 -0
- package/src/organisms/stepper/stepper.android.tsx +6 -0
- package/src/organisms/stepper/stepper.ios.tsx +6 -0
- package/src/organisms/stepper/stepper.md +150 -0
- package/src/organisms/stepper/stepper.shared.tsx +158 -0
- package/src/organisms/stepper/stepper.styles.ts +280 -0
- package/src/organisms/stepper/stepper.tsx +6 -0
- package/src/organisms/tabs/tabs.android.tsx +6 -0
- package/src/organisms/tabs/tabs.ios.tsx +6 -0
- package/src/organisms/tabs/tabs.md +127 -0
- package/src/organisms/tabs/tabs.shared.tsx +281 -0
- package/src/organisms/tabs/tabs.styles.ts +398 -0
- package/src/organisms/tabs/tabs.tsx +6 -0
- package/src/style/color.ts +17 -0
- package/src/style/index.ts +14 -0
- package/src/style/primitives.ts +26 -0
- package/src/style/responsive.ts +45 -0
- package/src/style/shadow.ts +21 -0
- package/src/style/theme.tsx +56 -0
- package/src/style/tokens.ts +487 -0
- package/styles/canvas.css +127 -74
- package/tsconfig.json +4 -2
- package/src/cn.ts +0 -3
- package/styles/atoms/avatar.css +0 -22
- package/styles/atoms/badge.css +0 -83
- package/styles/atoms/breadcrumb.css +0 -35
- package/styles/atoms/button-group.css +0 -23
- package/styles/atoms/button.css +0 -107
- package/styles/atoms/checkbox.css +0 -55
- package/styles/atoms/combobox.css +0 -76
- package/styles/atoms/dropdown.css +0 -54
- package/styles/atoms/icon.css +0 -8
- package/styles/atoms/input-group.css +0 -45
- package/styles/atoms/input.css +0 -56
- package/styles/atoms/kbd.css +0 -15
- package/styles/atoms/pagination.css +0 -48
- package/styles/atoms/popover.css +0 -14
- package/styles/atoms/radio.css +0 -28
- package/styles/atoms/select.css +0 -57
- package/styles/atoms/separator.css +0 -32
- package/styles/atoms/skeleton.css +0 -32
- package/styles/atoms/spinner.css +0 -26
- package/styles/atoms/switch.css +0 -45
- package/styles/atoms/textarea.css +0 -31
- package/styles/atoms/tooltip.css +0 -53
- package/styles/atoms/typography.css +0 -105
- package/styles/base.css +0 -17
- package/styles/molecules/alert.css +0 -66
- package/styles/molecules/card.css +0 -58
- package/styles/molecules/code-block.css +0 -18
- package/styles/molecules/empty-state.css +0 -17
- package/styles/molecules/field.css +0 -27
- package/styles/molecules/form.css +0 -27
- package/styles/molecules/page-header.css +0 -52
- package/styles/molecules/section-card.css +0 -49
- package/styles/molecules/stat-card.css +0 -71
- package/styles/molecules/toast.css +0 -95
- package/styles/organisms/app-shell.css +0 -46
- package/styles/organisms/calendar.css +0 -73
- package/styles/organisms/command.css +0 -95
- package/styles/organisms/data-table.css +0 -142
- package/styles/organisms/dialog.css +0 -72
- package/styles/organisms/filter-panel.css +0 -58
- package/styles/organisms/row-menu.css +0 -69
- package/styles/organisms/sheet.css +0 -70
- package/styles/organisms/sidebar.css +0 -146
- package/styles/organisms/stepper.css +0 -63
- package/styles/organisms/tabs.css +0 -40
- package/styles/organisms/topbar.css +0 -24
- package/styles/patterns/backdrops.css +0 -35
- package/styles/patterns/density.css +0 -66
- package/styles/patterns/focus.css +0 -22
- package/styles/patterns/glass.css +0 -85
- package/styles/patterns/high-contrast.css +0 -70
- package/styles/patterns/reduced-motion.css +0 -12
- package/styles/patterns/scrollbar.css +0 -10
- package/styles/reset.css +0 -89
- package/styles/tokens/colors.css +0 -108
- package/styles/tokens/motion.css +0 -33
- package/styles/tokens/radius.css +0 -10
- package/styles/tokens/shadows.css +0 -35
- package/styles/tokens/spacing.css +0 -19
- package/styles/tokens/typography.css +0 -6
- package/styles/tokens/z-index.css +0 -12
- package/styles/utilities/display.css +0 -66
- package/styles/utilities/flexbox.css +0 -240
- package/styles/utilities/gap.css +0 -288
- package/styles/utilities/grid.css +0 -138
- package/styles/utilities/position.css +0 -78
- package/styles/utilities/sizing.css +0 -138
package/README.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# @olympusoss/canvas
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Universal React Native UI kit. Canvas runs natively on iOS and Android, and on
|
|
4
|
+
the web through React Native Web, from a single component API. Components are
|
|
5
|
+
styled with semantic boolean props and authored desktop-first, so they adapt
|
|
6
|
+
cleanly from large desktop down to phone.
|
|
4
7
|
|
|
5
8
|
## Install
|
|
6
9
|
|
|
@@ -8,90 +11,97 @@ CSS-first design system for the Olympus platform.
|
|
|
8
11
|
npm install @olympusoss/canvas
|
|
9
12
|
```
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Import all styles:
|
|
14
|
-
|
|
15
|
-
```css
|
|
16
|
-
@import "@olympusoss/canvas/styles/canvas.css";
|
|
17
|
-
```
|
|
14
|
+
Canvas relies on three peer dependencies that you install alongside it:
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
```css
|
|
22
|
-
@layer canvas.reset, canvas.tokens, canvas.base, canvas.components, canvas.patterns;
|
|
23
|
-
|
|
24
|
-
@import "@olympusoss/canvas/styles/reset.css";
|
|
25
|
-
@import "@olympusoss/canvas/styles/tokens/colors.css";
|
|
26
|
-
@import "@olympusoss/canvas/styles/tokens/typography.css";
|
|
27
|
-
@import "@olympusoss/canvas/styles/base.css";
|
|
28
|
-
@import "@olympusoss/canvas/styles/atoms/button.css";
|
|
16
|
+
```bash
|
|
17
|
+
npm install react react-native react-native-svg
|
|
29
18
|
```
|
|
30
19
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
20
|
+
For web rendering, add `react-native-web` to your app and alias `react-native`
|
|
21
|
+
to `react-native-web` in your bundler, the same way any React Native Web project
|
|
22
|
+
does.
|
|
34
23
|
|
|
35
|
-
|
|
24
|
+
## Quick Start
|
|
36
25
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
Wrap your app in the `ThemeProvider`, then compose components imported
|
|
27
|
+
from `@olympusoss/canvas`. The provider supplies the active color scheme and
|
|
28
|
+
token map; omit `scheme` to follow the OS appearance, or force it with
|
|
29
|
+
`scheme="light"` / `scheme="dark"`.
|
|
30
|
+
|
|
31
|
+
```jsx
|
|
32
|
+
import { ThemeProvider, Card, CardHeader, CardTitle, CardContent, Button } from "@olympusoss/canvas";
|
|
33
|
+
|
|
34
|
+
export default function App() {
|
|
35
|
+
return (
|
|
36
|
+
<ThemeProvider>
|
|
37
|
+
<Card padded>
|
|
38
|
+
<CardHeader>
|
|
39
|
+
<CardTitle>Welcome to Canvas</CardTitle>
|
|
40
|
+
</CardHeader>
|
|
41
|
+
<CardContent>
|
|
42
|
+
<Button primary large onPress={() => console.log("saved")}>
|
|
43
|
+
Save
|
|
44
|
+
</Button>
|
|
45
|
+
</CardContent>
|
|
46
|
+
</Card>
|
|
47
|
+
</ThemeProvider>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
41
50
|
```
|
|
42
51
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Toggle themes with HTML attributes:
|
|
52
|
+
The same component tree renders natively on iOS and Android and, through React
|
|
53
|
+
Native Web, in the browser. There is no separate web component set to learn.
|
|
46
54
|
|
|
47
|
-
|
|
48
|
-
<!-- Dark mode -->
|
|
49
|
-
<html class="dark">
|
|
55
|
+
## Semantic boolean props
|
|
50
56
|
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
Styling is done with flat boolean props. Each style choice is its own prop,
|
|
58
|
+
named for the meaning it carries, and passing the prop turns it on. The prop
|
|
59
|
+
name is the value, so the call site reads like natural language ("a primary,
|
|
60
|
+
large button").
|
|
53
61
|
|
|
54
|
-
|
|
55
|
-
<
|
|
62
|
+
```jsx
|
|
63
|
+
<Button primary large>Save</Button>
|
|
64
|
+
<Button destructive>Delete</Button>
|
|
65
|
+
<Button ghost small>Cancel</Button>
|
|
66
|
+
<Card glass>...</Card>
|
|
56
67
|
```
|
|
57
68
|
|
|
58
|
-
|
|
69
|
+
Props are grouped into orthogonal axes (intent, size, surface, density, and
|
|
70
|
+
stacking state/layout flags). Props on different axes combine freely; props
|
|
71
|
+
within one axis are mutually exclusive, so you pass at most one and the
|
|
72
|
+
component resolves any conflict by a fixed precedence.
|
|
59
73
|
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
toggleTheme(); // switches between light/dark
|
|
64
|
-
setSurface("glass"); // enables glass surface
|
|
65
|
-
setDensity("compact"); // switches to compact density
|
|
74
|
+
```jsx
|
|
75
|
+
// Four props from four axes, all applied together.
|
|
76
|
+
<Button primary large loading block>Save</Button>
|
|
66
77
|
```
|
|
67
78
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
- **4 JS utilities**: theme switching, token access, class composition
|
|
72
|
-
- **5 cascade layers**: reset, tokens, base, components, patterns
|
|
73
|
-
- **45 component styles**: buttons, cards, tables, forms, dialogs, and more
|
|
74
|
-
- **Light/dark mode**, glass surface, compact/comfy density
|
|
75
|
-
- **WCAG AA** color contrast compliance
|
|
76
|
-
- **prefers-reduced-motion** and **prefers-contrast** support
|
|
79
|
+
String-valued enum props such as `variant="primary"`, `size="lg"`, or
|
|
80
|
+
`tone="destructive"` are not part of the API and are not accepted. The boolean
|
|
81
|
+
form is the only styling surface.
|
|
77
82
|
|
|
78
|
-
##
|
|
83
|
+
## Theming
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
- [Migration Guide (v2 to v3)](docs/migration.md)
|
|
84
|
-
- [Consumer Integration](docs/integration.md)
|
|
85
|
-
- [Browser Support](docs/browser-support.md)
|
|
85
|
+
`ThemeProvider` reads the OS color scheme by default and exposes the resolved
|
|
86
|
+
tokens to every Canvas component through `useTheme`. Force a scheme when you
|
|
87
|
+
need to:
|
|
86
88
|
|
|
87
|
-
|
|
89
|
+
```jsx
|
|
90
|
+
<ThemeProvider scheme="dark">
|
|
91
|
+
<App />
|
|
92
|
+
</ThemeProvider>
|
|
93
|
+
```
|
|
88
94
|
|
|
89
|
-
|
|
95
|
+
## What's Included
|
|
90
96
|
|
|
91
|
-
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
-
|
|
97
|
+
- A full component kit: buttons, inputs, cards, tables, tabs, dialogs,
|
|
98
|
+
dropdowns, calendars, charts, sidebars, and more, all exported from
|
|
99
|
+
`@olympusoss/canvas`.
|
|
100
|
+
- The style foundation: design tokens, the theme runtime (`ThemeProvider`,
|
|
101
|
+
`useTheme`), the `useResponsive` / `shadow` / `alpha` helpers, and the raw React
|
|
102
|
+
Native `View` / `Text` / `Pressable` / `Image` / `TextInput` / `ScrollView` primitives.
|
|
103
|
+
- Light and dark color schemes resolved through theme tokens.
|
|
104
|
+
- Desktop-first responsiveness built into every component.
|
|
95
105
|
|
|
96
106
|
## License
|
|
97
107
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olympusoss/canvas",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Universal React Native UI kit styled with Tailwind",
|
|
6
6
|
"main": "./src/index.ts",
|
|
7
7
|
"types": "./src/index.ts",
|
|
8
8
|
"exports": {
|
|
@@ -23,13 +23,10 @@
|
|
|
23
23
|
],
|
|
24
24
|
"scripts": {
|
|
25
25
|
"typecheck": "tsc --noEmit",
|
|
26
|
-
"generate-utilities": "bun scripts/generate-utilities.ts",
|
|
27
26
|
"validate-tokens": "bun scripts/validate-tokens.ts",
|
|
28
27
|
"check-size": "bun scripts/check-size.ts",
|
|
29
28
|
"check-duplicates": "bun scripts/check-duplicates.ts",
|
|
30
|
-
"check-contrast": "bun scripts/check-contrast.ts",
|
|
31
29
|
"screenshots": "bun scripts/capture-screenshots.ts",
|
|
32
|
-
"verify-docs": "bun scripts/verify-docs.ts",
|
|
33
30
|
"changeset": "changeset",
|
|
34
31
|
"version-packages": "changeset version",
|
|
35
32
|
"release": "changeset publish",
|
|
@@ -40,9 +37,18 @@
|
|
|
40
37
|
"registry": "https://registry.npmjs.org",
|
|
41
38
|
"access": "public"
|
|
42
39
|
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"react": ">=18",
|
|
42
|
+
"react-native": ">=0.74",
|
|
43
|
+
"react-native-svg": ">=13"
|
|
44
|
+
},
|
|
43
45
|
"devDependencies": {
|
|
44
46
|
"@changesets/cli": "^2.31.0",
|
|
45
47
|
"@playwright/test": "^1.60.0",
|
|
48
|
+
"@types/react": "^19.2.16",
|
|
49
|
+
"react": "^19.2.7",
|
|
50
|
+
"react-native": "^0.85.3",
|
|
51
|
+
"react-native-svg": "^15",
|
|
46
52
|
"typescript": "^5.8.3"
|
|
47
53
|
}
|
|
48
54
|
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Avatars
|
|
2
|
+
|
|
3
|
+
A photo when the account has one, falling back to two initials on a brand gradient (seeded admin accounts). Sizes scale font proportionally (40% of diameter).
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
<Avatar name="AO" />
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Variants
|
|
12
|
+
|
|
13
|
+
### Variant - stacked
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<View style={{ flexDirection: "row", alignItems: "center" }}>
|
|
17
|
+
<Avatar ring src="/rachel-chen.jpg" name="RC" />
|
|
18
|
+
<Avatar ring src="/liang-bao.jpg" name="LB" style={{ marginLeft: -12 }} />
|
|
19
|
+
<Avatar ring src="/marcus-allen.jpg" name="LB" style={{ marginLeft: -12 }} />
|
|
20
|
+
<Avatar ring src="/kira-tanaka.jpg" name="KT" style={{ marginLeft: -12 }} />
|
|
21
|
+
</View>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Variant - topbar
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
<Dropdown items={[
|
|
28
|
+
{ label: "Your profile", icon: "👤" },
|
|
29
|
+
{ label: "Settings", icon: "⚙" },
|
|
30
|
+
{ label: "Sign out", icon: "↩", separatorBefore: true }
|
|
31
|
+
]}>
|
|
32
|
+
<View style={{ flexDirection: "row", alignItems: "center", gap: 8, borderRadius: 9999, borderWidth: 1, borderColor: tokens.border, backgroundColor: tokens.card, paddingVertical: 4, paddingLeft: 4, paddingRight: 10 }}>
|
|
33
|
+
<Avatar small src="/marcus-allen.jpg" name="MA" />
|
|
34
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground }}>admin@example.com</Text>
|
|
35
|
+
<Icon chevronDown muted size={12} />
|
|
36
|
+
</View>
|
|
37
|
+
</Dropdown>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Variant - identity
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
<View style={{ flexDirection: "row", alignItems: "center", gap: 16 }}>
|
|
44
|
+
<Avatar src="/rachel-chen.jpg" name="RC" />
|
|
45
|
+
<View>
|
|
46
|
+
<Text style={{ fontSize: 16, lineHeight: 24, fontWeight: "600", color: tokens.foreground }}>Rachel Chen</Text>
|
|
47
|
+
<Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>rachel.chen@example.com</Text>
|
|
48
|
+
</View>
|
|
49
|
+
</View>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Variant - menu
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
<View style={{ flexDirection: "row", alignItems: "center", gap: 12, borderBottomWidth: 1, borderColor: tokens.border, paddingBottom: 12 }}>
|
|
56
|
+
<Avatar src="/ada-lovelace.jpg" name="AL" />
|
|
57
|
+
<View>
|
|
58
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "600", color: tokens.foreground }}>Ada Lovelace</Text>
|
|
59
|
+
<Text style={{ fontSize: 12, lineHeight: 16, color: tokens["muted-foreground"] }}>admin@example.com</Text>
|
|
60
|
+
</View>
|
|
61
|
+
</View>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Ring outline
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
<Avatar ring name="AO" />
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Do & Don't
|
|
71
|
+
|
|
72
|
+
### Single
|
|
73
|
+
|
|
74
|
+
**Do** — One or two initials, sized about 40% of the diameter.
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
<Avatar name="AO" />
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Don't** — Cramming in a full set of initials shrinks the type and crowds the circle.
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
<View style={{ flexShrink: 0, alignItems: "center", justifyContent: "center", overflow: "hidden", backgroundColor: tokens.muted, width: 40, height: 40, borderRadius: 9999 }}>
|
|
84
|
+
<Text style={{ fontWeight: "500", color: tokens["muted-foreground"], fontSize: 12 }}>ABCD</Text>
|
|
85
|
+
</View>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Stacked
|
|
89
|
+
|
|
90
|
+
**Do** — Cap the stack and summarize the rest with a +N count.
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<View style={{ flexDirection: "row", alignItems: "center" }}>
|
|
94
|
+
<Avatar small ring name="AO" />
|
|
95
|
+
<Avatar small ring name="RC" style={{ marginLeft: -10 }} />
|
|
96
|
+
<Avatar small ring name="LB" style={{ marginLeft: -10 }} />
|
|
97
|
+
<Avatar small ring name="KT" style={{ marginLeft: -10 }} />
|
|
98
|
+
<Text style={{ marginLeft: 6, fontSize: 12, lineHeight: 16, color: tokens["muted-foreground"] }}>+12</Text>
|
|
99
|
+
</View>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Don't** — An unbounded stack runs off the row and stops being scannable.
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
<View style={{ flexDirection: "row", alignItems: "center" }}>
|
|
106
|
+
<Avatar small ring name="AO" />
|
|
107
|
+
<Avatar small ring name="RC" style={{ marginLeft: -10 }} />
|
|
108
|
+
<Avatar small ring name="LB" style={{ marginLeft: -10 }} />
|
|
109
|
+
<Avatar small ring name="KT" style={{ marginLeft: -10 }} />
|
|
110
|
+
<Avatar small ring name="JD" style={{ marginLeft: -10 }} />
|
|
111
|
+
<Avatar small ring name="MA" style={{ marginLeft: -10 }} />
|
|
112
|
+
<Avatar small ring name="AL" style={{ marginLeft: -10 }} />
|
|
113
|
+
<Avatar small ring name="SK" style={{ marginLeft: -10 }} />
|
|
114
|
+
</View>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Topbar account menu
|
|
118
|
+
|
|
119
|
+
**Do** — Pair it with the account name and a chevron so it reads as a trigger.
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
<View style={{ flexDirection: "row", alignItems: "center", gap: 8, borderRadius: 9999, borderWidth: 1, borderColor: tokens.border, backgroundColor: tokens.card, paddingVertical: 4, paddingLeft: 4, paddingRight: 10 }}>
|
|
123
|
+
<Avatar small src="/marcus-allen.jpg" name="MA" />
|
|
124
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "500", color: tokens.foreground }}>admin@example.com</Text>
|
|
125
|
+
<Icon chevronDown muted size={12} />
|
|
126
|
+
</View>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Don't** — A lone avatar gives no hint that it opens the account menu.
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
<Avatar small src="/marcus-allen.jpg" name="MA" />
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Identity
|
|
136
|
+
|
|
137
|
+
**Do** — Name primary; email muted and secondary.
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
<View style={{ flexDirection: "row", alignItems: "center", gap: 16 }}>
|
|
141
|
+
<Avatar src="/rachel-chen.jpg" name="RC" />
|
|
142
|
+
<View>
|
|
143
|
+
<Text style={{ fontSize: 16, lineHeight: 24, fontWeight: "600", color: tokens.foreground }}>Rachel Chen</Text>
|
|
144
|
+
<Text style={{ fontSize: 14, lineHeight: 20, color: tokens["muted-foreground"] }}>rachel.chen@example.com</Text>
|
|
145
|
+
</View>
|
|
146
|
+
</View>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Don't** — Equal weight on the name and email flattens the hierarchy.
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
<View style={{ flexDirection: "row", alignItems: "center", gap: 16 }}>
|
|
153
|
+
<Avatar src="/rachel-chen.jpg" name="RC" />
|
|
154
|
+
<View>
|
|
155
|
+
<Text style={{ fontSize: 14, lineHeight: 20, color: tokens.foreground }}>Rachel Chen</Text>
|
|
156
|
+
<Text style={{ fontSize: 14, lineHeight: 20, color: tokens.foreground }}>rachel.chen@example.com</Text>
|
|
157
|
+
</View>
|
|
158
|
+
</View>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Menu header
|
|
162
|
+
|
|
163
|
+
**Do** — Keep one consistent circular avatar shape across contexts.
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
<View style={{ flexDirection: "row", alignItems: "center", gap: 12 }}>
|
|
167
|
+
<Avatar src="/ada-lovelace.jpg" name="AL" />
|
|
168
|
+
<View>
|
|
169
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "600", color: tokens.foreground }}>Ada Lovelace</Text>
|
|
170
|
+
<Text style={{ fontSize: 12, lineHeight: 16, color: tokens["muted-foreground"] }}>admin@example.com</Text>
|
|
171
|
+
</View>
|
|
172
|
+
</View>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**Don't** — Squaring the avatar here clashes with the circular avatars everywhere else.
|
|
176
|
+
|
|
177
|
+
```tsx
|
|
178
|
+
<View style={{ flexDirection: "row", alignItems: "center", gap: 12 }}>
|
|
179
|
+
<Avatar rounded src="/ada-lovelace.jpg" name="AL" />
|
|
180
|
+
<View>
|
|
181
|
+
<Text style={{ fontSize: 14, lineHeight: 20, fontWeight: "600", color: tokens.foreground }}>Ada Lovelace</Text>
|
|
182
|
+
<Text style={{ fontSize: 12, lineHeight: 16, color: tokens["muted-foreground"] }}>admin@example.com</Text>
|
|
183
|
+
</View>
|
|
184
|
+
</View>
|
|
185
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type ViewStyle, type TextStyle, type ImageStyle } from "react-native";
|
|
2
|
+
import { type ColorTokens } from "../../style/index.js";
|
|
3
|
+
|
|
4
|
+
// Co-located Avatar styles. Diameter per size, corner radius per shape, and the
|
|
5
|
+
// muted fallback surface, all built from the active tokens.
|
|
6
|
+
|
|
7
|
+
export type Size = "small" | "default" | "large";
|
|
8
|
+
export type Shape = "circle" | "rounded";
|
|
9
|
+
|
|
10
|
+
// Diameter per size: small is the inline topbar/stack size, default the 40px row
|
|
11
|
+
// avatar, large the identity-header size.
|
|
12
|
+
const BOX: Record<Size, number> = { small: 28, default: 40, large: 48 };
|
|
13
|
+
|
|
14
|
+
// Circle by default; the rounded square uses the card/menu radius.
|
|
15
|
+
const RADIUS: Record<Shape, number> = { circle: 9999, rounded: 6 };
|
|
16
|
+
|
|
17
|
+
// Initials type per size, ~40% of the diameter.
|
|
18
|
+
const LABEL_SIZE: Record<Size, { fontSize: number; lineHeight: number }> = {
|
|
19
|
+
small: { fontSize: 12, lineHeight: 16 },
|
|
20
|
+
default: { fontSize: 16, lineHeight: 24 },
|
|
21
|
+
large: { fontSize: 18, lineHeight: 28 },
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function container(tokens: ColorTokens, size: Size, shape: Shape, ring: boolean): ViewStyle {
|
|
25
|
+
return {
|
|
26
|
+
flexShrink: 0,
|
|
27
|
+
alignItems: "center",
|
|
28
|
+
justifyContent: "center",
|
|
29
|
+
overflow: "hidden",
|
|
30
|
+
backgroundColor: tokens.muted,
|
|
31
|
+
width: BOX[size],
|
|
32
|
+
height: BOX[size],
|
|
33
|
+
borderRadius: RADIUS[shape],
|
|
34
|
+
// No ring-* equivalent in RN; a 2px background-colored border is the stand-in
|
|
35
|
+
// for ring-2 ring-background, the separator outline used when avatars overlap.
|
|
36
|
+
...(ring ? { borderWidth: 2, borderColor: tokens.background } : null),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The photo fills the container exactly; the parent's overflow-hidden clips it
|
|
41
|
+
// to the circle (RN clips children to a parent's borderRadius).
|
|
42
|
+
export function image(shape: Shape): ImageStyle {
|
|
43
|
+
return { width: "100%", height: "100%", borderRadius: RADIUS[shape] };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function label(tokens: ColorTokens, size: Size): TextStyle {
|
|
47
|
+
return { fontWeight: "500", color: tokens["muted-foreground"], ...LABEL_SIZE[size] };
|
|
48
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { View, Image, Pressable, Text, useTheme, type StyleProp, type ViewStyle } from "../../style/index.js";
|
|
3
|
+
import * as s from "./avatar.styles.js";
|
|
4
|
+
import { type Size, type Shape } from "./avatar.styles.js";
|
|
5
|
+
|
|
6
|
+
// The avatar shows an account's photo when it has one, falling back to one or
|
|
7
|
+
// two initials on a muted surface. It is a circle by default (the consistent
|
|
8
|
+
// shape across topbars, identity rows, and menus), optionally a rounded square.
|
|
9
|
+
//
|
|
10
|
+
// Boolean-prop API: one boolean per option, grouped by axis, first-match
|
|
11
|
+
// precedence within an axis (mirrors Button's intentOf). Size picks the
|
|
12
|
+
// diameter and proportional type (~40% of the diameter); shape switches the
|
|
13
|
+
// corner radius; `ring` draws the separator outline used when avatars overlap
|
|
14
|
+
// in a stack.
|
|
15
|
+
|
|
16
|
+
export interface AvatarProps {
|
|
17
|
+
/** Photo URL. When set, the image fills the circle and the fallback is hidden. */
|
|
18
|
+
src?: string;
|
|
19
|
+
/** Alias for `src`, for callers that think in terms of a native image uri. */
|
|
20
|
+
uri?: string;
|
|
21
|
+
/** Initials fallback shown when there is no photo (e.g. "AO"). */
|
|
22
|
+
name?: string;
|
|
23
|
+
/** Same as `name`; the rendered initials when no photo is supplied. */
|
|
24
|
+
children?: ReactNode;
|
|
25
|
+
// Size (pick one; default is the 40px row avatar).
|
|
26
|
+
small?: boolean;
|
|
27
|
+
large?: boolean;
|
|
28
|
+
// Shape (pick one; default is a circle).
|
|
29
|
+
circle?: boolean;
|
|
30
|
+
rounded?: boolean;
|
|
31
|
+
/** Separator outline, for avatars that overlap in a stack. */
|
|
32
|
+
ring?: boolean;
|
|
33
|
+
/** When set, the avatar becomes pressable (e.g. a topbar account trigger). */
|
|
34
|
+
onPress?: () => void;
|
|
35
|
+
/** Escape hatch for layout/positioning composition (e.g. negative margin to overlap in a stack). */
|
|
36
|
+
style?: StyleProp<ViewStyle>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Size precedence when more than one is passed: first match wins.
|
|
40
|
+
function sizeOf(p: AvatarProps): Size {
|
|
41
|
+
if (p.small) return "small";
|
|
42
|
+
if (p.large) return "large";
|
|
43
|
+
return "default";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Shape precedence when more than one is passed: first match wins.
|
|
47
|
+
function shapeOf(p: AvatarProps): Shape {
|
|
48
|
+
if (p.circle) return "circle";
|
|
49
|
+
if (p.rounded) return "rounded";
|
|
50
|
+
return "circle";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Reduce a name or label to one or two initials ("Rachel Chen" -> "RC", "AO" ->
|
|
54
|
+
// "AO"), so callers can pass either a full name or ready-made initials.
|
|
55
|
+
function initialsFrom(text: string): string {
|
|
56
|
+
const parts = text.trim().split(/\s+/).filter(Boolean);
|
|
57
|
+
if (parts.length === 0) return "";
|
|
58
|
+
if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
|
|
59
|
+
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function Avatar(props: AvatarProps) {
|
|
63
|
+
const { src, uri, name, children, ring, onPress, style } = props;
|
|
64
|
+
const { tokens } = useTheme();
|
|
65
|
+
const size = sizeOf(props);
|
|
66
|
+
const shape = shapeOf(props);
|
|
67
|
+
const photo = src ?? uri;
|
|
68
|
+
|
|
69
|
+
const container: StyleProp<ViewStyle> = [s.container(tokens, size, shape, !!ring), style];
|
|
70
|
+
|
|
71
|
+
let inner: ReactNode;
|
|
72
|
+
if (photo) {
|
|
73
|
+
inner = (
|
|
74
|
+
<Image
|
|
75
|
+
style={s.image(shape)}
|
|
76
|
+
source={{ uri: photo }}
|
|
77
|
+
accessibilityLabel={name}
|
|
78
|
+
resizeMode="cover"
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
} else {
|
|
82
|
+
const source = name ?? (typeof children === "string" ? children : "");
|
|
83
|
+
const initials = source ? initialsFrom(source) : "";
|
|
84
|
+
inner = initials ? <Text style={s.label(tokens, size)}>{initials}</Text> : null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (onPress) {
|
|
88
|
+
return (
|
|
89
|
+
<Pressable
|
|
90
|
+
style={({ pressed }) => [container, pressed ? { opacity: 0.9 } : null]}
|
|
91
|
+
onPress={onPress}
|
|
92
|
+
accessibilityRole="button"
|
|
93
|
+
>
|
|
94
|
+
{inner}
|
|
95
|
+
</Pressable>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
return <View style={container}>{inner}</View>;
|
|
99
|
+
}
|