There were a lot of breaking changes between v5 and v6 of react-md, but a good
amount can be automated using the codemod. The migrations will be listed on
this page and prefixed with an icon:
Make sure to have committed or stashed any working changes before running the codemod to make reviewing changes easier and having a fallback if everything goes wrong. If you use a formatter, make sure to run it against all files afterwards to reduce the diffs as well.
Before getting started, remove all the @react-md/* packages and upgrade to
the latest react-md version.
npm uninstall \
react-md \
@react-md/alert \
@react-md/app-bar \
@react-md/autocomplete \
@react-md/avatar \
@react-md/badge \
@react-md/button \
@react-md/card \
@react-md/chip \
@react-md/dialog \
@react-md/divider \
@react-md/elevation \
@react-md/expansion-panel \
@react-md/form \
@react-md/icon \
@react-md/layout \
@react-md/link \
@react-md/list \
@react-md/material-icons \
@react-md/media \
@react-md/menu \
@react-md/overlay \
@react-md/portal \
@react-md/progress \
@react-md/sheet \
@react-md/states \
@react-md/table \
@react-md/tabs \
@react-md/theme \
@react-md/tooltip \
@react-md/transition \
@react-md/tree \
@react-md/typography \
@react-md/utilspnpm remove \
react-md \
@react-md/alert \
@react-md/app-bar \
@react-md/autocomplete \
@react-md/avatar \
@react-md/badge \
@react-md/button \
@react-md/card \
@react-md/chip \
@react-md/dialog \
@react-md/divider \
@react-md/elevation \
@react-md/expansion-panel \
@react-md/form \
@react-md/icon \
@react-md/layout \
@react-md/link \
@react-md/list \
@react-md/material-icons \
@react-md/media \
@react-md/menu \
@react-md/overlay \
@react-md/portal \
@react-md/progress \
@react-md/sheet \
@react-md/states \
@react-md/table \
@react-md/tabs \
@react-md/theme \
@react-md/tooltip \
@react-md/transition \
@react-md/tree \
@react-md/typography \
@react-md/utilsyarn remove \
react-md \
@react-md/alert \
@react-md/app-bar \
@react-md/autocomplete \
@react-md/avatar \
@react-md/badge \
@react-md/button \
@react-md/card \
@react-md/chip \
@react-md/dialog \
@react-md/divider \
@react-md/elevation \
@react-md/expansion-panel \
@react-md/form \
@react-md/icon \
@react-md/layout \
@react-md/link \
@react-md/list \
@react-md/material-icons \
@react-md/media \
@react-md/menu \
@react-md/overlay \
@react-md/portal \
@react-md/progress \
@react-md/sheet \
@react-md/states \
@react-md/table \
@react-md/tabs \
@react-md/theme \
@react-md/tooltip \
@react-md/transition \
@react-md/tree \
@react-md/typography \
@react-md/utilsnpm install react-md @react-md/material-iconspnpm add react-md @react-md/material-iconsyarn add react-md @react-md/material-iconsIf you just want to try auto-migrating everything through the codemods and
handling the TODOs/manual steps afterwards, you can run the following commands:
npx @react-md/codemod migrate/v5-to-v6
You will be prompted to provide the Javascript parser, which files/folder to run the codemod on, and if everything should be auto-confirmed.
react-md This step is required for any other codemods to work. The codemods
only look for the react-md package name.
npx @react-md/codemod v5-to-v6/to-react-md-imports
To make the migration easier, the codemod will begin by converting all scoped
package imports (@react-md/*) into the react-md package import.
+import {
+ AppBar,
+ AppBarNav,
+ ArrowBackSVGIcon,
+ Button,
+ Dialog,
+ DialogContent,
+ MediaContainer,
+} from "react-md";
+
import type { ReactElement } from "react";
import { useState } from "react";
-import { AppBar, AppBarNav } from "@react-md/app-bar";
-import { Button } from "@react-md/button";
-import { Dialog, DialogContent } from "@react-md/dialog";
-import { ArrowBackSVGIcon } from "@react-md/material-icons";
-import { MediaContainer } from "@react-md/media";
import AppBarTitle from "./AppBarTitle";
import styles from "./FullPageExample.module.scss";
npx @react-md/codemod v5-to-v6/hardcode-scss-variables
This codemod converts any @react-md/*/dist/scssVariables into hard coded constants since
it no longer exists.
-import alertVariables from "@react-md/alert/dist/scssVariables";
-import appBarVariables from "@react-md/app-bar/dist/scssVariables";
-import mediaVariables from "@react-md/media/dist/scssVariables";
import shouldNotChange from "another/scssVariables";
-const color = alertVariables["rmd-alert-theme-values"].color;
-const backgroundColor =
- alertVariables["rmd-alert-theme-values"]["background-color"];
+const color = "#fff";
+const backgroundColor = "#323232";
-const margin = alertVariables["rmd-snackbar-margin"];
-const zIndex = alertVariables["rmd-snackbar-z-index"];
+const margin = "1rem";
+const zIndex = 40;
-const titleKeyline = appBarVariables["rmd-app-bar-title-keyline"];
+const titleKeyline = "4.5rem";
-const mediaOverlayPositions = mediaVariables["rmd-media-overlay-positions"];
-const mediaOverlayPosition = mediaVariables["rmd-media-overlay-positions"][2];
-const aspectRatio = mediaVariables["rmd-media-default-aspect-ratios"]['"16-9"'];
+const mediaOverlayPositions = [
+ "top",
+ "right",
+ "bottom",
+ "left",
+ "middle",
+ "center",
+ "absolute-center",
+];
+const mediaOverlayPosition = "bottom";
+const aspectRatio = "16 9";
function Example() {
return (
<div
style={{
- backgroundColor:
- appBarVariables["rmd-app-bar-primary-background-color"],
+ backgroundColor: "var(--rmd-theme-primary, #9c27b0)",
}}
/>
);
FontIcon propsnpx @react-md/codemod v5-to-v6/icon/remove-deprecated-font-icon-props
The forceSize and forceFontSize props were removed from the FontIcon component.
<>
<FontIcon>material_unchanged</FontIcon>
<FontIcon iconClassName="fa fa-star" />
- <FontIcon iconClassName="fa fa-star" className={styles.icon} forceSize />
- <FontIcon iconClassName={styles.fontIcon} forceFontSize />
- <FontIcon
- iconClassName={styles.fontIcon}
- className={styles.icon}
- forceSize
- forceFontSize
- />
+ <FontIcon iconClassName="fa fa-star" className={styles.icon} />
+ <FontIcon iconClassName={styles.fontIcon} />
+ <FontIcon iconClassName={styles.fontIcon} className={styles.icon} />
</>
);
}
The @react-md/material-icons package was updated to support all the new icons
and material symbols but only exports SVG icon component versions. Choose one of
the following migrations:
npx @react-md/codemod v5-to-v6/material-icons/to-svg
Converts all material icons into the SVG components in v6.0.0.
+import ArrowDropDownIcon from "@react-md/material-icons/ArrowDropDownIcon";
+import ArrowUpwardIcon from "@react-md/material-icons/ArrowUpwardIcon";
+import CheckBoxIcon from "@react-md/material-icons/CheckBoxIcon";
+import CheckIcon from "@react-md/material-icons/CheckIcon";
+import ErrorOutlineIcon from "@react-md/material-icons/ErrorOutlineIcon";
+import FileUploadIcon from "@react-md/material-icons/FileUploadIcon";
+import KeyboardArrowDownIcon from "@react-md/material-icons/KeyboardArrowDownIcon";
+import KeyboardArrowLeftIcon from "@react-md/material-icons/KeyboardArrowLeftIcon";
+import KeyboardArrowRightIcon from "@react-md/material-icons/KeyboardArrowRightIcon";
+import MenuIcon from "@react-md/material-icons/MenuIcon";
+import NotificationsIcon from "@react-md/material-icons/NotificationsIcon";
+import RadioButtonCheckedIcon from "@react-md/material-icons/RadioButtonCheckedIcon";
+import RemoveRedEyeIcon from "@react-md/material-icons/RemoveRedEyeIcon";
import type { ReactElement, ReactNode } from "react";
import { Link, useLocation } from "react-router-dom";
import {
- ArrowDropDownSVGIcon,
- ArrowUpwardSVGIcon,
- CheckBoxSVGIcon,
- CheckSVGIcon,
ConfiguredIcons,
Configuration,
- ErrorOutlineSVGIcon,
- FileUploadSVGIcon,
- KeyboardArrowDownSVGIcon,
- KeyboardArrowLeftSVGIcon,
- KeyboardArrowRightFontIcon,
Layout as RMDLayout,
- MenuSVGIcon,
- NotificationsSVGIcon,
- RadioButtonCheckedSVGIcon,
- RemoveRedEyeSVGIcon as MyTestIcon,
useLayoutNavigation,
} from "react-md";
import navItems from "./navItems";
const icons: ConfiguredIcons = {
- back: <KeyboardArrowLeftSVGIcon />,
- checkbox: <CheckBoxSVGIcon />,
- dropdown: <ArrowDropDownSVGIcon />,
- error: <ErrorOutlineSVGIcon />,
- expander: <KeyboardArrowDownSVGIcon />,
- forward: <KeyboardArrowRightFontIcon />,
- menu: <MenuSVGIcon />,
- notification: <NotificationsSVGIcon />,
- password: <MyTestIcon />,
- radio: <RadioButtonCheckedSVGIcon />,
- selected: <CheckSVGIcon />,
- sort: <ArrowUpwardSVGIcon />,
- upload: <FileUploadSVGIcon></FileUploadSVGIcon>,
+ back: <KeyboardArrowLeftIcon />,
+ checkbox: <CheckBoxIcon />,
+ dropdown: <ArrowDropDownIcon />,
+ error: <ErrorOutlineIcon />,
+ expander: <KeyboardArrowDownIcon />,
+ forward: <KeyboardArrowRightIcon />,
+ menu: <MenuIcon />,
+ notification: <NotificationsIcon />,
+ password: <RemoveRedEyeIcon />,
+ radio: <RadioButtonCheckedIcon />,
+ selected: <CheckIcon />,
+ sort: <ArrowUpwardIcon />,
+ upload: <FileUploadIcon></FileUploadIcon>,
};
npx @react-md/codemod v5-to-v6/material-icons/to-font
Converts all material icons into the new MaterialIcon component.
@@ -1,39 +1,27 @@
import type { ReactElement, ReactNode } from "react";
import { Link, useLocation } from "react-router-dom";
import {
- ArrowDropDownFontIcon,
- ArrowUpwardFontIcon,
- CheckBoxFontIcon,
- CheckFontIcon,
- ConfiguredIcons,
Configuration,
- ErrorOutlineFontIcon,
- FileUploadFontIcon,
- KeyboardArrowDownFontIcon,
- KeyboardArrowLeftFontIcon,
- KeyboardArrowRightFontIcon,
+ ConfiguredIcons,
Layout as RMDLayout,
- MenuFontIcon,
- NotificationsFontIcon,
- RadioButtonCheckedFontIcon,
- RemoveRedEyeFontIcon as MyTestIcon,
+ MaterialIcon,
useLayoutNavigation,
} from "react-md";
import navItems from "./navItems";
const icons: ConfiguredIcons = {
- back: <KeyboardArrowLeftFontIcon />,
- checkbox: <CheckBoxFontIcon />,
- dropdown: <ArrowDropDownFontIcon />,
- error: <ErrorOutlineFontIcon />,
- expander: <KeyboardArrowDownFontIcon />,
- forward: <KeyboardArrowRightFontIcon />,
- menu: <MenuFontIcon />,
- notification: <NotificationsFontIcon />,
- password: <MyTestIcon />,
- radio: <RadioButtonCheckedFontIcon />,
- selected: <CheckFontIcon />,
- sort: <ArrowUpwardFontIcon />,
- upload: <FileUploadFontIcon></FileUploadFontIcon>,
+ back: <MaterialIcon name="keyboard_arrow_left" />,
+ checkbox: <MaterialIcon name="check_box" />,
+ dropdown: <MaterialIcon name="arrow_drop_down" />,
+ error: <MaterialIcon name="error_outline" />,
+ expander: <MaterialIcon name="keyboard_arrow_down" />,
+ forward: <MaterialIcon name="keyboard_arrow_right" />,
+ menu: <MaterialIcon name="menu" />,
+ notification: <MaterialIcon name="notifications" />,
+ password: <MaterialIcon name="remove_red_eye" />,
+ radio: <MaterialIcon name="radio_button_checked" />,
+ selected: <MaterialIcon name="check" />,
+ sort: <MaterialIcon name="arrow_upward" />,
+ upload: <MaterialIcon name="file_upload" />,
};
npx @react-md/codemod v5-to-v6/material-icons/to-symbol
Converts all material icons into the new MaterialSymbol component.
import type { ReactElement, ReactNode } from "react";
import { Link, useLocation } from "react-router-dom";
import {
- ArrowDropDownFontIcon,
- ArrowUpwardFontIcon,
- CheckBoxFontIcon,
- CheckFontIcon,
- ConfiguredIcons,
Configuration,
- ErrorOutlineFontIcon,
- FileUploadFontIcon,
- KeyboardArrowDownFontIcon,
- KeyboardArrowLeftFontIcon,
- KeyboardArrowRightFontIcon,
+ ConfiguredIcons,
Layout as RMDLayout,
- MenuFontIcon,
- NotificationsFontIcon,
- RadioButtonCheckedFontIcon,
- RemoveRedEyeFontIcon as MyTestIcon,
+ MaterialSymbol,
useLayoutNavigation,
} from "react-md";
import navItems from "./navItems";
const icons: ConfiguredIcons = {
- back: <KeyboardArrowLeftFontIcon />,
- checkbox: <CheckBoxFontIcon />,
- dropdown: <ArrowDropDownFontIcon />,
- error: <ErrorOutlineFontIcon />,
- expander: <KeyboardArrowDownFontIcon />,
- forward: <KeyboardArrowRightFontIcon />,
- menu: <MenuFontIcon />,
- notification: <NotificationsFontIcon />,
- password: <MyTestIcon />,
- radio: <RadioButtonCheckedFontIcon />,
- selected: <CheckFontIcon />,
- sort: <ArrowUpwardFontIcon />,
- upload: <FileUploadFontIcon></FileUploadFontIcon>,
+ back: <MaterialSymbol name="keyboard_arrow_left" />,
+ checkbox: <MaterialSymbol name="check_box" />,
+ dropdown: <MaterialSymbol name="arrow_drop_down" />,
+ error: <MaterialSymbol name="error_outline" />,
+ expander: <MaterialSymbol name="keyboard_arrow_down" />,
+ forward: <MaterialSymbol name="keyboard_arrow_right" />,
+ menu: <MaterialSymbol name="menu" />,
+ notification: <MaterialSymbol name="notifications" />,
+ password: <MaterialSymbol name="remove_red_eye" />,
+ radio: <MaterialSymbol name="radio_button_checked" />,
+ selected: <MaterialSymbol name="check" />,
+ sort: <MaterialSymbol name="arrow_upward" />,
+ upload: <MaterialSymbol name="file_upload" />,
};
There are a lot of breaking changes for the alert components and API. There are some auto-migrations available, but it is recommended to change a few things manually to adapt to the new API. The best way to understand the changes is to check out the new Snackbar Examples, but here's a summary of the changes:
Snackbar near the root of the app and display toasts with the
addToast exportMessageQueue is no longer required and replaced by an optional
ToastManagerProvideruseAddMessage hook is no longer required and replaced by useAddToast
addToast export instead for most casesmessageId has been renamed to toastIdmessagePriority has been renamed to priority"prevent" to "update"disableAutohide message option has been removed in favor of just
setting visibleTime to nulltwoLines option is no longer required since a resize observer
automatically determines multiple lines of text. If the number of lines are always known,
the multiline prop can be set to a boolean instead.useMessageQueueActions has been removed in favor of
useToastManager/useCurrentToastActionsHere's an example diff for converting the "Simple Message Queue" demo in v5 to the v6 implementation:
+import { Snackbar } from "@react-md/core/snackbar/Snackbar";
+import { addToast, type CreateToastOptions } from "@react-md/core/snackbar/ToastManager";
import type { ReactElement } from "react";
-import type { ToastMessage } from "@react-md/alert";
-import { MessageQueue, useAddMessage } from "@react-md/alert";
import { Button } from "@react-md/button";
import { Form, Radio, useChoice } from "@react-md/form";
const SINGLE_LINE = "SINGLE_LINE";
const SINGLE_LINE_ACTION = "SINGLE_LINE_ACTION";
const TWO_LINES = "TWO_LINES";
const TWO_LINES_ACTION = "TWO_LINES_ACTION";
const TWO_LINES_STACKED = "TWO_LINES_STACKED";
type MessageKeys =
| typeof SINGLE_LINE
| typeof SINGLE_LINE_ACTION
| typeof TWO_LINES
| typeof TWO_LINES_ACTION
| typeof TWO_LINES_STACKED;
-type MessageRecord = Record<MessageKeys, ToastMessage>;
+type MessageRecord = Record<MessageKeys, CreateToastOptions>;
const messages: MessageRecord = {
[SINGLE_LINE]: {
children: "This is an example message",
},
[SINGLE_LINE_ACTION]: {
action: "Action",
children: "This is an example message",
},
[TWO_LINES]: {
- twoLines: true,
+ // this is optional
+ multiline: true,
children: (
<>
<p>This is an example message</p>
<p>With a second line of text.</p>
</>
),
},
[TWO_LINES_ACTION]: {
action: "Action",
- twoLines: true,
+ // this is optional
+ multiline: true,
children: (
<>
<p>This is an example message</p>
<p>With a second line of text.</p>
</>
),
},
[TWO_LINES_STACKED]: {
action: "Action",
stacked: true,
- twoLines: true,
+ // this is optional
+ multiline: true,
children: (
<>
<p>This is an example message</p>
<p>With a second line of text.</p>
</>
),
},
};
function SimpleMessageQueue(): ReactElement {
- const addMessage = useAddMessage();
const [key, handleKeyChange] = useChoice<MessageKeys>(SINGLE_LINE);
return (
- <Form onSubmit={() => addMessage(messages[key])}>
+ <Form onSubmit={() => addToast(messages[key])}>
<Radio
id="mqr-1"
name="message"
value={SINGLE_LINE}
checked={key === SINGLE_LINE}
onChange={handleKeyChange}
label="Single Line Message"
/>
<Radio
id="mqr-2"
name="message"
value={SINGLE_LINE_ACTION}
checked={key === SINGLE_LINE_ACTION}
onChange={handleKeyChange}
label="Single Line Message with Action"
/>
<Radio
id="mqr-3"
name="message"
value={TWO_LINES}
checked={key === TWO_LINES}
onChange={handleKeyChange}
label="Two Line Message"
/>
<Radio
id="mqr-4"
name="message"
value={TWO_LINES_ACTION}
checked={key === TWO_LINES_ACTION}
onChange={handleKeyChange}
label="Two Line Message with Action"
/>
<Radio
id="mqr-5"
name="message"
value={TWO_LINES_STACKED}
checked={key === TWO_LINES_STACKED}
onChange={handleKeyChange}
label="Two Line Message with Stacked Action"
/>
<Button id="mqr-submit" type="submit" theme="primary">
Add Message
</Button>
</Form>
);
}
export default function SimpleMessageQueueContainer(): ReactElement {
return (
+ <>
- <MessageQueue id="simple-message-queue">
<SimpleMessageQueue />
+ <Snackbar />
+ <>
- </MessageQueue>
);
}
npx @react-md/codemod v5-to-v6/app-bar/remove-class-name-constants
The APP_BAR_OFFSET_* constants were removed and custom styles are required to
add any offset going forward. The codemod will apply the following diff:
+// TODO: Add styles for app bar offset
import cn from "classnames";
import { useState } from "react";
-import {
- APP_BAR_OFFSET_CLASSNAME,
- APP_BAR_OFFSET_DENSE_CLASSNAME,
- APP_BAR_OFFSET_PROMINENT_CLASSNAME,
- APP_BAR_OFFSET_PROMINENT_DENSE_CLASSNAME,
-} from "react-md";
import styles from "./styles.module.scss";
export default function Example() {
const [dense, setDense] = useState(false);
const [prominent, setProminent] = useState(false);
- return (
- <div
- className={cn(
- styles.content,
- {
- [APP_BAR_OFFSET_CLASSNAME]: !dense && !prominent,
- [APP_BAR_OFFSET_DENSE_CLASSNAME]: dense && !prominent,
- [APP_BAR_OFFSET_PROMINENT_CLASSNAME]: !dense && prominent,
- [APP_BAR_OFFSET_PROMINENT_DENSE_CLASSNAME]: dense && prominent,
- },
- !dense && !prominent && APP_BAR_OFFSET_CLASSNAME,
- dense && !prominent && APP_BAR_OFFSET_DENSE_CLASSNAME,
- !dense && prominent && APP_BAR_OFFSET_PROMINENT_CLASSNAME,
- dense && prominent && APP_BAR_OFFSET_PROMINENT_DENSE_CLASSNAME
- )}
- >
- content
- </div>
- );
+ return <div className={cn(styles.content, {})}>content</div>;
}
If the content should still be offset by the app bar's height, apply the following styles:
@use "react-md";
.container {
// use the current var(--rmd-app-bar-height) as the padding top
@include react-md.app-bar-use-var(padding-top, height);
// or choose one of the static values:
padding-top: react-md.$app-bar-height;
padding-top: react-md.$dense-height;
padding-top: react-md.$prominent-height;
padding-top: react-md.$prominent-dense-height;
}
npx @react-md/codemod v5-to-v6/app-bar/remove-use-action-class-name
The useActionClassName hook was removed since it is no longer needed for
spacing within an AppBar.
-import { useActionClassName } from "react-md";
import SomeComponent from "./SomeComponent";
import styles from "./styles.module.scss";
export function Example() {
- const className1 = useActionClassName();
- const className2 = useActionClassName({ first: true });
- const className3 = useActionClassName({ last: true });
- const className4 = useActionClassName({ className: styles.example });
+ const className4 = styles.example;
return (
<>
- <div className={className1} />
- <div className={className2} />
- <div className={className3} />
+ <div />
+ <div />
+ <div />
<div className={className4} />
<SomeComponent
- className1={useActionClassName()}
- className2={useActionClassName({ first: true })}
- className3={useActionClassName({ last: true })}
- className4={useActionClassName({ className: styles.example })}
+ className4={styles.example}
objectExample={{
- className1: useActionClassName(),
- className2: useActionClassName({ first: true }),
- className3: useActionClassName({ last: true }),
- className4: useActionClassName({ className: styles.example }),
+ className4: styles.example,
}}
/>
</>
npx @react-md/codemod v5-to-v6/app-bar/replace-nav-and-action-with-button
The AppBarAction and AppBarNav components were removed and can be replaced
with a Button.
import type { ReactElement } from "react";
import {
AppBar,
- AppBarAction,
- AppBarNav,
AppBarTitle,
+ Button,
MenuSVGIcon,
MoreVertSVGIcon,
SearchSVGIcon,
@@ -19,33 +18,21 @@ export default function Demo(): ReactElement {
<Container>
{themes.map((theme, i) => (
<AppBar id={`simple-usage-app-bar-${i}`} theme={theme} key={theme}>
- <AppBarNav
- id={`simple-usage-nav-${i}`}
- aria-label="Navigation"
- inheritColor
- >
+ <Button id={`simple-usage-nav-${i}`} aria-label="Navigation">
<MenuSVGIcon />
- </AppBarNav>
+ </Button>
<AppBarTitle
id={`simple-usage-title-${i}`}
className="rmd-typography--capitalize"
>
{theme}
</AppBarTitle>
- <AppBarAction
- id={`simple-usage-search-${i}`}
- first
- aria-label="Search"
- >
+ <Button id={`simple-usage-search-${i}`} aria-label="Search">
<SearchSVGIcon />
- </AppBarAction>
- <AppBarAction
- id={`simple-usage-kebab-${i}`}
- last
- aria-label="Actions"
- >
+ </Button>
+ <Button id={`simple-usage-kebab-${i}`} aria-label="Actions">
<MoreVertSVGIcon />
- </AppBarAction>
+ </Button>
</AppBar>
))}
</Container>
npx @react-md/codemod v5-to-v6/app-bar/update-app-bar-props
The following props have changed for the AppBar component:
component was renamed to asfixedElevation was renamed to disableElevationfixed was removed in favor of the new position propflexWrap and inheritColor were removed since they are no longer needed function Example() {
return (
<>
- <AppBar component="div">Hello</AppBar>
- <AppBar fixed={true}>Hello</AppBar>
- <AppBar fixed fixedElevation={false}>
- Hello
- </AppBar>
- <AppBar fixed={false} fixedElevation>
- Hello
- </AppBar>
- <AppBar flexWrap inheritColor>
+ <AppBar as="div">Hello</AppBar>
+ <AppBar position="fixed">Hello</AppBar>
+ <AppBar position="fixed" disableFixedElevation>
Hello
</AppBar>
+ <AppBar>Hello</AppBar>
+ <AppBar>Hello</AppBar>
</>
);
}
npx @react-md/codemod v5-to-v6/app-bar/update-app-bar-title-props
The following props have changed for the AppBarTitle component:
noWrap was removed in favor of the new textOverflow propkeyline is no longer a boolean function Example() {
return (
<>
- <AppBarTitle noWrap>Hello</AppBarTitle>
- <AppBarTitle noWrap={true}>Hello</AppBarTitle>
- <AppBarTitle noWrap={false}>Hello</AppBarTitle>
- <AppBarTitle keyline>Hello</AppBarTitle>
- <AppBarTitle keyline={true}>Hello</AppBarTitle>
- <AppBarTitle keyline={false}>Hello</AppBarTitle>
+ <AppBarTitle textOverflow="nowrap">Hello</AppBarTitle>
+ <AppBarTitle textOverflow="nowrap">Hello</AppBarTitle>
+ <AppBarTitle>Hello</AppBarTitle>
+ <AppBarTitle keyline="nav">Hello</AppBarTitle>
+ <AppBarTitle keyline="nav">Hello</AppBarTitle>
+ <AppBarTitle>Hello</AppBarTitle>
</>
);
}
The AutoComplete has a completely new API and has been renamed to Autocomplete. It
is recommended to check out the Autocomplete Demos to see
how to use the new API.
The main breaking changes are:
data prop was renamed to optionsvalue prop has been renamed to query since the value is now the
selected option(s)filter prop no longer accepts string values ("case-insensitive",
"fuzzy", "none") and instead should always be a filter function
"none" filter can be replaced with noopAutocompleteFilter from @react-md/core/autocomplete/defaults"case-insensitive" filter can be replaced with
defaultAutocompleteFilter from @react-md/core/autocomplete/defaults or
caseInsensitiveSearch from @react-md/core/searching/caseInsensitive"fuzzy" filter can be replaced with fuzzySearch from @react-md/core/searching/fuzzyfilter function now provides a single argument instead of multiple so
the query and data must be destructured.filterOptions and filterOnNoValue props were removed in favor of the
custom filter functionhighlight, highlightRepeating, highlightStyle, and highlightClassName props
were removed since highlighting is no longer supported. See the Highlights example
for a way to add highlights backlabelKey, valueKey, omitKeys, getResultId, getResultLabel, and
getResultValue props have been removed. Use getOptionLabel and
getOptionProps insteadbeforeResultsChildren and afterResultsChildren have been removed in favor
of just providing the custom children insteadautoComplete prop has been removed and only supports the "list" or
"none" behavior. Set the filter prop to noopAutocompleteFilter to
enable the "none" behavior.clearOnAutoComplete prop has been removed in favor of setting
updateQueryOnSelect to "clear"onAutocomplete prop has been removed in favor of controlling the value
or the onValueChange propdisableShowOnFocus prop has been removedlistboxProps:npx @react-md/codemod v5-to-v6/autocomplete/update-simple-props
This codemod will attempt to fix all the breaking changes and add TODOs for all the manual steps.
+// TODO: Ensure the `Autocomplete` options are strings or add the `getOptionLabel` prop
import { type ReactElement, useState } from "react";
-import { AutoComplete } from "react-md";
+import { Autocomplete } from "react-md";
const fruits = [
"Apple",
"Apricot",
"Banana",
"Blueberry",
"Cranberry",
"Kiwi",
"Peach",
"Plum",
"Strawberry",
];
export default function CustomFilterFunction(): ReactElement {
const [value, setValue] = useState("");
return (
<>
- <AutoComplete
+ <Autocomplete
id="simple-autocomplete-1"
label="Case insensitive"
placeholder="Apple"
- value={value}
+ query={value}
onChange={(event) => {
setValue(event.currentTarget.value)
}}
- data={fruits}
+ options={fruits}
- filter={(query, data, options) => {
+ filter={({ query, list: data, ...options }) => {
return data;
}}
- clearOnAutoComplete
+ updateQueryOnSelect="clear"
- onAutoComplete={({ value, index, result, dataIndex, filteredData }) => {
+ onValueChange={(value) => {
// do something
}}
- listboxStyle={{ color: "red" }}
- listboxClassName="custom-class-name"
- listboxWidth="auto"
- anchor={BELOW_CENTER_ANCHOR}
- vwMargin={20}
- vhMargin={20}
- xMargin={12}
- yMargin={12}
- closeOnResize={false}
- transformOrigin={false}
- closeOnScroll={false}
- preventOverlap={false}
- disableSwapping={false}
- disableVHBounds={false}
+ listboxProps={{
+ style: { color: "red" },
+ className: "custom-class-name",
+ width: "auto",
+ anchor: BELOW_CENTER_ANCHOR,
+ vwMargin: 20,
+ vhMargin: 20,
+ xMargin: 12,
+ yMargin: 12,
+ closeOnResize: false,
+ transformOrigin: false,
+ closeOnScroll: false,
+ preventOverlap: false,
+ disableSwapping: false,
+ disableVHBounds: false,
+ }}
/>
</>
);
}
No breaking changes!
npx @react-md/codemod v5-to-v6/badge/remove-badge-container
The BadgeContainer was removed and custom styles must be used instead.
import type { ReactElement } from "react";
-import {
- Badge,
- BadgeContainer,
- Button,
- NotificationsSVGIcon,
- Typography,
-} from "react-md";
+import { Badge, Button, NotificationsSVGIcon, Typography } from "react-md";
import { COPYRIGHT } from "constants/unicode";
@@ -14,15 +8,27 @@ import styles from "./CustomizingBadges.module.scss";
export default function CustomizingBadges(): ReactElement {
return (
<>
- <BadgeContainer className={styles.container}>
+ <span
+ className={styles.container}
+ style={{
+ display: "inline-flex",
+ position: "relative",
+ }}
+ >
{/* since the badge is presentational, don't add the `aria-describedby` value */}
<Typography>Some amazing product</Typography>
<Badge id="copyright-badge" theme="clear">
{COPYRIGHT}
</Badge>
- </BadgeContainer>
+ </span>
{/* this is _basically_ the `BadgedButton` component except with an extra `<span>` */}
- <BadgeContainer className={styles.custom}>
+ <span
+ className={styles.custom}
+ style={{
+ display: "inline-flex",
+ position: "relative",
+ }}
+ >
<Button
id="custom-badged-button"
aria-describedby="custom-badged-button-badge"
@@ -31,7 +37,7 @@ export default function CustomizingBadges(): ReactElement {
<NotificationsSVGIcon />
</Button>
<Badge id="custom-badged-button-badge">8</Badge>
- </BadgeContainer>
+ </span>
</>
);
}
npx @react-md/codemod v5-to-v6/badge/update-badge
The BadgedButton was removed and instead just use the Button and Badge
components together.
import { type ReactElement } from "react";
-import { BadgedButton } from "react-md";
+import { Badge, Button, getIcon } from "react-md";
import { NotificationsSVGIcon } from "@react-md/material-icons";
import styles from "./SimpleExamples.module.scss";
@@ -7,16 +7,24 @@ import styles from "./SimpleExamples.module.scss";
export default function Example(): ReactElement {
return (
<>
- <BadgedButton id="badged-button-1" className={styles.container}>
- 3
- </BadgedButton>
- <BadgedButton
+ <Button
+ id="badged-button-1"
+ className={styles.container}
+ aria-label="Notifications"
+ buttonType="icon"
+ >
+ {getIcon("notification")}
+ <Badge>3</Badge>
+ </Button>
+ <Button
id="badged-button-2"
className={styles.container}
- buttonChildren={<NotificationsSVGIcon />}
+ aria-label="Notifications"
+ buttonType="icon"
>
- 7
- </BadgedButton>
+ <NotificationsSVGIcon />
+ <Badge>7</Badge>
+ </Button>
</>
);
}
In addition, the BadgeTheme was updated "default" to be "greyscale". The
codemod will insert a temporary _toBadgeTheme helper when the theme is not
a string.
import type { ReactElement } from "react";
-import type { BadgeTheme } from "react-md";
-import { BadgedButton } from "react-md";
+import { Badge, BadgeTheme, Button, getIcon } from "react-md";
import styles from "./SimpleExamples.module.scss";
@@ -10,15 +9,23 @@ export default function ThemedBadges(): ReactElement {
return (
<>
{themes.map((theme) => (
- <BadgedButton
+ <Button
key={theme}
id={`badged-button-${theme}`}
- badgeTheme={theme}
className={styles.container}
+ aria-label="Notifications"
+ buttonType="icon"
>
- {theme.length}
- </BadgedButton>
+ {getIcon("notification")}
+ <Badge theme={_toBadgeTheme(theme)}>{theme.length}</Badge>
+ </Button>
))}
</>
);
}
+
+function _toBadgeTheme(
+ theme: BadgeTheme | "default" | undefined,
+): BadgeTheme | undefined {
+ return theme === "default" ? "greyscale" : theme;
+}
npx @react-md/codemod v5-to-v6/button/remove-unused-props
The Button no longer supports the ripple props.
import { Button } from "react-md";
import styles from "./styles.module.scss";
export default function Example() {
return (
<Button
onClick={() => {
// do something
}}
disableRipple
- disableProgrammaticRipple
- disableEnterClick
- disableSpacebarClick
- disablePressedFallback
- enablePressedAndRipple
- rippleTimeout={100}
- rippleClassName={styles.ripple}
- rippleClassNames={{ enter: "", exit: "" }}
- rippleContainerClassName="example"
>
Hello, world!
</Button>
);
}
npx @react-md/codemod v5-to-v6/button/rename-button-theme-class-names
The buttonThemeClassNames utility function was renamed to button.
import cn from "classnames";
import type { ReactElement } from "react";
import type { ButtonThemeProps, LinkProps } from "react-md";
-import { Link, buttonThemeClassNames } from "react-md";
+import { Link, button } from "react-md";
import styles from "./WithButtonStyles.module.scss";
@@ -17,7 +17,7 @@ function LinkStyledButton({
return (
<Link
{...props}
- className={buttonThemeClassNames({
+ className={button({
disabled,
theme,
themeType,
npx @react-md/codemod v5-to-v6/button/rename-fab
The FAB was renamed to FloatingActionButton.
import { ReactNode, ReactElement } from "react";
-import { FAB, FABProps, FABPosition } from "react-md";
+import {
+ FloatingActionButton,
+ FloatingActionButtonProps,
+ FloatingActionButtonPosition,
+} from "react-md";
-interface CustomProps extends FABProps {
- altPosition?: FABPosition;
+interface CustomProps extends FloatingActionButtonProps {
+ altPosition?: FloatingActionButtonPosition;
children: ReactNode;
}
@@ -10,8 +14,8 @@ export function Custom(props: CustomProps): ReactElement {
const { children, altPosition, ...remaining } = props;
return (
- <FAB {...remaining} position={altPosition}>
+ <FloatingActionButton {...remaining} position={altPosition}>
{children}
- </FAB>
+ </FloatingActionButton>
);
}
npx @react-md/codemod v5-to-v6/button/rename-unstyled-button
The UnstyledButton component was renamed to ButtonUnstyled.
@@ -1,4 +1,4 @@
-import { Button, UnstyledButton } from "react-md";
+import { Button, ButtonUnstyled } from "react-md";
export default function Example() {
return (
@@ -10,21 +10,21 @@ export default function Example() {
>
Hello!
</Button>
- <UnstyledButton
+ <ButtonUnstyled
onClick={() => {
// do something else
}}
>
Unstyled 1
- </UnstyledButton>
- <UnstyledButton
+ </ButtonUnstyled>
+ <ButtonUnstyled
onClick={() => {
// do something else
}}
className="example-class-name"
>
Unstyled 2
- </UnstyledButton>
+ </ButtonUnstyled>
</>
);
}
npx @react-md/codemod v5-to-v6/card/card-actions-to-card-footer
The CardActions component was renamed to CardFooter and the align prop
was renamed to justify.
import { type ReactElement } from "react";
-import { CardActions } from "react-md";
+import { CardFooter } from "react-md";
export default function Example(): ReactElement {
return (
- <CardActions align="start" className="example">
+ <CardFooter justify="start" className="example">
Content
- </CardActions>
+ </CardFooter>
);
}
npx @react-md/codemod v5-to-v6/card/remove-deprecated-card-props
The deprecated raiseable prop was removed in favor of raisable.
export default function Example() {
return (
<>
- <Card raiseable>Content</Card>
+ <Card raisable>Content</Card>
<Card raisable>Content</Card>
<Card>Content</Card>
</>
npx @react-md/codemod v5-to-v6/card/update-card-content-props
The CardContent component updated the following props:
disableExtraPadding was renamed to disableLastChildPaddingdisableParagraphMargin was removed return (
<>
<CardContent>Content</CardContent>
- <CardContent disableParagraphMargin>Content</CardContent>
- <CardContent disableExtraPadding>Content</CardContent>
+ <CardContent>Content</CardContent>
+ <CardContent disableLastChildPadding>Content</CardContent>
<CardContent disablePadding disableSecondaryColor className="custom">
Content
</CardContent>
npx @react-md/codemod v5-to-v6/card/update-card-header-props
The CardHeader updated the following props:
align was removedbeforeChildren was renamed to beforeAddonafterChildren was renamed to afterAddoncontentClassName was removed in favor of the new contentProps return (
<>
<CardHeader
- align="top"
- beforeChildren={<p>Hello</p>}
- afterChildren={<Typography>World!</Typography>}
- contentClassName="content-classname"
+ beforeAddon={<p>Hello</p>}
+ afterAddon={<Typography>World!</Typography>}
+ contentProps={{
+ className: "content-classname",
+ }}
>
Content
</CardHeader>
- <CardHeader contentClassName={styles.className}>Content</CardHeader>
- <CardHeader contentClassName={cn(styles.className, "another")}>
+ <CardHeader
+ contentProps={{
+ className: styles.className,
+ }}
+ >
+ Content
+ </CardHeader>
+ <CardHeader
+ contentProps={{
+ className: cn(styles.className, "another"),
+ }}
+ >
Content
</CardHeader>
</>
npx @react-md/codemod v5-to-v6/card/update-card-subtitle-props
The CardSubtitle updated the following props:
noWrap was removed in favor of the new textOverflow propdisableSecondaryColor was removed in favor of the new textColor prop }: ExampleProps): ReactElement {
return (
<>
- <CardSubtitle noWrap>{children}</CardSubtitle>
- <CardSubtitle disableSecondaryColor>{children}</CardSubtitle>
+ <CardSubtitle textOverflow="nowrap">{children}</CardSubtitle>
+ <CardSubtitle textColor={null}>{children}</CardSubtitle>
<CardSubtitle
- noWrap={noWrap}
- disableSecondaryColor={disableSecondaryColor}
+ textOverflow={noWrap ? "nowrap" : undefined}
+ textColor={disableSecondaryColor ? null : undefined}
>
{children}
</CardSubtitle>
npx @react-md/codemod v5-to-v6/card/update-card-title-props
The CardTitle updated the following props:
noWrap was removed in favor of the new textOverflow propsmall was removed in favor of setting the type Typography prop return (
<>
<CardTitle>{children}</CardTitle>
- <CardTitle small>{children}</CardTitle>
- <CardTitle small={false}>{children}</CardTitle>
- <CardTitle noWrap>{children}</CardTitle>
- <CardTitle noWrap={false}>{children}</CardTitle>
- <CardTitle small noWrap>
+ <CardTitle type="subtitle-1">{children}</CardTitle>
+ <CardTitle>{children}</CardTitle>
+ <CardTitle textOverflow="nowrap">{children}</CardTitle>
+ <CardTitle>{children}</CardTitle>
+ <CardTitle type="subtitle-1" textOverflow="nowrap">
{children}
</CardTitle>
</>
npx @react-md/codemod v5-to-v6/chip/update-chip-props
The Chip renamed the noninteractable prop to noninteractive.
export default function Example(): ReactElement {
return (
<>
- <Chip noninteractable>Hello!</Chip>
+ <Chip noninteractive>Hello!</Chip>
</>
);
}
npx @react-md/codemod v5-to-v6/dialog/remove-nested-dialog-context-provider
The NestedDialogContextProvider has been removed and is no longer required.
IconProvider,
type MenuConfiguration,
MenuConfigurationProvider,
- NestedDialogContextProvider,
StatesConfig,
type StatesConfigProps,
UserInteractionModeListener,
@@ -100,7 +99,7 @@ export function Configuration({
menuConfiguration,
}: ConfigurationProps): ReactElement {
return (
<Dir defaultDir={defaultDir}>
<AppSizeListener
defaultSize={defaultSize}
onChange={onAppResize}
@@ -110,7 +109,7 @@ export function Configuration({
desktopMinWidth={desktopMinWidth}
desktopLargeMinWidth={desktopLargeMinWidth}
>
- <NestedDialogContextProvider>
+ <>
<UserInteractionModeListener>
<StatesConfig
disableRipple={disableRipple}
@@ -129,8 +128,8 @@ export function Configuration({
</HoverModeProvider>
</StatesConfig>
</UserInteractionModeListener>
- </NestedDialogContextProvider>
+ </>
</AppSizeListener>
</Dir>
);
}
npx @react-md/codemod v5-to-v6/dialog/update-dialog-props
The Dialog and FixedDialog components have the following prop changes:
forceContainer has been removed since there is always a container element
nowoverlay has been renamed to disableOverlayoverlayStyle, overlayClassName, and overlayHidden have been removed in
favor of the overlayProps where overlayHidden is renamed to noOpacitycontainerStyle and containerClassName have been removed in favor of
containerPropscomponent has been removed and only supports being rendered as a "div"disableNestedDialogFixes has been removed since it is no longer neededdefaultFocus has been removed and default focus must be set manually
instead using autoFocus on a focusable element or custom logicdisableFocusContainer, disableFocusOnMount, disableFocusOnUnmount, and
disableTabFocusWrap have been removed in favor of the isFocusTypeDisabled functiondisableFocusCache, disableFocusOnMountScroll, and unmountFocusFallback
have been removed+// A `Dialog` set the `defaultFocus` but that is no longer supported. Enable the `autoFocus` prop on the target element instead.
import { ReactElement, useRef } from "react";
import {
Button,
FixedDialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
Typography,
useToggle,
} from "react-md";
export default function Demo(): ReactElement {
const [visible, enable, disable] = useToggle(false);
const fixedTo = useRef<HTMLButtonElement>(null);
return (
@@ -19,37 +20,31 @@ export default function Demo(): ReactElement {
Show Dialog
</Button>
<FixedDialog
id="simple-dialog"
fixedTo={fixedTo}
visible={visible}
onRequestClose={disable}
aria-labelledby="dialog-title"
- forceContainer
- defaultFocus="last"
- disableFocusContainer
- disableFocusCache
- disableFocusOnMount
- disableTabFocusWrap
- disableFocusOnMountScroll
- disableFocusOnUnmount
- unmountFocusFallback
- disableNestedDialogFixes
- component="nav"
- overlay={false}
- overlayHidden
- overlayStyle={{ color: "red" }}
- overlayClassName="custom-overlay-class"
- containerStyle={{ backgroundColor: "orange" }}
- containerClassName="custom-container-class"
+ disableOverlay
options={{ xMargin: 12, yMargin: 12 }}
- getOptions={() => ({
+ getFixedPositionOptions={() => ({
vhMargin: 20,
vwMargin: 20,
})}
+ overlayProps={{
+ noOpacity: true,
+ style: { color: "red" },
+ className: "custom-overlay-class",
+ }}
+ containerProps={{
+ style: { backgroundColor: "orange" },
+ className: "custom-container-class",
+ }}
+ isFocusTypeDisabled={() => true}
>
<DialogHeader>
<DialogTitle id="dialog-title">Simple Dialog</DialogTitle>
</DialogHeader>
<DialogContent>
<Typography margin="none">This is some text in a dialog.</Typography>
</DialogContent>
<DialogFooter>
npx @react-md/codemod v5-to-v6/divider/vertical-divider-to-divider
The VerticalDivider component was removed in favor of just enabling the
vertical prop on the Divider.
import { type ReactElement } from "react";
-import { VerticalDivider } from "react-md";
+import { Divider } from "react-md";
export default function Example(): ReactElement {
return (
<>
- <VerticalDivider />
- <VerticalDivider maxHeight={0.8} />
- <VerticalDivider maxHeight={0.8} className="custom-class-name" />
+ <Divider vertical />
+ <Divider vertical />
+ <Divider className="custom-class-name" vertical />
</>
);
}
In addition, the somewhat undocumented useVerticalDividerHeight hook was removed
and there is no replacement.
+// TODO: The following react-md imports have been removed from the library and must be manually removed from the rest of the file: VerticalDividerHeight, VerticalDividerHookOptions, useVerticalDividerHeight
import { type ReactElement } from "react";
-import {
- VerticalDividerHeight,
- VerticalDividerHookOptions,
- useVerticalDividerHeight,
-} from "react-md";
type H = VerticalDividerHeight;
type O = VerticalDividerHookOptions;
export default function Example(): ReactElement {
const { ref, style } = useVerticalDividerHeight({
maxHeight: 0.8,
});
return <div style={style} ref={ref} vertical />;
}
npx @react-md/codemod v5-to-v6/expansion-panel/update-expansion-panel-props
The ExpansionPanel updated the following props:
raiseable was renamed to raisabledisablePadding was renamed to disableContentPaddingheader was renamed to headerChildrencustomHeader was renamed to header export function SimpleExample(): ReactElement {
return (
<>
- <ExpansionPanel raiseable />
- <ExpansionPanel disablePadding />
- <ExpansionPanel disableLastParagraphMargin />
- <ExpansionPanel disableSecondaryColor />
- <ExpansionPanel disableSecondaryColor={false} />
- <ExpansionPanel disableSecondaryColor={flag || another} />
+ <ExpansionPanel raisable />
+ <ExpansionPanel disableContentPadding />
+ <ExpansionPanel />
+ <ExpansionPanel />
+ <ExpansionPanel
+ contentProps={{
+ disableSecondaryColor: false,
+ }}
+ />
+ <ExpansionPanel
+ contentProps={{
+ disableSecondaryColor: flag || another,
+ }}
+ />
</>
);
}
export function HeaderExample(): ReactElement {
return (
<>
- <ExpansionPanel header="Some Content">And some more</ExpansionPanel>
- <ExpansionPanel header={<Typography>Some JSX</Typography>}>
+ <ExpansionPanel headerChildren="Some Content">
And some more
</ExpansionPanel>
- <ExpansionPanel customHeader={<ExpansionPanelHeader />}>
- Content
+ <ExpansionPanel headerChildren={<Typography>Some JSX</Typography>}>
+ And some more
</ExpansionPanel>
+ <ExpansionPanel header={<ExpansionPanelHeader />}>Content</ExpansionPanel>
</>
);
}
npx @react-md/codemod v5-to-v6/expansion-panel/use-panels-to-use-expansion-panel
The usePanels hook was renamed to useExpansionPanels with a new API:
onKeyDown event handler is no longer returned since the ExpansionList
no longer requires itgetPanelProps instead of providing a
count of panel props to generatepreventAllClosed was renamed to preventAllCollapsedidPrefix was renamed to baseIdexpandedIds are now a ReadonlySet<string> instead of string[]@@ -6,7 +6,7 @@ import {
Fieldset,
Grid,
useChecked,
- usePanels,
+ useExpansionPanels,
} from "react-md";
interface Props {
@@ -25,19 +25,19 @@ function Example({
defaultExpandedIndex = multiple ? [1, 2] : 0;
}
- const [panels, onKeyDown] = usePanels({
- count: 3,
- idPrefix: "configuring-panels",
+ const { getPanelProps: getPanelProps } = useExpansionPanels({
+ baseId: "configuring-panels",
multiple,
- preventAllClosed,
+ preventAllCollapsed: preventAllClosed,
+
// this will be considered `0` if the `preventAllClosed` option is enabled
// but still `undefined`
defaultExpandedIndex,
});
return (
- <ExpansionList onKeyDown={onKeyDown}>
- <ExpansionPanel {...panels[0]} header="Panel 1">
+ <ExpansionList>
+ <ExpansionPanel {...getPanelProps(0)} header="Panel 1">
Nam lorem est, porta id tincidunt et, consectetur in nulla. Morbi cursus
at massa a feugiat. Mauris eu convallis elit, ac mollis metus. Quisque
pulvinar ante libero, ut laoreet dolor bibendum volutpat. In diam purus,
@@ -46,7 +46,7 @@ function Example({
ultricies lacus in massa finibus gravida. Maecenas turpis libero,
fringilla nec sodales sed, lacinia eget libero.
</ExpansionPanel>
- <ExpansionPanel {...panels[1]} header="Panel 2">
+ <ExpansionPanel {...getPanelProps(1)} header="Panel 2">
Aenean rhoncus tristique fringilla. Phasellus ac libero porta, iaculis
quam quis, porta nibh. Maecenas laoreet dignissim magna quis ultricies.
Vivamus ut blandit nisl. Curabitur vel turpis vulputate, mollis ante in,
@@ -54,7 +54,7 @@ function Example({
finibus lectus. Donec eleifend felis odio, vitae gravida purus ornare
sed.
</ExpansionPanel>
- <ExpansionPanel {...panels[2]} header="Panel 3">
+ <ExpansionPanel {...getPanelProps(2)} header="Panel 3">
Donec lacinia ut sem vitae molestie. Nam placerat tristique facilisis.
Aliquam iaculis augue eget mollis fermentum. Morbi mattis ultricies
lacinia. Fusce vitae commodo nisl. Donec congue arcu ut porta feugiat.
npx @react-md/codemod v5-to-v6/form/replace-with-message-components
The TextFieldWithMessage, TextAreaWithMessage, and PasswordWithMessage components
have been removed and instead the default behavior for the TextField,
TextArea, and Password components.
import { ReactElement, useCallback, useMemo, useState } from "react";
import {
Button,
ErrorChangeHandler,
Form,
GetErrorMessage,
- PasswordWithMessage,
- TextAreaWithMessage,
- TextFieldWithMessage,
+ Password,
+ TextArea,
+ TextField,
defaultGetErrorMessage,
useTextField,
} from "react-md";
@@ -38,94 +38,90 @@
return (
<Form>
- <TextFieldWithMessage
+ <TextField
{...nameFieldProps}
label="Name"
placeholder="John Doe"
name="name"
/>
- <TextFieldWithMessage
+ <TextField
{...dateFieldProps}
label="Date *"
placeholder="01/01/2020"
name="date"
/>
- <TextAreaWithMessage
+ <TextArea
{...descriptionFieldProps}
label="Description"
placeholder="Something amazing."
name="description"
/>
- <TextAreaWithMessage
+ <TextArea
{...description2FieldProps}
label="Description 2 *"
placeholder="Something amazing."
name="description2"
/>
- <PasswordWithMessage
+ <Password
{...passwordProps}
label="Password *"
name="password"
/>
<Button
type="submit"
disabled={errored}
theme="primary"
themeType="outline"
>
Submit
</Button>
</Form>
);
}
npx @react-md/codemod v5-to-v6/form/update-text-field-container-props
The TextFieldContainer updated a few props which affects the TextField,
TextArea, Password, and Select components:
leftChildren and rightChildren props were renamed to leftAddon and
rightAddonisLeftAddon and isRightAddon props were renamed to
disableLeftAddonStyles and disableRightAddonStylesstretch prop was removed export default function TextFieldContainerProps(): ReactElement {
const [value, setValue] = useState("");
const isLeftAddon = true;
const isRightAddon = false;
return (
<>
<TextField
label="Label"
- leftChildren={<span>Hello!</span>}
- stretch
- rightChildren={<span>World!</span>}
- isLeftAddon
- isRightAddon={false}
+ leftAddon={<span>Hello!</span>}
+ rightAddon={<span>World!</span>}
+ disableRightAddonStyles
/>
<TextArea
- stretch
label="Label"
- leftChildren={<span>Hello!</span>}
- rightChildren={<span>World!</span>}
- isLeftAddon={isLeftAddon}
- isRightAddon
+ leftAddon={<span>Hello!</span>}
+ rightAddon={<span>World!</span>}
+ disableLeftAddonStyles={!isLeftAddon}
/>
<Password
label="Label"
- leftChildren={<span>Hello!</span>}
- rightChildren={<span>World!</span>}
- stretch
+ leftAddon={<span>Hello!</span>}
+ rightAddon={<span>World!</span>}
/>
<Select
id="simple-select-example"
label="A Label"
placeholder="Choose..."
name="select"
options={states.map(({ abbreviation, name }) => ({
label: name,
value: abbreviation,
}))}
value={value}
onChange={(value) => setValue(value)}
- leftChildren={<span>Hello!</span>}
- rightChildren={<span>World!</span>}
- isLeftAddon={false}
- isRightAddon={false}
- stretch
+ leftAddon={<span>Hello!</span>}
+ rightAddon={<span>World!</span>}
+ disableLeftAddonStyles
+ disableRightAddonStyles
/>
</>
);
}
npx @react-md/codemod v5-to-v6/form/update-use-text-field-api
The useTextField and useNumberField hooks have updated their api slightly:
validateOnChange option was renamed to validationType and no longer
supports boolean valuestrue would now be "change"false would now be []getErrorMessage and isErrored options also renamed this option, but
is not handled by the codemodgetErrorIcon option now provides a single options object instead of multiple argumentsdefaultGetErrorIcon util matches this as well import { defaultGetErrorIcon, useNumberField, useTextField } from "react-md";
+export function ExampleDiff(): null {
- const [, textFieldProps] = useTextField({
+ const { fieldProps: textFieldProps } = useTextField({
name: "field",
- validateOnChange: true,
- getErrorIcon: (errorMessage, error, errorIcon) => {
+ validationType: "change",
+ getErrorIcon: (options) => {
+ const { error, errorIcon, errorMessage } = options;
+
if (errorMessage === "Hello") {
return errorIcon;
}
- return defaultGetErrorIcon(errorMessage, error, errorIcon);
+ return defaultGetErrorIcon({
+ error,
+ errorIcon,
+ errorMessage,
+ });
},
});
- const [numberValue, numberFieldProps, { reset, setState }] = useNumberField({
- name: "field2",
- validateOnChange: false,
- getErrorIcon: (errorMessage, error, errorIcon) => {
+ const {
+ value: numberValue,
+ fieldProps: numberFieldProps,
+ reset,
+ setState,
+ } = useNumberField({
+ name: "field",
+ validationType: [],
+ getErrorIcon: (options) => {
+ const { error, errorIcon, errorMessage } = options;
+
if (errorMessage === "Hello") {
return errorIcon;
}
- return defaultGetErrorIcon(errorMessage, error, errorIcon);
+ return defaultGetErrorIcon({
+ error,
+ errorIcon,
+ errorMessage,
+ });
},
});
return null;
}
npx @react-md/codemod v5-to-v6/form/update-select-api
The Select component has been updated to mimic the native <select> API meaning:
Select no longer accepts an options prop and instead each option
should be rendered as a child with the Option componentlabelKey, valueKey, getOptionId, getOptionLabel,
getOptionValue, and isOptionDisabled props have been removed since they are
invalid or should be provided to the Option component insteaddisableMovementChange prop was removed since it was bad for
accessibility to update the value when the user moves keyboard focuslabelStyle and labelClassName props have been removed in favor of
labelPropsdisplayLabelStyle and displayLabelClassName props have been removed
in favor of the new selectedOptionPropsgetDisplayLabel prop has been removed in favor of
selectedOptionProps.childrenanchor, listboxWidth, listboxStyle, listboxClassName,
closeOnScroll, closeOnResize, and positionOptions have been removed in
favor of menuPropsdisableLeftAddon has been renamed to disableOptionAddononChange prop has been updated to provide the
ChangeEvent<HTMLInputElement> instead of the current value. The
event.currentTarget.value should be used instead and will can be strictly
typed for typescript usersThe codemod will attempt to convert the select API, but there were too many edge cases so I gave up. You'll have to manually handle most of the updates.
import states from "constants/states";
import { type ReactElement, useState } from "react";
-import { Select } from "react-md";
+import { Option, Select } from "react-md";
export default function SimpleSelectExample(): ReactElement {
const [value, setValue] = useState("");
return (
<Select
id="simple-select-example"
label="A Label"
placeholder="Choose..."
name="select"
- options={states.map(({ abbreviation, name }) => ({
- label: name,
- value: abbreviation,
- }))}
value={value}
- onChange={(value) => setValue(value)}
- />
+ onChange={(event) => {
+ const value = event.currentTarget.value;
+ setValue(value);
+ }}
+ >
+ {states.map(({ abbreviation, name }) => (
+ <Option key={abbreviation} value={abbreviation}>
+ {name}
+ </Option>
+ ))}
+ </Select>
);
}
npx @react-md/codemod v5-to-v6/form/update-file-input-props
The FileInput removed the disableIconSpacing prop since it is no longer required.
import { type ReactElement } from "react";
import { FileInput } from "react-md";
export default function SimpleFileInput(): ReactElement {
return (
<>
<FileInput />
- <FileInput disableIconSpacing />
- <FileInput disableIconSpacing={someFlag} />
- <FileInput disableIconSpacing={false} />
+ <FileInput />
+ <FileInput />
+ <FileInput />
</>
);
}
npx @react-md/codemod v5-to-v6/form/update-slider-and-range-slider
There were a few breaking changes around the Slider and RangeSlider components:
Slider only requires the value and setValue props removing
minimum, maximum, increment, incrementJump, decrement,
decrementJump, and persist.RangeSlider was removed since all the functionality has been merged
with the Slider componentbaseId was removed in favor of id, thumbProps.id, thumb1Props.id,
thumb2Props.id, etc.label and labelProps props have been removed in favor of using an
aria-labelledby for a Fieldset + LegendanimationDuration prop was removedIn addition, the useSlider + useRangeSlider hooks have updated their API to
match the new components:
useSlider and useRangeSlider only accept a single options argument
instead of an optional default value followed by an optional options objectuseSlider useRangeSlider return a single object of props to pass
to the Slider instead of an ordered tupleuseSlider and useRangeSlider no longer support the updateOn option
as the value is always updated immediatelyuseSlider and useRangeSlider no longer support an onChange callback The codemod is only able to handle the simple conversions of renaming
baseId -> id and removing unused props. The diff shown below is a "real
world" conversion with manual updates.
-import { type ReactElement } from "react";
-import { Slider, useSlider } from "react-md";
+import { type ReactElement, useId } from "react";
+import { Fieldset, Legend, Slider, useSlider } from "react-md";
export default function SimpleSlider(): ReactElement | null {
- const [value, controls] = useSlider(20, { min: 0, max: 100 });
- const { setValue } = controls;
+ const legendId = useId();
+ const slider = useSlider({
+ min: 0,
+ max: 100,
+ defaultValue: 20,
+ });
+ const { value, setValue } = slider;
return (
- <>
- <Slider baseId="slider-1-id" label="Horizontal" {...controls} />
- </>
+ <Fieldset>
+ <Legend id={legendId}>Horizontal</Legend>
+ <Slider id="slider-1-id" {...slider} aria-labelledby={legendId} />
+ </Fieldset>
);
}
-import { type ReactElement } from "react";
-import { RangeSlider, useRangeSlider } from "react-md";
+import { type ReactElement, useId } from "react";
+import { Fieldset, Legend, Slider, useRangeSlider } from "react-md";
export default function SimpleSlider(): ReactElement | null {
- const [[minValue, maxValue], controls] = useRangeSlider([20, 60], { min: 0, max: 100 });
- const { setValue } = controls;
+ const legendId = useId();
+ const rangeSlider = useRangeSlider({
+ min: 0,
+ max: 100,
+ defaultValue: [20, 60],
+ });
+ const { rangeValue, setRangeValue: setValue } = rangeSlider;
+ const [minValue, maxValue] = rangeValue;
return (
- <>
- <Slider baseId="slider-1-id" label="Horizontal" {...controls} />
- </>
+ <Fieldset>
+ <Legend id={legendId}>Horizontal</Legend>
+ <Slider id="slider-1-id" {...rangeSlider} aria-labelledby={legendId} />
+ </Fieldset>
);
}
npx @react-md/codemod v5-to-v6/form/update-file-input-props
The Password component has the following breaking changes:
visibilityStyle, visibilityClassName, and onVisibilityClick props
were removed in favor of the visibilityProps objectdisableVisibility and rightChildren props were removed in favor of
just using a TextField insteadgetVisibilityIcon behavior was merged with the visibilityIcon prop
GetVisibilityIcon type was renamed to GetPasswordVisibilityIcon and
returns a boolean if the password type is visible(type) => type === "password" ? icon1 : icon, use
(isPassword) => isPassword ? icon1 : icon2+// TODO: Update `GetPasswordVisibilityIcon` references since it provides the `type === "password"` flag instead of the `type` now
import { type ReactElement } from "react";
-import { GetVisibilityIcon, Password } from "react-md";
+import { GetPasswordVisibilityIcon, Password } from "react-md";
-const getVisibilityIcon: GetVisibilityIcon = (type) =>
- type === "password" ? <span id="password-icon" /> : <span id="text-icon" />;
+// this is not auto-converted
+const getVisibilityIcon: GetPasswordVisibilityIcon = (isPassword) =>
+ isPassword ? <span id="password-icon" /> : <span id="text-icon" />;
export default function PasswordExample(): ReactElement {
return (
<>
<Password
id="example-password-field"
label="Password"
placeholder="Super secret password"
/>
<Password
id="example-password-field-2"
label="Password"
placeholder="Super secret password"
- visibilityStyle={{ opacity: 0.5 }}
- visibilityClassName="visibility-class-name"
- onVisibilityClick={(event) => {
- // do something
- }}
- />
+ visibilityProps={{
+ style: { opacity: 0.5 },
+ className: "visibility-class-name",
+
+ onClick: (event) => {
+ // do something
+ }
+ }} />
<Password
id="example-password-field-2"
label="Password"
placeholder="Super secret password"
- getVisibilityIcon={getVisibilityIcon}
+ visibilityIcon={getVisibilityIcon}
/>
</>
);
}
The Radio and Checkbox components no longer use a single icon and hackily
overlay the icon to show the checked/unchecked states.
inputStyle and inputClassName props have been removedtoggleStyle and toggleClassName props have been removeddisableIconOverlay has been removed since there is no longer an overlayinline prop has been removed since labels are always rendered inlinelabelDisabled prop has been removed in favor of labelProps={{ disabled: labelDisabled }}labelStyle and labelClassName props have been removed in favor of labelPropsThere is no longer a pre-built layout component so see the new Layout component documentation for the new setup. For convenience, here's a list of the changes:
Configuration component has been removed in favor of the
CoreProvidersLayout component has been removed in favor of building the layout manually
with the functionality provided by hooks:"toggleable", "floating", "clipped", and "full-height" variations"temporary" for all viewportsuseLayoutNavigation hook and LayoutTree. See the
Tree Main Navigation for example usage.Sheet + Navigation or Tree to replace
the LayoutNavigation componentLayoutMain has been renamed to Main and no longer handles transitionsLayoutAppBar no longer conditionally renders the LayoutNavToggle and
LayoutAppBarTitle and should only be used if the AppBar changes height. Use
the normal AppBar for all other casesLayoutAppBarTitle, LayoutChildren, LayoutCloseNavigationButton,
LayoutNavToggle, LayoutNavigation, LayoutNavigationHeader,
LayoutProvider, LayoutTree, and MiniLayoutWrapper components have been
removeddefaultMiniNavigationItemsRenderer and defaultNavigationItemRenderer
renderers have been removedgetLayoutType, isTemporaryLayout, isToggleableLayout,
isPersistentLayout, isFullHeightLayout, and isMiniLayout utils have been
removedHere's an example diff for converting the Configurable Layout Example from the v5 website.
A custom renderer must be passed to the Tree component if there
are non-tree items in the navigation tree like dividers or subheaders.
+import { AppBar } from "@react-md/core/app-bar/AppBar";
+import { AppBarTitle } from "@react-md/core/app-bar/AppBarTitle";
+import { Button } from "@react-md/core/button/Button";
+import { LayoutNav } from "@react-md/core/layout/LayoutNav";
+import { Main } from "@react-md/core/layout/Main";
+import { useExpandableLayout } from "@react-md/core/layout/useExpandableLayout";
+import { useLayoutTree } from "@react-md/core/layout/useLayoutTree";
+import { Sheet } from "@react-md/core/sheet/Sheet";
+import { Tree } from "@react-md/core/tree/Tree";
+import { type TreeData } from "@react-md/core/tree/types";
import {
HomeSVGIcon,
SecuritySVGIcon,
SettingsSVGIcon,
ShareSVGIcon,
SnoozeSVGIcon,
StarSVGIcon,
StorageSVGIcon,
} from "@react-md/material-icons";
import { type ReactElement, useState } from "react";
-import {
- DEFAULT_DESKTOP_LAYOUT,
- DEFAULT_LANDSCAPE_TABLET_LAYOUT,
- DEFAULT_PHONE_LAYOUT,
- DEFAULT_TABLET_LAYOUT,
- Layout,
- type LayoutNavigationTree,
- type SupportedPhoneLayout,
- type SupportedTabletLayout,
- type SupportedWideLayout,
- useLayoutNavigation,
-} from "react-md";
-import { ConfigurationForm } from "./ConfigurationForm";
import { CurrentChildren } from "./CurrentChildren";
-const navItems: LayoutNavigationTree = {
+const navItems: TreeData = {
"/": {
itemId: "/",
+ href: "/",
parentId: null,
children: "Home",
leftAddon: <HomeSVGIcon />,
},
"/route-1": {
itemId: "/route-1",
+ href: "/route-1",
parentId: null,
children: "Route 1",
leftAddon: <StarSVGIcon />,
},
"/divider-1": {
itemId: "/divider-1",
parentId: null,
divider: true,
isCustom: true,
},
"/route-2": {
itemId: "/route-2",
+ href: "/route-2",
parentId: null,
children: "Route 2",
leftAddon: <ShareSVGIcon />,
},
"/route-2-1": {
itemId: "/route-2-1",
+ href: "/route-2-1",
parentId: "/route-2",
children: "Route 2-1",
leftAddon: <SettingsSVGIcon />,
},
"/route-2-2": {
itemId: "/route-2-2",
+ href: "/route-2-2",
parentId: "/route-2",
children: "Route 2-2",
leftAddon: <StorageSVGIcon />,
},
"/route-2-3": {
itemId: "/route-2-3",
+ href: "/route-2-3",
parentId: "/route-2",
children: "Route 2-3",
leftAddon: <SecuritySVGIcon />,
},
"/route-3": {
itemId: "/route-3",
+ href: "/route-3",
parentId: null,
children: "Route 3",
leftAddon: <SnoozeSVGIcon />,
},
"/route-4": {
itemId: "/route-4",
+ href: "/route-4",
parentId: null,
children: "Route 4",
},
};
export default function Demo(): ReactElement {
- const [phoneLayout, setPhoneLayout] =
- useState<SupportedPhoneLayout>(DEFAULT_PHONE_LAYOUT);
- const [tabletLayout, setTabletLayout] = useState<SupportedTabletLayout>(
- DEFAULT_TABLET_LAYOUT
- );
- const [landscapeTabletLayout, setLandscapeTabletLayout] =
- useState<SupportedTabletLayout>(DEFAULT_LANDSCAPE_TABLET_LAYOUT);
- const [desktopLayout, setDesktopLayout] = useState<SupportedWideLayout>(
- DEFAULT_DESKTOP_LAYOUT
- );
- const [largeDesktopLayout, setLargeDesktopLayout] =
- useState<SupportedWideLayout>(DEFAULT_DESKTOP_LAYOUT);
-
const [selectedId, setSelectedId] = useState("/");
+ const tree = useLayoutTree({
+ navItems,
+ pathname: selectedId,
+ });
+ const {
+ temporary,
+ persistent,
+ temporaryNavProps,
+ navToggleProps,
+ appBarProps,
+ mainProps,
+ expandableNavProps,
+ } = useExpandableLayout({
+ pathname: selectedId,
+ fullHeightNav: "static",
+ });
return (
- <Layout
- id="configurable-layout"
- title="Configurable Layout Title"
- navHeaderTitle="Another Title"
- phoneLayout={phoneLayout}
- tabletLayout={tabletLayout}
- landscapeTabletLayout={landscapeTabletLayout}
- desktopLayout={desktopLayout}
- treeProps={{
- ...useLayoutNavigation(navItems, selectedId),
- onItemSelect: setSelectedId,
- }}
- // this is only required since I already have a main element due to the
- // documentation site's Layout component
- mainProps={{ component: "div" }}
- >
- <CurrentChildren route={selectedId} />
- <ConfigurationForm
- phoneLayout={phoneLayout}
- setPhoneLayout={setPhoneLayout}
- tabletLayout={tabletLayout}
- setTabletLayout={setTabletLayout}
- landscapeTabletLayout={landscapeTabletLayout}
- setLandscapeTabletLayout={setLandscapeTabletLayout}
- desktopLayout={desktopLayout}
- setDesktopLayout={setDesktopLayout}
- largeDesktopLayout={largeDesktopLayout}
- setLargeDesktopLayout={setLargeDesktopLayout}
- />
- </Layout>
+ <>
+ <AppBar {...appBarProps}>
+ <Button {...navToggleProps} />
+ <AppBarTitle>Configurable Layout Title</AppBarTitle>
+ </AppBar>
+ {persistent && (
+ <LayoutNav {...expandableNavProps}>
+ <AppBar>
+ <AppBarTitle>Another Title</AppBarTitle>
+ </AppBar>
+ <Tree
+ {...tree}
+ aria-label="Navigation"
+ toggleTreeItemSelection={setSelectedId}
+ />
+ </LayoutNav>
+ )}
+ {temporary && (
+ <Sheet {...temporaryNavProps}>
+ <Tree
+ {...tree}
+ aria-label="Navigation"
+ toggleTreeItemSelection={setSelectedId}
+ />
+ </Sheet>
+ )}
+ <Main {...mainProps}>
+ <CurrentChildren route={selectedId} />
+ </Main>
+ </>
);
}
npx @react-md/codemod v5-to-v6/link/update-link-props
The Link component updated the following props:
preventMaliciousTarget was removed since browsers implement this behavior
automatically nowflexCentered was renamed to flexcomponent prop was removed in favor of using the link utility function instead return (
<>
<Link href="#">Link 1</Link>
- <Link href="#" flexCentered>
+ <Link href="#" flex>
Link 1
</Link>
- <Link href="#" flexCentered={flexCentered}>
- Link 1
- </Link>
- <Link href="#" preventMaliciousTarget={false}>
+ <Link href="#" flex={flexCentered}>
Link 1
</Link>
+ <Link href="#">Link 1</Link>
</>
);
}
There are a few breaking changes for the list components:
SimpleListItem was removed in favor of using an <li> with the
ListItemChildren componentListItem and ListItemLink removed support for the ripple props
and updated the following props:
forceAddonWrap prop was removed in favor of the leftAddonForceWrap
and rightAddonForceWraptextChildren prop was renamed to disableTextChildrenListItemLink renamed component to as For Typescript users, the ListItemLink no longer allows
{ [key: string]: unknown } when the as component is provided.
npx @react-md/codemod v5-to-v6/list/update-list-item-props
Update textChildren prop:
import { type ReactElement } from "react";
import { ListItem } from "react-md";
export default function Example(): ReactElement {
return (
<>
- <ListItem textChildren>Hello, world!</ListItem>
- <ListItem textChildren={false}>Hello, world!</ListItem>
- <ListItem textChildren={true}>Hello, world!</ListItem>
- <ListItem textChildren={textChildren}>Hello, world!</ListItem>
+ <ListItem>Hello, world!</ListItem>
+ <ListItem disableTextChildren>Hello, world!</ListItem>
+ <ListItem>Hello, world!</ListItem>
+ <ListItem disableTextChildren={!textChildren}>Hello, world!</ListItem>
</>
);
}
Remove ripple props:
import { type ReactElement } from "react";
import { ListItem } from "react-md";
import styles from "./styles.module.scss";
export default function Example(): ReactElement {
return (
<ListItem
onClick={() => {
// do something
}}
disableRipple
- disableProgrammaticRipple
- disableEnterClick
- disableSpacebarClick
- disablePressedFallback
- enablePressedAndRipple
- rippleTimeout={100}
- rippleClassName={styles.ripple}
- rippleClassNames={{ enter: "", exit: "" }}
- rippleContainerClassName="example"
>
Hello, world!
</ListItem>
);
}
Rename component to as:
export default function Example(): ReactElement {
return (
<>
- <ListItemLink component={CustomLink} to="/some-path">
+ <ListItemLink as={CustomLink} to="/some-path">
Link 1
</ListItemLink>
- <ListItemLink component="a" href="/some-path">
+ <ListItemLink as="a" href="/some-path">
Link 2
</ListItemLink>
</>
Remove SimpleListItem:
import type { ReactElement } from "react";
import cn from "classnames";
-import { FavoriteSVGIcon, List, SimpleListItem } from "react-md";
+import { FavoriteSVGIcon, List, ListItemChildren } from "react-md";
import people from "./people";
@@ -12,33 +12,35 @@ export default function Demo(): ReactElement {
<Container>
<List>
{people.slice(0, 10).map((name) => (
- <SimpleListItem
+ <li
key={name}
className={cn(styles.item, styles.dotted, styles.margin)}
>
- {name}
- </SimpleListItem>
+ <ListItemChildren>{name}</ListItemChildren>
+ </li>
))}
</List>
<List className={styles.ordered}>
{people.slice(11, 20).map((name) => (
- <SimpleListItem key={name} className={cn(styles.item, styles.margin)}>
- {name}
- </SimpleListItem>
+ <li key={name} className={cn(styles.item, styles.margin)}>
+ <ListItemChildren>{name}</ListItemChildren>
+ </li>
))}
</List>
<List>
- <SimpleListItem
- primaryText={<span>Primary Text</span>}
- secondaryText={
- <span className={styles.secondary}>Secondary Text</span>
- }
- leftAddon={<FavoriteSVGIcon />}
- rightAddon={<img alt="" src="https://example.com/image.jpeg" />}
- rightAddonType="media"
- >
- Other children
- </SimpleListItem>
+ <li>
+ <ListItemChildren
+ primaryText={<span>Primary Text</span>}
+ secondaryText={
+ <span className={styles.secondary}>Secondary Text</span>
+ }
+ leftAddon={<FavoriteSVGIcon />}
+ rightAddon={<img alt="" src="https://example.com/image.jpeg" />}
+ rightAddonType="media"
+ >
+ Other children
+ </ListItemChildren>
+ </li>
</List>
</Container>
);
There are a few breaking changes for the media components since the new objectFit class name utility handles most use-cases now.
MediaContainer was renamed to ResponsiveItem
height and width props were removed in favor of the aspectRatio prop
aspectRatio={`${width}-${height}}auto prop was removed in favor of the responsive prop
auto -> responsive="auto" (this was the previous default)auto={false} -> responsive="manual"MediaContainerProps was renamed to ResponsiveItemPropsMediaOverlay was renamed to ResponsiveItemOverlay
MediaOverlayProps was renamed to ResponsiveItemOverlayPropsMediaOverlayPosition was renamed to ResponsiveItemOverlayPositionnpx @react-md/codemod v5-to-v6/media/update-media-components
import type { ReactElement } from "react";
-import { MediaContainer, MediaOverlay, Typography, type MediaOverlayPosition } from "react-md";
+import { ResponsiveItem, ResponsiveItemOverlay, Typography, ResponsiveItemOverlayPosition } from "react-md";
import styles from "./Container.module.scss";
-const positions: MediaOverlayPosition[] = [
+const positions: ResponsiveItemOverlayPosition[] = [
"top",
"right",
"bottom",
"left",
"middle",
"center",
"absolute-center",
];
export default function WithOverlay(): ReactElement {
return (
<>
{positions.map((position, i) => (
- <MediaContainer
+ <ResponsiveItem
key={position}
id={`overlay-container-${i}`}
- height={9}
- width={16}
className={styles.container}
- >
+ aspectRatio="16-9">
<img
src={`https://picsum.photos/800/800?image=43${i}`}
alt=""
aria-describedby={`overlay-container-overlay-${i}`}
/>
- <MediaOverlay
+ <ResponsiveItemOverlay
id={`overlay-container-overlay-${i}`}
position={position}
>
<Typography
type="headline-5"
margin="none"
align={
["left", "right", "center"].includes(position)
? "center"
: undefined
}
>
This is a random picture!
</Typography>
- </MediaOverlay>
- </MediaContainer>
+ </ResponsiveItemOverlay>
+ </ResponsiveItem>
))}
</>
);
}
The majority of the menu component changes were internal, but there are a few breaking changes that can mostly be automated through the codemod.
npx @react-md/codemod v5-to-v6/menu/replace-menu-item-link
The MenuItemLink was removed in favor of just using a ListItemLink with
role="menuitem". All the other transforms from
update-list-item-props must then be applied as well.
This codemod will convert to a ListItemLink and then handle the
ListItemLink migration.
import type { ReactElement } from "react";
-import { DropdownMenu, MenuItemLink, Link } from "react-md";
+import { DropdownMenu, Link, ListItemLink } from "react-md";
export default function SimpleExample(): ReactElement {
return (
<DropdownMenu buttonChildren="Options...">
- <MenuItemLink href="/link-1" component={Link}>
+ <ListItemLink href="/link-1" as={Link} role="menuitem">
Link 1
- </MenuItemLink>
- <MenuItemLink
+ </ListItemLink>
+ <ListItemLink
href="#link-2"
liProps={{ className: "container-class-name" }}
className="link-class-name"
- >
+ role="menuitem">
Link 2
- </MenuItemLink>
+ </ListItemLink>
</DropdownMenu>
);
}
npx @react-md/codemod v5-to-v6/menu/update-use-context-menu-api
The useContextMenu hook was updated for the latest Menu API and only supports
the following options: anchor, menuLabel, preventScroll, and
onContextMenu.
In addition, the hook only returns: visible, setVisible, menuProps, and
onContextMenu. The onContextMenu type definition has also been updated to
better support triggering the context menu from different element types.
Here is an example diff of the most common changes:
import ContentCopyIcon from "@react-md/material-icons/ContentCopyIcon";
import ContentCutIcon from "@react-md/material-icons/ContentCutIcon";
import ContentPasteIcon from "@react-md/material-icons/ContentPasteIcon";
import type { ReactElement } from "react";
import { Menu, MenuItem, TextArea, useContextMenu } from "react-md";
export default function SimpleContextMenu(): ReactElement {
- const { menuRef, menuProps, onContextMenu } = useContextMenu();
+ const {
+ menuProps,
+ onContextMenu
+ } = useContextMenu();
return (
<>
<TextArea
id="simple-context-menu-area"
onContextMenu={onContextMenu}
placeholder="Right click me!"
/>
- <Menu {...menuProps} ref={menuRef}>
+ <Menu {...menuProps}>
<MenuItem leftAddon={<ContentCutIcon />}>Cut</MenuItem>
<MenuItem leftAddon={<ContentCopyIcon />}>Copy</MenuItem>
<MenuItem leftAddon={<ContentPasteIcon />}>Paste</MenuItem>
</Menu>
</>
);
}
Here is an example diff of all the changes and what the codemod can support:
+// TODO: The `useContextMenu` no longer supports the `onFixedPositionScroll` callback
+// TODO: The `useContextMenu` no longer supports the `onFixedPositionResize` callback
+// TODO: The `useContextMenu` no longer returns `setCoords`. Manually provide an `initialX` and `initialY` to the `Menu` instead
+// TODO: The `useContextMenu` no longer returns `menuNodeRef` and must be implemented manually
import ContentCopyIcon from "@react-md/material-icons/ContentCopyIcon";
import ContentCutIcon from "@react-md/material-icons/ContentCutIcon";
import ContentPasteIcon from "@react-md/material-icons/ContentPasteIcon";
import type { ReactElement } from "react";
import { Menu, MenuItem, TextArea, TOP_RIGHT_ANCHOR, useContextMenu } from "react-md";
export default function ComplexContextMenu(): ReactElement {
const onEntering = (): void => {
// entering
};
const {
- menuRef,
- menuNodeRef,
menuProps,
onContextMenu,
- setCoords,
visible,
- setVisible,
+ setVisible
} = useContextMenu({
anchor: TOP_RIGHT_ANCHOR,
- baseId: "context-menu",
- closeOnResize: true,
- closeOnScroll: true,
- disableFocusOnMount: true,
- disableFocusOnUnmount: true,
- getFixedPositionOptions: () => ({}),
- horizontal: false,
menuLabel: "Context Menu",
- menuitem: false,
+
onContextMenu(event) {
// onContextMenu
},
- onEnter() {
- // enter
- },
- onEntering,
- onEntered: () => {
- // entered
- },
- onExited: () => {
- // exited
- },
- onFixedPositionResize: (event) => {
- // resized
- },
- onFixedPositionScroll: (event, data) => {
- // scroll
- },
- preventScroll: true,
- style: {
- background: "orange",
- },
+
+ preventScroll: true
});
return (
<>
<TextArea
id="simple-context-menu-area"
onContextMenu={onContextMenu}
placeholder="Right click me!"
/>
- <Menu {...menuProps} ref={menuRef}>
+ <Menu
+ {...menuProps}
+ id="context-menu"
+ closeOnResize={true}
+ closeOnScroll={true}
+ getFixedPositionOptions={() => ({})}
+ horizontal={false}
+ onEnter={() => {
+ // enter
+ }}
+ onEntering={onEntering}
+ onEntered={() => {
+ // entered
+ }}
+ onExited={() => {
+ // exited
+ }}
+ style={{
+ background: "orange"
+ }}
+ isFocusTypeDisabled={type => {
+ if (type === "mount") {
+ return true;
+ }
+
+ if (type === "unmount") {
+ return true;
+ }
+
+ return false;
+ }}>
<MenuItem leftAddon={<ContentCutIcon />}>Cut</MenuItem>
<MenuItem leftAddon={<ContentCopyIcon />}>Copy</MenuItem>
<MenuItem leftAddon={<ContentPasteIcon />}>Paste</MenuItem>
</Menu>
</>
);
}
npx @react-md/codemod v5-to-v6/overlay/update-overlay-props
The Overlay updated the following props:
hidden was renamed to noOpacity so the native hidden attribute can be usedonRequestClose was removed in favor of using the onClick handler <>
<Overlay
visible={visible}
- onRequestClose={() => {
+ onClick={() => {
setVisible(false);
}}
/>
- <Overlay visible={visible2} onRequestClose={hide} />
+ <Overlay visible={visible2} onClick={hide} />
<Overlay
visible={visible2}
- onRequestClose={() => {
+ onClick={() => {
hide();
}}
- hidden
+ noOpacity
/>
<Overlay
visible={visible}
- onRequestClose={() => {
+ onClick={() => {
setVisible(false);
}}
clickable
@@ -39,7 +39,7 @@ export default function Example({ handleClick }: ExampleProps): ReactElement {
onClick={(event) => {
handleClick?.(event);
}}
- onRequestClose={() => {
+ onClick={() => {
setVisible(false);
}}
clickable
npx @react-md/codemod v5-to-v6/portal/use-new-portal-api
Most of the Portal changes cannot be automated due to the new portal
container behavior, but should not affect most codebases since it is mostly an
internal component. The changes are:
into and intoId props were removed from the Portal component
PortalContainerProvider insteadportal, portalInto, and portalIntoId convenience props were removed
from all react-md components that used the Portal
PortalContainerProvider insteadPortalInto type was renamed to PortalContainer and no longer supports
functions for getting the portal nodeConditionalPortal was removed in favor of using the disabled prop on
the Portal instead+// TODO: Check how the Portal prop `intoId` was used since it is no longer supported.
+// TODO: Check how the Portal prop `into` was used since it is no longer supported.
import { type ReactElement } from "react";
import { Portal } from "react-md";
export default function Example(): ReactElement {
return (
<>
- <Portal into={something}>Content</Portal>
- <Portal intoId="some-id">Content</Portal>
- <Portal into={somethingElse}>Content</Portal>
- <Portal intoId="some-other-id">Content</Portal>
+ <Portal>Content</Portal>
+ <Portal>Content</Portal>
+ <Portal>Content</Portal>
+ <Portal>Content</Portal>
</>
);
}
-import { PortalInto } from "react-md";
+// TODO: The `PortalContainer` replaced the `PortalInto` type but does not support functions. Double check the usage before removing this line.
+import { PortalContainer } from "react-md";
export interface ExampleProps {
- portalInto: PortalInto;
+ portalInto: PortalContainer;
}
import { type ReactElement } from "react";
-import { ConditionalPortal } from "react-md";
+import { Portal } from "react-md";
export default function Example(): ReactElement {
return (
<>
- <ConditionalPortal portal={false}>Content</ConditionalPortal>
- <ConditionalPortal>Hello, world!</ConditionalPortal>
- <ConditionalPortal>
+ <Portal disabled>Content</Portal>
+ <Portal disabled>Hello, world!</Portal>
+ <Portal disabled>
<div>Hello, world!</div>
- </ConditionalPortal>
+ </Portal>
</>
);
}
In addition, the ConditionalPortal was removed.
npx @react-md/codemod v5-to-v6/progress/update-circular-progress-props
The CircularProgress updated the following props:
small was renamed to densecentered was renamed to disableCenteredmaxRotation was removed export default function Example(): ReactElement {
return (
<>
- <CircularProgress id="some-id-1" small />
- <CircularProgress id="some-id-2" small={false} />
- <CircularProgress id="some-id-3" centered />
- <CircularProgress id="some-id-4" centered={false} />
- <CircularProgress id="some-id-5" maxRotation={360 * 1.5} />
+ <CircularProgress id="some-id-1" dense />
+ <CircularProgress id="some-id-2" />
+ <CircularProgress id="some-id-3" />
+ <CircularProgress id="some-id-4" disableCentered />
+ <CircularProgress id="some-id-5" />
</>
);
}
The @react-md/states packages was mostly internal so codemods will not be provided
to update this package.
StatesConnfig context providerThe StatesConfig context provider has been removed in favor of the new
INTERACTION_CONFIG object. Here is an example on how to update the disableRipple
behavior:
+import { INTERACTION_CONFIG } from "@react-md/core/interaction/config";
-import { StatesConfig } from "react-md";
import { RestOfTheApp } from "./RestOfTheApp.js";
+INTERACTION_CONFIG.mode = "none";
export default function App() {
return (
- <StatesConfig disableRipple>
<RestOfTheApp />
- </StatesConfig>
);
}
useInteractionStates with useElementInteractionIf the useInteractionStates hook was used, switch to the
useElementInteraction hook.
import cn from "classnames";
import { type ButtonHTMLAttributes, type ReactElement } from "react";
-import { type InteractionStatesOptions, useInteractionStates } from "react-md";
+import { useElementInteraction } from "react-md";
import styles from "./CustomComponent.module.scss";
-interface CustomButtonProps
- extends ButtonHTMLAttributes<HTMLButtonElement>,
- Omit<InteractionStatesOptions, "handlers"> {}
+interface CustomButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
+ disableRipple?: boolean;
+}
function CustomButton({
disabled,
disableRipple,
- disableSpacebarClick,
- disableProgrammaticRipple,
- className: propClassName,
+ className,
children,
+ onBlur,
+ onClick,
onKeyDown,
onKeyUp,
onMouseDown,
onMouseUp,
onMouseLeave,
+ onDragStart,
onTouchStart,
onTouchMove,
onTouchEnd,
...props
}: CustomButtonProps): ReactElement {
- const { ripples, handlers, className } = useInteractionStates({
- handlers: {
+ const { ripples, handlers, pressed, pressedClassName } =
+ useElementInteraction({
+ onBlur,
+ onClick,
onKeyDown,
onKeyUp,
onMouseDown,
onMouseUp,
onMouseLeave,
+ onDragStart,
onTouchStart,
onTouchMove,
onTouchEnd,
- },
- disabled,
- disableRipple,
- disableSpacebarClick,
- disableProgrammaticRipple,
- className: propClassName,
- });
+ disabled,
+ mode: disableRipple ? "none" : undefined,
+ });
return (
<button
{...props}
type="button"
- className={cn(styles.button, className)}
+ className={cn(
+ styles.button,
+ className,
+ pressedClassName,
+ pressed && styles.pressed
+ )}
{...handlers}
>
{children}
{ripples}
</button>
);
}
npx @react-md/codemod v5-to-v6/table/update-table-cell-props
The TableCell updated the following props:
colSpan no longer supports a value of 100% or any non-numbers
disablePadding was removed in favor of the new padding prop+// TODO: Update the `TableCell` to have a `colSpan` number equal to the total number of columns in the table
import type { ReactElement } from "react";
import {
Table,
@@ -33,7 +34,7 @@ export default function StickyColumnsPart3(): ReactElement {
</TableBody>
<TableFooter sticky>
<TableRow>
- <TableCell colSpan="100%">
+ <TableCell>
This is the sticky footer content. Any components can be rendered
inside.
</TableCell>
- <TableCell disablePadding className="example">
+ <TableCell padding="none" className="example">
Content
</TableCell>
npx @react-md/codemod v5-to-v6/table/update-table-checkbox-props
The TableCheckbox no longer supports the cellId prop in favor of the id prop.
export function Example(props): ReactElement {
return (
<>
- <TableCheckbox {...props} cellId="some-unique-id" />
+ <TableCheckbox {...props} />
</>
);
}
npx @react-md/codemod v5-to-v6/table/caption-to-typography
The Caption component was removed in favor of using the existing Typography
component.
@@ -1,11 +1,11 @@
import type { ReactElement } from "react";
import {
- Caption,
Table,
TableBody,
TableCell,
TableHeader,
TableRow,
+ Typography,
} from "react-md";
import styles from "./DefaultStyles.module.scss";
@@ -13,7 +13,7 @@ import styles from "./DefaultStyles.module.scss";
export default function DefaultStyles(): ReactElement {
return (
<Table className={styles.centered}>
- <Caption>This is a caption</Caption>
+ <Typography type="caption">This is a caption</Typography>
<TableHeader>
<TableRow>
<TableCell>Column 1</TableCell>
There is a completely new tabs API which will require manual changes. First,
the TabsManager and Tabs components have been removed and should be
replaced by:
useTabs hook for controlling the active tab stateTabList component for basic styling and keyboard behaviorThe TabPanels and TabPanel components have been removed in favor of the
getTabPanelsProps and getTabPanelProps returned by the useTabs hook. The
previous slide transition can be implemented using the
SlideContainer and Slide components.
The Slide component behaves like the TabPanel with the
persistent flag enabled. If the tab panels should be unmounted while not
active, enable the temporary flag on the Slide.
To migrate to the new API, the step are as follows:
TabsManager component and replace with the useTabs hook
tabsId can be removed or added as the baseId hook optiondefaultActiveIndex, stacked, and iconAfter can be moved as hook
optionsactiveIndex and onActiveIndexChange must be provided together and
will be the activeIndex/setActiveIndex hook optionsgetTabListProps, getTabPanelsProps,
getTabPanelProps, and getTabProps which will be required for the new
componentsTabs component with the TabsList component
automatic prop has been removed in favor of
activationMode="automatic" or activationMode="manual" (default)orientation prop has been removed in favor of verticalTabList using the Tab component
{...getTabProps(index)}icon, stacked, and iconAfter
propsTabPanels component with the SlideContainer component
{...getTabPanelsProps()} to the SlideContainerdisableScrollFix prop was enabled, add it to the useTabs hook
insteaddisableTransition prop if it existedpersistent prop if it existedTabPanel component with the Slide component
{...getTabPanelProps(panelIndex)} to the Slide componenttimeout={0}temporary prop import type { ReactElement } from "react";
-import { TabPanel, TabPanels, Tabs, TabsManager, Typography } from "react-md";
+import {
+ Slide,
+ SlideContainer,
+ Tab,
+ TabList,
+ Typography,
+ useTabs,
+} from "react-md";
const tabs = ["Tab 1", "Tab 2", "Tab 3"];
const stacked = false;
const iconAfter = false;
const defaultActiveIndex = 0;
export default function Demo(): ReactElement {
+ const { getTabProps, getTabListProps, getTabPanelProps, getTabPanelsProps } =
+ useTabs({
+ baseId: "basic-usage-tabs",
+ stacked: stacked,
+ iconAfter: iconAfter,
+ defaultActiveIndex: defaultActiveIndex,
+ });
+
return (
- <TabsManager
- tabs={tabs}
- tabsId="basic-usage-tabs"
- stacked={stacked}
- iconAfter={iconAfter}
- defaultActiveIndex={defaultActiveIndex}
- >
- <Tabs />
- <TabPanels>
- <TabPanel>
+ <>
+ <TabList {...getTabListProps()}>
+ {tabs.map((tab, i) => (
+ <Tab {...getTabProps(i)}>{tab}</Tab>
+ ))}
+ </TabList>
+ <SlideContainer {...getTabPanelsProps()}>
+ <Slide {...getTabPanelProps(0)}>
<Typography type="headline-4">Panel 1</Typography>
- </TabPanel>
- <TabPanel>
+ </Slide>
+ <Slide {...getTabPanelProps(1)}>
<Typography type="headline-4">Panel 2</Typography>
- </TabPanel>
- <TabPanel>
+ </Slide>
+ <Slide {...getTabPanelProps(2)}>
<Typography type="headline-4">Panel 3</Typography>
- </TabPanel>
- </TabPanels>
- </TabsManager>
+ </Slide>
+ </SlideContainer>
+ </>
);
}
npx @react-md/codemod v5-to-v6/tabs/update-tabs-api
This codemod will try its best to convert tabs to the latest API but will
really only work if the TabsManager, Tabs, TabPanels, and TabPanel
components were defined in the same file.
-import type { ReactElement } from "react";
-import { TabPanel, TabPanels, Tabs, TabsManager, Typography } from "react-md";
+import { ReactElement, ReactNode } from "react";
+import {
+ Slide,
+ SlideContainer,
+ Tab,
+ TabList,
+ TabProps,
+ Typography,
+ useTabs,
+} from "react-md";
const tabs = ["Tab 1", "Tab 2", "Tab 3"];
export default function Demo(): ReactElement {
+ const { getTabProps, getTabListProps, getTabPanelProps, getTabPanelsProps } =
+ useTabs({
+ baseId: "basic-usage-tabs",
+ });
+
return (
- <TabsManager tabs={tabs} tabsId="basic-usage-tabs">
- <Tabs />
- <TabPanels>
- <TabPanel>
+ <>
+ <TabList {...getTabListProps()}>
+ {tabs.map((tab, i) => {
+ const tabProps = getTabProps(i);
+ let children: ReactNode;
+ let overrides: TabProps | undefined;
+
+ if (typeof tab !== "string" && "children" in tab) {
+ children = tab.children;
+
+ const {
+ children: _c,
+ contentStyle: _cs,
+ contentClassName: _ccn,
+ ...stillValidProps
+ } = tab;
+
+ overrides = stillValidProps;
+ } else {
+ children = tab;
+ }
+
+ return (
+ <Tab {...tabProps} {...overrides} key={tabProps.id}>
+ {children}
+ </Tab>
+ );
+ })}
+ </TabList>
+ <SlideContainer {...getTabPanelsProps()}>
+ <Slide {...getTabPanelProps(0)}>
<Typography type="headline-4">Panel 1</Typography>
- </TabPanel>
- <TabPanel>
+ </Slide>
+ <Slide {...getTabPanelProps(1)}>
<Typography type="headline-4">Panel 2</Typography>
- </TabPanel>
- <TabPanel>
+ </Slide>
+ <Slide {...getTabPanelProps(2)}>
<Typography type="headline-4">Panel 3</Typography>
- </TabPanel>
- </TabPanels>
- </TabsManager>
+ </Slide>
+ </SlideContainer>
+ </>
);
}
npx @react-md/codemod v5-to-v6/transition/update-scale-transition
The ScaleTransition component no longer supports the portal, portalInto, and
portalIntoId props.
+// TODO: The `portalInto` for the `ScaleTransition` cannot be converted automatically.
+// TODO: The `portalIntoId` for the `ScaleTransition` cannot be converted automatically.
import { type ReactElement } from "react";
-import { ScaleTransition } from "react-md";
+import { Portal, ScaleTransition } from "react-md";
import SomeComponent from "./SomeComponent";
export default function Example(): ReactElement {
return (
<>
- <ScaleTransition portalIntoId="some-id" transitionIn={transitionIn}>
- <SomeComponent />
- </ScaleTransition>
+ <Portal>
+ <ScaleTransition transitionIn={transitionIn}>
+ <SomeComponent />
+ </ScaleTransition>
+ </Portal>
</>
);
}
There were a lot of breaking changes for the Tree API and cannot be fully
converted automatically for complex implementations. The list of changes are:
Tree component updated the following props:
itemRenderer and getItemProps have been removed in favor of the new
rendererlabelKey, valueKey, getItemKey, and getItemValue were removedonItemExpansion was renamed to toggleTreeItemExpansiononMultiItemExpansion was renamed to expandMultipleTreeItemsonItemSelection was renamed to toggleTreeItemSelectiononMultiItemSelection was renamed to expandMultipleTreeItemsTree component no longer forwards refs and the new treeRef prop
should be used insteaddefaultTreeItemRenderer was removed in favor of the new
DefaultTreeItemRenderer componentuseTreeItemExpansion was renamed to useTreeExpansion and the returned
value was updated so that:
expandedIds is now a ReadonlySet<string> instead of string[]onItemExpansion was renamed to toggleTreeItemExpansiononMultiItemExpansion was renamed to expandMultipleTreeItemsuseTreeItemSelection was renamed to useTreeSelection and the returned
value was updated so that:
selectedIds is now a ReadonlySet<string> instead of string[]onItemSelection was renamed to toggleTreeItemSelectiononMultiItemSelection was renamed to expandMultipleTreeItemsTypescript type changes:
TreeItemExpansion type was renamed to TreeExpansionTreeItemSelection type was renamed to TreeSelectionTreeItemId was removed in favor of just using a stringTreeItemIds was renamed to TreeItemNodeExpandedIds and SelectedIds were removed in favor of TreeItemIdSetGetItemProps and TreeItemRenderer was removed in favor of TreeItemRendererPropsThe new renderer prop on the Tree should be a component that accepts the
following props:
item - the current tree itemdata - the full tree dataparents - an ordered list of parent tree itemschildren - any content to render if the current item has child itemsOne of the main differences with this new API is that the expanded,
selected, and focused states are no longer provided by default since it is
handled by the TreeItem component internally. Otherwise, the TreeItem no
longer supports the expanderLeft icon so icons must be provided on the Tree
component itself using the TreeProvider around each TreeItem.
See the Custom Tree Item Renderer example for an in-depth example using the API or the diff shown below for convert-get-item-props
All the following codemods can be run at once using:
npx @react-md/codemod v5-to-v6/tree/everything
@@ -1,13 +1,21 @@
+// TODO: The `getItemProps` have been removed from the `Tree` component and need to be manually changed. The `renderer` prop is the closest in functionality.
import cn from "classnames";
-import type { ReactElement, ReactNode } from "react";
-import type { GetItemProps, TreeData, TreeItemIds } from "react-md";
+import { ReactElement, ReactNode, useId } from "react";
+
import {
ArrowDropDownSVGIcon,
+ DefaultTreeItemRenderer,
FolderOpenSVGIcon,
FolderSVGIcon,
Tree,
- useTreeItemExpansion,
- useTreeItemSelection,
+ TreeData,
+ TreeItemNode,
+ TreeItemRendererProps,
+ TreeProvider,
+ useKeyboardMovementContext,
+ useTreeContext,
+ useTreeExpansion,
+ useTreeSelection,
} from "react-md";
import Html5SVGIcon from "icons/Html5SVGIcon";
@@ -19,7 +27,7 @@ import createIdGenerator from "./createIdGenerator";
import styles from "./CustomizingTreeItems.module.scss";
type ItemType = "folder" | "html" | "typescript" | "scss" | "text";
-interface Item extends TreeItemIds {
+interface Item extends TreeItemNode {
name: string;
type: ItemType;
}
@@ -28,7 +36,7 @@ const uuid = createIdGenerator("custom-tree-items");
const createItem = (
name: string,
type: ItemType,
- parentId: string | null = null
+ parentId: string | null = null,
): Item => {
const itemId = uuid();
return {
@@ -57,11 +65,25 @@ const data = [
index,
].reduce<TreeData<Item>>(
(tree, item) => ({ ...tree, [item.itemId]: item }),
- {}
+ {},
);
-const getItemProps: GetItemProps<Item> = (item) => {
- const { selected, focused, expanded, type } = item;
+// TODO: This might need to be renamed to match normal component naming conventions
+const getItemProps = function Renderer(
+ props: TreeItemRendererProps<Item>,
+): ReactElement {
+ const { item } = props;
+
+ const { type, itemId } = item;
+
+ const context = useTreeContext();
+
+ const { expandedIds, selectedIds } = context;
+
+ const expanded = expandedIds.has(itemId);
+ const selected = selectedIds.has(itemId);
+ const id = useId();
+ const focused = useKeyboardMovementContext().activeDescendantId === id;
let leftAddon: ReactNode = null;
switch (type) {
case "folder":
@@ -82,22 +104,24 @@ const getItemProps: GetItemProps<Item> = (item) => {
// no default
}
- return {
- leftAddon,
- expanderIcon: <ArrowDropDownSVGIcon />,
- className: cn(styles.item, {
- [styles.focused]: focused,
- [styles.selected]: selected,
- }),
- };
+ return (
+ <TreeProvider {...context} expanderIcon={<ArrowDropDownSVGIcon />}>
+ <DefaultTreeItemRenderer
+ {...props}
+ leftAddon={leftAddon}
+ className={cn(styles.item, {
+ [styles.focused]: focused,
+ [styles.selected]: selected,
+ })}
+ id={id}
+ />
+ </TreeProvider>
+ );
};
export default function Demo(): ReactElement {
- const selection = useTreeItemSelection([demo.itemId], false);
- const expansion = useTreeItemExpansion([
- srcFolder.itemId,
- publicFolder.itemId,
- ]);
+ const selection = useTreeSelection([demo.itemId], false);
+ const expansion = useTreeExpansion([srcFolder.itemId, publicFolder.itemId]);
return (
<Tree
npx @react-md/codemod v5-to-v6/tree/convert-get-item-props
import cn from "classnames";
-import type { ReactNode } from "react";
-import type { GetItemProps } from "react-md";
+import { ReactElement, ReactNode, useId } from "react";
import {
ArrowDropDownSVGIcon,
+ DefaultTreeItemRenderer,
FolderOpenSVGIcon,
FolderSVGIcon,
+ TreeItemRendererProps,
+ TreeProvider,
+ useKeyboardMovementContext,
+ useTreeContext,
} from "react-md";
import Html5SVGIcon from "icons/Html5SVGIcon";
import FileSVGIcon from "./FileSVGIcon";
import SassSVGIcon from "./SassSVGIcon";
import TypescriptSVGIcon from "./TypescriptSVGIcon";
import { Item } from "./anotherFile";
import styles from "./styles.module.scss";
-export const getItemProps: GetItemProps<Item> = ({
- selected,
- focused,
- expanded,
- type,
- ...item
-}) => {
+// TODO: This might need to be renamed to match normal component naming conventions
+export const getItemProps = function Renderer(
+ props: TreeItemRendererProps<Item>,
+): ReactElement {
+ const { item: tempItem } = props;
+
+ const { type, itemId, ...item } = tempItem;
+
+ const context = useTreeContext();
+
+ const { expandedIds, selectedIds } = context;
+
+ const expanded = expandedIds.has(itemId);
+ const selected = selectedIds.has(itemId);
+ const id = useId();
+ const focused = useKeyboardMovementContext().activeDescendantId === id;
let leftAddon: ReactNode = null;
switch (type) {
case "folder":
leftAddon = expanded ? <FolderOpenSVGIcon /> : <FolderSVGIcon />;
break;
case "html":
leftAddon = <Html5SVGIcon />;
break;
case "text":
leftAddon = <FileSVGIcon />;
break;
case "scss":
leftAddon = <SassSVGIcon />;
break;
case "typescript":
leftAddon = <TypescriptSVGIcon />;
break;
// no default
}
- return {
- leftAddon,
- expanderIcon: <ArrowDropDownSVGIcon />,
- className: cn(styles.item, {
- [styles.focused]: focused,
- [styles.selected]: selected,
- }),
- };
+ return (
+ <TreeProvider {...context} expanderIcon={<ArrowDropDownSVGIcon />}>
+ <DefaultTreeItemRenderer
+ {...props}
+ leftAddon={leftAddon}
+ className={cn(styles.item, {
+ [styles.focused]: focused,
+ [styles.selected]: selected,
+ })}
+ id={id}
+ />
+ </TreeProvider>
+ );
};
npx @react-md/codemod v5-to-v6/tree/item-renderer-to-render-component
-import { TreeItemRenderer, defaultTreeItemRenderer } from "react-md";
+// TODO: The `defaultTreeItemRenderer` has been replaced by the `DefaultTreeItemRenderer` component and cannot automatically be converted
+// TODO: The `TreeItemRenderer` type has been replaced by the `TreeItemRendererProps` type and cannot automatically be converted
+import { TreeItemRendererProps, DefaultTreeItemRenderer } from "react-md";
import { MyTreeItem } from "./types";
import MyFancyNonTreeItem from "./MyFancyNonTreeItem";
export const itemRenderer: TreeItemRenderer<MyTreeItem> = (
itemProps,
item,
treeProps
) => {
const { key } = itemProps;
const { isCustom } = item;
if (isCustom) {
return <MyFancyNonTreeItem item={item} key={key} />;
}
return defaultTreeItemRenderer(itemProps, item, treeProps);
};
npx @react-md/codemod v5-to-v6/tree/update-simple-types
-import { TreeItemId, TreeItemIds, ExpandedIds, SelectedIds } from "react-md";
+import { TreeItemIdSet, TreeItemNode } from "react-md";
-export interface Example1 extends TreeItemIds {
- itemId: TreeItemId;
- selectedIds: SelectedIds;
- expandedIds: ExpandedIds;
+export interface Example1 extends TreeItemNode {
+ itemId: string;
+ selectedIds: TreeItemIdSet;
+ expandedIds: TreeItemIdSet;
}
npx @react-md/codemod v5-to-v6/tree/update-tree-props
return (
<>
<Tree
- labelKey="example"
- valueKey="example-2"
- getItemLabel={(item) => item.something}
- getItemValue={(item) => item.somethingElse}
- onItemExpansion={(itemId) => {
+ toggleTreeItemExpansion={(itemId) => {
expand(itemId);
}}
- onMultiItemExpansion={(itemIds) => {
+ expandMultipleTreeItems={(itemIds) => {
setExpanded(itemIds);
}}
- onItemSelect={(itemId) => {
+ toggleTreeItemSelection={(itemId) => {
select(itemId);
}}
- onMultiItemSelect={(itemIds) => {
+ selectMultipleTreeItems={(itemIds) => {
multiSelect(itemIds);
}}
/>
npx @react-md/codemod v5-to-v6/tree/use-tree-hooks
import type { ReactElement } from "react";
-import { Tree, useTreeItemSelection, useTreeItemExpansion } from "react-md";
+import { Tree, useTreeSelection, useTreeExpansion } from "react-md";
import folders from "./folders";
export default function Demo(): ReactElement {
- const { selectedIds, multiSelect, onItemSelect, onMultiItemSelect } =
- useTreeItemSelection([], false);
- const { expandedIds, onItemExpansion, onMultiItemExpansion } =
- useTreeItemExpansion([]);
+ const {
+ selectedIds,
+ multiSelect,
+ toggleTreeItemSelection: onItemSelect,
+ selectMultipleTreeItems: onMultiItemSelect,
+ } = useTreeSelection([], false);
+ const {
+ expandedIds,
+ toggleTreeItemExpansion: onItemExpansion,
+ expandMultipleTreeItems: onMultiItemExpansion,
+ } = useTreeExpansion([]);
return (
<Tree
npx @react-md/codemod v5-to-v6/tooltip/convert-use-tooltip
The useTooltip went through an API change since it no longer uses the shared
"hover mode API" and instead has its own TooltipHoverModeProvider. The other
changes are:
baseId was renamed to idtouchTime and focusTime were removed in favor of hoverTimeoutdisableHoverMode was removed as an optionstuck, active, onClick, onMouseEnter, onMouseLeave, and handlers
were removedclearHoverTimeout was renamed to clearVisibilityTimeoutenableHoverMode, disableHoverMode, and startDisableTimer were removed
but available through the new useTooltipHoverMode hook+// TODO: `useTooltip` no longer supports the `disableHoverMode` option and was removed. See the new hover mode API docs or define the `hoverTimeout` to option.
import { type ReactElement } from "react";
import { Button, Tooltip, useTooltip } from "react-md";
export default function Example(): ReactElement {
const { elementProps, tooltipProps } = useTooltip({
- baseId: "example-1-id",
+ id: "example-1-id",
+
onClick(event) {
// DO SOMETHING
},
- touchTime: 500,
- focusTime: 400,
- disableHoverMode: true,
+
+ hoverTimeout: 400,
});
return (
<>
If the hover mode API was used, there will be a diff similar to:
+// TODO: `useTooltip` no longer returns the following keys from the hover mode api and must manually be updated: stuck, active, onClick, onMouseEnter, onMouseLeave
+// TODO: `useTooltip` no longer returns the `handlers` object. The event handlers can be extracted from the `elementProps` if they are still needed.
import { type ReactElement } from "react";
-import { Button, Tooltip, useTooltip } from "react-md";
+import { Button, Tooltip, useTooltip, useTooltipHoverMode } from "react-md";
export default function Example(): ReactElement {
const {
- elementProps,
- tooltipProps,
- stuck,
- active,
- onClick,
- onMouseEnter,
- onMouseLeave,
- handlers,
enableHoverMode: enable,
disableHoverMode,
startDisableTimer,
- clearHoverTimeout,
+ } = useTooltipHoverMode();
+
+ const {
+ elementProps,
+ tooltipProps,
+ clearVisibilityTimeout: clearHoverTimeout,
} = useTooltip({
- baseId: "example-1-id",
+ id: "example-1-id",
onClick(event) {
// DO SOMETHING
},
npx @react-md/codemod v5-to-v6/tooltip/remove-tooltipped-component
The Tooltipped component has been removed and a custom implementation must be
used instead.
+// TODO: The `Tooltipped` component has been removed. Update the code to use the `useTooltip` hook instead.
import { type ReactNode } from "react";
-import { SimplePosition, Tooltipped } from "react-md";
+import { SimplePosition, useTooltip } from "react-md";
interface Test1Props {
onClick?: (event: MouseEvent) => void;
npx @react-md/codemod v5-to-v6/tooltip/update-tooltip-props
The Tooltip component updated the following props:
portal was renamed to disablePortalportalInto and portalIntoId were removed due to the new portal APIlineWrap was removed in favor of the new textOverflow prop return (
<>
<Tooltip>Hello</Tooltip>
- <Tooltip portal>Hello</Tooltip>
- <Tooltip portal={false}>Hello</Tooltip>
- <Tooltip portalInto={() => document.getElementById("some-node")}>
- Hello
- </Tooltip>
- <Tooltip portalIntoId="some-dom-id">Hello</Tooltip>
- <Tooltip lineWrap>Hello</Tooltip>
- <Tooltip lineWrap={true}>Hello</Tooltip>
- <Tooltip lineWrap={lineWrap}>Hello</Tooltip>
- <Tooltip lineWrap={false}>Hello</Tooltip>
+ <Tooltip>Hello</Tooltip>
+ <Tooltip disablePortal>Hello</Tooltip>
+ <Tooltip>Hello</Tooltip>
+ <Tooltip>Hello</Tooltip>
+ <Tooltip>Hello</Tooltip>
+ <Tooltip>Hello</Tooltip>
+ <Tooltip textOverflow={lineWrap ? "allow" : "nowrap"}>Hello</Tooltip>
+ <Tooltip textOverflow="nowrap">Hello</Tooltip>
</>
);
}
npx @react-md/codemod v5-to-v6/typography/remove-removed-types
The following types were removed and cannot be migrated automatically.
-import {
- TextContainerSize,
- TextContainerRenderFunction,
- TypographyRenderFunction,
-} from "react-md";
-
+// TODO: Remove the `TypographyRenderFunction` usage since it no longer exists.
+// TODO: Remove the `TextContainerRenderFunction` usage since it no longer exists.
+// TODO: Remove the `TextContainerSize` usage since it no longer exists.
const x: TextContainerRenderFunction = ({ className }) => <>{className}</>;
const y: TypographyRenderFunction = ({ className }) => <>{className}</>;
npx @react-md/codemod v5-to-v6/typography/update-text-container-props
The TextContainer no longer supports the size prop and should be removed.
<TextContainer>
<Typography>Hello, world!</Typography>
</TextContainer>
- <TextContainer size="auto">
+ <TextContainer>
<Typography>Hello, world!</Typography>
</TextContainer>
- <TextContainer size="mobile">
+ <TextContainer>
<Typography>Hello, world!</Typography>
</TextContainer>
- <TextContainer size={size}>
+ <TextContainer>
<Typography>Hello, world!</Typography>
</TextContainer>
</>
npx @react-md/codemod v5-to-v6/typography/update-typography-props
The Typography and SrOnly components renamed the component prop to as.
export default function Example(): ReactElement {
return (
<>
- <Typography component="div">Hello, world!</Typography>
- <Typography component={CustomElement}>Hello, world!</Typography>
- <SrOnly component="div">Hello, world!</SrOnly>
- <SrOnly component={CustomElement}>Hello, world!</SrOnly>
+ <Typography as="div">Hello, world!</Typography>
+ <Typography as={CustomElement}>Hello, world!</Typography>
+ <SrOnly as="div">Hello, world!</SrOnly>
+ <SrOnly as={CustomElement}>Hello, world!</SrOnly>
</>
);
}
In addition, the Typography and SrOnly components no longer support the
child render function behavior and prefer the typography() or srOnly()
class name utility functions instead.
❌ This cannot be updated automatically.
+// TODO: Check the `Typography` usage to see if using the removed children function renderer behavior for getting the class name.
import { type ReactElement } from "react";
-import { Typography } from "react-md";
+import { Typography } from "react-md";
import CustomComponent from "./CustomComponent";
export default function Example(): ReactElement {
return (
- <Typography
- children={({ className }) => (
- <CustomComponent classNameProp={className}>
- Hello, world!
- </CustomComponent>
- )}
- />
+ <CustomComponent classNameProp={typography()}>
+ Hello, world!
+ </CustomComponent>
);
}
npx @react-md/codemod v5-to-v6/utils/dir-to-writing-direction-provider
There have been a few breaking changes around handling the dir attribute:
DEFAULT_DIR was renamed to DEFAULT_WRITING_DIRECTIONDir was renamed to WritingDirectionProviderTypescript only:
DirProps was renamed to WritingDirectionProviderPropsWritingDirect was renamed to Dir import { type ReactElement } from "react";
-import { Dir, DirProps, DEFAULT_DIR, WritingDirection, useDir } from "react-md";
+import {
+ WritingDirectionProvider,
+ WritingDirectionProviderProps,
+ DEFAULT_WRITING_DIRECTION,
+ Dir,
+ useDir,
+} from "react-md";
-export function Example1(props: DirProps): ReactElement {
- return <Dir defaultDir={DEFAULT_DIR} {...props} />;
+export function Example1(props: WritingDirectionProviderProps): ReactElement {
+ return (
+ <WritingDirectionProvider
+ defaultDir={DEFAULT_WRITING_DIRECTION}
+ {...props}
+ />
+ );
}
export function Example2(): ReactElement {
- let dir: WritingDirection = "ltr";
+ let dir: Dir = "ltr";
if (something) {
dir = "rtl";
}
- return <Dir defaultDir={dir} />;
+ return <WritingDirectionProvider defaultDir={dir} />;
}
export function Example3(): ReactElement {
npx @react-md/codemod v5-to-v6/utils/nearest-parameters-to-object
The nearest utility function was updated to accept a single object parameter instead of multiple parameters.
const steps = range;
const minValue = 2000;
const maxValue = 8000;
-expect(nearest(10000, min, maxValue, steps, range)).toBe(maxValue);
-expect(nearest(0, minValue, max, steps, range)).toBe(minValue);
+expect(
+ nearest({
+ value: 10000,
+ min: min,
+ max: maxValue,
+ steps: steps,
+ range: range,
+ }),
+).toBe(maxValue);
+expect(
+ nearest({
+ value: 0,
+ min: minValue,
+ max: max,
+ steps: steps,
+ range: range,
+ }),
+).toBe(minValue);
npx @react-md/codemod v5-to-v6/utils/remove-scroll-listener
The useScrollListener hook and ScrollListener component have been removed
and must be implemented manually.
+// TODO: The `ScrollListener`/`useScrollListener` have been removed from react-md. You will need to implement their behavior manually.
import { ArrowDropDownSVGIcon } from "@react-md/material-icons";
import type { CSSProperties, ReactElement } from "react";
import { useCallback, useRef, useState } from "react";
@@ -6,12 +7,10 @@ import {
List,
ListItem,
Overlay,
- ScrollListener,
TextIconSpacing,
Typography,
getFixedPosition,
useToggle,
- useScrollListener,
} from "react-md";
import styles from "./SimpleExample.module.scss";
@@ -38,10 +37,6 @@ export default function SimpleExample(): ReactElement {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
- useScrollListener({
- onUpdate: updatePosition,
- });
-
return (
<div className={styles.container}>
<Button
@@ -77,7 +72,6 @@ export default function SimpleExample(): ReactElement {
}
}}
>
- <ScrollListener onScroll={updatePosition} />
{Array.from({ length: 6 }).map((_, i) => (
<ListItem id={`menu-item-${i}`} key={i} role="menuitem">
{`Option ${i + 1}`}
npx @react-md/codemod v5-to-v6/utils/update-resize-listener
The useResizeListener options have been updated as follows:
onResize renamed to onUpdateimmediate as been removedoptions has been removed and instead should be passed directly to the hookenabled has been renamed to disabled export default function Example(): null {
const [size, setSize] = useState(window.innerWidth);
useResizeListener({
- onResize() {
+ onUpdate() {
setSize(window.innerWidth);
},
});
useResizeListener({
- onResize: () => setSize(window.innerWidth),
- enabled: false,
+ onUpdate: () => setSize(window.innerWidth),
+ disabled: true,
});
useResizeListener({
- onResize: () => setSize(window.innerWidth),
- enabled: someFlag || anotherFlag,
+ onUpdate: () => setSize(window.innerWidth),
+ disabled: !(someFlag || anotherFlag),
});
useResizeListener({
- immediate: false,
- onResize: () => setSize(window.innerWidth),
- options: false,
+ onUpdate: () => setSize(window.innerWidth),
+ capture: false,
});
useResizeListener({
- immediate: someFlag,
- onResize: () => {
+ onUpdate: () => {
console.log(window.innerWidth);
},
- options: {
- once: true,
- passive: true,
- },
+ once: true,
+ passive: true,
});
In addition, the ResizeListener component has been removed in favor of using the
useResizeListener hook.
import type { ReactElement } from "react";
import { useState } from "react";
-import { Checkbox, ResizeListener, Typography, useChecked } from "react-md";
+import { Checkbox, Typography, useChecked, useResizeListener } from "react-md";
import CodeBlock from "./CodeBlock";
@@ -16,6 +16,11 @@ export default function Demo(): ReactElement {
const [enabled, handleEnabledChange] = useChecked(true);
const [immediate, handleImmediateChange] = useChecked(true);
+ useResizeListener({
+ onUpdate: () => setSize(window.innerWidth),
+ disabled: !enabled,
+ });
+
return (
<>
<Checkbox
@@ -32,12 +37,7 @@ export default function Demo(): ReactElement {
onChange={handleImmediateChange}
label="Invoke on mount"
/>
- {enabled && (
- <ResizeListener
- immediate={immediate}
- onResize={() => setSize(window.innerWidth)}
- />
- )}
+
<Typography>The current app size is:</Typography>
<CodeBlock suppressHydrationWarning>{size}px</CodeBlock>
</>
npx @react-md/codemod v5-to-v6/utils/update-use-resize-observer
The useResizeObserver hook was updated so that it:
onUpdate propertyrefCallback instead of a tupleResizeObserverEntry instead of the
ResizeObserverElementData
height or width are needed, get from the entry.contentRect or
entry.borderBoxSize[0]element is needed, use entry.targetscrollHeight or scrollWidth are needed, use
entry.target.scrollHeight or entry.target.scrollWidth export default function Example(): ReactElement {
const [state, setState] = useState();
- const [, refCallback] = useResizeObserver(
- useCallback(
- (resizeData) =>
- setState({
- height: resizeData.scrollHeight,
- width: resizeData.scrollWidth,
- }),
- []
- )
- );
+ const refCallback = useResizeObserver({
+ onUpdate: useCallback((entry) => {
+ setState({
+ height: entry.target.scrollHeight,
+ width: entry.target.scrollWidth,
+ });
+ }, []),
+ });
return <></>;
}
If a ref is required within the component, provide it using the ref option
like before:
export default function Example(): ReactElement {
const [state, setState] = useState();
const nodeRef = useRef();
- const [ref, refCallback] = useResizeObserver(
- useCallback(
- (resizeData) =>
- setState({
- height: resizeData.scrollHeight,
- width: resizeData.scrollWidth,
- }),
- []
- ),
- {
- ref: nodeRef,
- }
- );
+ const refCallback = useResizeObserver({
+ onUpdate: useCallback((entry) => {
+ setState({
+ height: entry.target.scrollHeight,
+ width: entry.target.scrollWidth,
+ });
+ }, []),
+
+ ref: nodeRef,
+ });
// do stuff with `nodeRef.current`
If the nodeRef is dynamic, wrap with useEnsuredRef:
@@ -5,7 +5,7 @@ import {
useEffect,
useState,
} from "react";
-import { useResizeObserver } from "react-md";
+import { useEnsuredRef, useResizeObserver } from "react-md";
interface ExampleProps {
nodeRef?: Ref<HTMLDivElement>;
@@ -13,19 +13,17 @@ interface ExampleProps {
export default function Example({ nodeRef }: ExampleProps): ReactElement {
const [state, setState] = useState();
- const [ref, refCallback] = useResizeObserver(
- useCallback(
- (resizeData) =>
- setState({
- height: resizeData.scrollHeight,
- width: resizeData.scrollWidth,
- }),
- []
- ),
- {
- ref: nodeRef,
- }
- );
+ const [ref, nodeRefCallback] = useEnsuredRef(nodeRef);
+ const refCallback = useResizeObserver({
+ onUpdate: useCallback((entry) => {
+ setState({
+ height: entry.target.scrollHeight,
+ width: entry.target.scrollWidth,
+ });
+ }, []),
+
+ ref: nodeRefCallback,
+ });
useEffect(() => {
if (ref.current) {
npx @react-md/codemod v5-to-v6/utils/update-use-toggle-api
The useToggle hook was updated to return an object instead of an ordered array.
import { type ReactElement } from "react";
import { Button, useToggle } from "react-md";
export default function Example(): ReactElement {
- const [toggled, enable, disable, toggle] = useToggle();
+ const {
+ toggled: toggled,
+ enable: enable,
+ disable: disable,
+ toggle: toggle,
+ } = useToggle();
return (
<>
<Button onClick={enable}>Enable</Button>
<Button onClick={disable}>Diable</Button>
<Button onClick={toggle}>Toggle</Button>
{toggled && <>Hello, world!</>}
</>
);
}
npx @react-md/codemod v5-to-v6/utils/within-range-parameters-to-object
The withinRange util was updated to accept a single object parameter
instead of multiple parameters.
-expect(withinRange(0, 0, 10)).toBe(0);
-expect(withinRange(-1, 0, 10)).toBe(0);
+expect(
+ withinRange({
+ min: 0,
+ max: 10,
+ value: 0,
+ }),
+).toBe(0);
+expect(
+ withinRange({
+ min: 0,
+ max: 10,
+ value: -1,
+ }),
+).toBe(0);
npx @react-md/codemod v5-to-v6/utils/update-search-functions
There were a few breaking changes for the caseInsensitiveFilter, fuzzyFilter, and findIgnoreCase functions:
caseInsensitiveFilter and findIgnoreCase have been renamed to caseInsensitiveSearch
findIgnoreCase should add type: "search" to the optionsfuzzyFilter has been renamed to fuzzySearchvalueKey option was removedgetItemValue option was renamed to extractortrim and ignoreWhitespace have been merged into a single whitespace option which can be one of:
"trim", "ignore", or "as-is"DEFAULT_GET_ITEM_VALUEDEFAULT_VALUE_KEYDEFAULT_IGNORE_WHITESPACEDEFAULT_SEARCH_RESET_TIMEDEFAULT_SEARCH_OPTIONSGetItemValue type was renamed to TextExtractorSearchOptions type was removed+// TODO: Check if `caseInsensitiveSearch` is using a list of objects and requires an `extractor` option
+// TODO: Check if `fuzzySearch` is using a list of objects and requires an `extractor` option
+import { caseInsensitiveSearch, fuzzySearch } from "react-md";
-import { caseInsensitiveFilter, findIgnoreCase, fuzzyFilter } from "react-md";
const FRUITS = ["Apple", "Banana", "Mango", "Orange"];
-expect(caseInsensitiveFilter("", list1)).toBe(list1);
-expect(caseInsensitiveFilter("ap", FRUITS, { startsWith: true })).toEqual([
- "Apple",
-]);
-expect(caseInsensitiveFilter("an", FRUITS, { startsWith: true })).toEqual([]);
+expect(caseInsensitiveSearch({ query: "", list: list1 })).toBe(list1);
+expect(
+ caseInsensitiveSearch({
+ query: "ap",
+ list: FRUITS,
+ whitespace: "trim",
+ startsWith: true,
+ })
+).toEqual(["Apple"]);
+expect(
+ caseInsensitiveSearch({ query: "an", list: FRUITS, whitespace: "ignore" })
+).toEqual([]);
const list = ["Item 1", "This is Item 1"];
-expect(caseInsensitiveFilter("item", list, { startsWith: true })).toEqual([
- "Item 1",
-]);
+expect(
+ caseInsensitiveSearch({
+ query: "item",
+ list,
+ })
+).toEqual(["Item 1"]);
const item1 = "Lorem ipsum";
const item2 = "another item";
const item3 = "in this string";
const item4 = "not interested, mate";
const item5 = "not in my house";
const list2 = [item1, item2, item3, item4, item5];
-expect(fuzzyFilter("ti", list2)).toEqual([item3]);
-expect(fuzzyFilter("ti", list2, { ignoreWhitespace: true })).toEqual([
- item2,
- item3,
- item4,
- item5,
-]);
-expect(fuzzyFilter("t i", list2, { ignoreWhitespace: true })).toEqual([
- item2,
- item3,
- item4,
- item5,
-]);
-expect(fuzzyFilter("rem", list2, { ignoreWhitespace: true })).toEqual([
- item1,
- item2,
-]);
-expect(fuzzyFilter("tem", list2, { ignoreWhitespace: true })).toEqual([item2]);
+expect(fuzzySearch({ query: "ti", list: list2 })).toEqual([item3]);
+expect(fuzzySearch({ query: "ti", list: list2, whitespace: "ignore" })).toEqual(
+ [item2, item3, item4, item5]
+);
+expect(
+ fuzzySearch({ query: "t i", list: list2, whitespace: "ignore" })
+).toEqual([item2, item3, item4, item5]);
+expect(
+ fuzzySearch({ query: "rem", list: list2, whitespace: "ignore" })
+).toEqual([item1, item2]);
+expect(
+ fuzzySearch({ query: "tem", list: list2, whitespace: "ignore" })
+).toEqual([item2]);
-expect(findIgnoreCase("", list)).toBe(null);
-expect(findIgnoreCase("f", list)).toBe(item1);
-expect(findIgnoreCase("s", list)).toBe(item2);
-expect(findIgnoreCase("thi", list)).toBe(item3);
-const getItemValue1 = (item: string) => `thing-${item}`;
-expect(findIgnoreCase("thing-a", FRUITS, { getItemValue: getItemValue1 })).toBe(
- "Apple"
+expect(caseInsensitiveSearch({ query: "", list, type: "search" })).toBe(null);
+expect(caseInsensitiveSearch({ query: "f", list, type: "search" })).toBe(item1);
+expect(caseInsensitiveSearch({ query: "s", list, type: "search" })).toBe(item2);
+expect(caseInsensitiveSearch({ query: "thi", list, type: "search" })).toBe(
+ item3
);
+const getItemValue1 = (item: string) => `thing-${item}`;
+expect(
+ caseInsensitiveSearch({
+ query: "thing-a",
+ list: FRUITS,
+ type: "search",
+ extractor: getItemValue1,
+ })
+).toBe("Apple");
npx @react-md/codemod sass-migrator v5-to-v6
The provided codemod will attempt to handle most of the sass migrations except for the following:
@import or @use@import to @useThe codemod will:
TODO: comments for functions, variables, and mixins that have been
removed without a possible fallbackThis version of react-md only supports the new Sass module system through
@use where the main changes are:
The @react-md/{{PACKAGE_NAME}}/dist/* no longer exist. Instead use
@react-md/core, @react-md/core/colors, and @react-md/core/a11y instead:
-@use "@react-md/core/dist/color-palette" as *;
-@use "@react-md/button/dist/mixins" as *;
+@use "@react-md/core/colors" as *;
+@use "@react-md/core" as *;
The theme API has been updated to reference custom properties instead of
theme. The general pattern is rmd-{{PACKAGE_NAME}}-theme-var ->
{{GROUP_NAME}}-get-var, rmd-{{PACKAGE_NAME}}-theme ->
{{GROUP_NAME}}-use-var, and rmd-{{PACKAGE_NAME}}-theme-update-var ->
{{GROUP_NAME}}-set-var:
-@include rmd-app-bar-theme-update-var(height, 3.5rem);
+@include app-bar-set-var(height, 3.5rem);
-@include rmd-avatar-theme(background-color);
+@include avatar-use-var(background-color);
-color: rmd-button-theme-var(color);
+color: button-get-var(color);
The theme API no longer provides rmd-theme and
rmd-{{PACKAGE_NAME}}-theme functions since the {{GROUPNAME}}-get-var()
function is preferred
Variables, functions, and mixins are no longer prefixed with rmd- since the
new Sass module system prefers providing namespaces. The general pattern is
rmd-{{PACKAGE_NAME}}-{{REMAINING}} to {{GROUP_NAME}}-{{REMAINING}}:
-$rmd-badge-size
+$badge-size
This version of react-md now supports switching between, light, dark, and
system color schemes by setting a new $color-scheme variable instead of the
$rmd-theme-light and $rmd-theme-dark-class variables. If you were not using
the prefers-color-scheme behavior for the $rmd-theme-dark-class, just change
$rmd-theme-light: true|false to $color-scheme: light|dark
@use "react-md" with (
+ $color-scheme: dark
- $rmd-theme-light: false
);
If you were using the $rmd-theme-dark-class: prefers-color-scheme, set
$color-scheme: system and $disable-default-system-theme: true:
@use "react-md" with (
+ $color-scheme: system,
+ $disable-default-system-theme: true
- $rmd-theme-light: false,
- $rmd-theme-dark-class: 'prefers-color-scheme'
);
If you want to use the new system theme behavior, remove the
$disable-default-system-theme and every @media (prefers-color-scheme: dark)
that exist in your app.
background -> background-colorprimary -> primary-coloron-primary -> on-primary-colorsecondary -> secondary-coloron-secondary -> on-secondary-colorsurface -> surface-coloron-surface -> use text-primary-color or inverse-color insteadwarning -> warning-coloron-warning -> on-warning-colorerror -> error-coloron-error -> on-error-colorsuccess -> success-coloron-success -> on-success-colortext-primary-on-background -> text-primary-colortext-secondary-on-background -> text-secondary-colortext-hint-on-background -> text-hint-colortext-disabled-on-background -> text-disabled-colortext-icon-on-background -> use the core.icon-get-var(color) or core.icon-use-var(color) instead-@include rmd-theme(background-color, background);
+@include theme-use-var(background-color, background-color);
-@include rmd-theme(background-color, surface);
+@include theme-use-var(background-color, surface-color);
/* there is no `on-surface` variable type in v6, but inverse-color or text-primary-color are the closest */
-@include rmd-theme(color, on-surface);
+@include theme-use-var(color, inverse-color);
-@include rmd-theme(background-color, primary);
-@include rmd-theme(color, on-primary);
+@include theme-use-var(background-color, primary-color);
+@include theme-use-var(color, on-primary-color);
-@include rmd-theme(background-color, secondary);
-@include rmd-theme(color, on-secondary);
+@include theme-use-var(background-color, secondary-color);
+@include theme-use-var(color, on-secondary-color);
-@include rmd-theme(background-color, warning);
-@include rmd-theme(color, on-warning);
+@include theme-use-var(background-color, warning-color);
+@include theme-use-var(color, on-warning-color);
-@include rmd-theme(background-color, error);
-@include rmd-theme(color, on-error);
+@include theme-use-var(background-color, error-color);
+@include theme-use-var(color, on-error-color);
-@include rmd-theme(background-color, success);
-@include rmd-theme(color, on-success);
+@include theme-use-var(background-color, success-color);
+@include theme-use-var(color, on-success-color);
-@include rmd-theme(color, text-primary-on-background);
+@include theme-use-var(color, text-primary-color);
-@include rmd-theme(color, text-secondary-on-background);
+@include theme-use-var(color, text-secondary-color);
-@include rmd-theme(color, text-hint-on-background);
+@include theme-use-var(color, text-hint-color);
-@include rmd-theme(color, text-disabled-on-background);
+@include theme-use-var(color, text-disabled-color);
-@include rmd-theme(color, text-icon-on-background);
+@include icon-use-var(color);
light-backgroundlight-surfacedark-backgrounddark-surfacetext-primary-on-lighttext-secondary-on-lighttext-hint-on-lighttext-disabled-on-lighttext-icon-on-lighttext-primary-on-darktext-secondary-on-darktext-hint-on-darktext-disabled-on-darktext-icon-on-dark-@include rmd-theme(background-color, light-background);
-@include rmd-theme(background-color, light-surface);
-@include rmd-theme(background-color, dark-background);
-@include rmd-theme(background-color, dark-surface);
-@include rmd-theme(color, text-primary-on-light);
-@include rmd-theme(color, text-secondary-on-light);
-@include rmd-theme(color, text-hint-on-light);
-@include rmd-theme(color, text-disabled-on-light);
-@include rmd-theme(color, text-icon-on-light);
-@include rmd-theme(color, text-primary-on-dark);
-@include rmd-theme(color, text-secondary-on-dark);
-@include rmd-theme(color, text-hint-on-dark);
-@include rmd-theme(color, text-disabled-on-dark);
-@include rmd-theme(color, text-icon-on-dark);
@function rmd-theme@function rmd-theme-text-color@mixin rmd-theme-tone@mixin rmd-theme-dark-elevation-styles@mixin rmd-theme-dark-elevation$rmd-theme-default-contrast-ratio$rmd-theme-better-contrast-colors$rmd-theme-no-css-variables-fallback$rmd-theme-define-colors-with-rgba$rmd-theme-light - use $color-scheme: light, $color-scheme: dark, or $color-scheme: system instead$rmd-theme-dark-class$rmd-theme-on-surface$rmd-theme-light-text-colors$rmd-theme-dark-text-colors$rmd-theme-primary-text-on-light-color$rmd-theme-secondary-text-on-light-color$rmd-theme-hint-text-on-light-color$rmd-theme-disabled-text-on-light-color$rmd-theme-primary-text-on-dark-color$rmd-theme-secondary-text-on-dark-color$rmd-theme-hint-text-on-dark-color$rmd-theme-disabled-text-on-dark-color$rmd-theme-icon-on-light-color$rmd-theme-icon-on-dark-color$rmd-theme-values@function rmd-theme-var -> theme-get-var@mixin rmd-theme -> theme-use-var@mixin rmd-theme-update-var -> theme-set-var@mixin rmd-theme-light -> use-light-theme (all components and themes) /
use-light-theme-colors (only base theme colors)@mixin rmd-theme-dark -> use-dark-theme (all components and themes) /
use-dark-theme-colors (only base theme colors)@mixin rmd-theme-get-swatch -> get-swatch@mixin rmd-theme-contrast-tone -> contrast-color@mixin rmd-theme-best-contrast-color -> contrast-color@mixin react-md-theme -> theme-styles$rmd-theme-dark-elevation -> $disable-dark-elevation$rmd-theme-primary -> $primary-color$rmd-theme-on-primary -> $on-primary-color$rmd-theme-secondary -> $secondary-color$rmd-theme-on-secondary -> $on-secondary-color$rmd-theme-warning -> $warning-color$rmd-theme-on-warning -> $on-warning-color$rmd-theme-error -> $error-color$rmd-theme-on-error -> $on-error-color$rmd-theme-success -> $success-color$rmd-theme-on-success -> $on-success-color$rmd-theme-light-background -> $light-theme-background-color$rmd-theme-light-surface -> $light-theme-surface-color$rmd-theme-light-primary-text-color -> $light-theme-text-primary-color$rmd-theme-light-secondary-text-color -> $light-theme-text-secondary-color$rmd-theme-light-hint-text-color -> $light-theme-text-hint-color$rmd-theme-light-disabled-text-color -> $light-theme-text-disabled-color$rmd-theme-dark-background -> $dark-theme-background-color and changed
the default value to always be #121212$rmd-theme-dark-surface -> $dark-theme-surface-color and changed the
default value to be if($disable-dark-elevation, colors.$grey-800, null)$rmd-theme-dark-primary-text-color -> $dark-theme-text-primary-color$rmd-theme-dark-secondary-text-color -> $dark-theme-text-secondary-color$rmd-theme-dark-hint-text-color -> $dark-theme-text-hint-color$rmd-theme-dark-disabled-text-color -> $dark-theme-text-disabled-color$rmd-theme-light-icon-color -> $icon-light-theme-color$rmd-theme-dark-icon-color -> $icon-dark-theme-color$rmd-theme-icon-on-background-color -> $icon-color$rmd-theme-background -> $background-color$rmd-theme-surface -> $surface-color$rmd-theme-primary-text-on-background-color -> $text-primary-color$rmd-theme-secondary-text-on-background-color -> $text-secondary-color$rmd-theme-hint-text-on-background-color -> $text-hint-color$rmd-theme-disabled-text-on-background-color -> $text-disabled-color$rmd-theme-dark-elevation-colors -> $dark-elevation-colors$rmd-theme-color-map -> $color-map$rmd-theme-primary-suffixes -> $primary-suffixes$rmd-theme-accent-suffixes -> $accent-suffixes$rmd-theme-colors -> $available-color-nameslight-background-color,
light-color, dark-background-color, and dark-color variables@function rmd-alert-theme@mixin rmd-snackbar@mixin rmd-toast$rmd-toast-two-line-min-height$rmd-toast-action-margin$rmd-toast-stacked-action-margin-top$rmd-toast-enter-duration$rmd-toast-exit-duration$rmd-alert-theme-values@function rmd-alert-theme-var -> snackbar-get-var@mixin rmd-alert-theme -> snackbar-use-var@mixin rmd-alert-theme-update-var -> snackbar-set-var@mxin react-md-alert -> snackbar-stylesbackground-color, color,
primary, on-primary, secondary, on-secondary,
default-background-color, default-color, default-light-background-color,
default-light-color, default-dark-background-color, default-dark-color,
dense-height, priminent-height, and prominent-dense-height variables@function rmd-app-bar-theme@mixin rmd-app-bar-fixed@mixin rmd-app-bar-themes@mixin rmd-app-bar-nav@mixin rmd-app-bar-action-position@mixin rmd-app-bar-action@mixin rmd-app-bar-offset@mixin rmd-app-bar-offsets$rmd-app-bar-nav-margin$rmd-app-bar-primary-background-color$rmd-app-bar-primary-color$rmd-app-bar-secondary-background-color$rmd-app-bar-secondary-color$rmd-app-bar-theme-values@function rmd-app-bar-theme-var -> app-bar-get-var@mixin rmd-app-bar-theme -> app-bar-use-var@mixin rmd-app-bar-theme-update-var -> app-bar-set-var@mixin rmd-app-bar-dense-theme -> app-bar-dense-variables@mixin react-md-app-bar -> app-bar-styles$rmd-app-bar-z-index -> $app-bar-fixed-z-index$rmd-app-bar-fixed-elevation -> $app-bar-fixed-elevation$rmd-app-bar-height -> $app-bar-height$rmd-app-bar-dense-height -> app-bar-dense-height$rmd-app-bar-prominent-height -> app-bar-prominent-height$rmd-app-bar-prominent-dense-height -> app-bar-prominent-dense-height$rmd-app-bar-keyline -> $app-bar-keyline$rmd-app-bar-title-keyline -> $app-bar-title-keyline$rmd-app-bar-title-nav-margin -> $app-bar-nav-keyline and is now configurable$rmd-app-bar-lr-margin -> $app-bar-horizontal-padding and is applied as
padding instead of margin$rmd-app-bar-default-light-theme-background-color ->
$app-bar-light-theme-surface-background-color and changed the default value
from $grey-100 to $light-theme-surface-color ($white)$rmd-app-bar-default-light-theme-color -> $app-bar-light-theme-surface-color$rmd-app-bar-default-dark-theme-background-color ->
$app-bar-dark-theme-surface-background-color and changed the default value
from $rmd-grey-900 to if($disable-dark-elevation, $grey-800, null)$rmd-app-bar-default-dark-theme-color ->
$app-bar-dark-theme-surface-color and changed the default value to $white$rmd-app-bar-default-background-color ->
$app-bar-surface-background-color$rmd-app-bar-default-color -> $app-bar-surface-colorThe previous version did not have any custom Sass/SCSS.
@function rmd-avatar-theme@mixin rmd-avatar-color and @mixin rmd-avtar-colors were removed in favor
of core.avatar-custom-color$rmd-avatar-theme-values@function rmd-avatar-theme-var -> avatar-get-var@mixin rmd-avatar-theme -> avatar-use-var@mixin rmd-avatar-theme-update-var -> avatar-set-var@mixin react-md-avatar -> avatar-styles$rmd-avatar-color -> $avatar-color$rmd-avatar-background-color -> $avatar-background-color$rmd-avatar-border-color -> $avatar-border-color and the default value
changed to transparent$rmd-avatar-border-radius -> $avatar-border-radius$rmd-avatar-size -> $avatar-size -> size$rmd-avatar-font-size -> $avatar-font-size$rmd-avatar-line-height -> $avatar-line-height$rmd-avatar-colors -> $avatar-colors@function rmd-badge-theme$rmd-badge-theme-values@function rmd-badge-theme-var -> badge-get-var@mixin rmd-badge-theme -> badge-use-var@mixin rmd-badge-theme-update-var -> badge-set-var@mixin react-md-badge -> badge-styles$rmd-badge-size -> $badge-size$rmd-badge-border-radius -> $badge-border-radius$rmd-badge-default-background-color -> $badge-greyscale-background-color
and changed the default value from rgba($rmd-black-base, 0.2) to
if($light-theme, #ccc, $grey-700)$rmd-badge-default-color -> $badge-greyscale-color$rmd-badge-font-size -> $badge-font-size$rmd-badge-offset-top -> $badge-offset-top and changed the default value
to $badge-offset (0)$rmd-bagde-offset-right -> $badge-offset-right and changed the default
value to $badge-offset (0)outline and outline-width
variables. Instead, use the core.theme-get-var(outline-color),
core.theme-set-var(outline-color), and core.theme-use-var(outline-color) with outline-color
or outline-widthtext-border-radius -> border-radiustext-height -> text-min-height@function rmd-button-theme@mixin rmd-button-base@mixin rmd-button-icon@mixin rmd-button@mixin rmd-button-floating-positions@mixin rmd-fab$rmd-button-text-icon-inherit-color$rmd-button-outline-width$rmd-button-outline-color$rmd-button-box-shadow$rmd-button-background-color$rmd-button-color$rmd-button-contained-elevation-transition-time$rmd-button-theme-values@function rmd-button-theme-var -> button-get-var@mixin rmd-button-theme -> button-use-var@mixin rmd-button-theme-update-var -> button-set-var@mixin rmd-button-reset -> button-unstyled@mixin rmd-button-unstyled -> button-unstyled@mixin rmd-button-text -> button-text-styles@mixin react-md-button -> button-styles$rmd-button-text-border-radius -> $button-text-border-radius$rmd-button-text-horizontal-padding -> $button-text-horizontal-padding$rmd-button-text-vertical-padding -> $button-text-vertical-padding$rmd-button-text-height -> $button-text-min-height$rmd-button-text-min-width -> $button-text-min-width$rmd-button-text-icon-size -> $button-text-icon-size$rmd-button-icon-border-radius -> $button-icon-border-radius$rmd-button-icon-size -> $button-icon-size and changed the default
value from 3rem to auto$rmd-button-contained-resting-elevation -> $button-contained-elevation$rmd-button-contained-pressed-elevation -> $button-contained-pressed-elevation$rmd-button-floating-z-index -> $button-floating-z-index$rmd-button-floating-margin -> $button-floating-margin$rmd-button-floating-positions -> $button-floating-positions$rmd-button-circular-progress-size -> $button-circular-progress-sizesecondary-color variables@function rmd-card-theme@mixin rmd-card@mixin rmd-card-header@mixin rmd-card-title@mixin rmd-card-subtitle@mixin rmd-card-content@mixin rmd-card-actions$rmd-card-dark-elevation-background-color$rmd-card-secondary-color$rmd-card-actions-padding$rmd-card-theme-values@function rmd-card-theme-var -> card-get-var@mixin rmd-card-theme -> card-use-var@mixin rmd-card-theme-update-var -> card-set-var@mixin react-md-card -> card-styles$rmd-card-elevation -> $card-elevation$rmd-card-light-background-color -> $card-light-background-color$rmd-card-dark-background-color -> $card-dark-background-color$rmd-card-background-color -> $card-background-color$rmd-card-color -> $card-color$rmd-card-base-elevation -> $card-raisable-start-elevation$rmd-card-raised-elevation -> $card-raisable-end-elevation$rmd-card-border-radius -> $card-border-radius$rmd-card-header-padding -> $card-header-padding$rmd-card-header-padding-top -> $card-header-padding-top$rmd-card-header-spacing -> $card-header-spacing$rmd-card-content-padding -> $card-content-padding$rmd-card-content-padding-extra -> $card-content-padding-bottom$rmd-card-border-color -> $card-border-color$rmd-card-border-width -> $card-border-widthbackground-color and color variables@function rmd-chip-theme@mixin rmd-chip$rmd-chip-disable-focus-background-color$rmd-chip-box-shadow$rmd-chip-theme-values@function rmd-chip-theme-var -> chip-get-var@mixin rmd-chip-theme -> chip-use-var@mixin rmd-chip-theme-update-var -> chip-set-var@mixin react-md-chip -> chip-styles$rmd-chip-height -> $chip-height$rmd-chip-border-radius -> $chip-border-radius$rmd-chip-small-spacing -> $chip-addon-left-padding$rmd-chip-medium-spacing -> $chip-addon-right-padding$rmd-chip-large-spacing -> $chip-horizonal-padding$rmd-chip-icon-size -> $chip-icon-size$rmd-chip-avatar-size -> $chip-avatar-size$rmd-chip-progress-size -> $chip-progress-size$rmd-chip-progress-width -> $chip-progress-width$rmd-chip-themed-background-color -> $chip-theme-background-color$rmd-chip-themed-color -> $chip-theme-color$rmd-chip-solid-light-background-color -> $chip-solid-light-background-color$rmd-chip-solid-light-color -> $chip-solid-light-color$rmd-chip-solid-light-disabled-background-color -> $chip-solid-light-disabled-background-color$rmd-chip-solid-dark-background-color -> $chip-solid-dark-background-color$rmd-chip-solid-dark-color -> $chip-solid-dark-color$rmd-chip-solid-dark-disabled-background-color -> $chip-solid-dark-disabled-background-color$rmd-chip-solid-background-color -> $chip-solid-background-color$rmd-chip-solid-color -> $chip-solid-color$rmd-chip-solid-disabled-background-color -> $chip-solid-disabled-background-color$rmd-chip-outline-light-background-color -> $chip-outline-light-background-color$rmd-chip-outline-light-color -> $chip-outline-light-text-color$rmd-chip-outline-dark-background-color -> $chip-outline-dark-background-color$rmd-chip-outline-dark-color -> $chip-outline-dark-text-color$rmd-chip-outline-background-color -> $chip-outline-background-color$rmd-chip-outline-color -> $chip-outline-text-color$rmd-chip-outline-border-color -> $chip-outline-color$rmd-chip-transition-duration -> $chip-outline-raisable-transition-durationbackground-color variable and
renamed min-width to width@function rmd-dialog-theme@mixin rmd-dialog@mixin rmd-dialog-header@mixin rmd-dialog-title@mixin rmd-dialog-content@mixin rmd-dialog-footer@mixin rmd-dialog-container@mixin rmd-dialog-overlay$rmd-dialog-light-background-color$rmd-dialog-dark-elevation-background-color$rmd-dialog-dark-background-color$rmd-dialog-background-color$rmd-dialog-theme-values@function rmd-dialog-theme-var -> dialog-get-var@mixin rmd-dialog-theme -> dialog-use-var@mixin rmd-dialog-theme-update-var -> dialog-set-var@mixin react-md-dialog -> dialog-styles$rmd-dialog-z-index -> $dialog-z-index$rmd-dialog-elevation -> $dialog-elevation$rmd-dialog-min-width -> $dialog-min-width$rmd-dialog-vertical-margin -> $dialog-vertical-margin$rmd-dialog-horizontal-margin -> $dialog-horizontal-margin$rmd-dialog-header-padding -> $dialog-header-padding$rmd-dialog-header-padding-bottom -> $dialog-header-padding-bottom$rmd-dialog-content-padding -> $dialog-content-padding$rmd-dialog-footer-padding -> $dialog-footer-padding$rmd-dialog-transition-distance -> $dialog-transition-distance$rmd-dialog-enter-duration -> $dialog-enter-duration$rmd-dialog-leave-duration -> $dialog-leave-durationbackground-color -> colorbackground-color-on-lightbackground-color-on-dark@function rmd-divider-theme@mixin rmd-divider$rmd-divider-theme-values@function rmd-divider-theme-var -> divider-get-var@mixin rmd-divider-theme -> divider-use-var@mixin rmd-divider-theme-update-var -> divider-set-var@mixin rmd-divider-border -> divider-border-style@mixin react-md-divider -> divider-styles$rmd-divider-size -> $divider-size$rmd-divider-max-size -> $divider-max-size$rmd-divider-inset -> $divider-inset$rmd-divider-spacing -> $divider-spacing$rmd-divider-vertical-spacing -> $divider-vertical-spacing$rmd-divider-background-color-on-light -> $divider-light-theme-color$rmd-divider-background-color-on-dark -> $divider-dark-theme-color$rmd-divider-background-color -> $divider-color@function rmd-elevation -> box-shadow@mixin rmd-elevation -> box-shadow@mixin rmd-elevation-transition -> box-shadow-transition$rmd-elevation-color -> $box-shadow-color$rmd-elevation-shadow-1-opacity -> $box-shadow-1-opacity$rmd-elevation-shadow-2-opacity -> $box-shadow-2-opacity$rmd-elevation-shadow-3-opacity -> $box-shadow-3-opacity$rmd-elevation-shadow-1-map -> $box-shadow-1-layers$rmd-elevation-shadow-2-map -> $box-shadow-2-layers$rmd-elevation-shadow-3-map -> $box-shadow-3-layers@function rmd-expansion-panel-theme@function rmd-expansion-panel-theme-var@mixin rmd-expansion-panel-theme@mixin rmd-expansion-panel-theme-update-var@mixin rmd-expansion-panel$rmd-expansion-panel-theme-values@mixin react-md-expansion-panel -> expansion-panel-styles$rmd-expansion-panel-spacing -> $expansion-panel-spacing$rmd-expansion-panel-header-padding -> $expansion-panel-padding$rmd-expansion-panel-expander-icon-spacing -> $expansion-panel-button-spacingform - form-get-var, form-use-var, form-set-var
active-colorfocus-colorlabel - label-get-var, label-use-var, label-set-var
floating-top -> floating-ylabel-left-offset -> floating-active-xlabel-top-offset -> floating-active-ylabel-active-padding -> active-paddinglabel-active-background-color -> active-background-colortext-field - text-field-get-var, text-field-use-var, text-field-set-var
addon-topaddon-margin-toptext-padding-left -> padding-lefttext-padding-right -> padding-righttext-padding-top -> padding-toptext-border-color -> border-colortext-filled-color -> filled-colortext-height -> heighttext-area - text-area-get-var, text-area-use-var, text-area-set-var
textarea-padding -> paddingslider - slider-get-var, slider-use-var, slider-set-varswitch - switch-get-var, switch-use-var, switch-set-var
track-background-colorerror-colorerror-hover-colordisabled-colortoggle-insettoggle-dense-insetindeterminate-heightindeterminate-dense-heightfloating-dense-toplistbox-background-colortext-offsettext-active-colortext-border-hover-colortext-label-heighttext-label-dense-heighttext-placeholder-heighttext-placeholder-dense-height@function rmd-form-theme@mixin rmd-label$rmd-label-floating-font-size$rmd-text-field-filled-border-radius$rmd-listbox-elevation$rmd-listbox-light-background-color$rmd-listbox-dark-elevation-background-color$rmd-listbox-dark-background-color$rmd-listbox-background-color$rmd-listbox-z-index$rmd-option-focused-styles$rmd-option-selected-offset$rmd-option-selected-content$rmd-option-horizontal-padding$rmd-text-field-active-color$rmd-form-theme-values@function rmd-form-theme-var -> form-get-var@mixin rmd-form-theme -> form-use-var@mixin rmd-form-theme-update-var -> form-set-var@mixin react-md-form:
@mixin form-message-styles@mixin fieldset-styles@mixin label-styles@mixin text-field-styles@mixin text-area-styles@mixin password-styles@mixin slider-styles@mixin input-toggle-styles@mixin switch-styles@mixin files-styles$rmd-label-font-size -> $label-font-size$rmd-label-floating-padding -> $label-floating-padding$rmd-label-floating-top -> $label-floating-y$rmd-label-floating-dense-top -> $label-floating-y-dense$rmd-label-padding -> $label-floating-padding$rmd-select-native-multiple-padding -> $select-native-select-multiple-padding$rmd-select-native-addon-top -> $select-native-select-addon-top$rmd-option-selected-styles -> $select-option-selected-styles$rmd-slider-include-vertical -> $slider-disable-vertical$rmd-slider-size -> $slider-size$rmd-slider-vertical-size -> $slider-vertical-size$rmd-slider-active-track-size -> $slider-track-active-size$rmd-slider-active-track-color -> $slider-track-active-color$rmd-slider-active-track-opacity -> $slider-track-active-opacity$rmd-slider-inactive-track-size -> $slider-track-inactive-size$rmd-slider-inactive-track-color -> $slider-track-inactive-color$rmd-slider-disabled-track-color -> $slider-track-disabled-color$rmd-slider-disabled-thumb-color -> $slider-thumb-disabled-color$rmd-slider-inactive-track-opacity -> $slider-track-inactive-opacity$rmd-slider-inactive-track-z-index -> $slider-track-inactive-z-index$rmd-slider-active-track-z-index -> $slider-track-active-z-index$rmd-slider-thumb-size -> $slider-thumb-size$rmd-slider-thumb-radius -> $slider-thumb-border-radius$rmd-slider-thumb-z-index -> $slider-thumb-z-index$rmd-slider-thumb-bubble-opacity -> $slider-thumb-bubble-opacity$rmd-slider-thumb-focus-scale -> $slider-thumb-focus-scale$rmd-slider-thumb-active-scale -> $slider-thumb-active-scale$rmd-slider-thumb-disabled-scale -> $slider-thumb-disabled-scale$rmd-slider-thumb-disabled-mask-scale -> $slider-thumb-disabled-mask-scale$rmd-slider-thumb-value-caret-size -> $slider-tooltip-caret-size$rmd-slider-thumb-value-offset -> $slider-tooltip-offset$rmd-slider-container-padding -> $slider-container-padding$rmd-slider-container-addon-spacing -> $slider-container-addon-spacing$rmd-text-field-light-border-color -> $text-field-light-border-color$rmd-text-field-dark-border-color -> $text-field-dark-border-color$rmd-text-field-border-color -> $text-field-border-color$rmd-text-field-light-border-hover-color -> $text-field-light-hover-border-color$rmd-text-field-dark-border-hover-color -> $text-field-dark-hover-border-color$rmd-text-field-border-hover-color -> $text-field-hover-border-color$rmd-text-field-border-radius -> $text-field-border-radius$rmd-text-field-border-width -> $text-field-border-width$rmd-text-field-border-width-active -> $text-field-border-width-active$rmd-text-field-label-height -> $text-field-label-height$rmd-text-field-label-dense-height -> $text-field-label-dense-height$rmd-text-field-height -> $text-field-height$rmd-text-field-dense-height -> $text-field-dense-height$rmd-text-field-outline-padding -> $text-field-outlined-padding$rmd-text-field-underline-label-padding-top -> $text-field-underlined-label-padding-top$rmd-text-field-underline-label-left-offset -> $text-field-underlined-label-left-offset$rmd-text-field-underline-dense-padding-top -> $text-field-underlined-placeholder-addon-padding-top$rmd-text-field-underline-padding -> $text-field-underlined-padding$rmd-text-field-filled-padding -> $text-field-filled-padding$rmd-text-field-filled-light-background-color -> $text-field-light-filled-background-color$rmd-text-field-filled-dark-background-color -> $text-field-dark-filled-background-color$rmd-text-field-filled-background-color -> $text-field-filled-background-color$rmd-text-field-addon-margin -> $text-field-addon-margin$rmd-textarea-vertical-padding -> $text-area-vertical-padding$rmd-textarea-addon-top -> $text-area-addon-top$rmd-form-message-min-height -> $form-message-min-height$rmd-form-message-margin-top -> $form-message-margin-top$rmd-form-message-margin-bottom -> $form-message-margin-bottom$rmd-form-message-counter-spacing -> $form-message-counter-spacing$rmd-form-message-font-size -> $form-message-font-sizetext-spacing -> spacing@function rmd-icon-theme@mixin rmd-icon-base@mixin rmd-icon-font@mixin rmd-icon-dense-theme@mixin rmd-icon-svg@mixin rmd-icon-text-icon-spacing@mixin rmd-icon-spaced-with-text@mixin rmd-icon-icon-rotator@mixin rmd-icon@mixin rmd-icon-spacing@mixin rmd-icon-material-icons-font-face@mixin rmd-icon-material-icons-class@mixin rmd-icon-host-material-icons$rmd-icon-material-icons-font$rmd-icon-theme-values@function rmd-icon-theme-var -> icon-get-var@mixin rmd-icon-theme -> icon-use-var@mixin rmd-icon-theme-update-var -> icon-set-var@mixin react-md-icon -> icon-styles$rmd-icon-color -> $icon-color$rmd-icon-size -> $icon-size$rmd-icon-dense-size -> $icon-dense-size$rmd-icon-include-dense -> $icon-disable-dense$rmd-icon-use-font-icons -> $icon-disable-font$rmd-icon-use-svg-icons -> $icon-disable-svg$rmd-icon-spacing-with-text -> $icon-spacing$rmd-icon-rotator-transition-time -> $icon-rotate-duration$rmd-icon-rotator-from -> $icon-rotate-from$rmd-icon-rotator-to -> $icon-rotate-tonav-width -> sizemini-nav-widthmain-offset@function rmd-layout-theme$rmd-layout-main-focus-shadow$rmd-layout-navigation-mini-z-index$rmd-layout-mini-navigation-width$rmd-layout-theme-values@function rmd-layout-theme-var -> layout-get-var@mixin rmd-layout-theme -> layout-use-var@mixin rmd-layout-theme-update-var -> layout-set-var@mixin react-md-layout -> layout-styles$rmd-layout-enter-duration -> $layout-enter-duration$rmd-layout-leave-duration -> $layout-leave-duration$rmd-layout-main-focus-z-index -> $layout-main-focus-z-index$rmd-layout-navigation-z-index -> $layout-navigation-z-index$rmd-layout-navigation-width -> $layout-navigation-static-width@function rmd-link-theme@mixin rmd-link@mixin rmd-link-skip$rmd-link-theme-values@function rmd-link-theme-var -> link-get-var@mixin rmd-link-theme -> link-use-var@mixin rmd-link-theme-update-var -> link-set-var@mixin react-md-link -> link-styles$rmd-link-transition-time -> $link-transition-duration$rmd-link-color -> $link-color$rmd-link-visited-color -> $link-visited-color$rmd-link-hover-color -> $link-hover-color$rmd-link-skip-z-index -> $link-skip-to-main-z-index$rmd-link-skip-styles -> $link-skip-to-main-styles$rmd-link-skip-active-styles -> $link-skip-to-main-active-stylesvertical-paddinghorizontal-paddingfont-sizetext-keylineitem-heightitem-medium-heightitem-large-heightitem-extra-large-heightitem-three-line-heightitem-vertical-paddingitem-horizontal-paddingitem-secondary-three-line-heightdense-font-sizedense-vertical-paddingdense-horizontal-paddingdense-item-heightdense-item-medium-heightdense-item-large-heightdense-item-extra-large-heightdense-item-three-line-heightdense-item-secondary-three-line-heightmedia-sizemedia-spacingmedia-large-size@function rmd-list-theme@mixin rmd-list-unstyled@mixin rmd-list-dense-theme@mixin rmd-list@mixin rmd-list-item-base@mixin rmd-list-item-dense-theme@mixin rmd-list-item-addon-spacing@mixin rmd-list-item@mixin rmd-list-subheader$rmd-list-line-height$rmd-list-font-size$rmd-list-theme-values@function rmd-list-theme-var -> list-get-var@mixin rmd-list-theme -> list-use-var@mixin rmd-list-theme-update-var -> list-set-var@mixin react-md-list -> list-styles$rmd-list-vertical-padding -> $list-vertical-padding$rmd-list-dense-vertical-padding -> $list-dense-vertical-padding$rmd-list-horizontal-padding -> $list-horizontal-padding$rmd-list-dense-horizontal-padding -> $list-dense-horizontal-padding$rmd-list-dense-font-size -> $list-dense-font-size$rmd-list-item-vertical-padding -> $list-item-vertical-padding$rmd-list-item-horizontal-padding -> $list-item-horizontal-padding$rmd-list-item-height -> $list-item-height$rmd-list-item-dense-height -> $list-item-dense-height$rmd-list-item-medium-height -> $list-item-medium-height$rmd-list-item-dense-medium-height -> $list-item-dense-medium-height$rmd-list-item-large-height -> $list-item-large-height$rmd-list-item-dense-large-height -> $list-item-dense-large-height$rmd-list-item-extra-large-height -> $list-item-extra-large-height$rmd-list-item-dense-extra-large-height -> $list-item-dense-extra-large-height$rmd-list-item-three-line-height -> $list-item-mulitline-height$rmd-list-item-dense-three-line-height -> $list-item-dense-mulitline-height$rmd-list-item-secondary-text-line-height -> $list-item-secondary-text-line-height$rmd-list-item-secondary-text-three-line-max-height -> $list-item-mulitline-max-height$rmd-list-item-dense-secondary-text-three-line-max-height -> $list-item-dense-mulitline-max-height$rmd-list-item-text-keyline -> $list-item-keyline$rmd-list-item-media-size -> $list-item-media-size$rmd-list-item-media-large-size -> $list-item-media-large-size$rmd-list-item-media-spacing -> $list-item-media-spacing$rmd-list-item-disabled-opacity -> $list-item-disabled-opacity@function rmd-media-theme@mixin rmd-media-responsive-item@mixin rmd-media-overlay-position$rmd-media-default-aspect-ratio$rmd-media-overlay-positions - use
$responsive-item-disable-overlay-{top|right|bottom|left|middle|center|absoluite-center}
variables instead$rmd-media-theme-values@mixin react-md-media -> responsive-item-styles@mixin rmd-media-aspect-ratio -> responsive-item-aspect-ratio@mixin rmd-media-aspect-ratio-container -> responsive-item-aspect-ratio-container@mixin rmd-media-forced-aspect-ratio-item -> responsive-item-forced-aspect-ratio@mixin rmd-media-overlay -> responsive-item-overlay-styles@mixin rmd-media-container-> responsive-item-base-styles$rmd-media-selectors -> $responsive-item-selectors$rmd-media-default-aspect-ratios -> $responsive-item-default-aspect-ratios$rmd-media-overlay-background-color -> $responsive-item-overlay-background-color$rmd-media-overlay-padding -> $responsive-item-overlay-padding$rmd-media-overlay-horizontal-width -> $responsive-item-overlay-horizontal-widthactive-opacity variable@function rmd-overlay-theme@mixin rmd-overlay$rmd-overlay-theme-values@function rmd-overlay-theme-var -> overlay-get-var@mixin rmd-overlay-theme -> overlay-use-var@mixin rmd-overlay-theme-update-var -> overlay-set-var@mixin react-md-overlay -> overlay-styles$rmd-overlay-z-index -> $overlay-z-index$rmd-overlay-transition-duration -> $overlay-transition-duration$rmd-overlay-color -> $overlay-background-colorcircular-width to circular-stroke-width@function rmd-progress-theme@mixin rmd-progress-animation@mixin rmd-linear-progress-styles@mixin rmd-linear-progress-bar@mixin rmd-linear-progress@mixin rmd-circular-progress$rmd-progress-theme-values@function rmd-progress-theme-var -> progress-get-var@mixin rmd-progress-theme -> progress-use-var@mixin rmd-progress-theme-update-var -> progress-set-var@mixin react-md-progress -> progress-styles$rmd-progress-include-linear -> $progress-disable-linear$rmd-progress-include-circular -> $progress-disable-circular$rmd-progress-color -> $progress-color$rmd-progress-background-color -> $progress-background-color$rmd-linear-progress-size -> $progress-linear-size$rmd-linear-progress-transition-duration -> $progress-linear-transition-duration$rmd-linear-progress-short-animation-delay -> $progress-linear-short-animation-delay$rmd-linear-progress-styles -> $progress-linear-styles$rmd-linear-progress-short-styles -> $progress-linear-short-styles$rmd-linear-progress-reverse-styles -> $progress-linear-reverse-styles$rmd-linear-progress-reverse-short-styles -> $progress-linear-reverse-short-styles$rmd-linear-progress-vertical-styles -> $progress-linear-vertical-styles$rmd-linear-progress-vertical-short-styles -> $progress-linear-vertical-short-styles$rmd-linear-progress-vertical-reverse-styles -> $progress-linear-vertical-reverse-styles$rmd-linear-progress-vertical-reverse-short-styles -> $progress-linear-vertical-reverse-short-styles$rmd-circular-progress-size -> $progress-circular-size$rmd-circular-progress-small-size -> $progress-circular-dense-size$rmd-circular-progress-stroke-width -> $progress-circular-stroke-width$rmd-circular-progress-dasharray -> $progress-circular-dasharray$rmd-circular-progress-transition-duration -> $progress-circular-transition-duration$rmd-circular-progress-start-offset -> $progress-circular-start-offset$rmd-circular-progress-end-offset -> $progress-circular-end-offset$rmd-circular-progress-rotate-styles -> $progress-circular-rotate-styles$rmd-circular-progress-dash-styles -> $progress-circular-dash-stylestouchable-max-height -> touch-max-heightbackground-colorraised-background-color@function rmd-sheet-theme@mixin rmd-sheet-positions@mixin rmd-sheet$rmd-sheet-overlay-z-index$rmd-sheet-light-background-color$rmd-sheet-dark-elevation-background-color$rmd-sheet-dark-background-color$rmd-sheet-background-color$rmd-sheet-raised-light-background-color$rmd-sheet-raised-dark-elevation-background-color$rmd-sheet-raised-dark-background-color$rmd-sheet-raised-background-color$rmd-sheet-positions$rmd-sheet-enabled-positions
$sheet-disable-position-{left|right|bottom|top} variables instead$rmd-sheet-theme-values@function rmd-sheet-theme-var -> sheet-get-var@mixin rmd-sheet-theme -> sheet-use-var@mixin rmd-sheet-theme-update-var -> sheet-set-var@mixin react-md-sheet -> sheet-styles$rmd-sheet-z-index -> $sheet-z-index$rmd-sheet-raised-z-index -> $sheet-raised-z-index$rmd-sheet-elevation -> $sheet-elevation$rmd-sheet-raised-elevation -> $sheet-raised-elevation$rmd-sheet-enter-duration -> $sheet-enter-duration$rmd-sheet-leave-duration -> $sheet-leave-duration$rmd-sheet-touch-margin -> $sheet-touch-margin$rmd-sheet-touch-width -> $sheet-touch-width$rmd-sheet-static-width -> $sheet-static-width$rmd-sheet-max-height -> $sheet-max-height$rmd-sheet-touchable-max-height -> $sheet-touch-max-height$rmd-sheet-recommended-min-height -> $sheet-recommended-min-height$rmd-sheet-recommended-max-height -> $sheet-recommended-max-heighthover-color -> hover-background-colorfocus-color -> focus-background-colorpressed-color -> press-background-colorselected-color -> selected-background-colorfocus-shadowlight-hover-colorlight-focus-colorlight-pressed-colorlight-selected-colorlight-ripple-background-colordark-hover-colordark-focus-colordark-pressed-colordark-selected-colordark-ripple-background-color@function rmd-states-theme$rmd-states-use-ripple - use $interaction-mode: none or $interaction-mode: press instead$rmd-states-use-pressed-states-fallback - use $interaction-mode: press instead$rmd-states-background-color$rmd-states-focus-shadow$rmd-states-theme-values@function rmd-states-theme-var -> interaction-get-var@mixin rmd-states-theme -> interaction-use-var@mixin rmd-states-theme-update-var -> interaction-set-var@mixin react-md-states -> interaction-styles$rmd-states-use-focus-shadow -> $interaction-focus-box-shadow and
changed the default value from true to false$rmd-states-use-focus-background -> $interaction-disable-focus-background$rmd-states-light-theme-background-color -> $interaction-light-surface-base-background-color$rmd-states-dark-theme-background-color -> $interaction-dark-surface-base-background-color$rmd-states-light-theme-hover-color -> $interaction-light-surface-hover-color$rmd-states-light-theme-focus-color -> $interaction-light-surface-focus-color$rmd-states-light-theme-pressed-color -> $interaction-light-surface-pressed-color$rmd-states-light-theme-selected-color -> $interaction-light-surface-selected-color$rmd-states-dark-theme-hover-color -> $interaction-dark-surface-hover-color$rmd-states-dark-theme-focus-color -> $interaction-dark-surface-focus-color$rmd-states-dark-theme-pressed-color -> $interaction-dark-surface-pressed-color$rmd-states-dark-theme-selected-color -> $interaction-dark-surface-selected-color$rmd-states-light-theme-ripple-background-color -> $interaction-light-surface-ripple-background-color$rmd-states-dark-theme-ripple-background-color -> $interaction-dark-surface-ripple-background-color$rmd-states-hover-color -> $interaction-hover-color$rmd-states-focus-color -> $interaction-focus-color$rmd-states-pressed-color -> $interaction-pressed-color$rmd-states-selected-color -> $interaction-selected-color$rmd-states-focus-shadow-width -> $interaction-focus-width$rmd-states-focus-shadow-color -> $interaction-focus-color$rmd-states-ripple-background-color -> $interaction-ripple-background-color$rmd-states-ripple-transform-duration -> $interaction-ripple-transform-duration$rmd-states-ripple-opacity-duration -> $interaction-ripple-opacity-duration$rmd-states-pressed-class-name -> $interaction-pressed-class-name
.rmd-states--pressed to rmd-pressedcell-h-padding -> cell-horizontal-paddingcell-v-padding -> cell-vertical-paddingcell-dense-height@function rmd-table-theme@mixin rmd-table@mixin rmd-thead@mixin rmd-table-cell-horizontal-alignments@mixin rmd-table-cell-vertical-alignments@mixin rmd-table-cell@mixin rmd-table-row$rmd-table-cell-horizontal-alignments$rmd-table-cell-vertical-alignments - use $table-disable-cell-align-{top|bottom} instead$rmd-table-theme-values@function rmd-table-theme-var -> table-get-var@mixin rmd-table-theme -> table-use-var@mixin rmd-table-theme-update-var -> table-set-var@mixin react-md-table -> table-styles$rmd-table-light-border-color -> $table-light-theme-border-color$rmd-table-dark-border-color -> $table-dark-theme-border-color$rmd-table-border-color -> $table-border-color$rmd-table-cell-horizontal-padding -> $table-cell-horizontal-padding$rmd-table-cell-vertical-padding -> $table-cell-vertical-padding$rmd-table-cell-sticky-position -> $table-sticky-cell-position$rmd-table-cell-sticky-z-index -> $table-sticky-cell-z-index$rmd-table-cell-height -> $table-cell-height$rmd-table-cell-dense-height -> $table-cell-dense-height$rmd-table-cell-color -> $table-cell-color$rmd-table-header-cell-height -> $table-cell-header-height$rmd-table-header-cell-dense-height -> $table-cell-header-dense-height$rmd-table-header-cell-color -> $table-cell-header-color$rmd-table-header-sticky-position -> $table-sticky-header-position$rmd-table-row-hover-color -> $table-row-hover-color$rmd-table-row-selected-color -> $table-row-selected-color$rmd-table-footer-sticky-position -> $table-sticky-footer-position$rmd-table-checkbox-padding -> $table-cell-input-toggle-horizontal-paddingactive -> active-colorinactive -> inactive-colordisabled -> disabled-colorindicator-color -> indicator-background@function rmd-tabs-theme@mixin rmd-tabs@mixin rmd-tab@mixin rmd-tab-panels@mixin rmd-tab-panel$rmd-tabs-positions$rmd-tab-theme-values@function rmd-tabs-theme-var -> tabs-get-var@mixin rmd-tabs-theme -> tabs-use-var@mixin rmd-tabs-theme-update-var -> tabs-set-var@mixin react-md-tabs -> tabs-styles$rmd-tab-height -> $tabs-height$rmd-tab-stacked-height -> $tabs-stacked-height$rmd-tab-horizontal-padding -> $tabs-horizontal-padding$rmd-tab-vertical-padding -> $tabs-vertical-padding$rmd-tab-min-width -> $tabs-min-width$rmd-tab-max-width -> $tabs-max-width$rmd-tab-indicator-color -> $tabs-indicator-background$rmd-tab-active-color -> $tabs-active-color$rmd-tab-inactive-color -> $tabs-inactive-color$rmd-tab-disabled-color -> $tabs-disabled-color$rmd-tab-active-indicator-height -> $tabs-indicator-height$rmd-tabs-scrollable-padding -> $tabs-tablist-scrollable-horizontal-paddingspacingfont-sizeline-heightdense-spacingdense-font-sizedense-line-height@function rmd-tooltip-theme@function rmd-tooltip-position-to-property@function rmd-tooltip-inverse-position@mixin rmd-tooltip-base@mixin rmd-tooltip-line-wrap@mixin rmd-tooltip$rmd-tooltip-font-size - use $tooltip-typography instead$rmd-tooltip-line-height - use $tooltip-typography instead$rmd-tooltip-dense-font-size - use $tooltip-dense-typography instead$rmd-tooltip-dense-line-height - use $tooltip-dense-typography instead$rmd-tooltip-line-wrap-vertical-padding$rmd-tooltip-dense-line-wrap-vertical-padding$rmd-tooltip-position-values - use $tooltip-disable-{above|below|left|right} variables instead$rmd-tooltip-theme-values@function rmd-tooltip-theme-var -> tooltip-get-var@mixin rmd-tooltip-theme -> tooltip-use-var@mixin rmd-tooltip-theme-update-var -> tooltip-set-var@mixin rmd-tooltip-dense-theme -> tooltip-dense-variables@mixin react-md-tooltip -> tooltip-styles$rmd-tooltip-background-color -> $tooltip-background-color$rmd-tooltip-color -> $tooltip-color$rmd-tooltip-max-width -> $tooltip-max-width$rmd-tooltip-enter-duration -> $tooltip-enter-duration$rmd-tooltip-exit-duration -> $tooltip-leave-duration$rmd-tooltip-z-index -> $tooltip-z-index$rmd-tooltip-min-height -> $tooltip-min-height$rmd-tooltip-horizontal-padding -> $tooltip-horizontal-padding$rmd-tooltip-spacing -> $tooltip-spacing$rmd-tooltip-dense-min-height -> $tooltip-dense-min-height$rmd-tooltip-dense-horizontal-padding -> $tooltip-dense-horizontal-padding$rmd-tooltip-dense-spacing -> $tooltip-dense-spacing$rmd-tooltip-border-radius -> $tooltip-border-radius$rmd-tooltip-transition-distance -> $tooltip-transition-distance@mixin rmd-transition@mixin rmd-transition-parent-shadow@mixin rmd-transition-pseudo-shadow@mixin rmd-collapse@mixin rmd-cross-fade$rmd-collapse-enter-transition-func$rmd-collapse-leave-transition-func$rmd-transitions@mixin rmd-transition-shadow-transition -> box-shadow-transition@mixin rmd-transition-classes -> rmd-scale-transition and rmd-scale-y-transition@mixin react-md-transition -> transition-styles$rmd-transition-sharp -> $sharp-timing-function$rmd-transition-standard -> $standard-timing-function$rmd-transition-acceleration -> $acceleration-timing-function$rmd-transition-deceleration -> $deceleration-timing-function$rmd-transition-standard-time -> $linear-duration$rmd-transition-enter-duration -> $enter-duration$rmd-transition-leave-duration -> $leave-duration$rmd-cross-fade-translate-distance -> $cross-fade-translate-distance$rmd-cross-fade-transition-duration -> $cross-fade-transition-duration$rmd-transition-scale-enter-duration -> $scale-transition-enter-duration$rmd-transition-scale-leave-duration -> $scale-transition-leave-duration$rmd-transition-scale-y-enter-duration -> $scale-y-transition-enter-duration$rmd-transition-scale-y-leave-duration -> $scale-y-transition-leave-durationincrementor -> item-padding-incrementorbase-padding -> item-padding-base@function rmd-tree-theme@mixin rmd-tree-depths@mixin rmd-tree-item-at-depth@mixin rmd-tree@mixin rmd-tree-item@mixin rmd-tree-group$rmd-tree-item-focused-styles$rmd-tree-item-keyboard-focused-styles$rmd-tree-max-depth$rmd-tree-theme-values@function rmd-tree-theme-var -> tree-get-var@mixin rmd-tree-theme -> tree-use-var@mixin rmd-tree-theme-update-var -> tree-set-var@mixin react-md-tree -> tree-styles$rmd-tree-item-padding-incrementor -> $tree-item-padding-incrementor$rmd-tree-item-padding-base -> $tree-item-padding-baseline-width -> line-lengthmobile-line-widthdesktop-line-width@function rmd-typography-theme@function rmd-typography-value@function rmd-typography-google-font-suffix@mixin rmd-typography-value@mixin rmd-typography-base@mixin rmd-typography@mixin rmd-text-container-base@mixin rmd-text-container-auto@mixin rmd-text-container@mixin rmd-typography-google-font-face@mixin rmd-typography-host-google-font$rmd-typography-mobile-max-line-length$rmd-typography-desktop-max-line-length$rmd-typography-colors$rmd-typography-google-font-weight-suffixes$rmd-typography-text-container-breakpoint$rmd-typography-theme-values@function rmd-typography-theme-var -> typography-get-var@mixin rmd-typography-theme -> typography-use-var@mixin rmd-typography-theme-update-var -> typography-set-var@mixin rmd-typography-text-overflow-ellipsis -> text-overflow@mixin rmd-typography-line-clamp -> line-clamp@mixin react-md-typography -> typography-styles$rmd-typography-font-family -> $font-family$rmd-typography-base -> $base-font-styles$rmd-typography-thin -> $font-weight-thin$rmd-typography-light -> $font-weight-light$rmd-typography-regular -> $font-weight-regular$rmd-typography-medium -> $font-weight-medium$rmd-typography-bold -> $font-weight-bold$rmd-typography-semi-bold -> $font-weight-semi-bold$rmd-typography-black -> $font-weight-black$rmd-typography-font-weights -> $font-weights$rmd-typography-default-font-weights -> $font-weights$rmd-typography-alignments -> $text-alignments$rmd-typography-decorations -> $text-decorfations$rmd-typography-transforms -> $text-transforms$rmd-typography-font-styles -> $font-styles$rmd-typography-default-headline-1-styles -> $headline-1-recommended-styles$rmd-typography-headline-1-styles -> $headline-1-custom-styles$rmd-typography-default-headline-2-styles -> $headline-2-recommended-styles$rmd-typography-headline-2-styles -> $headline-2-custom-styles$rmd-typography-default-headline-3-styles -> $headline-3-recommended-styles$rmd-typography-headline-3-styles -> $headline-3-custom-styles$rmd-typography-default-headline-4-styles -> $headline-4-recommended-styles$rmd-typography-headline-4-styles -> $headline-4-custom-styles$rmd-typography-default-headline-5-styles -> $headline-5-recommended-styles$rmd-typography-headline-5-styles -> $headline-5-custom-styles$rmd-typography-default-headline-6-styles -> $headline-6-recommended-styles$rmd-typography-headline-6-styles -> $headline-6-custom-styles$rmd-typography-default-subtitle-1-styles -> $subtitle-1-recommended-styles$rmd-typography-subtitle-1-styles -> $subtitle-1-custom-styles$rmd-typography-default-subtitle-2-styles -> $subtitle-2-recommended-styles$rmd-typography-subtitle-2-styles -> $subtitle-2-custom-styles$rmd-typography-default-body-1-styles -> $body-1-recommended-styles$rmd-typography-body-1-styles -> $body-1-custom-styles$rmd-typography-default-body-2-styles -> $body-2-recommended-styles$rmd-typography-body-2-styles -> $body-2-custom-styles$rmd-typography-default-caption-styles -> $caption-recommended-styles$rmd-typography-caption-styles -> $caption-custom-styles$rmd-typography-default-button-styles -> $button-recommended-styles$rmd-typography-button-styles -> $button-custom-styles$rmd-typography-default-overline-styles -> $overline-recommended-styles$rmd-typography-overline-styles -> $overline-custom-styles$rmd-typography-styles -> $typography-stylesrmd-utils-rtl-autormd-utils-rtl-auto-grouprmd-utils-block-centeredrmd-utils-absolute-centeredrmd-utils-scrollrmd-utils-hide-focus-outlinermd-utils-full-screenrmd-utils-sr-only-focusablermd-grid - try using the new Box component instead!rmd-grid-cell-fullrmd-grid-cell-sizermd-grid-cellrmd-grid-list-cell-sizermd-grid-list-cellrmd-grid-listreact-md-utils-gridrmd-utils-dense$rmd-grid-columns-var$rmd-grid-gutter-var$rmd-grid-cell-margin-var$rmd-grid-cell-size-var$rmd-grid-padding$rmd-grid-cell-margin$rmd-grid-columns$rmd-grid-phone-columns$rmd-grid-tablet-columns$rmd-grid-desktop-columns$rmd-grid-large-desktop-columns$rmd-grid-list-padding$rmd-grid-list-cell-margin$rmd-grid-list-cell-max-size$rmd-utils-ios-scroll-momentum$rmd-utils-auto-dense$rmd-utils-swappable-positions$rmd-utils-swappable-position-prefixes$rmd-utils-fix-moz-focus@function rmd-utils-validate -> validate@function rmd-utils-swap-position -> swap-position@function rmd-utils-negate-var -> negate-var@mixin rmd-utils-map-to-styles -> map-to-styles@mixin rmd-utils-rtl -> @rtl@mixin rmd-utils-pseudo-element -> pseudo-element@mixin rmd-utils-sr-only -> sr-only@mixin rmd-utils-hide-scrollbar -> hide-scrollbar@mixin rmd-utils-phone-media -> phone-media@mixin rmd-utils-tablet-media -> tablet-media@mixin rmd-utils-tablet-only-media -> tablet-only-media@mixin rmd-utils-desktop-media -> desktop-media@mixin rmd-utils-large-desktop-media -> large-desktop-media@mixin rmd-utils-optional-css-modules -> optional-css-modules@mixin rmd-utils-touch-only -> touch-only@mixin rmd-utils-keyboard-only -> keyboard-only@mixin rmd-utils-mouse-only -> mouse-only@mixin rmd-utils-base -> css-reset@mixin react-md-utils -> styles
$rmd-utils-enable-rtl -> $disable-rtl$rmd-utils-temporary-element-z-index -> $utils-temporary-element-z-index$rmd-utils-skip-validation -> $disable-validation$rmd-utils-phone-max-width -> $phone-max-width$rmd-utils-tablet-min-width -> $tablet-min-width$rmd-utils-tablet-max-width -> $tablet-max-width$rmd-utils-desktop-min-width -> $desktop-min-width$rmd-utils-large-desktop-min-width -> $large-desktop-min-width