@sendbird/uikit-react-native
Version:
Sendbird UIKit for React Native: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.
303 lines (301 loc) • 11.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _message = require("@sendbird/chat/message");
var _uikitReactNativeFoundation = require("@sendbird/uikit-react-native-foundation");
var _uikitUtils = require("@sendbird/uikit-utils");
var _constants = require("../../constants");
var _useChannelInputItems = require("../../hooks/useChannelInputItems");
var _useContext = require("../../hooks/useContext");
var _SBUUtils = _interopRequireDefault(require("../../libs/SBUUtils"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
const SendInput = /*#__PURE__*/(0, _react.forwardRef)(function SendInput({
style,
VoiceMessageInput,
MessageToReplyPreview,
AttachmentsButton,
onPressSendUserMessage,
onPressSendFileMessage,
text,
onChangeText,
onSelectionChange,
mentionedUsers,
inputDisabled,
inputFrozen,
inputMuted,
channel,
messageToReply,
setMessageToReply,
messageForThread,
partialTextInputProps
}, ref) {
const {
playerService,
recorderService
} = (0, _useContext.usePlatformService)();
const {
mentionManager,
sbOptions
} = (0, _useContext.useSendbirdChat)();
const {
STRINGS
} = (0, _useContext.useLocalization)();
const {
openSheet
} = (0, _uikitReactNativeFoundation.useBottomSheet)();
const toast = (0, _uikitReactNativeFoundation.useToast)();
const {
onClose,
onDismiss,
visible: voiceMessageInputVisible,
setVisible: setVoiceMessageInputVisible
} = (0, _uikitUtils.useDeferredModalState)();
const messageReplyParams = (0, _uikitUtils.useIIFE)(() => {
const {
groupChannel
} = sbOptions.uikit;
if (channel.isGroupChannel()) {
if (groupChannel.channel.replyType === 'quote_reply' && messageToReply) {
return {
parentMessageId: messageToReply.messageId,
isReplyToChannel: true
};
} else if (groupChannel.channel.replyType === 'thread' && messageForThread) {
return {
parentMessageId: messageForThread.messageId,
isReplyToChannel: true
};
}
}
return {};
});
const messageMentionParams = (0, _uikitUtils.useIIFE)(() => {
const {
groupChannel
} = sbOptions.uikit;
if (!channel.isGroupChannel() || !groupChannel.channel.enableMention) return {};
return {
mentionType: _message.MentionType.USERS,
mentionedUserIds: mentionedUsers.map(it => it.user.userId),
mentionedMessageTemplate: mentionManager.textToMentionedMessageTemplate(text, mentionedUsers, groupChannel.channel.enableMention)
};
});
const onFailureToSend = error => {
toast.show(STRINGS.TOAST.SEND_MSG_ERROR, 'error');
_uikitUtils.Logger.error(STRINGS.TOAST.SEND_MSG_ERROR, error);
};
const sendUserMessage = () => {
onPressSendUserMessage({
message: text,
...messageMentionParams,
...messageReplyParams
}).catch(onFailureToSend);
// On iOS with autoCorrect enabled, calling onChangeText('') immediately after sending
// can be ignored due to the keyboard's autocorrect not being committed yet.
// Delay the clear call slightly to allow the autocorrected text to be applied first.
if (_reactNative.Platform.OS === 'ios') {
const textInputRef = ref;
if (textInputRef.current) {
setTimeout(() => {
onChangeText('');
}, 10);
}
} else {
onChangeText('');
}
setMessageToReply === null || setMessageToReply === void 0 || setMessageToReply();
};
const sendFileMessage = file => {
onPressSendFileMessage({
file,
...messageReplyParams
}).catch(onFailureToSend);
setMessageToReply === null || setMessageToReply === void 0 || setMessageToReply();
};
const sendVoiceMessage = (file, durationMills) => {
if (inputMuted) {
toast.show(STRINGS.TOAST.USER_MUTED_ERROR, 'error');
_uikitUtils.Logger.error(STRINGS.TOAST.USER_MUTED_ERROR);
} else if (inputFrozen) {
toast.show(STRINGS.TOAST.CHANNEL_FROZEN_ERROR, 'error');
_uikitUtils.Logger.error(STRINGS.TOAST.CHANNEL_FROZEN_ERROR);
} else {
onPressSendFileMessage({
file,
metaArrays: [new _message.MessageMetaArray({
key: _constants.VOICE_MESSAGE_META_ARRAY_DURATION_KEY,
value: [String(durationMills)]
}), new _message.MessageMetaArray({
key: _constants.VOICE_MESSAGE_META_ARRAY_MESSAGE_TYPE_KEY,
value: [`voice/${recorderService.options.extension}`]
})],
...messageReplyParams
}).catch(onFailureToSend);
}
onChangeText('');
setMessageToReply === null || setMessageToReply === void 0 || setMessageToReply();
};
const sheetItems = (0, _useChannelInputItems.useChannelInputItems)(channel, sendFileMessage);
const getPlaceholder = () => {
if (inputMuted) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_MUTED;
if (inputFrozen) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
if (inputDisabled) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_DISABLED;
if (messageToReply) return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_REPLY;
if (messageForThread) {
if (messageForThread.threadInfo && messageForThread.threadInfo.replyCount > 0) {
return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_REPLY_TO_THREAD;
} else {
return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_REPLY_IN_THREAD;
}
}
return STRINGS.LABELS.CHANNEL_INPUT_PLACEHOLDER_ACTIVE;
};
const voiceMessageEnabled = channel.isGroupChannel() && sbOptions.uikit.groupChannel.channel.enableVoiceMessage;
const sendButtonVisible = Boolean(text.trim());
return /*#__PURE__*/_react.default.createElement(_reactNative.View, null, MessageToReplyPreview && /*#__PURE__*/_react.default.createElement(MessageToReplyPreview, {
messageToReply: messageToReply,
setMessageToReply: setMessageToReply
}), /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: styles.sendInputContainer
}, AttachmentsButton && /*#__PURE__*/_react.default.createElement(AttachmentsButton, {
onPress: () => openSheet({
sheetItems
}),
disabled: inputDisabled
}), /*#__PURE__*/_react.default.createElement(_uikitReactNativeFoundation.TextInput, _extends({}, partialTextInputProps, {
ref: ref,
multiline: true,
disableFullscreenUI: true,
onSelectionChange: onSelectionChange,
editable: !inputDisabled,
onChangeText: onChangeText,
style: style,
placeholder: getPlaceholder(),
originalText: text,
supportRTLAlign: true
}), mentionManager.textToMentionedComponents(text, mentionedUsers, sbOptions.uikit.groupChannel.channel.enableMention)), voiceMessageEnabled && /*#__PURE__*/_react.default.createElement(VoiceMessageButton, {
visible: !sendButtonVisible,
disabled: inputDisabled,
onPress: () => setVoiceMessageInputVisible(true)
}), /*#__PURE__*/_react.default.createElement(UserMessageSendButton, {
visible: sendButtonVisible,
disabled: inputDisabled,
onPress: sendUserMessage
}), voiceMessageEnabled && VoiceMessageInput && /*#__PURE__*/_react.default.createElement(_uikitReactNativeFoundation.Modal, {
disableBackgroundClose: true,
onClose: onClose,
onDismiss: () => {
onDismiss();
playerService.reset().catch(() => {});
recorderService.reset().catch(() => {});
},
backgroundStyle: {
justifyContent: 'flex-end'
},
visible: voiceMessageInputVisible,
type: 'slide-no-gesture'
}, /*#__PURE__*/_react.default.createElement(VoiceMessageInput, {
onClose: onClose,
onSend: ({
file,
duration
}) => sendVoiceMessage(file, duration)
}))));
});
const VoiceMessageButton = ({
visible,
disabled,
onPress
}) => {
const {
STRINGS
} = (0, _useContext.useLocalization)();
const {
alert
} = (0, _uikitReactNativeFoundation.useAlert)();
const {
playerService,
recorderService
} = (0, _useContext.usePlatformService)();
const {
colors
} = (0, _uikitReactNativeFoundation.useUIKitTheme)();
if (!visible) return null;
const onPressWithPermissionCheck = async () => {
const recorderGranted = await recorderService.requestPermission();
if (!recorderGranted) {
alert({
title: STRINGS.DIALOG.ALERT_PERMISSIONS_TITLE,
message: STRINGS.DIALOG.ALERT_PERMISSIONS_MESSAGE(STRINGS.LABELS.PERMISSION_MICROPHONE, STRINGS.LABELS.PERMISSION_APP_NAME),
buttons: [{
text: STRINGS.DIALOG.ALERT_PERMISSIONS_OK,
onPress: () => _SBUUtils.default.openSettings()
}]
});
_uikitUtils.Logger.error('Failed to request permission for recorder');
return;
}
const playerGranted = await playerService.requestPermission();
if (!playerGranted) {
alert({
title: STRINGS.DIALOG.ALERT_PERMISSIONS_TITLE,
message: STRINGS.DIALOG.ALERT_PERMISSIONS_MESSAGE(STRINGS.LABELS.PERMISSION_DEVICE_STORAGE, STRINGS.LABELS.PERMISSION_APP_NAME),
buttons: [{
text: STRINGS.DIALOG.ALERT_PERMISSIONS_OK,
onPress: () => _SBUUtils.default.openSettings()
}]
});
_uikitUtils.Logger.error('Failed to request permission for player');
return;
}
onPress();
};
return /*#__PURE__*/_react.default.createElement(_reactNative.TouchableOpacity, {
onPress: onPressWithPermissionCheck,
disabled: disabled
}, /*#__PURE__*/_react.default.createElement(_uikitReactNativeFoundation.Icon, {
color: disabled ? colors.ui.input.default.disabled.highlight : colors.ui.input.default.active.highlight,
icon: 'audio-on',
size: 24,
containerStyle: styles.sendIcon
}));
};
const UserMessageSendButton = ({
visible,
disabled,
onPress
}) => {
const {
colors
} = (0, _uikitReactNativeFoundation.useUIKitTheme)();
if (!visible) return null;
return /*#__PURE__*/_react.default.createElement(_reactNative.TouchableOpacity, {
onPress: onPress,
disabled: disabled
}, /*#__PURE__*/_react.default.createElement(_uikitReactNativeFoundation.Icon, {
color: disabled ? colors.ui.input.default.disabled.highlight : colors.ui.input.default.active.highlight,
icon: 'send',
size: 24,
containerStyle: styles.sendIcon
}));
};
const styles = (0, _uikitReactNativeFoundation.createStyleSheet)({
sendInputContainer: {
paddingVertical: 10,
paddingHorizontal: 12,
alignItems: 'center',
flexDirection: 'row'
},
sendIcon: {
marginStart: 4,
padding: 4
}
});
var _default = exports.default = SendInput;
//# sourceMappingURL=SendInput.js.map