"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
    for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.utils = exports.GiftedAvatar = exports.Time = exports.Send = exports.MessageContainer = exports.Message = exports.LoadEarlier = exports.InputToolbar = exports.Day = exports.Composer = exports.MessageText = exports.MessageImage = exports.SystemMessage = exports.Bubble = exports.Avatar = exports.Actions = exports.GiftedChat = void 0;
const prop_types_1 = __importDefault(require("prop-types"));
const react_1 = __importDefault(require("react"));
const react_native_1 = require("react-native");
const react_native_action_sheet_1 = require("@expo/react-native-action-sheet");
const uuid_1 = __importDefault(require("uuid"));
const react_native_iphone_x_helper_1 = require("react-native-iphone-x-helper");
const dayjs_1 = __importDefault(require("dayjs"));
const localizedFormat_1 = __importDefault(require("dayjs/plugin/localizedFormat"));
const utils = __importStar(require("./utils"));
exports.utils = utils;
const Actions_1 = __importDefault(require("./Actions"));
exports.Actions = Actions_1.default;
const Avatar_1 = __importDefault(require("./Avatar"));
exports.Avatar = Avatar_1.default;
const Bubble_1 = __importDefault(require("./Bubble"));
exports.Bubble = Bubble_1.default;
const SystemMessage_1 = __importDefault(require("./SystemMessage"));
exports.SystemMessage = SystemMessage_1.default;
const MessageImage_1 = __importDefault(require("./MessageImage"));
exports.MessageImage = MessageImage_1.default;
const MessageText_1 = __importDefault(require("./MessageText"));
exports.MessageText = MessageText_1.default;
const Composer_1 = __importDefault(require("./Composer"));
exports.Composer = Composer_1.default;
const Day_1 = __importDefault(require("./Day"));
exports.Day = Day_1.default;
const InputToolbar_1 = __importDefault(require("./InputToolbar"));
exports.InputToolbar = InputToolbar_1.default;
const LoadEarlier_1 = __importDefault(require("./LoadEarlier"));
exports.LoadEarlier = LoadEarlier_1.default;
const Message_1 = __importDefault(require("./Message"));
exports.Message = Message_1.default;
const MessageContainer_1 = __importDefault(require("./MessageContainer"));
exports.MessageContainer = MessageContainer_1.default;
const Send_1 = __importDefault(require("./Send"));
exports.Send = Send_1.default;
const Time_1 = __importDefault(require("./Time"));
exports.Time = Time_1.default;
const GiftedAvatar_1 = __importDefault(require("./GiftedAvatar"));
exports.GiftedAvatar = GiftedAvatar_1.default;
const Constant_1 = require("./Constant");
dayjs_1.default.extend(localizedFormat_1.default);
class GiftedChat extends react_1.default.Component {
    constructor(props) {
        super(props);
        this._isMounted = false;
        this._keyboardHeight = 0;
        this._bottomOffset = 0;
        this._maxHeight = undefined;
        this._isFirstLayout = true;
        this._locale = 'en';
        this.invertibleScrollViewProps = undefined;
        this._actionSheetRef = undefined;
        this._messageContainerRef = react_1.default.createRef();
        this._isTextInputWasFocused = false;
        this.state = {
            isInitialized: false,
            composerHeight: this.props.minComposerHeight,
            messagesContainerHeight: undefined,
            typingDisabled: false,
            text: undefined,
            messages: undefined,
        };
        this.getLocale = () => this._locale;
        this.safeAreaSupport = (bottomOffset) => (bottomOffset != null ? bottomOffset : react_native_iphone_x_helper_1.getBottomSpace());
        this.onKeyboardWillShow = (e) => {
            this.handleTextInputFocusWhenKeyboardShow();
            if (this.props.isKeyboardInternallyHandled) {
                this.setIsTypingDisabled(true);
                this.setKeyboardHeight(e.endCoordinates ? e.endCoordinates.height : e.end.height);
                this.setBottomOffset(this.safeAreaSupport(this.props.bottomOffset));
                const newMessagesContainerHeight = this.getMessagesContainerHeightWithKeyboard();
                this.setState({
                    messagesContainerHeight: newMessagesContainerHeight,
                });
            }
        };
        this.onKeyboardWillHide = (_e) => {
            this.handleTextInputFocusWhenKeyboardHide();
            if (this.props.isKeyboardInternallyHandled) {
                this.setIsTypingDisabled(true);
                this.setKeyboardHeight(0);
                this.setBottomOffset(0);
                const newMessagesContainerHeight = this.getBasicMessagesContainerHeight();
                this.setState({
                    messagesContainerHeight: newMessagesContainerHeight,
                });
            }
        };
        this.onKeyboardDidShow = (e) => {
            if (react_native_1.Platform.OS === 'android') {
                this.onKeyboardWillShow(e);
            }
            this.setIsTypingDisabled(false);
        };
        this.onKeyboardDidHide = (e) => {
            if (react_native_1.Platform.OS === 'android') {
                this.onKeyboardWillHide(e);
            }
            this.setIsTypingDisabled(false);
        };
        this.onSend = (messages = [], shouldResetInputToolbar = false) => {
            if (!Array.isArray(messages)) {
                messages = [messages];
            }
            const newMessages = messages.map((message) => (Object.assign(Object.assign({}, message), { user: this.props.user, createdAt: new Date(), _id: this.props.messageIdGenerator && this.props.messageIdGenerator() })));
            if (shouldResetInputToolbar === true) {
                this.setIsTypingDisabled(true);
                this.resetInputToolbar();
            }
            if (this.props.onSend) {
                this.props.onSend(newMessages);
            }
            if (shouldResetInputToolbar === true) {
                setTimeout(() => {
                    if (this.getIsMounted() === true) {
                        this.setIsTypingDisabled(false);
                    }
                }, 100);
            }
        };
        this.onInputSizeChanged = (size) => {
            const newComposerHeight = Math.max(this.props.minComposerHeight, Math.min(this.props.maxComposerHeight, size.height));
            const newMessagesContainerHeight = this.getMessagesContainerHeightWithKeyboard(newComposerHeight);
            this.setState({
                composerHeight: newComposerHeight,
                messagesContainerHeight: newMessagesContainerHeight,
            });
        };
        this.onInputTextChanged = (text) => {
            if (this.getIsTypingDisabled()) {
                return;
            }
            if (this.props.onInputTextChanged) {
                this.props.onInputTextChanged(text);
            }
            // Only set state if it's not being overridden by a prop.
            if (this.props.text === undefined) {
                this.setState({ text });
            }
        };
        this.onInitialLayoutViewLayout = (e) => {
            const { layout } = e.nativeEvent;
            if (layout.height <= 0) {
                return;
            }
            this.notifyInputTextReset();
            this.setMaxHeight(layout.height);
            const newComposerHeight = this.props.minComposerHeight;
            const newMessagesContainerHeight = this.getMessagesContainerHeightWithKeyboard(newComposerHeight);
            const initialText = this.props.initialText || '';
            this.setState({
                isInitialized: true,
                text: this.getTextFromProp(initialText),
                composerHeight: newComposerHeight,
                messagesContainerHeight: newMessagesContainerHeight,
            });
        };
        this.onMainViewLayout = (e) => {
            // fix an issue when keyboard is dismissing during the initialization
            const { layout } = e.nativeEvent;
            if (this.getMaxHeight() !== layout.height
                || this.getIsFirstLayout() === true) {
                this.setMaxHeight(layout.height);
                this.setState({
                    messagesContainerHeight: this._keyboardHeight > 0
                        ? this.getMessagesContainerHeightWithKeyboard()
                        : this.getBasicMessagesContainerHeight(),
                });
            }
            if (this.getIsFirstLayout() === true) {
                this.setIsFirstLayout(false);
            }
        };
        this.invertibleScrollViewProps = {
            inverted: this.props.inverted,
            keyboardShouldPersistTaps: this.props.keyboardShouldPersistTaps,
            onKeyboardWillShow: this.onKeyboardWillShow,
            onKeyboardWillHide: this.onKeyboardWillHide,
            onKeyboardDidShow: this.onKeyboardDidShow,
            onKeyboardDidHide: this.onKeyboardDidHide,
        };
    }
    static append(currentMessages = [], messages, inverted = true) {
        if (!Array.isArray(messages)) {
            messages = [messages];
        }
        return inverted
            ? messages.concat(currentMessages)
            : currentMessages.concat(messages);
    }
    static prepend(currentMessages = [], messages, inverted = true) {
        if (!Array.isArray(messages)) {
            messages = [messages];
        }
        return inverted
            ? currentMessages.concat(messages)
            : messages.concat(currentMessages);
    }
    getChildContext() {
        return {
            actionSheet: this.props.actionSheet || (() => this._actionSheetRef.getContext()),
            getLocale: this.getLocale,
        };
    }
    componentDidMount() {
        const { messages, text } = this.props;
        this.setIsMounted(true);
        this.initLocale();
        this.setMessages(messages || []);
        this.setTextFromProp(text);
    }
    componentWillUnmount() {
        this.setIsMounted(false);
    }
    componentDidUpdate(prevProps = {}) {
        const { messages, text, inverted } = this.props;
        if (this.props !== prevProps) {
            this.setMessages(messages || []);
        }
        if (inverted === false
            && messages
            && prevProps.messages
            && messages.length !== prevProps.messages.length) {
            setTimeout(() => this.scrollToBottom(false), 200);
        }
        if (text !== prevProps.text) {
            this.setTextFromProp(text);
        }
    }
    initLocale() {
        if (this.props.locale === null) {
            this.setLocale('en');
        }
        else {
            this.setLocale(this.props.locale || 'en');
        }
    }
    setLocale(locale) {
        this._locale = locale;
    }
    setTextFromProp(textProp) {
        // Text prop takes precedence over state.
        if (textProp !== undefined && textProp !== this.state.text) {
            this.setState({ text: textProp });
        }
    }
    getTextFromProp(fallback) {
        if (this.props.text === undefined) {
            return fallback;
        }
        return this.props.text;
    }
    setMessages(messages) {
        this.setState({ messages });
    }
    getMessages() {
        return this.state.messages;
    }
    setMaxHeight(height) {
        this._maxHeight = height;
    }
    getMaxHeight() {
        return this._maxHeight;
    }
    setKeyboardHeight(height) {
        this._keyboardHeight = height;
    }
    getKeyboardHeight() {
        if (react_native_1.Platform.OS === 'android' && !this.props.forceGetKeyboardHeight) {
            // For android: on-screen keyboard resized main container and has own height.
            // @see https://developer.android.com/training/keyboard-input/visibility.html
            // So for calculate the messages container height ignore keyboard height.
            return 0;
        }
        return this._keyboardHeight;
    }
    setBottomOffset(value) {
        this._bottomOffset = value;
    }
    getBottomOffset() {
        return this._bottomOffset;
    }
    setIsFirstLayout(value) {
        this._isFirstLayout = value;
    }
    getIsFirstLayout() {
        return this._isFirstLayout;
    }
    setIsTypingDisabled(value) {
        this.setState({
            typingDisabled: value,
        });
    }
    getIsTypingDisabled() {
        return this.state.typingDisabled;
    }
    setIsMounted(value) {
        this._isMounted = value;
    }
    getIsMounted() {
        return this._isMounted;
    }
    getMinInputToolbarHeight() {
        return this.props.renderAccessory
            ? this.props.minInputToolbarHeight * 2
            : this.props.minInputToolbarHeight;
    }
    calculateInputToolbarHeight(composerHeight) {
        return (composerHeight
            + (this.getMinInputToolbarHeight() - this.props.minComposerHeight));
    }
    /**
     * Returns the height, based on current window size, without taking the keyboard into account.
     */
    getBasicMessagesContainerHeight(composerHeight = this.state.composerHeight) {
        return (this.getMaxHeight() - this.calculateInputToolbarHeight(composerHeight));
    }
    /**
     * Returns the height, based on current window size, taking the keyboard into account.
     */
    getMessagesContainerHeightWithKeyboard(composerHeight = this.state.composerHeight) {
        return (this.getBasicMessagesContainerHeight(composerHeight)
            - this.getKeyboardHeight()
            + this.getBottomOffset());
    }
    /**
     * Store text input focus status when keyboard hide to retrieve
     * it after wards if needed.
     * `onKeyboardWillHide` may be called twice in sequence so we
     * make a guard condition (eg. showing image picker)
     */
    handleTextInputFocusWhenKeyboardHide() {
        var _a;
        if (!this._isTextInputWasFocused) {
            this._isTextInputWasFocused = ((_a = this.textInput) === null || _a === void 0 ? void 0 : _a.isFocused()) || false;
        }
    }
    /**
     * Refocus the text input only if it was focused before showing keyboard.
     * This is needed in some cases (eg. showing image picker).
     */
    handleTextInputFocusWhenKeyboardShow() {
        if (this.textInput
            && this._isTextInputWasFocused
            && !this.textInput.isFocused()) {
            this.textInput.focus();
        }
        // Reset the indicator since the keyboard is shown
        this._isTextInputWasFocused = false;
    }
    scrollToBottom(animated = true) {
        if (this._messageContainerRef && this._messageContainerRef.current) {
            const { inverted } = this.props;
            if (!inverted) {
                this._messageContainerRef.current.scrollToEnd({ animated });
            }
            else {
                this._messageContainerRef.current.scrollToOffset({
                    offset: 0,
                    animated,
                });
            }
        }
    }
    renderMessages() {
        const _a = this.props, { messagesContainerStyle } = _a, messagesContainerProps = __rest(_a, ["messagesContainerStyle"]);
        const fragment = (react_1.default.createElement(react_native_1.View, { style: [
                {
                    height: this.state.messagesContainerHeight,
                },
                messagesContainerStyle,
            ] },
            react_1.default.createElement(MessageContainer_1.default, Object.assign({}, messagesContainerProps, { invertibleScrollViewProps: this.invertibleScrollViewProps, messages: this.getMessages(), forwardRef: this._messageContainerRef, isTyping: this.props.isTyping })),
            this.renderChatFooter()));
        return this.props.isKeyboardInternallyHandled ? (react_1.default.createElement(react_native_1.KeyboardAvoidingView, { enabled: true }, fragment)) : (fragment);
    }
    resetInputToolbar() {
        if (this.textInput) {
            this.textInput.clear();
        }
        this.notifyInputTextReset();
        const newComposerHeight = this.props.minComposerHeight;
        const newMessagesContainerHeight = this.getMessagesContainerHeightWithKeyboard(newComposerHeight);
        this.setState({
            text: this.getTextFromProp(''),
            composerHeight: newComposerHeight,
            messagesContainerHeight: newMessagesContainerHeight,
        });
    }
    focusTextInput() {
        if (this.textInput) {
            this.textInput.focus();
        }
    }
    notifyInputTextReset() {
        if (this.props.onInputTextChanged) {
            this.props.onInputTextChanged('');
        }
    }
    renderInputToolbar() {
        const inputToolbarProps = Object.assign(Object.assign({}, this.props), { text: this.getTextFromProp(this.state.text), composerHeight: Math.max(this.props.minComposerHeight, this.state.composerHeight), onSend: this.onSend, onInputSizeChanged: this.onInputSizeChanged, onTextChanged: this.onInputTextChanged, textInputProps: Object.assign(Object.assign({}, this.props.textInputProps), { ref: (textInput) => (this.textInput = textInput), maxLength: this.getIsTypingDisabled() ? 0 : this.props.maxInputLength }) });
        if (this.props.renderInputToolbar) {
            return this.props.renderInputToolbar(inputToolbarProps);
        }
        return react_1.default.createElement(InputToolbar_1.default, Object.assign({}, inputToolbarProps));
    }
    renderChatFooter() {
        if (this.props.renderChatFooter) {
            return this.props.renderChatFooter();
        }
        return null;
    }
    renderLoading() {
        if (this.props.renderLoading) {
            return this.props.renderLoading();
        }
        return null;
    }
    render() {
        if (this.state.isInitialized === true) {
            const { wrapInSafeArea } = this.props;
            const Wrapper = wrapInSafeArea ? react_native_1.SafeAreaView : react_native_1.View;
            return (react_1.default.createElement(Wrapper, { style: styles.safeArea },
                react_1.default.createElement(react_native_action_sheet_1.ActionSheetProvider, { ref: (component) => (this._actionSheetRef = component) },
                    react_1.default.createElement(react_native_1.View, { style: styles.container, onLayout: this.onMainViewLayout },
                        this.renderMessages(),
                        this.renderInputToolbar()))));
        }
        return (react_1.default.createElement(react_native_1.View, { style: styles.container, onLayout: this.onInitialLayoutViewLayout }, this.renderLoading()));
    }
}
exports.GiftedChat = GiftedChat;
GiftedChat.childContextTypes = {
    actionSheet: prop_types_1.default.func,
    getLocale: prop_types_1.default.func,
};
GiftedChat.defaultProps = {
    messages: [],
    messagesContainerStyle: undefined,
    text: undefined,
    placeholder: Constant_1.DEFAULT_PLACEHOLDER,
    disableComposer: false,
    messageIdGenerator: () => uuid_1.default.v4(),
    user: {},
    onSend: () => { },
    locale: null,
    timeFormat: Constant_1.TIME_FORMAT,
    dateFormat: Constant_1.DATE_FORMAT,
    loadEarlier: false,
    onLoadEarlier: () => { },
    isLoadingEarlier: false,
    renderLoading: null,
    renderLoadEarlier: null,
    renderAvatar: undefined,
    showUserAvatar: false,
    actionSheet: null,
    onPressAvatar: null,
    onLongPressAvatar: null,
    renderUsernameOnMessage: false,
    renderAvatarOnTop: false,
    renderBubble: null,
    renderSystemMessage: null,
    onLongPress: null,
    renderMessage: null,
    renderMessageText: null,
    renderMessageImage: null,
    renderMessageVideo: null,
    renderMessageAudio: null,
    imageProps: {},
    videoProps: {},
    audioProps: {},
    lightboxProps: {},
    textInputProps: {},
    listViewProps: {},
    renderCustomView: null,
    isCustomViewBottom: false,
    renderDay: null,
    renderTime: null,
    renderFooter: null,
    renderChatEmpty: null,
    renderChatFooter: null,
    renderInputToolbar: null,
    renderComposer: null,
    renderActions: null,
    renderSend: null,
    renderAccessory: null,
    isKeyboardInternallyHandled: true,
    onPressActionButton: null,
    bottomOffset: null,
    minInputToolbarHeight: 44,
    keyboardShouldPersistTaps: react_native_1.Platform.select({
        ios: 'never',
        android: 'always',
        default: 'never',
    }),
    onInputTextChanged: null,
    maxInputLength: null,
    forceGetKeyboardHeight: false,
    inverted: true,
    extraData: null,
    minComposerHeight: Constant_1.MIN_COMPOSER_HEIGHT,
    maxComposerHeight: Constant_1.MAX_COMPOSER_HEIGHT,
    wrapInSafeArea: true,
};
GiftedChat.propTypes = {
    messages: prop_types_1.default.arrayOf(prop_types_1.default.object),
    messagesContainerStyle: utils.StylePropType,
    text: prop_types_1.default.string,
    initialText: prop_types_1.default.string,
    placeholder: prop_types_1.default.string,
    disableComposer: prop_types_1.default.bool,
    messageIdGenerator: prop_types_1.default.func,
    user: prop_types_1.default.object,
    onSend: prop_types_1.default.func,
    locale: prop_types_1.default.string,
    timeFormat: prop_types_1.default.string,
    dateFormat: prop_types_1.default.string,
    isKeyboardInternallyHandled: prop_types_1.default.bool,
    loadEarlier: prop_types_1.default.bool,
    onLoadEarlier: prop_types_1.default.func,
    isLoadingEarlier: prop_types_1.default.bool,
    renderLoading: prop_types_1.default.func,
    renderLoadEarlier: prop_types_1.default.func,
    renderAvatar: prop_types_1.default.func,
    showUserAvatar: prop_types_1.default.bool,
    actionSheet: prop_types_1.default.func,
    onPressAvatar: prop_types_1.default.func,
    onLongPressAvatar: prop_types_1.default.func,
    renderUsernameOnMessage: prop_types_1.default.bool,
    renderAvatarOnTop: prop_types_1.default.bool,
    isCustomViewBottom: prop_types_1.default.bool,
    renderBubble: prop_types_1.default.func,
    renderSystemMessage: prop_types_1.default.func,
    onLongPress: prop_types_1.default.func,
    renderMessage: prop_types_1.default.func,
    renderMessageText: prop_types_1.default.func,
    renderMessageImage: prop_types_1.default.func,
    imageProps: prop_types_1.default.object,
    videoProps: prop_types_1.default.object,
    audioProps: prop_types_1.default.object,
    lightboxProps: prop_types_1.default.object,
    renderCustomView: prop_types_1.default.func,
    renderDay: prop_types_1.default.func,
    renderTime: prop_types_1.default.func,
    renderFooter: prop_types_1.default.func,
    renderChatEmpty: prop_types_1.default.func,
    renderChatFooter: prop_types_1.default.func,
    renderInputToolbar: prop_types_1.default.func,
    renderComposer: prop_types_1.default.func,
    renderActions: prop_types_1.default.func,
    renderSend: prop_types_1.default.func,
    renderAccessory: prop_types_1.default.func,
    onPressActionButton: prop_types_1.default.func,
    bottomOffset: prop_types_1.default.number,
    minInputToolbarHeight: prop_types_1.default.number,
    listViewProps: prop_types_1.default.object,
    keyboardShouldPersistTaps: prop_types_1.default.oneOf(['always', 'never', 'handled']),
    onInputTextChanged: prop_types_1.default.func,
    maxInputLength: prop_types_1.default.number,
    forceGetKeyboardHeight: prop_types_1.default.bool,
    inverted: prop_types_1.default.bool,
    textInputProps: prop_types_1.default.object,
    extraData: prop_types_1.default.object,
    minComposerHeight: prop_types_1.default.number,
    maxComposerHeight: prop_types_1.default.number,
    alignTop: prop_types_1.default.bool,
    wrapInSafeArea: prop_types_1.default.bool,
};
const styles = react_native_1.StyleSheet.create({
    container: {
        flex: 1,
    },
    safeArea: {
        flex: 1,
    },
});
__exportStar(require("./Models"), exports);
//# sourceMappingURL=GiftedChat.js.map