I use Two package
slate-react and emoji-mart
I want to when choose an Emoji , it puts on my editor.
import React from "react";
import { render } from "react-dom";
import { Editor } from "slate-react";
import { initialValue } from "./initialValue";
// Define our app...
class MyEditor extends React.Component {
// Set the initial value when the app is first constructed.
state = {
value: initialValue
};
// On change, update the app's React state with the new editor value.
onChange = ({ value }) => {
this.setState({ value });
};
onKeyDown = (event, change) => {
// This used to have stuff in it, but I moved it all to plugins.
};
clickMe=()=>{
this.setState({ value : this.state.value });
};
// Render the editor.
render() {
return (
<div>
<h1 onClick={this.clickMe}>Slate Editor Demo</h1>
<div style={{ border: "1px solid black", padding: "1em" }}>
<Editor
value={this.state.value}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
renderNode={this.renderNode}
spellCheck={false}
/>
</div>
</div>
);
}
}
export default MyEditor;
import React,{useState} from 'react';
import 'emoji-mart/css/emoji-mart.css';
import { Picker } from 'emoji-mart';
function Emoji() {
const [emoji,setEmoji] = useState(null);
const addEmoji = (e) => {
setEmoji(e.native)
};
return <Picker onSelect={addEmoji} />
}
export default Emoji;
Try passing the editor ref to picker. Then in Emoji component in addEmoji method, try editorRef.current.InsertText(e.native). After hours of trying to solve this:
const YourTextEditor = props => {
const editor = createEditor();
const addEmoji = async emoji => {
await setTimeout(() => {
editor.focus();
}, 100);
editor.insertText(emoji.native);
};
return (
<>
<Editor
value={initialValue}
/>
<Emoji addEmoji={addEmoji} />
</>
);
};
const Emoji = props => {
return (<Picker onSelect={e => props.addEmoji(e)} />);
};
Related
I have the following NextJS App (using reactjs, ethers.js, wagmi and connectkit), that just sends Eth from one connected Metamask Wallet to another Metamask Wallet, both of which I have access to. The problem is that before clicking the send button, it is automatically sending the transaction. I did a workaround where I have a boolean (hasClicked) that stops the transaction from taking place, but it seems a bit hamfisted. I am going off of the sendTransaction found here: https://wagmi.sh/examples/send-transaction
Below is my code:
// comps/transaction.tsx
import * as React from 'react';
import { useDebounce } from 'use-debounce';
import { usePrepareSendTransaction, useSendTransaction, useWaitForTransaction } from 'wagmi'
import { utils } from 'ethers';
export function SendTransaction() {
let hasClicked = false;
const [to, setTo] = React.useState('');
const [debouncedTo] = useDebounce(to, 500);
const [amount, setAmount] = React.useState('');
const [debouncedAmount] = useDebounce(amount, 500);
const { config } = usePrepareSendTransaction({
request: {
to: to,
value: (amount && hasClicked) ? utils.parseEther(amount) : undefined,
},
});
const { data, sendTransaction } = useSendTransaction(config);
const { isLoading, isSuccess } = useWaitForTransaction({
hash: data?.hash,
});
return (
<div>
<input
aria-label="Recipient"
onChange={(e) => {
console.log("Address Set:", e.target.value);
hasClicked = false;
e.preventDefault();
setTo(e.target.value);
}}
placeholder="0xA0Cf…251e"
value={to}
/>
<input
aria-label="Amount (ether)"
onChange={(e) => {
console.log("Amount Set:", e.target.value);
e.preventDefault();
hasClicked = false;
setAmount(e.target.value);
}}
placeholder="0.05"
value={amount}
/>
<button
onClick={(e) => {
e.preventDefault();
hasClicked = true;
sendTransaction?.();
}}
disabled={isLoading}>
{isLoading ? 'Sending...' : 'Send'}
</button>
{isSuccess && (
<div>
Successfully sent {amount} ether to {to}
<div>
<a href={`https://etherscan.io/tx/${data?.hash}`}>Etherscan</a>
</div>
</div>
)}
</div>
)
}
// pages/_app.tsx
import '../styles/globals.css';
import type { AppProps } from 'next/app';
import { WagmiConfig, createClient, useAccount, useConnect, useDisconnect, goerli } from 'wagmi';
import { mainnet, polygon, optimism, arbitrum } from 'wagmi/chains';
import { ConnectKitProvider, getDefaultClient } from 'connectkit';
import { SendTransaction } from '../comps/transaction';
const client = createClient(
getDefaultClient({
appName: 'ConnectKit Next.js demo',
//infuraId: process.env.NEXT_PUBLIC_INFURA_ID,
//alchemyId: process.env.NEXT_PUBLIC_ALCHEMY_ID,
chains: [mainnet, polygon, optimism, arbitrum, goerli],
})
);
function MyApp({ Component, pageProps }: AppProps) {
const { isConnected } = useAccount();
const loading = (
<div>
<SendTransaction />
</div>
);
return (
<WagmiConfig client={client}>
<ConnectKitProvider>
{isConnected ? (loading) : (<Component {...pageProps} />)}
</ConnectKitProvider>
</WagmiConfig>
);
}
export default MyApp;
// pages/index.tsx
import type { NextPage } from 'next';
import { ConnectKitButton } from 'connectkit';
const Home: NextPage = () => {
return (
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '100vh',
}}
>
<ConnectKitButton />
</div>
);
};
export default Home;
Again, without the hasClicked, the transaction is automatically sent.
I would also like to validate the constants "to" and "amount" before the transaction is sent, as this would be best practice, and would also like the "Send" button disabled until to and amount are validated as correct.
I am positive there must be a better way of doing this, but I am just not sure what that is.
I'm trying to use multiple rich text editors in a React form. I built the editor component using draft-js and also I integrated the inline toolbar from draft-js-plugins. Because this is a react-hook-form I wrapped the editor inside a Controller component.
The problem I have is that the InlineToolbar is displayed only for the last editor component in page.
Based on the draft-js-plugins documentation the initialization of the toolbar should happen outside the component so this is what I did:
const inlineToolbarPlugin = createInlineToolbarPlugin();
const { InlineToolbar } = inlineToolbarPlugin;
const plugins = [inlineToolbarPlugin];
function RichTextEditor({ control, name }) {
return (
<div>
<Controller
name={name}
control={control}
render={({ field: { value, onChange } }) => {
const newValue = value || EditorState.createEmpty();
return (
<>
<Editor
editorState={newValue}
onChange={onChange}
plugins={plugins}
/>
<InlineToolbar />
</>
);
}}
/>
</div>
);
}
A complete CodeSandbox example here: CodeSandbox link
Each editor get's its own plugins.
You can solve this issue ether by creating different plugin for each editor instance and pass them to the editor OR with create a function for creating a plugin inside the editor component and every time we init a editor we create a new plugin instance
So, this is the first solution:
const inlineToolbarPlugin1 = createInlineToolbarPlugin();
const { InlineToolbar:Tool1 } = inlineToolbarPlugin1;
const inlineToolbarPlugin2 = createInlineToolbarPlugin();
const { InlineToolbar:Tool2 } = inlineToolbarPlugin2;
And pass them into your custom editor components.
Second solution:
import React from "react";
import { Controller } from "react-hook-form";
import { EditorState } from "draft-js";
import PropTypes from "prop-types";
import Editor from "#draft-js-plugins/editor";
import createInlineToolbarPlugin from "#draft-js-plugins/inline-toolbar";
import "#draft-js-plugins/inline-toolbar/lib/plugin.css";
import "draft-js/dist/Draft.css";
const createtoolbarplugin = () => {
const InlineToolbarPlugin = createInlineToolbarPlugin();
const InlineToolbar = InlineToolbarPlugin.InlineToolbar;
return {
InlineToolbarPlugin,
InlineToolbar
};
};
function AnotherRichTextEditor({ control, aName }) {
const [{ InlineToolbarPlugin, InlineToolbar }] = React.useState(() => {
const { InlineToolbar, InlineToolbarPlugin } = createtoolbarplugin();
return {
InlineToolbarPlugin,
InlineToolbar
};
});
return (
<div
style={{
border: "1px solid #ccc",
minHeight: 30,
padding: 10
}}
>
<Controller
name={aName}
control={control}
render={({ field: { value, onChange } }) => {
const newValue = value || EditorState.createEmpty();
return (
<>
<Editor
editorState={newValue}
onChange={onChange}
plugins={[InlineToolbarPlugin]}
/>
<InlineToolbar />
</>
);
}}
/>
</div>
);
}
AnotherRichTextEditor.propTypes = {
control: PropTypes.object,
aName: PropTypes.string
};
export default AnotherRichTextEditor;
Hope That's help
what is the way to change class component to function component in my example ?
in my example i try to change it to a function component but it doesnt works ,
I would be happy to some help with this issue .
import * as React from 'react';
import { Searchbar } from 'react-native-paper';
export default class MyComponent extends React.Component {
state = {
firstQuery: '',
};
render() {
const { firstQuery } = this.state;
return (
<Searchbar
style={{marginTop: 60}}
placeholder="Search"
onChangeText={query => { this.setState({ firstQuery: query }); }}
value={firstQuery}
/>
);
}
}
import React, {useState} from 'react';
import { Searchbar } from 'react-native-paper';
const MyComponent =()=> {
const [firstQuery, setFirstQuery] = useState("");
return (
<Searchbar
style={{marginTop: 60}}
placeholder="Search"
onChangeText={query => { setFirstQuery(query ) }}
value={firstQuery}
/>
);
}
export default MyComponent;
Do it like this
const MyComponent = () => {
const [firstQuery, setFirstQuery] = useState('');
const _onChange = query => setFirstQuery(query);
return (
<Searchbar
style={{marginTop: 60}}
placeholder="Search"
onChangeText={_onChange}
value={firstQuery}
/>
);
}
const MyComponent = () => {
const [firstQuery, setFirstQuery] = useState('');
const handleChange = (query) => setFirstQuery(query);
return (
<Searchbar
style={{marginTop: 60}}
placeholder="Search"
onChangeText={handleChange}
value={firstQuery}
/>
);
}
Try this way
import * as React from 'react';
import { Searchbar } from 'react-native-paper';
const MyComponent = (props) => {
const [firstQuery, setFirstQuery] = React.useState('');
return (
<Searchbar
style={{marginTop: 60}}
placeholder="Search"
onChangeText={query => { setFirstQuery(query) }}
value={firstQuery}
/>
);
}
export default MyComponent;
This should do it for you:
//Only get what we need to reduce overhead
import React, { useState } from "react";
import { Searchbar } from "react-native-paper";
//you may include props here if needed, otherwise = () =>
const MyComponent = (props) => {
//State as hook, first object in array will be value second will be function to set value and notify update required
const [firstQuery, setFirstQuery] = useState("");
//handle for onChangeText
const onChangeTextHandle = (query) => {
//set state using hook
setFirstQuery(query);
};
//No need for render method, just return JSX
return (
<Searchbar
style={{ marginTop: 60 }}
placeholder="Search"
onChangeText={onChangeTextHandle}
value={firstQuery}
/>
);
};
//Export component Here
export default MyComponent;
I am trying to save the Range-slider value .If i click "NEXT" i want it save the value in 'Squarefeet' variable and redirect to another page .I have built a Rest API in the backend to bind and save the value in database.The code is something like this
import React, { Component } from 'react'
import Slider from 'react-rangeslider'
import Link from "next/link";
import axios from "axios";
import getConfig from "next/config";
const config = getConfig();
class Horizontal extends Component {
constructor (props, context) {
super(props, context)
this.state = {
apiUrl:config.publicRuntimeConfig.publicRuntimeConfigValue.apiUrl,
}
}
handleChangeStart = () => {
console.log('Change event started')
};
handleChange = value => {
this.setState({
value: value
})};
handleChangeComplete = () => {
console.log('Change event completed')
};
saveValue = () => {
console.log('saveValue ...', this.state);
axios.post( this.state.apiUrl+'/api/v1/LeadSurvey/save', {
'squareFeet':this.state.value,
}, {} )
};
render () {
const { value } = this.state
return (
<div>
<div className='slider' style={{ marginTop:'165px',marginLeft:'319px',width:'700px',backgroundColor:'EF5350'}} >
<Slider min={850} max={5000} value={value} onChangeStart={this.handleChangeStart}
onChange={this.handleChange}
onChangeComplete={this.handleChangeComplete}
/>
<div className='value'>{value} Squarefeet</div>
<div style={{marginTop:'86px'}}>
<Link prefetch href="/estimate"><a href="#" >
<span onChange={this.handleChange} onClick={() => this.saveValue()} >Next</span></a></Link>
</div>
</div>
</div>
)
}
}
export default Horizontal
I am not getting how to make it work to bind and save.How should i do it?
I'm using react-select along with material-ui to make a autocomplete component that looks and functions like the material ones.
I followed the basic setup here
https://material-ui.com/demos/autocomplete/
And then had to tweak to my setup with the data structure the way our API handles, this all works great but now I'm trying to allow the user to create a new option and I can't seem to get it to display the option back
Here is the component as is
import React, { Component } from 'react';
import { withStyles } from '#material-ui/core/styles';
import styles from "./styles";
import MenuItem from '#material-ui/core/MenuItem';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
import Typography from '#material-ui/core/Typography';
import ArrowDropDownIcon from '#material-ui/icons/ArrowDropDown';
import ArrowDropUpIcon from '#material-ui/icons/ArrowDropUp';
import Input from '#material-ui/core/Input';
import LinearProgress from '#material-ui/core/LinearProgress';
import classNames from 'classnames';
class Option extends React.Component {
handleClick = event => {
this.props.onSelect(this.props.option, event);
};
render() {
const { children, isFocused, isSelected, onFocus } = this.props;
return (
<MenuItem
onFocus={onFocus}
selected={isFocused}
disabled={isSelected}
onClick={this.handleClick}
component="div"
style={{
fontWeight: isSelected ? 500 : 400,
}}
>
{children}
{children === 'LOADING...' &&
<LinearProgress style={{ position: 'absolute',width: '100%',bottom: '0',left: '0',height: '2px', }} />
}
</MenuItem>
);
}
}
class SelectWrapped extends Component {
render() {
const { classes, ...other } = this.props;
return (
<Select
optionComponent={Option}
noResultsText={<Typography>{'No results found'}</Typography>}
clearRenderer={() => {}}
arrowRenderer={arrowProps => {
return arrowProps.isOpen ? <ArrowDropUpIcon /> : <ArrowDropDownIcon />;
}}
valueComponent={valueProps => {
const { children } = valueProps;
console.log(children)
return <div className="Select-value">{children}</div>;
}}
{...other}
/>
);
}
}
class SelectCreatable extends Component {
render() {
const { classes, ...other } = this.props;
console.log(this.props)
return (
<Select.Creatable
optionComponent={Option}
noResultsText={<Typography>{'No results found'}</Typography>}
clearRenderer={() => {}}
arrowRenderer={arrowProps => {
return arrowProps.isOpen ? <ArrowDropUpIcon /> : <ArrowDropDownIcon />;
}}
valueComponent={valueProps => {
const { children } = valueProps;
return <div className="Select-value">{children}</div>;
}}
{...other}
/>
);
}
}
class AutoCompleteComponent extends Component {
state = {
value: null,
};
handleChange = value => {
this.setState({ value: value })
const foundSuggestion = this.props.suggestions.find((s) => s.id === value);
if (this.props.creatable) {
this.props.onChange(foundSuggestion || {
[this.props.labelPropName]: value
})
} else {
this.props.onChange(foundSuggestion)
}
}
onChange = value => {
this.props.onChange(this.props.suggestions.find((s) => s.id === value))
};
render() {
const { classes, labelPropName, creatable } = this.props;
const suggestions = this.props.suggestions.map(suggestion => ({
value: suggestion.id,
label: this.props.labelFunction(suggestion)
}))
return (
<div className={classNames(classes.root,this.props.className)}>
<Input
fullWidth
inputComponent={creatable ? SelectCreatable : SelectWrapped}
value={this.state.value}
onChange={(value) => this.props.showValue ? this.handleChange(value) : this.onChange(value)}
placeholder={this.props.placeholder}
classes={{
input: classes.input,
...this.props.InputClasses
}}
inputProps={{
classes,
simpleValue: true,
options: suggestions
}}
/>
</div>
);
}
}
export default withStyles(styles, { withTheme: true })(AutoCompleteComponent);
I setup a stackblitz with a running example and some options. If you type and select an option you'll see it display the selected option, but if you type a new one and hit enter it doesn't display the option and I'm trying to figure out why, some help on what I'm doing wrong here would be super helpful
https://wmazc4.stackblitz.io
I thinks the bug is with your data conversion id to value messes with your react-select component
I went through a demo from an exact copy of your code (since your example wasn't working)
here is my example: https://codesandbox.io/s/p9j3xz843m
here I used
inputProps={{
classes,
name: "react-select-single",
instanceId: "react-select-single",
simpleValue: true,
options: colourOptions,
valueKey: "id",
labelKey: "label"
}}
find that I used valueKey and labelKey props to convert data you can find more from the live example
hope this will help you. please let me know if you want more clarifications.