fastcomments-react-native-sdk
Version:
React Native FastComments Components. Add live commenting to any React Native application.
95 lines (94 loc) • 6.59 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { FastCommentsImageAsset } from "../types";
import { Text, Image, View, ActivityIndicator } from "react-native";
import { Editor } from "./wysiwyg/wysiwyg-editor";
import { useEffect, useRef, useState } from "react";
import { EditorToolbar } from "./wysiwyg/editor-toolbar";
import { graphToString, hasContent, stringToNodes } from "./wysiwyg/editor-node-transform";
import { EditorFormatConfigurationHTML } from "./wysiwyg/transformers";
import { getLast, getLastFocused } from "./wysiwyg/node-navigate";
import { focusNode } from "./wysiwyg/node-focus";
export function CommentTextArea({ emoticonBarConfig, focusObserver, state, styles, output, onFocus: _onFocus, pickImage, pickGIF, value, }) {
const maxLength = state.config.maxCommentCharacterLength || 2000;
const hasDarkBackground = state.config.hasDarkBackground;
const [isFocused, setFocused] = useState(false);
const [isEmpty, setIsEmpty] = useState(!!value);
const [imageUploadProgress, setImageUploadProgress] = useState(null);
const editorInputNodesRef = useRef([]);
const editorCurrentNodesRef = useRef(null);
const updateNodesObserver = {};
useEffect(() => {
const newNodes = stringToNodes(EditorFormatConfigurationHTML, value || '');
editorInputNodesRef.current = newNodes;
updateNodesObserver.updateNodes(newNodes);
}, [value]);
const placeholder = _jsx(Text, { style: styles.commentTextArea?.placeholder, children: state.translations.ENTER_COMMENT_HERE });
const toolbarConfig = state.config.disableToolbar ? undefined : {
boldButton: _jsx(Image, { source: state.imageAssets[hasDarkBackground ? FastCommentsImageAsset.ICON_BOLD_WHITE : FastCommentsImageAsset.ICON_BOLD], style: styles.commentTextArea?.toolbarButton }),
italicButton: _jsx(Image, { source: state.imageAssets[hasDarkBackground ? FastCommentsImageAsset.ICON_ITALIC_WHITE : FastCommentsImageAsset.ICON_ITALIC], style: styles.commentTextArea?.toolbarButton }),
underlineButton: _jsx(Image, { source: state.imageAssets[hasDarkBackground ? FastCommentsImageAsset.ICON_UNDERLINE_WHITE : FastCommentsImageAsset.ICON_UNDERLINE], style: styles.commentTextArea?.toolbarButton }),
strikethroughButton: _jsx(Image, { source: state.imageAssets[hasDarkBackground ? FastCommentsImageAsset.ICON_STRIKETHROUGH_WHITE : FastCommentsImageAsset.ICON_STRIKETHROUGH], style: styles.commentTextArea?.toolbarButton }),
imageButton: pickImage ? _jsx(Image, { source: state.imageAssets[hasDarkBackground ? FastCommentsImageAsset.ICON_IMAGE_UPLOAD_WHITE : FastCommentsImageAsset.ICON_IMAGE_UPLOAD], style: [styles.commentTextArea?.toolbarButton] }) : null,
// TODO dark mode gif picker icon
gifPickerButton: pickGIF ? _jsx(Image, { source: state.imageAssets[hasDarkBackground ? FastCommentsImageAsset.ICON_GIF : FastCommentsImageAsset.ICON_GIF], style: [styles.commentTextArea?.toolbarButton] }) : null,
getGIFPathToInsert: pickGIF,
getImagePathToInsert: pickImage,
uploadImage: async (_node, photoData) => {
console.log('BEGIN UPLOAD IMAGE', photoData);
const formData = new FormData();
formData.append('file', photoData);
const xhr = new XMLHttpRequest();
xhr.open('POST', state.apiHost + '/upload-image/' + state.config.tenantId);
xhr.onprogress = function (progressEvent) {
console.log('uploading image', xhr.status);
const progress = Math.round(progressEvent.loaded / progressEvent.total);
setImageUploadProgress(progress);
};
return new Promise((resolve, reject) => {
xhr.onload = function () {
setImageUploadProgress(null);
console.log('done uploading image', xhr.status);
if (xhr.status === 200) {
const url = JSON.parse(xhr.response).url;
resolve(url);
}
else {
reject(xhr.response);
}
};
xhr.send(formData);
});
}
};
const stealth = { stealth: true, noproxy: true };
function onChange(nodes) {
// we could automatically trim content here, via updating the graph in-place.
// but it causes lag so probably better to just tell the user to shorten their text
// is better UX anyway vs losing keystrokes.
const newIsEmpty = !hasContent(nodes.get(stealth));
if (isEmpty !== newIsEmpty) {
setIsEmpty(newIsEmpty);
}
editorCurrentNodesRef.current = nodes;
}
output.getValue = () => {
return graphToString(editorCurrentNodesRef.current ? editorCurrentNodesRef.current.get() : null, EditorFormatConfigurationHTML, maxLength);
};
if (focusObserver) {
focusObserver.setFocused = (isFocused) => {
if (isFocused) {
const lastFocused = getLastFocused(editorInputNodesRef.current);
lastFocused.isFocused = false;
focusNode(getLast(editorInputNodesRef.current));
}
else {
const lastFocused = getLastFocused(editorInputNodesRef.current);
lastFocused.isFocused = false;
}
updateNodesObserver.updateNodes(editorInputNodesRef.current);
};
}
return _jsxs(View, { style: { width: '100%' }, children: [_jsx(Editor, { graph: editorInputNodesRef.current, updateNodesObserver: updateNodesObserver, isMultiLine: !state.config.useSingleLineCommentInput, onChange: onChange, style: styles.commentTextArea?.textarea, textStyle: styles.commentTextArea?.text, placeholder: !isFocused && isEmpty && placeholder, onFocus: () => setFocused(true), onBlur: () => setFocused(false), maxLength: maxLength, toolbar: (config) => _jsx(EditorToolbar, { config: config }), toolbarConfig: toolbarConfig, emoticonBarConfig: emoticonBarConfig }), imageUploadProgress !== null
? _jsx(View, { style: styles.commentTextArea?.imageUploadModalCenteredView, children: _jsxs(View, { style: styles.commentTextArea?.imageUploadModalContent, children: [_jsx(ActivityIndicator, { size: styles.commentTextArea?.imageUploadModalProgressSpinnerSize }), _jsxs(Text, { style: styles.commentTextArea?.imageUploadModalProgressText, children: [Math.round(imageUploadProgress * 100), "%"] })] }) })
: null] });
}