Apply CSS styling to Draft.js formatted text content - css

I'm implementing a rich text editor to my React web app using Draft.js.
The only options I've kept in the toolbar are inline-styling (bold, italic, underline) and numbered/bulleted lists.
Before implementing the text editor, the texts in my database were simple strings that I could retrieve, display in a styled component and apply CSS to, so the first letter in the text looked like this:
This was my React styled component :
export const Text = styled.p`
&:first-letter {
float: left;
font-family: 'Centaur';
font-size: 3.5rem;
line-height: 0.65;
margin: 0.1em 0.1em 0.1em 0;
}
`
Now that I'm using Draft's text editor, my text is being displayed in a div that has a dangerouslySetInnerHTML property applied to it, so I can't apply CSS to it to edit the style of the first letter.
How can I get my head around this? I know that I can retrieve the editor's plain text with: editorState.getCurrentContent().getPlainText('\u0001')
I was thinking about storing the first letter of the text in the database to wrap it with a CSS class when displaying it, but then I would need to remove that letter from the rest of the text content saved so that the first letter doesn't appear twice, and I don't know how to alter Draft.js text content while retaining the styling.
This is my Draft.js Editor component with a Preview component underneath that displays the formated text:
import { EditorState } from 'draft-js';
import { Editor } from 'react-draft-wysiwyg';
import { convertToHTML } from 'draft-convert';
export default function MyComponent() {
const [editorState, setEditorState] = useState( () => EditorState.createEmpty() );
const [convertedContent, setConvertedContent] = useState('');
const handleChange = () => {
let currentContentAsHTML = convertToHTML(editorState.getCurrentContent());
setConvertedContent(currentContentAsHTML);
}
const createMarkup = (html) => {
return {
__html: html
}
}
return (
<>
<Editor
editorState={editorState}
onEditorStateChange={setEditorState}
toolbar={{options: ['inline', 'list', 'link', 'emoji', 'remove', 'history']}}
onContentStateChange={handleChange}
/>
<Preview dangerouslySetInnerHTML={createMarkup(convertedContent)}></Preview>
</>
)
}
Do you have any suggestion?
Thank you!

Related

Input is always `valid` in React

I have a react component like so
export const SearchBar = ({
searchInput,
updateSearchKeyword,
}: SearchBarProps) => {
const dummy = "";
return (
<div className={`${styles.container} `}>
<input
className={`${styles["search-bar"]} `}
type={"text"}
value={dummy}
title="search"
placeholder="Search..."
onChange={(e) => updateSearchKeyword(e.target.value)}
/>
</div>
);
};
And I want to make come CSS changes when the Input filed has text in it. So, my CSS is like below
.search-bar:valid {
color: red;
}
However, the color is always red! In other words, in put is always 'valid'
I tried
.search-bar[type="text"]:valid {
color: red;
}
and even adding a pattern in the component. It is not working how do I fix this?
PS: I am using modules.css, hence the class names are a bit strange but they are working as expected for other properties.
you only declare
className={`${styles["search-bar"]} `}
you never update this, so yes, are gona be always red.
then, another mistake when you put:
const dummy = "";
value={dummy}
You will be not able to change the value of this input. You have to use like this:
const [dummy, setDummy] = useState('')
and then on the input:
value={dummy}
onChange={(e)=>setDummy(e.target.value)}
but this not solves you problem, but you can:
onChange={(e)=>handleChange(e.target.value)}
and just declare this:
const handleChange = (value) => {
setDummy(value)
if (dummy !== '') {
// here change the style of ur input (the color)
}
}
###################
to change the style u can:
document.getelemntbyId... bla bla bla (booooring)
or BETTER: declare the style on a state like this:
const [myStyle, setMyStyle] = useState(`${styles["search-bar"]}`)
and then when u want to change ur style just actualize using
setMyStyle(`${styles["search-bar-blue"]}`)
Then for the validation you need to declare a css pattern to check if true or false:
<input pattern="[a-z]+" type.../>
On the example is gona validate true ONLY if input are ONLY lowercase letters

Using Styled Components and passing props to psedo element before not working

I have the follwing styled component, I am trying to pass a prop to it and use it in a pseudo element selector, in this case before. However, it does not work as expected.
However, if I pass the same prop to the background css property or any other property, it works completely fine
Is the following allowed when using styled components?
const Label = styled.label`
/* This did not work */
&::before {
content: ${(props) => (props.field ? "Hi" : "")};
}
/*But this works perfectly fine*/
background: ${(props) => (props.field ? "palevioletred" : "white")};
`;
const Input = styled.input`
height: 32px;
`;
If you check devtools, you'll see that your CSS rule is making it to the DOM, but it's an invalid value for the content property. It's raw text, with no quotes: Hi. It needs to be "Hi".
Try doing (notice the backticks for a new template string literal):
content: ${(props) => (props.field ? `"Hi"` : "")};

How should I write Jest Test cases for styled component and spy on css to verify if the styles?

I have a component in React-redux, which has a PagedGrid component (basically a table which renders data row-wise).
<UsersContainer>
<Title>{t('users')}</Title>
<PagedGrid
data-auto-container="user:table"
pageData={user.data}
columns={this.column}
/>
</UsersContainer>
I have created a function for the custom styled component which applies css to the rows of the table inside PagedGrid
const UsersContainer = styled.div`
> table > tbody {
${props => customcss(props)};
}
`;
function customcss({ data = [] }) {
let styles = '';
if (data.length > 0) {
data.forEach((value, index) => {
if (value.mycondition) {
const rowStyle = `& > tr:nth-child(${index + 1}) {
background-color: ${LIGHT_BLUE}
}`;
}
});
}
return css` ${rowStyle} `;
}
Now I want to create a test case using jest to spy on the css of this table and check if the styles are getting applied or not. Can anyone help me on creating a test case for this.
Assuming that you use the #testing-library/react library, you could test your component's style by getting it directly from the html document, and see precisely what style is used for your specific element.
In your example, you can do something like below (assuming that the ${LIGHT_BLUE} value is blue):
import React from 'react';
import { render } from '#testing-library/react';
import UsersContainer from '../UsersContainer';
it('should have the background color set to blue', () => {
const { container, getAllByTestId } = render(
<UsersContainer />
);
// Replace <YOUR_CSS_SELECTOR> by your component's css selector (that can be found in the inspector panel)
let contentDiv = document.querySelector('<YOUR_CSS_SELECTOR>');
let style = window.getComputedStyle(contentDiv[0]);
expect(style.color).toBe('blue');
}
Here, to get the style of your element, I am using the element's CSS Selector. However, it could also work with the element's className, or id directly if it has one, respectively using the methods document.getElementByClassName('YOUR_DIV_CLASS_NAME'), document.getElementId('YOUR_DIV_ID') instead of document.querySelector('<YOUR_CSS_SELECTOR>'). Note that the given name here should be unique, either with the id technique, or the className.

How to use SyntaxHighlighter for inline code

I am using Syntax Highlighter for my website.But how can I use it for inline code? I mean when I use it for inline code it still shows the line number 1 and I want to remove it as it makes no sense to show line number for inline code
i.e
I want
"This is a java print code System.out.println("Hello");"
instead of
"This is a java print code 1 |System.out.println("Hello");"
(notice the line number in second case)
I searched it on google but no success.
There is a configuration for turning line number on/off:
setting gutter attribute allows you to turn gutter with line numbers on and off.
Here is reference , Here is DEMO
You will have to use a custom code block and style it yourself to achieve it:
Algo:
If Inline Display Custom Block
Else Allow SyntaxHighlighter to do its magic.
I have used the below code:
CodeHighlighter.js
import {Prism as SyntaxHighlighter} from "react-syntax-highlighter";
import {dracula} from "react-syntax-highlighter/dist/esm/styles/prism";
import './CodeHighlighter.css'
import {Card} from "#mui/material";
function cleanChildren(children){
for (var i = 0; i < children.length; i++){
children[i] = children[i].trim()
}
return children
}
export default function CodeHighlight({node, inline, className, children, ...props}) {
var lang = "";
try {
lang = className.replace("language-", "");
} catch {
lang = "";
}
return (
<div className='highlightRoot'>
{inline ?
(
<Card className='inlineCode' variant='outlined'>
<code >{children}</code>
</Card>
)
: (
<div>
<SyntaxHighlighter
language={lang}
style={dracula}
showLineNumbers={!inline}
startingLineNumber={1}
children={cleanChildren(children)}
/>
<p>{lang}</p>
</div>
)
}
</div>
);
}
CodeHighlighter.css
.highlightRoot{
display: inline;
}
.inlineCode{
display: inline;
padding: 0 4px;
background-color: #4b4b59;
color: white;
}
I have been using this in conjunction with ReactMarkdown library.
What I was able to achieve:

CSS text align justify big spaces

To format paragraphs I use text-align:justify, but I have one problem that there are big spaces between words, for IE the solution is to use text-justify: distribute;, but Chrome doesn't support this, my question is what should I use for Chrome and Firefox
Example of big spaces: http://jsfiddle.net/L5drN/
Give negative values as you prefer for word-spacing..
ex:
text-align:justify;
word-spacing:-2px;
Works for me and Hope this helps :)
Use:
word-break: break-all;
And Ok!
Consider using hyphenation (manual, CSS, server-side, or client-side JavaScript), see e.g. answers to Can I use CSS to justify text with hyphenating words at the end of a line?
Hyphenation tends to help a lot when there are long words in the text.
You can still keep text-justify: distribute, as it can improve the result on supporting browsers, and it can be expected to gain support, as it in the CSS standardization track (in CSS Text Module Level 3 WD).
text-align: justify;
text-justify: distribute;
text-align-last: left;
hope this will help you
I got something satisfying by combining both methods:
enable hyphens (using two variants for compatibility)
negative word spacing (no more than -0.05em otherwise text get condensed)
div.justify {
text-align: justify;
hyphens: auto;
-webkit-hyphens: auto;
word-spacing: -0.05em;
}
div.font {
font-size: 110%;
}
<div class="justify font">In publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used as a placeholder before final copy is available. It is also used to temporarily replace text in a process called greeking, which allows designers to consider the form of a webpage or publication, without the meaning of the text influencing the design.</div>
How do you want to format the paragraphs? Do you mean the width, height, letter spacing or word spacing?
Have you tried using the text-align CSS tag?
text-align:center
Or the word-spacing CSS tag?
word-spacing:10px
I have an alternate solution to get rid of the big spacing between word
first you should know one thing that text-align:justify is used only when you are rendering your text component on wider screen so in my case I was using it on card custom component so I simply increase the width of my card component and this helps me hope it will help you to.
Card.js
import React from 'react';
import styles from './Card.module.css'
const Card = (props) => {
return (
<div className={styles.card}>
{props.children}
</div>
);
} ;
export default Card;
Card.module.css
.card {
height: 30rem;
width: 25rem;
margin: 0 20px 10rem;
text-align: justify;
}
Calling card component in HOC
import React, { useEffect, useState } from "react";
import projectStyles from "./project.module.css";
import Card from "../UX/Card";
import axios from "axios";
const Project = () => {
const [loadedProjects, setLoadedUsers] = useState([]);
useEffect(() => {
const fetchUsers = async () => {
try {
const responseData = await axios("api/projects");
setLoadedUsers(responseData.data.projects);
} catch (err) {}
};
fetchUsers();
}, []);
const displayHandler = (
<div className={projectStyles.projectHolder}>
{loadedProjects.map((project,index) => {
return (
<Card key={index}>
<img src={project.image} alt="project" height={225} width={345} style={{marginBottom:"20px"}}/>
<p style={{fontSize:'25px' , fontWeight:'bold'}}>{project.title}</p>
<p className={projectStyles.body}>{project.info}</p>
<h4>Technologies Used</h4>
<ul key={project.image}>
{project.technology.map((tech) => {
return <li key={tech}>{tech}</li>;
})}
</ul>
</Card>
);
})}
</div>
);
return <div>{loadedProjects ? displayHandler : 'Fetching Projects...'}</div>;
};
export default Project;

Resources