Map is not re centering on marker position in react google maps - react-google-maps

react-google-maps is working fine,i use props to recenter the center position,but it seems map is not centering.Whats wrong in my code?
I have a map container and google map is a function base component.
import React, {useEffect, useState} from "react";
import {GoogleMap, InfoWindow, Marker, withGoogleMap, withScriptjs} from "react-google-maps";
import mapStyles from "./mapStyles";
import MapIcon from "../views/mapicon.png";
import MapMarked from "../views/mapMarked.png";
function Map(data) {
const cameras = data.data;
const [selectedPark, setSelectedPark] = useState(null);
const [cameraName,setCameraName]=useState(null);
const [center,setCenter]=useState(null);
const [zoom,setZoom]=useState(null)
useEffect(() => {
setCenter({lat: 23.8103, lng: 90.4125});
setZoom(11)
const listener = e => {
if (e.key === "Escape") {
setSelectedPark(null);
setZoom(11);
setCenter({lat: 23.8103, lng: 90.4125});
}
};
window.addEventListener("keydown", listener);
return () => {
window.removeEventListener("keydown", listener);
};
}, []);
const changeMap =(marker)=>{
const a= marker.lat, b=marker.lon;
const g= '{';
const v=':';
const centers=g.concat('lat',v,a,',','lng',v,b,'}');
setSelectedPark(marker);
setCameraName(marker.name);
setCenter(centers)
setZoom(15)
}
return (
<GoogleMap
zoom={zoom}
center={center}
defaultOptions={{ styles: mapStyles,
// gestureHandling:'greedy',
zoomControlOptions: { position: 14 },
}}
>
{cameras.map(marker=> (
<Marker
key={marker.id}
position={{
lat: marker.lat,
lng: marker.lon
}}
onClick={() => {
changeMap(marker);
}}
icon={{
url: cameraName !== marker.name ? MapIcon : MapMarked ,
scaledSize: new window.google.maps.Size(40, 40)
}}
/>
))}
{selectedPark && (
<InfoWindow
onCloseClick={() => {
setSelectedPark(null);
setCameraName(null);
setZoom(11);
setCenter({lat: 23.8103, lng: 90.4125});
}}
position={{
lat: selectedPark.lat,
lng: selectedPark.lon
}}
options={{
alignBottom: true,
pane: 'mapPane',
pixelOffset: new window.google.maps.Size(0, -50),
boxStyle: {
width: '80px'
},
closeBoxURL: ``,
enableEventPropagation: true
}}
>
<div>
<h3>{selectedPark.name}</h3>
<p>{selectedPark.address}</p>
</div>
</InfoWindow>
)}
</GoogleMap>
);
}
const MapWrapped = withScriptjs(withGoogleMap(Map));
class GoogleMapontainer extends React.Component {
render() {
if(this.props.data.length>0) {
return (
<div
style={{
position: "relative",
height: "calc(100vh - 175px)",
backgroundColor: "#F2F3F5"
}}
>
<MapWrapped
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=key`}
loadingElement={<div style={{height: `100%`}}/>}
containerElement={<div style={{height: `100%`}}/>}
mapElement={<div style={{height: `100%`}}/>}
data={this.props.data}
/>
</div>
);
}
else
return <div> Loading....</div>
}
}
export default GoogleMapontainer;

Related

Uncaught TypeError: Cannot read property 'appendChild' of undefined

I have a following return from my component
<div className="content page-with-map" >
<div className='route-editor'>
<Loader loading={routeSectionsLoadingList}/>
{this.renderRouteSectionsList()}
<div className='route-map-block'>
<MapComponent className='route-map'>
<Pane name='RouteSections' style={{ zIndex: 300 }}>
<RouteSectionsLayer
isAdd={isAdd}
isEdit={isEdit}
linesData={routeSectionsFeaturesList}
selectedLine={selectedSection}
setSelectedLine={this.handleSelectSection}
hoveredLine={hoveredSection}
onMouseOverLine={this.onMouseOver}
onMouseOutLine={this.onMouseOut}
/>
</Pane>
</MapComponent>
</div>
</div>
</div>
);
and here is my MapComponent, where i take children and add some custom props. Also rendering map on condition of higher div added to the DOM:
const cityBounds = CITY_BOUNDS;
// State
const [bounds, setBounds] = useState(cityBounds);
const [renderMap, setRenderMap] = useState(false);
const [zoom, setZoom] = useState();
const leafletContainerRef = useRef(null);
useEffect(() => {
if (leafletContainerRef.current) {
setRenderMap(true);
}
}, [leafletContainerRef.current]);
const onViewportChanged = (viewport) => {
const { zoom } = viewport;
setZoom(zoom);
};
const onBoundsChanged = (bounds) => {
setBounds(bounds);
};
const {
className,
children,
} = props;
let customProps = {};
return (
<div className={classNames('leaflet-container', className)} ref={leafletContainerRef}>
{renderMap ?
<MapContainer
bounds={bounds}
doubleClickZoom={false}
crs={L.CRS.EPSG3395}
onViewportChanged={onViewportChanged}
>
<TileLayer
url="https://vec{s}.maps.yandex.net/tiles?l=map&v=20.07.01-0&x={x}&y={y}&z={z}&scale=1&lang=ru_RU"
subdomains={['01', '02', '03', '04']}
attribution='<a http="yandex.ru" target="_blank">Яндекс</a>'
/>
{React.Children.map(children, child => {
customProps = { ...customProps, onBoundsChanged: onBoundsChanged, bounds: bounds };
return React.cloneElement(child, customProps);
})}
</MapContainer>
: null}
</div>
);
}
And also RouteSectionsLayer component:
export default function RouteSectionsLayer(props) {
const { isEdit = false, selectedLine } = props;
const getLines = () => {
const { onMouseOverLine = () => {}, onMouseOutLine = () => {}, linesData = [] } = props;
return linesData && linesData.length ?
linesData.map((lineFeature, i) => {
const lineIndex = i;
return <Polyline
key={hash(lineIndex)}
pane={'RouteSections'}
positions={lineFeature.geometry
&& lineFeature.geometry.coordinates
&& lineFeature.geometry.coordinates.map(line => line.map(vertex => vertex.map(coordinate => +coordinate)))}
attribution={`${i}`}
lineIndex={lineIndex}
pathOptions={{
color: 'black',
weight: 5,
}}
/>;
})
: null;
};
return (
getLines()
);
}
While rendering i get "Uncaught TypeError: Cannot read property 'appendChild' of undefined". What am i doing wrong?
UPDATE: I tried to rewrote RouteSectionsLayer following core architecture example from docs, now it looks like this:
export default function RouteSectionsLayer(props) {
const leafletContext = useLeafletContext();
const getLinesData = () => {
const { input, linesData = [] } = props;
if (input && input.value) {
return input.value;
}
return linesData;
};
useEffect(() => {
const container = leafletContext.layerContainer || leafletContext.map;
const linesData = getLinesData();
const polyLinesInstances = linesData && linesData.length ?
linesData.map((lineFeature, lineIndex) => {
const latlngs = lineFeature.geometry && coordsToNumbers(lineFeature.geometry.coordinates);
const layerOptions = {
attribution: `${lineIndex}`,
pane: 'RouteSections'
};
const pathOptions = normalRouteSectionStylePathOptions;
const polyLineOptions = {
lineIndex: { lineIndex },
...layerOptions,
...pathOptions
};
return new L.Polyline(latlngs, polyLineOptions)
})
: [];
const layerGroupInstance = new L.LayerGroup(polyLinesInstances);
container.addLayer(layerGroupInstance);
return () => {
container.removeLayer(layerGroupInstance);
};
});
const coordsToNumbers = (lineCoordinates) => {
return lineCoordinates && lineCoordinates.length ?
lineCoordinates.map(line => line.map(vertex => vertex.map(coordinate => +coordinate)))
: null;
};
And the error is still here
well, i found my mistake. In re-wrote RouteSectionsLayer i deleted pane in the options of the polyline:
const layerOptions = {
attribution: `${lineIndex}`,
pane: 'RouteSections' // <-- i deleted this.
};
It seams that the pane 'RouteSections' i created as a child of MapComponent was not found.

Text field with multiple value(image included for reference)

I'm looking for a text field with multiple inputs as:
Here as you can see I can add new text and on press of enter it saves that keyword.
Can someone guide which package to look for.... I found something similar in material ui autocomplete's costomized hook: https://material-ui.com/components/autocomplete/,
but I don't want it to be drop down I want it to be simply be a text field with option as shown in image.
I cannot find with such functionality or I might be looking work as I don't know proper term for it.
Any guidance will be of great help.
I've included material-ui , reactstrap as this is something I have worked with so if there is any other package also let me know
I was also building something like this few days back. This is what I've built till now.
import {
Chip,
FormControl,
Input,
makeStyles,
} from "#material-ui/core";
import React, { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const classes = useStyles();
const [values, setValues] = useState(["test"]);
const [currValue, setCurrValue] = useState("");
const handleKeyUp = (e) => {
console.log(e.keyCode);
if (e.keyCode == 32) {
setValues((oldState) => [...oldState, e.target.value]);
setCurrValue("");
}
};
useEffect(() => {
console.log(values);
}, [values]);
const handleChange = (e) => {
setCurrValue(e.target.value);
};
const handleDelete = ( item, index) =>{
let arr = [...values]
arr.splice(index,1)
console.log(item)
setValues(arr)
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<FormControl classes={{ root: classes.formControlRoot }}>
<div className={"container"}>
{values.map((item,index) => (
<Chip size="small" onDelete={()=>handleDelete(item,index)} label={item}/>
))}
</div>
<Input
value={currValue}
onChange={handleChange}
onKeyDown={handleKeyUp}
/>
</FormControl>
</div>
);
}
const useStyles = makeStyles((theme) => ({
formControlRoot: {
display: "flex",
alignItems: "center",
gap: "8px",
width: "300px",
flexWrap: "wrap",
flexDirection: "row",
border:'2px solid lightgray',
padding:4,
borderRadius:'4px',
"&> div.container": {
gap: "6px",
display: "flex",
flexDirection: "row",
flexWrap: "wrap"
},
"& > div.container > span": {
backgroundColor: "gray",
padding: "1px 3px",
borderRadius: "4px"
}
}
}));
Here is the working demo:
One possible way to do this using react-hook-form and Autocomplete using the Chip with renderTags function here is an example:
import {
Box,
TextField,
Autocomplete,
Chip,
} from '#mui/material'
...
const {
handleSubmit,
control,
formState: { errors },
} = useForm()
...
<Box mt={2}>
<Controller
control={control}
name="tags"
rules={{
required: "Veuillez choisir une réponse",
}}
render={({ field: { onChange } }) => (
<Autocomplete
defaultValue={
useCasesData?.tags ? JSON.parse(useCasesData?.tags) : []
}
multiple
id="tags-filled"
options={[]}
freeSolo
renderTags={(value, getTagProps) =>
value.map((option, index) => (
<Chip
variant="outlined"
label={option}
{...getTagProps({ index })}
/>
))
}
onChange={(event, values) => {
onChange(values);
}}
renderInput={(params) => (
<TextField
{...params}
label="Métadonnées"
placeholder="Ecriver les métadonnées"
helperText={errors.tags?.message}
error={!!errors.tags}
/>
)}
/>
)}
/>
</Box>

React Leaflet: setting a GeoJSON's style dynamically

I'm trying to change a GeoJSON component's style dynamically based on whether its ID matches a selector.
The author of the plugin refers to the Leaflet documentation, which says that the style should be passed as a function. Which I'm doing, but no dice.
My component:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../../actions';
import { Marker, Popup, GeoJSON } from 'react-leaflet';
import { centroid } from '#turf/turf';
const position = geoJSON => {
return centroid(geoJSON).geometry.coordinates.reverse();
};
export class PlotMarker extends Component {
render() {
const {
id,
name,
geoJSON,
zoomLevel,
selectedPlot,
plotBeingEdited
} = this.props;
const markerPosition = position(geoJSON);
let style = () => {
color: 'blue';
};
if (selectedPlot === id) {
style = () => {
color: 'red';
};
}
if (zoomLevel > 14) {
return (
<GeoJSON
id={id}
data={geoJSON}
style={style}
onClick={() => {
this.props.selectPlot(id);
}}
/>
);
}
return (
<Marker
id={id}
className="marker"
position={markerPosition}
onClick={() => {
this.props.selectPlot(id);
}}>
<Popup>
<span>{name}</span>
</Popup>
</Marker>
);
}
}
function mapStateToProps(state) {
return {
selectedPlot: state.plots.selectedPlot,
plotBeingEdited: state.plots.plotBeingEdited,
zoomLevel: state.plots.zoomLevel
};
}
export default connect(mapStateToProps, actions)(PlotMarker);
OK, got it. It had to do with the way I was defining the style function. This doesn't work:
let style = () => {
color: 'blue';
};
if (selectedPlot === id) {
style = () => {
color: 'red';
};
}
if (zoomLevel > 14) {
return (
<GeoJSON
id={id}
data={geoJSON}
style={style}
onClick={() => {
this.props.selectPlot(id);
}}
/>
);
}
This works:
let style = () => {
return {
color: 'blue'
};
};
if (selectedPlot === id) {
style = () => {
return {
color: 'red'
};
};
}
if (zoomLevel > 14) {
return (
<GeoJSON
id={id}
data={geoJSON}
style={style}
onClick={() => {
this.props.selectPlot(id);
}}
/>
);
}

react-google-maps multiple markers breaks on open

My app loads all my markers just fine, but crashes when I try and click a marker. I get the following error:
"React.Children.only expected to receive a single React element child."
In the main map component I build the map and bring in all the markers from Firebase. I wanted to componentize the markers and build them in a separate file just to keep things a bit straighter in my head.
Here is my Map component
const MyMapComponent = compose(
withProps({
googleMapURL: "https://maps.googleapis.com/maps/api/js?key=xxxxx&v=3.exp&libraries=geometry,drawing,places",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `500px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
withScriptjs,
withGoogleMap
)((props) =>
<GoogleMap
defaultZoom={15}
defaultCenter={{ lat: 34.6781445, lng: -82.8455519 }}
>
{props.markers.map(marker => (
<LotMarker key={marker.key} index={marker.key} lat={marker.latitude} lng={marker.longitude} />
))}
</GoogleMap>
);
class TheMap extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
test:'test',
lots: [],
isOpen: false
};
}
componentWillMount() {
base.bindToState('lots', {
context: this,
state: 'lots',
asArray: true,
});
}
handleMarkerClick = (key) => {
console.log(key);
}
render() {
return (
<MyMapComponent
isMarkerShown={this.state.isMarkerShown}
onMarkerClick={this.handleMarkerClick}
markers={this.state.lots}
/>
)
}
}
export default TheMap;
Here I put the marker together. I've housed the InfoWindow component inside the marker and then ask it to show when the marker is clicked. However, when I do click a marker it just crashes the whole app and white screens.
This is my LotMarker component:
class LotMarker extends React.Component {
// Constructor.
constructor(props) {
// Super Props.
super(props);
// State.
this.state = {
isOpen: false
}
}
onToggleOpen = () => {
console.log(this);
this.setState({isOpen: !this.state.isOpen});
}
// Render.
render() {
// console.log(this);
// Extract Props.
const {
props: {
index,
lat,
lng,
open
}
} = this
return (
<Marker key={index} position={{ lat: lat, lng: lng }} onClick={this.onToggleOpen}>
{this.state.isOpen && <InfoWindow onCloseClick={this.onToggleOpen}>{index}</InfoWindow>}
</Marker>
)
}
}
export default LotMarker;
Alright, it turns out there was a really simple fix here. The content inside the InfoWindow has to be wrapped in a JSX compliant element.
Rather than this:
<InfoWindow onCloseClick={this.onToggleOpen}>{index}</InfoWindow>
I had to have this:
<InfoWindow onCloseClick={this.onToggleOpen}><span>{index}</span></InfoWindow>

custom button in inline toolbar that calls custom function

I want to combine the inline toolbar with the example from draft.js to insert a link into the editor.
Thanks to the draft.js plugin FAQ I am able to add a decorator to the draft-js-plugin editor which inserts a link on a button click.
Now I want to put this button inside the inline-toolbar from draft-js-plugins. That doesn't seem to work. This is what I've done so far:
Editor.jsx
...
const inlineToolbarPlugin = createInlineToolbarPlugin({
theme: {buttonStyles, toolbarStyles},
structure: [..., LinkButton]
});
const {InlineToolbar} = inlineToolbarPlugin;
const plugins = [inlineToolbarPlugin];
class RMSEditor extends Component {
...
render() {
return (
<div>
<div className={editorStyles.editor}>
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
plugins={plugins}
decorators={this.decorator}
ref={(element) => {
this.editor = element;
}}
readOnly={this.state.readOnly}
/>
<InlineToolbar />
</div>
</div>
);
}
LinkButton.jsx
import classNames from "classnames/bind";
import React from "react";
import {Glyphicon} from "react-bootstrap";
import styles from "./buttonStyles.less";
const cx = classNames.bind(styles);
const LinkButton = () => {
return (
<div className={cx('buttonWrapper')} onClick={(e) => {
console.log("Div", e);
}}>
<button className={cx('button')} onClick={(e) => {
console.log("Button", e);
}}><Glyphicon glyph="link"/></button>
</div>
)
};
export default LinkButton;
This way, I have managed to get a Button that shows up in the inline toolbar. But when I clicked on that button, nothing happens. I expacted that one of the onClick handlers will fire but that is not the case.
Full source code
Here you can find my full sourcecode as I don't want to put only the relevant parts directly under the questions. Please notice that the code will not work in the run snipped thingy as I have no clue how to get it to work there without setting up the hole wabpack thing.
MentionsEditor.jsx
import {CompositeDecorator, EditorState, RichUtils} from "draft-js";
import {BoldButton, CodeButton, ItalicButton, UnderlineButton, UnorderedListButton} from "draft-js-buttons";
import createInlineToolbarPlugin from "draft-js-inline-toolbar-plugin";
import {defaultSuggestionsFilter} from "draft-js-mention-plugin"; // eslint-disable-line import/no-unresolved
import Editor from "draft-js-plugins-editor"; // eslint-disable-line import/no-unresolved
import React, {Component, PropTypes} from "react";
import {Button} from "react-bootstrap";
import buttonStyles from "./buttonStyles";
import editorStyles from "./editorStyles";
import LinkButton from "./InsertLinkButton";
import toolbarStyles from "./toolbarStyles";
const inlineToolbarPlugin = createInlineToolbarPlugin({
theme: {buttonStyles, toolbarStyles},
structure: [BoldButton, ItalicButton, UnderlineButton, CodeButton, UnorderedListButton, LinkButton]
});
const {InlineToolbar} = inlineToolbarPlugin;
const plugins = [inlineToolbarPlugin];
class RMSEditor extends Component {
constructor(props) {
super(props);
}
decorator = [
{
strategy: function findLinkEntities(contentBlock, callback, contentState) {
contentBlock.findEntityRanges(
(character) => {
const entityKey = character.getEntity();
return (
entityKey !== null &&
contentState.getEntity(entityKey).getType() === 'LINK'
);
},
callback
);
},
component: function (props) {
const {url} = props.contentState.getEntity(props.entityKey).getData();
return (
<a href={url}>
{props.children}
</a>
);
}
}
];
state = {
editorState: EditorState.createEmpty(),
};
onChange = (editorState) => {
this.setState({
editorState,
});
};
editorLink = function (props) {
const {url} = props.contentState.getEntity(props.entityKey).getData();
return (
<a href={url} style={{color: "blue"}}>
{props.children}
</a>
);
};
focus = () => {
this.editor.focus();
};
insertLink = (e) => {
e.preventDefault();
const {editorState} = this.state;
const contentState = editorState.getCurrentContent();
const contentStateWithEntity = contentState.createEntity(
'LINK',
'MUTABLE',
{url: "https://example.com"}
);
const entityKey = contentStateWithEntity.getLastCreatedEntityKey();
const newEditorState = EditorState.set(editorState, {currentContent: contentStateWithEntity});
this.setState({
editorState: RichUtils.toggleLink(
newEditorState,
newEditorState.getSelection(),
entityKey
)
}, () => {
setTimeout(() => {
this.focus()
}, 0);
});
};
render() {
return (
<div>
<Button onClick={this.insertLink}>insert URL</Button>
<div className={editorStyles.editor}>
<Editor
editorState={this.state.editorState}
onChange={this.onChange}
plugins={plugins}
decorators={this.decorator}
ref={(element) => {
this.editor = element;
}}
readOnly={this.state.readOnly}
/>
<InlineToolbar />
</div>
</div>
);
}
}
RMSEditor.propTypes = {
stakeholder: PropTypes.object.isRequired
};
export default RMSEditor;
LinkButton.jsx
import classNames from "classnames/bind";
import React from "react";
import {Glyphicon} from "react-bootstrap";
import styles from "./buttonStyles.less";
const cx = classNames.bind(styles);
const LinkButton = () => {
return (
<div className={cx('buttonWrapper')} onClick={(e) => {
console.log("Div", e);
}}>
<button className={cx('button')} onClick={(e) => {
console.log("Button", e);
}}><Glyphicon glyph="link"/></button>
</div>
)
};
export default LinkButton;
This works for me:
const MyButton = (props) => {
return (
<div className={props.className} onMouseDown={(e)=>e.preventDefault()}>
<button onClick={() => props.createComment('Hello')}>
Comment
</button>
</div>
)
}
const inlineToolbarPlugin = createInlineToolbarPlugin({
structure: [props => <MyButton {...props} createComment={(text) => alert(text)} />]
});
const { InlineToolbar } = inlineToolbarPlugin;
export default class MyComponent extends Component {
constructor(props) {
super(props);
}
render() {
const { editorState } = this.state;
return (
<div className="editor">
<Editor
editorState={editorState}
onChange={this.onChange}
plugins={[inlineToolbarPlugin]}
ref={(element) => { this.editor = element; }}
/>
<InlineToolbar />
</div>
)
}
}
Basically, this is what you need to do:
1) import the inline toolbar plugin (bonus there is a separator in there)
import createInlineToolbarPlugin, {Separator} from 'draft-js-inline-toolbar-plugin'
2) instantciate the plugin like this:
const inlineToolbarPlugin = createInlineToolbarPlugin({
structure: [
BoldButton,
ItalicButton,
UnderlineButton,
CodeButton,
Separator,
],
})
2.1) you can get those components and more from draft-js-buttons
3) add to the array more components (let's add a video button component)
AddVideoButton
this is what it looks like
import React, { Component, PropTypes } from 'react'
import classnames from 'classnames'
import { AtomicBlockUtils, RichUtils } from 'draft-js'
import createVideoPlugin from 'draft-js-video-plugin'
const {types} = createVideoPlugin()
export default class AddVideoButton extends Component {
static propTypes = {
getEditorState: PropTypes.func,
setEditorState: PropTypes.func,
style: PropTypes.shape(),
theme: PropTypes.shape(),
}
// toggleStyle(event){
// const { setEditorState, getEditorState, style } = this.props
//
// event.preventDefault()
// setEditorState(
// RichUtils.toggleInlineStyle(
// getEditorState(),
// style
// )
// )
// }
toggleVideo(event){
const { setEditorState, getEditorState } = this.props
event.preventDefault()
const style = { width: 100}
const editorState = getEditorState()
const currentContent = editorState.getCurrentContent()
const selectionState = editorState.getSelection()
const anchorKey = selectionState.getAnchorKey()
const currentContentBlock = currentContent.getBlockForKey(anchorKey)
const start = selectionState.getStartOffset()
const end = selectionState.getEndOffset()
const src = currentContentBlock.getText().slice(start, end)
if (RichUtils.getCurrentBlockType(editorState) === types.ATOMIC) {
return editorState
}
const contentState = editorState.getCurrentContent()
const contentStateWithEntity = contentState.createEntity(
types.VIDEOTYPE,
'IMMUTABLE',
{ src, style }
)
const entityKey = contentStateWithEntity.getLastCreatedEntityKey()
const newEditorState = AtomicBlockUtils.insertAtomicBlock(editorState, entityKey, ' ')
return setEditorState(newEditorState)
}
render(){
const { theme, style, getEditorState } = this.props
const styleIsActive = () => getEditorState().getCurrentInlineStyle().has(style)
return (
<div
className={theme.buttonWrapper}
onMouseDown={(e)=>e.preventDefault()}
>
<button
className={classnames({
[theme.active]:styleIsActive(),
[theme.button]:true,
})}
onClick={::this.toggleVideo}
>
<svg height="24" viewBox="0 0 120 100" width="24" xmlns="http://www.w3.org/2000/svg">
<path d="M111.374,20.922c-3.151-3.159-7.557-5.128-12.374-5.125H29c-4.817-0.002-9.222,1.966-12.375,5.125 c-3.159,3.152-5.128,7.557-5.125,12.375v40.038c-0.002,4.818,1.966,9.223,5.125,12.375c3.152,3.158,7.557,5.129,12.375,5.125h70 c4.817,0.004,9.224-1.967,12.375-5.125c3.159-3.152,5.128-7.557,5.125-12.375V33.296C116.503,28.479,114.534,24.074,111.374,20.922z M104.624,78.959c-1.454,1.447-3.413,2.328-5.624,2.33H29c-2.211-0.002-4.17-0.883-5.625-2.33c-1.447-1.455-2.328-3.414-2.33-5.625 V33.296c0.002-2.211,0.883-4.17,2.33-5.625c1.455-1.447,3.413-2.328,5.625-2.33h70c2.211,0.002,4.17,0.883,5.625,2.33 c1.447,1.455,2.327,3.413,2.329,5.625v40.038C106.952,75.545,106.072,77.504,104.624,78.959z" fill="#232323"/><path d="M77.519,50.744L57.45,39.161c-0.46-0.266-0.971-0.397-1.483-0.397c-0.513,0-1.023,0.131-1.484,0.397 c-0.918,0.528-1.483,1.509-1.483,2.569v23.171c0,1.061,0.565,2.04,1.483,2.57c0.46,0.267,0.971,0.396,1.484,0.396 c0.513,0,1.023-0.13,1.483-0.396l20.069-11.586c0.918-0.531,1.482-1.51,1.482-2.571C79.001,52.253,78.437,51.274,77.519,50.744z" fill="#232323"/>
<path d="M0 0h24v24H0z" fill="none" />
</svg>
</button>
</div>
)
}
}
or
you can imitate anything out of the draft-js-buttons
Let me know if I helped or if you have any other questions