@pagopa/io-app-design-system 2.0.1 → 2.0.3

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 (153) hide show
  1. package/lib/commonjs/components/contentWrapper/ContentWrapper.js +2 -0
  2. package/lib/commonjs/components/contentWrapper/ContentWrapper.js.map +1 -1
  3. package/lib/commonjs/components/layout/BlockButtons.js +1 -1
  4. package/lib/commonjs/components/layout/FooterActions.js +162 -0
  5. package/lib/commonjs/components/layout/FooterActions.js.map +1 -0
  6. package/lib/commonjs/components/layout/FooterActionsInline.js +113 -0
  7. package/lib/commonjs/components/layout/FooterActionsInline.js.map +1 -0
  8. package/lib/commonjs/components/layout/FooterWithButtons.js +3 -1
  9. package/lib/commonjs/components/layout/FooterWithButtons.js.map +1 -1
  10. package/lib/commonjs/components/layout/HeaderSecondLevel.js +9 -4
  11. package/lib/commonjs/components/layout/HeaderSecondLevel.js.map +1 -1
  12. package/lib/commonjs/components/layout/hooks/index.js +28 -0
  13. package/lib/commonjs/components/layout/hooks/index.js.map +1 -0
  14. package/lib/commonjs/components/layout/hooks/useBottomMargins.js +31 -0
  15. package/lib/commonjs/components/layout/hooks/useBottomMargins.js.map +1 -0
  16. package/lib/commonjs/components/layout/hooks/useFooterActionsInlineMeasurements.js +30 -0
  17. package/lib/commonjs/components/layout/hooks/useFooterActionsInlineMeasurements.js.map +1 -0
  18. package/lib/commonjs/components/layout/hooks/useFooterActionsMeasurements.js +31 -0
  19. package/lib/commonjs/components/layout/hooks/useFooterActionsMeasurements.js.map +1 -0
  20. package/lib/commonjs/components/layout/index.js +33 -0
  21. package/lib/commonjs/components/layout/index.js.map +1 -1
  22. package/lib/commonjs/components/listitems/ListItemTransaction.js +4 -2
  23. package/lib/commonjs/components/listitems/ListItemTransaction.js.map +1 -1
  24. package/lib/commonjs/components/pictograms/Pictogram.js +10 -2
  25. package/lib/commonjs/components/pictograms/Pictogram.js.map +1 -1
  26. package/lib/commonjs/components/pictograms/svg/PictogramFingerprint.js +49 -0
  27. package/lib/commonjs/components/pictograms/svg/PictogramFingerprint.js.map +1 -0
  28. package/lib/commonjs/components/pictograms/svg/PictogramSmile.js +32 -0
  29. package/lib/commonjs/components/pictograms/svg/PictogramSmile.js.map +1 -0
  30. package/lib/commonjs/components/pictograms/svg/PictogramWalletDoc.js +46 -0
  31. package/lib/commonjs/components/pictograms/svg/PictogramWalletDoc.js.map +1 -0
  32. package/lib/commonjs/components/pictograms/svg/originals/PictogramFingerprint.svg +1 -0
  33. package/lib/commonjs/components/pictograms/svg/originals/PictogramSmile.svg +1 -0
  34. package/lib/commonjs/components/pictograms/svg/originals/PictogramWalletDoc.svg +1 -0
  35. package/lib/commonjs/core/IOColors.js +11 -4
  36. package/lib/commonjs/core/IOColors.js.map +1 -1
  37. package/lib/commonjs/core/IOSpacing.js +10 -1
  38. package/lib/commonjs/core/IOSpacing.js.map +1 -1
  39. package/lib/commonjs/core/index.js +0 -11
  40. package/lib/commonjs/core/index.js.map +1 -1
  41. package/lib/module/components/contentWrapper/ContentWrapper.js +2 -0
  42. package/lib/module/components/contentWrapper/ContentWrapper.js.map +1 -1
  43. package/lib/module/components/layout/BlockButtons.js +1 -1
  44. package/lib/module/components/layout/FooterActions.js +153 -0
  45. package/lib/module/components/layout/FooterActions.js.map +1 -0
  46. package/lib/module/components/layout/FooterActionsInline.js +104 -0
  47. package/lib/module/components/layout/FooterActionsInline.js.map +1 -0
  48. package/lib/module/components/layout/FooterWithButtons.js +3 -1
  49. package/lib/module/components/layout/FooterWithButtons.js.map +1 -1
  50. package/lib/module/components/layout/HeaderSecondLevel.js +10 -5
  51. package/lib/module/components/layout/HeaderSecondLevel.js.map +1 -1
  52. package/lib/module/components/layout/hooks/index.js +3 -0
  53. package/lib/module/components/layout/hooks/index.js.map +1 -0
  54. package/lib/module/components/layout/hooks/useBottomMargins.js +25 -0
  55. package/lib/module/components/layout/hooks/useBottomMargins.js.map +1 -0
  56. package/lib/module/components/layout/hooks/useFooterActionsInlineMeasurements.js +23 -0
  57. package/lib/module/components/layout/hooks/useFooterActionsInlineMeasurements.js.map +1 -0
  58. package/lib/module/components/layout/hooks/useFooterActionsMeasurements.js +24 -0
  59. package/lib/module/components/layout/hooks/useFooterActionsMeasurements.js.map +1 -0
  60. package/lib/module/components/layout/index.js +3 -0
  61. package/lib/module/components/layout/index.js.map +1 -1
  62. package/lib/module/components/listitems/ListItemTransaction.js +4 -2
  63. package/lib/module/components/listitems/ListItemTransaction.js.map +1 -1
  64. package/lib/module/components/pictograms/Pictogram.js +10 -2
  65. package/lib/module/components/pictograms/Pictogram.js.map +1 -1
  66. package/lib/module/components/pictograms/svg/PictogramFingerprint.js +41 -0
  67. package/lib/module/components/pictograms/svg/PictogramFingerprint.js.map +1 -0
  68. package/lib/module/components/pictograms/svg/PictogramSmile.js +24 -0
  69. package/lib/module/components/pictograms/svg/PictogramSmile.js.map +1 -0
  70. package/lib/module/components/pictograms/svg/PictogramWalletDoc.js +38 -0
  71. package/lib/module/components/pictograms/svg/PictogramWalletDoc.js.map +1 -0
  72. package/lib/module/components/pictograms/svg/originals/PictogramFingerprint.svg +1 -0
  73. package/lib/module/components/pictograms/svg/originals/PictogramSmile.svg +1 -0
  74. package/lib/module/components/pictograms/svg/originals/PictogramWalletDoc.svg +1 -0
  75. package/lib/module/core/IOColors.js +11 -4
  76. package/lib/module/core/IOColors.js.map +1 -1
  77. package/lib/module/core/IOSpacing.js +9 -0
  78. package/lib/module/core/IOSpacing.js.map +1 -1
  79. package/lib/module/core/index.js +0 -1
  80. package/lib/module/core/index.js.map +1 -1
  81. package/lib/typescript/components/contentWrapper/ContentWrapper.d.ts +4 -3
  82. package/lib/typescript/components/contentWrapper/ContentWrapper.d.ts.map +1 -1
  83. package/lib/typescript/components/layout/BlockButtons.d.ts +1 -1
  84. package/lib/typescript/components/layout/FooterActions.d.ts +45 -0
  85. package/lib/typescript/components/layout/FooterActions.d.ts.map +1 -0
  86. package/lib/typescript/components/layout/FooterActionsInline.d.ts +17 -0
  87. package/lib/typescript/components/layout/FooterActionsInline.d.ts.map +1 -0
  88. package/lib/typescript/components/layout/FooterWithButtons.d.ts +3 -1
  89. package/lib/typescript/components/layout/FooterWithButtons.d.ts.map +1 -1
  90. package/lib/typescript/components/layout/HeaderFirstLevel.d.ts +7 -7
  91. package/lib/typescript/components/layout/HeaderFirstLevel.d.ts.map +1 -1
  92. package/lib/typescript/components/layout/HeaderSecondLevel.d.ts +7 -7
  93. package/lib/typescript/components/layout/HeaderSecondLevel.d.ts.map +1 -1
  94. package/lib/typescript/components/layout/common.d.ts +1 -1
  95. package/lib/typescript/components/layout/common.d.ts.map +1 -1
  96. package/lib/typescript/components/layout/hooks/index.d.ts +3 -0
  97. package/lib/typescript/components/layout/hooks/index.d.ts.map +1 -0
  98. package/lib/typescript/components/layout/hooks/useBottomMargins.d.ts +5 -0
  99. package/lib/typescript/components/layout/hooks/useBottomMargins.d.ts.map +1 -0
  100. package/lib/typescript/components/layout/hooks/useFooterActionsInlineMeasurements.d.ts +17 -0
  101. package/lib/typescript/components/layout/hooks/useFooterActionsInlineMeasurements.d.ts.map +1 -0
  102. package/lib/typescript/components/layout/hooks/useFooterActionsMeasurements.d.ts +17 -0
  103. package/lib/typescript/components/layout/hooks/useFooterActionsMeasurements.d.ts.map +1 -0
  104. package/lib/typescript/components/layout/index.d.ts +3 -0
  105. package/lib/typescript/components/layout/index.d.ts.map +1 -1
  106. package/lib/typescript/components/listitems/ListItemTransaction.d.ts.map +1 -1
  107. package/lib/typescript/components/pictograms/Pictogram.d.ts +3 -0
  108. package/lib/typescript/components/pictograms/Pictogram.d.ts.map +1 -1
  109. package/lib/typescript/components/pictograms/svg/PictogramFingerprint.d.ts +5 -0
  110. package/lib/typescript/components/pictograms/svg/PictogramFingerprint.d.ts.map +1 -0
  111. package/lib/typescript/components/pictograms/svg/PictogramSmile.d.ts +5 -0
  112. package/lib/typescript/components/pictograms/svg/PictogramSmile.d.ts.map +1 -0
  113. package/lib/typescript/components/pictograms/svg/PictogramWalletDoc.d.ts +5 -0
  114. package/lib/typescript/components/pictograms/svg/PictogramWalletDoc.d.ts.map +1 -0
  115. package/lib/typescript/core/IOColors.d.ts +1 -1
  116. package/lib/typescript/core/IOColors.d.ts.map +1 -1
  117. package/lib/typescript/core/IOSpacing.d.ts +8 -0
  118. package/lib/typescript/core/IOSpacing.d.ts.map +1 -1
  119. package/lib/typescript/core/index.d.ts +0 -1
  120. package/lib/typescript/core/index.d.ts.map +1 -1
  121. package/lib/typescript/utils/fonts.d.ts +2 -2
  122. package/package.json +1 -1
  123. package/src/components/contentWrapper/ContentWrapper.tsx +5 -2
  124. package/src/components/layout/BlockButtons.tsx +1 -1
  125. package/src/components/layout/FooterActions.tsx +260 -0
  126. package/src/components/layout/FooterActionsInline.tsx +137 -0
  127. package/src/components/layout/FooterWithButtons.tsx +3 -1
  128. package/src/components/layout/HeaderFirstLevel.tsx +7 -7
  129. package/src/components/layout/HeaderSecondLevel.tsx +20 -12
  130. package/src/components/layout/common.ts +1 -1
  131. package/src/components/layout/hooks/index.ts +2 -0
  132. package/src/components/layout/hooks/useBottomMargins.ts +30 -0
  133. package/src/components/layout/hooks/useFooterActionsInlineMeasurements.ts +38 -0
  134. package/src/components/layout/hooks/useFooterActionsMeasurements.ts +35 -0
  135. package/src/components/layout/index.tsx +3 -0
  136. package/src/components/listitems/ListItemTransaction.tsx +5 -2
  137. package/src/components/pictograms/Pictogram.tsx +11 -2
  138. package/src/components/pictograms/svg/PictogramFingerprint.tsx +50 -0
  139. package/src/components/pictograms/svg/PictogramSmile.tsx +22 -0
  140. package/src/components/pictograms/svg/PictogramWalletDoc.tsx +44 -0
  141. package/src/components/pictograms/svg/originals/PictogramFingerprint.svg +1 -0
  142. package/src/components/pictograms/svg/originals/PictogramSmile.svg +1 -0
  143. package/src/components/pictograms/svg/originals/PictogramWalletDoc.svg +1 -0
  144. package/src/core/IOColors.ts +13 -2
  145. package/src/core/IOSpacing.ts +14 -0
  146. package/src/core/index.ts +0 -1
  147. package/lib/commonjs/core/IOStyleVariables.js +0 -14
  148. package/lib/commonjs/core/IOStyleVariables.js.map +0 -1
  149. package/lib/module/core/IOStyleVariables.js +0 -7
  150. package/lib/module/core/IOStyleVariables.js.map +0 -1
  151. package/lib/typescript/core/IOStyleVariables.d.ts +0 -7
  152. package/lib/typescript/core/IOStyleVariables.d.ts.map +0 -1
  153. package/src/core/IOStyleVariables.ts +0 -6
@@ -0,0 +1,260 @@
1
+ import * as React from "react";
2
+ import { ComponentProps, Fragment, PropsWithChildren, useState } from "react";
3
+ import {
4
+ ColorValue,
5
+ LayoutChangeEvent,
6
+ LayoutRectangle,
7
+ StyleSheet,
8
+ Text,
9
+ View,
10
+ ViewStyle
11
+ } from "react-native";
12
+ import Animated from "react-native-reanimated";
13
+ import {
14
+ IOColors,
15
+ IOSpacer,
16
+ IOSpacing,
17
+ IOVisualCostants,
18
+ buttonSolidHeight,
19
+ hexToRgba,
20
+ useIOExperimentalDesign,
21
+ useIOTheme
22
+ } from "../../core";
23
+ import { WithTestID } from "../../utils/types";
24
+ import { ButtonLink, ButtonOutline, ButtonSolid } from "../buttons";
25
+ import { VSpacer } from "../spacer";
26
+ import { useBottomMargins } from "./hooks/useBottomMargins";
27
+
28
+ type FooterSingleButton = {
29
+ type: "SingleButton";
30
+ primary: Omit<ComponentProps<typeof ButtonSolid>, "fullWidth">;
31
+ secondary?: never;
32
+ tertiary?: never;
33
+ };
34
+
35
+ type FooterTwoButtons = {
36
+ type: "TwoButtons";
37
+ primary: Omit<ComponentProps<typeof ButtonSolid>, "fullWidth">;
38
+ secondary: Omit<ComponentProps<typeof ButtonLink>, "color">;
39
+ tertiary?: never;
40
+ };
41
+
42
+ type FooterThreeButtons = {
43
+ type: "ThreeButtons";
44
+ primary: Omit<ComponentProps<typeof ButtonSolid>, "fullWidth">;
45
+ secondary: Omit<ComponentProps<typeof ButtonOutline>, "fullWidth" | "color">;
46
+ tertiary: Omit<ComponentProps<typeof ButtonLink>, "color">;
47
+ };
48
+
49
+ export type FooterActionsMeasurements = {
50
+ // Height of the "Actions" block
51
+ actionBlockHeight: number;
52
+ /* Height of the safe bottom area. It includes:
53
+ - Margin between screen content
54
+ and actions (contentEndMargin)
55
+ - Actions block height
56
+ - Eventual safe area margin (bottomMargin)
57
+ This is the total bottom padding that needs
58
+ to be applied to the ScrollView.
59
+ */
60
+ safeBottomAreaHeight: number;
61
+ };
62
+
63
+ type FooterActions = FooterSingleButton | FooterTwoButtons | FooterThreeButtons;
64
+
65
+ type FooterAnimatedStyles = {
66
+ /* Apply object returned by `useAnimatedStyle` to the main block */
67
+ mainBlock?: Animated.AnimateStyle<ViewStyle>;
68
+ /* Apply object returned by `useAnimatedStyle` to the background */
69
+ background?: Animated.AnimateStyle<ViewStyle>;
70
+ };
71
+
72
+ type FooterActionsProps = WithTestID<
73
+ PropsWithChildren<{
74
+ actions?: FooterActions;
75
+ onMeasure?: (measurements: FooterActionsMeasurements) => void;
76
+ animatedStyles?: FooterAnimatedStyles;
77
+ /* Make the background transparent */
78
+ transparent?: boolean;
79
+ /* Don't include safe area insets */
80
+ excludeSafeAreaMargins?: boolean;
81
+ /* Fixed at the bottom of the screen */
82
+ fixed?: boolean;
83
+ /* Show the following elements:
84
+ - Opaque red background to show the component boundaries
85
+ - Height of the component */
86
+ debugMode?: boolean;
87
+ }>
88
+ >;
89
+
90
+ /* Margin between ButtonSolid and ButtonOutline */
91
+ const spaceBetweenActions: IOSpacer = 16;
92
+ /* Margin between ButtonSolid and ButtonLink */
93
+ const spaceBetweenActionAndLink: IOSpacer = 16;
94
+
95
+ const styles = StyleSheet.create({
96
+ buttonContainer: {
97
+ paddingHorizontal: IOVisualCostants.appMarginDefault,
98
+ width: "100%",
99
+ flexShrink: 0
100
+ },
101
+ debugText: {
102
+ position: "absolute",
103
+ right: 8,
104
+ top: -16,
105
+ color: IOColors.black,
106
+ fontSize: 9,
107
+ opacity: 0.75
108
+ },
109
+ blockShadow: {
110
+ shadowColor: IOColors.black,
111
+ shadowOffset: {
112
+ width: 0,
113
+ height: -4
114
+ },
115
+ shadowOpacity: 0.1,
116
+ shadowRadius: 32
117
+ }
118
+ });
119
+
120
+ export const FooterActions = ({
121
+ actions,
122
+ excludeSafeAreaMargins = false,
123
+ animatedStyles,
124
+ fixed = true,
125
+ transparent = false,
126
+ onMeasure,
127
+ testID,
128
+ debugMode = false
129
+ }: FooterActionsProps) => {
130
+ const theme = useIOTheme();
131
+ const { isExperimental } = useIOExperimentalDesign();
132
+
133
+ const { bottomMargin, extraBottomMargin } = useBottomMargins(
134
+ !!actions?.secondary,
135
+ excludeSafeAreaMargins
136
+ );
137
+
138
+ /* Total height of actions */
139
+ const [actionBlockHeight, setActionBlockHeight] =
140
+ useState<LayoutRectangle["height"]>(0);
141
+
142
+ /* Background color should be app main background
143
+ (both light and dark themes) */
144
+ const HEADER_BG_COLOR: ColorValue = IOColors[theme["appBackground-primary"]];
145
+ const TRANSPARENT_BG_COLOR: ColorValue = "transparent";
146
+ const BUTTONSOLID_HEIGHT = isExperimental ? buttonSolidHeight : 40;
147
+
148
+ /* Safe background block. Cover everything until it reaches
149
+ the half of the primary action button. It avoids
150
+ glitchy behavior underneath. */
151
+ const safeBackgroundBlockHeight =
152
+ bottomMargin + actionBlockHeight - BUTTONSOLID_HEIGHT / 2;
153
+
154
+ const getActionBlockMeasurements = (event: LayoutChangeEvent) => {
155
+ const { height } = event.nativeEvent.layout;
156
+ setActionBlockHeight(height);
157
+ /* Height of the safe bottom area, applied to the ScrollView:
158
+ Actions + Content end margin */
159
+ const safeBottomAreaHeight =
160
+ bottomMargin + height + IOSpacing.screenEndMargin;
161
+ onMeasure?.({ actionBlockHeight: height, safeBottomAreaHeight });
162
+ };
163
+
164
+ return (
165
+ <Animated.View
166
+ style={[
167
+ {
168
+ width: "100%",
169
+ paddingBottom: bottomMargin
170
+ },
171
+ fixed
172
+ ? { position: "absolute", bottom: 0 }
173
+ : { marginTop: IOSpacing.screenEndMargin },
174
+ debugMode && {
175
+ backgroundColor: hexToRgba(IOColors["error-500"], 0.15)
176
+ },
177
+ animatedStyles?.mainBlock
178
+ ]}
179
+ testID={testID}
180
+ >
181
+ {/* Safe background block. It's added because when you swipe up
182
+ quickly, the content below is visible for about 100ms. Without this
183
+ block, the content scrolls underneath. */}
184
+ <Animated.View
185
+ style={[
186
+ {
187
+ ...(fixed && {
188
+ width: "100%",
189
+ height: safeBackgroundBlockHeight,
190
+ position: "absolute",
191
+ bottom: 0,
192
+ backgroundColor: transparent
193
+ ? TRANSPARENT_BG_COLOR
194
+ : HEADER_BG_COLOR
195
+ }),
196
+ ...(fixed ? styles.blockShadow : null)
197
+ },
198
+ animatedStyles?.background
199
+ ]}
200
+ pointerEvents="none"
201
+ />
202
+
203
+ <View
204
+ style={styles.buttonContainer}
205
+ onLayout={getActionBlockMeasurements}
206
+ pointerEvents="box-none"
207
+ >
208
+ {debugMode && (
209
+ <Text style={styles.debugText}>{`Height: ${actionBlockHeight}`}</Text>
210
+ )}
211
+
212
+ {renderActions(actions, extraBottomMargin)}
213
+ </View>
214
+ </Animated.View>
215
+ );
216
+ };
217
+
218
+ const renderActions = (
219
+ actions: FooterActions | undefined,
220
+ extraBottomMargin: number
221
+ ) => {
222
+ if (!actions) {
223
+ return null;
224
+ }
225
+ const {
226
+ type,
227
+ primary: primaryAction,
228
+ secondary: secondaryAction,
229
+ tertiary: tertiaryAction
230
+ } = actions;
231
+ return (
232
+ <Fragment>
233
+ {primaryAction && <ButtonSolid fullWidth {...primaryAction} />}
234
+ {type === "TwoButtons" && secondaryAction && (
235
+ <View style={{ alignSelf: "center", marginBottom: extraBottomMargin }}>
236
+ <VSpacer size={spaceBetweenActionAndLink} />
237
+ <ButtonLink color="primary" {...secondaryAction} />
238
+ </View>
239
+ )}
240
+ {type === "ThreeButtons" && (
241
+ <>
242
+ {secondaryAction && (
243
+ <>
244
+ <VSpacer size={spaceBetweenActions} />
245
+ <ButtonOutline fullWidth color="primary" {...secondaryAction} />
246
+ </>
247
+ )}
248
+ {tertiaryAction && (
249
+ <View
250
+ style={{ alignSelf: "center", marginBottom: extraBottomMargin }}
251
+ >
252
+ <VSpacer size={spaceBetweenActionAndLink} />
253
+ <ButtonLink color="primary" {...tertiaryAction} />
254
+ </View>
255
+ )}
256
+ </>
257
+ )}
258
+ </Fragment>
259
+ );
260
+ };
@@ -0,0 +1,137 @@
1
+ import * as React from "react";
2
+ import { ComponentProps, PropsWithChildren } from "react";
3
+ import { ColorValue, LayoutChangeEvent, StyleSheet, View } from "react-native";
4
+ import {
5
+ IOColors,
6
+ IOSpacer,
7
+ IOSpacing,
8
+ IOSpacingScale,
9
+ IOVisualCostants,
10
+ useIOTheme,
11
+ useIOThemeContext
12
+ } from "../../core";
13
+ import { WithTestID } from "../../utils/types";
14
+ import { ButtonOutline, ButtonSolid } from "../buttons";
15
+ import { HSpacer } from "../spacer";
16
+ import { useBottomMargins } from "./hooks/useBottomMargins";
17
+
18
+ export type FooterActionsInlineMeasurements = {
19
+ /* Height of the safe bottom area. It includes:
20
+ - Margin between screen content
21
+ and actions (contentEndMargin)
22
+ - Actions block height
23
+ - Eventual safe area margin (bottomMargin)
24
+ This is the total bottom padding that needs
25
+ to be applied to the ScrollView.
26
+ */
27
+ safeBottomAreaHeight: number;
28
+ };
29
+
30
+ type FooterActionsInline = WithTestID<
31
+ PropsWithChildren<{
32
+ startAction: Omit<ComponentProps<typeof ButtonOutline>, "fullWidth">;
33
+ endAction: Omit<ComponentProps<typeof ButtonSolid>, "fullWidth">;
34
+ onMeasure?: (measurements: FooterActionsInlineMeasurements) => void;
35
+ /* Don't include safe area insets */
36
+ excludeSafeAreaMargins?: boolean;
37
+ /* Fixed at the bottom of the screen */
38
+ fixed?: boolean;
39
+ }>
40
+ >;
41
+
42
+ /* Margin between ButtonSolid and ButtonOutline */
43
+ const spaceBetweenActions: IOSpacer = 16;
44
+
45
+ const styles = StyleSheet.create({
46
+ buttonContainer: {
47
+ paddingHorizontal: IOVisualCostants.appMarginDefault,
48
+ width: "100%",
49
+ flexShrink: 0
50
+ },
51
+ buttonWrapper: {
52
+ flex: 1
53
+ },
54
+ blockShadow: {
55
+ shadowColor: IOColors.black,
56
+ shadowOffset: {
57
+ width: 0,
58
+ height: -4
59
+ },
60
+ shadowOpacity: 0.1,
61
+ shadowRadius: 32,
62
+ elevation: 10 // Prop supported on Android only
63
+ }
64
+ });
65
+
66
+ export const FooterActionsInline = ({
67
+ startAction,
68
+ endAction,
69
+ excludeSafeAreaMargins = false,
70
+ fixed = true,
71
+ onMeasure,
72
+ testID
73
+ }: FooterActionsInline) => {
74
+ const theme = useIOTheme();
75
+ const { themeType } = useIOThemeContext();
76
+
77
+ const { bottomMargin } = useBottomMargins(false, excludeSafeAreaMargins);
78
+
79
+ /* Top padding applied above the actions */
80
+ const topSpacingValue: IOSpacingScale = 16;
81
+ const topSpacing = fixed ? topSpacingValue : 0;
82
+
83
+ /* Background color should be app main background
84
+ (both light and dark themes) */
85
+ const HEADER_BG_COLOR: ColorValue = IOColors[theme["appBackground-primary"]];
86
+
87
+ const getActionBlockMeasurements = (event: LayoutChangeEvent) => {
88
+ const { height } = event.nativeEvent.layout;
89
+ /* Height of the safe bottom area, applied to the ScrollView:
90
+ Actions + Screen end margin */
91
+ const safeBottomAreaHeight =
92
+ bottomMargin + height + IOSpacing.screenEndMargin;
93
+ onMeasure?.({ safeBottomAreaHeight });
94
+ };
95
+
96
+ return (
97
+ <View
98
+ style={[
99
+ {
100
+ width: "100%",
101
+ paddingBottom: bottomMargin
102
+ },
103
+ fixed
104
+ ? {
105
+ position: "absolute",
106
+ bottom: 0,
107
+ backgroundColor: HEADER_BG_COLOR
108
+ }
109
+ : { marginTop: IOSpacing.screenEndMargin },
110
+ /* Apply shadow only on light theme OR if fixed */
111
+ fixed || themeType === "light" ? styles.blockShadow : {},
112
+ /* Apply bottom border only on dark theme */
113
+ themeType === "dark" && {
114
+ borderTopColor: IOColors[theme["divider-bottomBar"]],
115
+ borderTopWidth: 1
116
+ }
117
+ ]}
118
+ testID={testID}
119
+ >
120
+ <View
121
+ style={[styles.buttonContainer, { paddingTop: topSpacing }]}
122
+ onLayout={getActionBlockMeasurements}
123
+ pointerEvents="box-none"
124
+ >
125
+ <View style={{ flexDirection: "row" }}>
126
+ <View style={styles.buttonWrapper}>
127
+ <ButtonOutline fullWidth {...startAction} />
128
+ </View>
129
+ <HSpacer size={spaceBetweenActions} />
130
+ <View style={styles.buttonWrapper}>
131
+ <ButtonSolid fullWidth {...endAction} />
132
+ </View>
133
+ </View>
134
+ </View>
135
+ </View>
136
+ );
137
+ };
@@ -44,7 +44,9 @@ const verticalSpacing: IOSpacingScale = 16;
44
44
  /**
45
45
  * Implements a component that show buttons as sticky footer
46
46
  * It can include 1, 2 or 3 buttons. If they are 2, they can have the inlineHalf or the inlineOneThird style
47
- * @deprecated This component is deprecated. Use `FooterActions` in the main `io-app` repo instead.
47
+ * @deprecated This component is deprecated. Use `FooterActions` or `FooterActionsInline` instead.
48
+ * `FooterActionsInline` is the official replacement for `FooterWithButtons`, but use it only
49
+ * if explicitly required.
48
50
  */
49
51
  export const FooterWithButtons = ({
50
52
  sticky = false,
@@ -23,7 +23,7 @@ import { WithTestID } from "../../utils/types";
23
23
  import { IconButton } from "../buttons";
24
24
  import { HSpacer } from "../spacer";
25
25
  import { H3 } from "../typography";
26
- import { ActionProp } from "./common";
26
+ import { HeaderActionProps } from "./common";
27
27
 
28
28
  type CommonProps = WithTestID<{
29
29
  title: string;
@@ -41,23 +41,23 @@ interface Base extends CommonProps {
41
41
 
42
42
  interface OneAction extends CommonProps {
43
43
  type: "singleAction";
44
- firstAction: ActionProp;
44
+ firstAction: HeaderActionProps;
45
45
  secondAction?: never;
46
46
  thirdAction?: never;
47
47
  }
48
48
 
49
49
  interface TwoActions extends CommonProps {
50
50
  type: "twoActions";
51
- firstAction: ActionProp;
52
- secondAction: ActionProp;
51
+ firstAction: HeaderActionProps;
52
+ secondAction: HeaderActionProps;
53
53
  thirdAction?: never;
54
54
  }
55
55
 
56
56
  interface ThreeActions extends CommonProps {
57
57
  type: "threeActions";
58
- firstAction: ActionProp;
59
- secondAction: ActionProp;
60
- thirdAction: ActionProp;
58
+ firstAction: HeaderActionProps;
59
+ secondAction: HeaderActionProps;
60
+ thirdAction: HeaderActionProps;
61
61
  }
62
62
 
63
63
  export type HeaderFirstLevel = Base | OneAction | TwoActions | ThreeActions;
@@ -30,14 +30,15 @@ import {
30
30
  hexToRgba,
31
31
  iconBtnSizeSmall,
32
32
  useIOExperimentalDesign,
33
- useIOTheme
33
+ useIOTheme,
34
+ useIOThemeContext
34
35
  } from "../../core";
35
36
  import type { IOSpacer, IOSpacingScale } from "../../core/IOSpacing";
36
37
  import { WithTestID } from "../../utils/types";
37
38
  import IconButton from "../buttons/IconButton";
38
39
  import { HSpacer } from "../spacer";
39
40
  import { IOText } from "../typography";
40
- import { ActionProp } from "./common";
41
+ import { HeaderActionProps } from "./common";
41
42
 
42
43
  type ScrollValues = {
43
44
  contentOffsetY: SharedValue<number>;
@@ -85,23 +86,23 @@ interface Base extends CommonProps {
85
86
 
86
87
  interface OneAction extends CommonProps {
87
88
  type: "singleAction";
88
- firstAction: ActionProp;
89
+ firstAction: HeaderActionProps;
89
90
  secondAction?: never;
90
91
  thirdAction?: never;
91
92
  }
92
93
 
93
94
  interface TwoActions extends CommonProps {
94
95
  type: "twoActions";
95
- firstAction: ActionProp;
96
- secondAction: ActionProp;
96
+ firstAction: HeaderActionProps;
97
+ secondAction: HeaderActionProps;
97
98
  thirdAction?: never;
98
99
  }
99
100
 
100
101
  interface ThreeActions extends CommonProps {
101
102
  type: "threeActions";
102
- firstAction: ActionProp;
103
- secondAction: ActionProp;
104
- thirdAction: ActionProp;
103
+ firstAction: HeaderActionProps;
104
+ secondAction: HeaderActionProps;
105
+ thirdAction: HeaderActionProps;
105
106
  }
106
107
 
107
108
  export type HeaderSecondLevel = BackProps &
@@ -156,21 +157,26 @@ export const HeaderSecondLevel = ({
156
157
 
157
158
  const { isExperimental } = useIOExperimentalDesign();
158
159
  const theme = useIOTheme();
160
+ const { themeType } = useIOThemeContext();
159
161
  const insets = useSafeAreaInsets();
160
162
  const isTitleAccessible = React.useMemo(() => !!title.trim(), [title]);
161
163
  const paddingTop = useSharedValue(ignoreSafeAreaMargin ? 0 : insets.top);
162
164
 
163
165
  const AnimatedIOText = Animated.createAnimatedComponent(IOText);
164
166
 
167
+ const iconButtonColorDefault: ComponentProps<typeof IconButton>["color"] =
168
+ themeType === "dark" ? "contrast" : "neutral";
169
+
165
170
  const iconButtonColor: ComponentProps<typeof IconButton>["color"] =
166
- variant === "neutral" ? "neutral" : "contrast";
171
+ variant === "contrast" ? "contrast" : iconButtonColorDefault;
172
+
167
173
  const titleColor: ColorValue =
168
174
  variant === "neutral"
169
175
  ? IOColors[theme["textHeading-default"]]
170
176
  : IOColors.white;
171
177
 
172
178
  /* Visual attributes when there are transitions between states */
173
- const HEADER_DEFAULT_BG_COLOR: IOColors = "white";
179
+ const HEADER_DEFAULT_BG_COLOR: IOColors = theme["appBackground-primary"];
174
180
 
175
181
  const headerBgColorTransparentState = backgroundColor
176
182
  ? hexToRgba(backgroundColor, 0)
@@ -181,10 +187,12 @@ export const HeaderSecondLevel = ({
181
187
  const headerBgColorSolidState =
182
188
  backgroundColor ?? IOColors[HEADER_DEFAULT_BG_COLOR];
183
189
 
190
+ const borderColorDefault = IOColors[theme["divider-default"]];
191
+
184
192
  const borderColorTransparentState = backgroundColor
185
193
  ? hexToRgba(backgroundColor, 0)
186
- : hexToRgba(IOColors["grey-100"], 0);
187
- const borderColorSolidState = backgroundColor ?? IOColors["grey-100"];
194
+ : hexToRgba(borderColorDefault, 0);
195
+ const borderColorSolidState = backgroundColor ?? borderColorDefault;
188
196
 
189
197
  useLayoutEffect(() => {
190
198
  if (isTitleAccessible) {
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
2
  import { IconButton } from "../buttons";
3
3
 
4
- export type ActionProp = Pick<
4
+ export type HeaderActionProps = Pick<
5
5
  React.ComponentProps<typeof IconButton>,
6
6
  "icon" | "onPress" | "accessibilityLabel" | "accessibilityHint" | "testID"
7
7
  >;
@@ -0,0 +1,2 @@
1
+ export * from "./useFooterActionsMeasurements";
2
+ export * from "./useFooterActionsInlineMeasurements";
@@ -0,0 +1,30 @@
1
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
2
+ import { IOSpacingScale, IOVisualCostants } from "../../../core";
3
+
4
+ /* Extra bottom margin for iPhone bottom handle because
5
+ ButtonLink doesn't have a fixed height */
6
+ const extraSafeAreaMargin: IOSpacingScale = 8;
7
+
8
+ export const useBottomMargins = (
9
+ withSecondaryAction: boolean = false,
10
+ excludeSafeAreaMargins: boolean = false
11
+ ) => {
12
+ const insets = useSafeAreaInsets();
13
+ const needSafeAreaMargin = insets.bottom !== 0;
14
+
15
+ /* Check if the iPhone bottom handle is present.
16
+ If not, or if you don't need safe area insets,
17
+ add a default margin to prevent the button
18
+ from sticking to the bottom. */
19
+ const bottomMargin =
20
+ !needSafeAreaMargin || excludeSafeAreaMargins
21
+ ? IOVisualCostants.appMarginDefault
22
+ : insets.bottom;
23
+
24
+ /* When the secondary action is visible, add extra margin
25
+ to avoid little space from iPhone bottom handle */
26
+ const extraBottomMargin =
27
+ withSecondaryAction && needSafeAreaMargin ? extraSafeAreaMargin : 0;
28
+
29
+ return { bottomMargin, extraBottomMargin };
30
+ };
@@ -0,0 +1,38 @@
1
+ import { useState } from "react";
2
+ import { FooterActionsInlineMeasurements } from "../FooterActionsInline";
3
+
4
+ type UseFooterActionsInlineMeasurementsProps = {
5
+ footerActionsInlineMeasurements: FooterActionsInlineMeasurements;
6
+ handleFooterActionsInlineMeasurements: (
7
+ values: FooterActionsInlineMeasurements
8
+ ) => void;
9
+ };
10
+ /**
11
+ * Custom hook to handle the `FooterActions` measurements
12
+ * @returns
13
+ * - `footerActionsInlineMeasurements`
14
+ * Object containing the `FooterActionsInline` measurements
15
+ * - `handleFooterActionsInlineMeasurements`
16
+ * Function to update the footer actions measurements
17
+ * (to be applied to `onMeasure` prop of `FooterActionsInline`)
18
+ */
19
+ export const useFooterActionsInlineMeasurements =
20
+ (): UseFooterActionsInlineMeasurementsProps => {
21
+ const [
22
+ footerActionsInlineMeasurements,
23
+ setFooterActionsInlineMeasurements
24
+ ] = useState<FooterActionsInlineMeasurements>({
25
+ safeBottomAreaHeight: 0
26
+ });
27
+
28
+ const handleFooterActionsInlineMeasurements = (
29
+ values: FooterActionsInlineMeasurements
30
+ ) => {
31
+ setFooterActionsInlineMeasurements(values);
32
+ };
33
+
34
+ return {
35
+ footerActionsInlineMeasurements,
36
+ handleFooterActionsInlineMeasurements
37
+ };
38
+ };
@@ -0,0 +1,35 @@
1
+ import { useState } from "react";
2
+ import { FooterActionsMeasurements } from "../FooterActions";
3
+
4
+ type UseFooterActionsMeasurementsProps = {
5
+ footerActionsMeasurements: FooterActionsMeasurements;
6
+ handleFooterActionsMeasurements: (values: FooterActionsMeasurements) => void;
7
+ };
8
+ /**
9
+ * Custom hook to handle the `FooterActions` measurements
10
+ * @returns
11
+ * - `footerActionsMeasurements`
12
+ * Object containing the `FooterActions` measurements
13
+ * - `handleFooterActionsMeasurements`
14
+ * Function to update the footer actions measurements
15
+ * (to be applied to `onMeasure` prop of `FooterActions`)
16
+ */
17
+ export const useFooterActionsMeasurements =
18
+ (): UseFooterActionsMeasurementsProps => {
19
+ const [footerActionsMeasurements, setFooterActionsMeasurements] =
20
+ useState<FooterActionsMeasurements>({
21
+ actionBlockHeight: 0,
22
+ safeBottomAreaHeight: 0
23
+ });
24
+
25
+ const handleFooterActionsMeasurements = (
26
+ values: FooterActionsMeasurements
27
+ ) => {
28
+ setFooterActionsMeasurements(values);
29
+ };
30
+
31
+ return {
32
+ footerActionsMeasurements,
33
+ handleFooterActionsMeasurements
34
+ };
35
+ };
@@ -1,4 +1,6 @@
1
1
  export * from "./BlockButtons";
2
+ export * from "./FooterActions";
3
+ export * from "./FooterActionsInline";
2
4
  export * from "./FooterWithButtons";
3
5
  export * from "./ForceScrollDownView";
4
6
  export * from "./GradientBottomActions";
@@ -7,3 +9,4 @@ export * from "./HeaderFirstLevel";
7
9
  export * from "./HeaderSecondLevel";
8
10
  export * from "./ModalBSHeader";
9
11
  export * from "./common";
12
+ export * from "./hooks";