@pagopa/io-app-design-system 1.22.0 → 1.23.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/avatar/Avatar.js +21 -8
- package/lib/commonjs/components/avatar/Avatar.js.map +1 -1
- package/lib/commonjs/components/layout/HeaderSecondLevel.js +2 -0
- package/lib/commonjs/components/layout/HeaderSecondLevel.js.map +1 -1
- package/lib/commonjs/components/listitems/ListItemHeader.js +2 -1
- package/lib/commonjs/components/listitems/ListItemHeader.js.map +1 -1
- package/lib/commonjs/components/listitems/ListItemNav.js +13 -3
- package/lib/commonjs/components/listitems/ListItemNav.js.map +1 -1
- package/lib/commonjs/components/modules/ModuleAttachment.js +196 -0
- package/lib/commonjs/components/modules/ModuleAttachment.js.map +1 -0
- package/lib/commonjs/components/modules/index.js +11 -0
- package/lib/commonjs/components/modules/index.js.map +1 -1
- package/lib/module/components/avatar/Avatar.js +22 -8
- package/lib/module/components/avatar/Avatar.js.map +1 -1
- package/lib/module/components/layout/HeaderSecondLevel.js +2 -0
- package/lib/module/components/layout/HeaderSecondLevel.js.map +1 -1
- package/lib/module/components/listitems/ListItemHeader.js +2 -1
- package/lib/module/components/listitems/ListItemHeader.js.map +1 -1
- package/lib/module/components/listitems/ListItemNav.js +13 -3
- package/lib/module/components/listitems/ListItemNav.js.map +1 -1
- package/lib/module/components/modules/ModuleAttachment.js +186 -0
- package/lib/module/components/modules/ModuleAttachment.js.map +1 -0
- package/lib/module/components/modules/index.js +1 -0
- package/lib/module/components/modules/index.js.map +1 -1
- package/lib/typescript/components/avatar/Avatar.d.ts +9 -1
- package/lib/typescript/components/avatar/Avatar.d.ts.map +1 -1
- package/lib/typescript/components/layout/HeaderSecondLevel.d.ts.map +1 -1
- package/lib/typescript/components/listitems/ListItemHeader.d.ts.map +1 -1
- package/lib/typescript/components/listitems/ListItemNav.d.ts +2 -1
- package/lib/typescript/components/listitems/ListItemNav.d.ts.map +1 -1
- package/lib/typescript/components/modules/ModuleAttachment.d.ts +32 -0
- package/lib/typescript/components/modules/ModuleAttachment.d.ts.map +1 -0
- package/lib/typescript/components/modules/index.d.ts +1 -0
- package/lib/typescript/components/modules/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/avatar/Avatar.tsx +31 -13
- package/src/components/layout/HeaderSecondLevel.tsx +2 -0
- package/src/components/listitems/ListItemHeader.tsx +4 -1
- package/src/components/listitems/ListItemNav.tsx +15 -3
- package/src/components/modules/ModuleAttachment.tsx +254 -0
- package/src/components/modules/index.tsx +1 -0
|
@@ -143,6 +143,7 @@ export const HeaderSecondLevel = ({
|
|
|
143
143
|
: "transparent"
|
|
144
144
|
}));
|
|
145
145
|
|
|
146
|
+
const isTitleAccessible = !!title.trim();
|
|
146
147
|
const titleAnimatedStyle = useAnimatedStyle(() => ({
|
|
147
148
|
opacity: scrollValues
|
|
148
149
|
? interpolate(
|
|
@@ -183,6 +184,7 @@ export const HeaderSecondLevel = ({
|
|
|
183
184
|
)}
|
|
184
185
|
<Animated.Text
|
|
185
186
|
numberOfLines={1}
|
|
187
|
+
accessible={isTitleAccessible}
|
|
186
188
|
style={[
|
|
187
189
|
styles.headerTitle,
|
|
188
190
|
isExperimental
|
|
@@ -125,7 +125,10 @@ export const ListItemHeader = ({
|
|
|
125
125
|
accessible={endElement === undefined ? true : false}
|
|
126
126
|
accessibilityLabel={listItemAccessibilityLabel}
|
|
127
127
|
>
|
|
128
|
-
<View
|
|
128
|
+
<View
|
|
129
|
+
style={IOListItemStyles.listItemInner}
|
|
130
|
+
importantForAccessibility={endElement ? "auto" : "no-hide-descendants"}
|
|
131
|
+
>
|
|
129
132
|
{iconName && (
|
|
130
133
|
<View style={{ marginRight: iconMargin }}>
|
|
131
134
|
<Icon
|
|
@@ -26,6 +26,7 @@ import { IOIcons, Icon } from "../icons";
|
|
|
26
26
|
import { IOLogoPaymentType, LogoPayment } from "../logos";
|
|
27
27
|
import { HSpacer, VSpacer } from "../spacer";
|
|
28
28
|
import { Caption, H6, LabelSmall } from "../typography";
|
|
29
|
+
import { LoadingSpinner } from "../loadingSpinner";
|
|
29
30
|
|
|
30
31
|
type ListItemTopElementProps =
|
|
31
32
|
| {
|
|
@@ -40,6 +41,7 @@ type ListItemTopElementProps =
|
|
|
40
41
|
type ListItemNavPartialProps = WithTestID<{
|
|
41
42
|
value: string | React.ReactNode;
|
|
42
43
|
description?: string | React.ReactNode;
|
|
44
|
+
loading?: boolean;
|
|
43
45
|
onPress: (event: GestureResponderEvent) => void;
|
|
44
46
|
// Accessibility
|
|
45
47
|
accessibilityLabel: string;
|
|
@@ -64,7 +66,8 @@ export const ListItemNav = ({
|
|
|
64
66
|
accessibilityLabel,
|
|
65
67
|
testID,
|
|
66
68
|
hideChevron = false,
|
|
67
|
-
topElement
|
|
69
|
+
topElement,
|
|
70
|
+
loading
|
|
68
71
|
}: ListItemNav) => {
|
|
69
72
|
const isPressed = useSharedValue(0);
|
|
70
73
|
const { isExperimental } = useIOExperimentalDesign();
|
|
@@ -167,9 +170,17 @@ export const ListItemNav = ({
|
|
|
167
170
|
isPressed.value = 0;
|
|
168
171
|
}, [isPressed]);
|
|
169
172
|
|
|
173
|
+
const handleOnPress = (event: GestureResponderEvent) => {
|
|
174
|
+
if (!loading) {
|
|
175
|
+
onPress(event);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const primaryColor: IOColors = isExperimental ? "blueIO-500" : "blue";
|
|
180
|
+
|
|
170
181
|
return (
|
|
171
182
|
<Pressable
|
|
172
|
-
onPress={
|
|
183
|
+
onPress={handleOnPress}
|
|
173
184
|
onPressIn={handlePressIn}
|
|
174
185
|
onPressOut={handlePressOut}
|
|
175
186
|
accessible={true}
|
|
@@ -201,7 +212,8 @@ export const ListItemNav = ({
|
|
|
201
212
|
</View>
|
|
202
213
|
)}
|
|
203
214
|
<View style={IOStyles.flex}>{listItemNavContent}</View>
|
|
204
|
-
{
|
|
215
|
+
{loading && <LoadingSpinner color={primaryColor} />}
|
|
216
|
+
{!loading && !hideChevron && (
|
|
205
217
|
<View style={{ marginLeft: IOListItemVisualParams.iconMargin }}>
|
|
206
218
|
<Icon
|
|
207
219
|
name="chevronRightListItem"
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import React, { useCallback } from "react";
|
|
2
|
+
import {
|
|
3
|
+
GestureResponderEvent,
|
|
4
|
+
Pressable,
|
|
5
|
+
PressableProps,
|
|
6
|
+
StyleSheet,
|
|
7
|
+
View
|
|
8
|
+
} from "react-native";
|
|
9
|
+
import Animated, {
|
|
10
|
+
Extrapolate,
|
|
11
|
+
interpolate,
|
|
12
|
+
useAnimatedStyle,
|
|
13
|
+
useDerivedValue,
|
|
14
|
+
useSharedValue,
|
|
15
|
+
withSpring
|
|
16
|
+
} from "react-native-reanimated";
|
|
17
|
+
import Placeholder from "rn-placeholder";
|
|
18
|
+
import {
|
|
19
|
+
IOColors,
|
|
20
|
+
IOListItemVisualParams,
|
|
21
|
+
IOScaleValues,
|
|
22
|
+
IOSpringValues,
|
|
23
|
+
useIOTheme
|
|
24
|
+
} from "../../core";
|
|
25
|
+
import { WithTestID } from "../../utils/types";
|
|
26
|
+
import { Icon } from "../icons";
|
|
27
|
+
import { LabelSmall } from "../typography";
|
|
28
|
+
import { VSpacer } from "../spacer";
|
|
29
|
+
import { Badge } from "../badge";
|
|
30
|
+
import { LoadingSpinner } from "../loadingSpinner";
|
|
31
|
+
|
|
32
|
+
type PartialProps = WithTestID<{
|
|
33
|
+
title: string;
|
|
34
|
+
format: "doc" | "pdf";
|
|
35
|
+
isLoading?: boolean;
|
|
36
|
+
loadingAccessibilityLabel?: string;
|
|
37
|
+
isFetching?: boolean;
|
|
38
|
+
fetchingAccessibilityLabel?: string;
|
|
39
|
+
onPress: (event: GestureResponderEvent) => void;
|
|
40
|
+
}>;
|
|
41
|
+
|
|
42
|
+
export type ModuleAttachmentProps = PartialProps &
|
|
43
|
+
Pick<
|
|
44
|
+
PressableProps,
|
|
45
|
+
"onPress" | "accessibilityLabel" | "disabled" | "testID"
|
|
46
|
+
>;
|
|
47
|
+
|
|
48
|
+
type SkeletonComponentProps = {
|
|
49
|
+
loadingAccessibilityLabel?: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const styles = StyleSheet.create({
|
|
53
|
+
button: {
|
|
54
|
+
flexDirection: "row",
|
|
55
|
+
alignItems: "center",
|
|
56
|
+
paddingHorizontal: 16,
|
|
57
|
+
paddingVertical: 16,
|
|
58
|
+
borderRadius: 8,
|
|
59
|
+
borderColor: IOColors.bluegreyLight,
|
|
60
|
+
backgroundColor: IOColors.white,
|
|
61
|
+
borderStyle: "solid",
|
|
62
|
+
borderWidth: 1
|
|
63
|
+
},
|
|
64
|
+
innerContent: {
|
|
65
|
+
flex: 1,
|
|
66
|
+
flexDirection: "column"
|
|
67
|
+
},
|
|
68
|
+
rightSection: {
|
|
69
|
+
marginLeft: IOListItemVisualParams.iconMargin,
|
|
70
|
+
alignItems: "center"
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const DISABLED_OPACITY = 0.5;
|
|
75
|
+
|
|
76
|
+
const ModuleAttachmentContent = ({
|
|
77
|
+
isFetching,
|
|
78
|
+
format,
|
|
79
|
+
title,
|
|
80
|
+
testID
|
|
81
|
+
}: Pick<
|
|
82
|
+
ModuleAttachmentProps,
|
|
83
|
+
"isFetching" | "format" | "title" | "testID"
|
|
84
|
+
>) => {
|
|
85
|
+
const theme = useIOTheme();
|
|
86
|
+
const IconOrActivityIndicatorComponent = () => {
|
|
87
|
+
if (isFetching) {
|
|
88
|
+
const activityIndicatorTestId = testID
|
|
89
|
+
? `${testID}_activityIndicator`
|
|
90
|
+
: undefined;
|
|
91
|
+
return <LoadingSpinner testID={activityIndicatorTestId} />;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<Icon
|
|
96
|
+
name="chevronRightListItem"
|
|
97
|
+
color={theme["interactiveElem-default"]}
|
|
98
|
+
size={IOListItemVisualParams.chevronSize}
|
|
99
|
+
/>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<>
|
|
105
|
+
<View style={styles.innerContent}>
|
|
106
|
+
<LabelSmall
|
|
107
|
+
numberOfLines={1}
|
|
108
|
+
weight="SemiBold"
|
|
109
|
+
font="ReadexPro"
|
|
110
|
+
color="blueIO-500"
|
|
111
|
+
>
|
|
112
|
+
{title}
|
|
113
|
+
</LabelSmall>
|
|
114
|
+
<VSpacer size={4} />
|
|
115
|
+
<View style={{ width: 44 }}>
|
|
116
|
+
<Badge text={format.toUpperCase()} variant="default" />
|
|
117
|
+
</View>
|
|
118
|
+
</View>
|
|
119
|
+
<View style={styles.rightSection}>
|
|
120
|
+
<IconOrActivityIndicatorComponent />
|
|
121
|
+
</View>
|
|
122
|
+
</>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The `ModuleAttachment` component is a custom button component with an extended outline style.
|
|
128
|
+
* It provides an animated scaling effect when pressed.
|
|
129
|
+
*
|
|
130
|
+
* @param {string} accessibilityLabel - Optional accessibility label.
|
|
131
|
+
* @param {boolean} disabled - If true, the button is disabled.
|
|
132
|
+
* @param {string} fetchingAccessibilityLabel - Optional accessibility label to use during fetching.
|
|
133
|
+
* @param {string} format - Badge content. PDF or DOC.
|
|
134
|
+
* @param {boolean} isLoading - If true, displays a skeleton loading component.
|
|
135
|
+
* @param {boolean} isFetching - If true, displays an activity indicator.
|
|
136
|
+
* @param {string} loadingAccessibilityLabel - Optional accessibility label to use during loading.
|
|
137
|
+
* @param {function} onPress - The function to be executed when the item is pressed.
|
|
138
|
+
* @param {string} testID - The test ID for testing purposes.
|
|
139
|
+
* @param {string} title - The title text to display.
|
|
140
|
+
*
|
|
141
|
+
*/
|
|
142
|
+
export const ModuleAttachment = ({
|
|
143
|
+
accessibilityLabel,
|
|
144
|
+
disabled = false,
|
|
145
|
+
fetchingAccessibilityLabel,
|
|
146
|
+
format,
|
|
147
|
+
isLoading = false,
|
|
148
|
+
isFetching = false,
|
|
149
|
+
loadingAccessibilityLabel,
|
|
150
|
+
onPress,
|
|
151
|
+
testID,
|
|
152
|
+
title
|
|
153
|
+
}: ModuleAttachmentProps) => {
|
|
154
|
+
const isPressed: Animated.SharedValue<number> = useSharedValue(0);
|
|
155
|
+
|
|
156
|
+
// Scaling transformation applied when the button is pressed
|
|
157
|
+
const animationScaleValue = IOScaleValues?.magnifiedButton?.pressedState;
|
|
158
|
+
|
|
159
|
+
const scaleTraversed = useDerivedValue(() =>
|
|
160
|
+
withSpring(isPressed.value, IOSpringValues.button)
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Interpolate animation values from `isPressed` values
|
|
164
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
165
|
+
const scale = interpolate(
|
|
166
|
+
scaleTraversed.value,
|
|
167
|
+
[0, 1],
|
|
168
|
+
[1, animationScaleValue],
|
|
169
|
+
Extrapolate.CLAMP
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
transform: [{ scale }]
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const onPressIn = useCallback(() => {
|
|
178
|
+
// eslint-disable-next-line functional/immutable-data
|
|
179
|
+
isPressed.value = 1;
|
|
180
|
+
}, [isPressed]);
|
|
181
|
+
|
|
182
|
+
const onPressOut = useCallback(() => {
|
|
183
|
+
// eslint-disable-next-line functional/immutable-data
|
|
184
|
+
isPressed.value = 0;
|
|
185
|
+
}, [isPressed]);
|
|
186
|
+
|
|
187
|
+
const handleOnPress = useCallback(
|
|
188
|
+
(event: GestureResponderEvent) => {
|
|
189
|
+
if (isFetching) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
onPress(event);
|
|
193
|
+
},
|
|
194
|
+
[isFetching, onPress]
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
if (isLoading) {
|
|
198
|
+
return (
|
|
199
|
+
<SkeletonComponent
|
|
200
|
+
loadingAccessibilityLabel={loadingAccessibilityLabel}
|
|
201
|
+
/>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const pressableAccessibilityLabel =
|
|
206
|
+
(isFetching && !!fetchingAccessibilityLabel
|
|
207
|
+
? fetchingAccessibilityLabel
|
|
208
|
+
: accessibilityLabel) ?? title;
|
|
209
|
+
return (
|
|
210
|
+
<Pressable
|
|
211
|
+
testID={testID}
|
|
212
|
+
onPress={handleOnPress}
|
|
213
|
+
onPressIn={onPressIn}
|
|
214
|
+
onPressOut={onPressOut}
|
|
215
|
+
accessible={true}
|
|
216
|
+
accessibilityRole={"button"}
|
|
217
|
+
accessibilityHint={format}
|
|
218
|
+
accessibilityLabel={pressableAccessibilityLabel}
|
|
219
|
+
disabled={disabled || isFetching}
|
|
220
|
+
>
|
|
221
|
+
<Animated.View
|
|
222
|
+
style={[
|
|
223
|
+
styles.button,
|
|
224
|
+
animatedStyle,
|
|
225
|
+
{ opacity: disabled ? DISABLED_OPACITY : 1 }
|
|
226
|
+
]}
|
|
227
|
+
accessibilityElementsHidden={true}
|
|
228
|
+
importantForAccessibility="no-hide-descendants"
|
|
229
|
+
>
|
|
230
|
+
<ModuleAttachmentContent
|
|
231
|
+
isFetching={isFetching}
|
|
232
|
+
title={title}
|
|
233
|
+
format={format}
|
|
234
|
+
/>
|
|
235
|
+
</Animated.View>
|
|
236
|
+
</Pressable>
|
|
237
|
+
);
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const SkeletonComponent = ({
|
|
241
|
+
loadingAccessibilityLabel
|
|
242
|
+
}: SkeletonComponentProps) => (
|
|
243
|
+
<View
|
|
244
|
+
style={styles.button}
|
|
245
|
+
accessible={true}
|
|
246
|
+
accessibilityLabel={loadingAccessibilityLabel}
|
|
247
|
+
>
|
|
248
|
+
<View style={styles.innerContent}>
|
|
249
|
+
<Placeholder.Box animate="fade" radius={8} width={107} height={22} />
|
|
250
|
+
<VSpacer size={4} />
|
|
251
|
+
<Placeholder.Box animate="fade" radius={8} width={44} height={22} />
|
|
252
|
+
</View>
|
|
253
|
+
</View>
|
|
254
|
+
);
|