I am experiencing some issues with radio group buttons. Can someone help me with this issue. (your help is much appreciated)
Current Issue: Radio Group are not clickable. Im not sure where I missed up!
Technologies Used: React hooks, styled-components , and design
for the radio buttons.
RadioGroup.js
import React from "react";
import { Radio } from "antd";
import styled from "styled-components";
import { theme } from "constants/theme";
const { royalBlue, black } = theme.colors;
const { medium } = theme.typography.size;
const { display } = theme.typography.font.family;
const StyledRadioGroup = styled(Radio.Group)`
width: 100%;
margin-top: 0.5rem;
text-align: left;
.ant-radio-wrapper {
justify-content: space-between;
padding: ${(props) => props.padding};
white-space: break-spaces;
margin-left: -1.5rem;
span.ant-radio + * {
font-family: ${display};
font-size: ${medium};
color: ${black};
letter-spacing: 0;
}
.ant-radio-inner {
border-color: ${royalBlue};
border-width: 0.2rem;
width: 2.5rem;
height: 2.5rem;
&::after {
background-color: ${royalBlue};
top: 0.2rem;
left: 0.2rem;
}
}
}
`;
const RadioGroup = ({
options,
onChange,
value,
defaultValue,
flex,
padding,
}) => {
return (
<StyledRadioGroup
size="large"
flex={flex}
padding={padding}
onChange={onChange}
value={value}
defaultValue={defaultValue}
>
{options.map((option, index) => (
<Radio value={option.stateKey} key={index}>
{option.value}
</Radio>
))}
</StyledRadioGroup>
);
};
export default RadioGroup;
Navigation.js
import React, { useState, useReducer } from "react";
import styled from "styled-components";
import RadioModal from "components/Feedback/RadioModal";
import RadioGroup from "components/Feedback/RadioGroup";
const renderRadioModal = () => {
const inputLabelsText = [
{
stateKey: "age",
label: "What is your age?",
},
];
const radioButtonOptions = [
{
stateKey: "covidImpact",
value: "I go to work/school normally",
},
{
stateKey: "covidImpact",
value: "I am healthy but in a stay-at-home quarantine",
},
{
stateKey: "covidImpact",
value: "I have mild symptoms but haven't been tested",
},
{
stateKey: "covidImpact",
value: "I am diagnosed with Covid-19",
},
];
const RadioGroupWithLabel = withLabel(() => (
<RadioGroup
onChange={true}
options={radioButtonOptions}
value={true}
padding="1rem 1rem"
size="large"
></RadioGroup>
));
return (
<RadioModal
maskClosable={true}
closable={true}
visible={radioModal}
onClose={() => closeRadioModal()}
transparent
>
<h2 className="title">We are almost done!</h2>
{inputLabelsText.map((label, index) => (
<>
<StyledInput
key={index}
label={label.label}
value={label.stateKey}
onChange={dispatchAction}
></StyledInput>
<RadioGroupWithLabel label={"How has COVID-19 impacted you?"} />
</>
))}
<FeedbackSubmitButton
title="Submit Feedback"
onClick={closeRadioModal}
></FeedbackSubmitButton>
</RadioModal>
);
};
You have onChange={true} and value={true}. You need to handle the onChange and value properly. The value prop needs to match the value in your options that you pass into the radio group.
The options you pass in should be in the structure [{ value, label }, { value, label }]
Then in your onChange you need to handle setting that value + have a place to store it
Related
In this project, React, TypeScript and ant design are used. In a part of the project, only one box out of three boxes should be selected. I have used "useState" and toggle, but when I select one, they are all selected together when only one should be selected. I am using React version 18.2.0
I would be grateful if you could guide me.
allBox{
display: flex;
align-items: center;
justify-content: space-between;
width: 700px
}
.box{
width: 34px;
height: 34px;
border: 3px solid yellow;
background: green;
color:blue;
}
.box.active{
border: 3px solid black;
background: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import React, { useState } from "react";
function MyBox() {
const boxes = [
{
id: 1,
type: "1",
},
{
id: 2,
type: "2",
},
{
id: 3,
type: "3",
},
];
const [boxSelect, setBoxSelect] = useState(false);
const handleSelect = () => {
setBoxSelect(!boxSelect);
};
return (
<div>
<div className='allBox'>
{boxes.map((box) => {
return (
<div className={`${box} ${boxSelect && 'active'}`} key={box.id} onClick={handleSelect}>
<p>{box.type}</p>
</div>
);
})}
</div>
</div>
);
}
export default MyBox;
It's because all your boxes share the same const [boxSelect, setBoxSelect] = useState(false); so if you click on one of them, they will all be selected.
You have two solutions:
create a children component with only:
function mySubBox(box) {
const [boxSelect, setBoxSelect] = useState(false);
const handleSelect = () => {
setBoxSelect(!boxSelect);
};
return (
<div className={`${box} ${boxSelect && 'active'}`} key={box.id} onClick={handleSelect}>
<p>{box.type}</p>
</div>
);
}
And the parent loops through it:
{boxes.map((box, i) => <mySubBox box={box} key={i}/>)}
another solution would be to keep only one component and store the selected boxes in an array: if I click on the 2nd box, my selected array is [2], and you add/remove the item inside the array.
EDIT*** THE CODE IN THE SNIPPET IS NOT MEANT TO BE RUN BUT ONLY DISPLAY MY CODE, SORRY FOR THE CONFUSION
I am working a slider for an e-commerce app. Making each slider map over my useState array to create the different cards and the useState is receiving data from my fetched JSON server.
Now I am stuck at a brick wall in figuring how to use the same state to handle rendering the image onto my slider & click on the arrow to show the new slide.
I realize that I should update the state but I feel that I am over (or under) thinking things on how to do so.
My code snippets will show one, my code & two my JSON server data.
I receive an "uncaught error: too many re-renders." React limits number of renders to prevent an infinite loop
Can somebody please walk me through what I need to do here to complete this task? Thanks!
import {useState, useEffect} from 'react';
import { ArrowLeftOutlined, ArrowRightOutlined } from "#material-ui/icons";
import styled from "styled-components";
import { set } from 'react-hook-form';
const Container = styled.div`
width: 100%;
height: 95vh;
display: flex;
// background-color: #b3f0ff;
position: relative;
overflow: hidden;
`;
const Arrow = styled.div`
width: 50px;
height: 50px;
background-color: #e6ffff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
bottom: 0;
left: ${(props) => props.direction === "left" && "10px"};
right: ${(props) => props.direction === "right" && "10px"};
margin: auto;
cursor: pointer;
opacity: 0.5;
z-index: 2;
`;
const Wrapper = styled.div`
height: 100%;
display: flex;
transform: translateX(${props => props.slideIndx.data2 * -100}vw);
`
const Slide = styled.div`
width: 100vw;
height: 100vw;
display: flex;
align-items: center;
background-color: ${props => props.bg};
`
const ImgContainer = styled.div`
height: 100%;
flex:1;
`
const Image = styled.img`
padding-left: 30px;
align-items: left;
`
const InfoContainer = styled.div`
height: 80%;
flex:1;
padding: 30px;
`
const Title = styled.h1`
font-size: 50px
`
const Desc = styled.p`
margin: 50px 0px;
font-size: 20px;
font-weight: 500;
letter-spacing: 3px;
`
const Button = styled.button`
padding: 10px;
font-size: 20px;
background-color: transparent;
cursor: pointer;
`
const Slider = () => {
const [slideIndx, setSlideIndx] = useState({data1:[], data2: 0});
const handleClick = (direction) => {
if(direction === "left"){
setSlideIndx(slideIndx.data2 > 0 ? slideIndx.data2 - 1 : 2);
} else{
setArrowIndx(slideIndx.data2 < 2 ? slideIndx.data2 + 1 : 0);
}
};
const newArray = []
setSlideIndx((slideIndx) => ({
...slideIndx,
data2: [...newArray]
}));
const fetchSliderItems = (id) => {
fetch('http://localhost:3000/sliderItems')
.then(resp => resp.json())
.then(data => {
console.log(data)
setSlideIndx(data)
})
}
useEffect(() => {fetchSliderItems()}, [])
return (
<Container>
<Arrow direction="left" onClick={() => handleClick("left")}>
<ArrowLeftOutlined />
</Arrow>
<Wrapper slideIndx={slideIndx.data2}>
{slideIndx.data1.map((item) => (
<Slide bg={item.bg}>
<ImgContainer>
<Image src={item.img}/>
</ImgContainer>
<InfoContainer>
<Title>{item.title}</Title>
<Desc>{item.desc}</Desc>
<Button>SHOP NOW</Button>
</InfoContainer>
</Slide>
))}
</Wrapper>
<Arrow direction="right" onClick={() => handleClick("right")}>
<ArrowRightOutlined />
</Arrow>
</Container>
)
}
export default Slider
{
"sliderItems": [
{
"id": 1,
"img": "../images/model1.png",
"title": "SPRING CLEANING",
"desc": "DONT MISS OUR BEST COLLECTION YET! USE #FLATIRON10 TO RECEIVE 10% OFF YOUR FIRST ORDER",
"bg": "#b3ecff"
},
{
"id": 2,
"img": "../images/model2.png",
"title": "SHOW OFF HOW YOU DRESS",
"desc": "WITH OUR HUGE SELECTION OF CLOTHES WE FIT ALL YOUR STYLING NEEDS",
"bg": "#ccf2ff"
},
{
"id": 3,
"img": "../images/model3.png",
"title": "POPULAR DEALS",
"desc": "RECEIVE FREE SHIPPING ON ALL ORDERS OVER $50!",
"bg": "#fe6f9ff"
}
]
}
It is totally possible to do this with one useState, two useStates and my personal preference, useReducer.
I'll just give an example. I haven't tried running this code, as I don't have the components. So treat it like pseudo code:
const initialState = {
selectedIndex: 0,
"sliderItems": [
{
"id": 1,
"img": "../images/model1.png",
"title": "SPRING CLEANING",
"desc": "DONT MISS OUR BEST COLLECTION YET! USE #FLATIRON10 TO RECEIVE 10% OFF YOUR FIRST ORDER",
"bg": "#b3ecff"
},
{
"id": 2,
"img": "../images/model2.png",
"title": "SHOW OFF HOW YOU DRESS",
"desc": "WITH OUR HUGE SELECTION OF CLOTHES WE FIT ALL YOUR STYLING NEEDS",
"bg": "#ccf2ff"
},
{
"id": 3,
"img": "../images/model3.png",
"title": "POPULAR DEALS",
"desc": "RECEIVE FREE SHIPPING ON ALL ORDERS OVER $50!",
"bg": "#fe6f9ff"
},
],
}
function reducer(state, action) {
switch (action.type) {
case 'setData':
return {
selectedIndex: 0,
sliderItems: action.sliderItems,
};
case 'slideRight':
return {
...state,
// this assumes you want to go back to index 0 if you slide right on last item
selectedIndex: state.sliderItems.length - state.selectedIndex > 1 ? state.selectedIndex + 1 : 0,
};
case 'slideLeft':
return {
...state,
// this assumes you want to go to last item if sliding left on first item
selectedIndex: state.selectedIndex === 0 ? state.sliderItems.length - 1 : state.selectedIndex - 1,
};
default:
return state;
}
}
const Example = () => {
const [{ sliderItems, selectedIndex }, dispatch] = useReducer(initialState, reducer);
return (
<Container>
<Arrow direction="left" onClick={() => dispatch({ type: 'slideLeft' })}>
<ArrowLeftOutlined />
</Arrow>
<Wrapper slideIndx={selectedIndex}>
{sliderItems.map((item) => (
<Slide bg={item.bg}>
<ImgContainer>
<Image src={item.img}/>
</ImgContainer>
<InfoContainer>
<Title>{item.title}</Title>
<Desc>{item.desc}</Desc>
<Button>SHOP NOW</Button>
</InfoContainer>
</Slide>
))}
</Wrapper>
<Arrow direction="right" onClick={() => dispatch({ type: 'slideRight' })}>
<ArrowRightOutlined />
</Arrow>
</Container>
)
}
If you choose to try this approach, just dispatch a setData action in your fetch handler. That will reset the state with new items and start at index 0. The behavior can of course be modified to your liking.
dispatch({
type: 'setData',
sliderItems: fetchResult.sliderItems,
})
I've changed my style in StyledButton tag but it doesn't reflect on webpage. Can you help what is wrong in this code
import React, { Component } from 'react';
import './App.css';
//import Radium, {StyleRoot} from 'radium';
import Person from './Person/Person';
import { render } from 'react-dom';
import styled from 'styled-components'
const StyledButton = styled.button `
background-color: ${props => props.alt ? 'red' : 'green'}; //Here I have define these property which is not reflecting in output
color: white;
font: inherit;
border: 1px solid blue;
padding: 8px;
cursor:pointer;
&:hover:{
background-color:${props => props.alt ? 'salmon' : 'green'}; //Hover Function is also not working
color:black;
}`;
class App extends Component {
state ={
persons : [
{id:'12', name: 'Max', age: 28},
{id:'21', name: 'Manu', age:29},
{id:'33', name: 'Nikhil', age:23}
]};
nameChangeHandler = (event, id) => {
const personIndex = this.state.persons.findIndex(p=>{
return p.id===id;
});
const person = {
... this.state.persons[personIndex]
};
person.name = event.target.value;
const persons =[...this.state.persons];
persons[personIndex]=person;
this.setState({ persons: persons
});
}
deletePersonHandler = (personIndex) =>{
//const persons = this.state.persons.slice();
//const persons = this.state.persons
const persons = [... this.state.persons];
persons.splice(personIndex,1);
this.setState({persons: persons})
}
togglePersonsHandler = ()=> {
const doesShow = this.state.showPersons;
this.setState({showPersons: !doesShow});
}
render()
{
let persons = null;
if(this.state.showPersons)
{
persons = (
<div>
{ this.state.persons.map((person, index) =>{
return <Person
click = { () => this.deletePersonHandler(index) }
name={person.name}
age={person.age}
key= {person.id}
changed={(event)=> this.nameChangeHandler(event, person.id)}/>
})}
</div>
);
//StyledButton.backgroundColor= 'red';
}
let classes = []
if(this.state.persons.length<=2)
{
classes.push('red');
}
if(this.state.persons.length<=1)
{
classes.push('bold');
}
return (
<div className = "App">
<h1>Hi there this is my first react application</h1>
<p className= {classes.join(' ')}>Hi this is really working</p>
<StyledButton
alt ={ this.state.showPersons }
onClick = {this.togglePersonsHandler}>Toggle Persons</StyledButton>
{ persons }
</div>
);
}
}
export default App;
Code just toggle the names and ages when user click on button and delete the names when click on the paragraph and adding certain classes these are all works fine.
I'm using styled component package on toggle button and it is not working properly, I don't why Please let me know if you understand
You've defined alt to be a transient prop, i.e. $alt, but you don't pass that prop to the StyledButton.
You've also a typo in your hover selector, there's a trailing colon (:): &:hover: should be :hover (the leading parent node selector & is also unnecessary).
const StyledButton = styled.button `
background-color: ${props => props.$alt ? 'red' : 'green'};
color: white;
font: inherit;
border: 1px solid blue;
padding: 8px;
cursor: pointer;
:hover {
background-color:${props => props.$alt ? 'salmon' : 'green'};
color:black;
}
`;
...
<StyledButton
$alt={this.state.showPersons} // <-- pass transient prop
onClick={this.togglePersonsHandler}
>
Toggle Persons
</StyledButton>
This was introduced in v5.1. If you didn't intend to declare a transient prop or you aren't on v5.1 or newer, then simply remove the $ and use the alt prop.
const StyledButton = styled.button `
background-color: ${props => props.alt ? 'red' : 'green'};
color: white;
font: inherit;
border: 1px solid blue;
padding: 8px;
cursor: pointer;
:hover {
background-color:${props => props.alt ? 'salmon' : 'green'};
color:black;
}
}`;
...
<StyledButton
alt={this.state.showPersons} // <-- use alt prop
onClick={this.togglePersonsHandler}
>
Toggle Persons
</StyledButton>
Demo
In older code of react it just display the text active or in active for an user. Now I want to replace it to red or green small dot how can I do it.
CSS
div .colored-circle {
display: inline-block;
margin-left: 5px;
margin-right: 5px;
margin-bottom: -2px;
border-radius: 50%;
border-style: solid;
border-width: 0.5px;
border-color: black;
height: 20px;
width: 20px;
}
Component:
const ColoredCircle = ({ color }) => {
const styles = { backgroundColor: color };
return color ? (
<Fragment>
<span className="colored-circle" style={styles} />
</Fragment>
) : null;
};
export default ColoredCircle;
Use the same logic you used to show 'active' or 'inactive' and instead of text add a div with css or img of the desired color.
If you happen to use material UI, you can do like this:
import React, { Fragment } from "react";
import { makeStyles } from "#material-ui/core";
const RADIUS_DOT = 1.5;
const useStyles = makeStyles((theme) => ({
circle: {
borderRadius: RADIUS_DOT,
height: RADIUS_DOT * 2,
width: RADIUS_DOT * 2,
padding: 0,
},
}));
const ColoredCircle = ({ color }) => {
const styles = { backgroundColor: color };
const classes = useStyles();
return color ? (
<Fragment>
<span className={classes.circle} style={styles} />
</Fragment>
) : null;
};
export default ColoredCircle;
you can use this package, can be helpful
npm i react-color-circle
import Circle from '#uiw/react-color-circle';
return (
<Circle
colors={[ '#F44E3B' ]}
/>);
I am building a reactjs application.
I've created a variant of the RichEditor - which uses draft.js -- I am unsure though how to set content for this editor and also how to retrieve it if it were to be made part of a form.
here is my current code base
So if I were to treat it as a field.
const initialValues = {editor: "I am a <h2>bit</h2> of dummy <b>html</b> text"}
<RichEditor initialValues={initialValues} />
^ so something like this - but also how would I obtain the contents if it were part of like a react-redux form?
like this?
import React from 'react'
import { Field, reduxForm } from 'redux-form'
import renderField from '../_SharedFormComponents/renderField'
import validate from './validateComplaint'
import warn from './warnComplaint'
const ComplaintSyncValidationForm= props => {
const { handleSubmit, pristine, reset, submitting } = props
const initialValues = {editor: "I am a <h2>bit</h2> of dummy <b>html</b> text"}
return (
<form onSubmit={handleSubmit}>
<Field name="email" type="email" component={renderField} label="Email" />
<RichEditor initialValues={initialValues} />
<div>
<button type="submit" disabled={submitting}>
Complain
</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>
</div>
</form>
)
}
export default reduxForm({
form: 'syncValidationComplaint', // a unique identifier for this form
validate, // <--- validation function given to redux-form
warn // <--- warning function given to redux-form
})(ComplaintSyncValidationForm)
//RichEditor.js
import React from 'react';
import ReactDOM from 'react-dom';
import {Editor, EditorState, RichUtils} from 'draft-js';
import './RichEditor.scss';
class RichEditor extends React.Component {
constructor(props) {
super(props);
this.state = {editorState: EditorState.createEmpty()};
this.focus = () => this.refs.editor.focus();
this.onChange = (editorState) => this.setState({editorState});
this.handleKeyCommand = this._handleKeyCommand.bind(this);
this.onTab = this._onTab.bind(this);
this.toggleBlockType = this._toggleBlockType.bind(this);
this.toggleInlineStyle = this._toggleInlineStyle.bind(this);
}
_handleKeyCommand(command, editorState) {
const newState = RichUtils.handleKeyCommand(editorState, command);
if (newState) {
this.onChange(newState);
return true;
}
return false;
}
_onTab(e) {
const maxDepth = 4;
this.onChange(RichUtils.onTab(e, this.state.editorState, maxDepth));
}
_toggleBlockType(blockType) {
this.onChange(
RichUtils.toggleBlockType(
this.state.editorState,
blockType
)
);
}
_toggleInlineStyle(inlineStyle) {
this.onChange(
RichUtils.toggleInlineStyle(
this.state.editorState,
inlineStyle
)
);
}
render() {
const {editorState} = this.state;
// If the user changes block type before entering any text, we can
// either style the placeholder or hide it. Let's just hide it now.
let className = 'RichEditor-editor';
var contentState = editorState.getCurrentContent();
if (!contentState.hasText()) {
if (contentState.getBlockMap().first().getType() !== 'unstyled') {
className += ' RichEditor-hidePlaceholder';
}
}
return (
<div className="RichEditor-root">
<BlockStyleControls
editorState={editorState}
onToggle={this.toggleBlockType}
/>
<InlineStyleControls
editorState={editorState}
onToggle={this.toggleInlineStyle}
/>
<div className={className} onClick={this.focus}>
<Editor
blockStyleFn={getBlockStyle}
customStyleMap={styleMap}
editorState={editorState}
handleKeyCommand={this.handleKeyCommand}
onChange={this.onChange}
onTab={this.onTab}
placeholder="Tell a story..."
ref="editor"
spellCheck={true}
/>
</div>
</div>
);
}
}
// Custom overrides for "code" style.
const styleMap = {
CODE: {
backgroundColor: 'rgba(0, 0, 0, 0.05)',
fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace',
fontSize: 16,
padding: 2,
},
};
function getBlockStyle(block) {
switch (block.getType()) {
case 'blockquote': return 'RichEditor-blockquote';
default: return null;
}
}
class StyleButton extends React.Component {
constructor() {
super();
this.onToggle = (e) => {
e.preventDefault();
this.props.onToggle(this.props.style);
};
}
render() {
let className = 'RichEditor-styleButton';
if (this.props.active) {
className += ' RichEditor-activeButton';
}
return (
<span className={className} onMouseDown={this.onToggle}>
{this.props.label}
</span>
);
}
}
const BLOCK_TYPES = [
{label: 'H1', style: 'header-one'},
{label: 'H2', style: 'header-two'},
{label: 'H3', style: 'header-three'},/*
{label: 'H4', style: 'header-four'},
{label: 'H5', style: 'header-five'},
{label: 'H6', style: 'header-six'},
{label: 'Blockquote', style: 'blockquote'},
{label: 'UL', style: 'unordered-list-item'},
{label: 'OL', style: 'ordered-list-item'},
{label: 'Code Block', style: 'code-block'},*/
];
const BlockStyleControls = (props) => {
const {editorState} = props;
const selection = editorState.getSelection();
const blockType = editorState
.getCurrentContent()
.getBlockForKey(selection.getStartKey())
.getType();
return (
<div className="RichEditor-controls">
{BLOCK_TYPES.map((type) =>
<StyleButton
key={type.label}
active={type.style === blockType}
label={type.label}
onToggle={props.onToggle}
style={type.style}
/>
)}
</div>
);
};
var INLINE_STYLES = [
{label: 'Bold', style: 'BOLD'},
{label: 'Italic', style: 'ITALIC'},
{label: 'Underline', style: 'UNDERLINE'},
//{label: 'Monospace', style: 'CODE'},
];
const InlineStyleControls = (props) => {
var currentStyle = props.editorState.getCurrentInlineStyle();
return (
<div className="RichEditor-controls">
{INLINE_STYLES.map(type =>
<StyleButton
key={type.label}
active={currentStyle.has(type.style)}
label={type.label}
onToggle={props.onToggle}
style={type.style}
/>
)}
</div>
);
};
export default RichEditor
and the scss for it.
//RichEditor.scss
#import '../../colors.scss';
.RichEditor-root {
background: $white;
border: 1px solid $stone-grey;
font-family: 'Georgia', serif;
font-size: 14px;
padding: 15px;
}
.RichEditor-hidePlaceholder .public-DraftEditorPlaceholder-root {
display: none;
}
.RichEditor-controls {
font-family: 'Helvetica', sans-serif;
font-size: 14px;
margin-bottom: 5px;
user-select: none;
}
.RichEditor-styleButton {
color: $grey;
cursor: pointer;
margin-right: 16px;
padding: 2px 0;
display: inline-block;
}
.RichEditor-activeButton {
color: $light-blue;
}
.RichEditor-editor {
border-top: 1px solid $grey;
color: black;
cursor: text;
font-size: 16px;
margin-top: 10px;
.RichEditor-blockquote {
border-left: 5px solid $stone-grey;
color: #666;
font-family: 'Hoefler Text', 'Georgia', serif;
font-style: italic;
margin: 16px 0;
padding: 10px 20px;
}
.public-DraftStyleDefault-pre {
background-color: rgba(0, 0, 0, 0.05);
font-family: 'Inconsolata', 'Menlo', 'Consolas', monospace;
font-size: 16px;
padding: 20px;
}
.public-DraftEditorPlaceholder-root,
.public-DraftEditor-content {
margin: 0 -15px -15px;
padding: 15px;
}
.public-DraftEditor-content {
min-height: 100px;
}
h2{
color: $black!important;
}
}
I made the richtexteditor part of a react-redux component. It updates a hidden field on keyups.. it has to change the value instead of setting the state - this was to fool the react-redux form that the field had been "touched" --- although its not as fully sophisitcated as I would like - as the clear values button if shown - will reset the hidden field but not restore the old text in the editor.
//renderRichFieldTextarea react-redux field.
import React from 'react'
import RichEditor from '../_SharedGlobalComponents/RichEditor';
class ContentContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
value: this.props.input.value
};
this.handler = this.handler.bind(this);
}
handler(d) {
this.props.input.onChange(d);
}
render() {
const input = this.props.input;
const placeholder = this.props.placeholder;
const type = this.props.type;
const boxclass = this.props.boxclass;
return (
<div>
<RichEditor
initialValues={input.value}
handler={this.handler}
/>
<input {...input} type="hidden" />
</div>
);
}
}
const renderRichFieldTextarea = ({input, label, placeholder, boxclass, type, meta: {touched, error, warning}}) => (
<div className='field'>
<div>
<label>{label}</label>
</div>
<div>
<ContentContainer initialValues={input.value} onChange={this.onChange} input={input} placeholder={placeholder} type={type} boxclass={boxclass}/>
</div>
</div>
)
export default renderRichFieldTextarea
so I use it in a form component like this.
//EditPrivacySectionsSyncValidationForm - a react redux form
import React from 'react'
import { Field, reduxForm } from 'redux-form'
import { Row, Col, Collapse } from 'antd';
import renderField from '../_SharedFormComponents/renderField'
import renderRichFieldTextarea from '../_SharedFormComponents/renderRichFieldTextarea'
import renderRadioCheckField from '../_SharedFormComponents/renderRadioCheckField'
import renderError from '../_SharedFormComponents/renderError'
import validate from './validateEditSections'
import warn from './warnEditSections'
const Panel = Collapse.Panel;
const EditPrivacySectionsSyncValidationForm = props => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit} >
<Row>
<Col xs={24} sm={24} md={24}>
<div>
<Field name="privacy" type="textarea" component={renderRichFieldTextarea} label="Privacy" placeholder="Please write here..." boxclass="tall"/>
</div>
</Col>
</Row>
<div>
<button type="submit" disabled={submitting}>
Submit
</button>{/*
<button type="button" disabled={pristine || submitting} onClick={reset}>
Clear Values
</button>*/}
</div>
</form>
)
}
//initialValues = {interest: "art"}
export default reduxForm({
form: 'syncValidationEditPrivacySections', // a unique identifier for this form
validate, // <--- validation function given to redux-form
warn // <--- warning function given to redux-form
})(EditPrivacySectionsSyncValidationForm)