From 0230df94ca877fdd63a42c3e276f75c3a4316eea Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20Dudak?=
Date: Wed, 7 Jul 2021 12:05:32 +0200
Subject: [PATCH 1/9] [Switch] Create SwitchUnstyled and useSwitch (#26688)
Co-authored-by: Marija Najdova
Co-authored-by: Olivier Tassinari
---
docs/pages/api-docs/switch-unstyled.js | 23 +
docs/pages/api-docs/switch-unstyled.json | 29 ++
docs/src/modules/utils/parseTest.ts | 5 +-
.../components/switches/UnstyledSwitches.js | 73 +++
.../components/switches/UnstyledSwitches.tsx | 73 +++
.../switches/UnstyledSwitchesMaterial.js | 435 ++++++++++++++++++
.../components/switches/UseSwitchesBasic.js | 88 ++++
.../components/switches/UseSwitchesBasic.tsx | 88 ++++
.../components/switches/UseSwitchesCustom.js | 95 ++++
.../components/switches/UseSwitchesCustom.tsx | 95 ++++
.../switches/UseSwitchesMaterial.js | 399 ++++++++++++++++
.../src/pages/components/switches/switches.md | 43 +-
docs/src/pagesApi.js | 1 +
.../switch-unstyled/switch-unstyled-de.json | 1 +
.../switch-unstyled/switch-unstyled-es.json | 1 +
.../switch-unstyled/switch-unstyled-fr.json | 1 +
.../switch-unstyled/switch-unstyled-ja.json | 1 +
.../switch-unstyled/switch-unstyled-pt.json | 1 +
.../switch-unstyled/switch-unstyled-ru.json | 1 +
.../switch-unstyled/switch-unstyled-zh.json | 1 +
.../switch-unstyled/switch-unstyled.json | 16 +
.../material-ui-system/src/createStyled.js | 5 +-
packages/material-ui-unstyled/package.json | 1 +
.../SwitchUnstyled/SwitchUnstyled.test.tsx | 78 ++++
.../src/SwitchUnstyled/SwitchUnstyled.tsx | 211 +++++++++
.../src/SwitchUnstyled/index.ts | 6 +
.../SwitchUnstyled/switchUnstyledClasses.ts | 37 ++
.../src/SwitchUnstyled/useSwitch.test.tsx | 86 ++++
.../src/SwitchUnstyled/useSwitch.ts | 185 ++++++++
packages/material-ui-unstyled/src/index.d.ts | 3 +
packages/material-ui-unstyled/src/index.js | 3 +
.../material-ui-unstyled/src/utils/index.d.ts | 3 -
.../src/utils/{index.js => index.ts} | 0
.../src/utils/isHostComponent.js | 5 -
.../src/utils/isHostComponent.ts | 10 +
.../material-ui-unstyled/tsconfig.build.json | 4 +-
.../src/ButtonBase/TouchRipple.d.ts | 17 +-
.../material-ui/src/Switch/Switch.test.js | 14 +
.../material-ui/src/useTouchRipple/index.ts | 1 +
.../src/useTouchRipple/useTouchRipple.ts | 161 +++++++
test/utils/describeConformance.js | 3 +-
test/utils/describeConformanceUnstyled.tsx | 297 ++++++++++++
test/utils/index.js | 1 +
43 files changed, 2582 insertions(+), 19 deletions(-)
create mode 100644 docs/pages/api-docs/switch-unstyled.js
create mode 100644 docs/pages/api-docs/switch-unstyled.json
create mode 100644 docs/src/pages/components/switches/UnstyledSwitches.js
create mode 100644 docs/src/pages/components/switches/UnstyledSwitches.tsx
create mode 100644 docs/src/pages/components/switches/UnstyledSwitchesMaterial.js
create mode 100644 docs/src/pages/components/switches/UseSwitchesBasic.js
create mode 100644 docs/src/pages/components/switches/UseSwitchesBasic.tsx
create mode 100644 docs/src/pages/components/switches/UseSwitchesCustom.js
create mode 100644 docs/src/pages/components/switches/UseSwitchesCustom.tsx
create mode 100644 docs/src/pages/components/switches/UseSwitchesMaterial.js
create mode 100644 docs/translations/api-docs/switch-unstyled/switch-unstyled-de.json
create mode 100644 docs/translations/api-docs/switch-unstyled/switch-unstyled-es.json
create mode 100644 docs/translations/api-docs/switch-unstyled/switch-unstyled-fr.json
create mode 100644 docs/translations/api-docs/switch-unstyled/switch-unstyled-ja.json
create mode 100644 docs/translations/api-docs/switch-unstyled/switch-unstyled-pt.json
create mode 100644 docs/translations/api-docs/switch-unstyled/switch-unstyled-ru.json
create mode 100644 docs/translations/api-docs/switch-unstyled/switch-unstyled-zh.json
create mode 100644 docs/translations/api-docs/switch-unstyled/switch-unstyled.json
create mode 100644 packages/material-ui-unstyled/src/SwitchUnstyled/SwitchUnstyled.test.tsx
create mode 100644 packages/material-ui-unstyled/src/SwitchUnstyled/SwitchUnstyled.tsx
create mode 100644 packages/material-ui-unstyled/src/SwitchUnstyled/index.ts
create mode 100644 packages/material-ui-unstyled/src/SwitchUnstyled/switchUnstyledClasses.ts
create mode 100644 packages/material-ui-unstyled/src/SwitchUnstyled/useSwitch.test.tsx
create mode 100644 packages/material-ui-unstyled/src/SwitchUnstyled/useSwitch.ts
delete mode 100644 packages/material-ui-unstyled/src/utils/index.d.ts
rename packages/material-ui-unstyled/src/utils/{index.js => index.ts} (100%)
delete mode 100644 packages/material-ui-unstyled/src/utils/isHostComponent.js
create mode 100644 packages/material-ui-unstyled/src/utils/isHostComponent.ts
create mode 100644 packages/material-ui/src/useTouchRipple/index.ts
create mode 100644 packages/material-ui/src/useTouchRipple/useTouchRipple.ts
create mode 100644 test/utils/describeConformanceUnstyled.tsx
diff --git a/docs/pages/api-docs/switch-unstyled.js b/docs/pages/api-docs/switch-unstyled.js
new file mode 100644
index 00000000000000..cfe5e8e70f3db4
--- /dev/null
+++ b/docs/pages/api-docs/switch-unstyled.js
@@ -0,0 +1,23 @@
+import * as React from 'react';
+import ApiPage from 'docs/src/modules/components/ApiPage';
+import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations';
+import jsonPageContent from './switch-unstyled.json';
+
+export default function Page(props) {
+ const { descriptions, pageContent } = props;
+ return ;
+}
+
+Page.getInitialProps = () => {
+ const req = require.context(
+ 'docs/translations/api-docs/switch-unstyled',
+ false,
+ /switch-unstyled.*.json$/,
+ );
+ const descriptions = mapApiPageTranslations(req);
+
+ return {
+ descriptions,
+ pageContent: jsonPageContent,
+ };
+};
diff --git a/docs/pages/api-docs/switch-unstyled.json b/docs/pages/api-docs/switch-unstyled.json
new file mode 100644
index 00000000000000..f8a148346b7227
--- /dev/null
+++ b/docs/pages/api-docs/switch-unstyled.json
@@ -0,0 +1,29 @@
+{
+ "props": {
+ "checked": { "type": { "name": "bool" } },
+ "className": { "type": { "name": "string" } },
+ "component": { "type": { "name": "elementType" } },
+ "components": {
+ "type": {
+ "name": "shape",
+ "description": "{ Input?: elementType, Root?: elementType, Thumb?: elementType }"
+ },
+ "default": "{}"
+ },
+ "componentsProps": { "type": { "name": "object" }, "default": "{}" },
+ "defaultChecked": { "type": { "name": "bool" } },
+ "disabled": { "type": { "name": "bool" } },
+ "onChange": { "type": { "name": "func" } },
+ "readOnly": { "type": { "name": "bool" } },
+ "required": { "type": { "name": "bool" } }
+ },
+ "name": "SwitchUnstyled",
+ "styles": { "classes": [], "globalClasses": {}, "name": null },
+ "spread": true,
+ "forwardsRefTo": "HTMLSpanElement",
+ "filename": "/packages/material-ui-unstyled/src/SwitchUnstyled/SwitchUnstyled.tsx",
+ "inheritance": null,
+ "demos": "",
+ "styledComponent": true,
+ "cssComponent": false
+}
diff --git a/docs/src/modules/utils/parseTest.ts b/docs/src/modules/utils/parseTest.ts
index 86e6998e87bd36..ce88c0a05f3767 100644
--- a/docs/src/modules/utils/parseTest.ts
+++ b/docs/src/modules/utils/parseTest.ts
@@ -34,10 +34,7 @@ function findConformanceDescriptor(file: babel.ParseResult): babel.types.ObjectE
CallExpression(babelPath) {
const { node: callExpression } = babelPath;
const { callee } = callExpression;
- if (
- t.isIdentifier(callee) &&
- (callee.name === 'describeConformance' || callee.name === 'describeConformanceV5')
- ) {
+ if (t.isIdentifier(callee) && callee.name.startsWith('describeConformance')) {
const [, optionsFactory] = callExpression.arguments;
if (
t.isArrowFunctionExpression(optionsFactory) &&
diff --git a/docs/src/pages/components/switches/UnstyledSwitches.js b/docs/src/pages/components/switches/UnstyledSwitches.js
new file mode 100644
index 00000000000000..37667cb6f74c90
--- /dev/null
+++ b/docs/src/pages/components/switches/UnstyledSwitches.js
@@ -0,0 +1,73 @@
+import * as React from 'react';
+import { styled } from '@material-ui/system';
+import SwitchUnstyled, {
+ switchUnstyledClasses,
+} from '@material-ui/unstyled/SwitchUnstyled';
+
+const Root = styled('span')(`
+ font-size: 0;
+ position: relative;
+ display: inline-block;
+ width: 32px;
+ height: 20px;
+ background: #B3C3D3;
+ border-radius: 10px;
+ margin: 10px;
+ cursor: pointer;
+
+ &.${switchUnstyledClasses.disabled} {
+ opacity: 0.4;
+ cursor: not-allowed;
+ }
+
+ &.${switchUnstyledClasses.checked} {
+ background: #007FFF;
+ }
+
+ & .${switchUnstyledClasses.thumb} {
+ display: block;
+ width: 14px;
+ height: 14px;
+ top: 3px;
+ left: 3px;
+ border-radius: 16px;
+ background-color: #FFF;
+ position: relative;
+ transition: all 200ms ease;
+ }
+
+ &.${switchUnstyledClasses.focusVisible} .${switchUnstyledClasses.thumb} {
+ background-color: rgba(255,255,255,1);
+ box-shadow: 0 0 1px 8px rgba(0,0,0,0.25);
+ }
+
+ &.${switchUnstyledClasses.checked} .${switchUnstyledClasses.thumb} {
+ left: 14px;
+ top: 3px;
+ background-color: #FFF;
+ }
+
+ & .${switchUnstyledClasses.input} {
+ cursor: inherit;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ opacity: 0;
+ z-index: 1;
+ margin: 0;
+ }`);
+
+export default function UnstyledSwitches() {
+ const label = { componentsProps: { input: { 'aria-label': 'Demo switch' } } };
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/docs/src/pages/components/switches/UnstyledSwitches.tsx b/docs/src/pages/components/switches/UnstyledSwitches.tsx
new file mode 100644
index 00000000000000..37667cb6f74c90
--- /dev/null
+++ b/docs/src/pages/components/switches/UnstyledSwitches.tsx
@@ -0,0 +1,73 @@
+import * as React from 'react';
+import { styled } from '@material-ui/system';
+import SwitchUnstyled, {
+ switchUnstyledClasses,
+} from '@material-ui/unstyled/SwitchUnstyled';
+
+const Root = styled('span')(`
+ font-size: 0;
+ position: relative;
+ display: inline-block;
+ width: 32px;
+ height: 20px;
+ background: #B3C3D3;
+ border-radius: 10px;
+ margin: 10px;
+ cursor: pointer;
+
+ &.${switchUnstyledClasses.disabled} {
+ opacity: 0.4;
+ cursor: not-allowed;
+ }
+
+ &.${switchUnstyledClasses.checked} {
+ background: #007FFF;
+ }
+
+ & .${switchUnstyledClasses.thumb} {
+ display: block;
+ width: 14px;
+ height: 14px;
+ top: 3px;
+ left: 3px;
+ border-radius: 16px;
+ background-color: #FFF;
+ position: relative;
+ transition: all 200ms ease;
+ }
+
+ &.${switchUnstyledClasses.focusVisible} .${switchUnstyledClasses.thumb} {
+ background-color: rgba(255,255,255,1);
+ box-shadow: 0 0 1px 8px rgba(0,0,0,0.25);
+ }
+
+ &.${switchUnstyledClasses.checked} .${switchUnstyledClasses.thumb} {
+ left: 14px;
+ top: 3px;
+ background-color: #FFF;
+ }
+
+ & .${switchUnstyledClasses.input} {
+ cursor: inherit;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ opacity: 0;
+ z-index: 1;
+ margin: 0;
+ }`);
+
+export default function UnstyledSwitches() {
+ const label = { componentsProps: { input: { 'aria-label': 'Demo switch' } } };
+
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/docs/src/pages/components/switches/UnstyledSwitchesMaterial.js b/docs/src/pages/components/switches/UnstyledSwitchesMaterial.js
new file mode 100644
index 00000000000000..b10b4a1793bb26
--- /dev/null
+++ b/docs/src/pages/components/switches/UnstyledSwitchesMaterial.js
@@ -0,0 +1,435 @@
+/* eslint-disable no-restricted-imports, react/prop-types */
+import * as React from 'react';
+import clsx from 'clsx';
+import {
+ SwitchUnstyled,
+ unstable_composeClasses as composeClasses,
+} from '@material-ui/unstyled';
+import { alpha, darken, lighten, useThemeProps, styled } from '@material-ui/system';
+import { ThemeProvider, createTheme } from '@material-ui/core/styles';
+import { capitalize } from '@material-ui/core/utils';
+import {
+ useFormControl,
+ switchClasses,
+ getSwitchUtilityClass,
+} from '@material-ui/core';
+import TouchRipple from '@material-ui/core/ButtonBase/TouchRipple';
+import useTouchRipple from '@material-ui/core/useTouchRipple';
+
+const useUtilityClasses = (styleProps) => {
+ const { classes, edge, size, color, checked, disabled, focusVisible } = styleProps;
+
+ const slots = {
+ root: [
+ edge && `edge${capitalize(edge)}`,
+ `size${capitalize(size)}`,
+ `color${capitalize(color)}`,
+ ],
+ switchBase: [
+ 'switchBase',
+ `color${capitalize(color)}`,
+ focusVisible && 'focusVisible',
+ checked && 'checked',
+ disabled && 'disabled',
+ ],
+ track: ['track'],
+ };
+
+ return composeClasses(slots, getSwitchUtilityClass, classes);
+};
+
+const SwitchTrack = styled('span', {
+ name: 'MuiSwitch',
+ slot: 'Track',
+ overridesResolver: (props, styles) => styles.track,
+})(({ theme }) => ({
+ height: '100%',
+ width: '100%',
+ borderRadius: 14 / 2,
+ zIndex: -1,
+ transition: theme.transitions.create(['opacity', 'background-color'], {
+ duration: theme.transitions.duration.shortest,
+ }),
+ backgroundColor:
+ theme.palette.mode === 'light'
+ ? theme.palette.common.black
+ : theme.palette.common.white,
+ opacity: theme.palette.mode === 'light' ? 0.38 : 0.3,
+}));
+
+const SwitchBase = styled('span', {
+ name: 'MuiSwitch',
+ slot: 'SwitchBase',
+ overridesResolver: (props, styles) => {
+ const { styleProps } = props;
+
+ return {
+ ...styles.switchBase,
+ ...styles.input,
+ ...(styleProps.color !== 'default' &&
+ styles[`color${capitalize(styleProps.color)}`]),
+ };
+ },
+})(
+ ({ theme, styleProps }) => ({
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ zIndex: 1,
+ color:
+ theme.palette.mode === 'light'
+ ? theme.palette.common.white
+ : theme.palette.grey[300],
+ transition: theme.transitions.create(['left', 'transform'], {
+ duration: theme.transitions.duration.shortest,
+ }),
+ padding: 9,
+ borderRadius: '50%',
+ ...(styleProps.edge === 'start' && {
+ marginLeft: styleProps.size === 'small' ? -3 : -12,
+ }),
+ ...(styleProps.edge === 'end' && {
+ marginRight: styleProps.size === 'small' ? -3 : -12,
+ }),
+ display: 'inline-flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ boxSizing: 'border-box',
+ WebkitTapHighlightColor: 'transparent',
+ backgroundColor: 'transparent',
+ outline: 0,
+ border: 0,
+ margin: 0,
+ cursor: 'pointer',
+ userSelect: 'none',
+ verticalAlign: 'middle',
+ MozAppearance: 'none',
+ WebkitAppearance: 'none',
+ textDecoration: 'none',
+ '&::-moz-focus-inner': {
+ borderStyle: 'none',
+ },
+ '@media print': {
+ colorAdjust: 'exact',
+ },
+ [`&.${switchClasses.checked}`]: {
+ transform: 'translateX(20px)',
+ },
+ [`&.${switchClasses.disabled}`]: {
+ color:
+ theme.palette.mode === 'light'
+ ? theme.palette.grey[100]
+ : theme.palette.grey[600],
+ pointerEvents: 'none',
+ cursor: 'default',
+ },
+ [`&.${switchClasses.checked} + .${switchClasses.track}`]: {
+ opacity: 0.5,
+ },
+ [`&.${switchClasses.disabled} + .${switchClasses.track}`]: {
+ opacity: theme.palette.mode === 'light' ? 0.12 : 0.2,
+ },
+ }),
+ ({ theme, styleProps }) => ({
+ '&:hover': {
+ backgroundColor: alpha(
+ theme.palette.action.active,
+ theme.palette.action.hoverOpacity,
+ ),
+ '@media (hover: none)': {
+ backgroundColor: 'transparent',
+ },
+ },
+ ...(styleProps.color !== 'default' && {
+ [`&.${switchClasses.checked}`]: {
+ color: theme.palette[styleProps.color].main,
+ '&:hover': {
+ backgroundColor: alpha(
+ theme.palette[styleProps.color].main,
+ theme.palette.action.hoverOpacity,
+ ),
+ '@media (hover: none)': {
+ backgroundColor: 'transparent',
+ },
+ },
+ [`&.${switchClasses.disabled}`]: {
+ color:
+ theme.palette.mode === 'light'
+ ? lighten(theme.palette[styleProps.color].main, 0.62)
+ : darken(theme.palette[styleProps.color].main, 0.55),
+ },
+ },
+ [`&.${switchClasses.checked} + .${switchClasses.track}`]: {
+ backgroundColor: theme.palette[styleProps.color].main,
+ },
+ }),
+ }),
+);
+
+const SwitchRoot = styled('span', {
+ name: 'MuiSwitch',
+ slot: 'Root',
+ overridesResolver: (props, styles) => {
+ const { styleProps } = props;
+
+ return {
+ ...styles.root,
+ ...(styleProps.edge && styles[`edge${capitalize(styleProps.edge)}`]),
+ ...styles[`size${capitalize(styleProps.size)}`],
+ ...styles.input,
+ ...(styleProps.color !== 'default' &&
+ styles[`color${capitalize(styleProps.color)}`]),
+ };
+ },
+})(({ styleProps }) => ({
+ display: 'inline-flex',
+ width: 34 + 12 * 2,
+ height: 14 + 12 * 2,
+ overflow: 'hidden',
+ padding: 12,
+ boxSizing: 'border-box',
+ position: 'relative',
+ flexShrink: 0,
+ zIndex: 0,
+ verticalAlign: 'middle',
+ '@media print': {
+ colorAdjust: 'exact',
+ },
+ ...(styleProps.edge === 'start' && {
+ marginLeft: -8,
+ }),
+ ...(styleProps.edge === 'end' && {
+ marginRight: -8,
+ }),
+ ...(styleProps.size === 'small' && {
+ width: 40,
+ height: 24,
+ padding: 7,
+ [`& .${switchClasses.thumb}`]: {
+ width: 16,
+ height: 16,
+ },
+ [`& .${switchClasses.switchBase}`]: {
+ padding: 4,
+ [`&.${switchClasses.checked}`]: {
+ transform: 'translateX(16px)',
+ },
+ },
+ }),
+}));
+
+const SwitchInput = styled('input', {
+ name: 'MuiSwitch',
+ slot: 'Input',
+ skipSx: true,
+})({
+ cursor: 'inherit',
+ position: 'absolute',
+ opacity: 0,
+ width: '300%',
+ height: '100%',
+ top: 0,
+ left: '-100%',
+ margin: 0,
+ padding: 0,
+ zIndex: 1,
+});
+
+const SwitchThumb = styled(
+ ({ isChecked, icon, checkedIcon, className }) => {
+ if (!isChecked && icon) {
+ return icon;
+ }
+
+ if (isChecked && checkedIcon) {
+ return checkedIcon;
+ }
+
+ return ;
+ },
+ {
+ name: 'MuiSwitch',
+ slot: 'Thumb',
+ overridesResolver: (props, styles) => styles.thumb,
+ },
+)(({ theme }) => ({
+ boxShadow: theme.shadows[1],
+ backgroundColor: 'currentColor',
+ width: 20,
+ height: 20,
+ borderRadius: '50%',
+}));
+
+const SwitchLayout = React.forwardRef((props, ref) => {
+ const {
+ className,
+ disableRipple,
+ disableTouchRipple,
+ disableFocusRipple,
+ styleProps,
+ TouchRippleProps,
+ children,
+ onFocus,
+ onBlur,
+ ...other
+ } = props;
+
+ const { checked, disabled, focusVisible } = styleProps;
+
+ const rippleRef = React.useRef(null);
+
+ const { enableTouchRipple, getRippleHandlers } = useTouchRipple({
+ rippleRef,
+ focusVisible,
+ disabled,
+ disableRipple,
+ disableTouchRipple,
+ disableFocusRipple,
+ });
+
+ const rippleHandlers = getRippleHandlers({
+ onBlur,
+ });
+
+ const classes = useUtilityClasses({
+ ...styleProps,
+ checked,
+ disabled,
+ focusVisible,
+ });
+
+ return (
+
+
+ {children}
+ {enableTouchRipple && (
+
+ )}
+
+
+
+ );
+});
+
+const Switch = React.forwardRef(function Switch(inProps, ref) {
+ const props = useThemeProps({ props: inProps, name: 'MuiSwitch' });
+
+ const {
+ checked: checkedProp,
+ checkedIcon,
+ className,
+ color = 'primary',
+ disabled: disabledProp,
+ disableFocusRipple = false,
+ disableRipple = false,
+ disableTouchRipple = false,
+ edge = false,
+ icon,
+ inputProps,
+ onBlur,
+ onFocus,
+ size = 'medium',
+ TouchRippleProps,
+ ...other
+ } = props;
+
+ const muiFormControl = useFormControl();
+
+ const handleFocus = (event) => {
+ onFocus?.(event);
+
+ if (muiFormControl && muiFormControl.onFocus) {
+ muiFormControl.onFocus(event);
+ }
+ };
+
+ const handleBlur = (event) => {
+ onBlur?.(event);
+
+ if (muiFormControl && muiFormControl.onBlur) {
+ muiFormControl.onBlur(event);
+ }
+ };
+
+ let disabled = disabledProp;
+
+ if (muiFormControl) {
+ if (typeof disabled === 'undefined') {
+ disabled = muiFormControl.disabled;
+ }
+ }
+
+ const styleProps = {
+ ...props,
+ color,
+ edge,
+ size,
+ disableFocusRipple,
+ disableRipple,
+ disableTouchRipple,
+ };
+
+ const components = {
+ Root: SwitchLayout,
+ Input: SwitchInput,
+ Thumb: SwitchThumb,
+ };
+
+ const componentsProps = {
+ root: {
+ className,
+ styleProps,
+ disableFocusRipple,
+ disableRipple,
+ disableTouchRipple,
+ onBlur: handleBlur,
+ onFocus: handleFocus,
+ TouchRippleProps,
+ },
+ input: {
+ styleProps,
+ ...inputProps,
+ },
+ thumb: {
+ styleProps,
+ icon,
+ checkedIcon,
+ defaultThumbClassName: switchClasses.thumb,
+ },
+ };
+
+ return (
+
+ );
+});
+
+const label = { inputProps: { 'aria-label': 'Switch demo' } };
+
+export default function UseSwitchesCustom() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/docs/src/pages/components/switches/UseSwitchesBasic.js b/docs/src/pages/components/switches/UseSwitchesBasic.js
new file mode 100644
index 00000000000000..ca314dc286fa42
--- /dev/null
+++ b/docs/src/pages/components/switches/UseSwitchesBasic.js
@@ -0,0 +1,88 @@
+import * as React from 'react';
+import clsx from 'clsx';
+import { styled } from '@material-ui/system';
+import { useSwitch } from '@material-ui/unstyled/SwitchUnstyled';
+
+const BasicSwitchRoot = styled('span')(`
+ font-size: 0;
+ position: relative;
+ display: inline-block;
+ width: 32px;
+ height: 20px;
+ background: #B3C3D3;
+ border-radius: 10px;
+ margin: 10px;
+ cursor: pointer;
+
+ &.Switch-disabled {
+ opacity: 0.4;
+ cursor: not-allowed;
+ }
+
+ &.Switch-checked {
+ background: #007FFF;
+ }
+`);
+
+const BasicSwitchInput = styled('input')(`
+ cursor: inherit;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ opacity: 0;
+ z-index: 1;
+ margin: 0;
+`);
+
+const BasicSwitchThumb = styled('span')(`
+ display: block;
+ width: 14px;
+ height: 14px;
+ top: 3px;
+ left: 3px;
+ border-radius: 16px;
+ background-color: #FFF;
+ position: relative;
+ transition: all 200ms ease;
+
+ &.Switch-focusVisible {
+ background-color: rgba(255,255,255,1);
+ box-shadow: 0 0 1px 8px rgba(0,0,0,0.25);
+ }
+
+ &.Switch-checked {
+ left: 14px;
+ top: 3px;
+ background-color: #FFF;
+ }
+`);
+
+function BasicSwitch(props) {
+ const { getInputProps, checked, disabled, focusVisible } = useSwitch(props);
+
+ const stateClasses = {
+ 'Switch-checked': checked,
+ 'Switch-disabled': disabled,
+ 'Switch-focusVisible': focusVisible,
+ };
+
+ return (
+
+
+
+
+ );
+}
+
+export default function UseSwitchesBasic() {
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/docs/src/pages/components/switches/UseSwitchesBasic.tsx b/docs/src/pages/components/switches/UseSwitchesBasic.tsx
new file mode 100644
index 00000000000000..3ab1747730677b
--- /dev/null
+++ b/docs/src/pages/components/switches/UseSwitchesBasic.tsx
@@ -0,0 +1,88 @@
+import * as React from 'react';
+import clsx from 'clsx';
+import { styled } from '@material-ui/system';
+import { useSwitch, UseSwitchProps } from '@material-ui/unstyled/SwitchUnstyled';
+
+const BasicSwitchRoot = styled('span')(`
+ font-size: 0;
+ position: relative;
+ display: inline-block;
+ width: 32px;
+ height: 20px;
+ background: #B3C3D3;
+ border-radius: 10px;
+ margin: 10px;
+ cursor: pointer;
+
+ &.Switch-disabled {
+ opacity: 0.4;
+ cursor: not-allowed;
+ }
+
+ &.Switch-checked {
+ background: #007FFF;
+ }
+`);
+
+const BasicSwitchInput = styled('input')(`
+ cursor: inherit;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ opacity: 0;
+ z-index: 1;
+ margin: 0;
+`);
+
+const BasicSwitchThumb = styled('span')(`
+ display: block;
+ width: 14px;
+ height: 14px;
+ top: 3px;
+ left: 3px;
+ border-radius: 16px;
+ background-color: #FFF;
+ position: relative;
+ transition: all 200ms ease;
+
+ &.Switch-focusVisible {
+ background-color: rgba(255,255,255,1);
+ box-shadow: 0 0 1px 8px rgba(0,0,0,0.25);
+ }
+
+ &.Switch-checked {
+ left: 14px;
+ top: 3px;
+ background-color: #FFF;
+ }
+`);
+
+function BasicSwitch(props: UseSwitchProps) {
+ const { getInputProps, checked, disabled, focusVisible } = useSwitch(props);
+
+ const stateClasses = {
+ 'Switch-checked': checked,
+ 'Switch-disabled': disabled,
+ 'Switch-focusVisible': focusVisible,
+ };
+
+ return (
+
+
+
+
+ );
+}
+
+export default function UseSwitchesBasic() {
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/docs/src/pages/components/switches/UseSwitchesCustom.js b/docs/src/pages/components/switches/UseSwitchesCustom.js
new file mode 100644
index 00000000000000..085ff97af5edde
--- /dev/null
+++ b/docs/src/pages/components/switches/UseSwitchesCustom.js
@@ -0,0 +1,95 @@
+import * as React from 'react';
+import clsx from 'clsx';
+import { styled } from '@material-ui/system';
+import { useSwitch } from '@material-ui/unstyled/SwitchUnstyled';
+
+const SwitchRoot = styled('span')(`
+ display: inline-block;
+ position: relative;
+ width: 62px;
+ height: 34px;
+ padding: 7px;
+`);
+
+const SwitchInput = styled('input')(`
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ opacity: 0;
+ z-index: 1;
+ margin: 0;
+ cursor: pointer;
+`);
+
+const SwitchThumb = styled('span')(
+ ({ theme }) => `
+ position: absolute;
+ display: block;
+ background-color: ${theme.palette.mode === 'dark' ? '#003892' : '#001e3c'};
+ width: 32px;
+ height: 32px;
+ border-radius: 16px;
+ top: 1px;
+ left: 7px;
+ transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
+
+ &:before {
+ display: block;
+ content: "";
+ width: 100%;
+ height: 100%;
+ background: url('data:image/svg+xml;utf8, ') center center no-repeat;
+ }
+
+ &.focusVisible {
+ background-color: #79B;
+ }
+
+ &.checked {
+ transform: translateX(16px);
+
+ &:before {
+ background-image: url('data:image/svg+xml;utf8, ');
+ }
+ }
+`,
+);
+
+const SwitchTrack = styled('span')(
+ ({ theme }) => `
+ background-color: ${theme.palette.mode === 'dark' ? '#8796A5' : '#aab4be'};
+ border-radius: 10px;
+ width: 100%;
+ height: 100%;
+ display: block;
+`,
+);
+
+function MUISwitch(props) {
+ const { getInputProps, checked, disabled, focusVisible } = useSwitch(props);
+
+ const stateClasses = {
+ checked,
+ disabled,
+ focusVisible,
+ };
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default function UseSwitchesCustom() {
+ return ;
+}
diff --git a/docs/src/pages/components/switches/UseSwitchesCustom.tsx b/docs/src/pages/components/switches/UseSwitchesCustom.tsx
new file mode 100644
index 00000000000000..7dbeeaba86d759
--- /dev/null
+++ b/docs/src/pages/components/switches/UseSwitchesCustom.tsx
@@ -0,0 +1,95 @@
+import * as React from 'react';
+import clsx from 'clsx';
+import { styled } from '@material-ui/system';
+import { useSwitch, UseSwitchProps } from '@material-ui/unstyled/SwitchUnstyled';
+
+const SwitchRoot = styled('span')(`
+ display: inline-block;
+ position: relative;
+ width: 62px;
+ height: 34px;
+ padding: 7px;
+`);
+
+const SwitchInput = styled('input')(`
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ opacity: 0;
+ z-index: 1;
+ margin: 0;
+ cursor: pointer;
+`);
+
+const SwitchThumb = styled('span')(
+ ({ theme }) => `
+ position: absolute;
+ display: block;
+ background-color: ${theme.palette.mode === 'dark' ? '#003892' : '#001e3c'};
+ width: 32px;
+ height: 32px;
+ border-radius: 16px;
+ top: 1px;
+ left: 7px;
+ transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
+
+ &:before {
+ display: block;
+ content: "";
+ width: 100%;
+ height: 100%;
+ background: url('data:image/svg+xml;utf8, ') center center no-repeat;
+ }
+
+ &.focusVisible {
+ background-color: #79B;
+ }
+
+ &.checked {
+ transform: translateX(16px);
+
+ &:before {
+ background-image: url('data:image/svg+xml;utf8, ');
+ }
+ }
+`,
+);
+
+const SwitchTrack = styled('span')(
+ ({ theme }) => `
+ background-color: ${theme.palette.mode === 'dark' ? '#8796A5' : '#aab4be'};
+ border-radius: 10px;
+ width: 100%;
+ height: 100%;
+ display: block;
+`,
+);
+
+function MUISwitch(props: UseSwitchProps) {
+ const { getInputProps, checked, disabled, focusVisible } = useSwitch(props);
+
+ const stateClasses = {
+ checked,
+ disabled,
+ focusVisible,
+ };
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default function UseSwitchesCustom() {
+ return ;
+}
diff --git a/docs/src/pages/components/switches/UseSwitchesMaterial.js b/docs/src/pages/components/switches/UseSwitchesMaterial.js
new file mode 100644
index 00000000000000..8ae78b8a8e0132
--- /dev/null
+++ b/docs/src/pages/components/switches/UseSwitchesMaterial.js
@@ -0,0 +1,399 @@
+/* eslint-disable no-restricted-imports, react/prop-types */
+import * as React from 'react';
+import clsx from 'clsx';
+import {
+ unstable_composeClasses as composeClasses,
+ useSwitch,
+} from '@material-ui/unstyled';
+import { alpha, darken, lighten, useThemeProps, styled } from '@material-ui/system';
+import { ThemeProvider, createTheme } from '@material-ui/core/styles';
+import { capitalize } from '@material-ui/core/utils';
+import {
+ useFormControl,
+ switchClasses,
+ getSwitchUtilityClass,
+} from '@material-ui/core';
+import TouchRipple from '@material-ui/core/ButtonBase/TouchRipple';
+import useTouchRipple from '@material-ui/core/useTouchRipple';
+
+const useUtilityClasses = (styleProps) => {
+ const { classes, edge, size, color, checked, disabled, focusVisible } = styleProps;
+
+ const slots = {
+ root: [
+ 'root',
+ checked && 'checked',
+ disabled && 'disabled',
+ edge && `edge${capitalize(edge)}`,
+ `size${capitalize(size)}`,
+ `color${capitalize(color)}`,
+ ],
+ switchBase: [
+ 'switchBase',
+ `color${capitalize(color)}`,
+ focusVisible && 'focusVisible',
+ checked && 'checked',
+ disabled && 'disabled',
+ ],
+ thumb: ['thumb'],
+ track: ['track'],
+ input: ['input'],
+ };
+
+ const composedClasses = composeClasses(slots, getSwitchUtilityClass, classes);
+
+ return {
+ ...classes,
+ ...composedClasses,
+ };
+};
+
+const SwitchTrack = styled('span', {
+ name: 'MuiSwitch',
+ slot: 'Track',
+ overridesResolver: (props, styles) => styles.track,
+})(({ theme }) => ({
+ height: '100%',
+ width: '100%',
+ borderRadius: 14 / 2,
+ zIndex: -1,
+ transition: theme.transitions.create(['opacity', 'background-color'], {
+ duration: theme.transitions.duration.shortest,
+ }),
+ backgroundColor:
+ theme.palette.mode === 'light'
+ ? theme.palette.common.black
+ : theme.palette.common.white,
+ opacity: theme.palette.mode === 'light' ? 0.38 : 0.3,
+}));
+
+const SwitchBase = styled('span', {
+ name: 'MuiSwitch',
+ slot: 'SwitchBase',
+ overridesResolver: (props, styles) => {
+ const { styleProps } = props;
+
+ return {
+ ...styles.switchBase,
+ ...styles.input,
+ ...(styleProps.color !== 'default' &&
+ styles[`color${capitalize(styleProps.color)}`]),
+ };
+ },
+})(
+ ({ theme, styleProps }) => ({
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ zIndex: 1,
+ color:
+ theme.palette.mode === 'light'
+ ? theme.palette.common.white
+ : theme.palette.grey[300],
+ transition: theme.transitions.create(['left', 'transform'], {
+ duration: theme.transitions.duration.shortest,
+ }),
+ padding: 9,
+ borderRadius: '50%',
+ ...(styleProps.edge === 'start' && {
+ marginLeft: styleProps.size === 'small' ? -3 : -12,
+ }),
+ ...(styleProps.edge === 'end' && {
+ marginRight: styleProps.size === 'small' ? -3 : -12,
+ }),
+ display: 'inline-flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ boxSizing: 'border-box',
+ WebkitTapHighlightColor: 'transparent',
+ backgroundColor: 'transparent',
+ outline: 0,
+ border: 0,
+ margin: 0,
+ cursor: 'pointer',
+ userSelect: 'none',
+ verticalAlign: 'middle',
+ MozAppearance: 'none',
+ WebkitAppearance: 'none',
+ textDecoration: 'none',
+ '&::-moz-focus-inner': {
+ borderStyle: 'none',
+ },
+ '@media print': {
+ colorAdjust: 'exact',
+ },
+ [`&.${switchClasses.checked}`]: {
+ transform: 'translateX(20px)',
+ },
+ [`&.${switchClasses.disabled}`]: {
+ color:
+ theme.palette.mode === 'light'
+ ? theme.palette.grey[100]
+ : theme.palette.grey[600],
+ pointerEvents: 'none',
+ cursor: 'default',
+ },
+ [`&.${switchClasses.checked} + .${switchClasses.track}`]: {
+ opacity: 0.5,
+ },
+ [`&.${switchClasses.disabled} + .${switchClasses.track}`]: {
+ opacity: theme.palette.mode === 'light' ? 0.12 : 0.2,
+ },
+ }),
+ ({ theme, styleProps }) => ({
+ '&:hover': {
+ backgroundColor: alpha(
+ theme.palette.action.active,
+ theme.palette.action.hoverOpacity,
+ ),
+ '@media (hover: none)': {
+ backgroundColor: 'transparent',
+ },
+ },
+ ...(styleProps.color !== 'default' && {
+ [`&.${switchClasses.checked}`]: {
+ color: theme.palette[styleProps.color].main,
+ '&:hover': {
+ backgroundColor: alpha(
+ theme.palette[styleProps.color].main,
+ theme.palette.action.hoverOpacity,
+ ),
+ '@media (hover: none)': {
+ backgroundColor: 'transparent',
+ },
+ },
+ [`&.${switchClasses.disabled}`]: {
+ color:
+ theme.palette.mode === 'light'
+ ? lighten(theme.palette[styleProps.color].main, 0.62)
+ : darken(theme.palette[styleProps.color].main, 0.55),
+ },
+ },
+ [`&.${switchClasses.checked} + .${switchClasses.track}`]: {
+ backgroundColor: theme.palette[styleProps.color].main,
+ },
+ }),
+ }),
+);
+
+const SwitchRoot = styled('span', {
+ name: 'MuiSwitch',
+ slot: 'Root',
+ overridesResolver: (props, styles) => {
+ const { styleProps } = props;
+
+ return {
+ ...styles.root,
+ ...(styleProps.edge && styles[`edge${capitalize(styleProps.edge)}`]),
+ ...styles[`size${capitalize(styleProps.size)}`],
+ ...styles.input,
+ ...(styleProps.color !== 'default' &&
+ styles[`color${capitalize(styleProps.color)}`]),
+ };
+ },
+})(({ styleProps }) => ({
+ display: 'inline-flex',
+ width: 34 + 12 * 2,
+ height: 14 + 12 * 2,
+ overflow: 'hidden',
+ padding: 12,
+ boxSizing: 'border-box',
+ position: 'relative',
+ flexShrink: 0,
+ zIndex: 0,
+ verticalAlign: 'middle',
+ '@media print': {
+ colorAdjust: 'exact',
+ },
+ ...(styleProps.edge === 'start' && {
+ marginLeft: -8,
+ }),
+ ...(styleProps.edge === 'end' && {
+ marginRight: -8,
+ }),
+ ...(styleProps.size === 'small' && {
+ width: 40,
+ height: 24,
+ padding: 7,
+ [`& .${switchClasses.thumb}`]: {
+ width: 16,
+ height: 16,
+ },
+ [`& .${switchClasses.switchBase}`]: {
+ padding: 4,
+ [`&.${switchClasses.checked}`]: {
+ transform: 'translateX(16px)',
+ },
+ },
+ }),
+}));
+
+const SwitchThumb = styled('span', {
+ name: 'MuiSwitch',
+ slot: 'Thumb',
+ overridesResolver: (props, styles) => styles.thumb,
+})(({ theme }) => ({
+ boxShadow: theme.shadows[1],
+ backgroundColor: 'currentColor',
+ width: 20,
+ height: 20,
+ borderRadius: '50%',
+}));
+
+const SwitchInput = styled('input', {
+ name: 'MuiSwitch',
+ slot: 'Input',
+ skipSx: true,
+})({
+ cursor: 'inherit',
+ position: 'absolute',
+ opacity: 0,
+ width: '300%',
+ height: '100%',
+ top: 0,
+ left: '-100%',
+ margin: 0,
+ padding: 0,
+ zIndex: 1,
+});
+
+const renderThumb = (isChecked, icon, checkedIcon, defaultThumbClassName) => {
+ if (!isChecked && icon) {
+ return icon;
+ }
+
+ if (isChecked && checkedIcon) {
+ return checkedIcon;
+ }
+
+ return ;
+};
+
+const Switch = React.forwardRef(function Switch(inProps, ref) {
+ const props = useThemeProps({ props: inProps, name: 'MuiSwitch' });
+
+ const {
+ checked: checkedProp,
+ checkedIcon,
+ className,
+ color = 'primary',
+ defaultChecked,
+ disabled: disabledProp,
+ disableFocusRipple = false,
+ disableRipple = false,
+ disableTouchRipple = false,
+ edge = false,
+ icon,
+ inputProps,
+ onBlur,
+ onChange,
+ onFocus,
+ readOnly,
+ size = 'medium',
+ TouchRippleProps,
+ ...other
+ } = props;
+
+ const rippleRef = React.useRef(null);
+
+ const muiFormControl = useFormControl();
+
+ const handleFocus = (event) => {
+ onFocus?.(event);
+
+ if (muiFormControl && muiFormControl.onFocus) {
+ muiFormControl.onFocus(event);
+ }
+ };
+
+ const handleBlur = (event) => {
+ onBlur?.(event);
+
+ if (muiFormControl && muiFormControl.onBlur) {
+ muiFormControl.onBlur(event);
+ }
+ };
+
+ let disabled = disabledProp;
+ if (muiFormControl) {
+ if (typeof disabled === 'undefined') {
+ disabled = muiFormControl.disabled;
+ }
+ }
+
+ const {
+ getInputProps,
+ checked,
+ disabled: disabledState,
+ focusVisible,
+ } = useSwitch({
+ ...props,
+ disabled,
+ });
+
+ const styleProps = {
+ ...props,
+ checked,
+ disabled: disabledState,
+ focusVisible,
+ color,
+ edge,
+ size,
+ };
+
+ const { enableTouchRipple, getRippleHandlers } = useTouchRipple({
+ rippleRef,
+ focusVisible,
+ disabled: disabledState,
+ disableRipple,
+ disableTouchRipple,
+ disableFocusRipple,
+ });
+
+ const rippleHandlers = getRippleHandlers({
+ onBlur: handleBlur,
+ });
+
+ const classes = useUtilityClasses(styleProps);
+
+ return (
+
+
+
+ {renderThumb(checked, icon, checkedIcon, classes.thumb)}
+ {enableTouchRipple && (
+
+ )}
+
+
+
+ );
+});
+
+const label = { inputProps: { 'aria-label': 'Switch demo' } };
+
+export default function UseSwitchesMaterial() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/docs/src/pages/components/switches/switches.md b/docs/src/pages/components/switches/switches.md
index d22345fba2928d..1c1e7f34370724 100644
--- a/docs/src/pages/components/switches/switches.md
+++ b/docs/src/pages/components/switches/switches.md
@@ -1,6 +1,6 @@
---
title: React Switch component
-components: Switch, FormControl, FormGroup, FormLabel, FormControlLabel
+components: Switch, FormControl, FormGroup, FormLabel, FormControlLabel, SwitchUnstyled
githubLabel: 'component: Switch'
materialDesign: https://material.io/components/selection-controls#switches
---
@@ -57,6 +57,47 @@ Here are some examples of customizing the component. You can learn more about th
🎨 If you are looking for inspiration, you can check [MUI Treasury's customization examples](https://mui-treasury.com/styles/switch).
+## Unstyled switches
+
+The switch also comes with an unstyled version. It's ideal for doing heavy customizations and minimizing bundle size.
+
+```jsx
+import SwitchUnstyled from '@material-ui/unstyled/SwitchUnstyled';
+```
+
+The `SwitchUnstyled` component provides default components and assigns CSS classes you can style entirely on your own.
+You are free to choose any styling solution - plain CSS classes, a CSS framework, Emotion, etc.
+It is also possible to replace these default components by other HTML elements or custom components.
+
+There are three components you can override by the `components` prop: `Root`, `Thumb` and `Input`. Each one's props can be set using the `componentsProps` object.
+
+{{"demo": "pages/components/switches/UnstyledSwitches.js"}}
+
+### Recreation of Material-UI's Switch
+
+{{"demo": "pages/components/switches/UnstyledSwitchesMaterial.js"}}
+
+### useSwitch hook
+
+For the ultimate customizability, a `useSwitch` hook is available.
+It accepts almost the same options as the SwitchUnstyled component minus the `component`, `components`, and `componentsProps` props.
+
+```jsx
+import { useSwitch } from '@material-ui/unstyled/SwitchUnstyled';
+```
+
+#### Basic example
+
+{{"demo": "pages/components/switches/UseSwitchesBasic.js"}}
+
+#### Customized look and feel
+
+{{"demo": "pages/components/switches/UseSwitchesCustom.js"}}
+
+#### Recreation of Material-UI's Switch
+
+{{"demo": "pages/components/switches/UseSwitchesMaterial.js"}}
+
## Label placement
You can change the placement of the label:
diff --git a/docs/src/pagesApi.js b/docs/src/pagesApi.js
index 29730c6fda3e47..247ded85b3d231 100644
--- a/docs/src/pagesApi.js
+++ b/docs/src/pagesApi.js
@@ -132,6 +132,7 @@ module.exports = [
{ pathname: '/api-docs/svg-icon' },
{ pathname: '/api-docs/swipeable-drawer' },
{ pathname: '/api-docs/switch' },
+ { pathname: '/api-docs/switch-unstyled' },
{ pathname: '/api-docs/tab' },
{ pathname: '/api-docs/tab-context' },
{ pathname: '/api-docs/table' },
diff --git a/docs/translations/api-docs/switch-unstyled/switch-unstyled-de.json b/docs/translations/api-docs/switch-unstyled/switch-unstyled-de.json
new file mode 100644
index 00000000000000..f93d4cbd8c7985
--- /dev/null
+++ b/docs/translations/api-docs/switch-unstyled/switch-unstyled-de.json
@@ -0,0 +1 @@
+{ "componentDescription": "", "propDescriptions": {}, "classDescriptions": {} }
diff --git a/docs/translations/api-docs/switch-unstyled/switch-unstyled-es.json b/docs/translations/api-docs/switch-unstyled/switch-unstyled-es.json
new file mode 100644
index 00000000000000..f93d4cbd8c7985
--- /dev/null
+++ b/docs/translations/api-docs/switch-unstyled/switch-unstyled-es.json
@@ -0,0 +1 @@
+{ "componentDescription": "", "propDescriptions": {}, "classDescriptions": {} }
diff --git a/docs/translations/api-docs/switch-unstyled/switch-unstyled-fr.json b/docs/translations/api-docs/switch-unstyled/switch-unstyled-fr.json
new file mode 100644
index 00000000000000..f93d4cbd8c7985
--- /dev/null
+++ b/docs/translations/api-docs/switch-unstyled/switch-unstyled-fr.json
@@ -0,0 +1 @@
+{ "componentDescription": "", "propDescriptions": {}, "classDescriptions": {} }
diff --git a/docs/translations/api-docs/switch-unstyled/switch-unstyled-ja.json b/docs/translations/api-docs/switch-unstyled/switch-unstyled-ja.json
new file mode 100644
index 00000000000000..f93d4cbd8c7985
--- /dev/null
+++ b/docs/translations/api-docs/switch-unstyled/switch-unstyled-ja.json
@@ -0,0 +1 @@
+{ "componentDescription": "", "propDescriptions": {}, "classDescriptions": {} }
diff --git a/docs/translations/api-docs/switch-unstyled/switch-unstyled-pt.json b/docs/translations/api-docs/switch-unstyled/switch-unstyled-pt.json
new file mode 100644
index 00000000000000..f93d4cbd8c7985
--- /dev/null
+++ b/docs/translations/api-docs/switch-unstyled/switch-unstyled-pt.json
@@ -0,0 +1 @@
+{ "componentDescription": "", "propDescriptions": {}, "classDescriptions": {} }
diff --git a/docs/translations/api-docs/switch-unstyled/switch-unstyled-ru.json b/docs/translations/api-docs/switch-unstyled/switch-unstyled-ru.json
new file mode 100644
index 00000000000000..f93d4cbd8c7985
--- /dev/null
+++ b/docs/translations/api-docs/switch-unstyled/switch-unstyled-ru.json
@@ -0,0 +1 @@
+{ "componentDescription": "", "propDescriptions": {}, "classDescriptions": {} }
diff --git a/docs/translations/api-docs/switch-unstyled/switch-unstyled-zh.json b/docs/translations/api-docs/switch-unstyled/switch-unstyled-zh.json
new file mode 100644
index 00000000000000..f93d4cbd8c7985
--- /dev/null
+++ b/docs/translations/api-docs/switch-unstyled/switch-unstyled-zh.json
@@ -0,0 +1 @@
+{ "componentDescription": "", "propDescriptions": {}, "classDescriptions": {} }
diff --git a/docs/translations/api-docs/switch-unstyled/switch-unstyled.json b/docs/translations/api-docs/switch-unstyled/switch-unstyled.json
new file mode 100644
index 00000000000000..4e4001f4926436
--- /dev/null
+++ b/docs/translations/api-docs/switch-unstyled/switch-unstyled.json
@@ -0,0 +1,16 @@
+{
+ "componentDescription": "The foundation for building custom-styled switches.",
+ "propDescriptions": {
+ "checked": "If true
, the component is checked.",
+ "className": "Class name applied to the root element.",
+ "component": "The component used for the Root slot. Either a string to use a HTML element or a component. This is equivalent to components.Root
. If both are provided, the component
is used.",
+ "components": "The components used for each slot inside the Switch. Either a string to use a HTML element or a component.",
+ "componentsProps": "The props used for each slot inside the Switch.",
+ "defaultChecked": "The default checked state. Use when the component is not controlled.",
+ "disabled": "If true
, the component is disabled.",
+ "onChange": "Callback fired when the state is changed.Signature: function(event: object) => void
event: The event source of the callback. You can pull out the new value by accessing event.target.value
(string). You can pull out the new checked state by accessing event.target.checked
(boolean).",
+ "readOnly": "If true
, the component is read only.",
+ "required": "If true
, the input
element is required."
+ },
+ "classDescriptions": {}
+}
diff --git a/packages/material-ui-system/src/createStyled.js b/packages/material-ui-system/src/createStyled.js
index 2b55fcf31f2adb..a1aaae95486604 100644
--- a/packages/material-ui-system/src/createStyled.js
+++ b/packages/material-ui-system/src/createStyled.js
@@ -52,8 +52,9 @@ const variantsResolver = (props, styles, theme, name) => {
return variantsStyles;
};
-export const shouldForwardProp = (prop) =>
- prop !== 'styleProps' && prop !== 'theme' && prop !== 'sx' && prop !== 'as';
+export const shouldForwardProp = (prop) => {
+ return prop !== 'styleProps' && prop !== 'theme' && prop !== 'sx' && prop !== 'as';
+};
export const systemDefaultTheme = createTheme();
diff --git a/packages/material-ui-unstyled/package.json b/packages/material-ui-unstyled/package.json
index 1bacd83923fc3c..516821ace5b0c8 100644
--- a/packages/material-ui-unstyled/package.json
+++ b/packages/material-ui-unstyled/package.json
@@ -48,6 +48,7 @@
},
"dependencies": {
"@babel/runtime": "^7.4.4",
+ "@emotion/is-prop-valid": "^1.1.0",
"@material-ui/utils": "5.0.0-beta.0",
"clsx": "^1.0.4",
"prop-types": "^15.7.2",
diff --git a/packages/material-ui-unstyled/src/SwitchUnstyled/SwitchUnstyled.test.tsx b/packages/material-ui-unstyled/src/SwitchUnstyled/SwitchUnstyled.test.tsx
new file mode 100644
index 00000000000000..d08d6d18ad3f76
--- /dev/null
+++ b/packages/material-ui-unstyled/src/SwitchUnstyled/SwitchUnstyled.test.tsx
@@ -0,0 +1,78 @@
+import * as React from 'react';
+import { createMount, createClientRender, describeConformanceUnstyled } from 'test/utils';
+import SwitchUnstyled, {
+ SwitchState,
+ switchUnstyledClasses,
+} from '@material-ui/unstyled/SwitchUnstyled';
+import { expect } from 'chai';
+
+describe(' ', () => {
+ const mount = createMount();
+ const render = createClientRender();
+
+ describeConformanceUnstyled( , () => ({
+ inheritComponent: 'span',
+ render,
+ mount,
+ refInstanceof: window.HTMLSpanElement,
+ testComponentPropWith: 'span',
+ muiName: 'MuiSwitch',
+ slots: {
+ root: {
+ expectedClassName: switchUnstyledClasses.root,
+ },
+ thumb: {
+ expectedClassName: switchUnstyledClasses.thumb,
+ },
+ input: {
+ testWithElement: 'input',
+ expectedClassName: switchUnstyledClasses.input,
+ },
+ },
+ }));
+
+ describe('componentState', () => {
+ it('passes the styleProps prop to all the slots', () => {
+ interface CustomSlotProps {
+ styleProps: SwitchState;
+ children?: React.ReactNode;
+ }
+
+ const CustomSlot = React.forwardRef(
+ ({ styleProps: sp, children }: CustomSlotProps, ref: React.Ref) => {
+ return (
+
+ {children}
+
+ );
+ },
+ );
+
+ const components = {
+ Root: CustomSlot,
+ Input: CustomSlot,
+ Thumb: CustomSlot,
+ };
+
+ const { getAllByTestId } = render(
+ ,
+ );
+ const renderedComponents = getAllByTestId('custom');
+
+ expect(renderedComponents.length).to.equal(3);
+ for (let i = 0; i < renderedComponents.length; i += 1) {
+ expect(renderedComponents[i]).to.have.attribute('data-checked', 'true');
+ expect(renderedComponents[i]).to.have.attribute('data-disabled', 'true');
+ expect(renderedComponents[i]).to.have.attribute('data-readonly', 'false');
+ expect(renderedComponents[i]).to.have.attribute('data-focusvisible', 'false');
+ }
+ });
+ });
+});
diff --git a/packages/material-ui-unstyled/src/SwitchUnstyled/SwitchUnstyled.tsx b/packages/material-ui-unstyled/src/SwitchUnstyled/SwitchUnstyled.tsx
new file mode 100644
index 00000000000000..4a01265a4dea50
--- /dev/null
+++ b/packages/material-ui-unstyled/src/SwitchUnstyled/SwitchUnstyled.tsx
@@ -0,0 +1,211 @@
+import * as React from 'react';
+import PropTypes from 'prop-types';
+import clsx from 'clsx';
+import useSwitch, { SwitchState, UseSwitchProps } from './useSwitch';
+import classes from './switchUnstyledClasses';
+import { isHostComponent } from '../utils';
+
+export interface SwitchUnstyledProps extends UseSwitchProps {
+ /**
+ * Class name applied to the root element.
+ */
+ className?: string;
+ /**
+ * The component used for the Root slot.
+ * Either a string to use a HTML element or a component.
+ * This is equivalent to `components.Root`. If both are provided, the `component` is used.
+ */
+ component?: React.ElementType;
+ /**
+ * The components used for each slot inside the Switch.
+ * Either a string to use a HTML element or a component.
+ * @default {}
+ */
+ components?: {
+ Root?: React.ElementType;
+ Thumb?: React.ElementType;
+ Input?: React.ElementType;
+ };
+
+ /**
+ * The props used for each slot inside the Switch.
+ * @default {}
+ */
+ componentsProps?: {
+ root?: {};
+ thumb?: {};
+ input?: {};
+ };
+}
+
+const appendStyleProps = (
+ component: React.ElementType,
+ componentsProps: Record,
+ state: SwitchState,
+) => {
+ if (!isHostComponent(component)) {
+ componentsProps.styleProps = { ...componentsProps.styleProps, ...state };
+ }
+};
+
+/**
+ * The foundation for building custom-styled switches.
+ *
+ * Demos:
+ *
+ * - [Switches](https://material-ui.com/components/switches/)
+ *
+ * API:
+ *
+ * - [SwitchUnstyled API](https://material-ui.com/api/switch-unstyled/)
+ */
+const SwitchUnstyled = React.forwardRef(function SwitchUnstyled(
+ props: SwitchUnstyledProps,
+ ref: React.ForwardedRef,
+) {
+ const {
+ checked: checkedProp,
+ className,
+ component,
+ components = {},
+ componentsProps = {},
+ defaultChecked,
+ disabled: disabledProp,
+ onBlur,
+ onChange,
+ onFocus,
+ onFocusVisible,
+ readOnly: readOnlyProp,
+ required,
+ ...otherProps
+ } = props;
+
+ const Root: React.ElementType = component ?? components.Root ?? 'span';
+ const rootProps: any = { ...otherProps, ...componentsProps.root };
+
+ const Thumb: React.ElementType = components.Thumb ?? 'span';
+ const thumbProps: any = componentsProps.thumb ?? {};
+
+ const Input: React.ElementType = components.Input ?? 'input';
+ const inputProps: any = componentsProps.input ?? {};
+
+ const useSwitchProps = {
+ checked: checkedProp,
+ defaultChecked,
+ disabled: disabledProp,
+ onBlur,
+ onChange,
+ onFocus,
+ onFocusVisible,
+ readOnly: readOnlyProp,
+ };
+
+ const { getInputProps, checked, disabled, focusVisible, readOnly } = useSwitch(useSwitchProps);
+
+ const styleProps: SwitchState = {
+ ...props,
+ checked,
+ disabled,
+ focusVisible,
+ readOnly,
+ };
+
+ appendStyleProps(Root, rootProps, styleProps);
+ appendStyleProps(Input, inputProps, styleProps);
+ appendStyleProps(Thumb, thumbProps, styleProps);
+
+ const stateClasses = {
+ [classes.checked]: checked,
+ [classes.disabled]: disabled,
+ [classes.focusVisible]: focusVisible,
+ [classes.readOnly]: readOnly,
+ };
+
+ return (
+
+
+
+
+ );
+});
+
+SwitchUnstyled.propTypes /* remove-proptypes */ = {
+ // ----------------------------- Warning --------------------------------
+ // | These PropTypes are generated from the TypeScript type definitions |
+ // | To update them edit TypeScript types and run "yarn proptypes" |
+ // ----------------------------------------------------------------------
+ /**
+ * If `true`, the component is checked.
+ */
+ checked: PropTypes.bool,
+ /**
+ * Class name applied to the root element.
+ */
+ className: PropTypes.string,
+ /**
+ * The component used for the Root slot.
+ * Either a string to use a HTML element or a component.
+ * This is equivalent to `components.Root`. If both are provided, the `component` is used.
+ */
+ component: PropTypes.elementType,
+ /**
+ * The components used for each slot inside the Switch.
+ * Either a string to use a HTML element or a component.
+ * @default {}
+ */
+ components: PropTypes.shape({
+ Input: PropTypes.elementType,
+ Root: PropTypes.elementType,
+ Thumb: PropTypes.elementType,
+ }),
+ /**
+ * The props used for each slot inside the Switch.
+ * @default {}
+ */
+ componentsProps: PropTypes.object,
+ /**
+ * The default checked state. Use when the component is not controlled.
+ */
+ defaultChecked: PropTypes.bool,
+ /**
+ * If `true`, the component is disabled.
+ */
+ disabled: PropTypes.bool,
+ /**
+ * @ignore
+ */
+ onBlur: PropTypes.func,
+ /**
+ * Callback fired when the state is changed.
+ *
+ * @param {object} event The event source of the callback.
+ * You can pull out the new value by accessing `event.target.value` (string).
+ * You can pull out the new checked state by accessing `event.target.checked` (boolean).
+ */
+ onChange: PropTypes.func,
+ /**
+ * @ignore
+ */
+ onFocus: PropTypes.func,
+ /**
+ * @ignore
+ */
+ onFocusVisible: PropTypes.func,
+ /**
+ * If `true`, the component is read only.
+ */
+ readOnly: PropTypes.bool,
+ /**
+ * If `true`, the `input` element is required.
+ */
+ required: PropTypes.bool,
+} as any;
+
+export default SwitchUnstyled;
diff --git a/packages/material-ui-unstyled/src/SwitchUnstyled/index.ts b/packages/material-ui-unstyled/src/SwitchUnstyled/index.ts
new file mode 100644
index 00000000000000..ee88158a20e4bf
--- /dev/null
+++ b/packages/material-ui-unstyled/src/SwitchUnstyled/index.ts
@@ -0,0 +1,6 @@
+export { default } from './SwitchUnstyled';
+export * from './SwitchUnstyled';
+export { default as useSwitch } from './useSwitch';
+export * from './useSwitch';
+export { default as switchUnstyledClasses } from './switchUnstyledClasses';
+export * from './switchUnstyledClasses';
diff --git a/packages/material-ui-unstyled/src/SwitchUnstyled/switchUnstyledClasses.ts b/packages/material-ui-unstyled/src/SwitchUnstyled/switchUnstyledClasses.ts
new file mode 100644
index 00000000000000..8d979870ca1fde
--- /dev/null
+++ b/packages/material-ui-unstyled/src/SwitchUnstyled/switchUnstyledClasses.ts
@@ -0,0 +1,37 @@
+import generateUtilityClass from '../generateUtilityClass';
+import generateUtilityClasses from '../generateUtilityClasses';
+
+export interface SwitchUnstyledClasses {
+ /** Class applied to the root element. */
+ root: string;
+ /** Class applied to the internal input element */
+ input: string;
+ /** Class applied to the thumb element */
+ thumb: string;
+ /** Class applied to the root element if the switch is checked */
+ checked: string;
+ /** Class applied to the root element if the switch is disabled */
+ disabled: string;
+ /** Class applied to the root element if the switch has visible focus */
+ focusVisible: string;
+ /** Class applied to the root element if the switch is read-only */
+ readOnly: string;
+}
+
+export type SwitchUnstyledClassKey = keyof SwitchUnstyledClasses;
+
+export function getSwitchUnstyledUtilityClass(slot: string): string {
+ return generateUtilityClass('MuiSwitch', slot);
+}
+
+const switchUnstyledClasses: SwitchUnstyledClasses = generateUtilityClasses('MuiSwitch', [
+ 'root',
+ 'input',
+ 'thumb',
+ 'checked',
+ 'disabled',
+ 'focusVisible',
+ 'readOnly',
+]);
+
+export default switchUnstyledClasses;
diff --git a/packages/material-ui-unstyled/src/SwitchUnstyled/useSwitch.test.tsx b/packages/material-ui-unstyled/src/SwitchUnstyled/useSwitch.test.tsx
new file mode 100644
index 00000000000000..02b74d1a75d5ea
--- /dev/null
+++ b/packages/material-ui-unstyled/src/SwitchUnstyled/useSwitch.test.tsx
@@ -0,0 +1,86 @@
+import { expect } from 'chai';
+import React from 'react';
+import { spy } from 'sinon';
+import { act, createClientRender } from 'test/utils';
+import { useSwitch, UseSwitchProps, UseSwitchResult } from '@material-ui/unstyled/SwitchUnstyled';
+
+const TestComponent = React.forwardRef(
+ ({ useSwitchProps }: { useSwitchProps?: UseSwitchProps }, ref) => {
+ const switchDefinition = useSwitch(useSwitchProps ?? {});
+ React.useImperativeHandle(ref, () => switchDefinition, [switchDefinition]);
+ return null;
+ },
+);
+
+describe('useSwitch', () => {
+ const render = createClientRender();
+ const invokeUseSwitch = (props: UseSwitchProps) => {
+ const ref = React.createRef();
+ render( );
+ return ref.current as UseSwitchResult;
+ };
+
+ describe('getInputProps', () => {
+ it('should include the incoming uncontrolled props in the output', () => {
+ const props: UseSwitchProps = {
+ defaultChecked: true,
+ disabled: true,
+ readOnly: true,
+ required: true,
+ };
+
+ const { getInputProps } = invokeUseSwitch(props);
+ const inputProps = getInputProps();
+
+ expect(inputProps.defaultChecked).to.equal(true);
+ expect(inputProps.disabled).to.equal(true);
+ expect(inputProps.readOnly).to.equal(true);
+ expect(inputProps.required).to.equal(true);
+ });
+
+ it('should include the incoming controlled prop in the output', () => {
+ const props = {
+ checked: true,
+ };
+
+ const { getInputProps } = invokeUseSwitch(props);
+ const inputProps = getInputProps();
+
+ expect(inputProps!.checked).to.equal(true);
+ });
+
+ it('should call the provided event handlers when respective events are fired', () => {
+ const props = {
+ onChange: spy(),
+ onFocus: spy(),
+ onFocusVisible: spy(),
+ onBlur: spy(),
+ };
+
+ const dummyChangeEvent = {
+ nativeEvent: {
+ defaultPrevented: false,
+ },
+ target: {
+ checked: true,
+ },
+ } as React.ChangeEvent;
+
+ const dummyFocusEvent = {} as React.FocusEvent;
+ const dummyBlurEvent = {} as React.FocusEvent;
+
+ act(() => {
+ const { getInputProps } = invokeUseSwitch(props);
+ const inputProps = getInputProps();
+ inputProps.onChange(dummyChangeEvent);
+ inputProps.onFocus(dummyFocusEvent);
+ inputProps.onBlur(dummyBlurEvent);
+ });
+
+ expect(props.onChange.calledWith(dummyChangeEvent)).to.equal(true);
+ expect(props.onFocus.calledWith(dummyFocusEvent)).to.equal(true);
+ expect(props.onFocusVisible.calledWith(dummyFocusEvent)).to.equal(true);
+ expect(props.onBlur.calledWith(dummyBlurEvent)).to.equal(true);
+ });
+ });
+});
diff --git a/packages/material-ui-unstyled/src/SwitchUnstyled/useSwitch.ts b/packages/material-ui-unstyled/src/SwitchUnstyled/useSwitch.ts
new file mode 100644
index 00000000000000..bc478b095c749d
--- /dev/null
+++ b/packages/material-ui-unstyled/src/SwitchUnstyled/useSwitch.ts
@@ -0,0 +1,185 @@
+import * as React from 'react';
+import {
+ unstable_useControlled as useControlled,
+ unstable_useEventCallback as useEventCallback,
+ unstable_useForkRef as useForkRef,
+ unstable_useIsFocusVisible as useIsFocusVisible,
+} from '@material-ui/utils';
+
+export interface SwitchState {
+ checked: Readonly;
+ disabled: Readonly;
+ readOnly: Readonly;
+ focusVisible: Readonly;
+}
+
+export interface UseSwitchResult extends SwitchState {
+ /**
+ * Returns props for an HTML `input` element that is a part of a Switch.
+ */
+ getInputProps: (otherProps?: React.HTMLAttributes) => SwitchInputProps;
+}
+
+/**
+ * Props used by an HTML `input` element that is a part of a Switch.
+ */
+export interface SwitchInputProps {
+ checked?: boolean;
+ defaultChecked?: boolean;
+ disabled?: boolean;
+ onBlur: React.FocusEventHandler;
+ onChange: React.ChangeEventHandler;
+ onFocus: React.FocusEventHandler;
+ readOnly?: boolean;
+ ref: React.Ref;
+ required?: boolean;
+}
+
+export interface UseSwitchProps {
+ /**
+ * If `true`, the component is checked.
+ */
+ checked?: boolean;
+ /**
+ * The default checked state. Use when the component is not controlled.
+ */
+ defaultChecked?: boolean;
+ /**
+ * If `true`, the component is disabled.
+ */
+ disabled?: boolean;
+ onBlur?: React.FocusEventHandler;
+ /**
+ * Callback fired when the state is changed.
+ *
+ * @param {object} event The event source of the callback.
+ * You can pull out the new value by accessing `event.target.value` (string).
+ * You can pull out the new checked state by accessing `event.target.checked` (boolean).
+ */
+ onChange?: React.ChangeEventHandler;
+ onFocus?: React.FocusEventHandler;
+ onFocusVisible?: React.FocusEventHandler;
+ /**
+ * If `true`, the component is read only.
+ */
+ readOnly?: boolean;
+ /**
+ * If `true`, the `input` element is required.
+ */
+ required?: boolean;
+}
+
+/**
+ * The basic building block for creating custom switches.
+ *
+ * Demos:
+ *
+ * - [Switches](https://material-ui.com/components/switches/)
+ */
+export default function useSwitch(props: UseSwitchProps) {
+ const {
+ checked: checkedProp,
+ defaultChecked,
+ disabled,
+ onBlur,
+ onChange,
+ onFocus,
+ onFocusVisible,
+ readOnly,
+ required,
+ } = props;
+
+ const [checked, setCheckedState] = useControlled({
+ controlled: checkedProp,
+ default: Boolean(defaultChecked),
+ name: 'Switch',
+ state: 'checked',
+ });
+
+ const handleInputChange = useEventCallback(
+ (event: React.ChangeEvent, otherHandler?: React.FormEventHandler) => {
+ // Workaround for https://github.com/facebook/react/issues/9023
+ if (event.nativeEvent.defaultPrevented) {
+ return;
+ }
+
+ setCheckedState(event.target.checked);
+ onChange?.(event);
+ otherHandler?.(event);
+ },
+ );
+
+ const {
+ isFocusVisibleRef,
+ onBlur: handleBlurVisible,
+ onFocus: handleFocusVisible,
+ ref: focusVisibleRef,
+ } = useIsFocusVisible();
+
+ const [focusVisible, setFocusVisible] = React.useState(false);
+ if (disabled && focusVisible) {
+ setFocusVisible(false);
+ }
+
+ React.useEffect(() => {
+ isFocusVisibleRef.current = focusVisible;
+ }, [focusVisible, isFocusVisibleRef]);
+
+ const inputRef = React.useRef(null);
+
+ const handleFocus = useEventCallback(
+ (event: React.FocusEvent, otherHandler?: React.FocusEventHandler) => {
+ // Fix for https://github.com/facebook/react/issues/7769
+ if (!inputRef.current) {
+ inputRef.current = event.currentTarget;
+ }
+
+ handleFocusVisible(event);
+ if (isFocusVisibleRef.current === true) {
+ setFocusVisible(true);
+ onFocusVisible?.(event);
+ }
+
+ onFocus?.(event);
+ otherHandler?.(event);
+ },
+ );
+
+ const handleBlur = useEventCallback(
+ (event: React.FocusEvent, otherHandler?: React.FocusEventHandler) => {
+ handleBlurVisible(event);
+
+ if (isFocusVisibleRef.current === false) {
+ setFocusVisible(false);
+ }
+
+ onBlur?.(event);
+ otherHandler?.(event);
+ },
+ );
+
+ const handleRefChange = useForkRef(focusVisibleRef, inputRef);
+
+ const getInputProps = (otherProps: React.HTMLAttributes = {}) => ({
+ checked: checkedProp,
+ defaultChecked,
+ disabled,
+ readOnly,
+ required,
+ type: 'checkbox',
+ ...otherProps,
+ onChange: (event: React.ChangeEvent) =>
+ handleInputChange(event, otherProps.onChange),
+ onFocus: (event: React.FocusEvent) => handleFocus(event, otherProps.onFocus),
+ onBlur: (event: React.FocusEvent) => handleBlur(event, otherProps.onBlur),
+ ref: handleRefChange,
+ });
+
+ return {
+ checked,
+ disabled: Boolean(disabled),
+ focusVisible,
+ getInputProps,
+ readOnly: Boolean(readOnly),
+ } as UseSwitchResult;
+}
diff --git a/packages/material-ui-unstyled/src/index.d.ts b/packages/material-ui-unstyled/src/index.d.ts
index 5e2c860322674f..472ffc529c46dd 100644
--- a/packages/material-ui-unstyled/src/index.d.ts
+++ b/packages/material-ui-unstyled/src/index.d.ts
@@ -10,6 +10,9 @@ export * from './ModalUnstyled';
export { default as SliderUnstyled } from './SliderUnstyled';
export * from './SliderUnstyled';
+export { default as SwitchUnstyled } from './SwitchUnstyled';
+export * from './SwitchUnstyled';
+
export { default as Portal } from './Portal';
export * from './Portal';
diff --git a/packages/material-ui-unstyled/src/index.js b/packages/material-ui-unstyled/src/index.js
index 87391679d5687a..d58845ae969702 100644
--- a/packages/material-ui-unstyled/src/index.js
+++ b/packages/material-ui-unstyled/src/index.js
@@ -7,6 +7,9 @@ export * from './BadgeUnstyled';
export { default as SliderUnstyled } from './SliderUnstyled';
export * from './SliderUnstyled';
+export { default as SwitchUnstyled } from './SwitchUnstyled';
+export * from './SwitchUnstyled';
+
export { default as ModalUnstyled } from './ModalUnstyled';
export * from './ModalUnstyled';
diff --git a/packages/material-ui-unstyled/src/utils/index.d.ts b/packages/material-ui-unstyled/src/utils/index.d.ts
deleted file mode 100644
index ad997d95525494..00000000000000
--- a/packages/material-ui-unstyled/src/utils/index.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-/* eslint-disable import/prefer-default-export */
-
-export function isHostComponent(component: React.ElementType): boolean;
diff --git a/packages/material-ui-unstyled/src/utils/index.js b/packages/material-ui-unstyled/src/utils/index.ts
similarity index 100%
rename from packages/material-ui-unstyled/src/utils/index.js
rename to packages/material-ui-unstyled/src/utils/index.ts
diff --git a/packages/material-ui-unstyled/src/utils/isHostComponent.js b/packages/material-ui-unstyled/src/utils/isHostComponent.js
deleted file mode 100644
index 79aabd52adc747..00000000000000
--- a/packages/material-ui-unstyled/src/utils/isHostComponent.js
+++ /dev/null
@@ -1,5 +0,0 @@
-function isHostComponent(element) {
- return typeof element === 'string';
-}
-
-export default isHostComponent;
diff --git a/packages/material-ui-unstyled/src/utils/isHostComponent.ts b/packages/material-ui-unstyled/src/utils/isHostComponent.ts
new file mode 100644
index 00000000000000..94e4c950a06d49
--- /dev/null
+++ b/packages/material-ui-unstyled/src/utils/isHostComponent.ts
@@ -0,0 +1,10 @@
+import React from 'react';
+
+/**
+ * Determines if a given element is a DOM element name (i.e. not a React component).
+ */
+function isHostComponent(element: React.ElementType) {
+ return typeof element === 'string';
+}
+
+export default isHostComponent;
diff --git a/packages/material-ui-unstyled/tsconfig.build.json b/packages/material-ui-unstyled/tsconfig.build.json
index 722cf118a0eedf..a45de38c5d2fd4 100644
--- a/packages/material-ui-unstyled/tsconfig.build.json
+++ b/packages/material-ui-unstyled/tsconfig.build.json
@@ -10,6 +10,6 @@
"outDir": "build",
"rootDir": "./src"
},
- "include": ["src/**/*.ts"],
- "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"]
+ "include": ["src/**/*.ts*"],
+ "exclude": ["src/**/*.spec.ts*", "src/**/*.test.ts*"]
}
diff --git a/packages/material-ui/src/ButtonBase/TouchRipple.d.ts b/packages/material-ui/src/ButtonBase/TouchRipple.d.ts
index b26831ed4e979b..24fde425c0a987 100644
--- a/packages/material-ui/src/ButtonBase/TouchRipple.d.ts
+++ b/packages/material-ui/src/ButtonBase/TouchRipple.d.ts
@@ -4,6 +4,21 @@ import { TouchRippleClasses, TouchRippleClassKey } from './touchRippleClasses';
export { TouchRippleClassKey };
+export interface StartActionOptions {
+ pulsate?: boolean;
+ center?: boolean;
+}
+
+export interface TouchRippleActions {
+ start: (
+ event?: React.SyntheticEvent,
+ options?: StartActionOptions,
+ callback?: () => void,
+ ) => void;
+ pulsate: (event?: React.SyntheticEvent) => void;
+ stop: (event?: React.SyntheticEvent, callback?: () => void) => void;
+}
+
export type TouchRippleProps = StandardProps> & {
center?: boolean;
/**
@@ -12,6 +27,6 @@ export type TouchRippleProps = StandardProps>
classes?: Partial;
};
-declare const TouchRipple: React.JSXElementConstructor;
+declare const TouchRipple: React.ForwardRefRenderFunction;
export default TouchRipple;
diff --git a/packages/material-ui/src/Switch/Switch.test.js b/packages/material-ui/src/Switch/Switch.test.js
index 1e5c427a88b184..c69c81140a9c95 100644
--- a/packages/material-ui/src/Switch/Switch.test.js
+++ b/packages/material-ui/src/Switch/Switch.test.js
@@ -63,6 +63,20 @@ describe(' ', () => {
expect(getByRole('checkbox')).to.have.property('readOnly', true);
});
+ specify('renders a custom icon when provided', () => {
+ const { getByTestId } = render( } />);
+
+ expect(getByTestId('icon')).toBeVisible();
+ });
+
+ specify('renders a custom checked icon when provided', () => {
+ const { getByTestId } = render(
+ } />,
+ );
+
+ expect(getByTestId('icon')).toBeVisible();
+ });
+
specify('the Checked state changes after change events', () => {
const { getByRole } = render( );
diff --git a/packages/material-ui/src/useTouchRipple/index.ts b/packages/material-ui/src/useTouchRipple/index.ts
new file mode 100644
index 00000000000000..31e422f495fd10
--- /dev/null
+++ b/packages/material-ui/src/useTouchRipple/index.ts
@@ -0,0 +1 @@
+export { default } from './useTouchRipple';
diff --git a/packages/material-ui/src/useTouchRipple/useTouchRipple.ts b/packages/material-ui/src/useTouchRipple/useTouchRipple.ts
new file mode 100644
index 00000000000000..5f444d8e570026
--- /dev/null
+++ b/packages/material-ui/src/useTouchRipple/useTouchRipple.ts
@@ -0,0 +1,161 @@
+import * as React from 'react';
+import { TouchRippleActions } from '../ButtonBase/TouchRipple';
+import { useEventCallback } from '../utils';
+
+interface UseTouchRippleProps {
+ disabled: boolean;
+ disableFocusRipple?: boolean;
+ disableRipple?: boolean;
+ disableTouchRipple?: boolean;
+ focusVisible: boolean;
+ rippleRef: React.RefObject;
+}
+
+interface RippleEventHandlers {
+ onBlur: React.FocusEventHandler;
+ onContextMenu: React.MouseEventHandler;
+ onDragLeave: React.DragEventHandler;
+ onKeyDown: React.KeyboardEventHandler;
+ onKeyUp: React.KeyboardEventHandler;
+ onMouseDown: React.MouseEventHandler;
+ onMouseLeave: React.MouseEventHandler;
+ onMouseUp: React.MouseEventHandler;
+ onTouchEnd: React.TouchEventHandler;
+ onTouchMove: React.TouchEventHandler;
+ onTouchStart: React.TouchEventHandler;
+}
+
+const useTouchRipple = (props: UseTouchRippleProps) => {
+ const {
+ disabled,
+ disableFocusRipple,
+ disableRipple,
+ disableTouchRipple,
+ focusVisible,
+ rippleRef,
+ } = props;
+
+ React.useEffect(() => {
+ if (focusVisible && !disableFocusRipple && !disableRipple) {
+ rippleRef.current?.pulsate();
+ }
+ }, [rippleRef, focusVisible, disableFocusRipple, disableRipple]);
+
+ function useRippleHandler(
+ rippleAction: keyof TouchRippleActions,
+ eventCallback?: (event: React.SyntheticEvent) => void,
+ skipRippleAction = disableTouchRipple,
+ ) {
+ return useEventCallback((event: React.SyntheticEvent) => {
+ eventCallback?.(event);
+
+ if (!skipRippleAction && rippleRef.current) {
+ rippleRef.current[rippleAction](event);
+ }
+
+ return true;
+ });
+ }
+
+ const keydownRef = React.useRef(false);
+ const handleKeyDown = useEventCallback((event: React.KeyboardEvent) => {
+ if (
+ !disableFocusRipple &&
+ !keydownRef.current &&
+ focusVisible &&
+ rippleRef.current &&
+ event.key === ' '
+ ) {
+ keydownRef.current = true;
+ rippleRef.current.stop(event, () => {
+ rippleRef?.current?.start(event);
+ });
+ }
+ });
+
+ const handleKeyUp = useEventCallback((event: React.KeyboardEvent) => {
+ // calling preventDefault in keyUp on a will not dispatch a click event if Space is pressed
+ // https://codesandbox.io/s/button-keyup-preventdefault-dn7f0
+ if (
+ !disableFocusRipple &&
+ event.key === ' ' &&
+ rippleRef.current &&
+ focusVisible &&
+ !event.defaultPrevented
+ ) {
+ keydownRef.current = false;
+ rippleRef.current.stop(event, () => {
+ rippleRef?.current?.pulsate(event);
+ });
+ }
+ });
+
+ const handleBlur = useRippleHandler('stop');
+ const handleMouseDown = useRippleHandler('start');
+ const handleContextMenu = useRippleHandler('stop');
+ const handleDragLeave = useRippleHandler('stop');
+ const handleMouseUp = useRippleHandler('stop');
+ const handleMouseLeave = useRippleHandler('stop');
+ const handleTouchStart = useRippleHandler('start');
+ const handleTouchEnd = useRippleHandler('stop');
+ const handleTouchMove = useRippleHandler('stop');
+
+ const [mountedState, setMountedState] = React.useState(false);
+
+ React.useEffect(() => {
+ setMountedState(true);
+ }, []);
+
+ const enableTouchRipple = mountedState && !disableRipple && !disabled;
+
+ const getRippleHandlers = React.useMemo(() => {
+ const rippleHandlers = {
+ onBlur: handleBlur,
+ onKeyDown: handleKeyDown,
+ onKeyUp: handleKeyUp,
+ onMouseDown: handleMouseDown,
+ onMouseUp: handleMouseUp,
+ onMouseLeave: handleMouseLeave,
+ onContextMenu: handleContextMenu,
+ onDragLeave: handleDragLeave,
+ onTouchStart: handleTouchStart,
+ onTouchEnd: handleTouchEnd,
+ onTouchMove: handleTouchMove,
+ } as RippleEventHandlers;
+
+ return (otherEvents: Partial = {}) => {
+ const eventNames = Object.keys(rippleHandlers) as (keyof RippleEventHandlers)[];
+ const wrappedEvents = eventNames.map((eventName) => ({
+ name: eventName,
+ handler: (ev: any) => {
+ otherEvents[eventName]?.(ev);
+ rippleHandlers[eventName](ev);
+ },
+ }));
+
+ return wrappedEvents.reduce((acc, current) => {
+ acc[current.name] = current.handler;
+ return acc;
+ }, {} as RippleEventHandlers);
+ };
+ }, [
+ handleBlur,
+ handleKeyDown,
+ handleKeyUp,
+ handleMouseDown,
+ handleMouseUp,
+ handleMouseLeave,
+ handleContextMenu,
+ handleDragLeave,
+ handleTouchStart,
+ handleTouchEnd,
+ handleTouchMove,
+ ]);
+
+ return {
+ enableTouchRipple,
+ getRippleHandlers,
+ };
+};
+
+export default useTouchRipple;
diff --git a/test/utils/describeConformance.js b/test/utils/describeConformance.js
index 35da0cb8e274b2..27e1f5ba1b8e9a 100644
--- a/test/utils/describeConformance.js
+++ b/test/utils/describeConformance.js
@@ -51,7 +51,7 @@ export function findRootComponent(wrapper, { component }) {
});
}
-function randomStringValue() {
+export function randomStringValue() {
return `s${Math.random().toString(36).slice(2)}`;
}
@@ -208,6 +208,7 @@ const fullSuite = {
* @property {Array} [skip] - Skip the specified tests
* @property {string} [testComponentPropWith] - The host component that should be rendered instead.
* @property {(mount: (node: React.ReactNode) => import('enzyme').ReactWrapper) => (node: React.ReactNode) => import('enzyme').ReactWrapper} [wrapMount] - You can use this option to mount the component with enzyme in a WrapperComponent. Make sure the returned node corresponds to the input node and not the wrapper component.
+ * @property {(node: React.ReactElement) => import('./createClientRender').MuiRenderResult} [render] - Should be a return value from createClientRender
*/
/**
diff --git a/test/utils/describeConformanceUnstyled.tsx b/test/utils/describeConformanceUnstyled.tsx
new file mode 100644
index 00000000000000..5ed1adadb7b330
--- /dev/null
+++ b/test/utils/describeConformanceUnstyled.tsx
@@ -0,0 +1,297 @@
+import * as React from 'react';
+import { expect } from 'chai';
+import { unstable_capitalize as capitalize } from '@material-ui/utils';
+import { MuiRenderResult, RenderOptions } from './createClientRender';
+import {
+ ConformanceOptions,
+ describeRef,
+ randomStringValue,
+ testClassName,
+ testComponentProp,
+ testReactTestRenderer,
+} from './describeConformance';
+
+export interface SlotTestingOptions {
+ testWithComponent?: React.ComponentType;
+ testWithElement?: keyof JSX.IntrinsicElements;
+ expectedClassName: string;
+}
+
+export interface UnstyledConformanceOptions
+ extends Omit, 'render' | 'skip' | 'classes'> {
+ render: (
+ element: React.ReactElement>,
+ options?: RenderOptions | undefined,
+ ) => MuiRenderResult;
+ skip?: (keyof typeof fullSuite)[];
+ slots: Record;
+}
+
+function throwMissingPropError(field: string): never {
+ throw new Error(`missing "${field}" in options
+
+ > describeConformanceUnstyled(element, () => options)
+`);
+}
+
+interface WithClassName {
+ className: string;
+}
+
+interface WithCustomProp {
+ fooBar: string;
+ 'aria-label': string;
+ tabIndex: number;
+}
+
+interface WithStyleProps {
+ styleProps: Record;
+ expectedStyleProps: Record;
+}
+
+function forEachSlot(
+ slots: Record,
+ callback: (slotName: string, options: SlotTestingOptions) => void,
+) {
+ const slotNames = Object.keys(slots);
+ for (let i = 0; i < slotNames.length; i += 1) {
+ const slotName = slotNames[i];
+ const slot = slots[slotName];
+
+ callback(slotName, slot);
+ }
+}
+
+function testPropForwarding(
+ element: React.ReactElement,
+ getOptions: () => UnstyledConformanceOptions,
+) {
+ const { render } = getOptions();
+
+ if (!render) {
+ throwMissingPropError('render');
+ }
+
+ it('forwards custom props to the root element if a component is provided', () => {
+ const CustomRoot = ({ fooBar, tabIndex, 'aria-label': ariaLabel }: WithCustomProp) => {
+ return
;
+ };
+
+ const otherProps = {
+ tabIndex: '0',
+ 'aria-label': randomStringValue(),
+ fooBar: randomStringValue(),
+ };
+
+ const { container } = render(
+ React.cloneElement(element, { components: { Root: CustomRoot }, ...otherProps }),
+ );
+
+ expect(container.firstChild).to.have.attribute('tabindex', otherProps.tabIndex.toString());
+ expect(container.firstChild).to.have.attribute('aria-label', otherProps['aria-label']);
+ expect(container.firstChild).to.have.attribute('data-foobar', otherProps.fooBar);
+ });
+
+ it('does forward standard props to the root element if an intrinsic element is provided', () => {
+ const otherProps = {
+ tabIndex: '0',
+ 'aria-label': randomStringValue(),
+ };
+
+ const { container } = render(
+ React.cloneElement(element, { components: { Root: 'div' }, ...otherProps }),
+ );
+
+ expect(container.firstChild).to.have.attribute('tabindex', otherProps.tabIndex);
+ expect(container.firstChild).to.have.attribute('aria-label', otherProps['aria-label']);
+ });
+}
+
+function testComponentsProp(
+ element: React.ReactElement,
+ getOptions: () => UnstyledConformanceOptions,
+) {
+ const { render, slots } = getOptions();
+
+ if (!render) {
+ throwMissingPropError('render');
+ }
+
+ if (!slots) {
+ throwMissingPropError('slots');
+ }
+
+ const CustomComponent = React.forwardRef(({ className }: WithClassName, ref: React.Ref) => (
+
+ ));
+
+ forEachSlot(slots, (slotName, slotOptions) => {
+ it(`allows overriding the ${capitalize(slotName)} slot with a component`, () => {
+ const slotComponent = slotOptions.testWithComponent ?? CustomComponent;
+
+ const components = {
+ [capitalize(slotName)]: slotComponent,
+ };
+
+ const { getByTestId } = render(React.cloneElement(element, { components }));
+ const renderedElement = getByTestId('custom');
+ expect(renderedElement).to.have.class(slotOptions.expectedClassName);
+ });
+
+ it(`allows overriding the ${capitalize(slotName)} slot with an element`, () => {
+ const slotElement = slotOptions.testWithElement ?? 'i';
+
+ const components = {
+ [capitalize(slotName)]: slotElement,
+ };
+
+ const { container } = render(React.cloneElement(element, { components }));
+ const thumb = container.querySelector(slotElement);
+ expect(thumb).to.have.class(slotOptions.expectedClassName);
+ });
+ });
+
+ it('uses the component provided in component prop when both component and components.Root are provided', () => {
+ const RootComponentA = React.forwardRef(
+ ({ children }: React.PropsWithChildren<{}>, ref: React.Ref) => (
+
+ {children}
+
+ ),
+ );
+
+ const RootComponentB = React.forwardRef(
+ ({ children }: React.PropsWithChildren<{}>, ref: React.Ref) => (
+
+ {children}
+
+ ),
+ );
+
+ const { queryByTestId } = render(
+ React.cloneElement(element, {
+ component: RootComponentA,
+ components: { Root: RootComponentB },
+ }),
+ );
+
+ /* eslint-disable @typescript-eslint/no-unused-expressions */
+ expect(queryByTestId('a')).to.exist;
+ expect(queryByTestId('b')).not.to.exist;
+ });
+}
+
+function testComponentsPropsProp(
+ element: React.ReactElement,
+ getOptions: () => UnstyledConformanceOptions,
+) {
+ const { render, slots } = getOptions();
+
+ if (!render) {
+ throwMissingPropError('render');
+ }
+
+ if (!slots) {
+ throwMissingPropError('slots');
+ }
+
+ forEachSlot(slots, (slotName, slotOptions) => {
+ it(`sets custom properties on ${capitalize(slotName)} slot's element`, () => {
+ const componentsProps = {
+ [slotName]: {
+ 'data-testid': 'custom',
+ },
+ };
+
+ const { getByTestId } = render(React.cloneElement(element, { componentsProps }));
+
+ expect(getByTestId('custom')).to.have.class(slotOptions.expectedClassName);
+ });
+
+ it(`merges the class names provided in componentsProps.${slotName} with the built-in ones`, () => {
+ const componentsProps = {
+ [slotName]: {
+ 'data-testid': 'custom',
+ className: randomStringValue(),
+ },
+ };
+
+ const { getByTestId } = render(React.cloneElement(element, { componentsProps }));
+
+ expect(getByTestId('custom')).to.have.class(slotOptions.expectedClassName);
+ expect(getByTestId('custom')).to.have.class(componentsProps[slotName].className);
+ });
+ });
+}
+
+function testStylePropsPropagation(
+ element: React.ReactElement,
+ getOptions: () => UnstyledConformanceOptions,
+) {
+ const { render, slots } = getOptions();
+
+ if (!render) {
+ throwMissingPropError('render');
+ }
+
+ if (!slots) {
+ throwMissingPropError('slots');
+ }
+
+ forEachSlot(slots, (slotName) => {
+ it(`sets the styleProps prop on ${capitalize(slotName)} slot's component`, () => {
+ const TestComponent = React.forwardRef(
+ ({ styleProps, expectedStyleProps }: WithStyleProps, ref: React.Ref) => {
+ expect(styleProps).to.deep.include(expectedStyleProps);
+ return
;
+ },
+ );
+
+ const components = {
+ [capitalize(slotName)]: TestComponent,
+ };
+
+ const componentsProps = {
+ [slotName]: {
+ expectedStyleProps: {
+ id: 'foo',
+ },
+ },
+ };
+
+ render(React.cloneElement(element, { components, componentsProps, id: 'foo' }));
+ });
+ });
+}
+
+const fullSuite = {
+ componentProp: testComponentProp,
+ componentsProp: testComponentsProp,
+ componentsPropsProp: testComponentsPropsProp,
+ mergeClassName: testClassName,
+ propsSpread: testPropForwarding,
+ reactTestRenderer: testReactTestRenderer,
+ refForwarding: describeRef,
+ stylePropsPropagation: testStylePropsPropagation,
+};
+
+export default function describeConformanceUnstyled(
+ minimalElement: React.ReactElement,
+ getOptions: () => UnstyledConformanceOptions,
+) {
+ const { after: runAfterHook = () => {}, only = Object.keys(fullSuite), skip = [] } = getOptions();
+
+ const filteredTests = Object.keys(fullSuite).filter(
+ (testKey) =>
+ only.indexOf(testKey) !== -1 && skip.indexOf(testKey as keyof typeof fullSuite) === -1,
+ ) as (keyof typeof fullSuite)[];
+
+ describe('Material-UI unstyled component API', () => {
+ after(runAfterHook);
+
+ filteredTests.forEach((testKey) => {
+ const test = fullSuite[testKey];
+ test(minimalElement, getOptions as any);
+ });
+ });
+}
diff --git a/test/utils/index.js b/test/utils/index.js
index 7201f45b484669..492b8be4f51929 100644
--- a/test/utils/index.js
+++ b/test/utils/index.js
@@ -1,6 +1,7 @@
export * from './components';
export { default as describeConformance } from './describeConformance';
export { default as describeConformanceV5 } from './describeConformanceV5';
+export { default as describeConformanceUnstyled } from './describeConformanceUnstyled';
export * from './createClientRender';
export { default as createMount } from './createMount';
export { default as createServerRender } from './createServerRender';
From 0e030f8eebb42adb1ab78c41d70b7d9aacf8a9c5 Mon Sep 17 00:00:00 2001
From: Olivier Tassinari
Date: Wed, 7 Jul 2021 20:09:01 +0200
Subject: [PATCH 2/9] [examples] Remove forgotten StyledEngineProvider (#27163)
---
examples/gatsby-theme/src/pages/about.js | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/examples/gatsby-theme/src/pages/about.js b/examples/gatsby-theme/src/pages/about.js
index 0efaf254ba3f12..30798b9426fdec 100644
--- a/examples/gatsby-theme/src/pages/about.js
+++ b/examples/gatsby-theme/src/pages/about.js
@@ -1,5 +1,4 @@
import * as React from 'react';
-import { StyledEngineProvider } from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';
import Typography from '@material-ui/core/Typography';
import Box from '@material-ui/core/Box';
@@ -9,17 +8,15 @@ import Copyright from '../components/Copyright';
export default function About() {
return (
-
-
-
-
- Gatsby v5-beta example
-
- Go to the main page
-
-
-
-
-
+
+
+
+ Gatsby v5-beta example
+
+ Go to the main page
+
+
+
+
);
}
From 65c5a4e4e46d29c8e149a133a267ba9d256271c0 Mon Sep 17 00:00:00 2001
From: Matt
Date: Wed, 7 Jul 2021 22:55:16 +0100
Subject: [PATCH 3/9] [docs] Remove Ethical Ads (#27173)
---
docs/src/modules/components/Ad.js | 7 +-
docs/src/modules/components/AdReadthedocs.js | 80 --------------------
2 files changed, 1 insertion(+), 86 deletions(-)
delete mode 100644 docs/src/modules/components/AdReadthedocs.js
diff --git a/docs/src/modules/components/Ad.js b/docs/src/modules/components/Ad.js
index 34c2f1e84e4188..04da6355d00f7b 100644
--- a/docs/src/modules/components/Ad.js
+++ b/docs/src/modules/components/Ad.js
@@ -6,7 +6,6 @@ import Typography from '@material-ui/core/Typography';
import Box from '@material-ui/core/Box';
import Paper from '@material-ui/core/Paper';
import AdCarbon from 'docs/src/modules/components/AdCarbon';
-import AdReadthedocs from 'docs/src/modules/components/AdReadthedocs';
import AdInHouse from 'docs/src/modules/components/AdInHouse';
import { AdContext, adShape } from 'docs/src/modules/components/AdManager';
import { useTranslate } from 'docs/src/modules/utils/i18n';
@@ -105,7 +104,6 @@ function Ad(props) {
const [adblock, setAdblock] = React.useState(null);
const [carbonOut, setCarbonOut] = React.useState(null);
- const { current: randomSplit } = React.useRef(Math.random());
const { current: randomAdblock } = React.useRef(Math.random());
const { current: randomInHouse } = React.useRef(Math.random());
@@ -125,12 +123,9 @@ function Ad(props) {
} else if (carbonOut) {
children = ;
label = 'in-house-carbon';
- } else if (randomSplit < 0.9) {
+ } else {
children = ;
label = 'carbon';
- } else {
- children = ;
- label = 'readthedocs';
}
const ad = React.useContext(AdContext);
diff --git a/docs/src/modules/components/AdReadthedocs.js b/docs/src/modules/components/AdReadthedocs.js
deleted file mode 100644
index bab5fb0e374de1..00000000000000
--- a/docs/src/modules/components/AdReadthedocs.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import * as React from 'react';
-import { makeStyles } from '@material-ui/styles';
-import loadScript from 'docs/src/modules/utils/loadScript';
-import adStyles from 'docs/src/modules/components/ad.styles';
-import { adShape } from 'docs/src/modules/components/AdManager';
-
-const useStyles = makeStyles((theme) => {
- const styles = adStyles(theme);
-
- return {
- '@global': {
- '[data-ea-publisher][data-ea-publisher][data-ea-publisher][data-ea-publisher]': {
- '&&': {
- display: 'block',
- },
- '& .ea-placement': {
- ...styles.root,
- },
- '& .ea-content': {
- margin: 0,
- padding: 0,
- overflow: 'visible',
- boxShadow: 'none',
- background: 'transparent',
- maxWidth: '100%',
- color: 'inherit',
- },
- '& .ea-content > a': {
- ...styles.imgWrapper,
- marginLeft: -125,
- width: 120,
- height: 90,
- },
- '& .ea-content > a img': styles.img,
- '& a, & a:hover': styles.a,
- '& .ea-text': {
- marginTop: 0,
- color: 'inherit',
- textAlign: 'left',
- },
- '& .ea-text strong': {
- color: 'inherit',
- },
- '& .ea-text a': {
- ...styles.description,
- color: 'inherit',
- },
- '& .ea-callout': {
- margin: 0,
- padding: 0,
- fontStyle: 'normal',
- textAlign: 'left',
- ...styles.poweredby,
- },
- '& .ea-callout a': {
- fontSize: 'inherit',
- },
- },
- },
- };
-});
-
-export default function AdReadthedocs() {
- useStyles();
-
- React.useEffect(() => {
- const script = loadScript(
- 'https://media.ethicalads.io/media/client/ethicalads.min.js',
- document.querySelector('head'),
- );
-
- return () => {
- script.parentElement.removeChild(script);
- };
- }, []);
-
- return (
-
- );
-}
From 1a5622b5f89127e270fb1cf9717ced4e6698b75d Mon Sep 17 00:00:00 2001
From: Olivier Tassinari
Date: Thu, 8 Jul 2021 01:05:54 +0200
Subject: [PATCH 4/9] [docs] Fix alt description of movavi backer
---
README.md | 2 +-
docs/src/pages/discover-more/backers/backers.md | 2 +-
docs/src/pages/landing/backers.md | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index c0a6678cad9765..dd80b266ddcbc4 100644
--- a/README.md
+++ b/README.md
@@ -84,7 +84,7 @@ via [OpenCollective](https://opencollective.com/material-ui)
-
+
Direct
diff --git a/docs/src/pages/discover-more/backers/backers.md b/docs/src/pages/discover-more/backers/backers.md
index c2c91321063c1d..b0a1df1830d120 100644
--- a/docs/src/pages/discover-more/backers/backers.md
+++ b/docs/src/pages/discover-more/backers/backers.md
@@ -33,7 +33,7 @@ via [OpenCollective](https://opencollective.com/material-ui)
-
+
Direct
diff --git a/docs/src/pages/landing/backers.md b/docs/src/pages/landing/backers.md
index da917bf7a86f64..6c853379c479c6 100644
--- a/docs/src/pages/landing/backers.md
+++ b/docs/src/pages/landing/backers.md
@@ -24,7 +24,7 @@ _1/3 slots available_
-
+
### There are more!
From 972b994ae3876c78cc8a7af56ec0a568ad9607e9 Mon Sep 17 00:00:00 2001
From: Shirasawa <764798966@qq.com>
Date: Thu, 8 Jul 2021 08:12:07 +0800
Subject: [PATCH 5/9] [Avatar] Fix support for crossOrigin (#27013)
---
packages/material-ui/src/Avatar/Avatar.js | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/packages/material-ui/src/Avatar/Avatar.js b/packages/material-ui/src/Avatar/Avatar.js
index ee297f41f7f13e..0983956d0a3b4d 100644
--- a/packages/material-ui/src/Avatar/Avatar.js
+++ b/packages/material-ui/src/Avatar/Avatar.js
@@ -83,7 +83,7 @@ const AvatarFallback = styled(Person, {
height: '75%',
});
-function useLoaded({ src, srcSet }) {
+function useLoaded({ crossOrigin, referrerPolicy, src, srcSet }) {
const [loaded, setLoaded] = React.useState(false);
React.useEffect(() => {
@@ -107,6 +107,8 @@ function useLoaded({ src, srcSet }) {
}
setLoaded('error');
};
+ image.crossOrigin = crossOrigin;
+ image.referrerPolicy = referrerPolicy;
image.src = src;
if (srcSet) {
image.srcset = srcSet;
@@ -115,7 +117,7 @@ function useLoaded({ src, srcSet }) {
return () => {
active = false;
};
- }, [src, srcSet]);
+ }, [crossOrigin, referrerPolicy, src, srcSet]);
return loaded;
}
@@ -138,7 +140,7 @@ const Avatar = React.forwardRef(function Avatar(inProps, ref) {
let children = null;
// Use a hook instead of onError on the img element to support server-side rendering.
- const loaded = useLoaded({ src, srcSet });
+ const loaded = useLoaded({ ...imgProps, src, srcSet });
const hasImg = src || srcSet;
const hasImgNotFailing = hasImg && loaded !== 'error';
From dc9dbf2391d55b4ebf3a8e90eff9ee0af21b00eb Mon Sep 17 00:00:00 2001
From: Olivier Tassinari
Date: Thu, 8 Jul 2021 02:26:40 +0200
Subject: [PATCH 6/9] [core] Batch small changes (#26970)
---
CHANGELOG.md | 8 +-
CONTRIBUTING.md | 2 +-
docs/packages/markdown/parseMarkdown.js | 1 -
docs/pages/branding/about.tsx | 2 +-
docs/pages/branding/mui-x.tsx | 2 +-
docs/pages/company/lead-designer.js | 2 +-
docs/scripts/buildApi.ts | 6 +-
docs/scripts/helpers.js | 1 -
docs/src/modules/branding/BrandingFooter.tsx | 119 ++++++++++++++----
docs/src/modules/branding/BrandingHeader.tsx | 8 +-
docs/src/modules/branding/ComparisonTable.tsx | 2 +-
docs/src/modules/components/AppFooter.js | 47 +++++--
docs/src/modules/components/AppNavDrawer.js | 10 +-
docs/src/modules/components/Demo.js | 7 +-
docs/src/modules/utils/defaultPropsHandler.js | 1 -
.../components/app-bar/PrimarySearchAppBar.js | 10 +-
.../app-bar/PrimarySearchAppBar.tsx | 10 +-
.../components/badges/AccessibleBadges.js | 2 +-
.../components/badges/AccessibleBadges.tsx | 2 +-
.../pages/components/buttons/ColorButtons.js | 6 +-
.../pages/components/buttons/ColorButtons.tsx | 6 +-
.../components/buttons/ContainedButtons.js | 2 +-
.../components/buttons/ContainedButtons.tsx | 2 +-
.../components/buttons/IconButtonColors.js | 8 +-
.../components/buttons/IconButtonColors.tsx | 8 +-
.../components/buttons/IconButtonSizes.js | 8 +-
.../components/buttons/IconButtonSizes.tsx | 8 +-
.../pages/components/buttons/IconButtons.js | 5 +-
.../pages/components/buttons/IconButtons.tsx | 5 +-
.../components/buttons/IconLabelButtons.js | 2 +-
.../components/buttons/IconLabelButtons.tsx | 2 +-
.../components/buttons/LoadingButtons.js | 2 +-
.../components/buttons/LoadingButtons.tsx | 2 +-
.../components/buttons/OutlinedButtons.js | 2 +-
.../components/buttons/OutlinedButtons.tsx | 2 +-
.../pages/components/buttons/TextButtons.js | 2 +-
.../pages/components/buttons/TextButtons.tsx | 2 +-
.../pages/components/buttons/UploadButtons.js | 2 +-
.../components/buttons/UploadButtons.tsx | 2 +-
docs/src/pages/components/grid/grid.md | 14 +--
.../components/slider/MusicPlayerSlider.js | 2 +-
.../components/slider/MusicPlayerSlider.tsx | 2 +-
.../pages/components/slider/SliderSizes.js | 2 +-
.../pages/components/slider/SliderSizes.tsx | 2 +-
.../text-fields/FullWidthTextField.js | 2 +-
.../text-fields/FullWidthTextField.tsx | 2 +-
.../pages/customization/palette/DarkTheme.js | 5 +-
.../pages/customization/palette/Intentions.js | 12 +-
.../src/internal/pickers/PickersPopper.tsx | 1 -
.../macros/MuiError.macro.js | 1 -
.../src/integerPropType.test.js | 2 +-
.../src/FilledInput/FilledInput.js | 2 +-
.../material-ui/src/OverridableComponent.d.ts | 2 +-
.../material-ui/src/StepLabel/StepLabel.js | 2 +-
.../material-ui/src/colors/colors.spec.tsx | 2 +-
packages/material-ui/src/index.d.ts | 4 +-
packages/material-ui/src/styles/styled.d.ts | 1 -
scripts/buildColorTypes.js | 2 +-
scripts/buildTypes.js | 2 -
scripts/generateProptypes.ts | 4 +-
scripts/releaseChangelog.js | 1 -
test/bundling/scripts/createFixture.js | 1 -
test/utils/components.js | 3 +-
test/utils/describeConformance.js | 1 -
64 files changed, 248 insertions(+), 146 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 07888e4be16f59..946aa519fe3d93 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -149,7 +149,7 @@ Big thanks to the 18 contributors who made this release possible. Here are some
-- 💡 `IconButton` now supports 3 sizes (`small, medium, large`). [See demo](/components/buttons/#sizes-2).
+- 💡 `IconButton` now supports 3 sizes (`small, medium, large`). [See demo](https://next.material-ui.com/components/buttons/#sizes-2).
- ♿️ We have improved the default style of the `Link` to be more accessible (#26145) @ahmed-28
@@ -2338,7 +2338,7 @@ Big thanks to the 23 contributors who made this release possible. Here are some
### Docs
- [examples] Patch preact example not working (#24616)
-- [docs] Add missing newline in component JSDOC (#24610) @eps1lon
+- [docs] Add missing newline in component JSDoc (#24610) @eps1lon
- [docs] Add API of picker components (#24497) @eps1lon
- [examples] Add `locale` prop to the Nextjs Link component (#24596) @CyanoFresh
- [docs] List required props first in /api/* (#24526) @eps1lon
@@ -4791,7 +4791,7 @@ Here are some highlights ✨:
- [docs] Add 'size' prop to ToggleButton API docs (#22052) @zenje
- [docs] Add ClassKeys migration description for Renaming API (#22061) @kodai3
- [docs] Add a label to the TreeView demos (#21900) @joshwooding
-- [docs] Add missing JSDOC for various props (#22005) @eps1lon
+- [docs] Add missing JSDoc for various props (#22005) @eps1lon
- [docs] Add the services that support MUI in readme (#22137) @naineet
- [docs] Add trailingSlash: true (#22008) @oliviertassinari
- [docs] Add visibility to TypeScript examples (#22013) @esemeniuc
@@ -5930,7 +5930,7 @@ Here are some highlights ✨:
- [Tooltip] Fix TextField integration (#20252) @ShehryarShoukat96
- [Tooltip] Remove superfluous argument in handleBlur call (#20271) @CptWesley
- [TypeScript] Enable module augmentation of CommonColors (#20212) @eps1lon
-- [TypeScript] Add JSDOC to ListItem TypeScript props (#20171) @eps1lon
+- [TypeScript] Add JSDoc to ListItem TypeScript props (#20171) @eps1lon
- [TypeScript] Fix Checkbox and Radio type propType (#20293) @eps1lon
- [TypeScript] Fix incorrect typings regarding transition components a… (#20306) @eps1lon
- [TypeScript] Link to demos and API in IntelliSense (#20078) @eps1lon
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a8ea4d7266c52d..1012aacb2f908a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -194,7 +194,7 @@ on _Details_ to find out more about them.
### Updating the component API documentation
-The component API in the component `propTypes` and under `docs/pages/api-docs` is auto-generated from the [JSDOC](https://jsdoc.app/about-getting-started.html) in the TypeScript declarations.
+The component API in the component `propTypes` and under `docs/pages/api-docs` is auto-generated from the [JSDoc](https://jsdoc.app/about-getting-started.html) in the TypeScript declarations.
Be sure to update the documentation in the corresponding `.d.ts` files (e.g. `packages/material-ui/src/Button/Button.d.ts` for ``) and the run:
```sh
diff --git a/docs/packages/markdown/parseMarkdown.js b/docs/packages/markdown/parseMarkdown.js
index 795890fce929a6..31fe05758f630a 100644
--- a/docs/packages/markdown/parseMarkdown.js
+++ b/docs/packages/markdown/parseMarkdown.js
@@ -119,7 +119,6 @@ const externs = [
* @property {string} hash
* @property {number} level
* @property {string} text
- *
* @param {object} context
* @param {Record} context.headingHashes - WILL BE MUTATED
* @param {TableOfContentsEntry[]} context.toc - WILL BE MUTATED
diff --git a/docs/pages/branding/about.tsx b/docs/pages/branding/about.tsx
index 36cb62b4ce0d0a..73eb0d536d3d05 100644
--- a/docs/pages/branding/about.tsx
+++ b/docs/pages/branding/about.tsx
@@ -60,7 +60,7 @@ function BrandingHero() {
return (
- {"We're are making building "}
+ {"We're making building "}
UIs more accessible
diff --git a/docs/pages/branding/mui-x.tsx b/docs/pages/branding/mui-x.tsx
index de5a23ae716aa8..1aedbcd13e25b6 100644
--- a/docs/pages/branding/mui-x.tsx
+++ b/docs/pages/branding/mui-x.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import Container from '@material-ui/core/Container';
import Typography from '@material-ui/core/Typography';
import Grid from '@material-ui/core/Grid';
diff --git a/docs/pages/company/lead-designer.js b/docs/pages/company/lead-designer.js
index 31bf29dcef6b23..f53e3520556257 100644
--- a/docs/pages/company/lead-designer.js
+++ b/docs/pages/company/lead-designer.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import TopLayoutCompany from 'docs/src/modules/components/TopLayoutCompany';
import {
demos,
diff --git a/docs/scripts/buildApi.ts b/docs/scripts/buildApi.ts
index a96258075d7989..c038aa22767ffd 100644
--- a/docs/scripts/buildApi.ts
+++ b/docs/scripts/buildApi.ts
@@ -175,14 +175,14 @@ function createDescribeableProp(
if (shouldHaveDefaultAnnotation) {
throw new Error(
- `JSDOC @default annotation not found. Add \`@default ${defaultValue.value}\` to the JSDOC of this prop.`,
+ `JSDoc @default annotation not found. Add \`@default ${defaultValue.value}\` to the JSDoc of this prop.`,
);
}
} else if (jsdocDefaultValue !== undefined) {
// `defaultValue` can't be undefined or we would've thrown earlier.
if (jsdocDefaultValue.value !== defaultValue!.value) {
throw new Error(
- `Expected JSDOC @default annotation for prop '${propName}' of "${jsdocDefaultValue.value}" to equal runtime default value of "${defaultValue?.value}"`,
+ `Expected JSDoc @default annotation for prop '${propName}' of "${jsdocDefaultValue.value}" to equal runtime default value of "${defaultValue?.value}"`,
);
}
}
@@ -437,7 +437,7 @@ async function annotateComponentDefinition(context: {
const bindingId = babelPath.node.declaration.name;
const binding = babelPath.scope.bindings[bindingId];
- // The JSDOC MUST be located at the declaration
+ // The JSDoc MUST be located at the declaration
if (babel.types.isFunctionDeclaration(binding.path.node)) {
// For function declarations the binding is equal to the declaration
// /**
diff --git a/docs/scripts/helpers.js b/docs/scripts/helpers.js
index ae21845e57cfe3..682f004a12739f 100644
--- a/docs/scripts/helpers.js
+++ b/docs/scripts/helpers.js
@@ -26,7 +26,6 @@ function fixLineEndings(source, target) {
/**
* Converts styled or regular component d.ts file to unstyled d.ts
- *
* @param {string} filename - the file of the styled or regular mui component
*/
function getUnstyledFilename(filename, definitionFile = false) {
diff --git a/docs/src/modules/branding/BrandingFooter.tsx b/docs/src/modules/branding/BrandingFooter.tsx
index 21d181ba59e76e..0078f91d198da6 100644
--- a/docs/src/modules/branding/BrandingFooter.tsx
+++ b/docs/src/modules/branding/BrandingFooter.tsx
@@ -54,22 +54,32 @@ export default function BrandingFooter() {
{t1('Products')}
-
+
Material-UI
-
+
Material-UI X
-
+
{t1('Pricing')}
-
+
{t1('Store')}
@@ -79,6 +89,7 @@ export default function BrandingFooter() {
@@ -86,13 +97,19 @@ export default function BrandingFooter() {
-
+
Twitter
@@ -105,37 +122,52 @@ export default function BrandingFooter() {
{t1('Library')}
-
+
{t1('Free templates')}
-
+
{t1('Material Icons')}
-
+
{t1('Components')}
-
+
{t1('Components API')}
-
+
{t1('System')}
-
+
{t1('Customization')}
-
+
{t1('How To Guides')}
@@ -145,32 +177,62 @@ export default function BrandingFooter() {
{t1('Explore')}
-
+
{t1('Docs')}
-
+
{t1('Blog')}
-
+
{t1('Showcase')}
-
+
{t1('Related Projects')}
-
+
{t1('Roadmap')}
-
+
{t1('Languages')}
@@ -178,17 +240,22 @@ export default function BrandingFooter() {
{t('footerCompany')}
-
+
{t1('About')}
-
+
{t1('Contact Us')}
-
+
{t1('Jobs')}
@@ -198,7 +265,7 @@ export default function BrandingFooter() {
@@ -235,12 +302,13 @@ export default function BrandingFooter() {
-
+
@@ -249,7 +317,8 @@ export default function BrandingFooter() {
),
license: (
{t('license')}
diff --git a/docs/src/modules/branding/BrandingHeader.tsx b/docs/src/modules/branding/BrandingHeader.tsx
index aed4efcc743a9b..f0d2928fba04b9 100644
--- a/docs/src/modules/branding/BrandingHeader.tsx
+++ b/docs/src/modules/branding/BrandingHeader.tsx
@@ -26,7 +26,7 @@ const links = (
color="inherit"
underline="none"
activeClassName="Mui-active"
- href="/branding/mui-x"
+ href="/branding/mui-x/"
>
{t1('Material-UI X')}
@@ -37,7 +37,7 @@ const links = (
color="inherit"
underline="none"
activeClassName="Mui-active"
- href="/branding/pricing"
+ href="/branding/pricing/"
>
{t1('Pricing')}
@@ -48,7 +48,7 @@ const links = (
color="inherit"
underline="none"
activeClassName="Mui-active"
- href="/getting-started/templates"
+ href="/getting-started/templates/"
>
{t1('Templates')}
@@ -59,7 +59,7 @@ const links = (
color="inherit"
underline="none"
activeClassName="Mui-active"
- href="/branding/about"
+ href="/branding/about/"
>
{t1('About Us')}
diff --git a/docs/src/modules/branding/ComparisonTable.tsx b/docs/src/modules/branding/ComparisonTable.tsx
index 55062e697d2223..2a8833491ed717 100644
--- a/docs/src/modules/branding/ComparisonTable.tsx
+++ b/docs/src/modules/branding/ComparisonTable.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { styled, alpha, useTheme } from '@material-ui/core/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';
import Table from '@material-ui/core/Table';
diff --git a/docs/src/modules/components/AppFooter.js b/docs/src/modules/components/AppFooter.js
index b89b867e22b783..d48d0d2c8975f1 100644
--- a/docs/src/modules/components/AppFooter.js
+++ b/docs/src/modules/components/AppFooter.js
@@ -84,7 +84,7 @@ function AppFooter(props) {
-
+
Material-UI
@@ -98,13 +98,19 @@ function AppFooter(props) {
GitHub
-
+
Twitter
@@ -112,13 +118,19 @@ function AppFooter(props) {
StackOverflow
-
+
{t('pages./discover-more/team')}
@@ -130,17 +142,32 @@ function AppFooter(props) {
-
+
{t('pages./getting-started/support')}
-
+
{t('blogTitle')}
-
+
{t('pages./components/material-icons')}
@@ -152,20 +179,20 @@ function AppFooter(props) {
-
+
About
-
+
Contact Us
-
+
Careers
-
+
hiring
diff --git a/docs/src/modules/components/AppNavDrawer.js b/docs/src/modules/components/AppNavDrawer.js
index fb033549020863..e1a446e518e2c3 100644
--- a/docs/src/modules/components/AppNavDrawer.js
+++ b/docs/src/modules/components/AppNavDrawer.js
@@ -160,12 +160,20 @@ function AppNavDrawer(props) {
-
+
Material-UI
{process.env.LIB_VERSION ? (
-
+
@@ -130,10 +130,10 @@ export default function PrimarySearchAppBar() {
-
+
@@ -187,7 +187,7 @@ export default function PrimarySearchAppBar() {
-
+
@@ -196,7 +196,7 @@ export default function PrimarySearchAppBar() {
aria-label="show 17 new notifications"
color="inherit"
>
-
+
diff --git a/docs/src/pages/components/app-bar/PrimarySearchAppBar.tsx b/docs/src/pages/components/app-bar/PrimarySearchAppBar.tsx
index 136df0cf31ca0a..9d43a3b8511840 100644
--- a/docs/src/pages/components/app-bar/PrimarySearchAppBar.tsx
+++ b/docs/src/pages/components/app-bar/PrimarySearchAppBar.tsx
@@ -122,7 +122,7 @@ export default function PrimarySearchAppBar() {
>
-
+
@@ -131,10 +131,10 @@ export default function PrimarySearchAppBar() {
-
+
@@ -188,7 +188,7 @@ export default function PrimarySearchAppBar() {
-
+
@@ -197,7 +197,7 @@ export default function PrimarySearchAppBar() {
aria-label="show 17 new notifications"
color="inherit"
>
-
+
diff --git a/docs/src/pages/components/badges/AccessibleBadges.js b/docs/src/pages/components/badges/AccessibleBadges.js
index e23988ebafe43d..11bf53361c2962 100644
--- a/docs/src/pages/components/badges/AccessibleBadges.js
+++ b/docs/src/pages/components/badges/AccessibleBadges.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import IconButton from '@material-ui/core/IconButton';
import Badge from '@material-ui/core/Badge';
import MailIcon from '@material-ui/icons/Mail';
diff --git a/docs/src/pages/components/badges/AccessibleBadges.tsx b/docs/src/pages/components/badges/AccessibleBadges.tsx
index 383abe77e0973f..cb1d2cd2aa0def 100644
--- a/docs/src/pages/components/badges/AccessibleBadges.tsx
+++ b/docs/src/pages/components/badges/AccessibleBadges.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import IconButton from '@material-ui/core/IconButton';
import Badge from '@material-ui/core/Badge';
import MailIcon from '@material-ui/icons/Mail';
diff --git a/docs/src/pages/components/buttons/ColorButtons.js b/docs/src/pages/components/buttons/ColorButtons.js
index 5a5a6a50b83b69..3ebe9c6dce08ca 100644
--- a/docs/src/pages/components/buttons/ColorButtons.js
+++ b/docs/src/pages/components/buttons/ColorButtons.js
@@ -1,10 +1,10 @@
import * as React from 'react';
-import Box from '@material-ui/core/Box';
+import Stack from '@material-ui/core/Stack';
import Button from '@material-ui/core/Button';
export default function ColorButtons() {
return (
- :not(style)': { m: 1 } }}>
+
Secondary
Success
@@ -12,6 +12,6 @@ export default function ColorButtons() {
Error
-
+
);
}
diff --git a/docs/src/pages/components/buttons/ColorButtons.tsx b/docs/src/pages/components/buttons/ColorButtons.tsx
index 5a5a6a50b83b69..3ebe9c6dce08ca 100644
--- a/docs/src/pages/components/buttons/ColorButtons.tsx
+++ b/docs/src/pages/components/buttons/ColorButtons.tsx
@@ -1,10 +1,10 @@
import * as React from 'react';
-import Box from '@material-ui/core/Box';
+import Stack from '@material-ui/core/Stack';
import Button from '@material-ui/core/Button';
export default function ColorButtons() {
return (
- :not(style)': { m: 1 } }}>
+
Secondary
Success
@@ -12,6 +12,6 @@ export default function ColorButtons() {
Error
-
+
);
}
diff --git a/docs/src/pages/components/buttons/ContainedButtons.js b/docs/src/pages/components/buttons/ContainedButtons.js
index 091153f333bc6f..f861c48084543a 100644
--- a/docs/src/pages/components/buttons/ContainedButtons.js
+++ b/docs/src/pages/components/buttons/ContainedButtons.js
@@ -4,7 +4,7 @@ import Stack from '@material-ui/core/Stack';
export default function ContainedButtons() {
return (
-
+
Contained
Disabled
diff --git a/docs/src/pages/components/buttons/ContainedButtons.tsx b/docs/src/pages/components/buttons/ContainedButtons.tsx
index 091153f333bc6f..f861c48084543a 100644
--- a/docs/src/pages/components/buttons/ContainedButtons.tsx
+++ b/docs/src/pages/components/buttons/ContainedButtons.tsx
@@ -4,7 +4,7 @@ import Stack from '@material-ui/core/Stack';
export default function ContainedButtons() {
return (
-
+
Contained
Disabled
diff --git a/docs/src/pages/components/buttons/IconButtonColors.js b/docs/src/pages/components/buttons/IconButtonColors.js
index 2fd45873a1f1e0..524c9c76806c26 100644
--- a/docs/src/pages/components/buttons/IconButtonColors.js
+++ b/docs/src/pages/components/buttons/IconButtonColors.js
@@ -1,17 +1,17 @@
-import React from 'react';
-import Box from '@material-ui/core/Box';
+import * as React from 'react';
+import Stack from '@material-ui/core/Stack';
import IconButton from '@material-ui/core/IconButton';
import Fingerprint from '@material-ui/icons/Fingerprint';
export default function IconButtonColors() {
return (
-
+
-
+
);
}
diff --git a/docs/src/pages/components/buttons/IconButtonColors.tsx b/docs/src/pages/components/buttons/IconButtonColors.tsx
index 2fd45873a1f1e0..524c9c76806c26 100644
--- a/docs/src/pages/components/buttons/IconButtonColors.tsx
+++ b/docs/src/pages/components/buttons/IconButtonColors.tsx
@@ -1,17 +1,17 @@
-import React from 'react';
-import Box from '@material-ui/core/Box';
+import * as React from 'react';
+import Stack from '@material-ui/core/Stack';
import IconButton from '@material-ui/core/IconButton';
import Fingerprint from '@material-ui/icons/Fingerprint';
export default function IconButtonColors() {
return (
-
+
-
+
);
}
diff --git a/docs/src/pages/components/buttons/IconButtonSizes.js b/docs/src/pages/components/buttons/IconButtonSizes.js
index e2c99d3f934b3d..601cc1c457a2f9 100644
--- a/docs/src/pages/components/buttons/IconButtonSizes.js
+++ b/docs/src/pages/components/buttons/IconButtonSizes.js
@@ -1,11 +1,11 @@
-import React from 'react';
-import Box from '@material-ui/core/Box';
+import * as React from 'react';
+import Stack from '@material-ui/core/Stack';
import IconButton from '@material-ui/core/IconButton';
import DeleteIcon from '@material-ui/icons/Delete';
export default function IconButtonSizes() {
return (
-
+
@@ -18,6 +18,6 @@ export default function IconButtonSizes() {
-
+
);
}
diff --git a/docs/src/pages/components/buttons/IconButtonSizes.tsx b/docs/src/pages/components/buttons/IconButtonSizes.tsx
index e2c99d3f934b3d..601cc1c457a2f9 100644
--- a/docs/src/pages/components/buttons/IconButtonSizes.tsx
+++ b/docs/src/pages/components/buttons/IconButtonSizes.tsx
@@ -1,11 +1,11 @@
-import React from 'react';
-import Box from '@material-ui/core/Box';
+import * as React from 'react';
+import Stack from '@material-ui/core/Stack';
import IconButton from '@material-ui/core/IconButton';
import DeleteIcon from '@material-ui/icons/Delete';
export default function IconButtonSizes() {
return (
-
+
@@ -18,6 +18,6 @@ export default function IconButtonSizes() {
-
+
);
}
diff --git a/docs/src/pages/components/buttons/IconButtons.js b/docs/src/pages/components/buttons/IconButtons.js
index f7bcf7f57fbb22..b52db1cb4c11f0 100644
--- a/docs/src/pages/components/buttons/IconButtons.js
+++ b/docs/src/pages/components/buttons/IconButtons.js
@@ -1,12 +1,13 @@
import * as React from 'react';
import IconButton from '@material-ui/core/IconButton';
+import Stack from '@material-ui/core/Stack';
import DeleteIcon from '@material-ui/icons/Delete';
import AlarmIcon from '@material-ui/icons/Alarm';
import AddShoppingCartIcon from '@material-ui/icons/AddShoppingCart';
export default function IconButtons() {
return (
-
+
@@ -19,6 +20,6 @@ export default function IconButtons() {
-
+
);
}
diff --git a/docs/src/pages/components/buttons/IconButtons.tsx b/docs/src/pages/components/buttons/IconButtons.tsx
index f7bcf7f57fbb22..b52db1cb4c11f0 100644
--- a/docs/src/pages/components/buttons/IconButtons.tsx
+++ b/docs/src/pages/components/buttons/IconButtons.tsx
@@ -1,12 +1,13 @@
import * as React from 'react';
import IconButton from '@material-ui/core/IconButton';
+import Stack from '@material-ui/core/Stack';
import DeleteIcon from '@material-ui/icons/Delete';
import AlarmIcon from '@material-ui/icons/Alarm';
import AddShoppingCartIcon from '@material-ui/icons/AddShoppingCart';
export default function IconButtons() {
return (
-
+
@@ -19,6 +20,6 @@ export default function IconButtons() {
-
+
);
}
diff --git a/docs/src/pages/components/buttons/IconLabelButtons.js b/docs/src/pages/components/buttons/IconLabelButtons.js
index c94b1927d15aa5..4259e743a3f9b8 100644
--- a/docs/src/pages/components/buttons/IconLabelButtons.js
+++ b/docs/src/pages/components/buttons/IconLabelButtons.js
@@ -6,7 +6,7 @@ import Stack from '@material-ui/core/Stack';
export default function IconLabelButtons() {
return (
-
+
}>
Delete
diff --git a/docs/src/pages/components/buttons/IconLabelButtons.tsx b/docs/src/pages/components/buttons/IconLabelButtons.tsx
index c94b1927d15aa5..4259e743a3f9b8 100644
--- a/docs/src/pages/components/buttons/IconLabelButtons.tsx
+++ b/docs/src/pages/components/buttons/IconLabelButtons.tsx
@@ -6,7 +6,7 @@ import Stack from '@material-ui/core/Stack';
export default function IconLabelButtons() {
return (
-
+
}>
Delete
diff --git a/docs/src/pages/components/buttons/LoadingButtons.js b/docs/src/pages/components/buttons/LoadingButtons.js
index be943f7deeb156..37a78f8d1df82b 100644
--- a/docs/src/pages/components/buttons/LoadingButtons.js
+++ b/docs/src/pages/components/buttons/LoadingButtons.js
@@ -5,7 +5,7 @@ import Stack from '@material-ui/core/Stack';
export default function LoadingButtons() {
return (
-
+
Submit
diff --git a/docs/src/pages/components/buttons/LoadingButtons.tsx b/docs/src/pages/components/buttons/LoadingButtons.tsx
index be943f7deeb156..37a78f8d1df82b 100644
--- a/docs/src/pages/components/buttons/LoadingButtons.tsx
+++ b/docs/src/pages/components/buttons/LoadingButtons.tsx
@@ -5,7 +5,7 @@ import Stack from '@material-ui/core/Stack';
export default function LoadingButtons() {
return (
-
+
Submit
diff --git a/docs/src/pages/components/buttons/OutlinedButtons.js b/docs/src/pages/components/buttons/OutlinedButtons.js
index d8e6f89bc2a05f..6f2f4b07043999 100644
--- a/docs/src/pages/components/buttons/OutlinedButtons.js
+++ b/docs/src/pages/components/buttons/OutlinedButtons.js
@@ -4,7 +4,7 @@ import Stack from '@material-ui/core/Stack';
export default function OutlinedButtons() {
return (
-
+
Primary
Disabled
diff --git a/docs/src/pages/components/buttons/OutlinedButtons.tsx b/docs/src/pages/components/buttons/OutlinedButtons.tsx
index d8e6f89bc2a05f..6f2f4b07043999 100644
--- a/docs/src/pages/components/buttons/OutlinedButtons.tsx
+++ b/docs/src/pages/components/buttons/OutlinedButtons.tsx
@@ -4,7 +4,7 @@ import Stack from '@material-ui/core/Stack';
export default function OutlinedButtons() {
return (
-
+
Primary
Disabled
diff --git a/docs/src/pages/components/buttons/TextButtons.js b/docs/src/pages/components/buttons/TextButtons.js
index 5b96bc4abf3aba..99b2d43f2c8c79 100644
--- a/docs/src/pages/components/buttons/TextButtons.js
+++ b/docs/src/pages/components/buttons/TextButtons.js
@@ -4,7 +4,7 @@ import Stack from '@material-ui/core/Stack';
export default function TextButtons() {
return (
-
+
Primary
Disabled
Link
diff --git a/docs/src/pages/components/buttons/TextButtons.tsx b/docs/src/pages/components/buttons/TextButtons.tsx
index 5b96bc4abf3aba..99b2d43f2c8c79 100644
--- a/docs/src/pages/components/buttons/TextButtons.tsx
+++ b/docs/src/pages/components/buttons/TextButtons.tsx
@@ -4,7 +4,7 @@ import Stack from '@material-ui/core/Stack';
export default function TextButtons() {
return (
-
+
Primary
Disabled
Link
diff --git a/docs/src/pages/components/buttons/UploadButtons.js b/docs/src/pages/components/buttons/UploadButtons.js
index f2292ae294f7b9..1a2b9b7f4e8868 100644
--- a/docs/src/pages/components/buttons/UploadButtons.js
+++ b/docs/src/pages/components/buttons/UploadButtons.js
@@ -11,7 +11,7 @@ const Input = styled('input')({
export default function UploadButtons() {
return (
-
+
diff --git a/docs/src/pages/components/buttons/UploadButtons.tsx b/docs/src/pages/components/buttons/UploadButtons.tsx
index f2292ae294f7b9..1a2b9b7f4e8868 100644
--- a/docs/src/pages/components/buttons/UploadButtons.tsx
+++ b/docs/src/pages/components/buttons/UploadButtons.tsx
@@ -11,7 +11,7 @@ const Input = styled('input')({
export default function UploadButtons() {
return (
-
+
diff --git a/docs/src/pages/components/grid/grid.md b/docs/src/pages/components/grid/grid.md
index 2915742dfb7e9d..daea459d4dcbd4 100644
--- a/docs/src/pages/components/grid/grid.md
+++ b/docs/src/pages/components/grid/grid.md
@@ -57,6 +57,13 @@ The prop is converted into a CSS property using the [`theme.spacing()`](/customi
{{"demo": "pages/components/grid/SpacingGrid.js", "bg": true}}
+### Row & column spacing
+
+The `rowSpacing` and `columnSpacing` props allow for specifying the row and column gaps independently.
+It's similar to the `row-gap` and `column-gap` properties of [CSS Grid](/system/grid/#row-gap-amp-column-gap).
+
+{{"demo": "pages/components/grid/RowAndColumnSpacing.js", "bg": true}}
+
## Responsive values
You can switch the props' value based on the active breakpoint.
@@ -82,13 +89,6 @@ Responsive values is supported by:
>
> ```
-### Row & column spacing
-
-The `rowSpacing` and `columnSpacing` props allow for specifying the row and column gaps independently.
-It's similar to the `row-gap` and `column-gap` properties of [CSS Grid](/system/grid/#row-gap-amp-column-gap).
-
-{{"demo": "pages/components/grid/RowAndColumnSpacing.js", "bg": true}}
-
## Interactive
Below is an interactive demo that lets you explore the visual results of the different settings:
diff --git a/docs/src/pages/components/slider/MusicPlayerSlider.js b/docs/src/pages/components/slider/MusicPlayerSlider.js
index 7e4a10cf47ade9..8c8b48e9c7a70c 100644
--- a/docs/src/pages/components/slider/MusicPlayerSlider.js
+++ b/docs/src/pages/components/slider/MusicPlayerSlider.js
@@ -101,7 +101,7 @@ export default function MusicPlayerSlider() {
/>
-
+
Jun Pulse
diff --git a/docs/src/pages/components/slider/MusicPlayerSlider.tsx b/docs/src/pages/components/slider/MusicPlayerSlider.tsx
index 274628c08c67e0..4d8bccb0032430 100644
--- a/docs/src/pages/components/slider/MusicPlayerSlider.tsx
+++ b/docs/src/pages/components/slider/MusicPlayerSlider.tsx
@@ -101,7 +101,7 @@ export default function MusicPlayerSlider() {
/>
-
+
Jun Pulse
diff --git a/docs/src/pages/components/slider/SliderSizes.js b/docs/src/pages/components/slider/SliderSizes.js
index 677267866f8391..0a4c44552b42e4 100644
--- a/docs/src/pages/components/slider/SliderSizes.js
+++ b/docs/src/pages/components/slider/SliderSizes.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import Box from '@material-ui/core/Box';
import Slider from '@material-ui/core/Slider';
diff --git a/docs/src/pages/components/slider/SliderSizes.tsx b/docs/src/pages/components/slider/SliderSizes.tsx
index 677267866f8391..0a4c44552b42e4 100644
--- a/docs/src/pages/components/slider/SliderSizes.tsx
+++ b/docs/src/pages/components/slider/SliderSizes.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import Box from '@material-ui/core/Box';
import Slider from '@material-ui/core/Slider';
diff --git a/docs/src/pages/components/text-fields/FullWidthTextField.js b/docs/src/pages/components/text-fields/FullWidthTextField.js
index 4f9616d9c83185..eaebecb90a370a 100644
--- a/docs/src/pages/components/text-fields/FullWidthTextField.js
+++ b/docs/src/pages/components/text-fields/FullWidthTextField.js
@@ -10,7 +10,7 @@ export default function FullWidthTextField() {
maxWidth: '100%',
}}
>
-
+
);
}
diff --git a/docs/src/pages/components/text-fields/FullWidthTextField.tsx b/docs/src/pages/components/text-fields/FullWidthTextField.tsx
index 4f9616d9c83185..eaebecb90a370a 100644
--- a/docs/src/pages/components/text-fields/FullWidthTextField.tsx
+++ b/docs/src/pages/components/text-fields/FullWidthTextField.tsx
@@ -10,7 +10,7 @@ export default function FullWidthTextField() {
maxWidth: '100%',
}}
>
-
+
);
}
diff --git a/docs/src/pages/customization/palette/DarkTheme.js b/docs/src/pages/customization/palette/DarkTheme.js
index 82bca9f040c046..48cc2075fcefa4 100644
--- a/docs/src/pages/customization/palette/DarkTheme.js
+++ b/docs/src/pages/customization/palette/DarkTheme.js
@@ -1,6 +1,7 @@
import * as React from 'react';
import Typography from '@material-ui/core/Typography';
import Grid from '@material-ui/core/Grid';
+import Box from '@material-ui/core/Box';
import {
styled,
ThemeProvider,
@@ -105,13 +106,13 @@ export default function DarkTheme() {
// Note that if you intend to use two or more themes at the same time on your site,
// you need to wrap them with a single ThemeProvider at the root (not like in this example).
return (
-
+
-
+
);
}
diff --git a/docs/src/pages/customization/palette/Intentions.js b/docs/src/pages/customization/palette/Intentions.js
index 8b8b75b1da3dba..5cf83688186f6c 100644
--- a/docs/src/pages/customization/palette/Intentions.js
+++ b/docs/src/pages/customization/palette/Intentions.js
@@ -99,11 +99,17 @@ function IntentionsInner() {
);
}
-const defaultTheme = createTheme();
-
export default function Intentions() {
+ const theme = useTheme();
+
return (
-
+
);
diff --git a/packages/material-ui-lab/src/internal/pickers/PickersPopper.tsx b/packages/material-ui-lab/src/internal/pickers/PickersPopper.tsx
index 69c711a8b4467e..894a3e237a31ea 100644
--- a/packages/material-ui-lab/src/internal/pickers/PickersPopper.tsx
+++ b/packages/material-ui-lab/src/internal/pickers/PickersPopper.tsx
@@ -55,7 +55,6 @@ function clickedRootScrollbar(event: MouseEvent, doc: Document) {
/**
* Based on @material-ui/core/ClickAwayListener without the customization.
* We can probably strip away even more since children won't be portaled.
- *
* @param onClickAway
* @param onClick
* @param onTouchStart
diff --git a/packages/material-ui-utils/macros/MuiError.macro.js b/packages/material-ui-utils/macros/MuiError.macro.js
index 12c2dc7b06b377..9e7ac16dbe1d42 100644
--- a/packages/material-ui-utils/macros/MuiError.macro.js
+++ b/packages/material-ui-utils/macros/MuiError.macro.js
@@ -15,7 +15,6 @@ function invertObject(object) {
* Supported imports:
* 1. bare specifier e.g. `'@material-ui/utils/macros/MuiError.macro'`
* 2. relative import from `packages/material-ui-utils/src` e.g. `'../macros/MuiError.macro'`
- *
* @param {import('babel-plugin-macros').MacroParams} param0
*/
function muiError({ references, babel, config, source }) {
diff --git a/packages/material-ui-utils/src/integerPropType.test.js b/packages/material-ui-utils/src/integerPropType.test.js
index cbc45dcd3cf576..878a6bc25bd4cf 100644
--- a/packages/material-ui-utils/src/integerPropType.test.js
+++ b/packages/material-ui-utils/src/integerPropType.test.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import * as React from 'react';
import { expect } from 'chai';
import PropTypes from 'prop-types';
import { integerPropType } from '@material-ui/utils';
diff --git a/packages/material-ui/src/FilledInput/FilledInput.js b/packages/material-ui/src/FilledInput/FilledInput.js
index b8171e235b4da5..27721759591e5b 100644
--- a/packages/material-ui/src/FilledInput/FilledInput.js
+++ b/packages/material-ui/src/FilledInput/FilledInput.js
@@ -182,10 +182,10 @@ const FilledInput = React.forwardRef(function FilledInput(inProps, ref) {
const {
disableUnderline,
fullWidth = false,
+ hiddenLabel, // declare here to prevent spreading to DOM
inputComponent = 'input',
multiline = false,
type = 'text',
- hiddenLabel, // declare here to prevent spreading to DOM
...other
} = props;
diff --git a/packages/material-ui/src/OverridableComponent.d.ts b/packages/material-ui/src/OverridableComponent.d.ts
index 99cf7de9b963aa..3a3652f7c4c7ec 100644
--- a/packages/material-ui/src/OverridableComponent.d.ts
+++ b/packages/material-ui/src/OverridableComponent.d.ts
@@ -51,7 +51,7 @@ export type BaseProps =
/**
* Props that are valid for material-ui components.
*/
-// each component declares it's classes in a separate interface for proper JSDOC.
+// each component declares it's classes in a separate interface for proper JSDoc.
export interface CommonProps extends StyledComponentProps {
className?: string;
style?: React.CSSProperties;
diff --git a/packages/material-ui/src/StepLabel/StepLabel.js b/packages/material-ui/src/StepLabel/StepLabel.js
index 4dd8a86650f43b..1c8f6af15dcd34 100644
--- a/packages/material-ui/src/StepLabel/StepLabel.js
+++ b/packages/material-ui/src/StepLabel/StepLabel.js
@@ -117,12 +117,12 @@ const StepLabel = React.forwardRef(function StepLabel(inProps, ref) {
const {
children,
className,
+ componentsProps = {},
error = false,
icon: iconProp,
optional,
StepIconComponent: StepIconComponentProp,
StepIconProps,
- componentsProps = {},
...other
} = props;
diff --git a/packages/material-ui/src/colors/colors.spec.tsx b/packages/material-ui/src/colors/colors.spec.tsx
index 6ad001152f7f65..ec9a69911df1d2 100644
--- a/packages/material-ui/src/colors/colors.spec.tsx
+++ b/packages/material-ui/src/colors/colors.spec.tsx
@@ -8,7 +8,7 @@ type KeysEquivalent = keyof T extends keyof U
function colorTypeMatches(variants: keyof Color) {
// Checking that each color has the exact shape as Color
- // we don't use the Color type for these to provide JSDOC for each color
+ // we don't use the Color type for these to provide JSDoc for each color
// in which we preview the color
const amber: KeysEquivalent = true;
const blue: KeysEquivalent = true;
diff --git a/packages/material-ui/src/index.d.ts b/packages/material-ui/src/index.d.ts
index d086638b6919b4..ed08cc1d465ff4 100644
--- a/packages/material-ui/src/index.d.ts
+++ b/packages/material-ui/src/index.d.ts
@@ -26,13 +26,13 @@ export type StandardProps<
*
* Internal helper type for conform (describeConformance) components
* However, we don't declare classes on this type.
- * It is recommended to declare them manually with an interface so that each class can have a separate JSDOC.
+ * It is recommended to declare them manually with an interface so that each class can have a separate JSDoc.
*/
export type InternalStandardProps = DistributiveOmit<
C,
'classes' | Removals
> &
- // each component declares it's classes in a separate interface for proper JSDOC
+ // each component declares it's classes in a separate interface for proper JSDoc
StyledComponentProps & {
ref?: C extends { ref?: infer RefType } ? RefType : React.Ref;
// TODO: Remove implicit props. Up to each component.
diff --git a/packages/material-ui/src/styles/styled.d.ts b/packages/material-ui/src/styles/styled.d.ts
index 928ed5f1eaf63a..cf3c6977714a99 100644
--- a/packages/material-ui/src/styles/styled.d.ts
+++ b/packages/material-ui/src/styles/styled.d.ts
@@ -3,7 +3,6 @@ import { Theme } from './createTheme';
/**
* Custom styled utility that has a default MUI theme.
- *
* @param tag HTML tag or component that should serve as base.
* @param options Styled options for the created component.
* @returns React component that has styles attached to it.
diff --git a/scripts/buildColorTypes.js b/scripts/buildColorTypes.js
index 23c20622ca8330..f603787a87ff35 100644
--- a/scripts/buildColorTypes.js
+++ b/scripts/buildColorTypes.js
@@ -60,7 +60,7 @@ function buildColorPreviews(name, variants) {
/**
* The goal is to have a preview of the actual color and the color string in IntelliSense
* We create for each color an svg that is filled with that color and reference
- * that svg in the corresponding JSDOC.
+ * that svg in the corresponding JSDoc.
* Since we use https://material-ui.com as a reference changes are only visible
* after release
*/
diff --git a/scripts/buildTypes.js b/scripts/buildTypes.js
index 1c4bcec1839132..9218f14fea4c0b 100644
--- a/scripts/buildTypes.js
+++ b/scripts/buildTypes.js
@@ -10,9 +10,7 @@ const exec = promisify(childProcess.exec);
/**
* Fixes a wrong import path caused by https://github.com/microsoft/TypeScript/issues/39117
- *
* @remarks Paths are hardcoded since it is unclear if all these broken import paths target "public paths".
- *
* @param {string} importPath - POSIX path
*/
function rewriteImportPath(importPath) {
diff --git a/scripts/generateProptypes.ts b/scripts/generateProptypes.ts
index 6ee84cab6e008f..9a361ba90176ab 100644
--- a/scripts/generateProptypes.ts
+++ b/scripts/generateProptypes.ts
@@ -113,8 +113,8 @@ const transitionCallbacks = [
];
/**
* These are components that use props implemented by external components.
- * Those props have their own JSDOC which we don't want to emit in our docs
- * but do want them to have JSDOC in IntelliSense
+ * Those props have their own JSDoc which we don't want to emit in our docs
+ * but do want them to have JSDoc in IntelliSense
* TODO: In the future we want to ignore external docs on the initial load anyway
* since they will be fetched dynamically.
*/
diff --git a/scripts/releaseChangelog.js b/scripts/releaseChangelog.js
index c41b45d105cdb7..13af35228e37a3 100644
--- a/scripts/releaseChangelog.js
+++ b/scripts/releaseChangelog.js
@@ -28,7 +28,6 @@ function parseTags(commitMessage) {
}
/**
- *
* @param {Octokit.ReposCompareCommitsResponseCommitsItem} commitsItem
*/
function filterCommit(commitsItem) {
diff --git a/test/bundling/scripts/createFixture.js b/test/bundling/scripts/createFixture.js
index 806eee4b3a6184..cbbe77c3231932 100644
--- a/test/bundling/scripts/createFixture.js
+++ b/test/bundling/scripts/createFixture.js
@@ -9,7 +9,6 @@ import { URL } from 'url';
*/
/**
- *
* @param {URL} destinationUrl
* @param {string} templateSource
* @param {Record} templateValues
diff --git a/test/utils/components.js b/test/utils/components.js
index ae054d7ec9a1d2..7257e31e73a4da 100644
--- a/test/utils/components.js
+++ b/test/utils/components.js
@@ -37,7 +37,8 @@ export class ErrorBoundary extends React.Component {
}
/**
- * Allows counting how many times the owner of `RenderCounter` rendered.
+ * Allows counting how many times the owner of `RenderCounter` rendered or
+ * a component within the RenderCounter tree "commits" an update.
* @example ...
* getRenderCountRef.current() === 2
* @type {import('react').JSXElementConstructor<{children: import('react').ReactNode} & import('react').RefAttributes<() => number>>}
diff --git a/test/utils/describeConformance.js b/test/utils/describeConformance.js
index 27e1f5ba1b8e9a..3980e542786164 100644
--- a/test/utils/describeConformance.js
+++ b/test/utils/describeConformance.js
@@ -92,7 +92,6 @@ export function testComponentProp(element, getOptions) {
/**
* Material-UI components can spread additional props to a documented component.
- *
* @param {React.ReactElement} element
* @param {() => ConformanceOptions} getOptions
*/
From 7a96ef93a8955bf031992c2c3232d61e7123dda6 Mon Sep 17 00:00:00 2001
From: Olivier Tassinari
Date: Thu, 8 Jul 2021 02:29:15 +0200
Subject: [PATCH 7/9] [pickers] Fix default value of text keys (#26990)
---
docs/pages/api-docs/date-picker.json | 12 +++---
docs/pages/api-docs/date-range-picker.json | 14 +++----
docs/pages/api-docs/date-time-picker.json | 12 +++---
docs/pages/api-docs/desktop-date-picker.json | 4 +-
.../api-docs/desktop-date-range-picker.json | 4 +-
.../api-docs/desktop-date-time-picker.json | 4 +-
docs/pages/api-docs/desktop-time-picker.json | 4 +-
docs/pages/api-docs/mobile-date-picker.json | 12 +++---
.../api-docs/mobile-date-range-picker.json | 12 +++---
.../api-docs/mobile-date-time-picker.json | 12 +++---
docs/pages/api-docs/mobile-time-picker.json | 12 +++---
docs/pages/api-docs/static-date-picker.json | 4 +-
.../api-docs/static-date-range-picker.json | 4 +-
.../api-docs/static-date-time-picker.json | 4 +-
docs/pages/api-docs/static-time-picker.json | 4 +-
docs/pages/api-docs/time-picker.json | 12 +++---
.../src/DatePicker/DatePicker.tsx | 12 +++---
.../src/DatePicker/DatePickerToolbar.tsx | 2 +-
.../material-ui-lab/src/DatePicker/shared.ts | 5 +++
.../src/DateRangePicker/DateRangePicker.tsx | 16 ++++----
.../DateRangePickerToolbar.tsx | 2 +-
.../DateRangePicker/DateRangePickerView.tsx | 5 +++
.../src/DateTimePicker/DateTimePicker.tsx | 12 +++---
.../DateTimePicker/DateTimePickerToolbar.tsx | 2 +-
.../src/DateTimePicker/shared.ts | 5 +++
.../DesktopDatePicker/DesktopDatePicker.tsx | 4 +-
.../DesktopDateRangePicker.tsx | 4 +-
.../DesktopDateTimePicker.tsx | 4 +-
.../DesktopTimePicker/DesktopTimePicker.tsx | 4 +-
.../src/MobileDatePicker/MobileDatePicker.tsx | 12 +++---
.../MobileDateRangePicker.tsx | 12 +++---
.../MobileDateTimePicker.tsx | 12 +++---
.../src/MobileTimePicker/MobileTimePicker.tsx | 12 +++---
.../src/StaticDatePicker/StaticDatePicker.tsx | 4 +-
.../StaticDateRangePicker.tsx | 4 +-
.../StaticDateTimePicker.tsx | 4 +-
.../src/StaticTimePicker/StaticTimePicker.tsx | 4 +-
.../src/TimePicker/TimePicker.tsx | 12 +++---
.../src/TimePicker/TimePickerToolbar.tsx | 2 +-
.../material-ui-lab/src/TimePicker/shared.tsx | 5 +++
.../src/internal/pickers/Picker/Picker.tsx | 37 ++++++++++---------
.../internal/pickers/PickersModalDialog.tsx | 8 ++--
.../internal/pickers/typings/BasePicker.tsx | 5 +--
.../pickers/wrappers/ResponsiveWrapper.tsx | 4 +-
44 files changed, 182 insertions(+), 162 deletions(-)
diff --git a/docs/pages/api-docs/date-picker.json b/docs/pages/api-docs/date-picker.json
index 31b44d16b81486..c9b1010277d548 100644
--- a/docs/pages/api-docs/date-picker.json
+++ b/docs/pages/api-docs/date-picker.json
@@ -7,10 +7,10 @@
"default": "/\\dap/gi"
},
"allowSameDateSelection": { "type": { "name": "bool" } },
- "cancelText": { "type": { "name": "node" }, "default": "\"CANCEL\"" },
+ "cancelText": { "type": { "name": "node" }, "default": "'Cancel'" },
"className": { "type": { "name": "string" } },
"clearable": { "type": { "name": "bool" } },
- "clearText": { "type": { "name": "node" }, "default": "\"CLEAR\"" },
+ "clearText": { "type": { "name": "node" }, "default": "'Clear'" },
"components": {
"type": {
"name": "shape",
@@ -46,7 +46,7 @@
"leftArrowButtonText": { "type": { "name": "string" } },
"loading": { "type": { "name": "bool" } },
"mask": { "type": { "name": "string" } },
- "okText": { "type": { "name": "node" }, "default": "\"OK\"" },
+ "okText": { "type": { "name": "node" }, "default": "'OK'" },
"onAccept": { "type": { "name": "func" } },
"onClose": { "type": { "name": "func" } },
"onError": { "type": { "name": "func" } },
@@ -83,11 +83,11 @@
"showDaysOutsideCurrentMonth": { "type": { "name": "bool" } },
"showTodayButton": { "type": { "name": "bool" } },
"showToolbar": { "type": { "name": "bool" } },
- "todayText": { "type": { "name": "node" }, "default": "\"TODAY\"" },
+ "todayText": { "type": { "name": "node" }, "default": "'Today'" },
"ToolbarComponent": { "type": { "name": "elementType" }, "default": "DatePickerToolbar" },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select date'" },
"TransitionComponent": { "type": { "name": "elementType" } },
"value": {
"type": {
diff --git a/docs/pages/api-docs/date-range-picker.json b/docs/pages/api-docs/date-range-picker.json
index 38db2499d0a333..73cb3d92037e70 100644
--- a/docs/pages/api-docs/date-range-picker.json
+++ b/docs/pages/api-docs/date-range-picker.json
@@ -18,10 +18,10 @@
"type": { "name": "enum", "description": "1 | 2 | 3" },
"default": "2"
},
- "cancelText": { "type": { "name": "node" }, "default": "\"CANCEL\"" },
+ "cancelText": { "type": { "name": "node" }, "default": "'Cancel'" },
"className": { "type": { "name": "string" } },
"clearable": { "type": { "name": "bool" } },
- "clearText": { "type": { "name": "node" }, "default": "\"CLEAR\"" },
+ "clearText": { "type": { "name": "node" }, "default": "'Clear'" },
"components": {
"type": {
"name": "shape",
@@ -33,7 +33,7 @@
"defaultCalendarMonth": { "type": { "name": "any" } },
"desktopModeMediaQuery": {
"type": { "name": "string" },
- "default": "\"@media (pointer: fine)\""
+ "default": "'@media (pointer: fine)'"
},
"DialogProps": { "type": { "name": "object" } },
"disableAutoMonthSwitching": { "type": { "name": "bool" } },
@@ -61,7 +61,7 @@
"mask": { "type": { "name": "string" }, "default": "'__/__/____'" },
"maxDate": { "type": { "name": "any" }, "default": "defaultMaxDate" },
"minDate": { "type": { "name": "any" }, "default": "defaultMinDate" },
- "okText": { "type": { "name": "node" }, "default": "\"OK\"" },
+ "okText": { "type": { "name": "node" }, "default": "'OK'" },
"onAccept": { "type": { "name": "func" } },
"onClose": { "type": { "name": "func" } },
"onError": { "type": { "name": "func" } },
@@ -92,11 +92,11 @@
"showTodayButton": { "type": { "name": "bool" } },
"showToolbar": { "type": { "name": "bool" } },
"startText": { "type": { "name": "node" }, "default": "'Start'" },
- "todayText": { "type": { "name": "node" }, "default": "\"TODAY\"" },
+ "todayText": { "type": { "name": "node" }, "default": "'Today'" },
"ToolbarComponent": { "type": { "name": "elementType" } },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select date range'" },
"TransitionComponent": { "type": { "name": "elementType" } }
},
"name": "DateRangePicker",
diff --git a/docs/pages/api-docs/date-time-picker.json b/docs/pages/api-docs/date-time-picker.json
index c0db15340f316a..ceb460a1e180d6 100644
--- a/docs/pages/api-docs/date-time-picker.json
+++ b/docs/pages/api-docs/date-time-picker.json
@@ -9,10 +9,10 @@
"allowSameDateSelection": { "type": { "name": "bool" } },
"ampm": { "type": { "name": "bool" } },
"ampmInClock": { "type": { "name": "bool" } },
- "cancelText": { "type": { "name": "node" }, "default": "\"CANCEL\"" },
+ "cancelText": { "type": { "name": "node" }, "default": "'Cancel'" },
"className": { "type": { "name": "string" } },
"clearable": { "type": { "name": "bool" } },
- "clearText": { "type": { "name": "node" }, "default": "\"CLEAR\"" },
+ "clearText": { "type": { "name": "node" }, "default": "'Clear'" },
"components": {
"type": {
"name": "shape",
@@ -68,7 +68,7 @@
}
},
"minutesStep": { "type": { "name": "number" }, "default": "1" },
- "okText": { "type": { "name": "node" }, "default": "\"OK\"" },
+ "okText": { "type": { "name": "node" }, "default": "'OK'" },
"onAccept": { "type": { "name": "func" } },
"onClose": { "type": { "name": "func" } },
"onError": { "type": { "name": "func" } },
@@ -107,11 +107,11 @@
"showTodayButton": { "type": { "name": "bool" } },
"showToolbar": { "type": { "name": "bool" } },
"timeIcon": { "type": { "name": "node" } },
- "todayText": { "type": { "name": "node" }, "default": "\"TODAY\"" },
+ "todayText": { "type": { "name": "node" }, "default": "'Today'" },
"ToolbarComponent": { "type": { "name": "elementType" }, "default": "DateTimePickerToolbar" },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select date & time'" },
"TransitionComponent": { "type": { "name": "elementType" } },
"value": {
"type": {
diff --git a/docs/pages/api-docs/desktop-date-picker.json b/docs/pages/api-docs/desktop-date-picker.json
index 3fb6152ef98548..e57e8bd876d1ed 100644
--- a/docs/pages/api-docs/desktop-date-picker.json
+++ b/docs/pages/api-docs/desktop-date-picker.json
@@ -75,8 +75,8 @@
"showToolbar": { "type": { "name": "bool" } },
"ToolbarComponent": { "type": { "name": "elementType" }, "default": "DatePickerToolbar" },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select date'" },
"TransitionComponent": { "type": { "name": "elementType" } },
"value": {
"type": {
diff --git a/docs/pages/api-docs/desktop-date-range-picker.json b/docs/pages/api-docs/desktop-date-range-picker.json
index c2bde484b4bd36..8a46f59cf5c249 100644
--- a/docs/pages/api-docs/desktop-date-range-picker.json
+++ b/docs/pages/api-docs/desktop-date-range-picker.json
@@ -84,8 +84,8 @@
"startText": { "type": { "name": "node" }, "default": "'Start'" },
"ToolbarComponent": { "type": { "name": "elementType" } },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select date range'" },
"TransitionComponent": { "type": { "name": "elementType" } }
},
"name": "DesktopDateRangePicker",
diff --git a/docs/pages/api-docs/desktop-date-time-picker.json b/docs/pages/api-docs/desktop-date-time-picker.json
index 28ab6836221b0f..50dfbd306ba4c3 100644
--- a/docs/pages/api-docs/desktop-date-time-picker.json
+++ b/docs/pages/api-docs/desktop-date-time-picker.json
@@ -99,8 +99,8 @@
"timeIcon": { "type": { "name": "node" } },
"ToolbarComponent": { "type": { "name": "elementType" }, "default": "DateTimePickerToolbar" },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select date & time'" },
"TransitionComponent": { "type": { "name": "elementType" } },
"value": {
"type": {
diff --git a/docs/pages/api-docs/desktop-time-picker.json b/docs/pages/api-docs/desktop-time-picker.json
index 426b40062dd68b..cf9a55b4e47d7b 100644
--- a/docs/pages/api-docs/desktop-time-picker.json
+++ b/docs/pages/api-docs/desktop-time-picker.json
@@ -57,8 +57,8 @@
"showToolbar": { "type": { "name": "bool" } },
"ToolbarComponent": { "type": { "name": "elementType" }, "default": "TimePickerToolbar" },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select time'" },
"TransitionComponent": { "type": { "name": "elementType" } },
"value": {
"type": {
diff --git a/docs/pages/api-docs/mobile-date-picker.json b/docs/pages/api-docs/mobile-date-picker.json
index 05c20431512df5..f4b7334c0a3113 100644
--- a/docs/pages/api-docs/mobile-date-picker.json
+++ b/docs/pages/api-docs/mobile-date-picker.json
@@ -7,10 +7,10 @@
"default": "/\\dap/gi"
},
"allowSameDateSelection": { "type": { "name": "bool" } },
- "cancelText": { "type": { "name": "node" }, "default": "\"CANCEL\"" },
+ "cancelText": { "type": { "name": "node" }, "default": "'Cancel'" },
"className": { "type": { "name": "string" } },
"clearable": { "type": { "name": "bool" } },
- "clearText": { "type": { "name": "node" }, "default": "\"CLEAR\"" },
+ "clearText": { "type": { "name": "node" }, "default": "'Clear'" },
"components": {
"type": {
"name": "shape",
@@ -42,7 +42,7 @@
"leftArrowButtonText": { "type": { "name": "string" } },
"loading": { "type": { "name": "bool" } },
"mask": { "type": { "name": "string" } },
- "okText": { "type": { "name": "node" }, "default": "\"OK\"" },
+ "okText": { "type": { "name": "node" }, "default": "'OK'" },
"onAccept": { "type": { "name": "func" } },
"onClose": { "type": { "name": "func" } },
"onError": { "type": { "name": "func" } },
@@ -78,11 +78,11 @@
"showDaysOutsideCurrentMonth": { "type": { "name": "bool" } },
"showTodayButton": { "type": { "name": "bool" } },
"showToolbar": { "type": { "name": "bool" } },
- "todayText": { "type": { "name": "node" }, "default": "\"TODAY\"" },
+ "todayText": { "type": { "name": "node" }, "default": "'Today'" },
"ToolbarComponent": { "type": { "name": "elementType" }, "default": "DatePickerToolbar" },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select date'" },
"value": {
"type": {
"name": "union",
diff --git a/docs/pages/api-docs/mobile-date-range-picker.json b/docs/pages/api-docs/mobile-date-range-picker.json
index 1a6e8a0ad8af29..7ec4108d6e6f43 100644
--- a/docs/pages/api-docs/mobile-date-range-picker.json
+++ b/docs/pages/api-docs/mobile-date-range-picker.json
@@ -18,10 +18,10 @@
"type": { "name": "enum", "description": "1 | 2 | 3" },
"default": "2"
},
- "cancelText": { "type": { "name": "node" }, "default": "\"CANCEL\"" },
+ "cancelText": { "type": { "name": "node" }, "default": "'Cancel'" },
"className": { "type": { "name": "string" } },
"clearable": { "type": { "name": "bool" } },
- "clearText": { "type": { "name": "node" }, "default": "\"CLEAR\"" },
+ "clearText": { "type": { "name": "node" }, "default": "'Clear'" },
"components": {
"type": {
"name": "shape",
@@ -57,7 +57,7 @@
"mask": { "type": { "name": "string" }, "default": "'__/__/____'" },
"maxDate": { "type": { "name": "any" }, "default": "defaultMaxDate" },
"minDate": { "type": { "name": "any" }, "default": "defaultMinDate" },
- "okText": { "type": { "name": "node" }, "default": "\"OK\"" },
+ "okText": { "type": { "name": "node" }, "default": "'OK'" },
"onAccept": { "type": { "name": "func" } },
"onClose": { "type": { "name": "func" } },
"onError": { "type": { "name": "func" } },
@@ -87,11 +87,11 @@
"showTodayButton": { "type": { "name": "bool" } },
"showToolbar": { "type": { "name": "bool" } },
"startText": { "type": { "name": "node" }, "default": "'Start'" },
- "todayText": { "type": { "name": "node" }, "default": "\"TODAY\"" },
+ "todayText": { "type": { "name": "node" }, "default": "'Today'" },
"ToolbarComponent": { "type": { "name": "elementType" } },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" }
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select date range'" }
},
"name": "MobileDateRangePicker",
"styles": { "classes": [], "globalClasses": {}, "name": null },
diff --git a/docs/pages/api-docs/mobile-date-time-picker.json b/docs/pages/api-docs/mobile-date-time-picker.json
index 121836f670d893..7d153869fd8530 100644
--- a/docs/pages/api-docs/mobile-date-time-picker.json
+++ b/docs/pages/api-docs/mobile-date-time-picker.json
@@ -9,10 +9,10 @@
"allowSameDateSelection": { "type": { "name": "bool" } },
"ampm": { "type": { "name": "bool" } },
"ampmInClock": { "type": { "name": "bool" } },
- "cancelText": { "type": { "name": "node" }, "default": "\"CANCEL\"" },
+ "cancelText": { "type": { "name": "node" }, "default": "'Cancel'" },
"className": { "type": { "name": "string" } },
"clearable": { "type": { "name": "bool" } },
- "clearText": { "type": { "name": "node" }, "default": "\"CLEAR\"" },
+ "clearText": { "type": { "name": "node" }, "default": "'Clear'" },
"components": {
"type": {
"name": "shape",
@@ -64,7 +64,7 @@
}
},
"minutesStep": { "type": { "name": "number" }, "default": "1" },
- "okText": { "type": { "name": "node" }, "default": "\"OK\"" },
+ "okText": { "type": { "name": "node" }, "default": "'OK'" },
"onAccept": { "type": { "name": "func" } },
"onClose": { "type": { "name": "func" } },
"onError": { "type": { "name": "func" } },
@@ -102,11 +102,11 @@
"showTodayButton": { "type": { "name": "bool" } },
"showToolbar": { "type": { "name": "bool" } },
"timeIcon": { "type": { "name": "node" } },
- "todayText": { "type": { "name": "node" }, "default": "\"TODAY\"" },
+ "todayText": { "type": { "name": "node" }, "default": "'Today'" },
"ToolbarComponent": { "type": { "name": "elementType" }, "default": "DateTimePickerToolbar" },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select date & time'" },
"value": {
"type": {
"name": "union",
diff --git a/docs/pages/api-docs/mobile-time-picker.json b/docs/pages/api-docs/mobile-time-picker.json
index e9fe4f45ebd549..a2d839cf5343f0 100644
--- a/docs/pages/api-docs/mobile-time-picker.json
+++ b/docs/pages/api-docs/mobile-time-picker.json
@@ -8,10 +8,10 @@
},
"ampm": { "type": { "name": "bool" } },
"ampmInClock": { "type": { "name": "bool" } },
- "cancelText": { "type": { "name": "node" }, "default": "\"CANCEL\"" },
+ "cancelText": { "type": { "name": "node" }, "default": "'Cancel'" },
"className": { "type": { "name": "string" } },
"clearable": { "type": { "name": "bool" } },
- "clearText": { "type": { "name": "node" }, "default": "\"CLEAR\"" },
+ "clearText": { "type": { "name": "node" }, "default": "'Clear'" },
"components": {
"type": { "name": "shape", "description": "{ OpenPickerIcon?: elementType }" }
},
@@ -39,7 +39,7 @@
},
"mask": { "type": { "name": "string" } },
"minutesStep": { "type": { "name": "number" }, "default": "1" },
- "okText": { "type": { "name": "node" }, "default": "\"OK\"" },
+ "okText": { "type": { "name": "node" }, "default": "'OK'" },
"onAccept": { "type": { "name": "func" } },
"onClose": { "type": { "name": "func" } },
"onError": { "type": { "name": "func" } },
@@ -60,11 +60,11 @@
"shouldDisableTime": { "type": { "name": "func" } },
"showTodayButton": { "type": { "name": "bool" } },
"showToolbar": { "type": { "name": "bool" } },
- "todayText": { "type": { "name": "node" }, "default": "\"TODAY\"" },
+ "todayText": { "type": { "name": "node" }, "default": "'Today'" },
"ToolbarComponent": { "type": { "name": "elementType" }, "default": "TimePickerToolbar" },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select time'" },
"value": {
"type": {
"name": "union",
diff --git a/docs/pages/api-docs/static-date-picker.json b/docs/pages/api-docs/static-date-picker.json
index 9d4ae06386c4ac..f557ab10420493 100644
--- a/docs/pages/api-docs/static-date-picker.json
+++ b/docs/pages/api-docs/static-date-picker.json
@@ -78,8 +78,8 @@
"showToolbar": { "type": { "name": "bool" } },
"ToolbarComponent": { "type": { "name": "elementType" }, "default": "DatePickerToolbar" },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select date'" },
"value": {
"type": {
"name": "union",
diff --git a/docs/pages/api-docs/static-date-range-picker.json b/docs/pages/api-docs/static-date-range-picker.json
index f40b1c8ffb0672..ab47b72381ae9f 100644
--- a/docs/pages/api-docs/static-date-range-picker.json
+++ b/docs/pages/api-docs/static-date-range-picker.json
@@ -87,8 +87,8 @@
"startText": { "type": { "name": "node" }, "default": "'Start'" },
"ToolbarComponent": { "type": { "name": "elementType" } },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" }
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select date range'" }
},
"name": "StaticDateRangePicker",
"styles": { "classes": [], "globalClasses": {}, "name": null },
diff --git a/docs/pages/api-docs/static-date-time-picker.json b/docs/pages/api-docs/static-date-time-picker.json
index b11b0b9177e376..5f74085fc073e8 100644
--- a/docs/pages/api-docs/static-date-time-picker.json
+++ b/docs/pages/api-docs/static-date-time-picker.json
@@ -102,8 +102,8 @@
"timeIcon": { "type": { "name": "node" } },
"ToolbarComponent": { "type": { "name": "elementType" }, "default": "DateTimePickerToolbar" },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select date & time'" },
"value": {
"type": {
"name": "union",
diff --git a/docs/pages/api-docs/static-time-picker.json b/docs/pages/api-docs/static-time-picker.json
index 720231c31cb729..4516f851ec7b52 100644
--- a/docs/pages/api-docs/static-time-picker.json
+++ b/docs/pages/api-docs/static-time-picker.json
@@ -60,8 +60,8 @@
"showToolbar": { "type": { "name": "bool" } },
"ToolbarComponent": { "type": { "name": "elementType" }, "default": "TimePickerToolbar" },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select time'" },
"value": {
"type": {
"name": "union",
diff --git a/docs/pages/api-docs/time-picker.json b/docs/pages/api-docs/time-picker.json
index 5939c1f403e7fc..172437122d6192 100644
--- a/docs/pages/api-docs/time-picker.json
+++ b/docs/pages/api-docs/time-picker.json
@@ -8,10 +8,10 @@
},
"ampm": { "type": { "name": "bool" } },
"ampmInClock": { "type": { "name": "bool" } },
- "cancelText": { "type": { "name": "node" }, "default": "\"CANCEL\"" },
+ "cancelText": { "type": { "name": "node" }, "default": "'Cancel'" },
"className": { "type": { "name": "string" } },
"clearable": { "type": { "name": "bool" } },
- "clearText": { "type": { "name": "node" }, "default": "\"CLEAR\"" },
+ "clearText": { "type": { "name": "node" }, "default": "'Clear'" },
"components": {
"type": { "name": "shape", "description": "{ OpenPickerIcon?: elementType }" }
},
@@ -43,7 +43,7 @@
},
"mask": { "type": { "name": "string" } },
"minutesStep": { "type": { "name": "number" }, "default": "1" },
- "okText": { "type": { "name": "node" }, "default": "\"OK\"" },
+ "okText": { "type": { "name": "node" }, "default": "'OK'" },
"onAccept": { "type": { "name": "func" } },
"onClose": { "type": { "name": "func" } },
"onError": { "type": { "name": "func" } },
@@ -65,11 +65,11 @@
"shouldDisableTime": { "type": { "name": "func" } },
"showTodayButton": { "type": { "name": "bool" } },
"showToolbar": { "type": { "name": "bool" } },
- "todayText": { "type": { "name": "node" }, "default": "\"TODAY\"" },
+ "todayText": { "type": { "name": "node" }, "default": "'Today'" },
"ToolbarComponent": { "type": { "name": "elementType" }, "default": "TimePickerToolbar" },
"toolbarFormat": { "type": { "name": "string" } },
- "toolbarPlaceholder": { "type": { "name": "node" }, "default": "\"–\"" },
- "toolbarTitle": { "type": { "name": "node" }, "default": "\"SELECT DATE\"" },
+ "toolbarPlaceholder": { "type": { "name": "node" }, "default": "'–'" },
+ "toolbarTitle": { "type": { "name": "node" }, "default": "'Select time'" },
"TransitionComponent": { "type": { "name": "elementType" } },
"value": {
"type": {
diff --git a/packages/material-ui-lab/src/DatePicker/DatePicker.tsx b/packages/material-ui-lab/src/DatePicker/DatePicker.tsx
index 0f01f63cdf8b7a..a549d0681d8b8f 100644
--- a/packages/material-ui-lab/src/DatePicker/DatePicker.tsx
+++ b/packages/material-ui-lab/src/DatePicker/DatePicker.tsx
@@ -94,7 +94,7 @@ DatePicker.propTypes /* remove-proptypes */ = {
autoFocus: PropTypes.bool,
/**
* Cancel text message.
- * @default "CANCEL"
+ * @default 'Cancel'
*/
cancelText: PropTypes.node,
/**
@@ -112,7 +112,7 @@ DatePicker.propTypes /* remove-proptypes */ = {
clearable: PropTypes.bool,
/**
* Clear text message.
- * @default "CLEAR"
+ * @default 'Clear'
*/
clearText: PropTypes.node,
/**
@@ -256,7 +256,7 @@ DatePicker.propTypes /* remove-proptypes */ = {
]),
/**
* Ok button text.
- * @default "OK"
+ * @default 'OK'
*/
okText: PropTypes.node,
/**
@@ -378,7 +378,7 @@ DatePicker.propTypes /* remove-proptypes */ = {
showToolbar: PropTypes.bool,
/**
* Today text message.
- * @default "TODAY"
+ * @default 'Today'
*/
todayText: PropTypes.node,
/**
@@ -392,12 +392,12 @@ DatePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select date'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/DatePicker/DatePickerToolbar.tsx b/packages/material-ui-lab/src/DatePicker/DatePickerToolbar.tsx
index 59255e0be90009..2e1be172ff1d0e 100644
--- a/packages/material-ui-lab/src/DatePicker/DatePickerToolbar.tsx
+++ b/packages/material-ui-lab/src/DatePicker/DatePickerToolbar.tsx
@@ -38,7 +38,7 @@ const DatePickerToolbar = React.forwardRef
* @default DatePickerToolbar
*/
ToolbarComponent?: React.JSXElementConstructor>;
+ /**
+ * Mobile picker title, displaying in the toolbar.
+ * @default 'Select date'
+ */
+ toolbarTitle?: React.ReactNode;
/**
* Array of views to show.
*/
diff --git a/packages/material-ui-lab/src/DateRangePicker/DateRangePicker.tsx b/packages/material-ui-lab/src/DateRangePicker/DateRangePicker.tsx
index f6c930678f986a..d225932840eddf 100644
--- a/packages/material-ui-lab/src/DateRangePicker/DateRangePicker.tsx
+++ b/packages/material-ui-lab/src/DateRangePicker/DateRangePicker.tsx
@@ -196,7 +196,7 @@ DateRangePicker.propTypes /* remove-proptypes */ = {
calendars: PropTypes.oneOf([1, 2, 3]),
/**
* Cancel text message.
- * @default "CANCEL"
+ * @default 'Cancel'
*/
cancelText: PropTypes.node,
/**
@@ -214,7 +214,7 @@ DateRangePicker.propTypes /* remove-proptypes */ = {
clearable: PropTypes.bool,
/**
* Clear text message.
- * @default "CLEAR"
+ * @default 'Clear'
*/
clearText: PropTypes.node,
/**
@@ -242,8 +242,8 @@ DateRangePicker.propTypes /* remove-proptypes */ = {
defaultCalendarMonth: PropTypes.any,
/**
* CSS media query when `Mobile` mode will be changed to `Desktop`.
- * @default "@media (pointer: fine)"
- * @example "@media (min-width: 720px)" or theme.breakpoints.up("sm")
+ * @default '@media (pointer: fine)'
+ * @example '@media (min-width: 720px)' or theme.breakpoints.up('sm')
*/
desktopModeMediaQuery: PropTypes.string,
/**
@@ -361,7 +361,7 @@ DateRangePicker.propTypes /* remove-proptypes */ = {
minDate: PropTypes.any,
/**
* Ok button text.
- * @default "OK"
+ * @default 'OK'
*/
okText: PropTypes.node,
/**
@@ -491,7 +491,7 @@ DateRangePicker.propTypes /* remove-proptypes */ = {
startText: PropTypes.node,
/**
* Today text message.
- * @default "TODAY"
+ * @default 'Today'
*/
todayText: PropTypes.node,
/**
@@ -504,12 +504,12 @@ DateRangePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select date range'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/DateRangePicker/DateRangePickerToolbar.tsx b/packages/material-ui-lab/src/DateRangePicker/DateRangePickerToolbar.tsx
index ae5a2003c45a63..b11027ca7f49c6 100644
--- a/packages/material-ui-lab/src/DateRangePicker/DateRangePickerToolbar.tsx
+++ b/packages/material-ui-lab/src/DateRangePicker/DateRangePickerToolbar.tsx
@@ -46,7 +46,7 @@ const DateRangePickerToolbar = ({
startText,
toggleMobileKeyboardView,
toolbarFormat,
- toolbarTitle = 'SELECT DATE RANGE',
+ toolbarTitle = 'Select date range',
}: DateRangePickerToolbarProps) => {
const utils = useUtils();
diff --git a/packages/material-ui-lab/src/DateRangePicker/DateRangePickerView.tsx b/packages/material-ui-lab/src/DateRangePicker/DateRangePickerView.tsx
index 2cbd4496a92e24..42d841b6492696 100644
--- a/packages/material-ui-lab/src/DateRangePicker/DateRangePickerView.tsx
+++ b/packages/material-ui-lab/src/DateRangePicker/DateRangePickerView.tsx
@@ -37,6 +37,11 @@ export interface ExportedDateRangePickerViewProps
* @default false
*/
disableAutoMonthSwitching?: boolean;
+ /**
+ * Mobile picker title, displaying in the toolbar.
+ * @default 'Select date range'
+ */
+ toolbarTitle?: React.ReactNode;
}
interface DateRangePickerViewProps
diff --git a/packages/material-ui-lab/src/DateTimePicker/DateTimePicker.tsx b/packages/material-ui-lab/src/DateTimePicker/DateTimePicker.tsx
index c318f8561d6dfb..ce122e361d658f 100644
--- a/packages/material-ui-lab/src/DateTimePicker/DateTimePicker.tsx
+++ b/packages/material-ui-lab/src/DateTimePicker/DateTimePicker.tsx
@@ -104,7 +104,7 @@ DateTimePicker.propTypes /* remove-proptypes */ = {
autoFocus: PropTypes.bool,
/**
* Cancel text message.
- * @default "CANCEL"
+ * @default 'Cancel'
*/
cancelText: PropTypes.node,
/**
@@ -122,7 +122,7 @@ DateTimePicker.propTypes /* remove-proptypes */ = {
clearable: PropTypes.bool,
/**
* Clear text message.
- * @default "CLEAR"
+ * @default 'Clear'
*/
clearText: PropTypes.node,
/**
@@ -332,7 +332,7 @@ DateTimePicker.propTypes /* remove-proptypes */ = {
minutesStep: PropTypes.number,
/**
* Ok button text.
- * @default "OK"
+ * @default 'OK'
*/
okText: PropTypes.node,
/**
@@ -463,7 +463,7 @@ DateTimePicker.propTypes /* remove-proptypes */ = {
timeIcon: PropTypes.node,
/**
* Today text message.
- * @default "TODAY"
+ * @default 'Today'
*/
todayText: PropTypes.node,
/**
@@ -477,12 +477,12 @@ DateTimePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select date & time'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/DateTimePicker/DateTimePickerToolbar.tsx b/packages/material-ui-lab/src/DateTimePicker/DateTimePickerToolbar.tsx
index f9238c11eb7f94..a9690c6c4f80e3 100644
--- a/packages/material-ui-lab/src/DateTimePicker/DateTimePickerToolbar.tsx
+++ b/packages/material-ui-lab/src/DateTimePicker/DateTimePickerToolbar.tsx
@@ -55,7 +55,7 @@ const DateTimePickerToolbar = (props: ToolbarComponentProps) => {
toggleMobileKeyboardView,
toolbarFormat,
toolbarPlaceholder = '––',
- toolbarTitle = 'SELECT DATE & TIME',
+ toolbarTitle = 'Select date & time',
...other
} = props;
const utils = useUtils();
diff --git a/packages/material-ui-lab/src/DateTimePicker/shared.ts b/packages/material-ui-lab/src/DateTimePicker/shared.ts
index a95e95e95e8e1a..5f13a02dc8c4de 100644
--- a/packages/material-ui-lab/src/DateTimePicker/shared.ts
+++ b/packages/material-ui-lab/src/DateTimePicker/shared.ts
@@ -68,6 +68,11 @@ export interface BaseDateTimePickerProps
* @default DateTimePickerToolbar
*/
ToolbarComponent?: React.JSXElementConstructor>;
+ /**
+ * Mobile picker title, displaying in the toolbar.
+ * @default 'Select date & time'
+ */
+ toolbarTitle?: React.ReactNode;
/**
* Date format, that is displaying in toolbar.
*/
diff --git a/packages/material-ui-lab/src/DesktopDatePicker/DesktopDatePicker.tsx b/packages/material-ui-lab/src/DesktopDatePicker/DesktopDatePicker.tsx
index 84e116b84e4248..59735ad1d0be45 100644
--- a/packages/material-ui-lab/src/DesktopDatePicker/DesktopDatePicker.tsx
+++ b/packages/material-ui-lab/src/DesktopDatePicker/DesktopDatePicker.tsx
@@ -356,12 +356,12 @@ DesktopDatePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select date'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx b/packages/material-ui-lab/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx
index fb354ce2eccb62..c73d910a667c4c 100644
--- a/packages/material-ui-lab/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx
+++ b/packages/material-ui-lab/src/DesktopDateRangePicker/DesktopDateRangePicker.tsx
@@ -472,12 +472,12 @@ DesktopDateRangePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select date range'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx b/packages/material-ui-lab/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx
index a4d7629824140b..d2569bf207e302 100644
--- a/packages/material-ui-lab/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx
+++ b/packages/material-ui-lab/src/DesktopDateTimePicker/DesktopDateTimePicker.tsx
@@ -444,12 +444,12 @@ DesktopDateTimePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select date & time'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/DesktopTimePicker/DesktopTimePicker.tsx b/packages/material-ui-lab/src/DesktopTimePicker/DesktopTimePicker.tsx
index 384eb9bfbf3c9a..7c0a1de62751f5 100644
--- a/packages/material-ui-lab/src/DesktopTimePicker/DesktopTimePicker.tsx
+++ b/packages/material-ui-lab/src/DesktopTimePicker/DesktopTimePicker.tsx
@@ -298,12 +298,12 @@ DesktopTimePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select time'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/MobileDatePicker/MobileDatePicker.tsx b/packages/material-ui-lab/src/MobileDatePicker/MobileDatePicker.tsx
index 4379dc325c5e99..476262c76e75dc 100644
--- a/packages/material-ui-lab/src/MobileDatePicker/MobileDatePicker.tsx
+++ b/packages/material-ui-lab/src/MobileDatePicker/MobileDatePicker.tsx
@@ -92,7 +92,7 @@ MobileDatePicker.propTypes /* remove-proptypes */ = {
autoFocus: PropTypes.bool,
/**
* Cancel text message.
- * @default "CANCEL"
+ * @default 'Cancel'
*/
cancelText: PropTypes.node,
/**
@@ -110,7 +110,7 @@ MobileDatePicker.propTypes /* remove-proptypes */ = {
clearable: PropTypes.bool,
/**
* Clear text message.
- * @default "CLEAR"
+ * @default 'Clear'
*/
clearText: PropTypes.node,
/**
@@ -248,7 +248,7 @@ MobileDatePicker.propTypes /* remove-proptypes */ = {
]),
/**
* Ok button text.
- * @default "OK"
+ * @default 'OK'
*/
okText: PropTypes.node,
/**
@@ -366,7 +366,7 @@ MobileDatePicker.propTypes /* remove-proptypes */ = {
showToolbar: PropTypes.bool,
/**
* Today text message.
- * @default "TODAY"
+ * @default 'Today'
*/
todayText: PropTypes.node,
/**
@@ -380,12 +380,12 @@ MobileDatePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select date'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/MobileDateRangePicker/MobileDateRangePicker.tsx b/packages/material-ui-lab/src/MobileDateRangePicker/MobileDateRangePicker.tsx
index 4a4afc2f937db7..fdc5703d7d99ea 100644
--- a/packages/material-ui-lab/src/MobileDateRangePicker/MobileDateRangePicker.tsx
+++ b/packages/material-ui-lab/src/MobileDateRangePicker/MobileDateRangePicker.tsx
@@ -200,7 +200,7 @@ MobileDateRangePicker.propTypes /* remove-proptypes */ = {
calendars: PropTypes.oneOf([1, 2, 3]),
/**
* Cancel text message.
- * @default "CANCEL"
+ * @default 'Cancel'
*/
cancelText: PropTypes.node,
/**
@@ -218,7 +218,7 @@ MobileDateRangePicker.propTypes /* remove-proptypes */ = {
clearable: PropTypes.bool,
/**
* Clear text message.
- * @default "CLEAR"
+ * @default 'Clear'
*/
clearText: PropTypes.node,
/**
@@ -359,7 +359,7 @@ MobileDateRangePicker.propTypes /* remove-proptypes */ = {
minDate: PropTypes.any,
/**
* Ok button text.
- * @default "OK"
+ * @default 'OK'
*/
okText: PropTypes.node,
/**
@@ -485,7 +485,7 @@ MobileDateRangePicker.propTypes /* remove-proptypes */ = {
startText: PropTypes.node,
/**
* Today text message.
- * @default "TODAY"
+ * @default 'Today'
*/
todayText: PropTypes.node,
/**
@@ -498,12 +498,12 @@ MobileDateRangePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select date range'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/MobileDateTimePicker/MobileDateTimePicker.tsx b/packages/material-ui-lab/src/MobileDateTimePicker/MobileDateTimePicker.tsx
index f463ee2579777f..9f391e2f89f88b 100644
--- a/packages/material-ui-lab/src/MobileDateTimePicker/MobileDateTimePicker.tsx
+++ b/packages/material-ui-lab/src/MobileDateTimePicker/MobileDateTimePicker.tsx
@@ -105,7 +105,7 @@ MobileDateTimePicker.propTypes /* remove-proptypes */ = {
autoFocus: PropTypes.bool,
/**
* Cancel text message.
- * @default "CANCEL"
+ * @default 'Cancel'
*/
cancelText: PropTypes.node,
/**
@@ -123,7 +123,7 @@ MobileDateTimePicker.propTypes /* remove-proptypes */ = {
clearable: PropTypes.bool,
/**
* Clear text message.
- * @default "CLEAR"
+ * @default 'Clear'
*/
clearText: PropTypes.node,
/**
@@ -327,7 +327,7 @@ MobileDateTimePicker.propTypes /* remove-proptypes */ = {
minutesStep: PropTypes.number,
/**
* Ok button text.
- * @default "OK"
+ * @default 'OK'
*/
okText: PropTypes.node,
/**
@@ -454,7 +454,7 @@ MobileDateTimePicker.propTypes /* remove-proptypes */ = {
timeIcon: PropTypes.node,
/**
* Today text message.
- * @default "TODAY"
+ * @default 'Today'
*/
todayText: PropTypes.node,
/**
@@ -468,12 +468,12 @@ MobileDateTimePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select date & time'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/MobileTimePicker/MobileTimePicker.tsx b/packages/material-ui-lab/src/MobileTimePicker/MobileTimePicker.tsx
index 6b0729c565e1ff..07f72717496116 100644
--- a/packages/material-ui-lab/src/MobileTimePicker/MobileTimePicker.tsx
+++ b/packages/material-ui-lab/src/MobileTimePicker/MobileTimePicker.tsx
@@ -94,7 +94,7 @@ MobileTimePicker.propTypes /* remove-proptypes */ = {
ampmInClock: PropTypes.bool,
/**
* Cancel text message.
- * @default "CANCEL"
+ * @default 'Cancel'
*/
cancelText: PropTypes.node,
/**
@@ -112,7 +112,7 @@ MobileTimePicker.propTypes /* remove-proptypes */ = {
clearable: PropTypes.bool,
/**
* Clear text message.
- * @default "CLEAR"
+ * @default 'Clear'
*/
clearText: PropTypes.node,
/**
@@ -229,7 +229,7 @@ MobileTimePicker.propTypes /* remove-proptypes */ = {
minutesStep: PropTypes.number,
/**
* Ok button text.
- * @default "OK"
+ * @default 'OK'
*/
okText: PropTypes.node,
/**
@@ -308,7 +308,7 @@ MobileTimePicker.propTypes /* remove-proptypes */ = {
showToolbar: PropTypes.bool,
/**
* Today text message.
- * @default "TODAY"
+ * @default 'Today'
*/
todayText: PropTypes.node,
/**
@@ -322,12 +322,12 @@ MobileTimePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select time'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/StaticDatePicker/StaticDatePicker.tsx b/packages/material-ui-lab/src/StaticDatePicker/StaticDatePicker.tsx
index 00d48f699e9570..9ba7141597bb54 100644
--- a/packages/material-ui-lab/src/StaticDatePicker/StaticDatePicker.tsx
+++ b/packages/material-ui-lab/src/StaticDatePicker/StaticDatePicker.tsx
@@ -350,12 +350,12 @@ StaticDatePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select date'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/StaticDateRangePicker/StaticDateRangePicker.tsx b/packages/material-ui-lab/src/StaticDateRangePicker/StaticDateRangePicker.tsx
index 8172207c765bd1..f77af8f4e8ee80 100644
--- a/packages/material-ui-lab/src/StaticDateRangePicker/StaticDateRangePicker.tsx
+++ b/packages/material-ui-lab/src/StaticDateRangePicker/StaticDateRangePicker.tsx
@@ -461,12 +461,12 @@ StaticDateRangePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select date range'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/StaticDateTimePicker/StaticDateTimePicker.tsx b/packages/material-ui-lab/src/StaticDateTimePicker/StaticDateTimePicker.tsx
index b7686c82cb9d30..66d82b8f0c212f 100644
--- a/packages/material-ui-lab/src/StaticDateTimePicker/StaticDateTimePicker.tsx
+++ b/packages/material-ui-lab/src/StaticDateTimePicker/StaticDateTimePicker.tsx
@@ -438,12 +438,12 @@ StaticDateTimePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select date & time'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/StaticTimePicker/StaticTimePicker.tsx b/packages/material-ui-lab/src/StaticTimePicker/StaticTimePicker.tsx
index 2342119d68be45..46664bb7d6d3d4 100644
--- a/packages/material-ui-lab/src/StaticTimePicker/StaticTimePicker.tsx
+++ b/packages/material-ui-lab/src/StaticTimePicker/StaticTimePicker.tsx
@@ -290,12 +290,12 @@ StaticTimePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select time'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/TimePicker/TimePicker.tsx b/packages/material-ui-lab/src/TimePicker/TimePicker.tsx
index 7561ec5ba3c59a..439c629482ca0d 100644
--- a/packages/material-ui-lab/src/TimePicker/TimePicker.tsx
+++ b/packages/material-ui-lab/src/TimePicker/TimePicker.tsx
@@ -95,7 +95,7 @@ TimePicker.propTypes /* remove-proptypes */ = {
ampmInClock: PropTypes.bool,
/**
* Cancel text message.
- * @default "CANCEL"
+ * @default 'Cancel'
*/
cancelText: PropTypes.node,
/**
@@ -113,7 +113,7 @@ TimePicker.propTypes /* remove-proptypes */ = {
clearable: PropTypes.bool,
/**
* Clear text message.
- * @default "CLEAR"
+ * @default 'Clear'
*/
clearText: PropTypes.node,
/**
@@ -236,7 +236,7 @@ TimePicker.propTypes /* remove-proptypes */ = {
minutesStep: PropTypes.number,
/**
* Ok button text.
- * @default "OK"
+ * @default 'OK'
*/
okText: PropTypes.node,
/**
@@ -319,7 +319,7 @@ TimePicker.propTypes /* remove-proptypes */ = {
showToolbar: PropTypes.bool,
/**
* Today text message.
- * @default "TODAY"
+ * @default 'Today'
*/
todayText: PropTypes.node,
/**
@@ -333,12 +333,12 @@ TimePicker.propTypes /* remove-proptypes */ = {
toolbarFormat: PropTypes.string,
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder: PropTypes.node,
/**
* Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * @default 'Select time'
*/
toolbarTitle: PropTypes.node,
/**
diff --git a/packages/material-ui-lab/src/TimePicker/TimePickerToolbar.tsx b/packages/material-ui-lab/src/TimePicker/TimePickerToolbar.tsx
index 2b30dd106ffa76..1e1f3f2e4a8b29 100644
--- a/packages/material-ui-lab/src/TimePicker/TimePickerToolbar.tsx
+++ b/packages/material-ui-lab/src/TimePicker/TimePickerToolbar.tsx
@@ -127,7 +127,7 @@ const TimePickerToolbar: React.FC = (props) => {
openView,
setOpenView,
toggleMobileKeyboardView,
- toolbarTitle = 'SELECT TIME',
+ toolbarTitle = 'Select time',
views,
...other
} = props;
diff --git a/packages/material-ui-lab/src/TimePicker/shared.tsx b/packages/material-ui-lab/src/TimePicker/shared.tsx
index f3cd2779612eb7..445859b28ec3f4 100644
--- a/packages/material-ui-lab/src/TimePicker/shared.tsx
+++ b/packages/material-ui-lab/src/TimePicker/shared.tsx
@@ -29,6 +29,11 @@ export interface BaseTimePickerProps
* @default TimePickerToolbar
*/
ToolbarComponent?: React.JSXElementConstructor>;
+ /**
+ * Mobile picker title, displaying in the toolbar.
+ * @default 'Select time'
+ */
+ toolbarTitle?: React.ReactNode;
/**
* Array of views to show.
*/
diff --git a/packages/material-ui-lab/src/internal/pickers/Picker/Picker.tsx b/packages/material-ui-lab/src/internal/pickers/Picker/Picker.tsx
index edcebf49162c81..7df250e055ad93 100644
--- a/packages/material-ui-lab/src/internal/pickers/Picker/Picker.tsx
+++ b/packages/material-ui-lab/src/internal/pickers/Picker/Picker.tsx
@@ -63,24 +63,25 @@ const isDatePickerView = (view: AllAvailableViews): view is CalendarPickerView =
const isTimePickerView = (view: AllAvailableViews): view is ClockPickerView =>
view === 'hours' || view === 'minutes' || view === 'seconds';
-function Picker({
- autoFocus,
- className,
- date,
- DateInputProps,
- isMobileKeyboardViewOpen,
- onDateChange,
- openTo = 'day',
- orientation,
- showToolbar,
- toggleMobileKeyboardView,
- ToolbarComponent = () => null,
- toolbarFormat,
- toolbarPlaceholder,
- toolbarTitle,
- views = ['year', 'month', 'day', 'hours', 'minutes', 'seconds'],
- ...other
-}: PickerProps) {
+function Picker(props: PickerProps) {
+ const {
+ autoFocus,
+ className,
+ date,
+ DateInputProps,
+ isMobileKeyboardViewOpen,
+ onDateChange,
+ openTo = 'day',
+ orientation,
+ showToolbar,
+ toggleMobileKeyboardView,
+ ToolbarComponent = () => null,
+ toolbarFormat,
+ toolbarPlaceholder,
+ toolbarTitle,
+ views = ['year', 'month', 'day', 'hours', 'minutes', 'seconds'],
+ ...other
+ } = props;
const isLandscape = useIsLandscape(views, orientation);
const wrapperVariant = React.useContext(WrapperVariantContext);
diff --git a/packages/material-ui-lab/src/internal/pickers/PickersModalDialog.tsx b/packages/material-ui-lab/src/internal/pickers/PickersModalDialog.tsx
index 0811039a0bcf54..b706150d75ef2f 100644
--- a/packages/material-ui-lab/src/internal/pickers/PickersModalDialog.tsx
+++ b/packages/material-ui-lab/src/internal/pickers/PickersModalDialog.tsx
@@ -9,22 +9,22 @@ import { DIALOG_WIDTH } from './constants/dimensions';
export interface ExportedPickerModalProps {
/**
* Ok button text.
- * @default "OK"
+ * @default 'OK'
*/
okText?: React.ReactNode;
/**
* Cancel text message.
- * @default "CANCEL"
+ * @default 'Cancel'
*/
cancelText?: React.ReactNode;
/**
* Clear text message.
- * @default "CLEAR"
+ * @default 'Clear'
*/
clearText?: React.ReactNode;
/**
* Today text message.
- * @default "TODAY"
+ * @default 'Today'
*/
todayText?: React.ReactNode;
/**
diff --git a/packages/material-ui-lab/src/internal/pickers/typings/BasePicker.tsx b/packages/material-ui-lab/src/internal/pickers/typings/BasePicker.tsx
index 4dbeffeabcc965..87c2c3b9ef756c 100644
--- a/packages/material-ui-lab/src/internal/pickers/typings/BasePicker.tsx
+++ b/packages/material-ui-lab/src/internal/pickers/typings/BasePicker.tsx
@@ -86,12 +86,11 @@ export interface BasePickerProps {
toolbarFormat?: string;
/**
* Mobile picker date value placeholder, displaying if `value` === `null`.
- * @default "–"
+ * @default '–'
*/
toolbarPlaceholder?: React.ReactNode;
/**
- * Mobile picker title, displaying in the toolbar.
- * @default "SELECT DATE"
+ * Prop forwarded to the ToolbarComponent.
*/
toolbarTitle?: React.ReactNode;
/**
diff --git a/packages/material-ui-lab/src/internal/pickers/wrappers/ResponsiveWrapper.tsx b/packages/material-ui-lab/src/internal/pickers/wrappers/ResponsiveWrapper.tsx
index 24f2bba609de7d..c32c848d5eaa75 100644
--- a/packages/material-ui-lab/src/internal/pickers/wrappers/ResponsiveWrapper.tsx
+++ b/packages/material-ui-lab/src/internal/pickers/wrappers/ResponsiveWrapper.tsx
@@ -8,8 +8,8 @@ import { DateInputPropsLike, PrivateWrapperProps } from './WrapperProps';
export interface ResponsiveWrapperProps extends MobileWrapperProps, DesktopWrapperProps {
/**
* CSS media query when `Mobile` mode will be changed to `Desktop`.
- * @default "@media (pointer: fine)"
- * @example "@media (min-width: 720px)" or theme.breakpoints.up("sm")
+ * @default '@media (pointer: fine)'
+ * @example '@media (min-width: 720px)' or theme.breakpoints.up('sm')
*/
desktopModeMediaQuery?: string;
}
From f86eb44574860e829400eee8bccb51ecc5676077 Mon Sep 17 00:00:00 2001
From: Olivier Tassinari
Date: Thu, 8 Jul 2021 07:47:56 +0200
Subject: [PATCH 8/9] [ToggleButton] Fix the api page (#27164)
---
docs/pages/api-docs/toggle-button.json | 4 ++--
packages/material-ui/src/ToggleButton/ToggleButton.js | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/docs/pages/api-docs/toggle-button.json b/docs/pages/api-docs/toggle-button.json
index ac6198907b5089..446e4d2127d53b 100644
--- a/docs/pages/api-docs/toggle-button.json
+++ b/docs/pages/api-docs/toggle-button.json
@@ -6,7 +6,7 @@
"color": {
"type": {
"name": "union",
- "description": "'standard' | 'primary' | 'secondary' | string"
+ "description": "'standard' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' | string"
},
"default": "'standard'"
},
@@ -18,7 +18,7 @@
"size": {
"type": {
"name": "union",
- "description": "'standard' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' | string"
+ "description": "'large' | 'medium' | 'small' | string"
},
"default": "'medium'"
},
diff --git a/packages/material-ui/src/ToggleButton/ToggleButton.js b/packages/material-ui/src/ToggleButton/ToggleButton.js
index 36baa22f6f6075..5750f167b877b1 100644
--- a/packages/material-ui/src/ToggleButton/ToggleButton.js
+++ b/packages/material-ui/src/ToggleButton/ToggleButton.js
@@ -171,7 +171,7 @@ ToggleButton.propTypes /* remove-proptypes */ = {
* @default 'standard'
*/
color: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
- PropTypes.oneOf(['standard', 'primary', 'secondary']),
+ PropTypes.oneOf(['standard', 'primary', 'secondary', 'error', 'info', 'success', 'warning']),
PropTypes.string,
]),
/**
@@ -215,7 +215,7 @@ ToggleButton.propTypes /* remove-proptypes */ = {
* @default 'medium'
*/
size: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([
- PropTypes.oneOf(['standard', 'primary', 'secondary', 'error', 'info', 'success', 'warning']),
+ PropTypes.oneOf(['large', 'medium', 'small']),
PropTypes.string,
]),
/**
From c6642e370d589985588e097f8ebd421dcd01efd0 Mon Sep 17 00:00:00 2001
From: Sebastian Silbermann
Date: Thu, 8 Jul 2021 09:40:36 +0200
Subject: [PATCH 9/9] [docs] Remove usage of `url` package (#27151)
---
docs/src/modules/components/AppSearch.js | 4 ++--
.../customization/default-theme/DefaultTheme.js | 16 ++++++++++++----
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/docs/src/modules/components/AppSearch.js b/docs/src/modules/components/AppSearch.js
index 92a080fe207f52..6a92db970513ac 100644
--- a/docs/src/modules/components/AppSearch.js
+++ b/docs/src/modules/components/AppSearch.js
@@ -1,5 +1,4 @@
import * as React from 'react';
-import url from 'url';
import clsx from 'clsx';
import useLazyCSS from 'docs/src/modules/utils/useLazyCSS';
import useMediaQuery from '@material-ui/core/useMediaQuery';
@@ -200,7 +199,8 @@ export default function AppSearch() {
},
handleSelected: (input, event, suggestion) => {
event.button = 0;
- const parseUrl = url.parse(suggestion.url);
+ const parseUrl = document.createElement('a');
+ parseUrl.href = suggestion.url;
handleEvent(event, parseUrl.pathname + parseUrl.hash);
input.close();
},
diff --git a/docs/src/pages/customization/default-theme/DefaultTheme.js b/docs/src/pages/customization/default-theme/DefaultTheme.js
index 6543f8afcf764a..e4fabc48adffd1 100644
--- a/docs/src/pages/customization/default-theme/DefaultTheme.js
+++ b/docs/src/pages/customization/default-theme/DefaultTheme.js
@@ -1,6 +1,5 @@
import * as React from 'react';
import PropTypes from 'prop-types';
-import url from 'url';
import Box from '@material-ui/core/Box';
import ExpandIcon from '@material-ui/icons/ExpandMore';
import CollapseIcon from '@material-ui/icons/ChevronRight';
@@ -238,9 +237,18 @@ function DefaultTheme() {
const [darkTheme, setDarkTheme] = React.useState(false);
React.useEffect(() => {
- const URL = url.parse(document.location.href, true);
- // 'expend-path' is for backwards compatibility of any external links with a prior typo.
- const expandPath = URL.query['expand-path'] || URL.query['expend-path'];
+ let expandPath;
+ decodeURI(document.location.search.slice(1))
+ .split('&')
+ .forEach((param) => {
+ const [name, value] = param.split('=');
+ if (name === 'expand-path') {
+ expandPath = value;
+ } else if (name === 'expend-path' && !expandPath) {
+ // 'expend-path' is for backwards compatibility of any external links with a prior typo.
+ expandPath = value;
+ }
+ });
if (!expandPath) {
return;