I have been looking to implement Material-UI in my React ES6 project. As I have been trying things in a sandbox, I noticed a pretty significant styling quirk on the RaisedButton component. When hovering at times there is either a line at the top or bottom of the button where the hover effect doesn't completely overlap the button. The behavior changes when I override the margins. For instance when I have 8px margins the plain button has no line. When I add 6px margins the button has a line at the top. When I have a 4px margin it has a line at the bottom. This behavior changes also when there's different components next to each other in the HTML.
I am using Source Sans instead of Roboto, but switching back to Roboto has the same behavior. Likewise, keeping text-transform as uppercase instead of none has the same behavior.
I have tried wrapping the button in a div and applying margin or padding to that with the same result.
I am on the latest Chrome on Mac OSX 10.11.3.
Thanks in advance for your help.
I am wrapping the button in a custom class to allow consistent style overrides. Here's my wrappers:
Button Wrapper
...
let customTheme = ThemeManager.getMuiTheme(CustomTheme)
customTheme.button.textTransform = 'none'
const styles = {
button: {
margin: 8
}
}
#ThemeDecorator(customTheme)
class Button extends React.Component {
render() {
return (
<div className="c-button" style={{ display: 'inline-block' }}>
<RaisedButton
style={ styles.button }
label={ this.props.label }
onClick={ this.props.onClick }
primary={ this.props.primary }/>
</div>
)
}
}
...
Modal Wrapper
...
render() {
const actions = [
<Button
label="Cancel"
onClick={ this.props.handleClose } />,
<Button
label="Submit"
primary={ true }
onClick={ this.props.handleClose } />
]
return (
<Dialog
title="Dialog With Actions"
actions={ actions }
open={ this.props.open } >
Only actions can close this dialog.
</Dialog>
)
}
...
Plain RaisedButton by itself
...
<ul>
<li>
<h4>Plain Button</h4>
<Button label="Button" onClick={this.handleClick}/>
</li>
</ul>
...
Plain RaisedButton for Modal
...
<li>
<h4>Plain Modal</h4>
<Button label="Modal Dialog" onClick={ this.handleOpen } />
<Modal
open={ this.state.open }
handleClose={ this.handleClose }
handleOpen={ this.handleOpen } />
</li>
...
I'm hovering my mouse over the buttons in these screenshots. The only difference is the override of the margin in the first one to be 8px.
Related
I have this component:
const App = () => {
const [isModalVisible, setIsModalVisible] = useState(false);
const showModal = () => {
setIsModalVisible(true);
};
const handleOk = () => {
setIsModalVisible(false);
};
const handleCancel = () => {
setIsModalVisible(false);
};
return (
<>
<Button type="primary" onClick={showModal}>
Open Modal
</Button>
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
>
<DatePicker
onChange={test}
open={true}
showNow={false}
dateRender={(current) => {
const style = {};
if (arr.includes(current)) {
style.border = "1px solid red";
style.borderRadius = "50%";
}
return (
<div className="ant-picker-cell-inner" style={style}>
{current.date()}
</div>
);
}}
/>
</Modal>
</>
);
};
When i open the modal i get the calendar outside it. How to put the calendar inside the modal window, not outside like now?
demo: https://codesandbox.io/s/basic-antd494-forked-6lkqg?file=/index.js:269-1303
This is, IMO, incredibly hackish, but was the only way I could get the date picker's popup to behave a bit more nicely nested in a modal.
Use the getPopupContainer prop to specify what the parent should be, it defaults to "body". We can create our own element to append the date popup to.
Use the popupStyle prop to override and set the position CSS rule. It is position: absolute by default, we wan't relative positioning.
Add an empty div after DatePicker for the popup to attach to.
HACK ALERT: DatePicker inserts a div between the one we created and the popup, so CSS rule cascading & inheritance gets fubar'd, it has position: absolute as well. We need to override this to also use relative positioning.
Code:
<>
<Button type="primary" onClick={showModal}>
Open Modal
</Button>
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
>
<DatePicker
getPopupContainer={() => document.getElementById("date-popup")}
popupStyle={{
position: "relative"
}}
onChange={test}
open={true}
showNow={false}
dateRender={(current) => {
const style = {};
if (arr.includes(current)) {
style.border = "1px solid red";
style.borderRadius = "50%";
}
return (
<div className="ant-picker-cell-inner" style={style}>
{current.date()}
</div>
);
}}
/>
<div id="date-popup" />
</Modal>
</>
CSS
#date-popup > div {
position: relative !important;
}
The main reason this is hackish is because the use of !important should generally be avoided and instead you should strive to increase a selector's specificity. I was unable to bump it enough to override the style. (I believe this is because that div is also using some inline style prop/attribute)
DatePicker itself is also a kind of Modal so it can't be embedded inside Modal. You can simply check this by inspecting both Modal and DatePicker components.
If you want the DatePicker to be opened, you can control the height of modal body. Something like this.
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
bodyStyle={{
height: 400
}}
>
Here is another suggestion:
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
centered
style={{ minHeight: `500px` }}
>
I'm working on a React front-end that uses Reactstrap, in which I'm creating my own reusable modal component. Whenever there is too much content for the modal, it becomes scrollable and to make that clear to the user, I created an indicator at the bottom of the modal. (example screenshot)
The indicator sticks at the bottom of the modal while scrolling and I make it disappear when the user reaches the end (check onscroll event and moreContent state in code below).
So far so good, but my problem is that I can't find a way to check if I initially have to show the indicator when rendering the modal. Right now the moreContent state is initially set to true, but that should depend on whether the modal is scrollable or not.
I tried:
to find an event like onScroll that fires when Modal is rendered so that I can check if event.target.scrollHeight == event.target.clientHeight
useEffect hook with a reference to the modal. This fires too soon because scrollHeight and clientHeight are still 0.
The code for my modal component:
import React, {useEffect, useState} from 'react';
import {Button, Modal, ModalBody, ModalHeader} from "reactstrap";
const MyModal = (props) => {
const [moreContent, setMoreContent] = useState(true);
const ref = React.useRef();
useEffect(() => {
console.log("scrollHeight", ref.current._element.scrollHeight);
console.log("scrollTop", ref.current._element.scrollTop);
console.log("clientHeight", ref.current._element.clientHeight);
});
const onScroll = (event) => {
if (moreContent) {
setMoreContent(event.target.scrollHeight - event.target.scrollTop !== event.target.clientHeight);
}
}
return (
<Modal isOpen={props.isOpen} toggle={props.closeHandler} centered={true} scrollable={true} className="my-modal" onScroll={onScroll} ref={ref}>
<ModalHeader tag="div" toggle={props.closeHandler}>
...
</ModalHeader>
<ModalBody>
{props.children}
{moreContent &&
<div className="modal-scroll-down">
<i className="fa fa-arrow-down mr-4"></i> MEER <i className="fa fa-arrow-down ml-4"></i>
</div>
}
</ModalBody>
</Modal>
)
};
MyModal.defaultProps = {
showCloseButton : true
}
export default MyModal;
Any tip, advice, workaround is welcome.
Thanks in advance!
The issue here is that you are attaching ref to a Modal which is not a DOM element and therefore will not have these properties scrollHeight, scrollTop, and clientHeight. Furthermore even if it was a DOM element, it is not the element with the scrollbar - it is actually ModalBody. But, to make matters worst, it looks like Reactstrap does not really expose a prop for you attach a forwarded ref to the ModalBody.
To solve this you can replace ModalBody with a div - this is where we can attach a ref to.
<Modal
isOpen={props.isOpen}
toggle={props.closeHandler}
centered={true}
scrollable={true}
className="my-modal"
onScroll={onScroll}
onOpened={onOpened}
>
<ModalHeader tag="div" toggle={props.closeHandler}>
modal header
</ModalHeader>
<div ref={ref} style={{ overflowY: "auto", padding: "16px" }}>
{props.children}
{moreContent && (
<div className="modal-scroll-down">
<i className="fa fa-arrow-down mr-4"></i> MEER{" "}
<i className="fa fa-arrow-down ml-4"></i>
</div>
)}
</div>
</Modal>
Pay attention to the onOpened prop I attached to <Modal>, this answers what you sought:
execute javascript after bootstrap modal is completely rendered and
visible
const onOpened = () => {
setMoreContent(
ref.current.scrollHeight - ref.current.scrollTop !==
ref.current.clientHeight
);
};
I am using material-table "https://material-table.com/"
This is my component that renders a table of data. Here, I am using a custom button inside title for adding new data. It is inside title so that the button goes on the top-left side. I am not using the default add option given by material-table because I want to display a separate form page for adding data instead of inline-adding given by material-table. It works perfectly.
The problem is that the default styling of title has overflow:hidden which can be seen by inspecting it.
<div class='MTableToolbar-title-35'> .... </div>
I want this overflow:hidden to be overflow:auto. How can I override the styling of this title?
export const EmployeeView = ({columns,data}) => {
return (
<div>
<MaterialTable
columns={columns}
data={data}
title={
<div>
<IconButton size='small' color='primary' onClick={() => console.log("Add employee")}>
<AddCircleIcon />
</IconButton>
</div>
}
onRowClick={(event,rowData) => console.log(rowData)}
/>
</div>
)
}
Please use this in the css file
.MuiTypography-h6{
font-size: 1rem;
color: red;
overflow:auto
}
I mentioned the color and font size for testing.
I need to have only one button doing two things one by one. I have two buttons "Обучить" and "Генерировать" and they both do something onClick. Is it possible to do it all with one button?
<Button
variant="contained"
color="primary"
style={{
background:
"linear-gradient(45deg, #00ACD3 30%, #00BE68 90%)"
}}
onClick={this.parseInput}
>
Обучить
</Button>
<Button
variant="contained"
color="primary"
style={{
background:
"linear-gradient(45deg, #00ACD3 30%, #00BE68 90%)"
}}
onClick={() => {
this.props.updateData(this.state.filterArray);
}}
>
Генерировать
</Button>
Of course you can. You can use a variable to decide what action you want to perform on onClick function
onClick={() => {
if(this.props.type == 'update')
this.props.updateData(this.state.filterArray);
else
this.parseInput()
}}
You can use same property type (or anything you like) to render different labels
{{this.props.type=='update'? 'Генерировать': 'Обучить'}}
I assume that you want to make a component reusable? In that case you might want to design your component like so.
const NewButton = ({onClick, children}) => (
<Button
variant="contained"
color="primary"
style={{
background: "linear-gradient(45deg, #00ACD3 30%, #00BE68)
}}
onClick={onClick}>
children
</Button>);
Then your above snip becomes
<NewButton onClick={someFunction}>Something</NewButton>
<NewButton onClick={otherFunction}>Something</NewButton>
This is the basic idea behind any component-based front-end framework and I suggest you go to the react tutorials to learn more.
Otherwise, there are plenty of good articles about the topic out there
If I understand you correctly, you want to use the same component but make them do different things, on click for example.
Here is an example of how you can do it.
import React from 'react';
const Button = ({onClick}) => {
return (
<button
onClick={onClick}
>
Click on me
</button>
)
}
export default Button;
So when you want to pass down a method to the button, you can do it like this.
import Button from './button';
clickerTicker() {
alert("First method, clickerticker");
}
secondaryClick() {
alert("Second method yo");
}
render() {
return (
<div>
<ButtonComponent onClick={this.clickerTicker.bind(this)}/>
<br/>
<ButtonComponent onClick={this.secondaryClick.bind(this)}/>
</div>
);
}
Just pass the onClick to the component
Looking for a way to change the background-image of a jumbotron component
this is what I've tried but no luck:
class Jumbo extends Component {
render() {
var styles ={
"background-image":"http://worldkings.org/Userfiles/Upload/images/Yale.jpg"
}
return (
<div>
<Jumbotron style={styles}>
<h1>Public Art</h1>
<br/>
<p>
A crowd-sourced archive of art in public spaces.
</p>
<Button bsStyle="primary" href="#" >Learn more</Button>
<Button bsStyle="primary" href="#" >Submit a Piece</Button>
{/*link these!*/}
</Jumbotron>
</div>
);
}
}
any pointers?
Apparently you have to use backgroundImage instead of "background-image" for inline styles according to React doc's example:
const divStyle = {
color: 'blue',
backgroundImage: 'url(' + imgUrl + ')',
};
function HelloWorldComponent() {
return <div style={divStyle}>Hello World!</div>;
}
Taken From: https://reactjs.org/docs/dom-elements.html
style
The style attribute accepts a JavaScript object with camelCased
properties rather than a CSS string. This is consistent with the DOM
style JavaScript property, is more efficient, and prevents XSS
security holes.
Found a great solution here. I know this is old but it's the first result that comes up when searching the problem. Future react bootstrappers, enjoy!
First, import your image normally:
import bgimage from '../image_background.png'
Then you can apply the style to your tag like so:
<Jumbotron style={{ backgroundImage: `url(${bgimage})`, backgroundSize: 'cover' }}>