Skip to content

Commit 70e986b

Browse files
Merge branch 'main' into imgbot
2 parents 265cd68 + 2207a7d commit 70e986b

12 files changed

Lines changed: 272 additions & 70 deletions

File tree

.github/workflows/create_and_publish_releases.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ jobs:
1919

2020
- name: Setup git user
2121
run: |
22-
git config user.name "Paul Sojan"
23-
git config user.email "paul.sojan@bigbinary.com"
22+
git config user.name "Shashank Bhatotia"
23+
git config user.email "shashank.bhatotia@bigbinary.com"
2424
- name: Setup NodeJS LTS version
2525
uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516
2626
with:
@@ -29,9 +29,6 @@ jobs:
2929
- name: Setup the project
3030
run: yarn install
3131

32-
- name: Generate production build
33-
run: yarn build
34-
3532
- name: Prefix version tag with "v"
3633
run: yarn config set version-tag-prefix "v"
3734

@@ -50,6 +47,9 @@ jobs:
5047
if: ${{ contains(github.event.pull_request.labels.*.name, 'major') }}
5148
run: yarn version --major
5249

50+
- name: Generate production build
51+
run: yarn build
52+
5353
- name: Get the package version from package.json
5454
uses: tyankatsu0105/read-package-version-actions@5aad2bb630a577ee4255546eb3ee0593df68f6ca
5555
id: package-version

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bigbinary/neetoui-rn",
3-
"version": "2.0.1",
3+
"version": "2.0.6",
44
"main": ".",
55
"author": "BigBinary",
66
"license": "MIT",

src/components/Avatar.jsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import Animated, {
1010
} from "react-native-reanimated";
1111
import { moderateScale } from "react-native-size-matters";
1212

13-
import { Typography, Container } from "@components";
13+
import { Container } from "./Container";
14+
import { Typography } from "./Typography";
1415

1516
/**
1617
* Avatars can be used to represent people in a graphical way.
@@ -97,12 +98,14 @@ export const Avatar = ({
9798
{acronym.toUpperCase()}
9899
</Typography>
99100
</Container>
100-
<Animated.Image
101-
source={{ uri: imageUrl }}
102-
style={profileImageStyle}
103-
onLoad={() => (opacity.value = 1)}
104-
{...rest}
105-
/>
101+
{imageUrl && (
102+
<Animated.Image
103+
source={{ uri: imageUrl }}
104+
style={profileImageStyle}
105+
onLoad={() => (opacity.value = 1)}
106+
{...rest}
107+
/>
108+
)}
106109
</Container>
107110
);
108111
};

src/components/BottomSheet.jsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import React, { useCallback, useEffect, useMemo, useState } from "react";
2-
import { StyleSheet, FlatList, Keyboard } from "react-native";
2+
import {
3+
StyleSheet,
4+
FlatList,
5+
Keyboard,
6+
InteractionManager,
7+
} from "react-native";
38

49
import PropTypes from "prop-types";
510
import Modal from "react-native-modal";
@@ -176,6 +181,17 @@ export const BottomSheet = ({
176181
...rest
177182
}) => {
178183
const [searchText, setSearchText] = useState("");
184+
const [isReady, setIsReady] = useState(false);
185+
186+
useEffect(() => {
187+
if (isVisible) {
188+
InteractionManager.runAfterInteractions(() => {
189+
setIsReady(true);
190+
});
191+
} else {
192+
setIsReady(false);
193+
}
194+
}, [isVisible]);
179195

180196
const getLabel = useCallback(
181197
(item, index) => item?.label || labelExtractor(item, index) || item,
@@ -214,7 +230,7 @@ export const BottomSheet = ({
214230
avoidKeyboard
215231
hideModalContentWhileAnimating
216232
useNativeDriver
217-
isVisible={isVisible}
233+
isVisible={isVisible && isReady}
218234
style={styles.modalStyle}
219235
onRequestClose={hide}
220236
onBackdropPress={() => {

src/components/ChatInput/ChatInput.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ const labels = {
114114

115115
const convertMentionsToHTMLAndPlainText = ({ suggestions, value }) => {
116116
const mentionsRegex = new RegExp(/@\[[^)]*\)/g);
117-
let html = `<p>${value}</p>`;
117+
let html = `<p>${value.replace(/\n/g, "<br>")}</p>`; // Replace newlines with <br> for HTML output
118118
let plainText = value;
119119
const allMentions = html.matchAll(mentionsRegex);
120120

@@ -140,7 +140,6 @@ const convertMentionsToHTMLAndPlainText = ({ suggestions, value }) => {
140140

141141
return { html, plainText };
142142
};
143-
144143
export const ChatInput = forwardRef(
145144
(
146145
{

src/components/RichTextEditor.jsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import {
99
import styled from "styled-components/native";
1010
import { space, flexbox, border, layout } from "styled-system";
1111

12-
import { Container } from "@components";
1312
import { useKeyboard } from "@hooks";
1413

14+
import Container from "./Container";
15+
1516
export const ScrollView = styled.ScrollView.attrs(() => ({
1617
keyboardShouldPersistTaps: "handled",
1718
showsVerticalScrollIndicator: true,
@@ -80,13 +81,17 @@ export const RichTextEditor = ({
8081
toolbarActions,
8182
editorProps,
8283
toolBarProps,
84+
richTextRef: externalRichTextRef,
8385
...rest
8486
}) => {
85-
const richTextRef = useRef();
87+
const internalRichTextRef = useRef();
8688
const keyboardHeight = useKeyboard();
8789
const [toolbarVisible, setToolbarVisible] = useState(false);
8890
const showToolbar = keyboardHeight > 0 && toolbarVisible;
8991

92+
// Use the external ref if provided, otherwise use the internal ref
93+
const richTextRef = externalRichTextRef || internalRichTextRef;
94+
9095
const computeToolbarActions = () => {
9196
const actionItems = [];
9297
toolbarActions?.map(actionItem => {
@@ -116,11 +121,11 @@ export const RichTextEditor = ({
116121
onChange={onChange}
117122
onBlur={() => {
118123
setToolbarVisible(false);
119-
editorProps?.onBlurFn();
124+
editorProps?.onBlurFn?.();
120125
}}
121126
onFocus={() => {
122127
setToolbarVisible(true);
123-
editorProps?.onFocusFn();
128+
editorProps?.onFocusFn?.();
124129
}}
125130
{...editorProps}
126131
/>
@@ -160,4 +165,8 @@ RichTextEditor.propTypes = {
160165
toolBarProps: PropTypes.object,
161166
editorWrapperStyle: PropTypes.object,
162167
toolbarWrapperStyle: PropTypes.object,
168+
/**
169+
* Ref object to control the editor from outside the component.
170+
*/
171+
richTextRef: PropTypes.object,
163172
};

src/components/SearchBar.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ export const SearchBar = ({
137137
}}
138138
{...searchbarProps}
139139
/>
140-
{showCancelButton && (
140+
{showCancelButton && searchText.length > 0 && (
141141
<Container>
142142
<Touchable
143143
flexGrow={1}

src/components/SegmentedTopBar/Indicator.jsx

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect } from "react";
1+
import React, { useEffect, useRef } from "react";
22
import { StyleSheet } from "react-native";
33

44
import PropTypes from "prop-types";
@@ -14,32 +14,62 @@ import { theme } from "@theme";
1414

1515
const springConfig = {
1616
mass: 1,
17-
overshootClamping: true,
17+
damping: 18,
18+
stiffness: 100,
19+
overshootClamping: false,
1820
restSpeedThreshold: 0.5,
1921
restDisplacementThreshold: 0.5,
2022
};
2123

2224
const spacing = moderateScale(6);
2325

2426
export const Indicator = ({ measure }) => {
25-
const { x, width, height } = measure;
26-
27+
const firstRender = useRef(true);
2728
const translateX = useSharedValue(0);
2829
const animatedWidth = useSharedValue(0);
2930

3031
useEffect(() => {
31-
cancelAnimation(translateX);
32-
cancelAnimation(animatedWidth);
32+
if (!measure) return;
33+
34+
const { x, width } = measure;
35+
36+
if (firstRender.current) {
37+
if (translateX.value === 0 && x > 0) {
38+
translateX.value = x + spacing / 2;
39+
}
40+
41+
if (animatedWidth.value === 0 && width > 0) {
42+
animatedWidth.value = width - spacing;
43+
}
3344

34-
translateX.value = withSpring(x + spacing / 2, springConfig);
35-
animatedWidth.value = withSpring(width - spacing, springConfig);
36-
}, [animatedWidth, translateX, width, x]);
45+
firstRender.current = false;
46+
} else {
47+
// Cancel any ongoing animations first
48+
cancelAnimation(translateX);
49+
cancelAnimation(animatedWidth);
50+
51+
translateX.value = withSpring(x + spacing / 2, springConfig);
52+
animatedWidth.value = withSpring(width - spacing, springConfig);
53+
}
54+
}, [measure]);
3755

3856
const tabTranslateAnimatedStyles = useAnimatedStyle(() => ({
3957
transform: [{ translateX: translateX.value }],
4058
width: animatedWidth.value,
4159
}));
4260

61+
// Guard against undefined measure
62+
if (
63+
!measure ||
64+
typeof measure.x !== "number" ||
65+
typeof measure.width !== "number" ||
66+
typeof measure.height !== "number"
67+
) {
68+
return null;
69+
}
70+
71+
const { height } = measure;
72+
4373
return (
4474
<Animated.View
4575
style={[
Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,63 @@
11
import React, { forwardRef, useCallback } from "react";
2-
import { View } from "react-native";
2+
import { View, StyleSheet } from "react-native";
33

44
import PropTypes from "prop-types";
5+
import { moderateScale } from "react-native-size-matters";
56

67
import { Typography, Touchable } from "@components";
78

8-
export const Tab = forwardRef(({ label, value, navigation, flex }, ref) => {
9-
const handleOnPress = useCallback(
10-
() => navigation.navigate(value),
11-
[navigation, value]
12-
);
13-
14-
return (
15-
<View ref={ref} style={{ flex }}>
16-
<Touchable flex={1} justifyContent="center" onPress={handleOnPress}>
17-
<Typography
18-
fontFamily="sf500"
19-
fontSize="xs"
20-
numberOfLines={1}
21-
textAlign="center"
9+
export const Tab = forwardRef(
10+
({ label, value, navigation, flex, count }, ref) => {
11+
const handleOnPress = useCallback(
12+
() => navigation.navigate(value),
13+
[navigation, value]
14+
);
15+
16+
return (
17+
<View
18+
ref={ref}
19+
style={[
20+
styles.container,
21+
{
22+
flex,
23+
minWidth: count !== undefined ? moderateScale(56) : undefined,
24+
},
25+
]}
26+
>
27+
<Touchable
28+
alignItems="center"
29+
flex={1}
30+
justifyContent="center"
31+
onPress={handleOnPress}
2232
>
23-
{label}
24-
</Typography>
25-
</Touchable>
26-
</View>
27-
);
33+
<Typography
34+
fontFamily="sf600"
35+
fontSize="xs"
36+
numberOfLines={1}
37+
textAlign="center"
38+
>
39+
{label}
40+
</Typography>
41+
{count !== undefined && (
42+
<Typography
43+
fontFamily="sf500"
44+
fontSize="xs"
45+
numberOfLines={1}
46+
textAlign="center"
47+
>
48+
({count})
49+
</Typography>
50+
)}
51+
</Touchable>
52+
</View>
53+
);
54+
}
55+
);
56+
57+
const styles = StyleSheet.create({
58+
container: {
59+
height: "100%",
60+
},
2861
});
2962

3063
Tab.displayName = "Tab";
@@ -34,4 +67,9 @@ Tab.propTypes = {
3467
label: PropTypes.string.isRequired,
3568
value: PropTypes.string.isRequired,
3669
navigation: PropTypes.object,
70+
count: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
71+
};
72+
73+
Tab.defaultProps = {
74+
flex: 1,
3775
};

0 commit comments

Comments
 (0)