@jobber/components-native 0.20.0 → 0.20.1-test-web-v.8
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/BottomSheet/BottomSheet.js +52 -0
- package/dist/src/BottomSheet/BottomSheet.style.js +28 -0
- package/dist/src/BottomSheet/components/BottomSheetOption/BottomSheetOption.js +17 -0
- package/dist/src/BottomSheet/components/BottomSheetOption/BottomSheetOption.styles.js +18 -0
- package/dist/src/BottomSheet/components/BottomSheetOption/index.js +1 -0
- package/dist/src/BottomSheet/index.js +1 -0
- package/dist/src/BottomSheet/messages.js +8 -0
- package/dist/src/EmptyState/EmptyState.js +24 -0
- package/dist/src/EmptyState/EmptyState.style.js +8 -0
- package/dist/src/EmptyState/index.js +1 -0
- package/dist/src/InputPressable/InputPressable.style.js +3 -3
- package/dist/src/InputText/InputText.js +138 -0
- package/dist/src/InputText/InputText.style.js +20 -0
- package/dist/src/InputText/context/InputAccessoriesContext.js +17 -0
- package/dist/src/InputText/context/InputAccessoriesProvider.js +73 -0
- package/dist/src/InputText/context/InputAccessoriesProvider.style.js +21 -0
- package/dist/src/InputText/context/InputAccessory.style.js +16 -0
- package/dist/src/InputText/context/index.js +2 -0
- package/dist/src/InputText/context/types.js +1 -0
- package/dist/src/InputText/index.js +2 -0
- package/dist/src/Switch/Switch.js +16 -0
- package/dist/src/Switch/Switch.styles.js +20 -0
- package/dist/src/Switch/components/BaseSwitch/BaseSwitch.js +54 -0
- package/dist/src/Switch/components/BaseSwitch/index.js +1 -0
- package/dist/src/Switch/index.js +1 -0
- package/dist/src/Toast/Toast.js +64 -0
- package/dist/src/Toast/Toast.styles.js +30 -0
- package/dist/src/Toast/index.js +1 -0
- package/dist/src/Toast/messages.js +13 -0
- package/dist/src/hooks/index.js +2 -0
- package/dist/src/hooks/useFormController.js +38 -0
- package/dist/src/hooks/useIsScreenReaderEnabled.js +22 -0
- package/dist/src/index.js +5 -0
- package/dist/src/utils/design/index.js +3 -3
- package/dist/src/utils/test/MockSafeAreaProvider.js +10 -0
- package/dist/src/utils/test/index.js +1 -0
- package/dist/src/utils/test/wait.js +58 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/src/BottomSheet/BottomSheet.d.ts +28 -0
- package/dist/types/src/BottomSheet/BottomSheet.style.d.ts +32 -0
- package/dist/types/src/BottomSheet/components/BottomSheetOption/BottomSheetOption.d.ts +13 -0
- package/dist/types/src/BottomSheet/components/BottomSheetOption/BottomSheetOption.styles.d.ts +16 -0
- package/dist/types/src/BottomSheet/components/BottomSheetOption/index.d.ts +1 -0
- package/dist/types/src/BottomSheet/index.d.ts +1 -0
- package/dist/types/src/BottomSheet/messages.d.ts +7 -0
- package/dist/types/src/EmptyState/EmptyState.d.ts +35 -0
- package/dist/types/src/EmptyState/EmptyState.style.d.ts +6 -0
- package/dist/types/src/EmptyState/index.d.ts +2 -0
- package/dist/types/src/InputText/InputText.d.ts +165 -0
- package/dist/types/src/InputText/InputText.style.d.ts +16 -0
- package/dist/types/src/InputText/context/InputAccessoriesContext.d.ts +4 -0
- package/dist/types/src/InputText/context/InputAccessoriesProvider.d.ts +4 -0
- package/dist/types/src/InputText/context/InputAccessoriesProvider.style.d.ts +17 -0
- package/dist/types/src/InputText/context/InputAccessory.style.d.ts +14 -0
- package/dist/types/src/InputText/context/index.d.ts +2 -0
- package/dist/types/src/InputText/context/types.d.ts +23 -0
- package/dist/types/src/InputText/index.d.ts +3 -0
- package/dist/types/src/Switch/Switch.d.ts +16 -0
- package/dist/types/src/Switch/Switch.styles.d.ts +18 -0
- package/dist/types/src/Switch/components/BaseSwitch/BaseSwitch.d.ts +28 -0
- package/dist/types/src/Switch/components/BaseSwitch/index.d.ts +2 -0
- package/dist/types/src/Switch/index.d.ts +1 -0
- package/dist/types/src/Toast/Toast.d.ts +28 -0
- package/dist/types/src/Toast/Toast.styles.d.ts +31 -0
- package/dist/types/src/Toast/index.d.ts +2 -0
- package/dist/types/src/Toast/messages.d.ts +12 -0
- package/dist/types/src/hooks/index.d.ts +2 -0
- package/dist/types/src/hooks/useFormController.d.ts +12 -0
- package/dist/types/src/hooks/useIsScreenReaderEnabled.d.ts +1 -0
- package/dist/types/src/index.d.ts +5 -0
- package/dist/types/src/utils/design/index.d.ts +1 -1
- package/dist/types/src/utils/test/MockSafeAreaProvider.d.ts +9 -0
- package/dist/types/src/utils/test/index.d.ts +1 -0
- package/dist/types/src/utils/test/wait.d.ts +36 -0
- package/package.json +10 -4
- package/src/BottomSheet/BottomSheet.style.ts +35 -0
- package/src/BottomSheet/BottomSheet.test.tsx +152 -0
- package/src/BottomSheet/BottomSheet.tsx +149 -0
- package/src/BottomSheet/components/BottomSheetOption/BottomSheetOption.styles.ts +19 -0
- package/src/BottomSheet/components/BottomSheetOption/BottomSheetOption.test.tsx +34 -0
- package/src/BottomSheet/components/BottomSheetOption/BottomSheetOption.tsx +53 -0
- package/src/BottomSheet/components/BottomSheetOption/index.ts +1 -0
- package/src/BottomSheet/index.ts +1 -0
- package/src/BottomSheet/messages.ts +9 -0
- package/src/EmptyState/EmptyState.style.ts +9 -0
- package/src/EmptyState/EmptyState.test.tsx +108 -0
- package/src/EmptyState/EmptyState.tsx +91 -0
- package/src/EmptyState/index.ts +2 -0
- package/src/Flex/Flex.test.tsx +6 -6
- package/src/InputPressable/InputPressable.style.ts +3 -3
- package/src/InputText/InputText.style.ts +25 -0
- package/src/InputText/InputText.test.tsx +534 -0
- package/src/InputText/InputText.tsx +483 -0
- package/src/InputText/context/InputAccessoriesContext.ts +21 -0
- package/src/InputText/context/InputAccessoriesProvider.style.tsx +23 -0
- package/src/InputText/context/InputAccessoriesProvider.test.tsx +84 -0
- package/src/InputText/context/InputAccessoriesProvider.tsx +121 -0
- package/src/InputText/context/InputAccessory.style.ts +17 -0
- package/src/InputText/context/index.ts +2 -0
- package/src/InputText/context/types.ts +28 -0
- package/src/InputText/index.ts +3 -0
- package/src/Switch/Switch.styles.ts +21 -0
- package/src/Switch/Switch.test.tsx +98 -0
- package/src/Switch/Switch.tsx +58 -0
- package/src/Switch/components/BaseSwitch/BaseSwitch.test.tsx +62 -0
- package/src/Switch/components/BaseSwitch/BaseSwitch.tsx +107 -0
- package/src/Switch/components/BaseSwitch/__snapshots__/BaseSwitch.test.tsx.snap +217 -0
- package/src/Switch/components/BaseSwitch/index.ts +2 -0
- package/src/Switch/index.ts +1 -0
- package/src/Toast/Toast.styles.ts +31 -0
- package/src/Toast/Toast.test.tsx +74 -0
- package/src/Toast/Toast.tsx +128 -0
- package/src/Toast/index.ts +2 -0
- package/src/Toast/messages.ts +14 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useFormController.ts +68 -0
- package/src/hooks/useIsScreenReaderEnabled.ts +32 -0
- package/src/index.ts +5 -0
- package/src/utils/design/index.ts +4 -4
- package/src/utils/test/MockSafeAreaProvider.tsx +32 -0
- package/src/utils/test/index.ts +1 -0
- package/src/utils/test/wait.ts +52 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React, { forwardRef, useState } from "react";
|
|
2
|
+
import { Modalize } from "react-native-modalize";
|
|
3
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
4
|
+
import { Keyboard, View } from "react-native";
|
|
5
|
+
import { useIntl } from "react-intl";
|
|
6
|
+
import { BottomSheetOption } from "./components/BottomSheetOption";
|
|
7
|
+
import { styles } from "./BottomSheet.style";
|
|
8
|
+
import { messages } from "./messages";
|
|
9
|
+
import { useIsScreenReaderEnabled } from "../hooks";
|
|
10
|
+
import { Divider } from "../Divider";
|
|
11
|
+
import { Heading } from "../Heading";
|
|
12
|
+
export const BottomSheet = forwardRef(BottomSheetInternal);
|
|
13
|
+
function BottomSheetInternal({ children, showCancel, loading = false, heading, onOpen, onClose, }, ref) {
|
|
14
|
+
const isScreenReaderEnabled = useIsScreenReaderEnabled();
|
|
15
|
+
const [open, setOpen] = useState(false);
|
|
16
|
+
return (React.createElement(React.Fragment, null,
|
|
17
|
+
open && React.createElement(Overlay, null),
|
|
18
|
+
React.createElement(Modalize, { ref: ref, adjustToContentHeight: true, modalStyle: styles.modal, overlayStyle: styles.overlayModalize, HeaderComponent: heading && React.createElement(Header, { heading: heading }), FooterComponent: React.createElement(Footer, { cancellable: (showCancel && !loading) || isScreenReaderEnabled, onCancel: () => {
|
|
19
|
+
var _a;
|
|
20
|
+
(_a = ref === null || ref === void 0 ? void 0 : ref.current) === null || _a === void 0 ? void 0 : _a.close();
|
|
21
|
+
} }), withHandle: false, withReactModal: isScreenReaderEnabled, onOpen: openModal, onClose: closeModal },
|
|
22
|
+
React.createElement(View, { style: !showCancel && !isScreenReaderEnabled ? styles.children : undefined }, children))));
|
|
23
|
+
function openModal() {
|
|
24
|
+
onOpen === null || onOpen === void 0 ? void 0 : onOpen();
|
|
25
|
+
setOpen(true);
|
|
26
|
+
dismissKeyboard();
|
|
27
|
+
}
|
|
28
|
+
function closeModal() {
|
|
29
|
+
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
30
|
+
setOpen(false);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function Header({ heading }) {
|
|
34
|
+
return (React.createElement(View, { style: styles.header },
|
|
35
|
+
React.createElement(Heading, { level: "subtitle" }, heading)));
|
|
36
|
+
}
|
|
37
|
+
function Footer({ cancellable, onCancel, }) {
|
|
38
|
+
const insets = useSafeAreaInsets();
|
|
39
|
+
const { formatMessage } = useIntl();
|
|
40
|
+
return (React.createElement(View, { style: { marginBottom: insets.bottom } }, cancellable && (React.createElement(View, { style: styles.children },
|
|
41
|
+
React.createElement(View, { style: styles.footerDivider },
|
|
42
|
+
React.createElement(Divider, null)),
|
|
43
|
+
React.createElement(BottomSheetOption, { text: formatMessage(messages.cancel), icon: "remove", onPress: onCancel })))));
|
|
44
|
+
}
|
|
45
|
+
function dismissKeyboard() {
|
|
46
|
+
//Dismisses the keyboard before opening the bottom sheet.
|
|
47
|
+
//In the case where an input text field is focused we don't want to show the bottom sheet behind or above keyboard
|
|
48
|
+
Keyboard.dismiss();
|
|
49
|
+
}
|
|
50
|
+
function Overlay() {
|
|
51
|
+
return React.createElement(View, { style: styles.overlay });
|
|
52
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Dimensions, StyleSheet } from "react-native";
|
|
2
|
+
import { tokens } from "../utils/design";
|
|
3
|
+
const { height } = Dimensions.get("window");
|
|
4
|
+
const modalBorderRadius = tokens["radius-larger"];
|
|
5
|
+
export const styles = StyleSheet.create({
|
|
6
|
+
overlayModalize: {
|
|
7
|
+
backgroundColor: "transparent",
|
|
8
|
+
},
|
|
9
|
+
overlay: Object.assign(Object.assign({}, StyleSheet.absoluteFillObject), { backgroundColor: tokens["color-overlay"], height }),
|
|
10
|
+
modal: {
|
|
11
|
+
borderTopLeftRadius: modalBorderRadius,
|
|
12
|
+
borderTopRightRadius: modalBorderRadius,
|
|
13
|
+
paddingTop: tokens["space-small"],
|
|
14
|
+
},
|
|
15
|
+
children: {
|
|
16
|
+
paddingBottom: tokens["space-small"],
|
|
17
|
+
},
|
|
18
|
+
header: {
|
|
19
|
+
paddingHorizontal: tokens["space-base"],
|
|
20
|
+
paddingTop: tokens["space-small"],
|
|
21
|
+
paddingBottom: tokens["space-base"],
|
|
22
|
+
},
|
|
23
|
+
footerDivider: {
|
|
24
|
+
marginHorizontal: tokens["space-base"],
|
|
25
|
+
marginTop: tokens["space-small"],
|
|
26
|
+
marginBottom: tokens["space-smaller"],
|
|
27
|
+
},
|
|
28
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { TouchableOpacity, View } from "react-native";
|
|
3
|
+
import { styles } from "./BottomSheetOption.styles";
|
|
4
|
+
import { capitalize } from "../../../utils/intl";
|
|
5
|
+
import { Text } from "../../../Text";
|
|
6
|
+
import { Icon } from "../../../Icon";
|
|
7
|
+
export function BottomSheetOption({ text, icon, iconColor, textAlign, destructive, textTransform = "capitalize", onPress, }) {
|
|
8
|
+
const destructiveColor = "critical";
|
|
9
|
+
const textVariation = destructive ? destructiveColor : "subdued";
|
|
10
|
+
return (React.createElement(TouchableOpacity, { style: styles.bottomSheetOption, onPress: onPress, accessibilityLabel: text },
|
|
11
|
+
icon && (React.createElement(View, { style: styles.icon },
|
|
12
|
+
React.createElement(Icon, { name: icon, color: destructive ? destructiveColor : iconColor }))),
|
|
13
|
+
React.createElement(View, { style: styles.title },
|
|
14
|
+
React.createElement(Text, { variation: textVariation, emphasis: "strong", align: textAlign }, textTransform === "capitalize"
|
|
15
|
+
? capitalize(text.toLocaleLowerCase())
|
|
16
|
+
: text))));
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { StyleSheet } from "react-native";
|
|
2
|
+
import { tokens } from "../../../utils/design";
|
|
3
|
+
export const styles = StyleSheet.create({
|
|
4
|
+
bottomSheetOption: {
|
|
5
|
+
display: "flex",
|
|
6
|
+
flexDirection: "row",
|
|
7
|
+
alignContent: "center",
|
|
8
|
+
alignItems: "center",
|
|
9
|
+
padding: tokens["space-small"],
|
|
10
|
+
},
|
|
11
|
+
icon: {
|
|
12
|
+
paddingHorizontal: tokens["space-small"],
|
|
13
|
+
},
|
|
14
|
+
title: {
|
|
15
|
+
paddingHorizontal: tokens["space-small"],
|
|
16
|
+
flexShrink: 1,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { BottomSheetOption } from "./BottomSheetOption";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { BottomSheet } from "./BottomSheet";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { styles } from "./EmptyState.style";
|
|
4
|
+
import { Text } from "../Text";
|
|
5
|
+
import { Content } from "../Content";
|
|
6
|
+
import { Icon } from "../Icon";
|
|
7
|
+
import { Heading } from "../Heading";
|
|
8
|
+
import { Button } from "../Button";
|
|
9
|
+
function ButtonAction({ action, type }) {
|
|
10
|
+
if (!action)
|
|
11
|
+
return React.createElement(React.Fragment, null);
|
|
12
|
+
return React.createElement(Button, Object.assign({ fullWidth: false, type: type }, action));
|
|
13
|
+
}
|
|
14
|
+
export function EmptyState({ icon, title, description, primaryAction, secondaryAction, iconColor = "blue", }) {
|
|
15
|
+
return (React.createElement(Content, null,
|
|
16
|
+
icon && (React.createElement(View, { style: styles.icon },
|
|
17
|
+
React.createElement(Icon, { name: icon, size: "large", color: iconColor }))),
|
|
18
|
+
React.createElement(Content, { spacing: "none", childSpacing: "small" },
|
|
19
|
+
title && (React.createElement(Heading, { level: "subHeading", align: "center" }, title)),
|
|
20
|
+
description && React.createElement(Text, { align: "center" }, description),
|
|
21
|
+
(primaryAction || secondaryAction) && (React.createElement(Content, { spacing: "none", childSpacing: "small" },
|
|
22
|
+
React.createElement(ButtonAction, { action: primaryAction, type: "primary" }),
|
|
23
|
+
React.createElement(ButtonAction, { action: secondaryAction, type: "tertiary" }))))));
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { EmptyState } from "./EmptyState";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tokens } from "@jobber/design/foundation";
|
|
2
2
|
import { StyleSheet } from "react-native";
|
|
3
3
|
import { typographyStyles } from "../Typography/Typography.style";
|
|
4
4
|
const miniLabelFontSize = typographyStyles.smallSize.fontSize || 0;
|
|
5
|
-
const miniLabelPadding =
|
|
5
|
+
const miniLabelPadding = tokens["space-small"];
|
|
6
6
|
export const styles = StyleSheet.create({
|
|
7
7
|
pressable: {
|
|
8
8
|
flex: 1,
|
|
@@ -18,6 +18,6 @@ export const styles = StyleSheet.create({
|
|
|
18
18
|
color: typographyStyles.disabled.color,
|
|
19
19
|
},
|
|
20
20
|
inputInvalid: {
|
|
21
|
-
borderColor:
|
|
21
|
+
borderColor: tokens["color-critical"],
|
|
22
22
|
},
|
|
23
23
|
});
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState, } from "react";
|
|
2
|
+
import { Platform, TextInput, } from "react-native";
|
|
3
|
+
import identity from "lodash.identity";
|
|
4
|
+
import { styles } from "./InputText.style";
|
|
5
|
+
import { useInputAccessoriesContext } from "./context";
|
|
6
|
+
import { useFormController } from "../hooks";
|
|
7
|
+
import { InputFieldWrapper, useShowClear, } from "../InputFieldWrapper";
|
|
8
|
+
import { commonInputStyles } from "../InputFieldWrapper/CommonInputStyles.style";
|
|
9
|
+
export const InputText = forwardRef(InputTextInternal);
|
|
10
|
+
// eslint-disable-next-line max-statements
|
|
11
|
+
function InputTextInternal({ invalid, disabled, name, placeholder, assistiveText, keyboard, value: controlledValue, defaultValue, autoFocus, autoComplete = "off", spellCheck, textContentType = "none", validations, onChangeText, onSubmitEditing, onFocus, accessibilityLabel, accessibilityHint, autoCorrect, autoCapitalize, onBlur, multiline = false, prefix, suffix, transform = {}, clearable = multiline ? "never" : "while-editing", testID, secureTextEntry, styleOverride, }, ref) {
|
|
12
|
+
var _a;
|
|
13
|
+
const isAndroid = Platform.OS === "android";
|
|
14
|
+
const { input: inputTransform = identity, output: outputTransform = identity, } = transform;
|
|
15
|
+
const { error, field } = useFormController({
|
|
16
|
+
name,
|
|
17
|
+
value: controlledValue !== null && controlledValue !== void 0 ? controlledValue : defaultValue,
|
|
18
|
+
validations,
|
|
19
|
+
});
|
|
20
|
+
const internalValue = controlledValue !== null && controlledValue !== void 0 ? controlledValue : (_a = field.value) === null || _a === void 0 ? void 0 : _a.toString();
|
|
21
|
+
const hasValue = internalValue !== "" && internalValue !== undefined;
|
|
22
|
+
const [focused, setFocused] = useState(false);
|
|
23
|
+
const { hasMiniLabel, setHasMiniLabel } = useMiniLabel(internalValue);
|
|
24
|
+
const textInputRef = useTextInputRef({ ref, onClear: handleClear });
|
|
25
|
+
const showClear = useShowClear({
|
|
26
|
+
clearable,
|
|
27
|
+
multiline,
|
|
28
|
+
focused,
|
|
29
|
+
hasValue,
|
|
30
|
+
disabled,
|
|
31
|
+
});
|
|
32
|
+
// Android doesn't have an accessibility label like iOS does. By adding
|
|
33
|
+
// it as a placeholder it readds it like a label. However we don't want to
|
|
34
|
+
// add a placeholder on iOS.
|
|
35
|
+
const androidA11yProps = Object.assign({}, (isAndroid && {
|
|
36
|
+
placeholder: accessibilityLabel || placeholder,
|
|
37
|
+
placeholderTextColor: "transparent",
|
|
38
|
+
}));
|
|
39
|
+
const _name = name !== null && name !== void 0 ? name : field.name;
|
|
40
|
+
const { inputAccessoryID, register, unregister, setFocusedInput, canFocusNext, onFocusNext, } = useInputAccessoriesContext();
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
_name &&
|
|
43
|
+
register(_name, () => {
|
|
44
|
+
var _a;
|
|
45
|
+
(_a = textInputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
46
|
+
});
|
|
47
|
+
return () => {
|
|
48
|
+
_name && unregister(_name);
|
|
49
|
+
};
|
|
50
|
+
}, [_name, register, textInputRef, unregister]);
|
|
51
|
+
const returnKeyType = useMemo(() => {
|
|
52
|
+
if (!multiline) {
|
|
53
|
+
if (inputAccessoryID && isAndroid) {
|
|
54
|
+
return "next";
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
return "done";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
}, [multiline, inputAccessoryID, isAndroid]);
|
|
64
|
+
// If it's not inside an inputAcessoriesContext or cannot focus next,
|
|
65
|
+
// then hide the keyboard when the return key is pressed.
|
|
66
|
+
const shouldBlurOnSubmit = !multiline && (!inputAccessoryID || !canFocusNext || !isAndroid);
|
|
67
|
+
function handleOnFocusNext() {
|
|
68
|
+
if (multiline) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
onFocusNext();
|
|
72
|
+
}
|
|
73
|
+
return (React.createElement(InputFieldWrapper, { prefix: prefix, suffix: suffix, hasValue: hasValue, hasMiniLabel: hasMiniLabel, assistiveText: assistiveText, focused: focused, error: error, invalid: invalid, placeholder: placeholder, disabled: disabled, onClear: handleClear, showClearAction: showClear, styleOverride: styleOverride },
|
|
74
|
+
React.createElement(TextInput, Object.assign({ inputAccessoryViewID: inputAccessoryID || undefined, testID: testID, autoCapitalize: autoCapitalize, autoCorrect: autoCorrect, spellCheck: spellCheck, style: [
|
|
75
|
+
commonInputStyles.input,
|
|
76
|
+
styles.inputPaddingTop,
|
|
77
|
+
!hasMiniLabel && commonInputStyles.inputEmpty,
|
|
78
|
+
disabled && commonInputStyles.inputDisabled,
|
|
79
|
+
multiline && Platform.OS === "ios" && styles.multilineInputiOS,
|
|
80
|
+
multiline && styles.multiLineInput,
|
|
81
|
+
multiline && hasMiniLabel && styles.multiLineInputWithMini,
|
|
82
|
+
styleOverride === null || styleOverride === void 0 ? void 0 : styleOverride.inputText,
|
|
83
|
+
], editable: !disabled, keyboardType: keyboard, value: inputTransform(internalValue), autoFocus: autoFocus, autoComplete: autoComplete, multiline: multiline, scrollEnabled: false, textContentType: textContentType, onChangeText: handleChangeText, onSubmitEditing: handleOnSubmitEditing, returnKeyType: returnKeyType, blurOnSubmit: shouldBlurOnSubmit, accessibilityLabel: accessibilityLabel || placeholder, accessibilityHint: accessibilityHint, secureTextEntry: secureTextEntry }, androidA11yProps, { onFocus: event => {
|
|
84
|
+
_name && setFocusedInput(_name);
|
|
85
|
+
setFocused(true);
|
|
86
|
+
onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
|
|
87
|
+
}, onBlur: () => {
|
|
88
|
+
_name && setFocusedInput("");
|
|
89
|
+
setFocused(false);
|
|
90
|
+
onBlur === null || onBlur === void 0 ? void 0 : onBlur();
|
|
91
|
+
field.onBlur();
|
|
92
|
+
trimWhitespace(field, onChangeText);
|
|
93
|
+
}, ref: (instance) => {
|
|
94
|
+
// RHF wants us to do it this way
|
|
95
|
+
// https://react-hook-form.com/faqs#Howtosharerefusage
|
|
96
|
+
textInputRef.current = instance;
|
|
97
|
+
field.ref(instance);
|
|
98
|
+
} }))));
|
|
99
|
+
function handleChangeText(value) {
|
|
100
|
+
const newValue = outputTransform(value);
|
|
101
|
+
setHasMiniLabel(Boolean(newValue));
|
|
102
|
+
onChangeText === null || onChangeText === void 0 ? void 0 : onChangeText(newValue);
|
|
103
|
+
field.onChange(newValue);
|
|
104
|
+
}
|
|
105
|
+
function handleClear() {
|
|
106
|
+
handleChangeText("");
|
|
107
|
+
}
|
|
108
|
+
function handleOnSubmitEditing() {
|
|
109
|
+
onSubmitEditing === null || onSubmitEditing === void 0 ? void 0 : onSubmitEditing();
|
|
110
|
+
if (isAndroid) {
|
|
111
|
+
handleOnFocusNext();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function trimWhitespace(field, onChangeText) {
|
|
116
|
+
if (!field.value || !field.value.trim) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const trimmedInput = field.value.trim();
|
|
120
|
+
onChangeText === null || onChangeText === void 0 ? void 0 : onChangeText(trimmedInput);
|
|
121
|
+
field.onChange(trimmedInput);
|
|
122
|
+
}
|
|
123
|
+
function useTextInputRef({ ref, onClear }) {
|
|
124
|
+
const textInputRef = useRef(null);
|
|
125
|
+
useImperativeHandle(ref, () => ({
|
|
126
|
+
focus: () => { var _a; return (_a = textInputRef.current) === null || _a === void 0 ? void 0 : _a.focus(); },
|
|
127
|
+
blur: () => { var _a; return (_a = textInputRef.current) === null || _a === void 0 ? void 0 : _a.blur(); },
|
|
128
|
+
clear: onClear,
|
|
129
|
+
}), [onClear]);
|
|
130
|
+
return textInputRef;
|
|
131
|
+
}
|
|
132
|
+
function useMiniLabel(internalValue) {
|
|
133
|
+
const [hasMiniLabel, setHasMiniLabel] = useState(Boolean(internalValue));
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
setHasMiniLabel(Boolean(internalValue));
|
|
136
|
+
}, [internalValue]);
|
|
137
|
+
return { hasMiniLabel, setHasMiniLabel };
|
|
138
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { StyleSheet } from "react-native";
|
|
2
|
+
import { tokens } from "../utils/design";
|
|
3
|
+
import { typographyStyles } from "../Typography";
|
|
4
|
+
export const styles = StyleSheet.create({
|
|
5
|
+
inputPaddingTop: {
|
|
6
|
+
paddingTop: typographyStyles.smallSize.fontSize,
|
|
7
|
+
},
|
|
8
|
+
multiLineInput: {
|
|
9
|
+
paddingTop: tokens["space-base"] - tokens["space-smallest"],
|
|
10
|
+
paddingBottom: tokens["space-smaller"],
|
|
11
|
+
lineHeight: typographyStyles.defaultSize.lineHeight,
|
|
12
|
+
},
|
|
13
|
+
multiLineInputWithMini: {
|
|
14
|
+
paddingTop: tokens["space-large"],
|
|
15
|
+
},
|
|
16
|
+
multilineInputiOS: {
|
|
17
|
+
// for placeholder
|
|
18
|
+
paddingTop: (typographyStyles.smallSize.fontSize || 0) + tokens["space-smallest"],
|
|
19
|
+
},
|
|
20
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
const defaultValues = {
|
|
3
|
+
elements: {},
|
|
4
|
+
focusedInput: "",
|
|
5
|
+
canFocusNext: false,
|
|
6
|
+
canFocusPrevious: false,
|
|
7
|
+
inputAccessoryID: undefined,
|
|
8
|
+
register: () => undefined,
|
|
9
|
+
unregister: () => undefined,
|
|
10
|
+
onFocusNext: () => undefined,
|
|
11
|
+
onFocusPrevious: () => undefined,
|
|
12
|
+
setFocusedInput: () => undefined,
|
|
13
|
+
};
|
|
14
|
+
export const InputAccessoriesContext = createContext(defaultValues);
|
|
15
|
+
export function useInputAccessoriesContext() {
|
|
16
|
+
return useContext(InputAccessoriesContext);
|
|
17
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { InputAccessoryView, Keyboard, Platform,
|
|
3
|
+
// eslint-disable-next-line no-restricted-imports
|
|
4
|
+
Button as RNButton, View, useColorScheme, } from "react-native";
|
|
5
|
+
import { v4 } from "react-native-uuid";
|
|
6
|
+
import { InputAccessoriesContext } from "./InputAccessoriesContext";
|
|
7
|
+
import { styles } from "./InputAccessoriesProvider.style";
|
|
8
|
+
export function InputAccessoriesProvider({ children, }) {
|
|
9
|
+
const inputAccessoryID = useRef(v4()).current;
|
|
10
|
+
const { focusedInput, setFocusedInput, canFocusNext, canFocusPrevious, elements, setElements, previousKey, nextKey, } = useInputAccessoriesProviderState();
|
|
11
|
+
const colorScheme = useColorScheme();
|
|
12
|
+
return (React.createElement(InputAccessoriesContext.Provider, { value: {
|
|
13
|
+
elements,
|
|
14
|
+
focusedInput,
|
|
15
|
+
canFocusNext,
|
|
16
|
+
canFocusPrevious,
|
|
17
|
+
inputAccessoryID,
|
|
18
|
+
register,
|
|
19
|
+
unregister,
|
|
20
|
+
onFocusNext,
|
|
21
|
+
onFocusPrevious,
|
|
22
|
+
setFocusedInput,
|
|
23
|
+
} },
|
|
24
|
+
children,
|
|
25
|
+
Platform.OS === "ios" && (React.createElement(InputAccessoryView, { nativeID: inputAccessoryID },
|
|
26
|
+
React.createElement(View, { testID: "ATL-InputAccessory", style: [
|
|
27
|
+
styles.container,
|
|
28
|
+
colorScheme === "dark" ? styles.darkTheme : styles.lightTheme,
|
|
29
|
+
] },
|
|
30
|
+
React.createElement(RNButton, { onPress: Keyboard.dismiss, title: "Done", testID: "ATL-InputAccessory-Done", color: colorScheme === "dark" ? "white" : undefined }))))));
|
|
31
|
+
function register(name, onFocus) {
|
|
32
|
+
elements[name] = onFocus;
|
|
33
|
+
setElements(elements);
|
|
34
|
+
}
|
|
35
|
+
function unregister(name) {
|
|
36
|
+
delete elements[name];
|
|
37
|
+
setElements(elements);
|
|
38
|
+
}
|
|
39
|
+
function onFocusNext() {
|
|
40
|
+
const nextElement = elements[nextKey];
|
|
41
|
+
nextElement === null || nextElement === void 0 ? void 0 : nextElement();
|
|
42
|
+
}
|
|
43
|
+
function onFocusPrevious() {
|
|
44
|
+
const previousElement = elements[previousKey];
|
|
45
|
+
previousElement === null || previousElement === void 0 ? void 0 : previousElement();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function useInputAccessoriesProviderState() {
|
|
49
|
+
const [focusedInput, setFocusedInput] = useState("");
|
|
50
|
+
const [canFocusNext, setCanFocusNext] = useState(false);
|
|
51
|
+
const [canFocusPrevious, setCanFocusPrevious] = useState(false);
|
|
52
|
+
const [elements, setElements] = useState({});
|
|
53
|
+
const keys = Object.keys(elements);
|
|
54
|
+
const selectedIndex = keys.findIndex(key => key === focusedInput);
|
|
55
|
+
const nextKey = keys[selectedIndex + 1];
|
|
56
|
+
const previousKey = keys[selectedIndex - 1];
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
setCanFocusNext(Boolean(nextKey));
|
|
59
|
+
setCanFocusPrevious(Boolean(previousKey));
|
|
60
|
+
}, [previousKey, nextKey]);
|
|
61
|
+
return {
|
|
62
|
+
previousKey,
|
|
63
|
+
nextKey,
|
|
64
|
+
focusedInput,
|
|
65
|
+
setFocusedInput,
|
|
66
|
+
canFocusNext,
|
|
67
|
+
setCanFocusNext,
|
|
68
|
+
canFocusPrevious,
|
|
69
|
+
setCanFocusPrevious,
|
|
70
|
+
elements,
|
|
71
|
+
setElements,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { PlatformColor, StyleSheet } from "react-native";
|
|
2
|
+
import { tokens } from "../../utils/design";
|
|
3
|
+
const BAR_HEIGHT = 44;
|
|
4
|
+
export const styles = StyleSheet.create({
|
|
5
|
+
container: {
|
|
6
|
+
flexDirection: "row",
|
|
7
|
+
justifyContent: "flex-end",
|
|
8
|
+
alignItems: "center",
|
|
9
|
+
paddingHorizontal: tokens["space-small"],
|
|
10
|
+
borderTopWidth: tokens["space-minuscule"],
|
|
11
|
+
borderTopColor: tokens["color-border"],
|
|
12
|
+
height: BAR_HEIGHT,
|
|
13
|
+
},
|
|
14
|
+
lightTheme: {
|
|
15
|
+
backgroundColor: tokens["color-surface--background"],
|
|
16
|
+
},
|
|
17
|
+
darkTheme: {
|
|
18
|
+
// PlatformColor has to be conditional for Storybook to run without error
|
|
19
|
+
backgroundColor: PlatformColor === null || PlatformColor === void 0 ? void 0 : PlatformColor("systemGray3"),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { StyleSheet } from "react-native";
|
|
2
|
+
import { tokens } from "../../utils/design";
|
|
3
|
+
export const styles = StyleSheet.create({
|
|
4
|
+
container: {
|
|
5
|
+
flexDirection: "row",
|
|
6
|
+
justifyContent: "space-between",
|
|
7
|
+
alignItems: "center",
|
|
8
|
+
paddingHorizontal: tokens["space-small"],
|
|
9
|
+
backgroundColor: tokens["color-surface--background"],
|
|
10
|
+
borderTopWidth: tokens["space-minuscule"],
|
|
11
|
+
borderTopColor: tokens["color-border"],
|
|
12
|
+
},
|
|
13
|
+
buttonContainer: {
|
|
14
|
+
flexDirection: "row",
|
|
15
|
+
},
|
|
16
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { BaseSwitch } from "./components/BaseSwitch";
|
|
4
|
+
import { styles } from "./Switch.styles";
|
|
5
|
+
import { Text } from "../Text";
|
|
6
|
+
export function Switch(props) {
|
|
7
|
+
const switchProps = Object.assign(Object.assign({}, props), { accessibilityLabel: props.accessibilityLabel || props.label });
|
|
8
|
+
const [labelWidth, setLabelWidth] = useState();
|
|
9
|
+
return (React.createElement(View, { style: styles.container },
|
|
10
|
+
React.createElement(View, { style: styles.row },
|
|
11
|
+
props.label && (React.createElement(View, { style: styles.label, onLayout: event => setLabelWidth(event.nativeEvent.layout.width), testID: "switch-label-view" },
|
|
12
|
+
React.createElement(Text, { variation: props.disabled ? "disabled" : "base" }, props.label))),
|
|
13
|
+
React.createElement(BaseSwitch, Object.assign({}, switchProps))),
|
|
14
|
+
props.description && (React.createElement(View, { style: [styles.description, { maxWidth: labelWidth }], testID: "switch-description-view" },
|
|
15
|
+
React.createElement(Text, { level: "textSupporting", variation: "subdued" }, props.description)))));
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { StyleSheet } from "react-native";
|
|
2
|
+
import { tokens } from "../utils/design";
|
|
3
|
+
export const styles = StyleSheet.create({
|
|
4
|
+
container: {
|
|
5
|
+
marginTop: tokens["space-base"],
|
|
6
|
+
marginBottom: tokens["space-base"],
|
|
7
|
+
},
|
|
8
|
+
row: {
|
|
9
|
+
flexDirection: "row",
|
|
10
|
+
width: "100%",
|
|
11
|
+
},
|
|
12
|
+
label: {
|
|
13
|
+
flex: 1,
|
|
14
|
+
justifyContent: "center",
|
|
15
|
+
marginRight: tokens["space-small"],
|
|
16
|
+
},
|
|
17
|
+
description: {
|
|
18
|
+
marginTop: tokens["space-smaller"],
|
|
19
|
+
},
|
|
20
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Platform } from "react-native";
|
|
3
|
+
import { Switch } from "react-native-gesture-handler";
|
|
4
|
+
import { useFormController } from "../../../hooks";
|
|
5
|
+
import { tokens } from "../../../utils/design";
|
|
6
|
+
export function BaseSwitch({ value, defaultValue, onValueChange, disabled = false, accessibilityLabel, name, }) {
|
|
7
|
+
const { field } = useFormController({
|
|
8
|
+
name,
|
|
9
|
+
value: value !== null && value !== void 0 ? value : defaultValue,
|
|
10
|
+
});
|
|
11
|
+
const internalValue = value !== null && value !== void 0 ? value : field.value;
|
|
12
|
+
function getThumbColor() {
|
|
13
|
+
if (Platform.OS === "android") {
|
|
14
|
+
if (disabled) {
|
|
15
|
+
return tokens["color-disabled"];
|
|
16
|
+
}
|
|
17
|
+
else if (internalValue) {
|
|
18
|
+
return tokens["color-interactive"];
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
return tokens["color-surface--background"];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return undefined; //use default iOS
|
|
25
|
+
}
|
|
26
|
+
function getTrackColors() {
|
|
27
|
+
if (Platform.OS === "android") {
|
|
28
|
+
return {
|
|
29
|
+
true: disabled
|
|
30
|
+
? tokens["color-disabled--secondary"]
|
|
31
|
+
: tokens["color-green--lighter"],
|
|
32
|
+
false: disabled
|
|
33
|
+
? tokens["color-disabled--secondary"]
|
|
34
|
+
: tokens["color-disabled"],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
//iOS
|
|
39
|
+
return {
|
|
40
|
+
true: tokens["color-interactive"],
|
|
41
|
+
false: tokens["color-surface--background"],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return (React.createElement(Switch, { value: internalValue, onValueChange: (val) => {
|
|
46
|
+
if (!disabled) {
|
|
47
|
+
onValueChange === null || onValueChange === void 0 ? void 0 : onValueChange(val);
|
|
48
|
+
field.onChange(val);
|
|
49
|
+
}
|
|
50
|
+
}, disabled: disabled, thumbColor: getThumbColor(), trackColor: getTrackColors(), ios_backgroundColor: tokens["color-surface--background"], accessibilityLabel: accessibilityLabel, accessibilityRole: "switch", accessibilityState: {
|
|
51
|
+
disabled: disabled,
|
|
52
|
+
checked: internalValue,
|
|
53
|
+
} }));
|
|
54
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { BaseSwitch } from "./BaseSwitch";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Switch } from "./Switch";
|