@pagopa/io-app-design-system 4.2.1 → 4.3.1

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 (248) hide show
  1. package/lib/commonjs/components/alert/Alert.js +10 -31
  2. package/lib/commonjs/components/alert/Alert.js.map +1 -1
  3. package/lib/commonjs/components/alert/AlertEdgeToEdge.js +9 -29
  4. package/lib/commonjs/components/alert/AlertEdgeToEdge.js.map +1 -1
  5. package/lib/commonjs/components/banner/Banner.js +10 -34
  6. package/lib/commonjs/components/banner/Banner.js.map +1 -1
  7. package/lib/commonjs/components/buttons/ButtonLink.js +20 -53
  8. package/lib/commonjs/components/buttons/ButtonLink.js.map +1 -1
  9. package/lib/commonjs/components/buttons/ButtonOutline.js +24 -44
  10. package/lib/commonjs/components/buttons/ButtonOutline.js.map +1 -1
  11. package/lib/commonjs/components/buttons/ButtonSolid.js +14 -39
  12. package/lib/commonjs/components/buttons/ButtonSolid.js.map +1 -1
  13. package/lib/commonjs/components/buttons/IconButton.js +13 -32
  14. package/lib/commonjs/components/buttons/IconButton.js.map +1 -1
  15. package/lib/commonjs/components/buttons/IconButtonContained.js +19 -42
  16. package/lib/commonjs/components/buttons/IconButtonContained.js.map +1 -1
  17. package/lib/commonjs/components/buttons/IconButtonSolid.js +15 -31
  18. package/lib/commonjs/components/buttons/IconButtonSolid.js.map +1 -1
  19. package/lib/commonjs/components/buttons/__test__/__snapshots__/button.test.tsx.snap +34 -10
  20. package/lib/commonjs/components/layout/index.js +0 -11
  21. package/lib/commonjs/components/layout/index.js.map +1 -1
  22. package/lib/commonjs/components/listitems/ListItemAction.js +14 -40
  23. package/lib/commonjs/components/listitems/ListItemAction.js.map +1 -1
  24. package/lib/commonjs/components/listitems/ListItemCheckbox.js +13 -41
  25. package/lib/commonjs/components/listitems/ListItemCheckbox.js.map +1 -1
  26. package/lib/commonjs/components/listitems/ListItemHeader.js +2 -2
  27. package/lib/commonjs/components/listitems/ListItemHeader.js.map +1 -1
  28. package/lib/commonjs/components/listitems/ListItemInfoCopy.js +15 -43
  29. package/lib/commonjs/components/listitems/ListItemInfoCopy.js.map +1 -1
  30. package/lib/commonjs/components/listitems/ListItemNav.js +17 -48
  31. package/lib/commonjs/components/listitems/ListItemNav.js.map +1 -1
  32. package/lib/commonjs/components/listitems/ListItemNavAlert.js +19 -50
  33. package/lib/commonjs/components/listitems/ListItemNavAlert.js.map +1 -1
  34. package/lib/commonjs/components/listitems/ListItemRadio.js +20 -50
  35. package/lib/commonjs/components/listitems/ListItemRadio.js.map +1 -1
  36. package/lib/commonjs/components/listitems/ListItemRadioWithAmount.js +2 -2
  37. package/lib/commonjs/components/listitems/ListItemRadioWithAmount.js.map +1 -1
  38. package/lib/commonjs/components/listitems/ListItemTransaction.js +2 -2
  39. package/lib/commonjs/components/listitems/ListItemTransaction.js.map +1 -1
  40. package/lib/commonjs/components/listitems/{PressableListItemsBase.js → PressableListItemBase.js} +7 -7
  41. package/lib/commonjs/components/listitems/PressableListItemBase.js.map +1 -0
  42. package/lib/commonjs/components/listitems/__test__/__snapshots__/listitem.test.tsx.snap +13 -7
  43. package/lib/commonjs/components/listitems/__test__/listitem.test.js +3 -3
  44. package/lib/commonjs/components/listitems/__test__/listitem.test.js.map +1 -1
  45. package/lib/commonjs/components/listitems/index.js +11 -11
  46. package/lib/commonjs/components/listitems/index.js.map +1 -1
  47. package/lib/commonjs/components/modules/PressableModuleBase.js +17 -11
  48. package/lib/commonjs/components/modules/PressableModuleBase.js.map +1 -1
  49. package/lib/commonjs/components/modules/index.js +8 -8
  50. package/lib/commonjs/components/modules/index.js.map +1 -1
  51. package/lib/commonjs/components/numberpad/NumberButton.js +12 -28
  52. package/lib/commonjs/components/numberpad/NumberButton.js.map +1 -1
  53. package/lib/commonjs/components/numberpad/__test__/__snapshots__/NumberPad.test.tsx.snap +20 -0
  54. package/lib/commonjs/components/otpInput/OTPInput.js +2 -1
  55. package/lib/commonjs/components/otpInput/OTPInput.js.map +1 -1
  56. package/lib/commonjs/components/tabs/TabItem.js +15 -21
  57. package/lib/commonjs/components/tabs/TabItem.js.map +1 -1
  58. package/lib/commonjs/core/IOAnimations.js +6 -12
  59. package/lib/commonjs/core/IOAnimations.js.map +1 -1
  60. package/lib/commonjs/hooks/index.js +28 -0
  61. package/lib/commonjs/hooks/index.js.map +1 -0
  62. package/lib/commonjs/hooks/useListItemAnimation.js +40 -0
  63. package/lib/commonjs/hooks/useListItemAnimation.js.map +1 -0
  64. package/lib/commonjs/hooks/useScaleAnimation.js +36 -0
  65. package/lib/commonjs/hooks/useScaleAnimation.js.map +1 -0
  66. package/lib/commonjs/index.js +11 -0
  67. package/lib/commonjs/index.js.map +1 -1
  68. package/lib/commonjs/utils/hooks/index.js +28 -0
  69. package/lib/commonjs/utils/hooks/index.js.map +1 -0
  70. package/lib/commonjs/utils/hooks/useSpringPressProgressValue.js +5 -7
  71. package/lib/commonjs/utils/hooks/useSpringPressProgressValue.js.map +1 -1
  72. package/lib/module/components/alert/Alert.js +10 -32
  73. package/lib/module/components/alert/Alert.js.map +1 -1
  74. package/lib/module/components/alert/AlertEdgeToEdge.js +10 -31
  75. package/lib/module/components/alert/AlertEdgeToEdge.js.map +1 -1
  76. package/lib/module/components/banner/Banner.js +10 -33
  77. package/lib/module/components/banner/Banner.js.map +1 -1
  78. package/lib/module/components/buttons/ButtonLink.js +23 -56
  79. package/lib/module/components/buttons/ButtonLink.js.map +1 -1
  80. package/lib/module/components/buttons/ButtonOutline.js +27 -47
  81. package/lib/module/components/buttons/ButtonOutline.js.map +1 -1
  82. package/lib/module/components/buttons/ButtonSolid.js +17 -42
  83. package/lib/module/components/buttons/ButtonSolid.js.map +1 -1
  84. package/lib/module/components/buttons/IconButton.js +16 -35
  85. package/lib/module/components/buttons/IconButton.js.map +1 -1
  86. package/lib/module/components/buttons/IconButtonContained.js +21 -45
  87. package/lib/module/components/buttons/IconButtonContained.js.map +1 -1
  88. package/lib/module/components/buttons/IconButtonSolid.js +17 -34
  89. package/lib/module/components/buttons/IconButtonSolid.js.map +1 -1
  90. package/lib/module/components/buttons/__test__/__snapshots__/button.test.tsx.snap +34 -10
  91. package/lib/module/components/layout/index.js +0 -1
  92. package/lib/module/components/layout/index.js.map +1 -1
  93. package/lib/module/components/listitems/ListItemAction.js +15 -42
  94. package/lib/module/components/listitems/ListItemAction.js.map +1 -1
  95. package/lib/module/components/listitems/ListItemCheckbox.js +15 -43
  96. package/lib/module/components/listitems/ListItemCheckbox.js.map +1 -1
  97. package/lib/module/components/listitems/ListItemHeader.js +2 -2
  98. package/lib/module/components/listitems/ListItemHeader.js.map +1 -1
  99. package/lib/module/components/listitems/ListItemInfoCopy.js +16 -45
  100. package/lib/module/components/listitems/ListItemInfoCopy.js.map +1 -1
  101. package/lib/module/components/listitems/ListItemNav.js +17 -47
  102. package/lib/module/components/listitems/ListItemNav.js.map +1 -1
  103. package/lib/module/components/listitems/ListItemNavAlert.js +19 -49
  104. package/lib/module/components/listitems/ListItemNavAlert.js.map +1 -1
  105. package/lib/module/components/listitems/ListItemRadio.js +22 -52
  106. package/lib/module/components/listitems/ListItemRadio.js.map +1 -1
  107. package/lib/module/components/listitems/ListItemRadioWithAmount.js +1 -1
  108. package/lib/module/components/listitems/ListItemRadioWithAmount.js.map +1 -1
  109. package/lib/module/components/listitems/ListItemTransaction.js +1 -1
  110. package/lib/module/components/listitems/ListItemTransaction.js.map +1 -1
  111. package/lib/module/components/listitems/{PressableListItemsBase.js → PressableListItemBase.js} +7 -7
  112. package/lib/module/components/listitems/PressableListItemBase.js.map +1 -0
  113. package/lib/module/components/listitems/__test__/__snapshots__/listitem.test.tsx.snap +13 -7
  114. package/lib/module/components/listitems/__test__/listitem.test.js +1 -1
  115. package/lib/module/components/listitems/__test__/listitem.test.js.map +1 -1
  116. package/lib/module/components/listitems/index.js +1 -1
  117. package/lib/module/components/listitems/index.js.map +1 -1
  118. package/lib/module/components/modules/PressableModuleBase.js +17 -10
  119. package/lib/module/components/modules/PressableModuleBase.js.map +1 -1
  120. package/lib/module/components/modules/index.js +1 -1
  121. package/lib/module/components/modules/index.js.map +1 -1
  122. package/lib/module/components/numberpad/NumberButton.js +14 -30
  123. package/lib/module/components/numberpad/NumberButton.js.map +1 -1
  124. package/lib/module/components/numberpad/__test__/__snapshots__/NumberPad.test.tsx.snap +20 -0
  125. package/lib/module/components/otpInput/OTPInput.js +2 -1
  126. package/lib/module/components/otpInput/OTPInput.js.map +1 -1
  127. package/lib/module/components/tabs/TabItem.js +18 -24
  128. package/lib/module/components/tabs/TabItem.js.map +1 -1
  129. package/lib/module/core/IOAnimations.js +4 -10
  130. package/lib/module/core/IOAnimations.js.map +1 -1
  131. package/lib/module/hooks/index.js +3 -0
  132. package/lib/module/hooks/index.js.map +1 -0
  133. package/lib/module/hooks/useListItemAnimation.js +33 -0
  134. package/lib/module/hooks/useListItemAnimation.js.map +1 -0
  135. package/lib/module/hooks/useScaleAnimation.js +29 -0
  136. package/lib/module/hooks/useScaleAnimation.js.map +1 -0
  137. package/lib/module/index.js +1 -0
  138. package/lib/module/index.js.map +1 -1
  139. package/lib/module/utils/hooks/index.js +3 -0
  140. package/lib/module/utils/hooks/index.js.map +1 -0
  141. package/lib/module/utils/hooks/useSpringPressProgressValue.js +5 -5
  142. package/lib/module/utils/hooks/useSpringPressProgressValue.js.map +1 -1
  143. package/lib/typescript/components/alert/Alert.d.ts.map +1 -1
  144. package/lib/typescript/components/alert/AlertEdgeToEdge.d.ts.map +1 -1
  145. package/lib/typescript/components/banner/Banner.d.ts.map +1 -1
  146. package/lib/typescript/components/buttons/ButtonLink.d.ts.map +1 -1
  147. package/lib/typescript/components/buttons/ButtonOutline.d.ts.map +1 -1
  148. package/lib/typescript/components/buttons/ButtonSolid.d.ts.map +1 -1
  149. package/lib/typescript/components/buttons/IconButton.d.ts.map +1 -1
  150. package/lib/typescript/components/buttons/IconButtonContained.d.ts.map +1 -1
  151. package/lib/typescript/components/buttons/IconButtonSolid.d.ts.map +1 -1
  152. package/lib/typescript/components/layout/index.d.ts +0 -1
  153. package/lib/typescript/components/layout/index.d.ts.map +1 -1
  154. package/lib/typescript/components/listitems/ListItemAction.d.ts.map +1 -1
  155. package/lib/typescript/components/listitems/ListItemCheckbox.d.ts.map +1 -1
  156. package/lib/typescript/components/listitems/ListItemInfoCopy.d.ts.map +1 -1
  157. package/lib/typescript/components/listitems/ListItemNav.d.ts.map +1 -1
  158. package/lib/typescript/components/listitems/ListItemNavAlert.d.ts.map +1 -1
  159. package/lib/typescript/components/listitems/ListItemRadio.d.ts.map +1 -1
  160. package/lib/typescript/components/listitems/ListItemRadioWithAmount.d.ts.map +1 -1
  161. package/lib/typescript/components/listitems/ListItemTransaction.d.ts +1 -1
  162. package/lib/typescript/components/listitems/ListItemTransaction.d.ts.map +1 -1
  163. package/lib/typescript/components/listitems/{PressableListItemsBase.d.ts → PressableListItemBase.d.ts} +3 -2
  164. package/lib/typescript/components/listitems/PressableListItemBase.d.ts.map +1 -0
  165. package/lib/typescript/components/listitems/index.d.ts +1 -1
  166. package/lib/typescript/components/listitems/index.d.ts.map +1 -1
  167. package/lib/typescript/components/modules/PressableModuleBase.d.ts.map +1 -1
  168. package/lib/typescript/components/modules/index.d.ts +1 -1
  169. package/lib/typescript/components/modules/index.d.ts.map +1 -1
  170. package/lib/typescript/components/numberpad/NumberButton.d.ts.map +1 -1
  171. package/lib/typescript/components/otpInput/OTPInput.d.ts.map +1 -1
  172. package/lib/typescript/components/tabs/TabItem.d.ts.map +1 -1
  173. package/lib/typescript/core/IOAnimations.d.ts +6 -10
  174. package/lib/typescript/core/IOAnimations.d.ts.map +1 -1
  175. package/lib/typescript/hooks/index.d.ts +3 -0
  176. package/lib/typescript/hooks/index.d.ts.map +1 -0
  177. package/lib/typescript/hooks/useListItemAnimation.d.ts +10 -0
  178. package/lib/typescript/hooks/useListItemAnimation.d.ts.map +1 -0
  179. package/lib/typescript/hooks/useScaleAnimation.d.ts +10 -0
  180. package/lib/typescript/hooks/useScaleAnimation.d.ts.map +1 -0
  181. package/lib/typescript/index.d.ts +1 -0
  182. package/lib/typescript/index.d.ts.map +1 -1
  183. package/lib/typescript/utils/hooks/index.d.ts +3 -0
  184. package/lib/typescript/utils/hooks/index.d.ts.map +1 -0
  185. package/lib/typescript/utils/hooks/useSpringPressProgressValue.d.ts +7 -8
  186. package/lib/typescript/utils/hooks/useSpringPressProgressValue.d.ts.map +1 -1
  187. package/package.json +1 -1
  188. package/src/components/alert/Alert.tsx +7 -46
  189. package/src/components/alert/AlertEdgeToEdge.tsx +6 -46
  190. package/src/components/banner/Banner.tsx +6 -52
  191. package/src/components/buttons/ButtonLink.tsx +32 -89
  192. package/src/components/buttons/ButtonOutline.tsx +26 -60
  193. package/src/components/buttons/ButtonSolid.tsx +11 -58
  194. package/src/components/buttons/IconButton.tsx +10 -47
  195. package/src/components/buttons/IconButtonContained.tsx +21 -57
  196. package/src/components/buttons/IconButtonSolid.tsx +15 -46
  197. package/src/components/buttons/__test__/__snapshots__/button.test.tsx.snap +34 -10
  198. package/src/components/layout/index.tsx +0 -1
  199. package/src/components/listitems/ListItemAction.tsx +10 -66
  200. package/src/components/listitems/ListItemCheckbox.tsx +10 -68
  201. package/src/components/listitems/ListItemHeader.tsx +2 -2
  202. package/src/components/listitems/ListItemInfoCopy.tsx +11 -71
  203. package/src/components/listitems/ListItemNav.tsx +13 -74
  204. package/src/components/listitems/ListItemNavAlert.tsx +18 -92
  205. package/src/components/listitems/ListItemRadio.tsx +14 -75
  206. package/src/components/listitems/ListItemRadioWithAmount.tsx +2 -1
  207. package/src/components/listitems/ListItemTransaction.tsx +1 -1
  208. package/src/components/listitems/{PressableListItemsBase.tsx → PressableListItemBase.tsx} +7 -6
  209. package/src/components/listitems/__test__/__snapshots__/listitem.test.tsx.snap +13 -7
  210. package/src/components/listitems/__test__/listitem.test.tsx +1 -1
  211. package/src/components/listitems/index.tsx +1 -1
  212. package/src/components/modules/PressableModuleBase.tsx +15 -8
  213. package/src/components/modules/index.tsx +1 -1
  214. package/src/components/numberpad/NumberButton.tsx +12 -43
  215. package/src/components/numberpad/__test__/__snapshots__/NumberPad.test.tsx.snap +20 -0
  216. package/src/components/otpInput/OTPInput.tsx +1 -0
  217. package/src/components/tabs/TabItem.tsx +15 -29
  218. package/src/core/IOAnimations.ts +8 -10
  219. package/src/hooks/index.tsx +2 -0
  220. package/src/hooks/useListItemAnimation.tsx +59 -0
  221. package/src/hooks/useScaleAnimation.tsx +41 -0
  222. package/src/index.tsx +1 -0
  223. package/src/utils/hooks/index.tsx +2 -0
  224. package/src/utils/hooks/useSpringPressProgressValue.ts +14 -8
  225. package/lib/commonjs/components/layout/FooterWithButtons.js +0 -84
  226. package/lib/commonjs/components/layout/FooterWithButtons.js.map +0 -1
  227. package/lib/commonjs/components/listitems/PressableListItemsBase.js.map +0 -1
  228. package/lib/commonjs/components/listitems/hooks/useListItemSpringAnimation.js +0 -56
  229. package/lib/commonjs/components/listitems/hooks/useListItemSpringAnimation.js.map +0 -1
  230. package/lib/commonjs/components/modules/hooks/useModuleSpringAnimation.js +0 -41
  231. package/lib/commonjs/components/modules/hooks/useModuleSpringAnimation.js.map +0 -1
  232. package/lib/module/components/layout/FooterWithButtons.js +0 -75
  233. package/lib/module/components/layout/FooterWithButtons.js.map +0 -1
  234. package/lib/module/components/listitems/PressableListItemsBase.js.map +0 -1
  235. package/lib/module/components/listitems/hooks/useListItemSpringAnimation.js +0 -47
  236. package/lib/module/components/listitems/hooks/useListItemSpringAnimation.js.map +0 -1
  237. package/lib/module/components/modules/hooks/useModuleSpringAnimation.js +0 -34
  238. package/lib/module/components/modules/hooks/useModuleSpringAnimation.js.map +0 -1
  239. package/lib/typescript/components/layout/FooterWithButtons.d.ts +0 -16
  240. package/lib/typescript/components/layout/FooterWithButtons.d.ts.map +0 -1
  241. package/lib/typescript/components/listitems/PressableListItemsBase.d.ts.map +0 -1
  242. package/lib/typescript/components/listitems/hooks/useListItemSpringAnimation.d.ts +0 -13
  243. package/lib/typescript/components/listitems/hooks/useListItemSpringAnimation.d.ts.map +0 -1
  244. package/lib/typescript/components/modules/hooks/useModuleSpringAnimation.d.ts +0 -10
  245. package/lib/typescript/components/modules/hooks/useModuleSpringAnimation.d.ts.map +0 -1
  246. package/src/components/layout/FooterWithButtons.tsx +0 -90
  247. package/src/components/listitems/hooks/useListItemSpringAnimation.ts +0 -72
  248. package/src/components/modules/hooks/useModuleSpringAnimation.ts +0 -49
@@ -1,4 +1,4 @@
1
- import React, { ComponentProps, useCallback } from "react";
1
+ import React, { ComponentProps, forwardRef } from "react";
2
2
  import {
3
3
  GestureResponderEvent,
4
4
  Pressable,
@@ -6,24 +6,19 @@ import {
6
6
  View
7
7
  } from "react-native";
8
8
  import Animated, {
9
- Extrapolate,
10
- interpolate,
11
9
  interpolateColor,
12
10
  useAnimatedProps,
13
11
  useAnimatedStyle,
14
- useDerivedValue,
15
- useSharedValue,
16
- withSpring
12
+ useReducedMotion
17
13
  } from "react-native-reanimated";
18
14
  import {
19
15
  IOButtonLegacyStyles,
20
16
  IOButtonStyles,
21
17
  IOColors,
22
- IOScaleValues,
23
- IOSpringValues,
24
18
  hexToRgba,
25
19
  useIOExperimentalDesign
26
20
  } from "../../core/";
21
+ import { useScaleAnimation } from "../../hooks";
27
22
  import { WithTestID } from "../../utils/types";
28
23
  import {
29
24
  AnimatedIcon,
@@ -190,6 +185,11 @@ const mapLegacyColorStates: Record<
190
185
  }
191
186
  };
192
187
 
188
+ // Icon size
189
+ const iconSize: IOIconSizeScale = 20;
190
+
191
+ const DISABLED_OPACITY = 0.5;
192
+
193
193
  // TODO: Remove this when legacy look is deprecated https://pagopa.atlassian.net/browse/IOPLT-153
194
194
  const IOButtonLegacyStylesLocal = StyleSheet.create({
195
195
  buttonWithBorder: {
@@ -197,18 +197,13 @@ const IOButtonLegacyStylesLocal = StyleSheet.create({
197
197
  }
198
198
  });
199
199
 
200
- // Icon size
201
- const iconSize: IOIconSizeScale = 20;
202
-
203
- const DISABLED_OPACITY = 0.5;
204
-
205
200
  const IOButtonStylesLocal = StyleSheet.create({
206
201
  buttonWithBorder: {
207
202
  borderWidth: 2
208
203
  }
209
204
  });
210
205
 
211
- export const ButtonOutline = React.forwardRef<View, ButtonOutline>(
206
+ export const ButtonOutline = forwardRef<View, ButtonOutline>(
212
207
  (
213
208
  {
214
209
  color = "primary",
@@ -225,7 +220,9 @@ export const ButtonOutline = React.forwardRef<View, ButtonOutline>(
225
220
  ref
226
221
  ) => {
227
222
  const { isExperimental } = useIOExperimentalDesign();
228
- const isPressed: Animated.SharedValue<number> = useSharedValue(0);
223
+ const { progress, onPressIn, onPressOut, scaleAnimatedStyle } =
224
+ useScaleAnimation();
225
+ const reducedMotion = useReducedMotion();
229
226
 
230
227
  const AnimatedIOText = Animated.createAnimatedComponent(IOText);
231
228
 
@@ -243,80 +240,48 @@ export const ButtonOutline = React.forwardRef<View, ButtonOutline>(
243
240
  () => (isExperimental ? IOButtonStylesLocal : IOButtonLegacyStylesLocal),
244
241
  [isExperimental]
245
242
  );
246
- // Scaling transformation applied when the button is pressed
247
- const animationScaleValue = IOScaleValues?.basicButton?.pressedState;
248
-
249
- // Using a spring-based animation for our interpolations
250
- const progressPressed = useDerivedValue(() =>
251
- withSpring(isPressed.value, IOSpringValues.button)
252
- );
253
243
 
254
244
  // Interpolate animation values from `isPressed` values
255
245
  const pressedAnimationStyle = useAnimatedStyle(() => {
256
246
  // Link color states to the pressed states
257
247
  const backgroundColor = interpolateColor(
258
- progressPressed.value,
248
+ progress.value,
259
249
  [0, 1],
260
250
  [colorMap[color].background.default, colorMap[color].background.pressed]
261
251
  );
262
252
 
263
253
  const borderColor = interpolateColor(
264
- progressPressed.value,
254
+ progress.value,
265
255
  [0, 1],
266
256
  [colorMap[color].border.default, colorMap[color].border.pressed]
267
257
  );
268
258
 
269
- // Scale down button slightly when pressed
270
- const scale = interpolate(
271
- progressPressed.value,
272
- [0, 1],
273
- [1, animationScaleValue],
274
- Extrapolate.CLAMP
275
- );
276
-
277
259
  return {
278
260
  borderColor,
279
- backgroundColor,
280
- transform: [{ scale }]
261
+ backgroundColor
281
262
  };
282
263
  });
283
264
 
284
- const pressedColorLabelAnimationStyle = useAnimatedStyle(() => {
285
- // Link color states to the pressed states
286
-
287
- const labelColor = interpolateColor(
288
- progressPressed.value,
265
+ const pressedColorLabelAnimationStyle = useAnimatedStyle(() => ({
266
+ color: interpolateColor(
267
+ progress.value,
289
268
  [0, 1],
290
269
  [colorMap[color].border.default, colorMap[color].border.pressed]
291
- );
292
-
293
- return {
294
- color: labelColor
295
- };
296
- });
270
+ )
271
+ }));
297
272
 
298
273
  // Animate the <Icon> color prop
299
- const pressedColorIconAnimationStyle = useAnimatedProps(() => {
300
- const iconColor = interpolateColor(
301
- progressPressed.value,
274
+ const pressedColorIconAnimationStyle = useAnimatedProps(() => ({
275
+ color: interpolateColor(
276
+ progress.value,
302
277
  [0, 1],
303
278
  [colorMap[color].label.default, colorMap[color].label.pressed]
304
- );
305
- return { color: iconColor };
306
- });
279
+ )
280
+ }));
307
281
 
308
282
  const AnimatedIconClassComponent =
309
283
  Animated.createAnimatedComponent(IconClassComponent);
310
284
 
311
- const onPressIn = useCallback(() => {
312
- // eslint-disable-next-line functional/immutable-data
313
- isPressed.value = 1;
314
- }, [isPressed]);
315
- const onPressOut = useCallback(() => {
316
- // eslint-disable-next-line functional/immutable-data
317
- isPressed.value = 0;
318
- }, [isPressed]);
319
-
320
285
  return (
321
286
  <Pressable
322
287
  ref={ref}
@@ -351,6 +316,7 @@ export const ButtonOutline = React.forwardRef<View, ButtonOutline>(
351
316
  },
352
317
  /* Prevent Reanimated from overriding background colors
353
318
  if button is disabled */
319
+ !reducedMotion && !disabled && scaleAnimatedStyle,
354
320
  !disabled && pressedAnimationStyle
355
321
  ]}
356
322
  >
@@ -1,4 +1,4 @@
1
- import React, { ComponentProps, useCallback, useEffect, useRef } from "react";
1
+ import React, { ComponentProps, useCallback } from "react";
2
2
  import {
3
3
  GestureResponderEvent,
4
4
  Pressable,
@@ -7,25 +7,20 @@ import {
7
7
  } from "react-native";
8
8
  import ReactNativeHapticFeedback from "react-native-haptic-feedback";
9
9
  import Animated, {
10
- Extrapolate,
11
- interpolate,
12
10
  interpolateColor,
13
11
  useAnimatedStyle,
14
- useDerivedValue,
15
- useSharedValue,
16
- withSpring
12
+ useReducedMotion
17
13
  } from "react-native-reanimated";
18
14
  import {
19
15
  IOButtonLegacyStyles,
20
16
  IOButtonStyles,
21
17
  IOColors,
22
- IOScaleValues,
23
- IOSpringValues,
24
18
  enterTransitionInnerContent,
25
19
  enterTransitionInnerContentSmall,
26
20
  exitTransitionInnerContent,
27
21
  useIOExperimentalDesign
28
22
  } from "../../core";
23
+ import { useScaleAnimation } from "../../hooks";
29
24
  import { WithTestID } from "../../utils/types";
30
25
  import { IOIconSizeScale, IOIcons, Icon } from "../icons";
31
26
  import { LoadingSpinner } from "../loadingSpinner";
@@ -176,21 +171,10 @@ export const ButtonSolid = React.forwardRef<View, ButtonSolidProps>(
176
171
  },
177
172
  ref
178
173
  ) => {
179
- const isPressed = useSharedValue(0);
180
174
  const { isExperimental } = useIOExperimentalDesign();
181
- // Scaling transformation applied when the button is pressed
182
- const animationScaleValue = IOScaleValues?.basicButton?.pressedState;
183
-
184
- /* Prevent the component from triggering the `isEntering' transition
185
- on the on the first render. Solution from this discussion:
186
- https://github.com/software-mansion/react-native-reanimated/discussions/2513
187
- */
188
- const isMounted = useRef(false);
189
-
190
- useEffect(() => {
191
- // eslint-disable-next-line functional/immutable-data
192
- isMounted.current = true;
193
- }, []);
175
+ const { progress, onPressIn, onPressOut, scaleAnimatedStyle } =
176
+ useScaleAnimation();
177
+ const reducedMotion = useReducedMotion();
194
178
 
195
179
  const colorMap = React.useMemo(
196
180
  () => (isExperimental ? mapColorStates : mapLegacyColorStates),
@@ -202,43 +186,18 @@ export const ButtonSolid = React.forwardRef<View, ButtonSolidProps>(
202
186
  [isExperimental]
203
187
  );
204
188
 
205
- // Using a spring-based animation for our interpolations
206
- const progressPressed = useDerivedValue(() =>
207
- withSpring(isPressed.value, IOSpringValues.button)
208
- );
209
-
210
189
  // Interpolate animation values from `isPressed` values
211
190
  const pressedAnimationStyle = useAnimatedStyle(() => {
212
191
  // Link color states to the pressed states
213
192
  const backgroundColor = interpolateColor(
214
- progressPressed.value,
193
+ progress.value,
215
194
  [0, 1],
216
195
  [colorMap[color].default, colorMap[color].pressed]
217
196
  );
218
197
 
219
- // Scale down button slightly when pressed
220
- const scale = interpolate(
221
- progressPressed.value,
222
- [0, 1],
223
- [1, animationScaleValue],
224
- Extrapolate.CLAMP
225
- );
226
-
227
- return {
228
- backgroundColor,
229
- transform: [{ scale }]
230
- };
198
+ return { backgroundColor };
231
199
  });
232
200
 
233
- const onPressIn = useCallback(() => {
234
- // eslint-disable-next-line functional/immutable-data
235
- isPressed.value = 1;
236
- }, [isPressed]);
237
- const onPressOut = useCallback(() => {
238
- // eslint-disable-next-line functional/immutable-data
239
- isPressed.value = 0;
240
- }, [isPressed]);
241
-
242
201
  const handleOnPress = useCallback(
243
202
  (event: GestureResponderEvent) => {
244
203
  /* Don't call `onPress` if the button is
@@ -289,15 +248,14 @@ export const ButtonSolid = React.forwardRef<View, ButtonSolidProps>(
289
248
  : { backgroundColor: colorMap[color]?.default },
290
249
  /* Prevent Reanimated from overriding background colors
291
250
  if button is disabled */
251
+ !disabled && !reducedMotion && scaleAnimatedStyle,
292
252
  !disabled && pressedAnimationStyle
293
253
  ]}
294
254
  >
295
255
  {loading && (
296
256
  <Animated.View
297
257
  style={buttonStyles.buttonInner}
298
- entering={
299
- isMounted.current ? enterTransitionInnerContentSmall : undefined
300
- }
258
+ entering={enterTransitionInnerContentSmall}
301
259
  exiting={exitTransitionInnerContent}
302
260
  >
303
261
  <LoadingSpinner color={foregroundColor} />
@@ -310,12 +268,7 @@ export const ButtonSolid = React.forwardRef<View, ButtonSolidProps>(
310
268
  buttonStyles.buttonInner,
311
269
  iconPosition === "end" && { flexDirection: "row-reverse" }
312
270
  ]}
313
- entering={
314
- isMounted.current ? enterTransitionInnerContent : undefined
315
- }
316
- /* Temporarily disable the exiting transition because it caused
317
- a weird glitch on page exit */
318
- // exiting={exitTransitionInnerContent}
271
+ entering={enterTransitionInnerContent}
319
272
  >
320
273
  {icon && (
321
274
  <>
@@ -1,24 +1,18 @@
1
- import React, { useCallback, useMemo } from "react";
1
+ import React, { useMemo } from "react";
2
2
  import { GestureResponderEvent, Pressable } from "react-native";
3
3
  import Animated, {
4
- Extrapolate,
5
- interpolate,
6
4
  interpolateColor,
7
5
  useAnimatedProps,
8
- useAnimatedStyle,
9
- useDerivedValue,
10
- useSharedValue,
11
- withSpring
6
+ useReducedMotion
12
7
  } from "react-native-reanimated";
13
8
  import {
14
9
  IOColors,
15
10
  IOIconButtonStyles,
16
- IOScaleValues,
17
- IOSpringValues,
18
11
  IOStyles,
19
12
  hexToRgba,
20
13
  useIOExperimentalDesign
21
14
  } from "../../core";
15
+ import { useScaleAnimation } from "../../hooks";
22
16
  import { WithTestID } from "../../utils/types";
23
17
  import {
24
18
  AnimatedIcon,
@@ -116,7 +110,9 @@ export const IconButton = ({
116
110
  accessibilityHint,
117
111
  testID
118
112
  }: IconButton) => {
119
- const isPressed = useSharedValue(0);
113
+ const { progress, onPressIn, onPressOut, scaleAnimatedStyle } =
114
+ useScaleAnimation("exaggerated");
115
+ const reducedMotion = useReducedMotion();
120
116
 
121
117
  const { isExperimental } = useIOExperimentalDesign();
122
118
 
@@ -125,56 +121,23 @@ export const IconButton = ({
125
121
  [isExperimental]
126
122
  );
127
123
 
128
- // Scaling transformation applied when the button is pressed
129
- const animationScaleValue = IOScaleValues?.exaggeratedButton?.pressedState;
130
-
131
- // Using a spring-based animation for our interpolations
132
- const progressPressed = useDerivedValue(() =>
133
- withSpring(isPressed.value, IOSpringValues.button)
134
- );
135
-
136
- // Interpolate animation values from `isPressed` values
137
-
138
- const pressedAnimationStyle = useAnimatedStyle(() => {
139
- // Scale down button slightly when pressed
140
- const scale = interpolate(
141
- progressPressed.value,
142
- [0, 1],
143
- [1, animationScaleValue],
144
- Extrapolate.CLAMP
145
- );
146
-
147
- return {
148
- transform: [{ scale }]
149
- };
150
- });
151
-
152
124
  // Animate the <Icon> color prop
153
125
  const animatedColor = useAnimatedProps(() => {
154
126
  const iconColor = interpolateColor(
155
- progressPressed.value,
127
+ progress.value,
156
128
  [0, 1],
157
129
  [colorMap[color].icon.default, colorMap[color].icon.pressed]
158
130
  );
159
131
  return { color: iconColor };
160
132
  });
161
133
 
162
- const handlePressIn = useCallback(() => {
163
- // eslint-disable-next-line functional/immutable-data
164
- isPressed.value = 1;
165
- }, [isPressed]);
166
- const handlePressOut = useCallback(() => {
167
- // eslint-disable-next-line functional/immutable-data
168
- isPressed.value = 0;
169
- }, [isPressed]);
170
-
171
134
  return (
172
135
  <Pressable
173
136
  disabled={disabled}
174
137
  // Events
175
138
  onPress={onPress}
176
- onPressIn={handlePressIn}
177
- onPressOut={handlePressOut}
139
+ onPressIn={onPressIn}
140
+ onPressOut={onPressOut}
178
141
  // Accessibility
179
142
  accessible={true}
180
143
  accessibilityRole={"button"}
@@ -192,7 +155,7 @@ export const IconButton = ({
192
155
  IOIconButtonStyles.buttonSizeSmall,
193
156
  IOStyles.alignCenter,
194
157
  IOStyles.centerJustified,
195
- !disabled && pressedAnimationStyle
158
+ !disabled && !reducedMotion && scaleAnimatedStyle
196
159
  ]}
197
160
  >
198
161
  {!disabled ? (
@@ -1,15 +1,10 @@
1
1
  import * as React from "react";
2
- import { useCallback } from "react";
3
2
  import { GestureResponderEvent, Pressable } from "react-native";
4
3
  import Animated, {
5
- Extrapolate,
6
- interpolate,
7
4
  interpolateColor,
8
5
  useAnimatedProps,
9
6
  useAnimatedStyle,
10
- useDerivedValue,
11
- useSharedValue,
12
- withSpring
7
+ useReducedMotion
13
8
  } from "react-native-reanimated";
14
9
  import {
15
10
  AnimatedIcon,
@@ -20,11 +15,10 @@ import {
20
15
  IOButtonStyles,
21
16
  IOColors,
22
17
  IOIconButtonStyles,
23
- IOScaleValues,
24
- IOSpringValues,
25
18
  hexToRgba,
26
19
  useIOExperimentalDesign
27
20
  } from "../../core";
21
+ import { useScaleAnimation } from "../../hooks";
28
22
  import { WithTestID } from "../../utils/types";
29
23
 
30
24
  export type IconButtonContained = WithTestID<{
@@ -151,64 +145,33 @@ export const IconButtonContained = ({
151
145
  accessibilityHint,
152
146
  testID
153
147
  }: IconButtonContained) => {
154
- const isPressed = useSharedValue(0);
155
148
  const { isExperimental } = useIOExperimentalDesign();
156
149
 
150
+ const { progress, onPressIn, onPressOut, scaleAnimatedStyle } =
151
+ useScaleAnimation("exaggerated");
152
+ const reducedMotion = useReducedMotion();
153
+
157
154
  const colorMap = React.useMemo(
158
155
  () => (isExperimental ? mapColorStates : mapLegacyColorStates),
159
156
  [isExperimental]
160
157
  );
161
158
 
162
- // Scaling transformation applied when the button is pressed
163
- const animationScaleValue = IOScaleValues?.exaggeratedButton?.pressedState;
164
-
165
- // Using a spring-based animation for our interpolations
166
- const progressPressed = useDerivedValue(() =>
167
- withSpring(isPressed.value, IOSpringValues.button)
168
- );
169
-
170
- // Interpolate animation values from `isPressed` values
171
-
172
- const pressedAnimationStyle = useAnimatedStyle(() => {
173
- // Link color states to the pressed states
174
- const backgroundColor = interpolateColor(
175
- progressPressed.value,
159
+ const backgroundColorAnimationStyle = useAnimatedStyle(() => ({
160
+ backgroundColor: interpolateColor(
161
+ progress.value,
176
162
  [0, 1],
177
163
  [colorMap[color].background.default, colorMap[color].background.pressed]
178
- );
179
-
180
- // Scale down button slightly when pressed
181
- const scale = interpolate(
182
- progressPressed.value,
183
- [0, 1],
184
- [1, animationScaleValue],
185
- Extrapolate.CLAMP
186
- );
187
-
188
- return {
189
- backgroundColor,
190
- transform: [{ scale }]
191
- };
192
- });
164
+ )
165
+ }));
193
166
 
194
167
  // Animate the <Icon> color prop
195
- const animatedColor = useAnimatedProps(() => {
196
- const iconColor = interpolateColor(
197
- progressPressed.value,
168
+ const iconColorAnimationStyle = useAnimatedProps(() => ({
169
+ color: interpolateColor(
170
+ progress.value,
198
171
  [0, 1],
199
172
  [colorMap[color].icon.default, colorMap[color].icon.pressed]
200
- );
201
- return { color: iconColor };
202
- });
203
-
204
- const handlePressIn = useCallback(() => {
205
- // eslint-disable-next-line functional/immutable-data
206
- isPressed.value = 1;
207
- }, [isPressed]);
208
- const handlePressOut = useCallback(() => {
209
- // eslint-disable-next-line functional/immutable-data
210
- isPressed.value = 0;
211
- }, [isPressed]);
173
+ )
174
+ }));
212
175
 
213
176
  return (
214
177
  <Pressable
@@ -218,8 +181,8 @@ export const IconButtonContained = ({
218
181
  accessibilityState={{ disabled }}
219
182
  testID={testID}
220
183
  onPress={onPress}
221
- onPressIn={handlePressIn}
222
- onPressOut={handlePressOut}
184
+ onPressIn={onPressIn}
185
+ onPressOut={onPressOut}
223
186
  accessible={true}
224
187
  disabled={disabled}
225
188
  style={IOButtonStyles.dimensionsDefault}
@@ -228,13 +191,14 @@ export const IconButtonContained = ({
228
191
  style={[
229
192
  IOIconButtonStyles.button,
230
193
  IOIconButtonStyles.buttonSizeDefault,
231
- !disabled && pressedAnimationStyle
194
+ !disabled && !reducedMotion && scaleAnimatedStyle,
195
+ !disabled && backgroundColorAnimationStyle
232
196
  ]}
233
197
  >
234
198
  {!disabled ? (
235
199
  <AnimatedIconClassComponent
236
200
  name={icon}
237
- animatedProps={animatedColor}
201
+ animatedProps={iconColorAnimationStyle}
238
202
  color={colorMap[color]?.icon?.default}
239
203
  />
240
204
  ) : (
@@ -1,23 +1,17 @@
1
1
  import * as React from "react";
2
- import { useCallback } from "react";
3
2
  import { GestureResponderEvent, Pressable } from "react-native";
4
3
  import Animated, {
5
- Extrapolate,
6
- interpolate,
7
4
  interpolateColor,
8
5
  useAnimatedStyle,
9
- useDerivedValue,
10
- useSharedValue,
11
- withSpring
6
+ useReducedMotion
12
7
  } from "react-native-reanimated";
13
8
  import {
14
9
  IOButtonStyles,
15
10
  IOIconButtonStyles,
16
- IOScaleValues,
17
- IOSpringValues,
18
11
  useIOExperimentalDesign
19
12
  } from "../../core";
20
13
  import { IOColors, hexToRgba } from "../../core/IOColors";
14
+ import { useScaleAnimation } from "../../hooks";
21
15
  import { WithTestID } from "../../utils/types";
22
16
  import { AnimatedIcon, IOIcons } from "../icons";
23
17
 
@@ -110,50 +104,24 @@ export const IconButtonSolid = ({
110
104
  accessibilityHint,
111
105
  testID
112
106
  }: IconButtonSolid) => {
113
- const isPressed = useSharedValue(0);
114
107
  const { isExperimental } = useIOExperimentalDesign();
115
- // Scaling transformation applied when the button is pressed
116
- const animationScaleValue = IOScaleValues?.exaggeratedButton?.pressedState;
117
108
 
118
- // Using a spring-based animation for our interpolations
119
- const progressPressed = useDerivedValue(() =>
120
- withSpring(isPressed.value, IOSpringValues.button)
121
- );
109
+ const { progress, onPressIn, onPressOut, scaleAnimatedStyle } =
110
+ useScaleAnimation("exaggerated");
111
+ const reducedMotion = useReducedMotion();
122
112
 
123
113
  const colorMap = React.useMemo(
124
114
  () => (isExperimental ? mapColorStates : mapLegacyColorStates),
125
115
  [isExperimental]
126
116
  );
127
- // Interpolate animation values from `isPressed` values
128
- const pressedAnimationStyle = useAnimatedStyle(() => {
129
- const backgroundColor = interpolateColor(
130
- progressPressed.value,
131
- [0, 1],
132
- [colorMap[color].background.default, colorMap[color].background.pressed]
133
- );
134
117
 
135
- // Scale down button slightly when pressed
136
- const scale = interpolate(
137
- progressPressed.value,
118
+ const backgroundColorAnimationStyle = useAnimatedStyle(() => ({
119
+ backgroundColor: interpolateColor(
120
+ progress.value,
138
121
  [0, 1],
139
- [1, animationScaleValue],
140
- Extrapolate.CLAMP
141
- );
142
-
143
- return {
144
- backgroundColor,
145
- transform: [{ scale }]
146
- };
147
- });
148
-
149
- const handlePressIn = useCallback(() => {
150
- // eslint-disable-next-line functional/immutable-data
151
- isPressed.value = 1;
152
- }, [isPressed]);
153
- const handlePressOut = useCallback(() => {
154
- // eslint-disable-next-line functional/immutable-data
155
- isPressed.value = 0;
156
- }, [isPressed]);
122
+ [colorMap[color].background.default, colorMap[color].background.pressed]
123
+ )
124
+ }));
157
125
 
158
126
  return (
159
127
  <Pressable
@@ -163,8 +131,8 @@ export const IconButtonSolid = ({
163
131
  accessibilityState={{ disabled }}
164
132
  testID={testID}
165
133
  onPress={onPress}
166
- onPressIn={handlePressIn}
167
- onPressOut={handlePressOut}
134
+ onPressIn={onPressIn}
135
+ onPressOut={onPressOut}
168
136
  accessible={true}
169
137
  disabled={disabled}
170
138
  style={IOButtonStyles.dimensionsDefault}
@@ -173,7 +141,8 @@ export const IconButtonSolid = ({
173
141
  style={[
174
142
  IOIconButtonStyles.button,
175
143
  IOIconButtonStyles.buttonSizeLarge,
176
- !disabled && pressedAnimationStyle,
144
+ !disabled && !reducedMotion && scaleAnimatedStyle,
145
+ !disabled && backgroundColorAnimationStyle,
177
146
  disabled
178
147
  ? {
179
148
  backgroundColor: colorMap[color]?.background?.disabled