zero-to-app 2.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 +929 -0
- package/dist/brand/brandConfig.d.ts +48 -0
- package/dist/brand/brandConfig.d.ts.map +1 -0
- package/dist/brand/brandConfig.js +41 -0
- package/dist/brand/brandConfig.js.map +1 -0
- package/dist/brand/brandContext.d.ts +10 -0
- package/dist/brand/brandContext.d.ts.map +1 -0
- package/dist/brand/brandContext.js +16 -0
- package/dist/brand/brandContext.js.map +1 -0
- package/dist/brand/brandTypes.d.ts +54 -0
- package/dist/brand/brandTypes.d.ts.map +1 -0
- package/dist/brand/brandTypes.js +2 -0
- package/dist/brand/brandTypes.js.map +1 -0
- package/dist/brand/index.d.ts +4 -0
- package/dist/brand/index.d.ts.map +1 -0
- package/dist/brand/index.js +5 -0
- package/dist/brand/index.js.map +1 -0
- package/dist/components/action/ActionRow.d.ts +25 -0
- package/dist/components/action/ActionRow.d.ts.map +1 -0
- package/dist/components/action/ActionRow.js +66 -0
- package/dist/components/action/ActionRow.js.map +1 -0
- package/dist/components/action/index.d.ts +2 -0
- package/dist/components/action/index.d.ts.map +1 -0
- package/dist/components/action/index.js +3 -0
- package/dist/components/action/index.js.map +1 -0
- package/dist/components/card/Card.d.ts +11 -0
- package/dist/components/card/Card.d.ts.map +1 -0
- package/dist/components/card/Card.js +32 -0
- package/dist/components/card/Card.js.map +1 -0
- package/dist/components/card/index.d.ts +2 -0
- package/dist/components/card/index.d.ts.map +1 -0
- package/dist/components/card/index.js +2 -0
- package/dist/components/card/index.js.map +1 -0
- package/dist/components/chat/ChatContainer.d.ts +27 -0
- package/dist/components/chat/ChatContainer.d.ts.map +1 -0
- package/dist/components/chat/ChatContainer.js +52 -0
- package/dist/components/chat/ChatContainer.js.map +1 -0
- package/dist/components/chat/ChatInput.d.ts +9 -0
- package/dist/components/chat/ChatInput.d.ts.map +1 -0
- package/dist/components/chat/ChatInput.js +219 -0
- package/dist/components/chat/ChatInput.js.map +1 -0
- package/dist/components/chat/ChatMessages.d.ts +9 -0
- package/dist/components/chat/ChatMessages.d.ts.map +1 -0
- package/dist/components/chat/ChatMessages.js +35 -0
- package/dist/components/chat/ChatMessages.js.map +1 -0
- package/dist/components/chat/EmptyChat.d.ts +18 -0
- package/dist/components/chat/EmptyChat.d.ts.map +1 -0
- package/dist/components/chat/EmptyChat.js +64 -0
- package/dist/components/chat/EmptyChat.js.map +1 -0
- package/dist/components/chat/Message.d.ts +8 -0
- package/dist/components/chat/Message.d.ts.map +1 -0
- package/dist/components/chat/Message.js +47 -0
- package/dist/components/chat/Message.js.map +1 -0
- package/dist/components/chat/index.d.ts +6 -0
- package/dist/components/chat/index.d.ts.map +1 -0
- package/dist/components/chat/index.js +7 -0
- package/dist/components/chat/index.js.map +1 -0
- package/dist/components/chat/types.d.ts +34 -0
- package/dist/components/chat/types.d.ts.map +1 -0
- package/dist/components/chat/types.js +2 -0
- package/dist/components/chat/types.js.map +1 -0
- package/dist/components/form/DropDownSelect.d.ts +12 -0
- package/dist/components/form/DropDownSelect.d.ts.map +1 -0
- package/dist/components/form/DropDownSelect.js +63 -0
- package/dist/components/form/DropDownSelect.js.map +1 -0
- package/dist/components/form/EmailSubscriptionForm.d.ts +14 -0
- package/dist/components/form/EmailSubscriptionForm.d.ts.map +1 -0
- package/dist/components/form/EmailSubscriptionForm.js +58 -0
- package/dist/components/form/EmailSubscriptionForm.js.map +1 -0
- package/dist/components/form/FormErrors.d.ts +7 -0
- package/dist/components/form/FormErrors.d.ts.map +1 -0
- package/dist/components/form/FormErrors.js +35 -0
- package/dist/components/form/FormErrors.js.map +1 -0
- package/dist/components/form/FormInput.d.ts +14 -0
- package/dist/components/form/FormInput.d.ts.map +1 -0
- package/dist/components/form/FormInput.js +35 -0
- package/dist/components/form/FormInput.js.map +1 -0
- package/dist/components/form/FormSeparator.d.ts +6 -0
- package/dist/components/form/FormSeparator.d.ts.map +1 -0
- package/dist/components/form/FormSeparator.js +25 -0
- package/dist/components/form/FormSeparator.js.map +1 -0
- package/dist/components/form/index.d.ts +6 -0
- package/dist/components/form/index.d.ts.map +1 -0
- package/dist/components/form/index.js +7 -0
- package/dist/components/form/index.js.map +1 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +12 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/layout/Footer.d.ts +3 -0
- package/dist/components/layout/Footer.d.ts.map +1 -0
- package/dist/components/layout/Footer.js +60 -0
- package/dist/components/layout/Footer.js.map +1 -0
- package/dist/components/layout/MinimalFooter.d.ts +8 -0
- package/dist/components/layout/MinimalFooter.d.ts.map +1 -0
- package/dist/components/layout/MinimalFooter.js +57 -0
- package/dist/components/layout/MinimalFooter.js.map +1 -0
- package/dist/components/layout/MobileFooterBar.d.ts +7 -0
- package/dist/components/layout/MobileFooterBar.d.ts.map +1 -0
- package/dist/components/layout/MobileFooterBar.js +18 -0
- package/dist/components/layout/MobileFooterBar.js.map +1 -0
- package/dist/components/layout/ParallaxScrollView.d.ts +11 -0
- package/dist/components/layout/ParallaxScrollView.d.ts.map +1 -0
- package/dist/components/layout/ParallaxScrollView.js +67 -0
- package/dist/components/layout/ParallaxScrollView.js.map +1 -0
- package/dist/components/layout/WebPageLayout.d.ts +17 -0
- package/dist/components/layout/WebPageLayout.d.ts.map +1 -0
- package/dist/components/layout/WebPageLayout.js +103 -0
- package/dist/components/layout/WebPageLayout.js.map +1 -0
- package/dist/components/layout/index.d.ts +6 -0
- package/dist/components/layout/index.d.ts.map +1 -0
- package/dist/components/layout/index.js +9 -0
- package/dist/components/layout/index.js.map +1 -0
- package/dist/components/list/List.d.ts +10 -0
- package/dist/components/list/List.d.ts.map +1 -0
- package/dist/components/list/List.js +18 -0
- package/dist/components/list/List.js.map +1 -0
- package/dist/components/list/ListButton.d.ts +13 -0
- package/dist/components/list/ListButton.d.ts.map +1 -0
- package/dist/components/list/ListButton.js +24 -0
- package/dist/components/list/ListButton.js.map +1 -0
- package/dist/components/list/ListDivider.d.ts +7 -0
- package/dist/components/list/ListDivider.d.ts.map +1 -0
- package/dist/components/list/ListDivider.js +23 -0
- package/dist/components/list/ListDivider.js.map +1 -0
- package/dist/components/list/index.d.ts +4 -0
- package/dist/components/list/index.d.ts.map +1 -0
- package/dist/components/list/index.js +4 -0
- package/dist/components/list/index.js.map +1 -0
- package/dist/components/media/Carousel.d.ts +18 -0
- package/dist/components/media/Carousel.d.ts.map +1 -0
- package/dist/components/media/Carousel.js +60 -0
- package/dist/components/media/Carousel.js.map +1 -0
- package/dist/components/media/FeatureCard.d.ts +9 -0
- package/dist/components/media/FeatureCard.d.ts.map +1 -0
- package/dist/components/media/FeatureCard.js +68 -0
- package/dist/components/media/FeatureCard.js.map +1 -0
- package/dist/components/media/HorizontalCarousel.d.ts +17 -0
- package/dist/components/media/HorizontalCarousel.d.ts.map +1 -0
- package/dist/components/media/HorizontalCarousel.js +60 -0
- package/dist/components/media/HorizontalCarousel.js.map +1 -0
- package/dist/components/media/ImageCarousel.d.ts +14 -0
- package/dist/components/media/ImageCarousel.d.ts.map +1 -0
- package/dist/components/media/ImageCarousel.js +21 -0
- package/dist/components/media/ImageCarousel.js.map +1 -0
- package/dist/components/media/MediaTile.d.ts +30 -0
- package/dist/components/media/MediaTile.d.ts.map +1 -0
- package/dist/components/media/MediaTile.js +51 -0
- package/dist/components/media/MediaTile.js.map +1 -0
- package/dist/components/media/SkeletonMediaTile.d.ts +17 -0
- package/dist/components/media/SkeletonMediaTile.d.ts.map +1 -0
- package/dist/components/media/SkeletonMediaTile.js +67 -0
- package/dist/components/media/SkeletonMediaTile.js.map +1 -0
- package/dist/components/media/index.d.ts +7 -0
- package/dist/components/media/index.d.ts.map +1 -0
- package/dist/components/media/index.js +8 -0
- package/dist/components/media/index.js.map +1 -0
- package/dist/components/navigation/AppbarWeb.d.ts +18 -0
- package/dist/components/navigation/AppbarWeb.d.ts.map +1 -0
- package/dist/components/navigation/AppbarWeb.js +70 -0
- package/dist/components/navigation/AppbarWeb.js.map +1 -0
- package/dist/components/navigation/IconButtonGroup.d.ts +7 -0
- package/dist/components/navigation/IconButtonGroup.d.ts.map +1 -0
- package/dist/components/navigation/IconButtonGroup.js +33 -0
- package/dist/components/navigation/IconButtonGroup.js.map +1 -0
- package/dist/components/navigation/Logo.d.ts +16 -0
- package/dist/components/navigation/Logo.d.ts.map +1 -0
- package/dist/components/navigation/Logo.js +64 -0
- package/dist/components/navigation/Logo.js.map +1 -0
- package/dist/components/navigation/MobileMenuDrawer.d.ts +13 -0
- package/dist/components/navigation/MobileMenuDrawer.d.ts.map +1 -0
- package/dist/components/navigation/MobileMenuDrawer.js +184 -0
- package/dist/components/navigation/MobileMenuDrawer.js.map +1 -0
- package/dist/components/navigation/ScreenHeader.d.ts +30 -0
- package/dist/components/navigation/ScreenHeader.d.ts.map +1 -0
- package/dist/components/navigation/ScreenHeader.js +127 -0
- package/dist/components/navigation/ScreenHeader.js.map +1 -0
- package/dist/components/navigation/iconUtils.d.ts +24 -0
- package/dist/components/navigation/iconUtils.d.ts.map +1 -0
- package/dist/components/navigation/iconUtils.js +53 -0
- package/dist/components/navigation/iconUtils.js.map +1 -0
- package/dist/components/navigation/index.d.ts +6 -0
- package/dist/components/navigation/index.d.ts.map +1 -0
- package/dist/components/navigation/index.js +7 -0
- package/dist/components/navigation/index.js.map +1 -0
- package/dist/components/tile/Tile.d.ts +18 -0
- package/dist/components/tile/Tile.d.ts.map +1 -0
- package/dist/components/tile/Tile.js +41 -0
- package/dist/components/tile/Tile.js.map +1 -0
- package/dist/components/tile/index.d.ts +2 -0
- package/dist/components/tile/index.d.ts.map +1 -0
- package/dist/components/tile/index.js +2 -0
- package/dist/components/tile/index.js.map +1 -0
- package/dist/components/ui/ArrowButton.d.ts +8 -0
- package/dist/components/ui/ArrowButton.d.ts.map +1 -0
- package/dist/components/ui/ArrowButton.js +30 -0
- package/dist/components/ui/ArrowButton.js.map +1 -0
- package/dist/components/ui/BlurButton.d.ts +16 -0
- package/dist/components/ui/BlurButton.d.ts.map +1 -0
- package/dist/components/ui/BlurButton.js +26 -0
- package/dist/components/ui/BlurButton.js.map +1 -0
- package/dist/components/ui/Button.d.ts +24 -0
- package/dist/components/ui/Button.d.ts.map +1 -0
- package/dist/components/ui/Button.js +60 -0
- package/dist/components/ui/Button.js.map +1 -0
- package/dist/components/ui/ErrorBoundary.d.ts +18 -0
- package/dist/components/ui/ErrorBoundary.d.ts.map +1 -0
- package/dist/components/ui/ErrorBoundary.js +37 -0
- package/dist/components/ui/ErrorBoundary.js.map +1 -0
- package/dist/components/ui/IconButton.d.ts +13 -0
- package/dist/components/ui/IconButton.d.ts.map +1 -0
- package/dist/components/ui/IconButton.js +27 -0
- package/dist/components/ui/IconButton.js.map +1 -0
- package/dist/components/ui/LoadingIndicator.d.ts +6 -0
- package/dist/components/ui/LoadingIndicator.d.ts.map +1 -0
- package/dist/components/ui/LoadingIndicator.js +15 -0
- package/dist/components/ui/LoadingIndicator.js.map +1 -0
- package/dist/components/ui/NotificationBadge.d.ts +8 -0
- package/dist/components/ui/NotificationBadge.d.ts.map +1 -0
- package/dist/components/ui/NotificationBadge.js +24 -0
- package/dist/components/ui/NotificationBadge.js.map +1 -0
- package/dist/components/ui/SkeletonCard.d.ts +14 -0
- package/dist/components/ui/SkeletonCard.d.ts.map +1 -0
- package/dist/components/ui/SkeletonCard.js +50 -0
- package/dist/components/ui/SkeletonCard.js.map +1 -0
- package/dist/components/ui/StyledText.d.ts +17 -0
- package/dist/components/ui/StyledText.d.ts.map +1 -0
- package/dist/components/ui/StyledText.js +27 -0
- package/dist/components/ui/StyledText.js.map +1 -0
- package/dist/components/ui/StyledTextInput.d.ts +10 -0
- package/dist/components/ui/StyledTextInput.d.ts.map +1 -0
- package/dist/components/ui/StyledTextInput.js +62 -0
- package/dist/components/ui/StyledTextInput.js.map +1 -0
- package/dist/components/ui/TextLink.d.ts +14 -0
- package/dist/components/ui/TextLink.d.ts.map +1 -0
- package/dist/components/ui/TextLink.js +25 -0
- package/dist/components/ui/TextLink.js.map +1 -0
- package/dist/components/ui/ToggleIconButton.d.ts +14 -0
- package/dist/components/ui/ToggleIconButton.d.ts.map +1 -0
- package/dist/components/ui/ToggleIconButton.js +19 -0
- package/dist/components/ui/ToggleIconButton.js.map +1 -0
- package/dist/components/ui/index.d.ts +13 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/index.js +14 -0
- package/dist/components/ui/index.js.map +1 -0
- package/dist/context/scrollContext.d.ts +8 -0
- package/dist/context/scrollContext.d.ts.map +1 -0
- package/dist/context/scrollContext.js +16 -0
- package/dist/context/scrollContext.js.map +1 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +5 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useDimensions.d.ts +31 -0
- package/dist/hooks/useDimensions.d.ts.map +1 -0
- package/dist/hooks/useDimensions.js +44 -0
- package/dist/hooks/useDimensions.js.map +1 -0
- package/dist/hooks/useWindowHeight.d.ts +7 -0
- package/dist/hooks/useWindowHeight.d.ts.map +1 -0
- package/dist/hooks/useWindowHeight.js +10 -0
- package/dist/hooks/useWindowHeight.js.map +1 -0
- package/dist/hooks/useWindowWidth.d.ts +20 -0
- package/dist/hooks/useWindowWidth.d.ts.map +1 -0
- package/dist/hooks/useWindowWidth.js +27 -0
- package/dist/hooks/useWindowWidth.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/theme/index.d.ts +3 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +4 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/theme.d.ts +15 -0
- package/dist/theme/theme.d.ts.map +1 -0
- package/dist/theme/theme.js +38 -0
- package/dist/theme/theme.js.map +1 -0
- package/dist/theme/themeConfig.d.ts +19 -0
- package/dist/theme/themeConfig.d.ts.map +1 -0
- package/dist/theme/themeConfig.js +43 -0
- package/dist/theme/themeConfig.js.map +1 -0
- package/package.json +104 -0
package/README.md
ADDED
|
@@ -0,0 +1,929 @@
|
|
|
1
|
+
# zero-to-app Design System
|
|
2
|
+
|
|
3
|
+
## TL;DR
|
|
4
|
+
|
|
5
|
+
React Native design system with theme-aware UI components, responsive utilities, and brand configuration. Exports 30+ components (buttons, inputs, cards, forms, feedback) plus theme context, hooks, and brand tokens. Cross-platform (iOS, Android, Web). Wrap app root with `<ZeroToApp brand={createBrand({...})}>` to enable theming and brand context. All brand values must be provided at app level - no defaults are included. Use `useBrand()` hook to access brand values in components. All exports from `'zero-to-app'`.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { ZeroToApp, createBrand } from 'zero-to-app';
|
|
13
|
+
|
|
14
|
+
export default function Root() {
|
|
15
|
+
// Create your brand configuration - all values are required
|
|
16
|
+
const brand = createBrand({
|
|
17
|
+
name: 'My App',
|
|
18
|
+
colors: {
|
|
19
|
+
primary: '#cc3366',
|
|
20
|
+
secondary: '#cc3366',
|
|
21
|
+
backgroundColor: '#fafafc',
|
|
22
|
+
},
|
|
23
|
+
fontSizes: {
|
|
24
|
+
small: 14,
|
|
25
|
+
medium: 16,
|
|
26
|
+
large: 20,
|
|
27
|
+
xlarge: 25,
|
|
28
|
+
},
|
|
29
|
+
spacing: {
|
|
30
|
+
xs: 4,
|
|
31
|
+
sm: 8,
|
|
32
|
+
md: 12,
|
|
33
|
+
lg: 16,
|
|
34
|
+
xl: 20,
|
|
35
|
+
xxl: 24,
|
|
36
|
+
xxxl: 40,
|
|
37
|
+
},
|
|
38
|
+
borderRadius: 5,
|
|
39
|
+
logo: {
|
|
40
|
+
light: require('./assets/logo-light.png'),
|
|
41
|
+
dark: require('./assets/logo-dark.png'),
|
|
42
|
+
},
|
|
43
|
+
footerLinks: {
|
|
44
|
+
links: [
|
|
45
|
+
{ text: 'Home', route: '/(tabs)/home' },
|
|
46
|
+
{ text: 'About', route: '/(tabs)/about' },
|
|
47
|
+
],
|
|
48
|
+
},
|
|
49
|
+
navigation: {
|
|
50
|
+
items: [
|
|
51
|
+
{
|
|
52
|
+
route: '/(tabs)/home',
|
|
53
|
+
title: 'Home',
|
|
54
|
+
icon: { web: 'home', mobile: 'house' }
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
route: '/(tabs)/about',
|
|
58
|
+
title: 'About',
|
|
59
|
+
icon: { web: 'info', mobile: 'person' }
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<ZeroToApp brand={brand}>
|
|
67
|
+
<App />
|
|
68
|
+
</ZeroToApp>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { StyledText, Button, Card, useDimensions } from 'zero-to-app';
|
|
75
|
+
|
|
76
|
+
function MyComponent() {
|
|
77
|
+
const dimensions = useDimensions();
|
|
78
|
+
return (
|
|
79
|
+
<Card>
|
|
80
|
+
<StyledText fontSize="lg" bold>Welcome</StyledText>
|
|
81
|
+
<Button title="Get Started" onPress={() => {}} />
|
|
82
|
+
</Card>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Migration from Static Brand Import
|
|
90
|
+
|
|
91
|
+
If you're upgrading from an older version that used static brand imports:
|
|
92
|
+
|
|
93
|
+
**Old way (deprecated):**
|
|
94
|
+
```typescript
|
|
95
|
+
import { brand } from 'zero-to-app';
|
|
96
|
+
// Direct access: brand.colors.primary
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**New way (current):**
|
|
100
|
+
```typescript
|
|
101
|
+
import { createBrand, useBrand } from 'zero-to-app';
|
|
102
|
+
|
|
103
|
+
// In root component - all brand values must be provided
|
|
104
|
+
const brand = createBrand({
|
|
105
|
+
name: 'My App',
|
|
106
|
+
colors: { primary: '#ff0000', secondary: '#00ff00', backgroundColor: '#ffffff' },
|
|
107
|
+
fontSizes: { small: 12, medium: 14, large: 18, xlarge: 24 },
|
|
108
|
+
spacing: { xs: 4, sm: 8, md: 12, lg: 16, xl: 20, xxl: 24, xxxl: 40 },
|
|
109
|
+
borderRadius: 8,
|
|
110
|
+
});
|
|
111
|
+
<ZeroToApp brand={brand}>...</ZeroToApp>
|
|
112
|
+
|
|
113
|
+
// In child components
|
|
114
|
+
const brand = useBrand();
|
|
115
|
+
// Access: brand.colors.primary
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
This change makes the design system fully reusable - no embedded brand assumptions. You must provide all brand values at the app level, enabling true white-labeling and multi-brand support.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## File Map
|
|
123
|
+
|
|
124
|
+
| Directory | Purpose |
|
|
125
|
+
|-----------|---------|
|
|
126
|
+
| `brand/` | Brand configuration (colors, fonts, spacing, logos, navigation, footer links) |
|
|
127
|
+
| `theme/` | Theme system (light/dark themes, `ZeroToApp` provider) |
|
|
128
|
+
| `components/` | All components (composite + UI entrypoints) |
|
|
129
|
+
| `components/ui/` | UI components (Text, Button, Input, Feedback) |
|
|
130
|
+
| `hooks/` | Custom hooks (`useDimensions`, `useWindowWidth`, `useWindowHeight`) |
|
|
131
|
+
| `context/` | Scroll context utilities |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Structure and Exports
|
|
136
|
+
|
|
137
|
+
### Module Map
|
|
138
|
+
|
|
139
|
+
- **UI:** `ui` (Button, StyledText, StyledTextInput, ErrorBoundary, etc.)
|
|
140
|
+
- **Composite:** `components/action`, `components/chat`, `components/form`, `components/layout`, `components/media`, `components/navigation`, `components/list`, `components/card`, `components/tile`
|
|
141
|
+
- **Utilities:** `brand`, `theme`, `hooks`, `context`
|
|
142
|
+
|
|
143
|
+
### Import Examples
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import { Button, StyledText } from 'zero-to-app';
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import { Button } from 'zero-to-app/ui/Button';
|
|
151
|
+
import { List, ListButton } from 'zero-to-app/components/list';
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { FeatureCard } from 'zero-to-app/components/media';
|
|
156
|
+
import { AppbarWeb } from 'zero-to-app/components/navigation';
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Component Index
|
|
160
|
+
|
|
161
|
+
### UI Components
|
|
162
|
+
|
|
163
|
+
| Component | Import | Key Props |
|
|
164
|
+
|-----------|--------|-----------|
|
|
165
|
+
| `StyledText` | Named | `fontSize`, `align`, `color`, `bold`, `muted`, `numberOfLines` |
|
|
166
|
+
| `TextLink` | Default | `text`, `href`, `onPress`, `align` |
|
|
167
|
+
| `Button` | Default | `title`, `onPress`, `secondary`, `loading`, `icon`, `iconPosition` |
|
|
168
|
+
| `IconButton` | Default | `iconName`, `onPress`, `color`, `backgroundColor` |
|
|
169
|
+
| `ToggleIconButton` | Default | `iconName`, `alternateIconName`, `onPress`, `raised` |
|
|
170
|
+
| `BlurButton` | Default | `onPress`, `children`, `intensity`, `tint` |
|
|
171
|
+
| `ArrowButton` | Default | `direction`, `onPress`, `hidden` |
|
|
172
|
+
| `StyledTextInput` | Default | `value`, `onChangeText`, `inputHeight`, `onKeyDown` |
|
|
173
|
+
| `LoadingIndicator` | Default | - |
|
|
174
|
+
| `NotificationBadge` | Named | `count`, `maxCount` |
|
|
175
|
+
| `ErrorBoundary` | Default | Standard ErrorBoundary props |
|
|
176
|
+
| `SkeletonCard` | Default | `width`, `imageHeight`, `textLines` |
|
|
177
|
+
|
|
178
|
+
### Composite Components
|
|
179
|
+
|
|
180
|
+
| Component | Import | Category |
|
|
181
|
+
|-----------|--------|----------|
|
|
182
|
+
| `WebPageLayout` | Default | Layout |
|
|
183
|
+
| `ParallaxScrollView` | Default | Layout |
|
|
184
|
+
| `Footer`, `MinimalFooter`, `MobileFooterBar` | Named | Layout |
|
|
185
|
+
| `Card` | Default | Container |
|
|
186
|
+
| `Tile` | Default | Container |
|
|
187
|
+
| `List` | Default | Container |
|
|
188
|
+
| `ListButton` | Default | Container |
|
|
189
|
+
| `ListDivider` | Default | Container |
|
|
190
|
+
| `ScreenHeader` | Named | Navigation |
|
|
191
|
+
| `AppbarWeb` | Default | Navigation |
|
|
192
|
+
| `IconButtonGroup` | Default | Navigation |
|
|
193
|
+
| `Logo` | Default | Navigation |
|
|
194
|
+
| `ImageCarousel` | Named | Media |
|
|
195
|
+
| `FeatureCard` | Default | Media |
|
|
196
|
+
| `HorizontalCarousel` | Named | Media |
|
|
197
|
+
| `Carousel` | Named | Media |
|
|
198
|
+
| `MediaTile` | Named | Media |
|
|
199
|
+
| `SkeletonMediaTile` | Named | Media |
|
|
200
|
+
| `DropDownSelect` | Default | Form |
|
|
201
|
+
| `EmailSubscriptionForm` | Default | Form |
|
|
202
|
+
| `FormInput` | Default | Form |
|
|
203
|
+
| `FormErrors` | Default | Form |
|
|
204
|
+
| `FormSeparator` | Default | Form |
|
|
205
|
+
| `ActionRow` | Named | Action |
|
|
206
|
+
| `ChatContainer` | Default | Chat |
|
|
207
|
+
| `ChatMessages` | Default | Chat |
|
|
208
|
+
| `ChatInput` | Default | Chat |
|
|
209
|
+
| `EmptyChat` | Default | Chat |
|
|
210
|
+
|
|
211
|
+
### Hooks
|
|
212
|
+
|
|
213
|
+
| Hook | Returns | Purpose |
|
|
214
|
+
|------|---------|---------|
|
|
215
|
+
| `useDimensions()` | `{ width, height, breakpoint }` | Responsive dimensions |
|
|
216
|
+
| `useWindowWidth()` | `number` | Window width |
|
|
217
|
+
| `useWindowHeight()` | `number` | Window height |
|
|
218
|
+
| `useBrand()` | `Brand` | Access brand configuration (colors, spacing, fonts, logos) |
|
|
219
|
+
|
|
220
|
+
### Theme & Brand
|
|
221
|
+
|
|
222
|
+
| Export | Type | Purpose |
|
|
223
|
+
|--------|------|---------|
|
|
224
|
+
| `ZeroToApp` | Component | Theme provider (wrap app root, requires `brand` prop) |
|
|
225
|
+
| `ThemeContext` | Context | Access theme values and `toggleTheme()` |
|
|
226
|
+
| `createBrand` | Function | Create brand configuration object |
|
|
227
|
+
| `useBrand` | Hook | Access brand values in components |
|
|
228
|
+
| `BrandProvider` | Component | Brand context provider (used internally) |
|
|
229
|
+
| `breakpoints` | Object | `{ small: 480, medium: 768, large: 1024, xlarge: 1280 }` |
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Theme Quick Reference
|
|
234
|
+
|
|
235
|
+
### Theme Values
|
|
236
|
+
|
|
237
|
+
| Property | Light | Dark |
|
|
238
|
+
|----------|-------|------|
|
|
239
|
+
| `color` | `#000000` | `#FFFFFF` |
|
|
240
|
+
| `backgroundColor` | `#FFFFFF` | `#212121` |
|
|
241
|
+
| `cardBackgroundColor` | `#FFFFFF` | `#181818` |
|
|
242
|
+
| `appbarBackgroundColor` | `#FFFFFF` | `#000000` |
|
|
243
|
+
| `highlightColor` | Brand primary | Brand secondary |
|
|
244
|
+
| `borderColor` | `#dddfe2` | `#424242` |
|
|
245
|
+
| `inactiveIconColor` | `#606770` | `#b0b3b8` |
|
|
246
|
+
| `dividerColor` | `#dddfe2` | `#3e4042` |
|
|
247
|
+
| `iconButtonBackgroundColor` | `#999999` | `#3a3b3c` |
|
|
248
|
+
| `iconButtonIconColor` | `#ffffff` | `#ffffff` |
|
|
249
|
+
| `inputBackgroundColor` | `#ffffff` | `#3a3b3c` |
|
|
250
|
+
| `linkColor` | `#666666` | `#999999` |
|
|
251
|
+
| `isDark` | `false` | `true` |
|
|
252
|
+
|
|
253
|
+
### Usage
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
import { useContext } from 'react';
|
|
257
|
+
import { ThemeContext } from 'zero-to-app';
|
|
258
|
+
|
|
259
|
+
function MyComponent() {
|
|
260
|
+
const theme = useContext(ThemeContext);
|
|
261
|
+
// theme.values.backgroundColor
|
|
262
|
+
// theme.toggleTheme()
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**Default:** Dark mode. Use `theme.toggleTheme()` to switch.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Brand Quick Reference
|
|
271
|
+
|
|
272
|
+
### Brand Configuration
|
|
273
|
+
|
|
274
|
+
Brand configuration is passed to `ZeroToApp` as a prop. Use `createBrand()` to create your brand configuration - **all values are required** (except logo). Use `useBrand()` hook to access brand values in components.
|
|
275
|
+
|
|
276
|
+
**Creating Brand Configuration:**
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
import { createBrand } from 'zero-to-app';
|
|
280
|
+
|
|
281
|
+
// Complete brand configuration required - all values must be provided
|
|
282
|
+
const brand = createBrand({
|
|
283
|
+
name: 'My App',
|
|
284
|
+
colors: {
|
|
285
|
+
primary: '#ff0000',
|
|
286
|
+
secondary: '#00ff00',
|
|
287
|
+
backgroundColor: '#ffffff',
|
|
288
|
+
},
|
|
289
|
+
fontSizes: {
|
|
290
|
+
small: 12,
|
|
291
|
+
medium: 14,
|
|
292
|
+
large: 18,
|
|
293
|
+
xlarge: 24,
|
|
294
|
+
},
|
|
295
|
+
spacing: {
|
|
296
|
+
xs: 4,
|
|
297
|
+
sm: 8,
|
|
298
|
+
md: 12,
|
|
299
|
+
lg: 16,
|
|
300
|
+
xl: 20,
|
|
301
|
+
xxl: 24,
|
|
302
|
+
xxxl: 40,
|
|
303
|
+
},
|
|
304
|
+
borderRadius: 8,
|
|
305
|
+
logo: {
|
|
306
|
+
light: require('./assets/logo-light.png'),
|
|
307
|
+
dark: require('./assets/logo-dark.png'),
|
|
308
|
+
},
|
|
309
|
+
footerLinks: {
|
|
310
|
+
links: [
|
|
311
|
+
{ text: 'Home', route: '/(tabs)/home' },
|
|
312
|
+
{ text: 'About', route: '/(tabs)/about' },
|
|
313
|
+
],
|
|
314
|
+
},
|
|
315
|
+
navigation: {
|
|
316
|
+
items: [
|
|
317
|
+
{
|
|
318
|
+
route: '/(tabs)/home',
|
|
319
|
+
title: 'Home',
|
|
320
|
+
icon: { web: 'home', mobile: 'house' }
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
route: '/(tabs)/about',
|
|
324
|
+
title: 'About',
|
|
325
|
+
icon: { web: 'info', mobile: 'person' }
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
**Navigation Configuration:**
|
|
333
|
+
|
|
334
|
+
Navigation items are configured through brand config and automatically used by navigation components (AppbarWeb, MobileMenuDrawer, mobile tabs). Each navigation item includes:
|
|
335
|
+
|
|
336
|
+
- `route`: Full route path (e.g., `'/(tabs)/home'`)
|
|
337
|
+
- `title`: Display title for the navigation item
|
|
338
|
+
- `icon`: Platform-specific icons with explicit library specification
|
|
339
|
+
|
|
340
|
+
**Icon Configuration:**
|
|
341
|
+
|
|
342
|
+
Icons support both explicit library specification and backward-compatible string format:
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
// Explicit format (recommended)
|
|
346
|
+
icon: {
|
|
347
|
+
web: { library: 'Feather', name: 'home' },
|
|
348
|
+
mobile: { library: 'Feather', name: 'home' } // For Android fallback
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// String format (backward compatible - assumes Feather)
|
|
352
|
+
icon: {
|
|
353
|
+
web: 'home', // Assumes Feather library
|
|
354
|
+
mobile: 'house' // For iOS: SF Symbol name, for Android: assumes Feather
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Available Icon Libraries:**
|
|
359
|
+
- `Feather` (default for web/Android)
|
|
360
|
+
- `MaterialIcons`
|
|
361
|
+
- `Ionicons`
|
|
362
|
+
- `FontAwesome`
|
|
363
|
+
- `AntDesign`
|
|
364
|
+
- `Entypo`
|
|
365
|
+
- `EvilIcons`
|
|
366
|
+
- `Foundation`
|
|
367
|
+
- `MaterialCommunityIcons`
|
|
368
|
+
- `Octicons`
|
|
369
|
+
- `SimpleLineIcons`
|
|
370
|
+
- `Zocial`
|
|
371
|
+
|
|
372
|
+
**Platform-Specific Behavior:**
|
|
373
|
+
- **Web desktop/tablet**: Uses `item.icon.web` with specified library (default: Feather)
|
|
374
|
+
- **Web mobile**: Hamburger menu drawer uses `item.icon.web` with specified library (default: Feather)
|
|
375
|
+
- **iOS native tabs**: Uses `item.icon.mobile` name as SF Symbol (library is ignored - SF Symbols are not from @expo/vector-icons)
|
|
376
|
+
- **Android/fallback tabs**: Uses `item.icon.mobile` or `item.icon.web` with specified library (default: Feather)
|
|
377
|
+
|
|
378
|
+
**Example:**
|
|
379
|
+
```typescript
|
|
380
|
+
navigation: {
|
|
381
|
+
items: [
|
|
382
|
+
{
|
|
383
|
+
route: '/(tabs)/home',
|
|
384
|
+
title: 'Home',
|
|
385
|
+
icon: {
|
|
386
|
+
web: { library: 'Feather', name: 'home' },
|
|
387
|
+
mobile: 'house' // SF Symbol for iOS, or { library: 'Feather', name: 'home' } for Android
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
route: '/(tabs)/settings',
|
|
392
|
+
title: 'Settings',
|
|
393
|
+
icon: {
|
|
394
|
+
web: { library: 'MaterialIcons', name: 'settings' },
|
|
395
|
+
mobile: { library: 'MaterialIcons', name: 'settings' }
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
],
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
If navigation config is not provided, navigation components will not show menu items.
|
|
403
|
+
|
|
404
|
+
**White-Labeling Example:**
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
// Create different brands for different clients/products - all values required
|
|
408
|
+
const enterpriseBrand = createBrand({
|
|
409
|
+
name: 'Enterprise Edition',
|
|
410
|
+
colors: { primary: '#1a1a1a', secondary: '#4a4a4a', backgroundColor: '#ffffff' },
|
|
411
|
+
fontSizes: { small: 12, medium: 14, large: 18, xlarge: 24 },
|
|
412
|
+
spacing: { xs: 4, sm: 8, md: 12, lg: 16, xl: 20, xxl: 24, xxxl: 40 },
|
|
413
|
+
borderRadius: 8, // More corporate look
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
const consumerBrand = createBrand({
|
|
417
|
+
name: 'Consumer App',
|
|
418
|
+
colors: { primary: '#ff6600', secondary: '#ffaa00', backgroundColor: '#fafafc' },
|
|
419
|
+
fontSizes: { small: 14, medium: 16, large: 20, xlarge: 25 },
|
|
420
|
+
spacing: { xs: 4, sm: 8, md: 12, lg: 16, xl: 20, xxl: 24, xxxl: 40 },
|
|
421
|
+
borderRadius: 16, // More playful
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Switch based on user type or configuration
|
|
425
|
+
<ZeroToApp brand={isEnterprise ? enterpriseBrand : consumerBrand}>
|
|
426
|
+
<App />
|
|
427
|
+
</ZeroToApp>
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**Accessing Brand Values in Components:**
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
import { useBrand } from 'zero-to-app';
|
|
434
|
+
|
|
435
|
+
function MyComponent() {
|
|
436
|
+
const brand = useBrand();
|
|
437
|
+
|
|
438
|
+
return (
|
|
439
|
+
<View style={{
|
|
440
|
+
padding: brand.spacing.lg,
|
|
441
|
+
borderRadius: brand.borderRadius,
|
|
442
|
+
backgroundColor: brand.colors.backgroundColor,
|
|
443
|
+
}}>
|
|
444
|
+
<Text style={{ fontSize: brand.fontSizes.large }}>
|
|
445
|
+
{brand.name}
|
|
446
|
+
</Text>
|
|
447
|
+
</View>
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
**Navigation Configuration:**
|
|
453
|
+
|
|
454
|
+
Navigation items are configured through brand config and automatically used by navigation components (AppbarWeb, MobileMenuDrawer, mobile tabs). Each navigation item includes:
|
|
455
|
+
|
|
456
|
+
- `route`: Full route path (e.g., `'/(tabs)/home'`)
|
|
457
|
+
- `title`: Display title for the navigation item
|
|
458
|
+
- `icon`: Platform-specific icons
|
|
459
|
+
- `web`: Feather icon name for web platform
|
|
460
|
+
- `mobile`: SF Symbol name for iOS native tabs, or Feather icon name for Android fallback tabs
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
const brand = createBrand({
|
|
464
|
+
// ... other brand config
|
|
465
|
+
navigation: {
|
|
466
|
+
items: [
|
|
467
|
+
{
|
|
468
|
+
route: '/(tabs)/home',
|
|
469
|
+
title: 'Home',
|
|
470
|
+
icon: {
|
|
471
|
+
web: { library: 'Feather', name: 'home' },
|
|
472
|
+
mobile: 'house' // SF Symbol for iOS, or { library: 'Feather', name: 'home' } for Android
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
route: '/(tabs)/chat',
|
|
477
|
+
title: 'Chat',
|
|
478
|
+
icon: {
|
|
479
|
+
web: { library: 'Feather', name: 'message-circle' },
|
|
480
|
+
mobile: 'message' // SF Symbol for iOS
|
|
481
|
+
}
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
route: '/(tabs)/account',
|
|
485
|
+
title: 'Account',
|
|
486
|
+
icon: {
|
|
487
|
+
web: { library: 'Feather', name: 'user' },
|
|
488
|
+
mobile: 'person' // SF Symbol for iOS
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
],
|
|
492
|
+
},
|
|
493
|
+
});
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
**Icon Configuration Formats:**
|
|
497
|
+
|
|
498
|
+
Icons support both explicit library specification and backward-compatible string format:
|
|
499
|
+
|
|
500
|
+
```typescript
|
|
501
|
+
// Explicit format (recommended)
|
|
502
|
+
icon: {
|
|
503
|
+
web: { library: 'Feather', name: 'home' },
|
|
504
|
+
mobile: { library: 'Feather', name: 'home' } // For Android fallback
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// String format (backward compatible - assumes Feather)
|
|
508
|
+
icon: {
|
|
509
|
+
web: 'home', // Assumes Feather library
|
|
510
|
+
mobile: 'house' // For iOS: SF Symbol name, for Android: assumes Feather
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Mixed format (common pattern)
|
|
514
|
+
icon: {
|
|
515
|
+
web: { library: 'Feather', name: 'home' }, // Explicit for web
|
|
516
|
+
mobile: 'house' // String for iOS SF Symbol
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**Available Icon Libraries:**
|
|
521
|
+
- `Feather` (default for web/Android)
|
|
522
|
+
- `MaterialIcons`, `Ionicons`, `FontAwesome`, `AntDesign`, `Entypo`, `EvilIcons`, `Foundation`, `MaterialCommunityIcons`, `Octicons`, `SimpleLineIcons`, `Zocial`
|
|
523
|
+
|
|
524
|
+
Navigation components automatically use `brand.navigation.items`:
|
|
525
|
+
- **Web desktop/tablet**: Uses `item.icon.web` with specified library (default: Feather)
|
|
526
|
+
- **Web mobile**: Hamburger menu drawer uses `item.icon.web` with specified library (default: Feather)
|
|
527
|
+
- **iOS native tabs**: Uses `item.icon.mobile` name as SF Symbol (library ignored - SF Symbols are not from @expo/vector-icons)
|
|
528
|
+
- **Android/fallback tabs**: Uses `item.icon.mobile` or `item.icon.web` with specified library (default: Feather)
|
|
529
|
+
|
|
530
|
+
If navigation config is not provided, navigation components will not show menu items.
|
|
531
|
+
|
|
532
|
+
**Best Practices:**
|
|
533
|
+
|
|
534
|
+
1. **Create brand config in a shared file at app level:**
|
|
535
|
+
```typescript
|
|
536
|
+
// app/brand.ts
|
|
537
|
+
import { createBrand } from '../zero-to-app';
|
|
538
|
+
|
|
539
|
+
export const appBrand = createBrand({
|
|
540
|
+
name: 'My App',
|
|
541
|
+
colors: { primary: '#cc3366', secondary: '#cc3366', backgroundColor: '#fafafc' },
|
|
542
|
+
fontSizes: { small: 14, medium: 16, large: 20, xlarge: 25 },
|
|
543
|
+
spacing: { xs: 4, sm: 8, md: 12, lg: 16, xl: 20, xxl: 24, xxxl: 40 },
|
|
544
|
+
borderRadius: 5,
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
// app/_layout.tsx
|
|
548
|
+
import { appBrand } from './brand';
|
|
549
|
+
<ZeroToApp brand={appBrand}>...</ZeroToApp>
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
2. **Brand is stable at runtime:** Brand configuration is created once and doesn't change during app execution. This allows for optimal performance.
|
|
553
|
+
|
|
554
|
+
3. **StyleSheet.create() limitation:** Since `StyleSheet.create()` runs at module level, it cannot use hooks. For styles that need brand values, use inline styles instead:
|
|
555
|
+
```typescript
|
|
556
|
+
// ❌ Don't do this - StyleSheet.create() can't use hooks
|
|
557
|
+
const styles = StyleSheet.create({
|
|
558
|
+
container: {
|
|
559
|
+
padding: brand.spacing.xl, // Error: brand is undefined
|
|
560
|
+
},
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
// ✅ Do this - use inline styles with useBrand() hook
|
|
564
|
+
function MyComponent() {
|
|
565
|
+
const brand = useBrand();
|
|
566
|
+
return (
|
|
567
|
+
<View style={{
|
|
568
|
+
padding: brand.spacing.xl,
|
|
569
|
+
borderRadius: brand.borderRadius,
|
|
570
|
+
}}>
|
|
571
|
+
{/* Content */}
|
|
572
|
+
</View>
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
### Brand Properties
|
|
578
|
+
|
|
579
|
+
| Property | Type | Required | Description |
|
|
580
|
+
|----------|------|----------|-------------|
|
|
581
|
+
| `brand.colors.primary` | `string` | Yes | Primary brand color |
|
|
582
|
+
| `brand.colors.secondary` | `string` | Yes | Secondary brand color |
|
|
583
|
+
| `brand.colors.backgroundColor` | `string` | Yes | Background color |
|
|
584
|
+
| `brand.fontSizes.small` | `number` | Yes | Small font size |
|
|
585
|
+
| `brand.fontSizes.medium` | `number` | Yes | Medium font size |
|
|
586
|
+
| `brand.fontSizes.large` | `number` | Yes | Large font size |
|
|
587
|
+
| `brand.fontSizes.xlarge` | `number` | Yes | Extra large font size |
|
|
588
|
+
| `brand.spacing.xs` | `number` | Yes | Extra small spacing |
|
|
589
|
+
| `brand.spacing.sm` | `number` | Yes | Small spacing |
|
|
590
|
+
| `brand.spacing.md` | `number` | Yes | Medium spacing |
|
|
591
|
+
| `brand.spacing.lg` | `number` | Yes | Large spacing |
|
|
592
|
+
| `brand.spacing.xl` | `number` | Yes | Extra large spacing |
|
|
593
|
+
| `brand.spacing.xxl` | `number` | Yes | 2X large spacing |
|
|
594
|
+
| `brand.spacing.xxxl` | `number` | Yes | 3X large spacing |
|
|
595
|
+
| `brand.borderRadius` | `number` | Yes | Border radius |
|
|
596
|
+
| `brand.name` | `string` | Yes | Brand name |
|
|
597
|
+
| `brand.logo.light` | `LogoSource` | No | Light mode logo (optional) |
|
|
598
|
+
| `brand.logo.dark` | `LogoSource` | No | Dark mode logo (optional) |
|
|
599
|
+
| `brand.footerLinks.links` | `FooterLink[]` | No | Footer navigation links (optional) |
|
|
600
|
+
| `brand.navigation.items` | `NavigationItem[]` | No | Navigation menu items (optional) |
|
|
601
|
+
|
|
602
|
+
**Note:** All brand values must be provided when calling `createBrand()`. There are no defaults - this ensures the design system is fully reusable without embedded brand assumptions. Footer links and navigation items are optional - if not provided, those components will not show navigation links.
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
## Responsive Design
|
|
607
|
+
|
|
608
|
+
### Breakpoints
|
|
609
|
+
|
|
610
|
+
| Breakpoint | Width | Use Case |
|
|
611
|
+
|------------|-------|----------|
|
|
612
|
+
| `small` | < 480px | Mobile phones |
|
|
613
|
+
| `medium` | ≥ 768px | Tablets |
|
|
614
|
+
| `large` | ≥ 1024px | Small desktops |
|
|
615
|
+
| `xlarge` | ≥ 1280px | Large desktops |
|
|
616
|
+
|
|
617
|
+
### Usage
|
|
618
|
+
|
|
619
|
+
```typescript
|
|
620
|
+
import { useDimensions, breakpoints, useBrand } from 'zero-to-app';
|
|
621
|
+
|
|
622
|
+
function ResponsiveComponent() {
|
|
623
|
+
const dimensions = useDimensions();
|
|
624
|
+
const brand = useBrand();
|
|
625
|
+
const isDesktop = dimensions.width >= breakpoints.medium;
|
|
626
|
+
|
|
627
|
+
return (
|
|
628
|
+
<View style={{
|
|
629
|
+
padding: isDesktop ? brand.spacing.xxxl : brand.spacing.xl
|
|
630
|
+
}}>
|
|
631
|
+
{/* Content */}
|
|
632
|
+
</View>
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
## Common Patterns
|
|
640
|
+
|
|
641
|
+
### Pattern 1: Form with Validation
|
|
642
|
+
|
|
643
|
+
```typescript
|
|
644
|
+
import { useForm } from 'react-hook-form';
|
|
645
|
+
import { FormInput, FormErrors, Button, Card } from 'zero-to-app';
|
|
646
|
+
|
|
647
|
+
function LoginForm() {
|
|
648
|
+
const { control, handleSubmit, formState: { errors } } = useForm();
|
|
649
|
+
const [formError, setFormError] = useState<string | null>(null);
|
|
650
|
+
|
|
651
|
+
return (
|
|
652
|
+
<Card>
|
|
653
|
+
<FormInput
|
|
654
|
+
control={control}
|
|
655
|
+
name="email"
|
|
656
|
+
placeholder="Email"
|
|
657
|
+
keyboardType="email-address"
|
|
658
|
+
error={errors.email}
|
|
659
|
+
/>
|
|
660
|
+
<FormInput
|
|
661
|
+
control={control}
|
|
662
|
+
name="password"
|
|
663
|
+
placeholder="Password"
|
|
664
|
+
secureTextEntry
|
|
665
|
+
error={errors.password}
|
|
666
|
+
/>
|
|
667
|
+
<FormErrors error={formError} clearError={() => setFormError(null)} />
|
|
668
|
+
<Button title="Login" onPress={handleSubmit(onSubmit)} />
|
|
669
|
+
</Card>
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### Pattern 2: Theme-Aware Styling
|
|
675
|
+
|
|
676
|
+
```typescript
|
|
677
|
+
import { useContext } from 'react';
|
|
678
|
+
import { ThemeContext, useBrand } from 'zero-to-app';
|
|
679
|
+
|
|
680
|
+
function ThemedComponent() {
|
|
681
|
+
const theme = useContext(ThemeContext);
|
|
682
|
+
const brand = useBrand();
|
|
683
|
+
|
|
684
|
+
return (
|
|
685
|
+
<View style={{
|
|
686
|
+
backgroundColor: theme.values.cardBackgroundColor,
|
|
687
|
+
borderColor: theme.values.borderColor,
|
|
688
|
+
padding: brand.spacing.lg,
|
|
689
|
+
borderRadius: brand.borderRadius
|
|
690
|
+
}}>
|
|
691
|
+
<StyledText color={theme.values.highlightColor}>
|
|
692
|
+
Themed Content
|
|
693
|
+
</StyledText>
|
|
694
|
+
</View>
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
### Pattern 3: Button with Icon
|
|
700
|
+
|
|
701
|
+
```typescript
|
|
702
|
+
import { Button, IconButton } from 'zero-to-app';
|
|
703
|
+
|
|
704
|
+
function ButtonExamples() {
|
|
705
|
+
return (
|
|
706
|
+
<>
|
|
707
|
+
<Button
|
|
708
|
+
title="Save"
|
|
709
|
+
icon={{ library: 'Feather', name: 'save', size: 20 }}
|
|
710
|
+
iconPosition="left"
|
|
711
|
+
onPress={handleSave}
|
|
712
|
+
/>
|
|
713
|
+
<IconButton iconName="heart" onPress={handleLike} />
|
|
714
|
+
</>
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
### Pattern 4: Responsive Layout
|
|
720
|
+
|
|
721
|
+
```typescript
|
|
722
|
+
import { useDimensions, breakpoints, useBrand } from 'zero-to-app';
|
|
723
|
+
|
|
724
|
+
function ResponsiveLayout() {
|
|
725
|
+
const dimensions = useDimensions();
|
|
726
|
+
const brand = useBrand();
|
|
727
|
+
const isDesktop = dimensions.width >= breakpoints.medium;
|
|
728
|
+
|
|
729
|
+
return (
|
|
730
|
+
<View style={{
|
|
731
|
+
flexDirection: isDesktop ? 'row' : 'column',
|
|
732
|
+
padding: isDesktop ? brand.spacing.xxxl : brand.spacing.xl,
|
|
733
|
+
gap: brand.spacing.lg
|
|
734
|
+
}}>
|
|
735
|
+
{/* Content */}
|
|
736
|
+
</View>
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
### Pattern 5: List with Actions
|
|
742
|
+
|
|
743
|
+
```typescript
|
|
744
|
+
import { List, ListButton, ListDivider } from 'zero-to-app';
|
|
745
|
+
|
|
746
|
+
function SettingsList() {
|
|
747
|
+
return (
|
|
748
|
+
<List>
|
|
749
|
+
<ListButton text="Profile" icon="user" onPress={openProfile} />
|
|
750
|
+
<ListButton text="Settings" icon="settings" onPress={openSettings} />
|
|
751
|
+
<ListDivider />
|
|
752
|
+
<ListButton text="Logout" icon="log-out" onPress={handleLogout} />
|
|
753
|
+
</List>
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
---
|
|
759
|
+
|
|
760
|
+
## Customization Points
|
|
761
|
+
|
|
762
|
+
### Brand Customization
|
|
763
|
+
|
|
764
|
+
**Brand Configuration is Required**
|
|
765
|
+
All brand values must be provided when calling `createBrand()`. There are no defaults - this ensures the design system is fully reusable without embedded brand assumptions.
|
|
766
|
+
|
|
767
|
+
```typescript
|
|
768
|
+
// Complete brand configuration required
|
|
769
|
+
const brand = createBrand({
|
|
770
|
+
name: 'My App',
|
|
771
|
+
colors: {
|
|
772
|
+
primary: '#ff0000',
|
|
773
|
+
secondary: '#00ff00',
|
|
774
|
+
backgroundColor: '#ffffff',
|
|
775
|
+
},
|
|
776
|
+
fontSizes: {
|
|
777
|
+
small: 12,
|
|
778
|
+
medium: 14,
|
|
779
|
+
large: 18,
|
|
780
|
+
xlarge: 24,
|
|
781
|
+
},
|
|
782
|
+
spacing: {
|
|
783
|
+
xs: 4,
|
|
784
|
+
sm: 8,
|
|
785
|
+
md: 12,
|
|
786
|
+
lg: 16,
|
|
787
|
+
xl: 20,
|
|
788
|
+
xxl: 24,
|
|
789
|
+
xxxl: 40,
|
|
790
|
+
},
|
|
791
|
+
borderRadius: 8,
|
|
792
|
+
logo: {
|
|
793
|
+
light: require('./assets/logo-light.png'),
|
|
794
|
+
dark: require('./assets/logo-dark.png'),
|
|
795
|
+
},
|
|
796
|
+
});
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
**White-Labeling Support:**
|
|
800
|
+
Create different brands for different clients/products - each must provide all values:
|
|
801
|
+
```typescript
|
|
802
|
+
// Client A brand - all values required
|
|
803
|
+
const clientABrand = createBrand({
|
|
804
|
+
name: 'Client A App',
|
|
805
|
+
colors: { primary: '#ff0000', secondary: '#00ff00', backgroundColor: '#ffffff' },
|
|
806
|
+
fontSizes: { small: 12, medium: 14, large: 18, xlarge: 24 },
|
|
807
|
+
spacing: { xs: 4, sm: 8, md: 12, lg: 20, xl: 24, xxl: 28, xxxl: 44 },
|
|
808
|
+
borderRadius: 8,
|
|
809
|
+
navigation: {
|
|
810
|
+
items: [
|
|
811
|
+
{ route: '/(tabs)/home', title: 'Home', icon: { web: 'home', mobile: 'house' } },
|
|
812
|
+
{ route: '/(tabs)/dashboard', title: 'Dashboard', icon: { web: 'grid', mobile: 'square.grid.2x2' } },
|
|
813
|
+
],
|
|
814
|
+
},
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
// Client B brand - all values required
|
|
818
|
+
const clientBBrand = createBrand({
|
|
819
|
+
name: 'Client B App',
|
|
820
|
+
colors: { primary: '#0000ff', secondary: '#ffff00', backgroundColor: '#f5f5f5' },
|
|
821
|
+
fontSizes: { small: 14, medium: 16, large: 20, xlarge: 26 },
|
|
822
|
+
spacing: { xs: 4, sm: 8, md: 12, lg: 16, xl: 20, xxl: 24, xxxl: 40 },
|
|
823
|
+
borderRadius: 16,
|
|
824
|
+
navigation: {
|
|
825
|
+
items: [
|
|
826
|
+
{ route: '/(tabs)/main', title: 'Main', icon: { web: 'home', mobile: 'house' } },
|
|
827
|
+
{ route: '/(tabs)/profile', title: 'Profile', icon: { web: 'user', mobile: 'person' } },
|
|
828
|
+
],
|
|
829
|
+
},
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
// Use based on configuration
|
|
833
|
+
<ZeroToApp brand={getClientBrand()}>
|
|
834
|
+
<App />
|
|
835
|
+
</ZeroToApp>
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
**Accessing Brand in Components:**
|
|
839
|
+
Always use the `useBrand()` hook to access brand values:
|
|
840
|
+
```typescript
|
|
841
|
+
import { useBrand } from 'zero-to-app';
|
|
842
|
+
|
|
843
|
+
function MyComponent() {
|
|
844
|
+
const brand = useBrand();
|
|
845
|
+
// Use brand.colors, brand.spacing, etc.
|
|
846
|
+
}
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
### Theme Customization
|
|
850
|
+
|
|
851
|
+
Edit `theme/themeConfig.ts` to customize:
|
|
852
|
+
|
|
853
|
+
- **Light Theme:** `lightTheme` object
|
|
854
|
+
- **Dark Theme:** `darkTheme` object
|
|
855
|
+
- **Theme Values:** Colors, backgrounds, borders, etc.
|
|
856
|
+
|
|
857
|
+
### Component Customization
|
|
858
|
+
|
|
859
|
+
- **UI Components:** Edit files in `components/ui/` (e.g., `components/ui/Button.tsx`)
|
|
860
|
+
- **Composite Components:** Edit files in `components/{category}/` (e.g., `components/layout/WebPageLayout.tsx`)
|
|
861
|
+
|
|
862
|
+
---
|
|
863
|
+
|
|
864
|
+
## Component Props Reference
|
|
865
|
+
|
|
866
|
+
### StyledText
|
|
867
|
+
|
|
868
|
+
| Prop | Type | Default | Description |
|
|
869
|
+
|------|------|---------|-------------|
|
|
870
|
+
| `fontSize` | `'sm' \| 'md' \| 'lg' \| 'xl' \| number` | `'md'` | Font size |
|
|
871
|
+
| `align` | `'left' \| 'center' \| 'right'` | `'left'` | Text alignment |
|
|
872
|
+
| `color` | `string` | theme color | Text color |
|
|
873
|
+
| `bold` | `boolean` | `false` | Bold text |
|
|
874
|
+
| `muted` | `boolean` | `false` | Muted gray color |
|
|
875
|
+
| `uppercase` | `boolean` | `false` | Uppercase text |
|
|
876
|
+
| `numberOfLines` | `number` | undefined | Limit text lines |
|
|
877
|
+
|
|
878
|
+
### Button
|
|
879
|
+
|
|
880
|
+
| Prop | Type | Default | Description |
|
|
881
|
+
|------|------|---------|-------------|
|
|
882
|
+
| `title` | `string` | required | Button text |
|
|
883
|
+
| `onPress` | `(event) => void` | required | Press handler |
|
|
884
|
+
| `secondary` | `boolean` | `false` | Secondary style (outlined) |
|
|
885
|
+
| `loading` | `boolean` | `false` | Show loading spinner |
|
|
886
|
+
| `icon` | `{ library, name, size?, color? }` | undefined | Icon config |
|
|
887
|
+
| `iconPosition` | `'left' \| 'right'` | `'right'` | Icon position |
|
|
888
|
+
|
|
889
|
+
### FormInput
|
|
890
|
+
|
|
891
|
+
| Prop | Type | Default | Description |
|
|
892
|
+
|------|------|---------|-------------|
|
|
893
|
+
| `control` | `Control<T>` | required | React Hook Form control |
|
|
894
|
+
| `name` | `Path<T>` | required | Field name |
|
|
895
|
+
| `placeholder` | `string` | required | Placeholder text |
|
|
896
|
+
| `error` | `FieldError` | undefined | Validation error |
|
|
897
|
+
| `secureTextEntry` | `boolean` | `false` | Password input |
|
|
898
|
+
| `keyboardType` | `'default' \| 'email-address' \| 'numeric' \| 'phone-pad' \| 'number-pad'` | `'default'` | Keyboard type |
|
|
899
|
+
| `autoCapitalize` | `'none' \| 'sentences' \| 'words' \| 'characters'` | `'sentences'` | Auto capitalize |
|
|
900
|
+
|
|
901
|
+
### Tile
|
|
902
|
+
|
|
903
|
+
| Prop | Type | Default | Description |
|
|
904
|
+
|------|------|---------|-------------|
|
|
905
|
+
| `imageUrl` | `string \| number` | required | Image source |
|
|
906
|
+
| `title` | `string` | required | Tile title |
|
|
907
|
+
| `subtitle` | `string` | undefined | Tile subtitle |
|
|
908
|
+
| `onPress` | `() => void` | undefined | Press handler |
|
|
909
|
+
| `width` | `number \| { mobile: number, web: number }` | responsive | Tile width |
|
|
910
|
+
| `imageHeight` | `number \| { mobile: number, web: number }` | responsive | Image height |
|
|
911
|
+
|
|
912
|
+
---
|
|
913
|
+
|
|
914
|
+
## Dependencies
|
|
915
|
+
|
|
916
|
+
- `react-native`: Core React Native components
|
|
917
|
+
- `@expo/vector-icons`: Icon library (Feather, MaterialIcons, etc.)
|
|
918
|
+
- `react-hook-form`: Form validation (for `FormInput`)
|
|
919
|
+
- `expo-blur`: Blur effects (for `BlurButton`, `ArrowButton`)
|
|
920
|
+
|
|
921
|
+
---
|
|
922
|
+
|
|
923
|
+
## TypeScript Support
|
|
924
|
+
|
|
925
|
+
All components are fully typed. Import types as needed:
|
|
926
|
+
|
|
927
|
+
```typescript
|
|
928
|
+
import type { ThemeContextType, DimensionsInfo } from 'zero-to-app';
|
|
929
|
+
```
|