import { fabric } from 'fabric';
const Canvas = () => {
const [canvas, setCanvas] = useState('');
useEffect(() => {
setCanvas(initCanvas());
}, []);
const initCanvas = () => (
new fabric.Canvas('canvas', {
height: 800,
width: 800,
})
);
const addRect = canvi => {
const rect = new fabric.Rect({
height: 280,
width: 200,
fill: 'yellow'
});
canvi.add(rect);
canvi.renderAll();
}
return(
<div>
<button onClick={() => addRect(canvas)}></button>
<br/><br/>
<canvas id="canvas" />
</div>
);
}
export default Canvas;
I want to display the rectangle without using the button and also to display its state on the browser
the onload event is also not working in the react I also tried to use the other alternative of onload but it's of no help
I'm also working on this if you want to add rect without button click you can add it into the useEffect.
const fuctionName = ()=>{
useEffect(() => {
return () => {
const canvas = new fabric.Canvas('canvas-main');
const rect = new fabric.Rect({
height: 280,
width: 200,
fill: 'yellow',
});
canvas.add(rect);
}
}, [])
return (
<>
<canvas
style={{ border: 'solid 1px #555' }}
id="canvas-main"
width="600px"
height="600px"
/>
</>
);
};
Related
I want to have a resizeable modal only on height so I did write some code but while trying to grow it to the bottom because it's going fast and out of the element it doesn't have any impact, also I have seen codes like this but they work properly like this I don't know what I'm missing.
also, I want to ask; is it the right way of doing resizeable components in react? I did try to write it with states but I faced some problems like it was growing unexpectedly.
import React, { FC, useCallback, useMemo, useRef } from "react";
import { PrimitivesT } from "../Table/Table";
interface ModalProps {
children: JSX.Element | PrimitivesT;
display: boolean;
width: string;
height: string;
x?: number;
y?: number;
boxShadow?: boolean;
}
const Modal: FC<ModalProps> = ({
children,
display = false,
// initial height
height = "0",
width = "0",
x,
y,
boxShadow = true,
}) => {
const ref = useRef<HTMLDivElement>(null);
const styles = useMemo<React.CSSProperties>(
() => ({
display: display ? "block" : "none",
height: height,
width,
minHeight: "15px",
position: "absolute",
left: x,
top: y,
boxShadow: boxShadow ? "1px 1px 10px 5px var(--gray)" : undefined,
borderRadius: "5px",
backgroundColor: "white",
zIndex: 900,
}),
[display, height, width, x, y, boxShadow]
);
const bottomStyle = useMemo<React.CSSProperties>(
() => ({
cursor: "row-resize",
width: "100%",
position: "absolute",
bottom: "0",
left: "0",
height: "5px",
}),
[]
);
const onMouseDown =
useCallback((): React.MouseEventHandler<HTMLDivElement> => {
let y = 0;
let h = 60;
const onMouseMove = (e: MouseEvent) => {
const YDir = e.clientY - y;
if (ref.current) ref.current.style.height = `${h + YDir}px`;
};
const onMouseUp = () => {
try {
ref.current?.removeEventListener("mousemove", onMouseMove);
ref.current?.removeEventListener("mouseup", onMouseUp);
} catch (err) {
console.error(err);
}
};
return e => {
e.stopPropagation();
const bounding = ref.current?.getBoundingClientRect();
if (bounding?.height) h = bounding?.height;
y = e.clientY;
ref.current?.addEventListener("mousemove", onMouseMove);
ref.current?.addEventListener("mouseup", onMouseUp);
};
}, []);
return (
<div
ref={ref}
style={styles}
data-testid="Modal"
onMouseDown={e => e.stopPropagation()}>
{children}
<div style={bottomStyle} onMouseDown={onMouseDown()}></div>
</div>
);
};
export default Modal;
I think it didn't work that way because it's modal and it has to be fixed or absolute so I change the element that I was attaching event listeners instead of the resizeable target I used document object.
const onMouseDown =
useCallback((): React.MouseEventHandler<HTMLDivElement> => {
let y = 0;
let h = 60;
const onMouseMove = (e: MouseEvent) => {
const YDir = e.clientY - y;
if (ref.current) ref.current.style.height = `${h + YDir}px`;
};
const onMouseUp = () => {
try {
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", onMouseUp);
} catch (err) {
console.error(err);
}
};
return e => {
e.stopPropagation();
const bounding = ref.current?.getBoundingClientRect();
if (bounding?.height) h = bounding?.height;
y = e.clientY;
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", onMouseUp);
};
}, []);
I'm trying to do a loading bar with fixed timeout, says within 5 seconds, the bar should all filled up. I'm able to write the html and css but stuck in the js logic.
function App() {
const [tick, setTick] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setTick(tick => tick + 10); //some calculation is missing
}, 1000);
setTimeout(() => {
clearInterval(id);
}, 5000);
return () => clearInterval(id);
}, []);
return (
<div className="App">
<div
style={{
width: "100%",
background: "yellow",
border: "1px solid"
}}
>
<div
style={{
height: "10px",
background: "black",
width: tick + "%"
}}
/>
</div>
</div>
);
}
https://codesandbox.io/s/proud-architecture-fuwcw
I refactored your code a little.
I created 3 constants:
maxLoad: Is the percentage to cover, in your case a 100%.
fulfillInterval: It's the interval to fill a step in the bar.
step: It's the calculation of the width to fill in the present iteration.
Then I changed a while the code adding 1 milisecond to the clearTimeout to ensure that it's going to work and... it's working. :)
Hope this helps.
import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [tick, setTick] = useState(0);
const maxLoad = 100; // total percentage to cover
const fulfillInterval = 5000; // clear interval timeout
const step = maxLoad/(fulfillInterval/1000); // % filled every step
useEffect(() => {
const id = setInterval(() => {
setTick(tick => tick + step); // No dependency anymore
}, 1000);
setTimeout(() => {
clearInterval(id);
}, fulfillInterval+1);
return () => clearInterval(id);
}, []);
return (
<div className="App">
<div
style={{
width: "100%",
background: "yellow",
border: "1px solid"
}}
>
<div
style={{
height: "10px",
background: "black",
width: tick + "%"
}}
/>
</div>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
useEffect(() => {
const id = setInterval(() => {
if(tick !==100)
setTick(tick => tick + 10); // No dependency anymore
}, 1000);
setTimeout(() => {
clearInterval(id);
}, 5000);
return () => clearInterval(id);
}, [tick])
Replace your useEffect function like this.
everyone, I am trying to make a postcard application with these functionalities
Captures image data from the user, using a webcam
Modifies the image to contain a message (preferably using HTML canvas)
Finally, email the modified picture as an attachment
To start by capturing the image from the webcam I wanted to convert MDN HTML code to React but I am stuck
I have written code in previous projects for the second and last bullet point, but the first bullet is rattling my brain.
As a reference I used Bryan Bierce:Using the Webcam in React to start but a few errors came up
My questions:
Currently getUserMedia() isn't taking in the constraints and it
bypass stream and go directly to the catch(err). Is there a reason why it goes straight to the catch function ?
Should I be appending the variables to the page before using them? Specifically the variables created in takePicture() and clearPhoto()
Here is the current HTML code:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="http://localhost:5000/bundle.js" defer></script>
</head>
<body>
<div id='wrapper'>
<canvas id='canvas'></canvas>
</div>
<div id="root"></div>
</body>
</html>
Here is my current React code:
import React from 'react';
import ReactDOM from 'react-dom';
import {Component} from 'react'
import $ from 'jquery';
// CSS Styling
const styles = {
capture: {
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'center',
},
picSize: {
display: 'flex',
maxWidth: 340,
maxHeight: 340,
minWidth: 340,
minHeight: 340,
margin: 30,
},
box: {
maxWidth: 340,
maxHeight: 340,
minWidth: 340,
minHeight: 340,
border: '10px solid green',
}
}
const Camera = (props) => {
return(
<div className="camera"
style={ styles.box }
>
<video id="video"
style={ styles.picSize }
></video>
<button id="startbutton"
onClick={ props.handleStartClick }
>Take photo</button>
</div>
)
}
const Photo = (props) => {
return(
<div className="output"
style={ styles.box }>
<img id="photo" alt="Your photo"
style={ styles.picSize } />
<button id="saveButton" onClick={ props.handleSaveClick }>Save Photo</button>
</div>
)
}
//Components
class Capture extends React.Component{
constructor(props) {
super(props);
this.state = {
constraints: { photo: null,audio: false, video: { width: 320, height: 320, startbutton:null } }
};
this.handleStartClick = this.handleStartClick.bind(this);
this.takePicture = this.takePicture.bind(this);
this.clearPhoto = this.clearPhoto.bind(this);
}
componentDidMount(){
const constraints = this.state.constraints;
console.log("CONSTRAINTS:",constraints)
const getUserMedia = (params) => (
new Promise((successCallback, errorCallback) => {
return navigator.webkitGetUserMedia.call(navigator, params, successCallback, errorCallback);
})
);
getUserMedia(constraints)
.then((stream) => {
const video = document.querySelector('video');
const vendorURL = window.URL || window.webkitURL;
video.src = vendorURL.createObjectURL(stream);
video.play();
})
.catch((err) => {
console.log(err);
});
this.clearPhoto();
}
clearPhoto(){
const canvas = document.querySelector('canvas');
const photo = document.getElementById('photo');
const context = canvas.getContext('2d');
const { width, height } = this.state.constraints.video;
context.fillStyle = '#FFF';
context.fillRect(0, 0, width, height);
const data = canvas.toDataURL('image/png');
photo.setAttribute('src', data);
}
handleStartClick(event){
event.preventDefault();
this.takePicture();
}
takePicture(){
const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');
const video = document.querySelector('video');
const photo = document.getElementById('photo');
const { width, height } = this.state.constraints.video;
const startbutton = document.getElementById('startbutton');
let streaming = false;
canvas.width = width;
canvas.height = height;
context.drawImage(video, 0, 0, width, height);
const data = canvas.toDataURL('image/png');
console.log("PHOTO:",photo)
photo.setAttribute('src', data);
navigator.getMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
navigator.getMedia(
{
video: true,
audio: false
},
function(stream) {
if (navigator.mozGetUserMedia) {
video.mozSrcObject = stream;
} else {
var vendorURL = window.URL || window.webkitURL;
video.src = vendorURL.createObjectURL(stream);
}
video.play();
},
function(err) {
console.log("An error occured! " + err);
}
)
console.log("VIDEO:",video)
video.addEventListener('canplay', function(ev){
video.setAttribute('width', width);
video.setAttribute('height', height);
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
streaming = true;
}, false);
console.log("Start Button:",startbutton)
startbutton.addEventListener('click', function(event){
event.preventDefault();
this.takePicture();
console.log("Taking pictures:",this.takePicture())
}, false);
this.clearPhoto();
}
render(){
return (
<div className="capture"
style={ styles.capture }
>
<Camera
handleStartClick={ this.handleStartClick }
/>
<canvas id="canvas"
style={ styles.picSize }
hidden
></canvas>
<Photo />
</div>
);
}
}
ReactDOM.render(
<Capture />,
document.getElementById('root')
);
** LATEST Fiddle -- http://jsfiddle.net/cfrapLma/28/
adding chart types -- is there a better way to move this forward -- would the config json be handled via redux -- what is the next step forward. Has anyone tried making a dashboard application using reactjs and d3 before?
I am working on a reactjs project and I am keen to output a set of div holders that will contain future chart parameters, like width, height, url service.
++ How do I push and pull about multiple parameters to create different instances of a chart, placeholder..?
++ Is this a good start for creating a dashboard set of components do I need to create a configuration json for what charts, sizes, services I want to absorb.
//config json?
[{
"width": 200,
"height": 200,
"type": "piechart",
"serviceApi": "api.php?mode=GetCars"
}, {
"width": 100,
"height": 100,
"type": "barchart",
"serviceApi": "api.php?mode=GetBoats"
}]
do I need to create a config json that will control the parameters - an array of charts that are needing to be rendered?
var MultipleCharts = React.createClass({
render: function() {
return (
<div>
<div className="holder1"><PieChart width={this.props.width} height={this.props.height} service={this.props.service}/></div>
<div className="holder2"><PieChart width={this.props.width} height={this.props.height} service={this.props.service}/></div>
</div>
);
}
});
^ this is a hard coded approach and I would need to loop and push through a configuration json so each chart has different properties.
<div data-role="piechart" data-width=240 data-height=240 data-service="api.php?mode=GetCars">
//Latest Fiddle
http://jsfiddle.net/cfrapLma/24/
here is the first prototype build - whether I would have reactjs handle a stack of charts -- as if this information is coming from a configuration json -- like a dashboard setup.
Or the dashboard configuration is hardcoded on the template -- and reactjs invokes the charting tool.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>React Charts</title>
<script src="https://npmcdn.com/react#15.3.0/dist/react.js"></script>
<script src="https://npmcdn.com/react-dom#15.3.0/dist/react-dom.js"></script>
<script src="https://npmcdn.com/babel-core#5.8.38/browser.min.js"></script>
<script src="https://npmcdn.com/jquery#3.1.0/dist/jquery.min.js"></script>
<script src="https://npmcdn.com/remarkable#1.6.2/dist/remarkable.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
var config = [{
"width": 200,
"height": 200,
"type": "piechart",
"serviceApi": "api.php?mode=GetCars"
}, {
"width": 100,
"height": 100,
"type": "barchart",
"serviceApi": "api.php?mode=GetBoats"
}];
var MultipleCharts = React.createClass({
render: function() {
return (
<div>
<div className="holder1"><PieChart width={this.props.width} height={this.props.height} service={this.props.service}/></div>
<div className="holder2"><BarChart width={this.props.width} height={this.props.height} service={this.props.service}/></div>
</div>
);
}
});
var PieChart = React.createClass({
componentDidMount: function() {
var $this = $(ReactDOM.findDOMNode(this));
console.log("rendered div now engage d3");
// set el height and width etc.
},
render: function() {
return (
<div className="piechart" data-role="piechart" data-width={this.props.width} data-height={this.props.height} data-service={this.props.service}>pie.
</div>
);
}
});
var BarChart = React.createClass({
componentDidMount: function() {
var $this = $(ReactDOM.findDOMNode(this));
console.log("rendered div now engage d3");
// set el height and width etc.
},
render: function() {
return (
<div className="barchart" data-role="barchart" data-width={this.props.width} data-height={this.props.height} data-service={this.props.service}>pie.
</div>
);
}
});
ReactDOM.render(
<MultipleCharts width="200" height="200" service="api.php?mode=GetCars"/>,
document.getElementById('example')
);
</script>
</body>
</html>
So, what you can do is to create fabric method that will return corresponding component based on config.type.
Then, you can iterate through all your configs in render method.
And also pass config as props to your component MultipleCharts.
var config = [{
"width": 200,
"height": 200,
"type": "piechart",
"serviceApi": "api.php?mode=GetCars"
}, {
"width": 100,
"height": 100,
"type": "barchart",
"serviceApi": "api.php?mode=GetBoats"
}];
var MultipleCharts = React.createClass({
getChart: function(config) {
switch (config.type) {
case 'piechart':
return <PieChart width={config.width} height={config.height} service={config.service} />
case 'barchart':
return <BarChart width={config.width} height={config.height} service={config.service} />
}
},
render: function () {
var config = this.props.config;
return (
<div>
{config.map((chartConfig, index) => {
return (
<div key={index} className={'holder' + index}>
{this.getChart(chartConfig)}
</div>
)
})}
</div>
);
}
});
var PieChart = React.createClass({
componentDidMount: function () {
var $this = $(ReactDOM.findDOMNode(this));
console.log("rendered div now engage d3");
// set el height and width etc.
},
render: function () {
return (
<div className="piechart" data-role="piechart" data-width={this.props.width} data-height={this.props.height}
data-service={this.props.service}>pie.
</div>
);
}
});
var BarChart = React.createClass({
componentDidMount: function () {
var $this = $(ReactDOM.findDOMNode(this));
console.log("rendered div now engage d3");
// set el height and width etc.
},
render: function () {
return (
<div className="barchart" data-role="barchart" data-width={this.props.width} data-height={this.props.height}
data-service={this.props.service}>pie.
</div>
);
}
});
ReactDOM.render(
<MultipleCharts config={config} />,
document.getElementById('example')
);
And please, try to avoid using data-* attributes in React components.
Based in #Sergey's answer I have added a couple of modifications to make it really dynamic. Now there is a typeMapping object that maps from strings to components. If you want to add a new component, you just need to add it there. For convenience I am using ES6, I hope that you can translate it to ES5 if you need to.
var config = [{
"type": "PieChart",
"width": 200,
"height": 200,
"serviceApi": "api.php?mode=GetCars"
}, {
"type": "BarChart",
"width": 100,
"height": 100,
"serviceApi": "api.php?mode=GetBoats"
}];
var MultipleCharts = React.createClass({
getChart: function(config) {
const { type, ...props } = config;
return React.createElement(typeMapping[type], props);
},
render: function () {
var config = this.props.config;
return (
<div>
{config.map((chartConfig, index) => {
return (
<div key={index} className={'holder' + index}>
{this.getChart(chartConfig)}
</div>
)
})}
</div>
);
}
});
var PieChart = React.createClass({
componentDidMount: function () {
var $this = $(ReactDOM.findDOMNode(this));
console.log("rendered div now engage d3");
// set el height and width etc.
},
render: function () {
return (
<div className="piechart" data-role="piechart" data-width={this.props.width} data-height={this.props.height}
data-service={this.props.serviceApi}>pie.
</div>
);
}
});
var BarChart = React.createClass({
componentDidMount: function () {
var $this = $(ReactDOM.findDOMNode(this));
console.log("rendered div now engage d3");
// set el height and width etc.
},
render: function () {
return (
<div className="barchart" data-role="barchart" data-width={this.props.width} data-height={this.props.height}
data-service={this.props.serviceApi}>bar.
</div>
);
}
});
// Allowed types
const typeMapping = {
PieChart, // In ES6, it is the same as "PieChart": PieChart,
BarChart,
};
ReactDOM.render(
<MultipleCharts config={config} />,
document.getElementById('example')
);
.piechart{
background: pink;
width: 100px;
height: 50px;
border: 1px solid black;
}
.barchart{
background: green;
width: 100px;
height: 50px;
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://npmcdn.com/react#15.3.1/dist/react.js"></script>
<script src="https://npmcdn.com/react-dom#15.3.1/dist/react-dom.js"></script>
<div id="example"></div>
Alright so using the create-react-app as a base..
I've tried to start cutting up the files. I get an error when I try and put the PieChart/BarChart parts into their respective files -- do I need to modify them as a class?
/src/App.css
.App {
text-align: center;
}
.App-logo {
animation: App-logo-spin infinite 20s linear;
height: 80px;
}
.App-header {
background-color: #222;
height: 150px;
padding: 20px;
color: white;
}
.App-intro {
font-size: large;
}
#keyframes App-logo-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/src/App.js
import React, { Component } from 'react';
import './App.css';
import BarChart from './BarChart';
import PieChart from './PieChart';
import LineChart from './LineChart';
// Allowed types
const typeMapping = {
PieChart, // In ES6, it is the same as "PieChart": PieChart,
BarChart,
LineChart
};
class App extends Component {
getChart(config) {
const { type, ...props } = config;
return React.createElement(typeMapping[type], props);
}
render() {
var config = this.props.config;
return (
<div>
{config.map((chartConfig, index) => {
return (
<div key={index} className={'holder' + index}>
{this.getChart(chartConfig)}
</div>
)
})}
</div>
);
}
}
export default App;
/src/BarChart.js
//barchart
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
var $ = require("jquery");
class BarChart extends Component {
componentDidMount() {
var $this = $(ReactDOM.findDOMNode(this));
console.log("rendered div now engage d3", $this);
// set el height and width etc.
}
render() {
return (
<div className="barchart" data-role="barchart" data-width={this.props.width} data-height={this.props.height}
data-service={this.props.serviceApi}>bar.
</div>
);
}
};
export default BarChart;
/src/Index.css
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
.piechart{
background: pink;
width: 100px;
height: 50px;
border: 1px solid black;
}
.barchart{
background: green;
width: 100px;
height: 50px;
border: 1px solid black;
}
.linechart{
background: purple;
width: 100px;
height: 50px;
border: 1px solid black;
}
/src/Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
var config = [{
"type": "PieChart",
"width": 200,
"height": 200,
"serviceApi": "api.php?mode=GetCars"
}, {
"type": "BarChart",
"width": 100,
"height": 100,
"serviceApi": "api.php?mode=GetBoats"
}, {
"type": "LineChart",
"width": 100,
"height": 100,
"serviceApi": "api.php?mode=GetBoats"
}];
ReactDOM.render(
<App config={config} />,
document.getElementById('root')
);
/src/LineChart.js
//linechart
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
var $ = require("jquery");
class LineChart extends Component {
componentDidMount() {
var $this = $(ReactDOM.findDOMNode(this));
console.log("rendered div now engage d3", $this);
// set el height and width etc.
}
render() {
return (
<div className="linechart" data-role="linechart" data-width={this.props.width} data-height={this.props.height}
data-service={this.props.serviceApi}>line.
</div>
);
}
};
export default LineChart;
/src/PieChart.js
//piechart
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
var $ = require("jquery");
class PieChart extends Component {
componentDidMount() {
var $this = $(ReactDOM.findDOMNode(this));
console.log("rendered div now engage d3", $this);
// set el height and width etc.
var dataset = {
apples: [53245, 28479, 19697, 24037, 40245],
};
var width = 460,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.category20();
var pie = d3.layout.pie()
.sort(null);
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 50);
var svg = d3.select($this[0]).append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(pie(dataset.apples))
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
}
render() {
return (
<div className="piechart" data-role="piechart" data-width={this.props.width} data-height={this.props.height}
data-service={this.props.serviceApi}>pie.
</div>
);
}
};
export default PieChart;
Hi I have a problem in Draft-JS . I want to change the text like when user type ":)" it will change to emoji, But in this example I just want to change some word using "**" for testing. Somehow this.setState new editorstate in handleInput doesnt change the state.
import React, {Component} from 'react';
import {Editor, EditorState,getDefaultKeyBinding,moveFocusToEnd, KeyBindingUtil,getContentStateFragment, SelectionState, Modifier, CompositeDecorator} from 'draft-js';
const storage = {
"Abm7" : "Abminorseventh"
}
export default class MyEditor extends Component {
constructor(props) {
super(props);
this.state = { editorState: EditorState.createEmpty(), lastOffset:0 };
this.focus = () => this.refs.editor.focus();
this.logState = () => console.log(this.state.editorState.toJS());
}
onChange(editorState) {
this.setState({editorState});
}
handleBeforeInput(e) {
if(e === ' ') {
const { editorState } = this.state;
const content = editorState.getCurrentContent();
const selection = editorState.getSelection();
const end = selection.getEndOffset();
const block = content.getBlockForKey(selection.getAnchorKey());
const word = block.getText();
const result = word.slice(this.state.lastOffset, selection.getEndOffset());
const newSelection = new SelectionState({
anchorKey: block.getKey(),
anchorOffset: 0,
focusKey: block.getKey(),
focusOffset: 2
})
const contentReplaced = Modifier.replaceText(
content,
newSelection,
"**")
const editorStateModified = EditorState.push(
editorState,
contentReplaced,
'replace-text'
);
this.setState({lastOffset: selection.getEndOffset(), editorState:editorStateModified})
return true;
}else {
return false;
}
}
prompt(e) {
e.preventDefault();
const {editorState} = this.state;
const content = editorState.getCurrentContent();
const selection = editorState.getSelection();
const block = editorState.getCurrentContent().getBlockForKey(selection.getAnchorKey());
let text = block.getText().slice(selection.getStartOffset(), selection.getEndOffset());
const contentReplaced = Modifier.replaceText(
content,
selection,
storage[text])
const editorStateModified = EditorState.push(
editorState,
contentReplaced,
'replace-text'
);
console.log(editorStateModified.getCurrentContent())
this.setState({editorState:editorStateModified})
}
render() {
const styles = {
root: {
fontFamily: '\'Helvetica\', sans-serif',
padding: 20,
width: 600,
},
editor: {
border: '1px solid #ccc',
cursor: 'text',
minHeight: 80,
padding: 10,
},
button: {
marginTop: 10,
textAlign: 'center',
},
buttons: {
marginBottom: 10,
},
};
return (
<div style={styles.root}>
<div style={styles.buttons}>
<button
onMouseDown={(e)=>{this.prompt(e)}}
style={{marginRight: 10}}>
Change word
</button>
</div>
<div style={styles.editor} onClick={this.focus}>
<Editor
editorState={this.state.editorState}
onChange={(e)=>{this.onChange(e)}}
handleBeforeInput={(e)=>{this.handleBeforeInput(e)}}
placeholder="Enter some text..."
ref="editor"
/>
</div>
<input
onClick={this.logState}
style={styles.button}
type="button"
value="Log State"
/>
</div>
);
}
}
The function handleBeforeInput should return "handled", if you want for you changes to be applied. And it should be returned to Editor component, so you need to pass the function to the Editor component as it is, like this:
<Editor
...
handleBeforeInput={this.handleBeforeInput}
...
/>
Reference: https://draftjs.org/docs/api-reference-editor#handlebeforeinput