rnnovaui 0.9.2 → 0.9.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rnnovaui",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "react-native": "src/index.js",
@@ -7,39 +7,40 @@ import { useUIAccordionItem } from "./UIAccordionItem";
7
7
 
8
8
  export const UIAccordionContent = memo(function UIAccordionContent({
9
9
  children,
10
-
11
10
  style,
12
-
13
11
  innerStyle,
14
-
15
12
  testID,
16
-
17
13
  onLayout,
18
14
  }) {
19
15
  const accordion = useUIAccordion();
20
16
 
21
17
  const item = useUIAccordionItem();
22
18
 
19
+ const [contentHeight, setContentHeight] = useState(0);
20
+
21
+ const [mounted, setMounted] = useState(item.open);
22
+
23
23
  const heightAnimation = useRef(new Animated.Value(item.open ? 1 : 0)).current;
24
24
 
25
25
  const opacityAnimation = useRef(
26
26
  new Animated.Value(item.open ? 1 : 0),
27
27
  ).current;
28
28
 
29
- const [contentHeight, setContentHeight] = useState(0);
30
-
31
- const [mounted, setMounted] = useState(item.open);
29
+ const previousOpen = useRef(item.open);
32
30
 
33
31
  /*
34
- * ------------------------------------------------
35
- * MEASURE CONTENT
36
- * ------------------------------------------------
32
+ * -----------------------------------------------
33
+ * CONTENT MEASUREMENT
34
+ * -----------------------------------------------
35
+ *
36
+ * We only update the cached height when the
37
+ * actual content height changes.
37
38
  */
38
39
 
39
- const handleLayout = (event) => {
40
- const height = event.nativeEvent.layout.height;
40
+ const handleContentLayout = (event) => {
41
+ const height = Math.ceil(event.nativeEvent.layout.height);
41
42
 
42
- if (height !== contentHeight) {
43
+ if (height > 0 && height !== contentHeight) {
43
44
  setContentHeight(height);
44
45
  }
45
46
 
@@ -47,17 +48,43 @@ export const UIAccordionContent = memo(function UIAccordionContent({
47
48
  };
48
49
 
49
50
  /*
50
- * ------------------------------------------------
51
- * OPEN / CLOSE
52
- * ------------------------------------------------
51
+ * -----------------------------------------------
52
+ * OPEN / CLOSE ANIMATION
53
+ * -----------------------------------------------
53
54
  */
54
55
 
55
56
  useEffect(() => {
57
+ const wasOpen = previousOpen.current;
58
+
59
+ previousOpen.current = item.open;
60
+
61
+ /*
62
+ * Nothing changed.
63
+ */
64
+ if (wasOpen === item.open) {
65
+ return;
66
+ }
67
+
68
+ /*
69
+ * ---------------------------------------------
70
+ * OPEN
71
+ * ---------------------------------------------
72
+ */
73
+
56
74
  if (item.open) {
75
+ setMounted(true);
76
+
57
77
  /*
58
- * Mount before opening.
78
+ * If content has not been measured yet,
79
+ * wait for onLayout.
59
80
  */
60
- setMounted(true);
81
+ if (contentHeight <= 0) {
82
+ heightAnimation.setValue(0);
83
+
84
+ opacityAnimation.setValue(0);
85
+
86
+ return;
87
+ }
61
88
 
62
89
  if (!accordion.animated) {
63
90
  heightAnimation.setValue(1);
@@ -68,8 +95,12 @@ export const UIAccordionContent = memo(function UIAccordionContent({
68
95
  }
69
96
 
70
97
  /*
71
- * Smooth opening.
98
+ * Start exactly from closed.
72
99
  */
100
+ heightAnimation.setValue(0);
101
+
102
+ opacityAnimation.setValue(0);
103
+
73
104
  Animated.parallel([
74
105
  Animated.timing(heightAnimation, {
75
106
  toValue: 1,
@@ -82,7 +113,7 @@ export const UIAccordionContent = memo(function UIAccordionContent({
82
113
  Animated.timing(opacityAnimation, {
83
114
  toValue: 1,
84
115
 
85
- duration: Math.min(accordion.animationDuration, 180),
116
+ duration: Math.min(accordion.animationDuration, 160),
86
117
 
87
118
  useNativeDriver: false,
88
119
  }),
@@ -92,9 +123,9 @@ export const UIAccordionContent = memo(function UIAccordionContent({
92
123
  }
93
124
 
94
125
  /*
95
- * ------------------------------------------------
126
+ * ---------------------------------------------
96
127
  * CLOSE
97
- * ------------------------------------------------
128
+ * ---------------------------------------------
98
129
  */
99
130
 
100
131
  if (!accordion.animated) {
@@ -107,9 +138,6 @@ export const UIAccordionContent = memo(function UIAccordionContent({
107
138
  return;
108
139
  }
109
140
 
110
- /*
111
- * Animate to zero first.
112
- */
113
141
  Animated.parallel([
114
142
  Animated.timing(heightAnimation, {
115
143
  toValue: 0,
@@ -122,7 +150,7 @@ export const UIAccordionContent = memo(function UIAccordionContent({
122
150
  Animated.timing(opacityAnimation, {
123
151
  toValue: 0,
124
152
 
125
- duration: Math.min(accordion.animationDuration, 160),
153
+ duration: Math.min(accordion.animationDuration, 150),
126
154
 
127
155
  useNativeDriver: false,
128
156
  }),
@@ -133,6 +161,7 @@ export const UIAccordionContent = memo(function UIAccordionContent({
133
161
  });
134
162
  }, [
135
163
  item.open,
164
+ contentHeight,
136
165
  accordion.animated,
137
166
  accordion.animationDuration,
138
167
  heightAnimation,
@@ -140,31 +169,40 @@ export const UIAccordionContent = memo(function UIAccordionContent({
140
169
  ]);
141
170
 
142
171
  /*
143
- * ------------------------------------------------
144
- * CLOSED
145
- * ------------------------------------------------
172
+ * -----------------------------------------------
173
+ * IMPORTANT:
174
+ *
175
+ * Keep the content mounted while measuring.
176
+ *
177
+ * We use a wrapper whose height is animated.
178
+ * The inner content itself keeps its natural
179
+ * height.
180
+ * -----------------------------------------------
146
181
  */
147
182
 
148
- if (!mounted && !item.open) {
149
- return (
150
- <View
151
- style={{
152
- position: "absolute",
153
-
154
- opacity: 0,
183
+ if (!mounted) {
184
+ /*
185
+ * Keep a non-visible measurement copy mounted
186
+ * only when the component has never measured.
187
+ *
188
+ * Once contentHeight is known, don't keep
189
+ * measurement content around.
190
+ */
191
+ if (contentHeight > 0) {
192
+ return null;
193
+ }
155
194
 
156
- pointerEvents: "none",
157
- }}
158
- >
159
- <View onLayout={handleLayout}>{children}</View>
195
+ return (
196
+ <View style={styles.measureOnly} pointerEvents="none">
197
+ <View onLayout={handleContentLayout}>{children}</View>
160
198
  </View>
161
199
  );
162
200
  }
163
201
 
164
202
  /*
165
- * ------------------------------------------------
203
+ * -----------------------------------------------
166
204
  * ANIMATED HEIGHT
167
- * ------------------------------------------------
205
+ * -----------------------------------------------
168
206
  */
169
207
 
170
208
  const animatedHeight =
@@ -174,13 +212,7 @@ export const UIAccordionContent = memo(function UIAccordionContent({
174
212
 
175
213
  outputRange: [0, contentHeight],
176
214
  })
177
- : undefined;
178
-
179
- /*
180
- * ------------------------------------------------
181
- * RENDER
182
- * ------------------------------------------------
183
- */
215
+ : 0;
184
216
 
185
217
  return (
186
218
  <Animated.View
@@ -197,7 +229,7 @@ export const UIAccordionContent = memo(function UIAccordionContent({
197
229
  style,
198
230
  ]}
199
231
  >
200
- <View style={[styles.content, innerStyle]} onLayout={handleLayout}>
232
+ <View style={[styles.inner, innerStyle]} onLayout={handleContentLayout}>
201
233
  {children}
202
234
  </View>
203
235
  </Animated.View>
@@ -211,9 +243,21 @@ const styles = StyleSheet.create({
211
243
  overflow: "hidden",
212
244
  },
213
245
 
214
- content: {
246
+ inner: {
215
247
  width: "100%",
216
248
  },
249
+
250
+ measureOnly: {
251
+ position: "absolute",
252
+
253
+ left: 0,
254
+
255
+ right: 0,
256
+
257
+ opacity: 0,
258
+
259
+ zIndex: -1,
260
+ },
217
261
  });
218
262
 
219
263
  UIAccordionContent.displayName = "UIAccordion.Content";