diff --git a/examples/storybook/.storybook/main.js b/examples/storybook/.storybook/main.js
new file mode 100644
index 00000000000000..62fd47fa002bb6
--- /dev/null
+++ b/examples/storybook/.storybook/main.js
@@ -0,0 +1,12 @@
+module.exports = {
+ stories: ['../stories/**/*.stories.(ts|tsx|js|jsx)'],
+ addons: ['@storybook/addon-actions', '@storybook/addon-links', '@storybook/addon-docs'],
+ typescript: {
+ check: false,
+ checkOptions: {},
+ reactDocgen: 'react-docgen-typescript',
+ reactDocgenTypescriptOptions: {
+ propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
+ },
+ },
+};
diff --git a/examples/storybook/README.md b/examples/storybook/README.md
new file mode 100644
index 00000000000000..2624620d1a94fa
--- /dev/null
+++ b/examples/storybook/README.md
@@ -0,0 +1,10 @@
+# Storybook example
+
+The idea of this example is to provide you with a ready to go storybook containing all the demos we have in the documentation, so that you can see how theme changes affect the overall component look and feel.
+
+# How to use
+
+```
+yarn
+yarn storybook
+```
diff --git a/examples/storybook/package.json b/examples/storybook/package.json
new file mode 100644
index 00000000000000..f195b87dd2db4f
--- /dev/null
+++ b/examples/storybook/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "storybook",
+ "version": "1.0.0",
+ "main": "index.js",
+ "author": "sakulstra",
+ "license": "MIT",
+ "dependencies": {
+ "@material-ui/core": "^4.9.14",
+ "@material-ui/icons": "^4.9.1",
+ "@material-ui/lab": "^4.0.0-alpha.53",
+ "@storybook/addon-docs": "^5.3.18",
+ "material-table": "^1.57.2",
+ "notistack": "^0.9.16"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.9.6",
+ "@storybook/addon-actions": "^6.0.0-beta.12",
+ "@storybook/addon-links": "^6.0.0-beta.12",
+ "@storybook/addons": "^6.0.0-beta.12",
+ "@storybook/react": "^6.0.0-beta.12",
+ "babel-loader": "^8.1.0"
+ },
+ "scripts": {
+ "storybook": "start-storybook -p 6006",
+ "build-storybook": "build-storybook"
+ }
+}
diff --git a/examples/storybook/scripts/csf-transform.js b/examples/storybook/scripts/csf-transform.js
new file mode 100644
index 00000000000000..e8b0f845c37068
--- /dev/null
+++ b/examples/storybook/scripts/csf-transform.js
@@ -0,0 +1,29 @@
+// play around with ast https://astexplorer.net
+// https://github.com/benjamn/ast-types/
+
+module.exports = (fileInfo, api) => {
+ const j = api.jscodeshift;
+
+ const root = j(fileInfo.source);
+ const partials = fileInfo.path.replace('.tsx', '').split('/');
+ const component = partials[partials.length - 2];
+ const test = partials[partials.length - 1];
+
+ // make export a names export
+ root.find(j.ExportDefaultDeclaration).replaceWith((p) => {
+ return j.exportDeclaration(false, p.node.declaration);
+ });
+
+ // add default export
+ root
+ .get()
+ .node.program.body.push(
+ j.exportDefaultDeclaration(
+ j.objectExpression([
+ j.property('init', j.identifier('title'), j.literal(`Material-ui|${component}|${test}`)),
+ ]),
+ ),
+ );
+
+ return root.toSource();
+};
diff --git a/examples/storybook/scripts/prepare.sh b/examples/storybook/scripts/prepare.sh
new file mode 100644
index 00000000000000..7e65bf187f7767
--- /dev/null
+++ b/examples/storybook/scripts/prepare.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
+cd "$parent_path"
+
+# copy files
+rm -rf ../stories/material-ui
+cp -R ../../../docs/src/pages/components ../stories/material-ui
+
+# remove unnecessary files
+find ../stories/material-ui -name "*.md" -type f -delete
+find ../stories/material-ui -name "*.js" -type f -delete
+
+# rename files
+find ../stories/material-ui -name "*.tsx" -exec bash -c 'mv "$1" "${1%.tsx}".stories.tsx' - '{}' \;
+
+# alter files
+npx jscodeshift -t ./csf-transform.js --extensions=ts,tsx --parser=tsx ../stories/material-ui/**/*.tsx
+
+# remove stuff that is broken atm :)
+rm ../stories/material-ui/grid/InteractiveGrid.stories.tsx # references component from docs
+rm ../stories/material-ui/grid-list -rf # because i removed tile-list.js
+rm ../stories/material-ui/hidden/BreakpointDown.stories.tsx # current jscodeshift breaks hoc exports like export default withWidth()(BreakpointDown);
+rm ../stories/material-ui/hidden/BreakpointOnly.stories.tsx # ^^
+rm ../stories/material-ui/hidden/BreakpointUp.stories.tsx # ^^
+rm ../stories/material-ui/hidden/GridIntegration.stories.tsx # ^^
+rm ../stories/material-ui/steppers/SwipeableTextMobileStepper.stories.tsx # export default Sth currently breaks as well
diff --git a/examples/storybook/stories/0-Welcome.stories.tsx b/examples/storybook/stories/0-Welcome.stories.tsx
new file mode 100644
index 00000000000000..c76f45f3b4be46
--- /dev/null
+++ b/examples/storybook/stories/0-Welcome.stories.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import { linkTo } from '@storybook/addon-links';
+import { Welcome } from '@storybook/react/demo';
+
+export default {
+ title: 'Welcome',
+ component: Welcome,
+};
+
+export const ToStorybook = () => ;
+
+ToStorybook.story = {
+ name: 'to Storybook',
+};
diff --git a/examples/storybook/stories/material-ui/alert/ActionAlerts.stories.tsx b/examples/storybook/stories/material-ui/alert/ActionAlerts.stories.tsx
new file mode 100644
index 00000000000000..4473e8c3c4c2ff
--- /dev/null
+++ b/examples/storybook/stories/material-ui/alert/ActionAlerts.stories.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Alert from '@material-ui/lab/Alert';
+import Button from '@material-ui/core/Button';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function ActionAlerts() {
+ const classes = useStyles();
+
+ return (
+
+
{}}>This is a success alert — check it out!
+
+ UNDO
+
+ }
+ >
+ This is a success alert — check it out!
+
+
+ );
+}
+
+export default {
+ title: 'Material-ui|alert|ActionAlerts.stories',
+};
diff --git a/examples/storybook/stories/material-ui/alert/ColorAlerts.stories.tsx b/examples/storybook/stories/material-ui/alert/ColorAlerts.stories.tsx
new file mode 100644
index 00000000000000..3cbd4b2cfcb07a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/alert/ColorAlerts.stories.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Alert from '@material-ui/lab/Alert';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function ColorAlerts() {
+ const classes = useStyles();
+
+ return (
+
+
+ This is a success alert — check it out!
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|alert|ColorAlerts.stories"
+};
diff --git a/examples/storybook/stories/material-ui/alert/DescriptionAlerts.stories.tsx b/examples/storybook/stories/material-ui/alert/DescriptionAlerts.stories.tsx
new file mode 100644
index 00000000000000..99cdaf18a0182b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/alert/DescriptionAlerts.stories.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import { Alert, AlertTitle } from '@material-ui/lab';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function DescriptionAlerts() {
+ const classes = useStyles();
+
+ return (
+
+
+ Error
+ This is an error alert — check it out!
+
+
+ Warning
+ This is a warning alert — check it out!
+
+
+ Info
+ This is an info alert — check it out!
+
+
+ Success
+ This is a success alert — check it out!
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|alert|DescriptionAlerts.stories"
+};
diff --git a/examples/storybook/stories/material-ui/alert/FilledAlerts.stories.tsx b/examples/storybook/stories/material-ui/alert/FilledAlerts.stories.tsx
new file mode 100644
index 00000000000000..ca4eaba606d6a5
--- /dev/null
+++ b/examples/storybook/stories/material-ui/alert/FilledAlerts.stories.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Alert from '@material-ui/lab/Alert';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function SimpleAlerts() {
+ const classes = useStyles();
+
+ return (
+
+
+ This is an error alert — check it out!
+
+
+ This is a warning alert — check it out!
+
+
+ This is an info alert — check it out!
+
+
+ This is a success alert — check it out!
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|alert|FilledAlerts.stories"
+};
diff --git a/examples/storybook/stories/material-ui/alert/IconAlerts.stories.tsx b/examples/storybook/stories/material-ui/alert/IconAlerts.stories.tsx
new file mode 100644
index 00000000000000..63a4e8bb1c389c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/alert/IconAlerts.stories.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Alert from '@material-ui/lab/Alert';
+import CheckIcon from '@material-ui/icons/Check';
+import CheckCircleOutlineIcon from '@material-ui/icons/CheckCircleOutline';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function IconAlerts() {
+ const classes = useStyles();
+
+ return (
+
+
} severity="success">
+ This is a success alert — check it out!
+
+
}}>
+ This is a success alert — check it out!
+
+
+ This is a success alert — check it out!
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|alert|IconAlerts.stories"
+};
diff --git a/examples/storybook/stories/material-ui/alert/OutlinedAlerts.stories.tsx b/examples/storybook/stories/material-ui/alert/OutlinedAlerts.stories.tsx
new file mode 100644
index 00000000000000..12721298261430
--- /dev/null
+++ b/examples/storybook/stories/material-ui/alert/OutlinedAlerts.stories.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Alert from '@material-ui/lab/Alert';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function SimpleAlerts() {
+ const classes = useStyles();
+
+ return (
+
+
+ This is an error alert — check it out!
+
+
+ This is a warning alert — check it out!
+
+
+ This is an info alert — check it out!
+
+
+ This is a success alert — check it out!
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|alert|OutlinedAlerts.stories"
+};
diff --git a/examples/storybook/stories/material-ui/alert/SimpleAlerts.stories.tsx b/examples/storybook/stories/material-ui/alert/SimpleAlerts.stories.tsx
new file mode 100644
index 00000000000000..26de606746a48e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/alert/SimpleAlerts.stories.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Alert from '@material-ui/lab/Alert';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function SimpleAlerts() {
+ const classes = useStyles();
+
+ return (
+
+
This is an error alert — check it out!
+
This is a warning alert — check it out!
+
This is an info alert — check it out!
+
This is a success alert — check it out!
+
+ );
+}
+
+export default {
+ title: "Material-ui|alert|SimpleAlerts.stories"
+};
diff --git a/examples/storybook/stories/material-ui/alert/TransitionAlerts.stories.tsx b/examples/storybook/stories/material-ui/alert/TransitionAlerts.stories.tsx
new file mode 100644
index 00000000000000..629d9540f7521d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/alert/TransitionAlerts.stories.tsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Alert from '@material-ui/lab/Alert';
+import IconButton from '@material-ui/core/IconButton';
+import Collapse from '@material-ui/core/Collapse';
+import Button from '@material-ui/core/Button';
+import CloseIcon from '@material-ui/icons/Close';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function TransitionAlerts() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(true);
+
+ return (
+
+
+ {
+ setOpen(false);
+ }}
+ >
+
+
+ }
+ >
+ Close me!
+
+
+
{
+ setOpen(true);
+ }}
+ >
+ Re-open
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|alert|TransitionAlerts.stories"
+};
diff --git a/examples/storybook/stories/material-ui/app-bar/BackToTop.stories.tsx b/examples/storybook/stories/material-ui/app-bar/BackToTop.stories.tsx
new file mode 100644
index 00000000000000..2333dc1c1e58d6
--- /dev/null
+++ b/examples/storybook/stories/material-ui/app-bar/BackToTop.stories.tsx
@@ -0,0 +1,97 @@
+import React from 'react';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import Typography from '@material-ui/core/Typography';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import useScrollTrigger from '@material-ui/core/useScrollTrigger';
+import Box from '@material-ui/core/Box';
+import Container from '@material-ui/core/Container';
+import Fab from '@material-ui/core/Fab';
+import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';
+import Zoom from '@material-ui/core/Zoom';
+
+interface Props {
+ /**
+ * Injected by the documentation to work in an iframe.
+ * You won't need it on your project.
+ */
+ window?: () => Window;
+ children: React.ReactElement;
+}
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ position: 'fixed',
+ bottom: theme.spacing(2),
+ right: theme.spacing(2),
+ },
+ }),
+);
+
+function ScrollTop(props: Props) {
+ const { children, window } = props;
+ const classes = useStyles();
+ // Note that you normally won't need to set the window ref as useScrollTrigger
+ // will default to window.
+ // This is only being set here because the demo is in an iframe.
+ const trigger = useScrollTrigger({
+ target: window ? window() : undefined,
+ disableHysteresis: true,
+ threshold: 100,
+ });
+
+ const handleClick = (event: React.MouseEvent) => {
+ const anchor = ((event.target as HTMLDivElement).ownerDocument || document).querySelector(
+ '#back-to-top-anchor',
+ );
+
+ if (anchor) {
+ anchor.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ }
+ };
+
+ return (
+
+
+ {children}
+
+
+ );
+}
+
+export function BackToTop(props: Props) {
+ return (
+
+
+
+
+ Scroll to see button
+
+
+
+
+
+ {[...new Array(12)]
+ .map(
+ () => `Cras mattis consectetur purus sit amet fermentum.
+Cras justo odio, dapibus ac facilisis in, egestas eget quam.
+Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
+Praesent commodo cursus magna, vel scelerisque nisl consectetur et.`,
+ )
+ .join('\n')}
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|app-bar|BackToTop.stories"
+};
diff --git a/examples/storybook/stories/material-ui/app-bar/BottomAppBar.stories.tsx b/examples/storybook/stories/material-ui/app-bar/BottomAppBar.stories.tsx
new file mode 100644
index 00000000000000..153f7a9b43fc8e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/app-bar/BottomAppBar.stories.tsx
@@ -0,0 +1,150 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import Toolbar from '@material-ui/core/Toolbar';
+import Typography from '@material-ui/core/Typography';
+import IconButton from '@material-ui/core/IconButton';
+import Paper from '@material-ui/core/Paper';
+import Fab from '@material-ui/core/Fab';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemAvatar from '@material-ui/core/ListItemAvatar';
+import ListItemText from '@material-ui/core/ListItemText';
+import ListSubheader from '@material-ui/core/ListSubheader';
+import Avatar from '@material-ui/core/Avatar';
+import MenuIcon from '@material-ui/icons/Menu';
+import AddIcon from '@material-ui/icons/Add';
+import SearchIcon from '@material-ui/icons/Search';
+import MoreIcon from '@material-ui/icons/MoreVert';
+
+const messages = [
+ {
+ id: 1,
+ primary: 'Brunch this week?',
+ secondary: "I'll be in the neighbourhood this week. Let's grab a bite to eat",
+ person: '/static/images/avatar/5.jpg',
+ },
+ {
+ id: 2,
+ primary: 'Birthday Gift',
+ secondary: `Do you have a suggestion for a good present for John on his work
+ anniversary. I am really confused & would love your thoughts on it.`,
+ person: '/static/images/avatar/1.jpg',
+ },
+ {
+ id: 3,
+ primary: 'Recipe to try',
+ secondary: 'I am try out this new BBQ recipe, I think this might be amazing',
+ person: '/static/images/avatar/2.jpg',
+ },
+ {
+ id: 4,
+ primary: 'Yes!',
+ secondary: 'I have the tickets to the ReactConf for this year.',
+ person: '/static/images/avatar/3.jpg',
+ },
+ {
+ id: 5,
+ primary: "Doctor's Appointment",
+ secondary: 'My appointment for the doctor was rescheduled for next Saturday.',
+ person: '/static/images/avatar/4.jpg',
+ },
+ {
+ id: 6,
+ primary: 'Discussion',
+ secondary: `Menus that are generated by the bottom app bar (such as a bottom
+ navigation drawer or overflow menu) open as bottom sheets at a higher elevation
+ than the bar.`,
+ person: '/static/images/avatar/5.jpg',
+ },
+ {
+ id: 7,
+ primary: 'Summer BBQ',
+ secondary: `Who wants to have a cookout this weekend? I just got some furniture
+ for my backyard and would love to fire up the grill.`,
+ person: '/static/images/avatar/1.jpg',
+ },
+];
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ text: {
+ padding: theme.spacing(2, 2, 0),
+ },
+ paper: {
+ paddingBottom: 50,
+ },
+ list: {
+ marginBottom: theme.spacing(2),
+ },
+ subheader: {
+ backgroundColor: theme.palette.background.paper,
+ },
+ appBar: {
+ top: 'auto',
+ bottom: 0,
+ },
+ grow: {
+ flexGrow: 1,
+ },
+ fabButton: {
+ position: 'absolute',
+ zIndex: 1,
+ top: -30,
+ left: 0,
+ right: 0,
+ margin: '0 auto',
+ },
+ }),
+);
+
+export function BottomAppBar() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+ Inbox
+
+
+ {messages.map(({ id, primary, secondary, person }) => (
+
+ {id === 1 && Today }
+ {id === 3 && Yesterday }
+
+
+
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|app-bar|BottomAppBar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/app-bar/ButtonAppBar.stories.tsx b/examples/storybook/stories/material-ui/app-bar/ButtonAppBar.stories.tsx
new file mode 100644
index 00000000000000..28242fc97ea7ea
--- /dev/null
+++ b/examples/storybook/stories/material-ui/app-bar/ButtonAppBar.stories.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import Typography from '@material-ui/core/Typography';
+import Button from '@material-ui/core/Button';
+import IconButton from '@material-ui/core/IconButton';
+import MenuIcon from '@material-ui/icons/Menu';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ },
+ menuButton: {
+ marginRight: theme.spacing(2),
+ },
+ title: {
+ flexGrow: 1,
+ },
+ }),
+);
+
+export function ButtonAppBar() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+ News
+
+ Login
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|app-bar|ButtonAppBar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/app-bar/DenseAppBar.stories.tsx b/examples/storybook/stories/material-ui/app-bar/DenseAppBar.stories.tsx
new file mode 100644
index 00000000000000..ded9806f61b06a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/app-bar/DenseAppBar.stories.tsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import Typography from '@material-ui/core/Typography';
+import IconButton from '@material-ui/core/IconButton';
+import MenuIcon from '@material-ui/icons/Menu';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ },
+ menuButton: {
+ marginRight: theme.spacing(2),
+ },
+ }),
+);
+
+export function DenseAppBar() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+ Photos
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|app-bar|DenseAppBar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/app-bar/ElevateAppBar.stories.tsx b/examples/storybook/stories/material-ui/app-bar/ElevateAppBar.stories.tsx
new file mode 100644
index 00000000000000..e5d00f597ab846
--- /dev/null
+++ b/examples/storybook/stories/material-ui/app-bar/ElevateAppBar.stories.tsx
@@ -0,0 +1,65 @@
+import React from 'react';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import Typography from '@material-ui/core/Typography';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import useScrollTrigger from '@material-ui/core/useScrollTrigger';
+import Box from '@material-ui/core/Box';
+import Container from '@material-ui/core/Container';
+
+interface Props {
+ /**
+ * Injected by the documentation to work in an iframe.
+ * You won't need it on your project.
+ */
+ window?: () => Window;
+ children: React.ReactElement;
+}
+
+function ElevationScroll(props: Props) {
+ const { children, window } = props;
+ // Note that you normally won't need to set the window ref as useScrollTrigger
+ // will default to window.
+ // This is only being set here because the demo is in an iframe.
+ const trigger = useScrollTrigger({
+ disableHysteresis: true,
+ threshold: 0,
+ target: window ? window() : undefined,
+ });
+
+ return React.cloneElement(children, {
+ elevation: trigger ? 4 : 0,
+ });
+}
+
+export function ElevateAppBar(props: Props) {
+ return (
+
+
+
+
+
+ Scroll to Elevate App Bar
+
+
+
+
+
+
+ {[...new Array(12)]
+ .map(
+ () => `Cras mattis consectetur purus sit amet fermentum.
+Cras justo odio, dapibus ac facilisis in, egestas eget quam.
+Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
+Praesent commodo cursus magna, vel scelerisque nisl consectetur et.`,
+ )
+ .join('\n')}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|app-bar|ElevateAppBar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/app-bar/HideAppBar.stories.tsx b/examples/storybook/stories/material-ui/app-bar/HideAppBar.stories.tsx
new file mode 100644
index 00000000000000..20792ceed4a80c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/app-bar/HideAppBar.stories.tsx
@@ -0,0 +1,64 @@
+import React from 'react';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import Typography from '@material-ui/core/Typography';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import useScrollTrigger from '@material-ui/core/useScrollTrigger';
+import Box from '@material-ui/core/Box';
+import Container from '@material-ui/core/Container';
+import Slide from '@material-ui/core/Slide';
+
+interface Props {
+ /**
+ * Injected by the documentation to work in an iframe.
+ * You won't need it on your project.
+ */
+ window?: () => Window;
+ children: React.ReactElement;
+}
+
+function HideOnScroll(props: Props) {
+ const { children, window } = props;
+ // Note that you normally won't need to set the window ref as useScrollTrigger
+ // will default to window.
+ // This is only being set here because the demo is in an iframe.
+ const trigger = useScrollTrigger({ target: window ? window() : undefined });
+
+ return (
+
+ {children}
+
+ );
+}
+
+export function HideAppBar(props: Props) {
+ return (
+
+
+
+
+
+ Scroll to Hide App Bar
+
+
+
+
+
+
+ {[...new Array(12)]
+ .map(
+ () => `Cras mattis consectetur purus sit amet fermentum.
+Cras justo odio, dapibus ac facilisis in, egestas eget quam.
+Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
+Praesent commodo cursus magna, vel scelerisque nisl consectetur et.`,
+ )
+ .join('\n')}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|app-bar|HideAppBar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/app-bar/MenuAppBar.stories.tsx b/examples/storybook/stories/material-ui/app-bar/MenuAppBar.stories.tsx
new file mode 100644
index 00000000000000..6da95782ddf36f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/app-bar/MenuAppBar.stories.tsx
@@ -0,0 +1,102 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import Typography from '@material-ui/core/Typography';
+import IconButton from '@material-ui/core/IconButton';
+import MenuIcon from '@material-ui/icons/Menu';
+import AccountCircle from '@material-ui/icons/AccountCircle';
+import Switch from '@material-ui/core/Switch';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import FormGroup from '@material-ui/core/FormGroup';
+import MenuItem from '@material-ui/core/MenuItem';
+import Menu from '@material-ui/core/Menu';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ },
+ menuButton: {
+ marginRight: theme.spacing(2),
+ },
+ title: {
+ flexGrow: 1,
+ },
+ }),
+);
+
+export function MenuAppBar() {
+ const classes = useStyles();
+ const [auth, setAuth] = React.useState(true);
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const open = Boolean(anchorEl);
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setAuth(event.target.checked);
+ };
+
+ const handleMenu = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ return (
+
+
+ }
+ label={auth ? 'Logout' : 'Login'}
+ />
+
+
+
+
+
+
+
+ Photos
+
+ {auth && (
+
+ )}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|app-bar|MenuAppBar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/app-bar/PrimarySearchAppBar.stories.tsx b/examples/storybook/stories/material-ui/app-bar/PrimarySearchAppBar.stories.tsx
new file mode 100644
index 00000000000000..e3cf6968e6ac14
--- /dev/null
+++ b/examples/storybook/stories/material-ui/app-bar/PrimarySearchAppBar.stories.tsx
@@ -0,0 +1,238 @@
+import React from 'react';
+import { fade, makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import IconButton from '@material-ui/core/IconButton';
+import Typography from '@material-ui/core/Typography';
+import InputBase from '@material-ui/core/InputBase';
+import Badge from '@material-ui/core/Badge';
+import MenuItem from '@material-ui/core/MenuItem';
+import Menu from '@material-ui/core/Menu';
+import MenuIcon from '@material-ui/icons/Menu';
+import SearchIcon from '@material-ui/icons/Search';
+import AccountCircle from '@material-ui/icons/AccountCircle';
+import MailIcon from '@material-ui/icons/Mail';
+import NotificationsIcon from '@material-ui/icons/Notifications';
+import MoreIcon from '@material-ui/icons/MoreVert';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ grow: {
+ flexGrow: 1,
+ },
+ menuButton: {
+ marginRight: theme.spacing(2),
+ },
+ title: {
+ display: 'none',
+ [theme.breakpoints.up('sm')]: {
+ display: 'block',
+ },
+ },
+ search: {
+ position: 'relative',
+ borderRadius: theme.shape.borderRadius,
+ backgroundColor: fade(theme.palette.common.white, 0.15),
+ '&:hover': {
+ backgroundColor: fade(theme.palette.common.white, 0.25),
+ },
+ marginRight: theme.spacing(2),
+ marginLeft: 0,
+ width: '100%',
+ [theme.breakpoints.up('sm')]: {
+ marginLeft: theme.spacing(3),
+ width: 'auto',
+ },
+ },
+ searchIcon: {
+ padding: theme.spacing(0, 2),
+ height: '100%',
+ position: 'absolute',
+ pointerEvents: 'none',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ inputRoot: {
+ color: 'inherit',
+ },
+ inputInput: {
+ padding: theme.spacing(1, 1, 1, 0),
+ // vertical padding + font size from searchIcon
+ paddingLeft: `calc(1em + ${theme.spacing(4)}px)`,
+ transition: theme.transitions.create('width'),
+ width: '100%',
+ [theme.breakpoints.up('md')]: {
+ width: '20ch',
+ },
+ },
+ sectionDesktop: {
+ display: 'none',
+ [theme.breakpoints.up('md')]: {
+ display: 'flex',
+ },
+ },
+ sectionMobile: {
+ display: 'flex',
+ [theme.breakpoints.up('md')]: {
+ display: 'none',
+ },
+ },
+ }),
+);
+
+export function PrimarySearchAppBar() {
+ const classes = useStyles();
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const [mobileMoreAnchorEl, setMobileMoreAnchorEl] = React.useState(null);
+
+ const isMenuOpen = Boolean(anchorEl);
+ const isMobileMenuOpen = Boolean(mobileMoreAnchorEl);
+
+ const handleProfileMenuOpen = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleMobileMenuClose = () => {
+ setMobileMoreAnchorEl(null);
+ };
+
+ const handleMenuClose = () => {
+ setAnchorEl(null);
+ handleMobileMenuClose();
+ };
+
+ const handleMobileMenuOpen = (event: React.MouseEvent) => {
+ setMobileMoreAnchorEl(event.currentTarget);
+ };
+
+ const menuId = 'primary-search-account-menu';
+ const renderMenu = (
+
+ );
+
+ const mobileMenuId = 'primary-search-account-menu-mobile';
+ const renderMobileMenu = (
+
+ );
+
+ return (
+
+
+
+
+
+
+
+ Material-UI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {renderMobileMenu}
+ {renderMenu}
+
+ );
+}
+
+export default {
+ title: "Material-ui|app-bar|PrimarySearchAppBar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/app-bar/ProminentAppBar.stories.tsx b/examples/storybook/stories/material-ui/app-bar/ProminentAppBar.stories.tsx
new file mode 100644
index 00000000000000..7e6cf900ab8daa
--- /dev/null
+++ b/examples/storybook/stories/material-ui/app-bar/ProminentAppBar.stories.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import IconButton from '@material-ui/core/IconButton';
+import Typography from '@material-ui/core/Typography';
+import { makeStyles } from '@material-ui/core/styles';
+import MenuIcon from '@material-ui/icons/Menu';
+import SearchIcon from '@material-ui/icons/Search';
+import MoreIcon from '@material-ui/icons/MoreVert';
+
+const useStyles = makeStyles((theme) => ({
+ root: {
+ flexGrow: 1,
+ },
+ menuButton: {
+ marginRight: theme.spacing(2),
+ },
+ toolbar: {
+ minHeight: 128,
+ alignItems: 'flex-start',
+ paddingTop: theme.spacing(1),
+ paddingBottom: theme.spacing(2),
+ },
+ title: {
+ flexGrow: 1,
+ alignSelf: 'flex-end',
+ },
+}));
+
+export function ProminentAppBar() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+ Material-UI
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|app-bar|ProminentAppBar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/app-bar/SearchAppBar.stories.tsx b/examples/storybook/stories/material-ui/app-bar/SearchAppBar.stories.tsx
new file mode 100644
index 00000000000000..6c5b22a52451d7
--- /dev/null
+++ b/examples/storybook/stories/material-ui/app-bar/SearchAppBar.stories.tsx
@@ -0,0 +1,107 @@
+import React from 'react';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import IconButton from '@material-ui/core/IconButton';
+import Typography from '@material-ui/core/Typography';
+import InputBase from '@material-ui/core/InputBase';
+import { createStyles, fade, Theme, makeStyles } from '@material-ui/core/styles';
+import MenuIcon from '@material-ui/icons/Menu';
+import SearchIcon from '@material-ui/icons/Search';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ },
+ menuButton: {
+ marginRight: theme.spacing(2),
+ },
+ title: {
+ flexGrow: 1,
+ display: 'none',
+ [theme.breakpoints.up('sm')]: {
+ display: 'block',
+ },
+ },
+ search: {
+ position: 'relative',
+ borderRadius: theme.shape.borderRadius,
+ backgroundColor: fade(theme.palette.common.white, 0.15),
+ '&:hover': {
+ backgroundColor: fade(theme.palette.common.white, 0.25),
+ },
+ marginLeft: 0,
+ width: '100%',
+ [theme.breakpoints.up('sm')]: {
+ marginLeft: theme.spacing(1),
+ width: 'auto',
+ },
+ },
+ searchIcon: {
+ padding: theme.spacing(0, 2),
+ height: '100%',
+ position: 'absolute',
+ pointerEvents: 'none',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ inputRoot: {
+ color: 'inherit',
+ },
+ inputInput: {
+ padding: theme.spacing(1, 1, 1, 0),
+ // vertical padding + font size from searchIcon
+ paddingLeft: `calc(1em + ${theme.spacing(4)}px)`,
+ transition: theme.transitions.create('width'),
+ width: '100%',
+ [theme.breakpoints.up('sm')]: {
+ width: '12ch',
+ '&:focus': {
+ width: '20ch',
+ },
+ },
+ },
+ }),
+);
+
+export function SearchAppBar() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+ Material-UI
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|app-bar|SearchAppBar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/Asynchronous.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/Asynchronous.stories.tsx
new file mode 100644
index 00000000000000..1c2d8dffb6e5f8
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/Asynchronous.stories.tsx
@@ -0,0 +1,88 @@
+// *https://www.registers.service.gov.uk/registers/country/use-the-api*
+import fetch from 'cross-fetch';
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+import CircularProgress from '@material-ui/core/CircularProgress';
+
+interface CountryType {
+ name: string;
+}
+
+function sleep(delay = 0) {
+ return new Promise((resolve) => {
+ setTimeout(resolve, delay);
+ });
+}
+
+export function Asynchronous() {
+ const [open, setOpen] = React.useState(false);
+ const [options, setOptions] = React.useState([]);
+ const loading = open && options.length === 0;
+
+ React.useEffect(() => {
+ let active = true;
+
+ if (!loading) {
+ return undefined;
+ }
+
+ (async () => {
+ const response = await fetch('https://country.register.gov.uk/records.json?page-size=5000');
+ await sleep(1e3); // For demo purposes.
+ const countries = await response.json();
+
+ if (active) {
+ setOptions(Object.keys(countries).map((key) => countries[key].item[0]) as CountryType[]);
+ }
+ })();
+
+ return () => {
+ active = false;
+ };
+ }, [loading]);
+
+ React.useEffect(() => {
+ if (!open) {
+ setOptions([]);
+ }
+ }, [open]);
+
+ return (
+ {
+ setOpen(true);
+ }}
+ onClose={() => {
+ setOpen(false);
+ }}
+ getOptionSelected={(option, value) => option.name === value.name}
+ getOptionLabel={(option) => option.name}
+ options={options}
+ loading={loading}
+ renderInput={(params) => (
+
+ {loading ? : null}
+ {params.InputProps.endAdornment}
+
+ ),
+ }}
+ />
+ )}
+ />
+ );
+}
+
+export default {
+ title: "Material-ui|autocomplete|Asynchronous.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/CheckboxesTags.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/CheckboxesTags.stories.tsx
new file mode 100644
index 00000000000000..dcb7820b35ac54
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/CheckboxesTags.stories.tsx
@@ -0,0 +1,78 @@
+/* eslint-disable no-use-before-define */
+
+import React from 'react';
+import Checkbox from '@material-ui/core/Checkbox';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
+import CheckBoxIcon from '@material-ui/icons/CheckBox';
+
+const icon = ;
+const checkedIcon = ;
+
+export function CheckboxesTags() {
+ return (
+ option.title}
+ renderOption={(option, { selected }) => (
+
+
+ {option.title}
+
+ )}
+ style={{ width: 500 }}
+ renderInput={(params) => (
+
+ )}
+ />
+ );
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|CheckboxesTags.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/ComboBox.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/ComboBox.stories.tsx
new file mode 100644
index 00000000000000..fc82b8e63feea0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/ComboBox.stories.tsx
@@ -0,0 +1,124 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+
+export function ComboBox() {
+ return (
+ option.title}
+ style={{ width: 300 }}
+ renderInput={(params) => }
+ />
+ );
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ { title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', year: 1964 },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|ComboBox.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/ControllableStates.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/ControllableStates.stories.tsx
new file mode 100644
index 00000000000000..be17b05a75ab24
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/ControllableStates.stories.tsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+
+const options = ['Option 1', 'Option 2'];
+
+export function ControllableStates() {
+ const [value, setValue] = React.useState(options[0]);
+ const [inputValue, setInputValue] = React.useState('');
+
+ return (
+
+
{`value: ${value !== null ? `'${value}'` : 'null'}`}
+
{`inputValue: '${inputValue}'`}
+
+
{
+ setValue(newValue);
+ }}
+ inputValue={inputValue}
+ onInputChange={(event, newInputValue) => {
+ setInputValue(newInputValue);
+ }}
+ id="controllable-states-demo"
+ options={options}
+ style={{ width: 300 }}
+ renderInput={(params) => }
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|autocomplete|ControllableStates.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/CountrySelect.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/CountrySelect.stories.tsx
new file mode 100644
index 00000000000000..5ba47b93fbfd80
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/CountrySelect.stories.tsx
@@ -0,0 +1,321 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+import { makeStyles } from '@material-ui/core/styles';
+
+// ISO 3166-1 alpha-2
+// ⚠️ No support for IE 11
+function countryToFlag(isoCode: string) {
+ return typeof String.fromCodePoint !== 'undefined'
+ ? isoCode
+ .toUpperCase()
+ .replace(/./g, (char) => String.fromCodePoint(char.charCodeAt(0) + 127397))
+ : isoCode;
+}
+
+const useStyles = makeStyles({
+ option: {
+ fontSize: 15,
+ '& > span': {
+ marginRight: 10,
+ fontSize: 18,
+ },
+ },
+});
+
+export function CountrySelect() {
+ const classes = useStyles();
+
+ return (
+ option.label}
+ renderOption={(option) => (
+
+ {countryToFlag(option.code)}
+ {option.label} ({option.code}) +{option.phone}
+
+ )}
+ renderInput={(params) => (
+
+ )}
+ />
+ );
+}
+
+interface CountryType {
+ code: string;
+ label: string;
+ phone: string;
+}
+
+// From https://bitbucket.org/atlassian/atlaskit-mk-2/raw/4ad0e56649c3e6c973e226b7efaeb28cb240ccb0/packages/core/select/src/data/countries.js
+const countries = [
+ { code: 'AD', label: 'Andorra', phone: '376' },
+ { code: 'AE', label: 'United Arab Emirates', phone: '971' },
+ { code: 'AF', label: 'Afghanistan', phone: '93' },
+ { code: 'AG', label: 'Antigua and Barbuda', phone: '1-268' },
+ { code: 'AI', label: 'Anguilla', phone: '1-264' },
+ { code: 'AL', label: 'Albania', phone: '355' },
+ { code: 'AM', label: 'Armenia', phone: '374' },
+ { code: 'AO', label: 'Angola', phone: '244' },
+ { code: 'AQ', label: 'Antarctica', phone: '672' },
+ { code: 'AR', label: 'Argentina', phone: '54' },
+ { code: 'AS', label: 'American Samoa', phone: '1-684' },
+ { code: 'AT', label: 'Austria', phone: '43' },
+ { code: 'AU', label: 'Australia', phone: '61', suggested: true },
+ { code: 'AW', label: 'Aruba', phone: '297' },
+ { code: 'AX', label: 'Alland Islands', phone: '358' },
+ { code: 'AZ', label: 'Azerbaijan', phone: '994' },
+ { code: 'BA', label: 'Bosnia and Herzegovina', phone: '387' },
+ { code: 'BB', label: 'Barbados', phone: '1-246' },
+ { code: 'BD', label: 'Bangladesh', phone: '880' },
+ { code: 'BE', label: 'Belgium', phone: '32' },
+ { code: 'BF', label: 'Burkina Faso', phone: '226' },
+ { code: 'BG', label: 'Bulgaria', phone: '359' },
+ { code: 'BH', label: 'Bahrain', phone: '973' },
+ { code: 'BI', label: 'Burundi', phone: '257' },
+ { code: 'BJ', label: 'Benin', phone: '229' },
+ { code: 'BL', label: 'Saint Barthelemy', phone: '590' },
+ { code: 'BM', label: 'Bermuda', phone: '1-441' },
+ { code: 'BN', label: 'Brunei Darussalam', phone: '673' },
+ { code: 'BO', label: 'Bolivia', phone: '591' },
+ { code: 'BR', label: 'Brazil', phone: '55' },
+ { code: 'BS', label: 'Bahamas', phone: '1-242' },
+ { code: 'BT', label: 'Bhutan', phone: '975' },
+ { code: 'BV', label: 'Bouvet Island', phone: '47' },
+ { code: 'BW', label: 'Botswana', phone: '267' },
+ { code: 'BY', label: 'Belarus', phone: '375' },
+ { code: 'BZ', label: 'Belize', phone: '501' },
+ { code: 'CA', label: 'Canada', phone: '1', suggested: true },
+ { code: 'CC', label: 'Cocos (Keeling) Islands', phone: '61' },
+ { code: 'CD', label: 'Congo, Democratic Republic of the', phone: '243' },
+ { code: 'CF', label: 'Central African Republic', phone: '236' },
+ { code: 'CG', label: 'Congo, Republic of the', phone: '242' },
+ { code: 'CH', label: 'Switzerland', phone: '41' },
+ { code: 'CI', label: "Cote d'Ivoire", phone: '225' },
+ { code: 'CK', label: 'Cook Islands', phone: '682' },
+ { code: 'CL', label: 'Chile', phone: '56' },
+ { code: 'CM', label: 'Cameroon', phone: '237' },
+ { code: 'CN', label: 'China', phone: '86' },
+ { code: 'CO', label: 'Colombia', phone: '57' },
+ { code: 'CR', label: 'Costa Rica', phone: '506' },
+ { code: 'CU', label: 'Cuba', phone: '53' },
+ { code: 'CV', label: 'Cape Verde', phone: '238' },
+ { code: 'CW', label: 'Curacao', phone: '599' },
+ { code: 'CX', label: 'Christmas Island', phone: '61' },
+ { code: 'CY', label: 'Cyprus', phone: '357' },
+ { code: 'CZ', label: 'Czech Republic', phone: '420' },
+ { code: 'DE', label: 'Germany', phone: '49', suggested: true },
+ { code: 'DJ', label: 'Djibouti', phone: '253' },
+ { code: 'DK', label: 'Denmark', phone: '45' },
+ { code: 'DM', label: 'Dominica', phone: '1-767' },
+ { code: 'DO', label: 'Dominican Republic', phone: '1-809' },
+ { code: 'DZ', label: 'Algeria', phone: '213' },
+ { code: 'EC', label: 'Ecuador', phone: '593' },
+ { code: 'EE', label: 'Estonia', phone: '372' },
+ { code: 'EG', label: 'Egypt', phone: '20' },
+ { code: 'EH', label: 'Western Sahara', phone: '212' },
+ { code: 'ER', label: 'Eritrea', phone: '291' },
+ { code: 'ES', label: 'Spain', phone: '34' },
+ { code: 'ET', label: 'Ethiopia', phone: '251' },
+ { code: 'FI', label: 'Finland', phone: '358' },
+ { code: 'FJ', label: 'Fiji', phone: '679' },
+ { code: 'FK', label: 'Falkland Islands (Malvinas)', phone: '500' },
+ { code: 'FM', label: 'Micronesia, Federated States of', phone: '691' },
+ { code: 'FO', label: 'Faroe Islands', phone: '298' },
+ { code: 'FR', label: 'France', phone: '33', suggested: true },
+ { code: 'GA', label: 'Gabon', phone: '241' },
+ { code: 'GB', label: 'United Kingdom', phone: '44' },
+ { code: 'GD', label: 'Grenada', phone: '1-473' },
+ { code: 'GE', label: 'Georgia', phone: '995' },
+ { code: 'GF', label: 'French Guiana', phone: '594' },
+ { code: 'GG', label: 'Guernsey', phone: '44' },
+ { code: 'GH', label: 'Ghana', phone: '233' },
+ { code: 'GI', label: 'Gibraltar', phone: '350' },
+ { code: 'GL', label: 'Greenland', phone: '299' },
+ { code: 'GM', label: 'Gambia', phone: '220' },
+ { code: 'GN', label: 'Guinea', phone: '224' },
+ { code: 'GP', label: 'Guadeloupe', phone: '590' },
+ { code: 'GQ', label: 'Equatorial Guinea', phone: '240' },
+ { code: 'GR', label: 'Greece', phone: '30' },
+ { code: 'GS', label: 'South Georgia and the South Sandwich Islands', phone: '500' },
+ { code: 'GT', label: 'Guatemala', phone: '502' },
+ { code: 'GU', label: 'Guam', phone: '1-671' },
+ { code: 'GW', label: 'Guinea-Bissau', phone: '245' },
+ { code: 'GY', label: 'Guyana', phone: '592' },
+ { code: 'HK', label: 'Hong Kong', phone: '852' },
+ { code: 'HM', label: 'Heard Island and McDonald Islands', phone: '672' },
+ { code: 'HN', label: 'Honduras', phone: '504' },
+ { code: 'HR', label: 'Croatia', phone: '385' },
+ { code: 'HT', label: 'Haiti', phone: '509' },
+ { code: 'HU', label: 'Hungary', phone: '36' },
+ { code: 'ID', label: 'Indonesia', phone: '62' },
+ { code: 'IE', label: 'Ireland', phone: '353' },
+ { code: 'IL', label: 'Israel', phone: '972' },
+ { code: 'IM', label: 'Isle of Man', phone: '44' },
+ { code: 'IN', label: 'India', phone: '91' },
+ { code: 'IO', label: 'British Indian Ocean Territory', phone: '246' },
+ { code: 'IQ', label: 'Iraq', phone: '964' },
+ { code: 'IR', label: 'Iran, Islamic Republic of', phone: '98' },
+ { code: 'IS', label: 'Iceland', phone: '354' },
+ { code: 'IT', label: 'Italy', phone: '39' },
+ { code: 'JE', label: 'Jersey', phone: '44' },
+ { code: 'JM', label: 'Jamaica', phone: '1-876' },
+ { code: 'JO', label: 'Jordan', phone: '962' },
+ { code: 'JP', label: 'Japan', phone: '81', suggested: true },
+ { code: 'KE', label: 'Kenya', phone: '254' },
+ { code: 'KG', label: 'Kyrgyzstan', phone: '996' },
+ { code: 'KH', label: 'Cambodia', phone: '855' },
+ { code: 'KI', label: 'Kiribati', phone: '686' },
+ { code: 'KM', label: 'Comoros', phone: '269' },
+ { code: 'KN', label: 'Saint Kitts and Nevis', phone: '1-869' },
+ { code: 'KP', label: "Korea, Democratic People's Republic of", phone: '850' },
+ { code: 'KR', label: 'Korea, Republic of', phone: '82' },
+ { code: 'KW', label: 'Kuwait', phone: '965' },
+ { code: 'KY', label: 'Cayman Islands', phone: '1-345' },
+ { code: 'KZ', label: 'Kazakhstan', phone: '7' },
+ { code: 'LA', label: "Lao People's Democratic Republic", phone: '856' },
+ { code: 'LB', label: 'Lebanon', phone: '961' },
+ { code: 'LC', label: 'Saint Lucia', phone: '1-758' },
+ { code: 'LI', label: 'Liechtenstein', phone: '423' },
+ { code: 'LK', label: 'Sri Lanka', phone: '94' },
+ { code: 'LR', label: 'Liberia', phone: '231' },
+ { code: 'LS', label: 'Lesotho', phone: '266' },
+ { code: 'LT', label: 'Lithuania', phone: '370' },
+ { code: 'LU', label: 'Luxembourg', phone: '352' },
+ { code: 'LV', label: 'Latvia', phone: '371' },
+ { code: 'LY', label: 'Libya', phone: '218' },
+ { code: 'MA', label: 'Morocco', phone: '212' },
+ { code: 'MC', label: 'Monaco', phone: '377' },
+ { code: 'MD', label: 'Moldova, Republic of', phone: '373' },
+ { code: 'ME', label: 'Montenegro', phone: '382' },
+ { code: 'MF', label: 'Saint Martin (French part)', phone: '590' },
+ { code: 'MG', label: 'Madagascar', phone: '261' },
+ { code: 'MH', label: 'Marshall Islands', phone: '692' },
+ { code: 'MK', label: 'Macedonia, the Former Yugoslav Republic of', phone: '389' },
+ { code: 'ML', label: 'Mali', phone: '223' },
+ { code: 'MM', label: 'Myanmar', phone: '95' },
+ { code: 'MN', label: 'Mongolia', phone: '976' },
+ { code: 'MO', label: 'Macao', phone: '853' },
+ { code: 'MP', label: 'Northern Mariana Islands', phone: '1-670' },
+ { code: 'MQ', label: 'Martinique', phone: '596' },
+ { code: 'MR', label: 'Mauritania', phone: '222' },
+ { code: 'MS', label: 'Montserrat', phone: '1-664' },
+ { code: 'MT', label: 'Malta', phone: '356' },
+ { code: 'MU', label: 'Mauritius', phone: '230' },
+ { code: 'MV', label: 'Maldives', phone: '960' },
+ { code: 'MW', label: 'Malawi', phone: '265' },
+ { code: 'MX', label: 'Mexico', phone: '52' },
+ { code: 'MY', label: 'Malaysia', phone: '60' },
+ { code: 'MZ', label: 'Mozambique', phone: '258' },
+ { code: 'NA', label: 'Namibia', phone: '264' },
+ { code: 'NC', label: 'New Caledonia', phone: '687' },
+ { code: 'NE', label: 'Niger', phone: '227' },
+ { code: 'NF', label: 'Norfolk Island', phone: '672' },
+ { code: 'NG', label: 'Nigeria', phone: '234' },
+ { code: 'NI', label: 'Nicaragua', phone: '505' },
+ { code: 'NL', label: 'Netherlands', phone: '31' },
+ { code: 'NO', label: 'Norway', phone: '47' },
+ { code: 'NP', label: 'Nepal', phone: '977' },
+ { code: 'NR', label: 'Nauru', phone: '674' },
+ { code: 'NU', label: 'Niue', phone: '683' },
+ { code: 'NZ', label: 'New Zealand', phone: '64' },
+ { code: 'OM', label: 'Oman', phone: '968' },
+ { code: 'PA', label: 'Panama', phone: '507' },
+ { code: 'PE', label: 'Peru', phone: '51' },
+ { code: 'PF', label: 'French Polynesia', phone: '689' },
+ { code: 'PG', label: 'Papua New Guinea', phone: '675' },
+ { code: 'PH', label: 'Philippines', phone: '63' },
+ { code: 'PK', label: 'Pakistan', phone: '92' },
+ { code: 'PL', label: 'Poland', phone: '48' },
+ { code: 'PM', label: 'Saint Pierre and Miquelon', phone: '508' },
+ { code: 'PN', label: 'Pitcairn', phone: '870' },
+ { code: 'PR', label: 'Puerto Rico', phone: '1' },
+ { code: 'PS', label: 'Palestine, State of', phone: '970' },
+ { code: 'PT', label: 'Portugal', phone: '351' },
+ { code: 'PW', label: 'Palau', phone: '680' },
+ { code: 'PY', label: 'Paraguay', phone: '595' },
+ { code: 'QA', label: 'Qatar', phone: '974' },
+ { code: 'RE', label: 'Reunion', phone: '262' },
+ { code: 'RO', label: 'Romania', phone: '40' },
+ { code: 'RS', label: 'Serbia', phone: '381' },
+ { code: 'RU', label: 'Russian Federation', phone: '7' },
+ { code: 'RW', label: 'Rwanda', phone: '250' },
+ { code: 'SA', label: 'Saudi Arabia', phone: '966' },
+ { code: 'SB', label: 'Solomon Islands', phone: '677' },
+ { code: 'SC', label: 'Seychelles', phone: '248' },
+ { code: 'SD', label: 'Sudan', phone: '249' },
+ { code: 'SE', label: 'Sweden', phone: '46' },
+ { code: 'SG', label: 'Singapore', phone: '65' },
+ { code: 'SH', label: 'Saint Helena', phone: '290' },
+ { code: 'SI', label: 'Slovenia', phone: '386' },
+ { code: 'SJ', label: 'Svalbard and Jan Mayen', phone: '47' },
+ { code: 'SK', label: 'Slovakia', phone: '421' },
+ { code: 'SL', label: 'Sierra Leone', phone: '232' },
+ { code: 'SM', label: 'San Marino', phone: '378' },
+ { code: 'SN', label: 'Senegal', phone: '221' },
+ { code: 'SO', label: 'Somalia', phone: '252' },
+ { code: 'SR', label: 'Suriname', phone: '597' },
+ { code: 'SS', label: 'South Sudan', phone: '211' },
+ { code: 'ST', label: 'Sao Tome and Principe', phone: '239' },
+ { code: 'SV', label: 'El Salvador', phone: '503' },
+ { code: 'SX', label: 'Sint Maarten (Dutch part)', phone: '1-721' },
+ { code: 'SY', label: 'Syrian Arab Republic', phone: '963' },
+ { code: 'SZ', label: 'Swaziland', phone: '268' },
+ { code: 'TC', label: 'Turks and Caicos Islands', phone: '1-649' },
+ { code: 'TD', label: 'Chad', phone: '235' },
+ { code: 'TF', label: 'French Southern Territories', phone: '262' },
+ { code: 'TG', label: 'Togo', phone: '228' },
+ { code: 'TH', label: 'Thailand', phone: '66' },
+ { code: 'TJ', label: 'Tajikistan', phone: '992' },
+ { code: 'TK', label: 'Tokelau', phone: '690' },
+ { code: 'TL', label: 'Timor-Leste', phone: '670' },
+ { code: 'TM', label: 'Turkmenistan', phone: '993' },
+ { code: 'TN', label: 'Tunisia', phone: '216' },
+ { code: 'TO', label: 'Tonga', phone: '676' },
+ { code: 'TR', label: 'Turkey', phone: '90' },
+ { code: 'TT', label: 'Trinidad and Tobago', phone: '1-868' },
+ { code: 'TV', label: 'Tuvalu', phone: '688' },
+ { code: 'TW', label: 'Taiwan, Province of China', phone: '886' },
+ { code: 'TZ', label: 'United Republic of Tanzania', phone: '255' },
+ { code: 'UA', label: 'Ukraine', phone: '380' },
+ { code: 'UG', label: 'Uganda', phone: '256' },
+ { code: 'US', label: 'United States', phone: '1', suggested: true },
+ { code: 'UY', label: 'Uruguay', phone: '598' },
+ { code: 'UZ', label: 'Uzbekistan', phone: '998' },
+ { code: 'VA', label: 'Holy See (Vatican City State)', phone: '379' },
+ { code: 'VC', label: 'Saint Vincent and the Grenadines', phone: '1-784' },
+ { code: 'VE', label: 'Venezuela', phone: '58' },
+ { code: 'VG', label: 'British Virgin Islands', phone: '1-284' },
+ { code: 'VI', label: 'US Virgin Islands', phone: '1-340' },
+ { code: 'VN', label: 'Vietnam', phone: '84' },
+ { code: 'VU', label: 'Vanuatu', phone: '678' },
+ { code: 'WF', label: 'Wallis and Futuna', phone: '681' },
+ { code: 'WS', label: 'Samoa', phone: '685' },
+ { code: 'XK', label: 'Kosovo', phone: '383' },
+ { code: 'YE', label: 'Yemen', phone: '967' },
+ { code: 'YT', label: 'Mayotte', phone: '262' },
+ { code: 'ZA', label: 'South Africa', phone: '27' },
+ { code: 'ZM', label: 'Zambia', phone: '260' },
+ { code: 'ZW', label: 'Zimbabwe', phone: '263' },
+];
+
+export default {
+ title: "Material-ui|autocomplete|CountrySelect.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/CustomizedHook.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/CustomizedHook.stories.tsx
new file mode 100644
index 00000000000000..2e59808e1d0f2f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/CustomizedHook.stories.tsx
@@ -0,0 +1,287 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import useAutocomplete from '@material-ui/lab/useAutocomplete';
+import NoSsr from '@material-ui/core/NoSsr';
+import CheckIcon from '@material-ui/icons/Check';
+import CloseIcon from '@material-ui/icons/Close';
+import styled from 'styled-components';
+
+const Label = styled('label')`
+ padding: 0 0 4px;
+ line-height: 1.5;
+ display: block;
+`;
+
+const InputWrapper = styled('div')`
+ width: 300px;
+ border: 1px solid #d9d9d9;
+ background-color: #fff;
+ border-radius: 4px;
+ padding: 1px;
+ display: flex;
+ flex-wrap: wrap;
+
+ &:hover {
+ border-color: #40a9ff;
+ }
+
+ &.focused {
+ border-color: #40a9ff;
+ box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+ }
+
+ & input {
+ font-size: 14px;
+ height: 30px;
+ box-sizing: border-box;
+ padding: 4px 6px;
+ width: 0;
+ min-width: 30px;
+ flex-grow: 1;
+ border: 0;
+ margin: 0;
+ outline: 0;
+ }
+`;
+
+const Tag = styled(({ label, onDelete, ...props }) => (
+
+ {label}
+
+
+))`
+ display: flex;
+ align-items: center;
+ height: 24px;
+ margin: 2px;
+ line-height: 22px;
+ background-color: #fafafa;
+ border: 1px solid #e8e8e8;
+ border-radius: 2px;
+ box-sizing: content-box;
+ padding: 0 4px 0 10px;
+ outline: 0;
+ overflow: hidden;
+
+ &:focus {
+ border-color: #40a9ff;
+ background-color: #e6f7ff;
+ }
+
+ & span {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+
+ & svg {
+ font-size: 12px;
+ cursor: pointer;
+ padding: 4px;
+ }
+`;
+
+const Listbox = styled('ul')`
+ width: 300px;
+ margin: 2px 0 0;
+ padding: 0;
+ position: absolute;
+ list-style: none;
+ background-color: #fff;
+ overflow: auto;
+ max-height: 250px;
+ border-radius: 4px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+ z-index: 1;
+
+ & li {
+ padding: 5px 12px;
+ display: flex;
+
+ & span {
+ flex-grow: 1;
+ }
+
+ & svg {
+ color: transparent;
+ }
+ }
+
+ & li[aria-selected='true'] {
+ background-color: #fafafa;
+ font-weight: 600;
+
+ & svg {
+ color: #1890ff;
+ }
+ }
+
+ & li[data-focus='true'] {
+ background-color: #e6f7ff;
+ cursor: pointer;
+
+ & svg {
+ color: #000;
+ }
+ }
+`;
+
+export function CustomizedHook() {
+ const {
+ getRootProps,
+ getInputLabelProps,
+ getInputProps,
+ getTagProps,
+ getListboxProps,
+ getOptionProps,
+ groupedOptions,
+ value,
+ focused,
+ setAnchorEl,
+ } = useAutocomplete({
+ id: 'customized-hook-demo',
+ defaultValue: [top100Films[1]],
+ multiple: true,
+ options: top100Films,
+ getOptionLabel: (option) => option.title,
+ });
+
+ return (
+
+
+
+ Customized hook
+
+ {value.map((option: FilmOptionType, index: number) => (
+
+ ))}
+
+
+
+ {groupedOptions.length > 0 ? (
+
+ {groupedOptions.map((option, index) => (
+
+ {option.title}
+
+
+ ))}
+
+ ) : null}
+
+
+ );
+}
+
+interface FilmOptionType {
+ title: string;
+ year: number;
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ { title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', year: 1964 },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|CustomizedHook.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/DisabledOptions.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/DisabledOptions.stories.tsx
new file mode 100644
index 00000000000000..0e9070412565c0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/DisabledOptions.stories.tsx
@@ -0,0 +1,27 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+
+export function DisabledOptions() {
+ return (
+ option === timeSlots[0] || option === timeSlots[2]}
+ style={{ width: 300 }}
+ renderInput={(params) => (
+
+ )}
+ />
+ );
+}
+
+// One time slot every 30 minutes.
+const timeSlots = Array.from(new Array(24 * 2)).map(
+ (_, index) => `${index < 20 ? '0' : ''}${Math.floor(index / 2)}:${index % 2 === 0 ? '00' : '30'}`,
+);
+
+export default {
+ title: "Material-ui|autocomplete|DisabledOptions.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/Filter.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/Filter.stories.tsx
new file mode 100644
index 00000000000000..5e88eb6dffafba
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/Filter.stories.tsx
@@ -0,0 +1,135 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete, { createFilterOptions } from '@material-ui/lab/Autocomplete';
+
+const filterOptions = createFilterOptions({
+ matchFrom: 'start',
+ stringify: (option: FilmOptionType) => option.title,
+});
+
+export function Filter() {
+ return (
+ option.title}
+ filterOptions={filterOptions}
+ style={{ width: 300 }}
+ renderInput={(params) => }
+ />
+ );
+}
+
+interface FilmOptionType {
+ title: string;
+ year: number;
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ { title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', year: 1964 },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|Filter.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/FixedTags.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/FixedTags.stories.tsx
new file mode 100644
index 00000000000000..96baf2088782d7
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/FixedTags.stories.tsx
@@ -0,0 +1,147 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import Chip from '@material-ui/core/Chip';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+
+export function FixedTags() {
+ const fixedOptions = [top100Films[6]];
+ const [value, setValue] = React.useState([...fixedOptions, top100Films[13]]);
+
+ return (
+ {
+ setValue([
+ ...fixedOptions,
+ ...newValue.filter((option) => fixedOptions.indexOf(option) === -1),
+ ]);
+ }}
+ options={top100Films}
+ getOptionLabel={(option) => option.title}
+ renderTags={(tagValue, getTagProps) =>
+ tagValue.map((option, index) => (
+
+ ))
+ }
+ style={{ width: 500 }}
+ renderInput={(params) => (
+
+ )}
+ />
+ );
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ { title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', year: 1964 },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|FixedTags.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/FreeSolo.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/FreeSolo.stories.tsx
new file mode 100644
index 00000000000000..31ec0436b542c0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/FreeSolo.stories.tsx
@@ -0,0 +1,142 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+
+export function FreeSolo() {
+ return (
+
+
option.title)}
+ renderInput={(params) => (
+
+ )}
+ />
+ option.title)}
+ renderInput={(params) => (
+
+ )}
+ />
+
+ );
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ { title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', year: 1964 },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|FreeSolo.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/FreeSoloCreateOption.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/FreeSoloCreateOption.stories.tsx
new file mode 100644
index 00000000000000..6daedca5ea2684
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/FreeSoloCreateOption.stories.tsx
@@ -0,0 +1,183 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete, { createFilterOptions } from '@material-ui/lab/Autocomplete';
+
+const filter = createFilterOptions();
+
+export function FreeSoloCreateOption() {
+ const [value, setValue] = React.useState(null);
+
+ return (
+ {
+ if (typeof newValue === 'string') {
+ setValue({
+ title: newValue,
+ });
+ } else if (newValue && newValue.inputValue) {
+ // Create a new value from the user input
+ setValue({
+ title: newValue.inputValue,
+ });
+ } else {
+ setValue(newValue);
+ }
+ }}
+ filterOptions={(options, params) => {
+ const filtered = filter(options, params);
+
+ // Suggest the creation of a new value
+ if (params.inputValue !== '') {
+ filtered.push({
+ inputValue: params.inputValue,
+ title: `Add "${params.inputValue}"`,
+ });
+ }
+
+ return filtered;
+ }}
+ selectOnFocus
+ clearOnBlur
+ handleHomeEndKeys
+ id="free-solo-with-text-demo"
+ options={top100Films}
+ getOptionLabel={(option) => {
+ // Value selected with enter, right from the input
+ if (typeof option === 'string') {
+ return option;
+ }
+ // Add "xxx" option created dynamically
+ if (option.inputValue) {
+ return option.inputValue;
+ }
+ // Regular option
+ return option.title;
+ }}
+ renderOption={(option) => option.title}
+ style={{ width: 300 }}
+ freeSolo
+ renderInput={(params) => (
+
+ )}
+ />
+ );
+}
+
+interface FilmOptionType {
+ inputValue?: string;
+ title: string;
+ year?: number;
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films: FilmOptionType[] = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ {
+ title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb',
+ year: 1964,
+ },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|FreeSoloCreateOption.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/FreeSoloCreateOptionDialog.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/FreeSoloCreateOptionDialog.stories.tsx
new file mode 100644
index 00000000000000..82bc9137c6b612
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/FreeSoloCreateOptionDialog.stories.tsx
@@ -0,0 +1,252 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Dialog from '@material-ui/core/Dialog';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import DialogContent from '@material-ui/core/DialogContent';
+import DialogContentText from '@material-ui/core/DialogContentText';
+import DialogActions from '@material-ui/core/DialogActions';
+import Button from '@material-ui/core/Button';
+import Autocomplete, { createFilterOptions } from '@material-ui/lab/Autocomplete';
+
+const filter = createFilterOptions();
+
+export function FreeSoloCreateOptionDialog() {
+ const [value, setValue] = React.useState(null);
+ const [open, toggleOpen] = React.useState(false);
+
+ const handleClose = () => {
+ setDialogValue({
+ title: '',
+ year: '',
+ });
+ toggleOpen(false);
+ };
+
+ const [dialogValue, setDialogValue] = React.useState({
+ title: '',
+ year: '',
+ });
+
+ const handleSubmit = (event: React.FormEvent) => {
+ event.preventDefault();
+ setValue({
+ title: dialogValue.title,
+ year: parseInt(dialogValue.year, 10),
+ });
+ handleClose();
+ };
+
+ return (
+
+ {
+ if (typeof newValue === 'string') {
+ // timeout to avoid instant validation of the dialog's form.
+ setTimeout(() => {
+ toggleOpen(true);
+ setDialogValue({
+ title: newValue,
+ year: '',
+ });
+ });
+ } else if (newValue && newValue.inputValue) {
+ toggleOpen(true);
+ setDialogValue({
+ title: newValue.inputValue,
+ year: '',
+ });
+ } else {
+ setValue(newValue);
+ }
+ }}
+ filterOptions={(options, params) => {
+ const filtered = filter(options, params) as FilmOptionType[];
+
+ if (params.inputValue !== '') {
+ filtered.push({
+ inputValue: params.inputValue,
+ title: `Add "${params.inputValue}"`,
+ });
+ }
+
+ return filtered;
+ }}
+ id="free-solo-dialog-demo"
+ options={top100Films}
+ getOptionLabel={(option) => {
+ // e.g value selected with enter, right from the input
+ if (typeof option === 'string') {
+ return option;
+ }
+ if (option.inputValue) {
+ return option.inputValue;
+ }
+ return option.title;
+ }}
+ selectOnFocus
+ clearOnBlur
+ handleHomeEndKeys
+ renderOption={(option) => option.title}
+ style={{ width: 300 }}
+ freeSolo
+ renderInput={(params) => (
+
+ )}
+ />
+
+
+
+
+ );
+}
+
+interface FilmOptionType {
+ inputValue?: string;
+ title: string;
+ year?: number;
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films: FilmOptionType[] = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ {
+ title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb',
+ year: 1964,
+ },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|FreeSoloCreateOptionDialog.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/GitHubLabel.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/GitHubLabel.stories.tsx
new file mode 100644
index 00000000000000..6a62eb1d0fc479
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/GitHubLabel.stories.tsx
@@ -0,0 +1,340 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import { useTheme, fade, makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Popper from '@material-ui/core/Popper';
+import SettingsIcon from '@material-ui/icons/Settings';
+import CloseIcon from '@material-ui/icons/Close';
+import DoneIcon from '@material-ui/icons/Done';
+import Autocomplete, { AutocompleteCloseReason } from '@material-ui/lab/Autocomplete';
+import ButtonBase from '@material-ui/core/ButtonBase';
+import InputBase from '@material-ui/core/InputBase';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 221,
+ fontSize: 13,
+ },
+ button: {
+ fontSize: 13,
+ width: '100%',
+ textAlign: 'left',
+ paddingBottom: 8,
+ color: '#586069',
+ fontWeight: 600,
+ '&:hover,&:focus': {
+ color: '#0366d6',
+ },
+ '& span': {
+ width: '100%',
+ },
+ '& svg': {
+ width: 16,
+ height: 16,
+ },
+ },
+ tag: {
+ marginTop: 3,
+ height: 20,
+ padding: '.15em 4px',
+ fontWeight: 600,
+ lineHeight: '15px',
+ borderRadius: 2,
+ },
+ popper: {
+ border: '1px solid rgba(27,31,35,.15)',
+ boxShadow: '0 3px 12px rgba(27,31,35,.15)',
+ borderRadius: 3,
+ width: 300,
+ zIndex: 1,
+ fontSize: 13,
+ color: '#586069',
+ backgroundColor: '#f6f8fa',
+ },
+ header: {
+ borderBottom: '1px solid #e1e4e8',
+ padding: '8px 10px',
+ fontWeight: 600,
+ },
+ inputBase: {
+ padding: 10,
+ width: '100%',
+ borderBottom: '1px solid #dfe2e5',
+ '& input': {
+ borderRadius: 4,
+ backgroundColor: theme.palette.common.white,
+ padding: 8,
+ transition: theme.transitions.create(['border-color', 'box-shadow']),
+ border: '1px solid #ced4da',
+ fontSize: 14,
+ '&:focus': {
+ boxShadow: `${fade(theme.palette.primary.main, 0.25)} 0 0 0 0.2rem`,
+ borderColor: theme.palette.primary.main,
+ },
+ },
+ },
+ paper: {
+ boxShadow: 'none',
+ margin: 0,
+ color: '#586069',
+ fontSize: 13,
+ },
+ option: {
+ minHeight: 'auto',
+ alignItems: 'flex-start',
+ padding: 8,
+ '&[aria-selected="true"]': {
+ backgroundColor: 'transparent',
+ },
+ '&[data-focus="true"]': {
+ backgroundColor: theme.palette.action.hover,
+ },
+ },
+ popperDisablePortal: {
+ position: 'relative',
+ },
+ iconSelected: {
+ width: 17,
+ height: 17,
+ marginRight: 5,
+ marginLeft: -2,
+ },
+ color: {
+ width: 14,
+ height: 14,
+ flexShrink: 0,
+ borderRadius: 3,
+ marginRight: 8,
+ marginTop: 2,
+ },
+ text: {
+ flexGrow: 1,
+ },
+ close: {
+ opacity: 0.6,
+ width: 18,
+ height: 18,
+ },
+ }),
+);
+
+export function GitHubLabel() {
+ const classes = useStyles();
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const [value, setValue] = React.useState([labels[1], labels[11]]);
+ const [pendingValue, setPendingValue] = React.useState([]);
+ const theme = useTheme();
+
+ const handleClick = (event: React.MouseEvent) => {
+ setPendingValue(value);
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleClose = (event: React.ChangeEvent<{}>, reason: AutocompleteCloseReason) => {
+ if (reason === 'toggleInput') {
+ return;
+ }
+ setValue(pendingValue);
+ if (anchorEl) {
+ anchorEl.focus();
+ }
+ setAnchorEl(null);
+ };
+
+ const open = Boolean(anchorEl);
+ const id = open ? 'github-label' : undefined;
+
+ return (
+
+
+
+ Labels
+
+
+ {value.map((label) => (
+
+ {label.name}
+
+ ))}
+
+
+ Apply labels to this pull request
+ {
+ setPendingValue(newValue);
+ }}
+ disableCloseOnSelect
+ disablePortal
+ renderTags={() => null}
+ noOptionsText="No labels"
+ renderOption={(option, { selected }) => (
+
+
+
+
+ {option.name}
+
+ {option.description}
+
+
+
+ )}
+ options={[...labels].sort((a, b) => {
+ // Display the selected labels first.
+ let ai = value.indexOf(a);
+ ai = ai === -1 ? value.length + labels.indexOf(a) : ai;
+ let bi = value.indexOf(b);
+ bi = bi === -1 ? value.length + labels.indexOf(b) : bi;
+ return ai - bi;
+ })}
+ getOptionLabel={(option) => option.name}
+ renderInput={(params) => (
+
+ )}
+ />
+
+
+ );
+}
+
+interface LabelType {
+ name: string;
+ color: string;
+ description?: string;
+}
+
+// From https://github.com/abdonrd/github-labels
+const labels = [
+ {
+ name: 'good first issue',
+ color: '#7057ff',
+ description: 'Good for newcomers',
+ },
+ {
+ name: 'help wanted',
+ color: '#008672',
+ description: 'Extra attention is needed',
+ },
+ {
+ name: 'priority: critical',
+ color: '#b60205',
+ description: '',
+ },
+ {
+ name: 'priority: high',
+ color: '#d93f0b',
+ description: '',
+ },
+ {
+ name: 'priority: low',
+ color: '#0e8a16',
+ description: '',
+ },
+ {
+ name: 'priority: medium',
+ color: '#fbca04',
+ description: '',
+ },
+ {
+ name: "status: can't reproduce",
+ color: '#fec1c1',
+ description: '',
+ },
+ {
+ name: 'status: confirmed',
+ color: '#215cea',
+ description: '',
+ },
+ {
+ name: 'status: duplicate',
+ color: '#cfd3d7',
+ description: 'This issue or pull request already exists',
+ },
+ {
+ name: 'status: needs information',
+ color: '#fef2c0',
+ description: '',
+ },
+ {
+ name: 'status: wont do/fix',
+ color: '#eeeeee',
+ description: 'This will not be worked on',
+ },
+ {
+ name: 'type: bug',
+ color: '#d73a4a',
+ description: "Something isn't working",
+ },
+ {
+ name: 'type: discussion',
+ color: '#d4c5f9',
+ description: '',
+ },
+ {
+ name: 'type: documentation',
+ color: '#006b75',
+ description: '',
+ },
+ {
+ name: 'type: enhancement',
+ color: '#84b6eb',
+ description: '',
+ },
+ {
+ name: 'type: epic',
+ color: '#3e4b9e',
+ description: 'A theme of work that contain sub-tasks',
+ },
+ {
+ name: 'type: feature request',
+ color: '#fbca04',
+ description: 'New feature or request',
+ },
+ {
+ name: 'type: question',
+ color: '#d876e3',
+ description: 'Further information is requested',
+ },
+];
+
+export default {
+ title: "Material-ui|autocomplete|GitHubLabel.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/GoogleMaps.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/GoogleMaps.stories.tsx
new file mode 100644
index 00000000000000..91981274c6d0ba
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/GoogleMaps.stories.tsx
@@ -0,0 +1,161 @@
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+import LocationOnIcon from '@material-ui/icons/LocationOn';
+import Grid from '@material-ui/core/Grid';
+import Typography from '@material-ui/core/Typography';
+import { makeStyles } from '@material-ui/core/styles';
+import parse from 'autosuggest-highlight/parse';
+import throttle from 'lodash/throttle';
+
+function loadScript(src: string, position: HTMLElement | null, id: string) {
+ if (!position) {
+ return;
+ }
+
+ const script = document.createElement('script');
+ script.setAttribute('async', '');
+ script.setAttribute('id', id);
+ script.src = src;
+ position.appendChild(script);
+}
+
+const autocompleteService = { current: null };
+
+const useStyles = makeStyles((theme) => ({
+ icon: {
+ color: theme.palette.text.secondary,
+ marginRight: theme.spacing(2),
+ },
+}));
+
+interface PlaceType {
+ description: string;
+ structured_formatting: {
+ main_text: string;
+ secondary_text: string;
+ main_text_matched_substrings: [
+ {
+ offset: number;
+ length: number;
+ },
+ ];
+ };
+}
+
+export function GoogleMaps() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(null);
+ const [inputValue, setInputValue] = React.useState('');
+ const [options, setOptions] = React.useState([]);
+ const loaded = React.useRef(false);
+
+ if (typeof window !== 'undefined' && !loaded.current) {
+ if (!document.querySelector('#google-maps')) {
+ loadScript(
+ 'https://maps.googleapis.com/maps/api/js?key=AIzaSyBwRp1e12ec1vOTtGiA4fcCt2sCUS78UYc&libraries=places',
+ document.querySelector('head'),
+ 'google-maps',
+ );
+ }
+
+ loaded.current = true;
+ }
+
+ const fetch = React.useMemo(
+ () =>
+ throttle((request: { input: string }, callback: (results?: PlaceType[]) => void) => {
+ (autocompleteService.current as any).getPlacePredictions(request, callback);
+ }, 200),
+ [],
+ );
+
+ React.useEffect(() => {
+ let active = true;
+
+ if (!autocompleteService.current && (window as any).google) {
+ autocompleteService.current = new (window as any).google.maps.places.AutocompleteService();
+ }
+ if (!autocompleteService.current) {
+ return undefined;
+ }
+
+ if (inputValue === '') {
+ setOptions(value ? [value] : []);
+ return undefined;
+ }
+
+ fetch({ input: inputValue }, (results?: PlaceType[]) => {
+ if (active) {
+ let newOptions = [] as PlaceType[];
+
+ if (value) {
+ newOptions = [value];
+ }
+
+ if (results) {
+ newOptions = [...newOptions, ...results];
+ }
+
+ setOptions(newOptions);
+ }
+ });
+
+ return () => {
+ active = false;
+ };
+ }, [value, inputValue, fetch]);
+
+ return (
+ (typeof option === 'string' ? option : option.description)}
+ filterOptions={(x) => x}
+ options={options}
+ autoComplete
+ includeInputInList
+ filterSelectedOptions
+ value={value}
+ onChange={(event: any, newValue: PlaceType | null) => {
+ setOptions(newValue ? [newValue, ...options] : options);
+ setValue(newValue);
+ }}
+ onInputChange={(event, newInputValue) => {
+ setInputValue(newInputValue);
+ }}
+ renderInput={(params) => (
+
+ )}
+ renderOption={(option) => {
+ const matches = option.structured_formatting.main_text_matched_substrings;
+ const parts = parse(
+ option.structured_formatting.main_text,
+ matches.map((match: any) => [match.offset, match.offset + match.length]),
+ );
+
+ return (
+
+
+
+
+
+ {parts.map((part, index) => (
+
+ {part.text}
+
+ ))}
+
+ {option.structured_formatting.secondary_text}
+
+
+
+ );
+ }}
+ />
+ );
+}
+
+export default {
+ title: "Material-ui|autocomplete|GoogleMaps.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/Grouped.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/Grouped.stories.tsx
new file mode 100644
index 00000000000000..246b6dc11edcc3
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/Grouped.stories.tsx
@@ -0,0 +1,133 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+
+export function Grouped() {
+ const options = top100Films.map((option) => {
+ const firstLetter = option.title[0].toUpperCase();
+ return {
+ firstLetter: /[0-9]/.test(firstLetter) ? '0-9' : firstLetter,
+ ...option,
+ };
+ });
+
+ return (
+ -b.firstLetter.localeCompare(a.firstLetter))}
+ groupBy={(option) => option.firstLetter}
+ getOptionLabel={(option) => option.title}
+ style={{ width: 300 }}
+ renderInput={(params) => }
+ />
+ );
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ { title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', year: 1964 },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|Grouped.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/Highlights.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/Highlights.stories.tsx
new file mode 100644
index 00000000000000..73a7de778eb639
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/Highlights.stories.tsx
@@ -0,0 +1,142 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+import parse from 'autosuggest-highlight/parse';
+import match from 'autosuggest-highlight/match';
+
+export function Highlights() {
+ return (
+ option.title}
+ renderInput={(params) => (
+
+ )}
+ renderOption={(option, { inputValue }) => {
+ const matches = match(option.title, inputValue);
+ const parts = parse(option.title, matches);
+
+ return (
+
+ {parts.map((part, index) => (
+
+ {part.text}
+
+ ))}
+
+ );
+ }}
+ />
+ );
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ { title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', year: 1964 },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|Highlights.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/LimitTags.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/LimitTags.stories.tsx
new file mode 100644
index 00000000000000..65ff975fd6a054
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/LimitTags.stories.tsx
@@ -0,0 +1,144 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 500,
+ '& > * + *': {
+ marginTop: theme.spacing(3),
+ },
+ },
+ }),
+);
+
+export function LimitTags() {
+ const classes = useStyles();
+
+ return (
+
+
option.title}
+ defaultValue={[top100Films[13], top100Films[12], top100Films[11]]}
+ renderInput={(params) => (
+
+ )}
+ />
+
+ );
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ { title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', year: 1964 },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|LimitTags.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/Playground.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/Playground.stories.tsx
new file mode 100644
index 00000000000000..5a7fd9f316cccf
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/Playground.stories.tsx
@@ -0,0 +1,242 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+
+export function Playground() {
+ const defaultProps = {
+ options: top100Films,
+ getOptionLabel: (option: FilmOptionType) => option.title,
+ };
+ const flatProps = {
+ options: top100Films.map((option) => option.title),
+ };
+ const [value, setValue] = React.useState(null);
+
+ return (
+
+
}
+ />
+ (
+
+ )}
+ />
+ }
+ />
+ }
+ />
+ (
+
+ )}
+ />
+ }
+ />
+ {
+ setValue(newValue);
+ }}
+ renderInput={(params) => }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+ }
+ />
+
+ );
+}
+
+interface FilmOptionType {
+ title: string;
+ year: number;
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ { title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', year: 1964 },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|Playground.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/Sizes.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/Sizes.stories.tsx
new file mode 100644
index 00000000000000..83e51401bffc87
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/Sizes.stories.tsx
@@ -0,0 +1,217 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import Chip from '@material-ui/core/Chip';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 500,
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function Sizes() {
+ const classes = useStyles();
+
+ return (
+
+
option.title}
+ defaultValue={top100Films[13]}
+ renderInput={(params) => (
+
+ )}
+ />
+ option.title}
+ defaultValue={[top100Films[13]]}
+ renderInput={(params) => (
+
+ )}
+ />
+ option.title}
+ defaultValue={top100Films[13]}
+ renderInput={(params) => (
+
+ )}
+ />
+ option.title}
+ defaultValue={[top100Films[13]]}
+ renderInput={(params) => (
+
+ )}
+ />
+ option.title}
+ defaultValue={top100Films[13]}
+ renderTags={(value, getTagProps) =>
+ value.map((option, index) => (
+
+ ))
+ }
+ renderInput={(params) => (
+
+ )}
+ />
+ option.title}
+ defaultValue={[top100Films[13]]}
+ renderTags={(value, getTagProps) =>
+ value.map((option, index) => (
+
+ ))
+ }
+ renderInput={(params) => (
+
+ )}
+ />
+
+ );
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ { title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', year: 1964 },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|Sizes.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/Tags.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/Tags.stories.tsx
new file mode 100644
index 00000000000000..8b50466de3abbf
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/Tags.stories.tsx
@@ -0,0 +1,180 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import Chip from '@material-ui/core/Chip';
+import Autocomplete from '@material-ui/lab/Autocomplete';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 500,
+ '& > * + *': {
+ marginTop: theme.spacing(3),
+ },
+ },
+ }),
+);
+
+export function Tags() {
+ const classes = useStyles();
+
+ return (
+
+
option.title}
+ defaultValue={[top100Films[13]]}
+ renderInput={(params) => (
+
+ )}
+ />
+ option.title}
+ defaultValue={[top100Films[13]]}
+ filterSelectedOptions
+ renderInput={(params) => (
+
+ )}
+ />
+ option.title)}
+ defaultValue={[top100Films[13].title]}
+ freeSolo
+ renderTags={(value: string[], getTagProps) =>
+ value.map((option: string, index: number) => (
+
+ ))
+ }
+ renderInput={(params) => (
+
+ )}
+ />
+
+ );
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ { title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', year: 1964 },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|Tags.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/UseAutocomplete.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/UseAutocomplete.stories.tsx
new file mode 100644
index 00000000000000..3a483ee6850c80
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/UseAutocomplete.stories.tsx
@@ -0,0 +1,178 @@
+/* eslint-disable no-use-before-define */
+import React from 'react';
+import useAutocomplete from '@material-ui/lab/useAutocomplete';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ label: {
+ display: 'block',
+ },
+ input: {
+ width: 200,
+ },
+ listbox: {
+ width: 200,
+ margin: 0,
+ padding: 0,
+ zIndex: 1,
+ position: 'absolute',
+ listStyle: 'none',
+ backgroundColor: theme.palette.background.paper,
+ overflow: 'auto',
+ maxHeight: 200,
+ border: '1px solid rgba(0,0,0,.25)',
+ '& li[data-focus="true"]': {
+ backgroundColor: '#4a8df6',
+ color: 'white',
+ cursor: 'pointer',
+ },
+ '& li:active': {
+ backgroundColor: '#2977f5',
+ color: 'white',
+ },
+ },
+ }),
+);
+
+export function UseAutocomplete() {
+ const classes = useStyles();
+ const {
+ getRootProps,
+ getInputLabelProps,
+ getInputProps,
+ getListboxProps,
+ getOptionProps,
+ groupedOptions,
+ } = useAutocomplete({
+ id: 'use-autocomplete-demo',
+ options: top100Films,
+ getOptionLabel: (option) => option.title,
+ });
+
+ return (
+
+
+
+ useAutocomplete
+
+
+
+ {groupedOptions.length > 0 ? (
+
+ {groupedOptions.map((option, index) => (
+ {option.title}
+ ))}
+
+ ) : null}
+
+ );
+}
+
+// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
+const top100Films = [
+ { title: 'The Shawshank Redemption', year: 1994 },
+ { title: 'The Godfather', year: 1972 },
+ { title: 'The Godfather: Part II', year: 1974 },
+ { title: 'The Dark Knight', year: 2008 },
+ { title: '12 Angry Men', year: 1957 },
+ { title: "Schindler's List", year: 1993 },
+ { title: 'Pulp Fiction', year: 1994 },
+ { title: 'The Lord of the Rings: The Return of the King', year: 2003 },
+ { title: 'The Good, the Bad and the Ugly', year: 1966 },
+ { title: 'Fight Club', year: 1999 },
+ { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
+ { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
+ { title: 'Forrest Gump', year: 1994 },
+ { title: 'Inception', year: 2010 },
+ { title: 'The Lord of the Rings: The Two Towers', year: 2002 },
+ { title: "One Flew Over the Cuckoo's Nest", year: 1975 },
+ { title: 'Goodfellas', year: 1990 },
+ { title: 'The Matrix', year: 1999 },
+ { title: 'Seven Samurai', year: 1954 },
+ { title: 'Star Wars: Episode IV - A New Hope', year: 1977 },
+ { title: 'City of God', year: 2002 },
+ { title: 'Se7en', year: 1995 },
+ { title: 'The Silence of the Lambs', year: 1991 },
+ { title: "It's a Wonderful Life", year: 1946 },
+ { title: 'Life Is Beautiful', year: 1997 },
+ { title: 'The Usual Suspects', year: 1995 },
+ { title: 'Léon: The Professional', year: 1994 },
+ { title: 'Spirited Away', year: 2001 },
+ { title: 'Saving Private Ryan', year: 1998 },
+ { title: 'Once Upon a Time in the West', year: 1968 },
+ { title: 'American History X', year: 1998 },
+ { title: 'Interstellar', year: 2014 },
+ { title: 'Casablanca', year: 1942 },
+ { title: 'City Lights', year: 1931 },
+ { title: 'Psycho', year: 1960 },
+ { title: 'The Green Mile', year: 1999 },
+ { title: 'The Intouchables', year: 2011 },
+ { title: 'Modern Times', year: 1936 },
+ { title: 'Raiders of the Lost Ark', year: 1981 },
+ { title: 'Rear Window', year: 1954 },
+ { title: 'The Pianist', year: 2002 },
+ { title: 'The Departed', year: 2006 },
+ { title: 'Terminator 2: Judgment Day', year: 1991 },
+ { title: 'Back to the Future', year: 1985 },
+ { title: 'Whiplash', year: 2014 },
+ { title: 'Gladiator', year: 2000 },
+ { title: 'Memento', year: 2000 },
+ { title: 'The Prestige', year: 2006 },
+ { title: 'The Lion King', year: 1994 },
+ { title: 'Apocalypse Now', year: 1979 },
+ { title: 'Alien', year: 1979 },
+ { title: 'Sunset Boulevard', year: 1950 },
+ { title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', year: 1964 },
+ { title: 'The Great Dictator', year: 1940 },
+ { title: 'Cinema Paradiso', year: 1988 },
+ { title: 'The Lives of Others', year: 2006 },
+ { title: 'Grave of the Fireflies', year: 1988 },
+ { title: 'Paths of Glory', year: 1957 },
+ { title: 'Django Unchained', year: 2012 },
+ { title: 'The Shining', year: 1980 },
+ { title: 'WALL·E', year: 2008 },
+ { title: 'American Beauty', year: 1999 },
+ { title: 'The Dark Knight Rises', year: 2012 },
+ { title: 'Princess Mononoke', year: 1997 },
+ { title: 'Aliens', year: 1986 },
+ { title: 'Oldboy', year: 2003 },
+ { title: 'Once Upon a Time in America', year: 1984 },
+ { title: 'Witness for the Prosecution', year: 1957 },
+ { title: 'Das Boot', year: 1981 },
+ { title: 'Citizen Kane', year: 1941 },
+ { title: 'North by Northwest', year: 1959 },
+ { title: 'Vertigo', year: 1958 },
+ { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 },
+ { title: 'Reservoir Dogs', year: 1992 },
+ { title: 'Braveheart', year: 1995 },
+ { title: 'M', year: 1931 },
+ { title: 'Requiem for a Dream', year: 2000 },
+ { title: 'Amélie', year: 2001 },
+ { title: 'A Clockwork Orange', year: 1971 },
+ { title: 'Like Stars on Earth', year: 2007 },
+ { title: 'Taxi Driver', year: 1976 },
+ { title: 'Lawrence of Arabia', year: 1962 },
+ { title: 'Double Indemnity', year: 1944 },
+ { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 },
+ { title: 'Amadeus', year: 1984 },
+ { title: 'To Kill a Mockingbird', year: 1962 },
+ { title: 'Toy Story 3', year: 2010 },
+ { title: 'Logan', year: 2017 },
+ { title: 'Full Metal Jacket', year: 1987 },
+ { title: 'Dangal', year: 2016 },
+ { title: 'The Sting', year: 1973 },
+ { title: '2001: A Space Odyssey', year: 1968 },
+ { title: "Singin' in the Rain", year: 1952 },
+ { title: 'Toy Story', year: 1995 },
+ { title: 'Bicycle Thieves', year: 1948 },
+ { title: 'The Kid', year: 1921 },
+ { title: 'Inglourious Basterds', year: 2009 },
+ { title: 'Snatch', year: 2000 },
+ { title: '3 Idiots', year: 2009 },
+ { title: 'Monty Python and the Holy Grail', year: 1975 },
+];
+
+export default {
+ title: "Material-ui|autocomplete|UseAutocomplete.stories"
+};
diff --git a/examples/storybook/stories/material-ui/autocomplete/Virtualize.stories.tsx b/examples/storybook/stories/material-ui/autocomplete/Virtualize.stories.tsx
new file mode 100644
index 00000000000000..8da972f1af6335
--- /dev/null
+++ b/examples/storybook/stories/material-ui/autocomplete/Virtualize.stories.tsx
@@ -0,0 +1,139 @@
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import Autocomplete, { AutocompleteRenderGroupParams } from '@material-ui/lab/Autocomplete';
+import useMediaQuery from '@material-ui/core/useMediaQuery';
+import ListSubheader from '@material-ui/core/ListSubheader';
+import { useTheme, makeStyles } from '@material-ui/core/styles';
+import { VariableSizeList, ListChildComponentProps } from 'react-window';
+import { Typography } from '@material-ui/core';
+
+const LISTBOX_PADDING = 8; // px
+
+function renderRow(props: ListChildComponentProps) {
+ const { data, index, style } = props;
+ return React.cloneElement(data[index], {
+ style: {
+ ...style,
+ top: (style.top as number) + LISTBOX_PADDING,
+ },
+ });
+}
+
+const OuterElementContext = React.createContext({});
+
+const OuterElementType = React.forwardRef((props, ref) => {
+ const outerProps = React.useContext(OuterElementContext);
+ return
;
+});
+
+function useResetCache(data: any) {
+ const ref = React.useRef(null);
+ React.useEffect(() => {
+ if (ref.current != null) {
+ ref.current.resetAfterIndex(0, true);
+ }
+ }, [data]);
+ return ref;
+}
+
+// Adapter for react-window
+const ListboxComponent = React.forwardRef(function ListboxComponent(props, ref) {
+ const { children, ...other } = props;
+ const itemData = React.Children.toArray(children);
+ const theme = useTheme();
+ const smUp = useMediaQuery(theme.breakpoints.up('sm'), { noSsr: true });
+ const itemCount = itemData.length;
+ const itemSize = smUp ? 36 : 48;
+
+ const getChildSize = (child: React.ReactNode) => {
+ if (React.isValidElement(child) && child.type === ListSubheader) {
+ return 48;
+ }
+
+ return itemSize;
+ };
+
+ const getHeight = () => {
+ if (itemCount > 8) {
+ return 8 * itemSize;
+ }
+ return itemData.map(getChildSize).reduce((a, b) => a + b, 0);
+ };
+
+ const gridRef = useResetCache(itemCount);
+
+ return (
+
+
+ getChildSize(itemData[index])}
+ overscanCount={5}
+ itemCount={itemCount}
+ >
+ {renderRow}
+
+
+
+ );
+});
+
+function random(length: number) {
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+ let result = '';
+
+ for (let i = 0; i < length; i += 1) {
+ result += characters.charAt(Math.floor(Math.random() * characters.length));
+ }
+
+ return result;
+}
+
+const useStyles = makeStyles({
+ listbox: {
+ boxSizing: 'border-box',
+ '& ul': {
+ padding: 0,
+ margin: 0,
+ },
+ },
+});
+
+const OPTIONS = Array.from(new Array(10000))
+ .map(() => random(10 + Math.ceil(Math.random() * 20)))
+ .sort((a: string, b: string) => a.toUpperCase().localeCompare(b.toUpperCase()));
+
+const renderGroup = (params: AutocompleteRenderGroupParams) => [
+
+ {params.group}
+ ,
+ params.children,
+];
+
+export function Virtualize() {
+ const classes = useStyles();
+
+ return (
+ >}
+ renderGroup={renderGroup}
+ options={OPTIONS}
+ groupBy={(option) => option[0].toUpperCase()}
+ renderInput={(params) => }
+ renderOption={(option) => {option} }
+ />
+ );
+}
+
+export default {
+ title: "Material-ui|autocomplete|Virtualize.stories"
+};
diff --git a/examples/storybook/stories/material-ui/avatars/BadgeAvatars.stories.tsx b/examples/storybook/stories/material-ui/avatars/BadgeAvatars.stories.tsx
new file mode 100644
index 00000000000000..e7c13d5fd22d08
--- /dev/null
+++ b/examples/storybook/stories/material-ui/avatars/BadgeAvatars.stories.tsx
@@ -0,0 +1,89 @@
+import React from 'react';
+import Badge from '@material-ui/core/Badge';
+import Avatar from '@material-ui/core/Avatar';
+import { Theme, makeStyles, withStyles, createStyles } from '@material-ui/core/styles';
+
+const StyledBadge = withStyles((theme: Theme) =>
+ createStyles({
+ badge: {
+ backgroundColor: '#44b700',
+ color: '#44b700',
+ boxShadow: `0 0 0 2px ${theme.palette.background.paper}`,
+ '&::after': {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ width: '100%',
+ height: '100%',
+ borderRadius: '50%',
+ animation: '$ripple 1.2s infinite ease-in-out',
+ border: '1px solid currentColor',
+ content: '""',
+ },
+ },
+ '@keyframes ripple': {
+ '0%': {
+ transform: 'scale(.8)',
+ opacity: 1,
+ },
+ '100%': {
+ transform: 'scale(2.4)',
+ opacity: 0,
+ },
+ },
+ }),
+)(Badge);
+
+const SmallAvatar = withStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 22,
+ height: 22,
+ border: `2px solid ${theme.palette.background.paper}`,
+ },
+ }),
+)(Avatar);
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function BadgeAvatars() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|avatars|BadgeAvatars.stories"
+};
diff --git a/examples/storybook/stories/material-ui/avatars/FallbackAvatars.stories.tsx b/examples/storybook/stories/material-ui/avatars/FallbackAvatars.stories.tsx
new file mode 100644
index 00000000000000..80699f72c11704
--- /dev/null
+++ b/examples/storybook/stories/material-ui/avatars/FallbackAvatars.stories.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Avatar from '@material-ui/core/Avatar';
+import { deepOrange } from '@material-ui/core/colors';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ orange: {
+ color: theme.palette.getContrastText(deepOrange[500]),
+ backgroundColor: deepOrange[500],
+ },
+ }),
+);
+
+export function FallbackAvatars() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|avatars|FallbackAvatars.stories"
+};
diff --git a/examples/storybook/stories/material-ui/avatars/GroupAvatars.stories.tsx b/examples/storybook/stories/material-ui/avatars/GroupAvatars.stories.tsx
new file mode 100644
index 00000000000000..df1085aa03f7c5
--- /dev/null
+++ b/examples/storybook/stories/material-ui/avatars/GroupAvatars.stories.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import Avatar from '@material-ui/core/Avatar';
+import AvatarGroup from '@material-ui/lab/AvatarGroup';
+
+export function GroupAvatars() {
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|avatars|GroupAvatars.stories"
+};
diff --git a/examples/storybook/stories/material-ui/avatars/IconAvatars.stories.tsx b/examples/storybook/stories/material-ui/avatars/IconAvatars.stories.tsx
new file mode 100644
index 00000000000000..d57aff8e0459f9
--- /dev/null
+++ b/examples/storybook/stories/material-ui/avatars/IconAvatars.stories.tsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import { green, pink } from '@material-ui/core/colors';
+import Avatar from '@material-ui/core/Avatar';
+import FolderIcon from '@material-ui/icons/Folder';
+import PageviewIcon from '@material-ui/icons/Pageview';
+import AssignmentIcon from '@material-ui/icons/Assignment';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ pink: {
+ color: theme.palette.getContrastText(pink[500]),
+ backgroundColor: pink[500],
+ },
+ green: {
+ color: '#fff',
+ backgroundColor: green[500],
+ },
+ }),
+);
+
+export function IconAvatars() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|avatars|IconAvatars.stories"
+};
diff --git a/examples/storybook/stories/material-ui/avatars/ImageAvatars.stories.tsx b/examples/storybook/stories/material-ui/avatars/ImageAvatars.stories.tsx
new file mode 100644
index 00000000000000..9184f39cf5d96a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/avatars/ImageAvatars.stories.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Avatar from '@material-ui/core/Avatar';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function ImageAvatars() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|avatars|ImageAvatars.stories"
+};
diff --git a/examples/storybook/stories/material-ui/avatars/LetterAvatars.stories.tsx b/examples/storybook/stories/material-ui/avatars/LetterAvatars.stories.tsx
new file mode 100644
index 00000000000000..7fb3b9ffc24848
--- /dev/null
+++ b/examples/storybook/stories/material-ui/avatars/LetterAvatars.stories.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Avatar from '@material-ui/core/Avatar';
+import { deepOrange, deepPurple } from '@material-ui/core/colors';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ orange: {
+ color: theme.palette.getContrastText(deepOrange[500]),
+ backgroundColor: deepOrange[500],
+ },
+ purple: {
+ color: theme.palette.getContrastText(deepPurple[500]),
+ backgroundColor: deepPurple[500],
+ },
+ }),
+);
+
+export function LetterAvatars() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|avatars|LetterAvatars.stories"
+};
diff --git a/examples/storybook/stories/material-ui/avatars/SizeAvatars.stories.tsx b/examples/storybook/stories/material-ui/avatars/SizeAvatars.stories.tsx
new file mode 100644
index 00000000000000..e933fbe6037f96
--- /dev/null
+++ b/examples/storybook/stories/material-ui/avatars/SizeAvatars.stories.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Avatar from '@material-ui/core/Avatar';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ small: {
+ width: theme.spacing(3),
+ height: theme.spacing(3),
+ },
+ large: {
+ width: theme.spacing(7),
+ height: theme.spacing(7),
+ },
+ }),
+);
+
+export function ImageAvatars() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|avatars|SizeAvatars.stories"
+};
diff --git a/examples/storybook/stories/material-ui/avatars/VariantAvatars.stories.tsx b/examples/storybook/stories/material-ui/avatars/VariantAvatars.stories.tsx
new file mode 100644
index 00000000000000..f3d9c4cfac3d16
--- /dev/null
+++ b/examples/storybook/stories/material-ui/avatars/VariantAvatars.stories.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Avatar from '@material-ui/core/Avatar';
+import { deepOrange, green } from '@material-ui/core/colors';
+import AssignmentIcon from '@material-ui/icons/Assignment';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ square: {
+ color: theme.palette.getContrastText(deepOrange[500]),
+ backgroundColor: deepOrange[500],
+ },
+ rounded: {
+ color: '#fff',
+ backgroundColor: green[500],
+ },
+ }),
+);
+
+export function VariantAvatars() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|avatars|VariantAvatars.stories"
+};
diff --git a/examples/storybook/stories/material-ui/backdrop/SimpleBackdrop.stories.tsx b/examples/storybook/stories/material-ui/backdrop/SimpleBackdrop.stories.tsx
new file mode 100644
index 00000000000000..849e55655fc056
--- /dev/null
+++ b/examples/storybook/stories/material-ui/backdrop/SimpleBackdrop.stories.tsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import Backdrop from '@material-ui/core/Backdrop';
+import CircularProgress from '@material-ui/core/CircularProgress';
+import Button from '@material-ui/core/Button';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ backdrop: {
+ zIndex: theme.zIndex.drawer + 1,
+ color: '#fff',
+ },
+ }),
+);
+
+export function SimpleBackdrop() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+ const handleClose = () => {
+ setOpen(false);
+ };
+ const handleToggle = () => {
+ setOpen(!open);
+ };
+
+ return (
+
+
+ Show backdrop
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|backdrop|SimpleBackdrop.stories"
+};
diff --git a/examples/storybook/stories/material-ui/badges/BadgeMax.stories.tsx b/examples/storybook/stories/material-ui/badges/BadgeMax.stories.tsx
new file mode 100644
index 00000000000000..f5d13310789d49
--- /dev/null
+++ b/examples/storybook/stories/material-ui/badges/BadgeMax.stories.tsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Badge from '@material-ui/core/Badge';
+import MailIcon from '@material-ui/icons/Mail';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+const defaultProps = {
+ color: 'secondary' as 'secondary',
+ children: ,
+};
+
+export function BadgeMax() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|badges|BadgeMax.stories"
+};
diff --git a/examples/storybook/stories/material-ui/badges/BadgeOverlap.stories.tsx b/examples/storybook/stories/material-ui/badges/BadgeOverlap.stories.tsx
new file mode 100644
index 00000000000000..f824f26e5ad124
--- /dev/null
+++ b/examples/storybook/stories/material-ui/badges/BadgeOverlap.stories.tsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import clsx from 'clsx';
+import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
+import Badge from '@material-ui/core/Badge';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ shape: {
+ backgroundColor: theme.palette.primary.main,
+ width: 40,
+ height: 40,
+ },
+ shapeCircle: {
+ borderRadius: '50%',
+ },
+ }),
+);
+
+export function BadgeOverlap() {
+ const classes = useStyles();
+
+ const rectangle =
;
+ const circle =
;
+
+ return (
+
+
+ {rectangle}
+
+
+ {rectangle}
+
+
+ {circle}
+
+
+ {circle}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|badges|BadgeOverlap.stories"
+};
diff --git a/examples/storybook/stories/material-ui/badges/BadgeVisibility.stories.tsx b/examples/storybook/stories/material-ui/badges/BadgeVisibility.stories.tsx
new file mode 100644
index 00000000000000..d53bf663b3189c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/badges/BadgeVisibility.stories.tsx
@@ -0,0 +1,76 @@
+import React from 'react';
+import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
+import Badge from '@material-ui/core/Badge';
+import ButtonGroup from '@material-ui/core/ButtonGroup';
+import Button from '@material-ui/core/Button';
+import AddIcon from '@material-ui/icons/Add';
+import RemoveIcon from '@material-ui/icons/Remove';
+import MailIcon from '@material-ui/icons/Mail';
+import Switch from '@material-ui/core/Switch';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ flexDirection: 'column',
+ '& > *': {
+ marginBottom: theme.spacing(2),
+ },
+ '& .MuiBadge-root': {
+ marginRight: theme.spacing(4),
+ },
+ },
+ }),
+);
+
+export function BadgeVisibility() {
+ const classes = useStyles();
+ const [count, setCount] = React.useState(1);
+ const [invisible, setInvisible] = React.useState(false);
+
+ const handleBadgeVisibility = () => {
+ setInvisible(!invisible);
+ };
+
+ return (
+
+
+
+
+
+
+ {
+ setCount(Math.max(count - 1, 0));
+ }}
+ >
+
+
+ {
+ setCount(count + 1);
+ }}
+ >
+
+
+
+
+
+
+
+
+ }
+ label="Show Badge"
+ />
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|badges|BadgeVisibility.stories"
+};
diff --git a/examples/storybook/stories/material-ui/badges/CustomizedBadges.stories.tsx b/examples/storybook/stories/material-ui/badges/CustomizedBadges.stories.tsx
new file mode 100644
index 00000000000000..3da227af128a0e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/badges/CustomizedBadges.stories.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import Badge from '@material-ui/core/Badge';
+import { Theme, withStyles, createStyles } from '@material-ui/core/styles';
+import IconButton from '@material-ui/core/IconButton';
+import ShoppingCartIcon from '@material-ui/icons/ShoppingCart';
+
+const StyledBadge = withStyles((theme: Theme) =>
+ createStyles({
+ badge: {
+ right: -3,
+ top: 13,
+ border: `2px solid ${theme.palette.background.paper}`,
+ padding: '0 4px',
+ },
+ }),
+)(Badge);
+
+export function CustomizedBadges() {
+ return (
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|badges|CustomizedBadges.stories"
+};
diff --git a/examples/storybook/stories/material-ui/badges/DotBadge.stories.tsx b/examples/storybook/stories/material-ui/badges/DotBadge.stories.tsx
new file mode 100644
index 00000000000000..e823f726a72c44
--- /dev/null
+++ b/examples/storybook/stories/material-ui/badges/DotBadge.stories.tsx
@@ -0,0 +1,34 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Badge from '@material-ui/core/Badge';
+import MailIcon from '@material-ui/icons/Mail';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function DotBadge() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+ Typography
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|badges|DotBadge.stories"
+};
diff --git a/examples/storybook/stories/material-ui/badges/ShowZeroBadge.stories.tsx b/examples/storybook/stories/material-ui/badges/ShowZeroBadge.stories.tsx
new file mode 100644
index 00000000000000..736f1ddbd19b2c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/badges/ShowZeroBadge.stories.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
+import Badge from '@material-ui/core/Badge';
+import MailIcon from '@material-ui/icons/Mail';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function ShowZeroBadge() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|badges|ShowZeroBadge.stories"
+};
diff --git a/examples/storybook/stories/material-ui/badges/SimpleBadge.stories.tsx b/examples/storybook/stories/material-ui/badges/SimpleBadge.stories.tsx
new file mode 100644
index 00000000000000..22f254969b9aee
--- /dev/null
+++ b/examples/storybook/stories/material-ui/badges/SimpleBadge.stories.tsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Badge from '@material-ui/core/Badge';
+import MailIcon from '@material-ui/icons/Mail';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function SimpleBadge() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|badges|SimpleBadge.stories"
+};
diff --git a/examples/storybook/stories/material-ui/bottom-navigation/LabelBottomNavigation.stories.tsx b/examples/storybook/stories/material-ui/bottom-navigation/LabelBottomNavigation.stories.tsx
new file mode 100644
index 00000000000000..8c9986881339b8
--- /dev/null
+++ b/examples/storybook/stories/material-ui/bottom-navigation/LabelBottomNavigation.stories.tsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import BottomNavigation from '@material-ui/core/BottomNavigation';
+import BottomNavigationAction from '@material-ui/core/BottomNavigationAction';
+import FolderIcon from '@material-ui/icons/Folder';
+import RestoreIcon from '@material-ui/icons/Restore';
+import FavoriteIcon from '@material-ui/icons/Favorite';
+import LocationOnIcon from '@material-ui/icons/LocationOn';
+
+const useStyles = makeStyles({
+ root: {
+ width: 500,
+ },
+});
+
+export function LabelBottomNavigation() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState('recents');
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: string) => {
+ setValue(newValue);
+ };
+
+ return (
+
+ } />
+ } />
+ } />
+ } />
+
+ );
+}
+
+export default {
+ title: "Material-ui|bottom-navigation|LabelBottomNavigation.stories"
+};
diff --git a/examples/storybook/stories/material-ui/bottom-navigation/SimpleBottomNavigation.stories.tsx b/examples/storybook/stories/material-ui/bottom-navigation/SimpleBottomNavigation.stories.tsx
new file mode 100644
index 00000000000000..fef744947cce56
--- /dev/null
+++ b/examples/storybook/stories/material-ui/bottom-navigation/SimpleBottomNavigation.stories.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import BottomNavigation from '@material-ui/core/BottomNavigation';
+import BottomNavigationAction from '@material-ui/core/BottomNavigationAction';
+import RestoreIcon from '@material-ui/icons/Restore';
+import FavoriteIcon from '@material-ui/icons/Favorite';
+import LocationOnIcon from '@material-ui/icons/LocationOn';
+
+const useStyles = makeStyles({
+ root: {
+ width: 500,
+ },
+});
+
+export function SimpleBottomNavigation() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(0);
+
+ return (
+ {
+ setValue(newValue);
+ }}
+ showLabels
+ className={classes.root}
+ >
+ } />
+ } />
+ } />
+
+ );
+}
+
+export default {
+ title: "Material-ui|bottom-navigation|SimpleBottomNavigation.stories"
+};
diff --git a/examples/storybook/stories/material-ui/breadcrumbs/ActiveLastBreadcrumb.stories.tsx b/examples/storybook/stories/material-ui/breadcrumbs/ActiveLastBreadcrumb.stories.tsx
new file mode 100644
index 00000000000000..9aaee6bda20e78
--- /dev/null
+++ b/examples/storybook/stories/material-ui/breadcrumbs/ActiveLastBreadcrumb.stories.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import Breadcrumbs from '@material-ui/core/Breadcrumbs';
+import Link from '@material-ui/core/Link';
+
+function handleClick(event: React.MouseEvent) {
+ event.preventDefault();
+ console.info('You clicked a breadcrumb.');
+}
+
+export function ActiveLastBreadcrumb() {
+ return (
+
+
+ Material-UI
+
+
+ Core
+
+
+ Breadcrumb
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|breadcrumbs|ActiveLastBreadcrumb.stories"
+};
diff --git a/examples/storybook/stories/material-ui/breadcrumbs/CollapsedBreadcrumbs.stories.tsx b/examples/storybook/stories/material-ui/breadcrumbs/CollapsedBreadcrumbs.stories.tsx
new file mode 100644
index 00000000000000..7a5405c386aefb
--- /dev/null
+++ b/examples/storybook/stories/material-ui/breadcrumbs/CollapsedBreadcrumbs.stories.tsx
@@ -0,0 +1,34 @@
+/* eslint-disable jsx-a11y/anchor-is-valid */
+import React from 'react';
+import Breadcrumbs from '@material-ui/core/Breadcrumbs';
+import Typography from '@material-ui/core/Typography';
+import Link from '@material-ui/core/Link';
+
+function handleClick(event: React.MouseEvent) {
+ event.preventDefault();
+ console.info('You clicked a breadcrumb.');
+}
+
+export function CollapsedBreadcrumbs() {
+ return (
+
+
+ Home
+
+
+ Catalog
+
+
+ Accessories
+
+
+ New Collection
+
+ Belts
+
+ );
+}
+
+export default {
+ title: "Material-ui|breadcrumbs|CollapsedBreadcrumbs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/breadcrumbs/CustomSeparator.stories.tsx b/examples/storybook/stories/material-ui/breadcrumbs/CustomSeparator.stories.tsx
new file mode 100644
index 00000000000000..f7de86aeb0fe03
--- /dev/null
+++ b/examples/storybook/stories/material-ui/breadcrumbs/CustomSeparator.stories.tsx
@@ -0,0 +1,61 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Breadcrumbs from '@material-ui/core/Breadcrumbs';
+import Typography from '@material-ui/core/Typography';
+import Link from '@material-ui/core/Link';
+import NavigateNextIcon from '@material-ui/icons/NavigateNext';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+function handleClick(event: React.MouseEvent) {
+ event.preventDefault();
+ console.info('You clicked a breadcrumb.');
+}
+
+export function CustomSeparator() {
+ const classes = useStyles();
+
+ return (
+
+
+
+ Material-UI
+
+
+ Core
+
+ Breadcrumb
+
+
+
+ Material-UI
+
+
+ Core
+
+ Breadcrumb
+
+ } aria-label="breadcrumb">
+
+ Material-UI
+
+
+ Core
+
+ Breadcrumb
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|breadcrumbs|CustomSeparator.stories"
+};
diff --git a/examples/storybook/stories/material-ui/breadcrumbs/CustomizedBreadcrumbs.stories.tsx b/examples/storybook/stories/material-ui/breadcrumbs/CustomizedBreadcrumbs.stories.tsx
new file mode 100644
index 00000000000000..1dcc651249cac5
--- /dev/null
+++ b/examples/storybook/stories/material-ui/breadcrumbs/CustomizedBreadcrumbs.stories.tsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import { emphasize, withStyles, Theme } from '@material-ui/core/styles';
+import Breadcrumbs from '@material-ui/core/Breadcrumbs';
+import Chip from '@material-ui/core/Chip';
+import HomeIcon from '@material-ui/icons/Home';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+
+const StyledBreadcrumb = withStyles((theme: Theme) => ({
+ root: {
+ backgroundColor: theme.palette.grey[100],
+ height: theme.spacing(3),
+ color: theme.palette.grey[800],
+ fontWeight: theme.typography.fontWeightRegular,
+ '&:hover, &:focus': {
+ backgroundColor: theme.palette.grey[300],
+ },
+ '&:active': {
+ boxShadow: theme.shadows[1],
+ backgroundColor: emphasize(theme.palette.grey[300], 0.12),
+ },
+ },
+}))(Chip) as typeof Chip; // TypeScript only: need a type cast here because https://github.com/Microsoft/TypeScript/issues/26591
+
+function handleClick(event: React.MouseEvent) {
+ event.preventDefault();
+ console.info('You clicked a breadcrumb.');
+}
+
+export function CustomizedBreadcrumbs() {
+ return (
+
+ }
+ onClick={handleClick}
+ />
+
+ }
+ onClick={handleClick}
+ onDelete={handleClick}
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|breadcrumbs|CustomizedBreadcrumbs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/breadcrumbs/IconBreadcrumbs.stories.tsx b/examples/storybook/stories/material-ui/breadcrumbs/IconBreadcrumbs.stories.tsx
new file mode 100644
index 00000000000000..5dc0b14591dd50
--- /dev/null
+++ b/examples/storybook/stories/material-ui/breadcrumbs/IconBreadcrumbs.stories.tsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Breadcrumbs from '@material-ui/core/Breadcrumbs';
+import Link from '@material-ui/core/Link';
+import HomeIcon from '@material-ui/icons/Home';
+import WhatshotIcon from '@material-ui/icons/Whatshot';
+import GrainIcon from '@material-ui/icons/Grain';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ link: {
+ display: 'flex',
+ },
+ icon: {
+ marginRight: theme.spacing(0.5),
+ width: 20,
+ height: 20,
+ },
+ }),
+);
+
+function handleClick(event: React.MouseEvent) {
+ event.preventDefault();
+ console.info('You clicked a breadcrumb.');
+}
+
+export function IconBreadcrumbs() {
+ const classes = useStyles();
+
+ return (
+
+
+
+ Material-UI
+
+
+
+ Core
+
+
+
+ Breadcrumb
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|breadcrumbs|IconBreadcrumbs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/breadcrumbs/RouterBreadcrumbs.stories.tsx b/examples/storybook/stories/material-ui/breadcrumbs/RouterBreadcrumbs.stories.tsx
new file mode 100644
index 00000000000000..3ab5992e8c71af
--- /dev/null
+++ b/examples/storybook/stories/material-ui/breadcrumbs/RouterBreadcrumbs.stories.tsx
@@ -0,0 +1,125 @@
+/* eslint-disable no-nested-ternary */
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import Link, { LinkProps } from '@material-ui/core/Link';
+import ListItem from '@material-ui/core/ListItem';
+import Collapse from '@material-ui/core/Collapse';
+import ListItemText from '@material-ui/core/ListItemText';
+import Typography from '@material-ui/core/Typography';
+import ExpandLess from '@material-ui/icons/ExpandLess';
+import ExpandMore from '@material-ui/icons/ExpandMore';
+import Breadcrumbs from '@material-ui/core/Breadcrumbs';
+import { Route, MemoryRouter } from 'react-router';
+import { Link as RouterLink } from 'react-router-dom';
+import { Omit } from '@material-ui/types';
+
+interface ListItemLinkProps extends LinkProps {
+ to: string;
+ open?: boolean;
+}
+
+const breadcrumbNameMap: { [key: string]: string } = {
+ '/inbox': 'Inbox',
+ '/inbox/important': 'Important',
+ '/trash': 'Trash',
+ '/spam': 'Spam',
+ '/drafts': 'Drafts',
+};
+
+function ListItemLink(props: Omit) {
+ const { to, open, ...other } = props;
+ const primary = breadcrumbNameMap[to];
+
+ return (
+
+
+
+ {open != null ? open ? : : null}
+
+
+ );
+}
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ flexDirection: 'column',
+ width: 360,
+ },
+ lists: {
+ backgroundColor: theme.palette.background.paper,
+ marginTop: theme.spacing(1),
+ },
+ nested: {
+ paddingLeft: theme.spacing(4),
+ },
+ }),
+);
+
+interface LinkRouterProps extends LinkProps {
+ to: string;
+ replace?: boolean;
+}
+
+const LinkRouter = (props: LinkRouterProps) => ;
+
+export function RouterBreadcrumbs() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(true);
+
+ const handleClick = () => {
+ setOpen((prevOpen) => !prevOpen);
+ };
+
+ return (
+
+
+
+ {({ location }) => {
+ const pathnames = location.pathname.split('/').filter((x) => x);
+
+ return (
+
+
+ Home
+
+ {pathnames.map((value, index) => {
+ const last = index === pathnames.length - 1;
+ const to = `/${pathnames.slice(0, index + 1).join('/')}`;
+
+ return last ? (
+
+ {breadcrumbNameMap[to]}
+
+ ) : (
+
+ {breadcrumbNameMap[to]}
+
+ );
+ })}
+
+ );
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|breadcrumbs|RouterBreadcrumbs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/breadcrumbs/SimpleBreadcrumbs.stories.tsx b/examples/storybook/stories/material-ui/breadcrumbs/SimpleBreadcrumbs.stories.tsx
new file mode 100644
index 00000000000000..ded95bbfe307ee
--- /dev/null
+++ b/examples/storybook/stories/material-ui/breadcrumbs/SimpleBreadcrumbs.stories.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import Typography from '@material-ui/core/Typography';
+import Breadcrumbs from '@material-ui/core/Breadcrumbs';
+import Link from '@material-ui/core/Link';
+
+function handleClick(event: React.MouseEvent) {
+ event.preventDefault();
+ console.info('You clicked a breadcrumb.');
+}
+
+export function SimpleBreadcrumbs() {
+ return (
+
+
+ Material-UI
+
+
+ Core
+
+ Breadcrumb
+
+ );
+}
+
+export default {
+ title: "Material-ui|breadcrumbs|SimpleBreadcrumbs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/button-group/BasicButtonGroup.stories.tsx b/examples/storybook/stories/material-ui/button-group/BasicButtonGroup.stories.tsx
new file mode 100644
index 00000000000000..fad02513e47880
--- /dev/null
+++ b/examples/storybook/stories/material-ui/button-group/BasicButtonGroup.stories.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import ButtonGroup from '@material-ui/core/ButtonGroup';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function BasicButtonGroup() {
+ const classes = useStyles();
+
+ return (
+
+
+ One
+ Two
+ Three
+
+
+ One
+ Two
+ Three
+
+
+ One
+ Two
+ Three
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|button-group|BasicButtonGroup.stories"
+};
diff --git a/examples/storybook/stories/material-ui/button-group/DisableElevation.stories.tsx b/examples/storybook/stories/material-ui/button-group/DisableElevation.stories.tsx
new file mode 100644
index 00000000000000..7331c719bb8396
--- /dev/null
+++ b/examples/storybook/stories/material-ui/button-group/DisableElevation.stories.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import ButtonGroup from '@material-ui/core/ButtonGroup';
+import Button from '@material-ui/core/Button';
+
+export function DisableElevation() {
+ return (
+
+ One
+ Two
+
+ );
+}
+
+export default {
+ title: "Material-ui|button-group|DisableElevation.stories"
+};
diff --git a/examples/storybook/stories/material-ui/button-group/GroupOrientation.stories.tsx b/examples/storybook/stories/material-ui/button-group/GroupOrientation.stories.tsx
new file mode 100644
index 00000000000000..8d0dd0eb23cd93
--- /dev/null
+++ b/examples/storybook/stories/material-ui/button-group/GroupOrientation.stories.tsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import ButtonGroup from '@material-ui/core/ButtonGroup';
+import { makeStyles } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme) => ({
+ root: {
+ display: 'flex',
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+}));
+
+export function GroupOrientation() {
+ const classes = useStyles();
+
+ return (
+
+
+ One
+ Two
+ Three
+
+
+ One
+ Two
+ Three
+
+
+ One
+ Two
+ Three
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|button-group|GroupOrientation.stories"
+};
diff --git a/examples/storybook/stories/material-ui/button-group/GroupSizesColors.stories.tsx b/examples/storybook/stories/material-ui/button-group/GroupSizesColors.stories.tsx
new file mode 100644
index 00000000000000..3bb1e17545fead
--- /dev/null
+++ b/examples/storybook/stories/material-ui/button-group/GroupSizesColors.stories.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import ButtonGroup from '@material-ui/core/ButtonGroup';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function GroupSizesColors() {
+ const classes = useStyles();
+
+ return (
+
+
+ One
+ Two
+ Three
+
+
+ One
+ Two
+ Three
+
+
+ One
+ Two
+ Three
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|button-group|GroupSizesColors.stories"
+};
diff --git a/examples/storybook/stories/material-ui/button-group/SplitButton.stories.tsx b/examples/storybook/stories/material-ui/button-group/SplitButton.stories.tsx
new file mode 100644
index 00000000000000..6acdd65fe98ac3
--- /dev/null
+++ b/examples/storybook/stories/material-ui/button-group/SplitButton.stories.tsx
@@ -0,0 +1,95 @@
+import React from 'react';
+import Grid from '@material-ui/core/Grid';
+import Button from '@material-ui/core/Button';
+import ButtonGroup from '@material-ui/core/ButtonGroup';
+import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
+import ClickAwayListener from '@material-ui/core/ClickAwayListener';
+import Grow from '@material-ui/core/Grow';
+import Paper from '@material-ui/core/Paper';
+import Popper from '@material-ui/core/Popper';
+import MenuItem from '@material-ui/core/MenuItem';
+import MenuList from '@material-ui/core/MenuList';
+
+const options = ['Create a merge commit', 'Squash and merge', 'Rebase and merge'];
+
+export function SplitButton() {
+ const [open, setOpen] = React.useState(false);
+ const anchorRef = React.useRef(null);
+ const [selectedIndex, setSelectedIndex] = React.useState(1);
+
+ const handleClick = () => {
+ console.info(`You clicked ${options[selectedIndex]}`);
+ };
+
+ const handleMenuItemClick = (
+ event: React.MouseEvent,
+ index: number,
+ ) => {
+ setSelectedIndex(index);
+ setOpen(false);
+ };
+
+ const handleToggle = () => {
+ setOpen((prevOpen) => !prevOpen);
+ };
+
+ const handleClose = (event: React.MouseEvent) => {
+ if (anchorRef.current && anchorRef.current.contains(event.target as HTMLElement)) {
+ return;
+ }
+
+ setOpen(false);
+ };
+
+ return (
+
+
+
+ {options[selectedIndex]}
+
+
+
+
+
+ {({ TransitionProps, placement }) => (
+
+
+
+
+
+
+
+ )}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|button-group|SplitButton.stories"
+};
diff --git a/examples/storybook/stories/material-ui/buttons/ButtonBase.stories.tsx b/examples/storybook/stories/material-ui/buttons/ButtonBase.stories.tsx
new file mode 100644
index 00000000000000..75e37700d580dc
--- /dev/null
+++ b/examples/storybook/stories/material-ui/buttons/ButtonBase.stories.tsx
@@ -0,0 +1,140 @@
+import React from 'react';
+import { Theme, makeStyles, createStyles } from '@material-ui/core/styles';
+import ButtonBase from '@material-ui/core/ButtonBase';
+import Typography from '@material-ui/core/Typography';
+
+const images = [
+ {
+ url: '/static/images/grid-list/breakfast.jpg',
+ title: 'Breakfast',
+ width: '40%',
+ },
+ {
+ url: '/static/images/grid-list/burgers.jpg',
+ title: 'Burgers',
+ width: '30%',
+ },
+ {
+ url: '/static/images/grid-list/camera.jpg',
+ title: 'Camera',
+ width: '30%',
+ },
+];
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ minWidth: 300,
+ width: '100%',
+ },
+ image: {
+ position: 'relative',
+ height: 200,
+ [theme.breakpoints.down('xs')]: {
+ width: '100% !important', // Overrides inline-style
+ height: 100,
+ },
+ '&:hover, &$focusVisible': {
+ zIndex: 1,
+ '& $imageBackdrop': {
+ opacity: 0.15,
+ },
+ '& $imageMarked': {
+ opacity: 0,
+ },
+ '& $imageTitle': {
+ border: '4px solid currentColor',
+ },
+ },
+ },
+ focusVisible: {},
+ imageButton: {
+ position: 'absolute',
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0,
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ color: theme.palette.common.white,
+ },
+ imageSrc: {
+ position: 'absolute',
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0,
+ backgroundSize: 'cover',
+ backgroundPosition: 'center 40%',
+ },
+ imageBackdrop: {
+ position: 'absolute',
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0,
+ backgroundColor: theme.palette.common.black,
+ opacity: 0.4,
+ transition: theme.transitions.create('opacity'),
+ },
+ imageTitle: {
+ position: 'relative',
+ padding: `${theme.spacing(2)}px ${theme.spacing(4)}px ${theme.spacing(1) + 6}px`,
+ },
+ imageMarked: {
+ height: 3,
+ width: 18,
+ backgroundColor: theme.palette.common.white,
+ position: 'absolute',
+ bottom: -2,
+ left: 'calc(50% - 9px)',
+ transition: theme.transitions.create('opacity'),
+ },
+ }),
+);
+
+export function ButtonBases() {
+ const classes = useStyles();
+
+ return (
+
+ {images.map((image) => (
+
+
+
+
+
+ {image.title}
+
+
+
+
+ ))}
+
+ );
+}
+
+export default {
+ title: "Material-ui|buttons|ButtonBase.stories"
+};
diff --git a/examples/storybook/stories/material-ui/buttons/ButtonSizes.stories.tsx b/examples/storybook/stories/material-ui/buttons/ButtonSizes.stories.tsx
new file mode 100644
index 00000000000000..c10ec601adc5d3
--- /dev/null
+++ b/examples/storybook/stories/material-ui/buttons/ButtonSizes.stories.tsx
@@ -0,0 +1,77 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import IconButton from '@material-ui/core/IconButton';
+import DeleteIcon from '@material-ui/icons/Delete';
+import ArrowDownwardIcon from '@material-ui/icons/ArrowDownward';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ margin: {
+ margin: theme.spacing(1),
+ },
+ extendedIcon: {
+ marginRight: theme.spacing(1),
+ },
+ }),
+);
+
+export function ButtonSizes() {
+ const classes = useStyles();
+
+ return (
+
+
+
+ Small
+
+
+ Medium
+
+
+ Large
+
+
+
+
+ Small
+
+
+ Medium
+
+
+ Large
+
+
+
+
+ Small
+
+
+ Medium
+
+
+ Large
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|buttons|ButtonSizes.stories"
+};
diff --git a/examples/storybook/stories/material-ui/buttons/ContainedButtons.stories.tsx b/examples/storybook/stories/material-ui/buttons/ContainedButtons.stories.tsx
new file mode 100644
index 00000000000000..f06e0b935002b6
--- /dev/null
+++ b/examples/storybook/stories/material-ui/buttons/ContainedButtons.stories.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function ContainedButtons() {
+ const classes = useStyles();
+
+ return (
+
+ Default
+
+ Primary
+
+
+ Secondary
+
+
+ Disabled
+
+
+ Link
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|buttons|ContainedButtons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/buttons/CustomizedButtons.stories.tsx b/examples/storybook/stories/material-ui/buttons/CustomizedButtons.stories.tsx
new file mode 100644
index 00000000000000..60e28019238cd2
--- /dev/null
+++ b/examples/storybook/stories/material-ui/buttons/CustomizedButtons.stories.tsx
@@ -0,0 +1,97 @@
+import React from 'react';
+import {
+ createMuiTheme,
+ createStyles,
+ withStyles,
+ makeStyles,
+ Theme,
+ ThemeProvider,
+} from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import { green, purple } from '@material-ui/core/colors';
+
+const BootstrapButton = withStyles({
+ root: {
+ boxShadow: 'none',
+ textTransform: 'none',
+ fontSize: 16,
+ padding: '6px 12px',
+ border: '1px solid',
+ lineHeight: 1.5,
+ backgroundColor: '#0063cc',
+ borderColor: '#0063cc',
+ fontFamily: [
+ '-apple-system',
+ 'BlinkMacSystemFont',
+ '"Segoe UI"',
+ 'Roboto',
+ '"Helvetica Neue"',
+ 'Arial',
+ 'sans-serif',
+ '"Apple Color Emoji"',
+ '"Segoe UI Emoji"',
+ '"Segoe UI Symbol"',
+ ].join(','),
+ '&:hover': {
+ backgroundColor: '#0069d9',
+ borderColor: '#0062cc',
+ boxShadow: 'none',
+ },
+ '&:active': {
+ boxShadow: 'none',
+ backgroundColor: '#0062cc',
+ borderColor: '#005cbf',
+ },
+ '&:focus': {
+ boxShadow: '0 0 0 0.2rem rgba(0,123,255,.5)',
+ },
+ },
+})(Button);
+
+const ColorButton = withStyles((theme: Theme) => ({
+ root: {
+ color: theme.palette.getContrastText(purple[500]),
+ backgroundColor: purple[500],
+ '&:hover': {
+ backgroundColor: purple[700],
+ },
+ },
+}))(Button);
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ margin: {
+ margin: theme.spacing(1),
+ },
+ }),
+);
+
+const theme = createMuiTheme({
+ palette: {
+ primary: green,
+ },
+});
+
+export function CustomizedButtons() {
+ const classes = useStyles();
+
+ return (
+
+
+ Custom CSS
+
+
+
+ Theme Provider
+
+
+
+ Bootstrap
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|buttons|CustomizedButtons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/buttons/DisableElevation.stories.tsx b/examples/storybook/stories/material-ui/buttons/DisableElevation.stories.tsx
new file mode 100644
index 00000000000000..bc78b123ea2528
--- /dev/null
+++ b/examples/storybook/stories/material-ui/buttons/DisableElevation.stories.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+
+export function DisableElevation() {
+ return (
+
+ Disable elevation
+
+ );
+}
+
+export default {
+ title: "Material-ui|buttons|DisableElevation.stories"
+};
diff --git a/examples/storybook/stories/material-ui/buttons/IconButtons.stories.tsx b/examples/storybook/stories/material-ui/buttons/IconButtons.stories.tsx
new file mode 100644
index 00000000000000..9c655703705989
--- /dev/null
+++ b/examples/storybook/stories/material-ui/buttons/IconButtons.stories.tsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import IconButton from '@material-ui/core/IconButton';
+import DeleteIcon from '@material-ui/icons/Delete';
+import AlarmIcon from '@material-ui/icons/Alarm';
+import AddShoppingCartIcon from '@material-ui/icons/AddShoppingCart';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function IconButtons() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|buttons|IconButtons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/buttons/IconLabelButtons.stories.tsx b/examples/storybook/stories/material-ui/buttons/IconLabelButtons.stories.tsx
new file mode 100644
index 00000000000000..c2f706b8ff3336
--- /dev/null
+++ b/examples/storybook/stories/material-ui/buttons/IconLabelButtons.stories.tsx
@@ -0,0 +1,81 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import DeleteIcon from '@material-ui/icons/Delete';
+import CloudUploadIcon from '@material-ui/icons/CloudUpload';
+import KeyboardVoiceIcon from '@material-ui/icons/KeyboardVoice';
+import Icon from '@material-ui/core/Icon';
+import SaveIcon from '@material-ui/icons/Save';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ button: {
+ margin: theme.spacing(1),
+ },
+ }),
+);
+
+export function IconLabelButtons() {
+ const classes = useStyles();
+
+ return (
+
+ }
+ >
+ Delete
+
+ {/* This Button uses a Font Icon, see the installation instructions in the Icon component docs. */}
+ send}
+ >
+ Send
+
+ }
+ >
+ Upload
+
+ }
+ >
+ Talk
+
+ }
+ >
+ Save
+
+ }
+ >
+ Save
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|buttons|IconLabelButtons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/buttons/OutlinedButtons.stories.tsx b/examples/storybook/stories/material-ui/buttons/OutlinedButtons.stories.tsx
new file mode 100644
index 00000000000000..ae970540d9df04
--- /dev/null
+++ b/examples/storybook/stories/material-ui/buttons/OutlinedButtons.stories.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function OutlinedButtons() {
+ const classes = useStyles();
+
+ return (
+
+ Default
+
+ Primary
+
+
+ Secondary
+
+
+ Disabled
+
+
+ Link
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|buttons|OutlinedButtons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/buttons/TextButtons.stories.tsx b/examples/storybook/stories/material-ui/buttons/TextButtons.stories.tsx
new file mode 100644
index 00000000000000..1c2d54d9acfe54
--- /dev/null
+++ b/examples/storybook/stories/material-ui/buttons/TextButtons.stories.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function TextButtons() {
+ const classes = useStyles();
+
+ return (
+
+ Default
+ Primary
+ Secondary
+ Disabled
+
+ Link
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|buttons|TextButtons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/buttons/UploadButtons.stories.tsx b/examples/storybook/stories/material-ui/buttons/UploadButtons.stories.tsx
new file mode 100644
index 00000000000000..a78570958437e2
--- /dev/null
+++ b/examples/storybook/stories/material-ui/buttons/UploadButtons.stories.tsx
@@ -0,0 +1,49 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import IconButton from '@material-ui/core/IconButton';
+import PhotoCamera from '@material-ui/icons/PhotoCamera';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ input: {
+ display: 'none',
+ },
+ }),
+);
+
+export function UploadButtons() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|buttons|UploadButtons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/cards/ImgMediaCard.stories.tsx b/examples/storybook/stories/material-ui/cards/ImgMediaCard.stories.tsx
new file mode 100644
index 00000000000000..42928bb6a5dc1e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/cards/ImgMediaCard.stories.tsx
@@ -0,0 +1,54 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Card from '@material-ui/core/Card';
+import CardActionArea from '@material-ui/core/CardActionArea';
+import CardActions from '@material-ui/core/CardActions';
+import CardContent from '@material-ui/core/CardContent';
+import CardMedia from '@material-ui/core/CardMedia';
+import Button from '@material-ui/core/Button';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles({
+ root: {
+ maxWidth: 345,
+ },
+});
+
+export function ImgMediaCard() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+ Lizard
+
+
+ Lizards are a widespread group of squamate reptiles, with over 6,000 species, ranging
+ across all continents except Antarctica
+
+
+
+
+
+ Share
+
+
+ Learn More
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|cards|ImgMediaCard.stories"
+};
diff --git a/examples/storybook/stories/material-ui/cards/MediaCard.stories.tsx b/examples/storybook/stories/material-ui/cards/MediaCard.stories.tsx
new file mode 100644
index 00000000000000..fc1b50962fe35f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/cards/MediaCard.stories.tsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Card from '@material-ui/core/Card';
+import CardActionArea from '@material-ui/core/CardActionArea';
+import CardActions from '@material-ui/core/CardActions';
+import CardContent from '@material-ui/core/CardContent';
+import CardMedia from '@material-ui/core/CardMedia';
+import Button from '@material-ui/core/Button';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles({
+ root: {
+ maxWidth: 345,
+ },
+ media: {
+ height: 140,
+ },
+});
+
+export function MediaCard() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+ Lizard
+
+
+ Lizards are a widespread group of squamate reptiles, with over 6,000 species, ranging
+ across all continents except Antarctica
+
+
+
+
+
+ Share
+
+
+ Learn More
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|cards|MediaCard.stories"
+};
diff --git a/examples/storybook/stories/material-ui/cards/MediaControlCard.stories.tsx b/examples/storybook/stories/material-ui/cards/MediaControlCard.stories.tsx
new file mode 100644
index 00000000000000..876946a197cbd4
--- /dev/null
+++ b/examples/storybook/stories/material-ui/cards/MediaControlCard.stories.tsx
@@ -0,0 +1,78 @@
+import React from 'react';
+import { Theme, createStyles, makeStyles, useTheme } from '@material-ui/core/styles';
+import Card from '@material-ui/core/Card';
+import CardContent from '@material-ui/core/CardContent';
+import CardMedia from '@material-ui/core/CardMedia';
+import IconButton from '@material-ui/core/IconButton';
+import Typography from '@material-ui/core/Typography';
+import SkipPreviousIcon from '@material-ui/icons/SkipPrevious';
+import PlayArrowIcon from '@material-ui/icons/PlayArrow';
+import SkipNextIcon from '@material-ui/icons/SkipNext';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ },
+ details: {
+ display: 'flex',
+ flexDirection: 'column',
+ },
+ content: {
+ flex: '1 0 auto',
+ },
+ cover: {
+ width: 151,
+ },
+ controls: {
+ display: 'flex',
+ alignItems: 'center',
+ paddingLeft: theme.spacing(1),
+ paddingBottom: theme.spacing(1),
+ },
+ playIcon: {
+ height: 38,
+ width: 38,
+ },
+ }),
+);
+
+export function MediaControlCard() {
+ const classes = useStyles();
+ const theme = useTheme();
+
+ return (
+
+
+
+
+ Live From Space
+
+
+ Mac Miller
+
+
+
+
+ {theme.direction === 'rtl' ? : }
+
+
+
+
+
+ {theme.direction === 'rtl' ? : }
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|cards|MediaControlCard.stories"
+};
diff --git a/examples/storybook/stories/material-ui/cards/OutlinedCard.stories.tsx b/examples/storybook/stories/material-ui/cards/OutlinedCard.stories.tsx
new file mode 100644
index 00000000000000..2d85508da644ce
--- /dev/null
+++ b/examples/storybook/stories/material-ui/cards/OutlinedCard.stories.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Card from '@material-ui/core/Card';
+import CardActions from '@material-ui/core/CardActions';
+import CardContent from '@material-ui/core/CardContent';
+import Button from '@material-ui/core/Button';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles({
+ root: {
+ minWidth: 275,
+ },
+ bullet: {
+ display: 'inline-block',
+ margin: '0 2px',
+ transform: 'scale(0.8)',
+ },
+ title: {
+ fontSize: 14,
+ },
+ pos: {
+ marginBottom: 12,
+ },
+});
+
+export function OutlinedCard() {
+ const classes = useStyles();
+ const bull = • ;
+
+ return (
+
+
+
+ Word of the Day
+
+
+ be{bull}nev{bull}o{bull}lent
+
+
+ adjective
+
+
+ well meaning and kindly.
+
+ {'"a benevolent smile"'}
+
+
+
+ Learn More
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|cards|OutlinedCard.stories"
+};
diff --git a/examples/storybook/stories/material-ui/cards/RecipeReviewCard.stories.tsx b/examples/storybook/stories/material-ui/cards/RecipeReviewCard.stories.tsx
new file mode 100644
index 00000000000000..137370941ae534
--- /dev/null
+++ b/examples/storybook/stories/material-ui/cards/RecipeReviewCard.stories.tsx
@@ -0,0 +1,130 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import clsx from 'clsx';
+import Card from '@material-ui/core/Card';
+import CardHeader from '@material-ui/core/CardHeader';
+import CardMedia from '@material-ui/core/CardMedia';
+import CardContent from '@material-ui/core/CardContent';
+import CardActions from '@material-ui/core/CardActions';
+import Collapse from '@material-ui/core/Collapse';
+import Avatar from '@material-ui/core/Avatar';
+import IconButton from '@material-ui/core/IconButton';
+import Typography from '@material-ui/core/Typography';
+import { red } from '@material-ui/core/colors';
+import FavoriteIcon from '@material-ui/icons/Favorite';
+import ShareIcon from '@material-ui/icons/Share';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import MoreVertIcon from '@material-ui/icons/MoreVert';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ maxWidth: 345,
+ },
+ media: {
+ height: 0,
+ paddingTop: '56.25%', // 16:9
+ },
+ expand: {
+ transform: 'rotate(0deg)',
+ marginLeft: 'auto',
+ transition: theme.transitions.create('transform', {
+ duration: theme.transitions.duration.shortest,
+ }),
+ },
+ expandOpen: {
+ transform: 'rotate(180deg)',
+ },
+ avatar: {
+ backgroundColor: red[500],
+ },
+ }),
+);
+
+export function RecipeReviewCard() {
+ const classes = useStyles();
+ const [expanded, setExpanded] = React.useState(false);
+
+ const handleExpandClick = () => {
+ setExpanded(!expanded);
+ };
+
+ return (
+
+
+ R
+
+ }
+ action={
+
+
+
+ }
+ title="Shrimp and Chorizo Paella"
+ subheader="September 14, 2016"
+ />
+
+
+
+ This impressive paella is a perfect party dish and a fun meal to cook together with your
+ guests. Add 1 cup of frozen peas along with the mussels, if you like.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Method:
+
+ Heat 1/2 cup of the broth in a pot until simmering, add saffron and set aside for 10
+ minutes.
+
+
+ Heat oil in a (14- to 16-inch) paella pan or a large, deep skillet over medium-high
+ heat. Add chicken, shrimp and chorizo, and cook, stirring occasionally until lightly
+ browned, 6 to 8 minutes. Transfer shrimp to a large plate and set aside, leaving chicken
+ and chorizo in the pan. Add pimentón, bay leaves, garlic, tomatoes, onion, salt and
+ pepper, and cook, stirring often until thickened and fragrant, about 10 minutes. Add
+ saffron broth and remaining 4 1/2 cups chicken broth; bring to a boil.
+
+
+ Add rice and stir very gently to distribute. Top with artichokes and peppers, and cook
+ without stirring, until most of the liquid is absorbed, 15 to 18 minutes. Reduce heat to
+ medium-low, add reserved shrimp and mussels, tucking them down into the rice, and cook
+ again without stirring, until mussels have opened and rice is just tender, 5 to 7
+ minutes more. (Discard any mussels that don’t open.)
+
+
+ Set aside off of the heat to let rest for 10 minutes, and then serve.
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|cards|RecipeReviewCard.stories"
+};
diff --git a/examples/storybook/stories/material-ui/cards/SimpleCard.stories.tsx b/examples/storybook/stories/material-ui/cards/SimpleCard.stories.tsx
new file mode 100644
index 00000000000000..cfe4fa6a038274
--- /dev/null
+++ b/examples/storybook/stories/material-ui/cards/SimpleCard.stories.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Card from '@material-ui/core/Card';
+import CardActions from '@material-ui/core/CardActions';
+import CardContent from '@material-ui/core/CardContent';
+import Button from '@material-ui/core/Button';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles({
+ root: {
+ minWidth: 275,
+ },
+ bullet: {
+ display: 'inline-block',
+ margin: '0 2px',
+ transform: 'scale(0.8)',
+ },
+ title: {
+ fontSize: 14,
+ },
+ pos: {
+ marginBottom: 12,
+ },
+});
+
+export function SimpleCard() {
+ const classes = useStyles();
+ const bull = • ;
+
+ return (
+
+
+
+ Word of the Day
+
+
+ be{bull}nev{bull}o{bull}lent
+
+
+ adjective
+
+
+ well meaning and kindly.
+
+ {'"a benevolent smile"'}
+
+
+
+ Learn More
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|cards|SimpleCard.stories"
+};
diff --git a/examples/storybook/stories/material-ui/checkboxes/CheckboxLabels.stories.tsx b/examples/storybook/stories/material-ui/checkboxes/CheckboxLabels.stories.tsx
new file mode 100644
index 00000000000000..bc87afe619e7d1
--- /dev/null
+++ b/examples/storybook/stories/material-ui/checkboxes/CheckboxLabels.stories.tsx
@@ -0,0 +1,89 @@
+import React from 'react';
+import { withStyles } from '@material-ui/core/styles';
+import { green } from '@material-ui/core/colors';
+import FormGroup from '@material-ui/core/FormGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import Checkbox, { CheckboxProps } from '@material-ui/core/Checkbox';
+import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
+import CheckBoxIcon from '@material-ui/icons/CheckBox';
+import Favorite from '@material-ui/icons/Favorite';
+import FavoriteBorder from '@material-ui/icons/FavoriteBorder';
+
+const GreenCheckbox = withStyles({
+ root: {
+ color: green[400],
+ '&$checked': {
+ color: green[600],
+ },
+ },
+ checked: {},
+})((props: CheckboxProps) => );
+
+export function CheckboxLabels() {
+ const [state, setState] = React.useState({
+ checkedA: true,
+ checkedB: true,
+ checkedF: true,
+ checkedG: true,
+ });
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setState({ ...state, [event.target.name]: event.target.checked });
+ };
+
+ return (
+
+ }
+ label="Secondary"
+ />
+
+ }
+ label="Primary"
+ />
+ } label="Uncontrolled" />
+ } label="Disabled" />
+ } label="Disabled" />
+
+ }
+ label="Indeterminate"
+ />
+ }
+ label="Custom color"
+ />
+ } checkedIcon={ } name="checkedH" />}
+ label="Custom icon"
+ />
+ }
+ checkedIcon={ }
+ name="checkedI"
+ />
+ }
+ label="Custom size"
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|checkboxes|CheckboxLabels.stories"
+};
diff --git a/examples/storybook/stories/material-ui/checkboxes/Checkboxes.stories.tsx b/examples/storybook/stories/material-ui/checkboxes/Checkboxes.stories.tsx
new file mode 100644
index 00000000000000..6a1c2c151d096c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/checkboxes/Checkboxes.stories.tsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import Checkbox from '@material-ui/core/Checkbox';
+
+export function Checkboxes() {
+ const [checked, setChecked] = React.useState(true);
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setChecked(event.target.checked);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|checkboxes|Checkboxes.stories"
+};
diff --git a/examples/storybook/stories/material-ui/checkboxes/CheckboxesGroup.stories.tsx b/examples/storybook/stories/material-ui/checkboxes/CheckboxesGroup.stories.tsx
new file mode 100644
index 00000000000000..f5f09aabd4976d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/checkboxes/CheckboxesGroup.stories.tsx
@@ -0,0 +1,80 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import FormLabel from '@material-ui/core/FormLabel';
+import FormControl from '@material-ui/core/FormControl';
+import FormGroup from '@material-ui/core/FormGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import FormHelperText from '@material-ui/core/FormHelperText';
+import Checkbox from '@material-ui/core/Checkbox';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ },
+ formControl: {
+ margin: theme.spacing(3),
+ },
+ }),
+);
+
+export function CheckboxesGroup() {
+ const classes = useStyles();
+ const [state, setState] = React.useState({
+ gilad: true,
+ jason: false,
+ antoine: false,
+ });
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setState({ ...state, [event.target.name]: event.target.checked });
+ };
+
+ const { gilad, jason, antoine } = state;
+ const error = [gilad, jason, antoine].filter((v) => v).length !== 2;
+
+ return (
+
+
+ Assign responsibility
+
+ }
+ label="Gilad Gray"
+ />
+ }
+ label="Jason Killian"
+ />
+ }
+ label="Antoine Llorca"
+ />
+
+ Be careful
+
+
+ Pick two
+
+ }
+ label="Gilad Gray"
+ />
+ }
+ label="Jason Killian"
+ />
+ }
+ label="Antoine Llorca"
+ />
+
+ You can display an error
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|checkboxes|CheckboxesGroup.stories"
+};
diff --git a/examples/storybook/stories/material-ui/checkboxes/CustomizedCheckbox.stories.tsx b/examples/storybook/stories/material-ui/checkboxes/CustomizedCheckbox.stories.tsx
new file mode 100644
index 00000000000000..0c17fa0488c4f5
--- /dev/null
+++ b/examples/storybook/stories/material-ui/checkboxes/CustomizedCheckbox.stories.tsx
@@ -0,0 +1,79 @@
+import React from 'react';
+import clsx from 'clsx';
+import { makeStyles } from '@material-ui/core/styles';
+import Checkbox, { CheckboxProps } from '@material-ui/core/Checkbox';
+
+const useStyles = makeStyles({
+ root: {
+ '&:hover': {
+ backgroundColor: 'transparent',
+ },
+ },
+ icon: {
+ borderRadius: 3,
+ width: 16,
+ height: 16,
+ boxShadow: 'inset 0 0 0 1px rgba(16,22,26,.2), inset 0 -1px 0 rgba(16,22,26,.1)',
+ backgroundColor: '#f5f8fa',
+ backgroundImage: 'linear-gradient(180deg,hsla(0,0%,100%,.8),hsla(0,0%,100%,0))',
+ '$root.Mui-focusVisible &': {
+ outline: '2px auto rgba(19,124,189,.6)',
+ outlineOffset: 2,
+ },
+ 'input:hover ~ &': {
+ backgroundColor: '#ebf1f5',
+ },
+ 'input:disabled ~ &': {
+ boxShadow: 'none',
+ background: 'rgba(206,217,224,.5)',
+ },
+ },
+ checkedIcon: {
+ backgroundColor: '#137cbd',
+ backgroundImage: 'linear-gradient(180deg,hsla(0,0%,100%,.1),hsla(0,0%,100%,0))',
+ '&:before': {
+ display: 'block',
+ width: 16,
+ height: 16,
+ backgroundImage:
+ "url(\"data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath" +
+ " fill-rule='evenodd' clip-rule='evenodd' d='M12 5c-.28 0-.53.11-.71.29L7 9.59l-2.29-2.3a1.003 " +
+ "1.003 0 00-1.42 1.42l3 3c.18.18.43.29.71.29s.53-.11.71-.29l5-5A1.003 1.003 0 0012 5z' fill='%23fff'/%3E%3C/svg%3E\")",
+ content: '""',
+ },
+ 'input:hover ~ &': {
+ backgroundColor: '#106ba3',
+ },
+ },
+});
+
+// Inspired by blueprintjs
+function StyledCheckbox(props: CheckboxProps) {
+ const classes = useStyles();
+
+ return (
+ }
+ icon={ }
+ inputProps={{ 'aria-label': 'decorative checkbox' }}
+ {...props}
+ />
+ );
+}
+
+export function CustomizedCheckbox() {
+ return (
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|checkboxes|CustomizedCheckbox.stories"
+};
diff --git a/examples/storybook/stories/material-ui/checkboxes/FormControlLabelPosition.stories.tsx b/examples/storybook/stories/material-ui/checkboxes/FormControlLabelPosition.stories.tsx
new file mode 100644
index 00000000000000..cdf97320e83f51
--- /dev/null
+++ b/examples/storybook/stories/material-ui/checkboxes/FormControlLabelPosition.stories.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import Checkbox from '@material-ui/core/Checkbox';
+import FormGroup from '@material-ui/core/FormGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import FormControl from '@material-ui/core/FormControl';
+import FormLabel from '@material-ui/core/FormLabel';
+
+export function FormControlLabelPosition() {
+ return (
+
+ Label Placement
+
+ }
+ label="Top"
+ labelPlacement="top"
+ />
+ }
+ label="Start"
+ labelPlacement="start"
+ />
+ }
+ label="Bottom"
+ labelPlacement="bottom"
+ />
+ }
+ label="End"
+ labelPlacement="end"
+ />
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|checkboxes|FormControlLabelPosition.stories"
+};
diff --git a/examples/storybook/stories/material-ui/chips/Chips.stories.tsx b/examples/storybook/stories/material-ui/chips/Chips.stories.tsx
new file mode 100644
index 00000000000000..00e34ec601886b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/chips/Chips.stories.tsx
@@ -0,0 +1,84 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Avatar from '@material-ui/core/Avatar';
+import Chip from '@material-ui/core/Chip';
+import FaceIcon from '@material-ui/icons/Face';
+import DoneIcon from '@material-ui/icons/Done';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ justifyContent: 'center',
+ flexWrap: 'wrap',
+ '& > *': {
+ margin: theme.spacing(0.5),
+ },
+ },
+ }),
+);
+
+export function Chips() {
+ const classes = useStyles();
+
+ const handleDelete = () => {
+ console.info('You clicked the delete icon.');
+ };
+
+ const handleClick = () => {
+ console.info('You clicked the Chip.');
+ };
+
+ return (
+
+
+
+ M} label="Clickable" onClick={handleClick} />
+ }
+ label="Deletable"
+ onDelete={handleDelete}
+ />
+ }
+ label="Clickable deletable"
+ onClick={handleClick}
+ onDelete={handleDelete}
+ />
+ }
+ />
+
+ M}
+ label="Primary clickable"
+ clickable
+ color="primary"
+ onDelete={handleDelete}
+ deleteIcon={ }
+ />
+ }
+ label="Primary clickable"
+ clickable
+ color="primary"
+ onDelete={handleDelete}
+ deleteIcon={ }
+ />
+
+ }
+ label="Deletable secondary"
+ onDelete={handleDelete}
+ color="secondary"
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|chips|Chips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/chips/ChipsArray.stories.tsx b/examples/storybook/stories/material-ui/chips/ChipsArray.stories.tsx
new file mode 100644
index 00000000000000..011e642cc2424a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/chips/ChipsArray.stories.tsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import Chip from '@material-ui/core/Chip';
+import Paper from '@material-ui/core/Paper';
+import TagFacesIcon from '@material-ui/icons/TagFaces';
+
+interface ChipData {
+ key: number;
+ label: string;
+}
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ justifyContent: 'center',
+ flexWrap: 'wrap',
+ listStyle: 'none',
+ padding: theme.spacing(0.5),
+ margin: 0,
+ },
+ chip: {
+ margin: theme.spacing(0.5),
+ },
+ }),
+);
+
+export function ChipsArray() {
+ const classes = useStyles();
+ const [chipData, setChipData] = React.useState([
+ { key: 0, label: 'Angular' },
+ { key: 1, label: 'jQuery' },
+ { key: 2, label: 'Polymer' },
+ { key: 3, label: 'React' },
+ { key: 4, label: 'Vue.js' },
+ ]);
+
+ const handleDelete = (chipToDelete: ChipData) => () => {
+ setChipData((chips) => chips.filter((chip) => chip.key !== chipToDelete.key));
+ };
+
+ return (
+
+ {chipData.map((data) => {
+ let icon;
+
+ if (data.label === 'React') {
+ icon = ;
+ }
+
+ return (
+
+
+
+ );
+ })}
+
+ );
+}
+
+export default {
+ title: "Material-ui|chips|ChipsArray.stories"
+};
diff --git a/examples/storybook/stories/material-ui/chips/OutlinedChips.stories.tsx b/examples/storybook/stories/material-ui/chips/OutlinedChips.stories.tsx
new file mode 100644
index 00000000000000..e42599b9203e34
--- /dev/null
+++ b/examples/storybook/stories/material-ui/chips/OutlinedChips.stories.tsx
@@ -0,0 +1,95 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Avatar from '@material-ui/core/Avatar';
+import Chip from '@material-ui/core/Chip';
+import FaceIcon from '@material-ui/icons/Face';
+import DoneIcon from '@material-ui/icons/Done';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ justifyContent: 'center',
+ flexWrap: 'wrap',
+ '& > *': {
+ margin: theme.spacing(0.5),
+ },
+ },
+ }),
+);
+
+export function OutlinedChips() {
+ const classes = useStyles();
+
+ const handleDelete = () => {
+ console.info('You clicked the delete icon.');
+ };
+
+ const handleClick = () => {
+ console.info('You clicked the Chip.');
+ };
+
+ return (
+
+
+
+ M}
+ label="Clickable"
+ onClick={handleClick}
+ variant="outlined"
+ />
+ }
+ label="Deletable"
+ onDelete={handleDelete}
+ variant="outlined"
+ />
+ }
+ label="Clickable deletable"
+ onClick={handleClick}
+ onDelete={handleDelete}
+ variant="outlined"
+ />
+ }
+ variant="outlined"
+ />
+
+ M}
+ label="Primary clickable"
+ clickable
+ color="primary"
+ onDelete={handleDelete}
+ deleteIcon={ }
+ variant="outlined"
+ />
+ }
+ label="Primary clickable"
+ clickable
+ color="primary"
+ onDelete={handleDelete}
+ deleteIcon={ }
+ variant="outlined"
+ />
+
+ }
+ label="Deletable secondary"
+ onDelete={handleDelete}
+ color="secondary"
+ variant="outlined"
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|chips|OutlinedChips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/chips/SmallChips.stories.tsx b/examples/storybook/stories/material-ui/chips/SmallChips.stories.tsx
new file mode 100644
index 00000000000000..639eefc90a34bf
--- /dev/null
+++ b/examples/storybook/stories/material-ui/chips/SmallChips.stories.tsx
@@ -0,0 +1,89 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Avatar from '@material-ui/core/Avatar';
+import Chip from '@material-ui/core/Chip';
+import FaceIcon from '@material-ui/icons/Face';
+import DoneIcon from '@material-ui/icons/Done';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ justifyContent: 'center',
+ flexWrap: 'wrap',
+ '& > *': {
+ margin: theme.spacing(0.5),
+ },
+ },
+ }),
+);
+
+export function SmallChips() {
+ const classes = useStyles();
+
+ const handleDelete = () => {
+ console.info('You clicked the delete icon.');
+ };
+
+ const handleClick = () => {
+ console.info('You clicked the Chip.');
+ };
+
+ return (
+
+
+ M} label="Clickable" onClick={handleClick} />
+ }
+ label="Deletable"
+ onDelete={handleDelete}
+ />
+ }
+ label="Clickable Deletable"
+ onClick={handleClick}
+ onDelete={handleDelete}
+ />
+ }
+ />
+
+ M}
+ label="Primary Clickable"
+ clickable
+ color="primary"
+ onDelete={handleDelete}
+ deleteIcon={ }
+ />
+ }
+ label="Primary Clickable"
+ clickable
+ color="primary"
+ onDelete={handleDelete}
+ deleteIcon={ }
+ />
+
+ }
+ label="Deletable Secondary"
+ onDelete={handleDelete}
+ color="secondary"
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|chips|SmallChips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/chips/SmallOutlinedChips.stories.tsx b/examples/storybook/stories/material-ui/chips/SmallOutlinedChips.stories.tsx
new file mode 100644
index 00000000000000..adf8e8e4a8fe5b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/chips/SmallOutlinedChips.stories.tsx
@@ -0,0 +1,114 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Avatar from '@material-ui/core/Avatar';
+import Chip from '@material-ui/core/Chip';
+import FaceIcon from '@material-ui/icons/Face';
+import DoneIcon from '@material-ui/icons/Done';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ justifyContent: 'center',
+ flexWrap: 'wrap',
+ '& > *': {
+ margin: theme.spacing(0.5),
+ },
+ },
+ }),
+);
+
+export function SmallOutlinedChips() {
+ const classes = useStyles();
+
+ const handleDelete = () => {
+ console.info('You clicked the delete icon.');
+ };
+
+ const handleClick = () => {
+ console.info('You clicked the Chip.');
+ };
+
+ return (
+
+
+ M}
+ label="Clickable"
+ onClick={handleClick}
+ />
+ }
+ label="Deletable"
+ onDelete={handleDelete}
+ />
+ }
+ label="Clickable deletable"
+ onClick={handleClick}
+ onDelete={handleDelete}
+ />
+ }
+ />
+
+ M}
+ label="Primary clickable"
+ clickable
+ color="primary"
+ onDelete={handleDelete}
+ deleteIcon={ }
+ />
+ }
+ label="Primary clickable"
+ clickable
+ color="primary"
+ onDelete={handleDelete}
+ deleteIcon={ }
+ />
+
+ }
+ label="Deletable secondary"
+ onDelete={handleDelete}
+ color="secondary"
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|chips|SmallOutlinedChips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/click-away-listener/ClickAway.stories.tsx b/examples/storybook/stories/material-ui/click-away-listener/ClickAway.stories.tsx
new file mode 100644
index 00000000000000..f22099a5c60e89
--- /dev/null
+++ b/examples/storybook/stories/material-ui/click-away-listener/ClickAway.stories.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import ClickAwayListener from '@material-ui/core/ClickAwayListener';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ position: 'relative',
+ },
+ dropdown: {
+ position: 'absolute',
+ top: 28,
+ right: 0,
+ left: 0,
+ zIndex: 1,
+ border: '1px solid',
+ padding: theme.spacing(1),
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function ClickAway() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+
+ const handleClick = () => {
+ setOpen((prev) => !prev);
+ };
+
+ const handleClickAway = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+
+ Open menu dropdown
+
+ {open ? (
+
+ Click me, I will stay visible until you click outside.
+
+ ) : null}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|click-away-listener|ClickAway.stories"
+};
diff --git a/examples/storybook/stories/material-ui/click-away-listener/LeadingClickAway.stories.tsx b/examples/storybook/stories/material-ui/click-away-listener/LeadingClickAway.stories.tsx
new file mode 100644
index 00000000000000..3735c672c4fe72
--- /dev/null
+++ b/examples/storybook/stories/material-ui/click-away-listener/LeadingClickAway.stories.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import ClickAwayListener from '@material-ui/core/ClickAwayListener';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ position: 'relative',
+ },
+ dropdown: {
+ position: 'absolute',
+ top: 28,
+ right: 0,
+ left: 0,
+ zIndex: 1,
+ border: '1px solid',
+ padding: theme.spacing(1),
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function LeadingClickAway() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+
+ const handleClick = () => {
+ setOpen((prev) => !prev);
+ };
+
+ const handleClickAway = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+
+ Open menu dropdown
+
+ {open ? (
+
+ Click me, I will stay visible until you click outside.
+
+ ) : null}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|click-away-listener|LeadingClickAway.stories"
+};
diff --git a/examples/storybook/stories/material-ui/click-away-listener/PortalClickAway.stories.tsx b/examples/storybook/stories/material-ui/click-away-listener/PortalClickAway.stories.tsx
new file mode 100644
index 00000000000000..afd6598ec9d66f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/click-away-listener/PortalClickAway.stories.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import ClickAwayListener from '@material-ui/core/ClickAwayListener';
+import Portal from '@material-ui/core/Portal';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ dropdown: {
+ position: 'fixed',
+ width: 200,
+ top: '50%',
+ left: '50%',
+ transform: 'translate(-50%, -50%)',
+ border: '1px solid',
+ padding: theme.spacing(1),
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function PortalClickAway() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+
+ const handleClick = () => {
+ setOpen((prev) => !prev);
+ };
+
+ const handleClickAway = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+
+ Open menu dropdown
+
+ {open ? (
+
+
+ Click me, I will stay visible until you click outside.
+
+
+ ) : null}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|click-away-listener|PortalClickAway.stories"
+};
diff --git a/examples/storybook/stories/material-ui/container/FixedContainer.stories.tsx b/examples/storybook/stories/material-ui/container/FixedContainer.stories.tsx
new file mode 100644
index 00000000000000..8191ada29e8097
--- /dev/null
+++ b/examples/storybook/stories/material-ui/container/FixedContainer.stories.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import Typography from '@material-ui/core/Typography';
+import Container from '@material-ui/core/Container';
+
+export function FixedContainer() {
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|container|FixedContainer.stories"
+};
diff --git a/examples/storybook/stories/material-ui/container/SimpleContainer.stories.tsx b/examples/storybook/stories/material-ui/container/SimpleContainer.stories.tsx
new file mode 100644
index 00000000000000..829f621c6050cd
--- /dev/null
+++ b/examples/storybook/stories/material-ui/container/SimpleContainer.stories.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import Typography from '@material-ui/core/Typography';
+import Container from '@material-ui/core/Container';
+
+export function SimpleContainer() {
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|container|SimpleContainer.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dialogs/AlertDialog.stories.tsx b/examples/storybook/stories/material-ui/dialogs/AlertDialog.stories.tsx
new file mode 100644
index 00000000000000..59655fa26514c1
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dialogs/AlertDialog.stories.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+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 DialogContentText from '@material-ui/core/DialogContentText';
+import DialogTitle from '@material-ui/core/DialogTitle';
+
+export function AlertDialog() {
+ const [open, setOpen] = React.useState(false);
+
+ const handleClickOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+ Open alert dialog
+
+
+ {"Use Google's location service?"}
+
+
+ Let Google help apps determine location. This means sending anonymous location data to
+ Google, even when no apps are running.
+
+
+
+
+ Disagree
+
+
+ Agree
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dialogs|AlertDialog.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dialogs/AlertDialogSlide.stories.tsx b/examples/storybook/stories/material-ui/dialogs/AlertDialogSlide.stories.tsx
new file mode 100644
index 00000000000000..2a339c175a01ac
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dialogs/AlertDialogSlide.stories.tsx
@@ -0,0 +1,64 @@
+import React from 'react';
+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 DialogContentText from '@material-ui/core/DialogContentText';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import Slide from '@material-ui/core/Slide';
+import { TransitionProps } from '@material-ui/core/transitions';
+
+const Transition = React.forwardRef(function Transition(
+ props: TransitionProps & { children?: React.ReactElement },
+ ref: React.Ref,
+) {
+ return ;
+});
+
+export function AlertDialogSlide() {
+ const [open, setOpen] = React.useState(false);
+
+ const handleClickOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+ Slide in alert dialog
+
+
+ {"Use Google's location service?"}
+
+
+ Let Google help apps determine location. This means sending anonymous location data to
+ Google, even when no apps are running.
+
+
+
+
+ Disagree
+
+
+ Agree
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dialogs|AlertDialogSlide.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dialogs/ConfirmationDialog.stories.tsx b/examples/storybook/stories/material-ui/dialogs/ConfirmationDialog.stories.tsx
new file mode 100644
index 00000000000000..b38ba0e6da6e93
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dialogs/ConfirmationDialog.stories.tsx
@@ -0,0 +1,174 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemText from '@material-ui/core/ListItemText';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import DialogContent from '@material-ui/core/DialogContent';
+import DialogActions from '@material-ui/core/DialogActions';
+import Dialog from '@material-ui/core/Dialog';
+import RadioGroup from '@material-ui/core/RadioGroup';
+import Radio from '@material-ui/core/Radio';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+
+const options = [
+ 'None',
+ 'Atria',
+ 'Callisto',
+ 'Dione',
+ 'Ganymede',
+ 'Hangouts Call',
+ 'Luna',
+ 'Oberon',
+ 'Phobos',
+ 'Pyxis',
+ 'Sedna',
+ 'Titania',
+ 'Triton',
+ 'Umbriel',
+];
+
+export interface ConfirmationDialogRawProps {
+ classes: Record<'paper', string>;
+ id: string;
+ keepMounted: boolean;
+ value: string;
+ open: boolean;
+ onClose: (value?: string) => void;
+}
+
+function ConfirmationDialogRaw(props: ConfirmationDialogRawProps) {
+ const { onClose, value: valueProp, open, ...other } = props;
+ const [value, setValue] = React.useState(valueProp);
+ const radioGroupRef = React.useRef(null);
+
+ React.useEffect(() => {
+ if (!open) {
+ setValue(valueProp);
+ }
+ }, [valueProp, open]);
+
+ const handleEntering = () => {
+ if (radioGroupRef.current != null) {
+ radioGroupRef.current.focus();
+ }
+ };
+
+ const handleCancel = () => {
+ onClose();
+ };
+
+ const handleOk = () => {
+ onClose(value);
+ };
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setValue((event.target as HTMLInputElement).value);
+ };
+
+ return (
+
+ Phone Ringtone
+
+
+ {options.map((option) => (
+ } label={option} />
+ ))}
+
+
+
+
+ Cancel
+
+
+ Ok
+
+
+
+ );
+}
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ paper: {
+ width: '80%',
+ maxHeight: 435,
+ },
+ }),
+);
+
+export function ConfirmationDialog() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+ const [value, setValue] = React.useState('Dione');
+
+ const handleClickListItem = () => {
+ setOpen(true);
+ };
+
+ const handleClose = (newValue?: string) => {
+ setOpen(false);
+
+ if (newValue) {
+ setValue(newValue);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dialogs|ConfirmationDialog.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dialogs/CustomizedDialogs.stories.tsx b/examples/storybook/stories/material-ui/dialogs/CustomizedDialogs.stories.tsx
new file mode 100644
index 00000000000000..c1cf0a60d84bb7
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dialogs/CustomizedDialogs.stories.tsx
@@ -0,0 +1,105 @@
+import React from 'react';
+import { createStyles, Theme, withStyles, WithStyles } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import Dialog from '@material-ui/core/Dialog';
+import MuiDialogTitle from '@material-ui/core/DialogTitle';
+import MuiDialogContent from '@material-ui/core/DialogContent';
+import MuiDialogActions from '@material-ui/core/DialogActions';
+import IconButton from '@material-ui/core/IconButton';
+import CloseIcon from '@material-ui/icons/Close';
+import Typography from '@material-ui/core/Typography';
+
+const styles = (theme: Theme) =>
+ createStyles({
+ root: {
+ margin: 0,
+ padding: theme.spacing(2),
+ },
+ closeButton: {
+ position: 'absolute',
+ right: theme.spacing(1),
+ top: theme.spacing(1),
+ color: theme.palette.grey[500],
+ },
+ });
+
+export interface DialogTitleProps extends WithStyles {
+ id: string;
+ children: React.ReactNode;
+ onClose: () => void;
+}
+
+const DialogTitle = withStyles(styles)((props: DialogTitleProps) => {
+ const { children, classes, onClose, ...other } = props;
+ return (
+
+ {children}
+ {onClose ? (
+
+
+
+ ) : null}
+
+ );
+});
+
+const DialogContent = withStyles((theme: Theme) => ({
+ root: {
+ padding: theme.spacing(2),
+ },
+}))(MuiDialogContent);
+
+const DialogActions = withStyles((theme: Theme) => ({
+ root: {
+ margin: 0,
+ padding: theme.spacing(1),
+ },
+}))(MuiDialogActions);
+
+export function CustomizedDialogs() {
+ const [open, setOpen] = React.useState(false);
+
+ const handleClickOpen = () => {
+ setOpen(true);
+ };
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+ Open dialog
+
+
+
+ Modal title
+
+
+
+ Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis
+ in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
+
+
+ Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis
+ lacus vel augue laoreet rutrum faucibus dolor auctor.
+
+
+ Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel
+ scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus
+ auctor fringilla.
+
+
+
+
+ Save changes
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dialogs|CustomizedDialogs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dialogs/DraggableDialog.stories.tsx b/examples/storybook/stories/material-ui/dialogs/DraggableDialog.stories.tsx
new file mode 100644
index 00000000000000..178cca1001ff10
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dialogs/DraggableDialog.stories.tsx
@@ -0,0 +1,65 @@
+import React from 'react';
+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 DialogContentText from '@material-ui/core/DialogContentText';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import Paper, { PaperProps } from '@material-ui/core/Paper';
+import Draggable from 'react-draggable';
+
+function PaperComponent(props: PaperProps) {
+ return (
+
+
+
+ );
+}
+
+export function DraggableDialog() {
+ const [open, setOpen] = React.useState(false);
+
+ const handleClickOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+ Open form dialog
+
+
+
+ Subscribe
+
+
+
+ To subscribe to this website, please enter your email address here. We will send updates
+ occasionally.
+
+
+
+
+ Cancel
+
+
+ Subscribe
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dialogs|DraggableDialog.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dialogs/FormDialog.stories.tsx b/examples/storybook/stories/material-ui/dialogs/FormDialog.stories.tsx
new file mode 100644
index 00000000000000..70db77392a734f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dialogs/FormDialog.stories.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import TextField from '@material-ui/core/TextField';
+import Dialog from '@material-ui/core/Dialog';
+import DialogActions from '@material-ui/core/DialogActions';
+import DialogContent from '@material-ui/core/DialogContent';
+import DialogContentText from '@material-ui/core/DialogContentText';
+import DialogTitle from '@material-ui/core/DialogTitle';
+
+export function FormDialog() {
+ const [open, setOpen] = React.useState(false);
+
+ const handleClickOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+ Open form dialog
+
+
+ Subscribe
+
+
+ To subscribe to this website, please enter your email address here. We will send updates
+ occasionally.
+
+
+
+
+
+ Cancel
+
+
+ Subscribe
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dialogs|FormDialog.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dialogs/FullScreenDialog.stories.tsx b/examples/storybook/stories/material-ui/dialogs/FullScreenDialog.stories.tsx
new file mode 100644
index 00000000000000..b995eab6ba2f8b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dialogs/FullScreenDialog.stories.tsx
@@ -0,0 +1,83 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import Dialog from '@material-ui/core/Dialog';
+import ListItemText from '@material-ui/core/ListItemText';
+import ListItem from '@material-ui/core/ListItem';
+import List from '@material-ui/core/List';
+import Divider from '@material-ui/core/Divider';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import IconButton from '@material-ui/core/IconButton';
+import Typography from '@material-ui/core/Typography';
+import CloseIcon from '@material-ui/icons/Close';
+import Slide from '@material-ui/core/Slide';
+import { TransitionProps } from '@material-ui/core/transitions';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ appBar: {
+ position: 'relative',
+ },
+ title: {
+ marginLeft: theme.spacing(2),
+ flex: 1,
+ },
+ }),
+);
+
+const Transition = React.forwardRef(function Transition(
+ props: TransitionProps & { children?: React.ReactElement },
+ ref: React.Ref,
+) {
+ return ;
+});
+
+export function FullScreenDialog() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+
+ const handleClickOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+ Open full-screen dialog
+
+
+
+
+
+
+
+
+ Sound
+
+
+ save
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dialogs|FullScreenDialog.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dialogs/MaxWidthDialog.stories.tsx b/examples/storybook/stories/material-ui/dialogs/MaxWidthDialog.stories.tsx
new file mode 100644
index 00000000000000..614db215d8284c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dialogs/MaxWidthDialog.stories.tsx
@@ -0,0 +1,112 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import Dialog, { DialogProps } from '@material-ui/core/Dialog';
+import DialogActions from '@material-ui/core/DialogActions';
+import DialogContent from '@material-ui/core/DialogContent';
+import DialogContentText from '@material-ui/core/DialogContentText';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import FormControl from '@material-ui/core/FormControl';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import InputLabel from '@material-ui/core/InputLabel';
+import MenuItem from '@material-ui/core/MenuItem';
+import Select from '@material-ui/core/Select';
+import Switch from '@material-ui/core/Switch';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ form: {
+ display: 'flex',
+ flexDirection: 'column',
+ margin: 'auto',
+ width: 'fit-content',
+ },
+ formControl: {
+ marginTop: theme.spacing(2),
+ minWidth: 120,
+ },
+ formControlLabel: {
+ marginTop: theme.spacing(1),
+ },
+ }),
+);
+
+export function MaxWidthDialog() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+ const [fullWidth, setFullWidth] = React.useState(true);
+ const [maxWidth, setMaxWidth] = React.useState('sm');
+
+ const handleClickOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ const handleMaxWidthChange = (event: React.ChangeEvent<{ value: unknown }>) => {
+ setMaxWidth(event.target.value as DialogProps['maxWidth']);
+ };
+
+ const handleFullWidthChange = (event: React.ChangeEvent) => {
+ setFullWidth(event.target.checked);
+ };
+
+ return (
+
+
+ Open max-width dialog
+
+
+ Optional sizes
+
+
+ You can set my maximum width and whether to adapt or not.
+
+
+
+
+
+ Close
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dialogs|MaxWidthDialog.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dialogs/ResponsiveDialog.stories.tsx b/examples/storybook/stories/material-ui/dialogs/ResponsiveDialog.stories.tsx
new file mode 100644
index 00000000000000..ee735e7ce0daf6
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dialogs/ResponsiveDialog.stories.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+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 DialogContentText from '@material-ui/core/DialogContentText';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import useMediaQuery from '@material-ui/core/useMediaQuery';
+import { useTheme } from '@material-ui/core/styles';
+
+export function ResponsiveDialog() {
+ const [open, setOpen] = React.useState(false);
+ const theme = useTheme();
+ const fullScreen = useMediaQuery(theme.breakpoints.down('sm'));
+
+ const handleClickOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+ Open responsive dialog
+
+
+ {"Use Google's location service?"}
+
+
+ Let Google help apps determine location. This means sending anonymous location data to
+ Google, even when no apps are running.
+
+
+
+
+ Disagree
+
+
+ Agree
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dialogs|ResponsiveDialog.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dialogs/ScrollDialog.stories.tsx b/examples/storybook/stories/material-ui/dialogs/ScrollDialog.stories.tsx
new file mode 100644
index 00000000000000..dca9af145069cc
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dialogs/ScrollDialog.stories.tsx
@@ -0,0 +1,75 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Dialog, { DialogProps } from '@material-ui/core/Dialog';
+import DialogActions from '@material-ui/core/DialogActions';
+import DialogContent from '@material-ui/core/DialogContent';
+import DialogContentText from '@material-ui/core/DialogContentText';
+import DialogTitle from '@material-ui/core/DialogTitle';
+
+export function ScrollDialog() {
+ const [open, setOpen] = React.useState(false);
+ const [scroll, setScroll] = React.useState('paper');
+
+ const handleClickOpen = (scrollType: DialogProps['scroll']) => () => {
+ setOpen(true);
+ setScroll(scrollType);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ const descriptionElementRef = React.useRef(null);
+ React.useEffect(() => {
+ if (open) {
+ const { current: descriptionElement } = descriptionElementRef;
+ if (descriptionElement !== null) {
+ descriptionElement.focus();
+ }
+ }
+ }, [open]);
+
+ return (
+
+ scroll=paper
+ scroll=body
+
+ Subscribe
+
+
+ {[...new Array(50)]
+ .map(
+ () => `Cras mattis consectetur purus sit amet fermentum.
+Cras justo odio, dapibus ac facilisis in, egestas eget quam.
+Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
+Praesent commodo cursus magna, vel scelerisque nisl consectetur et.`,
+ )
+ .join('\n')}
+
+
+
+
+ Cancel
+
+
+ Subscribe
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dialogs|ScrollDialog.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dialogs/SimpleDialog.stories.tsx b/examples/storybook/stories/material-ui/dialogs/SimpleDialog.stories.tsx
new file mode 100644
index 00000000000000..70aa66c31189da
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dialogs/SimpleDialog.stories.tsx
@@ -0,0 +1,96 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import Avatar from '@material-ui/core/Avatar';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemAvatar from '@material-ui/core/ListItemAvatar';
+import ListItemText from '@material-ui/core/ListItemText';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import Dialog from '@material-ui/core/Dialog';
+import PersonIcon from '@material-ui/icons/Person';
+import AddIcon from '@material-ui/icons/Add';
+import Typography from '@material-ui/core/Typography';
+import { blue } from '@material-ui/core/colors';
+
+const emails = ['username@gmail.com', 'user02@gmail.com'];
+const useStyles = makeStyles({
+ avatar: {
+ backgroundColor: blue[100],
+ color: blue[600],
+ },
+});
+
+export interface SimpleDialogProps {
+ open: boolean;
+ selectedValue: string;
+ onClose: (value: string) => void;
+}
+
+function SimpleDialog(props: SimpleDialogProps) {
+ const classes = useStyles();
+ const { onClose, selectedValue, open } = props;
+
+ const handleClose = () => {
+ onClose(selectedValue);
+ };
+
+ const handleListItemClick = (value: string) => {
+ onClose(value);
+ };
+
+ return (
+
+ Set backup account
+
+ {emails.map((email) => (
+ handleListItemClick(email)} key={email}>
+
+
+
+
+
+
+
+ ))}
+ handleListItemClick('addAccount')}>
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export function SimpleDialogDemo() {
+ const [open, setOpen] = React.useState(false);
+ const [selectedValue, setSelectedValue] = React.useState(emails[1]);
+
+ const handleClickOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = (value: string) => {
+ setOpen(false);
+ setSelectedValue(value);
+ };
+
+ return (
+
+ Selected: {selectedValue}
+
+
+ Open simple dialog
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dialogs|SimpleDialog.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dividers/InsetDividers.stories.tsx b/examples/storybook/stories/material-ui/dividers/InsetDividers.stories.tsx
new file mode 100644
index 00000000000000..2f78f50e57364d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dividers/InsetDividers.stories.tsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemText from '@material-ui/core/ListItemText';
+import ListItemAvatar from '@material-ui/core/ListItemAvatar';
+import Avatar from '@material-ui/core/Avatar';
+import ImageIcon from '@material-ui/icons/Image';
+import WorkIcon from '@material-ui/icons/Work';
+import BeachAccessIcon from '@material-ui/icons/BeachAccess';
+import Divider from '@material-ui/core/Divider';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function InsetDividers() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dividers|InsetDividers.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dividers/ListDividers.stories.tsx b/examples/storybook/stories/material-ui/dividers/ListDividers.stories.tsx
new file mode 100644
index 00000000000000..a09d8ceec9eaca
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dividers/ListDividers.stories.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemText from '@material-ui/core/ListItemText';
+import Divider from '@material-ui/core/Divider';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function ListDividers() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dividers|ListDividers.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dividers/MiddleDividers.stories.tsx b/examples/storybook/stories/material-ui/dividers/MiddleDividers.stories.tsx
new file mode 100644
index 00000000000000..5c1a177fe9f50d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dividers/MiddleDividers.stories.tsx
@@ -0,0 +1,75 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Chip from '@material-ui/core/Chip';
+import Button from '@material-ui/core/Button';
+import Grid from '@material-ui/core/Grid';
+import Divider from '@material-ui/core/Divider';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ chip: {
+ margin: theme.spacing(0.5),
+ },
+ section1: {
+ margin: theme.spacing(3, 2),
+ },
+ section2: {
+ margin: theme.spacing(2),
+ },
+ section3: {
+ margin: theme.spacing(3, 1, 1),
+ },
+ }),
+);
+
+export function MiddleDividers() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+ Toothbrush
+
+
+
+
+ $4.50
+
+
+
+
+ Pinstriped cornflower blue cotton blouse takes you on a walk to the park or just down the
+ hall.
+
+
+
+
+
+ Select type
+
+
+
+
+
+
+
+
+
+ Add to cart
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dividers|MiddleDividers.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dividers/SubheaderDividers.stories.tsx b/examples/storybook/stories/material-ui/dividers/SubheaderDividers.stories.tsx
new file mode 100644
index 00000000000000..63d6ab30d63652
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dividers/SubheaderDividers.stories.tsx
@@ -0,0 +1,75 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemAvatar from '@material-ui/core/ListItemAvatar';
+import ListItemText from '@material-ui/core/ListItemText';
+import Avatar from '@material-ui/core/Avatar';
+import BeachAccessIcon from '@material-ui/icons/BeachAccess';
+import Divider from '@material-ui/core/Divider';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ dividerFullWidth: {
+ margin: `5px 0 0 ${theme.spacing(2)}px`,
+ },
+ dividerInset: {
+ margin: `5px 0 0 ${theme.spacing(9)}px`,
+ },
+ }),
+);
+
+export function SubheaderDividers() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+ Divider
+
+
+
+
+
+
+
+
+ Leisure
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|dividers|SubheaderDividers.stories"
+};
diff --git a/examples/storybook/stories/material-ui/dividers/VerticalDividers.stories.tsx b/examples/storybook/stories/material-ui/dividers/VerticalDividers.stories.tsx
new file mode 100644
index 00000000000000..bb020f3d96c518
--- /dev/null
+++ b/examples/storybook/stories/material-ui/dividers/VerticalDividers.stories.tsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import FormatAlignLeftIcon from '@material-ui/icons/FormatAlignLeft';
+import FormatAlignCenterIcon from '@material-ui/icons/FormatAlignCenter';
+import FormatAlignRightIcon from '@material-ui/icons/FormatAlignRight';
+import FormatBoldIcon from '@material-ui/icons/FormatBold';
+import FormatItalicIcon from '@material-ui/icons/FormatItalic';
+import FormatUnderlinedIcon from '@material-ui/icons/FormatUnderlined';
+import Grid from '@material-ui/core/Grid';
+import Divider from '@material-ui/core/Divider';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 'fit-content',
+ border: `1px solid ${theme.palette.divider}`,
+ borderRadius: theme.shape.borderRadius,
+ backgroundColor: theme.palette.background.paper,
+ color: theme.palette.text.secondary,
+ '& svg': {
+ margin: theme.spacing(1.5),
+ },
+ '& hr': {
+ margin: theme.spacing(0, 0.5),
+ },
+ },
+ }),
+);
+
+export function VerticalDividers() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|dividers|VerticalDividers.stories"
+};
diff --git a/examples/storybook/stories/material-ui/drawers/ClippedDrawer.stories.tsx b/examples/storybook/stories/material-ui/drawers/ClippedDrawer.stories.tsx
new file mode 100644
index 00000000000000..6e919dc43fda28
--- /dev/null
+++ b/examples/storybook/stories/material-ui/drawers/ClippedDrawer.stories.tsx
@@ -0,0 +1,116 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Drawer from '@material-ui/core/Drawer';
+import AppBar from '@material-ui/core/AppBar';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import Toolbar from '@material-ui/core/Toolbar';
+import List from '@material-ui/core/List';
+import Typography from '@material-ui/core/Typography';
+import Divider from '@material-ui/core/Divider';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import InboxIcon from '@material-ui/icons/MoveToInbox';
+import MailIcon from '@material-ui/icons/Mail';
+
+const drawerWidth = 240;
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ },
+ appBar: {
+ zIndex: theme.zIndex.drawer + 1,
+ },
+ drawer: {
+ width: drawerWidth,
+ flexShrink: 0,
+ },
+ drawerPaper: {
+ width: drawerWidth,
+ },
+ drawerContainer: {
+ overflow: 'auto',
+ },
+ content: {
+ flexGrow: 1,
+ padding: theme.spacing(3),
+ },
+ }),
+);
+
+export function ClippedDrawer() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+ Clipped drawer
+
+
+
+
+
+
+
+ {['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+ {['All mail', 'Trash', 'Spam'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
+ ut labore et dolore magna aliqua. Rhoncus dolor purus non enim praesent elementum
+ facilisis leo vel. Risus at ultrices mi tempus imperdiet. Semper risus in hendrerit
+ gravida rutrum quisque non tellus. Convallis convallis tellus id interdum velit laoreet id
+ donec ultrices. Odio morbi quis commodo odio aenean sed adipiscing. Amet nisl suscipit
+ adipiscing bibendum est ultricies integer quis. Cursus euismod quis viverra nibh cras.
+ Metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Mauris commodo quis
+ imperdiet massa tincidunt. Cras tincidunt lobortis feugiat vivamus at augue. At augue eget
+ arcu dictum varius duis at consectetur lorem. Velit sed ullamcorper morbi tincidunt. Lorem
+ donec massa sapien faucibus et molestie ac.
+
+
+ Consequat mauris nunc congue nisi vitae suscipit. Fringilla est ullamcorper eget nulla
+ facilisi etiam dignissim diam. Pulvinar elementum integer enim neque volutpat ac
+ tincidunt. Ornare suspendisse sed nisi lacus sed viverra tellus. Purus sit amet volutpat
+ consequat mauris. Elementum eu facilisis sed odio morbi. Euismod lacinia at quis risus sed
+ vulputate odio. Morbi tincidunt ornare massa eget egestas purus viverra accumsan in. In
+ hendrerit gravida rutrum quisque non tellus orci ac. Pellentesque nec nam aliquam sem et
+ tortor. Habitant morbi tristique senectus et. Adipiscing elit duis tristique sollicitudin
+ nibh sit. Ornare aenean euismod elementum nisi quis eleifend. Commodo viverra maecenas
+ accumsan lacus vel facilisis. Nulla posuere sollicitudin aliquam ultrices sagittis orci a.
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|drawers|ClippedDrawer.stories"
+};
diff --git a/examples/storybook/stories/material-ui/drawers/MiniDrawer.stories.tsx b/examples/storybook/stories/material-ui/drawers/MiniDrawer.stories.tsx
new file mode 100644
index 00000000000000..8cc8a861305570
--- /dev/null
+++ b/examples/storybook/stories/material-ui/drawers/MiniDrawer.stories.tsx
@@ -0,0 +1,195 @@
+import React from 'react';
+import clsx from 'clsx';
+import { createStyles, makeStyles, useTheme, Theme } from '@material-ui/core/styles';
+import Drawer from '@material-ui/core/Drawer';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import List from '@material-ui/core/List';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import Typography from '@material-ui/core/Typography';
+import Divider from '@material-ui/core/Divider';
+import IconButton from '@material-ui/core/IconButton';
+import MenuIcon from '@material-ui/icons/Menu';
+import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
+import ChevronRightIcon from '@material-ui/icons/ChevronRight';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import InboxIcon from '@material-ui/icons/MoveToInbox';
+import MailIcon from '@material-ui/icons/Mail';
+
+const drawerWidth = 240;
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ },
+ appBar: {
+ zIndex: theme.zIndex.drawer + 1,
+ transition: theme.transitions.create(['width', 'margin'], {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ },
+ appBarShift: {
+ marginLeft: drawerWidth,
+ width: `calc(100% - ${drawerWidth}px)`,
+ transition: theme.transitions.create(['width', 'margin'], {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ },
+ menuButton: {
+ marginRight: 36,
+ },
+ hide: {
+ display: 'none',
+ },
+ drawer: {
+ width: drawerWidth,
+ flexShrink: 0,
+ whiteSpace: 'nowrap',
+ },
+ drawerOpen: {
+ width: drawerWidth,
+ transition: theme.transitions.create('width', {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ },
+ drawerClose: {
+ transition: theme.transitions.create('width', {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ overflowX: 'hidden',
+ width: theme.spacing(7) + 1,
+ [theme.breakpoints.up('sm')]: {
+ width: theme.spacing(9) + 1,
+ },
+ },
+ toolbar: {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'flex-end',
+ padding: theme.spacing(0, 1),
+ // necessary for content to be below app bar
+ ...theme.mixins.toolbar,
+ },
+ content: {
+ flexGrow: 1,
+ padding: theme.spacing(3),
+ },
+ }),
+);
+
+export function MiniDrawer() {
+ const classes = useStyles();
+ const theme = useTheme();
+ const [open, setOpen] = React.useState(false);
+
+ const handleDrawerOpen = () => {
+ setOpen(true);
+ };
+
+ const handleDrawerClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ Mini variant drawer
+
+
+
+
+
+
+ {theme.direction === 'rtl' ? : }
+
+
+
+
+ {['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+ {['All mail', 'Trash', 'Spam'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
+ ut labore et dolore magna aliqua. Rhoncus dolor purus non enim praesent elementum
+ facilisis leo vel. Risus at ultrices mi tempus imperdiet. Semper risus in hendrerit
+ gravida rutrum quisque non tellus. Convallis convallis tellus id interdum velit laoreet id
+ donec ultrices. Odio morbi quis commodo odio aenean sed adipiscing. Amet nisl suscipit
+ adipiscing bibendum est ultricies integer quis. Cursus euismod quis viverra nibh cras.
+ Metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Mauris commodo quis
+ imperdiet massa tincidunt. Cras tincidunt lobortis feugiat vivamus at augue. At augue eget
+ arcu dictum varius duis at consectetur lorem. Velit sed ullamcorper morbi tincidunt. Lorem
+ donec massa sapien faucibus et molestie ac.
+
+
+ Consequat mauris nunc congue nisi vitae suscipit. Fringilla est ullamcorper eget nulla
+ facilisi etiam dignissim diam. Pulvinar elementum integer enim neque volutpat ac
+ tincidunt. Ornare suspendisse sed nisi lacus sed viverra tellus. Purus sit amet volutpat
+ consequat mauris. Elementum eu facilisis sed odio morbi. Euismod lacinia at quis risus sed
+ vulputate odio. Morbi tincidunt ornare massa eget egestas purus viverra accumsan in. In
+ hendrerit gravida rutrum quisque non tellus orci ac. Pellentesque nec nam aliquam sem et
+ tortor. Habitant morbi tristique senectus et. Adipiscing elit duis tristique sollicitudin
+ nibh sit. Ornare aenean euismod elementum nisi quis eleifend. Commodo viverra maecenas
+ accumsan lacus vel facilisis. Nulla posuere sollicitudin aliquam ultrices sagittis orci a.
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|drawers|MiniDrawer.stories"
+};
diff --git a/examples/storybook/stories/material-ui/drawers/PermanentDrawerLeft.stories.tsx b/examples/storybook/stories/material-ui/drawers/PermanentDrawerLeft.stories.tsx
new file mode 100644
index 00000000000000..6d9f0e446931b4
--- /dev/null
+++ b/examples/storybook/stories/material-ui/drawers/PermanentDrawerLeft.stories.tsx
@@ -0,0 +1,117 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Drawer from '@material-ui/core/Drawer';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import List from '@material-ui/core/List';
+import Typography from '@material-ui/core/Typography';
+import Divider from '@material-ui/core/Divider';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import InboxIcon from '@material-ui/icons/MoveToInbox';
+import MailIcon from '@material-ui/icons/Mail';
+
+const drawerWidth = 240;
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ },
+ appBar: {
+ width: `calc(100% - ${drawerWidth}px)`,
+ marginLeft: drawerWidth,
+ },
+ drawer: {
+ width: drawerWidth,
+ flexShrink: 0,
+ },
+ drawerPaper: {
+ width: drawerWidth,
+ },
+ // necessary for content to be below app bar
+ toolbar: theme.mixins.toolbar,
+ content: {
+ flexGrow: 1,
+ backgroundColor: theme.palette.background.default,
+ padding: theme.spacing(3),
+ },
+ }),
+);
+
+export function PermanentDrawerLeft() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+ Permanent drawer
+
+
+
+
+
+
+
+ {['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+ {['All mail', 'Trash', 'Spam'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
+ ut labore et dolore magna aliqua. Rhoncus dolor purus non enim praesent elementum
+ facilisis leo vel. Risus at ultrices mi tempus imperdiet. Semper risus in hendrerit
+ gravida rutrum quisque non tellus. Convallis convallis tellus id interdum velit laoreet id
+ donec ultrices. Odio morbi quis commodo odio aenean sed adipiscing. Amet nisl suscipit
+ adipiscing bibendum est ultricies integer quis. Cursus euismod quis viverra nibh cras.
+ Metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Mauris commodo quis
+ imperdiet massa tincidunt. Cras tincidunt lobortis feugiat vivamus at augue. At augue eget
+ arcu dictum varius duis at consectetur lorem. Velit sed ullamcorper morbi tincidunt. Lorem
+ donec massa sapien faucibus et molestie ac.
+
+
+ Consequat mauris nunc congue nisi vitae suscipit. Fringilla est ullamcorper eget nulla
+ facilisi etiam dignissim diam. Pulvinar elementum integer enim neque volutpat ac
+ tincidunt. Ornare suspendisse sed nisi lacus sed viverra tellus. Purus sit amet volutpat
+ consequat mauris. Elementum eu facilisis sed odio morbi. Euismod lacinia at quis risus sed
+ vulputate odio. Morbi tincidunt ornare massa eget egestas purus viverra accumsan in. In
+ hendrerit gravida rutrum quisque non tellus orci ac. Pellentesque nec nam aliquam sem et
+ tortor. Habitant morbi tristique senectus et. Adipiscing elit duis tristique sollicitudin
+ nibh sit. Ornare aenean euismod elementum nisi quis eleifend. Commodo viverra maecenas
+ accumsan lacus vel facilisis. Nulla posuere sollicitudin aliquam ultrices sagittis orci a.
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|drawers|PermanentDrawerLeft.stories"
+};
diff --git a/examples/storybook/stories/material-ui/drawers/PermanentDrawerRight.stories.tsx b/examples/storybook/stories/material-ui/drawers/PermanentDrawerRight.stories.tsx
new file mode 100644
index 00000000000000..1cf232ed1b4dd5
--- /dev/null
+++ b/examples/storybook/stories/material-ui/drawers/PermanentDrawerRight.stories.tsx
@@ -0,0 +1,117 @@
+import React from 'react';
+import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
+import Drawer from '@material-ui/core/Drawer';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import List from '@material-ui/core/List';
+import Typography from '@material-ui/core/Typography';
+import Divider from '@material-ui/core/Divider';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import InboxIcon from '@material-ui/icons/MoveToInbox';
+import MailIcon from '@material-ui/icons/Mail';
+
+const drawerWidth = 240;
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ },
+ appBar: {
+ width: `calc(100% - ${drawerWidth}px)`,
+ marginRight: drawerWidth,
+ },
+ drawer: {
+ width: drawerWidth,
+ flexShrink: 0,
+ },
+ drawerPaper: {
+ width: drawerWidth,
+ },
+ // necessary for content to be below app bar
+ toolbar: theme.mixins.toolbar,
+ content: {
+ flexGrow: 1,
+ backgroundColor: theme.palette.background.default,
+ padding: theme.spacing(3),
+ },
+ }),
+);
+
+export function PermanentDrawerRight() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+ Permanent drawer
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
+ ut labore et dolore magna aliqua. Rhoncus dolor purus non enim praesent elementum
+ facilisis leo vel. Risus at ultrices mi tempus imperdiet. Semper risus in hendrerit
+ gravida rutrum quisque non tellus. Convallis convallis tellus id interdum velit laoreet id
+ donec ultrices. Odio morbi quis commodo odio aenean sed adipiscing. Amet nisl suscipit
+ adipiscing bibendum est ultricies integer quis. Cursus euismod quis viverra nibh cras.
+ Metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Mauris commodo quis
+ imperdiet massa tincidunt. Cras tincidunt lobortis feugiat vivamus at augue. At augue eget
+ arcu dictum varius duis at consectetur lorem. Velit sed ullamcorper morbi tincidunt. Lorem
+ donec massa sapien faucibus et molestie ac.
+
+
+ Consequat mauris nunc congue nisi vitae suscipit. Fringilla est ullamcorper eget nulla
+ facilisi etiam dignissim diam. Pulvinar elementum integer enim neque volutpat ac
+ tincidunt. Ornare suspendisse sed nisi lacus sed viverra tellus. Purus sit amet volutpat
+ consequat mauris. Elementum eu facilisis sed odio morbi. Euismod lacinia at quis risus sed
+ vulputate odio. Morbi tincidunt ornare massa eget egestas purus viverra accumsan in. In
+ hendrerit gravida rutrum quisque non tellus orci ac. Pellentesque nec nam aliquam sem et
+ tortor. Habitant morbi tristique senectus et. Adipiscing elit duis tristique sollicitudin
+ nibh sit. Ornare aenean euismod elementum nisi quis eleifend. Commodo viverra maecenas
+ accumsan lacus vel facilisis. Nulla posuere sollicitudin aliquam ultrices sagittis orci a.
+
+
+
+
+
+
+ {['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+ {['All mail', 'Trash', 'Spam'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|drawers|PermanentDrawerRight.stories"
+};
diff --git a/examples/storybook/stories/material-ui/drawers/PersistentDrawerLeft.stories.tsx b/examples/storybook/stories/material-ui/drawers/PersistentDrawerLeft.stories.tsx
new file mode 100644
index 00000000000000..e49f8a3d074004
--- /dev/null
+++ b/examples/storybook/stories/material-ui/drawers/PersistentDrawerLeft.stories.tsx
@@ -0,0 +1,188 @@
+import React from 'react';
+import clsx from 'clsx';
+import { makeStyles, useTheme, Theme, createStyles } from '@material-ui/core/styles';
+import Drawer from '@material-ui/core/Drawer';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import List from '@material-ui/core/List';
+import Typography from '@material-ui/core/Typography';
+import Divider from '@material-ui/core/Divider';
+import IconButton from '@material-ui/core/IconButton';
+import MenuIcon from '@material-ui/icons/Menu';
+import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
+import ChevronRightIcon from '@material-ui/icons/ChevronRight';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import InboxIcon from '@material-ui/icons/MoveToInbox';
+import MailIcon from '@material-ui/icons/Mail';
+
+const drawerWidth = 240;
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ },
+ appBar: {
+ transition: theme.transitions.create(['margin', 'width'], {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ },
+ appBarShift: {
+ width: `calc(100% - ${drawerWidth}px)`,
+ marginLeft: drawerWidth,
+ transition: theme.transitions.create(['margin', 'width'], {
+ easing: theme.transitions.easing.easeOut,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ },
+ menuButton: {
+ marginRight: theme.spacing(2),
+ },
+ hide: {
+ display: 'none',
+ },
+ drawer: {
+ width: drawerWidth,
+ flexShrink: 0,
+ },
+ drawerPaper: {
+ width: drawerWidth,
+ },
+ drawerHeader: {
+ display: 'flex',
+ alignItems: 'center',
+ padding: theme.spacing(0, 1),
+ // necessary for content to be below app bar
+ ...theme.mixins.toolbar,
+ justifyContent: 'flex-end',
+ },
+ content: {
+ flexGrow: 1,
+ padding: theme.spacing(3),
+ transition: theme.transitions.create('margin', {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ marginLeft: -drawerWidth,
+ },
+ contentShift: {
+ transition: theme.transitions.create('margin', {
+ easing: theme.transitions.easing.easeOut,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ marginLeft: 0,
+ },
+ }),
+);
+
+export function PersistentDrawerLeft() {
+ const classes = useStyles();
+ const theme = useTheme();
+ const [open, setOpen] = React.useState(false);
+
+ const handleDrawerOpen = () => {
+ setOpen(true);
+ };
+
+ const handleDrawerClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ Persistent drawer
+
+
+
+
+
+
+ {theme.direction === 'ltr' ? : }
+
+
+
+
+ {['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+ {['All mail', 'Trash', 'Spam'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
+ ut labore et dolore magna aliqua. Rhoncus dolor purus non enim praesent elementum
+ facilisis leo vel. Risus at ultrices mi tempus imperdiet. Semper risus in hendrerit
+ gravida rutrum quisque non tellus. Convallis convallis tellus id interdum velit laoreet id
+ donec ultrices. Odio morbi quis commodo odio aenean sed adipiscing. Amet nisl suscipit
+ adipiscing bibendum est ultricies integer quis. Cursus euismod quis viverra nibh cras.
+ Metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Mauris commodo quis
+ imperdiet massa tincidunt. Cras tincidunt lobortis feugiat vivamus at augue. At augue eget
+ arcu dictum varius duis at consectetur lorem. Velit sed ullamcorper morbi tincidunt. Lorem
+ donec massa sapien faucibus et molestie ac.
+
+
+ Consequat mauris nunc congue nisi vitae suscipit. Fringilla est ullamcorper eget nulla
+ facilisi etiam dignissim diam. Pulvinar elementum integer enim neque volutpat ac
+ tincidunt. Ornare suspendisse sed nisi lacus sed viverra tellus. Purus sit amet volutpat
+ consequat mauris. Elementum eu facilisis sed odio morbi. Euismod lacinia at quis risus sed
+ vulputate odio. Morbi tincidunt ornare massa eget egestas purus viverra accumsan in. In
+ hendrerit gravida rutrum quisque non tellus orci ac. Pellentesque nec nam aliquam sem et
+ tortor. Habitant morbi tristique senectus et. Adipiscing elit duis tristique sollicitudin
+ nibh sit. Ornare aenean euismod elementum nisi quis eleifend. Commodo viverra maecenas
+ accumsan lacus vel facilisis. Nulla posuere sollicitudin aliquam ultrices sagittis orci a.
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|drawers|PersistentDrawerLeft.stories"
+};
diff --git a/examples/storybook/stories/material-ui/drawers/PersistentDrawerRight.stories.tsx b/examples/storybook/stories/material-ui/drawers/PersistentDrawerRight.stories.tsx
new file mode 100644
index 00000000000000..1de46a33ac3533
--- /dev/null
+++ b/examples/storybook/stories/material-ui/drawers/PersistentDrawerRight.stories.tsx
@@ -0,0 +1,188 @@
+import React from 'react';
+import clsx from 'clsx';
+import { makeStyles, useTheme, Theme, createStyles } from '@material-ui/core/styles';
+import Drawer from '@material-ui/core/Drawer';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import List from '@material-ui/core/List';
+import Typography from '@material-ui/core/Typography';
+import Divider from '@material-ui/core/Divider';
+import IconButton from '@material-ui/core/IconButton';
+import MenuIcon from '@material-ui/icons/Menu';
+import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
+import ChevronRightIcon from '@material-ui/icons/ChevronRight';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import InboxIcon from '@material-ui/icons/MoveToInbox';
+import MailIcon from '@material-ui/icons/Mail';
+
+const drawerWidth = 240;
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ },
+ appBar: {
+ transition: theme.transitions.create(['margin', 'width'], {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ },
+ appBarShift: {
+ width: `calc(100% - ${drawerWidth}px)`,
+ transition: theme.transitions.create(['margin', 'width'], {
+ easing: theme.transitions.easing.easeOut,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ marginRight: drawerWidth,
+ },
+ title: {
+ flexGrow: 1,
+ },
+ hide: {
+ display: 'none',
+ },
+ drawer: {
+ width: drawerWidth,
+ flexShrink: 0,
+ },
+ drawerPaper: {
+ width: drawerWidth,
+ },
+ drawerHeader: {
+ display: 'flex',
+ alignItems: 'center',
+ padding: theme.spacing(0, 1),
+ // necessary for content to be below app bar
+ ...theme.mixins.toolbar,
+ justifyContent: 'flex-start',
+ },
+ content: {
+ flexGrow: 1,
+ padding: theme.spacing(3),
+ transition: theme.transitions.create('margin', {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ marginRight: -drawerWidth,
+ },
+ contentShift: {
+ transition: theme.transitions.create('margin', {
+ easing: theme.transitions.easing.easeOut,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ marginRight: 0,
+ },
+ }),
+);
+
+export function PersistentDrawerRight() {
+ const classes = useStyles();
+ const theme = useTheme();
+ const [open, setOpen] = React.useState(false);
+
+ const handleDrawerOpen = () => {
+ setOpen(true);
+ };
+
+ const handleDrawerClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+
+
+
+ Persistent drawer
+
+
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
+ ut labore et dolore magna aliqua. Rhoncus dolor purus non enim praesent elementum
+ facilisis leo vel. Risus at ultrices mi tempus imperdiet. Semper risus in hendrerit
+ gravida rutrum quisque non tellus. Convallis convallis tellus id interdum velit laoreet id
+ donec ultrices. Odio morbi quis commodo odio aenean sed adipiscing. Amet nisl suscipit
+ adipiscing bibendum est ultricies integer quis. Cursus euismod quis viverra nibh cras.
+ Metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Mauris commodo quis
+ imperdiet massa tincidunt. Cras tincidunt lobortis feugiat vivamus at augue. At augue eget
+ arcu dictum varius duis at consectetur lorem. Velit sed ullamcorper morbi tincidunt. Lorem
+ donec massa sapien faucibus et molestie ac.
+
+
+ Consequat mauris nunc congue nisi vitae suscipit. Fringilla est ullamcorper eget nulla
+ facilisi etiam dignissim diam. Pulvinar elementum integer enim neque volutpat ac
+ tincidunt. Ornare suspendisse sed nisi lacus sed viverra tellus. Purus sit amet volutpat
+ consequat mauris. Elementum eu facilisis sed odio morbi. Euismod lacinia at quis risus sed
+ vulputate odio. Morbi tincidunt ornare massa eget egestas purus viverra accumsan in. In
+ hendrerit gravida rutrum quisque non tellus orci ac. Pellentesque nec nam aliquam sem et
+ tortor. Habitant morbi tristique senectus et. Adipiscing elit duis tristique sollicitudin
+ nibh sit. Ornare aenean euismod elementum nisi quis eleifend. Commodo viverra maecenas
+ accumsan lacus vel facilisis. Nulla posuere sollicitudin aliquam ultrices sagittis orci a.
+
+
+
+
+
+ {theme.direction === 'rtl' ? : }
+
+
+
+
+ {['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+ {['All mail', 'Trash', 'Spam'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|drawers|PersistentDrawerRight.stories"
+};
diff --git a/examples/storybook/stories/material-ui/drawers/ResponsiveDrawer.stories.tsx b/examples/storybook/stories/material-ui/drawers/ResponsiveDrawer.stories.tsx
new file mode 100644
index 00000000000000..605607024ac420
--- /dev/null
+++ b/examples/storybook/stories/material-ui/drawers/ResponsiveDrawer.stories.tsx
@@ -0,0 +1,182 @@
+import React from 'react';
+import AppBar from '@material-ui/core/AppBar';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import Divider from '@material-ui/core/Divider';
+import Drawer from '@material-ui/core/Drawer';
+import Hidden from '@material-ui/core/Hidden';
+import IconButton from '@material-ui/core/IconButton';
+import InboxIcon from '@material-ui/icons/MoveToInbox';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import MailIcon from '@material-ui/icons/Mail';
+import MenuIcon from '@material-ui/icons/Menu';
+import Toolbar from '@material-ui/core/Toolbar';
+import Typography from '@material-ui/core/Typography';
+import { makeStyles, useTheme, Theme, createStyles } from '@material-ui/core/styles';
+
+const drawerWidth = 240;
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ },
+ drawer: {
+ [theme.breakpoints.up('sm')]: {
+ width: drawerWidth,
+ flexShrink: 0,
+ },
+ },
+ appBar: {
+ [theme.breakpoints.up('sm')]: {
+ width: `calc(100% - ${drawerWidth}px)`,
+ marginLeft: drawerWidth,
+ },
+ },
+ menuButton: {
+ marginRight: theme.spacing(2),
+ [theme.breakpoints.up('sm')]: {
+ display: 'none',
+ },
+ },
+ // necessary for content to be below app bar
+ toolbar: theme.mixins.toolbar,
+ drawerPaper: {
+ width: drawerWidth,
+ },
+ content: {
+ flexGrow: 1,
+ padding: theme.spacing(3),
+ },
+ }),
+);
+
+interface Props {
+ /**
+ * Injected by the documentation to work in an iframe.
+ * You won't need it on your project.
+ */
+ window?: () => Window;
+}
+
+export function ResponsiveDrawer(props: Props) {
+ const { window } = props;
+ const classes = useStyles();
+ const theme = useTheme();
+ const [mobileOpen, setMobileOpen] = React.useState(false);
+
+ const handleDrawerToggle = () => {
+ setMobileOpen(!mobileOpen);
+ };
+
+ const drawer = (
+
+
+
+
+ {['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+ {['All mail', 'Trash', 'Spam'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+ );
+
+ const container = window !== undefined ? () => window().document.body : undefined;
+
+ return (
+
+
+
+
+
+
+
+
+ Responsive drawer
+
+
+
+
+ {/* The implementation can be swapped with js to avoid SEO duplication of links. */}
+
+
+ {drawer}
+
+
+
+
+ {drawer}
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
+ ut labore et dolore magna aliqua. Rhoncus dolor purus non enim praesent elementum
+ facilisis leo vel. Risus at ultrices mi tempus imperdiet. Semper risus in hendrerit
+ gravida rutrum quisque non tellus. Convallis convallis tellus id interdum velit laoreet id
+ donec ultrices. Odio morbi quis commodo odio aenean sed adipiscing. Amet nisl suscipit
+ adipiscing bibendum est ultricies integer quis. Cursus euismod quis viverra nibh cras.
+ Metus vulputate eu scelerisque felis imperdiet proin fermentum leo. Mauris commodo quis
+ imperdiet massa tincidunt. Cras tincidunt lobortis feugiat vivamus at augue. At augue eget
+ arcu dictum varius duis at consectetur lorem. Velit sed ullamcorper morbi tincidunt. Lorem
+ donec massa sapien faucibus et molestie ac.
+
+
+ Consequat mauris nunc congue nisi vitae suscipit. Fringilla est ullamcorper eget nulla
+ facilisi etiam dignissim diam. Pulvinar elementum integer enim neque volutpat ac
+ tincidunt. Ornare suspendisse sed nisi lacus sed viverra tellus. Purus sit amet volutpat
+ consequat mauris. Elementum eu facilisis sed odio morbi. Euismod lacinia at quis risus sed
+ vulputate odio. Morbi tincidunt ornare massa eget egestas purus viverra accumsan in. In
+ hendrerit gravida rutrum quisque non tellus orci ac. Pellentesque nec nam aliquam sem et
+ tortor. Habitant morbi tristique senectus et. Adipiscing elit duis tristique sollicitudin
+ nibh sit. Ornare aenean euismod elementum nisi quis eleifend. Commodo viverra maecenas
+ accumsan lacus vel facilisis. Nulla posuere sollicitudin aliquam ultrices sagittis orci a.
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|drawers|ResponsiveDrawer.stories"
+};
diff --git a/examples/storybook/stories/material-ui/drawers/SwipeableTemporaryDrawer.stories.tsx b/examples/storybook/stories/material-ui/drawers/SwipeableTemporaryDrawer.stories.tsx
new file mode 100644
index 00000000000000..9faa9b344ed7fe
--- /dev/null
+++ b/examples/storybook/stories/material-ui/drawers/SwipeableTemporaryDrawer.stories.tsx
@@ -0,0 +1,99 @@
+import React from 'react';
+import clsx from 'clsx';
+import { makeStyles } from '@material-ui/core/styles';
+import SwipeableDrawer from '@material-ui/core/SwipeableDrawer';
+import Button from '@material-ui/core/Button';
+import List from '@material-ui/core/List';
+import Divider from '@material-ui/core/Divider';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import InboxIcon from '@material-ui/icons/MoveToInbox';
+import MailIcon from '@material-ui/icons/Mail';
+
+const useStyles = makeStyles({
+ list: {
+ width: 250,
+ },
+ fullList: {
+ width: 'auto',
+ },
+});
+
+type Anchor = 'top' | 'left' | 'bottom' | 'right';
+
+export function SwipeableTemporaryDrawer() {
+ const classes = useStyles();
+ const [state, setState] = React.useState({
+ top: false,
+ left: false,
+ bottom: false,
+ right: false,
+ });
+
+ const toggleDrawer = (anchor: Anchor, open: boolean) => (
+ event: React.KeyboardEvent | React.MouseEvent,
+ ) => {
+ if (
+ event &&
+ event.type === 'keydown' &&
+ ((event as React.KeyboardEvent).key === 'Tab' ||
+ (event as React.KeyboardEvent).key === 'Shift')
+ ) {
+ return;
+ }
+
+ setState({ ...state, [anchor]: open });
+ };
+
+ const list = (anchor: Anchor) => (
+
+
+ {['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+ {['All mail', 'Trash', 'Spam'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+ );
+
+ return (
+
+ {(['left', 'right', 'top', 'bottom'] as Anchor[]).map((anchor) => (
+
+ {anchor}
+
+ {list(anchor)}
+
+
+ ))}
+
+ );
+}
+
+export default {
+ title: "Material-ui|drawers|SwipeableTemporaryDrawer.stories"
+};
diff --git a/examples/storybook/stories/material-ui/drawers/TemporaryDrawer.stories.tsx b/examples/storybook/stories/material-ui/drawers/TemporaryDrawer.stories.tsx
new file mode 100644
index 00000000000000..9e24bad14ccc6d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/drawers/TemporaryDrawer.stories.tsx
@@ -0,0 +1,93 @@
+import React from 'react';
+import clsx from 'clsx';
+import { makeStyles } from '@material-ui/core/styles';
+import Drawer from '@material-ui/core/Drawer';
+import Button from '@material-ui/core/Button';
+import List from '@material-ui/core/List';
+import Divider from '@material-ui/core/Divider';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import InboxIcon from '@material-ui/icons/MoveToInbox';
+import MailIcon from '@material-ui/icons/Mail';
+
+const useStyles = makeStyles({
+ list: {
+ width: 250,
+ },
+ fullList: {
+ width: 'auto',
+ },
+});
+
+type Anchor = 'top' | 'left' | 'bottom' | 'right';
+
+export function TemporaryDrawer() {
+ const classes = useStyles();
+ const [state, setState] = React.useState({
+ top: false,
+ left: false,
+ bottom: false,
+ right: false,
+ });
+
+ const toggleDrawer = (anchor: Anchor, open: boolean) => (
+ event: React.KeyboardEvent | React.MouseEvent,
+ ) => {
+ if (
+ event.type === 'keydown' &&
+ ((event as React.KeyboardEvent).key === 'Tab' ||
+ (event as React.KeyboardEvent).key === 'Shift')
+ ) {
+ return;
+ }
+
+ setState({ ...state, [anchor]: open });
+ };
+
+ const list = (anchor: Anchor) => (
+
+
+ {['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+
+ {['All mail', 'Trash', 'Spam'].map((text, index) => (
+
+ {index % 2 === 0 ? : }
+
+
+ ))}
+
+
+ );
+
+ return (
+
+ {(['left', 'right', 'top', 'bottom'] as Anchor[]).map((anchor) => (
+
+ {anchor}
+
+ {list(anchor)}
+
+
+ ))}
+
+ );
+}
+
+export default {
+ title: "Material-ui|drawers|TemporaryDrawer.stories"
+};
diff --git a/examples/storybook/stories/material-ui/expansion-panels/ActionsInExpansionPanelSummary.stories.tsx b/examples/storybook/stories/material-ui/expansion-panels/ActionsInExpansionPanelSummary.stories.tsx
new file mode 100644
index 00000000000000..e255172ba6d5cf
--- /dev/null
+++ b/examples/storybook/stories/material-ui/expansion-panels/ActionsInExpansionPanelSummary.stories.tsx
@@ -0,0 +1,94 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import ExpansionPanel from '@material-ui/core/ExpansionPanel';
+import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
+import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails';
+import Checkbox from '@material-ui/core/Checkbox';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import Typography from '@material-ui/core/Typography';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+
+const useStyles = makeStyles({
+ root: {
+ width: '100%',
+ },
+});
+
+export function ActionsInExpansionPanelSummary() {
+ const classes = useStyles();
+
+ return (
+
+
+ }
+ aria-label="Expand"
+ aria-controls="additional-actions1-content"
+ id="additional-actions1-header"
+ >
+ event.stopPropagation()}
+ onFocus={(event) => event.stopPropagation()}
+ control={ }
+ label="I acknowledge that I should stop the click event propagation"
+ />
+
+
+
+ The click event of the nested action will propagate up and expand the panel unless you
+ explicitly stop it.
+
+
+
+
+ }
+ aria-label="Expand"
+ aria-controls="additional-actions2-content"
+ id="additional-actions2-header"
+ >
+ event.stopPropagation()}
+ onFocus={(event) => event.stopPropagation()}
+ control={ }
+ label="I acknowledge that I should stop the focus event propagation"
+ />
+
+
+
+ The focus event of the nested action will propagate up and also focus the expansion
+ panel unless you explicitly stop it.
+
+
+
+
+ }
+ aria-label="Expand"
+ aria-controls="additional-actions3-content"
+ id="additional-actions3-header"
+ >
+ event.stopPropagation()}
+ onFocus={(event) => event.stopPropagation()}
+ control={ }
+ label="I acknowledge that I should provide an aria-label on each action that I add"
+ />
+
+
+
+ If you forget to put an aria-label on the nested action, the label of the action will
+ also be included in the label of the parent button that controls the panel expansion.
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|expansion-panels|ActionsInExpansionPanelSummary.stories"
+};
diff --git a/examples/storybook/stories/material-ui/expansion-panels/ControlledExpansionPanels.stories.tsx b/examples/storybook/stories/material-ui/expansion-panels/ControlledExpansionPanels.stories.tsx
new file mode 100644
index 00000000000000..cac3bd4d092223
--- /dev/null
+++ b/examples/storybook/stories/material-ui/expansion-panels/ControlledExpansionPanels.stories.tsx
@@ -0,0 +1,109 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import ExpansionPanel from '@material-ui/core/ExpansionPanel';
+import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails';
+import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
+import Typography from '@material-ui/core/Typography';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ },
+ heading: {
+ fontSize: theme.typography.pxToRem(15),
+ flexBasis: '33.33%',
+ flexShrink: 0,
+ },
+ secondaryHeading: {
+ fontSize: theme.typography.pxToRem(15),
+ color: theme.palette.text.secondary,
+ },
+ }),
+);
+
+export function ControlledExpansionPanels() {
+ const classes = useStyles();
+ const [expanded, setExpanded] = React.useState(false);
+
+ const handleChange = (panel: string) => (event: React.ChangeEvent<{}>, isExpanded: boolean) => {
+ setExpanded(isExpanded ? panel : false);
+ };
+
+ return (
+
+
+ }
+ aria-controls="panel1bh-content"
+ id="panel1bh-header"
+ >
+ General settings
+ I am an expansion panel
+
+
+
+ Nulla facilisi. Phasellus sollicitudin nulla et quam mattis feugiat. Aliquam eget
+ maximus est, id dignissim quam.
+
+
+
+
+ }
+ aria-controls="panel2bh-content"
+ id="panel2bh-header"
+ >
+ Users
+
+ You are currently not an owner
+
+
+
+
+ Donec placerat, lectus sed mattis semper, neque lectus feugiat lectus, varius pulvinar
+ diam eros in elit. Pellentesque convallis laoreet laoreet.
+
+
+
+
+ }
+ aria-controls="panel3bh-content"
+ id="panel3bh-header"
+ >
+ Advanced settings
+
+ Filtering has been entirely disabled for whole web server
+
+
+
+
+ Nunc vitae orci ultricies, auctor nunc in, volutpat nisl. Integer sit amet egestas eros,
+ vitae egestas augue. Duis vel est augue.
+
+
+
+
+ }
+ aria-controls="panel4bh-content"
+ id="panel4bh-header"
+ >
+ Personal data
+
+
+
+ Nunc vitae orci ultricies, auctor nunc in, volutpat nisl. Integer sit amet egestas eros,
+ vitae egestas augue. Duis vel est augue.
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|expansion-panels|ControlledExpansionPanels.stories"
+};
diff --git a/examples/storybook/stories/material-ui/expansion-panels/CustomizedExpansionPanels.stories.tsx b/examples/storybook/stories/material-ui/expansion-panels/CustomizedExpansionPanels.stories.tsx
new file mode 100644
index 00000000000000..478674d58855e0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/expansion-panels/CustomizedExpansionPanels.stories.tsx
@@ -0,0 +1,100 @@
+import React from 'react';
+import { withStyles } from '@material-ui/core/styles';
+import MuiExpansionPanel from '@material-ui/core/ExpansionPanel';
+import MuiExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
+import MuiExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails';
+import Typography from '@material-ui/core/Typography';
+
+const ExpansionPanel = withStyles({
+ root: {
+ border: '1px solid rgba(0, 0, 0, .125)',
+ boxShadow: 'none',
+ '&:not(:last-child)': {
+ borderBottom: 0,
+ },
+ '&:before': {
+ display: 'none',
+ },
+ '&$expanded': {
+ margin: 'auto',
+ },
+ },
+ expanded: {},
+})(MuiExpansionPanel);
+
+const ExpansionPanelSummary = withStyles({
+ root: {
+ backgroundColor: 'rgba(0, 0, 0, .03)',
+ borderBottom: '1px solid rgba(0, 0, 0, .125)',
+ marginBottom: -1,
+ minHeight: 56,
+ '&$expanded': {
+ minHeight: 56,
+ },
+ },
+ content: {
+ '&$expanded': {
+ margin: '12px 0',
+ },
+ },
+ expanded: {},
+})(MuiExpansionPanelSummary);
+
+const ExpansionPanelDetails = withStyles((theme) => ({
+ root: {
+ padding: theme.spacing(2),
+ },
+}))(MuiExpansionPanelDetails);
+
+export function CustomizedExpansionPanels() {
+ const [expanded, setExpanded] = React.useState('panel1');
+
+ const handleChange = (panel: string) => (event: React.ChangeEvent<{}>, newExpanded: boolean) => {
+ setExpanded(newExpanded ? panel : false);
+ };
+
+ return (
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex,
+ sit amet blandit leo lobortis eget. Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex,
+ sit amet blandit leo lobortis eget. Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
+
+
+
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex,
+ sit amet blandit leo lobortis eget. Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|expansion-panels|CustomizedExpansionPanels.stories"
+};
diff --git a/examples/storybook/stories/material-ui/expansion-panels/DetailedExpansionPanel.stories.tsx b/examples/storybook/stories/material-ui/expansion-panels/DetailedExpansionPanel.stories.tsx
new file mode 100644
index 00000000000000..516c11556bf8c5
--- /dev/null
+++ b/examples/storybook/stories/material-ui/expansion-panels/DetailedExpansionPanel.stories.tsx
@@ -0,0 +1,98 @@
+import React from 'react';
+import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
+import clsx from 'clsx';
+import ExpansionPanel from '@material-ui/core/ExpansionPanel';
+import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails';
+import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
+import ExpansionPanelActions from '@material-ui/core/ExpansionPanelActions';
+import Typography from '@material-ui/core/Typography';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import Chip from '@material-ui/core/Chip';
+import Button from '@material-ui/core/Button';
+import Divider from '@material-ui/core/Divider';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ },
+ heading: {
+ fontSize: theme.typography.pxToRem(15),
+ },
+ secondaryHeading: {
+ fontSize: theme.typography.pxToRem(15),
+ color: theme.palette.text.secondary,
+ },
+ icon: {
+ verticalAlign: 'bottom',
+ height: 20,
+ width: 20,
+ },
+ details: {
+ alignItems: 'center',
+ },
+ column: {
+ flexBasis: '33.33%',
+ },
+ helper: {
+ borderLeft: `2px solid ${theme.palette.divider}`,
+ padding: theme.spacing(1, 2),
+ },
+ link: {
+ color: theme.palette.primary.main,
+ textDecoration: 'none',
+ '&:hover': {
+ textDecoration: 'underline',
+ },
+ },
+ }),
+);
+
+export function DetailedExpansionPanel() {
+ const classes = useStyles();
+
+ return (
+
+
+ }
+ aria-controls="panel1c-content"
+ id="panel1c-header"
+ >
+
+ Location
+
+
+ Select trip destination
+
+
+
+
+
+ {}} />
+
+
+
+
+
+ Cancel
+
+ Save
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|expansion-panels|DetailedExpansionPanel.stories"
+};
diff --git a/examples/storybook/stories/material-ui/expansion-panels/SimpleExpansionPanel.stories.tsx b/examples/storybook/stories/material-ui/expansion-panels/SimpleExpansionPanel.stories.tsx
new file mode 100644
index 00000000000000..f565e87943a146
--- /dev/null
+++ b/examples/storybook/stories/material-ui/expansion-panels/SimpleExpansionPanel.stories.tsx
@@ -0,0 +1,71 @@
+import React from 'react';
+import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
+import ExpansionPanel from '@material-ui/core/ExpansionPanel';
+import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary';
+import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails';
+import Typography from '@material-ui/core/Typography';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ },
+ heading: {
+ fontSize: theme.typography.pxToRem(15),
+ fontWeight: theme.typography.fontWeightRegular,
+ },
+ }),
+);
+
+export function SimpleExpansionPanel() {
+ const classes = useStyles();
+
+ return (
+
+
+ }
+ aria-controls="panel1a-content"
+ id="panel1a-header"
+ >
+ Expansion Panel 1
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex,
+ sit amet blandit leo lobortis eget.
+
+
+
+
+ }
+ aria-controls="panel2a-content"
+ id="panel2a-header"
+ >
+ Expansion Panel 2
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex,
+ sit amet blandit leo lobortis eget.
+
+
+
+
+ }
+ aria-controls="panel3a-content"
+ id="panel3a-header"
+ >
+ Disabled Expansion Panel
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|expansion-panels|SimpleExpansionPanel.stories"
+};
diff --git a/examples/storybook/stories/material-ui/floating-action-button/FloatingActionButtonSize.stories.tsx b/examples/storybook/stories/material-ui/floating-action-button/FloatingActionButtonSize.stories.tsx
new file mode 100644
index 00000000000000..719972f1937bde
--- /dev/null
+++ b/examples/storybook/stories/material-ui/floating-action-button/FloatingActionButtonSize.stories.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Fab from '@material-ui/core/Fab';
+import AddIcon from '@material-ui/icons/Add';
+import NavigationIcon from '@material-ui/icons/Navigation';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ margin: {
+ margin: theme.spacing(1),
+ },
+ extendedIcon: {
+ marginRight: theme.spacing(1),
+ },
+ }),
+);
+
+export function FloatingActionButtonSize() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+ Extended
+
+
+
+ Extended
+
+
+
+ Extended
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|floating-action-button|FloatingActionButtonSize.stories"
+};
diff --git a/examples/storybook/stories/material-ui/floating-action-button/FloatingActionButtonZoom.stories.tsx b/examples/storybook/stories/material-ui/floating-action-button/FloatingActionButtonZoom.stories.tsx
new file mode 100644
index 00000000000000..916e4877017af9
--- /dev/null
+++ b/examples/storybook/stories/material-ui/floating-action-button/FloatingActionButtonZoom.stories.tsx
@@ -0,0 +1,162 @@
+import React from 'react';
+import clsx from 'clsx';
+import SwipeableViews from 'react-swipeable-views';
+import { makeStyles, useTheme, Theme, createStyles } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import Typography from '@material-ui/core/Typography';
+import Zoom from '@material-ui/core/Zoom';
+import Fab from '@material-ui/core/Fab';
+import AddIcon from '@material-ui/icons/Add';
+import EditIcon from '@material-ui/icons/Edit';
+import UpIcon from '@material-ui/icons/KeyboardArrowUp';
+import { green } from '@material-ui/core/colors';
+import Box from '@material-ui/core/Box';
+
+interface TabPanelProps {
+ children?: React.ReactNode;
+ dir?: string;
+ index: any;
+ value: any;
+}
+
+function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props;
+
+ return (
+
+ {value === index && {children} }
+
+ );
+}
+
+function a11yProps(index: any) {
+ return {
+ id: `action-tab-${index}`,
+ 'aria-controls': `action-tabpanel-${index}`,
+ };
+}
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ backgroundColor: theme.palette.background.paper,
+ width: 500,
+ position: 'relative',
+ minHeight: 200,
+ },
+ fab: {
+ position: 'absolute',
+ bottom: theme.spacing(2),
+ right: theme.spacing(2),
+ },
+ fabGreen: {
+ color: theme.palette.common.white,
+ backgroundColor: green[500],
+ '&:hover': {
+ backgroundColor: green[600],
+ },
+ },
+ }),
+);
+
+export function FloatingActionButtonZoom() {
+ const classes = useStyles();
+ const theme = useTheme();
+ const [value, setValue] = React.useState(0);
+
+ const handleChange = (event: unknown, newValue: number) => {
+ setValue(newValue);
+ };
+
+ const handleChangeIndex = (index: number) => {
+ setValue(index);
+ };
+
+ const transitionDuration = {
+ enter: theme.transitions.duration.enteringScreen,
+ exit: theme.transitions.duration.leavingScreen,
+ };
+
+ const fabs = [
+ {
+ color: 'primary' as 'primary',
+ className: classes.fab,
+ icon: ,
+ label: 'Add',
+ },
+ {
+ color: 'secondary' as 'secondary',
+ className: classes.fab,
+ icon: ,
+ label: 'Edit',
+ },
+ {
+ color: 'inherit' as 'inherit',
+ className: clsx(classes.fab, classes.fabGreen),
+ icon: ,
+ label: 'Expand',
+ },
+ ];
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ Item One
+
+
+ Item Two
+
+
+ Item Three
+
+
+ {fabs.map((fab, index) => (
+
+
+ {fab.icon}
+
+
+ ))}
+
+ );
+}
+
+export default {
+ title: "Material-ui|floating-action-button|FloatingActionButtonZoom.stories"
+};
diff --git a/examples/storybook/stories/material-ui/floating-action-button/FloatingActionButtons.stories.tsx b/examples/storybook/stories/material-ui/floating-action-button/FloatingActionButtons.stories.tsx
new file mode 100644
index 00000000000000..b1d562d30b2006
--- /dev/null
+++ b/examples/storybook/stories/material-ui/floating-action-button/FloatingActionButtons.stories.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import Fab from '@material-ui/core/Fab';
+import AddIcon from '@material-ui/icons/Add';
+import EditIcon from '@material-ui/icons/Edit';
+import FavoriteIcon from '@material-ui/icons/Favorite';
+import NavigationIcon from '@material-ui/icons/Navigation';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ extendedIcon: {
+ marginRight: theme.spacing(1),
+ },
+ }),
+);
+
+export function FloatingActionButtons() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+ Navigate
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|floating-action-button|FloatingActionButtons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/grid/AutoGrid.stories.tsx b/examples/storybook/stories/material-ui/grid/AutoGrid.stories.tsx
new file mode 100644
index 00000000000000..473f3420194e9a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/grid/AutoGrid.stories.tsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Paper from '@material-ui/core/Paper';
+import Grid from '@material-ui/core/Grid';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ },
+ paper: {
+ padding: theme.spacing(2),
+ textAlign: 'center',
+ color: theme.palette.text.secondary,
+ },
+ }),
+);
+
+export function AutoGrid() {
+ const classes = useStyles();
+
+ return (
+
+
+
+ xs
+
+
+ xs
+
+
+ xs
+
+
+
+
+ xs
+
+
+ xs=6
+
+
+ xs
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|grid|AutoGrid.stories"
+};
diff --git a/examples/storybook/stories/material-ui/grid/AutoGridNoWrap.stories.tsx b/examples/storybook/stories/material-ui/grid/AutoGridNoWrap.stories.tsx
new file mode 100644
index 00000000000000..01524492e8a4a4
--- /dev/null
+++ b/examples/storybook/stories/material-ui/grid/AutoGridNoWrap.stories.tsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import Paper from '@material-ui/core/Paper';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Grid from '@material-ui/core/Grid';
+import Avatar from '@material-ui/core/Avatar';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ overflow: 'hidden',
+ padding: theme.spacing(0, 3),
+ },
+ paper: {
+ maxWidth: 400,
+ margin: `${theme.spacing(1)}px auto`,
+ padding: theme.spacing(2),
+ },
+ }),
+);
+
+const message = `Truncation should be conditionally applicable on this long line of text
+ as this is a much longer line than what the container can support. `;
+
+export function AutoGridNoWrap() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+ W
+
+
+ {message}
+
+
+
+
+
+
+ W
+
+
+ {message}
+
+
+
+
+
+
+ W
+
+
+ {message}
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|grid|AutoGridNoWrap.stories"
+};
diff --git a/examples/storybook/stories/material-ui/grid/CSSGrid.stories.tsx b/examples/storybook/stories/material-ui/grid/CSSGrid.stories.tsx
new file mode 100644
index 00000000000000..8d63737a7365b3
--- /dev/null
+++ b/examples/storybook/stories/material-ui/grid/CSSGrid.stories.tsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Paper from '@material-ui/core/Paper';
+import Divider from '@material-ui/core/Divider';
+import Grid from '@material-ui/core/Grid';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ container: {
+ display: 'grid',
+ gridTemplateColumns: 'repeat(12, 1fr)',
+ gridGap: theme.spacing(3),
+ },
+ paper: {
+ padding: theme.spacing(1),
+ textAlign: 'center',
+ color: theme.palette.text.secondary,
+ whiteSpace: 'nowrap',
+ marginBottom: theme.spacing(1),
+ },
+ divider: {
+ margin: theme.spacing(2, 0),
+ },
+ }),
+);
+
+export function CSSGrid() {
+ const classes = useStyles();
+
+ return (
+
+
+ Material-UI Grid:
+
+
+
+ xs=3
+
+
+ xs=3
+
+
+ xs=3
+
+
+ xs=3
+
+
+ xs=8
+
+
+ xs=4
+
+
+
+
+ CSS Grid Layout:
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|grid|CSSGrid.stories"
+};
diff --git a/examples/storybook/stories/material-ui/grid/CenteredGrid.stories.tsx b/examples/storybook/stories/material-ui/grid/CenteredGrid.stories.tsx
new file mode 100644
index 00000000000000..727addfa16fde2
--- /dev/null
+++ b/examples/storybook/stories/material-ui/grid/CenteredGrid.stories.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Paper from '@material-ui/core/Paper';
+import Grid from '@material-ui/core/Grid';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ },
+ paper: {
+ padding: theme.spacing(2),
+ textAlign: 'center',
+ color: theme.palette.text.secondary,
+ },
+ }),
+);
+
+export function CenteredGrid() {
+ const classes = useStyles();
+
+ return (
+
+
+
+ xs=12
+
+
+ xs=6
+
+
+ xs=6
+
+
+ xs=3
+
+
+ xs=3
+
+
+ xs=3
+
+
+ xs=3
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|grid|CenteredGrid.stories"
+};
diff --git a/examples/storybook/stories/material-ui/grid/ComplexGrid.stories.tsx b/examples/storybook/stories/material-ui/grid/ComplexGrid.stories.tsx
new file mode 100644
index 00000000000000..448f5db6e2ff9c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/grid/ComplexGrid.stories.tsx
@@ -0,0 +1,74 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Grid from '@material-ui/core/Grid';
+import Paper from '@material-ui/core/Paper';
+import Typography from '@material-ui/core/Typography';
+import ButtonBase from '@material-ui/core/ButtonBase';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ },
+ paper: {
+ padding: theme.spacing(2),
+ margin: 'auto',
+ maxWidth: 500,
+ },
+ image: {
+ width: 128,
+ height: 128,
+ },
+ img: {
+ margin: 'auto',
+ display: 'block',
+ maxWidth: '100%',
+ maxHeight: '100%',
+ },
+ }),
+);
+
+export function ComplexGrid() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ Standard license
+
+
+ Full resolution 1920x1080 • JPEG
+
+
+ ID: 1030114
+
+
+
+
+ Remove
+
+
+
+
+ $19.00
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|grid|ComplexGrid.stories"
+};
diff --git a/examples/storybook/stories/material-ui/grid/FullWidthGrid.stories.tsx b/examples/storybook/stories/material-ui/grid/FullWidthGrid.stories.tsx
new file mode 100644
index 00000000000000..28851bc8b3a7af
--- /dev/null
+++ b/examples/storybook/stories/material-ui/grid/FullWidthGrid.stories.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Paper from '@material-ui/core/Paper';
+import Grid from '@material-ui/core/Grid';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ },
+ paper: {
+ padding: theme.spacing(2),
+ textAlign: 'center',
+ color: theme.palette.text.secondary,
+ },
+ }),
+);
+
+export function FullWidthGrid() {
+ const classes = useStyles();
+
+ return (
+
+
+
+ xs=12
+
+
+ xs=12 sm=6
+
+
+ xs=12 sm=6
+
+
+ xs=6 sm=3
+
+
+ xs=6 sm=3
+
+
+ xs=6 sm=3
+
+
+ xs=6 sm=3
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|grid|FullWidthGrid.stories"
+};
diff --git a/examples/storybook/stories/material-ui/grid/NestedGrid.stories.tsx b/examples/storybook/stories/material-ui/grid/NestedGrid.stories.tsx
new file mode 100644
index 00000000000000..d30a03bca1b9e1
--- /dev/null
+++ b/examples/storybook/stories/material-ui/grid/NestedGrid.stories.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Paper from '@material-ui/core/Paper';
+import Grid from '@material-ui/core/Grid';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ },
+ paper: {
+ padding: theme.spacing(1),
+ textAlign: 'center',
+ color: theme.palette.text.secondary,
+ },
+ }),
+);
+
+export function NestedGrid() {
+ const classes = useStyles();
+
+ function FormRow() {
+ return (
+
+
+ item
+
+
+ item
+
+
+ item
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|grid|NestedGrid.stories"
+};
diff --git a/examples/storybook/stories/material-ui/grid/SpacingGrid.stories.tsx b/examples/storybook/stories/material-ui/grid/SpacingGrid.stories.tsx
new file mode 100644
index 00000000000000..d3a4bbaffa76c4
--- /dev/null
+++ b/examples/storybook/stories/material-ui/grid/SpacingGrid.stories.tsx
@@ -0,0 +1,75 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Grid, { GridSpacing } from '@material-ui/core/Grid';
+import FormLabel from '@material-ui/core/FormLabel';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import RadioGroup from '@material-ui/core/RadioGroup';
+import Radio from '@material-ui/core/Radio';
+import Paper from '@material-ui/core/Paper';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ },
+ paper: {
+ height: 140,
+ width: 100,
+ },
+ control: {
+ padding: theme.spacing(2),
+ },
+ }),
+);
+
+export function SpacingGrid() {
+ const [spacing, setSpacing] = React.useState(2);
+ const classes = useStyles();
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setSpacing(Number((event.target as HTMLInputElement).value) as GridSpacing);
+ };
+
+ return (
+
+
+
+ {[0, 1, 2].map((value) => (
+
+
+
+ ))}
+
+
+
+
+
+
+ spacing
+
+ {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((value) => (
+ }
+ label={value.toString()}
+ />
+ ))}
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|grid|SpacingGrid.stories"
+};
diff --git a/examples/storybook/stories/material-ui/icons/FontAwesome.stories.tsx b/examples/storybook/stories/material-ui/icons/FontAwesome.stories.tsx
new file mode 100644
index 00000000000000..8f80aa7679e64d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/icons/FontAwesome.stories.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { loadCSS } from 'fg-loadcss';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import { green } from '@material-ui/core/colors';
+import Icon from '@material-ui/core/Icon';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > .fa': {
+ margin: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function FontAwesome() {
+ const classes = useStyles();
+
+ React.useEffect(() => {
+ const node = loadCSS(
+ 'https://use.fontawesome.com/releases/v5.12.0/css/all.css',
+ document.querySelector('#font-awesome-css'),
+ );
+
+ return () => {
+ node.parentNode!.removeChild(node);
+ };
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|icons|FontAwesome.stories"
+};
diff --git a/examples/storybook/stories/material-ui/icons/Icons.stories.tsx b/examples/storybook/stories/material-ui/icons/Icons.stories.tsx
new file mode 100644
index 00000000000000..d8da931cb70578
--- /dev/null
+++ b/examples/storybook/stories/material-ui/icons/Icons.stories.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import { green } from '@material-ui/core/colors';
+import Icon from '@material-ui/core/Icon';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > span': {
+ margin: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function Icons() {
+ const classes = useStyles();
+
+ return (
+
+ add_circle
+ add_circle
+ add_circle
+ add_circle
+ add_circle
+ add_circle
+
+ );
+}
+
+export default {
+ title: "Material-ui|icons|Icons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/icons/SvgIconsColor.stories.tsx b/examples/storybook/stories/material-ui/icons/SvgIconsColor.stories.tsx
new file mode 100644
index 00000000000000..a7d5ffc620e5c0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/icons/SvgIconsColor.stories.tsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import { green } from '@material-ui/core/colors';
+import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > svg': {
+ margin: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+function HomeIcon(props: SvgIconProps) {
+ return (
+
+
+
+ );
+}
+
+export function SvgIconsColor() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|icons|SvgIconsColor.stories"
+};
diff --git a/examples/storybook/stories/material-ui/icons/SvgIconsSize.stories.tsx b/examples/storybook/stories/material-ui/icons/SvgIconsSize.stories.tsx
new file mode 100644
index 00000000000000..f52c7e9bf1e28d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/icons/SvgIconsSize.stories.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > svg': {
+ margin: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+function HomeIcon(props: SvgIconProps) {
+ return (
+
+
+
+ );
+}
+
+export function SvgIconsSize() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|icons|SvgIconsSize.stories"
+};
diff --git a/examples/storybook/stories/material-ui/icons/SvgMaterialIcons.stories.tsx b/examples/storybook/stories/material-ui/icons/SvgMaterialIcons.stories.tsx
new file mode 100644
index 00000000000000..f36734b05615a6
--- /dev/null
+++ b/examples/storybook/stories/material-ui/icons/SvgMaterialIcons.stories.tsx
@@ -0,0 +1,81 @@
+import React from 'react';
+import Grid from '@material-ui/core/Grid';
+import Typography from '@material-ui/core/Typography';
+import DeleteIcon from '@material-ui/icons/Delete';
+import DeleteOutlinedIcon from '@material-ui/icons/DeleteOutlined';
+import DeleteRoundedIcon from '@material-ui/icons/DeleteRounded';
+import DeleteTwoToneIcon from '@material-ui/icons/DeleteTwoTone';
+import DeleteSharpIcon from '@material-ui/icons/DeleteSharp';
+import DeleteForeverIcon from '@material-ui/icons/DeleteForever';
+import DeleteForeverOutlinedIcon from '@material-ui/icons/DeleteForeverOutlined';
+import DeleteForeverRoundedIcon from '@material-ui/icons/DeleteForeverRounded';
+import DeleteForeverTwoToneIcon from '@material-ui/icons/DeleteForeverTwoTone';
+import DeleteForeverSharpIcon from '@material-ui/icons/DeleteForeverSharp';
+import ThreeDRotationIcon from '@material-ui/icons/ThreeDRotation';
+import FourKIcon from '@material-ui/icons/FourK';
+import ThreeSixtyIcon from '@material-ui/icons/ThreeSixty';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ color: theme.palette.text.primary,
+ },
+ }),
+);
+
+export function SvgMaterialIcons() {
+ const classes = useStyles();
+
+ return (
+
+
+ Filled
+
+
+
+
+
+
+ Outlined
+
+
+
+
+
+
+ Rounded
+
+
+
+
+
+
+ Two Tone
+
+
+
+
+
+
+ Sharp
+
+
+
+
+
+
+ Edge-cases
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|icons|SvgMaterialIcons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/links/ButtonLink.stories.tsx b/examples/storybook/stories/material-ui/links/ButtonLink.stories.tsx
new file mode 100644
index 00000000000000..e1fa3bd9b49bde
--- /dev/null
+++ b/examples/storybook/stories/material-ui/links/ButtonLink.stories.tsx
@@ -0,0 +1,21 @@
+/* eslint-disable jsx-a11y/anchor-is-valid */
+import React from 'react';
+import Link from '@material-ui/core/Link';
+
+export function ButtonLink() {
+ return (
+ {
+ console.info("I'm a button.");
+ }}
+ >
+ Button Link
+
+ );
+}
+
+export default {
+ title: "Material-ui|links|ButtonLink.stories"
+};
diff --git a/examples/storybook/stories/material-ui/links/Links.stories.tsx b/examples/storybook/stories/material-ui/links/Links.stories.tsx
new file mode 100644
index 00000000000000..3b9145803fd23d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/links/Links.stories.tsx
@@ -0,0 +1,38 @@
+/* eslint-disable jsx-a11y/anchor-is-valid */
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Link from '@material-ui/core/Link';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > * + *': {
+ marginLeft: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function Links() {
+ const classes = useStyles();
+ const preventDefault = (event: React.SyntheticEvent) => event.preventDefault();
+
+ return (
+
+
+ Link
+
+
+ {'color="inherit"'}
+
+
+ {'variant="body2"'}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|links|Links.stories"
+};
diff --git a/examples/storybook/stories/material-ui/lists/AlignItemsList.stories.tsx b/examples/storybook/stories/material-ui/lists/AlignItemsList.stories.tsx
new file mode 100644
index 00000000000000..e3a7ae8fa16dd9
--- /dev/null
+++ b/examples/storybook/stories/material-ui/lists/AlignItemsList.stories.tsx
@@ -0,0 +1,100 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import Divider from '@material-ui/core/Divider';
+import ListItemText from '@material-ui/core/ListItemText';
+import ListItemAvatar from '@material-ui/core/ListItemAvatar';
+import Avatar from '@material-ui/core/Avatar';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: '36ch',
+ backgroundColor: theme.palette.background.paper,
+ },
+ inline: {
+ display: 'inline',
+ },
+ }),
+);
+
+export function AlignItemsList() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+ Ali Connors
+
+ {" — I'll be in your neighborhood doing errands this…"}
+
+ }
+ />
+
+
+
+
+
+
+
+
+ to Scott, Alex, Jennifer
+
+ {" — Wish I could come, but I'm out of town this…"}
+
+ }
+ />
+
+
+
+
+
+
+
+
+ Sandra Adams
+
+ {' — Do you have Paris recommendations? Have you ever…'}
+
+ }
+ />
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|lists|AlignItemsList.stories"
+};
diff --git a/examples/storybook/stories/material-ui/lists/CheckboxList.stories.tsx b/examples/storybook/stories/material-ui/lists/CheckboxList.stories.tsx
new file mode 100644
index 00000000000000..b2215da71d82a6
--- /dev/null
+++ b/examples/storybook/stories/material-ui/lists/CheckboxList.stories.tsx
@@ -0,0 +1,70 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
+import ListItemText from '@material-ui/core/ListItemText';
+import Checkbox from '@material-ui/core/Checkbox';
+import IconButton from '@material-ui/core/IconButton';
+import CommentIcon from '@material-ui/icons/Comment';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function CheckboxList() {
+ const classes = useStyles();
+ const [checked, setChecked] = React.useState([0]);
+
+ const handleToggle = (value: number) => () => {
+ const currentIndex = checked.indexOf(value);
+ const newChecked = [...checked];
+
+ if (currentIndex === -1) {
+ newChecked.push(value);
+ } else {
+ newChecked.splice(currentIndex, 1);
+ }
+
+ setChecked(newChecked);
+ };
+
+ return (
+
+ {[0, 1, 2, 3].map((value) => {
+ const labelId = `checkbox-list-label-${value}`;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+ })}
+
+ );
+}
+
+export default {
+ title: "Material-ui|lists|CheckboxList.stories"
+};
diff --git a/examples/storybook/stories/material-ui/lists/CheckboxListSecondary.stories.tsx b/examples/storybook/stories/material-ui/lists/CheckboxListSecondary.stories.tsx
new file mode 100644
index 00000000000000..2cd7f9940c97f2
--- /dev/null
+++ b/examples/storybook/stories/material-ui/lists/CheckboxListSecondary.stories.tsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
+import ListItemText from '@material-ui/core/ListItemText';
+import ListItemAvatar from '@material-ui/core/ListItemAvatar';
+import Checkbox from '@material-ui/core/Checkbox';
+import Avatar from '@material-ui/core/Avatar';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function CheckboxListSecondary() {
+ const classes = useStyles();
+ const [checked, setChecked] = React.useState([1]);
+
+ const handleToggle = (value: number) => () => {
+ const currentIndex = checked.indexOf(value);
+ const newChecked = [...checked];
+
+ if (currentIndex === -1) {
+ newChecked.push(value);
+ } else {
+ newChecked.splice(currentIndex, 1);
+ }
+
+ setChecked(newChecked);
+ };
+
+ return (
+
+ {[0, 1, 2, 3].map((value) => {
+ const labelId = `checkbox-list-secondary-label-${value}`;
+ return (
+
+
+
+
+
+
+
+
+
+ );
+ })}
+
+ );
+}
+
+export default {
+ title: "Material-ui|lists|CheckboxListSecondary.stories"
+};
diff --git a/examples/storybook/stories/material-ui/lists/FolderList.stories.tsx b/examples/storybook/stories/material-ui/lists/FolderList.stories.tsx
new file mode 100644
index 00000000000000..ab021150a68465
--- /dev/null
+++ b/examples/storybook/stories/material-ui/lists/FolderList.stories.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemText from '@material-ui/core/ListItemText';
+import ListItemAvatar from '@material-ui/core/ListItemAvatar';
+import Avatar from '@material-ui/core/Avatar';
+import ImageIcon from '@material-ui/icons/Image';
+import WorkIcon from '@material-ui/icons/Work';
+import BeachAccessIcon from '@material-ui/icons/BeachAccess';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function FolderList() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|lists|FolderList.stories"
+};
diff --git a/examples/storybook/stories/material-ui/lists/InsetList.stories.tsx b/examples/storybook/stories/material-ui/lists/InsetList.stories.tsx
new file mode 100644
index 00000000000000..23f40b26ef1d86
--- /dev/null
+++ b/examples/storybook/stories/material-ui/lists/InsetList.stories.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import StarIcon from '@material-ui/icons/Star';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function InsetList() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|lists|InsetList.stories"
+};
diff --git a/examples/storybook/stories/material-ui/lists/InteractiveList.stories.tsx b/examples/storybook/stories/material-ui/lists/InteractiveList.stories.tsx
new file mode 100644
index 00000000000000..62f35dba70e7b5
--- /dev/null
+++ b/examples/storybook/stories/material-ui/lists/InteractiveList.stories.tsx
@@ -0,0 +1,162 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemAvatar from '@material-ui/core/ListItemAvatar';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
+import ListItemText from '@material-ui/core/ListItemText';
+import Avatar from '@material-ui/core/Avatar';
+import IconButton from '@material-ui/core/IconButton';
+import FormGroup from '@material-ui/core/FormGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import Checkbox from '@material-ui/core/Checkbox';
+import Grid from '@material-ui/core/Grid';
+import Typography from '@material-ui/core/Typography';
+import FolderIcon from '@material-ui/icons/Folder';
+import DeleteIcon from '@material-ui/icons/Delete';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ maxWidth: 752,
+ },
+ demo: {
+ backgroundColor: theme.palette.background.paper,
+ },
+ title: {
+ margin: theme.spacing(4, 0, 2),
+ },
+ }),
+);
+
+function generate(element: React.ReactElement) {
+ return [0, 1, 2].map((value) =>
+ React.cloneElement(element, {
+ key: value,
+ }),
+ );
+}
+
+export function InteractiveList() {
+ const classes = useStyles();
+ const [dense, setDense] = React.useState(false);
+ const [secondary, setSecondary] = React.useState(false);
+
+ return (
+
+
+ setDense(event.target.checked)} />
+ }
+ label="Enable dense"
+ />
+ setSecondary(event.target.checked)}
+ />
+ }
+ label="Enable secondary text"
+ />
+
+
+
+
+ Text only
+
+
+
+ {generate(
+
+
+ ,
+ )}
+
+
+
+
+
+ Icon with text
+
+
+
+ {generate(
+
+
+
+
+
+ ,
+ )}
+
+
+
+
+
+
+
+ Avatar with text
+
+
+
+ {generate(
+
+
+
+
+
+
+
+ ,
+ )}
+
+
+
+
+
+ Avatar with text and icon
+
+
+
+ {generate(
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ )}
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|lists|InteractiveList.stories"
+};
diff --git a/examples/storybook/stories/material-ui/lists/NestedList.stories.tsx b/examples/storybook/stories/material-ui/lists/NestedList.stories.tsx
new file mode 100644
index 00000000000000..4cd0a67829338c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/lists/NestedList.stories.tsx
@@ -0,0 +1,83 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import ListSubheader from '@material-ui/core/ListSubheader';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import Collapse from '@material-ui/core/Collapse';
+import InboxIcon from '@material-ui/icons/MoveToInbox';
+import DraftsIcon from '@material-ui/icons/Drafts';
+import SendIcon from '@material-ui/icons/Send';
+import ExpandLess from '@material-ui/icons/ExpandLess';
+import ExpandMore from '@material-ui/icons/ExpandMore';
+import StarBorder from '@material-ui/icons/StarBorder';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ nested: {
+ paddingLeft: theme.spacing(4),
+ },
+ }),
+);
+
+export function NestedList() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(true);
+
+ const handleClick = () => {
+ setOpen(!open);
+ };
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|lists|NestedList.stories"
+};
diff --git a/examples/storybook/stories/material-ui/lists/PinnedSubheaderList.stories.tsx b/examples/storybook/stories/material-ui/lists/PinnedSubheaderList.stories.tsx
new file mode 100644
index 00000000000000..115c230ace4156
--- /dev/null
+++ b/examples/storybook/stories/material-ui/lists/PinnedSubheaderList.stories.tsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemText from '@material-ui/core/ListItemText';
+import ListSubheader from '@material-ui/core/ListSubheader';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ position: 'relative',
+ overflow: 'auto',
+ maxHeight: 300,
+ },
+ listSection: {
+ backgroundColor: 'inherit',
+ },
+ ul: {
+ backgroundColor: 'inherit',
+ padding: 0,
+ },
+ }),
+);
+
+export function PinnedSubheaderList() {
+ const classes = useStyles();
+
+ return (
+
}>
+ {[0, 1, 2, 3, 4].map((sectionId) => (
+
+
+ {`I'm sticky ${sectionId}`}
+ {[0, 1, 2].map((item) => (
+
+
+
+ ))}
+
+
+ ))}
+
+ );
+}
+
+export default {
+ title: "Material-ui|lists|PinnedSubheaderList.stories"
+};
diff --git a/examples/storybook/stories/material-ui/lists/SelectedListItem.stories.tsx b/examples/storybook/stories/material-ui/lists/SelectedListItem.stories.tsx
new file mode 100644
index 00000000000000..1d165a6c20c869
--- /dev/null
+++ b/examples/storybook/stories/material-ui/lists/SelectedListItem.stories.tsx
@@ -0,0 +1,79 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import Divider from '@material-ui/core/Divider';
+import InboxIcon from '@material-ui/icons/Inbox';
+import DraftsIcon from '@material-ui/icons/Drafts';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function SelectedListItem() {
+ const classes = useStyles();
+ const [selectedIndex, setSelectedIndex] = React.useState(1);
+
+ const handleListItemClick = (
+ event: React.MouseEvent,
+ index: number,
+ ) => {
+ setSelectedIndex(index);
+ };
+
+ return (
+
+
+ handleListItemClick(event, 0)}
+ >
+
+
+
+
+
+ handleListItemClick(event, 1)}
+ >
+
+
+
+
+
+
+
+
+ handleListItemClick(event, 2)}
+ >
+
+
+ handleListItemClick(event, 3)}
+ >
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|lists|SelectedListItem.stories"
+};
diff --git a/examples/storybook/stories/material-ui/lists/SimpleList.stories.tsx b/examples/storybook/stories/material-ui/lists/SimpleList.stories.tsx
new file mode 100644
index 00000000000000..7c7527c877d10e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/lists/SimpleList.stories.tsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem, { ListItemProps } from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import Divider from '@material-ui/core/Divider';
+import InboxIcon from '@material-ui/icons/Inbox';
+import DraftsIcon from '@material-ui/icons/Drafts';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+function ListItemLink(props: ListItemProps<'a', { button?: true }>) {
+ return ;
+}
+
+export function SimpleList() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|lists|SimpleList.stories"
+};
diff --git a/examples/storybook/stories/material-ui/lists/SwitchListSecondary.stories.tsx b/examples/storybook/stories/material-ui/lists/SwitchListSecondary.stories.tsx
new file mode 100644
index 00000000000000..efa41772e68315
--- /dev/null
+++ b/examples/storybook/stories/material-ui/lists/SwitchListSecondary.stories.tsx
@@ -0,0 +1,76 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
+import ListItemText from '@material-ui/core/ListItemText';
+import ListSubheader from '@material-ui/core/ListSubheader';
+import Switch from '@material-ui/core/Switch';
+import WifiIcon from '@material-ui/icons/Wifi';
+import BluetoothIcon from '@material-ui/icons/Bluetooth';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ maxWidth: 360,
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function SwitchListSecondary() {
+ const classes = useStyles();
+ const [checked, setChecked] = React.useState(['wifi']);
+
+ const handleToggle = (value: string) => () => {
+ const currentIndex = checked.indexOf(value);
+ const newChecked = [...checked];
+
+ if (currentIndex === -1) {
+ newChecked.push(value);
+ } else {
+ newChecked.splice(currentIndex, 1);
+ }
+
+ setChecked(newChecked);
+ };
+
+ return (
+ Settings} className={classes.root}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|lists|SwitchListSecondary.stories"
+};
diff --git a/examples/storybook/stories/material-ui/lists/VirtualizedList.stories.tsx b/examples/storybook/stories/material-ui/lists/VirtualizedList.stories.tsx
new file mode 100644
index 00000000000000..e3664c317002ea
--- /dev/null
+++ b/examples/storybook/stories/material-ui/lists/VirtualizedList.stories.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemText from '@material-ui/core/ListItemText';
+import { FixedSizeList, ListChildComponentProps } from 'react-window';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ height: 400,
+ maxWidth: 300,
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+function renderRow(props: ListChildComponentProps) {
+ const { index, style } = props;
+
+ return (
+
+
+
+ );
+}
+
+export function VirtualizedList() {
+ const classes = useStyles();
+
+ return (
+
+
+ {renderRow}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|lists|VirtualizedList.stories"
+};
diff --git a/examples/storybook/stories/material-ui/menus/ContextMenu.stories.tsx b/examples/storybook/stories/material-ui/menus/ContextMenu.stories.tsx
new file mode 100644
index 00000000000000..9ebd4c392fa12b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/menus/ContextMenu.stories.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import Menu from '@material-ui/core/Menu';
+import MenuItem from '@material-ui/core/MenuItem';
+import Typography from '@material-ui/core/Typography';
+
+const initialState = {
+ mouseX: null,
+ mouseY: null,
+};
+
+export function ContextMenu() {
+ const [state, setState] = React.useState<{
+ mouseX: null | number;
+ mouseY: null | number;
+ }>(initialState);
+
+ const handleClick = (event: React.MouseEvent) => {
+ event.preventDefault();
+ setState({
+ mouseX: event.clientX - 2,
+ mouseY: event.clientY - 4,
+ });
+ };
+
+ const handleClose = () => {
+ setState(initialState);
+ };
+
+ return (
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ipsum purus, bibendum sit
+ amet vulputate eget, porta semper ligula. Donec bibendum vulputate erat, ac fringilla mi
+ finibus nec. Donec ac dolor sed dolor porttitor blandit vel vel purus. Fusce vel malesuada
+ ligula. Nam quis vehicula ante, eu finibus est. Proin ullamcorper fermentum orci, quis
+ finibus massa. Nunc lobortis, massa ut rutrum ultrices, metus metus finibus ex, sit amet
+ facilisis neque enim sed neque. Quisque accumsan metus vel maximus consequat. Suspendisse
+ lacinia tellus a libero volutpat maximus.
+
+
+ Copy
+ Print
+ Highlight
+ Email
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|menus|ContextMenu.stories"
+};
diff --git a/examples/storybook/stories/material-ui/menus/CustomizedMenus.stories.tsx b/examples/storybook/stories/material-ui/menus/CustomizedMenus.stories.tsx
new file mode 100644
index 00000000000000..344a0ada5b656c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/menus/CustomizedMenus.stories.tsx
@@ -0,0 +1,97 @@
+import React from 'react';
+import { withStyles } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import Menu, { MenuProps } from '@material-ui/core/Menu';
+import MenuItem from '@material-ui/core/MenuItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import InboxIcon from '@material-ui/icons/MoveToInbox';
+import DraftsIcon from '@material-ui/icons/Drafts';
+import SendIcon from '@material-ui/icons/Send';
+
+const StyledMenu = withStyles({
+ paper: {
+ border: '1px solid #d3d4d5',
+ },
+})((props: MenuProps) => (
+
+));
+
+const StyledMenuItem = withStyles((theme) => ({
+ root: {
+ '&:focus': {
+ backgroundColor: theme.palette.primary.main,
+ '& .MuiListItemIcon-root, & .MuiListItemText-primary': {
+ color: theme.palette.common.white,
+ },
+ },
+ },
+}))(MenuItem);
+
+export function CustomizedMenus() {
+ const [anchorEl, setAnchorEl] = React.useState(null);
+
+ const handleClick = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ return (
+
+
+ Open Menu
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|menus|CustomizedMenus.stories"
+};
diff --git a/examples/storybook/stories/material-ui/menus/FadeMenu.stories.tsx b/examples/storybook/stories/material-ui/menus/FadeMenu.stories.tsx
new file mode 100644
index 00000000000000..71ab4cb3347728
--- /dev/null
+++ b/examples/storybook/stories/material-ui/menus/FadeMenu.stories.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Menu from '@material-ui/core/Menu';
+import MenuItem from '@material-ui/core/MenuItem';
+import Fade from '@material-ui/core/Fade';
+
+export function FadeMenu() {
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const open = Boolean(anchorEl);
+
+ const handleClick = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ return (
+
+
+ Open with fade transition
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|menus|FadeMenu.stories"
+};
diff --git a/examples/storybook/stories/material-ui/menus/LongMenu.stories.tsx b/examples/storybook/stories/material-ui/menus/LongMenu.stories.tsx
new file mode 100644
index 00000000000000..0514cb9b9b6f59
--- /dev/null
+++ b/examples/storybook/stories/material-ui/menus/LongMenu.stories.tsx
@@ -0,0 +1,73 @@
+import React from 'react';
+import IconButton from '@material-ui/core/IconButton';
+import Menu from '@material-ui/core/Menu';
+import MenuItem from '@material-ui/core/MenuItem';
+import MoreVertIcon from '@material-ui/icons/MoreVert';
+
+const options = [
+ 'None',
+ 'Atria',
+ 'Callisto',
+ 'Dione',
+ 'Ganymede',
+ 'Hangouts Call',
+ 'Luna',
+ 'Oberon',
+ 'Phobos',
+ 'Pyxis',
+ 'Sedna',
+ 'Titania',
+ 'Triton',
+ 'Umbriel',
+];
+
+const ITEM_HEIGHT = 48;
+
+export function LongMenu() {
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const open = Boolean(anchorEl);
+
+ const handleClick = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|menus|LongMenu.stories"
+};
diff --git a/examples/storybook/stories/material-ui/menus/MenuListComposition.stories.tsx b/examples/storybook/stories/material-ui/menus/MenuListComposition.stories.tsx
new file mode 100644
index 00000000000000..bc9993e932e38f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/menus/MenuListComposition.stories.tsx
@@ -0,0 +1,99 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import ClickAwayListener from '@material-ui/core/ClickAwayListener';
+import Grow from '@material-ui/core/Grow';
+import Paper from '@material-ui/core/Paper';
+import Popper from '@material-ui/core/Popper';
+import MenuItem from '@material-ui/core/MenuItem';
+import MenuList from '@material-ui/core/MenuList';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ },
+ paper: {
+ marginRight: theme.spacing(2),
+ },
+ }),
+);
+
+export function MenuListComposition() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+ const anchorRef = React.useRef(null);
+
+ const handleToggle = () => {
+ setOpen((prevOpen) => !prevOpen);
+ };
+
+ const handleClose = (event: React.MouseEvent) => {
+ if (anchorRef.current && anchorRef.current.contains(event.target as HTMLElement)) {
+ return;
+ }
+
+ setOpen(false);
+ };
+
+ function handleListKeyDown(event: React.KeyboardEvent) {
+ if (event.key === 'Tab') {
+ event.preventDefault();
+ setOpen(false);
+ }
+ }
+
+ // return focus to the button when we transitioned from !open -> open
+ const prevOpen = React.useRef(open);
+ React.useEffect(() => {
+ if (prevOpen.current === true && open === false) {
+ anchorRef.current!.focus();
+ }
+
+ prevOpen.current = open;
+ }, [open]);
+
+ return (
+
+
+
+ Profile
+ My account
+ Logout
+
+
+
+
+ Toggle Menu Grow
+
+
+ {({ TransitionProps, placement }) => (
+
+
+
+
+
+
+
+ )}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|menus|MenuListComposition.stories"
+};
diff --git a/examples/storybook/stories/material-ui/menus/MenuPopupState.stories.tsx b/examples/storybook/stories/material-ui/menus/MenuPopupState.stories.tsx
new file mode 100644
index 00000000000000..a3691304d22fd9
--- /dev/null
+++ b/examples/storybook/stories/material-ui/menus/MenuPopupState.stories.tsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Menu from '@material-ui/core/Menu';
+import MenuItem from '@material-ui/core/MenuItem';
+import PopupState, { bindTrigger, bindMenu } from 'material-ui-popup-state';
+
+export function MenuPopupState() {
+ return (
+
+ {(popupState) => (
+
+
+ Open Menu
+
+
+ Cake
+ Death
+
+
+ )}
+
+ );
+}
+
+export default {
+ title: "Material-ui|menus|MenuPopupState.stories"
+};
diff --git a/examples/storybook/stories/material-ui/menus/SimpleListMenu.stories.tsx b/examples/storybook/stories/material-ui/menus/SimpleListMenu.stories.tsx
new file mode 100644
index 00000000000000..b44dfa5abbdfef
--- /dev/null
+++ b/examples/storybook/stories/material-ui/menus/SimpleListMenu.stories.tsx
@@ -0,0 +1,79 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemText from '@material-ui/core/ListItemText';
+import MenuItem from '@material-ui/core/MenuItem';
+import Menu from '@material-ui/core/Menu';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+const options = [
+ 'Show some love to Material-UI',
+ 'Show all notification content',
+ 'Hide sensitive notification content',
+ 'Hide all notification content',
+];
+
+export function SimpleListMenu() {
+ const classes = useStyles();
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const [selectedIndex, setSelectedIndex] = React.useState(1);
+
+ const handleClickListItem = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleMenuItemClick = (event: React.MouseEvent, index: number) => {
+ setSelectedIndex(index);
+ setAnchorEl(null);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|menus|SimpleListMenu.stories"
+};
diff --git a/examples/storybook/stories/material-ui/menus/SimpleMenu.stories.tsx b/examples/storybook/stories/material-ui/menus/SimpleMenu.stories.tsx
new file mode 100644
index 00000000000000..7a340f041d0cb0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/menus/SimpleMenu.stories.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Menu from '@material-ui/core/Menu';
+import MenuItem from '@material-ui/core/MenuItem';
+
+export function SimpleMenu() {
+ const [anchorEl, setAnchorEl] = React.useState(null);
+
+ const handleClick = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ return (
+
+
+ Open Menu
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|menus|SimpleMenu.stories"
+};
diff --git a/examples/storybook/stories/material-ui/menus/TypographyMenu.stories.tsx b/examples/storybook/stories/material-ui/menus/TypographyMenu.stories.tsx
new file mode 100644
index 00000000000000..8b2422c80a1a7a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/menus/TypographyMenu.stories.tsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import MenuList from '@material-ui/core/MenuList';
+import MenuItem from '@material-ui/core/MenuItem';
+import Paper from '@material-ui/core/Paper';
+import { makeStyles } from '@material-ui/core/styles';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import Typography from '@material-ui/core/Typography';
+import DraftsIcon from '@material-ui/icons/Drafts';
+import SendIcon from '@material-ui/icons/Send';
+import PriorityHighIcon from '@material-ui/icons/PriorityHigh';
+
+const useStyles = makeStyles({
+ root: {
+ width: 230,
+ },
+});
+
+export function TypographyMenu() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+ A short message
+
+
+
+
+
+ A very long text that overflows
+
+
+
+
+
+
+ A very long text that overflows
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|menus|TypographyMenu.stories"
+};
diff --git a/examples/storybook/stories/material-ui/modal/ServerModal.stories.tsx b/examples/storybook/stories/material-ui/modal/ServerModal.stories.tsx
new file mode 100644
index 00000000000000..150b1fa70f028a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/modal/ServerModal.stories.tsx
@@ -0,0 +1,61 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Modal from '@material-ui/core/Modal';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ height: 300,
+ flexGrow: 1,
+ minWidth: 300,
+ transform: 'translateZ(0)',
+ // The position fixed scoping doesn't work in IE 11.
+ // Disable this demo to preserve the others.
+ '@media all and (-ms-high-contrast: none)': {
+ display: 'none',
+ },
+ },
+ modal: {
+ display: 'flex',
+ padding: theme.spacing(1),
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ paper: {
+ width: 400,
+ backgroundColor: theme.palette.background.paper,
+ border: '2px solid #000',
+ boxShadow: theme.shadows[5],
+ padding: theme.spacing(2, 4, 3),
+ },
+ }),
+);
+
+export function ServerModal() {
+ const classes = useStyles();
+ const rootRef = React.useRef(null);
+
+ return (
+
+
rootRef.current}
+ >
+
+
Server-side modal
+
If you disable JavaScript, you will still see me.
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|modal|ServerModal.stories"
+};
diff --git a/examples/storybook/stories/material-ui/modal/SimpleModal.stories.tsx b/examples/storybook/stories/material-ui/modal/SimpleModal.stories.tsx
new file mode 100644
index 00000000000000..1a4645cf0d81f1
--- /dev/null
+++ b/examples/storybook/stories/material-ui/modal/SimpleModal.stories.tsx
@@ -0,0 +1,76 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Modal from '@material-ui/core/Modal';
+
+function rand() {
+ return Math.round(Math.random() * 20) - 10;
+}
+
+function getModalStyle() {
+ const top = 50 + rand();
+ const left = 50 + rand();
+
+ return {
+ top: `${top}%`,
+ left: `${left}%`,
+ transform: `translate(-${top}%, -${left}%)`,
+ };
+}
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ paper: {
+ position: 'absolute',
+ width: 400,
+ backgroundColor: theme.palette.background.paper,
+ border: '2px solid #000',
+ boxShadow: theme.shadows[5],
+ padding: theme.spacing(2, 4, 3),
+ },
+ }),
+);
+
+export function SimpleModal() {
+ const classes = useStyles();
+ // getModalStyle is not a pure function, we roll the style only on the first render
+ const [modalStyle] = React.useState(getModalStyle);
+ const [open, setOpen] = React.useState(false);
+
+ const handleOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ const body = (
+
+
Text in a modal
+
+ Duis mollis, est non commodo luctus, nisi erat porttitor ligula.
+
+
+
+ );
+
+ return (
+
+
+ Open Modal
+
+
+ {body}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|modal|SimpleModal.stories"
+};
diff --git a/examples/storybook/stories/material-ui/modal/SpringModal.stories.tsx b/examples/storybook/stories/material-ui/modal/SpringModal.stories.tsx
new file mode 100644
index 00000000000000..66e9fa9cfbea41
--- /dev/null
+++ b/examples/storybook/stories/material-ui/modal/SpringModal.stories.tsx
@@ -0,0 +1,96 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Modal from '@material-ui/core/Modal';
+import Backdrop from '@material-ui/core/Backdrop';
+import { useSpring, animated } from 'react-spring/web.cjs'; // web.cjs is required for IE 11 support
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ modal: {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ paper: {
+ backgroundColor: theme.palette.background.paper,
+ border: '2px solid #000',
+ boxShadow: theme.shadows[5],
+ padding: theme.spacing(2, 4, 3),
+ },
+ }),
+);
+
+interface FadeProps {
+ children?: React.ReactElement;
+ in: boolean;
+ onEnter?: () => {};
+ onExited?: () => {};
+}
+
+const Fade = React.forwardRef(function Fade(props, ref) {
+ const { in: open, children, onEnter, onExited, ...other } = props;
+ const style = useSpring({
+ from: { opacity: 0 },
+ to: { opacity: open ? 1 : 0 },
+ onStart: () => {
+ if (open && onEnter) {
+ onEnter();
+ }
+ },
+ onRest: () => {
+ if (!open && onExited) {
+ onExited();
+ }
+ },
+ });
+
+ return (
+
+ {children}
+
+ );
+});
+
+export function SpringModal() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+
+ const handleOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+ react-spring
+
+
+
+
+
Spring modal
+
react-spring animates me.
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|modal|SpringModal.stories"
+};
diff --git a/examples/storybook/stories/material-ui/modal/TransitionsModal.stories.tsx b/examples/storybook/stories/material-ui/modal/TransitionsModal.stories.tsx
new file mode 100644
index 00000000000000..3798375ac53cb3
--- /dev/null
+++ b/examples/storybook/stories/material-ui/modal/TransitionsModal.stories.tsx
@@ -0,0 +1,65 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Modal from '@material-ui/core/Modal';
+import Backdrop from '@material-ui/core/Backdrop';
+import Fade from '@material-ui/core/Fade';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ modal: {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ paper: {
+ backgroundColor: theme.palette.background.paper,
+ border: '2px solid #000',
+ boxShadow: theme.shadows[5],
+ padding: theme.spacing(2, 4, 3),
+ },
+ }),
+);
+
+export function TransitionsModal() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+
+ const handleOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+
+ react-transition-group
+
+
+
+
+
Transition modal
+
react-transition-group animates me.
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|modal|TransitionsModal.stories"
+};
diff --git a/examples/storybook/stories/material-ui/no-ssr/FrameDeferring.stories.tsx b/examples/storybook/stories/material-ui/no-ssr/FrameDeferring.stories.tsx
new file mode 100644
index 00000000000000..3bdd9449549b74
--- /dev/null
+++ b/examples/storybook/stories/material-ui/no-ssr/FrameDeferring.stories.tsx
@@ -0,0 +1,65 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import NoSsr from '@material-ui/core/NoSsr';
+
+const useStyles = makeStyles({
+ container: {
+ width: 300,
+ display: 'flex',
+ flexWrap: 'wrap',
+ },
+});
+
+function LargeTree(): any {
+ return Array.from(new Array(5000)).map((_, index) => . );
+}
+
+export function FrameDeferring() {
+ const classes = useStyles();
+ const [state, setState] = React.useState({ open: false, defer: false });
+
+ return (
+
+
+ setState({
+ open: !state.open,
+ defer: false,
+ })
+ }
+ >
+ {'Render NoSsr defer="false"'}
+
+
+
+ setState({
+ open: !state.open,
+ defer: true,
+ })
+ }
+ >
+ {'Render NoSsr defer="true"'}
+
+
+
+
+ {state.open ? (
+
+ Outside NoSsr
+
+ .....Inside NoSsr
+
+
+
+ ) : null}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|no-ssr|FrameDeferring.stories"
+};
diff --git a/examples/storybook/stories/material-ui/no-ssr/SimpleNoSsr.stories.tsx b/examples/storybook/stories/material-ui/no-ssr/SimpleNoSsr.stories.tsx
new file mode 100644
index 00000000000000..c94993db13d1b2
--- /dev/null
+++ b/examples/storybook/stories/material-ui/no-ssr/SimpleNoSsr.stories.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import NoSsr from '@material-ui/core/NoSsr';
+import Box from '@material-ui/core/Box';
+
+export function SimpleNoSsr() {
+ return (
+
+
+ Server and Client
+
+
+
+ Client only
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|no-ssr|SimpleNoSsr.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pagination/BasicPagination.stories.tsx b/examples/storybook/stories/material-ui/pagination/BasicPagination.stories.tsx
new file mode 100644
index 00000000000000..66af4694755ff5
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pagination/BasicPagination.stories.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { makeStyles, createStyles } from '@material-ui/core/styles';
+import Pagination from '@material-ui/lab/Pagination';
+
+const useStyles = makeStyles((theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function BasicPagination() {
+ const classes = useStyles();
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|pagination|BasicPagination.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pagination/PaginationButtons.stories.tsx b/examples/storybook/stories/material-ui/pagination/PaginationButtons.stories.tsx
new file mode 100644
index 00000000000000..0048ff54acec95
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pagination/PaginationButtons.stories.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { makeStyles, createStyles } from '@material-ui/core/styles';
+import Pagination from '@material-ui/lab/Pagination';
+
+const useStyles = makeStyles((theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function PaginationButtons() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|pagination|PaginationButtons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pagination/PaginationControlled.stories.tsx b/examples/storybook/stories/material-ui/pagination/PaginationControlled.stories.tsx
new file mode 100644
index 00000000000000..a0f439e0d99220
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pagination/PaginationControlled.stories.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { makeStyles, createStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Pagination from '@material-ui/lab/Pagination';
+
+const useStyles = makeStyles((theme) =>
+ createStyles({
+ root: {
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function PaginationControlled() {
+ const classes = useStyles();
+ const [page, setPage] = React.useState(1);
+ const handleChange = (event: React.ChangeEvent, value: number) => {
+ setPage(value);
+ };
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|pagination|PaginationControlled.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pagination/PaginationLink.stories.tsx b/examples/storybook/stories/material-ui/pagination/PaginationLink.stories.tsx
new file mode 100644
index 00000000000000..821b3e54752738
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pagination/PaginationLink.stories.tsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import { MemoryRouter, Route } from 'react-router';
+import { Link } from 'react-router-dom';
+import Pagination from '@material-ui/lab/Pagination';
+import PaginationItem from '@material-ui/lab/PaginationItem';
+
+export function PaginationLink() {
+ return (
+
+
+ {({ location }) => {
+ const query = new URLSearchParams(location.search);
+ const page = parseInt(query.get('page') || '1', 10);
+ return (
+ (
+
+ )}
+ />
+ );
+ }}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|pagination|PaginationLink.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pagination/PaginationOutlined.stories.tsx b/examples/storybook/stories/material-ui/pagination/PaginationOutlined.stories.tsx
new file mode 100644
index 00000000000000..cb9210e010b5d9
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pagination/PaginationOutlined.stories.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { makeStyles, createStyles } from '@material-ui/core/styles';
+import Pagination from '@material-ui/lab/Pagination';
+
+const useStyles = makeStyles((theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function PaginationOutlined() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|pagination|PaginationOutlined.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pagination/PaginationRanges.stories.tsx b/examples/storybook/stories/material-ui/pagination/PaginationRanges.stories.tsx
new file mode 100644
index 00000000000000..c0a5ebc2321347
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pagination/PaginationRanges.stories.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { makeStyles, createStyles } from '@material-ui/core/styles';
+import Pagination from '@material-ui/lab/Pagination';
+
+const useStyles = makeStyles((theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function PaginationRanges() {
+ const classes = useStyles();
+
+ return (
+
+
+
{/* Default ranges */}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|pagination|PaginationRanges.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pagination/PaginationRounded.stories.tsx b/examples/storybook/stories/material-ui/pagination/PaginationRounded.stories.tsx
new file mode 100644
index 00000000000000..3538dbae4de9c8
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pagination/PaginationRounded.stories.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { makeStyles, createStyles } from '@material-ui/core/styles';
+import Pagination from '@material-ui/lab/Pagination';
+
+const useStyles = makeStyles((theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function PaginationRounded() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|pagination|PaginationRounded.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pagination/PaginationSize.stories.tsx b/examples/storybook/stories/material-ui/pagination/PaginationSize.stories.tsx
new file mode 100644
index 00000000000000..e62b7276e01aba
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pagination/PaginationSize.stories.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { makeStyles, createStyles } from '@material-ui/core/styles';
+import Pagination from '@material-ui/lab/Pagination';
+
+const useStyles = makeStyles((theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function PaginationSize() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|pagination|PaginationSize.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pagination/TablePagination.stories.tsx b/examples/storybook/stories/material-ui/pagination/TablePagination.stories.tsx
new file mode 100644
index 00000000000000..098f8cfe6b0764
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pagination/TablePagination.stories.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import TablePagination from '@material-ui/core/TablePagination';
+
+export function TablePaginationDemo() {
+ const [page, setPage] = React.useState(2);
+ const [rowsPerPage, setRowsPerPage] = React.useState(10);
+
+ const handleChangePage = (event: React.MouseEvent | null, newPage: number) => {
+ setPage(newPage);
+ };
+
+ const handleChangeRowsPerPage = (
+ event: React.ChangeEvent,
+ ) => {
+ setRowsPerPage(parseInt(event.target.value, 10));
+ setPage(0);
+ };
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|pagination|TablePagination.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pagination/UsePagination.stories.tsx b/examples/storybook/stories/material-ui/pagination/UsePagination.stories.tsx
new file mode 100644
index 00000000000000..d774ff35c4b0b6
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pagination/UsePagination.stories.tsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import { usePagination } from '@material-ui/lab/Pagination';
+import { makeStyles } from '@material-ui/core/styles';
+
+const useStyles = makeStyles({
+ ul: {
+ listStyle: 'none',
+ padding: 0,
+ margin: 0,
+ display: 'flex',
+ },
+});
+
+export function UsePagination() {
+ const classes = useStyles();
+ const { items } = usePagination({
+ count: 10,
+ });
+
+ return (
+
+
+ {items.map(({ page, type, selected, ...item }, index) => {
+ let children = null;
+
+ if (type === 'start-ellipsis' || type === 'end-ellipsis') {
+ children = '…';
+ } else if (type === 'page') {
+ children = (
+
+ {page}
+
+ );
+ } else {
+ children = (
+
+ {type}
+
+ );
+ }
+
+ return {children} ;
+ })}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|pagination|UsePagination.stories"
+};
diff --git a/examples/storybook/stories/material-ui/paper/SimplePaper.stories.tsx b/examples/storybook/stories/material-ui/paper/SimplePaper.stories.tsx
new file mode 100644
index 00000000000000..42a910de9439d9
--- /dev/null
+++ b/examples/storybook/stories/material-ui/paper/SimplePaper.stories.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
+import Paper from '@material-ui/core/Paper';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ '& > *': {
+ margin: theme.spacing(1),
+ width: theme.spacing(16),
+ height: theme.spacing(16),
+ },
+ },
+ }),
+);
+
+export function SimplePaper() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|paper|SimplePaper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/paper/Variants.stories.tsx b/examples/storybook/stories/material-ui/paper/Variants.stories.tsx
new file mode 100644
index 00000000000000..0c31fc4a320127
--- /dev/null
+++ b/examples/storybook/stories/material-ui/paper/Variants.stories.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { Theme, createStyles, makeStyles } from '@material-ui/core/styles';
+import Paper from '@material-ui/core/Paper';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ '& > *': {
+ margin: theme.spacing(1),
+ width: theme.spacing(16),
+ height: theme.spacing(16),
+ },
+ },
+ }),
+);
+
+export function Variants() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|paper|Variants.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pickers/DateAndTimePickers.stories.tsx b/examples/storybook/stories/material-ui/pickers/DateAndTimePickers.stories.tsx
new file mode 100644
index 00000000000000..2811346df8351b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pickers/DateAndTimePickers.stories.tsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ container: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ },
+ textField: {
+ marginLeft: theme.spacing(1),
+ marginRight: theme.spacing(1),
+ width: 200,
+ },
+ }),
+);
+
+export function DateAndTimePickers() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|pickers|DateAndTimePickers.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pickers/DatePickers.stories.tsx b/examples/storybook/stories/material-ui/pickers/DatePickers.stories.tsx
new file mode 100644
index 00000000000000..5af875ac77fa5d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pickers/DatePickers.stories.tsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ container: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ },
+ textField: {
+ marginLeft: theme.spacing(1),
+ marginRight: theme.spacing(1),
+ width: 200,
+ },
+ }),
+);
+
+export function DatePickers() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|pickers|DatePickers.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pickers/MaterialUIPickers.stories.tsx b/examples/storybook/stories/material-ui/pickers/MaterialUIPickers.stories.tsx
new file mode 100644
index 00000000000000..0620807d55d228
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pickers/MaterialUIPickers.stories.tsx
@@ -0,0 +1,65 @@
+import 'date-fns';
+import React from 'react';
+import Grid from '@material-ui/core/Grid';
+import DateFnsUtils from '@date-io/date-fns';
+import {
+ MuiPickersUtilsProvider,
+ KeyboardTimePicker,
+ KeyboardDatePicker,
+} from '@material-ui/pickers';
+
+export function MaterialUIPickers() {
+ // The first commit of Material-UI
+ const [selectedDate, setSelectedDate] = React.useState(
+ new Date('2014-08-18T21:11:54'),
+ );
+
+ const handleDateChange = (date: Date | null) => {
+ setSelectedDate(date);
+ };
+
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|pickers|MaterialUIPickers.stories"
+};
diff --git a/examples/storybook/stories/material-ui/pickers/TimePickers.stories.tsx b/examples/storybook/stories/material-ui/pickers/TimePickers.stories.tsx
new file mode 100644
index 00000000000000..7ca2c29a7a85e2
--- /dev/null
+++ b/examples/storybook/stories/material-ui/pickers/TimePickers.stories.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ container: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ },
+ textField: {
+ marginLeft: theme.spacing(1),
+ marginRight: theme.spacing(1),
+ width: 200,
+ },
+ }),
+);
+
+export function TimePickers() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|pickers|TimePickers.stories"
+};
diff --git a/examples/storybook/stories/material-ui/popover/MouseOverPopover.stories.tsx b/examples/storybook/stories/material-ui/popover/MouseOverPopover.stories.tsx
new file mode 100644
index 00000000000000..ff00aea59da35f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/popover/MouseOverPopover.stories.tsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import Popover from '@material-ui/core/Popover';
+import Typography from '@material-ui/core/Typography';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ popover: {
+ pointerEvents: 'none',
+ },
+ paper: {
+ padding: theme.spacing(1),
+ },
+ }),
+);
+
+export function MouseOverPopover() {
+ const classes = useStyles();
+ const [anchorEl, setAnchorEl] = React.useState(null);
+
+ const handlePopoverOpen = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handlePopoverClose = () => {
+ setAnchorEl(null);
+ };
+
+ const open = Boolean(anchorEl);
+
+ return (
+
+
+ Hover with a Popover.
+
+
+ I use Popover.
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|popover|MouseOverPopover.stories"
+};
diff --git a/examples/storybook/stories/material-ui/popover/PopoverPopupState.stories.tsx b/examples/storybook/stories/material-ui/popover/PopoverPopupState.stories.tsx
new file mode 100644
index 00000000000000..41887e3ba3a1c0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/popover/PopoverPopupState.stories.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import Typography from '@material-ui/core/Typography';
+import Box from '@material-ui/core/Box';
+import Button from '@material-ui/core/Button';
+import Popover from '@material-ui/core/Popover';
+import PopupState, { bindTrigger, bindPopover } from 'material-ui-popup-state';
+
+export function PopoverPopupState() {
+ return (
+
+ {(popupState) => (
+
+
+ Open Popover
+
+
+
+ The content of the Popover.
+
+
+
+ )}
+
+ );
+}
+
+export default {
+ title: "Material-ui|popover|PopoverPopupState.stories"
+};
diff --git a/examples/storybook/stories/material-ui/popover/SimplePopover.stories.tsx b/examples/storybook/stories/material-ui/popover/SimplePopover.stories.tsx
new file mode 100644
index 00000000000000..db443809f5dd3a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/popover/SimplePopover.stories.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Popover from '@material-ui/core/Popover';
+import Typography from '@material-ui/core/Typography';
+import Button from '@material-ui/core/Button';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ typography: {
+ padding: theme.spacing(2),
+ },
+ }),
+);
+
+export function SimplePopover() {
+ const classes = useStyles();
+ const [anchorEl, setAnchorEl] = React.useState(null);
+
+ const handleClick = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ const open = Boolean(anchorEl);
+ const id = open ? 'simple-popover' : undefined;
+
+ return (
+
+
+ Open Popover
+
+
+ The content of the Popover.
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|popover|SimplePopover.stories"
+};
diff --git a/examples/storybook/stories/material-ui/popper/FakedReferencePopper.stories.tsx b/examples/storybook/stories/material-ui/popper/FakedReferencePopper.stories.tsx
new file mode 100644
index 00000000000000..1c411fef23c5ae
--- /dev/null
+++ b/examples/storybook/stories/material-ui/popper/FakedReferencePopper.stories.tsx
@@ -0,0 +1,72 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Popper, { PopperProps } from '@material-ui/core/Popper';
+import Typography from '@material-ui/core/Typography';
+import Fade from '@material-ui/core/Fade';
+import Paper from '@material-ui/core/Paper';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ typography: {
+ padding: theme.spacing(2),
+ },
+ }),
+);
+
+export function FakedReferencePopper() {
+ const [open, setOpen] = React.useState(false);
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const classes = useStyles();
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ const handleMouseUp = () => {
+ const selection = window.getSelection();
+
+ // Resets when the selection has a length of 0
+ if (!selection || selection.anchorOffset === selection.focusOffset) {
+ handleClose();
+ return;
+ }
+
+ const getBoundingClientRect = () => selection.getRangeAt(0).getBoundingClientRect();
+
+ setOpen(true);
+ setAnchorEl({
+ clientWidth: getBoundingClientRect().width,
+ clientHeight: getBoundingClientRect().height,
+ getBoundingClientRect,
+ });
+ };
+
+ const id = open ? 'faked-reference-popper' : undefined;
+
+ return (
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ipsum purus, bibendum sit
+ amet vulputate eget, porta semper ligula. Donec bibendum vulputate erat, ac fringilla mi
+ finibus nec. Donec ac dolor sed dolor porttitor blandit vel vel purus. Fusce vel malesuada
+ ligula. Nam quis vehicula ante, eu finibus est. Proin ullamcorper fermentum orci, quis
+ finibus massa. Nunc lobortis, massa ut rutrum ultrices, metus metus finibus ex, sit amet
+ facilisis neque enim sed neque. Quisque accumsan metus vel maximus consequat. Suspendisse
+ lacinia tellus a libero volutpat maximus.
+
+
+ {({ TransitionProps }) => (
+
+
+ The content of the Popper.
+
+
+ )}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|popper|FakedReferencePopper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/popper/PopperPopupState.stories.tsx b/examples/storybook/stories/material-ui/popper/PopperPopupState.stories.tsx
new file mode 100644
index 00000000000000..e71b2b29d3ab08
--- /dev/null
+++ b/examples/storybook/stories/material-ui/popper/PopperPopupState.stories.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { makeStyles, createStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Button from '@material-ui/core/Button';
+import Popper from '@material-ui/core/Popper';
+import PopupState, { bindToggle, bindPopper } from 'material-ui-popup-state';
+import Fade from '@material-ui/core/Fade';
+import Paper from '@material-ui/core/Paper';
+
+const useStyles = makeStyles((theme) =>
+ createStyles({
+ typography: {
+ padding: theme.spacing(2),
+ },
+ }),
+);
+
+export function PopperPopupState() {
+ const classes = useStyles();
+
+ return (
+
+ {(popupState) => (
+
+
+ Toggle Popper
+
+
+ {({ TransitionProps }) => (
+
+
+ The content of the Popper.
+
+
+ )}
+
+
+ )}
+
+ );
+}
+
+export default {
+ title: "Material-ui|popper|PopperPopupState.stories"
+};
diff --git a/examples/storybook/stories/material-ui/popper/PositionedPopper.stories.tsx b/examples/storybook/stories/material-ui/popper/PositionedPopper.stories.tsx
new file mode 100644
index 00000000000000..325561a690a2ae
--- /dev/null
+++ b/examples/storybook/stories/material-ui/popper/PositionedPopper.stories.tsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Popper, { PopperPlacementType } from '@material-ui/core/Popper';
+import Typography from '@material-ui/core/Typography';
+import Grid from '@material-ui/core/Grid';
+import Button from '@material-ui/core/Button';
+import Fade from '@material-ui/core/Fade';
+import Paper from '@material-ui/core/Paper';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 500,
+ },
+ typography: {
+ padding: theme.spacing(2),
+ },
+ }),
+);
+
+export function PositionedPopper() {
+ const [anchorEl, setAnchorEl] = React.useState(null);
+ const [open, setOpen] = React.useState(false);
+ const [placement, setPlacement] = React.useState();
+ const classes = useStyles();
+
+ const handleClick = (newPlacement: PopperPlacementType) => (
+ event: React.MouseEvent,
+ ) => {
+ setAnchorEl(event.currentTarget);
+ setOpen((prev) => placement !== newPlacement || !prev);
+ setPlacement(newPlacement);
+ };
+
+ return (
+
+
+ {({ TransitionProps }) => (
+
+
+ The content of the Popper.
+
+
+ )}
+
+
+
+ top-start
+ top
+ top-end
+
+
+
+
+ left-start
+
+ left
+
+ left-end
+
+
+
+ right-start
+
+
+ right
+
+
+ right-end
+
+
+
+
+
+ bottom-start
+ bottom
+ bottom-end
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|popper|PositionedPopper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/popper/SimplePopper.stories.tsx b/examples/storybook/stories/material-ui/popper/SimplePopper.stories.tsx
new file mode 100644
index 00000000000000..84777e0dd87341
--- /dev/null
+++ b/examples/storybook/stories/material-ui/popper/SimplePopper.stories.tsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Popper from '@material-ui/core/Popper';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ paper: {
+ border: '1px solid',
+ padding: theme.spacing(1),
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function SimplePopper() {
+ const classes = useStyles();
+ const [anchorEl, setAnchorEl] = React.useState(null);
+
+ const handleClick = (event: React.MouseEvent) => {
+ setAnchorEl(anchorEl ? null : event.currentTarget);
+ };
+
+ const open = Boolean(anchorEl);
+ const id = open ? 'simple-popper' : undefined;
+
+ return (
+
+
+ Toggle Popper
+
+
+ The content of the Popper.
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|popper|SimplePopper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/popper/SpringPopper.stories.tsx b/examples/storybook/stories/material-ui/popper/SpringPopper.stories.tsx
new file mode 100644
index 00000000000000..4cac5b8bf87137
--- /dev/null
+++ b/examples/storybook/stories/material-ui/popper/SpringPopper.stories.tsx
@@ -0,0 +1,76 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Popper from '@material-ui/core/Popper';
+import { useSpring, animated } from 'react-spring/web.cjs'; // web.cjs is required for IE 11 support
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ paper: {
+ border: '1px solid',
+ padding: theme.spacing(1),
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+interface FadeProps {
+ children?: React.ReactElement;
+ in?: boolean;
+ onEnter?: () => {};
+ onExited?: () => {};
+}
+
+const Fade = React.forwardRef(function Fade(props, ref) {
+ const { in: open, children, onEnter, onExited, ...other } = props;
+ const style = useSpring({
+ from: { opacity: 0 },
+ to: { opacity: open ? 1 : 0 },
+ onStart: () => {
+ if (open && onEnter) {
+ onEnter();
+ }
+ },
+ onRest: () => {
+ if (!open && onExited) {
+ onExited();
+ }
+ },
+ });
+
+ return (
+
+ {children}
+
+ );
+});
+
+export function SpringPopper() {
+ const classes = useStyles();
+ const [anchorEl, setAnchorEl] = React.useState(null);
+
+ const handleClick = (event: React.MouseEvent) => {
+ setAnchorEl(anchorEl ? null : event.currentTarget);
+ };
+
+ const open = Boolean(anchorEl);
+ const id = open ? 'spring-popper' : undefined;
+
+ return (
+
+
+ Toggle Popper
+
+
+ {({ TransitionProps }) => (
+
+ The content of the Popper.
+
+ )}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|popper|SpringPopper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/popper/TransitionsPopper.stories.tsx b/examples/storybook/stories/material-ui/popper/TransitionsPopper.stories.tsx
new file mode 100644
index 00000000000000..1c6ba809e74cde
--- /dev/null
+++ b/examples/storybook/stories/material-ui/popper/TransitionsPopper.stories.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Popper from '@material-ui/core/Popper';
+import Fade from '@material-ui/core/Fade';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ paper: {
+ border: '1px solid',
+ padding: theme.spacing(1),
+ backgroundColor: theme.palette.background.paper,
+ },
+ }),
+);
+
+export function TransitionsPopper() {
+ const classes = useStyles();
+ const [anchorEl, setAnchorEl] = React.useState(null);
+
+ const handleClick = (event: React.MouseEvent) => {
+ setAnchorEl(anchorEl ? null : event.currentTarget);
+ };
+
+ const open = Boolean(anchorEl);
+ const id = open ? 'transitions-popper' : undefined;
+
+ return (
+
+
+ Toggle Popper
+
+
+ {({ TransitionProps }) => (
+
+ The content of the Popper.
+
+ )}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|popper|TransitionsPopper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/portal/SimplePortal.stories.tsx b/examples/storybook/stories/material-ui/portal/SimplePortal.stories.tsx
new file mode 100644
index 00000000000000..392c45235c40a5
--- /dev/null
+++ b/examples/storybook/stories/material-ui/portal/SimplePortal.stories.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import Portal from '@material-ui/core/Portal';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ alert: {
+ padding: theme.spacing(1),
+ margin: theme.spacing(1, 0),
+ border: '1px solid',
+ },
+ }),
+);
+
+export function SimplePortal() {
+ const classes = useStyles();
+ const [show, setShow] = React.useState(false);
+ const container = React.useRef(null);
+
+ const handleClick = () => {
+ setShow(!show);
+ };
+
+ return (
+
+
+ {show ? 'Unmount children' : 'Mount children'}
+
+
+ It looks like I will render here.
+ {show ? (
+
+ But I actually render here!
+
+ ) : null}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|portal|SimplePortal.stories"
+};
diff --git a/examples/storybook/stories/material-ui/progress/CircularDeterminate.stories.tsx b/examples/storybook/stories/material-ui/progress/CircularDeterminate.stories.tsx
new file mode 100644
index 00000000000000..e290cbca142c02
--- /dev/null
+++ b/examples/storybook/stories/material-ui/progress/CircularDeterminate.stories.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import CircularProgress from '@material-ui/core/CircularProgress';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ '& > * + *': {
+ marginLeft: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function CircularDeterminate() {
+ const classes = useStyles();
+ const [progress, setProgress] = React.useState(0);
+
+ React.useEffect(() => {
+ function tick() {
+ // reset when reaching 100%
+ setProgress((oldProgress) => (oldProgress >= 100 ? 0 : oldProgress + 1));
+ }
+
+ const timer = setInterval(tick, 20);
+ return () => {
+ clearInterval(timer);
+ };
+ }, []);
+
+ return (
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|progress|CircularDeterminate.stories"
+};
diff --git a/examples/storybook/stories/material-ui/progress/CircularIndeterminate.stories.tsx b/examples/storybook/stories/material-ui/progress/CircularIndeterminate.stories.tsx
new file mode 100644
index 00000000000000..d5a326f4abb7df
--- /dev/null
+++ b/examples/storybook/stories/material-ui/progress/CircularIndeterminate.stories.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import CircularProgress from '@material-ui/core/CircularProgress';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ '& > * + *': {
+ marginLeft: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function CircularIndeterminate() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|progress|CircularIndeterminate.stories"
+};
diff --git a/examples/storybook/stories/material-ui/progress/CircularIntegration.stories.tsx b/examples/storybook/stories/material-ui/progress/CircularIntegration.stories.tsx
new file mode 100644
index 00000000000000..c3f85a333b4078
--- /dev/null
+++ b/examples/storybook/stories/material-ui/progress/CircularIntegration.stories.tsx
@@ -0,0 +1,103 @@
+import React from 'react';
+import clsx from 'clsx';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import CircularProgress from '@material-ui/core/CircularProgress';
+import { green } from '@material-ui/core/colors';
+import Button from '@material-ui/core/Button';
+import Fab from '@material-ui/core/Fab';
+import CheckIcon from '@material-ui/icons/Check';
+import SaveIcon from '@material-ui/icons/Save';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ alignItems: 'center',
+ },
+ wrapper: {
+ margin: theme.spacing(1),
+ position: 'relative',
+ },
+ buttonSuccess: {
+ backgroundColor: green[500],
+ '&:hover': {
+ backgroundColor: green[700],
+ },
+ },
+ fabProgress: {
+ color: green[500],
+ position: 'absolute',
+ top: -6,
+ left: -6,
+ zIndex: 1,
+ },
+ buttonProgress: {
+ color: green[500],
+ position: 'absolute',
+ top: '50%',
+ left: '50%',
+ marginTop: -12,
+ marginLeft: -12,
+ },
+ }),
+);
+
+export function CircularIntegration() {
+ const classes = useStyles();
+ const [loading, setLoading] = React.useState(false);
+ const [success, setSuccess] = React.useState(false);
+ const timer = React.useRef();
+
+ const buttonClassname = clsx({
+ [classes.buttonSuccess]: success,
+ });
+
+ React.useEffect(() => {
+ return () => {
+ clearTimeout(timer.current);
+ };
+ }, []);
+
+ const handleButtonClick = () => {
+ if (!loading) {
+ setSuccess(false);
+ setLoading(true);
+ timer.current = setTimeout(() => {
+ setSuccess(true);
+ setLoading(false);
+ }, 2000);
+ }
+ };
+
+ return (
+
+
+
+ {success ? : }
+
+ {loading && }
+
+
+
+ Accept terms
+
+ {loading && }
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|progress|CircularIntegration.stories"
+};
diff --git a/examples/storybook/stories/material-ui/progress/CircularStatic.stories.tsx b/examples/storybook/stories/material-ui/progress/CircularStatic.stories.tsx
new file mode 100644
index 00000000000000..27922e9997e652
--- /dev/null
+++ b/examples/storybook/stories/material-ui/progress/CircularStatic.stories.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import CircularProgress from '@material-ui/core/CircularProgress';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ '& > * + *': {
+ marginLeft: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function CircularStatic() {
+ const classes = useStyles();
+ const [completed, setCompleted] = React.useState(0);
+
+ React.useEffect(() => {
+ function progress() {
+ setCompleted((prevCompleted) => (prevCompleted >= 100 ? 0 : prevCompleted + 10));
+ }
+
+ const timer = setInterval(progress, 1000);
+ return () => {
+ clearInterval(timer);
+ };
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|progress|CircularStatic.stories"
+};
diff --git a/examples/storybook/stories/material-ui/progress/CircularUnderLoad.stories.tsx b/examples/storybook/stories/material-ui/progress/CircularUnderLoad.stories.tsx
new file mode 100644
index 00000000000000..7e3d07d440463b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/progress/CircularUnderLoad.stories.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import CircularProgress from '@material-ui/core/CircularProgress';
+
+export function CircularUnderLoad() {
+ return ;
+}
+
+export default {
+ title: "Material-ui|progress|CircularUnderLoad.stories"
+};
diff --git a/examples/storybook/stories/material-ui/progress/CustomizedProgressBars.stories.tsx b/examples/storybook/stories/material-ui/progress/CustomizedProgressBars.stories.tsx
new file mode 100644
index 00000000000000..d609d34f7b5b80
--- /dev/null
+++ b/examples/storybook/stories/material-ui/progress/CustomizedProgressBars.stories.tsx
@@ -0,0 +1,104 @@
+import React from 'react';
+import { lighten, makeStyles, createStyles, withStyles, Theme } from '@material-ui/core/styles';
+import CircularProgress, { CircularProgressProps } from '@material-ui/core/CircularProgress';
+import LinearProgress from '@material-ui/core/LinearProgress';
+
+const ColorCircularProgress = withStyles({
+ root: {
+ color: '#00695c',
+ },
+})(CircularProgress);
+
+const ColorLinearProgress = withStyles({
+ colorPrimary: {
+ backgroundColor: '#b2dfdb',
+ },
+ barColorPrimary: {
+ backgroundColor: '#00695c',
+ },
+})(LinearProgress);
+
+const BorderLinearProgress = withStyles({
+ root: {
+ height: 10,
+ backgroundColor: lighten('#ff6c5c', 0.5),
+ },
+ bar: {
+ borderRadius: 20,
+ backgroundColor: '#ff6c5c',
+ },
+})(LinearProgress);
+
+// Inspired by the Facebook spinners.
+const useStylesFacebook = makeStyles({
+ root: {
+ position: 'relative',
+ },
+ top: {
+ color: '#eef3fd',
+ },
+ bottom: {
+ color: '#6798e5',
+ animationDuration: '550ms',
+ position: 'absolute',
+ left: 0,
+ },
+});
+
+function FacebookProgress(props: CircularProgressProps) {
+ const classes = useStylesFacebook();
+
+ return (
+
+
+
+
+ );
+}
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexGrow: 1,
+ },
+ margin: {
+ margin: theme.spacing(1),
+ },
+ }),
+);
+
+export function CustomizedProgressBars() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|progress|CustomizedProgressBars.stories"
+};
diff --git a/examples/storybook/stories/material-ui/progress/DelayingAppearance.stories.tsx b/examples/storybook/stories/material-ui/progress/DelayingAppearance.stories.tsx
new file mode 100644
index 00000000000000..700f5ebe289b48
--- /dev/null
+++ b/examples/storybook/stories/material-ui/progress/DelayingAppearance.stories.tsx
@@ -0,0 +1,95 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Fade from '@material-ui/core/Fade';
+import Button from '@material-ui/core/Button';
+import CircularProgress from '@material-ui/core/CircularProgress';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ },
+ button: {
+ margin: theme.spacing(2),
+ },
+ placeholder: {
+ height: 40,
+ },
+ }),
+);
+
+export function DelayingAppearance() {
+ const classes = useStyles();
+ const [loading, setLoading] = React.useState(false);
+ const [query, setQuery] = React.useState('idle');
+ const timerRef = React.useRef();
+
+ React.useEffect(
+ () => () => {
+ clearTimeout(timerRef.current);
+ },
+ [],
+ );
+
+ const handleClickLoading = () => {
+ setLoading((prevLoading) => !prevLoading);
+ };
+
+ const handleClickQuery = () => {
+ clearTimeout(timerRef.current);
+
+ if (query !== 'idle') {
+ setQuery('idle');
+ return;
+ }
+
+ setQuery('progress');
+ timerRef.current = setTimeout(() => {
+ setQuery('success');
+ }, 2000);
+ };
+
+ return (
+
+
+
+
+
+
+
+ {loading ? 'Stop loading' : 'Loading'}
+
+
+ {query === 'success' ? (
+ Success!
+ ) : (
+
+
+
+ )}
+
+
+ {query !== 'idle' ? 'Reset' : 'Simulate a load'}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|progress|DelayingAppearance.stories"
+};
diff --git a/examples/storybook/stories/material-ui/progress/LinearBuffer.stories.tsx b/examples/storybook/stories/material-ui/progress/LinearBuffer.stories.tsx
new file mode 100644
index 00000000000000..492df968bec7f5
--- /dev/null
+++ b/examples/storybook/stories/material-ui/progress/LinearBuffer.stories.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import LinearProgress from '@material-ui/core/LinearProgress';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function LinearBuffer() {
+ const classes = useStyles();
+ const [completed, setCompleted] = React.useState(0);
+ const [buffer, setBuffer] = React.useState(10);
+
+ const progress = React.useRef(() => {});
+ React.useEffect(() => {
+ progress.current = () => {
+ if (completed > 100) {
+ setCompleted(0);
+ setBuffer(10);
+ } else {
+ const diff = Math.random() * 10;
+ const diff2 = Math.random() * 10;
+ setCompleted(completed + diff);
+ setBuffer(completed + diff + diff2);
+ }
+ };
+ });
+
+ React.useEffect(() => {
+ function tick() {
+ progress.current();
+ }
+ const timer = setInterval(tick, 500);
+
+ return () => {
+ clearInterval(timer);
+ };
+ }, []);
+
+ return (
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|progress|LinearBuffer.stories"
+};
diff --git a/examples/storybook/stories/material-ui/progress/LinearDeterminate.stories.tsx b/examples/storybook/stories/material-ui/progress/LinearDeterminate.stories.tsx
new file mode 100644
index 00000000000000..485d3ef9b1b1f4
--- /dev/null
+++ b/examples/storybook/stories/material-ui/progress/LinearDeterminate.stories.tsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import LinearProgress from '@material-ui/core/LinearProgress';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function LinearDeterminate() {
+ const classes = useStyles();
+ const [completed, setCompleted] = React.useState(0);
+
+ React.useEffect(() => {
+ function progress() {
+ setCompleted((oldCompleted) => {
+ if (oldCompleted === 100) {
+ return 0;
+ }
+ const diff = Math.random() * 10;
+ return Math.min(oldCompleted + diff, 100);
+ });
+ }
+
+ const timer = setInterval(progress, 500);
+ return () => {
+ clearInterval(timer);
+ };
+ }, []);
+
+ return (
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|progress|LinearDeterminate.stories"
+};
diff --git a/examples/storybook/stories/material-ui/progress/LinearIndeterminate.stories.tsx b/examples/storybook/stories/material-ui/progress/LinearIndeterminate.stories.tsx
new file mode 100644
index 00000000000000..6be9e350655906
--- /dev/null
+++ b/examples/storybook/stories/material-ui/progress/LinearIndeterminate.stories.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import LinearProgress from '@material-ui/core/LinearProgress';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function LinearIndeterminate() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|progress|LinearIndeterminate.stories"
+};
diff --git a/examples/storybook/stories/material-ui/progress/LinearQuery.stories.tsx b/examples/storybook/stories/material-ui/progress/LinearQuery.stories.tsx
new file mode 100644
index 00000000000000..0db4a9d963c205
--- /dev/null
+++ b/examples/storybook/stories/material-ui/progress/LinearQuery.stories.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import LinearProgress from '@material-ui/core/LinearProgress';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function LinearQuery() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|progress|LinearQuery.stories"
+};
diff --git a/examples/storybook/stories/material-ui/radio-buttons/CustomizedRadios.stories.tsx b/examples/storybook/stories/material-ui/radio-buttons/CustomizedRadios.stories.tsx
new file mode 100644
index 00000000000000..76f08ff910bcf8
--- /dev/null
+++ b/examples/storybook/stories/material-ui/radio-buttons/CustomizedRadios.stories.tsx
@@ -0,0 +1,88 @@
+import React from 'react';
+import clsx from 'clsx';
+import { makeStyles } from '@material-ui/core/styles';
+import Radio, { RadioProps } from '@material-ui/core/Radio';
+import RadioGroup from '@material-ui/core/RadioGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import FormControl from '@material-ui/core/FormControl';
+import FormLabel from '@material-ui/core/FormLabel';
+
+const useStyles = makeStyles({
+ root: {
+ '&:hover': {
+ backgroundColor: 'transparent',
+ },
+ },
+ icon: {
+ borderRadius: '50%',
+ width: 16,
+ height: 16,
+ boxShadow: 'inset 0 0 0 1px rgba(16,22,26,.2), inset 0 -1px 0 rgba(16,22,26,.1)',
+ backgroundColor: '#f5f8fa',
+ backgroundImage: 'linear-gradient(180deg,hsla(0,0%,100%,.8),hsla(0,0%,100%,0))',
+ '$root.Mui-focusVisible &': {
+ outline: '2px auto rgba(19,124,189,.6)',
+ outlineOffset: 2,
+ },
+ 'input:hover ~ &': {
+ backgroundColor: '#ebf1f5',
+ },
+ 'input:disabled ~ &': {
+ boxShadow: 'none',
+ background: 'rgba(206,217,224,.5)',
+ },
+ },
+ checkedIcon: {
+ backgroundColor: '#137cbd',
+ backgroundImage: 'linear-gradient(180deg,hsla(0,0%,100%,.1),hsla(0,0%,100%,0))',
+ '&:before': {
+ display: 'block',
+ width: 16,
+ height: 16,
+ backgroundImage: 'radial-gradient(#fff,#fff 28%,transparent 32%)',
+ content: '""',
+ },
+ 'input:hover ~ &': {
+ backgroundColor: '#106ba3',
+ },
+ },
+});
+
+// Inspired by blueprintjs
+function StyledRadio(props: RadioProps) {
+ const classes = useStyles();
+
+ return (
+ }
+ icon={ }
+ {...props}
+ />
+ );
+}
+
+export function CustomizedRadios() {
+ return (
+
+ Gender
+
+ } label="Female" />
+ } label="Male" />
+ } label="Other" />
+ }
+ label="(Disabled option)"
+ />
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|radio-buttons|CustomizedRadios.stories"
+};
diff --git a/examples/storybook/stories/material-ui/radio-buttons/ErrorRadios.stories.tsx b/examples/storybook/stories/material-ui/radio-buttons/ErrorRadios.stories.tsx
new file mode 100644
index 00000000000000..cb56623859ca91
--- /dev/null
+++ b/examples/storybook/stories/material-ui/radio-buttons/ErrorRadios.stories.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Radio from '@material-ui/core/Radio';
+import RadioGroup from '@material-ui/core/RadioGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import FormControl from '@material-ui/core/FormControl';
+import FormHelperText from '@material-ui/core/FormHelperText';
+import FormLabel from '@material-ui/core/FormLabel';
+import Button from '@material-ui/core/Button';
+
+const useStyles = makeStyles((theme) => ({
+ formControl: {
+ margin: theme.spacing(3),
+ },
+ button: {
+ margin: theme.spacing(1, 1, 0, 0),
+ },
+}));
+
+export function ErrorRadios() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState('');
+ const [error, setError] = React.useState(false);
+ const [helperText, setHelperText] = React.useState('Choose wisely');
+
+ const handleRadioChange = (event: React.ChangeEvent) => {
+ setValue((event.target as HTMLInputElement).value);
+ setHelperText(' ');
+ setError(false);
+ };
+
+ const handleSubmit = (event: React.FormEvent) => {
+ event.preventDefault();
+
+ if (value === 'best') {
+ setHelperText('You got it!');
+ setError(false);
+ } else if (value === 'worst') {
+ setHelperText('Sorry, wrong answer!');
+ setError(true);
+ } else {
+ setHelperText('Please select an option.');
+ setError(true);
+ }
+ };
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|radio-buttons|ErrorRadios.stories"
+};
diff --git a/examples/storybook/stories/material-ui/radio-buttons/FormControlLabelPlacement.stories.tsx b/examples/storybook/stories/material-ui/radio-buttons/FormControlLabelPlacement.stories.tsx
new file mode 100644
index 00000000000000..94ae2d52cf013a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/radio-buttons/FormControlLabelPlacement.stories.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import Radio from '@material-ui/core/Radio';
+import RadioGroup from '@material-ui/core/RadioGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import FormControl from '@material-ui/core/FormControl';
+import FormLabel from '@material-ui/core/FormLabel';
+
+export function FormControlLabelPlacement() {
+ return (
+
+ labelPlacement
+
+ }
+ label="Top"
+ labelPlacement="top"
+ />
+ }
+ label="Start"
+ labelPlacement="start"
+ />
+ }
+ label="Bottom"
+ labelPlacement="bottom"
+ />
+ } label="End" />
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|radio-buttons|FormControlLabelPlacement.stories"
+};
diff --git a/examples/storybook/stories/material-ui/radio-buttons/RadioButtons.stories.tsx b/examples/storybook/stories/material-ui/radio-buttons/RadioButtons.stories.tsx
new file mode 100644
index 00000000000000..8d2bc9687564d6
--- /dev/null
+++ b/examples/storybook/stories/material-ui/radio-buttons/RadioButtons.stories.tsx
@@ -0,0 +1,69 @@
+import React from 'react';
+import { withStyles } from '@material-ui/core/styles';
+import { green } from '@material-ui/core/colors';
+import Radio, { RadioProps } from '@material-ui/core/Radio';
+
+const GreenRadio = withStyles({
+ root: {
+ color: green[400],
+ '&$checked': {
+ color: green[600],
+ },
+ },
+ checked: {},
+})((props: RadioProps) => );
+
+export function RadioButtons() {
+ const [selectedValue, setSelectedValue] = React.useState('a');
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setSelectedValue(event.target.value);
+ };
+
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|radio-buttons|RadioButtons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/radio-buttons/RadioButtonsGroup.stories.tsx b/examples/storybook/stories/material-ui/radio-buttons/RadioButtonsGroup.stories.tsx
new file mode 100644
index 00000000000000..b5429d32c66f67
--- /dev/null
+++ b/examples/storybook/stories/material-ui/radio-buttons/RadioButtonsGroup.stories.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import Radio from '@material-ui/core/Radio';
+import RadioGroup from '@material-ui/core/RadioGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import FormControl from '@material-ui/core/FormControl';
+import FormLabel from '@material-ui/core/FormLabel';
+
+export function RadioButtonsGroup() {
+ const [value, setValue] = React.useState('female');
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setValue((event.target as HTMLInputElement).value);
+ };
+
+ return (
+
+ Gender
+
+ } label="Female" />
+ } label="Male" />
+ } label="Other" />
+ } label="(Disabled option)" />
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|radio-buttons|RadioButtonsGroup.stories"
+};
diff --git a/examples/storybook/stories/material-ui/rating/CustomizedRatings.stories.tsx b/examples/storybook/stories/material-ui/rating/CustomizedRatings.stories.tsx
new file mode 100644
index 00000000000000..b79344fab81f6c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/rating/CustomizedRatings.stories.tsx
@@ -0,0 +1,92 @@
+import React from 'react';
+import { withStyles } from '@material-ui/core/styles';
+import Rating, { IconContainerProps } from '@material-ui/lab/Rating';
+import StarBorderIcon from '@material-ui/icons/StarBorder';
+import FavoriteIcon from '@material-ui/icons/Favorite';
+import SentimentVeryDissatisfiedIcon from '@material-ui/icons/SentimentVeryDissatisfied';
+import SentimentDissatisfiedIcon from '@material-ui/icons/SentimentDissatisfied';
+import SentimentSatisfiedIcon from '@material-ui/icons/SentimentSatisfied';
+import SentimentSatisfiedAltIcon from '@material-ui/icons/SentimentSatisfiedAltOutlined';
+import SentimentVerySatisfiedIcon from '@material-ui/icons/SentimentVerySatisfied';
+import Typography from '@material-ui/core/Typography';
+import Box from '@material-ui/core/Box';
+
+const StyledRating = withStyles({
+ iconFilled: {
+ color: '#ff6d75',
+ },
+ iconHover: {
+ color: '#ff3d47',
+ },
+})(Rating);
+
+const customIcons: { [index: string]: { icon: React.ReactElement; label: string } } = {
+ 1: {
+ icon: ,
+ label: 'Very Dissatisfied',
+ },
+ 2: {
+ icon: ,
+ label: 'Dissatisfied',
+ },
+ 3: {
+ icon: ,
+ label: 'Neutral',
+ },
+ 4: {
+ icon: ,
+ label: 'Satisfied',
+ },
+ 5: {
+ icon: ,
+ label: 'Very Satisfied',
+ },
+};
+
+function IconContainer(props: IconContainerProps) {
+ const { value, ...other } = props;
+ return {customIcons[value].icon} ;
+}
+
+export function CustomizedRatings() {
+ return (
+
+
+ Custom empty icon
+ }
+ />
+
+
+ Custom icon and color
+ `${value} Heart${value !== 1 ? 's' : ''}`}
+ precision={0.5}
+ icon={ }
+ />
+
+
+ 10 stars
+
+
+
+ Custom icon set
+ customIcons[value].label}
+ IconContainerComponent={IconContainer}
+ />
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|rating|CustomizedRatings.stories"
+};
diff --git a/examples/storybook/stories/material-ui/rating/HalfRating.stories.tsx b/examples/storybook/stories/material-ui/rating/HalfRating.stories.tsx
new file mode 100644
index 00000000000000..b632e53fd9479e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/rating/HalfRating.stories.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import Rating from '@material-ui/lab/Rating';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ flexDirection: 'column',
+ '& > * + *': {
+ marginTop: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function HalfRating() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|rating|HalfRating.stories"
+};
diff --git a/examples/storybook/stories/material-ui/rating/HoverRating.stories.tsx b/examples/storybook/stories/material-ui/rating/HoverRating.stories.tsx
new file mode 100644
index 00000000000000..42f977088a3122
--- /dev/null
+++ b/examples/storybook/stories/material-ui/rating/HoverRating.stories.tsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Rating from '@material-ui/lab/Rating';
+import Box from '@material-ui/core/Box';
+
+const labels: { [index: string]: string } = {
+ 0.5: 'Useless',
+ 1: 'Useless+',
+ 1.5: 'Poor',
+ 2: 'Poor+',
+ 2.5: 'Ok',
+ 3: 'Ok+',
+ 3.5: 'Good',
+ 4: 'Good+',
+ 4.5: 'Excellent',
+ 5: 'Excellent+',
+};
+
+const useStyles = makeStyles({
+ root: {
+ width: 200,
+ display: 'flex',
+ alignItems: 'center',
+ },
+});
+
+export function HoverRating() {
+ const [value, setValue] = React.useState(2);
+ const [hover, setHover] = React.useState(-1);
+ const classes = useStyles();
+
+ return (
+
+ {
+ setValue(newValue);
+ }}
+ onChangeActive={(event, newHover) => {
+ setHover(newHover);
+ }}
+ />
+ {value !== null && {labels[hover !== -1 ? hover : value]} }
+
+ );
+}
+
+export default {
+ title: "Material-ui|rating|HoverRating.stories"
+};
diff --git a/examples/storybook/stories/material-ui/rating/RatingSize.stories.tsx b/examples/storybook/stories/material-ui/rating/RatingSize.stories.tsx
new file mode 100644
index 00000000000000..b7d1f2e0ea96fb
--- /dev/null
+++ b/examples/storybook/stories/material-ui/rating/RatingSize.stories.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import Rating from '@material-ui/lab/Rating';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ flexDirection: 'column',
+ '& > * + *': {
+ marginTop: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function HalfRating() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|rating|RatingSize.stories"
+};
diff --git a/examples/storybook/stories/material-ui/rating/SimpleRating.stories.tsx b/examples/storybook/stories/material-ui/rating/SimpleRating.stories.tsx
new file mode 100644
index 00000000000000..439529c47aa548
--- /dev/null
+++ b/examples/storybook/stories/material-ui/rating/SimpleRating.stories.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import Rating from '@material-ui/lab/Rating';
+import Typography from '@material-ui/core/Typography';
+import Box from '@material-ui/core/Box';
+
+export function SimpleRating() {
+ const [value, setValue] = React.useState(2);
+
+ return (
+
+
+ Controlled
+ {
+ setValue(newValue);
+ }}
+ />
+
+
+ Read only
+
+
+
+ Disabled
+
+
+
+ Pristine
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|rating|SimpleRating.stories"
+};
diff --git a/examples/storybook/stories/material-ui/selects/ControlledOpenSelect.stories.tsx b/examples/storybook/stories/material-ui/selects/ControlledOpenSelect.stories.tsx
new file mode 100644
index 00000000000000..e7dd6d70ebee66
--- /dev/null
+++ b/examples/storybook/stories/material-ui/selects/ControlledOpenSelect.stories.tsx
@@ -0,0 +1,69 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+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';
+import Button from '@material-ui/core/Button';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ button: {
+ display: 'block',
+ marginTop: theme.spacing(2),
+ },
+ formControl: {
+ margin: theme.spacing(1),
+ minWidth: 120,
+ },
+ }),
+);
+
+export function ControlledOpenSelect() {
+ const classes = useStyles();
+ const [age, setAge] = React.useState('');
+ const [open, setOpen] = React.useState(false);
+
+ const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => {
+ setAge(event.target.value as number);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ const handleOpen = () => {
+ setOpen(true);
+ };
+
+ return (
+
+
+ Open the select
+
+
+ Age
+
+
+ None
+
+ Ten
+ Twenty
+ Thirty
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|selects|ControlledOpenSelect.stories"
+};
diff --git a/examples/storybook/stories/material-ui/selects/CustomizedSelects.stories.tsx b/examples/storybook/stories/material-ui/selects/CustomizedSelects.stories.tsx
new file mode 100644
index 00000000000000..652802ae4358f0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/selects/CustomizedSelects.stories.tsx
@@ -0,0 +1,104 @@
+import React from 'react';
+import { createStyles, makeStyles, withStyles, Theme } from '@material-ui/core/styles';
+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';
+import NativeSelect from '@material-ui/core/NativeSelect';
+import InputBase from '@material-ui/core/InputBase';
+
+const BootstrapInput = withStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ 'label + &': {
+ marginTop: theme.spacing(3),
+ },
+ },
+ input: {
+ borderRadius: 4,
+ position: 'relative',
+ backgroundColor: theme.palette.background.paper,
+ border: '1px solid #ced4da',
+ fontSize: 16,
+ padding: '10px 26px 10px 12px',
+ transition: theme.transitions.create(['border-color', 'box-shadow']),
+ // Use the system font instead of the default Roboto font.
+ fontFamily: [
+ '-apple-system',
+ 'BlinkMacSystemFont',
+ '"Segoe UI"',
+ 'Roboto',
+ '"Helvetica Neue"',
+ 'Arial',
+ 'sans-serif',
+ '"Apple Color Emoji"',
+ '"Segoe UI Emoji"',
+ '"Segoe UI Symbol"',
+ ].join(','),
+ '&:focus': {
+ borderRadius: 4,
+ borderColor: '#80bdff',
+ boxShadow: '0 0 0 0.2rem rgba(0,123,255,.25)',
+ },
+ },
+ }),
+)(InputBase);
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ margin: {
+ margin: theme.spacing(1),
+ },
+ }),
+);
+
+export function CustomizedSelects() {
+ const classes = useStyles();
+ const [age, setAge] = React.useState('');
+ const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => {
+ setAge(event.target.value as string);
+ };
+ return (
+
+
+ Age
+
+
+
+ Age
+ }
+ >
+
+ None
+
+ Ten
+ Twenty
+ Thirty
+
+
+
+ Age
+ }
+ >
+
+ Ten
+ Twenty
+ Thirty
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|selects|CustomizedSelects.stories"
+};
diff --git a/examples/storybook/stories/material-ui/selects/DialogSelect.stories.tsx b/examples/storybook/stories/material-ui/selects/DialogSelect.stories.tsx
new file mode 100644
index 00000000000000..77fdd67f637e89
--- /dev/null
+++ b/examples/storybook/stories/material-ui/selects/DialogSelect.stories.tsx
@@ -0,0 +1,99 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } 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 InputLabel from '@material-ui/core/InputLabel';
+import Input from '@material-ui/core/Input';
+import MenuItem from '@material-ui/core/MenuItem';
+import FormControl from '@material-ui/core/FormControl';
+import Select from '@material-ui/core/Select';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ container: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ },
+ formControl: {
+ margin: theme.spacing(1),
+ minWidth: 120,
+ },
+ }),
+);
+
+export function DialogSelect() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+ const [age, setAge] = React.useState('');
+
+ const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => {
+ setAge(Number(event.target.value) || '');
+ };
+
+ const handleClickOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+ Open select dialog
+
+ Fill the form
+
+
+
+
+
+ Cancel
+
+
+ Ok
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|selects|DialogSelect.stories"
+};
diff --git a/examples/storybook/stories/material-ui/selects/GroupedSelect.stories.tsx b/examples/storybook/stories/material-ui/selects/GroupedSelect.stories.tsx
new file mode 100644
index 00000000000000..01ae8d01bb6715
--- /dev/null
+++ b/examples/storybook/stories/material-ui/selects/GroupedSelect.stories.tsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import InputLabel from '@material-ui/core/InputLabel';
+import MenuItem from '@material-ui/core/MenuItem';
+import ListSubheader from '@material-ui/core/ListSubheader';
+import FormControl from '@material-ui/core/FormControl';
+import Select from '@material-ui/core/Select';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ formControl: {
+ margin: theme.spacing(1),
+ minWidth: 120,
+ },
+ }),
+);
+
+export function GroupedSelect() {
+ const classes = useStyles();
+
+ return (
+
+
+ Grouping
+
+
+
+ Option 1
+ Option 2
+
+
+ Option 3
+ Option 4
+
+
+
+
+ Grouping
+
+
+ None
+
+ Category 1
+ Option 1
+ Option 2
+ Category 2
+ Option 3
+ Option 4
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|selects|GroupedSelect.stories"
+};
diff --git a/examples/storybook/stories/material-ui/selects/MultipleSelect.stories.tsx b/examples/storybook/stories/material-ui/selects/MultipleSelect.stories.tsx
new file mode 100644
index 00000000000000..8e8ace5179287d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/selects/MultipleSelect.stories.tsx
@@ -0,0 +1,204 @@
+import React from 'react';
+import clsx from 'clsx';
+import { createStyles, makeStyles, useTheme, Theme } 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 ListItemText from '@material-ui/core/ListItemText';
+import Select from '@material-ui/core/Select';
+import Checkbox from '@material-ui/core/Checkbox';
+import Chip from '@material-ui/core/Chip';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ formControl: {
+ margin: theme.spacing(1),
+ minWidth: 120,
+ maxWidth: 300,
+ },
+ chips: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ },
+ chip: {
+ margin: 2,
+ },
+ noLabel: {
+ marginTop: theme.spacing(3),
+ },
+ }),
+);
+
+const ITEM_HEIGHT = 48;
+const ITEM_PADDING_TOP = 8;
+const MenuProps = {
+ PaperProps: {
+ style: {
+ maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
+ width: 250,
+ },
+ },
+};
+
+const names = [
+ 'Oliver Hansen',
+ 'Van Henry',
+ 'April Tucker',
+ 'Ralph Hubbard',
+ 'Omar Alexander',
+ 'Carlos Abbott',
+ 'Miriam Wagner',
+ 'Bradley Wilkerson',
+ 'Virginia Andrews',
+ 'Kelly Snyder',
+];
+
+function getStyles(name: string, personName: string[], theme: Theme) {
+ return {
+ fontWeight:
+ personName.indexOf(name) === -1
+ ? theme.typography.fontWeightRegular
+ : theme.typography.fontWeightMedium,
+ };
+}
+
+export function MultipleSelect() {
+ const classes = useStyles();
+ const theme = useTheme();
+ const [personName, setPersonName] = React.useState([]);
+
+ const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => {
+ setPersonName(event.target.value as string[]);
+ };
+
+ const handleChangeMultiple = (event: React.ChangeEvent<{ value: unknown }>) => {
+ const { options } = event.target as HTMLSelectElement;
+ const value: string[] = [];
+ for (let i = 0, l = options.length; i < l; i += 1) {
+ if (options[i].selected) {
+ value.push(options[i].value);
+ }
+ }
+ setPersonName(value);
+ };
+
+ return (
+
+
+ Name
+ }
+ MenuProps={MenuProps}
+ >
+ {names.map((name) => (
+
+ {name}
+
+ ))}
+
+
+
+ Tag
+ }
+ renderValue={(selected) => (selected as string[]).join(', ')}
+ MenuProps={MenuProps}
+ >
+ {names.map((name) => (
+
+ -1} />
+
+
+ ))}
+
+
+
+ Chip
+ }
+ renderValue={(selected) => (
+
+ {(selected as string[]).map((value) => (
+
+ ))}
+
+ )}
+ MenuProps={MenuProps}
+ >
+ {names.map((name) => (
+
+ {name}
+
+ ))}
+
+
+
+ }
+ renderValue={(selected) => {
+ if ((selected as string[]).length === 0) {
+ return Placeholder ;
+ }
+
+ return (selected as string[]).join(', ');
+ }}
+ MenuProps={MenuProps}
+ inputProps={{ 'aria-label': 'Without label' }}
+ >
+
+ Placeholder
+
+ {names.map((name) => (
+
+ {name}
+
+ ))}
+
+
+
+
+ Native
+
+
+ {names.map((name) => (
+
+ {name}
+
+ ))}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|selects|MultipleSelect.stories"
+};
diff --git a/examples/storybook/stories/material-ui/selects/NativeSelects.stories.tsx b/examples/storybook/stories/material-ui/selects/NativeSelects.stories.tsx
new file mode 100644
index 00000000000000..0334dff51dfb0e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/selects/NativeSelects.stories.tsx
@@ -0,0 +1,238 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import InputLabel from '@material-ui/core/InputLabel';
+import FormHelperText from '@material-ui/core/FormHelperText';
+import FormControl from '@material-ui/core/FormControl';
+import Select from '@material-ui/core/Select';
+import NativeSelect from '@material-ui/core/NativeSelect';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ formControl: {
+ margin: theme.spacing(1),
+ minWidth: 120,
+ },
+ selectEmpty: {
+ marginTop: theme.spacing(2),
+ },
+ }),
+);
+
+export function NativeSelects() {
+ const classes = useStyles();
+ const [state, setState] = React.useState<{ age: string | number; name: string }>({
+ age: '',
+ name: 'hai',
+ });
+
+ const handleChange = (event: React.ChangeEvent<{ name?: string; value: unknown }>) => {
+ const name = event.target.name as keyof typeof state;
+ setState({
+ ...state,
+ [name]: event.target.value,
+ });
+ };
+
+ return (
+
+
+ Age
+
+
+ Ten
+ Twenty
+ Thirty
+
+
+
+ Age
+
+
+ Ten
+ Twenty
+ Thirty
+
+ Some important helper text
+
+
+
+ None
+ Ten
+ Twenty
+ Thirty
+
+ With visually hidden label
+
+
+
+ Age
+
+
+ None
+ Ten
+ Twenty
+ Thirty
+
+ Label + placeholder
+
+
+ Name
+
+ None
+
+ Hai
+
+
+ Olivier
+ Kevin
+
+
+ Disabled
+
+
+ Name
+
+
+ Hai
+
+
+ Olivier
+ Kevin
+
+
+ Error
+
+
+ Name
+
+ Ten
+ Twenty
+ Thirty
+
+ Uncontrolled
+
+
+
+
+ Placeholder
+
+ Ten
+ Twenty
+ Thirty
+
+ Placeholder
+
+
+ Age
+
+
+ Ten
+ Twenty
+ Thirty
+
+ Required
+
+
+ Age
+
+
+ Ten
+ Twenty
+ Thirty
+
+
+
+ Age
+
+
+ Ten
+ Twenty
+ Thirty
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|selects|NativeSelects.stories"
+};
diff --git a/examples/storybook/stories/material-ui/selects/SimpleSelect.stories.tsx b/examples/storybook/stories/material-ui/selects/SimpleSelect.stories.tsx
new file mode 100644
index 00000000000000..fd38d0e0a87d1f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/selects/SimpleSelect.stories.tsx
@@ -0,0 +1,244 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import InputLabel from '@material-ui/core/InputLabel';
+import MenuItem from '@material-ui/core/MenuItem';
+import FormHelperText from '@material-ui/core/FormHelperText';
+import FormControl from '@material-ui/core/FormControl';
+import Select from '@material-ui/core/Select';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ formControl: {
+ margin: theme.spacing(1),
+ minWidth: 120,
+ },
+ selectEmpty: {
+ marginTop: theme.spacing(2),
+ },
+ }),
+);
+
+export function SimpleSelect() {
+ const classes = useStyles();
+ const [age, setAge] = React.useState('');
+
+ const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => {
+ setAge(event.target.value as string);
+ };
+
+ return (
+
+
+ Age
+
+ Ten
+ Twenty
+ Thirty
+
+
+
+ Age
+
+
+ None
+
+ Ten
+ Twenty
+ Thirty
+
+ Some important helper text
+
+
+
+
+ None
+
+ Ten
+ Twenty
+ Thirty
+
+ Without label
+
+
+
+ Age
+
+
+
+ None
+
+ Ten
+ Twenty
+ Thirty
+
+ Label + placeholder
+
+
+ Name
+
+
+ None
+
+ Ten
+ Twenty
+ Thirty
+
+ Disabled
+
+
+ Name
+ `⚠️ - ${value}`}
+ >
+
+ None
+
+ Ten
+ Twenty
+ Thirty
+
+ Error
+
+
+ Name
+
+
+ None
+
+ Ten
+ Twenty
+ Thirty
+
+ Read only
+
+
+ Age
+
+
+ None
+
+ Ten
+ Twenty
+ Thirty
+
+ Auto width
+
+
+
+
+ Placeholder
+
+ Ten
+ Twenty
+ Thirty
+
+ Placeholder
+
+
+ Age
+
+
+ None
+
+ Ten
+ Twenty
+ Thirty
+
+ Required
+
+
+ Age
+
+
+ None
+
+ Ten
+ Twenty
+ Thirty
+
+
+
+ Age
+
+
+ None
+
+ Ten
+ Twenty
+ Thirty
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|selects|SimpleSelect.stories"
+};
diff --git a/examples/storybook/stories/material-ui/skeleton/Animations.stories.tsx b/examples/storybook/stories/material-ui/skeleton/Animations.stories.tsx
new file mode 100644
index 00000000000000..fab6f904101dcd
--- /dev/null
+++ b/examples/storybook/stories/material-ui/skeleton/Animations.stories.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import Skeleton from '@material-ui/lab/Skeleton';
+import { makeStyles } from '@material-ui/core/styles';
+
+const useStyles = makeStyles({
+ root: {
+ width: 300,
+ },
+});
+
+export function Animations() {
+ const classes = useStyles();
+ return (
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|skeleton|Animations.stories"
+};
diff --git a/examples/storybook/stories/material-ui/skeleton/Facebook.stories.tsx b/examples/storybook/stories/material-ui/skeleton/Facebook.stories.tsx
new file mode 100644
index 00000000000000..da8c271bc43898
--- /dev/null
+++ b/examples/storybook/stories/material-ui/skeleton/Facebook.stories.tsx
@@ -0,0 +1,100 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Card from '@material-ui/core/Card';
+import CardHeader from '@material-ui/core/CardHeader';
+import CardContent from '@material-ui/core/CardContent';
+import CardMedia from '@material-ui/core/CardMedia';
+import Avatar from '@material-ui/core/Avatar';
+import Typography from '@material-ui/core/Typography';
+import IconButton from '@material-ui/core/IconButton';
+import MoreVertIcon from '@material-ui/icons/MoreVert';
+import Skeleton from '@material-ui/lab/Skeleton';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ card: {
+ maxWidth: 345,
+ margin: theme.spacing(2),
+ },
+ media: {
+ height: 190,
+ },
+ }),
+);
+
+interface MediaProps {
+ loading?: boolean;
+}
+
+function Media(props: MediaProps) {
+ const { loading = false } = props;
+ const classes = useStyles();
+
+ return (
+
+
+ ) : (
+
+ )
+ }
+ action={
+ loading ? null : (
+
+
+
+ )
+ }
+ title={
+ loading ? (
+
+ ) : (
+ 'Ted'
+ )
+ }
+ subheader={loading ? : '5 hours ago'}
+ />
+ {loading ? (
+
+ ) : (
+
+ )}
+
+ {loading ? (
+
+
+
+
+ ) : (
+
+ {
+ "Why First Minister of Scotland Nicola Sturgeon thinks GDP is the wrong measure of a country's success:"
+ }
+
+ )}
+
+
+ );
+}
+
+export function Facebook() {
+ return (
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|skeleton|Facebook.stories"
+};
diff --git a/examples/storybook/stories/material-ui/skeleton/SkeletonChildren.stories.tsx b/examples/storybook/stories/material-ui/skeleton/SkeletonChildren.stories.tsx
new file mode 100644
index 00000000000000..16319ca86f698b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/skeleton/SkeletonChildren.stories.tsx
@@ -0,0 +1,75 @@
+import React from 'react';
+import Box from '@material-ui/core/Box';
+import Typography from '@material-ui/core/Typography';
+import Avatar from '@material-ui/core/Avatar';
+import Grid from '@material-ui/core/Grid';
+import { makeStyles } from '@material-ui/core/styles';
+import Skeleton from '@material-ui/lab/Skeleton';
+
+const useStyles = makeStyles(() => ({
+ image: {
+ width: '100%',
+ },
+}));
+
+function SkeletonChildrenDemo(props: { loading?: boolean }) {
+ const { loading = false } = props;
+ const classes = useStyles();
+
+ return (
+
+
+
+ {loading ? (
+
+
+
+ ) : (
+
+ )}
+
+
+ {loading ? (
+
+ .
+
+ ) : (
+ Ted
+ )}
+
+
+ {loading ? (
+
+
+
+ ) : (
+
+ )}
+
+ );
+}
+
+export function SkeletonChildren() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|skeleton|SkeletonChildren.stories"
+};
diff --git a/examples/storybook/stories/material-ui/skeleton/SkeletonTypography.stories.tsx b/examples/storybook/stories/material-ui/skeleton/SkeletonTypography.stories.tsx
new file mode 100644
index 00000000000000..5a35adfd5f0798
--- /dev/null
+++ b/examples/storybook/stories/material-ui/skeleton/SkeletonTypography.stories.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import Typography, { TypographyProps } from '@material-ui/core/Typography';
+import Skeleton from '@material-ui/lab/Skeleton';
+import Grid from '@material-ui/core/Grid';
+
+const variants = ['h1', 'h3', 'body1', 'caption'] as TypographyProps['variant'][];
+
+function TypographyDemo(props: { loading?: boolean }) {
+ const { loading = false } = props;
+
+ return (
+
+ {variants.map((variant) => (
+
+ {loading ? : variant}
+
+ ))}
+
+ );
+}
+
+export function SkeletonTypography() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|skeleton|SkeletonTypography.stories"
+};
diff --git a/examples/storybook/stories/material-ui/skeleton/Variants.stories.tsx b/examples/storybook/stories/material-ui/skeleton/Variants.stories.tsx
new file mode 100644
index 00000000000000..7b94e163779664
--- /dev/null
+++ b/examples/storybook/stories/material-ui/skeleton/Variants.stories.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import Skeleton from '@material-ui/lab/Skeleton';
+
+export function Variants() {
+ return (
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|skeleton|Variants.stories"
+};
diff --git a/examples/storybook/stories/material-ui/skeleton/YouTube.stories.tsx b/examples/storybook/stories/material-ui/skeleton/YouTube.stories.tsx
new file mode 100644
index 00000000000000..cca64254abe73e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/skeleton/YouTube.stories.tsx
@@ -0,0 +1,85 @@
+import React from 'react';
+import Grid from '@material-ui/core/Grid';
+import Box from '@material-ui/core/Box';
+import Typography from '@material-ui/core/Typography';
+import Skeleton from '@material-ui/lab/Skeleton';
+
+const data = [
+ {
+ src:
+ 'https://i.ytimg.com/vi/pLqipJNItIo/hqdefault.jpg?sqp=-oaymwEYCNIBEHZIVfKriqkDCwgBFQAAiEIYAXAB&rs=AOn4CLBkklsyaw9FxDmMKapyBYCn9tbPNQ',
+ title: 'Don Diablo @ Tomorrowland Main Stage 2019 | Official…',
+ channel: 'Don Diablo',
+ views: '396 k views',
+ createdAt: 'a week ago',
+ },
+ {
+ src:
+ 'https://i.ytimg.com/vi/_Uu12zY01ts/hqdefault.jpg?sqp=-oaymwEZCPYBEIoBSFXyq4qpAwsIARUAAIhCGAFwAQ==&rs=AOn4CLCpX6Jan2rxrCAZxJYDXppTP4MoQA',
+ title: 'Queen - Greatest Hits',
+ channel: 'Queen Official',
+ views: '40 M views',
+ createdAt: '3 years ago',
+ },
+ {
+ src:
+ 'https://i.ytimg.com/vi/kkLk2XWMBf8/hqdefault.jpg?sqp=-oaymwEYCNIBEHZIVfKriqkDCwgBFQAAiEIYAXAB&rs=AOn4CLB4GZTFu1Ju2EPPPXnhMZtFVvYBaw',
+ title: 'Calvin Harris, Sam Smith - Promises (Official Video)',
+ channel: 'Calvin Harris',
+ views: '130 M views',
+ createdAt: '10 months ago',
+ },
+];
+
+interface MediaProps {
+ loading?: boolean;
+}
+
+function Media(props: MediaProps) {
+ const { loading = false } = props;
+
+ return (
+
+ {(loading ? Array.from(new Array(3)) : data).map((item, index) => (
+
+ {item ? (
+
+ ) : (
+
+ )}
+ {item ? (
+
+
+ {item.title}
+
+
+ {item.channel}
+
+
+ {`${item.views} • ${item.createdAt}`}
+
+
+ ) : (
+
+
+
+
+ )}
+
+ ))}
+
+ );
+}
+
+export function YouTube() {
+ return (
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|skeleton|YouTube.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/ContinuousSlider.stories.tsx b/examples/storybook/stories/material-ui/slider/ContinuousSlider.stories.tsx
new file mode 100644
index 00000000000000..7b81ec8f7c9864
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/ContinuousSlider.stories.tsx
@@ -0,0 +1,49 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Grid from '@material-ui/core/Grid';
+import Typography from '@material-ui/core/Typography';
+import Slider from '@material-ui/core/Slider';
+import VolumeDown from '@material-ui/icons/VolumeDown';
+import VolumeUp from '@material-ui/icons/VolumeUp';
+
+const useStyles = makeStyles({
+ root: {
+ width: 200,
+ },
+});
+
+export function ContinuousSlider() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(30);
+
+ const handleChange = (event: any, newValue: number | number[]) => {
+ setValue(newValue as number);
+ };
+
+ return (
+
+
+ Volume
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Disabled slider
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|ContinuousSlider.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/CustomizedSlider.stories.tsx b/examples/storybook/stories/material-ui/slider/CustomizedSlider.stories.tsx
new file mode 100644
index 00000000000000..d88b0405434bca
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/CustomizedSlider.stories.tsx
@@ -0,0 +1,209 @@
+import React from 'react';
+import { withStyles, makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Slider from '@material-ui/core/Slider';
+import Typography from '@material-ui/core/Typography';
+import Tooltip from '@material-ui/core/Tooltip';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 300 + theme.spacing(3) * 2,
+ },
+ margin: {
+ height: theme.spacing(3),
+ },
+ }),
+);
+
+interface Props {
+ children: React.ReactElement;
+ open: boolean;
+ value: number;
+}
+
+function ValueLabelComponent(props: Props) {
+ const { children, open, value } = props;
+
+ return (
+
+ {children}
+
+ );
+}
+
+const iOSBoxShadow =
+ '0 3px 1px rgba(0,0,0,0.1),0 4px 8px rgba(0,0,0,0.13),0 0 0 1px rgba(0,0,0,0.02)';
+
+const marks = [
+ {
+ value: 0,
+ },
+ {
+ value: 20,
+ },
+ {
+ value: 37,
+ },
+ {
+ value: 100,
+ },
+];
+
+const IOSSlider = withStyles({
+ root: {
+ color: '#3880ff',
+ height: 2,
+ padding: '15px 0',
+ },
+ thumb: {
+ height: 28,
+ width: 28,
+ backgroundColor: '#fff',
+ boxShadow: iOSBoxShadow,
+ marginTop: -14,
+ marginLeft: -14,
+ '&:focus, &:hover, &$active': {
+ boxShadow: '0 3px 1px rgba(0,0,0,0.1),0 4px 8px rgba(0,0,0,0.3),0 0 0 1px rgba(0,0,0,0.02)',
+ // Reset on touch devices, it doesn't add specificity
+ '@media (hover: none)': {
+ boxShadow: iOSBoxShadow,
+ },
+ },
+ },
+ active: {},
+ valueLabel: {
+ left: 'calc(-50% + 12px)',
+ top: -22,
+ '& *': {
+ background: 'transparent',
+ color: '#000',
+ },
+ },
+ track: {
+ height: 2,
+ },
+ rail: {
+ height: 2,
+ opacity: 0.5,
+ backgroundColor: '#bfbfbf',
+ },
+ mark: {
+ backgroundColor: '#bfbfbf',
+ height: 8,
+ width: 1,
+ marginTop: -3,
+ },
+ markActive: {
+ opacity: 1,
+ backgroundColor: 'currentColor',
+ },
+})(Slider);
+
+const PrettoSlider = withStyles({
+ root: {
+ color: '#52af77',
+ height: 8,
+ },
+ thumb: {
+ height: 24,
+ width: 24,
+ backgroundColor: '#fff',
+ border: '2px solid currentColor',
+ marginTop: -8,
+ marginLeft: -12,
+ '&:focus, &:hover, &$active': {
+ boxShadow: 'inherit',
+ },
+ },
+ active: {},
+ valueLabel: {
+ left: 'calc(-50% + 4px)',
+ },
+ track: {
+ height: 8,
+ borderRadius: 4,
+ },
+ rail: {
+ height: 8,
+ borderRadius: 4,
+ },
+})(Slider);
+
+const AirbnbSlider = withStyles({
+ root: {
+ color: '#3a8589',
+ height: 3,
+ padding: '13px 0',
+ },
+ thumb: {
+ height: 27,
+ width: 27,
+ backgroundColor: '#fff',
+ border: '1px solid currentColor',
+ marginTop: -12,
+ marginLeft: -13,
+ boxShadow: '#ebebeb 0 2px 2px',
+ '&:focus, &:hover, &$active': {
+ boxShadow: '#ccc 0 2px 3px 1px',
+ },
+ '& .bar': {
+ // display: inline-block !important;
+ height: 9,
+ width: 1,
+ backgroundColor: 'currentColor',
+ marginLeft: 1,
+ marginRight: 1,
+ },
+ },
+ active: {},
+ track: {
+ height: 3,
+ },
+ rail: {
+ color: '#d8d8d8',
+ opacity: 1,
+ height: 3,
+ },
+})(Slider);
+
+function AirbnbThumbComponent(props: any) {
+ return (
+
+
+
+
+
+ );
+}
+
+export function CustomizedSlider() {
+ const classes = useStyles();
+
+ return (
+
+
iOS
+
+
+
pretto.fr
+
+
+
Tooltip value label
+
+
+
Airbnb
+
(index === 0 ? 'Minimum price' : 'Maximum price')}
+ defaultValue={[20, 40]}
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|CustomizedSlider.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/DiscreteSlider.stories.tsx b/examples/storybook/stories/material-ui/slider/DiscreteSlider.stories.tsx
new file mode 100644
index 00000000000000..afbb0d2284333c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/DiscreteSlider.stories.tsx
@@ -0,0 +1,54 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Slider from '@material-ui/core/Slider';
+
+const useStyles = makeStyles({
+ root: {
+ width: 300,
+ },
+});
+
+function valuetext(value: number) {
+ return `${value}°C`;
+}
+
+export function DiscreteSlider() {
+ const classes = useStyles();
+
+ return (
+
+
+ Temperature
+
+
+
+ Disabled
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|DiscreteSlider.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/DiscreteSliderLabel.stories.tsx b/examples/storybook/stories/material-ui/slider/DiscreteSliderLabel.stories.tsx
new file mode 100644
index 00000000000000..75160c6ee4f625
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/DiscreteSliderLabel.stories.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Slider from '@material-ui/core/Slider';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 300,
+ },
+ margin: {
+ height: theme.spacing(3),
+ },
+ }),
+);
+
+const marks = [
+ {
+ value: 0,
+ label: '0°C',
+ },
+ {
+ value: 20,
+ label: '20°C',
+ },
+ {
+ value: 37,
+ label: '37°C',
+ },
+ {
+ value: 100,
+ label: '100°C',
+ },
+];
+
+function valuetext(value: number) {
+ return `${value}°C`;
+}
+
+export function DiscreteSlider() {
+ const classes = useStyles();
+
+ return (
+
+
+ Always visible
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|DiscreteSliderLabel.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/DiscreteSliderMarks.stories.tsx b/examples/storybook/stories/material-ui/slider/DiscreteSliderMarks.stories.tsx
new file mode 100644
index 00000000000000..881c592bab293f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/DiscreteSliderMarks.stories.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Slider from '@material-ui/core/Slider';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 300,
+ },
+ margin: {
+ height: theme.spacing(3),
+ },
+ }),
+);
+
+const marks = [
+ {
+ value: 0,
+ label: '0°C',
+ },
+ {
+ value: 20,
+ label: '20°C',
+ },
+ {
+ value: 37,
+ label: '37°C',
+ },
+ {
+ value: 100,
+ label: '100°C',
+ },
+];
+
+function valuetext(value: number) {
+ return `${value}°C`;
+}
+
+export function DiscreteSlider() {
+ const classes = useStyles();
+
+ return (
+
+
+ Custom marks
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|DiscreteSliderMarks.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/DiscreteSliderSteps.stories.tsx b/examples/storybook/stories/material-ui/slider/DiscreteSliderSteps.stories.tsx
new file mode 100644
index 00000000000000..09ede983c55575
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/DiscreteSliderSteps.stories.tsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Slider from '@material-ui/core/Slider';
+
+const useStyles = makeStyles({
+ root: {
+ width: 300,
+ },
+});
+
+function valuetext(value: number) {
+ return `${value}°C`;
+}
+
+export function DiscreteSlider() {
+ const classes = useStyles();
+
+ return (
+
+
+ Small steps
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|DiscreteSliderSteps.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/DiscreteSliderValues.stories.tsx b/examples/storybook/stories/material-ui/slider/DiscreteSliderValues.stories.tsx
new file mode 100644
index 00000000000000..9853281ec20a53
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/DiscreteSliderValues.stories.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Slider from '@material-ui/core/Slider';
+
+const useStyles = makeStyles({
+ root: {
+ width: 300,
+ },
+});
+
+const marks = [
+ {
+ value: 0,
+ label: '0°C',
+ },
+ {
+ value: 20,
+ label: '20°C',
+ },
+ {
+ value: 37,
+ label: '37°C',
+ },
+ {
+ value: 100,
+ label: '100°C',
+ },
+];
+
+function valuetext(value: number) {
+ return `${value}°C`;
+}
+
+function valueLabelFormat(value: number) {
+ return marks.findIndex((mark) => mark.value === value) + 1;
+}
+
+export function DiscreteSlider() {
+ const classes = useStyles();
+
+ return (
+
+
+ Restricted values
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|DiscreteSliderValues.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/InputSlider.stories.tsx b/examples/storybook/stories/material-ui/slider/InputSlider.stories.tsx
new file mode 100644
index 00000000000000..77739cd6953a5f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/InputSlider.stories.tsx
@@ -0,0 +1,77 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Grid from '@material-ui/core/Grid';
+import Typography from '@material-ui/core/Typography';
+import Slider from '@material-ui/core/Slider';
+import Input from '@material-ui/core/Input';
+import VolumeUp from '@material-ui/icons/VolumeUp';
+
+const useStyles = makeStyles({
+ root: {
+ width: 250,
+ },
+ input: {
+ width: 42,
+ },
+});
+
+export function InputSlider() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState>(30);
+
+ const handleSliderChange = (event: any, newValue: number | number[]) => {
+ setValue(newValue);
+ };
+
+ const handleInputChange = (event: React.ChangeEvent) => {
+ setValue(event.target.value === '' ? '' : Number(event.target.value));
+ };
+
+ const handleBlur = () => {
+ if (value < 0) {
+ setValue(0);
+ } else if (value > 100) {
+ setValue(100);
+ }
+ };
+
+ return (
+
+
+ Volume
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|InputSlider.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/NonLinearSlider.stories.tsx b/examples/storybook/stories/material-ui/slider/NonLinearSlider.stories.tsx
new file mode 100644
index 00000000000000..9778675d87d9bc
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/NonLinearSlider.stories.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import Typography from '@material-ui/core/Typography';
+import Slider from '@material-ui/core/Slider';
+
+function valueLabelFormat(value: number) {
+ const [coefficient, exponent] = value
+ .toExponential()
+ .split('e')
+ .map((item) => Number(item));
+ return `${Math.round(coefficient)}e^${exponent}`;
+}
+
+export function NonLinearSlider() {
+ const [value, setValue] = React.useState(1);
+
+ const handleChange = (event: any, newValue: number | number[]) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+ Temperature range
+
+ x ** 10}
+ getAriaValueText={valueLabelFormat}
+ valueLabelFormat={valueLabelFormat}
+ onChange={handleChange}
+ valueLabelDisplay="auto"
+ aria-labelledby="non-linear-slider"
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|NonLinearSlider.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/RangeSlider.stories.tsx b/examples/storybook/stories/material-ui/slider/RangeSlider.stories.tsx
new file mode 100644
index 00000000000000..c350cc68895009
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/RangeSlider.stories.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Slider from '@material-ui/core/Slider';
+
+const useStyles = makeStyles({
+ root: {
+ width: 300,
+ },
+});
+
+function valuetext(value: number) {
+ return `${value}°C`;
+}
+
+export function RangeSlider() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState([20, 37]);
+
+ const handleChange = (event: any, newValue: number | number[]) => {
+ setValue(newValue as number[]);
+ };
+
+ return (
+
+
+ Temperature range
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|RangeSlider.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/TrackFalseSlider.stories.tsx b/examples/storybook/stories/material-ui/slider/TrackFalseSlider.stories.tsx
new file mode 100644
index 00000000000000..49a87a56218764
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/TrackFalseSlider.stories.tsx
@@ -0,0 +1,72 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Slider from '@material-ui/core/Slider';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 250,
+ },
+ margin: {
+ height: theme.spacing(3),
+ },
+ }),
+);
+
+const marks = [
+ {
+ value: 0,
+ label: '0°C',
+ },
+ {
+ value: 20,
+ label: '20°C',
+ },
+ {
+ value: 37,
+ label: '37°C',
+ },
+ {
+ value: 100,
+ label: '100°C',
+ },
+];
+
+function valuetext(value: number) {
+ return `${value}°C`;
+}
+
+export function TrackFalseSlider() {
+ const classes = useStyles();
+
+ return (
+
+
+ Removed track
+
+
+
+
+ Removed track range slider
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|TrackFalseSlider.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/TrackInvertedSlider.stories.tsx b/examples/storybook/stories/material-ui/slider/TrackInvertedSlider.stories.tsx
new file mode 100644
index 00000000000000..bb9b6bbf54ee61
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/TrackInvertedSlider.stories.tsx
@@ -0,0 +1,72 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Slider from '@material-ui/core/Slider';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 250,
+ },
+ margin: {
+ height: theme.spacing(3),
+ },
+ }),
+);
+
+const marks = [
+ {
+ value: 0,
+ label: '0°C',
+ },
+ {
+ value: 20,
+ label: '20°C',
+ },
+ {
+ value: 37,
+ label: '37°C',
+ },
+ {
+ value: 100,
+ label: '100°C',
+ },
+];
+
+function valuetext(value: number) {
+ return `${value}°C`;
+}
+
+export function TrackInvertedSlider() {
+ const classes = useStyles();
+
+ return (
+
+
+ Inverted track
+
+
+
+
+ Inverted track range
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|TrackInvertedSlider.stories"
+};
diff --git a/examples/storybook/stories/material-ui/slider/VerticalSlider.stories.tsx b/examples/storybook/stories/material-ui/slider/VerticalSlider.stories.tsx
new file mode 100644
index 00000000000000..589baadf84146b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/slider/VerticalSlider.stories.tsx
@@ -0,0 +1,71 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Typography from '@material-ui/core/Typography';
+import Slider from '@material-ui/core/Slider';
+
+const useStyles = makeStyles({
+ root: {
+ height: 300,
+ },
+});
+
+function valuetext(value: number) {
+ return `${value}°C`;
+}
+
+const marks = [
+ {
+ value: 0,
+ label: '0°C',
+ },
+ {
+ value: 20,
+ label: '20°C',
+ },
+ {
+ value: 37,
+ label: '37°C',
+ },
+ {
+ value: 100,
+ label: '100°C',
+ },
+];
+
+export function VerticalSlider() {
+ const classes = useStyles();
+
+ return (
+
+
+ Temperature
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|slider|VerticalSlider.stories"
+};
diff --git a/examples/storybook/stories/material-ui/snackbars/ConsecutiveSnackbars.stories.tsx b/examples/storybook/stories/material-ui/snackbars/ConsecutiveSnackbars.stories.tsx
new file mode 100644
index 00000000000000..fbf660fdc9f86d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/snackbars/ConsecutiveSnackbars.stories.tsx
@@ -0,0 +1,97 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import Snackbar from '@material-ui/core/Snackbar';
+import IconButton from '@material-ui/core/IconButton';
+import CloseIcon from '@material-ui/icons/Close';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ close: {
+ padding: theme.spacing(0.5),
+ },
+ }),
+);
+
+export interface SnackbarMessage {
+ message: string;
+ key: number;
+}
+
+export interface State {
+ open: boolean;
+ snackPack: SnackbarMessage[];
+ messageInfo?: SnackbarMessage;
+}
+
+export function ConsecutiveSnackbars() {
+ const [snackPack, setSnackPack] = React.useState([]);
+ const [open, setOpen] = React.useState(false);
+ const [messageInfo, setMessageInfo] = React.useState(undefined);
+
+ React.useEffect(() => {
+ if (snackPack.length && !messageInfo) {
+ // Set a new snack when we don't have an active one
+ setMessageInfo({ ...snackPack[0] });
+ setSnackPack((prev) => prev.slice(1));
+ setOpen(true);
+ } else if (snackPack.length && messageInfo && open) {
+ // Close an active snack when a new one is added
+ setOpen(false);
+ }
+ }, [snackPack, messageInfo, open]);
+
+ const handleClick = (message: string) => () => {
+ setSnackPack((prev) => [...prev, { message, key: new Date().getTime() }]);
+ };
+
+ const handleClose = (event: React.SyntheticEvent | MouseEvent, reason?: string) => {
+ if (reason === 'clickaway') {
+ return;
+ }
+ setOpen(false);
+ };
+
+ const handleExited = () => {
+ setMessageInfo(undefined);
+ };
+
+ const classes = useStyles();
+ return (
+
+ Show message A
+ Show message B
+
+
+ UNDO
+
+
+
+
+
+ }
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|snackbars|ConsecutiveSnackbars.stories"
+};
diff --git a/examples/storybook/stories/material-ui/snackbars/CustomizedSnackbars.stories.tsx b/examples/storybook/stories/material-ui/snackbars/CustomizedSnackbars.stories.tsx
new file mode 100644
index 00000000000000..49bd3cf494cf7b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/snackbars/CustomizedSnackbars.stories.tsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Snackbar from '@material-ui/core/Snackbar';
+import MuiAlert, { AlertProps } from '@material-ui/lab/Alert';
+import { makeStyles, Theme } from '@material-ui/core/styles';
+
+function Alert(props: AlertProps) {
+ return ;
+}
+
+const useStyles = makeStyles((theme: Theme) => ({
+ root: {
+ width: '100%',
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+}));
+
+export function CustomizedSnackbars() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+
+ const handleClick = () => {
+ setOpen(true);
+ };
+
+ const handleClose = (event?: React.SyntheticEvent, reason?: string) => {
+ if (reason === 'clickaway') {
+ return;
+ }
+
+ setOpen(false);
+ };
+
+ return (
+
+
+ Open success snackbar
+
+
+
+ This is a success message!
+
+
+
This is an error message!
+
This is a warning message!
+
This is an information message!
+
This is a success message!
+
+ );
+}
+
+export default {
+ title: "Material-ui|snackbars|CustomizedSnackbars.stories"
+};
diff --git a/examples/storybook/stories/material-ui/snackbars/DirectionSnackbar.stories.tsx b/examples/storybook/stories/material-ui/snackbars/DirectionSnackbar.stories.tsx
new file mode 100644
index 00000000000000..0d6ab8cdb93724
--- /dev/null
+++ b/examples/storybook/stories/material-ui/snackbars/DirectionSnackbar.stories.tsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Snackbar from '@material-ui/core/Snackbar';
+import Slide, { SlideProps } from '@material-ui/core/Slide';
+
+type TransitionProps = Omit;
+
+function TransitionLeft(props: TransitionProps) {
+ return ;
+}
+
+function TransitionUp(props: TransitionProps) {
+ return ;
+}
+
+function TransitionRight(props: TransitionProps) {
+ return ;
+}
+
+function TransitionDown(props: TransitionProps) {
+ return ;
+}
+
+export function DirectionSnackbar() {
+ const [open, setOpen] = React.useState(false);
+ const [transition, setTransition] = React.useState<
+ React.ComponentType | undefined
+ >(undefined);
+
+ const handleClick = (Transition: React.ComponentType) => () => {
+ setTransition(() => Transition);
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+ Right
+ Up
+ Left
+ Down
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|snackbars|DirectionSnackbar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/snackbars/FabIntegrationSnackbar.stories.tsx b/examples/storybook/stories/material-ui/snackbars/FabIntegrationSnackbar.stories.tsx
new file mode 100644
index 00000000000000..84132f1dbcc900
--- /dev/null
+++ b/examples/storybook/stories/material-ui/snackbars/FabIntegrationSnackbar.stories.tsx
@@ -0,0 +1,80 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import Toolbar from '@material-ui/core/Toolbar';
+import IconButton from '@material-ui/core/IconButton';
+import MenuIcon from '@material-ui/icons/Menu';
+import Typography from '@material-ui/core/Typography';
+import Button from '@material-ui/core/Button';
+import Fab from '@material-ui/core/Fab';
+import AddIcon from '@material-ui/icons/Add';
+import Snackbar from '@material-ui/core/Snackbar';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ '@global': {
+ body: {
+ backgroundColor: theme.palette.background.paper,
+ },
+ },
+ menuButton: {
+ marginRight: theme.spacing(2),
+ },
+ fab: {
+ position: 'absolute',
+ bottom: theme.spacing(2),
+ right: theme.spacing(2),
+ },
+ snackbar: {
+ [theme.breakpoints.down('xs')]: {
+ bottom: 90,
+ },
+ },
+ }),
+);
+
+export function FabIntegrationSnackbar() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+ App Bar
+
+
+
+
+
+
+
+ Undo
+
+ }
+ className={classes.snackbar}
+ />
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|snackbars|FabIntegrationSnackbar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/snackbars/IntegrationNotistack.stories.tsx b/examples/storybook/stories/material-ui/snackbars/IntegrationNotistack.stories.tsx
new file mode 100644
index 00000000000000..0af632c6427b1a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/snackbars/IntegrationNotistack.stories.tsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import { SnackbarProvider, VariantType, useSnackbar } from 'notistack';
+
+function MyApp() {
+ const { enqueueSnackbar } = useSnackbar();
+
+ const handleClick = () => {
+ enqueueSnackbar('I love snacks.');
+ };
+
+ const handleClickVariant = (variant: VariantType) => () => {
+ // variant could be success, error, warning, info, or default
+ enqueueSnackbar('This is a success message!', { variant });
+ };
+
+ return (
+
+ Show snackbar
+ Show success snackbar
+
+ );
+}
+
+export function IntegrationNotistack() {
+ return (
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|snackbars|IntegrationNotistack.stories"
+};
diff --git a/examples/storybook/stories/material-ui/snackbars/LongTextSnackbar.stories.tsx b/examples/storybook/stories/material-ui/snackbars/LongTextSnackbar.stories.tsx
new file mode 100644
index 00000000000000..b478eed8bd004c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/snackbars/LongTextSnackbar.stories.tsx
@@ -0,0 +1,49 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import SnackbarContent from '@material-ui/core/SnackbarContent';
+
+const action = (
+
+ lorem ipsum dolorem
+
+);
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ maxWidth: 600,
+ '& > * + *': {
+ marginTop: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+export function LongTextSnackbar() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|snackbars|LongTextSnackbar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/snackbars/PositionedSnackbar.stories.tsx b/examples/storybook/stories/material-ui/snackbars/PositionedSnackbar.stories.tsx
new file mode 100644
index 00000000000000..fef1c2a9306b97
--- /dev/null
+++ b/examples/storybook/stories/material-ui/snackbars/PositionedSnackbar.stories.tsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Snackbar, { SnackbarOrigin } from '@material-ui/core/Snackbar';
+
+export interface State extends SnackbarOrigin {
+ open: boolean;
+}
+
+export function PositionedSnackbar() {
+ const [state, setState] = React.useState({
+ open: false,
+ vertical: 'top',
+ horizontal: 'center',
+ });
+ const { vertical, horizontal, open } = state;
+
+ const handleClick = (newState: SnackbarOrigin) => () => {
+ setState({ open: true, ...newState });
+ };
+
+ const handleClose = () => {
+ setState({ ...state, open: false });
+ };
+
+ const buttons = (
+
+ Top-Center
+ Top-Right
+
+ Bottom-Right
+
+
+ Bottom-Center
+
+ Bottom-Left
+ Top-Left
+
+ );
+
+ return (
+
+ {buttons}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|snackbars|PositionedSnackbar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/snackbars/SimpleSnackbar.stories.tsx b/examples/storybook/stories/material-ui/snackbars/SimpleSnackbar.stories.tsx
new file mode 100644
index 00000000000000..387ac0fcd82f3f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/snackbars/SimpleSnackbar.stories.tsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Snackbar from '@material-ui/core/Snackbar';
+import IconButton from '@material-ui/core/IconButton';
+import CloseIcon from '@material-ui/icons/Close';
+
+export function SimpleSnackbar() {
+ const [open, setOpen] = React.useState(false);
+
+ const handleClick = () => {
+ setOpen(true);
+ };
+
+ const handleClose = (event: React.SyntheticEvent | React.MouseEvent, reason?: string) => {
+ if (reason === 'clickaway') {
+ return;
+ }
+
+ setOpen(false);
+ };
+
+ return (
+
+ Open simple snackbar
+
+
+ UNDO
+
+
+
+
+
+ }
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|snackbars|SimpleSnackbar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/snackbars/TransitionsSnackbar.stories.tsx b/examples/storybook/stories/material-ui/snackbars/TransitionsSnackbar.stories.tsx
new file mode 100644
index 00000000000000..a322afc30f04cb
--- /dev/null
+++ b/examples/storybook/stories/material-ui/snackbars/TransitionsSnackbar.stories.tsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Snackbar from '@material-ui/core/Snackbar';
+import Fade from '@material-ui/core/Fade';
+import Slide from '@material-ui/core/Slide';
+import Grow from '@material-ui/core/Grow';
+import { TransitionProps } from '@material-ui/core/transitions';
+
+function SlideTransition(props: TransitionProps) {
+ return ;
+}
+
+function GrowTransition(props: TransitionProps) {
+ return ;
+}
+
+export function TransitionsSnackbar() {
+ const [state, setState] = React.useState<{
+ open: boolean;
+ Transition: React.ComponentType }>;
+ }>({
+ open: false,
+ Transition: Fade,
+ });
+
+ const handleClick = (
+ Transition: React.ComponentType }>,
+ ) => () => {
+ setState({
+ open: true,
+ Transition,
+ });
+ };
+
+ const handleClose = () => {
+ setState({
+ ...state,
+ open: false,
+ });
+ };
+
+ return (
+
+ Grow Transition
+ Fade Transition
+ Slide Transition
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|snackbars|TransitionsSnackbar.stories"
+};
diff --git a/examples/storybook/stories/material-ui/speed-dial/OpenIconSpeedDial.stories.tsx b/examples/storybook/stories/material-ui/speed-dial/OpenIconSpeedDial.stories.tsx
new file mode 100644
index 00000000000000..72859db5fe7a9e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/speed-dial/OpenIconSpeedDial.stories.tsx
@@ -0,0 +1,81 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import SpeedDial from '@material-ui/lab/SpeedDial';
+import SpeedDialIcon from '@material-ui/lab/SpeedDialIcon';
+import SpeedDialAction from '@material-ui/lab/SpeedDialAction';
+import FileCopyIcon from '@material-ui/icons/FileCopyOutlined';
+import SaveIcon from '@material-ui/icons/Save';
+import PrintIcon from '@material-ui/icons/Print';
+import ShareIcon from '@material-ui/icons/Share';
+import FavoriteIcon from '@material-ui/icons/Favorite';
+import EditIcon from '@material-ui/icons/Edit';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ height: 380,
+ transform: 'translateZ(0px)',
+ flexGrow: 1,
+ },
+ speedDial: {
+ position: 'absolute',
+ bottom: theme.spacing(2),
+ right: theme.spacing(2),
+ },
+ }),
+);
+
+const actions = [
+ { icon: , name: 'Copy' },
+ { icon: , name: 'Save' },
+ { icon: , name: 'Print' },
+ { icon: , name: 'Share' },
+ { icon: , name: 'Like' },
+];
+
+export function OpenIconSpeedDial() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+ const [hidden, setHidden] = React.useState(false);
+
+ const handleVisibility = () => {
+ setHidden((prevHidden) => !prevHidden);
+ };
+
+ const handleOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+ Toggle Speed Dial
+ } />}
+ onClose={handleClose}
+ onOpen={handleOpen}
+ open={open}
+ >
+ {actions.map((action) => (
+
+ ))}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|speed-dial|OpenIconSpeedDial.stories"
+};
diff --git a/examples/storybook/stories/material-ui/speed-dial/SpeedDialTooltipOpen.stories.tsx b/examples/storybook/stories/material-ui/speed-dial/SpeedDialTooltipOpen.stories.tsx
new file mode 100644
index 00000000000000..bc4f964ca58c56
--- /dev/null
+++ b/examples/storybook/stories/material-ui/speed-dial/SpeedDialTooltipOpen.stories.tsx
@@ -0,0 +1,83 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import Backdrop from '@material-ui/core/Backdrop';
+import SpeedDial from '@material-ui/lab/SpeedDial';
+import SpeedDialIcon from '@material-ui/lab/SpeedDialIcon';
+import SpeedDialAction from '@material-ui/lab/SpeedDialAction';
+import FileCopyIcon from '@material-ui/icons/FileCopyOutlined';
+import SaveIcon from '@material-ui/icons/Save';
+import PrintIcon from '@material-ui/icons/Print';
+import ShareIcon from '@material-ui/icons/Share';
+import FavoriteIcon from '@material-ui/icons/Favorite';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ height: 380,
+ transform: 'translateZ(0px)',
+ flexGrow: 1,
+ },
+ speedDial: {
+ position: 'absolute',
+ bottom: theme.spacing(2),
+ right: theme.spacing(2),
+ },
+ }),
+);
+
+const actions = [
+ { icon: , name: 'Copy' },
+ { icon: , name: 'Save' },
+ { icon: , name: 'Print' },
+ { icon: , name: 'Share' },
+ { icon: , name: 'Like' },
+];
+
+export function SpeedDialTooltipOpen() {
+ const classes = useStyles();
+ const [open, setOpen] = React.useState(false);
+ const [hidden, setHidden] = React.useState(false);
+
+ const handleVisibility = () => {
+ setHidden((prevHidden) => !prevHidden);
+ };
+
+ const handleOpen = () => {
+ setOpen(true);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ return (
+
+ Toggle Speed Dial
+
+ }
+ onClose={handleClose}
+ onOpen={handleOpen}
+ open={open}
+ >
+ {actions.map((action) => (
+
+ ))}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|speed-dial|SpeedDialTooltipOpen.stories"
+};
diff --git a/examples/storybook/stories/material-ui/speed-dial/SpeedDials.stories.tsx b/examples/storybook/stories/material-ui/speed-dial/SpeedDials.stories.tsx
new file mode 100644
index 00000000000000..fcd1fffb6b3ff2
--- /dev/null
+++ b/examples/storybook/stories/material-ui/speed-dial/SpeedDials.stories.tsx
@@ -0,0 +1,123 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import FormLabel from '@material-ui/core/FormLabel';
+import Radio from '@material-ui/core/Radio';
+import RadioGroup from '@material-ui/core/RadioGroup';
+import Switch from '@material-ui/core/Switch';
+import SpeedDial, { SpeedDialProps } from '@material-ui/lab/SpeedDial';
+import SpeedDialIcon from '@material-ui/lab/SpeedDialIcon';
+import SpeedDialAction from '@material-ui/lab/SpeedDialAction';
+import FileCopyIcon from '@material-ui/icons/FileCopyOutlined';
+import SaveIcon from '@material-ui/icons/Save';
+import PrintIcon from '@material-ui/icons/Print';
+import ShareIcon from '@material-ui/icons/Share';
+import FavoriteIcon from '@material-ui/icons/Favorite';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ transform: 'translateZ(0px)',
+ flexGrow: 1,
+ },
+ exampleWrapper: {
+ position: 'relative',
+ marginTop: theme.spacing(3),
+ height: 380,
+ },
+ radioGroup: {
+ margin: theme.spacing(1, 0),
+ },
+ speedDial: {
+ position: 'absolute',
+ '&.MuiSpeedDial-directionUp, &.MuiSpeedDial-directionLeft': {
+ bottom: theme.spacing(2),
+ right: theme.spacing(2),
+ },
+ '&.MuiSpeedDial-directionDown, &.MuiSpeedDial-directionRight': {
+ top: theme.spacing(2),
+ left: theme.spacing(2),
+ },
+ },
+ }),
+);
+
+const actions = [
+ { icon: , name: 'Copy' },
+ { icon: , name: 'Save' },
+ { icon: , name: 'Print' },
+ { icon: , name: 'Share' },
+ { icon: , name: 'Like' },
+];
+
+export function SpeedDials() {
+ const classes = useStyles();
+ const [direction, setDirection] = React.useState('up');
+ const [open, setOpen] = React.useState(false);
+ const [hidden, setHidden] = React.useState(false);
+
+ const handleDirectionChange = (event: React.ChangeEvent) => {
+ setDirection((event.target as HTMLInputElement).value as SpeedDialProps['direction']);
+ };
+
+ const handleHiddenChange = (event: React.ChangeEvent) => {
+ setHidden(event.target.checked);
+ };
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ const handleOpen = () => {
+ setOpen(true);
+ };
+
+ return (
+
+
}
+ label="Hidden"
+ />
+
+ Direction
+
+
+ } label="Up" />
+ } label="Right" />
+ } label="Down" />
+ } label="Left" />
+
+
+ }
+ onClose={handleClose}
+ onOpen={handleOpen}
+ open={open}
+ direction={direction}
+ >
+ {actions.map((action) => (
+
+ ))}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|speed-dial|SpeedDials.stories"
+};
diff --git a/examples/storybook/stories/material-ui/steppers/CustomizedSteppers.stories.tsx b/examples/storybook/stories/material-ui/steppers/CustomizedSteppers.stories.tsx
new file mode 100644
index 00000000000000..19d7090086d9fb
--- /dev/null
+++ b/examples/storybook/stories/material-ui/steppers/CustomizedSteppers.stories.tsx
@@ -0,0 +1,253 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles, withStyles } from '@material-ui/core/styles';
+import clsx from 'clsx';
+import Stepper from '@material-ui/core/Stepper';
+import Step from '@material-ui/core/Step';
+import StepLabel from '@material-ui/core/StepLabel';
+import Check from '@material-ui/icons/Check';
+import SettingsIcon from '@material-ui/icons/Settings';
+import GroupAddIcon from '@material-ui/icons/GroupAdd';
+import VideoLabelIcon from '@material-ui/icons/VideoLabel';
+import StepConnector from '@material-ui/core/StepConnector';
+import Button from '@material-ui/core/Button';
+import Typography from '@material-ui/core/Typography';
+import { StepIconProps } from '@material-ui/core/StepIcon';
+
+const QontoConnector = withStyles({
+ alternativeLabel: {
+ top: 10,
+ left: 'calc(-50% + 16px)',
+ right: 'calc(50% + 16px)',
+ },
+ active: {
+ '& $line': {
+ borderColor: '#784af4',
+ },
+ },
+ completed: {
+ '& $line': {
+ borderColor: '#784af4',
+ },
+ },
+ line: {
+ borderColor: '#eaeaf0',
+ borderTopWidth: 3,
+ borderRadius: 1,
+ },
+})(StepConnector);
+
+const useQontoStepIconStyles = makeStyles({
+ root: {
+ color: '#eaeaf0',
+ display: 'flex',
+ height: 22,
+ alignItems: 'center',
+ },
+ active: {
+ color: '#784af4',
+ },
+ circle: {
+ width: 8,
+ height: 8,
+ borderRadius: '50%',
+ backgroundColor: 'currentColor',
+ },
+ completed: {
+ color: '#784af4',
+ zIndex: 1,
+ fontSize: 18,
+ },
+});
+
+function QontoStepIcon(props: StepIconProps) {
+ const classes = useQontoStepIconStyles();
+ const { active, completed } = props;
+
+ return (
+
+ );
+}
+
+const ColorlibConnector = withStyles({
+ alternativeLabel: {
+ top: 22,
+ },
+ active: {
+ '& $line': {
+ backgroundImage:
+ 'linear-gradient( 95deg,rgb(242,113,33) 0%,rgb(233,64,87) 50%,rgb(138,35,135) 100%)',
+ },
+ },
+ completed: {
+ '& $line': {
+ backgroundImage:
+ 'linear-gradient( 95deg,rgb(242,113,33) 0%,rgb(233,64,87) 50%,rgb(138,35,135) 100%)',
+ },
+ },
+ line: {
+ height: 3,
+ border: 0,
+ backgroundColor: '#eaeaf0',
+ borderRadius: 1,
+ },
+})(StepConnector);
+
+const useColorlibStepIconStyles = makeStyles({
+ root: {
+ backgroundColor: '#ccc',
+ zIndex: 1,
+ color: '#fff',
+ width: 50,
+ height: 50,
+ display: 'flex',
+ borderRadius: '50%',
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ active: {
+ backgroundImage:
+ 'linear-gradient( 136deg, rgb(242,113,33) 0%, rgb(233,64,87) 50%, rgb(138,35,135) 100%)',
+ boxShadow: '0 4px 10px 0 rgba(0,0,0,.25)',
+ },
+ completed: {
+ backgroundImage:
+ 'linear-gradient( 136deg, rgb(242,113,33) 0%, rgb(233,64,87) 50%, rgb(138,35,135) 100%)',
+ },
+});
+
+function ColorlibStepIcon(props: StepIconProps) {
+ const classes = useColorlibStepIconStyles();
+ const { active, completed } = props;
+
+ const icons: { [index: string]: React.ReactElement } = {
+ 1: ,
+ 2: ,
+ 3: ,
+ };
+
+ return (
+
+ {icons[String(props.icon)]}
+
+ );
+}
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ },
+ button: {
+ marginRight: theme.spacing(1),
+ },
+ instructions: {
+ marginTop: theme.spacing(1),
+ marginBottom: theme.spacing(1),
+ },
+ }),
+);
+
+function getSteps() {
+ return ['Select campaign settings', 'Create an ad group', 'Create an ad'];
+}
+
+function getStepContent(step: number) {
+ switch (step) {
+ case 0:
+ return 'Select campaign settings...';
+ case 1:
+ return 'What is an ad group anyways?';
+ case 2:
+ return 'This is the bit I really care about!';
+ default:
+ return 'Unknown step';
+ }
+}
+
+export function CustomizedSteppers() {
+ const classes = useStyles();
+ const [activeStep, setActiveStep] = React.useState(1);
+ const steps = getSteps();
+
+ const handleNext = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
+ };
+
+ const handleBack = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
+ };
+
+ const handleReset = () => {
+ setActiveStep(0);
+ };
+
+ return (
+
+
+ {steps.map((label) => (
+
+ {label}
+
+ ))}
+
+
}>
+ {steps.map((label) => (
+
+ {label}
+
+ ))}
+
+
}>
+ {steps.map((label) => (
+
+ {label}
+
+ ))}
+
+
+ {activeStep === steps.length ? (
+
+
+ All steps completed - you're finished
+
+
+ Reset
+
+
+ ) : (
+
+
{getStepContent(activeStep)}
+
+
+ Back
+
+
+ {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
+
+
+
+ )}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|steppers|CustomizedSteppers.stories"
+};
diff --git a/examples/storybook/stories/material-ui/steppers/DotsMobileStepper.stories.tsx b/examples/storybook/stories/material-ui/steppers/DotsMobileStepper.stories.tsx
new file mode 100644
index 00000000000000..a57c02df8a6c64
--- /dev/null
+++ b/examples/storybook/stories/material-ui/steppers/DotsMobileStepper.stories.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import { makeStyles, useTheme } from '@material-ui/core/styles';
+import MobileStepper from '@material-ui/core/MobileStepper';
+import Button from '@material-ui/core/Button';
+import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
+import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight';
+
+const useStyles = makeStyles({
+ root: {
+ maxWidth: 400,
+ flexGrow: 1,
+ },
+});
+
+export function DotsMobileStepper() {
+ const classes = useStyles();
+ const theme = useTheme();
+ const [activeStep, setActiveStep] = React.useState(0);
+
+ const handleNext = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
+ };
+
+ const handleBack = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
+ };
+
+ return (
+
+ Next
+ {theme.direction === 'rtl' ? : }
+
+ }
+ backButton={
+
+ {theme.direction === 'rtl' ? : }
+ Back
+
+ }
+ />
+ );
+}
+
+export default {
+ title: "Material-ui|steppers|DotsMobileStepper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/steppers/HorizontalLinearAlternativeLabelStepper.stories.tsx b/examples/storybook/stories/material-ui/steppers/HorizontalLinearAlternativeLabelStepper.stories.tsx
new file mode 100644
index 00000000000000..e8633884e9ace6
--- /dev/null
+++ b/examples/storybook/stories/material-ui/steppers/HorizontalLinearAlternativeLabelStepper.stories.tsx
@@ -0,0 +1,97 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Stepper from '@material-ui/core/Stepper';
+import Step from '@material-ui/core/Step';
+import StepLabel from '@material-ui/core/StepLabel';
+import Button from '@material-ui/core/Button';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ },
+ backButton: {
+ marginRight: theme.spacing(1),
+ },
+ instructions: {
+ marginTop: theme.spacing(1),
+ marginBottom: theme.spacing(1),
+ },
+ }),
+);
+
+function getSteps() {
+ return ['Select master blaster campaign settings', 'Create an ad group', 'Create an ad'];
+}
+
+function getStepContent(stepIndex: number) {
+ switch (stepIndex) {
+ case 0:
+ return 'Select campaign settings...';
+ case 1:
+ return 'What is an ad group anyways?';
+ case 2:
+ return 'This is the bit I really care about!';
+ default:
+ return 'Unknown stepIndex';
+ }
+}
+
+export function HorizontalLabelPositionBelowStepper() {
+ const classes = useStyles();
+ const [activeStep, setActiveStep] = React.useState(0);
+ const steps = getSteps();
+
+ const handleNext = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
+ };
+
+ const handleBack = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
+ };
+
+ const handleReset = () => {
+ setActiveStep(0);
+ };
+
+ return (
+
+
+ {steps.map((label) => (
+
+ {label}
+
+ ))}
+
+
+ {activeStep === steps.length ? (
+
+ All steps completed
+ Reset
+
+ ) : (
+
+
{getStepContent(activeStep)}
+
+
+ Back
+
+
+ {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
+
+
+
+ )}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|steppers|HorizontalLinearAlternativeLabelStepper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/steppers/HorizontalLinearStepper.stories.tsx b/examples/storybook/stories/material-ui/steppers/HorizontalLinearStepper.stories.tsx
new file mode 100644
index 00000000000000..753bae73d0d32d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/steppers/HorizontalLinearStepper.stories.tsx
@@ -0,0 +1,153 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Stepper from '@material-ui/core/Stepper';
+import Step from '@material-ui/core/Step';
+import StepLabel from '@material-ui/core/StepLabel';
+import Button from '@material-ui/core/Button';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ },
+ button: {
+ marginRight: theme.spacing(1),
+ },
+ instructions: {
+ marginTop: theme.spacing(1),
+ marginBottom: theme.spacing(1),
+ },
+ }),
+);
+
+function getSteps() {
+ return ['Select campaign settings', 'Create an ad group', 'Create an ad'];
+}
+
+function getStepContent(step: number) {
+ switch (step) {
+ case 0:
+ return 'Select campaign settings...';
+ case 1:
+ return 'What is an ad group anyways?';
+ case 2:
+ return 'This is the bit I really care about!';
+ default:
+ return 'Unknown step';
+ }
+}
+
+export function HorizontalLinearStepper() {
+ const classes = useStyles();
+ const [activeStep, setActiveStep] = React.useState(0);
+ const [skipped, setSkipped] = React.useState(new Set());
+ const steps = getSteps();
+
+ const isStepOptional = (step: number) => {
+ return step === 1;
+ };
+
+ const isStepSkipped = (step: number) => {
+ return skipped.has(step);
+ };
+
+ const handleNext = () => {
+ let newSkipped = skipped;
+ if (isStepSkipped(activeStep)) {
+ newSkipped = new Set(newSkipped.values());
+ newSkipped.delete(activeStep);
+ }
+
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
+ setSkipped(newSkipped);
+ };
+
+ const handleBack = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
+ };
+
+ const handleSkip = () => {
+ if (!isStepOptional(activeStep)) {
+ // You probably want to guard against something like this,
+ // it should never occur unless someone's actively trying to break something.
+ throw new Error("You can't skip a step that isn't optional.");
+ }
+
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
+ setSkipped((prevSkipped) => {
+ const newSkipped = new Set(prevSkipped.values());
+ newSkipped.add(activeStep);
+ return newSkipped;
+ });
+ };
+
+ const handleReset = () => {
+ setActiveStep(0);
+ };
+
+ return (
+
+
+ {steps.map((label, index) => {
+ const stepProps: { completed?: boolean } = {};
+ const labelProps: { optional?: React.ReactNode } = {};
+ if (isStepOptional(index)) {
+ labelProps.optional = Optional ;
+ }
+ if (isStepSkipped(index)) {
+ stepProps.completed = false;
+ }
+ return (
+
+ {label}
+
+ );
+ })}
+
+
+ {activeStep === steps.length ? (
+
+
+ All steps completed - you're finished
+
+
+ Reset
+
+
+ ) : (
+
+
{getStepContent(activeStep)}
+
+
+ Back
+
+ {isStepOptional(activeStep) && (
+
+ Skip
+
+ )}
+
+ {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
+
+
+
+ )}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|steppers|HorizontalLinearStepper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/steppers/HorizontalNonLinearAlternativeLabelStepper.stories.tsx b/examples/storybook/stories/material-ui/steppers/HorizontalNonLinearAlternativeLabelStepper.stories.tsx
new file mode 100644
index 00000000000000..077a0bfb2cfea9
--- /dev/null
+++ b/examples/storybook/stories/material-ui/steppers/HorizontalNonLinearAlternativeLabelStepper.stories.tsx
@@ -0,0 +1,219 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Stepper from '@material-ui/core/Stepper';
+import Step from '@material-ui/core/Step';
+import StepButton from '@material-ui/core/StepButton';
+import Button from '@material-ui/core/Button';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ },
+ button: {
+ marginRight: theme.spacing(1),
+ },
+ backButton: {
+ marginRight: theme.spacing(1),
+ },
+ completed: {
+ display: 'inline-block',
+ },
+ instructions: {
+ marginTop: theme.spacing(1),
+ marginBottom: theme.spacing(1),
+ },
+ }),
+);
+
+function getSteps() {
+ return ['Select campaign settings', 'Create an ad group', 'Create an ad'];
+}
+
+function getStepContent(step: number) {
+ switch (step) {
+ case 0:
+ return 'Step 1: Select campaign settings...';
+ case 1:
+ return 'Step 2: What is an ad group anyways?';
+ case 2:
+ return 'Step 3: This is the bit I really care about!';
+ default:
+ return 'Unknown step';
+ }
+}
+
+export function HorizontalNonLinearAlternativeLabelStepper() {
+ const classes = useStyles();
+ const [activeStep, setActiveStep] = React.useState(0);
+ const [completed, setCompleted] = React.useState(new Set());
+ const [skipped, setSkipped] = React.useState(new Set());
+ const steps = getSteps();
+
+ const totalSteps = () => {
+ return getSteps().length;
+ };
+
+ const isStepOptional = (step: number) => {
+ return step === 1;
+ };
+
+ const handleSkip = () => {
+ if (!isStepOptional(activeStep)) {
+ // You probably want to guard against something like this
+ // it should never occur unless someone's actively trying to break something.
+ throw new Error("You can't skip a step that isn't optional.");
+ }
+
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
+ setSkipped((prevSkipped) => {
+ const newSkipped = new Set(prevSkipped.values());
+ newSkipped.add(activeStep);
+ return newSkipped;
+ });
+ };
+
+ const skippedSteps = () => {
+ return skipped.size;
+ };
+
+ const completedSteps = () => {
+ return completed.size;
+ };
+
+ const allStepsCompleted = () => {
+ return completedSteps() === totalSteps() - skippedSteps();
+ };
+
+ const isLastStep = () => {
+ return activeStep === totalSteps() - 1;
+ };
+
+ const handleNext = () => {
+ const newActiveStep =
+ isLastStep() && !allStepsCompleted()
+ ? // It's the last step, but not all steps have been completed
+ // find the first step that has been completed
+ steps.findIndex((step, i) => !completed.has(i))
+ : activeStep + 1;
+
+ setActiveStep(newActiveStep);
+ };
+
+ const handleBack = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
+ };
+
+ const handleStep = (step: number) => () => {
+ setActiveStep(step);
+ };
+
+ const handleComplete = () => {
+ const newCompleted = new Set(completed);
+ newCompleted.add(activeStep);
+ setCompleted(newCompleted);
+
+ /**
+ * Sigh... it would be much nicer to replace the following if conditional with
+ * `if (!this.allStepsComplete())` however state is not set when we do this,
+ * thus we have to resort to not being very DRY.
+ */
+ if (completed.size !== totalSteps() - skippedSteps()) {
+ handleNext();
+ }
+ };
+
+ const handleReset = () => {
+ setActiveStep(0);
+ setCompleted(new Set());
+ setSkipped(new Set());
+ };
+
+ const isStepSkipped = (step: number) => {
+ return skipped.has(step);
+ };
+
+ function isStepComplete(step: number) {
+ return completed.has(step);
+ }
+
+ return (
+
+
+ {steps.map((label, index) => {
+ const stepProps: { completed?: boolean } = {};
+ const buttonProps: { optional?: React.ReactNode } = {};
+ if (isStepOptional(index)) {
+ buttonProps.optional = Optional ;
+ }
+ if (isStepSkipped(index)) {
+ stepProps.completed = false;
+ }
+ return (
+
+
+ {label}
+
+
+ );
+ })}
+
+
+ {allStepsCompleted() ? (
+
+
+ All steps completed - you're finished
+
+ Reset
+
+ ) : (
+
+
{getStepContent(activeStep)}
+
+
+ Back
+
+
+ Next
+
+ {isStepOptional(activeStep) && !completed.has(activeStep) && (
+
+ Skip
+
+ )}
+ {activeStep !== steps.length &&
+ (completed.has(activeStep) ? (
+
+ Step {activeStep + 1} already completed
+
+ ) : (
+
+ {completedSteps() === totalSteps() - 1 ? 'Finish' : 'Complete Step'}
+
+ ))}
+
+
+ )}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|steppers|HorizontalNonLinearAlternativeLabelStepper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/steppers/HorizontalNonLinearStepper.stories.tsx b/examples/storybook/stories/material-ui/steppers/HorizontalNonLinearStepper.stories.tsx
new file mode 100644
index 00000000000000..dbafee45b885a6
--- /dev/null
+++ b/examples/storybook/stories/material-ui/steppers/HorizontalNonLinearStepper.stories.tsx
@@ -0,0 +1,150 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Stepper from '@material-ui/core/Stepper';
+import Step from '@material-ui/core/Step';
+import StepButton from '@material-ui/core/StepButton';
+import Button from '@material-ui/core/Button';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ },
+ button: {
+ marginRight: theme.spacing(1),
+ },
+ completed: {
+ display: 'inline-block',
+ },
+ instructions: {
+ marginTop: theme.spacing(1),
+ marginBottom: theme.spacing(1),
+ },
+ }),
+);
+
+function getSteps() {
+ return ['Select campaign settings', 'Create an ad group', 'Create an ad'];
+}
+
+function getStepContent(step: number) {
+ switch (step) {
+ case 0:
+ return 'Step 1: Select campaign settings...';
+ case 1:
+ return 'Step 2: What is an ad group anyways?';
+ case 2:
+ return 'Step 3: This is the bit I really care about!';
+ default:
+ return 'Unknown step';
+ }
+}
+
+export function HorizontalNonLinearStepper() {
+ const classes = useStyles();
+ const [activeStep, setActiveStep] = React.useState(0);
+ const [completed, setCompleted] = React.useState<{ [k: number]: boolean }>({});
+ const steps = getSteps();
+
+ const totalSteps = () => {
+ return steps.length;
+ };
+
+ const completedSteps = () => {
+ return Object.keys(completed).length;
+ };
+
+ const isLastStep = () => {
+ return activeStep === totalSteps() - 1;
+ };
+
+ const allStepsCompleted = () => {
+ return completedSteps() === totalSteps();
+ };
+
+ const handleNext = () => {
+ const newActiveStep =
+ isLastStep() && !allStepsCompleted()
+ ? // It's the last step, but not all steps have been completed,
+ // find the first step that has been completed
+ steps.findIndex((step, i) => !(i in completed))
+ : activeStep + 1;
+ setActiveStep(newActiveStep);
+ };
+
+ const handleBack = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
+ };
+
+ const handleStep = (step: number) => () => {
+ setActiveStep(step);
+ };
+
+ const handleComplete = () => {
+ const newCompleted = completed;
+ newCompleted[activeStep] = true;
+ setCompleted(newCompleted);
+ handleNext();
+ };
+
+ const handleReset = () => {
+ setActiveStep(0);
+ setCompleted({});
+ };
+
+ return (
+
+
+ {steps.map((label, index) => (
+
+
+ {label}
+
+
+ ))}
+
+
+ {allStepsCompleted() ? (
+
+
+ All steps completed - you're finished
+
+ Reset
+
+ ) : (
+
+
{getStepContent(activeStep)}
+
+
+ Back
+
+
+ Next
+
+ {activeStep !== steps.length &&
+ (completed[activeStep] ? (
+
+ Step {activeStep + 1} already completed
+
+ ) : (
+
+ {completedSteps() === totalSteps() - 1 ? 'Finish' : 'Complete Step'}
+
+ ))}
+
+
+ )}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|steppers|HorizontalNonLinearStepper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/steppers/HorizontalNonLinearStepperWithError.stories.tsx b/examples/storybook/stories/material-ui/steppers/HorizontalNonLinearStepperWithError.stories.tsx
new file mode 100644
index 00000000000000..d8a28416203664
--- /dev/null
+++ b/examples/storybook/stories/material-ui/steppers/HorizontalNonLinearStepperWithError.stories.tsx
@@ -0,0 +1,164 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Stepper from '@material-ui/core/Stepper';
+import Step from '@material-ui/core/Step';
+import StepLabel from '@material-ui/core/StepLabel';
+import Button from '@material-ui/core/Button';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ },
+ button: {
+ marginRight: theme.spacing(1),
+ },
+ instructions: {
+ marginTop: theme.spacing(1),
+ marginBottom: theme.spacing(1),
+ },
+ }),
+);
+
+function getSteps() {
+ return ['Select campaign settings', 'Create an ad group', 'Create an ad'];
+}
+
+function getStepContent(step: number) {
+ switch (step) {
+ case 0:
+ return 'Select campaign settings...';
+ case 1:
+ return 'What is an ad group anyways?';
+ case 2:
+ return 'This is the bit I really care about!';
+ default:
+ return 'Unknown step';
+ }
+}
+
+export function HorizontalNonLinearStepperWithError() {
+ const classes = useStyles();
+ const [activeStep, setActiveStep] = React.useState(0);
+ const [skipped, setSkipped] = React.useState(new Set());
+ const steps = getSteps();
+
+ const isStepOptional = (step: number) => {
+ return step === 1;
+ };
+
+ const isStepFailed = (step: number) => {
+ return step === 1;
+ };
+
+ const isStepSkipped = (step: number) => {
+ return skipped.has(step);
+ };
+
+ const handleNext = () => {
+ let newSkipped = skipped;
+ if (isStepSkipped(activeStep)) {
+ newSkipped = new Set(skipped.values());
+ newSkipped.delete(activeStep);
+ }
+
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
+ setSkipped(newSkipped);
+ };
+
+ const handleBack = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
+ };
+
+ const handleSkip = () => {
+ if (!isStepOptional(activeStep)) {
+ // You probably want to guard against something like this,
+ // it should never occur unless someone's actively trying to break something.
+ throw new Error("You can't skip a step that isn't optional.");
+ }
+
+ setSkipped((prevSkipped) => {
+ const newSkipped = new Set(prevSkipped.values());
+ newSkipped.add(activeStep);
+ return newSkipped;
+ });
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
+ };
+
+ const handleReset = () => {
+ setActiveStep(0);
+ };
+
+ return (
+
+
+ {steps.map((label, index) => {
+ const stepProps: { completed?: boolean } = {};
+ const labelProps: { optional?: React.ReactNode; error?: boolean } = {};
+ if (isStepOptional(index)) {
+ labelProps.optional = (
+
+ Alert message
+
+ );
+ }
+ if (isStepFailed(index)) {
+ labelProps.error = true;
+ }
+ if (isStepSkipped(index)) {
+ stepProps.completed = false;
+ }
+ return (
+
+ {label}
+
+ );
+ })}
+
+
+ {activeStep === steps.length ? (
+
+
+ All steps completed - you're finished
+
+
+ Reset
+
+
+ ) : (
+
+
{getStepContent(activeStep)}
+
+
+ Back
+
+ {isStepOptional(activeStep) && (
+
+ Skip
+
+ )}
+
+ {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
+
+
+
+ )}
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|steppers|HorizontalNonLinearStepperWithError.stories"
+};
diff --git a/examples/storybook/stories/material-ui/steppers/ProgressMobileStepper.stories.tsx b/examples/storybook/stories/material-ui/steppers/ProgressMobileStepper.stories.tsx
new file mode 100644
index 00000000000000..fd8dcb2c8492c2
--- /dev/null
+++ b/examples/storybook/stories/material-ui/steppers/ProgressMobileStepper.stories.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import { makeStyles, useTheme } from '@material-ui/core/styles';
+import MobileStepper from '@material-ui/core/MobileStepper';
+import Button from '@material-ui/core/Button';
+import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
+import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight';
+
+const useStyles = makeStyles({
+ root: {
+ maxWidth: 400,
+ flexGrow: 1,
+ },
+});
+
+export function ProgressMobileStepper() {
+ const classes = useStyles();
+ const theme = useTheme();
+ const [activeStep, setActiveStep] = React.useState(0);
+
+ const handleNext = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
+ };
+
+ const handleBack = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
+ };
+
+ return (
+
+ Next
+ {theme.direction === 'rtl' ? : }
+
+ }
+ backButton={
+
+ {theme.direction === 'rtl' ? : }
+ Back
+
+ }
+ />
+ );
+}
+
+export default {
+ title: "Material-ui|steppers|ProgressMobileStepper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/steppers/TextMobileStepper.stories.tsx b/examples/storybook/stories/material-ui/steppers/TextMobileStepper.stories.tsx
new file mode 100644
index 00000000000000..5c7f761b3c124e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/steppers/TextMobileStepper.stories.tsx
@@ -0,0 +1,109 @@
+import React from 'react';
+import { makeStyles, Theme, useTheme, createStyles } from '@material-ui/core/styles';
+import MobileStepper from '@material-ui/core/MobileStepper';
+import Paper from '@material-ui/core/Paper';
+import Typography from '@material-ui/core/Typography';
+import Button from '@material-ui/core/Button';
+import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
+import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight';
+
+const tutorialSteps = [
+ {
+ label: 'San Francisco – Oakland Bay Bridge, United States',
+ imgPath:
+ 'https://images.unsplash.com/photo-1537944434965-cf4679d1a598?auto=format&fit=crop&w=400&h=250&q=60',
+ },
+ {
+ label: 'Bird',
+ imgPath:
+ 'https://images.unsplash.com/photo-1538032746644-0212e812a9e7?auto=format&fit=crop&w=400&h=250&q=60',
+ },
+ {
+ label: 'Bali, Indonesia',
+ imgPath:
+ 'https://images.unsplash.com/photo-1537996194471-e657df975ab4?auto=format&fit=crop&w=400&h=250&q=80',
+ },
+ {
+ label: 'NeONBRAND Digital Marketing, Las Vegas, United States',
+ imgPath:
+ 'https://images.unsplash.com/photo-1518732714860-b62714ce0c59?auto=format&fit=crop&w=400&h=250&q=60',
+ },
+ {
+ label: 'Goč, Serbia',
+ imgPath:
+ 'https://images.unsplash.com/photo-1512341689857-198e7e2f3ca8?auto=format&fit=crop&w=400&h=250&q=60',
+ },
+];
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ maxWidth: 400,
+ flexGrow: 1,
+ },
+ header: {
+ display: 'flex',
+ alignItems: 'center',
+ height: 50,
+ paddingLeft: theme.spacing(4),
+ backgroundColor: theme.palette.background.default,
+ },
+ img: {
+ height: 255,
+ maxWidth: 400,
+ overflow: 'hidden',
+ display: 'block',
+ width: '100%',
+ },
+ }),
+);
+
+export function TextMobileStepper() {
+ const classes = useStyles();
+ const theme = useTheme();
+ const [activeStep, setActiveStep] = React.useState(0);
+ const maxSteps = tutorialSteps.length;
+
+ const handleNext = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
+ };
+
+ const handleBack = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
+ };
+
+ return (
+
+
+ {tutorialSteps[activeStep].label}
+
+
+
+ Next
+ {theme.direction === 'rtl' ? : }
+
+ }
+ backButton={
+
+ {theme.direction === 'rtl' ? : }
+ Back
+
+ }
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|steppers|TextMobileStepper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/steppers/VerticalLinearStepper.stories.tsx b/examples/storybook/stories/material-ui/steppers/VerticalLinearStepper.stories.tsx
new file mode 100644
index 00000000000000..d06b901bf89b17
--- /dev/null
+++ b/examples/storybook/stories/material-ui/steppers/VerticalLinearStepper.stories.tsx
@@ -0,0 +1,113 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Stepper from '@material-ui/core/Stepper';
+import Step from '@material-ui/core/Step';
+import StepLabel from '@material-ui/core/StepLabel';
+import StepContent from '@material-ui/core/StepContent';
+import Button from '@material-ui/core/Button';
+import Paper from '@material-ui/core/Paper';
+import Typography from '@material-ui/core/Typography';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ },
+ button: {
+ marginTop: theme.spacing(1),
+ marginRight: theme.spacing(1),
+ },
+ actionsContainer: {
+ marginBottom: theme.spacing(2),
+ },
+ resetContainer: {
+ padding: theme.spacing(3),
+ },
+ }),
+);
+
+function getSteps() {
+ return ['Select campaign settings', 'Create an ad group', 'Create an ad'];
+}
+
+function getStepContent(step: number) {
+ switch (step) {
+ case 0:
+ return `For each ad campaign that you create, you can control how much
+ you're willing to spend on clicks and conversions, which networks
+ and geographical locations you want your ads to show on, and more.`;
+ case 1:
+ return 'An ad group contains one or more ads which target a shared set of keywords.';
+ case 2:
+ return `Try out different ad text to see what brings in the most customers,
+ and learn how to enhance your ads using features like ad extensions.
+ If you run into any problems with your ads, find out how to tell if
+ they're running and how to resolve approval issues.`;
+ default:
+ return 'Unknown step';
+ }
+}
+
+export function VerticalLinearStepper() {
+ const classes = useStyles();
+ const [activeStep, setActiveStep] = React.useState(0);
+ const steps = getSteps();
+
+ const handleNext = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep + 1);
+ };
+
+ const handleBack = () => {
+ setActiveStep((prevActiveStep) => prevActiveStep - 1);
+ };
+
+ const handleReset = () => {
+ setActiveStep(0);
+ };
+
+ return (
+
+
+ {steps.map((label, index) => (
+
+ {label}
+
+ {getStepContent(index)}
+
+
+
+ Back
+
+
+ {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
+
+
+
+
+
+ ))}
+
+ {activeStep === steps.length && (
+
+ All steps completed - you're finished
+
+ Reset
+
+
+ )}
+
+ );
+}
+
+export default {
+ title: "Material-ui|steppers|VerticalLinearStepper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/switches/CustomizedSwitches.stories.tsx b/examples/storybook/stories/material-ui/switches/CustomizedSwitches.stories.tsx
new file mode 100644
index 00000000000000..850a4c35de03f7
--- /dev/null
+++ b/examples/storybook/stories/material-ui/switches/CustomizedSwitches.stories.tsx
@@ -0,0 +1,159 @@
+import React from 'react';
+import { withStyles, Theme, createStyles } from '@material-ui/core/styles';
+import { purple } from '@material-ui/core/colors';
+import FormGroup from '@material-ui/core/FormGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import Switch, { SwitchClassKey, SwitchProps } from '@material-ui/core/Switch';
+import Grid from '@material-ui/core/Grid';
+import Typography from '@material-ui/core/Typography';
+
+interface Styles extends Partial> {
+ focusVisible?: string;
+}
+
+interface Props extends SwitchProps {
+ classes: Styles;
+}
+
+const PurpleSwitch = withStyles({
+ switchBase: {
+ color: purple[300],
+ '&$checked': {
+ color: purple[500],
+ },
+ '&$checked + $track': {
+ backgroundColor: purple[500],
+ },
+ },
+ checked: {},
+ track: {},
+})(Switch);
+
+const IOSSwitch = withStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 42,
+ height: 26,
+ padding: 0,
+ margin: theme.spacing(1),
+ },
+ switchBase: {
+ padding: 1,
+ '&$checked': {
+ transform: 'translateX(16px)',
+ color: theme.palette.common.white,
+ '& + $track': {
+ backgroundColor: '#52d869',
+ opacity: 1,
+ border: 'none',
+ },
+ },
+ '&$focusVisible $thumb': {
+ color: '#52d869',
+ border: '6px solid #fff',
+ },
+ },
+ thumb: {
+ width: 24,
+ height: 24,
+ },
+ track: {
+ borderRadius: 26 / 2,
+ border: `1px solid ${theme.palette.grey[400]}`,
+ backgroundColor: theme.palette.grey[50],
+ opacity: 1,
+ transition: theme.transitions.create(['background-color', 'border']),
+ },
+ checked: {},
+ focusVisible: {},
+ }),
+)(({ classes, ...props }: Props) => {
+ return (
+
+ );
+});
+
+const AntSwitch = withStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: 28,
+ height: 16,
+ padding: 0,
+ display: 'flex',
+ },
+ switchBase: {
+ padding: 2,
+ color: theme.palette.grey[500],
+ '&$checked': {
+ transform: 'translateX(12px)',
+ color: theme.palette.common.white,
+ '& + $track': {
+ opacity: 1,
+ backgroundColor: theme.palette.primary.main,
+ borderColor: theme.palette.primary.main,
+ },
+ },
+ },
+ thumb: {
+ width: 12,
+ height: 12,
+ boxShadow: 'none',
+ },
+ track: {
+ border: `1px solid ${theme.palette.grey[500]}`,
+ borderRadius: 16 / 2,
+ opacity: 1,
+ backgroundColor: theme.palette.common.white,
+ },
+ checked: {},
+ }),
+)(Switch);
+
+export function CustomizedSwitches() {
+ const [state, setState] = React.useState({
+ checkedA: true,
+ checkedB: true,
+ checkedC: true,
+ });
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setState({ ...state, [event.target.name]: event.target.checked });
+ };
+
+ return (
+
+ }
+ label="Custom color"
+ />
+ }
+ label="iOS style"
+ />
+
+
+ Off
+
+
+
+ On
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|switches|CustomizedSwitches.stories"
+};
diff --git a/examples/storybook/stories/material-ui/switches/FormControlLabelPosition.stories.tsx b/examples/storybook/stories/material-ui/switches/FormControlLabelPosition.stories.tsx
new file mode 100644
index 00000000000000..2ec4ea860d748d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/switches/FormControlLabelPosition.stories.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import Switch from '@material-ui/core/Switch';
+import FormGroup from '@material-ui/core/FormGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import FormControl from '@material-ui/core/FormControl';
+
+export function FormControlLabelPosition() {
+ return (
+
+
+ }
+ label="Top"
+ labelPlacement="top"
+ />
+ }
+ label="Start"
+ labelPlacement="start"
+ />
+ }
+ label="Bottom"
+ labelPlacement="bottom"
+ />
+ }
+ label="End"
+ labelPlacement="end"
+ />
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|switches|FormControlLabelPosition.stories"
+};
diff --git a/examples/storybook/stories/material-ui/switches/SwitchLabels.stories.tsx b/examples/storybook/stories/material-ui/switches/SwitchLabels.stories.tsx
new file mode 100644
index 00000000000000..8e63b57648e90b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/switches/SwitchLabels.stories.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import FormGroup from '@material-ui/core/FormGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import Switch from '@material-ui/core/Switch';
+
+export function SwitchLabels() {
+ const [state, setState] = React.useState({
+ checkedA: true,
+ checkedB: true,
+ });
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setState({ ...state, [event.target.name]: event.target.checked });
+ };
+
+ return (
+
+ }
+ label="Secondary"
+ />
+
+ }
+ label="Primary"
+ />
+ } label="Uncontrolled" />
+ } label="Disabled" />
+ } label="Disabled" />
+
+ );
+}
+
+export default {
+ title: "Material-ui|switches|SwitchLabels.stories"
+};
diff --git a/examples/storybook/stories/material-ui/switches/Switches.stories.tsx b/examples/storybook/stories/material-ui/switches/Switches.stories.tsx
new file mode 100644
index 00000000000000..2ddcb0ea2a7e5f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/switches/Switches.stories.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import Switch from '@material-ui/core/Switch';
+
+export function Switches() {
+ const [state, setState] = React.useState({
+ checkedA: true,
+ checkedB: true,
+ });
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setState({ ...state, [event.target.name]: event.target.checked });
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|switches|Switches.stories"
+};
diff --git a/examples/storybook/stories/material-ui/switches/SwitchesGroup.stories.tsx b/examples/storybook/stories/material-ui/switches/SwitchesGroup.stories.tsx
new file mode 100644
index 00000000000000..7a813340bfd1a5
--- /dev/null
+++ b/examples/storybook/stories/material-ui/switches/SwitchesGroup.stories.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import FormLabel from '@material-ui/core/FormLabel';
+import FormControl from '@material-ui/core/FormControl';
+import FormGroup from '@material-ui/core/FormGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import FormHelperText from '@material-ui/core/FormHelperText';
+import Switch from '@material-ui/core/Switch';
+
+export function SwitchesGroup() {
+ const [state, setState] = React.useState({
+ gilad: true,
+ jason: false,
+ antoine: true,
+ });
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setState({ ...state, [event.target.name]: event.target.checked });
+ };
+
+ return (
+
+ Assign responsibility
+
+ }
+ label="Gilad Gray"
+ />
+ }
+ label="Jason Killian"
+ />
+ }
+ label="Antoine Llorca"
+ />
+
+ Be careful
+
+ );
+}
+
+export default {
+ title: "Material-ui|switches|SwitchesGroup.stories"
+};
diff --git a/examples/storybook/stories/material-ui/switches/SwitchesSize.stories.tsx b/examples/storybook/stories/material-ui/switches/SwitchesSize.stories.tsx
new file mode 100644
index 00000000000000..b5cd2f65372e5b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/switches/SwitchesSize.stories.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import Switch from '@material-ui/core/Switch';
+import FormGroup from '@material-ui/core/FormGroup';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+
+export function SwitchesSize() {
+ const [checked, setChecked] = React.useState(false);
+
+ const toggleChecked = () => {
+ setChecked((prev) => !prev);
+ };
+
+ return (
+
+ }
+ label="Small"
+ />
+ }
+ label="Normal"
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|switches|SwitchesSize.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tables/AcccessibleTable.stories.tsx b/examples/storybook/stories/material-ui/tables/AcccessibleTable.stories.tsx
new file mode 100644
index 00000000000000..9eb4eae1977b72
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tables/AcccessibleTable.stories.tsx
@@ -0,0 +1,63 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableContainer from '@material-ui/core/TableContainer';
+import TableHead from '@material-ui/core/TableHead';
+import TableRow from '@material-ui/core/TableRow';
+import Paper from '@material-ui/core/Paper';
+
+const useStyles = makeStyles({
+ table: {
+ minWidth: 650,
+ },
+});
+
+function createData(name: string, calories: number, fat: number, carbs: number, protein: number) {
+ return { name, calories, fat, carbs, protein };
+}
+
+const rows = [
+ createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
+ createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
+ createData('Eclair', 262, 16.0, 24, 6.0),
+];
+
+export function AcccessibleTable() {
+ const classes = useStyles();
+
+ return (
+
+
+ A basic table example with a caption
+
+
+ Dessert (100g serving)
+ Calories
+ Fat (g)
+ Carbs (g)
+ Protein (g)
+
+
+
+ {rows.map((row) => (
+
+
+ {row.name}
+
+ {row.calories}
+ {row.fat}
+ {row.carbs}
+ {row.protein}
+
+ ))}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tables|AcccessibleTable.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tables/CollapsibleTable.stories.tsx b/examples/storybook/stories/material-ui/tables/CollapsibleTable.stories.tsx
new file mode 100644
index 00000000000000..9e417219465c8b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tables/CollapsibleTable.stories.tsx
@@ -0,0 +1,141 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Box from '@material-ui/core/Box';
+import Collapse from '@material-ui/core/Collapse';
+import IconButton from '@material-ui/core/IconButton';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableContainer from '@material-ui/core/TableContainer';
+import TableHead from '@material-ui/core/TableHead';
+import TableRow from '@material-ui/core/TableRow';
+import Typography from '@material-ui/core/Typography';
+import Paper from '@material-ui/core/Paper';
+import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
+import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';
+
+const useRowStyles = makeStyles({
+ root: {
+ '& > *': {
+ borderBottom: 'unset',
+ },
+ },
+});
+
+function createData(
+ name: string,
+ calories: number,
+ fat: number,
+ carbs: number,
+ protein: number,
+ price: number,
+) {
+ return {
+ name,
+ calories,
+ fat,
+ carbs,
+ protein,
+ price,
+ history: [
+ { date: '2020-01-05', customerId: '11091700', amount: 3 },
+ { date: '2020-01-02', customerId: 'Anonymous', amount: 1 },
+ ],
+ };
+}
+
+function Row(props: { row: ReturnType }) {
+ const { row } = props;
+ const [open, setOpen] = React.useState(false);
+ const classes = useRowStyles();
+
+ return (
+
+
+
+ setOpen(!open)}>
+ {open ? : }
+
+
+
+ {row.name}
+
+ {row.calories}
+ {row.fat}
+ {row.carbs}
+ {row.protein}
+
+
+
+
+
+
+ History
+
+
+
+
+ Date
+ Customer
+ Amount
+ Total price ($)
+
+
+
+ {row.history.map((historyRow) => (
+
+
+ {historyRow.date}
+
+ {historyRow.customerId}
+ {historyRow.amount}
+
+ {Math.round(historyRow.amount * row.price * 100) / 100}
+
+
+ ))}
+
+
+
+
+
+
+
+ );
+}
+
+const rows = [
+ createData('Frozen yoghurt', 159, 6.0, 24, 4.0, 3.99),
+ createData('Ice cream sandwich', 237, 9.0, 37, 4.3, 4.99),
+ createData('Eclair', 262, 16.0, 24, 6.0, 3.79),
+ createData('Cupcake', 305, 3.7, 67, 4.3, 2.5),
+ createData('Gingerbread', 356, 16.0, 49, 3.9, 1.5),
+];
+
+export function CollapsibleTable() {
+ return (
+
+
+
+
+
+ Dessert (100g serving)
+ Calories
+ Fat (g)
+ Carbs (g)
+ Protein (g)
+
+
+
+ {rows.map((row) => (
+
+ ))}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tables|CollapsibleTable.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tables/CustomPaginationActionsTable.stories.tsx b/examples/storybook/stories/material-ui/tables/CustomPaginationActionsTable.stories.tsx
new file mode 100644
index 00000000000000..9887a41fdc0d93
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tables/CustomPaginationActionsTable.stories.tsx
@@ -0,0 +1,179 @@
+import React from 'react';
+import { makeStyles, useTheme, Theme, createStyles } from '@material-ui/core/styles';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableContainer from '@material-ui/core/TableContainer';
+import TableFooter from '@material-ui/core/TableFooter';
+import TablePagination from '@material-ui/core/TablePagination';
+import TableRow from '@material-ui/core/TableRow';
+import Paper from '@material-ui/core/Paper';
+import IconButton from '@material-ui/core/IconButton';
+import FirstPageIcon from '@material-ui/icons/FirstPage';
+import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
+import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight';
+import LastPageIcon from '@material-ui/icons/LastPage';
+
+const useStyles1 = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ flexShrink: 0,
+ marginLeft: theme.spacing(2.5),
+ },
+ }),
+);
+
+interface TablePaginationActionsProps {
+ count: number;
+ page: number;
+ rowsPerPage: number;
+ onChangePage: (event: React.MouseEvent, newPage: number) => void;
+}
+
+function TablePaginationActions(props: TablePaginationActionsProps) {
+ const classes = useStyles1();
+ const theme = useTheme();
+ const { count, page, rowsPerPage, onChangePage } = props;
+
+ const handleFirstPageButtonClick = (event: React.MouseEvent) => {
+ onChangePage(event, 0);
+ };
+
+ const handleBackButtonClick = (event: React.MouseEvent) => {
+ onChangePage(event, page - 1);
+ };
+
+ const handleNextButtonClick = (event: React.MouseEvent) => {
+ onChangePage(event, page + 1);
+ };
+
+ const handleLastPageButtonClick = (event: React.MouseEvent) => {
+ onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1));
+ };
+
+ return (
+
+
+ {theme.direction === 'rtl' ? : }
+
+
+ {theme.direction === 'rtl' ? : }
+
+ = Math.ceil(count / rowsPerPage) - 1}
+ aria-label="next page"
+ >
+ {theme.direction === 'rtl' ? : }
+
+ = Math.ceil(count / rowsPerPage) - 1}
+ aria-label="last page"
+ >
+ {theme.direction === 'rtl' ? : }
+
+
+ );
+}
+
+function createData(name: string, calories: number, fat: number) {
+ return { name, calories, fat };
+}
+
+const rows = [
+ createData('Cupcake', 305, 3.7),
+ createData('Donut', 452, 25.0),
+ createData('Eclair', 262, 16.0),
+ createData('Frozen yoghurt', 159, 6.0),
+ createData('Gingerbread', 356, 16.0),
+ createData('Honeycomb', 408, 3.2),
+ createData('Ice cream sandwich', 237, 9.0),
+ createData('Jelly Bean', 375, 0.0),
+ createData('KitKat', 518, 26.0),
+ createData('Lollipop', 392, 0.2),
+ createData('Marshmallow', 318, 0),
+ createData('Nougat', 360, 19.0),
+ createData('Oreo', 437, 18.0),
+].sort((a, b) => (a.calories < b.calories ? -1 : 1));
+
+const useStyles2 = makeStyles({
+ table: {
+ minWidth: 500,
+ },
+});
+
+export function CustomPaginationActionsTable() {
+ const classes = useStyles2();
+ const [page, setPage] = React.useState(0);
+ const [rowsPerPage, setRowsPerPage] = React.useState(5);
+
+ const emptyRows = rowsPerPage - Math.min(rowsPerPage, rows.length - page * rowsPerPage);
+
+ const handleChangePage = (event: React.MouseEvent | null, newPage: number) => {
+ setPage(newPage);
+ };
+
+ const handleChangeRowsPerPage = (
+ event: React.ChangeEvent,
+ ) => {
+ setRowsPerPage(parseInt(event.target.value, 10));
+ setPage(0);
+ };
+
+ return (
+
+
+
+ {(rowsPerPage > 0
+ ? rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
+ : rows
+ ).map((row) => (
+
+
+ {row.name}
+
+
+ {row.calories}
+
+
+ {row.fat}
+
+
+ ))}
+ {emptyRows > 0 && (
+
+
+
+ )}
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tables|CustomPaginationActionsTable.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tables/CustomizedTables.stories.tsx b/examples/storybook/stories/material-ui/tables/CustomizedTables.stories.tsx
new file mode 100644
index 00000000000000..a3684e067fd280
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tables/CustomizedTables.stories.tsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import { withStyles, Theme, createStyles, makeStyles } from '@material-ui/core/styles';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableContainer from '@material-ui/core/TableContainer';
+import TableHead from '@material-ui/core/TableHead';
+import TableRow from '@material-ui/core/TableRow';
+import Paper from '@material-ui/core/Paper';
+
+const StyledTableCell = withStyles((theme: Theme) =>
+ createStyles({
+ head: {
+ backgroundColor: theme.palette.common.black,
+ color: theme.palette.common.white,
+ },
+ body: {
+ fontSize: 14,
+ },
+ }),
+)(TableCell);
+
+const StyledTableRow = withStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '&:nth-of-type(odd)': {
+ backgroundColor: theme.palette.action.hover,
+ },
+ },
+ }),
+)(TableRow);
+
+function createData(name: string, calories: number, fat: number, carbs: number, protein: number) {
+ return { name, calories, fat, carbs, protein };
+}
+
+const rows = [
+ createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
+ createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
+ createData('Eclair', 262, 16.0, 24, 6.0),
+ createData('Cupcake', 305, 3.7, 67, 4.3),
+ createData('Gingerbread', 356, 16.0, 49, 3.9),
+];
+
+const useStyles = makeStyles({
+ table: {
+ minWidth: 700,
+ },
+});
+
+export function CustomizedTables() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+ Dessert (100g serving)
+ Calories
+ Fat (g)
+ Carbs (g)
+ Protein (g)
+
+
+
+ {rows.map((row) => (
+
+
+ {row.name}
+
+ {row.calories}
+ {row.fat}
+ {row.carbs}
+ {row.protein}
+
+ ))}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tables|CustomizedTables.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tables/DenseTable.stories.tsx b/examples/storybook/stories/material-ui/tables/DenseTable.stories.tsx
new file mode 100644
index 00000000000000..882f89097e841c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tables/DenseTable.stories.tsx
@@ -0,0 +1,64 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableContainer from '@material-ui/core/TableContainer';
+import TableHead from '@material-ui/core/TableHead';
+import TableRow from '@material-ui/core/TableRow';
+import Paper from '@material-ui/core/Paper';
+
+const useStyles = makeStyles({
+ table: {
+ minWidth: 650,
+ },
+});
+
+function createData(name: string, calories: number, fat: number, carbs: number, protein: number) {
+ return { name, calories, fat, carbs, protein };
+}
+
+const rows = [
+ createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
+ createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
+ createData('Eclair', 262, 16.0, 24, 6.0),
+ createData('Cupcake', 305, 3.7, 67, 4.3),
+ createData('Gingerbread', 356, 16.0, 49, 3.9),
+];
+
+export function DenseTable() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+ Dessert (100g serving)
+ Calories
+ Fat (g)
+ Carbs (g)
+ Protein (g)
+
+
+
+ {rows.map((row) => (
+
+
+ {row.name}
+
+ {row.calories}
+ {row.fat}
+ {row.carbs}
+ {row.protein}
+
+ ))}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tables|DenseTable.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tables/EnhancedTable.stories.tsx b/examples/storybook/stories/material-ui/tables/EnhancedTable.stories.tsx
new file mode 100644
index 00000000000000..d286594f057d01
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tables/EnhancedTable.stories.tsx
@@ -0,0 +1,386 @@
+import React from 'react';
+import clsx from 'clsx';
+import { createStyles, lighten, makeStyles, Theme } from '@material-ui/core/styles';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableContainer from '@material-ui/core/TableContainer';
+import TableHead from '@material-ui/core/TableHead';
+import TablePagination from '@material-ui/core/TablePagination';
+import TableRow from '@material-ui/core/TableRow';
+import TableSortLabel from '@material-ui/core/TableSortLabel';
+import Toolbar from '@material-ui/core/Toolbar';
+import Typography from '@material-ui/core/Typography';
+import Paper from '@material-ui/core/Paper';
+import Checkbox from '@material-ui/core/Checkbox';
+import IconButton from '@material-ui/core/IconButton';
+import Tooltip from '@material-ui/core/Tooltip';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import Switch from '@material-ui/core/Switch';
+import DeleteIcon from '@material-ui/icons/Delete';
+import FilterListIcon from '@material-ui/icons/FilterList';
+
+interface Data {
+ calories: number;
+ carbs: number;
+ fat: number;
+ name: string;
+ protein: number;
+}
+
+function createData(
+ name: string,
+ calories: number,
+ fat: number,
+ carbs: number,
+ protein: number,
+): Data {
+ return { name, calories, fat, carbs, protein };
+}
+
+const rows = [
+ createData('Cupcake', 305, 3.7, 67, 4.3),
+ createData('Donut', 452, 25.0, 51, 4.9),
+ createData('Eclair', 262, 16.0, 24, 6.0),
+ createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
+ createData('Gingerbread', 356, 16.0, 49, 3.9),
+ createData('Honeycomb', 408, 3.2, 87, 6.5),
+ createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
+ createData('Jelly Bean', 375, 0.0, 94, 0.0),
+ createData('KitKat', 518, 26.0, 65, 7.0),
+ createData('Lollipop', 392, 0.2, 98, 0.0),
+ createData('Marshmallow', 318, 0, 81, 2.0),
+ createData('Nougat', 360, 19.0, 9, 37.0),
+ createData('Oreo', 437, 18.0, 63, 4.0),
+];
+
+function descendingComparator(a: T, b: T, orderBy: keyof T) {
+ if (b[orderBy] < a[orderBy]) {
+ return -1;
+ }
+ if (b[orderBy] > a[orderBy]) {
+ return 1;
+ }
+ return 0;
+}
+
+type Order = 'asc' | 'desc';
+
+function getComparator(
+ order: Order,
+ orderBy: Key,
+): (a: { [key in Key]: number | string }, b: { [key in Key]: number | string }) => number {
+ return order === 'desc'
+ ? (a, b) => descendingComparator(a, b, orderBy)
+ : (a, b) => -descendingComparator(a, b, orderBy);
+}
+
+function stableSort(array: T[], comparator: (a: T, b: T) => number) {
+ const stabilizedThis = array.map((el, index) => [el, index] as [T, number]);
+ stabilizedThis.sort((a, b) => {
+ const order = comparator(a[0], b[0]);
+ if (order !== 0) return order;
+ return a[1] - b[1];
+ });
+ return stabilizedThis.map((el) => el[0]);
+}
+
+interface HeadCell {
+ disablePadding: boolean;
+ id: keyof Data;
+ label: string;
+ numeric: boolean;
+}
+
+const headCells: HeadCell[] = [
+ { id: 'name', numeric: false, disablePadding: true, label: 'Dessert (100g serving)' },
+ { id: 'calories', numeric: true, disablePadding: false, label: 'Calories' },
+ { id: 'fat', numeric: true, disablePadding: false, label: 'Fat (g)' },
+ { id: 'carbs', numeric: true, disablePadding: false, label: 'Carbs (g)' },
+ { id: 'protein', numeric: true, disablePadding: false, label: 'Protein (g)' },
+];
+
+interface EnhancedTableProps {
+ classes: ReturnType;
+ numSelected: number;
+ onRequestSort: (event: React.MouseEvent, property: keyof Data) => void;
+ onSelectAllClick: (event: React.ChangeEvent) => void;
+ order: Order;
+ orderBy: string;
+ rowCount: number;
+}
+
+function EnhancedTableHead(props: EnhancedTableProps) {
+ const { classes, onSelectAllClick, order, orderBy, numSelected, rowCount, onRequestSort } = props;
+ const createSortHandler = (property: keyof Data) => (event: React.MouseEvent) => {
+ onRequestSort(event, property);
+ };
+
+ return (
+
+
+
+ 0 && numSelected < rowCount}
+ checked={rowCount > 0 && numSelected === rowCount}
+ onChange={onSelectAllClick}
+ inputProps={{ 'aria-label': 'select all desserts' }}
+ />
+
+ {headCells.map((headCell) => (
+
+
+ {headCell.label}
+ {orderBy === headCell.id ? (
+
+ {order === 'desc' ? 'sorted descending' : 'sorted ascending'}
+
+ ) : null}
+
+
+ ))}
+
+
+ );
+}
+
+const useToolbarStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ paddingLeft: theme.spacing(2),
+ paddingRight: theme.spacing(1),
+ },
+ highlight:
+ theme.palette.type === 'light'
+ ? {
+ color: theme.palette.secondary.main,
+ backgroundColor: lighten(theme.palette.secondary.light, 0.85),
+ }
+ : {
+ color: theme.palette.text.primary,
+ backgroundColor: theme.palette.secondary.dark,
+ },
+ title: {
+ flex: '1 1 100%',
+ },
+ }),
+);
+
+interface EnhancedTableToolbarProps {
+ numSelected: number;
+}
+
+const EnhancedTableToolbar = (props: EnhancedTableToolbarProps) => {
+ const classes = useToolbarStyles();
+ const { numSelected } = props;
+
+ return (
+ 0,
+ })}
+ >
+ {numSelected > 0 ? (
+
+ {numSelected} selected
+
+ ) : (
+
+ Nutrition
+
+ )}
+ {numSelected > 0 ? (
+
+
+
+
+
+ ) : (
+
+
+
+
+
+ )}
+
+ );
+};
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ width: '100%',
+ },
+ paper: {
+ width: '100%',
+ marginBottom: theme.spacing(2),
+ },
+ table: {
+ minWidth: 750,
+ },
+ visuallyHidden: {
+ border: 0,
+ clip: 'rect(0 0 0 0)',
+ height: 1,
+ margin: -1,
+ overflow: 'hidden',
+ padding: 0,
+ position: 'absolute',
+ top: 20,
+ width: 1,
+ },
+ }),
+);
+
+export function EnhancedTable() {
+ const classes = useStyles();
+ const [order, setOrder] = React.useState('asc');
+ const [orderBy, setOrderBy] = React.useState('calories');
+ const [selected, setSelected] = React.useState([]);
+ const [page, setPage] = React.useState(0);
+ const [dense, setDense] = React.useState(false);
+ const [rowsPerPage, setRowsPerPage] = React.useState(5);
+
+ const handleRequestSort = (event: React.MouseEvent, property: keyof Data) => {
+ const isAsc = orderBy === property && order === 'asc';
+ setOrder(isAsc ? 'desc' : 'asc');
+ setOrderBy(property);
+ };
+
+ const handleSelectAllClick = (event: React.ChangeEvent) => {
+ if (event.target.checked) {
+ const newSelecteds = rows.map((n) => n.name);
+ setSelected(newSelecteds);
+ return;
+ }
+ setSelected([]);
+ };
+
+ const handleClick = (event: React.MouseEvent, name: string) => {
+ const selectedIndex = selected.indexOf(name);
+ let newSelected: string[] = [];
+
+ if (selectedIndex === -1) {
+ newSelected = newSelected.concat(selected, name);
+ } else if (selectedIndex === 0) {
+ newSelected = newSelected.concat(selected.slice(1));
+ } else if (selectedIndex === selected.length - 1) {
+ newSelected = newSelected.concat(selected.slice(0, -1));
+ } else if (selectedIndex > 0) {
+ newSelected = newSelected.concat(
+ selected.slice(0, selectedIndex),
+ selected.slice(selectedIndex + 1),
+ );
+ }
+
+ setSelected(newSelected);
+ };
+
+ const handleChangePage = (event: unknown, newPage: number) => {
+ setPage(newPage);
+ };
+
+ const handleChangeRowsPerPage = (event: React.ChangeEvent) => {
+ setRowsPerPage(parseInt(event.target.value, 10));
+ setPage(0);
+ };
+
+ const handleChangeDense = (event: React.ChangeEvent) => {
+ setDense(event.target.checked);
+ };
+
+ const isSelected = (name: string) => selected.indexOf(name) !== -1;
+
+ const emptyRows = rowsPerPage - Math.min(rowsPerPage, rows.length - page * rowsPerPage);
+
+ return (
+
+
+
+
+
+
+
+ {stableSort(rows, getComparator(order, orderBy))
+ .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
+ .map((row, index) => {
+ const isItemSelected = isSelected(row.name);
+ const labelId = `enhanced-table-checkbox-${index}`;
+
+ return (
+ handleClick(event, row.name)}
+ role="checkbox"
+ aria-checked={isItemSelected}
+ tabIndex={-1}
+ key={row.name}
+ selected={isItemSelected}
+ >
+
+
+
+
+ {row.name}
+
+ {row.calories}
+ {row.fat}
+ {row.carbs}
+ {row.protein}
+
+ );
+ })}
+ {emptyRows > 0 && (
+
+
+
+ )}
+
+
+
+
+
+
}
+ label="Dense padding"
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|tables|EnhancedTable.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tables/MaterialTableDemo.stories.tsx b/examples/storybook/stories/material-ui/tables/MaterialTableDemo.stories.tsx
new file mode 100644
index 00000000000000..d5c4811891b829
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tables/MaterialTableDemo.stories.tsx
@@ -0,0 +1,87 @@
+import React from 'react';
+import MaterialTable, { Column } from 'material-table';
+
+interface Row {
+ name: string;
+ surname: string;
+ birthYear: number;
+ birthCity: number;
+}
+
+interface TableState {
+ columns: Array>;
+ data: Row[];
+}
+
+export function MaterialTableDemo() {
+ const [state, setState] = React.useState({
+ columns: [
+ { title: 'Name', field: 'name' },
+ { title: 'Surname', field: 'surname' },
+ { title: 'Birth Year', field: 'birthYear', type: 'numeric' },
+ {
+ title: 'Birth Place',
+ field: 'birthCity',
+ lookup: { 34: 'İstanbul', 63: 'Şanlıurfa' },
+ },
+ ],
+ data: [
+ { name: 'Mehmet', surname: 'Baran', birthYear: 1987, birthCity: 63 },
+ {
+ name: 'Zerya Betül',
+ surname: 'Baran',
+ birthYear: 2017,
+ birthCity: 34,
+ },
+ ],
+ });
+
+ return (
+
+ new Promise((resolve) => {
+ setTimeout(() => {
+ resolve();
+ setState((prevState) => {
+ const data = [...prevState.data];
+ data.push(newData);
+ return { ...prevState, data };
+ });
+ }, 600);
+ }),
+ onRowUpdate: (newData, oldData) =>
+ new Promise((resolve) => {
+ setTimeout(() => {
+ resolve();
+ if (oldData) {
+ setState((prevState) => {
+ const data = [...prevState.data];
+ data[data.indexOf(oldData)] = newData;
+ return { ...prevState, data };
+ });
+ }
+ }, 600);
+ }),
+ onRowDelete: (oldData) =>
+ new Promise((resolve) => {
+ setTimeout(() => {
+ resolve();
+ setState((prevState) => {
+ const data = [...prevState.data];
+ data.splice(data.indexOf(oldData), 1);
+ return { ...prevState, data };
+ });
+ }, 600);
+ }),
+ }}
+ />
+ );
+}
+
+export default {
+ title: "Material-ui|tables|MaterialTableDemo.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tables/ReactVirtualizedTable.stories.tsx b/examples/storybook/stories/material-ui/tables/ReactVirtualizedTable.stories.tsx
new file mode 100644
index 00000000000000..24cae4c1e49b7d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tables/ReactVirtualizedTable.stories.tsx
@@ -0,0 +1,241 @@
+import React from 'react';
+import clsx from 'clsx';
+import { createStyles, Theme, withStyles, WithStyles } from '@material-ui/core/styles';
+import TableCell from '@material-ui/core/TableCell';
+import Paper from '@material-ui/core/Paper';
+import { AutoSizer, Column, Table, TableCellRenderer, TableHeaderProps } from 'react-virtualized';
+
+declare module '@material-ui/core/styles/withStyles' {
+ // Augment the BaseCSSProperties so that we can control jss-rtl
+ interface BaseCSSProperties {
+ /*
+ * Used to control if the rule-set should be affected by rtl transformation
+ */
+ flip?: boolean;
+ }
+}
+
+const styles = (theme: Theme) =>
+ createStyles({
+ flexContainer: {
+ display: 'flex',
+ alignItems: 'center',
+ boxSizing: 'border-box',
+ },
+ table: {
+ // temporary right-to-left patch, waiting for
+ // https://github.com/bvaughn/react-virtualized/issues/454
+ '& .ReactVirtualized__Table__headerRow': {
+ flip: false,
+ paddingRight: theme.direction === 'rtl' ? '0 !important' : undefined,
+ },
+ },
+ tableRow: {
+ cursor: 'pointer',
+ },
+ tableRowHover: {
+ '&:hover': {
+ backgroundColor: theme.palette.grey[200],
+ },
+ },
+ tableCell: {
+ flex: 1,
+ },
+ noClick: {
+ cursor: 'initial',
+ },
+ });
+
+interface ColumnData {
+ dataKey: string;
+ label: string;
+ numeric?: boolean;
+ width: number;
+}
+
+interface Row {
+ index: number;
+}
+
+interface MuiVirtualizedTableProps extends WithStyles {
+ columns: ColumnData[];
+ headerHeight?: number;
+ onRowClick?: () => void;
+ rowCount: number;
+ rowGetter: (row: Row) => Data;
+ rowHeight?: number;
+}
+
+class MuiVirtualizedTable extends React.PureComponent {
+ static defaultProps = {
+ headerHeight: 48,
+ rowHeight: 48,
+ };
+
+ getRowClassName = ({ index }: Row) => {
+ const { classes, onRowClick } = this.props;
+
+ return clsx(classes.tableRow, classes.flexContainer, {
+ [classes.tableRowHover]: index !== -1 && onRowClick != null,
+ });
+ };
+
+ cellRenderer: TableCellRenderer = ({ cellData, columnIndex }) => {
+ const { columns, classes, rowHeight, onRowClick } = this.props;
+ return (
+
+ {cellData}
+
+ );
+ };
+
+ headerRenderer = ({ label, columnIndex }: TableHeaderProps & { columnIndex: number }) => {
+ const { headerHeight, columns, classes } = this.props;
+
+ return (
+
+ {label}
+
+ );
+ };
+
+ render() {
+ const { classes, columns, rowHeight, headerHeight, ...tableProps } = this.props;
+ return (
+
+ {({ height, width }) => (
+
+ {columns.map(({ dataKey, ...other }, index) => {
+ return (
+
+ this.headerRenderer({
+ ...headerProps,
+ columnIndex: index,
+ })
+ }
+ className={classes.flexContainer}
+ cellRenderer={this.cellRenderer}
+ dataKey={dataKey}
+ {...other}
+ />
+ );
+ })}
+
+ )}
+
+ );
+ }
+}
+
+const VirtualizedTable = withStyles(styles)(MuiVirtualizedTable);
+
+// ---
+
+interface Data {
+ calories: number;
+ carbs: number;
+ dessert: string;
+ fat: number;
+ id: number;
+ protein: number;
+}
+type Sample = [string, number, number, number, number];
+
+const sample: Sample[] = [
+ ['Frozen yoghurt', 159, 6.0, 24, 4.0],
+ ['Ice cream sandwich', 237, 9.0, 37, 4.3],
+ ['Eclair', 262, 16.0, 24, 6.0],
+ ['Cupcake', 305, 3.7, 67, 4.3],
+ ['Gingerbread', 356, 16.0, 49, 3.9],
+];
+
+function createData(
+ id: number,
+ dessert: string,
+ calories: number,
+ fat: number,
+ carbs: number,
+ protein: number,
+): Data {
+ return { id, dessert, calories, fat, carbs, protein };
+}
+
+const rows: Data[] = [];
+
+for (let i = 0; i < 200; i += 1) {
+ const randomSelection = sample[Math.floor(Math.random() * sample.length)];
+ rows.push(createData(i, ...randomSelection));
+}
+
+export function ReactVirtualizedTable() {
+ return (
+
+ rows[index]}
+ columns={[
+ {
+ width: 200,
+ label: 'Dessert',
+ dataKey: 'dessert',
+ },
+ {
+ width: 120,
+ label: 'Calories\u00A0(g)',
+ dataKey: 'calories',
+ numeric: true,
+ },
+ {
+ width: 120,
+ label: 'Fat\u00A0(g)',
+ dataKey: 'fat',
+ numeric: true,
+ },
+ {
+ width: 120,
+ label: 'Carbs\u00A0(g)',
+ dataKey: 'carbs',
+ numeric: true,
+ },
+ {
+ width: 120,
+ label: 'Protein\u00A0(g)',
+ dataKey: 'protein',
+ numeric: true,
+ },
+ ]}
+ />
+
+ );
+}
+
+export default {
+ title: "Material-ui|tables|ReactVirtualizedTable.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tables/SimpleTable.stories.tsx b/examples/storybook/stories/material-ui/tables/SimpleTable.stories.tsx
new file mode 100644
index 00000000000000..fe794f76d922c7
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tables/SimpleTable.stories.tsx
@@ -0,0 +1,64 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableContainer from '@material-ui/core/TableContainer';
+import TableHead from '@material-ui/core/TableHead';
+import TableRow from '@material-ui/core/TableRow';
+import Paper from '@material-ui/core/Paper';
+
+const useStyles = makeStyles({
+ table: {
+ minWidth: 650,
+ },
+});
+
+function createData(name: string, calories: number, fat: number, carbs: number, protein: number) {
+ return { name, calories, fat, carbs, protein };
+}
+
+const rows = [
+ createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
+ createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
+ createData('Eclair', 262, 16.0, 24, 6.0),
+ createData('Cupcake', 305, 3.7, 67, 4.3),
+ createData('Gingerbread', 356, 16.0, 49, 3.9),
+];
+
+export function SimpleTable() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+ Dessert (100g serving)
+ Calories
+ Fat (g)
+ Carbs (g)
+ Protein (g)
+
+
+
+ {rows.map((row) => (
+
+
+ {row.name}
+
+ {row.calories}
+ {row.fat}
+ {row.carbs}
+ {row.protein}
+
+ ))}
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tables|SimpleTable.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tables/SpanningTable.stories.tsx b/examples/storybook/stories/material-ui/tables/SpanningTable.stories.tsx
new file mode 100644
index 00000000000000..8d725242389de8
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tables/SpanningTable.stories.tsx
@@ -0,0 +1,104 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableContainer from '@material-ui/core/TableContainer';
+import TableHead from '@material-ui/core/TableHead';
+import TableRow from '@material-ui/core/TableRow';
+import Paper from '@material-ui/core/Paper';
+
+const TAX_RATE = 0.07;
+
+const useStyles = makeStyles({
+ table: {
+ minWidth: 700,
+ },
+});
+
+function ccyFormat(num: number) {
+ return `${num.toFixed(2)}`;
+}
+
+function priceRow(qty: number, unit: number) {
+ return qty * unit;
+}
+
+function createRow(desc: string, qty: number, unit: number) {
+ const price = priceRow(qty, unit);
+ return { desc, qty, unit, price };
+}
+
+interface Row {
+ desc: string;
+ qty: number;
+ unit: number;
+ price: number;
+}
+
+function subtotal(items: Row[]) {
+ return items.map(({ price }) => price).reduce((sum, i) => sum + i, 0);
+}
+
+const rows = [
+ createRow('Paperclips (Box)', 100, 1.15),
+ createRow('Paper (Case)', 10, 45.99),
+ createRow('Waste Basket', 2, 17.99),
+];
+
+const invoiceSubtotal = subtotal(rows);
+const invoiceTaxes = TAX_RATE * invoiceSubtotal;
+const invoiceTotal = invoiceTaxes + invoiceSubtotal;
+
+export function SpanningTable() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+ Details
+
+ Price
+
+
+ Desc
+ Qty.
+ Unit
+ Sum
+
+
+
+ {rows.map((row) => (
+
+ {row.desc}
+ {row.qty}
+ {row.unit}
+ {ccyFormat(row.price)}
+
+ ))}
+
+
+ Subtotal
+ {ccyFormat(invoiceSubtotal)}
+
+
+ Tax
+ {`${(TAX_RATE * 100).toFixed(0)} %`}
+ {ccyFormat(invoiceTaxes)}
+
+
+ Total
+ {ccyFormat(invoiceTotal)}
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tables|SpanningTable.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tables/StickyHeadTable.stories.tsx b/examples/storybook/stories/material-ui/tables/StickyHeadTable.stories.tsx
new file mode 100644
index 00000000000000..736438d298acc0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tables/StickyHeadTable.stories.tsx
@@ -0,0 +1,150 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Paper from '@material-ui/core/Paper';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableContainer from '@material-ui/core/TableContainer';
+import TableHead from '@material-ui/core/TableHead';
+import TablePagination from '@material-ui/core/TablePagination';
+import TableRow from '@material-ui/core/TableRow';
+
+interface Column {
+ id: 'name' | 'code' | 'population' | 'size' | 'density';
+ label: string;
+ minWidth?: number;
+ align?: 'right';
+ format?: (value: number) => string;
+}
+
+const columns: Column[] = [
+ { id: 'name', label: 'Name', minWidth: 170 },
+ { id: 'code', label: 'ISO\u00a0Code', minWidth: 100 },
+ {
+ id: 'population',
+ label: 'Population',
+ minWidth: 170,
+ align: 'right',
+ format: (value: number) => value.toLocaleString('en-US'),
+ },
+ {
+ id: 'size',
+ label: 'Size\u00a0(km\u00b2)',
+ minWidth: 170,
+ align: 'right',
+ format: (value: number) => value.toLocaleString('en-US'),
+ },
+ {
+ id: 'density',
+ label: 'Density',
+ minWidth: 170,
+ align: 'right',
+ format: (value: number) => value.toFixed(2),
+ },
+];
+
+interface Data {
+ name: string;
+ code: string;
+ population: number;
+ size: number;
+ density: number;
+}
+
+function createData(name: string, code: string, population: number, size: number): Data {
+ const density = population / size;
+ return { name, code, population, size, density };
+}
+
+const rows = [
+ createData('India', 'IN', 1324171354, 3287263),
+ createData('China', 'CN', 1403500365, 9596961),
+ createData('Italy', 'IT', 60483973, 301340),
+ createData('United States', 'US', 327167434, 9833520),
+ createData('Canada', 'CA', 37602103, 9984670),
+ createData('Australia', 'AU', 25475400, 7692024),
+ createData('Germany', 'DE', 83019200, 357578),
+ createData('Ireland', 'IE', 4857000, 70273),
+ createData('Mexico', 'MX', 126577691, 1972550),
+ createData('Japan', 'JP', 126317000, 377973),
+ createData('France', 'FR', 67022000, 640679),
+ createData('United Kingdom', 'GB', 67545757, 242495),
+ createData('Russia', 'RU', 146793744, 17098246),
+ createData('Nigeria', 'NG', 200962417, 923768),
+ createData('Brazil', 'BR', 210147125, 8515767),
+];
+
+const useStyles = makeStyles({
+ root: {
+ width: '100%',
+ },
+ container: {
+ maxHeight: 440,
+ },
+});
+
+export function StickyHeadTable() {
+ const classes = useStyles();
+ const [page, setPage] = React.useState(0);
+ const [rowsPerPage, setRowsPerPage] = React.useState(10);
+
+ const handleChangePage = (event: unknown, newPage: number) => {
+ setPage(newPage);
+ };
+
+ const handleChangeRowsPerPage = (event: React.ChangeEvent) => {
+ setRowsPerPage(+event.target.value);
+ setPage(0);
+ };
+
+ return (
+
+
+
+
+
+ {columns.map((column) => (
+
+ {column.label}
+
+ ))}
+
+
+
+ {rows.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row) => {
+ return (
+
+ {columns.map((column) => {
+ const value = row[column.id];
+ return (
+
+ {column.format && typeof value === 'number' ? column.format(value) : value}
+
+ );
+ })}
+
+ );
+ })}
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tables|StickyHeadTable.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/AccessibleTabs.stories.tsx b/examples/storybook/stories/material-ui/tabs/AccessibleTabs.stories.tsx
new file mode 100644
index 00000000000000..0566183c51f25f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/AccessibleTabs.stories.tsx
@@ -0,0 +1,104 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import Typography from '@material-ui/core/Typography';
+import Box from '@material-ui/core/Box';
+
+interface TabPanelProps {
+ children?: React.ReactNode;
+ index: number;
+ value: number;
+}
+
+function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props;
+
+ return (
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ );
+}
+
+interface DemoTabsProps {
+ labelId: string;
+ onChange: (event: unknown, value: number) => void;
+ selectionFollowsFocus?: boolean;
+ value: number;
+}
+function DemoTabs(props: DemoTabsProps) {
+ const { labelId, onChange, selectionFollowsFocus, value } = props;
+
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+const useStyles = makeStyles({
+ root: {
+ flexGrow: 1,
+ },
+});
+
+export function AccessibleTabs() {
+ const classes = useStyles();
+
+ const [value, setValue] = React.useState(0);
+ const handleChange = (event: unknown, newValue: number) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+ Tabs where selection follows focus
+
+
+
+ Tabs where each tab needs to be selected manually
+
+
+
+ Item One
+
+
+ Item Two
+
+
+ Item Three
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|AccessibleTabs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/CenteredTabs.stories.tsx b/examples/storybook/stories/material-ui/tabs/CenteredTabs.stories.tsx
new file mode 100644
index 00000000000000..a457352c5e34e7
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/CenteredTabs.stories.tsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Paper from '@material-ui/core/Paper';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+
+const useStyles = makeStyles({
+ root: {
+ flexGrow: 1,
+ },
+});
+
+export function CenteredTabs() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(0);
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|CenteredTabs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/CustomizedTabs.stories.tsx b/examples/storybook/stories/material-ui/tabs/CustomizedTabs.stories.tsx
new file mode 100644
index 00000000000000..ad8549d1190750
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/CustomizedTabs.stories.tsx
@@ -0,0 +1,135 @@
+import React from 'react';
+import { makeStyles, withStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import Typography from '@material-ui/core/Typography';
+
+const AntTabs = withStyles({
+ root: {
+ borderBottom: '1px solid #e8e8e8',
+ },
+ indicator: {
+ backgroundColor: '#1890ff',
+ },
+})(Tabs);
+
+const AntTab = withStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ textTransform: 'none',
+ minWidth: 72,
+ fontWeight: theme.typography.fontWeightRegular,
+ marginRight: theme.spacing(4),
+ fontFamily: [
+ '-apple-system',
+ 'BlinkMacSystemFont',
+ '"Segoe UI"',
+ 'Roboto',
+ '"Helvetica Neue"',
+ 'Arial',
+ 'sans-serif',
+ '"Apple Color Emoji"',
+ '"Segoe UI Emoji"',
+ '"Segoe UI Symbol"',
+ ].join(','),
+ '&:hover': {
+ color: '#40a9ff',
+ opacity: 1,
+ },
+ '&$selected': {
+ color: '#1890ff',
+ fontWeight: theme.typography.fontWeightMedium,
+ },
+ '&:focus': {
+ color: '#40a9ff',
+ },
+ },
+ selected: {},
+ }),
+)((props: StyledTabProps) => );
+
+interface StyledTabsProps {
+ value: number;
+ onChange: (event: React.ChangeEvent<{}>, newValue: number) => void;
+}
+
+const StyledTabs = withStyles({
+ indicator: {
+ display: 'flex',
+ justifyContent: 'center',
+ backgroundColor: 'transparent',
+ '& > span': {
+ maxWidth: 40,
+ width: '100%',
+ backgroundColor: '#635ee7',
+ },
+ },
+})((props: StyledTabsProps) => }} />);
+
+interface StyledTabProps {
+ label: string;
+}
+
+const StyledTab = withStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ textTransform: 'none',
+ color: '#fff',
+ fontWeight: theme.typography.fontWeightRegular,
+ fontSize: theme.typography.pxToRem(15),
+ marginRight: theme.spacing(1),
+ '&:focus': {
+ opacity: 1,
+ },
+ },
+ }),
+)((props: StyledTabProps) => );
+
+const useStyles = makeStyles((theme: Theme) => ({
+ root: {
+ flexGrow: 1,
+ },
+ padding: {
+ padding: theme.spacing(3),
+ },
+ demo1: {
+ backgroundColor: theme.palette.background.paper,
+ },
+ demo2: {
+ backgroundColor: '#2e1534',
+ },
+}));
+
+export function CustomizedTabs() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(0);
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
+ setValue(newValue);
+ };
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|CustomizedTabs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/DisabledTabs.stories.tsx b/examples/storybook/stories/material-ui/tabs/DisabledTabs.stories.tsx
new file mode 100644
index 00000000000000..a8b944e368a61f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/DisabledTabs.stories.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import Paper from '@material-ui/core/Paper';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+
+export function DisabledTabs() {
+ const [value, setValue] = React.useState(2);
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|DisabledTabs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/FullWidthTabs.stories.tsx b/examples/storybook/stories/material-ui/tabs/FullWidthTabs.stories.tsx
new file mode 100644
index 00000000000000..19bfdfcadcf29e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/FullWidthTabs.stories.tsx
@@ -0,0 +1,101 @@
+import React from 'react';
+import SwipeableViews from 'react-swipeable-views';
+import { makeStyles, Theme, useTheme } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import Typography from '@material-ui/core/Typography';
+import Box from '@material-ui/core/Box';
+
+interface TabPanelProps {
+ children?: React.ReactNode;
+ dir?: string;
+ index: any;
+ value: any;
+}
+
+function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props;
+
+ return (
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ );
+}
+
+function a11yProps(index: any) {
+ return {
+ id: `full-width-tab-${index}`,
+ 'aria-controls': `full-width-tabpanel-${index}`,
+ };
+}
+
+const useStyles = makeStyles((theme: Theme) => ({
+ root: {
+ backgroundColor: theme.palette.background.paper,
+ width: 500,
+ },
+}));
+
+export function FullWidthTabs() {
+ const classes = useStyles();
+ const theme = useTheme();
+ const [value, setValue] = React.useState(0);
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
+ setValue(newValue);
+ };
+
+ const handleChangeIndex = (index: number) => {
+ setValue(index);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ Item One
+
+
+ Item Two
+
+
+ Item Three
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|FullWidthTabs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/IconLabelTabs.stories.tsx b/examples/storybook/stories/material-ui/tabs/IconLabelTabs.stories.tsx
new file mode 100644
index 00000000000000..b541b36c0c0dd6
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/IconLabelTabs.stories.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import Paper from '@material-ui/core/Paper';
+import { makeStyles } from '@material-ui/core/styles';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import PhoneIcon from '@material-ui/icons/Phone';
+import FavoriteIcon from '@material-ui/icons/Favorite';
+import PersonPinIcon from '@material-ui/icons/PersonPin';
+
+const useStyles = makeStyles({
+ root: {
+ flexGrow: 1,
+ maxWidth: 500,
+ },
+});
+
+export function IconLabelTabs() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(0);
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+ } label="RECENTS" />
+ } label="FAVORITES" />
+ } label="NEARBY" />
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|IconLabelTabs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/IconTabs.stories.tsx b/examples/storybook/stories/material-ui/tabs/IconTabs.stories.tsx
new file mode 100644
index 00000000000000..628d14c409500d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/IconTabs.stories.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Paper from '@material-ui/core/Paper';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import PhoneIcon from '@material-ui/icons/Phone';
+import FavoriteIcon from '@material-ui/icons/Favorite';
+import PersonPinIcon from '@material-ui/icons/PersonPin';
+
+const useStyles = makeStyles({
+ root: {
+ flexGrow: 1,
+ maxWidth: 500,
+ },
+});
+
+export function IconTabs() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(0);
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+ } aria-label="phone" />
+ } aria-label="favorite" />
+ } aria-label="person" />
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|IconTabs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/LabTabs.stories.tsx b/examples/storybook/stories/material-ui/tabs/LabTabs.stories.tsx
new file mode 100644
index 00000000000000..cec5fd222c3d4b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/LabTabs.stories.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import { makeStyles, Theme } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Tab from '@material-ui/core/Tab';
+import TabContext from '@material-ui/lab/TabContext';
+import TabList from '@material-ui/lab/TabList';
+import TabPanel from '@material-ui/lab/TabPanel';
+
+const useStyles = makeStyles((theme: Theme) => ({
+ root: {
+ flexGrow: 1,
+ backgroundColor: theme.palette.background.paper,
+ },
+}));
+
+export function LabTabs() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState('1');
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: string) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+ Item One
+ Item Two
+ Item Three
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|LabTabs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/NavTabs.stories.tsx b/examples/storybook/stories/material-ui/tabs/NavTabs.stories.tsx
new file mode 100644
index 00000000000000..0e5a90f914bc8a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/NavTabs.stories.tsx
@@ -0,0 +1,103 @@
+import React from 'react';
+import { makeStyles, Theme } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import Typography from '@material-ui/core/Typography';
+import Box from '@material-ui/core/Box';
+
+interface TabPanelProps {
+ children?: React.ReactNode;
+ index: any;
+ value: any;
+}
+
+function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props;
+
+ return (
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ );
+}
+
+function a11yProps(index: any) {
+ return {
+ id: `nav-tab-${index}`,
+ 'aria-controls': `nav-tabpanel-${index}`,
+ };
+}
+
+interface LinkTabProps {
+ label?: string;
+ href?: string;
+}
+
+function LinkTab(props: LinkTabProps) {
+ return (
+ ) => {
+ event.preventDefault();
+ }}
+ {...props}
+ />
+ );
+}
+
+const useStyles = makeStyles((theme: Theme) => ({
+ root: {
+ flexGrow: 1,
+ backgroundColor: theme.palette.background.paper,
+ },
+}));
+
+export function NavTabs() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(0);
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+ Page One
+
+
+ Page Two
+
+
+ Page Three
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|NavTabs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/ScrollableTabsButtonAuto.stories.tsx b/examples/storybook/stories/material-ui/tabs/ScrollableTabsButtonAuto.stories.tsx
new file mode 100644
index 00000000000000..9d020f21111083
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/ScrollableTabsButtonAuto.stories.tsx
@@ -0,0 +1,106 @@
+import React from 'react';
+import { makeStyles, Theme } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import Typography from '@material-ui/core/Typography';
+import Box from '@material-ui/core/Box';
+
+interface TabPanelProps {
+ children?: React.ReactNode;
+ index: any;
+ value: any;
+}
+
+function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props;
+
+ return (
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ );
+}
+
+function a11yProps(index: any) {
+ return {
+ id: `scrollable-auto-tab-${index}`,
+ 'aria-controls': `scrollable-auto-tabpanel-${index}`,
+ };
+}
+
+const useStyles = makeStyles((theme: Theme) => ({
+ root: {
+ flexGrow: 1,
+ width: '100%',
+ backgroundColor: theme.palette.background.paper,
+ },
+}));
+
+export function ScrollableTabsButtonAuto() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(0);
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Item One
+
+
+ Item Two
+
+
+ Item Three
+
+
+ Item Four
+
+
+ Item Five
+
+
+ Item Six
+
+
+ Item Seven
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|ScrollableTabsButtonAuto.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/ScrollableTabsButtonForce.stories.tsx b/examples/storybook/stories/material-ui/tabs/ScrollableTabsButtonForce.stories.tsx
new file mode 100644
index 00000000000000..4525a82b0473e0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/ScrollableTabsButtonForce.stories.tsx
@@ -0,0 +1,113 @@
+import React from 'react';
+import { makeStyles, Theme } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import PhoneIcon from '@material-ui/icons/Phone';
+import FavoriteIcon from '@material-ui/icons/Favorite';
+import PersonPinIcon from '@material-ui/icons/PersonPin';
+import HelpIcon from '@material-ui/icons/Help';
+import ShoppingBasket from '@material-ui/icons/ShoppingBasket';
+import ThumbDown from '@material-ui/icons/ThumbDown';
+import ThumbUp from '@material-ui/icons/ThumbUp';
+import Typography from '@material-ui/core/Typography';
+import Box from '@material-ui/core/Box';
+
+interface TabPanelProps {
+ children?: React.ReactNode;
+ index: any;
+ value: any;
+}
+
+function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props;
+
+ return (
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ );
+}
+
+function a11yProps(index: any) {
+ return {
+ id: `scrollable-force-tab-${index}`,
+ 'aria-controls': `scrollable-force-tabpanel-${index}`,
+ };
+}
+
+const useStyles = makeStyles((theme: Theme) => ({
+ root: {
+ flexGrow: 1,
+ width: '100%',
+ backgroundColor: theme.palette.background.paper,
+ },
+}));
+
+export function ScrollableTabsButtonForce() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(0);
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+
+ } {...a11yProps(0)} />
+ } {...a11yProps(1)} />
+ } {...a11yProps(2)} />
+ } {...a11yProps(3)} />
+ } {...a11yProps(4)} />
+ } {...a11yProps(5)} />
+ } {...a11yProps(6)} />
+
+
+
+ Item One
+
+
+ Item Two
+
+
+ Item Three
+
+
+ Item Four
+
+
+ Item Five
+
+
+ Item Six
+
+
+ Item Seven
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|ScrollableTabsButtonForce.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/ScrollableTabsButtonPrevent.stories.tsx b/examples/storybook/stories/material-ui/tabs/ScrollableTabsButtonPrevent.stories.tsx
new file mode 100644
index 00000000000000..eabd1443794ffc
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/ScrollableTabsButtonPrevent.stories.tsx
@@ -0,0 +1,111 @@
+import React from 'react';
+import { makeStyles, Theme } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import PhoneIcon from '@material-ui/icons/Phone';
+import FavoriteIcon from '@material-ui/icons/Favorite';
+import PersonPinIcon from '@material-ui/icons/PersonPin';
+import HelpIcon from '@material-ui/icons/Help';
+import ShoppingBasket from '@material-ui/icons/ShoppingBasket';
+import ThumbDown from '@material-ui/icons/ThumbDown';
+import ThumbUp from '@material-ui/icons/ThumbUp';
+import Typography from '@material-ui/core/Typography';
+import Box from '@material-ui/core/Box';
+
+interface TabPanelProps {
+ children?: React.ReactNode;
+ index: any;
+ value: any;
+}
+
+function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props;
+
+ return (
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ );
+}
+
+function a11yProps(index: any) {
+ return {
+ id: `scrollable-prevent-tab-${index}`,
+ 'aria-controls': `scrollable-prevent-tabpanel-${index}`,
+ };
+}
+
+const useStyles = makeStyles((theme: Theme) => ({
+ root: {
+ flexGrow: 1,
+ width: '100%',
+ backgroundColor: theme.palette.background.paper,
+ },
+}));
+
+export function ScrollableTabsButtonPrevent() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(0);
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+
+ } aria-label="phone" {...a11yProps(0)} />
+ } aria-label="favorite" {...a11yProps(1)} />
+ } aria-label="person" {...a11yProps(2)} />
+ } aria-label="help" {...a11yProps(3)} />
+ } aria-label="shopping" {...a11yProps(4)} />
+ } aria-label="up" {...a11yProps(5)} />
+ } aria-label="down" {...a11yProps(6)} />
+
+
+
+ Item One
+
+
+ Item Two
+
+
+ Item Three
+
+
+ Item Four
+
+
+ Item Five
+
+
+ Item Six
+
+
+ Item Seven
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|ScrollableTabsButtonPrevent.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/SimpleTabs.stories.tsx b/examples/storybook/stories/material-ui/tabs/SimpleTabs.stories.tsx
new file mode 100644
index 00000000000000..0e0477edd130ba
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/SimpleTabs.stories.tsx
@@ -0,0 +1,81 @@
+import React from 'react';
+import { makeStyles, Theme } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import Typography from '@material-ui/core/Typography';
+import Box from '@material-ui/core/Box';
+
+interface TabPanelProps {
+ children?: React.ReactNode;
+ index: any;
+ value: any;
+}
+
+function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props;
+
+ return (
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ );
+}
+
+function a11yProps(index: any) {
+ return {
+ id: `simple-tab-${index}`,
+ 'aria-controls': `simple-tabpanel-${index}`,
+ };
+}
+
+const useStyles = makeStyles((theme: Theme) => ({
+ root: {
+ flexGrow: 1,
+ backgroundColor: theme.palette.background.paper,
+ },
+}));
+
+export function SimpleTabs() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(0);
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+ Item One
+
+
+ Item Two
+
+
+ Item Three
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|SimpleTabs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/TabsWrappedLabel.stories.tsx b/examples/storybook/stories/material-ui/tabs/TabsWrappedLabel.stories.tsx
new file mode 100644
index 00000000000000..09432ab0b5b2ad
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/TabsWrappedLabel.stories.tsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import { makeStyles, Theme } from '@material-ui/core/styles';
+import AppBar from '@material-ui/core/AppBar';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import Typography from '@material-ui/core/Typography';
+import Box from '@material-ui/core/Box';
+
+interface TabPanelProps {
+ children?: React.ReactNode;
+ index: any;
+ value: any;
+}
+
+function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props;
+
+ return (
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ );
+}
+
+function a11yProps(index: any) {
+ return {
+ id: `wrapped-tab-${index}`,
+ 'aria-controls': `wrapped-tabpanel-${index}`,
+ };
+}
+
+const useStyles = makeStyles((theme: Theme) => ({
+ root: {
+ flexGrow: 1,
+ backgroundColor: theme.palette.background.paper,
+ },
+}));
+
+export function TabsWrappedLabel() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState('one');
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: string) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+ Item One
+
+
+ Item Two
+
+
+ Item Three
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|TabsWrappedLabel.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tabs/VerticalTabs.stories.tsx b/examples/storybook/stories/material-ui/tabs/VerticalTabs.stories.tsx
new file mode 100644
index 00000000000000..a96be0baf55bff
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tabs/VerticalTabs.stories.tsx
@@ -0,0 +1,106 @@
+import React from 'react';
+import { makeStyles, Theme } from '@material-ui/core/styles';
+import Tabs from '@material-ui/core/Tabs';
+import Tab from '@material-ui/core/Tab';
+import Typography from '@material-ui/core/Typography';
+import Box from '@material-ui/core/Box';
+
+interface TabPanelProps {
+ children?: React.ReactNode;
+ index: any;
+ value: any;
+}
+
+function TabPanel(props: TabPanelProps) {
+ const { children, value, index, ...other } = props;
+
+ return (
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ );
+}
+
+function a11yProps(index: any) {
+ return {
+ id: `vertical-tab-${index}`,
+ 'aria-controls': `vertical-tabpanel-${index}`,
+ };
+}
+
+const useStyles = makeStyles((theme: Theme) => ({
+ root: {
+ flexGrow: 1,
+ backgroundColor: theme.palette.background.paper,
+ display: 'flex',
+ height: 224,
+ },
+ tabs: {
+ borderRight: `1px solid ${theme.palette.divider}`,
+ },
+}));
+
+export function VerticalTabs() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState(0);
+
+ const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
+ setValue(newValue);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ Item One
+
+
+ Item Two
+
+
+ Item Three
+
+
+ Item Four
+
+
+ Item Five
+
+
+ Item Six
+
+
+ Item Seven
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tabs|VerticalTabs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/BasicTextFields.stories.tsx b/examples/storybook/stories/material-ui/text-fields/BasicTextFields.stories.tsx
new file mode 100644
index 00000000000000..40c252b2830c42
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/BasicTextFields.stories.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ width: '25ch',
+ },
+ },
+ }),
+);
+
+export function BasicTextFields() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|BasicTextFields.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/ColorTextFields.stories.tsx b/examples/storybook/stories/material-ui/text-fields/ColorTextFields.stories.tsx
new file mode 100644
index 00000000000000..76c968d057fc6a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/ColorTextFields.stories.tsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ width: '25ch',
+ },
+ },
+ }),
+);
+
+export function ColorTextFields() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|ColorTextFields.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/ComposedTextField.stories.tsx b/examples/storybook/stories/material-ui/text-fields/ComposedTextField.stories.tsx
new file mode 100644
index 00000000000000..d91af0b93bacb0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/ComposedTextField.stories.tsx
@@ -0,0 +1,73 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import FilledInput from '@material-ui/core/FilledInput';
+import FormControl from '@material-ui/core/FormControl';
+import FormHelperText from '@material-ui/core/FormHelperText';
+import Input from '@material-ui/core/Input';
+import InputLabel from '@material-ui/core/InputLabel';
+import OutlinedInput from '@material-ui/core/OutlinedInput';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function ComposedTextField() {
+ const [name, setName] = React.useState('Composed TextField');
+ const classes = useStyles();
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setName(event.target.value);
+ };
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|ComposedTextField.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/CustomizedInputBase.stories.tsx b/examples/storybook/stories/material-ui/text-fields/CustomizedInputBase.stories.tsx
new file mode 100644
index 00000000000000..d984baf8d5878c
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/CustomizedInputBase.stories.tsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Paper from '@material-ui/core/Paper';
+import InputBase from '@material-ui/core/InputBase';
+import Divider from '@material-ui/core/Divider';
+import IconButton from '@material-ui/core/IconButton';
+import MenuIcon from '@material-ui/icons/Menu';
+import SearchIcon from '@material-ui/icons/Search';
+import DirectionsIcon from '@material-ui/icons/Directions';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ padding: '2px 4px',
+ display: 'flex',
+ alignItems: 'center',
+ width: 400,
+ },
+ input: {
+ marginLeft: theme.spacing(1),
+ flex: 1,
+ },
+ iconButton: {
+ padding: 10,
+ },
+ divider: {
+ height: 28,
+ margin: 4,
+ },
+ }),
+);
+
+export function CustomizedInputBase() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|CustomizedInputBase.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/CustomizedInputs.stories.tsx b/examples/storybook/stories/material-ui/text-fields/CustomizedInputs.stories.tsx
new file mode 100644
index 00000000000000..b1f03542514530
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/CustomizedInputs.stories.tsx
@@ -0,0 +1,201 @@
+import React from 'react';
+import {
+ createStyles,
+ fade,
+ Theme,
+ ThemeProvider,
+ withStyles,
+ makeStyles,
+ createMuiTheme,
+} from '@material-ui/core/styles';
+import InputBase from '@material-ui/core/InputBase';
+import InputLabel from '@material-ui/core/InputLabel';
+import TextField, { TextFieldProps } from '@material-ui/core/TextField';
+import FormControl from '@material-ui/core/FormControl';
+import { green } from '@material-ui/core/colors';
+import { OutlinedInputProps } from '@material-ui/core/OutlinedInput';
+
+const CssTextField = withStyles({
+ root: {
+ '& label.Mui-focused': {
+ color: 'green',
+ },
+ '& .MuiInput-underline:after': {
+ borderBottomColor: 'green',
+ },
+ '& .MuiOutlinedInput-root': {
+ '& fieldset': {
+ borderColor: 'red',
+ },
+ '&:hover fieldset': {
+ borderColor: 'yellow',
+ },
+ '&.Mui-focused fieldset': {
+ borderColor: 'green',
+ },
+ },
+ },
+})(TextField);
+
+const BootstrapInput = withStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ 'label + &': {
+ marginTop: theme.spacing(3),
+ },
+ },
+ input: {
+ borderRadius: 4,
+ position: 'relative',
+ backgroundColor: theme.palette.common.white,
+ border: '1px solid #ced4da',
+ fontSize: 16,
+ width: 'auto',
+ padding: '10px 12px',
+ transition: theme.transitions.create(['border-color', 'box-shadow']),
+ // Use the system font instead of the default Roboto font.
+ fontFamily: [
+ '-apple-system',
+ 'BlinkMacSystemFont',
+ '"Segoe UI"',
+ 'Roboto',
+ '"Helvetica Neue"',
+ 'Arial',
+ 'sans-serif',
+ '"Apple Color Emoji"',
+ '"Segoe UI Emoji"',
+ '"Segoe UI Symbol"',
+ ].join(','),
+ '&:focus': {
+ boxShadow: `${fade(theme.palette.primary.main, 0.25)} 0 0 0 0.2rem`,
+ borderColor: theme.palette.primary.main,
+ },
+ },
+ }),
+)(InputBase);
+
+const useStylesReddit = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ border: '1px solid #e2e2e1',
+ overflow: 'hidden',
+ borderRadius: 4,
+ backgroundColor: '#fcfcfb',
+ transition: theme.transitions.create(['border-color', 'box-shadow']),
+ '&:hover': {
+ backgroundColor: '#fff',
+ },
+ '&$focused': {
+ backgroundColor: '#fff',
+ boxShadow: `${fade(theme.palette.primary.main, 0.25)} 0 0 0 2px`,
+ borderColor: theme.palette.primary.main,
+ },
+ },
+ focused: {},
+ }),
+);
+
+function RedditTextField(props: TextFieldProps) {
+ const classes = useStylesReddit();
+
+ return (
+ }
+ {...props}
+ />
+ );
+}
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ },
+ margin: {
+ margin: theme.spacing(1),
+ },
+ }),
+);
+
+const ValidationTextField = withStyles({
+ root: {
+ '& input:valid + fieldset': {
+ borderColor: 'green',
+ borderWidth: 2,
+ },
+ '& input:invalid + fieldset': {
+ borderColor: 'red',
+ borderWidth: 2,
+ },
+ '& input:valid:focus + fieldset': {
+ borderLeftWidth: 6,
+ padding: '4px !important', // override inline-style
+ },
+ },
+})(TextField);
+
+const theme = createMuiTheme({
+ palette: {
+ primary: green,
+ },
+});
+
+export function CustomizedInputs() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|CustomizedInputs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/FormPropsTextFields.stories.tsx b/examples/storybook/stories/material-ui/text-fields/FormPropsTextFields.stories.tsx
new file mode 100644
index 00000000000000..bb2ab93d7b1e4a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/FormPropsTextFields.stories.tsx
@@ -0,0 +1,158 @@
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& .MuiTextField-root': {
+ margin: theme.spacing(1),
+ width: '25ch',
+ },
+ },
+ }),
+);
+
+export function FormPropsTextFields() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|FormPropsTextFields.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/FormattedInputs.stories.tsx b/examples/storybook/stories/material-ui/text-fields/FormattedInputs.stories.tsx
new file mode 100644
index 00000000000000..ff3f9f4738ff64
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/FormattedInputs.stories.tsx
@@ -0,0 +1,115 @@
+import React from 'react';
+import MaskedInput from 'react-text-mask';
+import NumberFormat from 'react-number-format';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Input from '@material-ui/core/Input';
+import InputLabel from '@material-ui/core/InputLabel';
+import TextField from '@material-ui/core/TextField';
+import FormControl from '@material-ui/core/FormControl';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+interface TextMaskCustomProps {
+ inputRef: (ref: HTMLInputElement | null) => void;
+}
+
+function TextMaskCustom(props: TextMaskCustomProps) {
+ const { inputRef, ...other } = props;
+
+ return (
+ {
+ inputRef(ref ? ref.inputElement : null);
+ }}
+ mask={['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]}
+ placeholderChar={'\u2000'}
+ showMask
+ />
+ );
+}
+
+interface NumberFormatCustomProps {
+ inputRef: (instance: NumberFormat | null) => void;
+ onChange: (event: { target: { name: string; value: string } }) => void;
+ name: string;
+}
+
+function NumberFormatCustom(props: NumberFormatCustomProps) {
+ const { inputRef, onChange, ...other } = props;
+
+ return (
+ {
+ onChange({
+ target: {
+ name: props.name,
+ value: values.value,
+ },
+ });
+ }}
+ thousandSeparator
+ isNumericString
+ prefix="$"
+ />
+ );
+}
+
+interface State {
+ textmask: string;
+ numberformat: string;
+}
+
+export function FormattedInputs() {
+ const classes = useStyles();
+ const [values, setValues] = React.useState({
+ textmask: '(1 ) - ',
+ numberformat: '1320',
+ });
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setValues({
+ ...values,
+ [event.target.name]: event.target.value,
+ });
+ };
+
+ return (
+
+
+ react-text-mask
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|FormattedInputs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/InputAdornments.stories.tsx b/examples/storybook/stories/material-ui/text-fields/InputAdornments.stories.tsx
new file mode 100644
index 00000000000000..40b911eec22898
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/InputAdornments.stories.tsx
@@ -0,0 +1,235 @@
+import React from 'react';
+import clsx from 'clsx';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import IconButton from '@material-ui/core/IconButton';
+import Input from '@material-ui/core/Input';
+import FilledInput from '@material-ui/core/FilledInput';
+import OutlinedInput from '@material-ui/core/OutlinedInput';
+import InputLabel from '@material-ui/core/InputLabel';
+import InputAdornment from '@material-ui/core/InputAdornment';
+import FormHelperText from '@material-ui/core/FormHelperText';
+import FormControl from '@material-ui/core/FormControl';
+import TextField from '@material-ui/core/TextField';
+import Visibility from '@material-ui/icons/Visibility';
+import VisibilityOff from '@material-ui/icons/VisibilityOff';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ },
+ margin: {
+ margin: theme.spacing(1),
+ },
+ withoutLabel: {
+ marginTop: theme.spacing(3),
+ },
+ textField: {
+ width: '25ch',
+ },
+ }),
+);
+
+interface State {
+ amount: string;
+ password: string;
+ weight: string;
+ weightRange: string;
+ showPassword: boolean;
+}
+
+export function InputAdornments() {
+ const classes = useStyles();
+ const [values, setValues] = React.useState({
+ amount: '',
+ password: '',
+ weight: '',
+ weightRange: '',
+ showPassword: false,
+ });
+
+ const handleChange = (prop: keyof State) => (event: React.ChangeEvent) => {
+ setValues({ ...values, [prop]: event.target.value });
+ };
+
+ const handleClickShowPassword = () => {
+ setValues({ ...values, showPassword: !values.showPassword });
+ };
+
+ const handleMouseDownPassword = (event: React.MouseEvent) => {
+ event.preventDefault();
+ };
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|InputAdornments.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/InputWithIcon.stories.tsx b/examples/storybook/stories/material-ui/text-fields/InputWithIcon.stories.tsx
new file mode 100644
index 00000000000000..e6ab56aa6b8cb9
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/InputWithIcon.stories.tsx
@@ -0,0 +1,63 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Input from '@material-ui/core/Input';
+import InputLabel from '@material-ui/core/InputLabel';
+import InputAdornment from '@material-ui/core/InputAdornment';
+import FormControl from '@material-ui/core/FormControl';
+import TextField from '@material-ui/core/TextField';
+import Grid from '@material-ui/core/Grid';
+import AccountCircle from '@material-ui/icons/AccountCircle';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ margin: {
+ margin: theme.spacing(1),
+ },
+ }),
+);
+
+export function InputWithIcon() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|InputWithIcon.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/Inputs.stories.tsx b/examples/storybook/stories/material-ui/text-fields/Inputs.stories.tsx
new file mode 100644
index 00000000000000..9032a8979b239f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/Inputs.stories.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { createStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Input from '@material-ui/core/Input';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
+export function Inputs() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|Inputs.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/LayoutTextFields.stories.tsx b/examples/storybook/stories/material-ui/text-fields/LayoutTextFields.stories.tsx
new file mode 100644
index 00000000000000..f3ff3231c08e4f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/LayoutTextFields.stories.tsx
@@ -0,0 +1,149 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ },
+ textField: {
+ marginLeft: theme.spacing(1),
+ marginRight: theme.spacing(1),
+ width: '25ch',
+ },
+ }),
+);
+
+export function LayoutTextFields() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|LayoutTextFields.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/MultilineTextFields.stories.tsx b/examples/storybook/stories/material-ui/text-fields/MultilineTextFields.stories.tsx
new file mode 100644
index 00000000000000..3d9c1abb7d5192
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/MultilineTextFields.stories.tsx
@@ -0,0 +1,107 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& .MuiTextField-root': {
+ margin: theme.spacing(1),
+ width: '25ch',
+ },
+ },
+ }),
+);
+
+export function MultilineTextFields() {
+ const classes = useStyles();
+ const [value, setValue] = React.useState('Controlled');
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setValue(event.target.value);
+ };
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|MultilineTextFields.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/SelectTextFields.stories.tsx b/examples/storybook/stories/material-ui/text-fields/SelectTextFields.stories.tsx
new file mode 100644
index 00000000000000..392f26e349ccd0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/SelectTextFields.stories.tsx
@@ -0,0 +1,155 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+import MenuItem from '@material-ui/core/MenuItem';
+
+const currencies = [
+ {
+ value: 'USD',
+ label: '$',
+ },
+ {
+ value: 'EUR',
+ label: '€',
+ },
+ {
+ value: 'BTC',
+ label: '฿',
+ },
+ {
+ value: 'JPY',
+ label: '¥',
+ },
+];
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& .MuiTextField-root': {
+ margin: theme.spacing(1),
+ width: '25ch',
+ },
+ },
+ }),
+);
+
+export function MultilineTextFields() {
+ const classes = useStyles();
+ const [currency, setCurrency] = React.useState('EUR');
+
+ const handleChange = (event: React.ChangeEvent) => {
+ setCurrency(event.target.value);
+ };
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|SelectTextFields.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/StateTextFields.stories.tsx b/examples/storybook/stories/material-ui/text-fields/StateTextFields.stories.tsx
new file mode 100644
index 00000000000000..a66ae45c805204
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/StateTextFields.stories.tsx
@@ -0,0 +1,65 @@
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& .MuiTextField-root': {
+ margin: theme.spacing(1),
+ width: '25ch',
+ },
+ },
+ }),
+);
+
+export function StateTextFields() {
+ const classes = useStyles();
+ const [name, setName] = React.useState('Cat in the Hat');
+ const handleChange = (event: React.ChangeEvent) => {
+ setName(event.target.value);
+ };
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|StateTextFields.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/TextFieldSizes.stories.tsx b/examples/storybook/stories/material-ui/text-fields/TextFieldSizes.stories.tsx
new file mode 100644
index 00000000000000..47d8c5c00247ed
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/TextFieldSizes.stories.tsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+import TextField from '@material-ui/core/TextField';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& .MuiTextField-root': {
+ margin: theme.spacing(1),
+ width: 200,
+ },
+ },
+ }),
+);
+
+export function TextFieldSizes() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|TextFieldSizes.stories"
+};
diff --git a/examples/storybook/stories/material-ui/text-fields/ValidationTextFields.stories.tsx b/examples/storybook/stories/material-ui/text-fields/ValidationTextFields.stories.tsx
new file mode 100644
index 00000000000000..367e91da80808f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/text-fields/ValidationTextFields.stories.tsx
@@ -0,0 +1,71 @@
+import React from 'react';
+import TextField from '@material-ui/core/TextField';
+import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& .MuiTextField-root': {
+ margin: theme.spacing(1),
+ width: 200,
+ },
+ },
+ }),
+);
+
+export function ValidationTextFields() {
+ const classes = useStyles();
+
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|text-fields|ValidationTextFields.stories"
+};
diff --git a/examples/storybook/stories/material-ui/textarea-autosize/EmptyTextarea.stories.tsx b/examples/storybook/stories/material-ui/textarea-autosize/EmptyTextarea.stories.tsx
new file mode 100644
index 00000000000000..b98ce28eb90841
--- /dev/null
+++ b/examples/storybook/stories/material-ui/textarea-autosize/EmptyTextarea.stories.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import TextareaAutosize from '@material-ui/core/TextareaAutosize';
+
+export function EmptyTextarea() {
+ return ;
+}
+
+export default {
+ title: "Material-ui|textarea-autosize|EmptyTextarea.stories"
+};
diff --git a/examples/storybook/stories/material-ui/textarea-autosize/MaxHeightTextarea.stories.tsx b/examples/storybook/stories/material-ui/textarea-autosize/MaxHeightTextarea.stories.tsx
new file mode 100644
index 00000000000000..2e3b5074959fd2
--- /dev/null
+++ b/examples/storybook/stories/material-ui/textarea-autosize/MaxHeightTextarea.stories.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import TextareaAutosize from '@material-ui/core/TextareaAutosize';
+
+export function MaxHeightTextarea() {
+ return (
+
+ );
+}
+
+export default {
+ title: "Material-ui|textarea-autosize|MaxHeightTextarea.stories"
+};
diff --git a/examples/storybook/stories/material-ui/textarea-autosize/MinHeightTextarea.stories.tsx b/examples/storybook/stories/material-ui/textarea-autosize/MinHeightTextarea.stories.tsx
new file mode 100644
index 00000000000000..66900da324234e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/textarea-autosize/MinHeightTextarea.stories.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import TextareaAutosize from '@material-ui/core/TextareaAutosize';
+
+export function MinHeightTextarea() {
+ return ;
+}
+
+export default {
+ title: "Material-ui|textarea-autosize|MinHeightTextarea.stories"
+};
diff --git a/examples/storybook/stories/material-ui/toggle-button/CustomizedDividers.stories.tsx b/examples/storybook/stories/material-ui/toggle-button/CustomizedDividers.stories.tsx
new file mode 100644
index 00000000000000..d96673186eb7b4
--- /dev/null
+++ b/examples/storybook/stories/material-ui/toggle-button/CustomizedDividers.stories.tsx
@@ -0,0 +1,108 @@
+import React from 'react';
+import { makeStyles, withStyles, Theme, createStyles } from '@material-ui/core/styles';
+import FormatAlignLeftIcon from '@material-ui/icons/FormatAlignLeft';
+import FormatAlignCenterIcon from '@material-ui/icons/FormatAlignCenter';
+import FormatAlignRightIcon from '@material-ui/icons/FormatAlignRight';
+import FormatAlignJustifyIcon from '@material-ui/icons/FormatAlignJustify';
+import FormatBoldIcon from '@material-ui/icons/FormatBold';
+import FormatItalicIcon from '@material-ui/icons/FormatItalic';
+import FormatUnderlinedIcon from '@material-ui/icons/FormatUnderlined';
+import FormatColorFillIcon from '@material-ui/icons/FormatColorFill';
+import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
+import Divider from '@material-ui/core/Divider';
+import Paper from '@material-ui/core/Paper';
+import ToggleButton from '@material-ui/lab/ToggleButton';
+import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ paper: {
+ display: 'flex',
+ border: `1px solid ${theme.palette.divider}`,
+ flexWrap: 'wrap',
+ },
+ divider: {
+ margin: theme.spacing(1, 0.5),
+ },
+ }),
+);
+
+const StyledToggleButtonGroup = withStyles((theme) => ({
+ grouped: {
+ margin: theme.spacing(0.5),
+ border: 'none',
+ '&:not(:first-child)': {
+ borderRadius: theme.shape.borderRadius,
+ },
+ '&:first-child': {
+ borderRadius: theme.shape.borderRadius,
+ },
+ },
+}))(ToggleButtonGroup);
+
+export function CustomizedDividers() {
+ const [alignment, setAlignment] = React.useState('left');
+ const [formats, setFormats] = React.useState(() => ['italic']);
+
+ const handleFormat = (event: React.MouseEvent, newFormats: string[]) => {
+ setFormats(newFormats);
+ };
+
+ const handleAlignment = (event: React.MouseEvent, newAlignment: string) => {
+ setAlignment(newAlignment);
+ };
+
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|toggle-button|CustomizedDividers.stories"
+};
diff --git a/examples/storybook/stories/material-ui/toggle-button/StandaloneToggleButton.stories.tsx b/examples/storybook/stories/material-ui/toggle-button/StandaloneToggleButton.stories.tsx
new file mode 100644
index 00000000000000..dfc9414a5f208d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/toggle-button/StandaloneToggleButton.stories.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import CheckIcon from '@material-ui/icons/Check';
+import ToggleButton from '@material-ui/lab/ToggleButton';
+
+export function StandaloneToggleButton() {
+ const [selected, setSelected] = React.useState(false);
+
+ return (
+ {
+ setSelected(!selected);
+ }}
+ >
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|toggle-button|StandaloneToggleButton.stories"
+};
diff --git a/examples/storybook/stories/material-ui/toggle-button/ToggleButtonNotEmpty.stories.tsx b/examples/storybook/stories/material-ui/toggle-button/ToggleButtonNotEmpty.stories.tsx
new file mode 100644
index 00000000000000..4e17d5406f9d07
--- /dev/null
+++ b/examples/storybook/stories/material-ui/toggle-button/ToggleButtonNotEmpty.stories.tsx
@@ -0,0 +1,84 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import FormatAlignLeftIcon from '@material-ui/icons/FormatAlignLeft';
+import FormatAlignCenterIcon from '@material-ui/icons/FormatAlignCenter';
+import FormatAlignRightIcon from '@material-ui/icons/FormatAlignRight';
+import FormatAlignJustifyIcon from '@material-ui/icons/FormatAlignJustify';
+import LaptopIcon from '@material-ui/icons/Laptop';
+import TvIcon from '@material-ui/icons/Tv';
+import PhoneAndroidIcon from '@material-ui/icons/PhoneAndroid';
+import Grid from '@material-ui/core/Grid';
+import ToggleButton from '@material-ui/lab/ToggleButton';
+import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
+
+const useStyles = makeStyles((theme) => ({
+ toggleContainer: {
+ margin: theme.spacing(2, 0),
+ },
+}));
+
+export function ToggleButtonNotEmpty() {
+ const [alignment, setAlignment] = React.useState('left');
+ const [formats, setFormats] = React.useState(() => ['phone']);
+
+ const handleFormat = (event: React.MouseEvent, newFormats: string[]) => {
+ if (newFormats.length) {
+ setFormats(newFormats);
+ }
+ };
+
+ const handleAlignment = (event: React.MouseEvent, newAlignment: string | null) => {
+ if (newAlignment !== null) {
+ setAlignment(newAlignment);
+ }
+ };
+
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|toggle-button|ToggleButtonNotEmpty.stories"
+};
diff --git a/examples/storybook/stories/material-ui/toggle-button/ToggleButtonSizes.stories.tsx b/examples/storybook/stories/material-ui/toggle-button/ToggleButtonSizes.stories.tsx
new file mode 100644
index 00000000000000..230b4a81522b73
--- /dev/null
+++ b/examples/storybook/stories/material-ui/toggle-button/ToggleButtonSizes.stories.tsx
@@ -0,0 +1,73 @@
+import React from 'react';
+import FormatAlignLeftIcon from '@material-ui/icons/FormatAlignLeft';
+import FormatAlignCenterIcon from '@material-ui/icons/FormatAlignCenter';
+import FormatAlignRightIcon from '@material-ui/icons/FormatAlignRight';
+import FormatAlignJustifyIcon from '@material-ui/icons/FormatAlignJustify';
+import Grid from '@material-ui/core/Grid';
+import ToggleButton from '@material-ui/lab/ToggleButton';
+import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
+
+export function ToggleButtonSizes() {
+ const [alignment, setAlignment] = React.useState('left');
+
+ const handleChange = (event: React.MouseEvent, newAlignment: string) => {
+ setAlignment(newAlignment);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|toggle-button|ToggleButtonSizes.stories"
+};
diff --git a/examples/storybook/stories/material-ui/toggle-button/ToggleButtons.stories.tsx b/examples/storybook/stories/material-ui/toggle-button/ToggleButtons.stories.tsx
new file mode 100644
index 00000000000000..d760e5f0fd4ba8
--- /dev/null
+++ b/examples/storybook/stories/material-ui/toggle-button/ToggleButtons.stories.tsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import FormatAlignLeftIcon from '@material-ui/icons/FormatAlignLeft';
+import FormatAlignCenterIcon from '@material-ui/icons/FormatAlignCenter';
+import FormatAlignRightIcon from '@material-ui/icons/FormatAlignRight';
+import FormatAlignJustifyIcon from '@material-ui/icons/FormatAlignJustify';
+import ToggleButton from '@material-ui/lab/ToggleButton';
+import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
+
+export function ToggleButtons() {
+ const [alignment, setAlignment] = React.useState('left');
+
+ const handleAlignment = (event: React.MouseEvent, newAlignment: string | null) => {
+ setAlignment(newAlignment);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|toggle-button|ToggleButtons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/toggle-button/ToggleButtonsMultiple.stories.tsx b/examples/storybook/stories/material-ui/toggle-button/ToggleButtonsMultiple.stories.tsx
new file mode 100644
index 00000000000000..6eab13c08f98a1
--- /dev/null
+++ b/examples/storybook/stories/material-ui/toggle-button/ToggleButtonsMultiple.stories.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import FormatBoldIcon from '@material-ui/icons/FormatBold';
+import FormatItalicIcon from '@material-ui/icons/FormatItalic';
+import FormatUnderlinedIcon from '@material-ui/icons/FormatUnderlined';
+import FormatColorFillIcon from '@material-ui/icons/FormatColorFill';
+import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
+import ToggleButton from '@material-ui/lab/ToggleButton';
+import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
+
+export function ToggleButtonsMultiple() {
+ const [formats, setFormats] = React.useState(() => ['bold', 'italic']);
+
+ const handleFormat = (event: React.MouseEvent, newFormats: string[]) => {
+ setFormats(newFormats);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|toggle-button|ToggleButtonsMultiple.stories"
+};
diff --git a/examples/storybook/stories/material-ui/toggle-button/VerticalToggleButtons.stories.tsx b/examples/storybook/stories/material-ui/toggle-button/VerticalToggleButtons.stories.tsx
new file mode 100644
index 00000000000000..645b777784a2e2
--- /dev/null
+++ b/examples/storybook/stories/material-ui/toggle-button/VerticalToggleButtons.stories.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import ViewListIcon from '@material-ui/icons/ViewList';
+import ViewModuleIcon from '@material-ui/icons/ViewModule';
+import ViewQuiltIcon from '@material-ui/icons/ViewQuilt';
+import ToggleButton from '@material-ui/lab/ToggleButton';
+import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
+
+export function VerticalToggleButtons() {
+ const [view, setView] = React.useState('list');
+
+ const handleChange = (event: React.MouseEvent, nextView: string) => {
+ setView(nextView);
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|toggle-button|VerticalToggleButtons.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tooltips/ArrowTooltips.stories.tsx b/examples/storybook/stories/material-ui/tooltips/ArrowTooltips.stories.tsx
new file mode 100644
index 00000000000000..80a6646767e4c9
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tooltips/ArrowTooltips.stories.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Tooltip from '@material-ui/core/Tooltip';
+
+export function ArrowTooltips() {
+ return (
+
+ Arrow
+
+ );
+}
+
+export default {
+ title: "Material-ui|tooltips|ArrowTooltips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tooltips/ControlledTooltips.stories.tsx b/examples/storybook/stories/material-ui/tooltips/ControlledTooltips.stories.tsx
new file mode 100644
index 00000000000000..55451b290a5c90
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tooltips/ControlledTooltips.stories.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Tooltip from '@material-ui/core/Tooltip';
+
+export function ControlledTooltips() {
+ const [open, setOpen] = React.useState(false);
+
+ const handleClose = () => {
+ setOpen(false);
+ };
+
+ const handleOpen = () => {
+ setOpen(true);
+ };
+
+ return (
+
+ Controlled
+
+ );
+}
+
+export default {
+ title: "Material-ui|tooltips|ControlledTooltips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tooltips/CustomizedTooltips.stories.tsx b/examples/storybook/stories/material-ui/tooltips/CustomizedTooltips.stories.tsx
new file mode 100644
index 00000000000000..ac8909a97f0907
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tooltips/CustomizedTooltips.stories.tsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import { withStyles, Theme, makeStyles } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import Tooltip, { TooltipProps } from '@material-ui/core/Tooltip';
+import Typography from '@material-ui/core/Typography';
+
+const LightTooltip = withStyles((theme: Theme) => ({
+ tooltip: {
+ backgroundColor: theme.palette.common.white,
+ color: 'rgba(0, 0, 0, 0.87)',
+ boxShadow: theme.shadows[1],
+ fontSize: 11,
+ },
+}))(Tooltip);
+
+const useStylesBootstrap = makeStyles((theme: Theme) => ({
+ arrow: {
+ color: theme.palette.common.black,
+ },
+ tooltip: {
+ backgroundColor: theme.palette.common.black,
+ },
+}));
+
+function BootstrapTooltip(props: TooltipProps) {
+ const classes = useStylesBootstrap();
+
+ return ;
+}
+
+const HtmlTooltip = withStyles((theme: Theme) => ({
+ tooltip: {
+ backgroundColor: '#f5f5f9',
+ color: 'rgba(0, 0, 0, 0.87)',
+ maxWidth: 220,
+ fontSize: theme.typography.pxToRem(12),
+ border: '1px solid #dadde9',
+ },
+}))(Tooltip);
+
+export function CustomizedTooltips() {
+ return (
+
+
+ Light
+
+
+ Bootstrap
+
+
+ Tooltip with HTML
+ {"And here's"} {'some'} {'amazing content'} .{' '}
+ {"It's very engaging. Right?"}
+
+ }
+ >
+ HTML
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tooltips|CustomizedTooltips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tooltips/DelayTooltips.stories.tsx b/examples/storybook/stories/material-ui/tooltips/DelayTooltips.stories.tsx
new file mode 100644
index 00000000000000..601d12c5dae71f
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tooltips/DelayTooltips.stories.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Tooltip from '@material-ui/core/Tooltip';
+
+export function DelayTooltips() {
+ return (
+
+ [500ms, 200ms]
+
+ );
+}
+
+export default {
+ title: "Material-ui|tooltips|DelayTooltips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tooltips/DisabledTooltips.stories.tsx b/examples/storybook/stories/material-ui/tooltips/DisabledTooltips.stories.tsx
new file mode 100644
index 00000000000000..949541e19a837b
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tooltips/DisabledTooltips.stories.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Tooltip from '@material-ui/core/Tooltip';
+
+export function DisabledTooltips() {
+ return (
+
+
+ A Disabled Button
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tooltips|DisabledTooltips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tooltips/InteractiveTooltips.stories.tsx b/examples/storybook/stories/material-ui/tooltips/InteractiveTooltips.stories.tsx
new file mode 100644
index 00000000000000..b6296f0dbec2db
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tooltips/InteractiveTooltips.stories.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Tooltip from '@material-ui/core/Tooltip';
+
+export function InteractiveTooltips() {
+ return (
+
+ Interactive
+
+ );
+}
+
+export default {
+ title: "Material-ui|tooltips|InteractiveTooltips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tooltips/PositionedTooltips.stories.tsx b/examples/storybook/stories/material-ui/tooltips/PositionedTooltips.stories.tsx
new file mode 100644
index 00000000000000..c4d37b9da45e2d
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tooltips/PositionedTooltips.stories.tsx
@@ -0,0 +1,82 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import Grid from '@material-ui/core/Grid';
+import Button from '@material-ui/core/Button';
+import Tooltip from '@material-ui/core/Tooltip';
+
+const useStyles = makeStyles({
+ root: {
+ width: 500,
+ },
+});
+
+export function PositionedTooltips() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+ top-start
+
+
+ top
+
+
+ top-end
+
+
+
+
+
+
+ left-start
+
+
+
+ left
+
+
+
+ left-end
+
+
+
+
+
+ right-start
+
+
+
+
+ right
+
+
+
+
+ right-end
+
+
+
+
+
+
+
+ bottom-start
+
+
+ bottom
+
+
+ bottom-end
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tooltips|PositionedTooltips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tooltips/SimpleTooltips.stories.tsx b/examples/storybook/stories/material-ui/tooltips/SimpleTooltips.stories.tsx
new file mode 100644
index 00000000000000..a065bdd1d57221
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tooltips/SimpleTooltips.stories.tsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import AddIcon from '@material-ui/icons/Add';
+import Fab from '@material-ui/core/Fab';
+import DeleteIcon from '@material-ui/icons/Delete';
+import IconButton from '@material-ui/core/IconButton';
+import Tooltip from '@material-ui/core/Tooltip';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ fab: {
+ margin: theme.spacing(2),
+ },
+ absolute: {
+ position: 'absolute',
+ bottom: theme.spacing(2),
+ right: theme.spacing(3),
+ },
+ }),
+);
+
+export function SimpleTooltips() {
+ const classes = useStyles();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tooltips|SimpleTooltips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tooltips/TransitionsTooltips.stories.tsx b/examples/storybook/stories/material-ui/tooltips/TransitionsTooltips.stories.tsx
new file mode 100644
index 00000000000000..224dc493d93f79
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tooltips/TransitionsTooltips.stories.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import Button from '@material-ui/core/Button';
+import Tooltip from '@material-ui/core/Tooltip';
+import Fade from '@material-ui/core/Fade';
+import Zoom from '@material-ui/core/Zoom';
+
+export function TransitionsTooltips() {
+ return (
+
+
+ Grow
+
+
+ Fade
+
+
+ Zoom
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tooltips|TransitionsTooltips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tooltips/TriggersTooltips.stories.tsx b/examples/storybook/stories/material-ui/tooltips/TriggersTooltips.stories.tsx
new file mode 100644
index 00000000000000..7500837cc8cdc4
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tooltips/TriggersTooltips.stories.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import Grid from '@material-ui/core/Grid';
+import Button from '@material-ui/core/Button';
+import Tooltip from '@material-ui/core/Tooltip';
+import ClickAwayListener from '@material-ui/core/ClickAwayListener';
+
+export function TriggersTooltips() {
+ const [open, setOpen] = React.useState(false);
+
+ const handleTooltipClose = () => {
+ setOpen(false);
+ };
+
+ const handleTooltipOpen = () => {
+ setOpen(true);
+ };
+
+ return (
+
+
+
+
+ Hover or touch
+
+
+
+
+ Focus or touch
+
+
+
+
+ Hover
+
+
+
+
+
+
+ Click
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tooltips|TriggersTooltips.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tooltips/VariableWidth.stories.tsx b/examples/storybook/stories/material-ui/tooltips/VariableWidth.stories.tsx
new file mode 100644
index 00000000000000..b696e9f525eb9e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tooltips/VariableWidth.stories.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Button from '@material-ui/core/Button';
+import Tooltip from '@material-ui/core/Tooltip';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ button: {
+ margin: theme.spacing(1),
+ },
+ customWidth: {
+ maxWidth: 500,
+ },
+ noMaxWidth: {
+ maxWidth: 'none',
+ },
+ }),
+);
+
+const longText = `
+Aliquam eget finibus ante, non facilisis lectus. Sed vitae dignissim est, vel aliquam tellus.
+Praesent non nunc mollis, fermentum neque at, semper arcu.
+Nullam eget est sed sem iaculis gravida eget vitae justo.
+`;
+
+export function VariableWidth() {
+ const classes = useStyles();
+
+ return (
+
+
+ Default Width [300px]
+
+
+ Custom Width [500px]
+
+
+ No wrapping
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tooltips|VariableWidth.stories"
+};
diff --git a/examples/storybook/stories/material-ui/transfer-list/SelectAllTransferList.stories.tsx b/examples/storybook/stories/material-ui/transfer-list/SelectAllTransferList.stories.tsx
new file mode 100644
index 00000000000000..1b89c6ddd4832e
--- /dev/null
+++ b/examples/storybook/stories/material-ui/transfer-list/SelectAllTransferList.stories.tsx
@@ -0,0 +1,164 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Grid from '@material-ui/core/Grid';
+import List from '@material-ui/core/List';
+import Card from '@material-ui/core/Card';
+import CardHeader from '@material-ui/core/CardHeader';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemText from '@material-ui/core/ListItemText';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import Checkbox from '@material-ui/core/Checkbox';
+import Button from '@material-ui/core/Button';
+import Divider from '@material-ui/core/Divider';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ margin: 'auto',
+ },
+ cardHeader: {
+ padding: theme.spacing(1, 2),
+ },
+ list: {
+ width: 200,
+ height: 230,
+ backgroundColor: theme.palette.background.paper,
+ overflow: 'auto',
+ },
+ button: {
+ margin: theme.spacing(0.5, 0),
+ },
+ }),
+);
+
+function not(a: number[], b: number[]) {
+ return a.filter((value) => b.indexOf(value) === -1);
+}
+
+function intersection(a: number[], b: number[]) {
+ return a.filter((value) => b.indexOf(value) !== -1);
+}
+
+function union(a: number[], b: number[]) {
+ return [...a, ...not(b, a)];
+}
+
+export function TransferList() {
+ const classes = useStyles();
+ const [checked, setChecked] = React.useState([]);
+ const [left, setLeft] = React.useState([0, 1, 2, 3]);
+ const [right, setRight] = React.useState([4, 5, 6, 7]);
+
+ const leftChecked = intersection(checked, left);
+ const rightChecked = intersection(checked, right);
+
+ const handleToggle = (value: number) => () => {
+ const currentIndex = checked.indexOf(value);
+ const newChecked = [...checked];
+
+ if (currentIndex === -1) {
+ newChecked.push(value);
+ } else {
+ newChecked.splice(currentIndex, 1);
+ }
+
+ setChecked(newChecked);
+ };
+
+ const numberOfChecked = (items: number[]) => intersection(checked, items).length;
+
+ const handleToggleAll = (items: number[]) => () => {
+ if (numberOfChecked(items) === items.length) {
+ setChecked(not(checked, items));
+ } else {
+ setChecked(union(checked, items));
+ }
+ };
+
+ const handleCheckedRight = () => {
+ setRight(right.concat(leftChecked));
+ setLeft(not(left, leftChecked));
+ setChecked(not(checked, leftChecked));
+ };
+
+ const handleCheckedLeft = () => {
+ setLeft(left.concat(rightChecked));
+ setRight(not(right, rightChecked));
+ setChecked(not(checked, rightChecked));
+ };
+
+ const customList = (title: React.ReactNode, items: number[]) => (
+
+
+ }
+ title={title}
+ subheader={`${numberOfChecked(items)}/${items.length} selected`}
+ />
+
+
+ {items.map((value: number) => {
+ const labelId = `transfer-list-all-item-${value}-label`;
+
+ return (
+
+
+
+
+
+
+ );
+ })}
+
+
+
+ );
+
+ return (
+
+ {customList('Choices', left)}
+
+
+
+ >
+
+
+ <
+
+
+
+ {customList('Chosen', right)}
+
+ );
+}
+
+export default {
+ title: "Material-ui|transfer-list|SelectAllTransferList.stories"
+};
diff --git a/examples/storybook/stories/material-ui/transfer-list/TransferList.stories.tsx b/examples/storybook/stories/material-ui/transfer-list/TransferList.stories.tsx
new file mode 100644
index 00000000000000..53f96623ffa185
--- /dev/null
+++ b/examples/storybook/stories/material-ui/transfer-list/TransferList.stories.tsx
@@ -0,0 +1,159 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import Grid from '@material-ui/core/Grid';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemIcon from '@material-ui/core/ListItemIcon';
+import ListItemText from '@material-ui/core/ListItemText';
+import Checkbox from '@material-ui/core/Checkbox';
+import Button from '@material-ui/core/Button';
+import Paper from '@material-ui/core/Paper';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ margin: 'auto',
+ },
+ paper: {
+ width: 200,
+ height: 230,
+ overflow: 'auto',
+ },
+ button: {
+ margin: theme.spacing(0.5, 0),
+ },
+ }),
+);
+
+function not(a: number[], b: number[]) {
+ return a.filter((value) => b.indexOf(value) === -1);
+}
+
+function intersection(a: number[], b: number[]) {
+ return a.filter((value) => b.indexOf(value) !== -1);
+}
+
+export function TransferList() {
+ const classes = useStyles();
+ const [checked, setChecked] = React.useState([]);
+ const [left, setLeft] = React.useState([0, 1, 2, 3]);
+ const [right, setRight] = React.useState([4, 5, 6, 7]);
+
+ const leftChecked = intersection(checked, left);
+ const rightChecked = intersection(checked, right);
+
+ const handleToggle = (value: number) => () => {
+ const currentIndex = checked.indexOf(value);
+ const newChecked = [...checked];
+
+ if (currentIndex === -1) {
+ newChecked.push(value);
+ } else {
+ newChecked.splice(currentIndex, 1);
+ }
+
+ setChecked(newChecked);
+ };
+
+ const handleAllRight = () => {
+ setRight(right.concat(left));
+ setLeft([]);
+ };
+
+ const handleCheckedRight = () => {
+ setRight(right.concat(leftChecked));
+ setLeft(not(left, leftChecked));
+ setChecked(not(checked, leftChecked));
+ };
+
+ const handleCheckedLeft = () => {
+ setLeft(left.concat(rightChecked));
+ setRight(not(right, rightChecked));
+ setChecked(not(checked, rightChecked));
+ };
+
+ const handleAllLeft = () => {
+ setLeft(left.concat(right));
+ setRight([]);
+ };
+
+ const customList = (items: number[]) => (
+
+
+ {items.map((value: number) => {
+ const labelId = `transfer-list-item-${value}-label`;
+
+ return (
+
+
+
+
+
+
+ );
+ })}
+
+
+
+ );
+
+ return (
+
+ {customList(left)}
+
+
+
+ ≫
+
+
+ >
+
+
+ <
+
+
+ ≪
+
+
+
+ {customList(right)}
+
+ );
+}
+
+export default {
+ title: "Material-ui|transfer-list|TransferList.stories"
+};
diff --git a/examples/storybook/stories/material-ui/transitions/SimpleCollapse.stories.tsx b/examples/storybook/stories/material-ui/transitions/SimpleCollapse.stories.tsx
new file mode 100644
index 00000000000000..aaf322cfe343d0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/transitions/SimpleCollapse.stories.tsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Switch from '@material-ui/core/Switch';
+import Paper from '@material-ui/core/Paper';
+import Collapse from '@material-ui/core/Collapse';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ height: 180,
+ },
+ container: {
+ display: 'flex',
+ },
+ paper: {
+ margin: theme.spacing(1),
+ },
+ svg: {
+ width: 100,
+ height: 100,
+ },
+ polygon: {
+ fill: theme.palette.common.white,
+ stroke: theme.palette.divider,
+ strokeWidth: 1,
+ },
+ }),
+);
+
+export function SimpleCollapse() {
+ const classes = useStyles();
+ const [checked, setChecked] = React.useState(false);
+
+ const handleChange = () => {
+ setChecked((prev) => !prev);
+ };
+
+ return (
+
+
}
+ label="Show"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|transitions|SimpleCollapse.stories"
+};
diff --git a/examples/storybook/stories/material-ui/transitions/SimpleFade.stories.tsx b/examples/storybook/stories/material-ui/transitions/SimpleFade.stories.tsx
new file mode 100644
index 00000000000000..6be08438f735e9
--- /dev/null
+++ b/examples/storybook/stories/material-ui/transitions/SimpleFade.stories.tsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Switch from '@material-ui/core/Switch';
+import Paper from '@material-ui/core/Paper';
+import Fade from '@material-ui/core/Fade';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ height: 180,
+ },
+ container: {
+ display: 'flex',
+ },
+ paper: {
+ margin: theme.spacing(1),
+ },
+ svg: {
+ width: 100,
+ height: 100,
+ },
+ polygon: {
+ fill: theme.palette.common.white,
+ stroke: theme.palette.divider,
+ strokeWidth: 1,
+ },
+ }),
+);
+
+export function SimpleFade() {
+ const classes = useStyles();
+ const [checked, setChecked] = React.useState(false);
+
+ const handleChange = () => {
+ setChecked((prev) => !prev);
+ };
+
+ return (
+
+
}
+ label="Show"
+ />
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|transitions|SimpleFade.stories"
+};
diff --git a/examples/storybook/stories/material-ui/transitions/SimpleGrow.stories.tsx b/examples/storybook/stories/material-ui/transitions/SimpleGrow.stories.tsx
new file mode 100644
index 00000000000000..253a0e78ff8950
--- /dev/null
+++ b/examples/storybook/stories/material-ui/transitions/SimpleGrow.stories.tsx
@@ -0,0 +1,72 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+import Switch from '@material-ui/core/Switch';
+import Paper from '@material-ui/core/Paper';
+import Grow from '@material-ui/core/Grow';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ height: 180,
+ },
+ container: {
+ display: 'flex',
+ },
+ paper: {
+ margin: theme.spacing(1),
+ },
+ svg: {
+ width: 100,
+ height: 100,
+ },
+ polygon: {
+ fill: theme.palette.common.white,
+ stroke: theme.palette.divider,
+ strokeWidth: 1,
+ },
+ }),
+);
+
+export function SimpleGrow() {
+ const classes = useStyles();
+ const [checked, setChecked] = React.useState(false);
+
+ const handleChange = () => {
+ setChecked((prev) => !prev);
+ };
+
+ return (
+
+
}
+ label="Show"
+ />
+
+
+
+
+
+
+
+
+ {/* Conditionally applies the timeout prop to change the entry speed. */}
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|transitions|SimpleGrow.stories"
+};
diff --git a/examples/storybook/stories/material-ui/transitions/SimpleSlide.stories.tsx b/examples/storybook/stories/material-ui/transitions/SimpleSlide.stories.tsx
new file mode 100644
index 00000000000000..12fab8b51c24e3
--- /dev/null
+++ b/examples/storybook/stories/material-ui/transitions/SimpleSlide.stories.tsx
@@ -0,0 +1,62 @@
+import React from 'react';
+import Switch from '@material-ui/core/Switch';
+import Paper from '@material-ui/core/Paper';
+import Slide from '@material-ui/core/Slide';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ height: 180,
+ },
+ wrapper: {
+ width: 100 + theme.spacing(2),
+ },
+ paper: {
+ zIndex: 1,
+ position: 'relative',
+ margin: theme.spacing(1),
+ },
+ svg: {
+ width: 100,
+ height: 100,
+ },
+ polygon: {
+ fill: theme.palette.common.white,
+ stroke: theme.palette.divider,
+ strokeWidth: 1,
+ },
+ }),
+);
+
+export function SimpleSlide() {
+ const classes = useStyles();
+ const [checked, setChecked] = React.useState(false);
+
+ const handleChange = () => {
+ setChecked((prev) => !prev);
+ };
+
+ return (
+
+
+
}
+ label="Show"
+ />
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|transitions|SimpleSlide.stories"
+};
diff --git a/examples/storybook/stories/material-ui/transitions/SimpleZoom.stories.tsx b/examples/storybook/stories/material-ui/transitions/SimpleZoom.stories.tsx
new file mode 100644
index 00000000000000..085da280fc0675
--- /dev/null
+++ b/examples/storybook/stories/material-ui/transitions/SimpleZoom.stories.tsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import Switch from '@material-ui/core/Switch';
+import Paper from '@material-ui/core/Paper';
+import Zoom from '@material-ui/core/Zoom';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ height: 180,
+ },
+ container: {
+ display: 'flex',
+ },
+ paper: {
+ margin: theme.spacing(1),
+ },
+ svg: {
+ width: 100,
+ height: 100,
+ },
+ polygon: {
+ fill: theme.palette.common.white,
+ stroke: theme.palette.divider,
+ strokeWidth: 1,
+ },
+ }),
+);
+
+export function SimpleZoom() {
+ const classes = useStyles();
+ const [checked, setChecked] = React.useState(false);
+
+ const handleChange = () => {
+ setChecked((prev) => !prev);
+ };
+
+ return (
+
+
}
+ label="Show"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|transitions|SimpleZoom.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tree-view/ControlledTreeView.stories.tsx b/examples/storybook/stories/material-ui/tree-view/ControlledTreeView.stories.tsx
new file mode 100644
index 00000000000000..6d57e0e76e49c0
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tree-view/ControlledTreeView.stories.tsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import TreeView from '@material-ui/lab/TreeView';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import ChevronRightIcon from '@material-ui/icons/ChevronRight';
+import TreeItem from '@material-ui/lab/TreeItem';
+
+const useStyles = makeStyles({
+ root: {
+ height: 216,
+ flexGrow: 1,
+ maxWidth: 400,
+ },
+});
+
+export function ControlledTreeView() {
+ const classes = useStyles();
+ const [expanded, setExpanded] = React.useState([]);
+ const [selected, setSelected] = React.useState([]);
+
+ const handleToggle = (event: React.ChangeEvent<{}>, nodeIds: string[]) => {
+ setExpanded(nodeIds);
+ };
+
+ const handleSelect = (event: React.ChangeEvent<{}>, nodeIds: string[]) => {
+ setSelected(nodeIds);
+ };
+
+ return (
+ }
+ defaultExpandIcon={ }
+ expanded={expanded}
+ selected={selected}
+ onNodeToggle={handleToggle}
+ onNodeSelect={handleSelect}
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tree-view|ControlledTreeView.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tree-view/CustomizedTreeView.stories.tsx b/examples/storybook/stories/material-ui/tree-view/CustomizedTreeView.stories.tsx
new file mode 100644
index 00000000000000..62d19cce934830
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tree-view/CustomizedTreeView.stories.tsx
@@ -0,0 +1,106 @@
+import React from 'react';
+import SvgIcon, { SvgIconProps } from '@material-ui/core/SvgIcon';
+import { fade, makeStyles, withStyles, Theme, createStyles } from '@material-ui/core/styles';
+import TreeView from '@material-ui/lab/TreeView';
+import TreeItem, { TreeItemProps } from '@material-ui/lab/TreeItem';
+import Collapse from '@material-ui/core/Collapse';
+import { useSpring, animated } from 'react-spring/web.cjs'; // web.cjs is required for IE 11 support
+import { TransitionProps } from '@material-ui/core/transitions';
+
+function MinusSquare(props: SvgIconProps) {
+ return (
+
+ {/* tslint:disable-next-line: max-line-length */}
+
+
+ );
+}
+
+function PlusSquare(props: SvgIconProps) {
+ return (
+
+ {/* tslint:disable-next-line: max-line-length */}
+
+
+ );
+}
+
+function CloseSquare(props: SvgIconProps) {
+ return (
+
+ {/* tslint:disable-next-line: max-line-length */}
+
+
+ );
+}
+
+function TransitionComponent(props: TransitionProps) {
+ const style = useSpring({
+ from: { opacity: 0, transform: 'translate3d(20px,0,0)' },
+ to: { opacity: props.in ? 1 : 0, transform: `translate3d(${props.in ? 0 : 20}px,0,0)` },
+ });
+
+ return (
+
+
+
+ );
+}
+
+const StyledTreeItem = withStyles((theme: Theme) =>
+ createStyles({
+ iconContainer: {
+ '& .close': {
+ opacity: 0.3,
+ },
+ },
+ group: {
+ marginLeft: 7,
+ paddingLeft: 18,
+ borderLeft: `1px dashed ${fade(theme.palette.text.primary, 0.4)}`,
+ },
+ }),
+)((props: TreeItemProps) => );
+
+const useStyles = makeStyles(
+ createStyles({
+ root: {
+ height: 264,
+ flexGrow: 1,
+ maxWidth: 400,
+ },
+ }),
+);
+
+export function CustomizedTreeView() {
+ const classes = useStyles();
+
+ return (
+ }
+ defaultExpandIcon={ }
+ defaultEndIcon={ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tree-view|CustomizedTreeView.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tree-view/FileSystemNavigator.stories.tsx b/examples/storybook/stories/material-ui/tree-view/FileSystemNavigator.stories.tsx
new file mode 100644
index 00000000000000..d06b996c507536
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tree-view/FileSystemNavigator.stories.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import TreeView from '@material-ui/lab/TreeView';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import ChevronRightIcon from '@material-ui/icons/ChevronRight';
+import TreeItem from '@material-ui/lab/TreeItem';
+
+const useStyles = makeStyles({
+ root: {
+ height: 240,
+ flexGrow: 1,
+ maxWidth: 400,
+ },
+});
+
+export function FileSystemNavigator() {
+ const classes = useStyles();
+
+ return (
+ }
+ defaultExpandIcon={ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tree-view|FileSystemNavigator.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tree-view/GmailTreeView.stories.tsx b/examples/storybook/stories/material-ui/tree-view/GmailTreeView.stories.tsx
new file mode 100644
index 00000000000000..23007ff6f2df22
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tree-view/GmailTreeView.stories.tsx
@@ -0,0 +1,182 @@
+import React from 'react';
+import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
+import TreeView from '@material-ui/lab/TreeView';
+import TreeItem, { TreeItemProps } from '@material-ui/lab/TreeItem';
+import Typography from '@material-ui/core/Typography';
+import MailIcon from '@material-ui/icons/Mail';
+import DeleteIcon from '@material-ui/icons/Delete';
+import Label from '@material-ui/icons/Label';
+import SupervisorAccountIcon from '@material-ui/icons/SupervisorAccount';
+import InfoIcon from '@material-ui/icons/Info';
+import ForumIcon from '@material-ui/icons/Forum';
+import LocalOfferIcon from '@material-ui/icons/LocalOffer';
+import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
+import ArrowRightIcon from '@material-ui/icons/ArrowRight';
+import { SvgIconProps } from '@material-ui/core/SvgIcon';
+
+declare module 'csstype' {
+ interface Properties {
+ '--tree-view-color'?: string;
+ '--tree-view-bg-color'?: string;
+ }
+}
+
+type StyledTreeItemProps = TreeItemProps & {
+ bgColor?: string;
+ color?: string;
+ labelIcon: React.ElementType;
+ labelInfo?: string;
+ labelText: string;
+};
+
+const useTreeItemStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ color: theme.palette.text.secondary,
+ '&:hover > $content': {
+ backgroundColor: theme.palette.action.hover,
+ },
+ '&:focus > $content, &$selected > $content': {
+ backgroundColor: `var(--tree-view-bg-color, ${theme.palette.grey[400]})`,
+ color: 'var(--tree-view-color)',
+ },
+ '&:focus > $content $label, &:hover > $content $label, &$selected > $content $label': {
+ backgroundColor: 'transparent',
+ },
+ },
+ content: {
+ color: theme.palette.text.secondary,
+ borderTopRightRadius: theme.spacing(2),
+ borderBottomRightRadius: theme.spacing(2),
+ paddingRight: theme.spacing(1),
+ fontWeight: theme.typography.fontWeightMedium,
+ '$expanded > &': {
+ fontWeight: theme.typography.fontWeightRegular,
+ },
+ },
+ group: {
+ marginLeft: 0,
+ '& $content': {
+ paddingLeft: theme.spacing(2),
+ },
+ },
+ expanded: {},
+ selected: {},
+ label: {
+ fontWeight: 'inherit',
+ color: 'inherit',
+ },
+ labelRoot: {
+ display: 'flex',
+ alignItems: 'center',
+ padding: theme.spacing(0.5, 0),
+ },
+ labelIcon: {
+ marginRight: theme.spacing(1),
+ },
+ labelText: {
+ fontWeight: 'inherit',
+ flexGrow: 1,
+ },
+ }),
+);
+
+function StyledTreeItem(props: StyledTreeItemProps) {
+ const classes = useTreeItemStyles();
+ const { labelText, labelIcon: LabelIcon, labelInfo, color, bgColor, ...other } = props;
+
+ return (
+
+
+
+ {labelText}
+
+
+ {labelInfo}
+
+
+ }
+ style={{
+ '--tree-view-color': color,
+ '--tree-view-bg-color': bgColor,
+ }}
+ classes={{
+ root: classes.root,
+ content: classes.content,
+ expanded: classes.expanded,
+ selected: classes.selected,
+ group: classes.group,
+ label: classes.label,
+ }}
+ {...other}
+ />
+ );
+}
+
+const useStyles = makeStyles(
+ createStyles({
+ root: {
+ height: 264,
+ flexGrow: 1,
+ maxWidth: 400,
+ },
+ }),
+);
+
+export function GmailTreeView() {
+ const classes = useStyles();
+
+ return (
+ }
+ defaultExpandIcon={ }
+ defaultEndIcon={
}
+ >
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tree-view|GmailTreeView.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tree-view/MultiSelectTreeView.stories.tsx b/examples/storybook/stories/material-ui/tree-view/MultiSelectTreeView.stories.tsx
new file mode 100644
index 00000000000000..a474113b343bbf
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tree-view/MultiSelectTreeView.stories.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import TreeView from '@material-ui/lab/TreeView';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import ChevronRightIcon from '@material-ui/icons/ChevronRight';
+import TreeItem from '@material-ui/lab/TreeItem';
+
+const useStyles = makeStyles({
+ root: {
+ height: 216,
+ flexGrow: 1,
+ maxWidth: 400,
+ },
+});
+
+export function MultiSelectTreeView() {
+ const classes = useStyles();
+
+ return (
+ }
+ defaultExpandIcon={ }
+ multiSelect
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|tree-view|MultiSelectTreeView.stories"
+};
diff --git a/examples/storybook/stories/material-ui/tree-view/RecursiveTreeView.stories.tsx b/examples/storybook/stories/material-ui/tree-view/RecursiveTreeView.stories.tsx
new file mode 100644
index 00000000000000..4e141e848327a8
--- /dev/null
+++ b/examples/storybook/stories/material-ui/tree-view/RecursiveTreeView.stories.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import TreeView from '@material-ui/lab/TreeView';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import ChevronRightIcon from '@material-ui/icons/ChevronRight';
+import TreeItem from '@material-ui/lab/TreeItem';
+
+interface RenderTree {
+ id: string;
+ name: string;
+ children?: RenderTree[];
+}
+
+const data: RenderTree = {
+ id: 'root',
+ name: 'Parent',
+ children: [
+ {
+ id: '1',
+ name: 'Child - 1',
+ },
+ {
+ id: '3',
+ name: 'Child - 3',
+ children: [
+ {
+ id: '4',
+ name: 'Child - 4',
+ },
+ ],
+ },
+ ],
+};
+
+const useStyles = makeStyles({
+ root: {
+ height: 110,
+ flexGrow: 1,
+ maxWidth: 400,
+ },
+});
+
+export function RecursiveTreeView() {
+ const classes = useStyles();
+
+ const renderTree = (nodes: RenderTree) => (
+
+ {Array.isArray(nodes.children) ? nodes.children.map((node) => renderTree(node)) : null}
+
+ );
+
+ return (
+ }
+ defaultExpanded={['root']}
+ defaultExpandIcon={ }
+ >
+ {renderTree(data)}
+
+ );
+}
+
+export default {
+ title: "Material-ui|tree-view|RecursiveTreeView.stories"
+};
diff --git a/examples/storybook/stories/material-ui/typography/Types.stories.tsx b/examples/storybook/stories/material-ui/typography/Types.stories.tsx
new file mode 100644
index 00000000000000..0a1cba8beb44b9
--- /dev/null
+++ b/examples/storybook/stories/material-ui/typography/Types.stories.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import Typography from '@material-ui/core/Typography';
+import { makeStyles } from '@material-ui/core/styles';
+
+const useStyles = makeStyles({
+ root: {
+ width: '100%',
+ maxWidth: 500,
+ },
+});
+
+export function Types() {
+ const classes = useStyles();
+
+ return (
+
+
+ h1. Heading
+
+
+ h2. Heading
+
+
+ h3. Heading
+
+
+ h4. Heading
+
+
+ h5. Heading
+
+
+ h6. Heading
+
+
+ subtitle1. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur
+
+
+ subtitle2. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur
+
+
+ body1. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur
+ unde suscipit, quam beatae rerum inventore consectetur, neque doloribus, cupiditate numquam
+ dignissimos laborum fugiat deleniti? Eum quasi quidem quibusdam.
+
+
+ body2. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur
+ unde suscipit, quam beatae rerum inventore consectetur, neque doloribus, cupiditate numquam
+ dignissimos laborum fugiat deleniti? Eum quasi quidem quibusdam.
+
+
+ button text
+
+
+ caption text
+
+
+ overline text
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|typography|Types.stories"
+};
diff --git a/examples/storybook/stories/material-ui/typography/TypographyTheme.stories.tsx b/examples/storybook/stories/material-ui/typography/TypographyTheme.stories.tsx
new file mode 100644
index 00000000000000..e404836c4a28bd
--- /dev/null
+++ b/examples/storybook/stories/material-ui/typography/TypographyTheme.stories.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ ...theme.typography.button,
+ backgroundColor: theme.palette.background.paper,
+ padding: theme.spacing(1),
+ },
+ }),
+);
+
+export function TypographyTheme() {
+ const classes = useStyles();
+
+ return {"This div's text looks like that of a button."}
;
+}
+
+export default {
+ title: "Material-ui|typography|TypographyTheme.stories"
+};
diff --git a/examples/storybook/stories/material-ui/use-media-query/JavaScriptMedia.stories.tsx b/examples/storybook/stories/material-ui/use-media-query/JavaScriptMedia.stories.tsx
new file mode 100644
index 00000000000000..4a8a5ef1729c9a
--- /dev/null
+++ b/examples/storybook/stories/material-ui/use-media-query/JavaScriptMedia.stories.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import json2mq from 'json2mq';
+import useMediaQuery from '@material-ui/core/useMediaQuery';
+
+export function JavaScriptMedia() {
+ const matches = useMediaQuery(
+ json2mq({
+ minWidth: 600,
+ }),
+ );
+
+ return {`{ minWidth: 600 } matches: ${matches}`} ;
+}
+
+export default {
+ title: "Material-ui|use-media-query|JavaScriptMedia.stories"
+};
diff --git a/examples/storybook/stories/material-ui/use-media-query/ServerSide.stories.tsx b/examples/storybook/stories/material-ui/use-media-query/ServerSide.stories.tsx
new file mode 100644
index 00000000000000..1e89e108d33622
--- /dev/null
+++ b/examples/storybook/stories/material-ui/use-media-query/ServerSide.stories.tsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import mediaQuery from 'css-mediaquery';
+import { ThemeProvider, Theme } from '@material-ui/core/styles';
+import useMediaQuery from '@material-ui/core/useMediaQuery';
+
+function MyComponent() {
+ const matches = useMediaQuery('(min-width:600px)');
+
+ return {`(min-width:600px) matches: ${matches}`} ;
+}
+
+export function ServerSide() {
+ const ssrMatchMedia = (query: string) => ({
+ matches: mediaQuery.match(query, {
+ // The estimated CSS width of the browser.
+ width: 800,
+ }),
+ });
+
+ return (
+
+ theme={{
+ props: {
+ // Change the default options of useMediaQuery
+ MuiUseMediaQuery: { ssrMatchMedia },
+ },
+ }}
+ >
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|use-media-query|ServerSide.stories"
+};
diff --git a/examples/storybook/stories/material-ui/use-media-query/SimpleMediaQuery.stories.tsx b/examples/storybook/stories/material-ui/use-media-query/SimpleMediaQuery.stories.tsx
new file mode 100644
index 00000000000000..146770baeaf9d1
--- /dev/null
+++ b/examples/storybook/stories/material-ui/use-media-query/SimpleMediaQuery.stories.tsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import useMediaQuery from '@material-ui/core/useMediaQuery';
+
+export function SimpleMediaQuery() {
+ const matches = useMediaQuery('(min-width:600px)');
+
+ return {`(min-width:600px) matches: ${matches}`} ;
+}
+
+export default {
+ title: "Material-ui|use-media-query|SimpleMediaQuery.stories"
+};
diff --git a/examples/storybook/stories/material-ui/use-media-query/ThemeHelper.stories.tsx b/examples/storybook/stories/material-ui/use-media-query/ThemeHelper.stories.tsx
new file mode 100644
index 00000000000000..18d9c610bb5bfb
--- /dev/null
+++ b/examples/storybook/stories/material-ui/use-media-query/ThemeHelper.stories.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import { createMuiTheme, ThemeProvider, useTheme } from '@material-ui/core/styles';
+import useMediaQuery from '@material-ui/core/useMediaQuery';
+
+function MyComponent() {
+ const theme = useTheme();
+ const matches = useMediaQuery(theme.breakpoints.up('sm'));
+
+ return {`theme.breakpoints.up('sm') matches: ${matches}`} ;
+}
+
+const theme = createMuiTheme();
+
+export function ThemeHelper() {
+ return (
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|use-media-query|ThemeHelper.stories"
+};
diff --git a/examples/storybook/stories/material-ui/use-media-query/UseWidth.stories.tsx b/examples/storybook/stories/material-ui/use-media-query/UseWidth.stories.tsx
new file mode 100644
index 00000000000000..abf581792c62d1
--- /dev/null
+++ b/examples/storybook/stories/material-ui/use-media-query/UseWidth.stories.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { Theme, ThemeProvider, useTheme, createMuiTheme } from '@material-ui/core/styles';
+import useMediaQuery from '@material-ui/core/useMediaQuery';
+import { Breakpoint } from '@material-ui/core/styles/createBreakpoints';
+
+type BreakpointOrNull = Breakpoint | null;
+
+/**
+ * Be careful using this hook. It only works because the number of
+ * breakpoints in theme is static. It will break once you change the number of
+ * breakpoints. See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
+ */
+function useWidth() {
+ const theme: Theme = useTheme();
+ const keys: Breakpoint[] = [...theme.breakpoints.keys].reverse();
+ return (
+ keys.reduce((output: BreakpointOrNull, key: Breakpoint) => {
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ const matches = useMediaQuery(theme.breakpoints.up(key));
+ return !output && matches ? key : output;
+ }, null) || 'xs'
+ );
+}
+
+function MyComponent() {
+ const width = useWidth();
+ return {`width: ${width}`} ;
+}
+
+const theme = createMuiTheme();
+
+export function UseWidth() {
+ return (
+
+
+
+ );
+}
+
+export default {
+ title: "Material-ui|use-media-query|UseWidth.stories"
+};