Mock hover state in Storybook? - storybook

I have a hover style in my component:
const style = css`
color: blue;
&:hover {
color: red;
}
`;
Can you mock this in Storybook so that it can be shown without having to manually hover over the component?

Since in Storybook you need to show the component hover appearance, rather than correctly simulate the hover related stuff,
the first option is to add a css class with the same style as :hover :
// scss
.component {
&:hover, &.__hover {
color: red;
}
}
// JSX (story)
const ComponentWithHover = () => <Component className="component __hover">Component with hover</Component>
the second one is to use this addon.

Related

Material-ui show pointer cursor when hovering over TextField

Material-ui/ReactJS newbie question. I'm trying to show a pointer cursor when hovering over a Material-ui TextField but having a difficult time doing so. It makes use of 'cursor: text' by default. I've been able to successfully change the textfield background color on hover but adding "cursor: pointer !important" does no good. I've tried making use of className, class, style (inline), but I'm certain I'm not doing something correctly. Material-ui has a demo illustrating how to change textfield styling on hover and focused at [https://codesandbox.io/s/p7uwn?file=/demo.js][1] where I have also tried changing the cursor to a pointer on hover but still no luck. Any assistance would be greatly appreciated.
import React from 'react';
import styled from 'styled-components';
import { TextField, NoSsr } from '#material-ui/core';
const StyledTextField = styled(TextField)`
label.Mui-focused {
color: green;
}
.MuiOutlinedInput-root {
fieldset {
border-color: red;
}
&:hover fieldset {
border-color: yellow;
cursor: pointer !important;
}
&.Mui-focused fieldset {
border-color: green;
}
}
`;
export default function GlobalClassName() {
return (
<NoSsr>
<StyledTextField label="Deterministic" variant="outlined" id="deterministic-outlined-input" />
</NoSsr>
);
}
Just a quick browser inspection gave the CSS component we need to target. It's
.MuiOutlinedInput-input
Just giving it a
cursor: pointer;
property will solve your problem.
Here is the code:
import React from 'react';
import styled from 'styled-components';
import { TextField, NoSsr } from '#material-ui/core';
const StyledTextField = styled(TextField)`
label.Mui-focused {
color: green;
}
.MuiOutlinedInput-input {
cursor: pointer;
}
.MuiOutlinedInput-root {
fieldset {
border-color: red;
}
&:hover fieldset {
border-color: blue;
cursor: pointer;
}
&.Mui-focused fieldset {
border-color: green;
}
}
`;
export default function GlobalClassName() {
return (
<NoSsr>
<StyledTextField label="Deterministic" variant="outlined" id="deterministic-outlined-input" />
</NoSsr>
);
}
Or just literally put cursor:pointer into its css, either in-line as <Component style={{cursor: 'pointer'}}> or <Component sx={{cursor: 'pointer'}}> or in its styled component css. This will automatically change your mouse onHover, and the top answer here is way over the top. Just add cursor: 'pointer' to the component's css.
Using
<TextField sx={{ cursor: 'pointer' }} />
did not work for me, instead, I needed to specify it as
<TextField sx={{ input: { cursor: 'pointer' } }}
which did affect the desired change.

How to test CSS hover in Enzyme - React

I am new To React testing with Enzyme and Jest, and I have this scenario to test:
When hover the ParentDiv, The Child div should change style to background-color: green and display: block.
But in testing, after simulate mouseenter event, none of the style is changed, they still background-color: red and display: none
This is a Class-based component
const Child = styled.div`
background-color: red;
display: none;
`;
const ParentDiv = styled.div`
&:hover {
${Child} {
background-color: green;
display: block;
}
}
`;
<ParentDiv>
<Child>
<p>{text}</p>
</Child>
</ParentDiv>
Test.js
it('Hover over ParentDiv should display the child', () => {
const Wrapper = mount(<MyComponent >);
const parent = Wrapper.find('ParentDiv');
const child = Wrapper.find('child');
expect(child).toHaveStyleRule('display', 'none');
expect(child).toHaveStyleRule('background-color', 'red');
parent.simulate('mouseenter');
// next two lines not working
// expect(child).toHaveStyleRule('display', 'block'); // expected display: block but received display: none
// expect(child).toHaveStyleRule('background-color', 'green');
});
In case anyone comes looking, the solution for this is to use the opts parameter in toHaveStyleRule.
so you need to use this:
expect(child).toHaveStyleRule('display', 'block', { modifier: ':hover' });
Here is a link to the docs: https://github.com/styled-components/jest-styled-components#tohavestylerule

react how to style : styled-dropdown-component

I am trying to change the color and the size of the DropdownMenu using the styled-components like the code below:
const DropdownCustom = styled.DropdownMenu`
font-family: sans-serif;
font-size: 1.3rem;
border: none;
border-radius: 5px;
background-color: red;
`;
Then I try to use it like this:
<Dropdown>
<button onClick={() => setState(!state)}>Create</button>
<DropdownCustom hidden={!state}>
<DropdownItem>Action</DropdownItem>
<DropdownItem>Another action</DropdownItem>
<DropdownItem>Something else here</DropdownItem>
</DropdownCustom>
</Dropdown>
But it gives me an error saying that _styledComponents.default.DropdownMenu is not a function.
I am very new to styling with css and it is very confusing, so any advice or guide would be really appreciated! :)
Edited
import {
Dropdown,
DropdownItem,
DropdownMenu
} from "styled-dropdown-component";
If you trying to style a custom component you need to use styled as a function:
const DropdownCustom = styled(DropdownMenu)`
font-family: ...
`;
It will work only if the custom component uses the className props.
Therefore, you sometimes want to style custom component's parent, and target the styling with selectors - as it's just a CSS:
const Wrapper = styled.div`
font-family: ...;
.dropDown {
....;
}
`;
<Wrapper>
<Dropdown />
</Wrapper>

How to properly overwrite existing className with emotionJS

I'm trying to use emotion to overwrite the styling of an existing React component from a 3rd party library.
I try my best to simplified the problem in this codesandbox
The ExternalLib simulates a 3rd party component I'm using which I should not change the code.
As you can see it accepts a "prefix" props for css namespace and uses className in static string.(the original one has it as sass variable also)
I first try to get the base className hash with css function, then I try to compose those in emotion way of composition, and I get the expected visual result.
const baseStyle = css`
background-color: blue;
width: 200px;
height: 200px;
`;
const getItemStyle = ({ disabled }) => {
return `
height: 50px;
margin: 4px;
background-color: ${disabled ? "gray" : "yellow"};
`;
};
const getTextStyle = ({ color }) => {
return `
color: ${color}
`;
};
const StyledExternalLib = styled(ExternalLib)`
.${baseStyle}-track {
${getItemStyle};
}
.${baseStyle}-text {
${getTextStyle};
}
`;
however inspecting the style tags, I got many duplicated styles, what am I doing wrong?
you can see there are twice the yellow background
Here what i found, use css prop to the parent tag
css={{
"& .class__youwant--overwrite": {
margin: 80
}
}}
Worked in my case

Apply same styling on multiple elements in component

const GreenRow = styled.div`
background-color: green;
`
const RedRow = styled.div`
background-color: red;
`
const YellowRow = styled.div`
background-color: yellow;
`
const GreyRow = styled.div`
background-color: grey;
`
const MyComponent = () =>
<div>
<GreenRow>Green row</GreenRow>
<div>Blue row</div>
<RedRow>Red row</RedRow>
<YellowRow>Yellow row</YellowRow>
<GreyRow>Grey row</GreyRow>
</div>
I'm using styled-components to style elements in a component.
I want to apply a repeated styling (e.g. font-weight) on some elements in a component. Some of these component are already styled with styled-component, so this would be some kind of "second dimension" styling.
For example, if I could define styling with a certain classname, I could then apply that classname to each of those elements. But as I've understood, styled-components don't return any classname. And I don't want to start defining styles in other files than the component itself.
Another thought is to render styling with styled-component's css library (see code below) and include it in every applicable styled-component definition. But then I would need to convert some elements to styled-components just for this purpose (as they aren't styled otherwise).
const FontWeight = css`
font-weight: 600;
`
What would be the most succinct way to apply this "second dimension" styling?
You can interpolate a function into the template literal, which gets passed the props of the component with ${props => props.component_name && css ... }.
In the following, I hook into Row and add some additional styling for Green:
import styled, { css } from styled-components
const Row = styled.div`
/* Generic row styling */
font-weight: 600;
/* Unique row styling */
${props => props.Green && css`
background: green;
`}
`
Note that you'll additionally need to import css!
Now all you have to do is render the row with the additional property when you want a green one:
render(
<div>
<Row>Normal Row</Row>
<Row Green>Green Row</Row>
</div>
);
The green row will inherit all of the styling of the regular rows, and also inherit the rules that are unique to that specific element.
Hope this helps!

Resources