multiple conditions for styling with Css modules - css

I am trying to set multiple conditions with ternary operator to style an element using Css modules. I can't find the exact syntax. is it even possible?
there are some boxes that have 3 sizes , their default small size, the big size for the one that's hovered, and the medium size when at least one of them is hovered.
import style from './styles.module.sass'
const Slider =()=>{
const [hover,isHovered]=useState(false);
const [anyCardHovered,setAnyCardHovered]=useState(false)
return
<div className={`{ hover? ${style.hoveredBox}: anyCardHovered? ${style.smallBox}: style.box}`>
</div>

<div className={hover
? style.hoveredBox
: anyCardHovered
? style.smallBox
: style.box
}></div>
Another way:
/* Bits: hover, anyCardHovered */
const classNames = [
style.box, // 00
style.smallBox, // 01
style.hoveredBox, // 10
style.hoveredBox // 11
];
<div className={classNames[hover << 1 | anyCardHovered]}>
</div>
More details in: https://blog.uidrafter.com/bitwise-table-lookup

I would probably create a variable called classes and set its value and logic above your JSX return statement. Then you could simply set classname={classes} in your boxes.
let classes = 'small';
if(hover) {
classes = 'big'
} else if (anyCardHovered) {
classes = 'medium'
} else {
classes = 'small'
}

Related

Set media query dynamically in Tailwind css

In my react js application i have a component where i want to set the mobile break pint according to a variable:
<Component size={'500px'}/>
const Component = ({size}) => {
return (
<div md:flex>hello</div>
)
}
I want to add instead of md:flex something like [size]:flex to be able to set break point according to that props.(ex: set display flex if the size is 500px or 100px or 900px) Question: Is there possible to set the mediaquery according to the way that i described above?
You could use classnames npm package:
const rootClassName = cn(
// you can add any tailwind classNames first
"h-full flex flex-col",
// this is conditional part. based on size prop, define className
{
[md:flex-1]: size === "A",
[sm:flex-1]: size === "B",
}
)

Make a component with different sizes using SASS in React

I was always wondering how to make component with different sizes using SASS in React.
These are from airbnb, and let's assume these are same components.
The first one is 520px and the second one is around 130px.
If there exist these two sizes only, I know I can adjust the size using different className.
But what if I need different sizes more than two? like 300px, 400px and etc? Is it the only way to set className every time?
I could pass style prop to component, but it's CSS in JS so I think it becomes meaningless to use SASS.
How do others work with SASS in this kind of situation? I can't shift to Styled component now.
I would go with dynamic className and a prop size. Something like this:
const Button = ({ size, ... }) => {
[...]
return (
<button className={`button-${size}`}>
[...]
</button>
);
}
Button.propTypes = {
size: PropTypes.oneOf([
"small",
"regular",
"large",
]),
...
};
Button.defaultProps = {
size: "regular"
};
In you styles:
$buttonSizes: (
small: 300px,
regular: 400px,
large: 500px,
);
button {
#each $sizeName, $size in $buttonSizes {
&-#{$sizeName} {
width: $size;
}
}
}

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;

In React,How to make a page that contains two dynamic size components

If data in container A collapses(minimised), Component B should increase vertically in size and appear on full page. Similarly if Component B is collapsed,component A should increase.By default,both the components have equal screen space.
there are tons of ways to do this, you can check how flexbox in CSS works. it should not bee very react specific, All you need to do from react is to know which component is collapsed and which is to expanded.
In the parent component, you'll want to track which component is maximised. Then, pass a maximised prop to component A and component B, and let them set their CSS classes based on it. You could hide most of the content if you just want a mini version of the component.
Assuming you're using function components with hooks, it would look somewhat like this:
const Container = () => {
// Either "A", "B" or null (equal sizes)
const [componentMaximised, setComponentMaximised] = useState(null);
return (
<div className="container">
<A maximised={componentMaximised === "A"}/>
<B maximised={componentMaximised === "B"}/>
</div>
);
};
const A = props => {
return (
<div className={props.maximised ? "component component-maximised" : "component"}>
// ...
</div>
);
};
const B = props => {
return (
<div className={props.maximised ? "component component-maximised" : "component"}>
// ...
</div>
);
};
You'll also want to pass the setComponentMaximised function to each component as a prop if you want them to be able to have a button to maximise and minimise themselves.
For your CSS, use display: flex in combination with flex-grow to set how the items share the space:
.container {
height: 100vh; /* approx full height */
display: flex;
flex-flow: column nowrap;
}
.component {
flex-grow: 1;
overflow: hidden; /* prevent contents from spilling out of component */
}
.component-maximised {
flex-grow: 3;
}
Quick demo of this technique (try changing the classes manually in HTML)
https://codepen.io/gh102003/pen/MWKOQqE
You can use flex-grow: 0 if you just want the component to take up the space it needs.

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');
});

Resources