@tactics/toddle-styleguide 5.4.47 → 5.4.48
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/paragraph-components/paragraph-text.styles.d.ts +2 -0
- package/src/components/atoms/paragraph-components/paragraph-text.styles.js +2 -0
- package/src/components/templates/popover-action/popover-action.component.tsx +47 -16
- package/src/components/templates/popover-action/popover-action.preview.tsx +148 -114
- package/src/components/templates/popover-action/popover-action.styles.d.ts +6 -0
- package/src/components/templates/popover-action/popover-action.styles.js +6 -0
package/package.json
CHANGED
|
@@ -20,6 +20,7 @@ import { Backdrop } from '../../atoms/backdrop/backdrop.component';
|
|
|
20
20
|
import { Stylesheet } from './popover-action.styles';
|
|
21
21
|
import { Swipe } from '../../molecules/swipe/swipe.component';
|
|
22
22
|
import { ThemeCtx } from '../../../context/theme.context';
|
|
23
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
23
24
|
|
|
24
25
|
type PopOverActionProps = {
|
|
25
26
|
isVisible: boolean;
|
|
@@ -51,18 +52,29 @@ export const PopOverAction = ({
|
|
|
51
52
|
) => {
|
|
52
53
|
// Ignore zero-height layouts which can occur before content renders,
|
|
53
54
|
// otherwise the sheet may collapse and appear to lose content.
|
|
54
|
-
if (layout?.height
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
if (!layout?.height || layout.height <= 0) return;
|
|
56
|
+
|
|
57
|
+
setChildDimensions((prev) => {
|
|
58
|
+
const existing = prev[index];
|
|
59
|
+
// Some children mount their real content a tick after an initial empty
|
|
60
|
+
// render (e.g. TimePicker), so a later layout call can briefly report a
|
|
61
|
+
// smaller height than what was already measured. Keep the tallest
|
|
62
|
+
// measurement seen instead of last-write-wins, otherwise the sheet can
|
|
63
|
+
// settle on a stale, too-small height and clip content.
|
|
64
|
+
if (existing && existing.height >= layout.height) return prev;
|
|
65
|
+
const updated = [...prev];
|
|
66
|
+
updated[index] = layout;
|
|
67
|
+
return updated;
|
|
68
|
+
});
|
|
60
69
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
// Ensure element size is known for the currently visible child so the animation can open
|
|
71
|
+
// even if Swipe never emits onIndexChange (e.g., only one child or Swipe not implemented yet).
|
|
72
|
+
if (index === currentChildIndex) {
|
|
73
|
+
setElementSize((prev) =>
|
|
74
|
+
prev.height >= layout.height
|
|
75
|
+
? prev
|
|
76
|
+
: { width: layout.width, height: layout.height }
|
|
77
|
+
);
|
|
66
78
|
}
|
|
67
79
|
};
|
|
68
80
|
|
|
@@ -117,10 +129,16 @@ export const PopOverAction = ({
|
|
|
117
129
|
|
|
118
130
|
const context = useContext(ThemeCtx);
|
|
119
131
|
const styles = Stylesheet(context);
|
|
132
|
+
const insets = useSafeAreaInsets();
|
|
120
133
|
|
|
121
134
|
const elementHeight = Math.round(elementSize.height);
|
|
122
135
|
const maxHeight = Math.round(windowHeight * 0.9);
|
|
123
|
-
|
|
136
|
+
// On Android, Dimensions.get('window') excludes the space behind the
|
|
137
|
+
// navigation bar, but the sheet's container renders behind it (edge-to-edge).
|
|
138
|
+
// Without this, the sheet doesn't travel far enough down when closed and its
|
|
139
|
+
// top edge peeks out from behind the navigation bar.
|
|
140
|
+
const translateYStartingPoint =
|
|
141
|
+
windowHeight + (Platform.OS === 'android' ? insets.bottom : 0);
|
|
124
142
|
const saveHeight = elementHeight > maxHeight ? maxHeight : elementHeight;
|
|
125
143
|
|
|
126
144
|
const translateY = React.useRef(new Animated.Value(translateYStartingPoint)).current;
|
|
@@ -166,15 +184,28 @@ export const PopOverAction = ({
|
|
|
166
184
|
<Backdrop isVisible={isVisible} touchBackDrop={touchBackDrop} />
|
|
167
185
|
<Animated.View
|
|
168
186
|
style={[styles.slidePanelContainer, {maxHeight: maxHeight}, {transform: transform}]}
|
|
169
|
-
onLayout={(event) => {
|
|
170
|
-
const {width, height} = event.nativeEvent.layout;
|
|
171
|
-
setElementSize({width: width, height: height});
|
|
172
|
-
}}
|
|
173
187
|
>
|
|
174
188
|
<Swipe onIndexChange={handleChildIndexChange}>
|
|
175
189
|
{renderChildrenWithLayout(children, handleChildLayout)}
|
|
176
190
|
</Swipe>
|
|
177
191
|
</Animated.View>
|
|
192
|
+
{/* Hidden pass so every child's height is measured up front, regardless of
|
|
193
|
+
which pages the Swipe pager actually keeps mounted (it doesn't guarantee
|
|
194
|
+
all of them are laid out ahead of time). Without this, swiping to a page
|
|
195
|
+
that hasn't been measured yet leaves the sheet at the previous page's height.
|
|
196
|
+
Height is fixed to maxHeight (rather than left to shrink-wrap) so that a child
|
|
197
|
+
using a percentage height (e.g. height: '100%') resolves against a real value
|
|
198
|
+
instead of collapsing to 0, which otherwise leaves the sheet stuck fully closed. */}
|
|
199
|
+
<View
|
|
200
|
+
style={[
|
|
201
|
+
styles.slidePanelContainer,
|
|
202
|
+
styles.measurementContainer,
|
|
203
|
+
{height: maxHeight},
|
|
204
|
+
]}
|
|
205
|
+
pointerEvents="none"
|
|
206
|
+
>
|
|
207
|
+
{renderChildrenWithLayout(children, handleChildLayout)}
|
|
208
|
+
</View>
|
|
178
209
|
</View>
|
|
179
210
|
);
|
|
180
211
|
};
|
|
@@ -5,12 +5,135 @@ import {PopOverAction} from './popover-action.component';
|
|
|
5
5
|
import {Heading2} from '../../atoms/heading-components';
|
|
6
6
|
import {Icon} from '../../../icons/index';
|
|
7
7
|
import {Paragraph} from '../../atoms/paragraph-components';
|
|
8
|
-
import {
|
|
8
|
+
import {MoreInfoButton} from '../../molecules/more-info-button/more-info-button.component';
|
|
9
|
+
import {BareTimePicker} from '../../molecules/bare-time-picker/bare-time-picker.component';
|
|
10
|
+
import {Scale} from '../../../theme/scale/index';
|
|
11
|
+
|
|
12
|
+
// Mirrors Toddle-For-Daycares' src/modals/actions-single-child/actions-single-child.modal.tsx,
|
|
13
|
+
// which renders this exact shape as the two PopOverAction pages shown when a caregiver taps a
|
|
14
|
+
// child in the home list. Each page root uses height:'100%'/width:'100%' (actions-single-child's
|
|
15
|
+
// and action-content's `rootContainer`), and the time picker is `BareTimePicker`, not `TimePicker`
|
|
16
|
+
// - both details matter for reproducing the sizing bug reported in production.
|
|
17
|
+
// Called as a plain function (not JSX) so the View it returns is the direct child of
|
|
18
|
+
// PopOverAction - PopOverAction measures each direct child via cloneElement(child, {onLayout}),
|
|
19
|
+
// which only reaches a real host View, not a custom component placed between them.
|
|
20
|
+
const renderActionContent = ({
|
|
21
|
+
pageKey,
|
|
22
|
+
actionLabel,
|
|
23
|
+
childDisplayName,
|
|
24
|
+
buttonLabel,
|
|
25
|
+
secondaryButtonLabel,
|
|
26
|
+
hours,
|
|
27
|
+
minutes,
|
|
28
|
+
setHours,
|
|
29
|
+
setMinutes,
|
|
30
|
+
}: {
|
|
31
|
+
pageKey: string;
|
|
32
|
+
actionLabel: string;
|
|
33
|
+
childDisplayName: string;
|
|
34
|
+
buttonLabel: string;
|
|
35
|
+
secondaryButtonLabel: string;
|
|
36
|
+
hours: string;
|
|
37
|
+
minutes: string;
|
|
38
|
+
setHours: (value: string) => void;
|
|
39
|
+
setMinutes: (value: string) => void;
|
|
40
|
+
}) => (
|
|
41
|
+
<View key={pageKey} style={{height: '100%', width: '100%'}}>
|
|
42
|
+
<View style={{alignItems: 'center', marginBottom: Scale.s}}>
|
|
43
|
+
<Heading2 bold={true} textAlign={'center'}>
|
|
44
|
+
{actionLabel}
|
|
45
|
+
</Heading2>
|
|
46
|
+
|
|
47
|
+
<View
|
|
48
|
+
style={{
|
|
49
|
+
flexDirection: 'row',
|
|
50
|
+
justifyContent: 'center',
|
|
51
|
+
alignItems: 'center',
|
|
52
|
+
paddingTop: Scale.xs,
|
|
53
|
+
paddingBottom: Scale.xs,
|
|
54
|
+
}}
|
|
55
|
+
>
|
|
56
|
+
<Icon style={'regular'} name={'calendar'} color={'#000000'} />
|
|
57
|
+
<View style={{marginLeft: Scale.xs}}>
|
|
58
|
+
<Paragraph>17 Jan 2021</Paragraph>
|
|
59
|
+
</View>
|
|
60
|
+
</View>
|
|
61
|
+
</View>
|
|
62
|
+
|
|
63
|
+
<View style={{justifyContent: 'center'}}>
|
|
64
|
+
<View
|
|
65
|
+
style={{
|
|
66
|
+
marginLeft: 'auto',
|
|
67
|
+
marginRight: 'auto',
|
|
68
|
+
alignItems: 'center',
|
|
69
|
+
justifyContent: 'center',
|
|
70
|
+
marginBottom: Scale.l,
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
<View
|
|
74
|
+
style={{
|
|
75
|
+
borderRadius: 50,
|
|
76
|
+
alignItems: 'center',
|
|
77
|
+
justifyContent: 'center',
|
|
78
|
+
height: 40,
|
|
79
|
+
maxHeight: 40,
|
|
80
|
+
paddingLeft: Scale.s,
|
|
81
|
+
paddingTop: Scale.xs,
|
|
82
|
+
paddingRight: Scale.s,
|
|
83
|
+
paddingBottom: Scale.xs,
|
|
84
|
+
backgroundColor: '#E5E5E5',
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
<Paragraph
|
|
88
|
+
bold={true}
|
|
89
|
+
textAlign={'center'}
|
|
90
|
+
ellipsizeMode={'tail'}
|
|
91
|
+
numberOfLines={1}
|
|
92
|
+
>
|
|
93
|
+
{childDisplayName}
|
|
94
|
+
</Paragraph>
|
|
95
|
+
</View>
|
|
96
|
+
</View>
|
|
97
|
+
|
|
98
|
+
<View
|
|
99
|
+
style={{
|
|
100
|
+
alignItems: 'center',
|
|
101
|
+
justifyContent: 'center',
|
|
102
|
+
marginBottom: Scale.m,
|
|
103
|
+
}}
|
|
104
|
+
>
|
|
105
|
+
<BareTimePicker
|
|
106
|
+
initialHours={hours}
|
|
107
|
+
initialMinutes={minutes}
|
|
108
|
+
onChangeHours={setHours}
|
|
109
|
+
onChangeMinutes={setMinutes}
|
|
110
|
+
/>
|
|
111
|
+
</View>
|
|
112
|
+
|
|
113
|
+
<View
|
|
114
|
+
style={{
|
|
115
|
+
alignItems: 'center',
|
|
116
|
+
marginBottom: Scale.m * 3.75,
|
|
117
|
+
gap: Scale.m * 1.25,
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
<Button label={buttonLabel} onPress={() => console.log('pressed')} />
|
|
121
|
+
<MoreInfoButton
|
|
122
|
+
label={secondaryButtonLabel}
|
|
123
|
+
textColor={'#000000'}
|
|
124
|
+
onPress={() => console.log('secondary pressed')}
|
|
125
|
+
/>
|
|
126
|
+
</View>
|
|
127
|
+
</View>
|
|
128
|
+
</View>
|
|
129
|
+
);
|
|
9
130
|
|
|
10
131
|
export const PopOverActionPreview = () => {
|
|
11
132
|
const [isVisible, setIsVisible] = useState<boolean>(false);
|
|
12
133
|
const [checkInHours, setCheckInHours] = useState('09');
|
|
13
134
|
const [checkInMinutes, setCheckInMinutes] = useState('06');
|
|
135
|
+
const [messageHours, setMessageHours] = useState('09');
|
|
136
|
+
const [messageMinutes, setMessageMinutes] = useState('06');
|
|
14
137
|
|
|
15
138
|
return (
|
|
16
139
|
<View style={{width: '100%', height: '100%', zIndex: 10000}}>
|
|
@@ -22,120 +145,31 @@ export const PopOverActionPreview = () => {
|
|
|
22
145
|
</View>
|
|
23
146
|
|
|
24
147
|
<PopOverAction isVisible={isVisible} touchBackDrop={setIsVisible}>
|
|
25
|
-
{/*
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
</Heading2>
|
|
38
|
-
|
|
39
|
-
<View
|
|
40
|
-
style={{
|
|
41
|
-
flexDirection: 'row',
|
|
42
|
-
gap: 16,
|
|
43
|
-
justifyContent: 'center',
|
|
44
|
-
alignItems: 'center',
|
|
45
|
-
}}
|
|
46
|
-
>
|
|
47
|
-
<Icon style={'regular'} name={'calendar'} color={'#000000'} />
|
|
48
|
-
<View>
|
|
49
|
-
<Paragraph>17 Jan 2021</Paragraph>
|
|
50
|
-
</View>
|
|
51
|
-
</View>
|
|
52
|
-
</View>
|
|
53
|
-
<TimePicker
|
|
54
|
-
initialHours={checkInHours}
|
|
55
|
-
initialMinutes={checkInMinutes}
|
|
56
|
-
onChangeHours={setCheckInHours}
|
|
57
|
-
onChangeMinutes={setCheckInMinutes}
|
|
58
|
-
/>
|
|
59
|
-
</View>
|
|
60
|
-
|
|
61
|
-
{/*SECOND CHILD*/}
|
|
62
|
-
|
|
63
|
-
<View
|
|
64
|
-
style={{
|
|
65
|
-
alignItems: 'center',
|
|
66
|
-
gap: 60,
|
|
67
|
-
height: 400,
|
|
68
|
-
}}
|
|
69
|
-
key={2}
|
|
70
|
-
>
|
|
71
|
-
<View style={{gap: 12}}>
|
|
72
|
-
<Heading2 bold={true} textAlign={'center'}>
|
|
73
|
-
Uurregistratie
|
|
74
|
-
</Heading2>
|
|
75
|
-
|
|
76
|
-
<View
|
|
77
|
-
style={{
|
|
78
|
-
flexDirection: 'row',
|
|
79
|
-
gap: 16,
|
|
80
|
-
justifyContent: 'center',
|
|
81
|
-
alignItems: 'center',
|
|
82
|
-
}}
|
|
83
|
-
>
|
|
84
|
-
<Icon style={'regular'} name={'calendar'} color={'#000000'} />
|
|
85
|
-
<View>
|
|
86
|
-
<Paragraph>17 Jan 2021</Paragraph>
|
|
87
|
-
</View>
|
|
88
|
-
</View>
|
|
89
|
-
</View>
|
|
90
|
-
|
|
91
|
-
<TimePicker
|
|
92
|
-
initialHours={checkInHours}
|
|
93
|
-
initialMinutes={checkInMinutes}
|
|
94
|
-
onChangeHours={setCheckInHours}
|
|
95
|
-
onChangeMinutes={setCheckInMinutes}
|
|
96
|
-
/>
|
|
148
|
+
{/* CHECK IN / OUT - matches the modal's incomplete-presence branch */}
|
|
149
|
+
{renderActionContent({
|
|
150
|
+
pageKey: 'checkin',
|
|
151
|
+
actionLabel: 'Uurregistratie',
|
|
152
|
+
childDisplayName: 'Nora',
|
|
153
|
+
buttonLabel: 'Check in',
|
|
154
|
+
secondaryButtonLabel: 'View registrations',
|
|
155
|
+
hours: checkInHours,
|
|
156
|
+
minutes: checkInMinutes,
|
|
157
|
+
setHours: setCheckInHours,
|
|
158
|
+
setMinutes: setCheckInMinutes,
|
|
159
|
+
})}
|
|
97
160
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
height: 600,
|
|
111
|
-
}}
|
|
112
|
-
key={3}
|
|
113
|
-
>
|
|
114
|
-
<View style={{gap: 12}}>
|
|
115
|
-
<Heading2 bold={true} textAlign={'center'}>
|
|
116
|
-
Uurregistratie
|
|
117
|
-
</Heading2>
|
|
118
|
-
|
|
119
|
-
<View
|
|
120
|
-
style={{
|
|
121
|
-
flexDirection: 'row',
|
|
122
|
-
gap: 16,
|
|
123
|
-
justifyContent: 'center',
|
|
124
|
-
alignItems: 'center',
|
|
125
|
-
}}
|
|
126
|
-
>
|
|
127
|
-
<Icon style={'regular'} name={'calendar'} color={'#000000'} />
|
|
128
|
-
<View>
|
|
129
|
-
<Paragraph>17 Jan 2021</Paragraph>
|
|
130
|
-
</View>
|
|
131
|
-
</View>
|
|
132
|
-
</View>
|
|
133
|
-
|
|
134
|
-
<Button
|
|
135
|
-
label={'Test button'}
|
|
136
|
-
onPress={() => console.log('pressed')}
|
|
137
|
-
/>
|
|
138
|
-
</View>
|
|
161
|
+
{/* ADD A MESSAGE - matches the modal's second PopOverAction page */}
|
|
162
|
+
{renderActionContent({
|
|
163
|
+
pageKey: 'message',
|
|
164
|
+
actionLabel: 'Add a message',
|
|
165
|
+
childDisplayName: 'Nora',
|
|
166
|
+
buttonLabel: 'Custom message',
|
|
167
|
+
secondaryButtonLabel: 'Standard messages',
|
|
168
|
+
hours: messageHours,
|
|
169
|
+
minutes: messageMinutes,
|
|
170
|
+
setHours: setMessageHours,
|
|
171
|
+
setMinutes: setMessageMinutes,
|
|
172
|
+
})}
|
|
139
173
|
</PopOverAction>
|
|
140
174
|
</View>
|
|
141
175
|
);
|