MDL - ripple effect changes margin on some elements - css

I'm using react with mdl and I want to create a menu with a drawer, and I'm pretty happy with the result, except one thing, when there is a scroller on the menu and I click on a menu item there is a ripple effect that sometimes makes the other menu items move a bit:
I don't know what is going on, here is my menu item component:
import React from 'react'
export default class MenuItem extends React.Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick() {
this.props.onClick(this.props.id);
}
render () {
let liClassNames = this.props.isSelected ? 'menuItemSelected' : 'menuItemNotSelected';
return (
<div className={'mdl-list__item mdl-button mdl-js-button mdl-js-ripple-effect menuItem ' + liClassNames} onClick={this.onClick}>
<span className='mdl-list__item-primary-content'>
<i className={'material-icons menuItemIcon md-28'}>{this.props.icon}</i>
<span>{this.props.screenName}</span>
</span>
</div>
)
}
}
React.propTypes = {
id: React.PropTypes.number.isRequired,
screenName: React.PropTypes.string.isRequired,
icon: React.PropTypes.string.isRequired,
isSelected: React.PropTypes.bool.isRequired,
onClick: React.PropTypes.func.isRequired
};
Menu:
import React from 'react';
import MenuItem from './MenuItem';
export default class Menu extends React.Component {
constructor(props) {
super(props);
this.state = {
isMaximized: true,
selectedMenuItem: this.props.modules[0].screens[0].id
};
this.handleMenuToggle = this.handleMenuToggle.bind(this);
this.onMenuItemClick = this.onMenuItemClick.bind(this);
}
handleMenuToggle() {
this.setState({ isMaximized: !this.state.isMaximized });
}
onMenuItemClick(screenId) {
this.setState({ selectedMenuItem: screenId });
}
render () {
let drawerClassNames = this.state.isMaximized ? 'drawerMaximized' : 'drawerMinimized';
return (
<div className='mdl-js-layout mdl-layout--fixed-drawer'>
<div className={'mdl-layout__drawer drawer scrollbar ' + drawerClassNames }>
<ul className='demo-list-item mdl-list content'>
{this.props.modules.map((module, index) =>
<li key={index}>
<span className="mdl-layout-title menuHeader">{module.moduleName}</span>
{module.screens.map((screen) =>
<MenuItem key={screen.id}
id={screen.id}
screenName={screen.screenName}
icon={screen.icon}
isSelected={ screen.id === this.state.selectedMenuItem ? true : false }
onClick={this.onMenuItemClick}/>
)}
</li>)}
</ul>
</div>
</div>
);
}
}
Menu.propTypes = {
modules: React.PropTypes.arrayOf(
React.PropTypes.shape({
moduleName: React.PropTypes.string.isRequired,
id: React.PropTypes.number.isRequired,
screens: React.PropTypes.arrayOf(
React.PropTypes.shape({
id: React.PropTypes.number.isRequired,
screenName: React.PropTypes.string.isRequired,
icon: React.PropTypes.string.isRequired
})
).isRequired
}
)
).isRequired
}
When I remove the ripple effect from the li tag, (mdl-js-ripple-effect class) it works fine.
What is the problem here?

Related

How to pass props into a Stencil child component in Storybook?

I have two Stencil components. MyCard and MyButton.
MyButton.tsx
import { Component, h, Prop } from '#stencil/core';
#Component({
tag: 'my-button',
styleUrl: 'my-button.css',
shadow: true,
})
export class MyButton {
#Prop() label: string;
render() {
return (
<div>
<button>
{this.label}
</button>
</div>
);
}
}
MyButton.stories.ts
const Template = (args) => `<my-button label="${args.label}"></my-button>`;
export const Example = Template.bind({});
Example.args = {
label: 'my custom button'
}
MyCard.tsx
import { Component, h, Prop } from '#stencil/core';
#Component({
tag: 'my-card',
styleUrls: ['my-card.scss'],
shadow: true,
})
export class MyCard {
render() {
return (
<div>
<div>
<my-button></my-button>
</div>
</div>
)
}
}
MyCard.stories.ts
const MyCardDefault = (args) => (
`<my-card>
<my-button label="${args.label}"></my-button>
</my-card>`
)
export const CardExample = MyCardDefault.bind({});
CardExample.args = {
label: "CardButton"
}
If I open the MyButton component in Storybook, the args are properly passed, and the label is applied to the button, but when I open the MyCard component, the button innerHTML is empty. The props are not passed. Why? How do I pass props to a nested child component in Stencil?
I don't know Storybook, but your MyCard component does not have any properties and does not set any properties on it's my-button element, so binding a label to the card won't do anything because MyCard doesn't use the label. I think you need:
export class MyCard {
#Prop() label: string;
render() {
return (
<div>
<div>
<my-button label={this.label}></my-button>
</div>
</div>
)
}
}

How to apply user defined style(CSS) to React-Treebeard?

I'm working with treebeard in my react project.
when I try to add a user-defined style it's not getting applied to the container.
I have tried different methods to achieve this.
I tried to define the style from tag, tried to define style.css in a different file, import it and assign it to style in Treedeard tag.
the main goal is to change the background color and the position.
Here is my code:
workspace.jsx
import React from "react";
import {Treebeard} from 'react-treebeard';
import data from "./data";
export class WorkSpace extends React. Component {
constructor(props){
super(props);
this.state = {
data: {data}
};
this.onToggle = this.onToggle.bind(this);
const decorators = {
Container: (props) => {
return (
<div style={props.backgroundColor="yellow"}>
</div>
);
}
};
}
onToggle(node, toggled){
const {cursor, data} = this.state.data;
if (cursor) {
this.setState(() => ({cursor, active: false}));
}
node.active = true;
if (node.children) {
node.toggled = toggled;
}
this.setState(() => ({cursor: node, data: Object.assign({}, data)}));
}
render() {
return (
<div className="base_container">
<h3>Select Component</h3>
<div className="components">
<Treebeard
data={data}
onToggle={this.onToggle}
style = {style_components}
decorators={this.decorators}
/>
</div>
</div>
);
}
}

Issue in displaying submenu on hover

I am making a reactjs application with reactstrap where I have made a dropdown which consists of sub menus inside it.
I am trying to achieve the result of making the submenus display on hover over the dropdown and if there is n numbers of dropdown then the submenus related with the hover item needs to be displayed.
Code tried:
<Dropdown
className="d-inline-block"
onMouseOver={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}
isOpen={this.state.dropdownOpen}
toggle={this.toggle}
>
<DropdownToggle caret>Dropdown1</DropdownToggle>
<DropdownMenu>
<DropdownItem header>Submenu 1</DropdownItem>
<DropdownItem>Submenu 1.1</DropdownItem>
</DropdownMenu>
<DropdownToggle caret>Dropdown2</DropdownToggle>
<DropdownMenu>
<DropdownItem header>Submenu 2</DropdownItem>
<DropdownItem>Submenu 2.1</DropdownItem>
<DropdownItem>Submenu 2.2</DropdownItem>
</DropdownMenu>
<br />
<br />
<DropdownToggle caret>Dropdown3</DropdownToggle>
<DropdownMenu>
<DropdownItem header>Submenu 3</DropdownItem>
<DropdownItem>Submenu 3.1</DropdownItem>
<DropdownItem>Submenu 3.2</DropdownItem>
<DropdownItem>Submenu 3.3</DropdownItem>
</DropdownMenu>
</Dropdown>
Click here for working demo
Expected Result: http://supply.com/
In the above given link you could able to see the horizontal menu which on hover will display their respective submenu and I am in the need to achieve the same behaviour.
You need to separate those menus and put in a single <Dropdown> component.
And you need to set an event handler for each of them.
You may use Array.prototype.map to simplify setting handlers.
import React from "react";
import {
Dropdown,
DropdownToggle,
DropdownMenu,
DropdownItem
} from "reactstrap";
export default class Example extends React.Component {
constructor(props) {
super(props);
this.onMouseEnter = this.onMouseEnter.bind(this);
this.onMouseLeave = this.onMouseLeave.bind(this);
this.state = {
dropdownOpen: -1
};
this.toggle = this.toggle.bind(this);
this.menus = [
{
title: "Bathroom",
submenus: [{ title: "Toilets" }, { title: "Toilet seats" }]
},
{
title: "Kitchen",
submenus: [{ title: "Farmhouse Sinks" }, { title: "Cast Iron Sinks" }]
}
];
}
onMouseEnter(current) {
this.setState({ dropdownOpen: current });
}
onMouseLeave() {
this.setState({ dropdownOpen: -1 });
}
toggle() {}
render() {
return (
<div>
{this.menus.map((menu, i) => (
<Dropdown
className="d-inline-block"
onMouseOver={e => this.onMouseEnter(i)}
onMouseLeave={this.onMouseLeave}
isOpen={this.state.dropdownOpen === i}
toggle={this.toggle}
>
<DropdownToggle caret>{menu.title}</DropdownToggle>
<DropdownMenu>
{menu.submenus.map((submenu, i) => (
<DropdownItem header>{submenu.title}</DropdownItem>
))}
</DropdownMenu>
</Dropdown>
))}
</div>
);
}
}
stackblitz: https://stackblitz.com/edit/reactstrap-v6-qsffjj

ReactJs changing css property onclick

I made a variable that has the style which I would want the input box to change to when it is clicked on.
How can I implement it so that when the input box is clicked, the border color of the input box changes to blue, considering that CSS, styles and everything else are imported?
const inputStyle = css
border-color: blue;
;
const InputBox = styled.input
myClick: function () {
inputstyle
}
;
render() {
return (
<InputBox
placeholder='Click Me'
type='text'
onClick={this.myClick}
/>
styled.foo doesn't return a class component, so writing methods as if they're on a class in the template string won't work.
Since you're handling something stateful (was this thing clicked?) you need to have some place to put that state. Then you can pass that state to the InputBox component:
const InputBox = styled.input`
border-color: ${({ clicked }) => clicked ? 'blue' : 'transparent'};
`
class Parent extends React.Component {
constructor (props) {
this.state = { clicked: false }
}
handleClick () {
this.setState({ clicked: true })
}
render () {
return (
<InputBox
placeholder="Click Me"
type="text"
clicked={this.state.clicked}
onClick={this.handleClick}
/>
)
}
}
I'd suggest checking out the "Passed Props" section of the styled-components docs.
you can do this :
const Styles = {
inputNormal:{color:'blue'},
inputClicked:{color:'red'}
}
class Parent extends React.Component {
constructor (props) {
this.state = { clicked: false }
}
handleClick () {
this.setState({ clicked: true })
}
render () {
return (
<InputBox
placeholder="Click Me"
type="text"
style={this.state.clicked?styles.inputNormal:styles.inputClicked}
onClick={this.handleClick}
/>
)}}
You should add styles with variables like this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
clicked: false
};
}
myClick = () => {
this.setState({
clicked: true
});
};
render() {
const inputStyle = {
borderColor: "blue"
};
return (
<input
placeholder="Click Me"
type="text"
onClick={this.myClick}
style={this.state.clicked ? inputStyle : null}
/>
);
}
}
Here is a working demo:
DEMO

Access Event Of Component That Is Passed As Prop

I pass a React Component as a Prop to a child.
That component has an event.
In child component, I want to get access to that event and bind it to a method inside child. How can I do that ?
I often use Semantic-UI React Modal as following:
class Example extends Component {
constructor(props) {
super(props);
this.state = {
modalOpen: false
}
}
handleOpen = () => this.setState({ modalOpen: true })
handleClose = () => this.setState({ modalOpen: false })
render(){
return(
<Modal
onClose={this.handleClose}
open={this.state.modalOpen}
trigger={<Button onClick={this.handleOpen}>Gandalf</Button>}>
<Modal.Header>Balrog</Modal.Header>
<Modal.Content>
<h1>You shall not pass!</h1>
{/*
Some form that closes Modal on success
onSuccess : this.handleClose
*/}
<Button onClick={this.handleClose}>Grrrrr</Button>
</Modal.Content>
</Modal>
)
}
}
export default Example
Now I want to make it reusable
import React, { Component } from 'react'
import { Modal } from 'semantic-ui-react'
class ReusableModal extends Component {
constructor(props) {
super(props);
this.state = {
modalOpen: false
}
}
handleOpen = () => this.setState({ modalOpen: true })
handleClose = () => this.setState({ modalOpen: false })
render(){
return(
<Modal
onClose={() => this.handleClose}
open={this.state.modalOpen}
{/*
How to access onClick event on trigger prop content ?
this.prop.trigger can be a Button or a Menu.Item
*/}
{...this.props}>
{this.props.children}
</Modal>
)
}
}
How can I have access to the trigger prop Component and bind its onClick event to handleOpen method ?
Edit :
to be more precise here is what I'm looking for
<ChildComponent trigger={<Button>This button should fire a function defined in child component</Button>} />
ChildComponent extends Component {
functionToCall = () => { console.log('hello') }
// I would like to :
// let myButton = this.props.trigger
// myButton.onClick = functionToCall
}
In React, data flows from parent to child. If there are multiple child components that have events that need to trigger changes in parent component you must fire callback function in child component.
Parent component:
handleOpen = () => { // do something }
(...)
<childComponent onClickCallback={this.handleOpen}
And in child component:
<button onClick={this.props.onClickCallback}> Click to close</button>
Pass this.handleOpen as a prop and call it as a prop in child component, and it will trigger function in the parent component, where you can handle data however you want.
Is this what you asked for?
The key here is to clone element
ChildComponent extends Component {
functionToCall = () => { console.log('hello') }
this.Trigger = React.cloneElement(
this.props.trigger,
{ onClick: this.functionToCall }
)
}

Resources