@jobber/components-native 0.26.0 → 0.27.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 (33) hide show
  1. package/dist/src/ButtonGroup/ButtonGroup.js +29 -0
  2. package/dist/src/ButtonGroup/ButtonGroup.style.js +18 -0
  3. package/dist/src/ButtonGroup/ButtonGroupAction.js +10 -0
  4. package/dist/src/ButtonGroup/components/SecondaryActionSheet/SecondaryActionSheet.js +17 -0
  5. package/dist/src/ButtonGroup/components/SecondaryActionSheet/index.js +1 -0
  6. package/dist/src/ButtonGroup/index.js +2 -0
  7. package/dist/src/ButtonGroup/messages.js +18 -0
  8. package/dist/src/ButtonGroup/types.js +1 -0
  9. package/dist/src/ButtonGroup/utils.js +42 -0
  10. package/dist/src/index.js +1 -0
  11. package/dist/tsconfig.tsbuildinfo +1 -1
  12. package/dist/types/src/ButtonGroup/ButtonGroup.d.ts +30 -0
  13. package/dist/types/src/ButtonGroup/ButtonGroup.style.d.ts +16 -0
  14. package/dist/types/src/ButtonGroup/ButtonGroupAction.d.ts +47 -0
  15. package/dist/types/src/ButtonGroup/components/SecondaryActionSheet/SecondaryActionSheet.d.ts +13 -0
  16. package/dist/types/src/ButtonGroup/components/SecondaryActionSheet/index.d.ts +1 -0
  17. package/dist/types/src/ButtonGroup/index.d.ts +3 -0
  18. package/dist/types/src/ButtonGroup/messages.d.ts +17 -0
  19. package/dist/types/src/ButtonGroup/types.d.ts +7 -0
  20. package/dist/types/src/ButtonGroup/utils.d.ts +19 -0
  21. package/dist/types/src/index.d.ts +1 -0
  22. package/package.json +2 -2
  23. package/src/ButtonGroup/ButtonGroup.style.ts +19 -0
  24. package/src/ButtonGroup/ButtonGroup.test.tsx +325 -0
  25. package/src/ButtonGroup/ButtonGroup.tsx +113 -0
  26. package/src/ButtonGroup/ButtonGroupAction.tsx +66 -0
  27. package/src/ButtonGroup/components/SecondaryActionSheet/SecondaryActionSheet.tsx +55 -0
  28. package/src/ButtonGroup/components/SecondaryActionSheet/index.ts +1 -0
  29. package/src/ButtonGroup/index.ts +8 -0
  30. package/src/ButtonGroup/messages.ts +19 -0
  31. package/src/ButtonGroup/types.ts +30 -0
  32. package/src/ButtonGroup/utils.ts +86 -0
  33. package/src/index.ts +1 -0
@@ -0,0 +1,66 @@
1
+ import { IconColorNames, IconNames } from "@jobber/design";
2
+ import React from "react";
3
+ import { ButtonType, ButtonVariation } from "../Button";
4
+
5
+ export interface ButtonGroupActionProps {
6
+ /**
7
+ * Text to be displayed on the action button
8
+ */
9
+ label: string;
10
+
11
+ /**
12
+ * Icon to be displayed on the action button
13
+ */
14
+ icon?: IconNames;
15
+
16
+ /**
17
+ * Determines the color of the icon. If not specified, some icons have a default system colour which will be used
18
+ * Others that don't have a system colour fall back to greyBlue.
19
+ * Only applies the iconColor to ButtonGroup.PrimaryAction when it is rendered under the "more" menu.
20
+ */
21
+ iconColor?: IconColorNames;
22
+
23
+ /**
24
+ * Press handler for the action button
25
+ */
26
+ onPress: () => void;
27
+ loading?: boolean;
28
+ }
29
+
30
+ export interface ButtonGroupSecondaryActionProps
31
+ extends ButtonGroupActionProps {
32
+ /**
33
+ * Indicates whether the secondary action is destructive in nature.
34
+ */
35
+ destructive?: boolean;
36
+ }
37
+
38
+ export interface ButtonGroupPrimaryActionProps extends ButtonGroupActionProps {
39
+ /**
40
+ * Sets the action button style (default: "primary")
41
+ */
42
+ buttonType?: ButtonType;
43
+
44
+ /**
45
+ * Themes the action button to the type of action it performs (default: "work")
46
+ */
47
+ buttonVariation?: ButtonVariation;
48
+
49
+ /**
50
+ * Optional custom button that can be rendered in place of the primary action button
51
+ */
52
+ customButton?: JSX.Element;
53
+ loading?: boolean;
54
+ }
55
+
56
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
57
+ export function PrimaryAction(_: ButtonGroupPrimaryActionProps): JSX.Element {
58
+ return <></>;
59
+ }
60
+
61
+ export function SecondaryAction(
62
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
63
+ _: ButtonGroupSecondaryActionProps,
64
+ ): JSX.Element {
65
+ return <></>;
66
+ }
@@ -0,0 +1,55 @@
1
+ import React, { RefObject } from "react";
2
+ import { View } from "react-native";
3
+ import { Portal } from "react-native-portalize";
4
+ import { ButtonGroupSecondaryActionProps } from "../../types";
5
+ import { BottomSheetOption } from "../../../BottomSheet/components/BottomSheetOption";
6
+ import { BottomSheet, BottomSheetRef } from "../../../BottomSheet/BottomSheet";
7
+
8
+ interface SecondaryActionSheetProps {
9
+ actions: ButtonGroupSecondaryActionProps[];
10
+ secondaryActionsRef: RefObject<BottomSheetRef>;
11
+ showCancel?: boolean;
12
+ heading?: string;
13
+ onOpenBottomSheet?: () => void;
14
+ onCloseBottomSheet?: () => void;
15
+ }
16
+
17
+ export function SecondaryActionSheet({
18
+ actions,
19
+ secondaryActionsRef,
20
+ heading,
21
+ showCancel,
22
+ onOpenBottomSheet,
23
+ onCloseBottomSheet,
24
+ }: SecondaryActionSheetProps): JSX.Element {
25
+ return (
26
+ <Portal>
27
+ <BottomSheet
28
+ heading={heading}
29
+ showCancel={showCancel}
30
+ ref={secondaryActionsRef}
31
+ onOpen={onOpenBottomSheet}
32
+ onClose={onCloseBottomSheet}
33
+ >
34
+ <View>
35
+ {actions.map((action, index) => {
36
+ const { label, onPress, icon, iconColor, destructive } = action;
37
+ return (
38
+ <BottomSheetOption
39
+ destructive={destructive}
40
+ key={index}
41
+ text={label}
42
+ onPress={() => {
43
+ secondaryActionsRef?.current?.close();
44
+ onPress();
45
+ }}
46
+ icon={icon}
47
+ iconColor={iconColor}
48
+ />
49
+ );
50
+ })}
51
+ </View>
52
+ </BottomSheet>
53
+ </Portal>
54
+ );
55
+ }
@@ -0,0 +1 @@
1
+ export { SecondaryActionSheet } from "./SecondaryActionSheet";
@@ -0,0 +1,8 @@
1
+ export { ButtonGroup } from "./ButtonGroup";
2
+ export type {
3
+ ButtonGroupActionProps,
4
+ ButtonGroupPrimaryActionProps,
5
+ ButtonGroupSecondaryActionProps,
6
+ ButtonGroupActionElement,
7
+ } from "./types";
8
+ export { usePreventTapWhenOffline } from "./utils";
@@ -0,0 +1,19 @@
1
+ import { defineMessages } from "react-intl";
2
+
3
+ export const messages = defineMessages({
4
+ more: {
5
+ id: "more",
6
+ defaultMessage: "More",
7
+ description: "Accessibility label for the More button",
8
+ },
9
+ unavailableNetworkTitle: {
10
+ id: "unavailableNetworkTitle",
11
+ defaultMessage: "Network unavailable",
12
+ description: "The title for alert about network unavailable",
13
+ },
14
+ unavailableNetworkMessage: {
15
+ id: "unavailableNetworkMessage",
16
+ defaultMessage: "Check your internet connection and try again later.",
17
+ description: "The message for alert about network unavailable",
18
+ },
19
+ });
@@ -0,0 +1,30 @@
1
+ import { ReactElement } from "react";
2
+ import {
3
+ ButtonGroupActionProps,
4
+ ButtonGroupPrimaryActionProps,
5
+ ButtonGroupSecondaryActionProps,
6
+ PrimaryAction,
7
+ SecondaryAction,
8
+ } from "./ButtonGroupAction";
9
+
10
+ export type ButtonGroupPrimaryActionElement = ReactElement<
11
+ ButtonGroupPrimaryActionProps,
12
+ typeof PrimaryAction
13
+ >;
14
+
15
+ export type ButtonGroupSecondaryActionElement = ReactElement<
16
+ ButtonGroupActionProps,
17
+ typeof SecondaryAction
18
+ >;
19
+
20
+ export type ButtonGroupActionElement =
21
+ | ButtonGroupPrimaryActionElement
22
+ | ButtonGroupSecondaryActionElement;
23
+
24
+ export type BottomSheetTextTransform = "capitalize" | "none";
25
+
26
+ export type {
27
+ ButtonGroupActionProps,
28
+ ButtonGroupPrimaryActionProps,
29
+ ButtonGroupSecondaryActionProps,
30
+ };
@@ -0,0 +1,86 @@
1
+ import React, { useCallback } from "react";
2
+ import { useIntl } from "react-intl";
3
+ import { Alert } from "react-native";
4
+ import { messages } from "./messages";
5
+ import {
6
+ ButtonGroupActionElement,
7
+ ButtonGroupPrimaryActionElement,
8
+ } from "./types";
9
+ import {
10
+ ButtonGroupActionProps,
11
+ PrimaryAction,
12
+ SecondaryAction,
13
+ } from "./ButtonGroupAction";
14
+ import { useAtlantisContext } from "../AtlantisContext/AtlantisContext";
15
+
16
+ interface UsePreventTapWhenOfflineShape {
17
+ readonly handlePress: (
18
+ callback: ButtonGroupActionProps["onPress"],
19
+ ) => () => void;
20
+ }
21
+
22
+ /**
23
+ * Determine if the onPress should be fired or an alert when the device is
24
+ * online or offline
25
+ */
26
+ export function usePreventTapWhenOffline(): UsePreventTapWhenOfflineShape {
27
+ const { formatMessage } = useIntl();
28
+ const { isOnline } = useAtlantisContext();
29
+
30
+ const handlePress = useCallback(
31
+ (callback: ButtonGroupActionProps["onPress"]) => {
32
+ if (isOnline) return callback;
33
+
34
+ return () =>
35
+ Alert.alert(
36
+ formatMessage(messages.unavailableNetworkTitle),
37
+ formatMessage(messages.unavailableNetworkMessage),
38
+ );
39
+ },
40
+ [formatMessage, isOnline],
41
+ );
42
+
43
+ return { handlePress };
44
+ }
45
+
46
+ interface GetActionShape {
47
+ readonly primaryActions: ButtonGroupPrimaryActionElement[];
48
+ readonly secondaryActions: ButtonGroupActionElement[];
49
+ }
50
+
51
+ /**
52
+ * Separate the Primary and Secondary actions into 2 const
53
+ */
54
+ export function getActions(
55
+ children: ButtonGroupActionElement | ButtonGroupActionElement[],
56
+ ): GetActionShape {
57
+ const childArray = React.Children.toArray(
58
+ children,
59
+ ) as ButtonGroupActionElement[];
60
+
61
+ let primaryActions = childArray.filter(
62
+ action =>
63
+ /* Checking the component type does not work in dev environments due to
64
+ * wrapper components used for hot-reload
65
+ * However, checking the type name does not work in prod due to code minification
66
+ * Hence 2 different checks here */
67
+ action.type === PrimaryAction || action.type.name === "PrimaryAction",
68
+ ) as ButtonGroupPrimaryActionElement[];
69
+
70
+ let secondaryActions = childArray.filter(
71
+ action =>
72
+ action.type === SecondaryAction || action.type.name === "SecondaryAction",
73
+ );
74
+
75
+ if (primaryActions.length > 2) {
76
+ secondaryActions = primaryActions.slice(2).concat(secondaryActions);
77
+ primaryActions = primaryActions.slice(0, 2);
78
+ }
79
+
80
+ if (primaryActions.length === 0) {
81
+ primaryActions = secondaryActions.slice(0, 1);
82
+ secondaryActions = secondaryActions.slice(1);
83
+ }
84
+
85
+ return { primaryActions, secondaryActions };
86
+ }
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ export * from "./ActivityIndicator";
4
4
  export * from "./AtlantisContext";
5
5
  export * from "./BottomSheet";
6
6
  export * from "./Button";
7
+ export * from "./ButtonGroup";
7
8
  export * from "./Card";
8
9
  export * from "./Chip";
9
10
  export * from "./Content";