@urbint/cl 1.0.1
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/.cursor/rules +313 -0
- package/.rnstorybook/index.ts +11 -0
- package/.rnstorybook/main.ts +8 -0
- package/.rnstorybook/preview.tsx +14 -0
- package/.rnstorybook/storybook.requires.ts +49 -0
- package/.storybook/main.ts +16 -0
- package/.storybook/preview.ts +32 -0
- package/.storybook/vitest.setup.ts +7 -0
- package/App.tsx +422 -0
- package/README.md +229 -0
- package/app.json +33 -0
- package/assets/adaptive-icon.png +0 -0
- package/assets/favicon.png +0 -0
- package/assets/icon.png +0 -0
- package/assets/splash-icon.png +0 -0
- package/babel.config.js +16 -0
- package/docs/components/CodeBlock.tsx +80 -0
- package/docs/components/PropTable.tsx +93 -0
- package/docs/components/Sidebar.tsx +199 -0
- package/docs/components/index.ts +8 -0
- package/docs/data/colorTokens.ts +70 -0
- package/docs/data/componentData.tsx +1685 -0
- package/docs/data/index.ts +7 -0
- package/docs/index.ts +19 -0
- package/docs/navigation.ts +94 -0
- package/docs/pages/ColorsPage.tsx +226 -0
- package/docs/pages/ComponentPage.tsx +235 -0
- package/docs/pages/InstallationPage.tsx +232 -0
- package/docs/pages/IntroductionPage.tsx +163 -0
- package/docs/pages/ThemingPage.tsx +251 -0
- package/docs/pages/index.ts +10 -0
- package/docs/theme.ts +64 -0
- package/docs/types.ts +54 -0
- package/index.ts +8 -0
- package/llms.txt +1893 -0
- package/mcp-config.example.json +10 -0
- package/mcp-server/README.md +192 -0
- package/mcp-server/package-lock.json +1707 -0
- package/mcp-server/package.json +38 -0
- package/mcp-server/src/index.ts +1136 -0
- package/mcp-server/src/registry/components.ts +1446 -0
- package/mcp-server/src/registry/index.ts +3 -0
- package/mcp-server/src/registry/tokens.ts +256 -0
- package/mcp-server/tsconfig.json +19 -0
- package/package.json +92 -0
- package/src/components/Accordion/Accordion.stories.tsx +226 -0
- package/src/components/Accordion/Accordion.tsx +255 -0
- package/src/components/Accordion/index.ts +12 -0
- package/src/components/ActionSheet/ActionSheet.stories.tsx +393 -0
- package/src/components/ActionSheet/ActionSheet.tsx +258 -0
- package/src/components/ActionSheet/index.ts +2 -0
- package/src/components/Alert/Alert.stories.tsx +165 -0
- package/src/components/Alert/Alert.tsx +164 -0
- package/src/components/Alert/index.ts +2 -0
- package/src/components/AlertDialog/AlertDialog.stories.tsx +330 -0
- package/src/components/AlertDialog/AlertDialog.tsx +234 -0
- package/src/components/AlertDialog/index.ts +2 -0
- package/src/components/Avatar/Avatar.stories.tsx +154 -0
- package/src/components/Avatar/Avatar.tsx +219 -0
- package/src/components/Avatar/index.ts +2 -0
- package/src/components/Badge/Badge.stories.tsx +146 -0
- package/src/components/Badge/Badge.tsx +125 -0
- package/src/components/Badge/index.ts +2 -0
- package/src/components/Box/Box.stories.tsx +192 -0
- package/src/components/Box/Box.tsx +184 -0
- package/src/components/Box/index.ts +2 -0
- package/src/components/Button/Button.stories.tsx +157 -0
- package/src/components/Button/Button.tsx +180 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/Card/Card.stories.tsx +145 -0
- package/src/components/Card/Card.tsx +169 -0
- package/src/components/Card/index.ts +11 -0
- package/src/components/Center/Center.stories.tsx +215 -0
- package/src/components/Center/Center.tsx +29 -0
- package/src/components/Center/index.ts +2 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +94 -0
- package/src/components/Checkbox/Checkbox.tsx +242 -0
- package/src/components/Checkbox/index.ts +2 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +623 -0
- package/src/components/DatePicker/DatePicker.tsx +1228 -0
- package/src/components/DatePicker/index.ts +8 -0
- package/src/components/Divider/Divider.stories.tsx +224 -0
- package/src/components/Divider/Divider.tsx +73 -0
- package/src/components/Divider/index.ts +2 -0
- package/src/components/Drawer/Drawer.stories.tsx +414 -0
- package/src/components/Drawer/Drawer.tsx +342 -0
- package/src/components/Drawer/index.ts +11 -0
- package/src/components/Fab/Fab.stories.tsx +360 -0
- package/src/components/Fab/Fab.tsx +185 -0
- package/src/components/Fab/index.ts +2 -0
- package/src/components/FormControl/FormControl.stories.tsx +276 -0
- package/src/components/FormControl/FormControl.tsx +185 -0
- package/src/components/FormControl/index.ts +12 -0
- package/src/components/Grid/Grid.stories.tsx +244 -0
- package/src/components/Grid/Grid.tsx +93 -0
- package/src/components/Grid/index.ts +2 -0
- package/src/components/HStack/HStack.stories.tsx +230 -0
- package/src/components/HStack/HStack.tsx +80 -0
- package/src/components/HStack/index.ts +2 -0
- package/src/components/Heading/Heading.stories.tsx +111 -0
- package/src/components/Heading/Heading.tsx +85 -0
- package/src/components/Heading/index.ts +2 -0
- package/src/components/Icon/Icon.stories.tsx +320 -0
- package/src/components/Icon/Icon.tsx +117 -0
- package/src/components/Icon/index.ts +2 -0
- package/src/components/Image/Image.stories.tsx +357 -0
- package/src/components/Image/Image.tsx +168 -0
- package/src/components/Image/index.ts +2 -0
- package/src/components/Input/Input.stories.tsx +164 -0
- package/src/components/Input/Input.tsx +274 -0
- package/src/components/Input/index.ts +2 -0
- package/src/components/Link/Link.stories.tsx +187 -0
- package/src/components/Link/Link.tsx +104 -0
- package/src/components/Link/index.ts +2 -0
- package/src/components/Menu/Menu.stories.tsx +363 -0
- package/src/components/Menu/Menu.tsx +238 -0
- package/src/components/Menu/index.ts +2 -0
- package/src/components/Modal/Modal.stories.tsx +156 -0
- package/src/components/Modal/Modal.tsx +280 -0
- package/src/components/Modal/index.ts +11 -0
- package/src/components/Popover/Popover.stories.tsx +330 -0
- package/src/components/Popover/Popover.tsx +315 -0
- package/src/components/Popover/index.ts +11 -0
- package/src/components/Portal/Portal.stories.tsx +376 -0
- package/src/components/Portal/Portal.tsx +100 -0
- package/src/components/Portal/index.ts +2 -0
- package/src/components/Pressable/Pressable.stories.tsx +338 -0
- package/src/components/Pressable/Pressable.tsx +71 -0
- package/src/components/Pressable/index.ts +2 -0
- package/src/components/Progress/Progress.stories.tsx +131 -0
- package/src/components/Progress/Progress.tsx +219 -0
- package/src/components/Progress/index.ts +2 -0
- package/src/components/Radio/Radio.stories.tsx +101 -0
- package/src/components/Radio/Radio.tsx +234 -0
- package/src/components/Radio/index.ts +2 -0
- package/src/components/Select/Select.stories.tsx +908 -0
- package/src/components/Select/Select.tsx +659 -0
- package/src/components/Select/index.ts +8 -0
- package/src/components/Skeleton/Skeleton.stories.tsx +154 -0
- package/src/components/Skeleton/Skeleton.tsx +192 -0
- package/src/components/Skeleton/index.ts +8 -0
- package/src/components/Slider/Slider.stories.tsx +363 -0
- package/src/components/Slider/Slider.tsx +209 -0
- package/src/components/Slider/index.ts +2 -0
- package/src/components/Spinner/Spinner.stories.tsx +108 -0
- package/src/components/Spinner/Spinner.tsx +121 -0
- package/src/components/Spinner/index.ts +2 -0
- package/src/components/Switch/Switch.stories.tsx +116 -0
- package/src/components/Switch/Switch.tsx +172 -0
- package/src/components/Switch/index.ts +2 -0
- package/src/components/Table/Table.stories.tsx +417 -0
- package/src/components/Table/Table.tsx +233 -0
- package/src/components/Table/index.ts +2 -0
- package/src/components/Text/Text.stories.tsx +93 -0
- package/src/components/Text/Text.tsx +119 -0
- package/src/components/Text/index.ts +2 -0
- package/src/components/Textarea/Textarea.stories.tsx +280 -0
- package/src/components/Textarea/Textarea.tsx +212 -0
- package/src/components/Textarea/index.ts +2 -0
- package/src/components/Toast/Toast.stories.tsx +446 -0
- package/src/components/Toast/Toast.tsx +221 -0
- package/src/components/Toast/index.ts +2 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +354 -0
- package/src/components/Tooltip/Tooltip.tsx +261 -0
- package/src/components/Tooltip/index.ts +2 -0
- package/src/components/VStack/VStack.stories.tsx +183 -0
- package/src/components/VStack/VStack.tsx +76 -0
- package/src/components/VStack/index.ts +2 -0
- package/src/components/index.ts +62 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/useControllableState.ts +41 -0
- package/src/hooks/useDisclosure.ts +51 -0
- package/src/index.ts +22 -0
- package/src/stories/Button.stories.tsx +53 -0
- package/src/stories/Button.tsx +101 -0
- package/src/stories/Configure.mdx +364 -0
- package/src/stories/Header.stories.tsx +33 -0
- package/src/stories/Header.tsx +75 -0
- package/src/stories/Page.stories.tsx +25 -0
- package/src/stories/Page.tsx +154 -0
- package/src/stories/assets/accessibility.png +0 -0
- package/src/stories/assets/accessibility.svg +1 -0
- package/src/stories/assets/addon-library.png +0 -0
- package/src/stories/assets/assets.png +0 -0
- package/src/stories/assets/avif-test-image.avif +0 -0
- package/src/stories/assets/context.png +0 -0
- package/src/stories/assets/discord.svg +1 -0
- package/src/stories/assets/docs.png +0 -0
- package/src/stories/assets/figma-plugin.png +0 -0
- package/src/stories/assets/github.svg +1 -0
- package/src/stories/assets/share.png +0 -0
- package/src/stories/assets/styling.png +0 -0
- package/src/stories/assets/testing.png +0 -0
- package/src/stories/assets/theming.png +0 -0
- package/src/stories/assets/tutorials.svg +1 -0
- package/src/stories/assets/youtube.svg +1 -0
- package/src/styles/index.ts +7 -0
- package/src/styles/tokens.ts +318 -0
- package/src/styles/unistyles.ts +254 -0
- package/src/utils/createContext.tsx +25 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/mergeRefs.ts +21 -0
- package/tsconfig.json +26 -0
- package/urbint-cl-1.0.0.tgz +0 -0
- package/vitest.config.ts +37 -0
- package/vitest.shims.d.ts +1 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { View, StyleSheet } from 'react-native';
|
|
3
|
+
import { Grid, GridItem } from './Grid';
|
|
4
|
+
import { VStack } from '../VStack';
|
|
5
|
+
import { Box } from '../Box';
|
|
6
|
+
import { Text } from '../Text';
|
|
7
|
+
import { colors, spacing, borderRadius } from '../../styles/tokens';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Story container with design system tokens
|
|
11
|
+
*/
|
|
12
|
+
const StoryContainer: React.FC<{ children: React.ReactNode }> = ({ children }) => (
|
|
13
|
+
<View style={styles.container}>{children}</View>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const meta: Meta<typeof Grid> = {
|
|
17
|
+
title: 'Layout/Grid',
|
|
18
|
+
component: Grid,
|
|
19
|
+
decorators: [
|
|
20
|
+
(Story) => (
|
|
21
|
+
<StoryContainer>
|
|
22
|
+
<Story />
|
|
23
|
+
</StoryContainer>
|
|
24
|
+
),
|
|
25
|
+
],
|
|
26
|
+
argTypes: {
|
|
27
|
+
columns: { control: 'number' },
|
|
28
|
+
gap: { control: 'number' },
|
|
29
|
+
rowGap: { control: 'number' },
|
|
30
|
+
columnGap: { control: 'number' },
|
|
31
|
+
},
|
|
32
|
+
args: {
|
|
33
|
+
columns: 3,
|
|
34
|
+
gap: spacing.md,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default meta;
|
|
39
|
+
|
|
40
|
+
type Story = StoryObj<typeof Grid>;
|
|
41
|
+
|
|
42
|
+
export const Default: Story = {
|
|
43
|
+
render: (args) => (
|
|
44
|
+
<Grid {...args}>
|
|
45
|
+
{[1, 2, 3, 4, 5, 6].map((i) => (
|
|
46
|
+
<GridItem key={i}>
|
|
47
|
+
<Box p={spacing.lg} bg={colors.feedback.info.background} rounded="md" alignItems="center">
|
|
48
|
+
<Text>Item {i}</Text>
|
|
49
|
+
</Box>
|
|
50
|
+
</GridItem>
|
|
51
|
+
))}
|
|
52
|
+
</Grid>
|
|
53
|
+
),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const TwoColumns: Story = {
|
|
57
|
+
render: () => (
|
|
58
|
+
<VStack space={spacing.lg}>
|
|
59
|
+
<Text weight="semiBold">2 Column Grid</Text>
|
|
60
|
+
<Grid columns={2} gap={spacing.md}>
|
|
61
|
+
{[1, 2, 3, 4].map((i) => (
|
|
62
|
+
<GridItem key={i}>
|
|
63
|
+
<Box p={spacing.lg} bg={colors.feedback.info.border} rounded="md" alignItems="center">
|
|
64
|
+
<Text>Item {i}</Text>
|
|
65
|
+
</Box>
|
|
66
|
+
</GridItem>
|
|
67
|
+
))}
|
|
68
|
+
</Grid>
|
|
69
|
+
</VStack>
|
|
70
|
+
),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const ThreeColumns: Story = {
|
|
74
|
+
render: () => (
|
|
75
|
+
<VStack space={spacing.lg}>
|
|
76
|
+
<Text weight="semiBold">3 Column Grid</Text>
|
|
77
|
+
<Grid columns={3} gap={spacing.md}>
|
|
78
|
+
{[1, 2, 3, 4, 5, 6].map((i) => (
|
|
79
|
+
<GridItem key={i}>
|
|
80
|
+
<Box p={spacing.lg} bg={colors.brand.blue} rounded="md" alignItems="center">
|
|
81
|
+
<Text color={colors.white}>Item {i}</Text>
|
|
82
|
+
</Box>
|
|
83
|
+
</GridItem>
|
|
84
|
+
))}
|
|
85
|
+
</Grid>
|
|
86
|
+
</VStack>
|
|
87
|
+
),
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const FourColumns: Story = {
|
|
91
|
+
render: () => (
|
|
92
|
+
<VStack space={spacing.lg}>
|
|
93
|
+
<Text weight="semiBold">4 Column Grid</Text>
|
|
94
|
+
<Grid columns={4} gap={spacing.sm}>
|
|
95
|
+
{[1, 2, 3, 4, 5, 6, 7, 8].map((i) => (
|
|
96
|
+
<GridItem key={i}>
|
|
97
|
+
<Box p={spacing.md} bg={colors.brand.navy} rounded="md" alignItems="center">
|
|
98
|
+
<Text color={colors.white}>{i}</Text>
|
|
99
|
+
</Box>
|
|
100
|
+
</GridItem>
|
|
101
|
+
))}
|
|
102
|
+
</Grid>
|
|
103
|
+
</VStack>
|
|
104
|
+
),
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export const ColumnSpan: Story = {
|
|
108
|
+
render: () => (
|
|
109
|
+
<VStack space={spacing.lg}>
|
|
110
|
+
<Text weight="semiBold">Grid with Column Span</Text>
|
|
111
|
+
<Grid columns={4} gap={spacing.md}>
|
|
112
|
+
<GridItem colSpan={2}>
|
|
113
|
+
<Box p={spacing.lg} bg={colors.feedback.error.background} rounded="md" alignItems="center">
|
|
114
|
+
<Text>Span 2</Text>
|
|
115
|
+
</Box>
|
|
116
|
+
</GridItem>
|
|
117
|
+
<GridItem>
|
|
118
|
+
<Box p={spacing.lg} bg={colors.feedback.warning.background} rounded="md" alignItems="center">
|
|
119
|
+
<Text>1</Text>
|
|
120
|
+
</Box>
|
|
121
|
+
</GridItem>
|
|
122
|
+
<GridItem>
|
|
123
|
+
<Box p={spacing.lg} bg={colors.feedback.warning.border} rounded="md" alignItems="center">
|
|
124
|
+
<Text>1</Text>
|
|
125
|
+
</Box>
|
|
126
|
+
</GridItem>
|
|
127
|
+
<GridItem>
|
|
128
|
+
<Box p={spacing.lg} bg={colors.feedback.success.background} rounded="md" alignItems="center">
|
|
129
|
+
<Text>1</Text>
|
|
130
|
+
</Box>
|
|
131
|
+
</GridItem>
|
|
132
|
+
<GridItem colSpan={3}>
|
|
133
|
+
<Box p={spacing.lg} bg={colors.feedback.info.background} rounded="md" alignItems="center">
|
|
134
|
+
<Text>Span 3</Text>
|
|
135
|
+
</Box>
|
|
136
|
+
</GridItem>
|
|
137
|
+
<GridItem colSpan={4}>
|
|
138
|
+
<Box p={spacing.lg} bg={colors.secondary.default} rounded="md" alignItems="center">
|
|
139
|
+
<Text>Span 4 (Full Width)</Text>
|
|
140
|
+
</Box>
|
|
141
|
+
</GridItem>
|
|
142
|
+
</Grid>
|
|
143
|
+
</VStack>
|
|
144
|
+
),
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const DifferentGaps: Story = {
|
|
148
|
+
render: () => (
|
|
149
|
+
<VStack space={spacing.xl}>
|
|
150
|
+
<Text weight="semiBold">Different Gap Sizes</Text>
|
|
151
|
+
<VStack space={spacing.sm}>
|
|
152
|
+
<Text variant="small" color={colors.text.secondary}>gap={spacing.xs}</Text>
|
|
153
|
+
<Grid columns={3} gap={spacing.xs}>
|
|
154
|
+
{[1, 2, 3, 4, 5, 6].map((i) => (
|
|
155
|
+
<GridItem key={i}>
|
|
156
|
+
<Box p={spacing.md} bg={colors.feedback.error.background} rounded="sm" alignItems="center">
|
|
157
|
+
<Text>{i}</Text>
|
|
158
|
+
</Box>
|
|
159
|
+
</GridItem>
|
|
160
|
+
))}
|
|
161
|
+
</Grid>
|
|
162
|
+
</VStack>
|
|
163
|
+
<VStack space={spacing.sm}>
|
|
164
|
+
<Text variant="small" color={colors.text.secondary}>gap={spacing.lg}</Text>
|
|
165
|
+
<Grid columns={3} gap={spacing.lg}>
|
|
166
|
+
{[1, 2, 3, 4, 5, 6].map((i) => (
|
|
167
|
+
<GridItem key={i}>
|
|
168
|
+
<Box p={spacing.md} bg={colors.feedback.success.background} rounded="sm" alignItems="center">
|
|
169
|
+
<Text>{i}</Text>
|
|
170
|
+
</Box>
|
|
171
|
+
</GridItem>
|
|
172
|
+
))}
|
|
173
|
+
</Grid>
|
|
174
|
+
</VStack>
|
|
175
|
+
<VStack space={spacing.sm}>
|
|
176
|
+
<Text variant="small" color={colors.text.secondary}>gap={spacing.xl}</Text>
|
|
177
|
+
<Grid columns={3} gap={spacing.xl}>
|
|
178
|
+
{[1, 2, 3, 4, 5, 6].map((i) => (
|
|
179
|
+
<GridItem key={i}>
|
|
180
|
+
<Box p={spacing.md} bg={colors.feedback.info.background} rounded="sm" alignItems="center">
|
|
181
|
+
<Text>{i}</Text>
|
|
182
|
+
</Box>
|
|
183
|
+
</GridItem>
|
|
184
|
+
))}
|
|
185
|
+
</Grid>
|
|
186
|
+
</VStack>
|
|
187
|
+
</VStack>
|
|
188
|
+
),
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
export const AsymmetricGaps: Story = {
|
|
192
|
+
render: () => (
|
|
193
|
+
<VStack space={spacing.lg}>
|
|
194
|
+
<Text weight="semiBold">Different Row and Column Gaps</Text>
|
|
195
|
+
<Text variant="small" color={colors.text.secondary}>rowGap={spacing.xl}, columnGap={spacing.sm}</Text>
|
|
196
|
+
<Grid columns={3} rowGap={spacing.xl} columnGap={spacing.sm}>
|
|
197
|
+
{[1, 2, 3, 4, 5, 6, 7, 8, 9].map((i) => (
|
|
198
|
+
<GridItem key={i}>
|
|
199
|
+
<Box p={spacing.lg} bg={colors.badge.purple} rounded="md" alignItems="center">
|
|
200
|
+
<Text color={colors.white}>Item {i}</Text>
|
|
201
|
+
</Box>
|
|
202
|
+
</GridItem>
|
|
203
|
+
))}
|
|
204
|
+
</Grid>
|
|
205
|
+
</VStack>
|
|
206
|
+
),
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
export const CardGrid: Story = {
|
|
210
|
+
render: () => (
|
|
211
|
+
<VStack space={spacing.lg}>
|
|
212
|
+
<Text weight="semiBold">Card Grid Layout</Text>
|
|
213
|
+
<Grid columns={2} gap={spacing.lg}>
|
|
214
|
+
{['Dashboard', 'Analytics', 'Reports', 'Settings'].map((title, i) => (
|
|
215
|
+
<GridItem key={i}>
|
|
216
|
+
<Box p={spacing.xl} bg={colors.background.default} rounded="lg" shadow="10">
|
|
217
|
+
<VStack space={spacing.sm}>
|
|
218
|
+
<Box w={40} h={40} bg={colors.feedback.info.background} rounded="md" alignItems="center" justifyContent="center">
|
|
219
|
+
<Text>📊</Text>
|
|
220
|
+
</Box>
|
|
221
|
+
<Text weight="semiBold">{title}</Text>
|
|
222
|
+
<Text variant="small" color={colors.text.secondary}>
|
|
223
|
+
Click to view details
|
|
224
|
+
</Text>
|
|
225
|
+
</VStack>
|
|
226
|
+
</Box>
|
|
227
|
+
</GridItem>
|
|
228
|
+
))}
|
|
229
|
+
</Grid>
|
|
230
|
+
</VStack>
|
|
231
|
+
),
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Styles using design system tokens
|
|
236
|
+
*/
|
|
237
|
+
const styles = StyleSheet.create({
|
|
238
|
+
container: {
|
|
239
|
+
padding: spacing.lg,
|
|
240
|
+
backgroundColor: colors.background.default,
|
|
241
|
+
borderRadius: borderRadius.lg,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grid Component
|
|
3
|
+
* CSS-like grid layout for React Native
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { forwardRef, Children, isValidElement, cloneElement } from 'react';
|
|
7
|
+
import { View, ViewProps, ViewStyle } from 'react-native';
|
|
8
|
+
import { spacing, SpacingToken } from '../../styles/tokens';
|
|
9
|
+
|
|
10
|
+
/** Spacing value can be a token name or raw number */
|
|
11
|
+
type SpacingValue = SpacingToken | number;
|
|
12
|
+
|
|
13
|
+
/** Resolve spacing value to pixels */
|
|
14
|
+
const resolveSpacing = (value: SpacingValue): number => {
|
|
15
|
+
if (typeof value === 'number') return value;
|
|
16
|
+
return spacing[value];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export interface GridProps extends ViewProps {
|
|
20
|
+
/** Number of columns */
|
|
21
|
+
columns?: number;
|
|
22
|
+
/** Gap between items - accepts token ('sm', 'md', 'lg') or number */
|
|
23
|
+
gap?: SpacingValue;
|
|
24
|
+
/** Row gap - accepts token or number */
|
|
25
|
+
rowGap?: SpacingValue;
|
|
26
|
+
/** Column gap - accepts token or number */
|
|
27
|
+
columnGap?: SpacingValue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface GridItemProps extends ViewProps {
|
|
31
|
+
/** Column span */
|
|
32
|
+
colSpan?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const Grid = forwardRef<View, GridProps>(
|
|
36
|
+
({ style, columns = 1, gap = 'none', rowGap, columnGap, children, ...props }, ref) => {
|
|
37
|
+
const resolvedGap = resolveSpacing(gap);
|
|
38
|
+
const effectiveRowGap = rowGap !== undefined ? resolveSpacing(rowGap) : resolvedGap;
|
|
39
|
+
const effectiveColumnGap = columnGap !== undefined ? resolveSpacing(columnGap) : resolvedGap;
|
|
40
|
+
|
|
41
|
+
const childArray = Children.toArray(children);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<View
|
|
45
|
+
ref={ref}
|
|
46
|
+
style={[
|
|
47
|
+
{
|
|
48
|
+
flexDirection: 'row',
|
|
49
|
+
flexWrap: 'wrap',
|
|
50
|
+
marginHorizontal: -effectiveColumnGap / 2,
|
|
51
|
+
marginVertical: -effectiveRowGap / 2,
|
|
52
|
+
},
|
|
53
|
+
style,
|
|
54
|
+
]}
|
|
55
|
+
{...props}
|
|
56
|
+
>
|
|
57
|
+
{childArray.map((child, index) => {
|
|
58
|
+
if (!isValidElement<GridItemProps>(child)) return child;
|
|
59
|
+
|
|
60
|
+
const colSpan = child.props.colSpan || 1;
|
|
61
|
+
const itemWidth = `${(colSpan / columns) * 100}%` as const;
|
|
62
|
+
|
|
63
|
+
return cloneElement(child, {
|
|
64
|
+
key: index,
|
|
65
|
+
style: [
|
|
66
|
+
{
|
|
67
|
+
width: itemWidth as ViewStyle['width'],
|
|
68
|
+
paddingHorizontal: effectiveColumnGap / 2,
|
|
69
|
+
paddingVertical: effectiveRowGap / 2,
|
|
70
|
+
},
|
|
71
|
+
child.props.style,
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
})}
|
|
75
|
+
</View>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
Grid.displayName = 'Grid';
|
|
81
|
+
|
|
82
|
+
export const GridItem = forwardRef<View, GridItemProps>(
|
|
83
|
+
({ style, children, ...props }, ref) => {
|
|
84
|
+
return (
|
|
85
|
+
<View ref={ref} style={style} {...props}>
|
|
86
|
+
{children}
|
|
87
|
+
</View>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
GridItem.displayName = 'GridItem';
|
|
93
|
+
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { View, StyleSheet } from 'react-native';
|
|
3
|
+
import { HStack } from './HStack';
|
|
4
|
+
import { VStack } from '../VStack';
|
|
5
|
+
import { Box } from '../Box';
|
|
6
|
+
import { Text } from '../Text';
|
|
7
|
+
import { colors, spacing, borderRadius } from '../../styles/tokens';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Story container with design system tokens
|
|
11
|
+
*/
|
|
12
|
+
const StoryContainer: React.FC<{ children: React.ReactNode }> = ({ children }) => (
|
|
13
|
+
<View style={styles.container}>{children}</View>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const meta: Meta<typeof HStack> = {
|
|
17
|
+
title: 'Layout/HStack',
|
|
18
|
+
component: HStack,
|
|
19
|
+
decorators: [
|
|
20
|
+
(Story) => (
|
|
21
|
+
<StoryContainer>
|
|
22
|
+
<Story />
|
|
23
|
+
</StoryContainer>
|
|
24
|
+
),
|
|
25
|
+
],
|
|
26
|
+
argTypes: {
|
|
27
|
+
space: { control: 'number' },
|
|
28
|
+
alignItems: {
|
|
29
|
+
control: 'select',
|
|
30
|
+
options: ['flex-start', 'center', 'flex-end', 'stretch'],
|
|
31
|
+
},
|
|
32
|
+
justifyContent: {
|
|
33
|
+
control: 'select',
|
|
34
|
+
options: ['flex-start', 'center', 'flex-end', 'space-between', 'space-around'],
|
|
35
|
+
},
|
|
36
|
+
wrap: { control: 'boolean' },
|
|
37
|
+
reversed: { control: 'boolean' },
|
|
38
|
+
},
|
|
39
|
+
args: {
|
|
40
|
+
space: spacing.md,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default meta;
|
|
45
|
+
|
|
46
|
+
type Story = StoryObj<typeof HStack>;
|
|
47
|
+
|
|
48
|
+
export const Default: Story = {
|
|
49
|
+
render: (args) => (
|
|
50
|
+
<HStack {...args}>
|
|
51
|
+
<Box p={spacing.md} bg={colors.feedback.info.background} rounded="md">
|
|
52
|
+
<Text>Item 1</Text>
|
|
53
|
+
</Box>
|
|
54
|
+
<Box p={spacing.md} bg={colors.feedback.info.background} rounded="md">
|
|
55
|
+
<Text>Item 2</Text>
|
|
56
|
+
</Box>
|
|
57
|
+
<Box p={spacing.md} bg={colors.feedback.info.background} rounded="md">
|
|
58
|
+
<Text>Item 3</Text>
|
|
59
|
+
</Box>
|
|
60
|
+
</HStack>
|
|
61
|
+
),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const Spacing: Story = {
|
|
65
|
+
render: () => (
|
|
66
|
+
<VStack space={spacing.lg}>
|
|
67
|
+
<Text weight="semiBold">Different Spacing Values</Text>
|
|
68
|
+
<Box p={spacing.md} bg={colors.feedback.info.background} rounded="md">
|
|
69
|
+
<Text variant="small" color={colors.text.secondary}>space={spacing.xs}</Text>
|
|
70
|
+
<HStack space={spacing.xs}>
|
|
71
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>A</Text></Box>
|
|
72
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>B</Text></Box>
|
|
73
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>C</Text></Box>
|
|
74
|
+
</HStack>
|
|
75
|
+
</Box>
|
|
76
|
+
<Box p={spacing.md} bg={colors.feedback.info.background} rounded="md">
|
|
77
|
+
<Text variant="small" color={colors.text.secondary}>space={spacing.lg}</Text>
|
|
78
|
+
<HStack space={spacing.lg}>
|
|
79
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>A</Text></Box>
|
|
80
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>B</Text></Box>
|
|
81
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>C</Text></Box>
|
|
82
|
+
</HStack>
|
|
83
|
+
</Box>
|
|
84
|
+
<Box p={spacing.md} bg={colors.feedback.info.background} rounded="md">
|
|
85
|
+
<Text variant="small" color={colors.text.secondary}>space={spacing['2xl']}</Text>
|
|
86
|
+
<HStack space={spacing['2xl']}>
|
|
87
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>A</Text></Box>
|
|
88
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>B</Text></Box>
|
|
89
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>C</Text></Box>
|
|
90
|
+
</HStack>
|
|
91
|
+
</Box>
|
|
92
|
+
</VStack>
|
|
93
|
+
),
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const JustifyContent: Story = {
|
|
97
|
+
render: () => (
|
|
98
|
+
<VStack space={spacing.lg}>
|
|
99
|
+
<Text weight="semiBold">Justify Content Options</Text>
|
|
100
|
+
<Box p={spacing.md} bg={colors.feedback.warning.background} rounded="md">
|
|
101
|
+
<Text variant="small">justifyContent="flex-start"</Text>
|
|
102
|
+
<HStack justifyContent="flex-start" space={spacing.sm}>
|
|
103
|
+
<Box p={spacing.sm} bg={colors.feedback.warning.border} rounded="sm"><Text>1</Text></Box>
|
|
104
|
+
<Box p={spacing.sm} bg={colors.feedback.warning.border} rounded="sm"><Text>2</Text></Box>
|
|
105
|
+
<Box p={spacing.sm} bg={colors.feedback.warning.border} rounded="sm"><Text>3</Text></Box>
|
|
106
|
+
</HStack>
|
|
107
|
+
</Box>
|
|
108
|
+
<Box p={spacing.md} bg={colors.feedback.warning.background} rounded="md">
|
|
109
|
+
<Text variant="small">justifyContent="center"</Text>
|
|
110
|
+
<HStack justifyContent="center" space={spacing.sm}>
|
|
111
|
+
<Box p={spacing.sm} bg={colors.feedback.warning.border} rounded="sm"><Text>1</Text></Box>
|
|
112
|
+
<Box p={spacing.sm} bg={colors.feedback.warning.border} rounded="sm"><Text>2</Text></Box>
|
|
113
|
+
<Box p={spacing.sm} bg={colors.feedback.warning.border} rounded="sm"><Text>3</Text></Box>
|
|
114
|
+
</HStack>
|
|
115
|
+
</Box>
|
|
116
|
+
<Box p={spacing.md} bg={colors.feedback.warning.background} rounded="md">
|
|
117
|
+
<Text variant="small">justifyContent="flex-end"</Text>
|
|
118
|
+
<HStack justifyContent="flex-end" space={spacing.sm}>
|
|
119
|
+
<Box p={spacing.sm} bg={colors.feedback.warning.border} rounded="sm"><Text>1</Text></Box>
|
|
120
|
+
<Box p={spacing.sm} bg={colors.feedback.warning.border} rounded="sm"><Text>2</Text></Box>
|
|
121
|
+
<Box p={spacing.sm} bg={colors.feedback.warning.border} rounded="sm"><Text>3</Text></Box>
|
|
122
|
+
</HStack>
|
|
123
|
+
</Box>
|
|
124
|
+
<Box p={spacing.md} bg={colors.feedback.warning.background} rounded="md">
|
|
125
|
+
<Text variant="small">justifyContent="space-between"</Text>
|
|
126
|
+
<HStack justifyContent="space-between">
|
|
127
|
+
<Box p={spacing.sm} bg={colors.feedback.warning.border} rounded="sm"><Text>1</Text></Box>
|
|
128
|
+
<Box p={spacing.sm} bg={colors.feedback.warning.border} rounded="sm"><Text>2</Text></Box>
|
|
129
|
+
<Box p={spacing.sm} bg={colors.feedback.warning.border} rounded="sm"><Text>3</Text></Box>
|
|
130
|
+
</HStack>
|
|
131
|
+
</Box>
|
|
132
|
+
</VStack>
|
|
133
|
+
),
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const AlignItems: Story = {
|
|
137
|
+
render: () => (
|
|
138
|
+
<VStack space={spacing.lg}>
|
|
139
|
+
<Text weight="semiBold">Align Items Options</Text>
|
|
140
|
+
<Box p={spacing.md} bg={colors.feedback.success.background} rounded="md">
|
|
141
|
+
<Text variant="small">alignItems="flex-start"</Text>
|
|
142
|
+
<HStack alignItems="flex-start" space={spacing.sm} style={{ height: 80 }}>
|
|
143
|
+
<Box p={spacing.sm} h={30} bg={colors.feedback.success.border} rounded="sm"><Text>Short</Text></Box>
|
|
144
|
+
<Box p={spacing.sm} h={50} bg={colors.feedback.success.border} rounded="sm"><Text>Medium</Text></Box>
|
|
145
|
+
<Box p={spacing.sm} h={70} bg={colors.feedback.success.border} rounded="sm"><Text>Tall</Text></Box>
|
|
146
|
+
</HStack>
|
|
147
|
+
</Box>
|
|
148
|
+
<Box p={spacing.md} bg={colors.feedback.success.background} rounded="md">
|
|
149
|
+
<Text variant="small">alignItems="center"</Text>
|
|
150
|
+
<HStack alignItems="center" space={spacing.sm} style={{ height: 80 }}>
|
|
151
|
+
<Box p={spacing.sm} h={30} bg={colors.feedback.success.border} rounded="sm"><Text>Short</Text></Box>
|
|
152
|
+
<Box p={spacing.sm} h={50} bg={colors.feedback.success.border} rounded="sm"><Text>Medium</Text></Box>
|
|
153
|
+
<Box p={spacing.sm} h={70} bg={colors.feedback.success.border} rounded="sm"><Text>Tall</Text></Box>
|
|
154
|
+
</HStack>
|
|
155
|
+
</Box>
|
|
156
|
+
<Box p={spacing.md} bg={colors.feedback.success.background} rounded="md">
|
|
157
|
+
<Text variant="small">alignItems="flex-end"</Text>
|
|
158
|
+
<HStack alignItems="flex-end" space={spacing.sm} style={{ height: 80 }}>
|
|
159
|
+
<Box p={spacing.sm} h={30} bg={colors.feedback.success.border} rounded="sm"><Text>Short</Text></Box>
|
|
160
|
+
<Box p={spacing.sm} h={50} bg={colors.feedback.success.border} rounded="sm"><Text>Medium</Text></Box>
|
|
161
|
+
<Box p={spacing.sm} h={70} bg={colors.feedback.success.border} rounded="sm"><Text>Tall</Text></Box>
|
|
162
|
+
</HStack>
|
|
163
|
+
</Box>
|
|
164
|
+
</VStack>
|
|
165
|
+
),
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export const Wrap: Story = {
|
|
169
|
+
render: () => (
|
|
170
|
+
<VStack space={spacing.lg}>
|
|
171
|
+
<Text weight="semiBold">Wrap Behavior</Text>
|
|
172
|
+
<Box p={spacing.md} bg={colors.feedback.error.background} rounded="md">
|
|
173
|
+
<Text variant="small">wrap=false (default)</Text>
|
|
174
|
+
<HStack space={spacing.sm} wrap={false}>
|
|
175
|
+
{[1, 2, 3, 4, 5, 6, 7, 8].map((i) => (
|
|
176
|
+
<Box key={i} p={spacing.sm} bg={colors.feedback.error.border} rounded="sm">
|
|
177
|
+
<Text>Item {i}</Text>
|
|
178
|
+
</Box>
|
|
179
|
+
))}
|
|
180
|
+
</HStack>
|
|
181
|
+
</Box>
|
|
182
|
+
<Box p={spacing.md} bg={colors.feedback.error.background} rounded="md">
|
|
183
|
+
<Text variant="small">wrap=true</Text>
|
|
184
|
+
<HStack space={spacing.sm} wrap>
|
|
185
|
+
{[1, 2, 3, 4, 5, 6, 7, 8].map((i) => (
|
|
186
|
+
<Box key={i} p={spacing.sm} bg={colors.feedback.error.border} rounded="sm">
|
|
187
|
+
<Text>Item {i}</Text>
|
|
188
|
+
</Box>
|
|
189
|
+
))}
|
|
190
|
+
</HStack>
|
|
191
|
+
</Box>
|
|
192
|
+
</VStack>
|
|
193
|
+
),
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
export const Reversed: Story = {
|
|
197
|
+
render: () => (
|
|
198
|
+
<VStack space={spacing.lg}>
|
|
199
|
+
<Text weight="semiBold">Reversed Direction</Text>
|
|
200
|
+
<Box p={spacing.md} bg={colors.feedback.info.background} rounded="md">
|
|
201
|
+
<Text variant="small">Normal (reversed=false)</Text>
|
|
202
|
+
<HStack space={spacing.sm}>
|
|
203
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>1st</Text></Box>
|
|
204
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>2nd</Text></Box>
|
|
205
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>3rd</Text></Box>
|
|
206
|
+
</HStack>
|
|
207
|
+
</Box>
|
|
208
|
+
<Box p={spacing.md} bg={colors.feedback.info.background} rounded="md">
|
|
209
|
+
<Text variant="small">Reversed (reversed=true)</Text>
|
|
210
|
+
<HStack space={spacing.sm} reversed>
|
|
211
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>1st</Text></Box>
|
|
212
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>2nd</Text></Box>
|
|
213
|
+
<Box p={spacing.sm} bg={colors.feedback.info.border} rounded="sm"><Text>3rd</Text></Box>
|
|
214
|
+
</HStack>
|
|
215
|
+
</Box>
|
|
216
|
+
</VStack>
|
|
217
|
+
),
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Styles using design system tokens
|
|
222
|
+
*/
|
|
223
|
+
const styles = StyleSheet.create({
|
|
224
|
+
container: {
|
|
225
|
+
padding: spacing.lg,
|
|
226
|
+
backgroundColor: colors.background.default,
|
|
227
|
+
borderRadius: borderRadius.lg,
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HStack Component
|
|
3
|
+
* Horizontal stack - arranges children in a row
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { forwardRef } from 'react';
|
|
7
|
+
import { View, ViewProps, ViewStyle } from 'react-native';
|
|
8
|
+
import { spacing, SpacingToken } from '../../styles/tokens';
|
|
9
|
+
|
|
10
|
+
/** Spacing value can be a token name or raw number */
|
|
11
|
+
type SpacingValue = SpacingToken | number;
|
|
12
|
+
|
|
13
|
+
/** Resolve spacing value to pixels */
|
|
14
|
+
const resolveSpacing = (value: SpacingValue): number => {
|
|
15
|
+
if (typeof value === 'number') return value;
|
|
16
|
+
return spacing[value];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export interface HStackProps extends ViewProps {
|
|
20
|
+
/** Space between children - accepts token ('sm', 'md', 'lg') or number */
|
|
21
|
+
space?: SpacingValue;
|
|
22
|
+
/** Padding on all sides - accepts token ('sm', 'md', 'lg') or number */
|
|
23
|
+
p?: SpacingValue;
|
|
24
|
+
/** Horizontal padding - accepts token ('sm', 'md', 'lg') or number */
|
|
25
|
+
px?: SpacingValue;
|
|
26
|
+
/** Vertical padding - accepts token ('sm', 'md', 'lg') or number */
|
|
27
|
+
py?: SpacingValue;
|
|
28
|
+
/** Align items */
|
|
29
|
+
alignItems?: ViewStyle['alignItems'];
|
|
30
|
+
/** Justify content */
|
|
31
|
+
justifyContent?: ViewStyle['justifyContent'];
|
|
32
|
+
/** Wrap children */
|
|
33
|
+
wrap?: boolean;
|
|
34
|
+
/** Reverse direction */
|
|
35
|
+
reversed?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const HStack = forwardRef<View, HStackProps>(
|
|
39
|
+
(
|
|
40
|
+
{
|
|
41
|
+
style,
|
|
42
|
+
space = 'none',
|
|
43
|
+
p,
|
|
44
|
+
px,
|
|
45
|
+
py,
|
|
46
|
+
alignItems = 'center',
|
|
47
|
+
justifyContent,
|
|
48
|
+
wrap = false,
|
|
49
|
+
reversed = false,
|
|
50
|
+
children,
|
|
51
|
+
...props
|
|
52
|
+
},
|
|
53
|
+
ref
|
|
54
|
+
) => {
|
|
55
|
+
return (
|
|
56
|
+
<View
|
|
57
|
+
ref={ref}
|
|
58
|
+
style={[
|
|
59
|
+
{
|
|
60
|
+
flexDirection: reversed ? 'row-reverse' : 'row',
|
|
61
|
+
gap: resolveSpacing(space),
|
|
62
|
+
alignItems,
|
|
63
|
+
justifyContent,
|
|
64
|
+
flexWrap: wrap ? 'wrap' : 'nowrap',
|
|
65
|
+
...(p !== undefined && { padding: resolveSpacing(p) }),
|
|
66
|
+
...(px !== undefined && { paddingHorizontal: resolveSpacing(px) }),
|
|
67
|
+
...(py !== undefined && { paddingVertical: resolveSpacing(py) }),
|
|
68
|
+
},
|
|
69
|
+
style,
|
|
70
|
+
]}
|
|
71
|
+
{...props}
|
|
72
|
+
>
|
|
73
|
+
{children}
|
|
74
|
+
</View>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
HStack.displayName = 'HStack';
|
|
80
|
+
|