@tactics/toddle-styleguide 5.4.48 → 5.4.50
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/package.json +1 -1
- package/src/components/atoms/backdrop/backdrop.component.tsx +5 -4
- package/src/components/templates/popover/components/foreground/foreground.component.tsx +5 -1
- package/src/components/templates/popover/components/modal/close/close.component.tsx +1 -1
- package/src/components/templates/popover/components/modal/modal.component.tsx +15 -5
- package/src/components/templates/popover/components/modal/scroll-content/scroll-content.component.tsx +11 -2
- package/src/components/templates/popover/popover.component.tsx +6 -7
- package/src/components/templates/popover/popover.preview.tsx +6 -0
- package/src/components/templates/popover-action/popover-action.component.tsx +7 -8
- package/src/components/templates/popover-action/popover-action.preview.tsx +7 -1
package/package.json
CHANGED
|
@@ -2,9 +2,11 @@ import * as React from 'react';
|
|
|
2
2
|
import {useContext, useEffect, useRef} from 'react';
|
|
3
3
|
|
|
4
4
|
import {ThemeCtx} from '../../../context/theme.context';
|
|
5
|
-
import {Animated} from 'react-native';
|
|
5
|
+
import {Animated, Pressable} from 'react-native';
|
|
6
6
|
import {Stylesheet} from './backdrop.styles';
|
|
7
7
|
|
|
8
|
+
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
|
|
9
|
+
|
|
8
10
|
type PopoverBackdropProps = {
|
|
9
11
|
isVisible: boolean;
|
|
10
12
|
touchBackDrop?: (value: boolean) => void;
|
|
@@ -25,12 +27,11 @@ const Backdrop = ({isVisible, touchBackDrop}: PopoverBackdropProps) => {
|
|
|
25
27
|
}, [isVisible, opacity]);
|
|
26
28
|
|
|
27
29
|
return (
|
|
28
|
-
<
|
|
30
|
+
<AnimatedPressable
|
|
29
31
|
accessible={true}
|
|
30
32
|
accessibilityRole="button"
|
|
31
33
|
accessibilityLabel="Close modal"
|
|
32
|
-
|
|
33
|
-
onTouchStart={() => (touchBackDrop ? touchBackDrop(false) : null)}
|
|
34
|
+
onPress={() => (touchBackDrop ? touchBackDrop(false) : null)}
|
|
34
35
|
style={[styles.element, {opacity: opacity}]}
|
|
35
36
|
/>
|
|
36
37
|
);
|
|
@@ -10,6 +10,10 @@ type PopoverForegroundProps = {
|
|
|
10
10
|
const Foreground = ({children}: PopoverForegroundProps) => {
|
|
11
11
|
const styles = Stylesheet();
|
|
12
12
|
|
|
13
|
-
return
|
|
13
|
+
return (
|
|
14
|
+
<View style={styles.element} pointerEvents="box-none">
|
|
15
|
+
{children}
|
|
16
|
+
</View>
|
|
17
|
+
);
|
|
14
18
|
};
|
|
15
19
|
export {Foreground as Foreground};
|
|
@@ -15,7 +15,7 @@ const Close = ({onPress}: ModalCloseProps) => {
|
|
|
15
15
|
const styles = Stylesheet();
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
|
-
<Pressable onPress={onPress} style={styles.container}>
|
|
18
|
+
<Pressable onPress={onPress} hitSlop={12} style={styles.container}>
|
|
19
19
|
<Icon
|
|
20
20
|
style={'regular'}
|
|
21
21
|
name={'xmark'}
|
|
@@ -14,6 +14,7 @@ type PopoverModalProps = {
|
|
|
14
14
|
isVisible: boolean;
|
|
15
15
|
children: React.ReactNode;
|
|
16
16
|
windowHeight: number;
|
|
17
|
+
bottomInset?: number;
|
|
17
18
|
disableScrollContent?: boolean;
|
|
18
19
|
};
|
|
19
20
|
|
|
@@ -24,6 +25,7 @@ const Modal = ({
|
|
|
24
25
|
onClose,
|
|
25
26
|
children,
|
|
26
27
|
windowHeight,
|
|
28
|
+
bottomInset = 0,
|
|
27
29
|
disableScrollContent,
|
|
28
30
|
}: PopoverModalProps) => {
|
|
29
31
|
// Keep element and window size in local state.
|
|
@@ -35,19 +37,27 @@ const Modal = ({
|
|
|
35
37
|
|
|
36
38
|
const elementHeight = Math.round(elementSize.height);
|
|
37
39
|
|
|
38
|
-
const maxHeight = Math.round(windowHeight
|
|
39
|
-
|
|
40
|
+
const maxHeight = Math.round(windowHeight * 0.9);
|
|
41
|
+
// windowHeight already reflects the full edge-to-edge screen height on
|
|
42
|
+
// Android, but it excludes the space behind the navigation bar, so the
|
|
43
|
+
// sheet's rest/closed position needs bottomInset added or its top edge
|
|
44
|
+
// peeks out from behind the nav bar when closed (see PopoverAction).
|
|
45
|
+
const translateYStartingPoint = windowHeight + bottomInset;
|
|
40
46
|
|
|
41
47
|
const saveHeight = elementHeight > maxHeight ? maxHeight : elementHeight;
|
|
42
48
|
|
|
43
49
|
const translateY = useRef(new Animated.Value(translateYStartingPoint)).current;
|
|
44
50
|
|
|
45
|
-
// Animate when visibility changes
|
|
51
|
+
// Animate when visibility changes.
|
|
52
|
+
// useNativeDriver is off: on Android, Pressables nested inside a view whose
|
|
53
|
+
// transform is driven on the native thread (bypassing the JS shadow tree)
|
|
54
|
+
// can stop receiving onPress entirely (onPressIn/onPressOut still fire) on
|
|
55
|
+
// some OS/device combinations, even long after the animation has settled.
|
|
46
56
|
useEffect(() => {
|
|
47
57
|
Animated.timing(translateY, {
|
|
48
58
|
toValue: isVisible ? translateYStartingPoint - saveHeight : translateYStartingPoint,
|
|
49
59
|
duration: 500,
|
|
50
|
-
useNativeDriver:
|
|
60
|
+
useNativeDriver: false,
|
|
51
61
|
}).start();
|
|
52
62
|
}, [isVisible, saveHeight, translateYStartingPoint, translateY]);
|
|
53
63
|
|
|
@@ -77,7 +87,7 @@ const Modal = ({
|
|
|
77
87
|
{disableScrollContent ? (
|
|
78
88
|
<View>{children}</View>
|
|
79
89
|
) : (
|
|
80
|
-
<ScrollContent>{children}</ScrollContent>
|
|
90
|
+
<ScrollContent bottomInset={bottomInset}>{children}</ScrollContent>
|
|
81
91
|
)}
|
|
82
92
|
</Animated.View>
|
|
83
93
|
</Animated.View>
|
|
@@ -4,17 +4,26 @@ import {useContext} from 'react';
|
|
|
4
4
|
import {ScrollView} from 'react-native';
|
|
5
5
|
import {Stylesheet} from './scroll-content.styles';
|
|
6
6
|
import {ThemeCtx} from '../../../../../../context/theme.context';
|
|
7
|
+
import {Scale} from '../../../../../../theme/scale';
|
|
7
8
|
|
|
8
9
|
type ModalScrollContentProps = {
|
|
9
10
|
children: React.ReactNode;
|
|
11
|
+
bottomInset?: number;
|
|
10
12
|
};
|
|
11
13
|
|
|
12
|
-
const ScrollContent = ({children}: ModalScrollContentProps) => {
|
|
14
|
+
const ScrollContent = ({children, bottomInset = 0}: ModalScrollContentProps) => {
|
|
13
15
|
const context = useContext(ThemeCtx);
|
|
14
16
|
const styles = Stylesheet(context);
|
|
15
17
|
|
|
16
18
|
return (
|
|
17
|
-
<ScrollView
|
|
19
|
+
<ScrollView
|
|
20
|
+
contentContainerStyle={[
|
|
21
|
+
styles.element,
|
|
22
|
+
{paddingBottom: bottomInset + Scale.xxxxl},
|
|
23
|
+
]}
|
|
24
|
+
>
|
|
25
|
+
{children}
|
|
26
|
+
</ScrollView>
|
|
18
27
|
);
|
|
19
28
|
};
|
|
20
29
|
export {ScrollContent as ScrollContent};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import {useEffect, useState} from 'react';
|
|
3
|
-
import {Dimensions, Platform,
|
|
3
|
+
import {Dimensions, Platform, View} from 'react-native';
|
|
4
|
+
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
|
4
5
|
import {Stylesheet} from './popover.styles';
|
|
5
6
|
import {Backdrop} from '../../atoms/backdrop/backdrop.component';
|
|
6
7
|
import {Modal, Foreground} from './components';
|
|
@@ -23,17 +24,14 @@ const Popover = ({
|
|
|
23
24
|
disableScrollContent,
|
|
24
25
|
}: PopoverProps) => {
|
|
25
26
|
const styles = Stylesheet();
|
|
27
|
+
const insets = useSafeAreaInsets();
|
|
26
28
|
const [windowHeight, setWindowHeight] = useState(
|
|
27
29
|
Dimensions.get('window').height
|
|
28
30
|
);
|
|
29
31
|
|
|
30
32
|
useEffect(() => {
|
|
31
33
|
const updateWindowHeight = () => {
|
|
32
|
-
|
|
33
|
-
if (Platform.OS === 'android') {
|
|
34
|
-
availableHeight += StatusBar.currentHeight ?? 0;
|
|
35
|
-
}
|
|
36
|
-
setWindowHeight(availableHeight);
|
|
34
|
+
setWindowHeight(Dimensions.get('window').height);
|
|
37
35
|
};
|
|
38
36
|
|
|
39
37
|
updateWindowHeight();
|
|
@@ -48,10 +46,11 @@ const Popover = ({
|
|
|
48
46
|
|
|
49
47
|
return (
|
|
50
48
|
<View style={styles.element} pointerEvents={isVisible ? 'auto' : 'none'}>
|
|
51
|
-
<Backdrop isVisible={isVisible} />
|
|
49
|
+
<Backdrop isVisible={isVisible} touchBackDrop={() => onClose()} />
|
|
52
50
|
<Foreground>
|
|
53
51
|
<Modal
|
|
54
52
|
windowHeight={windowHeight}
|
|
53
|
+
bottomInset={Platform.OS === 'android' ? insets.bottom * 1.7 : 0}
|
|
55
54
|
isVisible={isVisible}
|
|
56
55
|
onClose={onClose}
|
|
57
56
|
title={title}
|
|
@@ -30,6 +30,12 @@ export const PopoverPreview = ({}: {}) => {
|
|
|
30
30
|
title={'Taal'}
|
|
31
31
|
subtitle={'Welke taal wilt u gebruiken?'}
|
|
32
32
|
>
|
|
33
|
+
<View>
|
|
34
|
+
<Button
|
|
35
|
+
label={'Confirm'}
|
|
36
|
+
onPress={() => setPopoverIsVisible(false)}
|
|
37
|
+
/>
|
|
38
|
+
</View>
|
|
33
39
|
<View>
|
|
34
40
|
<Button label={'test'} />
|
|
35
41
|
</View>
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
Dimensions,
|
|
13
13
|
LayoutChangeEvent,
|
|
14
14
|
Platform,
|
|
15
|
-
StatusBar,
|
|
16
15
|
View,
|
|
17
16
|
ViewProps,
|
|
18
17
|
} from 'react-native';
|
|
@@ -114,11 +113,7 @@ export const PopOverAction = ({
|
|
|
114
113
|
|
|
115
114
|
useEffect(() => {
|
|
116
115
|
const updateWindowHeight = () => {
|
|
117
|
-
|
|
118
|
-
if (Platform.OS === 'android') {
|
|
119
|
-
availableHeight += StatusBar.currentHeight ?? 0;
|
|
120
|
-
}
|
|
121
|
-
setWindowHeight(availableHeight);
|
|
116
|
+
setWindowHeight(Dimensions.get('window').height);
|
|
122
117
|
};
|
|
123
118
|
|
|
124
119
|
updateWindowHeight();
|
|
@@ -143,11 +138,15 @@ export const PopOverAction = ({
|
|
|
143
138
|
|
|
144
139
|
const translateY = React.useRef(new Animated.Value(translateYStartingPoint)).current;
|
|
145
140
|
|
|
141
|
+
// useNativeDriver is off: on Android, Pressables nested inside a view whose
|
|
142
|
+
// transform is driven on the native thread (bypassing the JS shadow tree)
|
|
143
|
+
// can stop receiving onPress entirely (onPressIn/onPressOut still fire) on
|
|
144
|
+
// some OS/device combinations, even long after the animation has settled.
|
|
146
145
|
const open = () => {
|
|
147
146
|
Animated.timing(translateY, {
|
|
148
147
|
toValue: translateYStartingPoint - saveHeight,
|
|
149
148
|
duration: 500,
|
|
150
|
-
useNativeDriver:
|
|
149
|
+
useNativeDriver: false,
|
|
151
150
|
}).start();
|
|
152
151
|
};
|
|
153
152
|
|
|
@@ -155,7 +154,7 @@ export const PopOverAction = ({
|
|
|
155
154
|
Animated.timing(translateY, {
|
|
156
155
|
toValue: translateYStartingPoint,
|
|
157
156
|
duration: 500,
|
|
158
|
-
useNativeDriver:
|
|
157
|
+
useNativeDriver: false,
|
|
159
158
|
}).start();
|
|
160
159
|
};
|
|
161
160
|
|
|
@@ -27,6 +27,7 @@ const renderActionContent = ({
|
|
|
27
27
|
minutes,
|
|
28
28
|
setHours,
|
|
29
29
|
setMinutes,
|
|
30
|
+
onButtonPress,
|
|
30
31
|
}: {
|
|
31
32
|
pageKey: string;
|
|
32
33
|
actionLabel: string;
|
|
@@ -37,6 +38,7 @@ const renderActionContent = ({
|
|
|
37
38
|
minutes: string;
|
|
38
39
|
setHours: (value: string) => void;
|
|
39
40
|
setMinutes: (value: string) => void;
|
|
41
|
+
onButtonPress?: () => void;
|
|
40
42
|
}) => (
|
|
41
43
|
<View key={pageKey} style={{height: '100%', width: '100%'}}>
|
|
42
44
|
<View style={{alignItems: 'center', marginBottom: Scale.s}}>
|
|
@@ -117,7 +119,10 @@ const renderActionContent = ({
|
|
|
117
119
|
gap: Scale.m * 1.25,
|
|
118
120
|
}}
|
|
119
121
|
>
|
|
120
|
-
<Button
|
|
122
|
+
<Button
|
|
123
|
+
label={buttonLabel}
|
|
124
|
+
onPress={onButtonPress ?? (() => console.log('pressed'))}
|
|
125
|
+
/>
|
|
121
126
|
<MoreInfoButton
|
|
122
127
|
label={secondaryButtonLabel}
|
|
123
128
|
textColor={'#000000'}
|
|
@@ -169,6 +174,7 @@ export const PopOverActionPreview = () => {
|
|
|
169
174
|
minutes: messageMinutes,
|
|
170
175
|
setHours: setMessageHours,
|
|
171
176
|
setMinutes: setMessageMinutes,
|
|
177
|
+
onButtonPress: () => setIsVisible(false),
|
|
172
178
|
})}
|
|
173
179
|
</PopOverAction>
|
|
174
180
|
</View>
|