UNPKG

fastcomments-react-native-sdk

Version:

React Native FastComments Components. Add live commenting to any React Native application.

95 lines (94 loc) 6.59 kB
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] }); }