@pagopa/io-app-design-system 4.4.8 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/components/alert/Alert.js.map +1 -1
- package/lib/commonjs/components/listitems/ListItemInfo.js +47 -13
- package/lib/commonjs/components/listitems/ListItemInfo.js.map +1 -1
- package/lib/commonjs/components/listitems/PressableListItemBase.js.map +1 -1
- package/lib/commonjs/components/modules/PressableModuleBase.js +10 -2
- package/lib/commonjs/components/modules/PressableModuleBase.js.map +1 -1
- package/lib/commonjs/components/textInput/TextInputBase.js +18 -15
- package/lib/commonjs/components/textInput/TextInputBase.js.map +1 -1
- package/lib/commonjs/components/textInput/TextInputValidation.js +8 -6
- package/lib/commonjs/components/textInput/TextInputValidation.js.map +1 -1
- package/lib/commonjs/core/IOColors.js +15 -2
- package/lib/commonjs/core/IOColors.js.map +1 -1
- package/lib/commonjs/core/IOThemeContextProvider.js +12 -7
- package/lib/commonjs/core/IOThemeContextProvider.js.map +1 -1
- package/lib/module/components/alert/Alert.js.map +1 -1
- package/lib/module/components/listitems/ListItemInfo.js +48 -15
- package/lib/module/components/listitems/ListItemInfo.js.map +1 -1
- package/lib/module/components/listitems/PressableListItemBase.js.map +1 -1
- package/lib/module/components/modules/PressableModuleBase.js +10 -2
- package/lib/module/components/modules/PressableModuleBase.js.map +1 -1
- package/lib/module/components/textInput/TextInputBase.js +19 -16
- package/lib/module/components/textInput/TextInputBase.js.map +1 -1
- package/lib/module/components/textInput/TextInputValidation.js +8 -6
- package/lib/module/components/textInput/TextInputValidation.js.map +1 -1
- package/lib/module/core/IOColors.js +15 -2
- package/lib/module/core/IOColors.js.map +1 -1
- package/lib/module/core/IOThemeContextProvider.js +14 -8
- package/lib/module/core/IOThemeContextProvider.js.map +1 -1
- package/lib/typescript/components/alert/Alert.d.ts.map +1 -1
- package/lib/typescript/components/listitems/ListItemInfo.d.ts +13 -11
- package/lib/typescript/components/listitems/ListItemInfo.d.ts.map +1 -1
- package/lib/typescript/components/listitems/PressableListItemBase.d.ts +2 -2
- package/lib/typescript/components/listitems/PressableListItemBase.d.ts.map +1 -1
- package/lib/typescript/components/modules/PressableModuleBase.d.ts.map +1 -1
- package/lib/typescript/components/textInput/TextInputBase.d.ts +2 -2
- package/lib/typescript/components/textInput/TextInputBase.d.ts.map +1 -1
- package/lib/typescript/components/textInput/TextInputValidation.d.ts.map +1 -1
- package/lib/typescript/components/tooltip/styles.d.ts +2 -2
- package/lib/typescript/core/IOColors.d.ts +1 -1
- package/lib/typescript/core/IOColors.d.ts.map +1 -1
- package/lib/typescript/core/IOStyles.d.ts +2 -2
- package/lib/typescript/core/IOThemeContextProvider.d.ts +6 -6
- package/lib/typescript/core/IOThemeContextProvider.d.ts.map +1 -1
- package/lib/typescript/utils/fonts.d.ts +1 -1
- package/package.json +3 -3
- package/src/components/alert/Alert.tsx +3 -2
- package/src/components/listitems/ListItemInfo.tsx +107 -53
- package/src/components/listitems/PressableListItemBase.tsx +3 -2
- package/src/components/modules/PressableModuleBase.tsx +15 -4
- package/src/components/textInput/TextInputBase.tsx +28 -16
- package/src/components/textInput/TextInputValidation.tsx +18 -10
- package/src/core/IOColors.ts +18 -0
- package/src/core/IOThemeContextProvider.tsx +27 -15
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import React, { ComponentProps, useCallback, useMemo } from "react";
|
|
2
|
-
import { AccessibilityRole, Platform, View } from "react-native";
|
|
1
|
+
import React, { ComponentProps, ReactNode, useCallback, useMemo } from "react";
|
|
2
|
+
import { AccessibilityRole, Platform, Pressable, View } from "react-native";
|
|
3
|
+
import Animated from "react-native-reanimated";
|
|
3
4
|
import {
|
|
4
5
|
IOListItemStyles,
|
|
5
6
|
IOListItemVisualParams,
|
|
6
7
|
IOStyles,
|
|
7
8
|
useIOTheme
|
|
8
9
|
} from "../../core";
|
|
10
|
+
import { useListItemAnimation } from "../../hooks";
|
|
9
11
|
import { useIOFontDynamicScale } from "../../utils/accessibility";
|
|
10
12
|
import { WithTestID } from "../../utils/types";
|
|
11
13
|
import { Badge } from "../badge";
|
|
@@ -13,7 +15,7 @@ import { ButtonLink, IconButton } from "../buttons";
|
|
|
13
15
|
import { LogoPaymentWithFallback } from "../common/LogoPaymentWithFallback";
|
|
14
16
|
import { IOIconSizeScale, IOIcons, Icon } from "../icons";
|
|
15
17
|
import { IOLogoPaymentType } from "../logos";
|
|
16
|
-
import {
|
|
18
|
+
import { BodySmall, H6 } from "../typography";
|
|
17
19
|
|
|
18
20
|
type ButtonLinkActionProps = {
|
|
19
21
|
type: "buttonLink";
|
|
@@ -35,25 +37,32 @@ type EndElementProps =
|
|
|
35
37
|
| IconButtonActionProps
|
|
36
38
|
| BadgeProps;
|
|
37
39
|
|
|
40
|
+
type GraphicProps =
|
|
41
|
+
| {
|
|
42
|
+
paymentLogoIcon?: IOLogoPaymentType;
|
|
43
|
+
icon?: never;
|
|
44
|
+
}
|
|
45
|
+
| {
|
|
46
|
+
paymentLogoIcon?: never;
|
|
47
|
+
icon?: IOIcons;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
type InteractiveProps = Pick<
|
|
51
|
+
ComponentProps<typeof Pressable>,
|
|
52
|
+
"onLongPress" | "accessibilityActions" | "onAccessibilityAction"
|
|
53
|
+
>;
|
|
54
|
+
|
|
38
55
|
export type ListItemInfo = WithTestID<{
|
|
39
56
|
label: string;
|
|
40
|
-
value: string |
|
|
57
|
+
value: string | ReactNode;
|
|
41
58
|
numberOfLines?: number;
|
|
42
59
|
endElement?: EndElementProps;
|
|
43
60
|
// Accessibility
|
|
44
61
|
accessibilityLabel?: string;
|
|
45
62
|
accessibilityRole?: AccessibilityRole;
|
|
46
63
|
}> &
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
paymentLogoIcon?: IOLogoPaymentType;
|
|
50
|
-
icon?: never;
|
|
51
|
-
}
|
|
52
|
-
| {
|
|
53
|
-
icon?: IOIcons;
|
|
54
|
-
paymentLogoIcon?: never;
|
|
55
|
-
}
|
|
56
|
-
);
|
|
64
|
+
GraphicProps &
|
|
65
|
+
InteractiveProps;
|
|
57
66
|
|
|
58
67
|
const PAYMENT_LOGO_SIZE: IOIconSizeScale = 24;
|
|
59
68
|
|
|
@@ -66,22 +75,25 @@ export const ListItemInfo = ({
|
|
|
66
75
|
endElement,
|
|
67
76
|
accessibilityLabel,
|
|
68
77
|
accessibilityRole,
|
|
78
|
+
accessibilityActions,
|
|
79
|
+
onAccessibilityAction,
|
|
80
|
+
onLongPress,
|
|
69
81
|
testID
|
|
70
82
|
}: ListItemInfo) => {
|
|
71
83
|
const theme = useIOTheme();
|
|
72
84
|
const { dynamicFontScale, spacingScaleMultiplier, hugeFontEnabled } =
|
|
73
85
|
useIOFontDynamicScale();
|
|
74
86
|
|
|
87
|
+
const { onPressIn, onPressOut, scaleAnimatedStyle, backgroundAnimatedStyle } =
|
|
88
|
+
useListItemAnimation();
|
|
89
|
+
|
|
75
90
|
const componentValueToAccessibility = useMemo(
|
|
76
91
|
() => (typeof value === "string" ? value : ""),
|
|
77
92
|
[value]
|
|
78
93
|
);
|
|
79
94
|
|
|
80
95
|
const listItemAccessibilityLabel = useMemo(
|
|
81
|
-
() =>
|
|
82
|
-
accessibilityLabel
|
|
83
|
-
? accessibilityLabel
|
|
84
|
-
: `${label}; ${componentValueToAccessibility}`,
|
|
96
|
+
() => accessibilityLabel ?? `${label}; ${componentValueToAccessibility}`,
|
|
85
97
|
[label, componentValueToAccessibility, accessibilityLabel]
|
|
86
98
|
);
|
|
87
99
|
|
|
@@ -136,44 +148,86 @@ export const ListItemInfo = ({
|
|
|
136
148
|
return <></>;
|
|
137
149
|
}, [endElement]);
|
|
138
150
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
151
|
+
const ListItemInfoContent = () => (
|
|
152
|
+
<>
|
|
153
|
+
{icon && !hugeFontEnabled && (
|
|
154
|
+
<Icon
|
|
155
|
+
allowFontScaling
|
|
156
|
+
name={icon}
|
|
157
|
+
color="grey-450"
|
|
158
|
+
size={IOListItemVisualParams.iconSize}
|
|
159
|
+
/>
|
|
160
|
+
)}
|
|
161
|
+
{paymentLogoIcon && (
|
|
162
|
+
<LogoPaymentWithFallback
|
|
163
|
+
brand={paymentLogoIcon}
|
|
164
|
+
size={PAYMENT_LOGO_SIZE}
|
|
165
|
+
/>
|
|
166
|
+
)}
|
|
167
|
+
<View style={IOStyles.flex}>{itemInfoTextComponent}</View>
|
|
168
|
+
{endElement && <View>{listItemInfoAction()}</View>}
|
|
169
|
+
</>
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
if (onLongPress) {
|
|
173
|
+
return (
|
|
174
|
+
<Pressable
|
|
175
|
+
onLongPress={onLongPress}
|
|
176
|
+
testID={testID}
|
|
177
|
+
accessible={!endElement}
|
|
178
|
+
onPressIn={onPressIn}
|
|
179
|
+
onPressOut={onPressOut}
|
|
180
|
+
onTouchEnd={onPressOut}
|
|
181
|
+
accessibilityRole={"button"}
|
|
182
|
+
accessibilityLabel={listItemAccessibilityLabel}
|
|
183
|
+
accessibilityActions={accessibilityActions}
|
|
184
|
+
onAccessibilityAction={onAccessibilityAction}
|
|
185
|
+
>
|
|
186
|
+
<Animated.View
|
|
187
|
+
style={[IOListItemStyles.listItem, backgroundAnimatedStyle]}
|
|
188
|
+
>
|
|
189
|
+
<Animated.View
|
|
190
|
+
style={[
|
|
191
|
+
IOListItemStyles.listItemInner,
|
|
192
|
+
{
|
|
193
|
+
columnGap:
|
|
194
|
+
IOListItemVisualParams.iconMargin *
|
|
195
|
+
dynamicFontScale *
|
|
196
|
+
spacingScaleMultiplier
|
|
197
|
+
},
|
|
198
|
+
scaleAnimatedStyle
|
|
199
|
+
]}
|
|
200
|
+
>
|
|
201
|
+
<ListItemInfoContent />
|
|
202
|
+
</Animated.View>
|
|
203
|
+
</Animated.View>
|
|
204
|
+
</Pressable>
|
|
205
|
+
);
|
|
206
|
+
} else {
|
|
207
|
+
return (
|
|
147
208
|
<View
|
|
148
|
-
style={
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
dynamicFontScale *
|
|
154
|
-
spacingScaleMultiplier
|
|
155
|
-
}
|
|
156
|
-
]}
|
|
209
|
+
style={IOListItemStyles.listItem}
|
|
210
|
+
testID={testID}
|
|
211
|
+
accessible={!endElement}
|
|
212
|
+
accessibilityLabel={listItemAccessibilityLabel}
|
|
213
|
+
accessibilityRole={accessibilityRole}
|
|
157
214
|
>
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
)}
|
|
172
|
-
<View style={IOStyles.flex}>{itemInfoTextComponent}</View>
|
|
173
|
-
{endElement && <View>{listItemInfoAction()}</View>}
|
|
215
|
+
<View
|
|
216
|
+
style={[
|
|
217
|
+
IOListItemStyles.listItemInner,
|
|
218
|
+
{
|
|
219
|
+
columnGap:
|
|
220
|
+
IOListItemVisualParams.iconMargin *
|
|
221
|
+
dynamicFontScale *
|
|
222
|
+
spacingScaleMultiplier
|
|
223
|
+
}
|
|
224
|
+
]}
|
|
225
|
+
>
|
|
226
|
+
<ListItemInfoContent />
|
|
227
|
+
</View>
|
|
174
228
|
</View>
|
|
175
|
-
|
|
176
|
-
|
|
229
|
+
);
|
|
230
|
+
}
|
|
177
231
|
};
|
|
178
232
|
|
|
179
233
|
export default ListItemInfo;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { PropsWithChildren } from "react";
|
|
2
|
+
import { ComponentProps, PropsWithChildren } from "react";
|
|
3
3
|
import { Pressable } from "react-native";
|
|
4
4
|
import Animated from "react-native-reanimated";
|
|
5
5
|
import { IOListItemStyles, IOListItemVisualParams } from "../../core";
|
|
@@ -8,7 +8,7 @@ import { useListItemAnimation } from "../../hooks";
|
|
|
8
8
|
|
|
9
9
|
export type PressableBaseProps = WithTestID<
|
|
10
10
|
Pick<
|
|
11
|
-
|
|
11
|
+
ComponentProps<typeof Pressable>,
|
|
12
12
|
| "onPress"
|
|
13
13
|
| "accessibilityLabel"
|
|
14
14
|
| "accessibilityHint"
|
|
@@ -26,6 +26,7 @@ export const PressableListItemBase = ({
|
|
|
26
26
|
}: PropsWithChildren<PressableBaseProps>) => {
|
|
27
27
|
const { onPressIn, onPressOut, scaleAnimatedStyle, backgroundAnimatedStyle } =
|
|
28
28
|
useListItemAnimation();
|
|
29
|
+
|
|
29
30
|
return (
|
|
30
31
|
<Pressable
|
|
31
32
|
onPress={onPress}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { PropsWithChildren } from "react";
|
|
3
|
-
import { Pressable } from "react-native";
|
|
2
|
+
import { PropsWithChildren, useCallback } from "react";
|
|
3
|
+
import { GestureResponderEvent, Pressable } from "react-native";
|
|
4
|
+
import ReactNativeHapticFeedback from "react-native-haptic-feedback";
|
|
4
5
|
import Animated, { useReducedMotion } from "react-native-reanimated";
|
|
5
|
-
import { useScaleAnimation } from "../../hooks";
|
|
6
6
|
import {
|
|
7
7
|
IOColors,
|
|
8
8
|
IOModuleIDPSavedVSpacing,
|
|
9
9
|
IOModuleStyles,
|
|
10
10
|
useIOTheme
|
|
11
11
|
} from "../../core";
|
|
12
|
+
import { useScaleAnimation } from "../../hooks";
|
|
12
13
|
import { WithTestID } from "../../utils/types";
|
|
13
14
|
|
|
14
15
|
export type PressableModuleBaseProps = WithTestID<
|
|
@@ -39,9 +40,19 @@ export const PressableModuleBase = ({
|
|
|
39
40
|
If we remove it, they they won't be able to understand
|
|
40
41
|
if there's an ongoing interaction. */
|
|
41
42
|
|
|
43
|
+
const handleOnPress = useCallback(
|
|
44
|
+
(event: GestureResponderEvent) => {
|
|
45
|
+
if (onPress) {
|
|
46
|
+
ReactNativeHapticFeedback.trigger("impactLight");
|
|
47
|
+
onPress(event);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
[onPress]
|
|
51
|
+
);
|
|
52
|
+
|
|
42
53
|
return (
|
|
43
54
|
<Pressable
|
|
44
|
-
onPress={
|
|
55
|
+
onPress={handleOnPress}
|
|
45
56
|
testID={testID}
|
|
46
57
|
accessible={true}
|
|
47
58
|
onPressIn={onPressIn}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
/* eslint-disable functional/immutable-data */
|
|
2
|
-
import React, {
|
|
2
|
+
import React, {
|
|
3
|
+
ReactNode,
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState
|
|
9
|
+
} from "react";
|
|
3
10
|
import {
|
|
4
11
|
ColorValue,
|
|
5
12
|
LayoutChangeEvent,
|
|
@@ -46,7 +53,7 @@ type InputTextProps = WithTestID<{
|
|
|
46
53
|
inputType?: InputType;
|
|
47
54
|
status?: InputStatus;
|
|
48
55
|
icon?: IOIcons;
|
|
49
|
-
rightElement?:
|
|
56
|
+
rightElement?: ReactNode;
|
|
50
57
|
counterLimit?: number;
|
|
51
58
|
bottomMessage?: string;
|
|
52
59
|
bottomMessageColor?: IOColors;
|
|
@@ -67,12 +74,8 @@ const inputLabelScaleFactor: number = 0.75; /* 16pt becomes 12pt */
|
|
|
67
74
|
const inputLabelFontSize: IOFontSize = 16;
|
|
68
75
|
const inputDisabledOpacity: number = 0.5;
|
|
69
76
|
const inputRightElementMargin: IOSpacingScale = 8;
|
|
70
|
-
const iconColor: IOColors = "grey-300";
|
|
71
77
|
const iconSize: IOIconSizeScale = 24;
|
|
72
78
|
const iconMargin: IOSpacingScale = 8;
|
|
73
|
-
const inputLabelColor: ColorValue = IOColors["grey-700"];
|
|
74
|
-
const inputTextColor: ColorValue = IOColors.black;
|
|
75
|
-
const inputDisabledTextColor: ColorValue = IOColors["grey-850"];
|
|
76
79
|
|
|
77
80
|
const styles = StyleSheet.create({
|
|
78
81
|
textInput: {
|
|
@@ -126,11 +129,9 @@ const styles = StyleSheet.create({
|
|
|
126
129
|
justifyContent: "center"
|
|
127
130
|
},
|
|
128
131
|
textInputLabel: {
|
|
129
|
-
color: inputLabelColor,
|
|
130
132
|
...makeFontStyleObject(inputLabelFontSize, "Titillio", undefined, "Regular")
|
|
131
133
|
},
|
|
132
134
|
textInputLabelLegacyFont: {
|
|
133
|
-
color: inputLabelColor,
|
|
134
135
|
...makeFontStyleObject(
|
|
135
136
|
inputLabelFontSize,
|
|
136
137
|
"TitilliumSansPro",
|
|
@@ -149,10 +150,15 @@ const HelperRow = ({
|
|
|
149
150
|
value,
|
|
150
151
|
counterLimit,
|
|
151
152
|
bottomMessage,
|
|
152
|
-
bottomMessageColor
|
|
153
|
+
bottomMessageColor
|
|
153
154
|
}: InputTextHelperRow) => {
|
|
155
|
+
const theme = useIOTheme();
|
|
154
156
|
const valueCount = useMemo(() => value.length, [value]);
|
|
155
157
|
|
|
158
|
+
const bottomMessageColorDefault: IOColors = theme["textBody-tertiary"];
|
|
159
|
+
const bottomMessageColorValue =
|
|
160
|
+
bottomMessageColor ?? bottomMessageColorDefault;
|
|
161
|
+
|
|
156
162
|
const helperRowStyle: ViewStyle = useMemo(() => {
|
|
157
163
|
if (counterLimit && bottomMessage) {
|
|
158
164
|
return {
|
|
@@ -189,14 +195,14 @@ const HelperRow = ({
|
|
|
189
195
|
}
|
|
190
196
|
>
|
|
191
197
|
{bottomMessage && (
|
|
192
|
-
<BodySmall weight="Regular" color={
|
|
198
|
+
<BodySmall weight="Regular" color={bottomMessageColorValue}>
|
|
193
199
|
{bottomMessage}
|
|
194
200
|
</BodySmall>
|
|
195
201
|
)}
|
|
196
202
|
{counterLimit && (
|
|
197
203
|
<BodySmall
|
|
198
204
|
weight="Regular"
|
|
199
|
-
color=
|
|
205
|
+
color={bottomMessageColorValue}
|
|
200
206
|
>{`${valueCount} / ${counterLimit}`}</BodySmall>
|
|
201
207
|
)}
|
|
202
208
|
</View>
|
|
@@ -226,7 +232,7 @@ export const TextInputBase = ({
|
|
|
226
232
|
}: InputTextProps) => {
|
|
227
233
|
const inputRef = useRef<TextInput>(null);
|
|
228
234
|
const isSecretInput = useMemo(() => isPassword, [isPassword]);
|
|
229
|
-
const [inputStatus, setInputStatus] =
|
|
235
|
+
const [inputStatus, setInputStatus] = useState<InputStatus>(
|
|
230
236
|
disabled ? "disabled" : "initial"
|
|
231
237
|
);
|
|
232
238
|
const focusedState = useSharedValue<number>(0);
|
|
@@ -234,9 +240,14 @@ export const TextInputBase = ({
|
|
|
234
240
|
const { dynamicFontScale, spacingScaleMultiplier } = useIOFontDynamicScale();
|
|
235
241
|
|
|
236
242
|
const theme = useIOTheme();
|
|
243
|
+
const iconColor: IOColors = theme["icon-decorative"];
|
|
244
|
+
const inputLabelColor: ColorValue = IOColors[theme["textInputLabel-default"]];
|
|
245
|
+
const inputTextColor: ColorValue = IOColors[theme["textInputValue-default"]];
|
|
246
|
+
const inputDisabledTextColor: ColorValue =
|
|
247
|
+
IOColors[theme["textInputValue-disabled"]];
|
|
237
248
|
|
|
238
249
|
/* Get the label width to enable the correct translation */
|
|
239
|
-
const [labelWidth, setLabelWidth] =
|
|
250
|
+
const [labelWidth, setLabelWidth] = useState<number>(0);
|
|
240
251
|
|
|
241
252
|
const getLabelWidth = ({ nativeEvent }: LayoutChangeEvent) => {
|
|
242
253
|
setLabelWidth(nativeEvent.layout.width);
|
|
@@ -255,10 +266,10 @@ export const TextInputBase = ({
|
|
|
255
266
|
|
|
256
267
|
const borderColorMap: Record<InputStatus, string> = useMemo(
|
|
257
268
|
() => ({
|
|
258
|
-
initial: IOColors["
|
|
259
|
-
disabled: IOColors["
|
|
269
|
+
initial: IOColors[theme["textInputBorder-default"]],
|
|
270
|
+
disabled: IOColors[theme["textInputBorder-default"]],
|
|
260
271
|
focused: IOColors[theme["interactiveElem-default"]],
|
|
261
|
-
error: IOColors[
|
|
272
|
+
error: IOColors[theme.errorText]
|
|
262
273
|
}),
|
|
263
274
|
[theme]
|
|
264
275
|
);
|
|
@@ -467,6 +478,7 @@ export const TextInputBase = ({
|
|
|
467
478
|
isExperimental
|
|
468
479
|
? styles.textInputLabel
|
|
469
480
|
: styles.textInputLabelLegacyFont,
|
|
481
|
+
{ color: inputLabelColor },
|
|
470
482
|
animatedLabelStyle
|
|
471
483
|
]}
|
|
472
484
|
>
|
|
@@ -2,6 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import { useCallback, useMemo, useState } from "react";
|
|
3
3
|
import { AccessibilityInfo, View } from "react-native";
|
|
4
4
|
import Animated from "react-native-reanimated";
|
|
5
|
+
import { useIOTheme } from "../../core";
|
|
5
6
|
import { IOColors } from "../../core/IOColors";
|
|
6
7
|
import {
|
|
7
8
|
enterTransitionInputIcon,
|
|
@@ -18,8 +19,8 @@ type TextInputValidationProps = Omit<
|
|
|
18
19
|
"rightElement" | "status" | "bottomMessageColor" | "isPassword"
|
|
19
20
|
> & {
|
|
20
21
|
/**
|
|
21
|
-
* This function can return either a `boolean` or a `ValidationWithOptions` object.
|
|
22
|
-
* If a `boolean` is returned and the field is not valid, the value of the errorMessage prop will be displayed/announced.
|
|
22
|
+
* This function can return either a `boolean` or a `ValidationWithOptions` object.
|
|
23
|
+
* If a `boolean` is returned and the field is not valid, the value of the errorMessage prop will be displayed/announced.
|
|
23
24
|
* If a `ValidationWithOptions` object is returned and the field is not valid, the value displayed/announced will be the one contained within this object.
|
|
24
25
|
*/
|
|
25
26
|
onValidate: (value: string) => boolean | ValidationWithOptions;
|
|
@@ -29,8 +30,14 @@ type TextInputValidationProps = Omit<
|
|
|
29
30
|
errorMessage: string;
|
|
30
31
|
};
|
|
31
32
|
|
|
32
|
-
function isValidationWithOptions(
|
|
33
|
-
|
|
33
|
+
function isValidationWithOptions(
|
|
34
|
+
validation: boolean | ValidationWithOptions
|
|
35
|
+
): validation is ValidationWithOptions {
|
|
36
|
+
return (
|
|
37
|
+
typeof validation === "object" &&
|
|
38
|
+
"isValid" in validation &&
|
|
39
|
+
"errorMessage" in validation
|
|
40
|
+
);
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
const feedbackIconSize: IOIconSizeScale = 24;
|
|
@@ -44,6 +51,7 @@ export const TextInputValidation = ({
|
|
|
44
51
|
onFocus,
|
|
45
52
|
...props
|
|
46
53
|
}: TextInputValidationProps) => {
|
|
54
|
+
const theme = useIOTheme();
|
|
47
55
|
const [isValid, setIsValid] = useState<boolean | undefined>(undefined);
|
|
48
56
|
const [errMessage, setErrMessage] = useState(errorMessage);
|
|
49
57
|
|
|
@@ -78,13 +86,13 @@ export const TextInputValidation = ({
|
|
|
78
86
|
}, [onFocus]);
|
|
79
87
|
|
|
80
88
|
const labelError = useMemo(
|
|
81
|
-
() => (isValid
|
|
89
|
+
() => (!isValid && errMessage ? errMessage : bottomMessage),
|
|
82
90
|
[isValid, errMessage, bottomMessage]
|
|
83
91
|
);
|
|
84
92
|
|
|
85
93
|
const labelErrorColor: IOColors | undefined = useMemo(
|
|
86
|
-
() => (isValid
|
|
87
|
-
[isValid, errMessage]
|
|
94
|
+
() => (!isValid && errMessage ? theme.errorText : undefined),
|
|
95
|
+
[isValid, errMessage, theme.errorText]
|
|
88
96
|
);
|
|
89
97
|
|
|
90
98
|
const feedbackIconAttrMap: Record<
|
|
@@ -94,14 +102,14 @@ export const TextInputValidation = ({
|
|
|
94
102
|
() => ({
|
|
95
103
|
valid: {
|
|
96
104
|
name: "success",
|
|
97
|
-
color:
|
|
105
|
+
color: theme.successIcon
|
|
98
106
|
},
|
|
99
107
|
notValid: {
|
|
100
108
|
name: "errorFilled",
|
|
101
|
-
color:
|
|
109
|
+
color: theme.errorIcon
|
|
102
110
|
}
|
|
103
111
|
}),
|
|
104
|
-
[]
|
|
112
|
+
[theme]
|
|
105
113
|
);
|
|
106
114
|
|
|
107
115
|
const feedbackIcon = useMemo(() => {
|
package/src/core/IOColors.ts
CHANGED
|
@@ -276,12 +276,19 @@ const themeKeys = [
|
|
|
276
276
|
"textBody-tertiary",
|
|
277
277
|
// Design System related
|
|
278
278
|
"cardBorder-default",
|
|
279
|
+
"textInputBorder-default",
|
|
279
280
|
"icon-default",
|
|
280
281
|
"icon-decorative",
|
|
282
|
+
// Inputs
|
|
283
|
+
"textInputBorder-default",
|
|
284
|
+
"textInputLabel-default",
|
|
285
|
+
"textInputValue-default",
|
|
286
|
+
"textInputValue-disabled",
|
|
281
287
|
// Layout
|
|
282
288
|
"divider-header",
|
|
283
289
|
"divider-default",
|
|
284
290
|
"divider-bottomBar",
|
|
291
|
+
"pdfViewer-background",
|
|
285
292
|
// Status
|
|
286
293
|
"errorIcon",
|
|
287
294
|
"errorText",
|
|
@@ -320,10 +327,16 @@ export const IOThemeLight: IOTheme = {
|
|
|
320
327
|
"cardBorder-default": "grey-100",
|
|
321
328
|
"icon-default": "grey-650",
|
|
322
329
|
"icon-decorative": "grey-300",
|
|
330
|
+
// Inputs
|
|
331
|
+
"textInputBorder-default": "grey-200",
|
|
332
|
+
"textInputLabel-default": "grey-700",
|
|
333
|
+
"textInputValue-default": "black",
|
|
334
|
+
"textInputValue-disabled": "grey-850",
|
|
323
335
|
// Layout
|
|
324
336
|
"divider-header": "grey-100",
|
|
325
337
|
"divider-default": "grey-200",
|
|
326
338
|
"divider-bottomBar": "grey-200",
|
|
339
|
+
"pdfViewer-background": "grey-700",
|
|
327
340
|
// Status
|
|
328
341
|
errorIcon: "error-600",
|
|
329
342
|
errorText: "error-600",
|
|
@@ -365,6 +378,11 @@ export const IOThemeDark: IOTheme = {
|
|
|
365
378
|
"cardBorder-default": "grey-850",
|
|
366
379
|
"icon-default": "grey-450",
|
|
367
380
|
"icon-decorative": "grey-650",
|
|
381
|
+
// Inputs
|
|
382
|
+
"textInputBorder-default": "grey-850",
|
|
383
|
+
"textInputLabel-default": "grey-450",
|
|
384
|
+
"textInputValue-default": "white",
|
|
385
|
+
"textInputValue-disabled": "grey-100",
|
|
368
386
|
// Layout
|
|
369
387
|
"divider-header": "grey-850",
|
|
370
388
|
"divider-default": "grey-850",
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
PropsWithChildren,
|
|
4
|
+
useCallback,
|
|
5
|
+
useContext,
|
|
6
|
+
useMemo,
|
|
7
|
+
useState
|
|
8
|
+
} from "react";
|
|
9
|
+
import { Appearance, ColorSchemeName } from "react-native";
|
|
3
10
|
import {
|
|
4
11
|
IOTheme,
|
|
5
12
|
IOThemeDark,
|
|
@@ -10,39 +17,44 @@ import { useIOExperimentalDesign } from "./IODSExperimentalContextProvider";
|
|
|
10
17
|
|
|
11
18
|
export const IOThemes = { light: IOThemeLight, dark: IOThemeDark };
|
|
12
19
|
export const legacyIOThemes = { light: IOThemeLightLegacy, dark: IOThemeDark };
|
|
13
|
-
type IOThemeType = keyof typeof IOThemes;
|
|
20
|
+
// type IOThemeType = keyof typeof IOThemes | null;
|
|
14
21
|
|
|
15
22
|
type IOThemeContextType = {
|
|
16
|
-
themeType:
|
|
23
|
+
themeType: ColorSchemeName;
|
|
17
24
|
theme: IOTheme;
|
|
18
|
-
setTheme: (theme:
|
|
25
|
+
setTheme: (theme: ColorSchemeName) => void;
|
|
19
26
|
};
|
|
20
27
|
|
|
21
28
|
export const IOThemeContext: React.Context<IOThemeContextType> =
|
|
22
|
-
|
|
23
|
-
themeType: Appearance.getColorScheme()
|
|
29
|
+
createContext<IOThemeContextType>({
|
|
30
|
+
themeType: Appearance.getColorScheme(),
|
|
24
31
|
theme:
|
|
25
32
|
Appearance.getColorScheme() === "dark" ? IOThemes.dark : IOThemes.light,
|
|
26
|
-
setTheme: () =>
|
|
33
|
+
setTheme: (theme: ColorSchemeName) => Appearance.setColorScheme(theme)
|
|
27
34
|
});
|
|
28
35
|
|
|
29
|
-
export const useIOThemeContext = () =>
|
|
36
|
+
export const useIOThemeContext = () => useContext(IOThemeContext);
|
|
30
37
|
|
|
31
38
|
export const useIOTheme = () => useIOThemeContext().theme;
|
|
32
39
|
|
|
33
40
|
type IOThemeContextProviderProps = {
|
|
34
|
-
theme?:
|
|
41
|
+
theme?: ColorSchemeName;
|
|
35
42
|
};
|
|
36
43
|
|
|
37
44
|
export const IOThemeContextProvider = ({
|
|
38
45
|
children,
|
|
39
46
|
theme
|
|
40
|
-
}:
|
|
41
|
-
const [currentTheme, setCurrentTheme] =
|
|
42
|
-
theme ??
|
|
47
|
+
}: PropsWithChildren<IOThemeContextProviderProps>) => {
|
|
48
|
+
const [currentTheme, setCurrentTheme] = useState<ColorSchemeName>(
|
|
49
|
+
theme ?? Appearance.getColorScheme()
|
|
43
50
|
);
|
|
44
51
|
const { isExperimental } = useIOExperimentalDesign();
|
|
45
52
|
|
|
53
|
+
const handleThemeChange = useCallback((newTheme: ColorSchemeName) => {
|
|
54
|
+
setCurrentTheme(newTheme);
|
|
55
|
+
Appearance.setColorScheme(newTheme);
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
46
58
|
const themeMap = useMemo(
|
|
47
59
|
() => (isExperimental ? IOThemes : legacyIOThemes),
|
|
48
60
|
[isExperimental]
|
|
@@ -52,8 +64,8 @@ export const IOThemeContextProvider = ({
|
|
|
52
64
|
<IOThemeContext.Provider
|
|
53
65
|
value={{
|
|
54
66
|
themeType: currentTheme,
|
|
55
|
-
theme: themeMap[currentTheme],
|
|
56
|
-
setTheme:
|
|
67
|
+
theme: themeMap[currentTheme ?? "light"],
|
|
68
|
+
setTheme: handleThemeChange
|
|
57
69
|
}}
|
|
58
70
|
>
|
|
59
71
|
{children}
|