Assign two className to child - button

I have below code in my parent's component -
<Button className={'row1 column1'} value={'1'}/>
So I am sending two className to the child's component.
Then in my child component I have
render() {
var { value, className, ...other} = this.props;
return (
<button className={s[className]}> {value} </button>
)
}
}
export default withStyles(s)(Button);
usually I manually set className={s.something} and it works, but this is not. In rendered html it looks like - <button is="null"></button> Any idea?

Supposed you use react-with-style, withStyles will add a styles object to your props.
This object does not know any classNames, you just need to pass those styles to your button as inline styles.
e.g.:
render() {
var { value, className, style, ...other} = this.props;
return (
<button
className={ className }
style={ style }
>
{ value }
</button>
)
}
EDIT:
The advantage of withStyle is to use inline styles. And I suppose your s object does not have a key row1 column1 but rather row1 and column1, so you would need to manually split the classname.
But then again, why do you want the styles in the className?

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

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;

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.

Add a class to the parent .wp-block element in gutenberg editor

When Gutenberg creates a class, it seems to be of the format
div.wp-block
div.editor-block-list__insertion-point
div.editor-block-list__block-edit
div.editor-block-contextual-toolbar
div
<your actual block html goes here>
I'd like to be able to add a class to that top div.wp-block element so I can properly style my block in the editor. The class is dynamically generated based on an attribute so I can't just use the block name class. Is there a clean way of doing this? I can hack it using javascript DOM, but it gets overwritten quickly enough.
https://wordpress.org/gutenberg/handbook/designers-developers/developers/filters/block-filters/#editor-blocklistblock
const { createHigherOrderComponent } = wp.compose
const withCustomClassName = createHigherOrderComponent((BlockListBlock) => {
return props => {
return <BlockListBlock { ...props } className={ 'my-custom-class' } />
}
}, 'withCustomClassName')
wp.hooks.addFilter('editor.BlockListBlock', 'my-plugin/with-custom-class-name', withCustomClassName)
You can add class in your block edit view by using className that is present in this.props, className will print class in following format wp-blocks-[block_name]
edit( { className } ) { // using destructing from JavaScript ES-6
return <div className={ className }></div>
}
Suggestion
Always try to look for manipulating DOM via React instead of manipulating DOM directly because React manages it's own state and issues can occur by manipulating DOM directly.

How to style input tag without class with JSS

I am using the react-select component on my app. I am also only styling my app with JSS. My issue is that since react-select is an npm package, I don't have the capability to modify class names in the component. So there is an input in there that I need to target with my styles.
<div class="Select-input"><input type="text" name="style-me" /></div>
And my JSS is a little something like this:
jss.setup(preset());
const stylus = {
'Select-input': {
background: 'red'
}
}
const { classes } = jss.createStyleSheet(stylus).attach();
What do I need to do in JSS to style that child input tag?
According to this answer, you can pass in a class name for react-select. The rest of my answer shows how to target child elements.
I checked the github page for JSS here:
https://github.com/cssinjs/jss
They have a live example for nested CSS rules here:
https://github.com/cssinjs/examples/blob/gh-pages/plugins/jss-nested/simple/app.js
In the code to target a nested <button> element, it uses a property named & button. Notice the space between the ampersand and button. So for your specific code, you can target the <input> like this:
jss.setup(preset());
const stylus = {
'Select-input': {
background: 'red',
'& input': {
/* your input styles here */
}
}
}
const { classes } = jss.createStyleSheet(stylus).attach();
Assuming you're referring to this package:
https://github.com/JedWatson/react-select
You can in fact pass in className as a prop
You have always at least 2 ways:
Pass the generated class name
Use JSS as you should by default, avoid unscoped class names. Use generated class name and pass it to the component you want to use
const {classes} = jss.createStyleSheet({
input: {background: 'red'}
}).attach()
<Input className={classes.input} />
Use scoped global selector
If its impossible to pass a class name, you can still have a locally scoped global selector
const {classes} = jss.createStyleSheet({
container: {
'#global': {
input: {background: 'red'}
}
}
}).attach()
<div className={classes.container}>
<Input />
</div>

Resources