Anyone know how to change the fontSize of the TableHeaderRow in a DevExtreme React Grid?
Here's an example of code from the website (https://devexpress.github.io/devextreme-reactive/react/grid/demos/featured/data-editing/) that I have been working with
import * as React from 'react';
import {
SortingState, EditingState, PagingState,
IntegratedPaging, IntegratedSorting,
} from '#devexpress/dx-react-grid';
import {
Grid,
Table, TableHeaderRow, TableEditRow, TableEditColumn,
PagingPanel, DragDropProvider, TableColumnReordering,
} from '#devexpress/dx-react-grid-material-ui';
import Paper from '#material-ui/core/Paper';
import Dialog from '#material-ui/core/Dialog';
import DialogActions from '#material-ui/core/DialogActions';
import DialogContent from '#material-ui/core/DialogContent';
import DialogContentText from '#material-ui/core/DialogContentText';
import DialogTitle from '#material-ui/core/DialogTitle';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import Input from '#material-ui/core/Input';
import Select from '#material-ui/core/Select';
import MenuItem from '#material-ui/core/MenuItem';
import TableCell from '#material-ui/core/TableCell';
import DeleteIcon from '#material-ui/icons/Delete';
import EditIcon from '#material-ui/icons/Edit';
import SaveIcon from '#material-ui/icons/Save';
import CancelIcon from '#material-ui/icons/Cancel';
import { withStyles } from '#material-ui/core/styles';
import { ProgressBarCell } from '../../../theme-sources/material-ui/components/progress-bar-cell';
import { HighlightedCell } from '../../../theme-sources/material-ui/components/highlighted-cell';
import { CurrencyTypeProvider } from '../../../theme-sources/material-ui/components/currency-type-provider';
import { PercentTypeProvider } from '../../../theme-sources/material-ui/components/percent-type-provider';
import {
generateRows,
globalSalesValues,
} from '../../../demo-data/generator';
const styles = theme => ({
lookupEditCell: {
paddingTop: theme.spacing.unit * 0.875,
paddingRight: theme.spacing.unit,
paddingLeft: theme.spacing.unit,
},
dialog: {
width: 'calc(100% - 16px)',
},
inputRoot: {
width: '100%',
},
});
const AddButton = ({ onExecute }) => (
<div style={{ textAlign: 'center' }}>
<Button
color="primary"
onClick={onExecute}
title="Create new row"
>
New
</Button>
</div>
);
const EditButton = ({ onExecute }) => (
<IconButton onClick={onExecute} title="Edit row">
<EditIcon />
</IconButton>
);
const DeleteButton = ({ onExecute }) => (
<IconButton onClick={onExecute} title="Delete row">
<DeleteIcon />
</IconButton>
);
const CommitButton = ({ onExecute }) => (
<IconButton onClick={onExecute} title="Save changes">
<SaveIcon />
</IconButton>
);
const CancelButton = ({ onExecute }) => (
<IconButton color="secondary" onClick={onExecute} title="Cancel changes">
<CancelIcon />
</IconButton>
);
const commandComponents = {
add: AddButton,
edit: EditButton,
delete: DeleteButton,
commit: CommitButton,
cancel: CancelButton,
};
const Command = ({ id, onExecute }) => {
const CommandButton = commandComponents[id];
return (
<CommandButton
onExecute={onExecute}
/>
);
};
const availableValues = {
product: globalSalesValues.product,
region: globalSalesValues.region,
customer: globalSalesValues.customer,
};
const LookupEditCellBase = ({
availableColumnValues, value, onValueChange, classes,
}) => (
<TableCell
className={classes.lookupEditCell}
>
<Select
value={value}
onChange={event => onValueChange(event.target.value)}
input={(
<Input
classes={{ root: classes.inputRoot }}
/>
)}
>
{availableColumnValues.map(item => (
<MenuItem key={item} value={item}>
{item}
</MenuItem>
))}
</Select>
</TableCell>
);
export const LookupEditCell = withStyles(styles, { name: 'ControlledModeDemo' })(LookupEditCellBase);
const Cell = (props) => {
const { column } = props;
if (column.name === 'discount') {
return <ProgressBarCell {...props} />;
}
if (column.name === 'amount') {
return <HighlightedCell {...props} />;
}
return <Table.Cell {...props} />;
};
const EditCell = (props) => {
const { column } = props;
const availableColumnValues = availableValues[column.name];
if (availableColumnValues) {
return <LookupEditCell {...props} availableColumnValues={availableColumnValues} />;
}
return <TableEditRow.Cell {...props} />;
};
const getRowId = row => row.id;
class DemoBase extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
columns: [
{ name: 'product', title: 'Product' },
{ name: 'region', title: 'Region' },
{ name: 'amount', title: 'Sale Amount' },
{ name: 'discount', title: 'Discount' },
{ name: 'saleDate', title: 'Sale Date' },
{ name: 'customer', title: 'Customer' },
],
tableColumnExtensions: [
{ columnName: 'amount', align: 'right' },
],
rows: generateRows({
columnValues: { id: ({ index }) => index, ...globalSalesValues },
length: 12,
}),
sorting: [],
editingRowIds: [],
addedRows: [],
rowChanges: {},
currentPage: 0,
deletingRows: [],
pageSize: 0,
pageSizes: [5, 10, 0],
columnOrder: ['product', 'region', 'amount', 'discount', 'saleDate', 'customer'],
currencyColumns: ['amount'],
percentColumns: ['discount'],
};
const getStateDeletingRows = () => {
const { deletingRows } = this.state;
return deletingRows;
};
const getStateRows = () => {
const { rows } = this.state;
return rows;
};
this.changeSorting = sorting => this.setState({ sorting });
this.changeEditingRowIds = editingRowIds => this.setState({ editingRowIds });
this.changeAddedRows = addedRows => this.setState({
addedRows: addedRows.map(row => (Object.keys(row).length ? row : {
amount: 0,
discount: 0,
saleDate: new Date().toISOString().split('T')[0],
product: availableValues.product[0],
region: availableValues.region[0],
customer: availableValues.customer[0],
})),
});
this.changeRowChanges = rowChanges => this.setState({ rowChanges });
this.changeCurrentPage = currentPage => this.setState({ currentPage });
this.changePageSize = pageSize => this.setState({ pageSize });
this.commitChanges = ({ added, changed, deleted }) => {
let { rows } = this.state;
if (added) {
const startingAddedId = rows.length > 0 ? rows[rows.length - 1].id + 1 : 0;
rows = [
...rows,
...added.map((row, index) => ({
id: startingAddedId + index,
...row,
})),
];
}
if (changed) {
rows = rows.map(row => (changed[row.id] ? { ...row, ...changed[row.id] } : row));
}
this.setState({ rows, deletingRows: deleted || getStateDeletingRows() });
};
this.cancelDelete = () => this.setState({ deletingRows: [] });
this.deleteRows = () => {
const rows = getStateRows().slice();
getStateDeletingRows().forEach((rowId) => {
const index = rows.findIndex(row => row.id === rowId);
if (index > -1) {
rows.splice(index, 1);
}
});
this.setState({ rows, deletingRows: [] });
};
this.changeColumnOrder = (order) => {
this.setState({ columnOrder: order });
};
}
render() {
const {
classes,
} = this.props;
const {
rows,
columns,
tableColumnExtensions,
sorting,
editingRowIds,
addedRows,
rowChanges,
currentPage,
deletingRows,
pageSize,
pageSizes,
columnOrder,
currencyColumns,
percentColumns,
} = this.state;
return (
<Paper>
<Grid
rows={rows}
columns={columns}
getRowId={getRowId}
>
<SortingState
sorting={sorting}
onSortingChange={this.changeSorting}
/>
<PagingState
currentPage={currentPage}
onCurrentPageChange={this.changeCurrentPage}
pageSize={pageSize}
onPageSizeChange={this.changePageSize}
/>
<IntegratedSorting />
<IntegratedPaging />
<CurrencyTypeProvider for={currencyColumns} />
<PercentTypeProvider for={percentColumns} />
<EditingState
editingRowIds={editingRowIds}
onEditingRowIdsChange={this.changeEditingRowIds}
rowChanges={rowChanges}
onRowChangesChange={this.changeRowChanges}
addedRows={addedRows}
onAddedRowsChange={this.changeAddedRows}
onCommitChanges={this.commitChanges}
/>
<DragDropProvider />
<Table
columnExtensions={tableColumnExtensions}
cellComponent={Cell}
/>
<TableColumnReordering
order={columnOrder}
onOrderChange={this.changeColumnOrder}
/>
<TableHeaderRow showSortingControls />
<TableEditRow
cellComponent={EditCell}
/>
<TableEditColumn
width={120}
showAddCommand={!addedRows.length}
showEditCommand
showDeleteCommand
commandComponent={Command}
/>
<PagingPanel
pageSizes={pageSizes}
/>
</Grid>
<Dialog
open={!!deletingRows.length}
onClose={this.cancelDelete}
classes={{ paper: classes.dialog }}
>
<DialogTitle>
Delete Row
</DialogTitle>
<DialogContent>
<DialogContentText>
Are you sure to delete the following row?
</DialogContentText>
<Paper>
<Grid
rows={rows.filter(row => deletingRows.indexOf(row.id) > -1)}
columns={columns}
>
<CurrencyTypeProvider for={currencyColumns} />
<PercentTypeProvider for={percentColumns} />
<Table
columnExtensions={tableColumnExtensions}
cellComponent={Cell}
/>
<TableHeaderRow />
</Grid>
</Paper>
</DialogContent>
<DialogActions>
<Button onClick={this.cancelDelete} color="primary">
Cancel
</Button>
<Button onClick={this.deleteRows} color="secondary">
Delete
</Button>
</DialogActions>
</Dialog>
</Paper>
);
}
}
export default withStyles(styles, { name: 'ControlledModeDemo' })(DemoBase);
The font size of the text labelling the columns (e.g. product, region, amount) is fixed, and I see no parameters that can change it. Any ideas?
I think there are a few ways around this, the way I have used is having a fully controlled component.
Looks a little like this
<TableHeaderRow cellComponent={this.ExampleHeaderCell} />
Where ExampleHeaderCell is a component that would look something like this
ExampleHeaderCell = (props: any) => (<TableHeaderRow.Cell
className={exampleClass}
{...props}
key={column.name}
getMessage={() => column.title}
/>)
From there you can pass it a class as shown with exampleClass
You can take this further and have it customised for a particular column.
ExampleHeaderCells = (props: any) => {
const exampleClass = css({ backgroundColor: "blue" })
const { column } = props
if (column.name === "name") {
return (
<TableHeaderRow.Cell
className={exampleClass}
{...props}
key={column.name}
getMessage={() => column.title}
/>
)
}
return <TableHeaderRow.Cell {...props} key={column.name} getMessage={() => column.title} />
}
The example above is returning a specific cell with the exampleClass if the column name is equal to "name". Otherwise it just returns the regular TableHeaderRow.Cell
Related
I have 3 inputs and I have a state where I store all the inputs in an object. I have a button that clears all the states of the 3 inputs. When I'm logging the console it's actually clearing the inputs but it's not updating the UI. Do I have to get the previous state and clear it and not just set the new object to empty values?
Here is the code:
/*eslint-disable*/
import React, { useState, useMemo } from 'react';
import TextField from '#mui/material/TextField';
import Button from '#mui/material/Button';
import { SortProps, SorterProps } from '../../types/Sorter';
import SorterField from './SorterField';
import styles from '../../assets/components/Sorter/sorter.module.scss';
import '../../assets/utils/_sorterContainer.scss';
const initSelects = (fields) => {
return Object.fromEntries(
fields.map(({ name, defaultValue }) => [name, defaultValue ?? ''])
);
};
const Sorter = ({ menuItemsValue, setSortData, activeSort }: SortProps) => {
const fields: SorterProps[] = [
{
name: 'sorterParam1',
title: 'Sort by',
optional: true,
options: [],
},
{
name: 'sorterParam2',
title: 'Then by',
optional: true,
options: [],
},
{
name: 'sorterParam3',
title: 'Then by',
optional: true,
options: [],
},
];
const [select, setSelect] = useState<any>(() => initSelects(fields));
const fieldsWithOptions = useMemo(() => {
const taken = new Set();
return fields.map((field) => {
// options without previous selections
const withOptions = {
...field,
options: menuItemsValue.filter((item) => !taken.has(item)),
};
// only track non-empty values
if (select[field.name]) {
// exclude the current field selection
taken.add(select[field.name]);
}
return withOptions;
});
}, [fields, menuItemsValue, select]);
const NewIcon = (props) => (
<svg
{...props}
className="sorter-dropdown"
width="8"
height="5"
viewBox="0 0 8 5"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M1 1L4 3.5L7 1" stroke="#4C4C4D" stroke-linecap="round" />
</svg>
);
const handleSelectChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const { name, value } = e.target;
setSelect({ ...select, [name]: value });
};
const handleClearAllInputs = () => {
setSelect({
sorterParam1: '',
sorterParam2: null,
sorterParam3: null,
});
};
const handleConfirm = () => {
setSortData(
select.sorterParam3 || select.sorterParam2 || select.sorterParam1
);
};
return (
<TextField
label="Advanced Sorting"
className={styles.sorter__inputs}
id="sorter-parameter-1"
variant="standard"
InputProps={{
disableUnderline: true,
}}
select
SelectProps={{
IconComponent: (props) => <NewIcon {...props} />,
}}
sx={{
fontSize: '12px',
width: '100%',
'& .MuiInputBase-input:focus': {
backgroundColor: 'transparent !important',
},
'& .MuiInputLabel-root': {
color: '#9E9E9E',
},
'& .MuiTextField-root': {
fontSize: '13px',
},
'& .MuiOutlinedInput-root': {
backgroundColor: '#fff',
},
}}
>
{fieldsWithOptions.map((option, index) => {
return (
<SorterField
key={option.name}
menuItemsValue={option.options}
name={option.name}
option={option}
count={fields.length}
handleChange={handleSelectChange}
index={index + 1} // setData={setData}
activeSort={activeSort}
setSortData={setSortData}
/>
);
})}
<div className={styles.sorter__inputControllers}>
<Button
className={styles.sorter__clearAllInput}
onClick={handleClearAllInputs}
>
Clear All
</Button>
<Button
onClick={() => handleConfirm()}
className={styles.sorter__confirmInput}
>
Confirm
</Button>
</div>
</TextField>
);
};
export default Sorter;
<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>
This is my initial state:
const [inputList, setInputList] = useState([
{ answer: "Answer 1", isCorrect: false, points: 0 },
]);
I am adding input field dynamically and initially there will be one field. There is an Add button through which I can add more fields and remove button with that I can remove fields. But the problem I'm facing, after submitting the value I want to clear all the fields and there should be only one field as it was initially.Suppose if I add 4 fields and after submitting there should be only one. But when I'm trying to do that its not working but add, remove and even setting empty the state is working but setting only one field is not working.I'm mapping depending on inputList value but still after submitting I'm getting all the fields. If I have added 4 fields then after submitting also its 4. The state value is not being changed at all.
ADD more function:
const handleAddClick = () => {
let count = inputList.length;
let newfield = {
answer: `Answer ${count + 1}`,
isCorrect: false,
points: 0,
};
setInputList([...inputList, newfield]);
};
remove function:
const handleRemoveClick = (index) => {
let list = [...inputList];
let newList = list.filter((item, ind) => ind !== index);
setInputList(newList);
};
submit function: This should reset the state to initial state that is only one field should be there But not working
const Save = () => {
setInputList([{ answer: "Answer 1", isCorrect: false, points: 0 }])
}
I tried to do loop also for deleting every index but it only removes one no matter how many times the loop runs
Whole Component:
import DeleteIcon from "#mui/icons-material/Delete";
import React from "react";
import Checkbox from "#mui/material/Checkbox";
import Radio from "#mui/material/Radio";
import FormControl from "#mui/material/FormControl";
import IconButton from "#mui/material/IconButton";
import Switch from "#mui/material/Switch";
import TextField from "#mui/material/TextField";
import { useState } from "react";
import PlusSign from "../../../../Files/img/plus.png";
import Header from "../../../Header/Header";
import Topbar from "../../../Topbar/Topbar";
import styles from "../MultipleResponse/MultipleResponse.module.scss";
import QuestionEditor from "../../Editor/QuestionEditor/QuestionEditor";
import ReactTag from "../../TagInput/ReactTag";
import FormControlLabel from "#mui/material/FormControlLabel";
import { styled } from "#mui/material/styles";
import axios from "axios";
import "react-quill/dist/quill.snow.css";
import AnswerEditor from "../../Editor/AnswerEditor/AnswerEditor";
import SelectComp from "../../SelectComp/SelectComp";
import {
timeOptions,
categoryOptions,
difficultyLevelOptions,
} from "../../../../utils/constants";
import { RadioGroup } from "#mui/material";
import Snackbars from "../../../Assesment/MyAssesment/Snackbar";
import { useEffect } from "react";
export default function MultipleChoice() {
const baseURL = "http://localhost:5000/api/question";
const [distributePoints, setDistributePoints] = useState(false);
const [inputList, setInputList] = useState([
{ answer: "Answer 1", isCorrect: false, points: 0 },
]);
const [question, setQuestion] = useState("");
const [tags, setTag] = useState([]);
const [title, setTitle] = useState("");
const [time, setTime] = useState("");
const [difficultyLevel, setdifficultyLevel] = useState("");
const [category, setCategory] = useState("");
const [whatToLook, setwhatToLook] = useState("");
const [questionRelevent, setQuestionRelevent] = useState("");
const [shuffle, setShuffle] = useState(false);
const [value, setValue] = React.useState("");
const [loading, setLoading] = useState(false);
const [loading2, setLoading2] = useState(false);
const [snackText, setSnackText] = useState("");
const [severity,setSeverity]=useState("")
useEffect(() => {
const items = JSON.parse(localStorage.getItem("tempData"));
if (items) {
setTitle(items[0].title);
setdifficultyLevel(items[0].level);
setwhatToLook(items[0].whatToLookFor);
setQuestionRelevent(items[0].whyQuestionIsRelevant);
setTag(items[0].tags);
setTime(items[0].time);
setInputList(items[0].answers);
setCategory(items[0].category);
setQuestion(items[0].detail);
setShuffle(items[0].shuffleAnswers);
setDistributePoints(items[0].distributePoints);
setValue(items[0].radioValue);
}
}, []);
const [snack, setSnack] = React.useState(false);
const closeSnackbar = (event, reason) => {
if (reason === "clickaway") {
return;
}
setSnack(false);
};
const IOSSwitch = styled((props) => (
<Switch
focusVisibleClassName=".Mui-focusVisible"
disableRipple
{...props}
/>
))(({ theme }) => ({
width: 40,
height: 24,
padding: 0,
marginRight: 10,
"& .MuiSwitch-switchBase": {
padding: 0,
margin: 2,
transitionDuration: "300ms",
"&.Mui-checked": {
transform: "translateX(16px)",
color: "#fff",
"& + .MuiSwitch-track": {
backgroundColor:
theme.palette.mode === "dark" ? "#3699FF" : "#3699FF",
opacity: 1,
border: 0,
},
"&.Mui-disabled + .MuiSwitch-track": {
opacity: 0.5,
},
},
"&.Mui-focusVisible .MuiSwitch-thumb": {
color: "#33cf4d",
border: "6px solid #fff",
},
"&.Mui-disabled .MuiSwitch-thumb": {
color:
theme.palette.mode === "light"
? theme.palette.grey[100]
: theme.palette.grey[600],
},
"&.Mui-disabled + .MuiSwitch-track": {
opacity: theme.palette.mode === "light" ? 0.7 : 0.3,
},
},
"& .MuiSwitch-thumb": {
boxSizing: "border-box",
width: 20,
height: 20,
backgroundColor: "#FFFFFF",
},
"& .MuiSwitch-track": {
borderRadius: 26 / 2,
backgroundColor: theme.palette.mode === "light" ? "#E9E9EA" : "#39393D",
opacity: 1,
transition: theme.transitions.create(["background-color"], {
duration: 500,
}),
},
}));
const switchHandler = (event) => {
setDistributePoints(event.target.checked);
};
const handleInputChange = (e, index) => {
const list = [...inputList];
list[index]["answer"] = e;
setInputList(list);
};
const handlePointChange = (e, index) => {
const { name, value } = e.target;
const list = [...inputList];
list[index][name] = value;
setInputList(list);
};
const handleRemoveClick = (index) => {
let list = [...inputList];
let newList = list.filter((item, ind) => ind !== index);
setInputList(newList);
};
const handleAddClick = () => {
let count = inputList.length;
let newfield = {
answer: `Answer ${count + 1}`,
isCorrect: false,
points: 0,
};
setInputList([...inputList, newfield]);
};
const SaveAndAddAnother = () => {
setLoading2(true);
const newInputList = inputList.map(({ points, ...rest }) => {
return rest;
});
try {
axios
.post(baseURL, {
questionType: "MULTIPLE_CHOICE",
time: time.toString(),
title: title,
level: difficultyLevel,
detail: question,
category: category,
tags: tags,
whatToLookFor: whatToLook,
whyQuestionIsRelevant: questionRelevent,
answers: distributePoints ? inputList : newInputList,
distributePoints: distributePoints,
shuffleAnswers: shuffle,
})
.then((response) => {
setLoading(false);
if (response.data.result === 1) {
setSnack(true);
setSeverity('success')
setTimeout(() => {
setLoading2(false);
}, 1000);
setSnackText("Question added successfully");
setTime("");
setTitle("");
setdifficultyLevel("");
setQuestion("");
setCategory("");
setTag([]);
setwhatToLook("");
setQuestionRelevent("");
setDistributePoints(false);
setShuffle(false);
setValue("A");
let newList = [{ answer: "Answer 1", isCorrect: false, points: 0 }];
setInputList(newList);
localStorage.removeItem("tempData");
} else {
setLoading(false);
}
})
.catch((err) => {
// Handle error
setLoading2(false);
setSnack(true)
setSnackText("Error Adding question")
setSeverity('error')
});
} catch (e) {
setLoading(false);
}
};
const Save = () => {
setInputList([{ answer: "Answer 1", isCorrect: false, points: 0 }])
// setSnack(true);
// setSnackText("Question Saved as draft");
// setSeverity('success')
// setLoading(true);
// const localData = [
// {
// questionType: "MULTIPLE_CHOICE",
// time: time.toString(),
// title: title,
// level: difficultyLevel,
// detail: question,
// category: category,
// tags: tags,
// whatToLookFor: whatToLook,
// whyQuestionIsRelevant: questionRelevent,
// answers: inputList,
// distributePoints: distributePoints,
// shuffleAnswers: shuffle,
// radioValue: value,
// },
// ];
// localStorage.setItem("tempData", JSON.stringify(localData));
// setTimeout(() => {
// setLoading(false);
// }, 2000);
};
const questionText = (value) => {
setQuestion(value);
};
const selectedTags = (tags) => {
setTag(tags);
};
const handleTitle = (e) => {
setTitle(e.target.value);
};
const handleTime = (e) => {
setTime(e.target.value);
};
const handleDifficulty = (e) => {
setdifficultyLevel(e.target.value);
};
const handleCategory = (e) => {
setCategory(e.target.value);
};
const handleWhatToLookFor = (e) => {
setwhatToLook(e.target.value);
};
const handleQuestionRelevent = (e) => {
setQuestionRelevent(e.target.value);
};
const handleShuffle = (event) => {
setShuffle(event.target.checked);
};
function handleRadioButton(event, i) {
if (event.target.value === value) {
setValue("");
} else {
setValue(event.target.value);
}
const list = [...inputList];
Object.keys(list).forEach((key) => {
list[key]["isCorrect"] = false;
});
list[i]["isCorrect"] = true;
setInputList(list);
}
return (
<div className={styles.mainContainer}>
<Header />
<Topbar
questionType="Multiple-response"
loading={loading}
loading2={loading2}
SaveAndAddAnother={SaveAndAddAnother}
save={Save}
/>
<div className={styles.Container}>
<div className={styles.questionContainer}>
<div className={styles.left}>
<p className={styles.question}>Question</p>
<div className={styles.input}>
<TextField
variant="standard"
InputProps={{
disableUnderline: true,
}}
className={styles.title}
placeholder="Title.."
value={title}
onChange={(e) => handleTitle(e)}
/>
<QuestionEditor
question={question}
questionText={questionText}
theme="snow"
/>
</div>
<div className={styles.category}>
<ReactTag tags={tags} selectedTags={selectedTags} />
</div>
</div>
<div className={styles.right}>
<div className={styles.rightText}>
<span className={styles.heading}>Select the right answer</span>
<div>
<IOSSwitch
checked={distributePoints}
onChange={switchHandler}
/>
<span className={styles.instructinHeading}>
Distribute points across answers
</span>
</div>
</div>
<div className={styles.answers}>
<div className={styles.radio}>
<FormControl style={{ display: "flex", flex: 1 }}>
<RadioGroup
aria-labelledby="demo-controlled-radio-buttons-group"
name="controlled-radio-buttons-group"
value={value}
>
{inputList.map((x, i) => {
return (
<div key={i}>
<div key={i} className={styles.options}>
{!distributePoints ? (
<FormControlLabel
key={i}
value={x.answer}
control={
<Radio
onClick={(e) => handleRadioButton(e, i)}
/>
}
defaultChecked={false}
/>
) : (
""
)}
<div className="editor">
<AnswerEditor
handleAnswer={handleInputChange}
index={i}
theme="bubble"
val={x.answer}
/>
</div>
{distributePoints ? (
<div className={styles.inputCounter}>
<TextField
variant="standard"
name="points"
InputProps={{
disableUnderline: true,
type: "number",
}}
inputProps={{
min: 0,
style: { textAlign: "center" },
}}
value={x.points}
onChange={(e) => handlePointChange(e, i)}
/>
</div>
) : (
""
)}
{inputList.length > 1 && (
<IconButton
onClick={() => handleRemoveClick(i)}
className={styles.icon}
>
<DeleteIcon
sx={{ fontSize: 24, color: "#3699FF" }}
/>
</IconButton>
)}
</div>
{inputList.length - 1 === i && (
<div className={styles.bottomItemContainer}>
{distributePoints ? (
<div className={styles.pointsInfoText}>
Allocate points across answers. Give the best
answer 5 points
</div>
) : (
""
)}
{!inputList.some((el) => el.isCorrect === true) &&
!distributePoints ? (
<div className={styles.pointsInfoText}>
Select the correct answer
</div>
) : (
""
)}
<div
style={{
display: "flex",
justifyContent: "space-between",
}}
>
<button
onClick={handleAddClick}
type="button"
className={styles.addButton}
>
<img src={PlusSign} alt="" /> Add another
answer
</button>
<div className={styles.label}>
<Checkbox
checked={shuffle}
onChange={handleShuffle}
style={{ color: "#00A3FF" }}
/>
Shuffle answer
</div>
</div>
</div>
)}
</div>
);
})}
</RadioGroup>
</FormControl>
</div>
</div>
</div>
</div>
<div className={styles.itemContainer}>
<div className={styles.timeContainer}>
<SelectComp
handleChange={handleTime}
title="Time to answer the question"
val={time}
optionData={timeOptions}
/>
</div>
<div className={styles.timeContainer}>
<SelectComp
handleChange={handleCategory}
title="Question Category"
val={category}
optionData={categoryOptions}
/>
</div>
</div>
<div className={styles.itemContainer}>
<div style={{ flex: 1 }}>What to look for in the answer?</div>
<div style={{ flex: 1 }}>Why is this question relevant?</div>
</div>
<div className={styles.itemContainer}>
<div className={styles.releventText}>
<TextField
variant="standard"
InputProps={{
disableUnderline: true,
}}
className={styles.text}
placeholder="What to look for in the answer..."
value={whatToLook}
onChange={(e) => handleWhatToLookFor(e)}
/>
</div>
<div className={styles.releventText}>
<TextField
variant="standard"
InputProps={{
disableUnderline: true,
}}
className={styles.text}
placeholder="Why is this question relevant.."
value={questionRelevent}
onChange={(e) => handleQuestionRelevent(e)}
/>
</div>
</div>
<div className={styles.itemContainer}>
<div className={styles.difficultyLevel}>
<SelectComp
handleChange={handleDifficulty}
title="Difficulty Level"
val={difficultyLevel}
optionData={difficultyLevelOptions}
/>
</div>
{/* <div style={{ flex: 1 }}>Why is this question relevant?</div> */}
</div>
<div className={styles.bottomInfo}>
<div className={styles.element}>
<div className={styles.circle}></div>
<div className={styles.text}>
How should I formate my questions?
</div>
</div>
<div className={styles.element}>
<div className={styles.circle2}></div>
<div className={styles.text}>
{" "}
How do I use the question editor?
</div>
</div>
<div className={styles.element}>
<div className={styles.circle3}></div>
<div className={styles.text}>How do I use the formula editor?</div>
</div>
</div>
</div>
{snack && (
<Snackbars
text={snackText}
snack={snack}
closeSnackbar={closeSnackbar}
severity={severity}
/>
)}
{/* <div style={{ marginTop: 20 }}>{JSON.stringify(inputList)}</div> */}
</div>
);
}
I am using react hooks mostly in my current app. I need the below code expressed as react hooks, without the this.state and this.props. My current app is expressed entirely as React Hooks. If you see it closely, the below code is writing out SQL query code with the click of a button. I need that functionality in my current app, but I don't know how to assimilate that in my app. Any ideas?
import React from 'react';
import { Row, Col, Tabs, Spin, Card, Alert, Tooltip, Icon, Button } from 'antd';
import cubejs from '#cubejs-client/core';
import { QueryRenderer } from '#cubejs-client/react';
import sqlFormatter from "sql-formatter";
import JSONPretty from 'react-json-pretty';
import Prism from "prismjs";
import "./css/prism.css";
const HACKER_NEWS_DATASET_API_KEY = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpIjozODU5NH0.5wEbQo-VG2DEjR2nBpRpoJeIcE_oJqnrm78yUo9lasw'
class PrismCode extends React.Component {
componentDidMount() {
Prism.highlightAll();
}
componentDidUpdate() {
Prism.highlightAll();
}
render() {
return (
<pre>
<code className='language-javascript'>
{ this.props.code }
</code>
</pre>
)
}
}
const tabList = [{
key: 'code',
tab: 'Code'
}, {
key: 'sqlQuery',
tab: 'Generated SQL'
}, {
key: 'response',
tab: 'Response'
}];
class CodeExample extends React.Component {
constructor(props) {
super(props);
this.state = { activeTabKey: 'code' };
}
onTabChange(key) {
this.setState({ activeTabKey: key });
}
render() {
const { codeExample, resultSet, sqlQuery } = this.props;
const contentList = {
code: <PrismCode code={codeExample} />,
response: <PrismCode code={JSON.stringify(resultSet, null, 2)} />,
sqlQuery: <PrismCode code={sqlQuery && sqlFormatter.format(sqlQuery.sql())} />
};
return (<Card
type="inner"
tabList={tabList}
activeTabKey={this.state.activeTabKey}
onTabChange={(key) => { this.onTabChange(key, 'key'); }}
>
{ contentList[this.state.activeTabKey] }
</Card>);
}
}
const Loader = () => (
<div style={{textAlign: 'center', marginTop: "50px" }}>
<Spin size="large" />
</div>
)
const TabPane = Tabs.TabPane;
class Example extends React.Component {
constructor(props) {
super(props);
this.state = { showCode: false };
}
render() {
const { query, codeExample, render, title } = this.props;
return (
<QueryRenderer
query={query}
cubejsApi={cubejs(HACKER_NEWS_DATASET_API_KEY)}
loadSql
render={ ({ resultSet, sqlQuery, error, loadingState }) => {
if (error) {
return <Alert
message="Error occured while loading your query"
description={error.message}
type="error"
/>
}
if (resultSet && !loadingState.isLoading) {
return (<Card
title={title || "Example"}
extra={<Button
onClick={() => this.setState({ showCode: !this.state.showCode })}
icon="code"
size="small"
type={this.state.showCode ? 'primary' : 'default'}
>{this.state.showCode ? 'Hide Code' : 'Show Code'}</Button>}
>
{render({ resultSet, error })}
{this.state.showCode && <CodeExample resultSet={resultSet} codeExample={codeExample} sqlQuery={sqlQuery}/>}
</Card>);
}
return <Loader />
}}
/>
);
}
};
export default Example;
It's quite easy to convert a class to a functional component.
Remember these steps:
class => const
// Class
export class Example
// FC
export const Example
componentLifeCycles => useEffect
// Class lifecycle
componentDidMount() {
// logic here
}
// FC
useEffect(() => {
// logic here
})
render => return
// Class
render () {
return (<Component/>)
}
// FC
return (<Component />)`
constructor => useState
// Class
constructor(props) {
this.state.val = props.val
}
// FC
const [val, setVal] = useState(props.val)
setState => second arg from useState
// Class
constructor() {
this.state.val = val // constructor
}
this.setState({ val }) // class
// FC
const[val, setVal] = useState(null)
setVal("someVal")
TLDR: Solution
import React, { useEffect, useState } from "react"
import { Tabs, Spin, Card, Alert, Button } from "antd"
import cubejs from "#cubejs-client/core"
import { QueryRenderer } from "#cubejs-client/react"
import sqlFormatter from "sql-formatter"
import Prism from "prismjs"
import "./css/prism.css"
const HACKER_NEWS_DATASET_API_KEY =
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpIjozODU5NH0.5wEbQo-VG2DEjR2nBpRpoJeIcE_oJqnrm78yUo9lasw"
const PrismCode: React.FC = ({ code }) => {
useEffect(() => {
Prism.highlightAll()
})
return (
<pre>
<code className="language-javascript">{code}</code>
</pre>
)
}
const TabList = [
{
key: "code",
tab: "Code",
},
{
key: "sqlQuery",
tab: "Generated SQL",
},
{
key: "response",
tab: "Response",
},
]
const CodeExample: React.FC = ( { codeExample, resultSet, sqlQuery } ) => {
const [activeTabKey, setActiveTab] = useState("code")
const onTabChange = (key) => setActiveTab(key)
const contentList = {
code: <PrismCode code={codeExample} />,
response: <PrismCode code={JSON.stringify(resultSet, null, 2)} />,
sqlQuery: (
<PrismCode code={sqlQuery && sqlFormatter.format(sqlQuery.sql())} />
),
}
return (
<Card
type="inner"
tabList={TabList}
activeTabKey={activeTabKey}
onTabChange={(key) => {
onTabChange(key)
}}
>
{contentList[activeTabKey]}
</Card>
)
}
const Loader = () => (
<div style={{ textAlign: "center", marginTop: "50px" }}>
<Spin size="large" />
</div>
)
const TabPane = Tabs.TabPane
const Example: React.FC = ({ query, codeExample, render, title }) => {
const [showCode, toggleCode] = useState(false)
return (
<QueryRenderer
query={query}
cubejsApi={cubejs(HACKER_NEWS_DATASET_API_KEY)}
loadSql
render={({ resultSet, sqlQuery, error, loadingState }) => {
if (error) {
return (
<Alert
message="Error occured while loading your query"
description={error.message}
type="error"
/>
)
}
if (resultSet && !loadingState.isLoading) {
return (
<Card
title={title || "Example"}
extra={
<Button
onClick={() =>
toggleCode(!this.state.showCode)
}
icon="code"
size="small"
type={showCode ? "primary" : "default"}
>
{showCode ? "Hide Code" : "Show Code"}
</Button>
}
>
{render({ resultSet, error })}
{showCode && (
<CodeExample
resultSet={resultSet}
codeExample={codeExample}
sqlQuery={sqlQuery}
/>
)}
</Card>
)
}
return <Loader />
}}
/>
)
}
export default Example
i am trying to make a todo list in reacthook. my App.js:
import React,{useState} from 'react';
import AddTodo from './TodoFiles/AddTodo'
import TodoList from './TodoFiles/TodoList'
const defaultItems=[
{id:1,title:'Write React Todo Project',completed:true},
{id:2,title:'Upload it to github', completed:false}
]
const App=()=>{
const [items,setItems]=useState(defaultItems)
return(
<div style={{width:400}}>
<AddTodo items={items} setItems={setItems}/>
<br/>
<hr/>
<TodoList items={items}/>
<hr/>
</div>
)
}
export default App;
the addTodo.js is:
import React,{useState} from 'react'
const AddTodo=({items,setItems})=>{
const[title,setTitle]=useState('')
const handleTitle=(event)=>{
setTitle(event.target.value)
}
const handleAddTodo=()=>{
const NewItem={title}
setItems([NewItem,...items])
}
return(
<form onSubmit={e=>{e.preventDefault();handleAddTodo()}}>
<input type="text" placeholder="enter new task..." style={{width:350,height:15}}
value={title} onChange={handleTitle}/>
<input type="submit" style={{float:'right', marginTop:2}}/>
</form>
)
}
export default AddTodo
TodoList.js is:
import React, { useState } from "react";
const TodoItem = ({ title, completed, completeTodo, removeTodo, index }) => {
return (
<div style={{ width: 400, height: 25 }}>
<input type="checkbox" checked={completed} />
{title}
<button style={{ float: "right" }} onClick={() => completeTodo(index)}>
Complete
</button>
<button style={{ float: "right" }} onClick={removeTodo}>
Remove
</button>
</div>
);
};
const TodoList = ({ items = [], index }) => {
const [, setItems] = useState("");
const completeTodo = index => {
console.log(index);
const newItem = [...items];
newItem[index].completed = true;
setItems(newItem);
};
const removeTodo = index => {
setItems(items.filter((p,index)=>p.index!==index))
};
return items.map((p, index) => (
<TodoItem
{...p}
key={p.id}
index={index}
completeTodo={completeTodo}
removeTodo={removeTodo}
/>
));
};
export default TodoList;
CompeleteTodo has been resolved but when i press the remove button it is not working and nothing has been deleted. there is no error while executing npm start. developer tools showing a warning:
index.js:1 Warning: Failed prop type: You provided a `checked` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultChecked`. Otherwise, set either `onChange` or `readOnly`.
in input (at TodoList.js:6)
in div (at TodoList.js:5)
in TodoItem (at TodoList.js:30)
in TodoList (at App.js:18)
in div (at App.js:13)
in App (at src/index.js:9)
in StrictMode (at src/index.js:8)
what more i can to to fix it?
You don't set index in parameter of your function, simply you can do this:
const TodoItem = ({ title, completed, completeTodo, removeTodo, index }) => {
return (
<div style={{ width: 400, height: 25 }}>
<input type="checkbox" checked={completed} />
{title}
<button style={{ float: "right" }} onClick={() => completeTodo(index)}>
Remove
</button>
<button style={{ float: "right" }} onClick={removeTodo}>
Complete
</button>
</div>
);
};
const TodoList = ({ items = [], index }) => {
const [, setItems] = useState("");
const completeTodo = index => {
console.log(index);
const newItem = [...items];
newItem[index].completed = true;
setItems(newItem);
};
const removeTodo = index => {
const newItem = [...items];
newItem.splice(index, 1);
setItems(newItem);
};
return items.map((p, index) => (
<TodoItem
{...p}
key={p.id}
index={index}
completeTodo={completeTodo}
removeTodo={removeTodo}
/>
));
};
export default TodoList;
and your remove and complete function is upside down :)
Check this
here is my suggestion > implement remove-complete functional with array items id and not index of elements.
please read this Lists and Keys
Here is Demo
App
import React, { useState } from "react";
import AddTodo from "./TodoFiles/AddTodo";
import TodoList from "./TodoFiles/TodoList";
const defaultItems = [
{ id: 1, title: "Write React Todo Project", completed: true },
{ id: 2, title: "Upload it to github", completed: false }
];
const App = () => {
const [items, setItems] = useState(defaultItems);
return (
<div style={{ width: 400 }}>
<AddTodo items={items} setItems={setItems} />
<br />
<hr />
<TodoList items={items} setItems={setItems} />
<hr />
</div>
);
};
export default App;
AddTodo
import React, { useState } from "react";
const AddTodo = ({ items, setItems }) => {
const [title, setTitle] = useState("");
const handleTitle = event => {
setTitle(event.target.value);
};
const handleAddTodo = () => {
const newItem = [
{
id: Math.max(...items.map(x => x.id), 0) + 1
completed: false,
title
},
...items
];
setItems(newItem);
};
return (
<form
onSubmit={e => {
e.preventDefault();
handleAddTodo();
}}
>
<input
type="text"
placeholder="enter new task..."
style={{ width: 350, height: 15 }}
value={title}
onChange={handleTitle}
/>
<input type="submit" style={{ float: "right", marginTop: 2 }} />
</form>
);
};
export default AddTodo;
TodoList
import React from "react";
import TodoItem from "./TodoItem";
const TodoList = ({ items, setItems }) => {
const completeTodo = id => {
setItems(
items.map(item => (item.id === id ? { ...item, completed: true } : item))
);
};
const removeTodo = id => {
setItems(items.filter(p => p.id !== id));
};
return items.map(p => (
<TodoItem
{...p}
key={p.id}
completeTodo={completeTodo}
removeTodo={removeTodo}
/>
));
};
export default TodoList;
TodoItem
import React from "react";
const TodoItem = ({ id, title, completed, completeTodo, removeTodo }) => {
return (
<div style={{ width: 400, height: 25 }}>
<input type="checkbox" checked={completed} onChange={() => {}} />
{title}
<button style={{ float: "right" }} onClick={() => completeTodo(id)}>
Complete
</button>
<button style={{ float: "right" }} onClick={() => removeTodo(id)}>
Remove
</button>
</div>
);
};
export default TodoItem;
I found this this Draftjs with Formik example on Codesandbox and I'm trying to implement in my NextJS project.
I don't understand what is the problem here.
This is my code:
Article.js
import { useState, useEffect } from 'react';
import { addArticle } from '../../store/actions/articleActions';
import { useDispatch, useSelector } from 'react-redux'
import * as Yup from 'yup'
import { Formik } from 'formik'
import dynamic from 'next/dynamic'
import {Editor, EditorState, convertToRaw, convertFromRaw } from 'draft-js';
import {stateToHTML} from 'draft-js-export-html';
import ArticleForm from './ArticleForm'
// reactstrap components
import {
Card,
CardBody,
Container,
Row,
Col
} from "reactstrap";
const Article = () => {
const initialArticle = {
title: '',
slug: '',
content: EditorState.createEmpty()
}
const validationSchema = Yup.object({
title: Yup.string()
.min(3, "Password must be more than 3 charachters!")
.max(20, "Password cant have more than 20 charachters"),
content: Yup.string()
.min(3, "Password must be more than 3 charachters!")
.max(20, "Password cant have more than 20 charachters")
})
const dispatch = useDispatch()
const handleSubmit = async (values) => {
const html = stateToHTML(values.content.getCurrentContent());
console.log("HTMLL", html)
const saveArticle = {
title: values.title,
slug: values.slug,
content: html
}
console.log("articleee", saveArticle)
dispatch(addArticle(saveArticle))
console.log("articleee", saveArticle)
}
return (
<main>
<section className="">
<Container className="pt-lg-md">
<Row className="justify-content-center">
<Col lg="12">
<Card className="bg-secondary shadow border-0">
<CardBody className="px-lg-5 py-lg-5">
<Formik
enableReinitialize={true}
component={ArticleForm}
initialValues={initialArticle}
validationSchema={validationSchema}
validateOnChange={false}
validateOnBlur={true}
onSubmit={(values) => {
handleSubmit(values)
}}
/>
</CardBody>
</Card>
</Col>
</Row>
</Container>
</section>
</main>
);
};
export default Article;
ArticleForm.js
import { Form } from 'formik'
import dynamic from 'next/dynamic'
import {Editor} from 'draft-js';
import { RichEditorExample } from '../../helpers/RichEditor';
// reactstrap components
import {
Button,
FormGroup,
Input,
InputGroupAddon,
InputGroupText,
InputGroup,
} from "reactstrap";
const ArticleForm = props => {
const {
values: {
title,
slug,
content
},
handleChange,
handleSubmit,
setFieldValue,
handleBlur
} = props
// Custom overrides for "code" style.
return (
<React.Fragment>
<Form onSubmit={(e) => {
e.preventDefault()
console.log('submitted')
handleSubmit()
}}
>
<FormGroup>
<InputGroup className="input-group-alternative mb-3">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="ni ni-lock-circle-open" />
</InputGroupText>
</InputGroupAddon>
<Input
placeholder="Title"
type='text'
name='title'
value={title}
onBlur={handleBlur}
onChange={handleChange}
/>
</InputGroup>
</FormGroup>
<FormGroup>
<InputGroup className="input-group-alternative mb-3">
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="ni ni-lock-circle-open" />
</InputGroupText>
</InputGroupAddon>
<Input
placeholder="Slug"
type='text'
name='slug'
value={slug}
onBlur={handleBlur}
onChange={handleChange}
/>
</InputGroup>
</FormGroup>
<FormGroup>
<RichEditorExample
editorState={content}
onChange={value => setFieldValue("content", value)}
/>
</FormGroup>
<div className="text-center">
<Button
className="mt-4"
color="primary"
type="submit"
>
Create
</Button>
</div>
</Form>
</React.Fragment>
);
}
export default ArticleForm;
RichEditorExample.js
import React from "react";
import {
Editor,
EditorState,
RichUtils,
convertToRaw,
convertFromRaw
} from "draft-js";
export class RichEditorExample extends React.Component {
onChange = editorState => {
const raw = convertToRaw(editorState.getCurrentContent());
const inputValue = convertFromRaw(raw);
console.log("##raw", { raw, inputValue });
this.props.onChange("editorState", editorState);
};
focus = () => this.refs.editor.focus();
handleKeyCommand = command => {
const { editorState } = this.props;
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.props.editorState, maxDepth));
};
toggleBlockType = blockType => {
this.onChange(RichUtils.toggleBlockType(this.props.editorState, blockType));
};
toggleInlineStyle = inlineStyle => {
this.onChange(
RichUtils.toggleInlineStyle(this.props.editorState, inlineStyle)
);
};
render() {
const { editorState } = this.props;
// 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() ;
console.log("contentState", contentState)
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=""
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>
);
};
Previosly, I'm trying to implement react-quill Editor on similar way but there is problem that i can't bold text and i can't save to database more than 2 words. So I decided to try with DraftJS.
If you can help me I will be very thankful!