@momo-kits/foundation 0.168.1-beta.8 → 0.168.1-duo.1

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.
@@ -37,6 +37,8 @@ import SystemTextInput from './SystemTextInput';
37
37
 
38
38
  const moneyFormatter = new Intl.NumberFormat('vi-VN');
39
39
 
40
+ // Finds the common prefix and suffix of `old` and `text`; `size` counts the
41
+ // characters removed plus inserted between them.
40
42
  const findEdit = (old: string, text: string) => {
41
43
  let start = 0;
42
44
  while (start < text.length && old[start] === text[start]) {
@@ -127,8 +129,11 @@ const InputMoney = forwardRef(
127
129
  setLastDisplayValue(displayValue);
128
130
  }, [displayValue]);
129
131
 
132
+ // The selection only rides along with the render that reformats the text,
133
+ // then it is released so the user can move the caret freely.
130
134
  useEffect(() => {
131
135
  if (!caretSelection) return;
136
+ // A newer keystroke may already have queued its own selection; keep it.
132
137
  setCaretSelection(current =>
133
138
  current === caretSelection ? undefined : current,
134
139
  );
@@ -138,6 +143,9 @@ const InputMoney = forwardRef(
138
143
  const next = numeric ? moneyFormatter.format(Number(numeric)) : '';
139
144
  setDisplayValue(next);
140
145
 
146
+ // Android moves the caret proportionally when the text is replaced, so
147
+ // it lands before the typed digit once a separator is added. Send the
148
+ // caret together with the text, keeping the same digits after it.
141
149
  const digitsAfter = caretDigitsAfter.current;
142
150
  caretDigitsAfter.current = undefined;
143
151
  if (Platform.OS !== 'android' || digitsAfter === undefined) return;
@@ -179,6 +187,9 @@ const InputMoney = forwardRef(
179
187
  return;
180
188
  }
181
189
  const digits = parseInputText(text);
190
+ // When typing outpaces JS (slow devices) native rejects the stale
191
+ // formatted text and keeps the raw one, so the edit may apply to either.
192
+ // Pick the one that differs from the new text by a single edit.
182
193
  const raw = lastRawText.current;
183
194
  lastRawText.current = text;
184
195
  const formattedEdit = findEdit(lastDisplayValue, text);
@@ -188,6 +199,7 @@ const InputMoney = forwardRef(
188
199
  caretDigitsAfter.current = parseInputText(
189
200
  text.slice(text.length - suffix),
190
201
  ).length;
202
+ // Deleting a separator removes the digit before it.
191
203
  if (text.length < old.length && digits === numericValue) {
192
204
  const index = parseInputText(text.slice(0, start)).length - 1;
193
205
  if (index >= 0) {
@@ -279,6 +291,8 @@ const InputMoney = forwardRef(
279
291
  disabled: disabled,
280
292
  ...props.accessibilityState,
281
293
  }}
294
+ // No width: the input sizes to its text natively, so the
295
+ // currency follows it without waiting for JS.
282
296
  style={[textStyle, styles.moneyTextInput, { color: textColor }]}
283
297
  allowFontScaling={false}
284
298
  textBreakStrategy="highQuality"
package/Input/styles.ts CHANGED
@@ -223,8 +223,9 @@ export default StyleSheet.create({
223
223
  },
224
224
  moneyTextInput: {
225
225
  flexShrink: 1,
226
+ height: '100%',
226
227
  paddingLeft: 0,
227
228
  paddingRight: Spacing.XXS,
228
- paddingVertical: 0,
229
+ paddingVertical: Spacing.S,
229
230
  },
230
231
  });
package/Layout/Screen.tsx CHANGED
@@ -11,6 +11,7 @@ import React, {
11
11
  useImperativeHandle,
12
12
  useMemo,
13
13
  useRef,
14
+ useState,
14
15
  } from 'react';
15
16
  import {
16
17
  Animated,
@@ -25,8 +26,9 @@ import {
25
26
  View,
26
27
  ViewProps,
27
28
  } from 'react-native';
28
- import {
29
+ import ReAnimated, {
29
30
  useAnimatedReaction,
31
+ useAnimatedStyle,
30
32
  useSharedValue,
31
33
  withTiming,
32
34
  } from 'react-native-reanimated';
@@ -280,6 +282,14 @@ const Screen = forwardRef(
280
282
  const headerHide = useSharedValue(0);
281
283
  const lastScrollY = useSharedValue(0);
282
284
 
285
+ // iPhone Duo: the header component rides under the quick return header and the
286
+ // content scrolls beneath both, instead of staying pinned below an empty band
287
+ const floatHeaderComponent = useDuoGlass && scrollable && !!Header;
288
+ const [headerComponentHeight, setHeaderComponentHeight] = useState(0);
289
+ const headerComponentStyle = useAnimatedStyle(() => ({
290
+ transform: [{ translateY: -headerHide.value }],
291
+ }));
292
+
283
293
  useAnimatedReaction(
284
294
  () => sharedValue.value,
285
295
  y => {
@@ -780,7 +790,7 @@ const Screen = forwardRef(
780
790
  paddingLeft: layout.insetLeft,
781
791
  paddingRight: layout.insetRight,
782
792
  };
783
- const offsetBodyByHeader = useDuoGlass && (!scrollable || !!Header);
793
+ const offsetBodyByHeader = useDuoGlass && !scrollable;
784
794
  const hasDuoTabInset = !Footer && isTab && !!duoTabInset;
785
795
 
786
796
  let floatingButtonBottom = bottomInset + Spacing.S;
@@ -838,7 +848,22 @@ const Screen = forwardRef(
838
848
  android: undefined,
839
849
  })}
840
850
  >
841
- {Header}
851
+ {floatHeaderComponent ? (
852
+ <ReAnimated.View
853
+ style={[
854
+ styles.floatingHeaderComponent,
855
+ { top: heightHeader },
856
+ headerComponentStyle,
857
+ ]}
858
+ onLayout={e =>
859
+ setHeaderComponentHeight(e.nativeEvent.layout.height)
860
+ }
861
+ >
862
+ {Header}
863
+ </ReAnimated.View>
864
+ ) : (
865
+ Header
866
+ )}
842
867
 
843
868
  <Component
844
869
  {...scrollViewProps}
@@ -857,7 +882,11 @@ const Screen = forwardRef(
857
882
  scrollable && !Footer && !isTab && { paddingBottom: bottomInset },
858
883
  scrollable && hasDuoTabInset && { paddingBottom: duoTabInset },
859
884
  scrollable && contentInsetStyle,
860
- useDuoGlass && !Header && { paddingTop: heightHeader },
885
+ useDuoGlass && {
886
+ paddingTop:
887
+ heightHeader +
888
+ (floatHeaderComponent ? headerComponentHeight : 0),
889
+ },
861
890
  scrollViewProps?.contentContainerStyle,
862
891
  ]}
863
892
  >
package/Layout/styles.ts CHANGED
@@ -91,6 +91,12 @@ export default StyleSheet.create({
91
91
  },
92
92
  }),
93
93
  },
94
+ floatingHeaderComponent: {
95
+ position: 'absolute',
96
+ left: 0,
97
+ right: 0,
98
+ zIndex: 1,
99
+ },
94
100
  footerClip: {
95
101
  marginTop: -Spacing.XL,
96
102
  paddingTop: Spacing.XL,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.168.1-beta.8",
3
+ "version": "0.168.1-duo.1",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {},