@granite-js/style-utils 0.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/CHANGELOG.md +27 -0
- package/LICENSE +202 -0
- package/README.md +24 -0
- package/dist/box-spacing.d.ts +220 -0
- package/dist/children.d.ts +53 -0
- package/dist/flex.d.ts +166 -0
- package/dist/index.d.ts +4 -0
- package/dist/spacing.d.ts +44 -0
- package/dist/stack.d.ts +126 -0
- package/package.json +52 -0
- package/src/box-spacing.spec.tsx +220 -0
- package/src/box-spacing.tsx +306 -0
- package/src/children.spec.tsx +24 -0
- package/src/children.tsx +74 -0
- package/src/flex.spec.tsx +92 -0
- package/src/flex.tsx +214 -0
- package/src/index.ts +4 -0
- package/src/spacing.spec.tsx +24 -0
- package/src/spacing.tsx +57 -0
- package/src/stack.spec.tsx +39 -0
- package/src/stack.tsx +155 -0
package/src/flex.tsx
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { forwardRef, type ReactElement, type ReactNode, type Ref } from 'react';
|
|
2
|
+
import { View, type ViewProps, type ViewStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
interface FlexOptions {
|
|
5
|
+
align?: ViewStyle['alignItems'];
|
|
6
|
+
justify?: ViewStyle['justifyContent'];
|
|
7
|
+
direction?: ViewStyle['flexDirection'];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface Props extends FlexOptions, ViewProps {
|
|
11
|
+
style?: ViewProps['style'];
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type FlexReturnType = (props: Props & { ref?: Ref<View> }) => ReactElement | null;
|
|
16
|
+
|
|
17
|
+
export function flex(options: FlexOptions | ViewStyle['alignItems']): ViewStyle;
|
|
18
|
+
export function flex(
|
|
19
|
+
align: ViewStyle['alignItems'] | FlexOptions,
|
|
20
|
+
justify?: ViewStyle['justifyContent'],
|
|
21
|
+
direction?: ViewStyle['flexDirection']
|
|
22
|
+
): ViewStyle;
|
|
23
|
+
export function flex(
|
|
24
|
+
alignOrFlexOptions: FlexOptions | ViewStyle['alignItems'],
|
|
25
|
+
justify: ViewStyle['justifyContent'] = 'flex-start',
|
|
26
|
+
direction: ViewStyle['flexDirection'] = 'column'
|
|
27
|
+
): ViewStyle {
|
|
28
|
+
if (typeof alignOrFlexOptions === 'object') {
|
|
29
|
+
const { align = 'stretch', direction = 'column', justify = 'flex-start' } = alignOrFlexOptions;
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
alignItems: align,
|
|
33
|
+
display: 'flex',
|
|
34
|
+
flexDirection: direction,
|
|
35
|
+
justifyContent: justify,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
display: 'flex',
|
|
41
|
+
alignItems: alignOrFlexOptions,
|
|
42
|
+
flexDirection: direction,
|
|
43
|
+
justifyContent: justify,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
flex.center = (direction?: FlexOptions['direction']) => flex({ justify: 'center', align: 'center', direction });
|
|
48
|
+
|
|
49
|
+
const BaseFlex = forwardRef<View, Props>(function (
|
|
50
|
+
{ align = 'stretch', justify = 'flex-start', direction = 'column', style, ...restProps },
|
|
51
|
+
ref
|
|
52
|
+
) {
|
|
53
|
+
return <View ref={ref} style={[flex({ align, direction, justify }), style]} {...restProps} />;
|
|
54
|
+
}) as FlexReturnType;
|
|
55
|
+
|
|
56
|
+
type FlexType = typeof BaseFlex & {
|
|
57
|
+
Center: typeof BaseFlex;
|
|
58
|
+
CenterVertical: typeof BaseFlex;
|
|
59
|
+
CenterHorizontal: typeof BaseFlex;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @public
|
|
64
|
+
* @category UI
|
|
65
|
+
* @name Flex
|
|
66
|
+
* @description
|
|
67
|
+
* `Flex` is a component that arranges child elements based on [**Flexbox Layout**](https://reactnative.dev/docs/0.72/flexbox). Using Flexbox, you can easily align elements horizontally and vertically, and set center alignment with ease.
|
|
68
|
+
* Use `Flex.Center` to place child elements in the center, `Flex.CenterVertical` for vertical center alignment, and `Flex.CenterHorizontal` for horizontal center alignment.
|
|
69
|
+
*
|
|
70
|
+
* @param {object} [props] - The `props` object passed to the component.
|
|
71
|
+
* @param {'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'} [props.align = 'stretch'] - The alignment value for child elements along the main axis (Flex direction). For example, in `'column'` direction, `'center'` places elements at the horizontal center, and `'stretch'` expands elements to match the parent's width when their width is `'auto'`. This value is applied to [`alignItems`](https://reactnative.dev/docs/0.72/layout-props#alignitems), with a default value of `'stretch'`.
|
|
72
|
+
* @param {'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly'} [props.justify = 'flex-start'] - The alignment value for child elements along the cross axis (perpendicular to Flex direction). For example, in `'column'` direction, `flex-start` places elements at the top of the parent, and `'center'` places them at the vertical center. This value is applied to [`justifyContent`](https://reactnative.dev/docs/0.72/layout-props#justifycontent), with a default value of `'flex-start'`.
|
|
73
|
+
* @param {'column' | 'row'} [props.direction = 'column'] - The value that sets the direction in which child elements are arranged. This is applied to [`flexDirection`](https://reactnative.dev/docs/0.72/layout-props#flexdirection), with a default value of `'column'`.
|
|
74
|
+
* @param {ViewProps['style']} [props.style] - The `style` object to be applied to the `Flex` component. Used to specify styles other than Flexbox layout, such as background color, border, and margin. Default value is `undefined`.
|
|
75
|
+
*
|
|
76
|
+
* @property {FlexCenter} [Center] - `Flex.Center` is a component that places child elements at the exact center both horizontally and vertically based on **Flex Layout**.
|
|
77
|
+
* @property {FlexCenterVertical} [CenterVertical] - `Flex.CenterVertical` is a component for **vertically centering** child elements based on Flex Layout.
|
|
78
|
+
* @property {FlexCenterHorizontal} [CenterHorizontal] - `Flex.CenterHorizontal` is a component for **horizontally centering** child elements based on Flex Layout.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ### Example of arranging elements horizontally and vertically
|
|
82
|
+
*
|
|
83
|
+
* ```tsx
|
|
84
|
+
* import { Flex } from '@granite-js/react-native';
|
|
85
|
+
* import { Text } from 'react-native';
|
|
86
|
+
*
|
|
87
|
+
* function FlexExample() {
|
|
88
|
+
* return (
|
|
89
|
+
* <>
|
|
90
|
+
* <Flex direction="column">
|
|
91
|
+
* <Text>Arrange vertically</Text>
|
|
92
|
+
* <Text>1</Text>
|
|
93
|
+
* <Text>2</Text>
|
|
94
|
+
* <Text>3</Text>
|
|
95
|
+
* </Flex>
|
|
96
|
+
* <Flex direction="row">
|
|
97
|
+
* <Text>Arrange horizontally</Text>
|
|
98
|
+
* <Text>1</Text>
|
|
99
|
+
* <Text>2</Text>
|
|
100
|
+
* <Text>3</Text>
|
|
101
|
+
* </Flex>
|
|
102
|
+
* </>
|
|
103
|
+
* );
|
|
104
|
+
* }
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
export const Flex = BaseFlex as FlexType;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @public
|
|
111
|
+
* @category UI
|
|
112
|
+
* @name FlexCenter
|
|
113
|
+
* @description
|
|
114
|
+
* `Flex.Center` is a component that places child elements at the exact center both horizontally and vertically based on [**Flexbox Layout**](https://reactnative.dev/docs/0.72/flexbox).
|
|
115
|
+
* Both `alignItems` and `justifyContent` properties are set to `'center'`, placing child elements at the center of the parent component.
|
|
116
|
+
* You can easily center-align elements using `Flexbox`.
|
|
117
|
+
*
|
|
118
|
+
* @param {object} [props] - The props object passed to the component.
|
|
119
|
+
* @param {'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'} [props.align = 'center'] - The alignment value for child elements along the main axis (Flex direction). For example, in `'column'` direction, `'center'` places elements at the horizontal center, and `'stretch'` expands elements to match the parent's width when their width is `'auto'`. This value is applied to [`alignItems`](https://reactnative.dev/docs/0.72/layout-props#alignitems), with a default value of `'center'`.
|
|
120
|
+
* @param {'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly'} [props.justify = 'center'] - The alignment value for child elements along the cross axis (perpendicular to Flex direction). For example, in `'column'` direction, `flex-start` places elements at the top of the parent, and `'center'` places them at the vertical center. This value is applied to [`justifyContent`](https://reactnative.dev/docs/0.72/layout-props#justifycontent), with a default value of `'center'`.
|
|
121
|
+
* @param {'column' | 'row'} [props.direction = 'column'] - The value that sets the direction in which child elements are arranged. Default value is `'column'`, arranging elements vertically.
|
|
122
|
+
* @param {ViewProps['style']} [props.style] - The `style` object to be applied to the `Flex.Center` component. Used to specify styles other than Flexbox layout, such as background color, border, and margin. Default value is `undefined`.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ### Example of placing elements at the exact center
|
|
126
|
+
*
|
|
127
|
+
* ```tsx
|
|
128
|
+
* import { Flex } from '@granite-js/react-native';
|
|
129
|
+
* import { Text } from 'react-native';
|
|
130
|
+
*
|
|
131
|
+
* function FlexCenterExample() {
|
|
132
|
+
* return (
|
|
133
|
+
* <Flex.Center style={{ width: '100%', height: 100, borderWidth: 1 }}>
|
|
134
|
+
* <Text>Place at the exact center</Text>
|
|
135
|
+
* </Flex.Center>
|
|
136
|
+
* );
|
|
137
|
+
* }
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export const FlexCenter = forwardRef<View, Props>(function FlexCenter(props, ref) {
|
|
141
|
+
return <BaseFlex align="center" justify="center" {...props} ref={ref} />;
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @public
|
|
146
|
+
* @category UI
|
|
147
|
+
* @name FlexCenterVertical
|
|
148
|
+
* @description
|
|
149
|
+
* `Flex.CenterVertical` is a component for **vertically centering** child elements based on [**Flexbox Layout**](https://reactnative.dev/docs/0.72/flexbox).
|
|
150
|
+
* The `justifyContent` property is set to `'center'`, placing child elements at the vertical center of the parent component.
|
|
151
|
+
*
|
|
152
|
+
* @param {object} [props] - The props object passed to the component.
|
|
153
|
+
* @param {'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'} [props.align = 'center'] - The alignment value for child elements along the main axis (Flex direction). For example, in `'column'` direction, `'center'` places elements at the horizontal center, and `'stretch'` expands elements to match the parent's width when their width is `'auto'`. This value is applied to [`alignItems`](https://reactnative.dev/docs/0.72/layout-props#alignitems), with a default value of `'stretch'`.
|
|
154
|
+
* @param {'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly'} [props.justify = 'center'] - The alignment value for child elements along the cross axis (perpendicular to Flex direction). For example, in `'column'` direction, `flex-start` places elements at the top of the parent, and `'center'` places them at the vertical center. This value is applied to [`justifyContent`](https://reactnative.dev/docs/0.72/layout-props#justifycontent), with a default value of `'center'`.
|
|
155
|
+
* @param {'column' | 'row'} [props.direction = 'column'] - The value that sets the direction in which child elements are arranged. Default value is `'column'`, arranging elements vertically.
|
|
156
|
+
* @param {ViewProps['style']} [props.style] - The `style` object to be applied to the `Flex.CenterVertical` component. Used to specify styles other than Flexbox layout, such as background color, border, and margin. Default value is `undefined`.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ### Example of vertically centering elements
|
|
160
|
+
*
|
|
161
|
+
* ```tsx
|
|
162
|
+
* import { Flex } from '@granite-js/react-native';
|
|
163
|
+
* import { Text } from 'react-native';
|
|
164
|
+
*
|
|
165
|
+
* function FlexCenterVerticalExample() {
|
|
166
|
+
* return (
|
|
167
|
+
* <Flex.CenterVertical style={{ width: '100%', height: 100, borderWidth: 1 }}>
|
|
168
|
+
* <Text>Place at the vertical center</Text>
|
|
169
|
+
* </Flex.CenterVertical>
|
|
170
|
+
* );
|
|
171
|
+
* }
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
export const FlexCenterVertical = forwardRef<View, Props>(function FlexCenterVertical(props, ref) {
|
|
175
|
+
return <BaseFlex justify="center" {...props} ref={ref} />;
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @public
|
|
180
|
+
* @category UI
|
|
181
|
+
* @name FlexCenterHorizontal
|
|
182
|
+
* @description
|
|
183
|
+
* `Flex.CenterHorizontal` is a component for **horizontally centering** child elements based on [**Flexbox Layout**](https://reactnative.dev/docs/0.72/flexbox).
|
|
184
|
+
* The `alignItems` property is set to `'center'`, placing child elements at the horizontal center of the parent component.
|
|
185
|
+
*
|
|
186
|
+
* @param {object} [props] - The props object passed to the component.
|
|
187
|
+
* @param {'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'} [props.align = 'center'] - The alignment value for child elements along the main axis (Flex direction). For example, in `'column'` direction, `'center'` places elements at the horizontal center, and `'stretch'` expands elements to match the parent's width when their width is `'auto'`. This value is applied to [`alignItems`](https://reactnative.dev/docs/0.72/layout-props#alignitems), with a default value of `'center'`.
|
|
188
|
+
* @param {'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly'} [props.justify = 'flex-start'] - The alignment value for child elements along the cross axis (perpendicular to Flex direction). For example, in `'column'` direction, `flex-start` places elements at the top of the parent, and `'center'` places them at the vertical center. This value is applied to [`justifyContent`](https://reactnative.dev/docs/0.72/layout-props#justifycontent), with a default value of `'flex-start'`.
|
|
189
|
+
* @param {'column' | 'row'} [props.direction = 'column'] - The value that sets the direction in which child elements are arranged. Default value is `'column'`, arranging elements vertically.
|
|
190
|
+
* @param {ViewProps['style']} [props.style] - The `style` object to be applied to the `Flex.CenterHorizontal` component. Used to specify styles other than Flexbox layout, such as background color, border, and margin. Default value is `undefined`.
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ### Example of horizontally centering elements
|
|
194
|
+
*
|
|
195
|
+
* ```tsx
|
|
196
|
+
* import { Flex } from '@granite-js/react-native';
|
|
197
|
+
* import { Text } from 'react-native';
|
|
198
|
+
*
|
|
199
|
+
* function FlexCenterHorizontalExample() {
|
|
200
|
+
* return (
|
|
201
|
+
* <Flex.CenterHorizontal style={{ width: '100%', height: 100, borderWidth: 1 }}>
|
|
202
|
+
* <Text>Place at the horizontal center</Text>
|
|
203
|
+
* </Flex.CenterHorizontal>
|
|
204
|
+
* );
|
|
205
|
+
* }
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
export const FlexCenterHorizontal = forwardRef<View, Props>(function FlexCenterHorizontal(props, ref) {
|
|
209
|
+
return <BaseFlex align="center" {...props} ref={ref} />;
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
Flex.Center = FlexCenter as FlexReturnType;
|
|
213
|
+
Flex.CenterVertical = FlexCenterVertical as FlexReturnType;
|
|
214
|
+
Flex.CenterHorizontal = FlexCenterHorizontal as FlexReturnType;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react-native';
|
|
2
|
+
import type { ReactTestRendererJSON } from 'react-test-renderer';
|
|
3
|
+
import { Spacing } from './spacing';
|
|
4
|
+
|
|
5
|
+
describe('Spacing', () => {
|
|
6
|
+
it('Spacing is rendered as <View />', () => {
|
|
7
|
+
const rendererJSON = render(<Spacing size={8} />).toJSON() as ReactTestRendererJSON;
|
|
8
|
+
expect(rendererJSON.type).toBe('View');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('When Spacing is vertical, it is rendered with "height" props', () => {
|
|
12
|
+
render(<Spacing size={8} testID="spacing" />);
|
|
13
|
+
expect(screen.getByTestId('spacing')).toHaveStyle({
|
|
14
|
+
height: 8,
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('When Spacing is horizontal, it is rendered with "width" props', () => {
|
|
19
|
+
render(<Spacing size={8} direction="horizontal" testID="spacing" />);
|
|
20
|
+
expect(screen.getByTestId('spacing')).toHaveStyle({
|
|
21
|
+
width: 8,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
});
|
package/src/spacing.tsx
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { memo } from 'react';
|
|
2
|
+
import { View, type StyleProp, type ViewProps, type ViewStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
interface Props extends ViewProps {
|
|
5
|
+
size: number;
|
|
6
|
+
direction?: 'vertical' | 'horizontal';
|
|
7
|
+
style?: StyleProp<ViewStyle>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @public
|
|
12
|
+
* @category UI
|
|
13
|
+
* @name Spacing
|
|
14
|
+
* @description
|
|
15
|
+
* `Spacing` is a component that adds margin by occupying empty space. You can specify the size of the margin in either horizontal or vertical direction.
|
|
16
|
+
*
|
|
17
|
+
* @param {object} [props] - The `props` object passed to the component.
|
|
18
|
+
* @param {number} props.size - A numeric value that sets the size of the margin.
|
|
19
|
+
* @param {'vertical' | 'horizontal'} [props.direction = 'vertical'] - Sets the direction in which the margin will occupy space. Default value is `'vertical'`.
|
|
20
|
+
* @param {StyleProp<ViewStyle>} [props.style] - The `style` value to be applied to the `Spacing` component. Default value is `undefined`, used when applying additional styles.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ### Example of creating empty space by adding margins of size `16` in both horizontal and vertical directions
|
|
24
|
+
*
|
|
25
|
+
* ```tsx
|
|
26
|
+
* import { View, Text } from 'react-native';
|
|
27
|
+
* import { Spacing } from '@granite-js/react-native';
|
|
28
|
+
*
|
|
29
|
+
* export function SpacingExample() {
|
|
30
|
+
* return (
|
|
31
|
+
* <View>
|
|
32
|
+
* <Text>Top</Text>
|
|
33
|
+
* <Spacing size={16} direction="vertical" style={{ backgroundColor: 'red', width: 5 }} />
|
|
34
|
+
* <Text>Bottom, positioned below by the vertical margin</Text>
|
|
35
|
+
*
|
|
36
|
+
* <View style={{ flexDirection: 'row' }}>
|
|
37
|
+
* <Text>Left</Text>
|
|
38
|
+
* <Spacing size={16} direction="horizontal" style={{ backgroundColor: 'red', height: 5 }} />
|
|
39
|
+
* <Text>Right, positioned to the side by the horizontal margin</Text>
|
|
40
|
+
* </View>
|
|
41
|
+
* </View>
|
|
42
|
+
* );
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export const Spacing = memo(function Spacing({ size, direction = 'vertical', style, ...restProps }: Props) {
|
|
47
|
+
const directionStyle =
|
|
48
|
+
direction === 'vertical'
|
|
49
|
+
? {
|
|
50
|
+
height: size,
|
|
51
|
+
}
|
|
52
|
+
: {
|
|
53
|
+
width: size,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return <View style={[directionStyle, style]} {...restProps} />;
|
|
57
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { render } from '@testing-library/react-native';
|
|
2
|
+
import type { ReactTestRendererJSON } from 'react-test-renderer';
|
|
3
|
+
import { Stack } from './stack';
|
|
4
|
+
|
|
5
|
+
describe('Stack', () => {
|
|
6
|
+
it('Default Stack is rendered in vertical direction', () => {
|
|
7
|
+
const rendererJSON = render(<Stack gutter={16} />).toJSON() as ReactTestRendererJSON;
|
|
8
|
+
|
|
9
|
+
expect(rendererJSON.props.style[0]).toEqual(
|
|
10
|
+
expect.objectContaining({
|
|
11
|
+
flexDirection: 'column',
|
|
12
|
+
})
|
|
13
|
+
);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('Stack.Vertical', () => {
|
|
17
|
+
it('Stack.Vertical is rendered in vertical direction', () => {
|
|
18
|
+
const rendererJSON = render(<Stack.Vertical gutter={16} />).toJSON() as ReactTestRendererJSON;
|
|
19
|
+
|
|
20
|
+
expect(rendererJSON.props.style[0]).toEqual(
|
|
21
|
+
expect.objectContaining({
|
|
22
|
+
flexDirection: 'column',
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('Stack.Horizontal', () => {
|
|
29
|
+
it('Stack.Horizontal is rendered in horizontal direction', () => {
|
|
30
|
+
const rendererJSON = render(<Stack.Horizontal gutter={16} />).toJSON() as ReactTestRendererJSON;
|
|
31
|
+
|
|
32
|
+
expect(rendererJSON.props.style[0]).toEqual(
|
|
33
|
+
expect.objectContaining({
|
|
34
|
+
flexDirection: 'row',
|
|
35
|
+
})
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
});
|
package/src/stack.tsx
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { forwardRef, type ReactElement } from 'react';
|
|
2
|
+
import { View, type ViewProps, type ViewStyle } from 'react-native';
|
|
3
|
+
import { Children } from './children';
|
|
4
|
+
import { Flex } from './flex';
|
|
5
|
+
import { Spacing } from './spacing';
|
|
6
|
+
|
|
7
|
+
type Direction = 'horizontal' | 'vertical';
|
|
8
|
+
|
|
9
|
+
interface StackProps extends ViewProps {
|
|
10
|
+
direction?: Direction;
|
|
11
|
+
gutter?: number | ReactElement;
|
|
12
|
+
align?: ViewStyle['alignItems'];
|
|
13
|
+
justify?: ViewStyle['justifyContent'];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const BaseStack = forwardRef<View, StackProps>(function BaseStack(props, ref) {
|
|
17
|
+
const { direction = 'vertical', gutter = 0, children, ...rest } = props;
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Flex ref={ref} direction={direction === 'vertical' ? 'column' : 'row'} {...rest}>
|
|
21
|
+
<Children.Gap
|
|
22
|
+
gap={typeof gutter === 'number' ? <Spacing direction={direction} size={gutter ?? 24} /> : props.gutter}
|
|
23
|
+
>
|
|
24
|
+
{children}
|
|
25
|
+
</Children.Gap>
|
|
26
|
+
</Flex>
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @public
|
|
32
|
+
* @category UI
|
|
33
|
+
* @name Stack
|
|
34
|
+
* @description
|
|
35
|
+
* `Stack` is a component that arranges child elements in a stack layout either horizontally or vertically, and allows you to set spacing between child elements.
|
|
36
|
+
* You can specify the direction as horizontal or vertical using the `direction` property, and control the spacing between child elements using the `gutter` property.
|
|
37
|
+
* You can use `Stack.Horizontal` for horizontal arrangement and `Stack.Vertical` for vertical arrangement.
|
|
38
|
+
*
|
|
39
|
+
* @param {object} [props] - The props object passed to the component.
|
|
40
|
+
* @param {'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'} [props.align] - The alignment value for child elements along the main axis (Flex direction). For example, in `'column'` direction, `'center'` places elements at the horizontal center, and `'stretch'` expands elements to match the parent's width when their width is `'auto'`. This value is applied to [`alignItems`](https://reactnative.dev/docs/0.72/layout-props#alignitems).
|
|
41
|
+
* @param {'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly'} [props.justify] - The alignment value for child elements along the cross axis (perpendicular to Flex direction). For example, in `'column'` direction, `flex-start` places elements at the top of the parent, and `'center'` places them at the vertical center. This value is applied to [`justifyContent`](https://reactnative.dev/docs/0.72/layout-props#justifycontent).
|
|
42
|
+
* @param {'vertical' | 'horizontal'} [props.direction = 'vertical'] - The value that sets the direction in which child elements are arranged. Default value is `'vertical'`.
|
|
43
|
+
* @param {number | ReactElement} [props.gutter] - The value that sets the spacing between child elements. When a number is provided, it sets the margin in pixels, and when a `ReactElement` is passed, that component is used as the spacing. Using a number allows for precise control of spacing, while using a `ReactElement` enables more complex custom spacing implementations.
|
|
44
|
+
*
|
|
45
|
+
* @property {StackHorizontal} [Horizontal] - `Stack.Horizontal` is a component that arranges child elements in a **horizontal** stack.
|
|
46
|
+
* @property {StackVertical} [Vertical] - `Stack.Vertical` is a component that arranges child elements in a **vertical** stack.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ### Example of arranging elements horizontally and vertically with a spacing of 16
|
|
50
|
+
*
|
|
51
|
+
* ```tsx
|
|
52
|
+
* import { Text } from 'react-native';
|
|
53
|
+
* import { Stack } from '@granite-js/react-native';
|
|
54
|
+
*
|
|
55
|
+
* export function StackExample() {
|
|
56
|
+
* return (
|
|
57
|
+
* <>
|
|
58
|
+
* <Stack gutter={16} direction="horizontal">
|
|
59
|
+
* <Text>Arrange horizontally with 16 spacing</Text>
|
|
60
|
+
* <Text>1</Text>
|
|
61
|
+
* <Text>2</Text>
|
|
62
|
+
* <Text>3</Text>
|
|
63
|
+
* </Stack>
|
|
64
|
+
* <Stack gutter={16} direction="vertical">
|
|
65
|
+
* <Text>Arrange vertically with 16 spacing</Text>
|
|
66
|
+
* <Text>1</Text>
|
|
67
|
+
* <Text>2</Text>
|
|
68
|
+
* <Text>3</Text>
|
|
69
|
+
* </Stack>
|
|
70
|
+
* </>
|
|
71
|
+
* );
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export const Stack = BaseStack as StackType;
|
|
76
|
+
|
|
77
|
+
type StackType = typeof BaseStack & {
|
|
78
|
+
Vertical: typeof StackVertical;
|
|
79
|
+
Horizontal: typeof StackHorizontal;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
type StackWithoutDirectionProps = Omit<StackProps, 'direction'>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @public
|
|
86
|
+
* @category UI
|
|
87
|
+
* @name StackHorizontal
|
|
88
|
+
* @description
|
|
89
|
+
* `Stack.Horizontal` is a component that arranges child elements in a horizontal stack. Using this component, you can easily control the spacing between child elements with the `gutter` property, maintaining a consistent layout in the horizontal direction.
|
|
90
|
+
*
|
|
91
|
+
* @param {object} [props] - The props object passed to the component.
|
|
92
|
+
* @param {'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline'} [props.align = 'stretch'] - The value that sets the horizontal alignment of child elements. Works the same as Flexbox's `align-items` property, with a default value of `'stretch'` that expands child elements to match the parent's width when their width is `'auto'`.
|
|
93
|
+
* @param {'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly'} [props.justify = 'flex-start'] - The value that sets the horizontal alignment of child elements. Works the same as Flexbox's `justify-content` property, with a default value of `'flex-start'` that aligns child elements to the top.
|
|
94
|
+
* @param {number | ReactElement} [props.gutter] - The value that sets the spacing between child elements. When a number is provided, it sets the margin in pixels, and when a `ReactElement` is passed, that component is used as the spacing. Using a number allows for precise control of spacing, while using a `ReactElement` enables more complex custom spacing implementations.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ### Example of arranging elements horizontally with a spacing of 16
|
|
98
|
+
*
|
|
99
|
+
* ```tsx
|
|
100
|
+
* import { Stack } from '@granite-js/react-native';
|
|
101
|
+
* import { View, Text } from 'react-native';
|
|
102
|
+
*
|
|
103
|
+
* function StackHorizontalExample() {
|
|
104
|
+
* return (
|
|
105
|
+
* <Stack.Horizontal gutter={16}>
|
|
106
|
+
* <Text>Arrange horizontally with 16 spacing</Text>
|
|
107
|
+
* <Text>1</Text>
|
|
108
|
+
* <Text>2</Text>
|
|
109
|
+
* <Text>3</Text>
|
|
110
|
+
* </Stack.Horizontal>
|
|
111
|
+
* );
|
|
112
|
+
* }
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
const StackHorizontal = forwardRef<View, StackWithoutDirectionProps>(function StackHorizontal(props, ref) {
|
|
116
|
+
return <Stack direction="horizontal" {...props} ref={ref} />;
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @public
|
|
121
|
+
* @category UI
|
|
122
|
+
* @name StackVertical
|
|
123
|
+
* @description
|
|
124
|
+
* `Stack.Vertical` is a component that arranges child elements in a vertical stack. Using this component, you can easily control the spacing between child elements with the `gutter` property, maintaining a consistent layout in the vertical direction.
|
|
125
|
+
*
|
|
126
|
+
* @param {object} [props] - The props object passed to the component.
|
|
127
|
+
* @param {string} [props.align = 'stretch'] - The value that sets the vertical alignment of child elements. Works the same as Flexbox's `align-items` property, with a default value of `'stretch'` that expands child elements to match the parent's height when their height is `'auto'`.
|
|
128
|
+
* @param {string} [props.justify = 'flex-start'] - The value that sets the horizontal alignment of child elements. Works the same as Flexbox's `justify-content` property, with a default value of `'flex-start'` that aligns child elements to the left.
|
|
129
|
+
* @param {number | ReactElement} [props.gutter] - The value that sets the spacing between child elements. When a number is provided, it sets the margin in pixels, and when a `ReactElement` is passed, that component is used as the spacing. Using a number allows for precise control of spacing, while using a `ReactElement` enables more complex custom spacing implementations.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ### Example of arranging elements vertically with a spacing of 16
|
|
133
|
+
*
|
|
134
|
+
* ```tsx
|
|
135
|
+
* import { Stack } from '@granite-js/react-native';
|
|
136
|
+
* import { View, Text } from 'react-native';
|
|
137
|
+
*
|
|
138
|
+
* function StackVerticalExample() {
|
|
139
|
+
* return (
|
|
140
|
+
* <Stack.Vertical gutter={16}>
|
|
141
|
+
* <Text>Arrange vertically with 16 spacing</Text>
|
|
142
|
+
* <Text>1</Text>
|
|
143
|
+
* <Text>2</Text>
|
|
144
|
+
* <Text>3</Text>
|
|
145
|
+
* </Stack.Vertical>
|
|
146
|
+
* );
|
|
147
|
+
* }
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
const StackVertical = forwardRef<View, StackWithoutDirectionProps>(function StackVertical(props, ref) {
|
|
151
|
+
return <Stack direction="vertical" {...props} ref={ref} />;
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
Stack.Horizontal = StackHorizontal;
|
|
155
|
+
Stack.Vertical = StackVertical;
|