softchatjs-react-native
Version:
React native UI SDK for softchatjs-core. Create a free account at: https://www.softchatjs.com
539 lines (522 loc) • 16.3 kB
JavaScript
// src/components/Chat/ChatItem/Quoted.tsx
import React8 from "react";
import {
StyleSheet as StyleSheet2,
View as View4,
TouchableOpacity as TouchableOpacity2,
Text as Text4
} from "react-native";
import {
AttachmentTypes,
MediaType
} from "softchatjs-core";
// src/components/Chat/ChatItem/Sticker.tsx
import React, { useCallback } from "react";
import { Image } from "expo-image";
function Sticker(props) {
const { message } = props;
const renderSicker = useCallback(() => {
return /* @__PURE__ */ React.createElement(
Image,
{
source: { uri: message.attachedMedia[0].mediaUrl },
cachePolicy: "disk",
style: { height: 70, width: 70, borderRadius: 8 }
}
);
}, []);
return /* @__PURE__ */ React.createElement(React.Fragment, null, renderSicker());
}
// src/components/Chat/MessageAvatar.tsx
import React5 from "react";
import { TouchableOpacity, Text as Text2 } from "react-native";
// src/constants/Colors.ts
var Colors = {
greyLighter: "#F0F0F0"
};
// src/components/Chat/MessageAvatar.tsx
import { Image as Image2 } from "expo-image";
// src/contexts/ChatProvider.tsx
import React4, { createContext as createContext3, useContext as useContext3 } from "react";
// src/contexts/ModalProvider.tsx
import React2, { createContext, useContext, useState } from "react";
import {
Modal,
View
} from "react-native";
var initial = {
displayModal: () => {
},
resetModal: () => {
},
modalProps: {
dismissable: true,
justifyContent: "center",
children: null,
animation: "slide",
containerWidth: "100%"
}
};
var ModalProviderContext = createContext(initial);
// src/theme/colors.ts
var teal = {
50: "#DCF2F0",
100: "#A9DFD8",
200: "#73CABE",
300: "#3AB4A4",
400: "#00A391",
500: "#00927E",
600: "#008572",
700: "#007662",
800: "#006654",
900: "#004A38"
};
var green = {
50: "#E6F5E4",
100: "#C2E6BD",
200: "#9AD693",
300: "#6FC666",
400: "#4ABA42",
500: "#17AE13",
600: "#029F04",
700: "#008D00",
800: "#007C00",
900: "#005E00"
};
var grey = {
50: "#F6F6FF",
100: "#F2F1FF",
200: "#EBEBF9",
300: "#CAC9D7",
400: "#ACACB9",
500: "#82818F",
600: "#6D6D7A",
700: "#4D4D59",
800: "#2B2B36",
900: "#21222D",
A100: "#1D1E26"
};
var stone = {
50: "#F8F8F8",
100: "#EFEFEF",
200: "#E8E8E8",
300: "#D9D9D9",
400: "#D2D2D2",
500: "#A0A0A0",
600: "#87888C",
700: "#2C2D33",
800: "#1D1E26",
900: "#171821"
};
// src/theme/index.ts
var theme = {
background: {
primary: stone[900],
secondary: grey[900],
disabled: grey[800]
},
text: {
primary: "black",
secondary: stone[200],
disabled: stone[500]
},
action: {
primary: teal[50],
secondary: stone[300]
},
chatBubble: {
left: {
bgColor: grey[900],
messageColor: stone[200],
messageTimeColor: "grey",
replyBorderColor: stone[200]
},
right: {
bgColor: "#474952",
messageColor: "white",
messageTimeColor: "grey",
replyBorderColor: green[900]
}
},
icon: "white",
divider: stone[700]
};
var theme_default = theme;
// src/contexts/MessageStateContext.tsx
import React3, {
createContext as createContext2,
useState as useState2,
useContext as useContext2
} from "react";
import { Audio } from "expo-av";
// src/constants/defaultUser.ts
var defaultUser_default = {
id: "",
uid: "",
username: "",
firstname: "",
lastname: "",
profileUrl: "",
color: "",
custom: {}
};
// src/contexts/MessageStateContext.tsx
var initialMessageStateContext = {
globalTextMessage: "",
setGlobalTextMessage: () => {
},
stickers: [],
setStickers: () => {
},
pendingMessages: [],
addNewPendingMessages: (message) => {
},
removePendingMessage: (messageId) => {
},
updatePendingMessage: (messageId, message) => {
},
playVoiceMessage: (media) => {
},
pauseVoiceMessage: () => {
},
resumeVoiceMessage: () => {
},
audioState: null,
unload: () => {
},
sound: null,
activeVoiceMessage: null,
avPlayBackStatus: null,
userMeta: defaultUser_default,
setUserMeta: () => {
},
conversationList: [],
setConversationList: () => {
}
};
var MessageStateContext = createContext2(
initialMessageStateContext
);
// src/contexts/ChatProvider.tsx
var ConfigContext = createContext3({
theme: theme_default,
client: null,
fontFamily: void 0,
fontScale: 1
});
function useConfig() {
return useContext3(ConfigContext);
}
// src/components/Chat/MessageAvatar.tsx
function MessageAvatar(props) {
const { imgUrl, initials, size = 40, style } = props;
const { fontFamily } = useConfig();
return /* @__PURE__ */ React5.createElement(
TouchableOpacity,
{
style: {
height: size,
width: size,
borderRadius: size,
backgroundColor: "black",
alignItems: "center",
justifyContent: "center",
...style
}
},
imgUrl ? /* @__PURE__ */ React5.createElement(
Image2,
{
source: { uri: imgUrl },
cachePolicy: "disk",
style: {
height: size,
width: size,
borderRadius: size,
backgroundColor: Colors.greyLighter
}
}
) : /* @__PURE__ */ React5.createElement(
Text2,
{
style: {
fontSize: size / 2,
textTransform: "uppercase",
color: "white",
fontFamily
}
},
initials
)
);
}
// src/utils/index.ts
import moment from "moment";
import { MessageStates } from "softchatjs-core";
var truncate = (str, len) => {
return str.length > len ? str.substring(0, len) + "..." : str;
};
function convertToMinutes(seconds) {
var _seconds = Number(seconds.toFixed(0));
const minutes = Math.floor(_seconds / 60);
const remainingSeconds = _seconds % 60;
const paddedMinutes = String(minutes).padStart(2, "0");
const paddedSeconds = String(remainingSeconds).padStart(2, "0");
return `${paddedMinutes}:${paddedSeconds}`;
}
// src/assets/icons.tsx
import React6 from "react";
import { View as View2 } from "react-native";
import { Svg, Path, G, Defs, ClipPath, Rect } from "react-native-svg";
function MicIcon(props) {
const { size = 25, color = "black" } = props;
return /* @__PURE__ */ React6.createElement(Svg, { width: size, height: size, viewBox: "0 0 256 256", fill: "none" }, /* @__PURE__ */ React6.createElement(
Path,
{
d: "M128 176C140.726 175.987 152.928 170.925 161.927 161.927C170.925 152.928 175.987 140.726 176 128V64C176 51.2696 170.943 39.0606 161.941 30.0589C152.939 21.0571 140.73 16 128 16C115.27 16 103.061 21.0571 94.0589 30.0589C85.0571 39.0606 80 51.2696 80 64V128C80.0132 140.726 85.0746 152.928 94.0735 161.927C103.072 170.925 115.274 175.987 128 176ZM96 64C96 55.5131 99.3714 47.3737 105.373 41.3726C111.374 35.3714 119.513 32 128 32C136.487 32 144.626 35.3714 150.627 41.3726C156.629 47.3737 160 55.5131 160 64V128C160 136.487 156.629 144.626 150.627 150.627C144.626 156.629 136.487 160 128 160C119.513 160 111.374 156.629 105.373 150.627C99.3714 144.626 96 136.487 96 128V64ZM136 207.6V232C136 234.122 135.157 236.157 133.657 237.657C132.157 239.157 130.122 240 128 240C125.878 240 123.843 239.157 122.343 237.657C120.843 236.157 120 234.122 120 232V207.6C100.276 205.593 81.9976 196.344 68.6984 181.641C55.3992 166.938 48.0244 147.825 48 128C48 125.878 48.8429 123.843 50.3431 122.343C51.8434 120.843 53.8783 120 56 120C58.1217 120 60.1566 120.843 61.6569 122.343C63.1571 123.843 64 125.878 64 128C64 144.974 70.7428 161.253 82.7452 173.255C94.7475 185.257 111.026 192 128 192C144.974 192 161.253 185.257 173.255 173.255C185.257 161.253 192 144.974 192 128C192 125.878 192.843 123.843 194.343 122.343C195.843 120.843 197.878 120 200 120C202.122 120 204.157 120.843 205.657 122.343C207.157 123.843 208 125.878 208 128C207.976 147.825 200.601 166.938 187.302 181.641C174.002 196.344 155.724 205.593 136 207.6Z",
fill: color
}
));
}
var LinkIcon = (props) => {
const { size = 25, color = "black" } = props;
return /* @__PURE__ */ React6.createElement(Svg, { width: size, height: size, viewBox: "0 0 24 24", fill: "none" }, /* @__PURE__ */ React6.createElement(
Path,
{
d: "M11 17H7C5.61667 17 4.43767 16.5123 3.463 15.537C2.48833 14.5617 2.00067 13.3827 2 12C1.99933 10.6173 2.487 9.43833 3.463 8.463C4.439 7.48767 5.618 7 7 7H11V9H7C6.16667 9 5.45833 9.29167 4.875 9.875C4.29167 10.4583 4 11.1667 4 12C4 12.8333 4.29167 13.5417 4.875 14.125C5.45833 14.7083 6.16667 15 7 15H11V17ZM8 13V11H16V13H8ZM13 17V15H17C17.8333 15 18.5417 14.7083 19.125 14.125C19.7083 13.5417 20 12.8333 20 12C20 11.1667 19.7083 10.4583 19.125 9.875C18.5417 9.29167 17.8333 9 17 9H13V7H17C18.3833 7 19.5627 7.48767 20.538 8.463C21.5133 9.43833 22.0007 10.6173 22 12C21.9993 13.3827 21.5117 14.562 20.537 15.538C19.5623 16.514 18.3833 17.0013 17 17H13Z",
fill: color
}
));
};
// src/components/Chat/ChatItem/Preview.tsx
import { View as View3, Text as Text3 } from "react-native";
import React7 from "react";
import { LinkPreview } from "@flyerhq/react-native-link-preview";
import { Image as Image3 } from "expo-image";
function Preview({
message,
color
}) {
const { theme: theme2, fontFamily, fontScale } = useConfig();
const urlRegex = /(https?:\/\/[^\s]+)/gi;
if (!urlRegex.test(message)) {
return null;
}
return /* @__PURE__ */ React7.createElement(
LinkPreview,
{
text: message,
renderLinkPreview: (data) => /* @__PURE__ */ React7.createElement(
View3,
{
style: {
flexDirection: "row",
alignItems: "flex-start",
width: "100%",
minWidth: 220,
// marginBottom: 5,
// borderWidth: 1,
// borderColor: theme?.icon,
padding: 8,
borderRadius: 10
}
},
data.previewData?.image?.url ? /* @__PURE__ */ React7.createElement(View3, { style: { height: 80, width: 80, borderRadius: 10, backgroundColor: "lightgrey", alignItems: "center", justifyContent: "center" } }, /* @__PURE__ */ React7.createElement(LinkIcon, { color: "black" })) : /* @__PURE__ */ React7.createElement(
Image3,
{
source: { uri: data.previewData?.image?.url },
cachePolicy: "disk",
style: { backgroundColor: "lightgrey", borderRadius: 10, height: 80, width: 80 }
}
),
/* @__PURE__ */ React7.createElement(View3, { style: { flex: 1, width: "100%" } }, /* @__PURE__ */ React7.createElement(
Text3,
{
style: {
display: data.previewData?.title ? "flex" : "none",
flex: 1,
color,
marginStart: 8,
textDecorationLine: "underline",
fontFamily
}
},
data.previewData?.title
), /* @__PURE__ */ React7.createElement(
Text3,
{
style: {
display: data.previewData?.description ? "flex" : "none",
flex: 1,
color,
fontSize: 12 * fontScale,
marginStart: 8,
textDecorationLine: "underline",
fontFamily
}
},
truncate(data.previewData?.description || "", 100)
))
)
}
);
}
// src/components/Chat/ChatItem/Quoted.tsx
function Quoted(props) {
const { quotedMessage, layout, onPress, theme: theme2, position, chatUserId } = props;
const { fontFamily, fontScale } = useConfig();
if (!quotedMessage) {
return null;
}
const renderMediaPreview = () => {
switch (quotedMessage.attachmentType) {
case AttachmentTypes.STICKER:
return /* @__PURE__ */ React8.createElement(Sticker, { message: quotedMessage });
case AttachmentTypes.MEDIA:
var mediaType = quotedMessage.attachedMedia[0]?.type;
if (mediaType === MediaType.IMAGE) {
return /* @__PURE__ */ React8.createElement(Sticker, { message: quotedMessage });
} else if (mediaType === MediaType.AUDIO) {
return /* @__PURE__ */ React8.createElement(View4, { style: { flexDirection: "row", alignItems: "center" } }, /* @__PURE__ */ React8.createElement(MicIcon, { size: 20, color: "white" }), /* @__PURE__ */ React8.createElement(
Text4,
{
style: {
color: "white",
marginStart: 5
}
},
convertToMinutes(
quotedMessage.attachedMedia[0]?.meta?.audioDurationSec ?? 0
)
));
}
}
};
if (layout === "stacked") {
return /* @__PURE__ */ React8.createElement(
TouchableOpacity2,
{
onPress: () => onPress?.(),
style: { flexDirection: "row", alignItems: "center" }
},
/* @__PURE__ */ React8.createElement(
View4,
{
style: {
height: "70%",
width: "100%",
flex: 1,
borderLeftWidth: 2,
borderTopWidth: 2,
borderTopLeftRadius: 10,
marginStart: 22,
borderColor: theme2?.divider
}
}
),
/* @__PURE__ */ React8.createElement(
View4,
{
style: {
width: "85%",
top: -8,
flexDirection: "row",
alignItems: "center"
}
},
/* @__PURE__ */ React8.createElement(
MessageAvatar,
{
size: 20,
initials: quotedMessage?.messageOwner?.username.substring(0, 2),
imgUrl: quotedMessage.messageOwner.profileUrl,
style: {
marginEnd: 5,
backgroundColor: quotedMessage.messageOwner.color
}
}
),
quotedMessage.message ? /* @__PURE__ */ React8.createElement(Text4, { style: { flex: 1, color: theme2?.text.disabled, fontFamily } }, truncate(quotedMessage?.message, 100)) : /* @__PURE__ */ React8.createElement(React8.Fragment, null, renderMediaPreview())
)
);
}
let rightStyle = {
borderRadius: 10,
alignItems: "flex-end",
padding: 8,
backgroundColor: theme2?.chatBubble.right.bgColor
};
let leftStyle = {
padding: 8,
borderRadius: 10,
alignItems: "flex-start",
backgroundColor: theme2?.chatBubble.left.bgColor
};
return /* @__PURE__ */ React8.createElement(
TouchableOpacity2,
{
onPress: () => onPress?.(),
style: [
{
backgroundColor: "rgba(0,0,0,.3)",
padding: 8,
marginTop: 8,
marginLeft: 8,
marginRight: 8,
borderRadius: 10,
borderLeftWidth: 4,
borderTopWidth: 4,
borderTopColor: "transparent",
borderLeftColor: quotedMessage.messageOwner.color
}
]
},
/* @__PURE__ */ React8.createElement(
Text4,
{
style: {
color: quotedMessage.messageOwner.color,
textTransform: "capitalize",
fontFamily,
marginBottom: 5,
textShadowColor: "rgba(0, 0, 0, 0.3)",
textShadowOffset: { width: 0.5, height: 0.5 },
textShadowRadius: 5
}
},
quotedMessage.messageOwner.uid === chatUserId ? "You" : quotedMessage.messageOwner.username
),
/* @__PURE__ */ React8.createElement(React8.Fragment, null, renderMediaPreview()),
/* @__PURE__ */ React8.createElement(
Preview,
{
message: quotedMessage.message,
color: position === "left" ? theme2?.chatBubble.left.messageColor : theme2?.chatBubble.right.messageColor
}
),
quotedMessage.message && /* @__PURE__ */ React8.createElement(
Text4,
{
style: {
display: quotedMessage.message ? "flex" : "none",
fontFamily,
color: "white",
fontSize: 14 * fontScale,
marginTop: 5
}
},
quotedMessage.message
)
);
}
var styles = StyleSheet2.create({
main: {
padding: 5,
borderLeftWidth: 2,
marginBottom: 5
}
});
export {
Quoted as default
};
//# sourceMappingURL=Quoted.mjs.map