@jobber/components-native 0.54.4-JOB-88641.9 → 0.54.4-fix-inline.6
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/package.json +7 -7
- package/dist/src/ActionItem/ActionItem.js +1 -1
- package/dist/src/Banner/Banner.js +1 -1
- package/dist/src/Button/Button.js +2 -2
- package/dist/src/Button/Button.style.js +2 -2
- package/dist/src/Button/components/InternalButtonLoading/InternalButtonLoading.js +3 -0
- package/dist/src/ButtonGroup/ButtonGroup.js +1 -1
- package/dist/src/ButtonGroup/ButtonGroup.style.js +1 -1
- package/dist/src/Card/Card.js +7 -8
- package/dist/src/Disclosure/Disclosure.js +3 -3
- package/dist/src/Glimmer/Glimmer.js +42 -0
- package/dist/src/Glimmer/Glimmer.shape.style.js +16 -0
- package/dist/src/Glimmer/Glimmer.size.style.js +9 -0
- package/dist/src/Glimmer/Glimmer.style.js +20 -0
- package/dist/src/Glimmer/index.js +1 -0
- package/dist/src/InputCurrency/InputCurrency.js +16 -17
- package/dist/src/InputFieldWrapper/InputFieldWrapper.js +39 -18
- package/dist/src/InputFieldWrapper/InputFieldWrapper.style.js +38 -1
- package/dist/src/InputText/InputText.js +6 -3
- package/dist/src/Menu/Menu.js +20 -3
- package/dist/src/Menu/Menu.style.js +1 -1
- package/dist/src/Menu/utils.js +2 -7
- package/dist/src/index.js +6 -5
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/src/BottomSheet/components/BottomSheetOption/BottomSheetOption.d.ts +1 -1
- package/dist/types/src/ButtonGroup/ButtonGroup.style.d.ts +1 -1
- package/dist/types/src/ButtonGroup/components/SecondaryActionSheet/SecondaryActionSheet.d.ts +6 -6
- package/dist/types/src/Checkbox/CheckboxGroup.d.ts +2 -2
- package/dist/types/src/Form/components/FormBody/FormBody.d.ts +3 -3
- package/dist/types/src/Form/components/FormCache/FormCache.d.ts +4 -4
- package/dist/types/src/Form/components/FormMessageBanner/FormMessageBanner.d.ts +1 -1
- package/dist/types/src/FormField/FormField.d.ts +2 -2
- package/dist/types/src/FormatFile/FormatFile.d.ts +6 -6
- package/dist/types/src/FormatFile/components/FileView/FileView.d.ts +6 -6
- package/dist/types/src/FormatFile/components/FormatFileBottomSheet/FormatFileBottomSheet.d.ts +4 -4
- package/dist/types/src/FormatFile/components/MediaView/MediaView.d.ts +6 -6
- package/dist/types/src/FormatFile/components/ProgressBar/ProgressBar.d.ts +3 -3
- package/dist/types/src/Glimmer/Glimmer.d.ts +31 -0
- package/dist/types/src/Glimmer/Glimmer.shape.style.d.ts +14 -0
- package/dist/types/src/Glimmer/Glimmer.size.style.d.ts +17 -0
- package/dist/types/src/Glimmer/Glimmer.style.d.ts +18 -0
- package/dist/types/src/Glimmer/index.d.ts +1 -0
- package/dist/types/src/InputCurrency/InputCurrency.d.ts +3 -3
- package/dist/types/src/InputFieldWrapper/InputFieldWrapper.d.ts +19 -1
- package/dist/types/src/InputFieldWrapper/InputFieldWrapper.style.d.ts +34 -0
- package/dist/types/src/InputFieldWrapper/components/Prefix/Prefix.d.ts +12 -12
- package/dist/types/src/InputFieldWrapper/components/Suffix/Suffix.d.ts +14 -14
- package/dist/types/src/InputPassword/InputPassword.d.ts +1 -1
- package/dist/types/src/InputText/InputText.d.ts +6 -2
- package/dist/types/src/InputText/context/InputAccessoriesProvider.d.ts +1 -1
- package/dist/types/src/Toast/Toast.d.ts +1 -1
- package/dist/types/src/index.d.ts +6 -5
- package/dist/types/src/utils/test/MockSafeAreaProvider.d.ts +3 -3
- package/jestSetup.js +2 -0
- package/package.json +7 -7
- package/src/ActionItem/ActionItem.test.tsx +2 -2
- package/src/ActionItem/ActionItem.tsx +3 -1
- package/src/ActionItem/ActionItemGroup.tsx +1 -0
- package/src/AutoLink/hooks/useCreateLinkedText.ts +1 -0
- package/src/AutoLink/hooks/useTokenGenerator.ts +1 -0
- package/src/Banner/Banner.tsx +1 -1
- package/src/BottomSheet/BottomSheet.tsx +3 -3
- package/src/BottomSheet/components/BottomSheetOption/BottomSheetOption.tsx +3 -1
- package/src/Button/Button.style.ts +2 -2
- package/src/Button/Button.test.tsx +2 -2
- package/src/Button/Button.tsx +2 -2
- package/src/Button/components/InternalButtonLoading/InternalButtonLoading.tsx +4 -0
- package/src/ButtonGroup/ButtonGroup.style.ts +1 -1
- package/src/ButtonGroup/ButtonGroup.tsx +1 -0
- package/src/ButtonGroup/components/SecondaryActionSheet/SecondaryActionSheet.tsx +7 -6
- package/src/Card/Card.tsx +31 -32
- package/src/Card/components/InternalCardHeader.tsx +1 -0
- package/src/Checkbox/CheckboxGroup.tsx +12 -2
- package/src/Chip/Chip.tsx +2 -0
- package/src/Content/Content.test.tsx +1 -0
- package/src/Content/Content.tsx +1 -0
- package/src/ContentOverlay/ContentOverlay.test.tsx +1 -0
- package/src/Disclosure/Disclosure.tsx +3 -8
- package/src/Disclosure/__snapshots__/Disclosure.test.tsx.snap +18 -24
- package/src/Divider/Divider.tsx +1 -0
- package/src/EmptyState/EmptyState.tsx +2 -2
- package/src/Flex/Flex.styles.tsx +1 -0
- package/src/Flex/Flex.test.tsx +2 -0
- package/src/Form/Form.test.tsx +19 -14
- package/src/Form/components/FormBody/FormBody.tsx +4 -3
- package/src/Form/components/FormCache/FormCache.tsx +5 -4
- package/src/Form/components/FormMessage/FormMessage.tsx +1 -0
- package/src/Form/components/FormMessageBanner/FormMessageBanner.tsx +1 -1
- package/src/Form/components/FormSaveButton/FormSaveButton.test.tsx +5 -5
- package/src/Form/context/AtlantisFormContext.tsx +1 -0
- package/src/Form/hooks/useFormViewRefs.ts +1 -0
- package/src/Form/hooks/useOfflineHandler.ts +1 -0
- package/src/Form/hooks/useScrollToError/useScrollToError.ts +2 -0
- package/src/FormField/FormField.test.tsx +6 -8
- package/src/FormField/FormField.tsx +2 -2
- package/src/FormatFile/FormatFile.tsx +15 -14
- package/src/FormatFile/components/FileView/FileView.tsx +9 -6
- package/src/FormatFile/components/FormatFileBottomSheet/FormatFileBottomSheet.tsx +4 -4
- package/src/FormatFile/components/MediaView/MediaView.tsx +15 -14
- package/src/FormatFile/components/ProgressBar/ProgressBar.tsx +3 -3
- package/src/FormatFile/utils/createUseCreateThumbnail.ts +1 -0
- package/src/Glimmer/Glimmer.shape.style.ts +17 -0
- package/src/Glimmer/Glimmer.size.style.ts +10 -0
- package/src/Glimmer/Glimmer.style.ts +23 -0
- package/src/Glimmer/Glimmer.test.tsx +73 -0
- package/src/Glimmer/Glimmer.tsx +106 -0
- package/src/Glimmer/index.ts +1 -0
- package/src/Heading/__snapshots__/Heading.test.tsx.snap +7 -7
- package/src/Icon/Icon.tsx +1 -0
- package/src/Icon/__snapshots__/Icon.test.tsx.snap +96 -31
- package/src/InputCurrency/InputCurrency.tsx +40 -38
- package/src/InputCurrency/utils.ts +9 -0
- package/src/InputDate/InputDate.test.tsx +1 -0
- package/src/InputFieldWrapper/InputFieldWrapper.style.ts +46 -1
- package/src/InputFieldWrapper/InputFieldWrapper.test.tsx +74 -0
- package/src/InputFieldWrapper/InputFieldWrapper.tsx +131 -64
- package/src/InputFieldWrapper/components/ClearAction/ClearAction.tsx +1 -0
- package/src/InputFieldWrapper/components/Prefix/Prefix.tsx +12 -12
- package/src/InputFieldWrapper/components/Suffix/Suffix.tsx +14 -14
- package/src/InputNumber/InputNumber.tsx +8 -0
- package/src/InputPassword/InputPassword.test.tsx +1 -0
- package/src/InputPassword/InputPassword.tsx +2 -1
- package/src/InputPressable/InputPressable.test.tsx +1 -0
- package/src/InputSearch/InputSearch.tsx +1 -0
- package/src/InputText/InputText.test.tsx +11 -0
- package/src/InputText/InputText.tsx +27 -2
- package/src/InputText/context/InputAccessoriesProvider.test.tsx +6 -1
- package/src/InputText/context/InputAccessoriesProvider.tsx +1 -1
- package/src/InputTime/utils/index.ts +1 -0
- package/src/Menu/Menu.style.ts +1 -1
- package/src/Menu/Menu.tsx +23 -2
- package/src/Menu/components/MenuOption/MenuOption.tsx +1 -0
- package/src/Menu/utils.ts +3 -7
- package/src/ProgressBar/ProgressBarInner.tsx +1 -0
- package/src/ProgressBar/__snapshots__/ProgressBar.test.tsx.snap +4 -4
- package/src/Select/components/SelectInternalPicker/SelectInternalPicker.tsx +1 -0
- package/src/Select/components/SelectInternalPicker/utils.ts +1 -0
- package/src/StatusLabel/StatusLabel.tsx +1 -1
- package/src/StatusLabel/__snapshots__/StatusLabel.test.tsx.snap +20 -20
- package/src/Switch/components/BaseSwitch/BaseSwitch.tsx +1 -0
- package/src/Switch/components/BaseSwitch/__snapshots__/BaseSwitch.test.tsx.snap +18 -18
- package/src/Text/Text.tsx +1 -0
- package/src/Text/__snapshots__/Text.test.tsx.snap +9 -9
- package/src/ThumbnailList/__snapshots__/ThumbnailList.test.tsx.snap +3 -3
- package/src/Toast/Toast.tsx +2 -1
- package/src/Typography/Typography.tsx +5 -0
- package/src/Typography/__snapshots__/Typography.test.tsx.snap +3 -3
- package/src/hooks/useAtlantisI18n/utils/dateFormatter.ts +1 -0
- package/src/hooks/useFormController.ts +2 -0
- package/src/index.ts +6 -5
- package/src/utils/intl/capitalize.ts +1 -0
- package/src/utils/test/MockSafeAreaProvider.tsx +3 -3
|
@@ -6,9 +6,9 @@ import { FormActionBar, FormActionBarProps } from "../FormActionBar";
|
|
|
6
6
|
import { tokens } from "../../../utils/design";
|
|
7
7
|
|
|
8
8
|
interface FormBodyProps extends FormActionBarProps {
|
|
9
|
-
children: JSX.Element;
|
|
10
|
-
shouldRenderActionBar?: boolean;
|
|
11
|
-
saveButtonOffset?: number;
|
|
9
|
+
readonly children: JSX.Element;
|
|
10
|
+
readonly shouldRenderActionBar?: boolean;
|
|
11
|
+
readonly saveButtonOffset?: number;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function FormBody({
|
|
@@ -58,5 +58,6 @@ export function FormBody({
|
|
|
58
58
|
export function useBottomPadding(): number {
|
|
59
59
|
const { insets } = useScreenInformation();
|
|
60
60
|
const extraBottomSpace = insets.bottom - tokens["space-base"];
|
|
61
|
+
|
|
61
62
|
return extraBottomSpace >= 0 ? extraBottomSpace : 0;
|
|
62
63
|
}
|
|
@@ -3,11 +3,12 @@ import { FieldValues, useFormContext, useWatch } from "react-hook-form";
|
|
|
3
3
|
import omit from "lodash/omit";
|
|
4
4
|
|
|
5
5
|
interface FormCacheProps<T extends FieldValues> {
|
|
6
|
-
localCacheId?: string | string[];
|
|
7
|
-
localCacheKey?: string;
|
|
8
|
-
localCacheExclude?: string[];
|
|
9
|
-
setLocalCache: (data: T) => void;
|
|
6
|
+
readonly localCacheId?: string | string[];
|
|
7
|
+
readonly localCacheKey?: string;
|
|
8
|
+
readonly localCacheExclude?: string[];
|
|
9
|
+
readonly setLocalCache: (data: T) => void;
|
|
10
10
|
}
|
|
11
|
+
|
|
11
12
|
export function FormCache<T extends FieldValues>({
|
|
12
13
|
localCacheExclude,
|
|
13
14
|
localCacheKey,
|
|
@@ -3,7 +3,7 @@ import { FormBannerMessage, FormBannerMessageType } from "../../types";
|
|
|
3
3
|
import { Banner, BannerTypes } from "../../../Banner";
|
|
4
4
|
|
|
5
5
|
interface FormMessageBannerProps {
|
|
6
|
-
bannerMessages?: FormBannerMessage[];
|
|
6
|
+
readonly bannerMessages?: FormBannerMessage[];
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export function FormMessageBanner({
|
|
@@ -16,11 +16,11 @@ interface TestSecondaryActionProp {
|
|
|
16
16
|
destructive?: boolean;
|
|
17
17
|
}
|
|
18
18
|
interface TestFormSaveButtonProps {
|
|
19
|
-
primaryAction: () => Promise<void>;
|
|
20
|
-
loading: boolean;
|
|
21
|
-
label?: string;
|
|
22
|
-
secondaryAction?: TestSecondaryActionProp[];
|
|
23
|
-
setSecondaryActionLoading: (bool: boolean) => void;
|
|
19
|
+
readonly primaryAction: () => Promise<void>;
|
|
20
|
+
readonly loading: boolean;
|
|
21
|
+
readonly label?: string;
|
|
22
|
+
readonly secondaryAction?: TestSecondaryActionProp[];
|
|
23
|
+
readonly setSecondaryActionLoading: (bool: boolean) => void;
|
|
24
24
|
}
|
|
25
25
|
jest.mock("react-hook-form", () => ({
|
|
26
26
|
...jest.requireActual("react-hook-form"),
|
|
@@ -33,6 +33,7 @@ export function useScrollToError<T extends FieldValues>({
|
|
|
33
33
|
// went up.
|
|
34
34
|
const hasBeenSubmitted = submitCounter < submitCount;
|
|
35
35
|
if (!hasBeenSubmitted) return;
|
|
36
|
+
|
|
36
37
|
if (isScreenReaderEnabled) {
|
|
37
38
|
manuallyScrollToElement();
|
|
38
39
|
Keyboard.dismiss();
|
|
@@ -44,6 +45,7 @@ export function useScrollToError<T extends FieldValues>({
|
|
|
44
45
|
|
|
45
46
|
function defaultAutoScroll() {
|
|
46
47
|
if (isValid) return;
|
|
48
|
+
|
|
47
49
|
try {
|
|
48
50
|
focusInputWithRHF(errors, setFocus);
|
|
49
51
|
} catch {
|
|
@@ -78,14 +78,12 @@ describe("when a component is wrapped in a FormField within a Form", () => {
|
|
|
78
78
|
>
|
|
79
79
|
{field => {
|
|
80
80
|
return (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
/>
|
|
88
|
-
</>
|
|
81
|
+
<InputText
|
|
82
|
+
name={field.name}
|
|
83
|
+
accessibilityLabel={inputAccessibilityLabel}
|
|
84
|
+
value={field.value}
|
|
85
|
+
onChangeText={field.onChange}
|
|
86
|
+
/>
|
|
89
87
|
);
|
|
90
88
|
}}
|
|
91
89
|
</FormField>
|
|
@@ -11,7 +11,7 @@ interface FormFieldProps<T> {
|
|
|
11
11
|
/**
|
|
12
12
|
* Name of the field.
|
|
13
13
|
*/
|
|
14
|
-
name: string;
|
|
14
|
+
readonly name: string;
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* The initial value of the form field.
|
|
@@ -21,7 +21,7 @@ interface FormFieldProps<T> {
|
|
|
21
21
|
/**
|
|
22
22
|
* Children to render.
|
|
23
23
|
*/
|
|
24
|
-
children: (
|
|
24
|
+
readonly children: (
|
|
25
25
|
field: ControllerRenderProps<FieldValues, string>,
|
|
26
26
|
error?: FieldError,
|
|
27
27
|
) => React.ReactNode;
|
|
@@ -24,7 +24,7 @@ export interface FormatFileProps<T> {
|
|
|
24
24
|
/**
|
|
25
25
|
* File upload details object. Can be a File or a FileUpload
|
|
26
26
|
*/
|
|
27
|
-
file: T;
|
|
27
|
+
readonly file: T;
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* Accessibility label
|
|
@@ -38,25 +38,25 @@ export interface FormatFileProps<T> {
|
|
|
38
38
|
/**
|
|
39
39
|
* A function which handles the onTap event.
|
|
40
40
|
*/
|
|
41
|
-
onTap?: (file: T) => void;
|
|
41
|
+
readonly onTap?: (file: T) => void;
|
|
42
42
|
/**
|
|
43
43
|
* A function to be called on "Remove" Bottom Sheet Option press
|
|
44
44
|
*/
|
|
45
|
-
onRemove?: () => void;
|
|
45
|
+
readonly onRemove?: () => void;
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Handler for the "Preview" Bottom Sheet Option press
|
|
49
49
|
*/
|
|
50
|
-
onPreviewPress?: (formattedFile: FormattedFile) => void;
|
|
50
|
+
readonly onPreviewPress?: (formattedFile: FormattedFile) => void;
|
|
51
51
|
/**
|
|
52
52
|
* A file type to show at Bottom Sheet options
|
|
53
53
|
*/
|
|
54
|
-
bottomSheetOptionsSuffix?: BottomSheetOptionsSuffix;
|
|
54
|
+
readonly bottomSheetOptionsSuffix?: BottomSheetOptionsSuffix;
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Uses a grid layout when multi-file upload is supported
|
|
58
58
|
*/
|
|
59
|
-
styleInGrid?: boolean;
|
|
59
|
+
readonly styleInGrid?: boolean;
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* A reference to the element in the rendered output
|
|
@@ -75,17 +75,17 @@ type FormatFileInternalProps = Omit<
|
|
|
75
75
|
FormatFileProps<File | FileUpload>,
|
|
76
76
|
"file" | "onTap"
|
|
77
77
|
> & {
|
|
78
|
-
file: FormattedFile;
|
|
79
|
-
onTap: () => void;
|
|
78
|
+
readonly file: FormattedFile;
|
|
79
|
+
readonly onTap: () => void;
|
|
80
80
|
};
|
|
81
81
|
|
|
82
82
|
interface FormatFileContentProps {
|
|
83
|
-
accessibilityLabel?: string;
|
|
84
|
-
file: FormattedFile;
|
|
85
|
-
showOverlay: boolean;
|
|
86
|
-
styleInGrid: boolean;
|
|
87
|
-
onUploadComplete: () => void;
|
|
88
|
-
isMedia: boolean;
|
|
83
|
+
readonly accessibilityLabel?: string;
|
|
84
|
+
readonly file: FormattedFile;
|
|
85
|
+
readonly showOverlay: boolean;
|
|
86
|
+
readonly styleInGrid: boolean;
|
|
87
|
+
readonly onUploadComplete: () => void;
|
|
88
|
+
readonly isMedia: boolean;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
function FormatFileContent({
|
|
@@ -288,6 +288,7 @@ function FormatFileInternal({
|
|
|
288
288
|
function handleOnPress() {
|
|
289
289
|
if (showOverlay || !onRemove) {
|
|
290
290
|
onTap();
|
|
291
|
+
|
|
291
292
|
return;
|
|
292
293
|
}
|
|
293
294
|
|
|
@@ -11,12 +11,12 @@ import { ErrorIcon } from "../ErrorIcon";
|
|
|
11
11
|
import { useAtlantisI18n } from "../../../hooks/useAtlantisI18n";
|
|
12
12
|
|
|
13
13
|
interface FileViewProps {
|
|
14
|
-
accessibilityLabel?: string;
|
|
15
|
-
showOverlay: boolean;
|
|
16
|
-
showError: boolean;
|
|
17
|
-
file: FormattedFile;
|
|
18
|
-
styleInGrid: boolean;
|
|
19
|
-
onUploadComplete: () => void;
|
|
14
|
+
readonly accessibilityLabel?: string;
|
|
15
|
+
readonly showOverlay: boolean;
|
|
16
|
+
readonly showError: boolean;
|
|
17
|
+
readonly file: FormattedFile;
|
|
18
|
+
readonly styleInGrid: boolean;
|
|
19
|
+
readonly onUploadComplete: () => void;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export function FileView({
|
|
@@ -37,6 +37,7 @@ export function FileView({
|
|
|
37
37
|
|
|
38
38
|
const freezeProgressBar =
|
|
39
39
|
file.status !== StatusCode.Completed && file.progress >= 0.9;
|
|
40
|
+
|
|
40
41
|
return (
|
|
41
42
|
<View
|
|
42
43
|
style={[
|
|
@@ -107,6 +108,7 @@ interface FileTypeToIconNameParams {
|
|
|
107
108
|
fileName?: string;
|
|
108
109
|
fileType?: string;
|
|
109
110
|
}
|
|
111
|
+
|
|
110
112
|
function mapFileTypeToIconName({
|
|
111
113
|
fileName,
|
|
112
114
|
fileType,
|
|
@@ -114,6 +116,7 @@ function mapFileTypeToIconName({
|
|
|
114
116
|
if (!fileName && !fileType) {
|
|
115
117
|
return "alert";
|
|
116
118
|
}
|
|
119
|
+
|
|
117
120
|
if (fileType?.includes("pdf") || fileName?.match(/~*.pdf$/)) {
|
|
118
121
|
return "pdf";
|
|
119
122
|
} else if (
|
|
@@ -7,10 +7,10 @@ import { useAtlantisI18n } from "../../../hooks/useAtlantisI18n";
|
|
|
7
7
|
export type BottomSheetOptionsSuffix = "receipt" | "image" | "file" | "video";
|
|
8
8
|
|
|
9
9
|
interface FormatFileBottomSheetProps {
|
|
10
|
-
bottomSheetRef: RefObject<BottomSheetRef>;
|
|
11
|
-
onPreviewPress?: () => void;
|
|
12
|
-
onRemovePress?: () => void;
|
|
13
|
-
bottomSheetOptionsSuffix?: BottomSheetOptionsSuffix;
|
|
10
|
+
readonly bottomSheetRef: RefObject<BottomSheetRef>;
|
|
11
|
+
readonly onPreviewPress?: () => void;
|
|
12
|
+
readonly onRemovePress?: () => void;
|
|
13
|
+
readonly bottomSheetOptionsSuffix?: BottomSheetOptionsSuffix;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export const FormatFileBottomSheet = ({
|
|
@@ -11,12 +11,12 @@ import { useAtlantisFormatFileContext } from "../../context/FormatFileContext";
|
|
|
11
11
|
import { useAtlantisI18n } from "../../../hooks/useAtlantisI18n";
|
|
12
12
|
|
|
13
13
|
interface MediaViewProps {
|
|
14
|
-
accessibilityLabel?: string;
|
|
15
|
-
showOverlay: boolean;
|
|
16
|
-
showError: boolean;
|
|
17
|
-
file: FormattedFile;
|
|
18
|
-
styleInGrid: boolean;
|
|
19
|
-
onUploadComplete: () => void;
|
|
14
|
+
readonly accessibilityLabel?: string;
|
|
15
|
+
readonly showOverlay: boolean;
|
|
16
|
+
readonly showError: boolean;
|
|
17
|
+
readonly file: FormattedFile;
|
|
18
|
+
readonly styleInGrid: boolean;
|
|
19
|
+
readonly onUploadComplete: () => void;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export function MediaView({
|
|
@@ -68,11 +68,11 @@ export function MediaView({
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
interface OverlayProps {
|
|
71
|
-
isLoading: boolean;
|
|
72
|
-
showOverlay: boolean;
|
|
73
|
-
hasError: boolean;
|
|
74
|
-
file: FormattedFile;
|
|
75
|
-
onUploadComplete: () => void;
|
|
71
|
+
readonly isLoading: boolean;
|
|
72
|
+
readonly showOverlay: boolean;
|
|
73
|
+
readonly hasError: boolean;
|
|
74
|
+
readonly file: FormattedFile;
|
|
75
|
+
readonly onUploadComplete: () => void;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
function Overlay({
|
|
@@ -104,9 +104,9 @@ function Overlay({
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
interface ProgressOverlayProps {
|
|
107
|
-
status: StatusCode;
|
|
108
|
-
progress: number;
|
|
109
|
-
onUploadComplete: () => void;
|
|
107
|
+
readonly status: StatusCode;
|
|
108
|
+
readonly progress: number;
|
|
109
|
+
readonly onUploadComplete: () => void;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
function ProgressOverlay({
|
|
@@ -115,6 +115,7 @@ function ProgressOverlay({
|
|
|
115
115
|
onUploadComplete,
|
|
116
116
|
}: ProgressOverlayProps) {
|
|
117
117
|
const freezeProgressBar = status !== StatusCode.Completed && progress >= 0.9;
|
|
118
|
+
|
|
118
119
|
return (
|
|
119
120
|
<View
|
|
120
121
|
style={[styles.imageBackground, styles.overlay]}
|
|
@@ -7,15 +7,15 @@ interface ProgressBarProps {
|
|
|
7
7
|
/**
|
|
8
8
|
* Upload progress value from 0 to 1
|
|
9
9
|
*/
|
|
10
|
-
progress: number;
|
|
10
|
+
readonly progress: number;
|
|
11
11
|
/**
|
|
12
12
|
* Upload status
|
|
13
13
|
*/
|
|
14
|
-
status: StatusCode;
|
|
14
|
+
readonly status: StatusCode;
|
|
15
15
|
/**
|
|
16
16
|
* Function to be called when the progress is finished
|
|
17
17
|
*/
|
|
18
|
-
onComplete?: () => void;
|
|
18
|
+
readonly onComplete?: () => void;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export const ProgressBar = ({
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { StyleSheet } from "react-native";
|
|
2
|
+
import { tokens } from "../utils/design";
|
|
3
|
+
|
|
4
|
+
export const shapeStyles = StyleSheet.create({
|
|
5
|
+
rectangle: {
|
|
6
|
+
width: "100%",
|
|
7
|
+
},
|
|
8
|
+
square: {
|
|
9
|
+
width: "auto",
|
|
10
|
+
aspectRatio: 1 / 1,
|
|
11
|
+
},
|
|
12
|
+
circle: {
|
|
13
|
+
width: "auto",
|
|
14
|
+
aspectRatio: 1 / 1,
|
|
15
|
+
borderRadius: tokens["radius-circle"],
|
|
16
|
+
},
|
|
17
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { StyleSheet } from "react-native";
|
|
2
|
+
import { tokens } from "../utils/design";
|
|
3
|
+
|
|
4
|
+
export const sizeStyles = StyleSheet.create({
|
|
5
|
+
small: { height: tokens["space-small"] },
|
|
6
|
+
base: { height: tokens["space-base"] },
|
|
7
|
+
large: { height: tokens["space-large"] },
|
|
8
|
+
larger: { height: tokens["space-larger"] },
|
|
9
|
+
largest: { height: tokens["space-largest"] },
|
|
10
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { StyleSheet } from "react-native";
|
|
2
|
+
import { tokens } from "../utils/design";
|
|
3
|
+
|
|
4
|
+
export const shineWidth = tokens["space-largest"];
|
|
5
|
+
|
|
6
|
+
export const styles = StyleSheet.create({
|
|
7
|
+
container: {
|
|
8
|
+
backgroundColor: tokens["color-surface--background"],
|
|
9
|
+
overflow: "hidden",
|
|
10
|
+
position: "relative",
|
|
11
|
+
width: "100%",
|
|
12
|
+
height: tokens["space-base"],
|
|
13
|
+
borderRadius: tokens["radius-base"],
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
shine: {
|
|
17
|
+
position: "absolute",
|
|
18
|
+
top: 0,
|
|
19
|
+
left: 0,
|
|
20
|
+
width: shineWidth,
|
|
21
|
+
height: "100%",
|
|
22
|
+
},
|
|
23
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
act,
|
|
4
|
+
fireEvent,
|
|
5
|
+
render as renderComponent,
|
|
6
|
+
} from "@testing-library/react-native";
|
|
7
|
+
import { GLIMMER_SHINE_TEST_ID, GLIMMER_TEST_ID, Glimmer } from "./Glimmer";
|
|
8
|
+
import { tokens } from "../utils/design";
|
|
9
|
+
|
|
10
|
+
let screen: ReturnType<typeof renderComponent<typeof Glimmer>>;
|
|
11
|
+
|
|
12
|
+
function render<T>(...params: Parameters<typeof renderComponent<T>>) {
|
|
13
|
+
screen = renderComponent(...params);
|
|
14
|
+
|
|
15
|
+
return screen;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe("Glimmer", () => {
|
|
19
|
+
it("renders a Glimmer with default styling", () => {
|
|
20
|
+
render(<Glimmer />);
|
|
21
|
+
const element = screen.getByTestId(GLIMMER_TEST_ID);
|
|
22
|
+
|
|
23
|
+
expect(element.props.style).toEqual(
|
|
24
|
+
expect.arrayContaining([
|
|
25
|
+
expect.objectContaining({ height: 16 }),
|
|
26
|
+
expect.objectContaining({ width: "100%" }),
|
|
27
|
+
]),
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("renders a Glimmer with custom width", () => {
|
|
32
|
+
render(<Glimmer width={50} />);
|
|
33
|
+
const element = screen.getByTestId(GLIMMER_TEST_ID);
|
|
34
|
+
|
|
35
|
+
expect(element.props.style).toEqual(
|
|
36
|
+
expect.arrayContaining([expect.objectContaining({ width: 50 })]),
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("renders a Glimmer with custom percent width", () => {
|
|
41
|
+
render(<Glimmer width="50%" />);
|
|
42
|
+
const element = screen.getByTestId(GLIMMER_TEST_ID);
|
|
43
|
+
|
|
44
|
+
expect(element.props.style).toEqual(
|
|
45
|
+
expect.arrayContaining([expect.objectContaining({ width: "50%" })]),
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("renders sets the correct width", () => {
|
|
50
|
+
jest.useFakeTimers();
|
|
51
|
+
render(<Glimmer />);
|
|
52
|
+
|
|
53
|
+
act(() => {
|
|
54
|
+
fireEvent(screen.getByTestId(GLIMMER_TEST_ID), "onLayout", {
|
|
55
|
+
nativeEvent: { layout: { width: 300 } },
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const element = screen.getByTestId(GLIMMER_SHINE_TEST_ID);
|
|
60
|
+
|
|
61
|
+
expect(element.props.style).toEqual(
|
|
62
|
+
expect.objectContaining({ transform: [{ translateX: -48 }] }),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
jest.advanceTimersByTime(tokens["timing-loading--extended"]);
|
|
66
|
+
|
|
67
|
+
expect(element.props.style).toEqual(
|
|
68
|
+
expect.objectContaining({ transform: [{ translateX: 348 }] }),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
jest.useRealTimers();
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { Animated, Easing, LayoutChangeEvent, View } from "react-native";
|
|
3
|
+
import Svg, { Defs, LinearGradient, Rect, Stop } from "react-native-svg";
|
|
4
|
+
import { shineWidth, styles } from "./Glimmer.style";
|
|
5
|
+
import { sizeStyles } from "./Glimmer.size.style";
|
|
6
|
+
import { shapeStyles } from "./Glimmer.shape.style";
|
|
7
|
+
import { tokens } from "../utils/design";
|
|
8
|
+
|
|
9
|
+
export type GlimmerShapes = keyof typeof shapeStyles;
|
|
10
|
+
export type GlimmerSizes = keyof typeof sizeStyles;
|
|
11
|
+
export type GlimmerTimings = "base" | "fast";
|
|
12
|
+
|
|
13
|
+
interface GlimmerProps {
|
|
14
|
+
/**
|
|
15
|
+
* Sets the size of the glimmer.
|
|
16
|
+
*/
|
|
17
|
+
readonly shape?: GlimmerShapes;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Sets the shape of the glimmer.
|
|
21
|
+
*
|
|
22
|
+
* If you need a specific width, use the `width` prop.
|
|
23
|
+
*/
|
|
24
|
+
readonly size?: GlimmerSizes;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Control how fast the shine moves from left to right. This is useful when
|
|
28
|
+
* the glimmer is used on smaller spaces.
|
|
29
|
+
*/
|
|
30
|
+
readonly timing?: GlimmerTimings;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Adjust the width of the glimmer in px or % values.
|
|
34
|
+
*/
|
|
35
|
+
readonly width?: number | `${number}%`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const GLIMMER_TEST_ID = "ATL-Glimmer";
|
|
39
|
+
export const GLIMMER_SHINE_TEST_ID = "ATL-Glimmer-Shine";
|
|
40
|
+
|
|
41
|
+
export function Glimmer({
|
|
42
|
+
width,
|
|
43
|
+
shape = "rectangle",
|
|
44
|
+
size = "base",
|
|
45
|
+
timing = "base",
|
|
46
|
+
}: GlimmerProps) {
|
|
47
|
+
const leftPosition = useRef(new Animated.Value(-shineWidth)).current;
|
|
48
|
+
const [parentWidth, setParentWidth] = useState(0);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const shine = Animated.loop(
|
|
52
|
+
Animated.timing(leftPosition, {
|
|
53
|
+
toValue: parentWidth + shineWidth,
|
|
54
|
+
duration:
|
|
55
|
+
timing === "base"
|
|
56
|
+
? tokens["timing-loading--extended"]
|
|
57
|
+
: tokens["timing-loading"],
|
|
58
|
+
easing: Easing.ease,
|
|
59
|
+
useNativeDriver: true,
|
|
60
|
+
}),
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
shine.start();
|
|
64
|
+
|
|
65
|
+
return shine.stop;
|
|
66
|
+
}, [parentWidth]);
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<View
|
|
70
|
+
style={[
|
|
71
|
+
styles.container,
|
|
72
|
+
sizeStyles[size],
|
|
73
|
+
shapeStyles[shape],
|
|
74
|
+
{ width },
|
|
75
|
+
]}
|
|
76
|
+
onLayout={getWidth}
|
|
77
|
+
testID={GLIMMER_TEST_ID}
|
|
78
|
+
>
|
|
79
|
+
<Animated.View
|
|
80
|
+
style={[styles.shine, { transform: [{ translateX: leftPosition }] }]}
|
|
81
|
+
testID={GLIMMER_SHINE_TEST_ID}
|
|
82
|
+
>
|
|
83
|
+
<Svg>
|
|
84
|
+
<Defs>
|
|
85
|
+
<LinearGradient id="gradientShine" x1={0} y1={0.5} x2={1} y2={0.5}>
|
|
86
|
+
<Stop
|
|
87
|
+
offset="0%"
|
|
88
|
+
stopColor={tokens["color-surface--background"]}
|
|
89
|
+
/>
|
|
90
|
+
<Stop offset="50%" stopColor={tokens["color-surface"]} />
|
|
91
|
+
<Stop
|
|
92
|
+
offset="100%"
|
|
93
|
+
stopColor={tokens["color-surface--background"]}
|
|
94
|
+
/>
|
|
95
|
+
</LinearGradient>
|
|
96
|
+
</Defs>
|
|
97
|
+
<Rect fill="url(#gradientShine)" height="100%" width="100%" />
|
|
98
|
+
</Svg>
|
|
99
|
+
</Animated.View>
|
|
100
|
+
</View>
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
function getWidth(event: LayoutChangeEvent) {
|
|
104
|
+
setParentWidth(event.nativeEvent.layout.width);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Glimmer";
|
|
@@ -15,7 +15,7 @@ exports[`when Heading called with Subtitle variation should match snapshot 1`] =
|
|
|
15
15
|
"fontFamily": "inter-bold",
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
|
-
"color": "rgb(1,
|
|
18
|
+
"color": "rgb(1, 40, 55)",
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"textAlign": "left",
|
|
@@ -48,7 +48,7 @@ exports[`when Heading called with an alignment should match snapshot 1`] = `
|
|
|
48
48
|
"fontFamily": "inter-bold",
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
|
-
"color": "rgb(1,
|
|
51
|
+
"color": "rgb(1, 40, 55)",
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
"textAlign": "right",
|
|
@@ -82,7 +82,7 @@ exports[`when Heading called with maxLines should match snapshot 1`] = `
|
|
|
82
82
|
"fontFamily": "inter-bold",
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
|
-
"color": "rgb(1,
|
|
85
|
+
"color": "rgb(1, 40, 55)",
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
88
|
"textAlign": "left",
|
|
@@ -149,7 +149,7 @@ exports[`when Heading called with sub-heading variation and text-color should ma
|
|
|
149
149
|
"fontFamily": "inter-semibold",
|
|
150
150
|
},
|
|
151
151
|
{
|
|
152
|
-
"color": "rgb(
|
|
152
|
+
"color": "rgb(78, 105, 116)",
|
|
153
153
|
},
|
|
154
154
|
{
|
|
155
155
|
"textAlign": "left",
|
|
@@ -183,7 +183,7 @@ exports[`when Heading called with sub-heading variation should match snapshot 1`
|
|
|
183
183
|
"fontFamily": "inter-semibold",
|
|
184
184
|
},
|
|
185
185
|
{
|
|
186
|
-
"color": "rgb(1,
|
|
186
|
+
"color": "rgb(1, 40, 55)",
|
|
187
187
|
},
|
|
188
188
|
{
|
|
189
189
|
"textAlign": "left",
|
|
@@ -216,7 +216,7 @@ exports[`when Heading called with text as the only prop should match snapshot 1`
|
|
|
216
216
|
"fontFamily": "inter-bold",
|
|
217
217
|
},
|
|
218
218
|
{
|
|
219
|
-
"color": "rgb(1,
|
|
219
|
+
"color": "rgb(1, 40, 55)",
|
|
220
220
|
},
|
|
221
221
|
{
|
|
222
222
|
"textAlign": "left",
|
|
@@ -250,7 +250,7 @@ exports[`when Heading called with title variation should match snapshot 1`] = `
|
|
|
250
250
|
"fontFamily": "jobberpro-xbd",
|
|
251
251
|
},
|
|
252
252
|
{
|
|
253
|
-
"color": "rgb(1,
|
|
253
|
+
"color": "rgb(1, 40, 55)",
|
|
254
254
|
},
|
|
255
255
|
{
|
|
256
256
|
"textAlign": "left",
|