how to use hover in objects in react - javascript

I defined a object useStyle and called it in the component SecondTest defined background color, is it possible to add hover in the object useStyle
const useStyle = {
backgroundColor: "red",
};
function SecondTest() {
return <div style={useStyle}>SecondTest go down</div>;
}
export default SecondTest;

You can use Radium React Library
import React from "react";
import Radium from "radium";
const style = {
color: "#000000",
":hover": {
color: "#ffffff"
}
};
const MyComponent = () => {
return <section style={style}>hello world</section>;
};
const MyStyledComponent = Radium(MyComponent);
export default function App() {
return (
<>
<MyStyledComponent />
</>
);
}

You can accomplish it with events like onMouseEnter & onMouseLeave if you wish to use javascript to solve your issue. Easier way to do it would be just to give an element className like
<section className='myClass'>hello world</section>
and then just to add desired properties in your .css file which you can import in your component or globally.
.myClass {
color: #000000;
}
.myClass:hover {
color: #ffffff;
}
It is not possible to add hover with in-line styles.

Related

Problem in higher order components in react

I'm learning how to use higher order components. There I want to highlight some text. In my code I can highlight the whole line by using <div>. The problem is I only want to highlight a part of the text. So I tried <span>. But when I use span the whole highlighting part doesn't work. Since it doesn't give any error I can't understand what where the error comes from.
HighlightedText.js
import React, { Component } from 'react';
import UpdatedComponent from './Hoc';
class HighlightedText extends Component {
render() {
return <h1>Highlighted Text</h1>
}
}
export default UpdatedComponent(HighlightedText);
Hoc.js
const UpdatedComponent = OriginalComponent => {
class NewComponent extends React.Component {
render() {
return(props) =>(
<div style={{ background: 'Yellow', padding: 2 }}>
<OriginalComponent {...props}/>
</div>
)
}
}
return NewComponent;
}
export default UpdatedComponent;
Issues
Your HOC looks to be trying to return a functional component from the render method of a class-based component.
Props aren't spread correctly.
padding: 2 may not be valid, it should probably provide a unit, whatever you need
Solution
To fix the highlighting I believe you just need to specify a display: inline-block; CSS rule to the div. Spread this.props from the class-based component to the wrapped component.
const updatedComponent = (OriginalComponent) => {
class NewComponent extends React.Component {
render() {
return (
<div
style={{
background: "Yellow",
padding: "1rem", // <-- provide unit, 1rem ~ 16px
display: "inline-block" // <-- inline-block display
}}
>
<OriginalComponent {...this.props} />
</div>
);
}
}
return NewComponent;
};
If you want to highlight just a part of the text, it requires modifying the virtual DOM tree returned by the original component, since you can't just easily wrap it like in your example. You might want to use react-string-replace to achieve this.

How do I reference a styled-component that is a functional component?

This is the most basic example I could think of:
import React from 'react';
import {
css,
} from 'styled-components';
const Foo = (props) => {
console.log(props);
const {
children,
} = props;
return <div {...props}>{children}</div>;
};
export default () => {
return <div
css={css`
${Foo} {
background: #f00;
}
`}
>
<Foo>FOO</Foo>
</div>;
};
In this example, I want to style Foo component that is a descendent of div.
I would expect the resulting markup to look something like:
<div class="test__Foo-wusfqk-0 hNfawX">FOO</div>
However, instead it is simply:
<div>FOO</div>
It seems like no styling is applied anywhere.
Furthermore, the component Foo is rendered only once, but it is invoked twice, with different parameters:
{children: {…}, theme: {…}}
children: {$$typeof: Symbol(react.element), key: null, ref: null, props: {…}, type: ƒ, …}
theme: {}
{children: "FOO"}
I should mention that I tried:
// #flow
import React from 'react';
import styled, {
css,
} from 'styled-components';
const Foo = styled((props) => {
const {
className,
children,
} = props;
return <div className={className}>{children}</div>;
});
export default () => {
return <div
css={css`
${Foo} {
background: #f00;
}
`}
>
<Foo>FOO</Foo>
</div>;
};
However, when executing this code in next.js I am getting the following error:
The component Styled(Component) with the id of "sc-dlnjPT" has been created dynamically.
You may see this warning because you've called styled inside another component.
To resolve this only create new StyledComponents outside of any render method and function component.
The component Styled(Component) with the id of "sc-hKFyIo" has been created dynamically.
You may see this warning because you've called styled inside another component.
To resolve this only create new StyledComponents outside of any render method and function component.
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
which does not make much sense given the subject code snippet.
The main issue is that <Foo /> is not a styled component its a functional component
I think you would need to do
const Foo = styled.div`
background: #f00;
`
Then you can change the style of Foo using css and the $ refrence
The reason your code does not work is the following
This behaviour is only supported within the context of Styled Components: attempting to mount B in the following example will fail because component Foo is an instance of React.Component not a Styled Component.
const Foo = () => <div> </div>
const B = styled.div`
${Foo} {
}
`
However, wrapping Foo in a styled() factory makes it eligible for interpolation -- just make sure the wrapped component passes along className.
const Foo = (props) => {
console.log(props);
const {
children,
} = props;
return <div className="Test-Class" {...props}>{children}</div>;
};
const StyledFoo = styled(Foo)``
const Main = styled.div`
${StyledFoo} {
background: #f00;
}
`
Code Sandbox
import { render } from "react-dom";
import React from "react";
import styled from "styled-components";
const Foo = (props) => {
const { className, children } = props;
return <div className={className}>{children}</div>;
};
const Bar = styled(Foo)``;
const Main = styled.div`
${Bar} {
background-color: #000;
color: #fff;
}
`;
const App = () => {
return (
<Main>
{" "}
<Bar>Hello </Bar>{" "}
</Main>
);
};
render(<App />, document.getElementById("root"));
https://codesandbox.io/s/styled-components-forked-5s201?file=/index.js

How to override style of nested Material UI component from the ancestors?

I am using a component from an external library that does not allow me to change much of its style, but I would like to change the style of a button that is a material ui button, when inspecting the element it clearly shows the classes MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit
how can I override the MuiIconButton-root style, for instance? this is my component:
class MyComponent extends Component {
render() {
const { classes } = this.props;
return (
<div className={classes.myComponent}>
<3rdPartyComponent />
</div>
);
}
}
export default withStyles(styles)(MyComponent)
I have tried declaring my styles function as follows, without success:
const styles = theme => ({
myComponent: {
"&.MuiIconButton-root": {
padding: "0px"
}
}
});
Can anybody help me? Thanks in advance.
Let's say that the class name generated for myComponent is myComponent-jss123. The selector you used in your styles (&.MuiIconButton-root) would be equivalent to .myComponent-jss123.MuiIconButton-root which would match any element that has both of these classes applied to it. I believe your intent was to match icon buttons which are descendants of the div on which you are applying the myComponent class. In this case you need to use the descendant combinator represented by a space, so the appropriate styles would look like the following:
const styles = theme => ({
myComponent: {
"& .MuiIconButton-root": {
padding: 0
}
}
});
Here's a full working example:
import React from "react";
import IconButton from "#material-ui/core/IconButton";
import DeleteIcon from "#material-ui/icons/Delete";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles({
myComponent: {
"& .MuiIconButton-root": {
padding: 0
}
}
});
const ThirdPartyComponent = () => {
return (
<div>
I'm a third party component that contains an IconButton:
<IconButton color="primary">
<DeleteIcon />
</IconButton>
</div>
);
};
export default function App() {
const classes = useStyles();
return (
<div className={classes.myComponent}>
<ThirdPartyComponent />
</div>
);
}
Related documentation:
https://cssinjs.org/jss-plugin-nested/?v=v10.0.4#use--to-reference-selector-of-the-parent-rule
https://developer.mozilla.org/en-US/docs/Web/CSS/Class_selectors
https://developer.mozilla.org/en-US/docs/Web/CSS/Descendant_combinator

Testing DOM in Enzyme

Let's say I have a tiny component like this:
Button.js
import React from 'react';
import './Button.css';
export default class Button extends React.Component {
render() {
return (
<a href={ this.props.url } className={`button button-${ this.props.type }`}>
{ this.props.content }
</a>
);
}
}
And there's some super basic styling like this:
Button.css
.button {
color: white;
padding: 1em;
border-radius: 5px;
text-decoration: none;
}
.button-primary {
background-color: red;
}
.button-primary:hover {
background-color: darkred
}
.button-secondary {
background-color: aqua;
color: black;
}
.button-secondary:hover {
background-color: darkcyan;
color: white;
}
And let's say I want to write some tests for this:
Button.test.js
import React from 'react';
import Enzyme, {shallow, mount} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({adapter: new Adapter()});
import Button from './Button';
import './Button.css';
// Render buttons
const primaryButton = mount(
<Button
content="Primary button"
url="http://www.amazon.co.uk"
type="primary"
/>
);
const secondaryButton = mount(
<Button
content="Secondary button"
url="http://www.ebay.co.uk"
type="secondary"
/>
);
it('should exist', () => {
expect(primaryButton).toBeDefined();
expect(secondaryButton).toBeDefined();
});
it('should display text in the button', () => {
expect(primaryButton.text()).toEqual('Primary button');
});
it('should have the correct CSS classes', () => {
expect(primaryButton.find('.button').hasClass('button-primary')).toEqual(true);
expect(secondaryButton.find('.button').hasClass('button-secondary')).toEqual(true);
});
I've set this up using react-create-app and all the above works perfectly.
My question is: how do I test that what is getting rendered looks correct? For example, in this case I would want to make sure that the buttons have the correct background colours defined in the CSS file and that they have the correct border radius. This will prevent other developers accidentally overriding critical styling for example.
I was under the impression that Enzyme did this out of the box, but I cannot understand how to interrogate the virtual DOM which I assume is happening in the background? I thought that JSDOM was automatically running and I'm executing this from the CLI which is a Node environment.
I've tried this so far:
it('should have the correct background colours', () => {
const domNode = primaryButton.find('.button').at(0).getDOMNode();
const background = getComputedStyle(domNode).getPropertyValue('background');
expect(background).toBe('red');
});
But background is returned blank, in fact if I do console.log(getComputedStyle(domNode)) I get this returned which seems to be missing the styles:
console.log src/modules/Button/Button.test.js:42
CSSStyleDeclaration {
_values: {},
_importants: {},
_length: 0,
_onChange: [Function] }
The getDOMNode of an enzyme wrapper gets you the corresponding DOM node.
You can then use getComputedStyle to get the style of that DOM:
const renderedComponent = mount(<MyComponent /);
const domNode = renderedComponent.find('div').at(0).getDOMNode();
const background = getComputedStyle(domNode).getPropertyValue('background');
expect(background).toBe('red');

Javascript react-jss hover not changing color

I am trying out React-Jss from cssinjs.org/react.jss and this is what I've done upto now:
Installation:
npm install --save react-jss
I then tested this file where I added a Hover to the footer just to give this a test:
import React from 'react';
import injectSheet from 'react-jss';
const style = {
Footer: {
backgroundColor: '#000000',
},
'&:hover': {
backgroundColor: '#ff0000',
}
};
export class Footer extends React.Component {
render() {
return (
<Footer>This is the footer</Footer>
);
}
}
export default injectSheet(style);
When I hover over the Footer component I would expect the footer to turn red but nothing is happening.
I'm I missing something or is something wrong in the syntax?
There's a handful of reasons the code above isn't working. There's issues with your React code beyond the JSS syntax.
In regards to the JSS style declaration specifically, let's first make sure you understand what you're declaring in the style object. The properties of the style object (in your case Footer, are the class names that you want to define and as such should probably be all lowercase. The value of each of those properties is an object containing the CSS styles that you want applied by that class. If you want to define a hover styles for a given class then you would declare those styles inside of the class's style object like so:
const style = {
footer: {
backgroundColor: '#000000',
'&:hover': {
backgroundColor: '#ff0000',
}
}
};
I suspect you're attempting to follow the first code example under 'Usage' in the package's readme. Here's a working example that follows that approach.
import React from 'react'
import injectSheet from 'react-jss'
const style = {
footer: {
backgroundColor: '#000000',
'&:hover': {
backgroundColor: '#ff0000'
}
}
}
const Footer = ({sheet}) => (
<div className={sheet.classes.footer}>This is the footer</div>
)
export default injectSheet(style)(Footer)
Below is a working example that utilizes the advantages of ES6 in case you're interested.
import React, {PropTypes} from 'react';
import injectSheet from 'react-jss';
const style = {
footer: {
backgroundColor: '#000000',
'&:hover': {
backgroundColor: '#ff0000'
}
}
};
#injectSheet(style)
export default class Footer extends React.Component {
static propTypes = {
sheet: PropTypes.object.isRequired
}
render() {
const {sheet} = this.props
return (
<div className={sheet.classes.footer}>This is the footer</div>
);
}
}

Categories

Resources