How to mimic css multiple class names in jsx - javascript

How could I recreate the following css in a react style css module?
.thing1, .thing2, .thing3, .thing4 { color: red }
.thing5, .thing6, .thing7 { color: blue }
Essentially I receive a prop containing a number/string which are grouped to the same css. But im not sure how I would recreate this setup in javascript. The below seems a bit silly to have to do. I would also like If i could avoid doing something like a array look up
const styles = {
thing1:{ color:red },
thing2:{ color:red },
thing3:{ color:red },
thing4:{ color:red },
thing5:{ color:blue },
thing6:{ color:blue },
thing7:{ color:blue },
}
Thoughts?
Edit
So an example would be:
render() {
let {classes} = this.props
return (
<div className={??? + this.props.input}></div>
)
}
if going the css route I would do
render() {
let {classes} = this.props
return (
<div className={"thing" + this.props.input}></div>
)
}

I made a helper to merge the styles, here is it:
const mergeStyles = styles => styles.join(' ');
export default mergeStyles;
And i use it this way:
<div className={mergeStyles([styles.boxInfo, styles.narrowBoxInfo])}>
If the styles are
.boxInfo {}
.narrowBoxInfo {}
Hope it helps!

Related

Mapping through array of objects to display images

I'm trying to map through an array of objects to display the images. Here is my code:
import React from 'react';
import photos from '../photo-store';
class Landing extends React.Component {
render() {
const photoDisplay = Object.keys(photos).map((photo, i) => {
return <img key={i} src={`.${photos[photo][i].src}`} alt='headshot'/>
})
console.log('photoDisplay', photoDisplay)
return (
<div>
<p>Photos will go here</p>
{photoDisplay}
</div>
)
}
}
export default Landing;
The src value is correct when I console.log, but for some reason I'm just getting my alt information rendering, and it's not going through all of the objects in the array. Any pointers on what might be happening here would be awesome. Thanks in advance for your help!
Here is a snippet of what is in "photos":
"photos": [
{
id: 1,
name: "AmberB",
src: "./images/AmberB.jpg"
},
{
id: 2,
name: "AmberR",
src: "./images/AmberR.jpg"
}
]
}
You made a small mistake in the return statement. If you have for src attribute the ${photos[photo].src} instead of photos[photo][i].src then it should work.
const photoDisplay = Object.keys(photos).map((photo, i) => {
return <img key={i} src={`${photos[photo].src}`} alt='headshot'/>
})
Please also consider removing the . as well but not sure about that.
I hope that helps!

How to use <Link /> component inside dangerouslySetInnerHTML

Currently I have this in one of my components:
{someObject.map(obj => (
<div
dangerouslySetInnerHTML={{
__html: obj.text
}}
/>
))}
Basically, I am mapping over someObject which on another file. The structure is like this:
export default someObject = [
{
obj: "<p>Some text 1.</p>"
},
{
obj: "<p>Some text 2.</p>"
}
]
I'm just simplifying the content for demonstration's sake. However, I ran into a problem because I need to use the <Link /> component in one of the items. As in:
export default someObject = [
{
obj: "<p>Some text 1.</p>"
},
{
obj: "<p>Some text 2.</p>"
},
{
obj: "<p>Some text 2 and <Link to="/someroute">link</Link>.</p>"
}
]
However, it's not working because that entire <p></p> tag is wrapped in dangerouslySetInnerHTML.
I can just use plain <a></a> tag for the link but that doesn't seem like a good solution as the entire application would reload instead of just going to another route.
What are the other options to make this work?
Why don't you just export the object as a jsx object? I think use dangerouslySetInnerHTML is a bad practice, it might cause XSS attack.
const someObject = [
{
obj: <p>Some text 1.</p>
},
{
obj: <p>Some text 2.google</p>
}
]
class App extends React.Component {
render(){
return (
<div className="App">
<h1>Hello world</h1>
<h2>Jsx object goes here {someObject[1].obj}</h2>
</div>
)};
}
const rootElement = document.getElementById("container");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
There's is two ways to solve this problem :
First Way :
it's like a more general approach you can use it to opt your code.
try to use this library (https://github.com/tasti/react-linkify/)
Here's the simpler form of the component :
import React, {PropTypes} from 'react';
import Linkify from 'react-linkify';
export default class TextWithLink extends React.Component {
constructor(props) {
super(props);
}
render() {
let text = this.props.text;
if(this.props.showLink) {
text = <Linkify properties={{target: '_blank', rel: "nofollow noopener"}}>{text}</Linkify>
}
return (<div>{text}</div>);
}
}
Second Way :
In case, if you want to create a hyperlink (<a>), you should have a function which builds elements and returns the result.
Example :
list = {
text: 'hello world',
link: 'www.facebook.com'
}
And the render function could be something like :
buildLink() {
return(
<p>
{list.text}. <a href={list.link}>{list.link}</a>
</p>
);
}
render() {
return (this.buildLink());
}
export default someObject = [
{
obj: "<p>Some text 1.</p>"
},
{
obj: "<p>Some text 2.</p>"
},
{
obj: linkto('/someroute')
}
]
linkto will solve your issue.

How would I change the background color of a list item upon click? (ES6 & Polymer)

I've cloned a repository which focuses on creating a To-Do application using ES6 and Polymer 3. I'm trying to implement a button which turns the background color containing a string green upon click. I've tried doing this, but I keep failing to get the desired result.
Example code:
static get properties() {
return {
list: {type: Array},
todo: {type: String},
};
}
constructor() {
super();
this.list = [
this.todoItem('buy cereal'),
this.todoItem('buy milk')
];
this.todo = '';
this.createNewToDoItem = this.createNewToDoItem.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
this.handleInput = this.handleInput.bind(this);
}
todoItem(todo) {
return {todo}
}
createNewToDoItem() {
this.list = [
...this.list,
this.todoItem(this.todo)
];
this.todo = '';
}
//Right here is where I tried to implement the background color change.
checkItem() {
checkItem = document.getElementById('checkItem'),
checkItem.addEventListener('click', () => {
this.list = this.list.filter(this.todo)
document.body.style.backgroundColor = 'green';
});
}
deleteItem(indexToDelete) {
this.list = this.list.filter((toDo, index) => index !== indexToDelete);
}
render() {
return html`
${style}
<div class="ToDo">
<h1>Grocery List</h1>
<h1 class="ToDo-Header">What do I need to buy today?</h1>
<div class="ToDo-Container">
<div class="ToDo-Content">
${repeat(
this.list,
(item, key) => {
return html`
<to-do-item
item=${item.todo}
.deleteItem=${this.deleteItem.bind(this, key)}
></to-do-item>
`;
}
)}
</div>
I'd be eternally thankful if someone helped me out. I've created two JSFiddle links which show the code I've worked on thus far:
Link 1: https://jsfiddle.net/r2mxzp1c/ (Check line 42-49)
Link 2: https://jsfiddle.net/zt0x5u94/ (Check line 13 & 22-24)
I'm not sure about the approach. But this link might help you
https://stackblitz.com/edit/web-components-zero-to-hero-part-one?file=to-do-app.js
from this guy: https://stackblitz.com/#thepassle
You should try to make the reactive templating work for you by defining presentation details in terms of your element's properties.
For example, this is a stripped-down approach to the same problem:
class TestElement extends LitElement{
static get properties() {
return {
'items': { 'type': Array }
};
}
constructor() {
super();
// set up a data structure I can use to selectively color items
this.items = [ 'a', 'b', 'c' ].map((name) =>
({ name, 'highlight': false }));
}
render() {
return html`<ol>${
this.items.map((item, idx) =>
html`<li
#click="${ () => this.toggle(idx) }"
style="background: ${ item.highlight ? '#0f0' : '#fff' }">
${ item.name }
</li>`)
}</ol>`;
}
toggle(idx) {
// rendering won't trigger unless you replace the whole array or object
// when using properties of those types. alternatively, mutate with the
// usual .push(), .splice(), etc methods and then call `this.requestUpdate()`
this.items = this.items.map((item, jdx) =>
jdx === idx ? { ...item, 'highlight': !item.highlight } : item
);
}
}
https://jsfiddle.net/rzhofu81/305/
I define the template such that the elements are colored the way I want depending on an aspect of their state (the "highlight" attribute of each entry in the list), and then I focus the interaction on updating the state to reflect what the user is doing.

Can't get draft-js Modifier's applyInlineStyle function to apply inline style

I am leveraging the draft-js and react-draft-wysiwyg libraries to create a WYSIWYG editor. I am looking to add some custom options to the toolbar to render the final HTML, such as inline line-height. However, I cannot get the Modifier's applyInlineStyle() function to work properly.
Editor:
import React, { Component } from "react";
import { ContentState, convertFromHTML, convertFromRaw, convertToRaw, EditorState, Modifier } from "draft-js";
import { Editor } from "react-draft-wysiwyg";
import draftToHtml from "draftjs-to-html";
import "../node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
const toolbarOptions = {
options: ["inline"],
inline: {
options: ["bold", "italic", "underline"],
bold: { className: "rich-text-icon" },
italic: { className: "rich-text-icon" },
underline: { className: "rich-text-icon" }
},
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty(),
finalHTML: ""
};
}
onEditorStateChange = editorState => {
const raw = convertToRaw(editorState.getCurrentContent());
const markup = draftToHtml(raw);
this.setState({
editorState,
finalHTML: markup
});
console.log(markup);
};
render() {
return (
<div>
<div className="App">
<Editor
editorState={this.state.editorState}
onEditorStateChange={this.onEditorStateChange}
toolbar={toolbarOptions}
toolbarCustomButtons={[<ApplyLineHeight />]}
stripPastedStyles={true}
/>
</div>
</div>
);
}
}
Custom line height option:
class ApplyLineHeight extends Component {
applyLineHeight = () => {
const { editorState, onChange } = this.props;
const contentState = Modifier.applyInlineStyle(editorState.getCurrentContent(), editorState.getSelection(), "line-height: 20px;");
onChange(EditorState.push(editorState, contentState, "change-inline-style"));
};
render() {
return <div onClick={this.applyLineHeight}>Change line height</div>;
}
}
When I follow the example from the docs (under "Adding new option to the toolbar"), it works with the Modifier.replaceText() function (to replace text) but it does not work when attempting to return line-height. I am returned the same <p></p> tags with no inline style applied. What could be causing this function to not render?
let's see api Modifier.applyInlineStyle() first
applyInlineStyle(
contentState: ContentState,
selectionState: SelectionState,
inlineStyle: string
): ContentState
The inlineStyle should be name defined in customStyleMap
The customStyleMap is property of Editor
just like this
import {Editor} from 'draft-js';
const styleMap = {
'STRIKETHROUGH': { // STRIKETHROUGH is the one which should be applied to inlineStyle
textDecoration: 'line-through',
},
};
class MyEditor extends React.Component {
// ...
render() {
return (
<Editor
customStyleMap={styleMap}
editorState={this.state.editorState}
...
/>
);
}
}
// The usage should be like this:
// Modifier.applyInlineStyle(xxx, xxx, 'STRIKETHROUGH')
draftjs-to-html does not convert every inline style,yet it supports a few things like color, background color, font-size, font-family
Firstly define the styles with an individual CSS property:
Eg:
const styles = {
'color-#222833': {
color: '#222833',
},
'color-#005EFF': {
color: '#005EFF',
},
'fontfamily-Montserrat': {
fontFamily: 'Montserrat',
},
'fontsize-18px': {
fontSize: '18px',
},}
Note : use the exact same inline style names
Secondly To add multiple CSS properties at once ,Create an array of custom classes created
Eg:
H2: ['color-#222833', 'fontsize-18px', 'fontfamily-Montserrat', 'BOLD'],
BODY: ['color-#222833', 'fontsize-15px', 'fontfamily-Montserrat'],
Iterate the Array to apply the styles one by one using the RichUtils API
import { RichUtils } from 'draft-js';
const UpdateState = ['color#222833','fontsize15px','fontfamilyMontserrat']
.reduce((state, style)=>RichUtils.toggleInlineStyle(state, style)
, editorState);
onChange(UpdateState);
Reference :
https://www.npmjs.com/package/draftjs-to-html
https://github.com/facebook/draft-js/blob/main/examples/draft-0-10-0/color/color.html

React/JSX - changing element type conditionally with minimal code duplication

Let's say I have something that is:
<div>
{/* a lot of code */}
</div>
But if some condition is true, I want it to be:
<tr>
{/* same code as before */}
</tr>
Is there any way to achieve this without a huge amount of code duplication from copy pasting?
You could render the content in a variable using React.Fragment and choose the enclosing element depending on the condition.
Example
class App extends Component {
state = { condition: true };
render() {
const { condition } = this.state;
const content = (
<Fragment>
<h1>Hello world</h1>
<h2>This is a lot of text...</h2>
</Fragment>
);
return condition ? <div> {content} </div> : <tr> {content} </tr>;
}
}
Marked someone else as accepted answer, but the solution I ended up using was to call React.createElement(condition ? "div" : "tr", {attribute: stuff}, <div>Inner content</div>). Just an alternative for anyone who stumbles upon this in the future :)
Add your code inside the function
function returnView() {
render (
// a lot of code
);
}
if condition is true call that function
condition? returnView() : ' '
Have you tried with createElement() method? It works well for me.
So the code is:
import { createElement } from 'react';
createElement(type, props, ...children)
Example:
function Element({ condition, children, onClick }) {
if (condition) {
return createElement(
'div',
{ className: 'element-style' },
children
);
}
return createElement(
'tr',
{ className: 'element-style' },
children
);
}
If you have some of the special props and the rest of them is same, you can pass it in object variable
function Element({ condition, children, onClick }) {
const elementProps = {
className: 'element-style',
onClick,
};
if (condition) {
return createElement(
'div',
{ ...elementProps, style: { color: 'white' } },
children
);
}
return createElement(
'tr',
{ ...elementProps, style: { color: 'black' } },
children
);
}
Source: https://beta.reactjs.org/reference/react/createElement

Categories

Resources