@jobber/components-native 0.42.2 → 0.43.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.
@@ -0,0 +1,5 @@
1
+ /// <reference types="react" />
2
+ import { ThumbnailListProps } from "./types";
3
+ import { File } from "../FormatFile";
4
+ export declare const filterImages: (files: File[]) => File[];
5
+ export declare function ThumbnailList({ files, rowCount, handleOpenFile, createThumbnail, }: ThumbnailListProps): JSX.Element;
@@ -0,0 +1,47 @@
1
+ export declare const styles: {
2
+ list: {
3
+ display: "flex";
4
+ flexDirection: "row";
5
+ flexWrap: "wrap";
6
+ maxHeight: number;
7
+ overflow: "hidden";
8
+ marginTop: number;
9
+ };
10
+ maxDimensionsForThreeRows: {
11
+ maxHeight: number;
12
+ };
13
+ thumbnail: {
14
+ width: number;
15
+ height: number;
16
+ marginRight: number;
17
+ marginBottom: number;
18
+ borderRadius: number;
19
+ borderColor: string;
20
+ borderWidth: number;
21
+ };
22
+ centerThumbnailImage: {
23
+ display: "flex";
24
+ alignItems: "center";
25
+ justifyContent: "center";
26
+ };
27
+ dimensionsThumbnailImage: {
28
+ width: number;
29
+ height: number;
30
+ };
31
+ thumbnailName: {
32
+ position: "absolute";
33
+ right: number;
34
+ bottom: number;
35
+ left: number;
36
+ paddingHorizontal: number;
37
+ paddingVertical: number;
38
+ borderTopColor: string;
39
+ borderTopWidth: number;
40
+ };
41
+ thumbnailIcon: {
42
+ top: number;
43
+ display: "flex";
44
+ alignItems: "center";
45
+ justifyContent: "center";
46
+ };
47
+ };
@@ -0,0 +1,2 @@
1
+ export { ThumbnailList } from "./ThumbnailList";
2
+ export * from "./types";
@@ -0,0 +1,15 @@
1
+ import { CreateThumbnail, File } from "../FormatFile";
2
+ export declare enum RowCount {
3
+ TwoRows = 2,
4
+ ThreeRows = 3
5
+ }
6
+ export interface ThumbnailListProps {
7
+ files: File[];
8
+ rowCount?: RowCount;
9
+ handleOpenFile?: ({ file, index, imageList, }: {
10
+ file: File;
11
+ index: number;
12
+ imageList: File[];
13
+ }) => void;
14
+ createThumbnail: CreateThumbnail;
15
+ }
@@ -34,6 +34,7 @@ export * from "./InputTime";
34
34
  export * from "./InputText";
35
35
  export * from "./Menu";
36
36
  export * from "./TextList";
37
+ export * from "./ThumbnailList";
37
38
  export * from "./ProgressBar";
38
39
  export * from "./Select";
39
40
  export * from "./StatusLabel";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components-native",
3
- "version": "0.42.2",
3
+ "version": "0.43.0",
4
4
  "license": "MIT",
5
5
  "description": "React Native implementation of Atlantis",
6
6
  "repository": {
@@ -79,5 +79,5 @@
79
79
  "react-native": ">=0.69.2",
80
80
  "react-native-modal-datetime-picker": " >=13.0.0"
81
81
  },
82
- "gitHead": "2df6573edb9d186f038ccdad7ef0e8dc5d438f58"
82
+ "gitHead": "7fc42f774c940e8da3e862b6b4f39b174132b669"
83
83
  }
@@ -0,0 +1,50 @@
1
+ import { StyleSheet } from "react-native";
2
+ import { tokens } from "../utils/design";
3
+
4
+ export const styles = StyleSheet.create({
5
+ list: {
6
+ display: "flex",
7
+ flexDirection: "row",
8
+ flexWrap: "wrap",
9
+ maxHeight: (tokens["space-extravagant"] + tokens["space-smaller"]) * 2,
10
+ overflow: "hidden",
11
+ marginTop: tokens["space-smaller"],
12
+ },
13
+ maxDimensionsForThreeRows: {
14
+ maxHeight: (tokens["space-extravagant"] + tokens["space-smaller"]) * 3,
15
+ },
16
+ thumbnail: {
17
+ width: tokens["space-extravagant"],
18
+ height: tokens["space-extravagant"],
19
+ marginRight: tokens["space-smaller"],
20
+ marginBottom: tokens["space-smaller"],
21
+ borderRadius: tokens["radius-base"],
22
+ borderColor: tokens["color-border"],
23
+ borderWidth: tokens["border-base"],
24
+ },
25
+ centerThumbnailImage: {
26
+ display: "flex",
27
+ alignItems: "center",
28
+ justifyContent: "center",
29
+ },
30
+ dimensionsThumbnailImage: {
31
+ width: tokens["space-extravagant"],
32
+ height: tokens["space-extravagant"],
33
+ },
34
+ thumbnailName: {
35
+ position: "absolute",
36
+ right: 0,
37
+ bottom: 0,
38
+ left: 0,
39
+ paddingHorizontal: tokens["space-smaller"],
40
+ paddingVertical: tokens["space-smallest"],
41
+ borderTopColor: tokens["color-border"],
42
+ borderTopWidth: tokens["space-minuscule"],
43
+ },
44
+ thumbnailIcon: {
45
+ top: tokens["space-smaller"],
46
+ display: "flex",
47
+ alignItems: "center",
48
+ justifyContent: "center",
49
+ },
50
+ });
@@ -0,0 +1,81 @@
1
+ import React from "react";
2
+ import { fireEvent, render } from "@testing-library/react-native";
3
+ import { Host } from "react-native-portalize";
4
+ import { ThumbnailList } from "./ThumbnailList";
5
+ import { File } from "../FormatFile/types";
6
+
7
+ const snapshotFile: File[] = [
8
+ {
9
+ contentType: "image/jpeg",
10
+ fileName: "image.jpeg",
11
+ thumbnailUrl: "https://imageurl.com/ababathumb.jpg",
12
+ url: "https://imageurl.com/ababa1.jpg",
13
+ fileSize: 1024,
14
+ },
15
+ ];
16
+
17
+ const files: File[] = [
18
+ {
19
+ contentType: "image/jpeg",
20
+ fileName: "image.jpeg",
21
+ thumbnailUrl: "https://imageurl.com/ababathumb.jpg",
22
+ url: "https://imageurl.com/ababa1.jpg",
23
+ fileSize: 1024,
24
+ },
25
+ {
26
+ contentType: "image/jpeg",
27
+ fileName: "image1.jpeg",
28
+ thumbnailUrl: "https://imageurl.com/ababathumb.jpg",
29
+ url: "https://imageurl.com/ababa2.jpg",
30
+ fileSize: 1024,
31
+ },
32
+ {
33
+ contentType: "pdf",
34
+ fileName: "image2.pdf",
35
+ thumbnailUrl: "https://imageurl.com/ababathumb.jpg",
36
+ url: undefined,
37
+ fileSize: 1024,
38
+ },
39
+ ];
40
+
41
+ const onOpenFile = jest.fn();
42
+ const mockCreateThumbnail = jest.fn(async () => ({
43
+ thumbnail: "thumbnail",
44
+ error: false,
45
+ }));
46
+
47
+ function setup(snapshot?: boolean) {
48
+ return render(
49
+ <Host>
50
+ <ThumbnailList
51
+ files={snapshot ? snapshotFile : files}
52
+ handleOpenFile={onOpenFile}
53
+ createThumbnail={mockCreateThumbnail}
54
+ />
55
+ </Host>,
56
+ );
57
+ }
58
+
59
+ beforeEach(() => {
60
+ jest.clearAllMocks();
61
+ });
62
+
63
+ it("renders a thumbnail component with attachments", () => {
64
+ const tree = setup(true);
65
+ expect(tree.toJSON()).toMatchSnapshot();
66
+ });
67
+
68
+ describe("when a an array of files is provided", () => {
69
+ it("calls the previewImages util on pressing a valid file", () => {
70
+ const { getByLabelText } = setup();
71
+ fireEvent.press(
72
+ getByLabelText(files[0].fileName ? files[0].fileName : "file"),
73
+ );
74
+ expect(onOpenFile).toHaveBeenCalledTimes(1);
75
+ });
76
+
77
+ it("calls createThumbnail", () => {
78
+ setup();
79
+ expect(mockCreateThumbnail).toHaveBeenCalledTimes(2);
80
+ });
81
+ });
@@ -0,0 +1,57 @@
1
+ import React from "react";
2
+ import { View } from "react-native";
3
+ import isNil from "lodash/isNil";
4
+ import { RowCount, ThumbnailListProps } from "./types";
5
+ import { styles } from "./ThumbnailList.style";
6
+ import { File, FormatFile } from "../FormatFile";
7
+
8
+ function isImage(file: File) {
9
+ return !!file.contentType && file.contentType.includes("image/");
10
+ }
11
+
12
+ function hasValidUrl(file: File) {
13
+ return !isNil(file.url);
14
+ }
15
+
16
+ export const filterImages = (files: File[]): File[] => {
17
+ return files.filter((file: File) => {
18
+ return isImage(file) && hasValidUrl(file);
19
+ });
20
+ };
21
+
22
+ export function ThumbnailList({
23
+ files,
24
+ rowCount = RowCount.TwoRows,
25
+ handleOpenFile,
26
+ createThumbnail,
27
+ }: ThumbnailListProps): JSX.Element {
28
+ const imageList = filterImages(files);
29
+
30
+ return (
31
+ <View
32
+ style={[
33
+ styles.list,
34
+ rowCount === RowCount.ThreeRows && styles.maxDimensionsForThreeRows,
35
+ ]}
36
+ >
37
+ {files.map((file, index) => {
38
+ return (
39
+ <FormatFile
40
+ file={file}
41
+ accessibilityLabel={file.fileName}
42
+ key={`${file.fileName}-${index}`}
43
+ styleInGrid
44
+ onTap={openFile(file, index)}
45
+ createThumbnail={createThumbnail}
46
+ />
47
+ );
48
+ })}
49
+ </View>
50
+ );
51
+
52
+ function openFile(file: File, index: number) {
53
+ return () => {
54
+ handleOpenFile?.({ file, index, imageList });
55
+ };
56
+ }
57
+ }
@@ -0,0 +1,154 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`renders a thumbnail component with attachments 1`] = `
4
+ [
5
+ <View
6
+ collapsable={false}
7
+ pointerEvents="box-none"
8
+ style={
9
+ [
10
+ {
11
+ "flex": 1,
12
+ },
13
+ undefined,
14
+ ]
15
+ }
16
+ >
17
+ <View
18
+ style={
19
+ [
20
+ {
21
+ "display": "flex",
22
+ "flexDirection": "row",
23
+ "flexWrap": "wrap",
24
+ "marginTop": 4,
25
+ "maxHeight": 136,
26
+ "overflow": "hidden",
27
+ },
28
+ false,
29
+ ]
30
+ }
31
+ >
32
+ <View>
33
+ <View
34
+ accessibilityHint="Select for more options"
35
+ accessibilityRole="imagebutton"
36
+ accessibilityState={
37
+ {
38
+ "busy": undefined,
39
+ "checked": undefined,
40
+ "disabled": undefined,
41
+ "expanded": undefined,
42
+ "selected": undefined,
43
+ }
44
+ }
45
+ accessibilityValue={
46
+ {
47
+ "max": undefined,
48
+ "min": undefined,
49
+ "now": undefined,
50
+ "text": undefined,
51
+ }
52
+ }
53
+ accessible={true}
54
+ collapsable={false}
55
+ focusable={true}
56
+ onClick={[Function]}
57
+ onResponderGrant={[Function]}
58
+ onResponderMove={[Function]}
59
+ onResponderRelease={[Function]}
60
+ onResponderTerminate={[Function]}
61
+ onResponderTerminationRequest={[Function]}
62
+ onStartShouldSetResponder={[Function]}
63
+ style={
64
+ {
65
+ "opacity": 1,
66
+ }
67
+ }
68
+ >
69
+ <View
70
+ style={
71
+ [
72
+ {
73
+ "backgroundColor": "rgb(244, 244, 244)",
74
+ "borderColor": "rgb(225, 225, 225)",
75
+ "borderRadius": 2,
76
+ "borderWidth": 1,
77
+ "marginBottom": 8,
78
+ },
79
+ {
80
+ "height": 64,
81
+ "marginRight": 8,
82
+ "width": 64,
83
+ },
84
+ ]
85
+ }
86
+ >
87
+ <View
88
+ accessibilityLabel="image.jpeg"
89
+ accessible={true}
90
+ >
91
+ <View
92
+ accessibilityIgnoresInvertColors={true}
93
+ style={
94
+ [
95
+ {
96
+ "alignItems": "center",
97
+ "justifyContent": "center",
98
+ "width": "100%",
99
+ },
100
+ {
101
+ "height": "100%",
102
+ },
103
+ ]
104
+ }
105
+ >
106
+ <Image
107
+ onLoadEnd={[Function]}
108
+ onLoadStart={[Function]}
109
+ resizeMode="cover"
110
+ source={
111
+ {
112
+ "uri": "https://imageurl.com/ababathumb.jpg",
113
+ }
114
+ }
115
+ style={
116
+ [
117
+ {
118
+ "bottom": 0,
119
+ "left": 0,
120
+ "position": "absolute",
121
+ "right": 0,
122
+ "top": 0,
123
+ },
124
+ {
125
+ "height": "100%",
126
+ "width": "100%",
127
+ },
128
+ undefined,
129
+ ]
130
+ }
131
+ testID="test-image"
132
+ />
133
+ </View>
134
+ </View>
135
+ </View>
136
+ </View>
137
+ </View>
138
+ </View>
139
+ </View>,
140
+ <View
141
+ collapsable={false}
142
+ pointerEvents="box-none"
143
+ style={
144
+ {
145
+ "bottom": 0,
146
+ "left": 0,
147
+ "position": "absolute",
148
+ "right": 0,
149
+ "top": 0,
150
+ }
151
+ }
152
+ />,
153
+ ]
154
+ `;
@@ -0,0 +1,2 @@
1
+ export { ThumbnailList } from "./ThumbnailList";
2
+ export * from "./types";
@@ -0,0 +1,21 @@
1
+ import { CreateThumbnail, File } from "../FormatFile";
2
+
3
+ export enum RowCount {
4
+ TwoRows = 2,
5
+ ThreeRows = 3,
6
+ }
7
+
8
+ export interface ThumbnailListProps {
9
+ files: File[];
10
+ rowCount?: RowCount;
11
+ handleOpenFile?: ({
12
+ file,
13
+ index,
14
+ imageList,
15
+ }: {
16
+ file: File;
17
+ index: number;
18
+ imageList: File[];
19
+ }) => void;
20
+ createThumbnail: CreateThumbnail;
21
+ }
package/src/index.ts CHANGED
@@ -34,6 +34,7 @@ export * from "./InputTime";
34
34
  export * from "./InputText";
35
35
  export * from "./Menu";
36
36
  export * from "./TextList";
37
+ export * from "./ThumbnailList";
37
38
  export * from "./ProgressBar";
38
39
  export * from "./Select";
39
40
  export * from "./StatusLabel";