From 9eef18d95e2649d22124f722b7edb62f89d7da0e Mon Sep 17 00:00:00 2001 From: Veda Date: Sat, 13 Mar 2021 21:32:45 +0530 Subject: [PATCH 01/13] [Button, ButtonBase]: add ability to customize link component via theme --- docs/pages/api-docs/button-base.json | 1 + .../api-docs/button-base/button-base.json | 1 + packages/material-ui/src/Button/Button.js | 10 ++++++++ .../src/ButtonBase/ButtonBase.d.ts | 5 ++++ .../material-ui/src/ButtonBase/ButtonBase.js | 8 +++++- .../src/ButtonBase/ButtonBase.test.js | 24 ++++++++++++++++++ test/docs-regressions-before.png | Bin 1443 -> 1442 bytes test/docs-regressions-diff.png | Bin 2085 -> 2084 bytes 8 files changed, 48 insertions(+), 1 deletion(-) diff --git a/docs/pages/api-docs/button-base.json b/docs/pages/api-docs/button-base.json index e201f31e99e844..cd2ae650a24f7c 100644 --- a/docs/pages/api-docs/button-base.json +++ b/docs/pages/api-docs/button-base.json @@ -10,6 +10,7 @@ "disableTouchRipple": { "type": { "name": "bool" } }, "focusRipple": { "type": { "name": "bool" } }, "focusVisibleClassName": { "type": { "name": "string" } }, + "LinkComponent": { "type": { "name": "elementType" }, "default": "'a'" }, "onFocusVisible": { "type": { "name": "func" } }, "sx": { "type": { "name": "object" } }, "TouchRippleProps": { "type": { "name": "object" } } diff --git a/docs/translations/api-docs/button-base/button-base.json b/docs/translations/api-docs/button-base/button-base.json index dff6172092c505..c4512a402e56f0 100644 --- a/docs/translations/api-docs/button-base/button-base.json +++ b/docs/translations/api-docs/button-base/button-base.json @@ -11,6 +11,7 @@ "disableTouchRipple": "If true, the touch ripple effect is disabled.", "focusRipple": "If true, the base button will have a keyboard focus ripple.", "focusVisibleClassName": "This prop can help identify which element has keyboard focus. The class name will be applied when the element gains the focus through keyboard interaction. It's a polyfill for the CSS :focus-visible selector. The rationale for using this feature is explained here. A polyfill can be used to apply a focus-visible class to other components if needed.", + "LinkComponent": "Custom component for routing", "onFocusVisible": "Callback fired when the component is focused with a keyboard. We trigger a onFocus callback too.", "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.", "TouchRippleProps": "Props applied to the TouchRipple element." diff --git a/packages/material-ui/src/Button/Button.js b/packages/material-ui/src/Button/Button.js index 4fd270f676d87e..cb9d3286152e86 100644 --- a/packages/material-ui/src/Button/Button.js +++ b/packages/material-ui/src/Button/Button.js @@ -322,9 +322,14 @@ const Button = React.forwardRef(function Button(inProps, ref) { startIcon: startIconProp, type, variant = 'text', + sx, ...other } = props; + const { components } = props.theme; + const { MuiButton = {} } = components; + const { link } = MuiButton; + const styleProps = { ...props, color, @@ -361,6 +366,7 @@ const Button = React.forwardRef(function Button(inProps, ref) { focusVisibleClassName={clsx(classes.focusVisible, focusVisibleClassName)} ref={ref} type={type} + LinkComponent={link} {...other} classes={classes} > @@ -463,6 +469,10 @@ Button.propTypes /* remove-proptypes */ = { * The system prop that allows defining system overrides as well as additional CSS styles. */ sx: PropTypes.object, + /** + * @ignore + */ + theme: PropTypes.object, /** * @ignore */ diff --git a/packages/material-ui/src/ButtonBase/ButtonBase.d.ts b/packages/material-ui/src/ButtonBase/ButtonBase.d.ts index 0f50cee128f328..e95158eb8681d6 100644 --- a/packages/material-ui/src/ButtonBase/ButtonBase.d.ts +++ b/packages/material-ui/src/ButtonBase/ButtonBase.d.ts @@ -71,6 +71,11 @@ export interface ButtonBaseTypeMap

', () => { expect(button).to.have.attribute('href', 'https://google.com'); }); + it('should use custom LinkComponent when provided', () => { + const CustomLink = React.forwardRef((props, _) => { + return ( + {props.children} + ) + }); + + const { container, getByTestId } = render( + + Hello + + ); + const button = container.firstChild; + + expect(getByTestId('customLink')).not.to.equal(null); + expect(button).to.have.property('nodeName', 'A'); + expect(button).not.to.have.attribute('role'); + expect(button).not.to.have.attribute('type'); + expect(button).to.have.attribute('href', 'https://google.com'); + }); + it('applies role="button" when an anchor is used without href', () => { const { getByRole } = render(Hello); const button = getByRole('button'); diff --git a/test/docs-regressions-before.png b/test/docs-regressions-before.png index 2cab5396d5d2dab7c94d838eadd769587ccfbf15..d1e7f17a11b2ed701cbb491cfd9702dd304e45b8 100644 GIT binary patch delta 13 UcmZ3?y@;EoGr-S%BkMd?03IU*CjbBd delta 14 VcmZ3)y_lP|Gr-TCcO%O@RsbP41T+8u diff --git a/test/docs-regressions-diff.png b/test/docs-regressions-diff.png index d6d602f16e732c9408ff22cdb757604a67845369..f6849065128a8fa010d6576758f784c521153de2 100644 GIT binary patch delta 13 UcmZ1~utb2RGr-S%BdY=j03FB!x&QzG delta 14 VcmZ1?uvCDxGr-TCcO#1e2LK@I1IGXW From a05bf3a045fdefe088bcd900f0b5013ff179d02a Mon Sep 17 00:00:00 2001 From: Veda Date: Sat, 13 Mar 2021 22:02:56 +0530 Subject: [PATCH 02/13] fix lint errors --- packages/material-ui/src/Button/Button.d.ts | 4 ++++ .../src/ButtonBase/ButtonBase.test.js | 17 +++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/material-ui/src/Button/Button.d.ts b/packages/material-ui/src/Button/Button.d.ts index 61046e08cd6819..0fecd1b2f9e72b 100644 --- a/packages/material-ui/src/Button/Button.d.ts +++ b/packages/material-ui/src/Button/Button.d.ts @@ -151,6 +151,10 @@ export type ButtonTypeMap< * The system prop that allows defining system overrides as well as additional CSS styles. */ sx?: SxProps; + /** + * @ignore + */ + theme?: SxProps; /** * The variant to use. * @default 'text' diff --git a/packages/material-ui/src/ButtonBase/ButtonBase.test.js b/packages/material-ui/src/ButtonBase/ButtonBase.test.js index 07c560607b3c72..4a7d9c6b854345 100644 --- a/packages/material-ui/src/ButtonBase/ButtonBase.test.js +++ b/packages/material-ui/src/ButtonBase/ButtonBase.test.js @@ -97,26 +97,23 @@ describe('', () => { }); it('should use custom LinkComponent when provided', () => { - const CustomLink = React.forwardRef((props, _) => { + const CustomLink = React.forwardRef((props, ref) => { return ( - {props.children} - ) + + {props.children} + + ); }); const { container, getByTestId } = render( - + Hello - + , ); const button = container.firstChild; expect(getByTestId('customLink')).not.to.equal(null); expect(button).to.have.property('nodeName', 'A'); - expect(button).not.to.have.attribute('role'); - expect(button).not.to.have.attribute('type'); expect(button).to.have.attribute('href', 'https://google.com'); }); From 4440e3d6576ee8716abc5f3fd2ed25691041b6cb Mon Sep 17 00:00:00 2001 From: Veda Date: Sat, 13 Mar 2021 22:04:31 +0530 Subject: [PATCH 03/13] yarn prettier --- packages/material-ui/src/ButtonBase/ButtonBase.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/material-ui/src/ButtonBase/ButtonBase.test.js b/packages/material-ui/src/ButtonBase/ButtonBase.test.js index 4a7d9c6b854345..c5613b12bfddb6 100644 --- a/packages/material-ui/src/ButtonBase/ButtonBase.test.js +++ b/packages/material-ui/src/ButtonBase/ButtonBase.test.js @@ -101,7 +101,7 @@ describe('', () => { return ( {props.children} - + ); }); From 78f9736e4a1ddf9daf2b37ffbe579b4efe43c9d0 Mon Sep 17 00:00:00 2001 From: Veda Date: Sun, 14 Mar 2021 18:37:00 +0530 Subject: [PATCH 04/13] fix: add LinkComponent to MuiButtonBase theme, update docs & tests --- docs/pages/api-docs/button-base.json | 1 - .../guides/composition/LinkRouterWithTheme.js | 39 +++++++++++++++++++ .../pages/guides/composition/composition.md | 4 ++ .../api-docs/button-base/button-base.json | 1 - packages/material-ui/src/Button/Button.d.ts | 4 -- packages/material-ui/src/Button/Button.js | 10 ----- .../src/ButtonBase/ButtonBase.d.ts | 9 ++--- .../material-ui/src/ButtonBase/ButtonBase.js | 13 ++++--- .../src/ButtonBase/ButtonBase.test.js | 17 +++++--- 9 files changed, 66 insertions(+), 32 deletions(-) create mode 100644 docs/src/pages/guides/composition/LinkRouterWithTheme.js diff --git a/docs/pages/api-docs/button-base.json b/docs/pages/api-docs/button-base.json index cd2ae650a24f7c..e201f31e99e844 100644 --- a/docs/pages/api-docs/button-base.json +++ b/docs/pages/api-docs/button-base.json @@ -10,7 +10,6 @@ "disableTouchRipple": { "type": { "name": "bool" } }, "focusRipple": { "type": { "name": "bool" } }, "focusVisibleClassName": { "type": { "name": "string" } }, - "LinkComponent": { "type": { "name": "elementType" }, "default": "'a'" }, "onFocusVisible": { "type": { "name": "func" } }, "sx": { "type": { "name": "object" } }, "TouchRippleProps": { "type": { "name": "object" } } diff --git a/docs/src/pages/guides/composition/LinkRouterWithTheme.js b/docs/src/pages/guides/composition/LinkRouterWithTheme.js new file mode 100644 index 00000000000000..8e03c62f9cbf21 --- /dev/null +++ b/docs/src/pages/guides/composition/LinkRouterWithTheme.js @@ -0,0 +1,39 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { MemoryRouter as Router } from 'react-router'; +import { Link as RouterLink } from 'react-router-dom'; +import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; + +const LinkBehavior = React.forwardRef(({ href, ...props }, ref) => ( + +)); + +LinkBehavior.propTypes = { + href: PropTypes.string, +}; + +const theme = createMuiTheme({ + components: { + MuiButtonBase: { + LinkComponent: LinkBehavior, + }, + MuiButton: { + styleOverrides: { + root: { + fontSize: '1rem', + }, + }, + }, + }, +}); + +export default function GlobalThemeOverride() { + return ( + + + + + + ); +} diff --git a/docs/src/pages/guides/composition/composition.md b/docs/src/pages/guides/composition/composition.md index 0c0aeebe07e7d8..b52b73cdf5aecd 100644 --- a/docs/src/pages/guides/composition/composition.md +++ b/docs/src/pages/guides/composition/composition.md @@ -143,6 +143,10 @@ They cover the Button, Link, and List components. You can apply the same strateg {{"demo": "pages/guides/composition/LinkRouter.js"}} +### Link configuration using theme + +{{"demo": "pages/guides/composition/LinkRouterWithTheme.js"}} + ### List {{"demo": "pages/guides/composition/ListRouter.js"}} diff --git a/docs/translations/api-docs/button-base/button-base.json b/docs/translations/api-docs/button-base/button-base.json index c4512a402e56f0..dff6172092c505 100644 --- a/docs/translations/api-docs/button-base/button-base.json +++ b/docs/translations/api-docs/button-base/button-base.json @@ -11,7 +11,6 @@ "disableTouchRipple": "If true, the touch ripple effect is disabled.", "focusRipple": "If true, the base button will have a keyboard focus ripple.", "focusVisibleClassName": "This prop can help identify which element has keyboard focus. The class name will be applied when the element gains the focus through keyboard interaction. It's a polyfill for the CSS :focus-visible selector. The rationale for using this feature is explained here. A polyfill can be used to apply a focus-visible class to other components if needed.", - "LinkComponent": "Custom component for routing", "onFocusVisible": "Callback fired when the component is focused with a keyboard. We trigger a onFocus callback too.", "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.", "TouchRippleProps": "Props applied to the TouchRipple element." diff --git a/packages/material-ui/src/Button/Button.d.ts b/packages/material-ui/src/Button/Button.d.ts index 0fecd1b2f9e72b..61046e08cd6819 100644 --- a/packages/material-ui/src/Button/Button.d.ts +++ b/packages/material-ui/src/Button/Button.d.ts @@ -151,10 +151,6 @@ export type ButtonTypeMap< * The system prop that allows defining system overrides as well as additional CSS styles. */ sx?: SxProps; - /** - * @ignore - */ - theme?: SxProps; /** * The variant to use. * @default 'text' diff --git a/packages/material-ui/src/Button/Button.js b/packages/material-ui/src/Button/Button.js index cb9d3286152e86..4fd270f676d87e 100644 --- a/packages/material-ui/src/Button/Button.js +++ b/packages/material-ui/src/Button/Button.js @@ -322,14 +322,9 @@ const Button = React.forwardRef(function Button(inProps, ref) { startIcon: startIconProp, type, variant = 'text', - sx, ...other } = props; - const { components } = props.theme; - const { MuiButton = {} } = components; - const { link } = MuiButton; - const styleProps = { ...props, color, @@ -366,7 +361,6 @@ const Button = React.forwardRef(function Button(inProps, ref) { focusVisibleClassName={clsx(classes.focusVisible, focusVisibleClassName)} ref={ref} type={type} - LinkComponent={link} {...other} classes={classes} > @@ -469,10 +463,6 @@ Button.propTypes /* remove-proptypes */ = { * The system prop that allows defining system overrides as well as additional CSS styles. */ sx: PropTypes.object, - /** - * @ignore - */ - theme: PropTypes.object, /** * @ignore */ diff --git a/packages/material-ui/src/ButtonBase/ButtonBase.d.ts b/packages/material-ui/src/ButtonBase/ButtonBase.d.ts index e95158eb8681d6..fd1712377a9251 100644 --- a/packages/material-ui/src/ButtonBase/ButtonBase.d.ts +++ b/packages/material-ui/src/ButtonBase/ButtonBase.d.ts @@ -71,11 +71,6 @@ export interface ButtonBaseTypeMap

', () => { expect(button).to.have.attribute('href', 'https://google.com'); }); - it('should use custom LinkComponent when provided', () => { + it('should use custom LinkComponent when provided in the theme', () => { const CustomLink = React.forwardRef((props, ref) => { return ( @@ -104,14 +105,20 @@ describe('', () => { ); }); + const theme = createMuiTheme({ + components: { + MuiButtonBase: { + LinkComponent: CustomLink, + }, + }, + }); const { container, getByTestId } = render( - - Hello - , + + Hello + , ); const button = container.firstChild; - expect(getByTestId('customLink')).not.to.equal(null); expect(button).to.have.property('nodeName', 'A'); expect(button).to.have.attribute('href', 'https://google.com'); From 650533f94559f71afe7fb063e7f9254ed37b8fef Mon Sep 17 00:00:00 2001 From: Veda Date: Sun, 14 Mar 2021 19:32:19 +0530 Subject: [PATCH 05/13] fix: type errors --- .../pages/guides/composition/LinkRouterWithTheme.js | 4 +++- packages/material-ui/src/ButtonBase/ButtonBase.d.ts | 8 ++++---- packages/material-ui/src/ButtonBase/ButtonBase.js | 12 +++++------- .../material-ui/src/ButtonBase/ButtonBase.test.js | 4 +++- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/src/pages/guides/composition/LinkRouterWithTheme.js b/docs/src/pages/guides/composition/LinkRouterWithTheme.js index 8e03c62f9cbf21..b9f0c16325cb18 100644 --- a/docs/src/pages/guides/composition/LinkRouterWithTheme.js +++ b/docs/src/pages/guides/composition/LinkRouterWithTheme.js @@ -16,7 +16,9 @@ LinkBehavior.propTypes = { const theme = createMuiTheme({ components: { MuiButtonBase: { - LinkComponent: LinkBehavior, + defaultProps: { + LinkComponent: LinkBehavior, + }, }, MuiButton: { styleOverrides: { diff --git a/packages/material-ui/src/ButtonBase/ButtonBase.d.ts b/packages/material-ui/src/ButtonBase/ButtonBase.d.ts index fd1712377a9251..9baefba78f6924 100644 --- a/packages/material-ui/src/ButtonBase/ButtonBase.d.ts +++ b/packages/material-ui/src/ButtonBase/ButtonBase.d.ts @@ -71,6 +71,10 @@ export interface ButtonBaseTypeMap

; - /** - * @ignore - */ - theme?: Theme; // @types/react is stricter /** * @default 0 diff --git a/packages/material-ui/src/ButtonBase/ButtonBase.js b/packages/material-ui/src/ButtonBase/ButtonBase.js index 9d1fd17be1cd08..240f2ac4ffb38f 100644 --- a/packages/material-ui/src/ButtonBase/ButtonBase.js +++ b/packages/material-ui/src/ButtonBase/ButtonBase.js @@ -86,6 +86,7 @@ const ButtonBase = React.forwardRef(function ButtonBase(inProps, ref) { disableTouchRipple = false, focusRipple = false, focusVisibleClassName, + LinkComponent = 'a', onBlur, onClick, onContextMenu, @@ -106,9 +107,6 @@ const ButtonBase = React.forwardRef(function ButtonBase(inProps, ref) { ...other } = props; - const MuiButtonBase = props.theme?.components?.MuiButtonBase; - const LinkComponent = MuiButtonBase?.LinkComponent || 'a'; - const buttonRef = React.useRef(null); const rippleRef = React.useRef(null); @@ -454,6 +452,10 @@ ButtonBase.propTypes /* remove-proptypes */ = { * @ignore */ href: PropTypes /* @typescript-to-proptypes-ignore */.any, + /** + * @ignore + */ + LinkComponent: PropTypes.elementType, /** * @ignore */ @@ -519,10 +521,6 @@ ButtonBase.propTypes /* remove-proptypes */ = { * @default 0 */ tabIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - /** - * @ignore - */ - theme: PropTypes.object, /** * Props applied to the `TouchRipple` element. */ diff --git a/packages/material-ui/src/ButtonBase/ButtonBase.test.js b/packages/material-ui/src/ButtonBase/ButtonBase.test.js index a71261847a501c..fdf494503353cd 100644 --- a/packages/material-ui/src/ButtonBase/ButtonBase.test.js +++ b/packages/material-ui/src/ButtonBase/ButtonBase.test.js @@ -108,7 +108,9 @@ describe('', () => { const theme = createMuiTheme({ components: { MuiButtonBase: { - LinkComponent: CustomLink, + defaultProps: { + LinkComponent: CustomLink, + }, }, }, }); From 3e1e7580a8b6badbea2653beea31c752c43ded9b Mon Sep 17 00:00:00 2001 From: Olivier Tassinari Date: Sun, 14 Mar 2021 15:35:17 +0100 Subject: [PATCH 06/13] add a description to the prop --- docs/pages/api-docs/button-base.json | 1 + docs/translations/api-docs/button-base/button-base.json | 1 + packages/material-ui/src/ButtonBase/ButtonBase.d.ts | 3 ++- packages/material-ui/src/ButtonBase/ButtonBase.js | 3 ++- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/pages/api-docs/button-base.json b/docs/pages/api-docs/button-base.json index e201f31e99e844..cd2ae650a24f7c 100644 --- a/docs/pages/api-docs/button-base.json +++ b/docs/pages/api-docs/button-base.json @@ -10,6 +10,7 @@ "disableTouchRipple": { "type": { "name": "bool" } }, "focusRipple": { "type": { "name": "bool" } }, "focusVisibleClassName": { "type": { "name": "string" } }, + "LinkComponent": { "type": { "name": "elementType" }, "default": "'a'" }, "onFocusVisible": { "type": { "name": "func" } }, "sx": { "type": { "name": "object" } }, "TouchRippleProps": { "type": { "name": "object" } } diff --git a/docs/translations/api-docs/button-base/button-base.json b/docs/translations/api-docs/button-base/button-base.json index dff6172092c505..9a7b2316a02744 100644 --- a/docs/translations/api-docs/button-base/button-base.json +++ b/docs/translations/api-docs/button-base/button-base.json @@ -11,6 +11,7 @@ "disableTouchRipple": "If true, the touch ripple effect is disabled.", "focusRipple": "If true, the base button will have a keyboard focus ripple.", "focusVisibleClassName": "This prop can help identify which element has keyboard focus. The class name will be applied when the element gains the focus through keyboard interaction. It's a polyfill for the CSS :focus-visible selector. The rationale for using this feature is explained here. A polyfill can be used to apply a focus-visible class to other components if needed.", + "LinkComponent": "The component used to render a link when the href prop is provided.", "onFocusVisible": "Callback fired when the component is focused with a keyboard. We trigger a onFocus callback too.", "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.", "TouchRippleProps": "Props applied to the TouchRipple element." diff --git a/packages/material-ui/src/ButtonBase/ButtonBase.d.ts b/packages/material-ui/src/ButtonBase/ButtonBase.d.ts index 9baefba78f6924..e0c6fecb2ef8d8 100644 --- a/packages/material-ui/src/ButtonBase/ButtonBase.d.ts +++ b/packages/material-ui/src/ButtonBase/ButtonBase.d.ts @@ -72,7 +72,8 @@ export interface ButtonBaseTypeMap

Date: Sun, 14 Mar 2021 16:43:18 +0100 Subject: [PATCH 07/13] improve documentation --- docs/pages/guides/routing.js | 20 +++++++ docs/src/pages.ts | 1 + docs/src/pages/components/buttons/buttons.md | 2 +- docs/src/pages/components/links/Links.js | 4 +- docs/src/pages/components/links/Links.tsx | 4 +- .../pages/components/links/UnderlineLink.js | 4 +- .../pages/components/links/UnderlineLink.tsx | 4 +- docs/src/pages/components/links/links.md | 2 +- docs/src/pages/components/lists/lists.md | 2 +- docs/src/pages/getting-started/faq/faq.md | 4 +- .../guides/composition/LinkRouterWithTheme.js | 41 ------------- .../pages/guides/composition/composition.md | 25 +------- docs/src/pages/guides/routing/ButtonDemo.js | 15 +++++ docs/src/pages/guides/routing/ButtonDemo.tsx | 15 +++++ .../{composition => routing}/ButtonRouter.js | 8 +-- .../{composition => routing}/ButtonRouter.tsx | 8 +-- docs/src/pages/guides/routing/LinkDemo.js | 13 +++++ docs/src/pages/guides/routing/LinkDemo.tsx | 13 +++++ .../{composition => routing}/LinkRouter.js | 9 +-- .../{composition => routing}/LinkRouter.tsx | 9 +-- .../guides/routing/LinkRouterWithTheme.js | 57 +++++++++++++++++++ .../guides/routing/LinkRouterWithTheme.tsx | 54 ++++++++++++++++++ .../{composition => routing}/ListRouter.js | 0 .../{composition => routing}/ListRouter.tsx | 0 docs/src/pages/guides/routing/routing.md | 47 +++++++++++++++ .../src/pages/guides/typescript/typescript.md | 2 +- 26 files changed, 268 insertions(+), 95 deletions(-) create mode 100644 docs/pages/guides/routing.js delete mode 100644 docs/src/pages/guides/composition/LinkRouterWithTheme.js create mode 100644 docs/src/pages/guides/routing/ButtonDemo.js create mode 100644 docs/src/pages/guides/routing/ButtonDemo.tsx rename docs/src/pages/guides/{composition => routing}/ButtonRouter.js (91%) rename docs/src/pages/guides/{composition => routing}/ButtonRouter.tsx (92%) create mode 100644 docs/src/pages/guides/routing/LinkDemo.js create mode 100644 docs/src/pages/guides/routing/LinkDemo.tsx rename docs/src/pages/guides/{composition => routing}/LinkRouter.js (83%) rename docs/src/pages/guides/{composition => routing}/LinkRouter.tsx (84%) create mode 100644 docs/src/pages/guides/routing/LinkRouterWithTheme.js create mode 100644 docs/src/pages/guides/routing/LinkRouterWithTheme.tsx rename docs/src/pages/guides/{composition => routing}/ListRouter.js (100%) rename docs/src/pages/guides/{composition => routing}/ListRouter.tsx (100%) create mode 100644 docs/src/pages/guides/routing/routing.md diff --git a/docs/pages/guides/routing.js b/docs/pages/guides/routing.js new file mode 100644 index 00000000000000..04b21f34057898 --- /dev/null +++ b/docs/pages/guides/routing.js @@ -0,0 +1,20 @@ +import * as React from 'react'; +import MarkdownDocs from 'docs/src/modules/components/MarkdownDocs'; +import { prepareMarkdown } from 'docs/src/modules/utils/parseMarkdown'; + +const pageFilename = 'guides/routing'; +const requireDemo = require.context('docs/src/pages/guides/routing', false, /\.(js|tsx)$/); +const requireRaw = require.context( + '!raw-loader!../../src/pages/guides/routing', + false, + /\.(js|md|tsx)$/, +); + +export default function Page({ demos, docs }) { + return ; +} + +Page.getInitialProps = () => { + const { demos, docs } = prepareMarkdown({ pageFilename, requireRaw }); + return { demos, docs }; +}; diff --git a/docs/src/pages.ts b/docs/src/pages.ts index c7cafad7ffe82c..1d254181bb74fd 100644 --- a/docs/src/pages.ts +++ b/docs/src/pages.ts @@ -254,6 +254,7 @@ const pages: MuiPage[] = [ { pathname: '/guides/interoperability', title: 'Style Library Interoperability' }, { pathname: '/guides/minimizing-bundle-size' }, { pathname: '/guides/composition' }, + { pathname: '/guides/routing' }, { pathname: '/guides/server-rendering' }, { pathname: '/guides/responsive-ui', title: 'Responsive UI' }, { pathname: '/guides/pickers-migration', title: 'Migration from @material-ui/pickers' }, diff --git a/docs/src/pages/components/buttons/buttons.md b/docs/src/pages/components/buttons/buttons.md index 67ab58eb3e62bb..90d4b244d4f6cb 100644 --- a/docs/src/pages/components/buttons/buttons.md +++ b/docs/src/pages/components/buttons/buttons.md @@ -132,7 +132,7 @@ component forwards this ref to the underlying DOM node. Given that many of the interactive components rely on `ButtonBase`, you should be able to take advantage of it everywhere. -Here is an [integration example with react-router](/guides/composition/#button). +Here is an [integration example with react-router](/guides/routing/#button). ## Limitations diff --git a/docs/src/pages/components/links/Links.js b/docs/src/pages/components/links/Links.js index 719afc4361ff55..701739ab1f6de6 100644 --- a/docs/src/pages/components/links/Links.js +++ b/docs/src/pages/components/links/Links.js @@ -3,9 +3,9 @@ import * as React from 'react'; import Box from '@material-ui/core/Box'; import Link from '@material-ui/core/Link'; -export default function Links() { - const preventDefault = (event) => event.preventDefault(); +const preventDefault = (event) => event.preventDefault(); +export default function Links() { return ( event.preventDefault(); +const preventDefault = (event: React.SyntheticEvent) => event.preventDefault(); +export default function Links() { return ( event.preventDefault(); +const preventDefault = (event) => event.preventDefault(); +export default function UnderlineLink() { return ( event.preventDefault(); +const preventDefault = (event: React.SyntheticEvent) => event.preventDefault(); +export default function UnderlineLink() { return ( ; ``` -You can find a [demo with React Router following this section](/guides/composition/#react-router) of the documentation. +You can find a [demo with React Router following this section](/guides/routing/#list) of the documentation. ## Nested List diff --git a/docs/src/pages/getting-started/faq/faq.md b/docs/src/pages/getting-started/faq/faq.md index c2631c03df10db..600f8faee1d9b6 100644 --- a/docs/src/pages/getting-started/faq/faq.md +++ b/docs/src/pages/getting-started/faq/faq.md @@ -127,7 +127,7 @@ or are already familiar with a different API, and don't want to learn a new one? [Style Library Interoperability](/guides/interoperability/) section, where we show how simple it is to restyle Material-UI components with alternative style libraries. -## When should I use inline-style vs CSS? +## When should I use inline-style vs. CSS? As a rule of thumb, only use inline-styles for dynamic style properties. The CSS alternative provides more advantages, such as: @@ -139,7 +139,7 @@ The CSS alternative provides more advantages, such as: ## How do I use react-router? -We detail the [integration with third-party routing libraries](/guides/composition/#routing-libraries) like react-router, Gatsby or Next.js in our guide. +We detail the [integration with third-party routing libraries](/guides/routing/) like react-router, Gatsby or Next.js in our guide. ## How can I access the DOM element? diff --git a/docs/src/pages/guides/composition/LinkRouterWithTheme.js b/docs/src/pages/guides/composition/LinkRouterWithTheme.js deleted file mode 100644 index b9f0c16325cb18..00000000000000 --- a/docs/src/pages/guides/composition/LinkRouterWithTheme.js +++ /dev/null @@ -1,41 +0,0 @@ -import * as React from 'react'; -import PropTypes from 'prop-types'; -import { MemoryRouter as Router } from 'react-router'; -import { Link as RouterLink } from 'react-router-dom'; -import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; -import Button from '@material-ui/core/Button'; - -const LinkBehavior = React.forwardRef(({ href, ...props }, ref) => ( - -)); - -LinkBehavior.propTypes = { - href: PropTypes.string, -}; - -const theme = createMuiTheme({ - components: { - MuiButtonBase: { - defaultProps: { - LinkComponent: LinkBehavior, - }, - }, - MuiButton: { - styleOverrides: { - root: { - fontSize: '1rem', - }, - }, - }, - }, -}); - -export default function GlobalThemeOverride() { - return ( - - - - - - ); -} diff --git a/docs/src/pages/guides/composition/composition.md b/docs/src/pages/guides/composition/composition.md index b52b73cdf5aecd..bc2e9c159f88b7 100644 --- a/docs/src/pages/guides/composition/composition.md +++ b/docs/src/pages/guides/composition/composition.md @@ -6,7 +6,7 @@ In order to provide the maximum flexibility and performance, we need a way to know the nature of the child elements a component receives. -To solve this problem we tag some of the components +To solve this problem, we tag some of the components with a `muiName` static property when needed. You may, however, need to wrap a component in order to enhance it, @@ -128,29 +128,6 @@ The component providing the `component` prop (e.g. ListItem) might not forward a You can find the details in the [TypeScript guide](/guides/typescript/#usage-of-component-prop). -## Routing libraries - -The integration with third-party routing libraries is achieved with the `component` prop. -The behavior is identical to the description of the prop above. -Here are a few demos with [react-router-dom](https://github.com/ReactTraining/react-router). -They cover the Button, Link, and List components. You can apply the same strategy with all the components (BottomNavigation, Card, etc.). - -### Button - -{{"demo": "pages/guides/composition/ButtonRouter.js"}} - -### Link - -{{"demo": "pages/guides/composition/LinkRouter.js"}} - -### Link configuration using theme - -{{"demo": "pages/guides/composition/LinkRouterWithTheme.js"}} - -### List - -{{"demo": "pages/guides/composition/ListRouter.js"}} - ## Caveat with refs This section covers caveats when using a custom component as `children` or for the diff --git a/docs/src/pages/guides/routing/ButtonDemo.js b/docs/src/pages/guides/routing/ButtonDemo.js new file mode 100644 index 00000000000000..1fc380f3638f1b --- /dev/null +++ b/docs/src/pages/guides/routing/ButtonDemo.js @@ -0,0 +1,15 @@ +import * as React from 'react'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; + +const preventDefault = (event) => event.preventDefault(); + +export default function ButtonDemo() { + return ( + + + + ); +} diff --git a/docs/src/pages/guides/routing/ButtonDemo.tsx b/docs/src/pages/guides/routing/ButtonDemo.tsx new file mode 100644 index 00000000000000..eee2bfa849af0f --- /dev/null +++ b/docs/src/pages/guides/routing/ButtonDemo.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; +import Box from '@material-ui/core/Box'; +import Button from '@material-ui/core/Button'; + +const preventDefault = (event: React.SyntheticEvent) => event.preventDefault(); + +export default function ButtonDemo() { + return ( + + + + ); +} diff --git a/docs/src/pages/guides/composition/ButtonRouter.js b/docs/src/pages/guides/routing/ButtonRouter.js similarity index 91% rename from docs/src/pages/guides/composition/ButtonRouter.js rename to docs/src/pages/guides/routing/ButtonRouter.js index c6865f1734736b..da65000ddd285e 100644 --- a/docs/src/pages/guides/composition/ButtonRouter.js +++ b/docs/src/pages/guides/routing/ButtonRouter.js @@ -9,14 +9,14 @@ const LinkBehavior = React.forwardRef((props, ref) => ( export default function ButtonRouter() { return ( - -

+
+
-
- + +
); } diff --git a/docs/src/pages/guides/composition/ButtonRouter.tsx b/docs/src/pages/guides/routing/ButtonRouter.tsx similarity index 92% rename from docs/src/pages/guides/composition/ButtonRouter.tsx rename to docs/src/pages/guides/routing/ButtonRouter.tsx index 4d468adaf6a337..0cbcb17272d082 100644 --- a/docs/src/pages/guides/composition/ButtonRouter.tsx +++ b/docs/src/pages/guides/routing/ButtonRouter.tsx @@ -11,14 +11,14 @@ const LinkBehavior = React.forwardRef>( export default function ButtonRouter() { return ( - -
+
+
-
- + +
); } diff --git a/docs/src/pages/guides/routing/LinkDemo.js b/docs/src/pages/guides/routing/LinkDemo.js new file mode 100644 index 00000000000000..fec5638e0ab1de --- /dev/null +++ b/docs/src/pages/guides/routing/LinkDemo.js @@ -0,0 +1,13 @@ +import * as React from 'react'; +import Link from '@material-ui/core/Link'; +import Box from '@material-ui/core/Box'; + +const preventDefault = (event) => event.preventDefault(); + +export default function LinkDemo() { + return ( + + Link + + ); +} diff --git a/docs/src/pages/guides/routing/LinkDemo.tsx b/docs/src/pages/guides/routing/LinkDemo.tsx new file mode 100644 index 00000000000000..5fba35c5a8e814 --- /dev/null +++ b/docs/src/pages/guides/routing/LinkDemo.tsx @@ -0,0 +1,13 @@ +import * as React from 'react'; +import Link from '@material-ui/core/Link'; +import Box from '@material-ui/core/Box'; + +const preventDefault = (event: React.SyntheticEvent) => event.preventDefault(); + +export default function LinkDemo() { + return ( + + Link + + ); +} diff --git a/docs/src/pages/guides/composition/LinkRouter.js b/docs/src/pages/guides/routing/LinkRouter.js similarity index 83% rename from docs/src/pages/guides/composition/LinkRouter.js rename to docs/src/pages/guides/routing/LinkRouter.js index 0e4ac26cb4a1b9..9a8f2bfcf2dd90 100644 --- a/docs/src/pages/guides/composition/LinkRouter.js +++ b/docs/src/pages/guides/routing/LinkRouter.js @@ -3,6 +3,7 @@ import * as React from 'react'; import { MemoryRouter as Router } from 'react-router'; import { Link as RouterLink } from 'react-router-dom'; import Link from '@material-ui/core/Link'; +import Box from '@material-ui/core/Box'; const LinkBehavior = React.forwardRef((props, ref) => ( @@ -10,14 +11,14 @@ const LinkBehavior = React.forwardRef((props, ref) => ( export default function LinkRouter() { return ( - -
+ + With prop forwarding
Without prop forwarding -
-
+
+ ); } diff --git a/docs/src/pages/guides/composition/LinkRouter.tsx b/docs/src/pages/guides/routing/LinkRouter.tsx similarity index 84% rename from docs/src/pages/guides/composition/LinkRouter.tsx rename to docs/src/pages/guides/routing/LinkRouter.tsx index 5ebbc09aa534da..ae512955c5ce8f 100644 --- a/docs/src/pages/guides/composition/LinkRouter.tsx +++ b/docs/src/pages/guides/routing/LinkRouter.tsx @@ -3,6 +3,7 @@ import * as React from 'react'; import { MemoryRouter as Router } from 'react-router'; import { Link as RouterLink, LinkProps as RouterLinkProps } from 'react-router-dom'; import Link from '@material-ui/core/Link'; +import Box from '@material-ui/core/Box'; const LinkBehavior = React.forwardRef>( (props, ref) => ( @@ -12,14 +13,14 @@ const LinkBehavior = React.forwardRef>( export default function LinkRouter() { return ( - -
+ + With prop forwarding
Without prop forwarding -
-
+ + ); } diff --git a/docs/src/pages/guides/routing/LinkRouterWithTheme.js b/docs/src/pages/guides/routing/LinkRouterWithTheme.js new file mode 100644 index 00000000000000..d0190a9926f8fd --- /dev/null +++ b/docs/src/pages/guides/routing/LinkRouterWithTheme.js @@ -0,0 +1,57 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { MemoryRouter as Router } from 'react-router'; +import { Link as RouterLink } from 'react-router-dom'; +import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import Box from '@material-ui/core/Box'; +import Link from '@material-ui/core/Link'; + +const LinkBehavior = React.forwardRef((props, ref) => { + const { href, ...other } = props; + return ; +}); + +LinkBehavior.propTypes = { + href: PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.string]) + .isRequired, +}; + +const theme = createMuiTheme({ + components: { + MuiLink: { + defaultProps: { + // @ts-ignore + component: LinkBehavior, + }, + }, + MuiButtonBase: { + defaultProps: { + LinkComponent: LinkBehavior, + }, + }, + }, +}); + +export default function LinkRouterWithTheme() { + return ( + :not(style) + :not(style)': { mt: 1 }, + }} + > + + + Link + + + + + ); +} diff --git a/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx b/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx new file mode 100644 index 00000000000000..6f3d79a5004210 --- /dev/null +++ b/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx @@ -0,0 +1,54 @@ +import * as React from 'react'; +import { MemoryRouter as Router } from 'react-router'; +import { Link as RouterLink, LinkProps as RouterLinkProps } from 'react-router-dom'; +import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; +import Button from '@material-ui/core/Button'; +import Box from '@material-ui/core/Box'; +import Link from '@material-ui/core/Link'; + +const LinkBehavior = React.forwardRef< + any, + Omit & { href: RouterLinkProps['to'] } +>((props, ref) => { + const { href, ...other } = props; + return ; +}); + +const theme = createMuiTheme({ + components: { + MuiLink: { + defaultProps: { + // @ts-ignore + component: LinkBehavior, + }, + }, + MuiButtonBase: { + defaultProps: { + LinkComponent: LinkBehavior, + }, + }, + }, +}); + +export default function LinkRouterWithTheme() { + return ( + :not(style) + :not(style)': { mt: 1 }, + }} + > + + + Link + + + + + ); +} diff --git a/docs/src/pages/guides/composition/ListRouter.js b/docs/src/pages/guides/routing/ListRouter.js similarity index 100% rename from docs/src/pages/guides/composition/ListRouter.js rename to docs/src/pages/guides/routing/ListRouter.js diff --git a/docs/src/pages/guides/composition/ListRouter.tsx b/docs/src/pages/guides/routing/ListRouter.tsx similarity index 100% rename from docs/src/pages/guides/composition/ListRouter.tsx rename to docs/src/pages/guides/routing/ListRouter.tsx diff --git a/docs/src/pages/guides/routing/routing.md b/docs/src/pages/guides/routing/routing.md new file mode 100644 index 00000000000000..2d5c20f965efc7 --- /dev/null +++ b/docs/src/pages/guides/routing/routing.md @@ -0,0 +1,47 @@ +# Routing libraries + +

By default, the navigation is performed with a native <a> element. You can customize it to use your own router. For instance, using Next.js's Link or react-router.

+ +## Navigation components + +There are two main components available to perform navigations. +The most common one is the [`Link`](/components/link/) as its name might suggest. +It renders a native `` element and applies the `href` as an attribute. + +{{"demo": "pages/guides/routing/LinkDemo.js"}} + +You can also make a button perform navigation actions. +As long as your component is extending [`ButtonBase`](/components/buttons/#complex-buttons), the `href` prop will enable the link mode. + +{{"demo": "pages/guides/routing/ButtonDemo.js"}} + +## Global theme Link + +In real-life applications, using a native `` element is very rarely enough. +The UX can be improved by using an enhanced Link component systematically. +The theme of Material-UI allows to configure this component once: + +{{"demo": "pages/guides/routing/LinkRouterWithTheme.js"}} + +> ⚠️ This approach has limitations with TypeScript. The `href` prop only accepts a string. +> In the event you need to provide a richer structure, see the next section. + +## `component` prop + +The integration with third-party routing libraries can be achieved with the `component` prop. +You can learn more about this prop in the [composition guide](/guides/composition/#component-prop). + +Here are a few demos with [react-router-dom](https://github.com/ReactTraining/react-router). +You can apply the same strategy with all the components (BottomNavigation, Card, etc.). + +### Link + +{{"demo": "pages/guides/routing/LinkRouter.js"}} + +### Button + +{{"demo": "pages/guides/routing/ButtonRouter.js"}} + +### List + +{{"demo": "pages/guides/routing/ListRouter.js"}} diff --git a/docs/src/pages/guides/typescript/typescript.md b/docs/src/pages/guides/typescript/typescript.md index 41e5045a60a254..764e5aa1a5db64 100644 --- a/docs/src/pages/guides/typescript/typescript.md +++ b/docs/src/pages/guides/typescript/typescript.md @@ -287,7 +287,7 @@ const theme = createMyTheme({ Many Material-UI components allow you to replace their root node via a `component` prop, this will be detailed in the component's API documentation. For example, a Button's root node can be replaced with a React Router's Link, and any additional props that are passed to Button, such as `to`, will be spread to the Link component. -For a code example concerning Button and react-router-dom checkout [these demos](/guides/composition/#routing-libraries). +For a code example concerning Button and react-router-dom checkout [these demos](/guides/routing/#component-prop). To be able to use props of such a Material-UI component on their own, props should be used with type arguments. Otherwise, the `component` prop will not be present in the props of the Material-UI component. From 04a04b317d54a5ec817b910726e0498619d88d2c Mon Sep 17 00:00:00 2001 From: Olivier Tassinari Date: Sun, 14 Mar 2021 18:17:11 +0100 Subject: [PATCH 08/13] improve the docs --- .../guides/routing/LinkRouterWithTheme.js | 28 ++++++++++--------- .../guides/routing/LinkRouterWithTheme.tsx | 28 ++++++++++--------- docs/src/pages/guides/routing/routing.md | 3 +- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/docs/src/pages/guides/routing/LinkRouterWithTheme.js b/docs/src/pages/guides/routing/LinkRouterWithTheme.js index d0190a9926f8fd..0e88b0eb9945ee 100644 --- a/docs/src/pages/guides/routing/LinkRouterWithTheme.js +++ b/docs/src/pages/guides/routing/LinkRouterWithTheme.js @@ -1,6 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { MemoryRouter as Router } from 'react-router'; + import { Link as RouterLink } from 'react-router-dom'; import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; @@ -17,21 +18,22 @@ LinkBehavior.propTypes = { .isRequired, }; -const theme = createMuiTheme({ - components: { - MuiLink: { - defaultProps: { - // @ts-ignore - component: LinkBehavior, +const themeSetter = (outerTheme) => + createMuiTheme(outerTheme, { + components: { + MuiLink: { + defaultProps: { + // @ts-ignore + component: LinkBehavior, + }, }, - }, - MuiButtonBase: { - defaultProps: { - LinkComponent: LinkBehavior, + MuiButtonBase: { + defaultProps: { + LinkComponent: LinkBehavior, + }, }, }, - }, -}); + }); export default function LinkRouterWithTheme() { return ( @@ -44,7 +46,7 @@ export default function LinkRouterWithTheme() { '& > :not(style) + :not(style)': { mt: 1 }, }} > - + Link + ); + } + ``` + +- The second version of the adapter is the `Link` component. + This component is styled, it leverages the [link component of Material-UI](https://material-ui.com/components/links/) with `NextLinkComposed`. + + ```tsx + import Link from '../src/Link'; + + export default function Index() { + return ( + + Link + + ); + } + ``` diff --git a/examples/nextjs-with-typescript/README.md b/examples/nextjs-with-typescript/README.md index 6731bfecd5de1f..d3aed748a67626 100644 --- a/examples/nextjs-with-typescript/README.md +++ b/examples/nextjs-with-typescript/README.md @@ -27,47 +27,5 @@ The project uses [Next.js](https://github.com/zeit/next.js), which is a framewor ## The link component Next.js has [a custom Link component](https://nextjs.org/docs/api-reference/next/link). -The example provides adapters for usage with Material-UI. - -- The first version of the adapter is the `NextLinkComposed` component. - This component is unstyled and only responsible for handling the navigation. - The prop `href` was renamed `to`. - - ```tsx - import Button from '@material-ui/core/Button'; - import { NextLinkComposed } from '../src/Link'; - - export default function Index() { - return ( - - ); - } - ``` - -- The second version of the adapter is the `Link` component. - This component is styled, it leverages the [link component of Material-UI](https://material-ui.com/components/links/) with `NextLinkComposed`. - - ```tsx - import Link from '../src/Link'; - - export default function Index() { - return ( - - Link - - ); - } - ``` +The example folder provides adapters for usage with Material-UI. +More information [in the documentation](https://next.material-ui.com/guides/routing/#next-js). diff --git a/examples/nextjs/README.md b/examples/nextjs/README.md index bbf95025ae26db..d03e247066f495 100644 --- a/examples/nextjs/README.md +++ b/examples/nextjs/README.md @@ -27,47 +27,5 @@ The project uses [Next.js](https://github.com/zeit/next.js), which is a framewor ## The link component Next.js has [a custom Link component](https://nextjs.org/docs/api-reference/next/link). -The example provides adapters for usage with Material-UI. - -- The first version of the adapter is the `NextLinkComposed` component. - This component is unstyled and only responsible for handling the navigation. - The prop `href` was renamed `to`. - - ```tsx - import Button from '@material-ui/core/Button'; - import { NextLinkComposed } from '../src/Link'; - - export default function Index() { - return ( - - ); - } - ``` - -- The second version of the adapter is the `Link` component. - This component is styled, it leverages the [link component of Material-UI](https://material-ui.com/components/links/) with `NextLinkComposed`. - - ```tsx - import Link from '../src/Link'; - - export default function Index() { - return ( - - Link - - ); - } - ``` +The example folder provides adapters for usage with Material-UI. +More information [in the documentation](https://next.material-ui.com/guides/routing/#next-js). From 3db2ad7e1ea3d97a2bc4b675bc2426bd99945d12 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari Date: Sun, 14 Mar 2021 18:35:11 +0100 Subject: [PATCH 10/13] fix ci --- docs/src/pages/guides/routing/LinkRouterWithTheme.js | 1 - docs/src/pages/guides/routing/LinkRouterWithTheme.tsx | 3 +-- docs/translations/translations.json | 1 + 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/src/pages/guides/routing/LinkRouterWithTheme.js b/docs/src/pages/guides/routing/LinkRouterWithTheme.js index 0e88b0eb9945ee..2eea9ab6c847cd 100644 --- a/docs/src/pages/guides/routing/LinkRouterWithTheme.js +++ b/docs/src/pages/guides/routing/LinkRouterWithTheme.js @@ -1,7 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { MemoryRouter as Router } from 'react-router'; - import { Link as RouterLink } from 'react-router-dom'; import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; diff --git a/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx b/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx index d7715e16d9e415..ed574550053f56 100644 --- a/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx +++ b/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx @@ -1,8 +1,7 @@ import * as React from 'react'; import { MemoryRouter as Router } from 'react-router'; -import { Theme } from '@material-ui/core/styles'; import { Link as RouterLink, LinkProps as RouterLinkProps } from 'react-router-dom'; -import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; +import { Theme, ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; import Button from '@material-ui/core/Button'; import Box from '@material-ui/core/Box'; import Link from '@material-ui/core/Link'; diff --git a/docs/translations/translations.json b/docs/translations/translations.json index ae30e831946f55..5786d09d6cea6c 100644 --- a/docs/translations/translations.json +++ b/docs/translations/translations.json @@ -296,6 +296,7 @@ "/guides/interoperability": "Style Library Interoperability", "/guides/minimizing-bundle-size": "Minimizing Bundle Size", "/guides/composition": "Composition", + "/guides/routing": "Routing", "/guides/server-rendering": "Server Rendering", "/guides/responsive-ui": "Responsive UI", "/guides/pickers-migration": "Migration from @material-ui/pickers", From de527e2d03c9941cd1a3a1cdefc467bd33f68622 Mon Sep 17 00:00:00 2001 From: Veda Date: Mon, 15 Mar 2021 12:12:04 +0530 Subject: [PATCH 11/13] Update docs/src/pages/guides/routing/routing.md Co-authored-by: Olivier Tassinari --- docs/src/pages/guides/routing/routing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/pages/guides/routing/routing.md b/docs/src/pages/guides/routing/routing.md index 0a97e700f3dfd0..4132f87e3a36cd 100644 --- a/docs/src/pages/guides/routing/routing.md +++ b/docs/src/pages/guides/routing/routing.md @@ -18,7 +18,7 @@ For instance, with a `Button` component: ## Global theme Link -In real-life applications, using a native `` element is very rarely enough. +In real-life applications, using a native `` element is rarely enough. The User Experience can be improved by using an enhanced Link component systematically. The theme of Material-UI allows configuring this component once. For instance, with react-router: From 0876b82fa7a414539ec05a3f8788726da34578f7 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari Date: Thu, 18 Mar 2021 19:50:48 +0100 Subject: [PATCH 12/13] improve markdown --- docs/src/pages/guides/routing/routing.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/src/pages/guides/routing/routing.md b/docs/src/pages/guides/routing/routing.md index 4132f87e3a36cd..56d36441952aa5 100644 --- a/docs/src/pages/guides/routing/routing.md +++ b/docs/src/pages/guides/routing/routing.md @@ -19,18 +19,19 @@ For instance, with a `Button` component: ## Global theme Link In real-life applications, using a native `` element is rarely enough. -The User Experience can be improved by using an enhanced Link component systematically. +You can improve the user experience by using an enhanced Link component systematically. The theme of Material-UI allows configuring this component once. For instance, with react-router: {{"demo": "pages/guides/routing/LinkRouterWithTheme.js"}} -> ⚠️ This approach has limitations with TypeScript. The `href` prop only accepts a string. +> ⚠️ This approach has limitations with TypeScript. +> The `href` prop only accepts a string. > In the event you need to provide a richer structure, see the next section. ## `component` prop -The integration with third-party routing libraries can be achieved with the `component` prop. +You can achieve the integration with third-party routing libraries with the `component` prop. You can learn more about this prop in the [composition guide](/guides/composition/#component-prop). Here are a few demos with [react-router](https://github.com/ReactTraining/react-router). @@ -79,7 +80,7 @@ The [example folder](https://github.com/mui-org/material-ui/tree/HEAD/examples/n ``` - The second version of the adapter is the `Link` component. - This component is styled, it leverages the [link component of Material-UI](https://material-ui.com/components/links/) with `NextLinkComposed`. + This component is styled. It leverages the [link component of Material-UI](https://material-ui.com/components/links/) with `NextLinkComposed`. ```tsx import Link from '../src/Link'; From 94ce1c019126ce02c8462316f95825fb08eda5c5 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari Date: Thu, 18 Mar 2021 20:05:24 +0100 Subject: [PATCH 13/13] go the extra mile --- .../guides/routing/LinkRouterWithTheme.js | 1 + .../guides/routing/LinkRouterWithTheme.tsx | 1 + docs/src/pages/guides/routing/routing.md | 40 +++++++++++++++++-- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/docs/src/pages/guides/routing/LinkRouterWithTheme.js b/docs/src/pages/guides/routing/LinkRouterWithTheme.js index 2eea9ab6c847cd..5116a38e4f5829 100644 --- a/docs/src/pages/guides/routing/LinkRouterWithTheme.js +++ b/docs/src/pages/guides/routing/LinkRouterWithTheme.js @@ -9,6 +9,7 @@ import Link from '@material-ui/core/Link'; const LinkBehavior = React.forwardRef((props, ref) => { const { href, ...other } = props; + // Map href (Material-UI) -> to (react-router) return ; }); diff --git a/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx b/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx index ed574550053f56..cd468f8dc74f58 100644 --- a/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx +++ b/docs/src/pages/guides/routing/LinkRouterWithTheme.tsx @@ -11,6 +11,7 @@ const LinkBehavior = React.forwardRef< Omit & { href: RouterLinkProps['to'] } >((props, ref) => { const { href, ...other } = props; + // Map href (Material-UI) -> to (react-router) return ; }); diff --git a/docs/src/pages/guides/routing/routing.md b/docs/src/pages/guides/routing/routing.md index 56d36441952aa5..9d69686619f0b0 100644 --- a/docs/src/pages/guides/routing/routing.md +++ b/docs/src/pages/guides/routing/routing.md @@ -23,7 +23,33 @@ You can improve the user experience by using an enhanced Link component systemat The theme of Material-UI allows configuring this component once. For instance, with react-router: -{{"demo": "pages/guides/routing/LinkRouterWithTheme.js"}} +```jsx +const LinkBehavior = React.forwardRef< + any, + Omit & { href: RouterLinkProps['to'] } +>((props, ref) => { + const { href, ...other } = props; + // Map href (Material-UI) -> to (react-router) + return ; +}); + +const theme = createMuiTheme({ + components: { + MuiLink: { + defaultProps: { + component: LinkBehavior, + }, + }, + MuiButtonBase: { + defaultProps: { + LinkComponent: LinkBehavior, + }, + }, + }, +}); +``` + +{{"demo": "pages/guides/routing/LinkRouterWithTheme.js", "defaultCodeOpen": false}} > ⚠️ This approach has limitations with TypeScript. > The `href` prop only accepts a string. @@ -56,9 +82,10 @@ You can apply the same strategy with all the components (BottomNavigation, Card, Next.js has [a custom Link component](https://nextjs.org/docs/api-reference/next/link). The [example folder](https://github.com/mui-org/material-ui/tree/HEAD/examples/nextjs-with-typescript) provides adapters for usage with Material-UI. -- The first version of the adapter is the `NextLinkComposed` component. +- The first version of the adapter is the [`NextLinkComposed`](https://github.com/mui-org/material-ui/tree/HEAD/examples/nextjs-with-typescript/src/Link.tsx) component. This component is unstyled and only responsible for handling the navigation. The prop `href` was renamed `to` to avoid a naming conflict. + This is similar to react-router's Link component. ```tsx import Button from '@material-ui/core/Button'; @@ -80,7 +107,8 @@ The [example folder](https://github.com/mui-org/material-ui/tree/HEAD/examples/n ``` - The second version of the adapter is the `Link` component. - This component is styled. It leverages the [link component of Material-UI](https://material-ui.com/components/links/) with `NextLinkComposed`. + This component is styled. + It leverages the [link component of Material-UI](https://material-ui.com/components/links/) with `NextLinkComposed`. ```tsx import Link from '../src/Link'; @@ -98,3 +126,9 @@ The [example folder](https://github.com/mui-org/material-ui/tree/HEAD/examples/n ); } ``` + +### Gatsby + +The [Link](https://www.gatsbyjs.com/docs/linking-between-pages/) component of Gatsby is built on `@reach/router`. +You can use the same previous documentation for react-router. +Unlike Next.js, it doesn't require to create an adapter.