@jobber/components-native 0.98.3 → 0.98.5
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 +2 -2
- package/dist/src/Chip/Chip.style.js +0 -2
- package/dist/src/index.js +0 -1
- package/dist/src/utils/meta/meta.json +0 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/types/src/Chip/Chip.style.d.ts +0 -2
- package/dist/types/src/index.d.ts +0 -1
- package/package.json +2 -2
- package/src/Chip/Chip.stories.tsx +49 -38
- package/src/Chip/Chip.style.ts +0 -2
- package/src/index.ts +0 -1
- package/src/utils/meta/meta.json +0 -1
- package/dist/src/Menu/Menu.js +0 -85
- package/dist/src/Menu/Menu.style.js +0 -7
- package/dist/src/Menu/components/MenuOption/MenuOption.js +0 -27
- package/dist/src/Menu/components/MenuOption/MenuOption.style.js +0 -11
- package/dist/src/Menu/components/MenuOption/index.js +0 -1
- package/dist/src/Menu/components/Overlay/Overlay.js +0 -10
- package/dist/src/Menu/components/Overlay/Overlay.style.js +0 -8
- package/dist/src/Menu/components/Overlay/index.js +0 -1
- package/dist/src/Menu/index.js +0 -1
- package/dist/src/Menu/types.js +0 -1
- package/dist/src/Menu/utils.js +0 -78
- package/dist/types/src/Menu/Menu.d.ts +0 -3
- package/dist/types/src/Menu/Menu.style.d.ts +0 -18
- package/dist/types/src/Menu/components/MenuOption/MenuOption.d.ts +0 -3
- package/dist/types/src/Menu/components/MenuOption/MenuOption.style.d.ts +0 -8
- package/dist/types/src/Menu/components/MenuOption/index.d.ts +0 -1
- package/dist/types/src/Menu/components/Overlay/Overlay.d.ts +0 -3
- package/dist/types/src/Menu/components/Overlay/Overlay.style.d.ts +0 -12
- package/dist/types/src/Menu/components/Overlay/index.d.ts +0 -1
- package/dist/types/src/Menu/index.d.ts +0 -2
- package/dist/types/src/Menu/types.d.ts +0 -26
- package/dist/types/src/Menu/utils.d.ts +0 -11
- package/src/Menu/Menu.stories.tsx +0 -52
- package/src/Menu/Menu.style.ts +0 -17
- package/src/Menu/Menu.test.tsx +0 -203
- package/src/Menu/Menu.tsx +0 -141
- package/src/Menu/components/MenuOption/MenuOption.style.tsx +0 -12
- package/src/Menu/components/MenuOption/MenuOption.tsx +0 -66
- package/src/Menu/components/MenuOption/index.ts +0 -1
- package/src/Menu/components/Overlay/Overlay.style.ts +0 -15
- package/src/Menu/components/Overlay/Overlay.tsx +0 -18
- package/src/Menu/components/Overlay/index.ts +0 -1
- package/src/Menu/index.ts +0 -6
- package/src/Menu/types.ts +0 -31
- package/src/Menu/utils.ts +0 -148
package/src/Menu/Menu.test.tsx
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { fireEvent, render } from "@testing-library/react-native";
|
|
3
|
-
import { Host } from "react-native-portalize";
|
|
4
|
-
import { View } from "react-native";
|
|
5
|
-
import type { MenuOptionProps, MenuProps } from ".";
|
|
6
|
-
import { Menu } from ".";
|
|
7
|
-
import { tokens } from "../utils/design";
|
|
8
|
-
import { Icon } from "../Icon";
|
|
9
|
-
import { Button } from "../Button";
|
|
10
|
-
|
|
11
|
-
const mockOnPress = jest.fn();
|
|
12
|
-
jest
|
|
13
|
-
.spyOn(View.prototype, "measureInWindow")
|
|
14
|
-
.mockImplementation(cb => cb(50, 50, 100, 100));
|
|
15
|
-
|
|
16
|
-
const setup = (props?: MenuProps) => {
|
|
17
|
-
return render(
|
|
18
|
-
<Host>
|
|
19
|
-
<Menu
|
|
20
|
-
menuOptions={props?.menuOptions}
|
|
21
|
-
customActivator={props?.customActivator}
|
|
22
|
-
/>
|
|
23
|
-
</Host>,
|
|
24
|
-
);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const menuLabel = "Menu";
|
|
28
|
-
|
|
29
|
-
describe("Menu", () => {
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
mockOnPress.mockClear();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it("renders the default Activator", () => {
|
|
35
|
-
const { getByTestId, getByLabelText } = setup({
|
|
36
|
-
menuOptions: [{ label: "hi", icon: "add", onPress: mockOnPress }],
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
expect(getByTestId("more")).toBeDefined();
|
|
40
|
-
expect(getByLabelText(menuLabel)).toBeDefined();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("renders every menu option when menu is opened", () => {
|
|
44
|
-
const menuOptions: MenuOptionProps[] = [
|
|
45
|
-
{ label: "option1", icon: "add", onPress: mockOnPress },
|
|
46
|
-
{ label: "option2", icon: "arrowDown", onPress: mockOnPress },
|
|
47
|
-
{ label: "option3", onPress: mockOnPress },
|
|
48
|
-
];
|
|
49
|
-
const { getByLabelText } = setup({
|
|
50
|
-
menuOptions,
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
fireEvent.press(getByLabelText(menuLabel));
|
|
54
|
-
expect(getByLabelText(menuOptions[0].label)).toBeDefined();
|
|
55
|
-
expect(getByLabelText(menuOptions[1].label)).toBeDefined();
|
|
56
|
-
expect(getByLabelText(menuOptions[2].label)).toBeDefined();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
describe("Custom Activator", () => {
|
|
60
|
-
it("renders a custom Activator", () => {
|
|
61
|
-
const { getByTestId } = setup({
|
|
62
|
-
menuOptions: [{ label: "hi", onPress: mockOnPress }],
|
|
63
|
-
customActivator: <Icon name="addNote" />,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
expect(getByTestId("addNote")).toBeDefined();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("renders menu when the custom activator is clicked", () => {
|
|
70
|
-
const { getByLabelText, getByTestId, getAllByTestId } = setup({
|
|
71
|
-
menuOptions: [
|
|
72
|
-
{ label: "hi", icon: "add", onPress: mockOnPress },
|
|
73
|
-
{ label: "option2", onPress: mockOnPress },
|
|
74
|
-
],
|
|
75
|
-
customActivator: <Icon name="addNote" />,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
fireEvent.press(getByTestId("addNote"));
|
|
79
|
-
|
|
80
|
-
expect(getAllByTestId("ATL-MENU-OPTIONS")).toHaveLength(2);
|
|
81
|
-
expect(getByTestId("add")).toBeDefined();
|
|
82
|
-
expect(getByLabelText("hi")).toBeDefined();
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
describe("Pressable used as Custom Activator", () => {
|
|
86
|
-
it("menu is open and custom activator's onPress is called", () => {
|
|
87
|
-
const mockActivatorPress = jest.fn();
|
|
88
|
-
const buttonLabel = "Test me!";
|
|
89
|
-
const menuOptions: MenuOptionProps[] = [
|
|
90
|
-
{ label: "menuOption", icon: "add", onPress: mockOnPress },
|
|
91
|
-
];
|
|
92
|
-
|
|
93
|
-
const { getByLabelText } = setup({
|
|
94
|
-
menuOptions,
|
|
95
|
-
customActivator: (
|
|
96
|
-
<Button label={buttonLabel} onPress={mockActivatorPress} />
|
|
97
|
-
),
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
fireEvent.press(getByLabelText(buttonLabel));
|
|
101
|
-
|
|
102
|
-
expect(mockActivatorPress).toHaveBeenCalledTimes(1);
|
|
103
|
-
expect(getByLabelText(menuOptions[0].label)).toBeDefined();
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
describe("Menu Options", () => {
|
|
109
|
-
it("fires the onPress of the menu option", () => {
|
|
110
|
-
const { getByLabelText } = setup({
|
|
111
|
-
menuOptions: [
|
|
112
|
-
{
|
|
113
|
-
label: "hi",
|
|
114
|
-
icon: "add",
|
|
115
|
-
onPress: mockOnPress,
|
|
116
|
-
destructive: true,
|
|
117
|
-
},
|
|
118
|
-
],
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
fireEvent.press(getByLabelText(menuLabel));
|
|
122
|
-
fireEvent.press(getByLabelText("hi"));
|
|
123
|
-
expect(mockOnPress).toHaveBeenCalled();
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it("renders a menuOption with an icon with destructive styling", () => {
|
|
127
|
-
const { getByLabelText, getByTestId } = setup({
|
|
128
|
-
menuOptions: [
|
|
129
|
-
{ label: "hi", icon: "add", onPress: mockOnPress, destructive: true },
|
|
130
|
-
],
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
fireEvent.press(getByLabelText(menuLabel));
|
|
134
|
-
expect(getByTestId("add").props.style).toContainEqual({
|
|
135
|
-
display: "flex",
|
|
136
|
-
fill: tokens["color-critical"],
|
|
137
|
-
height: 24,
|
|
138
|
-
verticalAlign: "middle",
|
|
139
|
-
width: 24,
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("closes the menu after clicking on a menu option", () => {
|
|
144
|
-
const { getByLabelText, queryByLabelText } = setup({
|
|
145
|
-
menuOptions: [
|
|
146
|
-
{
|
|
147
|
-
label: "hi",
|
|
148
|
-
icon: "add",
|
|
149
|
-
onPress: mockOnPress,
|
|
150
|
-
destructive: true,
|
|
151
|
-
},
|
|
152
|
-
],
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
fireEvent.press(getByLabelText(menuLabel));
|
|
156
|
-
fireEvent.press(getByLabelText("hi"));
|
|
157
|
-
expect(mockOnPress).toHaveBeenCalled();
|
|
158
|
-
expect(queryByLabelText("hi")).toBeNull();
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
it("transforms the text", () => {
|
|
162
|
-
const { getByLabelText, getByText } = setup({
|
|
163
|
-
menuOptions: [
|
|
164
|
-
{
|
|
165
|
-
label: "hi",
|
|
166
|
-
icon: "add",
|
|
167
|
-
onPress: mockOnPress,
|
|
168
|
-
textTransform: "capitalize",
|
|
169
|
-
},
|
|
170
|
-
],
|
|
171
|
-
});
|
|
172
|
-
fireEvent.press(getByLabelText(menuLabel));
|
|
173
|
-
expect(getByText("Hi")).toBeDefined();
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it("does not transform the text when textTransform set to none", () => {
|
|
177
|
-
const { getByLabelText, getByText } = setup({
|
|
178
|
-
menuOptions: [
|
|
179
|
-
{
|
|
180
|
-
label: "hi",
|
|
181
|
-
icon: "add",
|
|
182
|
-
onPress: mockOnPress,
|
|
183
|
-
textTransform: "none",
|
|
184
|
-
},
|
|
185
|
-
],
|
|
186
|
-
});
|
|
187
|
-
fireEvent.press(getByLabelText(menuLabel));
|
|
188
|
-
expect(getByText("hi")).toBeDefined();
|
|
189
|
-
});
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
it("renders a menu when the default activator is clicked", () => {
|
|
193
|
-
const { getByLabelText, getByTestId } = setup({
|
|
194
|
-
menuOptions: [{ label: "hi", icon: "add", onPress: mockOnPress }],
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
fireEvent.press(getByLabelText(menuLabel));
|
|
198
|
-
|
|
199
|
-
expect(getByTestId("ATL-MENU-OPTIONS")).toBeDefined();
|
|
200
|
-
expect(getByTestId("add")).toBeDefined();
|
|
201
|
-
expect(getByLabelText("hi")).toBeDefined();
|
|
202
|
-
});
|
|
203
|
-
});
|
package/src/Menu/Menu.tsx
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import React, { useCallback, useRef, useState } from "react";
|
|
2
|
-
import type { LayoutRectangle } from "react-native";
|
|
3
|
-
import {
|
|
4
|
-
Keyboard,
|
|
5
|
-
Platform,
|
|
6
|
-
Pressable,
|
|
7
|
-
View,
|
|
8
|
-
useWindowDimensions,
|
|
9
|
-
} from "react-native";
|
|
10
|
-
import { Portal } from "react-native-portalize";
|
|
11
|
-
import { useSafeAreaFrame } from "react-native-safe-area-context";
|
|
12
|
-
import { useStyles } from "./Menu.style";
|
|
13
|
-
import { findViewpoint } from "./utils";
|
|
14
|
-
import type { MenuProps } from "./types";
|
|
15
|
-
import { MenuOption } from "./components/MenuOption";
|
|
16
|
-
import { Overlay } from "./components/Overlay";
|
|
17
|
-
import { Button } from "../Button";
|
|
18
|
-
import { Content } from "../Content";
|
|
19
|
-
import { useAtlantisContext } from "../AtlantisContext";
|
|
20
|
-
import { useAtlantisI18n } from "../hooks/useAtlantisI18n";
|
|
21
|
-
import { useAtlantisTheme } from "../AtlantisThemeContext";
|
|
22
|
-
|
|
23
|
-
export function Menu({ menuOptions, customActivator }: MenuProps) {
|
|
24
|
-
const [open, setOpen] = useState<boolean>(false);
|
|
25
|
-
const [menuPosition, setMenuPosition] = useState<object>();
|
|
26
|
-
const activatorLayout = useRef<LayoutRectangle>(null);
|
|
27
|
-
const menuButtonRef = useRef<View>(null);
|
|
28
|
-
const screenInfo = useScreenInformation();
|
|
29
|
-
|
|
30
|
-
const { t } = useAtlantisI18n();
|
|
31
|
-
const styles = useStyles();
|
|
32
|
-
|
|
33
|
-
const findMenuLayout = useCallback(() => {
|
|
34
|
-
if (activatorLayout.current) {
|
|
35
|
-
setMenuPosition(
|
|
36
|
-
findViewpoint(screenInfo, activatorLayout.current, styles),
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
}, [screenInfo, activatorLayout, styles]);
|
|
40
|
-
|
|
41
|
-
const openMenu = () => {
|
|
42
|
-
menuButtonRef.current?.measureInWindow(
|
|
43
|
-
(x: number, y: number, width: number, height: number) => {
|
|
44
|
-
activatorLayout.current = {
|
|
45
|
-
x,
|
|
46
|
-
y,
|
|
47
|
-
width,
|
|
48
|
-
height,
|
|
49
|
-
};
|
|
50
|
-
findMenuLayout();
|
|
51
|
-
setOpen(true);
|
|
52
|
-
},
|
|
53
|
-
);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const activatorOnPress = (onPress?: () => void) => {
|
|
57
|
-
onPress && onPress();
|
|
58
|
-
|
|
59
|
-
if (Platform.OS === "ios" && Keyboard.isVisible()) {
|
|
60
|
-
// On iOS, the keyboard height causes problems with the menu positioning logic.
|
|
61
|
-
// Wait until the keyboard is fully hidden before we show the menu.
|
|
62
|
-
onKeyboardDidHide(openMenu);
|
|
63
|
-
Keyboard.dismiss();
|
|
64
|
-
} else {
|
|
65
|
-
openMenu();
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const { tokens } = useAtlantisTheme();
|
|
70
|
-
|
|
71
|
-
return (
|
|
72
|
-
<>
|
|
73
|
-
<View
|
|
74
|
-
ref={ref => {
|
|
75
|
-
menuButtonRef.current = ref;
|
|
76
|
-
}}
|
|
77
|
-
collapsable={false}
|
|
78
|
-
>
|
|
79
|
-
{customActivator && (
|
|
80
|
-
<Pressable
|
|
81
|
-
style={({ pressed }) => [
|
|
82
|
-
{
|
|
83
|
-
opacity: pressed ? tokens["opacity-pressed"] : 1,
|
|
84
|
-
},
|
|
85
|
-
]}
|
|
86
|
-
pointerEvents="box-only"
|
|
87
|
-
onPress={() => {
|
|
88
|
-
activatorOnPress(customActivator.props.onPress);
|
|
89
|
-
}}
|
|
90
|
-
onLongPress={customActivator.props.onLongPress}
|
|
91
|
-
>
|
|
92
|
-
{customActivator}
|
|
93
|
-
</Pressable>
|
|
94
|
-
)}
|
|
95
|
-
|
|
96
|
-
{!customActivator && (
|
|
97
|
-
<Button
|
|
98
|
-
icon="more"
|
|
99
|
-
accessibilityLabel={t("menu")}
|
|
100
|
-
variation="cancel"
|
|
101
|
-
type="tertiary"
|
|
102
|
-
onPress={() => {
|
|
103
|
-
activatorOnPress();
|
|
104
|
-
}}
|
|
105
|
-
/>
|
|
106
|
-
)}
|
|
107
|
-
</View>
|
|
108
|
-
<Portal>
|
|
109
|
-
{open && (
|
|
110
|
-
<>
|
|
111
|
-
<Overlay setOpen={setOpen} />
|
|
112
|
-
<View style={[open && menuPosition, styles.menu]}>
|
|
113
|
-
<Content spacing="none" childSpacing="small">
|
|
114
|
-
{menuOptions?.map((menuOption, index) => {
|
|
115
|
-
return (
|
|
116
|
-
<MenuOption {...menuOption} key={index} setOpen={setOpen} />
|
|
117
|
-
);
|
|
118
|
-
})}
|
|
119
|
-
</Content>
|
|
120
|
-
</View>
|
|
121
|
-
</>
|
|
122
|
-
)}
|
|
123
|
-
</Portal>
|
|
124
|
-
</>
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function useScreenInformation() {
|
|
129
|
-
const { headerHeight } = useAtlantisContext();
|
|
130
|
-
const windowWidth = useWindowDimensions().width;
|
|
131
|
-
const { height: windowHeight } = useSafeAreaFrame();
|
|
132
|
-
|
|
133
|
-
return { headerHeight, windowWidth, windowHeight };
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function onKeyboardDidHide(callback: () => void) {
|
|
137
|
-
const listener = Keyboard.addListener("keyboardDidHide", () => {
|
|
138
|
-
listener.remove();
|
|
139
|
-
callback();
|
|
140
|
-
});
|
|
141
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { buildThemedStyles } from "../../../AtlantisThemeContext";
|
|
2
|
-
|
|
3
|
-
export const useStyles = buildThemedStyles(tokens => {
|
|
4
|
-
return {
|
|
5
|
-
menuOption: {
|
|
6
|
-
display: "flex",
|
|
7
|
-
paddingHorizontal: tokens["space-base"],
|
|
8
|
-
paddingVertical: tokens["space-small"],
|
|
9
|
-
borderRadius: tokens["radius-large"],
|
|
10
|
-
},
|
|
11
|
-
};
|
|
12
|
-
});
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Pressable, View } from "react-native";
|
|
3
|
-
import capitalize from "lodash/capitalize";
|
|
4
|
-
import { useStyles } from "./MenuOption.style";
|
|
5
|
-
import type { MenuOptionInternalProps } from "../../types";
|
|
6
|
-
import { Flex } from "../../../Flex";
|
|
7
|
-
import { Typography } from "../../../Typography";
|
|
8
|
-
import { Icon } from "../../../Icon";
|
|
9
|
-
import { useAtlantisTheme } from "../../../AtlantisThemeContext";
|
|
10
|
-
|
|
11
|
-
export function MenuOption({
|
|
12
|
-
label,
|
|
13
|
-
icon,
|
|
14
|
-
iconColor = "heading",
|
|
15
|
-
textAlign,
|
|
16
|
-
destructive,
|
|
17
|
-
textTransform = "capitalize",
|
|
18
|
-
onPress,
|
|
19
|
-
setOpen,
|
|
20
|
-
}: MenuOptionInternalProps) {
|
|
21
|
-
const destructiveColor = "destructive";
|
|
22
|
-
const textVariation = destructive ? destructiveColor : "heading";
|
|
23
|
-
const styles = useStyles();
|
|
24
|
-
const { tokens } = useAtlantisTheme();
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<View testID="ATL-MENU-OPTIONS">
|
|
28
|
-
<Pressable
|
|
29
|
-
style={({ pressed }) => [
|
|
30
|
-
styles.menuOption,
|
|
31
|
-
{ opacity: pressed ? tokens["opacity-pressed"] : 1 },
|
|
32
|
-
]}
|
|
33
|
-
onPress={() => {
|
|
34
|
-
onPress();
|
|
35
|
-
setOpen(false);
|
|
36
|
-
}}
|
|
37
|
-
accessibilityLabel={label}
|
|
38
|
-
>
|
|
39
|
-
<Flex
|
|
40
|
-
template={["grow", "shrink"]}
|
|
41
|
-
align={"flex-start"}
|
|
42
|
-
gap={"smaller"}
|
|
43
|
-
>
|
|
44
|
-
<Typography
|
|
45
|
-
selectable={false}
|
|
46
|
-
color={textVariation}
|
|
47
|
-
fontWeight={"semiBold"}
|
|
48
|
-
lineHeight={"large"}
|
|
49
|
-
align={textAlign}
|
|
50
|
-
>
|
|
51
|
-
{textTransform === "capitalize"
|
|
52
|
-
? capitalize(label.toLocaleLowerCase())
|
|
53
|
-
: label}
|
|
54
|
-
</Typography>
|
|
55
|
-
|
|
56
|
-
{icon && (
|
|
57
|
-
<Icon
|
|
58
|
-
name={icon}
|
|
59
|
-
color={destructive ? destructiveColor : iconColor}
|
|
60
|
-
/>
|
|
61
|
-
)}
|
|
62
|
-
</Flex>
|
|
63
|
-
</Pressable>
|
|
64
|
-
</View>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { MenuOption } from "./MenuOption";
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Dimensions, StyleSheet } from "react-native";
|
|
2
|
-
import { buildThemedStyles } from "../../../AtlantisThemeContext";
|
|
3
|
-
|
|
4
|
-
const { height } = Dimensions.get("window");
|
|
5
|
-
|
|
6
|
-
export const useStyles = buildThemedStyles(tokens => {
|
|
7
|
-
return {
|
|
8
|
-
overlay: {
|
|
9
|
-
...StyleSheet.absoluteFillObject,
|
|
10
|
-
backgroundColor: tokens["color-overlay"],
|
|
11
|
-
opacity: 0,
|
|
12
|
-
height,
|
|
13
|
-
},
|
|
14
|
-
};
|
|
15
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Pressable, View } from "react-native";
|
|
3
|
-
import { useStyles } from "./Overlay.style";
|
|
4
|
-
import type { OverlayProp } from "../../types";
|
|
5
|
-
|
|
6
|
-
export function Overlay({ setOpen }: OverlayProp) {
|
|
7
|
-
const styles = useStyles();
|
|
8
|
-
|
|
9
|
-
return (
|
|
10
|
-
<Pressable
|
|
11
|
-
onPressIn={() => {
|
|
12
|
-
setOpen(false);
|
|
13
|
-
}}
|
|
14
|
-
>
|
|
15
|
-
<View style={styles.overlay} />
|
|
16
|
-
</Pressable>
|
|
17
|
-
);
|
|
18
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { Overlay } from "./Overlay";
|
package/src/Menu/index.ts
DELETED
package/src/Menu/types.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { ReactElement } from "react";
|
|
2
|
-
import type { IconColorNames, IconNames } from "@jobber/design";
|
|
3
|
-
import type { TextAlign } from "../Typography";
|
|
4
|
-
|
|
5
|
-
export interface MenuOptionProps {
|
|
6
|
-
readonly label: string;
|
|
7
|
-
readonly icon?: IconNames;
|
|
8
|
-
readonly iconColor?: IconColorNames;
|
|
9
|
-
readonly textAlign?: TextAlign;
|
|
10
|
-
readonly destructive?: boolean;
|
|
11
|
-
readonly textTransform?: "none" | "capitalize";
|
|
12
|
-
onPress: () => void;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface MenuOptionInternalProps extends MenuOptionProps {
|
|
16
|
-
setOpen: (bool: boolean) => void;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface CustomActivatorProps {
|
|
20
|
-
readonly onPress?: () => void;
|
|
21
|
-
readonly onLongPress?: () => void;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface MenuProps {
|
|
25
|
-
readonly menuOptions?: MenuOptionProps[];
|
|
26
|
-
readonly customActivator?: ReactElement<CustomActivatorProps>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface OverlayProp {
|
|
30
|
-
setOpen: (bool: boolean) => void;
|
|
31
|
-
}
|
package/src/Menu/utils.ts
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import type { LayoutRectangle } from "react-native";
|
|
2
|
-
import type { useStyles } from "./Menu.style";
|
|
3
|
-
|
|
4
|
-
interface ScreenInfo {
|
|
5
|
-
windowHeight: number;
|
|
6
|
-
headerHeight: number;
|
|
7
|
-
windowWidth: number;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function findViewpoint(
|
|
11
|
-
screenInfo: ScreenInfo,
|
|
12
|
-
activatorLayout: LayoutRectangle,
|
|
13
|
-
styles: ReturnType<typeof useStyles>,
|
|
14
|
-
): { [key: string]: number | undefined } {
|
|
15
|
-
const { windowHeight, windowWidth, headerHeight } = screenInfo;
|
|
16
|
-
const pos: { [key: string]: number | undefined } = {};
|
|
17
|
-
const menuWidth = styles.menu.width;
|
|
18
|
-
const windowHalf = (windowHeight - headerHeight) / 2 + headerHeight;
|
|
19
|
-
const menuPositionVertical =
|
|
20
|
-
activatorLayout.y + activatorLayout.height > windowHalf
|
|
21
|
-
? "menuAbove"
|
|
22
|
-
: "menuBelow";
|
|
23
|
-
|
|
24
|
-
const menuPositionHorizontal =
|
|
25
|
-
windowWidth / 2 > activatorLayout.width / 2 + activatorLayout.x
|
|
26
|
-
? "menuRight"
|
|
27
|
-
: "menuLeft";
|
|
28
|
-
|
|
29
|
-
const menuPadding = 36;
|
|
30
|
-
|
|
31
|
-
getVerticalPosition(pos, windowHeight, activatorLayout, menuPositionVertical);
|
|
32
|
-
|
|
33
|
-
getHorizontalPosition(
|
|
34
|
-
pos,
|
|
35
|
-
activatorLayout,
|
|
36
|
-
windowWidth,
|
|
37
|
-
menuPadding,
|
|
38
|
-
menuWidth,
|
|
39
|
-
menuPositionHorizontal,
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
return pos;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function getVerticalPosition(
|
|
46
|
-
pos: { [key: string]: number | undefined },
|
|
47
|
-
windowHeight: number,
|
|
48
|
-
activatorLayout: LayoutRectangle,
|
|
49
|
-
menuPositionVertical: string,
|
|
50
|
-
) {
|
|
51
|
-
if (menuPositionVertical === "menuAbove") {
|
|
52
|
-
getAbovePosition(pos, windowHeight, activatorLayout);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (menuPositionVertical === "menuBelow") {
|
|
56
|
-
getBelowPosition(pos, activatorLayout);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function getBelowPosition(
|
|
61
|
-
pos: { [key: string]: number | undefined },
|
|
62
|
-
activatorLayout: LayoutRectangle,
|
|
63
|
-
) {
|
|
64
|
-
pos.top = activatorLayout.y + activatorLayout.height;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function getAbovePosition(
|
|
68
|
-
pos: { [key: string]: number | undefined },
|
|
69
|
-
windowHeight: number,
|
|
70
|
-
activatorLayout: LayoutRectangle,
|
|
71
|
-
) {
|
|
72
|
-
pos.bottom = windowHeight - activatorLayout.y;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function getHorizontalPosition(
|
|
76
|
-
pos: { [key: string]: number | undefined },
|
|
77
|
-
activatorLayout: LayoutRectangle,
|
|
78
|
-
windowWidth: number,
|
|
79
|
-
menuPadding: number,
|
|
80
|
-
menuWidth: number,
|
|
81
|
-
menuPositionHorizontal: string,
|
|
82
|
-
) {
|
|
83
|
-
if (menuPositionHorizontal === "menuRight") {
|
|
84
|
-
getRightPosition(pos, activatorLayout, windowWidth, menuPadding, menuWidth);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (menuPositionHorizontal === "menuLeft") {
|
|
88
|
-
getLeftPosition(pos, activatorLayout, windowWidth, menuPadding, menuWidth);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function getLeftPosition(
|
|
93
|
-
pos: { [key: string]: number | undefined },
|
|
94
|
-
activatorLayout: LayoutRectangle,
|
|
95
|
-
windowWidth: number,
|
|
96
|
-
menuHorizontalPadding: number,
|
|
97
|
-
menuWidth: number,
|
|
98
|
-
) {
|
|
99
|
-
const overflowLeft =
|
|
100
|
-
windowWidth -
|
|
101
|
-
activatorLayout.x -
|
|
102
|
-
activatorLayout.width +
|
|
103
|
-
activatorLayout.width / 2 -
|
|
104
|
-
menuHorizontalPadding +
|
|
105
|
-
menuWidth >
|
|
106
|
-
windowWidth;
|
|
107
|
-
|
|
108
|
-
const overflowRight =
|
|
109
|
-
windowWidth -
|
|
110
|
-
activatorLayout.x -
|
|
111
|
-
activatorLayout.width +
|
|
112
|
-
activatorLayout.width / 2 -
|
|
113
|
-
menuHorizontalPadding <
|
|
114
|
-
0;
|
|
115
|
-
|
|
116
|
-
if (overflowLeft) {
|
|
117
|
-
pos.right = undefined;
|
|
118
|
-
pos.left = 0;
|
|
119
|
-
} else if (overflowRight) {
|
|
120
|
-
pos.right = 0;
|
|
121
|
-
} else {
|
|
122
|
-
pos.right = windowWidth - activatorLayout.x - activatorLayout.width;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function getRightPosition(
|
|
127
|
-
pos: { [key: string]: number | undefined },
|
|
128
|
-
activatorLayout: LayoutRectangle,
|
|
129
|
-
windowWidth: number,
|
|
130
|
-
menuPadding: number,
|
|
131
|
-
menuWidth: number,
|
|
132
|
-
) {
|
|
133
|
-
const overflowRight =
|
|
134
|
-
activatorLayout.x + activatorLayout.width / 2 - menuPadding + menuWidth >
|
|
135
|
-
windowWidth;
|
|
136
|
-
|
|
137
|
-
const overflowLeft =
|
|
138
|
-
activatorLayout.x + activatorLayout.width / 2 - menuPadding < 0;
|
|
139
|
-
|
|
140
|
-
if (overflowRight) {
|
|
141
|
-
pos.left = undefined;
|
|
142
|
-
pos.right = 0;
|
|
143
|
-
} else if (overflowLeft) {
|
|
144
|
-
pos.left = 0;
|
|
145
|
-
} else {
|
|
146
|
-
pos.left = activatorLayout.x;
|
|
147
|
-
}
|
|
148
|
-
}
|