@momo-kits/foundation 0.168.1-beta.24 → 0.168.1-beta.29
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/Popup/PopupNotify.tsx +27 -2
- package/Popup/types.ts +7 -0
- package/Popup/utils.ts +46 -1
- package/package.json +7 -7
package/Popup/PopupNotify.tsx
CHANGED
|
@@ -8,12 +8,18 @@ import { Image } from '../Image';
|
|
|
8
8
|
import { Text, useScaleSize } from '../Text';
|
|
9
9
|
import { PopupNotifyProps } from './types';
|
|
10
10
|
import { scheduleOnRN } from 'react-native-worklets';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
getPopupRadius,
|
|
13
|
+
splitHighlightText,
|
|
14
|
+
usePopupMaxHeight,
|
|
15
|
+
usePopupWidth,
|
|
16
|
+
} from './utils';
|
|
12
17
|
|
|
13
18
|
const PopupNotify: React.FC<PopupNotifyProps> = ({
|
|
14
19
|
image,
|
|
15
20
|
title = 'Title',
|
|
16
21
|
description = 'Description',
|
|
22
|
+
highlightText,
|
|
17
23
|
error,
|
|
18
24
|
secondary,
|
|
19
25
|
primary,
|
|
@@ -135,6 +141,25 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
|
|
|
135
141
|
return renderColumn();
|
|
136
142
|
};
|
|
137
143
|
|
|
144
|
+
/**
|
|
145
|
+
* build description text, highlighted keywords keep size/lineHeight and use weight 600
|
|
146
|
+
*/
|
|
147
|
+
const renderDescription = (text: string) => {
|
|
148
|
+
const segments = splitHighlightText(text, highlightText);
|
|
149
|
+
if (!segments) {
|
|
150
|
+
return text;
|
|
151
|
+
}
|
|
152
|
+
return segments.map((segment, index) =>
|
|
153
|
+
segment.highlight ? (
|
|
154
|
+
<Text key={index} typography={'header_s_semibold'}>
|
|
155
|
+
{segment.text}
|
|
156
|
+
</Text>
|
|
157
|
+
) : (
|
|
158
|
+
segment.text
|
|
159
|
+
),
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
|
|
138
163
|
/**
|
|
139
164
|
* build close action
|
|
140
165
|
*/
|
|
@@ -200,7 +225,7 @@ const PopupNotify: React.FC<PopupNotifyProps> = ({
|
|
|
200
225
|
}
|
|
201
226
|
}}
|
|
202
227
|
>
|
|
203
|
-
{description}
|
|
228
|
+
{renderDescription(description)}
|
|
204
229
|
</Text>
|
|
205
230
|
) : (
|
|
206
231
|
description
|
package/Popup/types.ts
CHANGED
|
@@ -20,6 +20,13 @@ export type PopupNotifyProps = {
|
|
|
20
20
|
*/
|
|
21
21
|
description?: string | React.ReactNode;
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* `highlightText`: Optional. List of words/phrases within `description` to be rendered in semibold.
|
|
25
|
+
* Only applies when `description` is a string. Matching is whole-word and case-sensitive;
|
|
26
|
+
* every occurrence of each string is highlighted.
|
|
27
|
+
*/
|
|
28
|
+
highlightText?: string[];
|
|
29
|
+
|
|
23
30
|
/**
|
|
24
31
|
* `error`: Optional. Represents additional error text to be displayed in the PopupNotify component.
|
|
25
32
|
*/
|
package/Popup/utils.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
|
3
3
|
import { Radius, Spacing } from '../Consts';
|
|
4
4
|
import { getDuoModalBounds, isIPhoneDuo } from '../Application/device';
|
|
5
5
|
|
|
6
|
+
type HighlightSegment = { text: string; highlight: boolean };
|
|
7
|
+
|
|
6
8
|
const usePopupWidth = () => {
|
|
7
9
|
const insets = useSafeAreaInsets();
|
|
8
10
|
const { width, height } = useWindowDimensions();
|
|
@@ -23,4 +25,47 @@ const usePopupMaxHeight = () => {
|
|
|
23
25
|
|
|
24
26
|
const getPopupRadius = () => (isIPhoneDuo() ? Radius.XL : Radius.L);
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
const isWordChar = (char?: string) =>
|
|
29
|
+
!!char && (char.toLowerCase() !== char.toUpperCase() || /[0-9_]/.test(char));
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Split `text` into plain/highlighted segments (same matching as Information `highlightText`):
|
|
33
|
+
* whole-word, case-sensitive, every occurrence, longest keyword first.
|
|
34
|
+
* Returns `undefined` when there is nothing to highlight.
|
|
35
|
+
*/
|
|
36
|
+
const splitHighlightText = (
|
|
37
|
+
text: string,
|
|
38
|
+
highlightText?: string[],
|
|
39
|
+
): HighlightSegment[] | undefined => {
|
|
40
|
+
const keywords = highlightText?.filter(
|
|
41
|
+
keyword => typeof keyword === 'string' && keyword,
|
|
42
|
+
);
|
|
43
|
+
if (!keywords?.length) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
const pattern = [...keywords]
|
|
47
|
+
.sort((a, b) => b.length - a.length)
|
|
48
|
+
.map(keyword => keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
|
49
|
+
.join('|');
|
|
50
|
+
const regex = new RegExp(pattern, 'g');
|
|
51
|
+
const segments: HighlightSegment[] = [];
|
|
52
|
+
let lastIndex = 0;
|
|
53
|
+
let match;
|
|
54
|
+
while ((match = regex.exec(text))) {
|
|
55
|
+
const start = match.index;
|
|
56
|
+
const end = start + match[0].length;
|
|
57
|
+
if (isWordChar(text[start - 1]) || isWordChar(text[end])) {
|
|
58
|
+
regex.lastIndex = start + 1;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (start > lastIndex) {
|
|
62
|
+
segments.push({ text: text.slice(lastIndex, start), highlight: false });
|
|
63
|
+
}
|
|
64
|
+
segments.push({ text: match[0], highlight: true });
|
|
65
|
+
lastIndex = end;
|
|
66
|
+
}
|
|
67
|
+
segments.push({ text: text.slice(lastIndex), highlight: false });
|
|
68
|
+
return segments;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export { usePopupWidth, usePopupMaxHeight, getPopupRadius, splitHighlightText };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@momo-kits/foundation",
|
|
3
|
-
"version": "0.168.1-beta.
|
|
3
|
+
"version": "0.168.1-beta.29",
|
|
4
4
|
"description": "React Native Component Kits",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"scripts": {},
|
|
@@ -8,21 +8,21 @@
|
|
|
8
8
|
"@momo-kits/foundation"
|
|
9
9
|
],
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"react-native-fast-image": "git+https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-fast-image.git#v8.11.0",
|
|
12
11
|
"@react-navigation/bottom-tabs": "7.4.2",
|
|
13
12
|
"@react-navigation/core": "7.12.1",
|
|
14
13
|
"@react-navigation/elements": "2.5.2",
|
|
15
14
|
"@react-navigation/native": "7.1.14",
|
|
16
15
|
"@react-navigation/routers": "7.4.1",
|
|
17
16
|
"@react-navigation/stack": "7.4.2",
|
|
17
|
+
"@shopify/flash-list": "2.1.0",
|
|
18
|
+
"lottie-react-native": "7.2.4",
|
|
19
|
+
"react-native-fast-image": "git+https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-fast-image.git#v8.11.0",
|
|
18
20
|
"react-native-gesture-handler": "2.27.1",
|
|
19
21
|
"react-native-linear-gradient": "git+https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-linear-gradient#v3.0.0",
|
|
20
22
|
"react-native-reanimated": "4.2.2",
|
|
21
|
-
"react-native-worklets": "0.6.1",
|
|
22
|
-
"react-native-safe-area-context": "5.5.2",
|
|
23
23
|
"react-native-reserved-regions": "0.2.0",
|
|
24
|
-
"
|
|
25
|
-
"
|
|
24
|
+
"react-native-safe-area-context": "5.5.2",
|
|
25
|
+
"react-native-worklets": "0.6.1"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react-native": "*",
|
|
@@ -35,4 +35,4 @@
|
|
|
35
35
|
"registry": "https://registry.npmjs.org/"
|
|
36
36
|
},
|
|
37
37
|
"license": "MoMo"
|
|
38
|
-
}
|
|
38
|
+
}
|