How to use urls in React CSS inline styling without `$`? - css

Learning React and trying to cheat off this codepen. I do not understand 2 things.
What is the ... before largebox, flex, and other css classes?
return <div style={{...largebox, ...flex}} key={props.id}
What does the $ do in the css url param? Is it jQuery?
`url(${props.photo})
const FormCard = (props) => (
<div>
{
DATA.map((props) => {
return <div style={{...largebox, ...flex}} key={props.id}>
<div style={{...Photo,backgroundImage: `url(${props.photo})`}}></div>
<div>
<Author author={props.author}/>
<Something bio={props.bio}/>
<AdBox adpic={props.adpic} />
<IconBox />
</div>
</div>
})
}
</div>
)

The three dots '...' are called spread operator, see here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
The $ sign is no Jquery but is actually referencing template literals: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
Hopefully, the docs are enough as I currently can't find [the link] to [that tutorial] I remember...

Spread operator:
const styleA = { color: 'red' };
const styleB = { background: 'blue' };
const styleC = { ...styleA, ...styleB };
// styleC = {color: "red", background: "blue"}
String Template:
const user = 'Bob';
const greetings = `Hello ${user}`;
// greetings = 'Hello Bob'

for your first question we call it Spread Operator in a simple description for below line :
style={{...largebox, ...flex}}
this is mean copy all property of largebox and flex object into a new object and assing it to style.or this line means :
style={{...Photo,backgroundImage:"myurl}"}
create a new object for me with all property of Photo object and also add a property with name backgroundImage to it. so if Photo is equal to {name:'1.jpg'} the new object is equal to
{name:'1.jpg',backgroundImage:"myUrl"}
Now for your second question, this is template literal and allow you to write variables or call functions inside a string. think we have not this so we must write it like :
backgroundImage: "url(" + props.photo +")"
so as you see it is something like concating props.photo and other strings.but with template literals we can wrap string with backticks and then write variable or function of javascript between ${} like below
backgroundImage: `url(${props.photo})`
then ${props.photo} replace with its value.

Related

Produce css value based on boolean value from scss file

I have the following which works fine where I am using in line style to decide the percentage values based on a boolean value.
Is there a way I could prevent using inline styling and instead pass this styling to my scss file and still be able to perform this logic more elegantly?
Working copy with inline styling.
const MyPage = ({isSmall}) => {
return (
<div>
<div style={{flex: `0 0 ${isSmall ? '50%' : '33%'}`}}>
hello
</div>
</div>
);
};
export default MyPage;
Looking to be able to move my css to my scss file and use that as a className instead but still be able to toggle the percentage value based on the boolean isSmall prop value.
Move it to scss file.
.flexer {
flex: '0 0 33%' // some way to make the 33% be dynamic and not hard code like this to be able to switch its value between 50% and 33%
}
Then use this flexer class instead of inline css.
Is this possible? Or any better elegant way to achieve this instead of inline?
You can set boolean state and change class name depends on this state inside the className then you can modifiy it in css
const MyPage = ({isSmall}) => {
const [isSmall,setIsSmall] = useState(false);
return (
<div>
<div className={isBigClass `${isSmall} ? "isSmallClass" : ""}`} >
hello
</div>
</div>
);
};
export default MyPage;

Programmatically assigning css classes in React

In my React app I have a set of classes that I am assigning to various elements. They are named button1, button2, button3, etc. Currently I am using a switch statement to determine which class to assign.
switch (num) {
case 1:
return {
memberButton: styles.button1
};
case 2:
return {
memberButton: styles.button2
};
case 3:
return {
memberButton: styles.button3
};
}
Is there a way to assign the class by doing something like this:
className={styles.button + rowNumber}
Of course that doesn't work. I'm trying to eliminate the need for a switch statement by constructing the class name in code.
Yo should do it like this:
className={styles[`button${rowNumber}`]}
You need to use brackets to access an Objects hash value using a variable since variables can't be used with dot notation. E.g.:
styles = {
'button1': 'button 1 styles',
'button2': 'button 2 styles',
'button3': 'button 3 styles',
}
Then you would just do:
className={ styles[`button${rowNumber}`] }
In short - With dot notation you cannot use variables, but with bracket notation you can.
You can try the following approaches
<div className={"form-group "+ this.props.errorMessage.roleError ?this.props.errorMessage.roleError : '' +" has-feedback"}></div>
another with template literal
<div className={`form-group ${this.props.errorMessage.roleError ?this.props.errorMessage.roleError : ''} has-feedback`}></div>
in your code
className={ styles[`button${rowNumber}`] }
or
className={styles['button'+rowNumber+'\''] }

Cypress testing pseudo CSS class :before

Is there a way in which I can test the content of the pseudo CSS class for :before on my element with Cypress?
I have seen links documenting:
Accessing nth-child pseudo element
Accessing the actual content pseudo class of a normal CSS class
But I have not found anything for CSS classes using the ::before pseudo class.
Imagine the code:
.myClass:before {
content: "foo-";
}
<div>
<span class="myClass">Bar</span>
</div>
How could one test that 'foo-' is present?
There's a way to assert on the CSS properties of pseudo-elements, although it's not as simple as just using a Cypress command.
Use cy.get() to get a reference to the element.
Read the Window object off of the element, and then invoke Window.getComputedStyle(), which can read the computed CSS of pseudo selectors.
Use getPropertyValue on the returned CSS declaration to read the value of the content property.
Assert on it.
Here's an example that works on the code posted in the OP:
cy.get('.myClass')
.then($els => {
// get Window reference from element
const win = $els[0].ownerDocument.defaultView
// use getComputedStyle to read the pseudo selector
const before = win.getComputedStyle($els[0], 'before')
// read the value of the `content` CSS property
const contentValue = before.getPropertyValue('content')
// the returned value will have double quotes around it, but this is correct
expect(contentValue).to.eq('"foo-"')
})
Based on Zach's answer I created a command that returns the pseudo-element property (without single quotes around).
function unquote(str) {
return str.replace(/(^")|("$)/g, '');
}
Cypress.Commands.add(
'before',
{
prevSubject: 'element',
},
(el, property) => {
const win = el[0].ownerDocument.defaultView;
const before = win.getComputedStyle(el[0], 'before');
return unquote(before.getPropertyValue(property));
},
);
You will use it like this
it('color is black', () => {
cy.get('button')
.before('color')
.should('eq', 'rgb(0,0,0)'); // Or .then()
});
Try asserting on the text of the parent:
cy.get('.myClass').parent().should('have.text', 'foo-bar')
If that doesn't work, you may have to use the textContent property:
cy.get('.myClass').parent(). should($el => expect ($el).to.contain('foo-bar')
)
This was my solution to get, convert and compare a hexadecimal's background-color with a rgb returned.
const RGBToHex = (rgbColor) => {
// it parse rgb(255, 13, 200) to #fa92D4
const [red, green, blue] = rgbColor.replace(/[a-z]|\(|\)|\s/g, '').split(',');
let r = parseInt(red, 10).toString(16);
let g = parseInt(green, 10).toString(16);
let b = parseInt(blue, 10).toString(16);
if (r.length === 1) r = `0${r}`;
if (g.length === 1) g = `0${g}`;
if (b.length === 1) b = `0${b}`;
return `#${r}${g}${b}`;
};
cy.get('.element').then(($el) => {
const win = $el[0].ownerDocument.defaultView;
const before = win.getComputedStyle($el[0], 'before');
const bgColor = before.getPropertyValue('background-color');
expect(RGBToHex(bgColor)).to.eq('#HEXA');
});

How to get access to the children's css values from a styled component?

I am using a REACT BIG CALENDAR and I want to get access to the css values in one of my functions.
I created a style component and override the library
const StyledCalendar = styled(Calendar);
Now for example there is a div inside of the Calendar with the class = "hello",
How would I access the css values of "hello" in a function? Similar to property lookup say in stylus.
I have tried window.getComputedStyle(elem, null).getPropertyValue("width") but this gives the css of the parent component.
If you know the class name, you should be able to select that and give that element to getComputedStyle instead of giving it StyledCalendar. Something like:
const childElement = document.getElementsByClassName('hello')[0];
const childWidth = getComputedStyle(childElement).getPropertyValue('width');
(this assumes that there's only one element with the class 'hello' on the page, otherwise you'll have to figure out where the one you want is in the node list that's returned by getElementsByClassName)
You can do it using simple string interpolation, just need to be sure that className is being passed to Calendar's root element.
Like this:
const StyledCalendar = styled(Calendar)`
.hello {
color: red;
}
`
Calendar component
const Calendar = props => (
// I don't know exact how this library is structured
// but need to have this root element to be with className from props
// if it's possible to pass it like this then you can do it in this way
<div className={props.className}>
...
<span className="hello"> Hello </span>
...
</div>
)
See more here.

react-virtualized Grid.cellRenderer - issues adding style prop

I am using the Grid component and have a cellRenderer. In it I attempt to add a backgroundColor style to the outer div.
customColumnRenderer(props: GridCellProps): React.ReactNode {
...
props.style.backgroundColor = "hotpink";
...
return <div style={props.style}
... </div>;
}
All is good at first, but then I scroll vertically a bit and I get this exception:
Uncaught TypeError: Cannot assign to read only property 'backgroundColor' of object '#<Object>'
When I look in the debugger. props.style looks like a simple Object to me. The doc says
"You can add additional class names or style properties as you would like."
Any thoughts on what I might be doing wrong?
Best workaround I could come up with is to merge in style props from a different object using the spread operator. Something like this:
customColumnRenderer(props: GridCellProps): React.ReactNode {
...
let myStyles = {backgroundColor: "hotpink"};
let styles = {...props.style, ...myStyles};
...
return <div style={styles}
... </div>;
}

Resources