Skip to content

Commit 3b06103

Browse files
authored
Merge pull request #117 from adaptui/tappable-animation
2 parents f538bc7 + 7db5b36 commit 3b06103

File tree

16 files changed

+1392
-978
lines changed

16 files changed

+1392
-978
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
"select",
2626
"text-area",
2727
"types",
28-
"theme"
28+
"theme",
29+
"components"
2930
],
3031
"git.branchProtection": ["main"]
3132
}

docs/getting-started.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,30 @@ export default App;
4444

4545
```
4646

47+
## Further Instructions
48+
49+
### Fonts Loading (Android)
50+
Our components look well with the Inter font on Android.
51+
52+
You can pick the fonts from [here](../font-assets/)
53+
54+
And link and load it up in your React Native project using [expo-font](https://docs.expo.dev/versions/latest/sdk/font/) library if using Expo.
55+
56+
The library works well with bare React Native workflow too.
57+
58+
Check out blogs on getting to know about [Adding Fonts to React Native](https://medium.com/@_iam_karthik/list/adding-fonts-to-react-native-93aee6bace40) in our [Publication](https://medium.com/timeless).
59+
60+
### Haptics
61+
62+
Haptics is a technology that allows devices to provide tactile feedback to users, simulating the sense of touch. So it can be used to enhance the user experience in a variety of ways, such as providing feedback when a button is pressed, alerting the user to an event, or guiding the user through a task.
63+
64+
In AdaptUI we have enabled the Haptics to all our Tappable components (Button, Tag, Radio, Checkbox and Switch) through [expo-haptics](https://docs.expo.dev/versions/latest/sdk/haptics/).
65+
66+
You will have to install this as a dependency to get your haptics working on our Tappable components.
67+
68+
You can use the haptics through our hook [`useHaptics`](../src//utils//useHaptic.ts)
69+
70+
4771
## Simple Usage
4872

4973
Code below will render an [Avatar](./Avatar.md)

example/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"@react-navigation/drawer": "^6.5.3",
1515
"@react-navigation/native": "^6.0.16",
1616
"expo": "^47.0.0",
17+
"expo-haptics": "~12.0.1",
1718
"expo-screen-orientation": "^5.0.1",
1819
"expo-splash-screen": "~0.17.5",
1920
"expo-status-bar": "~1.4.2",

example/src/modules/primitives/ButtonScreen.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@ export const ButtonScreen = () => {
2525
const [hasPrefix, setHasPrefix] = useState<boolean>(false);
2626
const [hasSuffix, setHasSuffix] = useState<boolean>(false);
2727
const [isLoading, setIsLoading] = useState<boolean>(false);
28+
const [fullWidth, setFullWidth] = useState<boolean>(false);
29+
2830
const { bottom } = useSafeAreaInsets();
2931

3032
return (
3133
<Box style={tailwind.style("flex-1 justify-center bg-white-900")}>
3234
<Box
3335
style={tailwind.style(
34-
"flex-1 px-2 justify-center items-center bg-white-900",
36+
`flex-1 px-2 justify-center bg-white-900 ${
37+
fullWidth ? "" : "items-center"
38+
}`,
3539
)}
3640
>
3741
<Button
@@ -122,6 +126,15 @@ export const ButtonScreen = () => {
122126
style={tailwind.style("mt-2 ml-1")}
123127
label="Loading"
124128
/>
129+
<Switch
130+
state={fullWidth}
131+
onStateChange={(value: SetStateAction<boolean>) =>
132+
setFullWidth(value)
133+
}
134+
size="md"
135+
style={tailwind.style("mt-2 ml-1")}
136+
label="Full Width"
137+
/>
125138
</Box>
126139
</Box>
127140
</Box>

example/yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5328,6 +5328,11 @@ expo-font@~11.0.1:
53285328
dependencies:
53295329
fontfaceobserver "^2.1.0"
53305330

5331+
expo-haptics@~12.0.1:
5332+
version "12.0.1"
5333+
resolved "https://registry.yarnpkg.com/expo-haptics/-/expo-haptics-12.0.1.tgz#151dc57bc01c1fa16d021e4714b23916bbc9f8e5"
5334+
integrity sha512-YubK3P3WTdjp5mFZcaF3ienqXHoDqzPpe61yTEIR5y+CVWqk+If9cC3ZYxn6lSp8KiNUmz7zC0GvUAVEqn8t6Q==
5335+
53315336
expo-keep-awake@~11.0.1:
53325337
version "11.0.1"
53335338
resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-11.0.1.tgz#ee354465892a94040ffe09901b85b469e7d54fb3"

font-assets/fonts.zip

1.43 MB
Binary file not shown.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,15 +121,17 @@
121121
"react-native-svg": "13.4.0",
122122
"release-it": "15.1.4",
123123
"sort-package-json": "2.0.0",
124-
"typescript": "4.8.3"
124+
"typescript": "4.8.3",
125+
"expo-haptics": "12.0.1"
125126
},
126127
"peerDependencies": {
127128
"react": "18.1.0",
128129
"react-dom": "18.1.0",
129130
"react-native": "0.70.0",
130131
"react-native-gesture-handler": "2.8.0",
131132
"react-native-reanimated": "2.12.0",
132-
"react-native-svg": "13.4.0"
133+
"react-native-svg": "13.4.0",
134+
"expo-haptics": "12.0.1"
133135
},
134136
"publishConfig": {
135137
"access": "public",

src/components/button/Button.tsx

Lines changed: 87 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
1-
import React, { forwardRef } from "react";
1+
import React, { forwardRef, useCallback } from "react";
22
import {
3+
GestureResponderEvent,
34
Platform,
45
PressableProps,
56
PressableStateCallbackType,
67
TextStyle,
78
} from "react-native";
89

910
import { RenderPropType } from "../../index";
10-
import { Box, Text, Touchable } from "../../primitives";
11+
import { AnimatedBox, Box, Text, Touchable } from "../../primitives";
1112
import { getTextFontFamily, useTailwind, useTheme } from "../../theme";
1213
import {
1314
createComponent,
1415
cx,
1516
generateBoxShadow,
1617
styleAdapter,
18+
useHaptic,
1719
useOnFocus,
1820
useOnHover,
21+
useScaleAnimation,
1922
} from "../../utils";
2023
import { createIcon } from "../create-icon";
2124
import { Icon } from "../icon";
@@ -90,6 +93,12 @@ export interface ButtonProps extends PressableProps {
9093
* VoiceOver will read this string when a user selects the associated element.
9194
*/
9295
accesibilityLabel: string;
96+
/**
97+
* When set to true, The Tap creates a Touch Feedback
98+
* Check more -> https://docs.expo.dev/versions/latest/sdk/haptics/
99+
* @default true
100+
*/
101+
hapticEnabled: boolean;
93102
}
94103

95104
const RNButton: React.FC<Partial<ButtonProps>> = forwardRef<
@@ -102,27 +111,36 @@ const RNButton: React.FC<Partial<ButtonProps>> = forwardRef<
102111
variant = "solid",
103112
themeColor = "base",
104113
loading = false,
114+
hapticEnabled = true,
105115
prefix,
106116
suffix,
107117
iconOnly,
108118
spinner,
109119
textStyle,
110120
style,
111121
accesibilityLabel,
122+
onPress,
112123
...props
113124
},
114125
ref,
115126
) => {
116127
const { ts, gc } = useTailwind();
117128
const buttonTheme = useTheme("button");
118-
129+
const { handlers, animatedStyle } = useScaleAnimation();
130+
const hapticMedium = useHaptic("medium");
119131
const { onHoverIn, onHoverOut, hovered } = useOnHover();
120132
const { onFocus, onBlur, focused } = useOnFocus();
121133

122134
const iconAspectRatio = 1;
123135

124136
const isButtonDisabled = props.disabled || loading;
125137

138+
const handlePress = useCallback((event: GestureResponderEvent) => {
139+
onPress && onPress(event);
140+
hapticEnabled && hapticMedium();
141+
// eslint-disable-next-line react-hooks/exhaustive-deps
142+
}, []);
143+
126144
/**
127145
* Button Prefix Component
128146
*/
@@ -266,69 +284,73 @@ const RNButton: React.FC<Partial<ButtonProps>> = forwardRef<
266284
);
267285

268286
return (
269-
<Touchable
270-
style={(touchState: PressableStateCallbackType) => {
271-
return [
272-
ts(
273-
cx(
274-
buttonTheme.base,
275-
buttonTheme.size[size]?.default,
276-
buttonTheme.themeColor[themeColor]?.[variant]?.container
277-
?.wrapper,
278-
isButtonDisabled
279-
? buttonTheme.themeColor[themeColor]?.[variant]?.container
280-
?.disabled
281-
: "",
282-
hovered.value
283-
? buttonTheme.themeColor[themeColor]?.[variant]?.container
284-
?.hover
285-
: "",
286-
touchState.pressed
287-
? buttonTheme.themeColor[themeColor]?.[variant]?.container
288-
?.pressed
289-
: "",
287+
<AnimatedBox style={animatedStyle}>
288+
<Touchable
289+
style={(touchState: PressableStateCallbackType) => {
290+
return [
291+
ts(
292+
cx(
293+
buttonTheme.base,
294+
buttonTheme.size[size]?.default,
295+
buttonTheme.themeColor[themeColor]?.[variant]?.container
296+
?.wrapper,
297+
isButtonDisabled
298+
? buttonTheme.themeColor[themeColor]?.[variant]?.container
299+
?.disabled
300+
: "",
301+
hovered.value
302+
? buttonTheme.themeColor[themeColor]?.[variant]?.container
303+
?.hover
304+
: "",
305+
touchState.pressed
306+
? buttonTheme.themeColor[themeColor]?.[variant]?.container
307+
?.pressed
308+
: "",
309+
),
290310
),
291-
),
292-
focused.value
293-
? Platform.select({
294-
web: {
295-
outline: 0,
296-
boxShadow: `${generateBoxShadow(
297-
buttonTheme.themeColor[themeColor]?.[variant]?.container
298-
?.focus?.offset,
299-
gc(
300-
cx(
301-
buttonTheme.themeColor[themeColor]?.[variant]
302-
?.container?.focus?.color,
303-
),
304-
) as string,
305-
)}`,
306-
borderColor:
307-
buttonTheme.themeColor[themeColor]?.[variant]?.container
308-
?.focus?.borderColor,
309-
},
310-
})
311-
: {},
312-
styleAdapter(style, touchState),
313-
];
314-
}}
315-
{...props}
316-
// Web Callbacks
317-
onHoverIn={onHoverIn}
318-
onHoverOut={onHoverOut}
319-
onFocus={onFocus}
320-
onBlur={onBlur}
321-
// Web Callbacks
322-
// A11y Props
323-
accessible
324-
accessibilityLabel={accesibilityLabel}
325-
accessibilityRole="button"
326-
// A11y Props
327-
ref={ref}
328-
disabled={isButtonDisabled}
329-
>
330-
{children}
331-
</Touchable>
311+
focused.value
312+
? Platform.select({
313+
web: {
314+
outline: 0,
315+
boxShadow: `${generateBoxShadow(
316+
buttonTheme.themeColor[themeColor]?.[variant]?.container
317+
?.focus?.offset,
318+
gc(
319+
cx(
320+
buttonTheme.themeColor[themeColor]?.[variant]
321+
?.container?.focus?.color,
322+
),
323+
) as string,
324+
)}`,
325+
borderColor:
326+
buttonTheme.themeColor[themeColor]?.[variant]?.container
327+
?.focus?.borderColor,
328+
},
329+
})
330+
: {},
331+
styleAdapter(style, touchState),
332+
];
333+
}}
334+
{...props}
335+
// Web Callbacks
336+
onHoverIn={onHoverIn}
337+
onHoverOut={onHoverOut}
338+
onFocus={onFocus}
339+
onBlur={onBlur}
340+
// Web Callbacks
341+
// A11y Props
342+
accessible
343+
accessibilityLabel={accesibilityLabel}
344+
accessibilityRole="button"
345+
// A11y Props
346+
ref={ref}
347+
disabled={isButtonDisabled}
348+
{...handlers}
349+
onPress={handlePress}
350+
>
351+
{children}
352+
</Touchable>
353+
</AnimatedBox>
332354
);
333355
},
334356
);

0 commit comments

Comments
 (0)