@jobber/components-native 0.9.0 → 0.11.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.
Files changed (66) hide show
  1. package/dist/src/Button/Button.js +78 -0
  2. package/dist/src/Button/Button.style.js +92 -0
  3. package/dist/src/Button/components/InternalButtonLoading/InternalButtonLoading.js +36 -0
  4. package/dist/src/Button/components/InternalButtonLoading/InternalButtonLoading.style.js +4 -0
  5. package/dist/src/Button/components/InternalButtonLoading/index.js +1 -0
  6. package/dist/src/Button/index.js +1 -0
  7. package/dist/src/Button/types.js +1 -0
  8. package/dist/src/InputFieldWrapper/CommonInputStyles.style.js +33 -0
  9. package/dist/src/InputFieldWrapper/InputFieldWrapper.js +88 -0
  10. package/dist/src/InputFieldWrapper/InputFieldWrapper.style.js +79 -0
  11. package/dist/src/InputFieldWrapper/components/ClearAction/ClearAction.js +12 -0
  12. package/dist/src/InputFieldWrapper/components/ClearAction/ClearAction.style.js +25 -0
  13. package/dist/src/InputFieldWrapper/components/ClearAction/index.js +2 -0
  14. package/dist/src/InputFieldWrapper/components/ClearAction/messages.js +8 -0
  15. package/dist/src/InputFieldWrapper/components/Prefix/Prefix.js +34 -0
  16. package/dist/src/InputFieldWrapper/components/Suffix/Suffix.js +35 -0
  17. package/dist/src/InputFieldWrapper/hooks/useShowClear.js +15 -0
  18. package/dist/src/InputFieldWrapper/index.js +3 -0
  19. package/dist/src/index.js +2 -0
  20. package/dist/tsconfig.tsbuildinfo +1 -1
  21. package/dist/types/src/Button/Button.d.ts +71 -0
  22. package/dist/types/src/Button/Button.style.d.ts +86 -0
  23. package/dist/types/src/Button/components/InternalButtonLoading/InternalButtonLoading.d.ts +11 -0
  24. package/dist/types/src/Button/components/InternalButtonLoading/InternalButtonLoading.style.d.ts +4 -0
  25. package/dist/types/src/Button/components/InternalButtonLoading/index.d.ts +1 -0
  26. package/dist/types/src/Button/index.d.ts +2 -0
  27. package/dist/types/src/Button/types.d.ts +3 -0
  28. package/dist/types/src/InputFieldWrapper/CommonInputStyles.style.d.ts +30 -0
  29. package/dist/types/src/InputFieldWrapper/InputFieldWrapper.d.ts +63 -0
  30. package/dist/types/src/InputFieldWrapper/InputFieldWrapper.style.d.ts +82 -0
  31. package/dist/types/src/InputFieldWrapper/components/ClearAction/ClearAction.d.ts +10 -0
  32. package/dist/types/src/InputFieldWrapper/components/ClearAction/ClearAction.style.d.ts +22 -0
  33. package/dist/types/src/InputFieldWrapper/components/ClearAction/index.d.ts +2 -0
  34. package/dist/types/src/InputFieldWrapper/components/ClearAction/messages.d.ts +7 -0
  35. package/dist/types/src/InputFieldWrapper/components/Prefix/Prefix.d.ts +23 -0
  36. package/dist/types/src/InputFieldWrapper/components/Suffix/Suffix.d.ts +25 -0
  37. package/dist/types/src/InputFieldWrapper/hooks/useShowClear.d.ts +10 -0
  38. package/dist/types/src/InputFieldWrapper/index.d.ts +4 -0
  39. package/dist/types/src/index.d.ts +2 -0
  40. package/package.json +5 -2
  41. package/src/Button/Button.style.ts +116 -0
  42. package/src/Button/Button.test.tsx +298 -0
  43. package/src/Button/Button.tsx +223 -0
  44. package/src/Button/components/InternalButtonLoading/InternalButtonLoading.style.ts +5 -0
  45. package/src/Button/components/InternalButtonLoading/InternalButtonLoading.test.tsx +39 -0
  46. package/src/Button/components/InternalButtonLoading/InternalButtonLoading.tsx +77 -0
  47. package/src/Button/components/InternalButtonLoading/index.ts +1 -0
  48. package/src/Button/index.ts +2 -0
  49. package/src/Button/types.ts +3 -0
  50. package/src/InputFieldWrapper/CommonInputStyles.style.ts +37 -0
  51. package/src/InputFieldWrapper/InputFieldWrapper.style.ts +93 -0
  52. package/src/InputFieldWrapper/InputFieldWrapper.test.tsx +243 -0
  53. package/src/InputFieldWrapper/InputFieldWrapper.tsx +317 -0
  54. package/src/InputFieldWrapper/components/ClearAction/ClearAction.style.ts +27 -0
  55. package/src/InputFieldWrapper/components/ClearAction/ClearAction.test.tsx +15 -0
  56. package/src/InputFieldWrapper/components/ClearAction/ClearAction.tsx +32 -0
  57. package/src/InputFieldWrapper/components/ClearAction/index.ts +2 -0
  58. package/src/InputFieldWrapper/components/ClearAction/messages.ts +9 -0
  59. package/src/InputFieldWrapper/components/Prefix/Prefix.test.tsx +221 -0
  60. package/src/InputFieldWrapper/components/Prefix/Prefix.tsx +104 -0
  61. package/src/InputFieldWrapper/components/Suffix/Suffix.test.tsx +101 -0
  62. package/src/InputFieldWrapper/components/Suffix/Suffix.tsx +113 -0
  63. package/src/InputFieldWrapper/hooks/useShowClear.test.ts +158 -0
  64. package/src/InputFieldWrapper/hooks/useShowClear.ts +31 -0
  65. package/src/InputFieldWrapper/index.ts +4 -0
  66. package/src/index.ts +2 -0
@@ -0,0 +1,78 @@
1
+ import React from "react";
2
+ import { TouchableHighlight, View } from "react-native";
3
+ import { styles } from "./Button.style";
4
+ // eslint-disable-next-line import/no-internal-modules
5
+ import { InternalButtonLoading } from "./components/InternalButtonLoading";
6
+ import { ActionLabel } from "../ActionLabel";
7
+ import { Icon } from "../Icon";
8
+ import { tokens } from "../utils/design";
9
+ export function Button({ label, onPress, variation = "work", type = "primary", fullHeight = false, fullWidth = true, disabled = false, loading = false, size = "base", accessibilityLabel, accessibilityHint, icon, }) {
10
+ const buttonStyle = [
11
+ styles.button,
12
+ styles[variation],
13
+ styles[type],
14
+ styles[size],
15
+ disabled && styles.disabled,
16
+ fullHeight && styles.fullHeight,
17
+ fullWidth && styles.reducedPaddingForFullWidth,
18
+ ];
19
+ // attempts to use Pressable caused problems. When a ScrollView contained
20
+ // an InputText that was focused, it required two presses to activate the
21
+ // Pressable. Using a TouchableHighlight made things register correctly
22
+ // in a single press
23
+ return (React.createElement(TouchableHighlight, { onPress: onPress, testID: accessibilityLabel || label, accessibilityLabel: accessibilityLabel || label, accessibilityHint: accessibilityHint, accessibilityRole: "button", accessibilityState: { disabled, busy: loading }, disabled: disabled || loading, underlayColor: tokens["color-greyBlue--dark"], activeOpacity: tokens["opacity-pressed"], style: [
24
+ styles.touchable,
25
+ fullWidth && styles.fullWidth,
26
+ fullHeight && styles.fullHeight,
27
+ ] },
28
+ React.createElement(View, { style: buttonStyle },
29
+ loading && React.createElement(InternalButtonLoading, { variation: variation, type: type }),
30
+ React.createElement(View, { style: getContentStyles(label, icon) },
31
+ icon && (React.createElement(View, { style: styles.iconStyle },
32
+ React.createElement(Icon, { name: icon, color: getIconColorVariation(variation, type, disabled) }))),
33
+ label && (React.createElement(View, { style: styles.labelStyle },
34
+ React.createElement(ActionLabel, { variation: getActionLabelVariation(variation, type), disabled: disabled, align: icon ? "start" : undefined }, label)))))));
35
+ }
36
+ function getActionLabelVariation(variation, type) {
37
+ if (type === "primary" && variation !== "cancel") {
38
+ return "onPrimary";
39
+ }
40
+ switch (variation) {
41
+ case "learning":
42
+ return "learning";
43
+ case "destructive":
44
+ return "destructive";
45
+ case "cancel":
46
+ return "subtle";
47
+ default:
48
+ return "interactive";
49
+ }
50
+ }
51
+ function getIconColorVariation(variation, type, disabled) {
52
+ if (disabled) {
53
+ return "disabled";
54
+ }
55
+ if (type === "primary" && variation !== "cancel") {
56
+ return "white";
57
+ }
58
+ switch (variation) {
59
+ case "learning":
60
+ return "informative";
61
+ case "destructive":
62
+ return "destructive";
63
+ case "cancel":
64
+ return "interactiveSubtle";
65
+ default:
66
+ return "interactive";
67
+ }
68
+ }
69
+ function getContentStyles(label, icon) {
70
+ if (label && !icon) {
71
+ return undefined;
72
+ }
73
+ return [
74
+ styles.content,
75
+ icon && !!label && styles.iconPaddingOffset,
76
+ !!label && styles.contentWithLabel,
77
+ ];
78
+ }
@@ -0,0 +1,92 @@
1
+ import { StyleSheet } from "react-native";
2
+ import { tokens } from "../utils/design";
3
+ const iconTranslateY = tokens["space-large"] / 2;
4
+ const buttonRadius = tokens["radius-large"];
5
+ export const baseButtonHeight = tokens["space-base"] * 3.5;
6
+ export const smallButtonHeight = tokens["space-base"] * 2.25;
7
+ export const styles = StyleSheet.create({
8
+ fullHeight: {
9
+ flexGrow: 1,
10
+ flexShrink: 0,
11
+ },
12
+ fullWidth: {
13
+ alignSelf: "stretch",
14
+ },
15
+ touchable: {
16
+ borderRadius: buttonRadius,
17
+ },
18
+ button: {
19
+ justifyContent: "center",
20
+ alignItems: "center",
21
+ alignSelf: "stretch",
22
+ flexDirection: "row",
23
+ overflow: "hidden",
24
+ margin: 0,
25
+ borderRadius: buttonRadius,
26
+ borderWidth: tokens["border-base"],
27
+ paddingVertical: tokens["space-small"],
28
+ },
29
+ base: {
30
+ minHeight: baseButtonHeight,
31
+ paddingHorizontal: tokens["space-base"],
32
+ },
33
+ small: {
34
+ minHeight: smallButtonHeight,
35
+ paddingHorizontal: tokens["space-small"] + tokens["space-smaller"],
36
+ },
37
+ reducedPaddingForFullWidth: {
38
+ paddingHorizontal: tokens["space-smaller"],
39
+ },
40
+ iconPaddingOffset: {
41
+ paddingRight: tokens["space-smaller"],
42
+ },
43
+ content: {
44
+ paddingLeft: tokens["space-large"],
45
+ height: "100%",
46
+ },
47
+ contentWithLabel: {
48
+ paddingLeft: tokens["space-large"] + tokens["space-small"],
49
+ },
50
+ iconStyle: {
51
+ position: "absolute",
52
+ top: "50%",
53
+ left: 0,
54
+ transform: [{ translateY: -iconTranslateY }],
55
+ },
56
+ labelStyle: {
57
+ flexGrow: 1,
58
+ justifyContent: "center",
59
+ },
60
+ /* Variations */
61
+ work: {
62
+ backgroundColor: tokens["color-interactive"],
63
+ borderColor: tokens["color-interactive"],
64
+ },
65
+ learning: {
66
+ backgroundColor: tokens["color-informative"],
67
+ borderColor: tokens["color-informative"],
68
+ },
69
+ destructive: {
70
+ backgroundColor: tokens["color-destructive"],
71
+ borderColor: tokens["color-destructive"],
72
+ },
73
+ /* Cancel is special because, by default, it's styled as a secondary button */
74
+ cancel: {
75
+ backgroundColor: tokens["color-surface"],
76
+ borderColor: tokens["color-interactive--subtle"],
77
+ },
78
+ /* Types */
79
+ primary: {},
80
+ secondary: {
81
+ backgroundColor: tokens["color-surface"],
82
+ },
83
+ tertiary: {
84
+ backgroundColor: tokens["color-surface"],
85
+ borderColor: tokens["color-surface"],
86
+ },
87
+ /* Disabled */
88
+ disabled: {
89
+ borderColor: tokens["color-disabled--secondary"],
90
+ backgroundColor: tokens["color-disabled--secondary"],
91
+ },
92
+ });
@@ -0,0 +1,36 @@
1
+ import React from "react";
2
+ import { ImageBackground, PixelRatio } from "react-native";
3
+ import Animated, { Easing, useAnimatedStyle, useSharedValue, withDelay, withRepeat, withTiming, } from "react-native-reanimated";
4
+ import { styles } from "./InternalButtonLoading.style";
5
+ import { tokens } from "../../../utils/design";
6
+ const imageWidth = 96;
7
+ const offset = PixelRatio.roundToNearestPixel(imageWidth / PixelRatio.get());
8
+ const leftOffset = -1 * offset;
9
+ const AnimatedImage = Animated.createAnimatedComponent(ImageBackground);
10
+ function InternalButtonLoadingInternal({ variation, type, }) {
11
+ const translateX = useSharedValue(0);
12
+ translateX.value = withRepeat(withTiming(offset, {
13
+ duration: tokens["timing-loading"],
14
+ easing: Easing.linear,
15
+ }), -1);
16
+ const opacity = useSharedValue(0);
17
+ opacity.value = withDelay(tokens["timing-quick"], withTiming(1, {
18
+ duration: tokens["timing-base"],
19
+ easing: Easing.linear,
20
+ }));
21
+ const animations = useAnimatedStyle(() => ({
22
+ opacity: opacity.value,
23
+ transform: [{ translateX: translateX.value }],
24
+ }));
25
+ return (React.createElement(AnimatedImage, { testID: "loadingImage", source: { uri: getLoadingPattern({ variation, type }) }, resizeMode: "repeat", style: [styles.image, { left: leftOffset }, animations] }));
26
+ }
27
+ export const darkPattern = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgAgMAAACf9p+rAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAJcEhZcwAAITgAACE4AUWWMWAAAAAMUExURQAAAEdwTAAAAAAAAKDh18UAAAAEdFJOUxkADQwimkzpAAAAtUlEQVRIx+3NqxHDQBRDUc0YuxyXokxgSkmT7sdgP++3YoYrqAsOYDto+7gfpwtfHy4Xfj7cLvw3sYlNbOINAoI4IIgTgrggiBuCIAThQyB8CIQLkXAhEi5EwoVIWEiEhURYSISFRMyQiRkyMUMmZsjECIUYoRAjFGKEQvRQiR4q0UMleqhECwuihQXRwoJoYUEQgiAEQQiCEAQhCEIQhCAIQRCCIARBCIIQBCEIQhCEIAhB8AEuzZ5wHe17xgAAAABJRU5ErkJggg==";
28
+ export const lightPattern = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgAgMAAACf9p+rAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAJcEhZcwAAITgAACE4AUWWMWAAAAAJUExURf///0dwTP///0SistEAAAADdFJOU0AAILGCadYAAAC0SURBVEjH7c2pFcNAFENRHTMX4pKUE5hS0oT7NZjlbyNmOIJ64AK2g7aP+3G68PXhcuHnw+3CfxOb2MQm3iAgiAOCOCGIC4K4IQhCED4EwodAuBAJFyLhQiRciISFRFhIhIVEWEjEDJmYIRMzZGKGTIxQiBEKMUIhRihED5XooRI9VKKHSrSwIFpYEC0siBYWBCEIQhCEIAhBEIIgBEEIghAEIQhCEIQgCEEQgiAEQQiCEAQfva6WeBniVLgAAAAASUVORK5CYII=";
29
+ function getLoadingPattern({ variation, type, }) {
30
+ if (variation === "cancel")
31
+ return darkPattern;
32
+ if (type === "primary")
33
+ return lightPattern;
34
+ return darkPattern;
35
+ }
36
+ export const InternalButtonLoading = React.memo(InternalButtonLoadingInternal);
@@ -0,0 +1,4 @@
1
+ import { StyleSheet } from "react-native";
2
+ export const styles = StyleSheet.create({
3
+ image: StyleSheet.absoluteFillObject,
4
+ });
@@ -0,0 +1 @@
1
+ export { InternalButtonLoading } from "./InternalButtonLoading";
@@ -0,0 +1 @@
1
+ export { Button } from "./Button";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,33 @@
1
+ import { StyleSheet } from "react-native";
2
+ import { typographyStyles } from "../Typography";
3
+ import { tokens } from "../utils/design";
4
+ export const commonInputStyles = StyleSheet.create({
5
+ input: {
6
+ width: "100%",
7
+ flexShrink: 1,
8
+ flexGrow: 1,
9
+ color: tokens["color-text"],
10
+ fontFamily: typographyStyles.baseRegularRegular.fontFamily,
11
+ fontSize: typographyStyles.defaultSize.fontSize,
12
+ letterSpacing: typographyStyles.baseLetterSpacing.letterSpacing,
13
+ minHeight: tokens["space-largest"],
14
+ padding: 0,
15
+ },
16
+ inputEmpty: {
17
+ paddingTop: 0,
18
+ },
19
+ inputDisabled: {
20
+ color: typographyStyles.disabled.color,
21
+ },
22
+ container: {
23
+ marginVertical: tokens["space-smaller"],
24
+ backgroundColor: tokens["color-surface"],
25
+ minHeight: tokens["space-largest"],
26
+ flexDirection: "row",
27
+ justifyContent: "space-between",
28
+ width: "100%",
29
+ borderColor: tokens["color-grey"],
30
+ borderStyle: "solid",
31
+ borderBottomWidth: tokens["border-base"],
32
+ },
33
+ });
@@ -0,0 +1,88 @@
1
+ import React from "react";
2
+ import {
3
+ // eslint-disable-next-line no-restricted-imports
4
+ Text as RNText, View, } from "react-native";
5
+ import { styles } from "./InputFieldWrapper.style";
6
+ import { PrefixIcon, PrefixLabel } from "./components/Prefix/Prefix";
7
+ import { SuffixIcon, SuffixLabel } from "./components/Suffix/Suffix";
8
+ import { ClearAction } from "./components/ClearAction";
9
+ import { ErrorMessageWrapper } from "../ErrorMessageWrapper";
10
+ import { typographyStyles } from "../Typography";
11
+ import { Text } from "../Text";
12
+ export function InputFieldWrapper({ invalid, disabled, placeholder, assistiveText, prefix, suffix, hasMiniLabel = false, hasValue = false, error, focused = false, children, onClear, showClearAction = false, styleOverride, }) {
13
+ fieldAffixRequiredPropsCheck([prefix, suffix]);
14
+ const handleClear = onClear !== null && onClear !== void 0 ? onClear : noopClear;
15
+ warnIfClearActionWithNoOnClear(onClear, showClearAction);
16
+ const inputInvalid = Boolean(invalid) || Boolean(error);
17
+ return (React.createElement(ErrorMessageWrapper, { message: getMessage({ invalid, error }) },
18
+ React.createElement(View, { testID: "ATL-InputFieldWrapper", style: [
19
+ styles.container,
20
+ focused && styles.inputFocused,
21
+ (Boolean(invalid) || error) && styles.inputInvalid,
22
+ disabled && styles.disabled,
23
+ styleOverride === null || styleOverride === void 0 ? void 0 : styleOverride.container,
24
+ ] },
25
+ (prefix === null || prefix === void 0 ? void 0 : prefix.icon) && (React.createElement(PrefixIcon, { disabled: disabled, focused: focused, hasMiniLabel: hasMiniLabel, inputInvalid: inputInvalid, icon: prefix.icon })),
26
+ React.createElement(View, { style: [styles.inputContainer] },
27
+ React.createElement(View, { style: [
28
+ !!placeholder && styles.label,
29
+ hasMiniLabel && styles.miniLabel,
30
+ disabled && styles.disabled,
31
+ hasMiniLabel &&
32
+ showClearAction &&
33
+ styles.miniLabelShowClearAction,
34
+ ], pointerEvents: "none" },
35
+ React.createElement(Placeholder, { placeholder: placeholder, labelVariation: getLabelVariation(error, invalid, focused, disabled), hasMiniLabel: hasMiniLabel, styleOverride: styleOverride === null || styleOverride === void 0 ? void 0 : styleOverride.placeholderText })),
36
+ (prefix === null || prefix === void 0 ? void 0 : prefix.label) && hasValue && (React.createElement(PrefixLabel, { disabled: disabled, focused: focused, hasMiniLabel: hasMiniLabel, inputInvalid: inputInvalid, label: prefix.label, styleOverride: styleOverride === null || styleOverride === void 0 ? void 0 : styleOverride.prefixLabel })),
37
+ children,
38
+ (showClearAction || (suffix === null || suffix === void 0 ? void 0 : suffix.label) || (suffix === null || suffix === void 0 ? void 0 : suffix.icon)) && (React.createElement(View, { style: styles.inputEndContainer },
39
+ showClearAction && (React.createElement(ClearAction, { hasMarginRight: !!(suffix === null || suffix === void 0 ? void 0 : suffix.icon) || !!(suffix === null || suffix === void 0 ? void 0 : suffix.label), onPress: handleClear })),
40
+ (suffix === null || suffix === void 0 ? void 0 : suffix.label) && hasValue && (React.createElement(SuffixLabel, { disabled: disabled, focused: focused, hasMiniLabel: hasMiniLabel, inputInvalid: inputInvalid, label: suffix.label, hasLeftMargin: !showClearAction, styleOverride: styleOverride === null || styleOverride === void 0 ? void 0 : styleOverride.suffixLabel })),
41
+ (suffix === null || suffix === void 0 ? void 0 : suffix.icon) && (React.createElement(SuffixIcon, { disabled: disabled, focused: focused, hasMiniLabel: hasMiniLabel, hasLeftMargin: !!(!showClearAction || (suffix === null || suffix === void 0 ? void 0 : suffix.label)), inputInvalid: inputInvalid, icon: suffix.icon, onPress: suffix.onPress })))))),
42
+ assistiveText && !error && !invalid && (React.createElement(Text, { level: "textSupporting", variation: disabled ? "disabled" : focused ? "interactive" : "subdued" }, assistiveText))));
43
+ }
44
+ function getLabelVariation(error, invalid, focused, disabled) {
45
+ if (invalid || error) {
46
+ return "error";
47
+ }
48
+ else if (disabled) {
49
+ return "disabled";
50
+ }
51
+ else if (focused) {
52
+ return "interactive";
53
+ }
54
+ return "subdued";
55
+ }
56
+ function fieldAffixRequiredPropsCheck(affixPair) {
57
+ affixPair.map(affix => {
58
+ if (typeof affix !== "undefined" && !affix.icon && !affix.label) {
59
+ throw new Error(`One of 'label' or 'icon' is required by the field affix component.`);
60
+ }
61
+ });
62
+ }
63
+ function warnIfClearActionWithNoOnClear(onClear, showClearAction) {
64
+ if (showClearAction && !onClear && __DEV__) {
65
+ console.warn("Declare an `onClear` prop on your input. You can set `clearable` to never or `showClearAction` to false if you don't need a clearable input");
66
+ }
67
+ }
68
+ function noopClear() {
69
+ warnIfClearActionWithNoOnClear(undefined, true);
70
+ }
71
+ function getMessage({ invalid, error, }) {
72
+ const messages = [];
73
+ if (error === null || error === void 0 ? void 0 : error.message)
74
+ messages.push(error.message);
75
+ if (invalid && typeof invalid === "string")
76
+ messages.push(invalid);
77
+ return messages.join("\n");
78
+ }
79
+ function Placeholder({ placeholder, styleOverride, labelVariation, hasMiniLabel, }) {
80
+ return (React.createElement(React.Fragment, null, !styleOverride ? (React.createElement(Text, { hideFromScreenReader: true, maxLines: "single", variation: labelVariation, level: hasMiniLabel ? "textSupporting" : "text" }, placeholder)) : (React.createElement(RNText, { accessibilityRole: "none", accessible: false, importantForAccessibility: "no-hide-descendants", numberOfLines: 1, style: [
81
+ typographyStyles[labelVariation],
82
+ typographyStyles.baseRegularRegular,
83
+ hasMiniLabel
84
+ ? typographyStyles.smallSize
85
+ : typographyStyles.defaultSize,
86
+ styleOverride,
87
+ ] }, placeholder))));
88
+ }
@@ -0,0 +1,79 @@
1
+ import { StyleSheet } from "react-native";
2
+ import { commonInputStyles } from "./CommonInputStyles.style";
3
+ import { tokens } from "../utils/design";
4
+ import { typographyStyles } from "../Typography";
5
+ export const styles = StyleSheet.create({
6
+ container: StyleSheet.flatten([commonInputStyles.container]),
7
+ inputContainer: {
8
+ flexDirection: "row",
9
+ flex: 1,
10
+ justifyContent: "flex-start",
11
+ },
12
+ inputFocused: {
13
+ borderColor: tokens["color-interactive"],
14
+ },
15
+ inputInvalid: {
16
+ borderColor: tokens["color-critical"],
17
+ },
18
+ label: {
19
+ // for placeholder
20
+ position: "absolute",
21
+ top: typographyStyles.smallSize.fontSize,
22
+ right: 0,
23
+ bottom: 0,
24
+ left: 0,
25
+ },
26
+ miniLabel: {
27
+ top: 0,
28
+ paddingTop: tokens["space-smallest"],
29
+ backgroundColor: tokens["color-surface"],
30
+ maxHeight: (typographyStyles.smallSize.lineHeight || 0) + tokens["space-smaller"],
31
+ zIndex: 1,
32
+ },
33
+ // Prevents the miniLabel from cutting off the ClearAction button
34
+ miniLabelShowClearAction: {
35
+ backgroundColor: "transparent",
36
+ },
37
+ disabled: {
38
+ backgroundColor: tokens["color-disabled--secondary"],
39
+ borderTopLeftRadius: tokens["radius-large"],
40
+ borderTopRightRadius: tokens["radius-large"],
41
+ },
42
+ fieldAffix: {
43
+ flexDirection: "row",
44
+ },
45
+ fieldAffixMiniLabel: {
46
+ paddingTop: 0,
47
+ // @ts-expect-error tsc-ci
48
+ top: typographyStyles.smallSize.fontSize / 2,
49
+ right: 0,
50
+ bottom: 0,
51
+ left: 0,
52
+ },
53
+ prefixIcon: {
54
+ justifyContent: "center",
55
+ paddingRight: tokens["space-small"],
56
+ },
57
+ prefixLabel: {
58
+ justifyContent: "center",
59
+ paddingTop: tokens["space-minuscule"],
60
+ paddingRight: tokens["space-minuscule"],
61
+ },
62
+ suffixIcon: {
63
+ justifyContent: "center",
64
+ },
65
+ suffixLabel: {
66
+ justifyContent: "center",
67
+ paddingTop: tokens["space-minuscule"],
68
+ },
69
+ suffixIconMargin: {
70
+ marginLeft: tokens["space-small"] + tokens["space-smaller"],
71
+ },
72
+ suffixLabelMargin: {
73
+ marginLeft: tokens["space-smallest"],
74
+ },
75
+ inputEndContainer: {
76
+ flexDirection: "row",
77
+ zIndex: 1,
78
+ },
79
+ });
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ import { Pressable, View } from "react-native";
3
+ import { useIntl } from "react-intl";
4
+ import { styles } from "./ClearAction.style";
5
+ import { messages } from "./messages";
6
+ import { Icon } from "../../../Icon";
7
+ export function ClearAction({ onPress, hasMarginRight = false, }) {
8
+ const { formatMessage } = useIntl();
9
+ return (React.createElement(Pressable, { style: [styles.container, hasMarginRight && styles.addedMargin], onPress: onPress, accessibilityLabel: formatMessage(messages.clearTextLabel) },
10
+ React.createElement(View, { style: styles.circle },
11
+ React.createElement(Icon, { size: "small", name: "cross", color: "interactiveSubtle" }))));
12
+ }
@@ -0,0 +1,25 @@
1
+ import { StyleSheet } from "react-native";
2
+ import { tokens } from "../../../utils/design";
3
+ const width = tokens["space-smaller"] + tokens["space-larger"];
4
+ export const styles = StyleSheet.create({
5
+ container: {
6
+ width,
7
+ height: "100%",
8
+ flexDirection: "row",
9
+ justifyContent: "center",
10
+ alignItems: "center",
11
+ alignSelf: "center",
12
+ },
13
+ circle: {
14
+ backgroundColor: tokens["color-surface--background"],
15
+ borderRadius: tokens["radius-circle"],
16
+ width: tokens["space-large"],
17
+ height: tokens["space-large"],
18
+ flexDirection: "row",
19
+ justifyContent: "center",
20
+ alignItems: "center",
21
+ },
22
+ addedMargin: {
23
+ marginRight: tokens["space-small"],
24
+ },
25
+ });
@@ -0,0 +1,2 @@
1
+ export { ClearAction } from "./ClearAction";
2
+ export { messages } from "./messages";
@@ -0,0 +1,8 @@
1
+ import { defineMessages } from "react-intl";
2
+ export const messages = defineMessages({
3
+ clearTextLabel: {
4
+ id: "clearTextLabel",
5
+ defaultMessage: "Clear input",
6
+ description: "Accessiblity label for the clear input button",
7
+ },
8
+ });
@@ -0,0 +1,34 @@
1
+ import React from "react";
2
+ import {
3
+ // eslint-disable-next-line no-restricted-imports
4
+ Text as RNText, View, } from "react-native";
5
+ import { Icon } from "../../../Icon";
6
+ import { Text } from "../../../Text";
7
+ import { tokens } from "../../../utils/design";
8
+ import { typographyStyles } from "../../../Typography";
9
+ import { styles } from "../../InputFieldWrapper.style";
10
+ export const prefixLabelTestId = "ATL-InputFieldWrapper-PrefixLabel";
11
+ export const prefixIconTestId = "ATL-InputFieldWrapper-PrefixIcon";
12
+ export function PrefixLabel({ focused, disabled, hasMiniLabel, inputInvalid, label, styleOverride, }) {
13
+ return (React.createElement(View, { style: [
14
+ styles.fieldAffix,
15
+ focused && styles.inputFocused,
16
+ inputInvalid && styles.inputInvalid,
17
+ ], testID: prefixLabelTestId },
18
+ React.createElement(View, { style: [styles.prefixLabel, hasMiniLabel && styles.fieldAffixMiniLabel] }, !styleOverride ? (React.createElement(Text, { variation: disabled ? "disabled" : "base" }, label)) : (React.createElement(RNText, { allowFontScaling: true, style: [
19
+ typographyStyles.baseRegularRegular,
20
+ typographyStyles.base,
21
+ typographyStyles.defaultSize,
22
+ disabled ? typographyStyles.subdued : typographyStyles.base,
23
+ styleOverride,
24
+ ] }, label)))));
25
+ }
26
+ export function PrefixIcon({ focused, disabled, inputInvalid, icon, }) {
27
+ return (React.createElement(View, { testID: prefixIconTestId, style: [
28
+ styles.fieldAffix,
29
+ focused && styles.inputFocused,
30
+ inputInvalid && styles.inputInvalid,
31
+ ] },
32
+ React.createElement(View, { style: styles.prefixIcon },
33
+ React.createElement(Icon, { customColor: disabled ? tokens["color-disabled"] : tokens["color-greyBlue"], name: icon }))));
34
+ }
@@ -0,0 +1,35 @@
1
+ import React from "react";
2
+ import { Pressable,
3
+ // eslint-disable-next-line no-restricted-imports
4
+ Text as RNText, View, } from "react-native";
5
+ import { tokens } from "../../../utils/design";
6
+ import { Icon } from "../../../Icon";
7
+ import { Text } from "../../../Text";
8
+ import { typographyStyles } from "../../../Typography";
9
+ import { styles } from "../../InputFieldWrapper.style";
10
+ export const suffixLabelTestId = "ATL-InputFieldWrapper-SuffixLabel";
11
+ export const suffixIconTestId = "ATL-InputFieldWrapper-SuffixIcon";
12
+ export function SuffixLabel({ focused, disabled, hasMiniLabel, inputInvalid, label, hasLeftMargin = true, styleOverride, }) {
13
+ return (React.createElement(View, { testID: suffixLabelTestId, style: [
14
+ styles.fieldAffix,
15
+ focused && styles.inputFocused,
16
+ inputInvalid && styles.inputInvalid,
17
+ hasLeftMargin && styles.suffixLabelMargin,
18
+ ] },
19
+ React.createElement(View, { style: [styles.suffixLabel, hasMiniLabel && styles.fieldAffixMiniLabel] }, !styleOverride ? (React.createElement(Text, { variation: disabled ? "disabled" : "base" }, label)) : (React.createElement(RNText, { allowFontScaling: true, style: [
20
+ typographyStyles.baseRegularRegular,
21
+ typographyStyles.base,
22
+ typographyStyles.defaultSize,
23
+ disabled ? typographyStyles.subdued : typographyStyles.base,
24
+ styleOverride,
25
+ ] }, label)))));
26
+ }
27
+ export function SuffixIcon({ focused, disabled, inputInvalid, icon, hasLeftMargin = false, onPress, }) {
28
+ return (React.createElement(View, { testID: suffixIconTestId, style: [
29
+ styles.fieldAffix,
30
+ focused && styles.inputFocused,
31
+ inputInvalid && styles.inputInvalid,
32
+ ] },
33
+ React.createElement(Pressable, { style: [styles.suffixIcon, hasLeftMargin && styles.suffixIconMargin], onPress: onPress },
34
+ React.createElement(Icon, { customColor: disabled ? tokens["color-disabled"] : tokens["color-greyBlue"], name: icon }))));
35
+ }
@@ -0,0 +1,15 @@
1
+ export function useShowClear({ clearable, multiline, focused, hasValue, disabled = false, }) {
2
+ if (multiline && clearable !== "never") {
3
+ throw new Error("Multiline inputs can not be clearable");
4
+ }
5
+ // Do not show if there is no value
6
+ if (!hasValue || clearable === "never" || disabled) {
7
+ return false;
8
+ }
9
+ switch (clearable) {
10
+ case "while-editing":
11
+ return focused;
12
+ case "always":
13
+ return true;
14
+ }
15
+ }
@@ -0,0 +1,3 @@
1
+ export { commonInputStyles } from "./CommonInputStyles.style";
2
+ export { InputFieldWrapper } from "./InputFieldWrapper";
3
+ export { useShowClear } from "./hooks/useShowClear";
package/dist/src/index.js CHANGED
@@ -9,3 +9,5 @@ export * from "./ActivityIndicator";
9
9
  export * from "./Card";
10
10
  export * from "./StatusLabel";
11
11
  export * from "./AtlantisContext";
12
+ export * from "./Button";
13
+ export * from "./InputFieldWrapper";