How to create a new DraftInlineStyle? - draftjs

I have tried to create a new state with Modifier.insertText and the third argument is supposed to a draftInlineStyle
let ncs = Modifier.insertText(contentStates, selections, superscriptVar, ["BOLD"]);
This does give bold but when i try to change the style later on it doesn't change. I have figured out this is because draftInlineStyle is supposed to be a constructor. So how do I create a draftInlineStyle constructor if i am supposed to pass a draftInlineStyle constructor? or is there any other way to do this?

You should use OrderedSet.of from Immutable.js.
let ncs = Modifier.insertText(
contentStates,
selections,
superscriptVar,
OrderedSet.of('BOLD')
);
If you want to apply many styles, pass them as arguments: OrderedSet.of('BOLD', 'ITALIC')
Check the simplified demo in the hidden snippet below:
const {Editor, RichUtils, Modifier, SelectionState, EditorState} = Draft;
const { OrderedSet } = Immutable;
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty()
};
}
insertTextHandler = (nameOfCustomStyle) => {
const currentSelection = this.state.editorState.getSelection();
const currentContent = this.state.editorState.getCurrentContent();
if (!currentSelection.isCollapsed()) return;
const newContentState = Modifier.insertText(currentContent, currentSelection, 'INSERTED TEXT', OrderedSet.of('BOLD'));
const newEditorState = EditorState.push(
this.state.editorState,
newContentState,
'change-inline-style'
);
this._handleChange(newEditorState)
}
toggleBoldStyle = () => {
this._handleChange(
RichUtils.toggleInlineStyle(
this.state.editorState,
'BOLD'
)
);
}
_handleChange = (editorState) => {
this.setState({ editorState });
}
render() {
return (
<div>
<div className="container-root">
<Editor
placeholder="Type away :)"
editorState={this.state.editorState}
onChange={this._handleChange}
/>
</div>
<button onClick={() => this.insertTextHandler()}>
INSERT TEXT
</button>
<button onClick={() => this.toggleBoldStyle()}>
TOGGLE BOLD STYLE FOR SELECTED TEXT
</button>
</div>
);
}
}
ReactDOM.render(<Container />, document.getElementById('react-root'))
body {
font-family: Helvetica, sans-serif;
}
.public-DraftEditor-content {
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.0/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/draft-js/0.7.0/Draft.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/draft-js/0.10.0/Draft.js"></script>
<div id="react-root"></div>

Related

How to send trigger onClick to child component in soldjs and display it in parent?

I was trying to take example from react but seem it doesn't work as I expected.
I am trying to open a modal when user click the button in parent component, but function to open modal is located in the child component.
Parent component just where i try to invoke a modal:
<label class="text-white m-5 p-1">
<input type="checkbox" checked={false} onChange={handleCheck} />
I have read and agree to the <button onClick={}>Privacy</button>
<Portal>
<TermsModal />
</Portal>
</label>
How to do that?
If you want the Modal component to control the state, instead of it being passed with props you can use this pattern:
const { Modal, openModal } = createModal();
return (
<>
<button type="button" onClick={openModal}>
open modal
</button>
<Modal />
</>
);
It may be weird at first, but it's really fun and powerful :)
https://playground.solidjs.com/anonymous/d3a74069-e3d4-4d3e-9fb2-bafc5d6f5bf5
Create a signal inside parent component and pass it to the child component. Bind the visibility of the modal window to the signal's value:
import { Component, createSignal, Show } from 'solid-js';
import { Portal, render } from 'solid-js/web';
const Modal: Component<{ show: boolean }> = (props) => {
return (
<Show when={props.show}>
<div>Modal Window</div>
</Show>
);
};
const App = () => {
const [show, setShow] = createSignal(false);
const toggleShow = () => setShow(prev => !prev);
return (
<div>
<div>Show: {show() ? 'true': 'false'} <button onClick={toggleShow}>Toggle Show</button></div>
<Portal><Modal show={show()} /></Portal>
</div>
)
};
render(() => <App />, document.body);
https://playground.solidjs.com/anonymous/adf9ba7a-3e1b-4ce9-92b2-e78ff3fa55ec
You can further improve your component by creating a close handler and passing it to the child component. Now, modal window can show a close button.
Also you can add an event handler to the document in order to close the window whenever Escape key is pressed:
import { Component, createSignal, onCleanup, onMount, Show } from 'solid-js';
import { Portal, render } from 'solid-js/web';
const Modal: Component<{ show: boolean, close: () => void }> = (props) => {
const handleKeydown = (event) => {
if (event.key === 'Escape') {
props.close();
}
};
onMount(() => {
document.addEventListener('keydown', handleKeydown);
});
onCleanup(() => {
document.removeEventListener('keydown', handleKeydown);
});
return (
<Show when={props.show}>
<div>Modal Window <button onclick={props.close}>close</button></div>
</Show>
);
};
const App = () => {
const [show, setShow] = createSignal(false);
const close = () => setShow(false);
const toggleShow = () => setShow(prev => !prev);
return (
<div>
<div>Show: {show()} <button onClick={toggleShow}>Toggle Show</button></div>
<Portal><Modal show={show()} close={close} /></Portal>
</div>
)
};
render(() => <App />, document.body);
https://playground.solidjs.com/anonymous/0ae98cf1-19d6-487f-80dc-72d3c2e554dc
You can use a state in the parent component to keep track of whether the modal should be open or closed, and pass a function as a prop to the child component that updates that state:
const [isModalOpen, setIsModalOpen] = React.useState(false);
const handleButtonClick = () => {
setIsModalOpen(true);
};
return (
<div>
<label className="text-white m-5 p-1">
<input type="checkbox" checked={false} onChange={handleCheck} />
I have read and agree to the <button onClick={handleButtonClick}>Privacy</button>
<Portal>
<TermsModal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} />
</Portal>
</label>
</div>
);
// Child component
const TermsModal = ({ isOpen, onClose }) => {
if (!isOpen) {
return null;
}
return (
<div className="modal">
{/* Modal content */}
<button onClick={onClose}>Close</button>
</div>
);
};

Undefined value with customized radio input using react-hook-form

I want to make radio button input forms without radio button circles. I am able to make the interface of the form, but the form is sending undefined data.
Additionally, I added CSS that put a solid black border when radio buttons are checked, but this is not working either.
If I remove the CSS display: none, the form works fine; the data shows value, not undefined.
can anyone help me with this? Thank you so much in advance!
The form consists of three components
CustomRadioBtn.module.css
.radioInput + .radioLabel:before{
content: "";
display: inline-block;
background-size: contain;
width: 140px;
height: 140px;
}
.radioLabel {
border-radius: 10px;
color: gray;
cursor: pointer;
margin: auto;
position: relative;
text-align: center;
transition: 0.5s;
}
.radioInput[value="slept less than 7hrs"]+.radioLabel:before{
background-image: url(../../../public/images/sleep/lessThan7hrs.png);
}
.radioInput[value="slept more than 7hrs"]+.radioLabel:before{
background-image: url(../../../public/images/sleep/moreThan7hrs.png);
}
/* below styling is not working */
.radioInput:checked + .radioLabel::before{
border: 3px solid #000;
}
.radioInput{
display: none;
}
CustomeIconContainer.tsx
import { Controller, useForm } from "react-hook-form";
import styled from "styled-components";
import CustomIconInputForm from "../molecules/CustomIconInputForm";
import StyledFlexboxRow from "components/layouts/Flexbox/StyledFlexboxRow";
type Tdata = {
sleep?: string;
stool?: string;
movement?: string;
};
interface IContainerProps {
name: string;
options: string[];
desc: string;
iconLog?: TIconValueData;
}
export type TIconValueData = {
id?: number;
sleep?: string;
movement?: string;
stool?: string;
};
/**
* CustomIconContainer - handle icon input
*/
const CustomIconContainer = (props: IContainerProps) => {
const { name, options, desc } = props;
const { handleSubmit, control } = useForm();
const onSubmit = (data: Tdata) => {
if (data === undefined) {
throw new Error("your log is undefined");
}
console.log(data);
};
const StyledLabel = styled.label`
display: block;
`;
return (
<div className="CustomIconContainer">
<form onSubmit={handleSubmit(onSubmit)}>
<StyledLabel>{desc}</StyledLabel>
{/* mapping icon buttons */}
<StyledFlexboxRow>
{options.map((option, index) => (
<Controller
key={index}
name={name}
control={control}
render={({ field: { onChange, ref, ...props } }) => (
<CustomIconInputForm
{...props}
onChange={onChange}
value={option}
inputRef={ref}
desc={option}
/>
)}
/>
))}
</StyledFlexboxRow>
<button type="submit">Save</button>
</form>
</div>
);
};
export default CustomIconContainer;
CustomIconInputForm.tsx
import { IconDefinition } from "#fortawesome/fontawesome-common-types";
import { RefCallBack } from "react-hook-form";
import styles from "./CustomRadioBtn.module.css";
interface ICustomIconProps {
onChange?: () => void;
name?: string;
value?: string;
icon?: IconDefinition;
desc: string;
inputRef?: RefCallBack;
}
const CustomIconInputForm = (props: ICustomIconProps) => {
const { name, onChange, inputRef, value } = props;
const onChangeHandler = () => {
if (value !== undefined) {
onChange && onChange();
}
};
return (
<span className="CustomIconInputForm">
<input
ref={inputRef}
name={name}
value={value}
onChange={() => {
onChangeHandler;
}}
type="radio"
{...props}
className={styles.radioInput}
/>
<label htmlFor={name} className={styles.radioLabel}>
</label>
</span>
);
};
export default CustomIconInputForm;
no radio button circles
with radio button circles

how to use material-ui Dialog PaperProps

I'm using v1.1.0 of material-ui in React 16.3.2. I'm trying to create a landing page similar to Showcase - Local Insights
where the dialog has opacity (Find foreclosures). I'm trying to use PaperProps for Dialog component described here Dialog doc
Here's a component I've created to try to do this.
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import Dialog from '#material-ui/core/Dialog';
import DialogActions from '#material-ui/core/DialogActions';
import DialogContent from '#material-ui/core/DialogContent';
import DialogTitle from '#material-ui/core/DialogTitle';
import ForwardIcon from '#material-ui/icons/Forward';
import Input from '#material-ui/core/Input';
import FormControl from '#material-ui/core/FormControl';
import Slide from '#material-ui/core/Slide';
const styles = theme => ({
dialogPaper: {
opacity: 0.5,
border: '#FF0000 1px solid',
},
button: {
margin: '30px'
}
});
function Transition(props) {
return <Slide direction="up" {...props} />;
}
class SignInDialog extends React.Component {
state = {
open: false,
username: ''
};
handleClickOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
handleChange = name => event => {
this.setState({
[name]: event.target.value,
});
};
render() {
const { classes } = this.props;
return (
<div>
<Button variant="fab" color="primary" aria-label="add" className={classes.button} onClick={this.handleClickOpen}>
<ForwardIcon />
</Button>
<Dialog
PaperProps={styles.dialogPaper}
open={this.state.open}
TransitionComponent={Transition}
onClose={this.handleClose}
aria-labelledby="form-dialog-title"
>
<DialogTitle id="form-dialog-title">WELCOME</DialogTitle>
<DialogContent>
<p>SIGN IN</p>
<FormControl className={classes.formControl}>
<Input
value={this.state.searchString}
onChange={this.handleChange('search')}
id="siginin-input"
placeholder="Enter your username"
/>
</FormControl>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color="primary">
Cancel
</Button>
<Button onClick={this.handleClose} color="primary">
Continue
</Button>
</DialogActions>
</Dialog>
</div>
);
}
}
SignInDialog.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(SignInDialog);
I haven't been able to figure out how to get the Dialog to take the styles. What is needed to get PaperProps to work?
If you want to use PaperProps you have to specify the props of the Paperfor which you are applying style.
<Dialog
PaperProps={{ classes: {root: classes.dialogPaper } }}
/>
You can also use classes property and override the style
<Dialog
classes={{paper:classes.dialogPaper}}
/>
The correct way to overide paper props is by using classNames
<Dialog
PaperProps={{ className: classNames(classes.dialogPaper) }}/>
<Dialog
PaperProps={{ classes: {root: classes.dialogPaper } }}
/>

How to pass state from checkboxes to a parent component?

I have a class (Cookbook) that passes a click handler "handleOnChange" to a child component (Filter). Filter renders checkboxes. On those checkboxes, I execute the handleOnChange. I want to update the state that exists in Cookbook, but even though handleOnChange is declared in Cookbook, it does not recognize this.state.selectedStaples. The error takes place in the handleOnChange function on the first non-console.log line. How do I update the state of selectedStaples in Cookbook?
Here is Cookbook
class Cookbook extends React.Component {
constructor(){
super();
this.state ={
cookbook: data,
selectedStaples: [],
}
}
getStapleList(recipes){
let stapleList = [];
recipes.forEach(function(recipe){
recipe.ingredient_list.forEach(function(list){
stapleList.push(list.needed_staple);
});
});
let flattenedStapleList = stapleList.reduce(function(a,b){
return a.concat(b);
})
return flattenedStapleList
}
handleOnChange(staple, isChecked, selectedStaples) {
console.log(staple);
console.log(isChecked);
console.log(selectedStaples);
const selectedStaples = this.state.selectedStaples;
// if (isChecked) {
// this.setState({
// selectedStaples: selectedStaples.push(staple)
// })
// } else {
// this.setState({
// selectedStaples: selectedStaples.filter(selectedStaple => selectedStaple !== staple)
// })
// }
}
render(){
const selectedStaples = this.state.selectedState;
const cookbook = this.state.cookbook;
const stapleList = this.getStapleList(cookbook.recipes);
return(
<div className="cookbook">
<div className="filter-section">
<h1>This is the filter section</h1>
<Filter stapleList = {stapleList} onChange={this.handleOnChange}/>
</div>
<div className="recipes">
<h1>This is where the recipes go</h1>
<div className="recipe">
<Recipe cookbook = {cookbook}/>
</div>
</div>
</div>
);
}
}
and Filter
class Filter extends React.Component {
render(){
const stapleList = this.props.stapleList;
const checkboxItems = stapleList.map((staple, index) =>
<div key = {index}>
<label>
<input
type="checkbox"
value="{staple}"
onClick={e => this.props.onChange(staple, e.target.checked)}
/>
{staple}
</label>
</div>
);
return (
<form>
{checkboxItems}
</form>
);
}
}

How to manage checkbox filtering with React?

I am working on my first React app. It is a recipe sort of app. It has an ingredients filter. The main component is the Cookbook component. It has a Filter component and a Recipe component.
The Recipe component displays all recipes on load. The Filter component displays all needed ingredients or staples. This part all works great.
What I want to do now is when a person clicks on a staple, lets say butter, it would then filter the entire recipe list. My assumption is that I need to pass the state of Filter up. How can I do this with these checkboxes?
Here is what I have:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
var data = require('./recipes.json');
function IngredientDetailList(props){
const ingredientList = props.ingredientList;
const listItems = ingredientList.map((ingredient, index) =>
<div key={index}>
{ingredient.measurement_amount}
{ingredient.measurement_unit}
{ingredient.ingredient}
</div>
);
return (
<div>{listItems}</div>
)
}
function Recipe(props){
const recipeList = props.cookbook.recipes
const listItems = recipeList.map((recipe) =>
<div key={recipe.id}>
<h2>{recipe.name}</h2>
<IngredientDetailList ingredientList = {recipe.ingredient_list}/>
</div>
);
return(
<div>{listItems}</div>
)
}
class Filter extends React.Component {
constructor(){
super();
this.state = {
checkedStaples: {},
}
}
render(){
const stapleList = this.props.stapleList;
const checkboxItems = stapleList.map((staple, index) =>
<div key = {index}>
<label>
<input type="checkbox" value="{staple}"/>
{staple}
</label>
</div>
);
return (
<form>
{checkboxItems}
</form>
);
}
}
class Cookbook extends React.Component {
constructor(){
super();
this.state ={
cookbook: data
}
}
getStapleList(recipes){
let stapleList = [];
recipes.forEach(function(recipe){
recipe.ingredient_list.forEach(function(list){
stapleList.push(list.needed_staple);
});
});
let flattenedStapleList = stapleList.reduce(function(a,b){
return a.concat(b);
})
return flattenedStapleList
}
render(){
const cookbook = this.state.cookbook;
const stapleList = this.getStapleList(cookbook.recipes);
return(
<div className="cookbook">
<div className="filter-section">
<h1>This is the filter section</h1>
<Filter stapleList = {stapleList}/>
</div>
<div className="recipes">
<h1>This is where the recipes go</h1>
<div className="recipe">
<Recipe cookbook = {cookbook}/>
</div>
</div>
</div>
);
}
}
ReactDOM.render(
<Cookbook />,
document.getElementById('root')
);
You could try to do something like this:
// ....
function Recipe(props){
const selectedStaples = props.selectedStaples;
const recipeList = props.cookbook.recipes
const listItems = recipeList.map((recipe) => {
const hasStaple = ingredient_list.reduce(
(_hasStaple, staple) => _hasStaple || selectedStaples.includes(staple),
false
);
// only show recipe if it has a staple
if (selectedStaples.length === 0 || hasStaple)
return (
<div key={recipe.id}>
<h2>{recipe.name}</h2>
<IngredientDetailList ingredientList = {recipe.ingredient_list}/>
</div>
);
}
return null;
}
);
return(
<div>{listItems}</div>
)
}
class Filter extends React.Component {
constructor(){
super();
this.state = {
checkedStaples: {},
}
}
render(){
const stapleList = this.props.stapleList;
const checkboxItems = stapleList.map((staple, index) =>
<div key = {index}>
<label>
<input
type="checkbox"
value="{staple}"
onClick={e => this.props.onChange(staple, e.checked)}
/>
{staple}
</label>
</div>
);
return (
<form>
{checkboxItems}
</form>
);
}
}
class Cookbook extends React.Component {
constructor(){
super();
this.state ={
cookbook: data,
selectedStaples: []
}
}
getStapleList(recipes){
let stapleList = [];
recipes.forEach(function(recipe){
recipe.ingredient_list.forEach(function(list){
stapleList.push(list.needed_staple);
});
});
let flattenedStapleList = stapleList.reduce(function(a,b){
return a.concat(b);
})
return flattenedStapleList
}
handleOnChange(staple, isChecked) {
const selectedStaples = this.state.selectedStaples;
if (isChecked) {
this.setState({
selectedStaples: selectedStaples.push(staple);
})
} else {
this.setState({
selectedStaples: selectedStaples.filter(selectedStaple => selectedStaple !== staple);
})
}
}
render(){
const selectedStaples = this.state.selectedStaples;
const cookbook = this.state.cookbook;
const stapleList = this.getStapleList(cookbook.recipes);
return(
<div className="cookbook">
<div className="filter-section">
<h1>This is the filter section</h1>
<Filter stapleList = {stapleList} onChange={this.handleOnChange.bind(this)}/>
</div>
<div className="recipes">
<h1>This is where the recipes go</h1>
<div className="recipe">
<Recipe cookbook = {cookbook} selectedStaples={selectedStaples} />
</div>
</div>
</div>
);
}
}
ReactDOM.render(
<Cookbook />,
document.getElementById('root')
);
It keeps track of the selected stapes in the cookbook component and passes that on to recipe