Issue in displaying submenu on hover - css

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

Related

MUI Typography color change on selection

I'm trying to change styling of Typography component embedded inside MenuItem. I'm unable to add styling on ListItem but unable to do so
Here is the link to my code: https://codesandbox.io/s/dztbc?file=/demo.tsx:1481-1804
Expected behavior: Change styling when selected. Color of Access should turn green and fontWeight bolder on selection
Current behavior: Styling only getting applied to 'light mail' when selected. How can I resolve it?
MenuItem accepts a style rule for the selected item as in classes prop by the key name selected. But for this to work item should also receive a boolean select prop, whether the item is selected or not.
const StyledMenuItem = withStyles((theme) => ({
root: {
"&:focus": {
backgroundColor: theme.palette.primary.main,
},
},
selected: {
color: "red",
}
}))(MenuItem);
export default function CustomizedMenus() {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const [selected, setSelected] = React.useState(null);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const handleMenuItemClick = (e, index) => {
setSelected(index);
};
const menuArr = [
{
Icon: SendIcon,
text: "Sent mail"
},
{
Icon: DraftsIcon,
text: "Sent mail"
},
{
Icon: InboxIcon,
text: "Inbox"
}
];
return (
<div>
<Button
aria-controls="customized-menu"
aria-haspopup="true"
variant="contained"
color="primary"
onClick={handleClick}
>
Open Menu
</Button>
<StyledMenu
id="customized-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
{menuArr.map((item, index) => (
<StyledMenuItem
selected={index === selected}
onClick={(event) => handleMenuItemClick(event, index)}
>
<ListItemIcon>
<item.Icon fontSize="small" />
</ListItemIcon>
<ListItemText primary={item.text} />
</StyledMenuItem>
))}
</StyledMenu>
</div>
);
}
Here is a working demo:

How to remove drop down menu in Transfer ant-design?

I want to use Transfer Component from antd but I don't need the drop down menu as you can see in the below picture . How can I remove it?
It looks like the only way is through css selection since the component API doesn't have any control over it via props. Put below code in your css file:
span.ant-transfer-list-header-dropdown {
display: none;
}
DEMO
EDIT
It's possible to "change" the menu options by setting the selectAllLabels props of the component but you'd have to build the dropdown menu yourself. You'll still have to hide their header dropdown in CSS since you're replacing their menu with your own menu.
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Transfer, Dropdown, Menu, Space, Button } from "antd";
import { DownOutlined } from "#ant-design/icons";
const mockData = [];
for (let i = 0; i < 20; i++) {
mockData.push({
key: i.toString(),
title: `content${i + 1}`,
description: `description of content${i + 1}`
});
}
const initialTargetKeys = mockData
.filter((item) => +item.key > 10)
.map((item) => item.key);
const App = () => {
const [targetKeys, setTargetKeys] = useState(initialTargetKeys);
const [selectedKeys, setSelectedKeys] = useState([]);
const onChange = (nextTargetKeys, direction, moveKeys) => {
console.log("targetKeys:", nextTargetKeys);
console.log("direction:", direction);
console.log("moveKeys:", moveKeys);
setTargetKeys(nextTargetKeys);
};
const onSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
console.log("sourceSelectedKeys:", sourceSelectedKeys);
console.log("targetSelectedKeys:", targetSelectedKeys);
setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
};
const onScroll = (direction, e) => {
console.log("direction:", direction);
console.log("target:", e.target);
};
const leftLabel = ({ selectedCount, totalCount }) => (
<Space size={5}>
<Dropdown
placement="bottomLeft"
overlay={
<Menu>
<Menu.Item>
<a>Option 1</a>
</Menu.Item>
<Menu.Item>
<a>Option 2</a>
</Menu.Item>
<Menu.Item>
<a>Option 3</a>
</Menu.Item>
</Menu>
}
>
<DownOutlined style={{ fontSize: 11 }} />
</Dropdown>
{selectedCount > 0 ? `${selectedCount}/${totalCount}` : totalCount} items
</Space>
);
const rightLabel = ({ selectedCount, totalCount }) => (
<Space size={5}>
<Dropdown
placement="bottomLeft"
overlay={
<Menu>
<Menu.Item>
<a>Option A</a>
</Menu.Item>
<Menu.Item>
<a>Option B</a>
</Menu.Item>
<Menu.Item>
<a>Option C</a>
</Menu.Item>
</Menu>
}
>
<DownOutlined style={{ fontSize: 11 }} />
</Dropdown>
{selectedCount > 0 ? `${selectedCount}/${totalCount}` : totalCount} items
</Space>
);
return (
<Transfer
dataSource={mockData}
titles={["Source", "Target"]}
targetKeys={targetKeys}
selectedKeys={selectedKeys}
onChange={onChange}
onSelectChange={onSelectChange}
onScroll={onScroll}
render={(item) => item.title}
selectAllLabels={[leftLabel, rightLabel]}
/>
);
};
ReactDOM.render(<App />, document.getElementById("container"));
DEMO

How to set Select component in Material-UI to loose its focus state after selecting one of its item

Expected behavior:
After selecting an item, Menu list will be close immediately and Select component loses its focus state with borderBottom become 1px solid and backgroundColor become white.
Current behavior:
Select behavior after selecting an item
As shown in the image above, the borderBottom is 2px solid and the backgroundColor isn't white which are indicating the Select component is in a focus state.
What should I do to achive the expected behavior?
Additional Explanation:
Actually what annoys me is the focus appearance of the Select component, not the focus itself, What I want is the behavior like in fonts.google.com. After selecting a style (e.g. Bold 700), yeah the Select component still in focus state but it doesn't show any sign of focus and that is what I actually want.
Below is an example showing how to customize the focus appearance of Select.
You can find some explanation about the underline customization in my answer here: How do I custom style the underline of Material-UI without using theme?
import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "#material-ui/core/styles";
import Input from "#material-ui/core/Input";
import InputLabel from "#material-ui/core/InputLabel";
import MenuItem from "#material-ui/core/MenuItem";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
const styles = theme => ({
formControl: {
margin: theme.spacing.unit,
minWidth: 120
},
select: {
"&:focus": {
backgroundColor: "white"
}
},
selectInput: {
"&:hover:not($disabled):not($focused):not($error):before": {
borderBottomWidth: 1
},
"&:after": {
borderBottomWidth: 1
}
},
disabled: {},
focused: {},
error: {}
});
class SimpleSelect extends React.Component {
state = {
age: ""
};
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
};
render() {
const { classes } = this.props;
const selectInputClasses = {
root: classes.selectInput,
disabled: classes.disabled,
focused: classes.focused,
error: classes.error
};
return (
<FormControl className={classes.formControl}>
<InputLabel htmlFor="age-simple">Age</InputLabel>
<Select
value={this.state.age}
onChange={this.handleChange}
input={<Input classes={selectInputClasses} />}
inputProps={{
name: "age",
id: "age-simple",
classes: { select: classes.select }
}}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
);
}
}
SimpleSelect.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(SimpleSelect);
I don't know if I've understood the question correctly, but I think you can solve this using refs, as the React docs state:
[...] Managing focus, text selection, or media playback.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.selector= React.createRef();
}
render() {
return <Selector ref={this.selector}>[...]</Selector>;
}
}
Then you can access the element itself by doing this.selector.current, and you can set (or unset) it's focus by doing this.selector.current.focus() or this.selector.current.blur() on Selector's element click. If what you want to do is to focus another element on click, you should get the ref for the element you want to focus and do it the same way.
I hope this is what you needed!
You can use this trick to force Select to lose its focus:
<>
<InputLabel
id="CUSTOM_TITLE"
shrink
>
{ANY_TITLE}
</InputLabel>
<Select
ref={YOUR_SELECT_REF}
input={<OutlinedInput notched label="ANY_TITLE" />}
labelId="CUSTOM_TITLE"
onClose={() => {
ref.current.classList.remove('Mui-focused');
ref.current.previousSibling?.classList.remove('Mui-focused');
}}
onOpen={() => {
ref.current.classList?.add('Mui-focused');
ref.current.previousSibling?.classList.add('Mui-focused');
}}
>
{props.children}
</Select>
</>

Semantic UI React, How to programatically select value in Dropdown?

I want to clear dropdown inside a form, when a user clicks reset button.
But can't figure out how to programatically set value.
SUIR uses declarative API. You need to use HOC for controlling Dropdown's value.
I've made a basic example that shows how to deal with it.
const {
Button,
Container,
Divider,
Dropdown,
Label,
} = semanticUIReact
const options = [
{ value: 'all', text: 'All' },
{ value: 'articles', text: 'Articles' },
{ value: 'products', text: 'Products' },
]
class App extends React.Component {
constructor(props) {
super(props);
this.state = { value: 'all' }
}
reset() {
this.setState({ value: undefined })
}
setProducts() {
this.setState({ value: 'products' })
}
setValue(e, data) {
this.setState({ value: data.value })
}
render() {
const { value } = this.state
return (
<Container>
<Label content={`Current: ${value}`} />
<Divider />
<Dropdown
onChange={this.setValue.bind(this)}
options={options}
selection
value={value}
/>
<Divider />
<Button
content='Reset'
onClick={this.reset.bind(this)}
/>
<Button
content='Set products'
onClick={this.setProducts.bind(this)}
/>
</Container>
)
}
}
// ----------------------------------------
// Render to DOM
// ----------------------------------------
const mountNode = document.createElement('div')
document.body.appendChild(mountNode)
ReactDOM.render(<App />, mountNode)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
<script src="https://unpkg.com/semantic-ui-react/dist/umd/semantic-ui-react.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.4/semantic.min.css">
Difficult without seeing your code, try setting 'value': []

MDL - ripple effect changes margin on some elements

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?

Resources