@jobber/components-native 0.2.1 → 0.4.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/dist/src/ActivityIndicator/ActivityIndicator.js +6 -0
- package/dist/src/ActivityIndicator/index.js +1 -0
- package/dist/src/Content/Content.js +24 -0
- package/dist/src/Content/ContentHorizontal.style.js +30 -0
- package/dist/src/Content/ContentSpaceAround.style.js +22 -0
- package/dist/src/Content/ContentVertical.style.js +30 -0
- package/dist/src/Content/index.js +1 -0
- package/dist/src/Text/Text.js +36 -0
- package/dist/src/Text/index.js +1 -0
- package/dist/src/index.js +3 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/src/ActivityIndicator/ActivityIndicator.d.ts +3 -0
- package/dist/types/src/ActivityIndicator/index.d.ts +1 -0
- package/dist/types/src/Content/Content.d.ts +18 -0
- package/dist/types/src/Content/ContentHorizontal.style.d.ts +28 -0
- package/dist/types/src/Content/ContentSpaceAround.style.d.ts +20 -0
- package/dist/types/src/Content/ContentVertical.style.d.ts +22 -0
- package/dist/types/src/Content/index.d.ts +2 -0
- package/dist/types/src/Text/Text.d.ts +56 -0
- package/dist/types/src/Text/index.d.ts +1 -0
- package/dist/types/src/index.d.ts +3 -0
- package/package.json +3 -2
- package/src/ActivityIndicator/ActivityIndicator.test.tsx +28 -0
- package/src/ActivityIndicator/ActivityIndicator.tsx +15 -0
- package/src/ActivityIndicator/index.ts +1 -0
- package/src/Content/Content.test.tsx +260 -0
- package/src/Content/Content.tsx +66 -0
- package/src/Content/ContentHorizontal.style.ts +38 -0
- package/src/Content/ContentSpaceAround.style.ts +28 -0
- package/src/Content/ContentVertical.style.ts +38 -0
- package/src/Content/index.ts +2 -0
- package/src/Text/Text.test.tsx +139 -0
- package/src/Text/Text.tsx +151 -0
- package/src/Text/__snapshots__/Text.test.tsx.snap +618 -0
- package/src/Text/index.ts +1 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { JobberActivityIndicator as ActivityIndicator } from "./ActivityIndicator";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
export type Spacing = "none" | "base" | "small" | "smaller" | "smallest" | "large";
|
|
3
|
+
export interface ContentProps {
|
|
4
|
+
/**
|
|
5
|
+
* The child or children that will be given spacing.
|
|
6
|
+
*/
|
|
7
|
+
readonly children: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* The amount of spacing that content will give.
|
|
10
|
+
*/
|
|
11
|
+
readonly spacing?: Spacing;
|
|
12
|
+
/**
|
|
13
|
+
* The amount of spacing that will be applied between children.
|
|
14
|
+
*/
|
|
15
|
+
readonly childSpacing?: Spacing;
|
|
16
|
+
readonly direction?: "horizontal" | "vertical";
|
|
17
|
+
}
|
|
18
|
+
export declare function Content({ children, spacing, childSpacing, direction, }: ContentProps): JSX.Element;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const horizontalStyles: {
|
|
2
|
+
wrapper: {
|
|
3
|
+
flexDirection: "row";
|
|
4
|
+
};
|
|
5
|
+
childWrapper: {
|
|
6
|
+
flexGrow: number;
|
|
7
|
+
flexShrink: number;
|
|
8
|
+
flexBasis: number;
|
|
9
|
+
};
|
|
10
|
+
noneChildSpace: {
|
|
11
|
+
padding: number;
|
|
12
|
+
};
|
|
13
|
+
smallestChildSpace: {
|
|
14
|
+
paddingLeft: number;
|
|
15
|
+
};
|
|
16
|
+
smallerChildSpace: {
|
|
17
|
+
paddingLeft: number;
|
|
18
|
+
};
|
|
19
|
+
smallChildSpace: {
|
|
20
|
+
paddingLeft: number;
|
|
21
|
+
};
|
|
22
|
+
baseChildSpace: {
|
|
23
|
+
paddingLeft: number;
|
|
24
|
+
};
|
|
25
|
+
largeChildSpace: {
|
|
26
|
+
paddingLeft: number;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare const spaceStyles: {
|
|
2
|
+
noneSpace: {
|
|
3
|
+
padding: number;
|
|
4
|
+
};
|
|
5
|
+
smallestSpace: {
|
|
6
|
+
padding: number;
|
|
7
|
+
};
|
|
8
|
+
smallerSpace: {
|
|
9
|
+
padding: number;
|
|
10
|
+
};
|
|
11
|
+
smallSpace: {
|
|
12
|
+
padding: number;
|
|
13
|
+
};
|
|
14
|
+
baseSpace: {
|
|
15
|
+
padding: number;
|
|
16
|
+
};
|
|
17
|
+
largeSpace: {
|
|
18
|
+
padding: number;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare const verticalStyles: {
|
|
2
|
+
wrapper: {};
|
|
3
|
+
childWrapper: {};
|
|
4
|
+
noneChildSpace: {
|
|
5
|
+
padding: number;
|
|
6
|
+
};
|
|
7
|
+
smallestChildSpace: {
|
|
8
|
+
paddingTop: number;
|
|
9
|
+
};
|
|
10
|
+
smallerChildSpace: {
|
|
11
|
+
paddingTop: number;
|
|
12
|
+
};
|
|
13
|
+
smallChildSpace: {
|
|
14
|
+
paddingTop: number;
|
|
15
|
+
};
|
|
16
|
+
baseChildSpace: {
|
|
17
|
+
paddingTop: number;
|
|
18
|
+
};
|
|
19
|
+
largeChildSpace: {
|
|
20
|
+
paddingTop: number;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { TextAlign, TextVariation, TruncateLength, TypographyProps } from "../Typography";
|
|
3
|
+
interface TextProps extends Pick<TypographyProps<"base">, "maxFontScaleSize" | "selectable"> {
|
|
4
|
+
/**
|
|
5
|
+
* Visual hierarchy of the text
|
|
6
|
+
*/
|
|
7
|
+
readonly level?: TextLevel;
|
|
8
|
+
/**
|
|
9
|
+
* Color variation of text
|
|
10
|
+
*/
|
|
11
|
+
readonly variation?: TextVariation;
|
|
12
|
+
/**
|
|
13
|
+
* Change the appearance of the text
|
|
14
|
+
*/
|
|
15
|
+
readonly emphasis?: "strong";
|
|
16
|
+
/**
|
|
17
|
+
* Allow text to be resized based on user's device display scale
|
|
18
|
+
*/
|
|
19
|
+
readonly allowFontScaling?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Determines whether text should be scaled down to fit based on maxLines prop
|
|
22
|
+
*/
|
|
23
|
+
readonly adjustsFontSizeToFit?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* The maximum amount of lines the text can occupy before being truncated with "...".
|
|
26
|
+
* Uses predefined string values that correspond to a doubling scale for the amount of lines.
|
|
27
|
+
*/
|
|
28
|
+
readonly maxLines?: TruncateLength;
|
|
29
|
+
/**
|
|
30
|
+
* Alignment of text
|
|
31
|
+
*/
|
|
32
|
+
readonly align?: TextAlign;
|
|
33
|
+
/**
|
|
34
|
+
* Text to display
|
|
35
|
+
*/
|
|
36
|
+
readonly children?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Reverse theme for better display on dark background
|
|
39
|
+
*/
|
|
40
|
+
readonly reverseTheme?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Have text styled with strike through
|
|
43
|
+
*/
|
|
44
|
+
readonly strikeThrough?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* This will make the text inaccessible to the screen reader.
|
|
47
|
+
* This should be avoided unless there is a good reason.
|
|
48
|
+
* For example this is used in InputText to make it so the label isn't
|
|
49
|
+
* selectable because it is already read from the accessibilityLabel
|
|
50
|
+
* of the TextInput
|
|
51
|
+
*/
|
|
52
|
+
readonly hideFromScreenReader?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export type TextLevel = "text" | "textSupporting";
|
|
55
|
+
export declare function Text({ level, variation, emphasis, allowFontScaling, adjustsFontSizeToFit, maxLines, align, children, reverseTheme, strikeThrough, hideFromScreenReader, maxFontScaleSize, selectable, }: TextProps): JSX.Element;
|
|
56
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Text, TextLevel } from "./Text";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jobber/components-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"module": "dist/src/index.js",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"@types/react": "^18.0.28",
|
|
33
33
|
"@types/react-native": "^0.71.6",
|
|
34
34
|
"metro-react-native-babel-preset": "^0.76.0",
|
|
35
|
+
"react-test-renderer": "^18.2.0",
|
|
35
36
|
"typescript": "^4.9.5"
|
|
36
37
|
},
|
|
37
38
|
"peerDependencies": {
|
|
@@ -39,5 +40,5 @@
|
|
|
39
40
|
"react": "^18",
|
|
40
41
|
"react-native": ">=0.69.2"
|
|
41
42
|
},
|
|
42
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "d9e4bbca01e3aa0a05ade2c3251681a416214789"
|
|
43
44
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@testing-library/react-native";
|
|
3
|
+
import { ActivityIndicator } from "./index";
|
|
4
|
+
import { tokens } from "../utils/design";
|
|
5
|
+
|
|
6
|
+
const testId = "ActivityIndicator";
|
|
7
|
+
describe("ActivityIndicator", () => {
|
|
8
|
+
it("renders with the default color when no props are provided", () => {
|
|
9
|
+
const { getByTestId } = render(<ActivityIndicator />);
|
|
10
|
+
expect(getByTestId(testId).props.color).toBe(tokens["color-greyBlue"]);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("renders with a custom color", () => {
|
|
14
|
+
const color = "red";
|
|
15
|
+
const { getByTestId } = render(<ActivityIndicator color={color} />);
|
|
16
|
+
expect(getByTestId(testId).props.color).toBe(color);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("renders with large size", () => {
|
|
20
|
+
const size = "large";
|
|
21
|
+
const color = "red";
|
|
22
|
+
const { getByTestId } = render(
|
|
23
|
+
<ActivityIndicator color={color} size={size} />,
|
|
24
|
+
);
|
|
25
|
+
expect(getByTestId(testId).props.size).toBe(size);
|
|
26
|
+
expect(getByTestId(testId).props.color).toBe(color);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ActivityIndicator, ActivityIndicatorProps } from "react-native";
|
|
3
|
+
import { tokens } from "../utils/design";
|
|
4
|
+
|
|
5
|
+
export function JobberActivityIndicator(
|
|
6
|
+
props: ActivityIndicatorProps,
|
|
7
|
+
): JSX.Element {
|
|
8
|
+
return (
|
|
9
|
+
<ActivityIndicator
|
|
10
|
+
{...props}
|
|
11
|
+
color={props.color || tokens["color-greyBlue"]}
|
|
12
|
+
testID={props.testID || "ActivityIndicator"}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { JobberActivityIndicator as ActivityIndicator } from "./ActivityIndicator";
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@testing-library/react-native";
|
|
3
|
+
import { View } from "react-native";
|
|
4
|
+
import { ReactTestInstance } from "react-test-renderer";
|
|
5
|
+
import { Content, ContentProps } from "./Content";
|
|
6
|
+
import { spaceStyles } from "./ContentSpaceAround.style";
|
|
7
|
+
import { verticalStyles } from "./ContentVertical.style";
|
|
8
|
+
import { horizontalStyles } from "./ContentHorizontal.style";
|
|
9
|
+
import { Text } from "../Text";
|
|
10
|
+
|
|
11
|
+
function getContentComponent(parentView: ReactTestInstance) {
|
|
12
|
+
return (parentView?.children[0] as ReactTestInstance)
|
|
13
|
+
?.children[0] as ReactTestInstance;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getContentChildren(contentView: ReactTestInstance) {
|
|
17
|
+
return (contentView.children[0] as ReactTestInstance)
|
|
18
|
+
?.children as ReactTestInstance[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const text = "🌚 I am the text 🌞";
|
|
22
|
+
|
|
23
|
+
function setupContent(
|
|
24
|
+
props?: Pick<ContentProps, "spacing" | "childSpacing" | "direction">,
|
|
25
|
+
) {
|
|
26
|
+
const container = render(
|
|
27
|
+
<View accessibilityLabel="contentView">
|
|
28
|
+
<Content
|
|
29
|
+
spacing={props?.spacing}
|
|
30
|
+
childSpacing={props?.childSpacing}
|
|
31
|
+
direction={props?.direction}
|
|
32
|
+
>
|
|
33
|
+
<Text>{text}</Text>
|
|
34
|
+
<Text>{text}</Text>
|
|
35
|
+
</Content>
|
|
36
|
+
</View>,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const parentView = container.getByLabelText("contentView");
|
|
40
|
+
const contentView = getContentComponent(parentView);
|
|
41
|
+
const contentChildren = getContentChildren(contentView);
|
|
42
|
+
return { ...container, parentView, contentView, contentChildren };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
describe("Space around", () => {
|
|
46
|
+
it("should have a base padding around the component", () => {
|
|
47
|
+
const { contentView } = setupContent();
|
|
48
|
+
expect(contentView.props.style).toContainEqual(spaceStyles.baseSpace);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should have a small padding around the component", () => {
|
|
52
|
+
const { contentView } = setupContent({ spacing: "small" });
|
|
53
|
+
expect(contentView.props.style).toContainEqual(spaceStyles.smallSpace);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should have a large padding around the component", () => {
|
|
57
|
+
const { contentView } = setupContent({ spacing: "large" });
|
|
58
|
+
expect(contentView.props.style).toContainEqual(spaceStyles.largeSpace);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should have a no padding around the component", () => {
|
|
62
|
+
const { contentView } = setupContent({ spacing: "none" });
|
|
63
|
+
expect(contentView.props.style).toContainEqual(spaceStyles.noneSpace);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should have a smaller padding around the component", () => {
|
|
67
|
+
const { contentView } = setupContent({ spacing: "smaller" });
|
|
68
|
+
expect(contentView.props.style).toContainEqual(spaceStyles.smallerSpace);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should have the smallest padding around the component", () => {
|
|
72
|
+
const { contentView } = setupContent({ spacing: "smallest" });
|
|
73
|
+
expect(contentView.props.style).toContainEqual(spaceStyles.smallestSpace);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("Vertical", () => {
|
|
78
|
+
it("should have the vertical wrapper style", () => {
|
|
79
|
+
const { contentView } = setupContent();
|
|
80
|
+
expect(contentView.props.style).toContainEqual(verticalStyles.wrapper);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe("Child space between", () => {
|
|
84
|
+
it("should have a base top padding on every child but the first", () => {
|
|
85
|
+
const { contentChildren } = setupContent({
|
|
86
|
+
direction: "vertical",
|
|
87
|
+
childSpacing: "base",
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
expect(contentChildren[0].props.style).toEqual([
|
|
91
|
+
verticalStyles.childWrapper,
|
|
92
|
+
]);
|
|
93
|
+
expect(contentChildren[1].props.style).toContainEqual(
|
|
94
|
+
verticalStyles.baseChildSpace,
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should have a small top padding on every child but the first", () => {
|
|
99
|
+
const { contentChildren } = setupContent({
|
|
100
|
+
direction: "vertical",
|
|
101
|
+
childSpacing: "small",
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(contentChildren[0].props.style).toEqual([
|
|
105
|
+
verticalStyles.childWrapper,
|
|
106
|
+
]);
|
|
107
|
+
expect(contentChildren[1].props.style).toContainEqual(
|
|
108
|
+
verticalStyles.smallChildSpace,
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should have a large top padding on every child but the first", () => {
|
|
113
|
+
const { contentChildren } = setupContent({
|
|
114
|
+
direction: "vertical",
|
|
115
|
+
childSpacing: "large",
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(contentChildren[0].props.style).toEqual([
|
|
119
|
+
verticalStyles.childWrapper,
|
|
120
|
+
]);
|
|
121
|
+
expect(contentChildren[1].props.style).toContainEqual(
|
|
122
|
+
verticalStyles.largeChildSpace,
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("should have no top padding on every child but the first", () => {
|
|
127
|
+
const { contentChildren } = setupContent({
|
|
128
|
+
direction: "vertical",
|
|
129
|
+
childSpacing: "none",
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
expect(contentChildren[0].props.style).toEqual([
|
|
133
|
+
verticalStyles.childWrapper,
|
|
134
|
+
]);
|
|
135
|
+
expect(contentChildren[1].props.style).toContainEqual(
|
|
136
|
+
verticalStyles.noneChildSpace,
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("should have a smaller top padding on every child but the first", () => {
|
|
141
|
+
const { contentChildren } = setupContent({
|
|
142
|
+
direction: "vertical",
|
|
143
|
+
childSpacing: "smaller",
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
expect(contentChildren[0].props.style).toEqual([
|
|
147
|
+
verticalStyles.childWrapper,
|
|
148
|
+
]);
|
|
149
|
+
expect(contentChildren[1].props.style).toContainEqual(
|
|
150
|
+
verticalStyles.smallerChildSpace,
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should have the smallest top padding on every child but the first", () => {
|
|
155
|
+
const { contentChildren } = setupContent({
|
|
156
|
+
direction: "vertical",
|
|
157
|
+
childSpacing: "smallest",
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
expect(contentChildren[0].props.style).toEqual([
|
|
161
|
+
verticalStyles.childWrapper,
|
|
162
|
+
]);
|
|
163
|
+
expect(contentChildren[1].props.style).toContainEqual(
|
|
164
|
+
verticalStyles.smallestChildSpace,
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe("Horizontal", () => {
|
|
171
|
+
it("should have the horizontal wrapper style", () => {
|
|
172
|
+
const { contentView } = setupContent({ direction: "horizontal" });
|
|
173
|
+
expect(contentView.props.style).toContainEqual(horizontalStyles.wrapper);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe("Child space between", () => {
|
|
177
|
+
it("should have a base left padding on every child but the first", () => {
|
|
178
|
+
const { contentChildren } = setupContent({
|
|
179
|
+
direction: "horizontal",
|
|
180
|
+
childSpacing: "base",
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
expect(contentChildren[0].props.style).toEqual([
|
|
184
|
+
horizontalStyles.childWrapper,
|
|
185
|
+
]);
|
|
186
|
+
expect(contentChildren[1].props.style).toContainEqual(
|
|
187
|
+
horizontalStyles.baseChildSpace,
|
|
188
|
+
);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("should have a small left padding on every child but the first", () => {
|
|
192
|
+
const { contentChildren } = setupContent({
|
|
193
|
+
direction: "horizontal",
|
|
194
|
+
childSpacing: "small",
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
expect(contentChildren[0].props.style).toEqual([
|
|
198
|
+
horizontalStyles.childWrapper,
|
|
199
|
+
]);
|
|
200
|
+
expect(contentChildren[1].props.style).toContainEqual(
|
|
201
|
+
horizontalStyles.smallChildSpace,
|
|
202
|
+
);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("should have a large left padding on every child but the first", () => {
|
|
206
|
+
const { contentChildren } = setupContent({
|
|
207
|
+
direction: "horizontal",
|
|
208
|
+
childSpacing: "large",
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
expect(contentChildren[0].props.style).toEqual([
|
|
212
|
+
horizontalStyles.childWrapper,
|
|
213
|
+
]);
|
|
214
|
+
expect(contentChildren[1].props.style).toContainEqual(
|
|
215
|
+
horizontalStyles.largeChildSpace,
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("should have no left padding on every child but the first", () => {
|
|
220
|
+
const { contentChildren } = setupContent({
|
|
221
|
+
direction: "horizontal",
|
|
222
|
+
childSpacing: "none",
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
expect(contentChildren[0].props.style).toEqual([
|
|
226
|
+
horizontalStyles.childWrapper,
|
|
227
|
+
]);
|
|
228
|
+
expect(contentChildren[1].props.style).toContainEqual(
|
|
229
|
+
horizontalStyles.noneChildSpace,
|
|
230
|
+
);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("should have a smaller left padding on every child but the first", () => {
|
|
234
|
+
const { contentChildren } = setupContent({
|
|
235
|
+
direction: "horizontal",
|
|
236
|
+
childSpacing: "smaller",
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
expect(contentChildren[0].props.style).toEqual([
|
|
240
|
+
horizontalStyles.childWrapper,
|
|
241
|
+
]);
|
|
242
|
+
expect(contentChildren[1].props.style).toContainEqual(
|
|
243
|
+
horizontalStyles.smallerChildSpace,
|
|
244
|
+
);
|
|
245
|
+
});
|
|
246
|
+
it("should have the smallest left padding on every child but the first", () => {
|
|
247
|
+
const { contentChildren } = setupContent({
|
|
248
|
+
direction: "horizontal",
|
|
249
|
+
childSpacing: "smallest",
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
expect(contentChildren[0].props.style).toEqual([
|
|
253
|
+
horizontalStyles.childWrapper,
|
|
254
|
+
]);
|
|
255
|
+
expect(contentChildren[1].props.style).toContainEqual(
|
|
256
|
+
horizontalStyles.smallestChildSpace,
|
|
257
|
+
);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React, { ReactNode } from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { horizontalStyles } from "./ContentHorizontal.style";
|
|
4
|
+
import { verticalStyles } from "./ContentVertical.style";
|
|
5
|
+
import { spaceStyles } from "./ContentSpaceAround.style";
|
|
6
|
+
|
|
7
|
+
export type Spacing =
|
|
8
|
+
| "none"
|
|
9
|
+
| "base"
|
|
10
|
+
| "small"
|
|
11
|
+
| "smaller"
|
|
12
|
+
| "smallest"
|
|
13
|
+
| "large";
|
|
14
|
+
|
|
15
|
+
export interface ContentProps {
|
|
16
|
+
/**
|
|
17
|
+
* The child or children that will be given spacing.
|
|
18
|
+
*/
|
|
19
|
+
readonly children: ReactNode;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The amount of spacing that content will give.
|
|
23
|
+
*/
|
|
24
|
+
readonly spacing?: Spacing;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The amount of spacing that will be applied between children.
|
|
28
|
+
*/
|
|
29
|
+
readonly childSpacing?: Spacing;
|
|
30
|
+
|
|
31
|
+
readonly direction?: "horizontal" | "vertical";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function Content({
|
|
35
|
+
children,
|
|
36
|
+
spacing = "base",
|
|
37
|
+
childSpacing = "base",
|
|
38
|
+
direction = "vertical",
|
|
39
|
+
}: ContentProps): JSX.Element {
|
|
40
|
+
const styles = direction === "horizontal" ? horizontalStyles : verticalStyles;
|
|
41
|
+
const styleName = `${spacing}Space` as const;
|
|
42
|
+
const containerStyle = spaceStyles[styleName];
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<View style={[styles.wrapper, containerStyle]}>{renderChildren()}</View>
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
function renderChildren() {
|
|
49
|
+
const childArray = React.Children.toArray(children);
|
|
50
|
+
if (childArray.length === 1) return children;
|
|
51
|
+
|
|
52
|
+
const spaceName = `${childSpacing}ChildSpace` as const;
|
|
53
|
+
const childContainerStyle = styles[spaceName];
|
|
54
|
+
|
|
55
|
+
return childArray.map((child, index) => {
|
|
56
|
+
// In order to get spacing between the children, we apply the child spacing on each of
|
|
57
|
+
// the children except for the first (top) child
|
|
58
|
+
const childStyle = index !== 0 ? [childContainerStyle] : [];
|
|
59
|
+
return (
|
|
60
|
+
<View key={index} style={[styles.childWrapper, ...childStyle]}>
|
|
61
|
+
{child}
|
|
62
|
+
</View>
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { StyleSheet } from "react-native";
|
|
2
|
+
import { tokens } from "../utils/design";
|
|
3
|
+
|
|
4
|
+
export const horizontalStyles = StyleSheet.create({
|
|
5
|
+
wrapper: {
|
|
6
|
+
flexDirection: "row",
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
childWrapper: {
|
|
10
|
+
flexGrow: 1,
|
|
11
|
+
flexShrink: 1,
|
|
12
|
+
flexBasis: 0,
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
noneChildSpace: {
|
|
16
|
+
padding: 0,
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
smallestChildSpace: {
|
|
20
|
+
paddingLeft: tokens["space-smallest"],
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
smallerChildSpace: {
|
|
24
|
+
paddingLeft: tokens["space-smaller"],
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
smallChildSpace: {
|
|
28
|
+
paddingLeft: tokens["space-small"],
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
baseChildSpace: {
|
|
32
|
+
paddingLeft: tokens["space-base"],
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
largeChildSpace: {
|
|
36
|
+
paddingLeft: tokens["space-large"],
|
|
37
|
+
},
|
|
38
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { StyleSheet } from "react-native";
|
|
2
|
+
import { tokens } from "../utils/design";
|
|
3
|
+
|
|
4
|
+
export const spaceStyles = StyleSheet.create({
|
|
5
|
+
noneSpace: {
|
|
6
|
+
padding: 0,
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
smallestSpace: {
|
|
10
|
+
padding: tokens["space-smallest"],
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
smallerSpace: {
|
|
14
|
+
padding: tokens["space-smaller"],
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
smallSpace: {
|
|
18
|
+
padding: tokens["space-small"],
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
baseSpace: {
|
|
22
|
+
padding: tokens["space-base"],
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
largeSpace: {
|
|
26
|
+
padding: tokens["space-large"],
|
|
27
|
+
},
|
|
28
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { StyleSheet } from "react-native";
|
|
2
|
+
import { tokens } from "../utils/design";
|
|
3
|
+
|
|
4
|
+
export const verticalStyles = StyleSheet.create({
|
|
5
|
+
wrapper: {
|
|
6
|
+
// No style. Default `<View />` styling should suffice.
|
|
7
|
+
// Only need this key to exist.
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
childWrapper: {
|
|
11
|
+
// No style. Default `<View />` styling should suffice.
|
|
12
|
+
// Only need this key to exist.
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
noneChildSpace: {
|
|
16
|
+
padding: 0,
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
smallestChildSpace: {
|
|
20
|
+
paddingTop: tokens["space-smallest"],
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
smallerChildSpace: {
|
|
24
|
+
paddingTop: tokens["space-smaller"],
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
smallChildSpace: {
|
|
28
|
+
paddingTop: tokens["space-small"],
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
baseChildSpace: {
|
|
32
|
+
paddingTop: tokens["space-base"],
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
largeChildSpace: {
|
|
36
|
+
paddingTop: tokens["space-large"],
|
|
37
|
+
},
|
|
38
|
+
});
|