mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-30 00:52:42 +03:00
Changed markdown component with react hooks
This commit is contained in:
parent
6d985eb1b9
commit
67797d527d
@ -1,9 +1,6 @@
|
||||
import { replaceBetween } from './utils';
|
||||
|
||||
export default async ({ getState, item, setState }) => {
|
||||
const states = getState();
|
||||
let { text } = states;
|
||||
const { selection } = states;
|
||||
export default async ({ text, selection, setText, setNewSelection, item }) => {
|
||||
let newText;
|
||||
let newSelection;
|
||||
|
||||
@ -35,6 +32,6 @@ export default async ({ getState, item, setState }) => {
|
||||
newSelection = { start: selection.start + 3, end: selection.start + 3 };
|
||||
}
|
||||
|
||||
await setState({ text: newText, textUpdated: true });
|
||||
await setState({ newSelection });
|
||||
await setText(newText);
|
||||
await setNewSelection(newSelection);
|
||||
};
|
||||
|
@ -3,8 +3,7 @@ import { isStringWebLink, replaceBetween } from './utils';
|
||||
export const writeUrlTextHere = 'https://example.com';
|
||||
export const writeTextHereString = 'Text here';
|
||||
|
||||
export default async ({ getState, item, setState, isImage = null }) => {
|
||||
const { selection, text } = getState();
|
||||
export default async ({ text, selection, setText, setNewSelection, item, isImage = null }) => {
|
||||
const imagePrefix = isImage ? '!' : '';
|
||||
const itemText = item ? item.text : writeTextHereString;
|
||||
const itemUrl = item ? item.url : writeUrlTextHere;
|
||||
@ -41,7 +40,6 @@ export default async ({ getState, item, setState, isImage = null }) => {
|
||||
}
|
||||
}
|
||||
|
||||
await setState({ text: newText, textUpdated: true }, async () => {
|
||||
await setState({ newSelection });
|
||||
});
|
||||
await setText(newText);
|
||||
await setNewSelection(newSelection);
|
||||
};
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { replaceBetween } from './utils';
|
||||
|
||||
export default ({ getState, item, setState }) => {
|
||||
const { text, selection } = getState();
|
||||
export default async ({ text, selection, setText, setNewSelection, item }) => {
|
||||
const newText = replaceBetween(
|
||||
text,
|
||||
selection,
|
||||
@ -15,7 +14,6 @@ export default ({ getState, item, setState }) => {
|
||||
newPosition = selection.end + item.wrapper.length * 2;
|
||||
}
|
||||
|
||||
setState({ text: newText, textUpdated: true }, () => {
|
||||
setState({ newSelection: { start: newPosition, end: newPosition } });
|
||||
});
|
||||
await setText(newText);
|
||||
await setNewSelection({ start: newPosition, end: newPosition });
|
||||
};
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { replaceBetween } from './utils';
|
||||
|
||||
export default async ({ getState, item, setState }) => {
|
||||
const { text, selection } = getState();
|
||||
export default async ({ text, selection, setText, setNewSelection, item }) => {
|
||||
let newText = replaceBetween(
|
||||
text,
|
||||
selection,
|
||||
@ -41,8 +40,6 @@ export default async ({ getState, item, setState }) => {
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
|
||||
await setState({ text: newText, textUpdated: true }, async () => {
|
||||
await setState({ newSelection: { start: newPosition, end: newPosition } });
|
||||
});
|
||||
await setText(newText);
|
||||
await setNewSelection({ start: newPosition, end: newPosition });
|
||||
};
|
||||
|
@ -1,9 +1,9 @@
|
||||
import regexValidator from './webLinkValidator';
|
||||
|
||||
export const replaceBetween = (text: string, selection: Object, what: string) =>
|
||||
export const replaceBetween = (text, selection, what) =>
|
||||
text.substring(0, selection.start) + what + text.substring(selection.end);
|
||||
|
||||
export const isStringWebLink = (text: string): boolean => {
|
||||
export const isStringWebLink = text => {
|
||||
const pattern = regexValidator;
|
||||
return pattern.test(text);
|
||||
};
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React, { Component } from 'react';
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
import { View, KeyboardAvoidingView, FlatList, Text, Platform, ScrollView } from 'react-native';
|
||||
import ActionSheet from 'react-native-actionsheet';
|
||||
import { renderPostBody } from '@esteemapp/esteem-render-helpers';
|
||||
|
||||
// Utils
|
||||
import applyImageLink from './formats/applyWebLinkFormat';
|
||||
import Formats from './formats/formats';
|
||||
import applyImageLink from './formats/applyWebLinkFormat';
|
||||
|
||||
// Components
|
||||
import { IconButton } from '../../iconButton';
|
||||
@ -16,73 +16,65 @@ import { TextInput } from '../../textInput';
|
||||
// Styles
|
||||
import styles from './markdownEditorStyles';
|
||||
|
||||
export default class MarkdownEditorView extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
text: props.draftBody || '',
|
||||
selection: { start: 0, end: 0 },
|
||||
textUpdated: false,
|
||||
newSelection: null,
|
||||
};
|
||||
const MarkdownEditorView = ({
|
||||
draftBody,
|
||||
handleIsFormValid,
|
||||
handleOpenImagePicker,
|
||||
intl,
|
||||
isPreviewActive,
|
||||
isReply,
|
||||
isLoading,
|
||||
initialFields,
|
||||
onChange,
|
||||
handleOnTextChange,
|
||||
handleIsValid,
|
||||
componentID,
|
||||
uploadedImage,
|
||||
}) => {
|
||||
const [text, setText] = useState(draftBody || '');
|
||||
const [selection, setSelection] = useState({ start: 0, end: 0 });
|
||||
|
||||
this.inputRef = React.createRef();
|
||||
this.galleryRef = React.createRef();
|
||||
this.clearRef = React.createRef();
|
||||
}
|
||||
const [newSelection, setNewSelection] = useState(null);
|
||||
|
||||
// Lifecycle functions
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
const { draftBody, uploadedImage, isPreviewActive } = this.props;
|
||||
if (!nextProps.isPreviewActive && isPreviewActive) {
|
||||
this.setState({
|
||||
selection: { start: 0, end: 0 },
|
||||
});
|
||||
}
|
||||
if (nextProps.draftBody && draftBody !== nextProps.draftBody) {
|
||||
this.setState({
|
||||
text: nextProps.draftBody,
|
||||
});
|
||||
}
|
||||
const inputRef = useRef(null);
|
||||
const galleryRef = useRef(null);
|
||||
const clearRef = useRef(null);
|
||||
|
||||
if (
|
||||
nextProps.uploadedImage &&
|
||||
nextProps.uploadedImage.url &&
|
||||
nextProps.uploadedImage !== uploadedImage
|
||||
) {
|
||||
useEffect(() => {
|
||||
setSelection({ start: 0, end: 0 });
|
||||
}, [isPreviewActive]);
|
||||
|
||||
useEffect(() => {
|
||||
if (uploadedImage && uploadedImage.url) {
|
||||
applyImageLink({
|
||||
getState: this._getState,
|
||||
setState: async (state, callback) => {
|
||||
await this.setState(state, callback);
|
||||
},
|
||||
item: { url: nextProps.uploadedImage.url, text: nextProps.uploadedImage.hash },
|
||||
isImage: !!nextProps.uploadedImage,
|
||||
text,
|
||||
selection,
|
||||
setText,
|
||||
setNewSelection,
|
||||
item: { url: uploadedImage.url, text: uploadedImage.hash },
|
||||
isImage: !!uploadedImage,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [uploadedImage]);
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const { text } = this.state;
|
||||
const { handleIsFormValid } = this.props;
|
||||
useEffect(() => {
|
||||
setText(draftBody);
|
||||
}, [draftBody]);
|
||||
|
||||
if (prevState.text !== text) {
|
||||
const nextText = text.replace(prevState.text, '');
|
||||
useEffect(() => {
|
||||
const nextText = text.replace(text, '');
|
||||
|
||||
if (nextText && nextText.length > 0) {
|
||||
this._changeText(text);
|
||||
if (nextText && nextText.length > 0) {
|
||||
_changeText(text);
|
||||
|
||||
if (handleIsFormValid) {
|
||||
handleIsFormValid(text);
|
||||
}
|
||||
if (handleIsFormValid) {
|
||||
handleIsFormValid(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [text]);
|
||||
|
||||
// Component functions
|
||||
_changeText = input => {
|
||||
const { onChange, handleOnTextChange, handleIsValid, componentID } = this.props;
|
||||
|
||||
this.setState({ text: input });
|
||||
const _changeText = input => {
|
||||
setText(input);
|
||||
|
||||
if (onChange) {
|
||||
onChange(input);
|
||||
@ -97,36 +89,22 @@ export default class MarkdownEditorView extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
_handleOnSelectionChange = event => {
|
||||
const { newSelection } = this.state;
|
||||
|
||||
const _handleOnSelectionChange = event => {
|
||||
if (newSelection) {
|
||||
this.setState({
|
||||
selection: newSelection,
|
||||
newSelection: null,
|
||||
});
|
||||
setSelection(newSelection);
|
||||
setNewSelection(null);
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
selection: event.nativeEvent.selection,
|
||||
});
|
||||
setSelection(event.nativeEvent.selection);
|
||||
};
|
||||
|
||||
_getState = () => {
|
||||
return this.state;
|
||||
};
|
||||
const _renderPreview = () => (
|
||||
<ScrollView style={styles.previewContainer}>
|
||||
{text ? <PostBody body={renderPostBody(text)} /> : <Text>...</Text>}
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
_renderPreview = () => {
|
||||
const { text } = this.state;
|
||||
|
||||
return (
|
||||
<ScrollView style={styles.previewContainer}>
|
||||
{text ? <PostBody body={renderPostBody(text)} /> : <Text>...</Text>}
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
_renderMarkupButton = ({ item, getState, setState }) => (
|
||||
const _renderMarkupButton = ({ item }) => (
|
||||
<View style={styles.buttonWrapper}>
|
||||
<IconButton
|
||||
size={20}
|
||||
@ -134,20 +112,18 @@ export default class MarkdownEditorView extends Component {
|
||||
iconStyle={styles.icon}
|
||||
iconType={item.iconType}
|
||||
name={item.icon}
|
||||
onPress={() => item.onPress({ getState, setState, item })}
|
||||
onPress={() => item.onPress({ text, selection, setText, setNewSelection, item })}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
_renderEditorButtons = ({ getState, setState }) => (
|
||||
const _renderEditorButtons = () => (
|
||||
<StickyBar>
|
||||
<View style={styles.leftButtonsWrapper}>
|
||||
<FlatList
|
||||
data={Formats}
|
||||
keyboardShouldPersistTaps="always"
|
||||
renderItem={({ item, index }) =>
|
||||
index !== 9 && this._renderMarkupButton({ item, getState, setState })
|
||||
}
|
||||
renderItem={({ item, index }) => index !== 9 && _renderMarkupButton({ item })}
|
||||
horizontal
|
||||
/>
|
||||
</View>
|
||||
@ -158,10 +134,10 @@ export default class MarkdownEditorView extends Component {
|
||||
iconStyle={styles.icon}
|
||||
iconType="FontAwesome"
|
||||
name="link"
|
||||
onPress={() => Formats[9].onPress({ getState, setState })}
|
||||
onPress={() => Formats[9].onPress({ text, selection, setText, setNewSelection })}
|
||||
/>
|
||||
<IconButton
|
||||
onPress={() => this.galleryRef.current.show()}
|
||||
onPress={() => galleryRef.current.show()}
|
||||
style={styles.rightIcons}
|
||||
size={20}
|
||||
iconStyle={styles.icon}
|
||||
@ -170,7 +146,7 @@ export default class MarkdownEditorView extends Component {
|
||||
/>
|
||||
<View style={styles.clearButtonWrapper}>
|
||||
<IconButton
|
||||
onPress={() => this.clearRef.current.show()}
|
||||
onPress={() => clearRef.current.show()}
|
||||
size={20}
|
||||
iconStyle={styles.clearIcon}
|
||||
iconType="FontAwesome"
|
||||
@ -182,87 +158,141 @@ export default class MarkdownEditorView extends Component {
|
||||
</StickyBar>
|
||||
);
|
||||
|
||||
_handleClear = () => {
|
||||
const { initialFields } = this.props;
|
||||
|
||||
initialFields();
|
||||
|
||||
this.setState({ text: '' });
|
||||
const _handleClear = index => {
|
||||
if (index === 0) {
|
||||
initialFields();
|
||||
setText('');
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { handleOpenImagePicker, intl, isPreviewActive, isReply, isLoading } = this.props;
|
||||
const { text, selection } = this.state;
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
style={styles.container}
|
||||
keyboardVerticalOffset={Platform.select({ ios: 0, android: 25 })}
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : null}
|
||||
>
|
||||
{!isPreviewActive ? (
|
||||
<TextInput
|
||||
multiline
|
||||
onChangeText={_changeText}
|
||||
onSelectionChange={_handleOnSelectionChange}
|
||||
placeholder={intl.formatMessage({
|
||||
id: isReply ? 'editor.reply_placeholder' : 'editor.default_placeholder',
|
||||
})}
|
||||
placeholderTextColor="#c1c5c7"
|
||||
selection={selection}
|
||||
selectionColor="#357ce6"
|
||||
style={styles.textWrapper}
|
||||
underlineColorAndroid="transparent"
|
||||
value={text}
|
||||
innerRef={inputRef}
|
||||
editable={!isLoading}
|
||||
/>
|
||||
) : (
|
||||
_renderPreview()
|
||||
)}
|
||||
{!isPreviewActive && _renderEditorButtons()}
|
||||
<ActionSheet
|
||||
ref={galleryRef}
|
||||
options={[
|
||||
intl.formatMessage({
|
||||
id: 'editor.open_gallery',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'editor.capture_photo',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'alert.cancel',
|
||||
}),
|
||||
]}
|
||||
cancelButtonIndex={2}
|
||||
onPress={index => {
|
||||
handleOpenImagePicker(index === 0 ? 'image' : index === 1 && 'camera');
|
||||
}}
|
||||
/>
|
||||
<ActionSheet
|
||||
ref={clearRef}
|
||||
title={intl.formatMessage({
|
||||
id: 'alert.clear_alert',
|
||||
})}
|
||||
options={[
|
||||
intl.formatMessage({
|
||||
id: 'alert.clear',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'alert.cancel',
|
||||
}),
|
||||
]}
|
||||
cancelButtonIndex={1}
|
||||
onPress={_handleClear}
|
||||
/>
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
style={styles.container}
|
||||
keyboardVerticalOffset={Platform.select({ ios: 0, android: 25 })}
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : null}
|
||||
>
|
||||
{!isPreviewActive ? (
|
||||
<TextInput
|
||||
multiline
|
||||
onChangeText={this._changeText}
|
||||
onSelectionChange={this._handleOnSelectionChange}
|
||||
placeholder={intl.formatMessage({
|
||||
id: isReply ? 'editor.reply_placeholder' : 'editor.default_placeholder',
|
||||
})}
|
||||
placeholderTextColor="#c1c5c7"
|
||||
selection={selection}
|
||||
selectionColor="#357ce6"
|
||||
style={styles.textWrapper}
|
||||
underlineColorAndroid="transparent"
|
||||
value={text}
|
||||
innerRef={this.inputRef}
|
||||
editable={!isLoading}
|
||||
/>
|
||||
) : (
|
||||
this._renderPreview()
|
||||
)}
|
||||
{!isPreviewActive &&
|
||||
this._renderEditorButtons({
|
||||
getState: this._getState,
|
||||
setState: (state, callback) => {
|
||||
this.inputRef.current.focus();
|
||||
this.setState(state, callback);
|
||||
},
|
||||
})}
|
||||
<ActionSheet
|
||||
ref={this.galleryRef}
|
||||
options={[
|
||||
intl.formatMessage({
|
||||
id: 'editor.open_gallery',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'editor.capture_photo',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'alert.cancel',
|
||||
}),
|
||||
]}
|
||||
cancelButtonIndex={2}
|
||||
onPress={index => {
|
||||
handleOpenImagePicker(index === 0 ? 'image' : index === 1 && 'camera');
|
||||
}}
|
||||
/>
|
||||
<ActionSheet
|
||||
ref={this.clearRef}
|
||||
title={intl.formatMessage({
|
||||
id: 'alert.clear_alert',
|
||||
})}
|
||||
options={[
|
||||
intl.formatMessage({
|
||||
id: 'alert.clear',
|
||||
}),
|
||||
intl.formatMessage({
|
||||
id: 'alert.cancel',
|
||||
}),
|
||||
]}
|
||||
cancelButtonIndex={1}
|
||||
onPress={index => index === 0 && this._handleClear()}
|
||||
/>
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default MarkdownEditorView;
|
||||
// class MarkdownEditorView extends Component {
|
||||
// constructor(props) {
|
||||
// super(props);
|
||||
// this.state = {
|
||||
// text: props.draftBody || '',
|
||||
// selection: { start: 0, end: 0 },
|
||||
// textUpdated: false,
|
||||
// newSelection: null,
|
||||
// };
|
||||
|
||||
// this.inputRef = React.createRef();
|
||||
// this.galleryRef = React.createRef();
|
||||
// this.clearRef = React.createRef();
|
||||
// }
|
||||
|
||||
// // Lifecycle functions
|
||||
// UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
// const { draftBody, uploadedImage, isPreviewActive } = this.props;
|
||||
// if (!nextProps.isPreviewActive && isPreviewActive) {
|
||||
// this.setState({
|
||||
// selection: { start: 0, end: 0 },
|
||||
// });
|
||||
// }
|
||||
// if (nextProps.draftBody && draftBody !== nextProps.draftBody) {
|
||||
// this.setState({
|
||||
// text: nextProps.draftBody,
|
||||
// });
|
||||
// }
|
||||
|
||||
// if (
|
||||
// nextProps.uploadedImage &&
|
||||
// nextProps.uploadedImage.url &&
|
||||
// nextProps.uploadedImage !== uploadedImage
|
||||
// ) {
|
||||
// applyImageLink({
|
||||
// getState: this._getState,
|
||||
// setState: async (state, callback) => {
|
||||
// await this.setState(state, callback);
|
||||
// },
|
||||
// item: { url: nextProps.uploadedImage.url, text: nextProps.uploadedImage.hash },
|
||||
// isImage: !!nextProps.uploadedImage,
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
|
||||
// componentDidUpdate(prevProps, prevState) {
|
||||
// const { text } = this.state;
|
||||
// const { handleIsFormValid } = this.props;
|
||||
|
||||
// if (prevState.text !== text) {
|
||||
// const nextText = text.replace(prevState.text, '');
|
||||
|
||||
// if (nextText && nextText.length > 0) {
|
||||
// this._changeText(text);
|
||||
|
||||
// if (handleIsFormValid) {
|
||||
// handleIsFormValid(text);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Component functions
|
||||
|
||||
// }
|
||||
|
Loading…
Reference in New Issue
Block a user