Override large medium and small button labels, material-ui - material-ui

I'm trying to style Button only using overrides in the theme. I can use sizeLarge and sizeSmall to target the corresponding buttons, but there is no sizeMedium. Targeting root gets overwritten by MuiButton-label and targeting label overwrites sizeSmall and sizeLarge.
Here's the code
<Button color="primary" variant="contained" size="large">
Button Name - Large
</Button>
<Button color="primary" variant="contained">
Button Name - Medium
</Button>
<Button color="primary" variant="contained" size="small">
Button Name - Small
</Button>
and theme.js
import { createMuiTheme } from "#material-ui/core/styles";
import "typeface-poppins";
import "typeface-open-sans";
export const theme = createMuiTheme({
overrides: {
// Style sheet name ⚛️
MuiButton: {
// Name of the rule
// gets overwritten by label styles
// if label, overwrites below styles
root: {
// Some CSS
font: "normal normal 700 0.875rem/1.6875rem Open Sans",
color: "green",
},
sizeLarge: {
// Some CSS
font: "normal normal 700 0.9375rem/1.6875rem Open Sans",
},
sizeSmall: {
font: "normal normal 700 0.8125rem/1.6875rem Open Sans",
},
},
},
});

You can still reference the label rule name, but for root, specify that the CSS rules are not to be applied to .MuiButton-sizeLarge & .MuiButton-sizeSmall
const theme = createMuiTheme({
overrides: {
MuiButton: {
root: {
"&:not($sizeLarge):not($sizeSmall) $label": {
font: "normal normal 700 0.875rem/1.6875rem Open Sans",
color: "green"
}
},
sizeLarge: {
"& $label": {
font: "normal normal 700 0.9375rem/1.6875rem Open Sans",
}
},
sizeSmall: {
"& $label": {
font: "normal normal 700 0.8125rem/1.6875rem Open Sans"
}
}
}
}
});
function App () {
return (
<ThemeProvider theme={theme}>
<Button color="primary" variant="contained" size="large">
Button Name - Large
</Button>
<Button color="primary" variant="contained">
Button Name - Medium
</Button>
<Button color="primary" variant="contained" size="small">
Button Name - Small
</Button>
</ThemeProvider>
);
}
ReactDOM.render(<App/>, document.getElementById("root"));
<body>
<div id="root"></div>
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script src="https://unpkg.com/#material-ui/core#latest/umd/material-ui.development.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght#0,300;0,400;0,600;0,700;0,800;1,300;1,400;1,600;1,700;1,800&display=swap" rel="stylesheet">
<script type="text/babel">
const { createMuiTheme, Button, ThemeProvider } = MaterialUI;
</script>
</body>

Related

Antd Modal+Carousel+Form shudders for 10ms

During opening antd modal I can see for 10ms that my modal is increased and displays not the first page of the carousel inside.
Here I have attached a Json file, which you can play in your Chrome DevTools (F12 -> Performance -> Load profile). Described problem appears on 1150ms. Here is the link to the codesanbox where you can play with my code. I found that the modal increases because my form layout equal to "vertical", but I still didn't get why the last page of my carousel appears first. I am thinking of some hooks in React like useLayoutEffect to render it correctly, however it seems to my as a antd bug, or my mistake somewhere and I don't want to overload my code with useless hooks.
Here is the code for that who won't open codesanbox:
import "./styles.css";
import React, { useState, useRef } from "react";
import { Modal, Carousel, Form, Button, Input, Image } from "antd";
export default function App() {
const [modal, setModal] = useState<boolean>(false);
const [pageOneForm] = Form.useForm();
const [pageTwoForm] = Form.useForm();
return (
<>
<Button onClick={() => setModal(true)}> open </Button>
<Modal
width={500}
centered
closable={false}
title={"Title of my modal"}
open={modal}
onCancel={() => setModal(false)}
okButtonProps={{ style: { display: "none" } }}
>
<Carousel dotPosition="top" swipeToSlide draggable arrows>
<div>
<img alt="card1" src="card1.png" className="card" />
<Form
form={pageOneForm}
layout="vertical" //it makes my modal huge for few ms
>
<Form.Item
label="Some input for 1 page"
name="carteVitale"
rules={[{ required: true, message: "" }]}
>
<Input />
</Form.Item>
</Form>
</div>
<div>
<img alt="card2" src="card2.png" className="card" />
<Form form={pageTwoForm} layout="vertical">
<Form.Item
label="Some input for 2 page"
rules={[{ required: true, message: "" }]}
>
<Input />
</Form.Item>
</Form>
</div>
</Carousel>
</Modal>
</>
);
}
I expect to render this modal without unplanned modal shakes
UPDATE:
Size of modal can be fixed by adding two keys to Carousel component:
<Carousel
adaptiveHeight={false}
lazyLoad="progressive"
...
or by playing with css:
<Carousel
initialSlide={0}
lazyLoad="ondemand"
className="cards-container"
...
<Form.Item
className="no-wrap"
...
and css will looks like:
.cards-container {
animation: fadein 0.5s ease;
position: relative;
}
#keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.no-wrap label {
white-space: nowrap;
overflow: hidden;
}

In Material UI how can I modify MuiBotton-endIcon's margin left?

New to Material UI I'm building a navigation component while reading through the docs and I ran across Buttons with icons and label. Wanting to build a button I created my component but there is a large gap between the text and icon.
Button:
<Button
onClick={selected}
{...{
size: 'small',
'aria-label': 'menu',
'aria-haspopup': 'true',
}}
className={navBtn}
endIcon={<MenuIcon />}
>
Menu
</Button>
When I review button in the browser the rendered element is:
<span class="MuiButton-endIcon">
<svg class="MuiSvgIcon-root" focusable="false" viewBox="0 0 24 24" aria-hidden="true">
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path>
</svg>
</span>
followed with the CSS of:
.MuiButton-endIcon {
display: inherit;
margin-left: 8px;
margin-right: -4px;
}
Wanting to modify the CSS of the margin left I attempted to target MuiButton-endIcon:
navBtn: {
color: '#363537',
verticalAlign: 'middle',
'&:hover': {
backgroundColor: '#FFFFFF',
boxShadow: 'none',
},
'&:focus': {
boxShadow: 'none',
},
MuiButtonEndIcon: {
marginLeft: '2px',
},
},
which did not work. The only hack I can get to work is to add a span with inline styling:
<Button
onClick={selected}
{...{
size: 'small',
'aria-label': 'menu',
'aria-haspopup': 'true',
}}
className={navBtn}
endIcon={<MenuIcon />}
>
<span style={{ marginRight: '-6px' }}>Menu</span>
</Button>
the full component:
import React from 'react'
// Material UI
import { Button } from '#material-ui/core'
import MenuIcon from '#material-ui/icons/Menu'
// Styles
import useStyles from '../styles'
const NavIcon = ({ selected }) => {
const { navBtn } = useStyles()
return (
<Button
onClick={selected}
{...{
size: 'small',
'aria-label': 'menu',
'aria-haspopup': 'true',
}}
className={navBtn}
endIcon={<MenuIcon />}
>
<span style={{ marginRight: '-6px' }}>Menu</span>
</Button>
)
}
export default NavIcon
Research:
Align material icon vertically
How to Align tab-label and tab-icon horizontally in material-UI using Tabs API
Centered icon and text (React Material-UI)
Material UI - Align icon to center with the Typography text
In Material UI is there a way to modify the margin from the <MenuIcon /> to the text with a <Button /> without implementing an inline style hack on the text?
Edit
Per the answer that mentioned spacing I tried the following:
on <Button>:
<Button
m={1}
onClick={selected}
{...{
size: 'small',
'aria-label': 'menu',
'aria-haspopup': 'true',
}}
className={navBtn}
endIcon={<MenuIcon />}
>
Menu
</Button>
on <MenuIcon>:
<Button
onClick={selected}
{...{
size: 'small',
'aria-label': 'menu',
'aria-haspopup': 'true',
}}
className={navBtn}
endIcon={<MenuIcon m={1} />}
>
Menu
</Button>
styling:
navBtn: {
color: '#363537',
'&:hover': {
backgroundColor: '#FFFFFF',
boxShadow: 'none',
},
'&:focus': {
boxShadow: 'none',
},
},
and there is no effect on the margin to the component. My understanding from the docs for spacing to work I would need to build a theme.
for every component of the material-ui, they take a classes prop, by which you can target the inside classes directly. For endIcon, button receives a style object to endIcon key in classes prop.
App.js
import React from 'react'
// Material UI
import { Button } from '#material-ui/core'
import MenuIcon from '#material-ui/icons/Menu'
// Styles from style.js
import styles from './styles'
const NavIcon = ({ selected }) => {
const classes = styles()
return (
<Button
{...{
size: 'small',
'aria-label': 'menu',
'aria-haspopup': 'true',
}}
classes={{endIcon:classes.endIcon}}
endIcon={<MenuIcon />}
className={classes.navBtn}
>
<span style={{ marginRight: '-6px' }}>Menu</span>
</Button>
)
}
export default NavIcon
styles.js
import { makeStyles, createStyles } from '#material-ui/core/styles';
const useStyles = makeStyles(() =>
createStyles({
endIcon:{
marginLeft:'4px'
},
navBtn: {
color: '#363537',
'&:hover': {
backgroundColor: '#FFFFFF',
boxShadow: 'none',
},
'&:focus': {
boxShadow: 'none',
},
},
}),
);
export default useStyles
Add the required margin in endIcon class.
Documentation
From the Spacing docs
In order for it to work you have to wrap the element you want in a so called "Box"
import Box from '#material-ui/core/Box';
You can specify a prop called "m" to the Button, for example:
<Box m="5px"> <Button /> </Box>
This adds 5 pixels to the overall margin of the button, but if you want to apply only margin to the left you can do:
<Box ml="5px"> <Button /> </Box>

Ionic-Vue Ionicons 5.x.x doesn't show icon

I used ionic-vue with ionicons 5.0.1 but after call
<ion-icon name="add"></ion-icon>
i was following https://dev.to/aaronksaunders/build-your-first-ionic-vue-app-18kj and https://github.com/ionic-team/ionic/issues/19078 tutorial, but stucked and icon in FAB cannot be show.
This is my syntax, thank you for helping.
<template>
<ion-page>
....
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button #click="$router.push({ name: 'new-item' })">
<ion-icon name="add"></ion-icon>
</ion-fab-button>
</ion-fab>
</ion-content>
</ion-page>
</template>
<script>
...
import { addIcons } from 'ionicons';
import * as allIcons from 'ionicons/icons';
const currentIcons = Object.keys(allIcons).map(i => {
const key = i.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`)
if(typeof allIcons[i] === 'string') {
return {
[key]: allIcons[i],
}
}
return {
['ios-' + key]: allIcons[i].ios,
['md-' + key]: allIcons[i].md,
};
});
const iconsObject = Object.assign({}, ...currentIcons);
addIcons(iconsObject);
...
</script>
Result FAB does not show icon 'add':
For Ionic Vue 3 using Composition API:
<template>
<ion-icon :icon="rocket" />
</template>
<script>
import { IonIcon } from '#ionic/vue';
import { rocket } from 'ionicons/icons';
export default {
components: { IonIcon },
setup() {
return {
rocket
}
}
}
</script>
For <script setup>
<script setup>
import { IonIcon } from '#ionic/vue';
import { rocket } from 'ionicons/icons';
</script>
<template>
<ion-icon :icon="rocket" />
</template>
I was also following the same guide(https://dev.to/devmount/how-to-use-ionicons-v5-with-vue-js-53g2), and I encountered the same issue.
I decided to downgrade the ionicons version to version 4:
npm i ionicons#4
This solved my issue.
The code that I used from the guide:
<template>
<ion-page>
<ion-header>
<ion-toolbar color="primary">
<ion-title>Home</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<ion-list>
<ion-item>
<ion-checkbox slot="start"></ion-checkbox>
<ion-label>
<h1>Create Ideaa</h1>
<ion-note>Run Idea by Brandy</ion-note>
</ion-label>
<ion-badge color="success" slot="end">5 Days</ion-badge>
</ion-item>
</ion-list>
<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button >
<ion-icon name="add" ></ion-icon>
</ion-fab-button>
</ion-fab>
</ion-content>
</ion-page>
</template>
<script>
import { add } from "ionicons/icons";
import { addIcons } from "ionicons";
addIcons({
"ios-add": add.ios,
"md-add": add.md
});
export default {
name: "HomePage",
props: {
msg: String
}
};
</script>
In your main.js file
import * as allIcons from "ionicons/icons";
Vue.mixin({
data() {
return {
i: allIcons,
};
},
methods: {
icon(name) {
return this.i[name];
}
}
});
now you can use <ion-icon :src="icon('search')"></ion-icon> anywhere in the vue application, it is going to work
hey thanks for checking out the blogs and videos...
you can also get the icons this way...
<template>
<ion-button #click="handleAddItemClicked" >
<ion-icon slot="icon-only" :src="i.saveOutline" ></ion-icon>
</ion-button>
<ion-button #click="handleAddItemClicked" >
<ion-icon slot="icon-only" :src="i.save" ></ion-icon>
</ion-button>
<ion-button #click="handleAddItemClicked" >
<ion-icon slot="icon-only" :src="i.saveSharp" ></ion-icon>
</ion-button>
</template>
<script>
import * as allIcons from "ionicons/icons";
...
data() {
return {
i : allIcons,
};
},
</script>
I followed this comment in a closed issue on #modus/ionic-vue repo: https://github.com/ModusCreateOrg/ionic-vue/issues/120#issuecomment-633666592
import { addIcons } from 'ionicons'
import { add, cartOutline } from 'ionicons/icons'
addIcons({ add, "cart-outline": cartOutline })
This worked with ionicons#5.1.2 installed. Note how the multi word icon imports are camel case instead of kebab case. If you want to use the kebab case variant of the name for an ion-icon you have to do the assignment to the kebab case name yourself like in the case of cart-outline above.
Though if you wanted to add all of them at once and support kebab case, you could map a new object like this:
import { addIcons } from 'ionicons'
import * as allIcons from 'ionicons/icons'
import _ from 'lodash'
addIcons(_.mapKeys(allIcons, (value, key) => _.kebabCase(key))
After i tried everything, there weren't any errors reported anywehere, just icon wasn't there.
Please check twice, that you have set the color of the icon, because in default icon style color is inhereit.
So, if you have for example, a green button, the color of the icon will be also green, if you do not specify.

how to use material-ui Dialog PaperProps

I'm using v1.1.0 of material-ui in React 16.3.2. I'm trying to create a landing page similar to Showcase - Local Insights
where the dialog has opacity (Find foreclosures). I'm trying to use PaperProps for Dialog component described here Dialog doc
Here's a component I've created to try to do this.
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import Dialog from '#material-ui/core/Dialog';
import DialogActions from '#material-ui/core/DialogActions';
import DialogContent from '#material-ui/core/DialogContent';
import DialogTitle from '#material-ui/core/DialogTitle';
import ForwardIcon from '#material-ui/icons/Forward';
import Input from '#material-ui/core/Input';
import FormControl from '#material-ui/core/FormControl';
import Slide from '#material-ui/core/Slide';
const styles = theme => ({
dialogPaper: {
opacity: 0.5,
border: '#FF0000 1px solid',
},
button: {
margin: '30px'
}
});
function Transition(props) {
return <Slide direction="up" {...props} />;
}
class SignInDialog extends React.Component {
state = {
open: false,
username: ''
};
handleClickOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
handleChange = name => event => {
this.setState({
[name]: event.target.value,
});
};
render() {
const { classes } = this.props;
return (
<div>
<Button variant="fab" color="primary" aria-label="add" className={classes.button} onClick={this.handleClickOpen}>
<ForwardIcon />
</Button>
<Dialog
PaperProps={styles.dialogPaper}
open={this.state.open}
TransitionComponent={Transition}
onClose={this.handleClose}
aria-labelledby="form-dialog-title"
>
<DialogTitle id="form-dialog-title">WELCOME</DialogTitle>
<DialogContent>
<p>SIGN IN</p>
<FormControl className={classes.formControl}>
<Input
value={this.state.searchString}
onChange={this.handleChange('search')}
id="siginin-input"
placeholder="Enter your username"
/>
</FormControl>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color="primary">
Cancel
</Button>
<Button onClick={this.handleClose} color="primary">
Continue
</Button>
</DialogActions>
</Dialog>
</div>
);
}
}
SignInDialog.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(SignInDialog);
I haven't been able to figure out how to get the Dialog to take the styles. What is needed to get PaperProps to work?
If you want to use PaperProps you have to specify the props of the Paperfor which you are applying style.
<Dialog
PaperProps={{ classes: {root: classes.dialogPaper } }}
/>
You can also use classes property and override the style
<Dialog
classes={{paper:classes.dialogPaper}}
/>
The correct way to overide paper props is by using classNames
<Dialog
PaperProps={{ className: classNames(classes.dialogPaper) }}/>
<Dialog
PaperProps={{ classes: {root: classes.dialogPaper } }}
/>

How to create a new DraftInlineStyle?

I have tried to create a new state with Modifier.insertText and the third argument is supposed to a draftInlineStyle
let ncs = Modifier.insertText(contentStates, selections, superscriptVar, ["BOLD"]);
This does give bold but when i try to change the style later on it doesn't change. I have figured out this is because draftInlineStyle is supposed to be a constructor. So how do I create a draftInlineStyle constructor if i am supposed to pass a draftInlineStyle constructor? or is there any other way to do this?
You should use OrderedSet.of from Immutable.js.
let ncs = Modifier.insertText(
contentStates,
selections,
superscriptVar,
OrderedSet.of('BOLD')
);
If you want to apply many styles, pass them as arguments: OrderedSet.of('BOLD', 'ITALIC')
Check the simplified demo in the hidden snippet below:
const {Editor, RichUtils, Modifier, SelectionState, EditorState} = Draft;
const { OrderedSet } = Immutable;
class Container extends React.Component {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty()
};
}
insertTextHandler = (nameOfCustomStyle) => {
const currentSelection = this.state.editorState.getSelection();
const currentContent = this.state.editorState.getCurrentContent();
if (!currentSelection.isCollapsed()) return;
const newContentState = Modifier.insertText(currentContent, currentSelection, 'INSERTED TEXT', OrderedSet.of('BOLD'));
const newEditorState = EditorState.push(
this.state.editorState,
newContentState,
'change-inline-style'
);
this._handleChange(newEditorState)
}
toggleBoldStyle = () => {
this._handleChange(
RichUtils.toggleInlineStyle(
this.state.editorState,
'BOLD'
)
);
}
_handleChange = (editorState) => {
this.setState({ editorState });
}
render() {
return (
<div>
<div className="container-root">
<Editor
placeholder="Type away :)"
editorState={this.state.editorState}
onChange={this._handleChange}
/>
</div>
<button onClick={() => this.insertTextHandler()}>
INSERT TEXT
</button>
<button onClick={() => this.toggleBoldStyle()}>
TOGGLE BOLD STYLE FOR SELECTED TEXT
</button>
</div>
);
}
}
ReactDOM.render(<Container />, document.getElementById('react-root'))
body {
font-family: Helvetica, sans-serif;
}
.public-DraftEditor-content {
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.0/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/draft-js/0.7.0/Draft.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/draft-js/0.10.0/Draft.js"></script>
<div id="react-root"></div>