Skip to content

Commit 78b7396

Browse files
committed
chore(website): Add migration guides for react-md major versions
1 parent b7264d3 commit 78b7396

File tree

9 files changed

+370
-7
lines changed

9 files changed

+370
-7
lines changed

packages/dev-utils/src/indexer/generate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function pluralize(s: string): string {
2525
}
2626

2727
function getMarkdownForRoute(route: string): string | null {
28-
const simpleReadmeMatch = route.match(/^\/(blog|guides)\//);
28+
const simpleReadmeMatch = route.match(/^\/(blog|guides|migration-guides)\//);
2929
const packageMarkdownMatch = route.match(/\/(installation|changelog)$/);
3030

3131
let path = "";

packages/dev-utils/src/indexer/getRoutes.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { getPackages, glob } from "../utils";
66

77
interface GetRoutesOptions {
88
guides: readonly string[];
9+
migrations: readonly string[];
910
changelogs: readonly string[];
1011
blogs: readonly string[];
1112
}
@@ -15,6 +16,7 @@ const replaceIds = (pathname: string, values: readonly string[]): string[] =>
1516

1617
export async function getRoutes({
1718
guides,
19+
migrations,
1820
changelogs,
1921
blogs,
2022
}: GetRoutesOptions): Promise<string[]> {
@@ -46,6 +48,8 @@ export async function getRoutes({
4648
return "";
4749
case "/guides/[id]":
4850
return replaceIds(pathname, guides);
51+
case "/migration-guides/[id]":
52+
return replaceIds(pathname, migrations);
4953
case "/blog/[id]":
5054
return replaceIds(pathname, blogs);
5155
case "/packages/[id]/api":

packages/dev-utils/src/indexer/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@ export async function indexer(): Promise<void> {
1212

1313
const guidesFolder = join(documentationRoot, src, "guides");
1414
const guides = await glob("*.md", { cwd: guidesFolder });
15+
const migrationsFolder = join(documentationRoot, src, "migration-guides");
16+
const migrations = await glob("*.md", { cwd: migrationsFolder });
1517
const changelogsFolder = join(documentationRoot, src, "changelogs");
1618
const changelogs = await glob("*.md", { cwd: changelogsFolder });
1719
const blogsFolder = join(documentationRoot, src, "blogs");
1820
const blogs = await glob("*.md", { cwd: blogsFolder, ignore: ["index.md"] });
1921

2022
const routes = await getRoutes({
2123
guides,
24+
migrations,
2225
changelogs,
2326
blogs,
2427
});

packages/dev-utils/src/indexer/parseMarkdown.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export function parseMarkdown(markdown: string): MarkdownResult {
1717
const joinedNames = getPackages().join("|");
1818
const anchors: TOCAnchor[] = [];
1919
const renderer = new Renderer({ gfm: true, sanitize: false });
20+
const forceAllHeadings = markdown.startsWith("# Migrate from v");
2021
renderer.heading = (text, _level, _raw, slugger) => {
2122
// if it is over 60 characters, it is probably not really a title
2223
const isNoMargin = text.includes("<!-- no-margin -->");
@@ -25,7 +26,7 @@ export function parseMarkdown(markdown: string): MarkdownResult {
2526
text = text.replace(/<!-- ([A-z]+(-[A-z]+)*) -->/g, "");
2627

2728
const isValidHeading =
28-
isForcedHeading || (text.length <= 60 && !isNoMargin);
29+
forceAllHeadings || isForcedHeading || (text.length <= 60 && !isNoMargin);
2930

3031
if (
3132
!isValidHeading ||

packages/dev-utils/src/utils/titles.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ export function toBreadcrumbPageTitle(
5858
default:
5959
title = "Server error";
6060
}
61+
} else if (/v\d+-to-v\d+$/.test(pathname)) {
62+
const [migration] = pathname.split("/").reverse();
63+
title = `Migration Guides - ${migration.replace(/-/g, " ")}`;
6164
} else {
6265
const parts = pathname.split("/").filter((p) => !!p && !/packages/.test(p));
6366
title = parts.map((p) => toTitle(p)).join(" - ");

packages/documentation/src/constants/navItems.tsx

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { snakeCase } from "lodash";
12
import { LayoutNavigationTree } from "@react-md/layout";
23
import {
34
BuildSVGIcon,
@@ -7,21 +8,21 @@ import {
78
HomeSVGIcon,
89
InfoOutlineSVGIcon,
910
LibraryBooksSVGIcon,
11+
TrendingUpSVGIcon,
1012
} from "@react-md/material-icons";
1113

1214
import MaterialDesignSVGIcon from "icons/MaterialDesignSVGIcon";
1315
import ReactSVGIcon from "icons/ReactSVGIcon";
1416
import createIdGenerator from "utils/createIdGenerator";
1517
import { toTitle } from "utils/toTitle";
1618

17-
import { PACKAGE_NAMES, SCSS_PACKAGES, TYPESCRIPT_PACKAGES } from "./packages";
1819
import {
19-
RouteNavItem,
20-
NavItem,
2120
DividerNavItem,
21+
NavItem,
22+
RouteNavItem,
2223
SubheaderNavItem,
2324
} from "./meta/types";
24-
import { snakeCase } from "lodash";
25+
import { PACKAGE_NAMES, SCSS_PACKAGES, TYPESCRIPT_PACKAGES } from "./packages";
2526

2627
const uuid = createIdGenerator("nav");
2728
const TSDOCS_PREFIX = "/tsdocs/modules/_react_md_";
@@ -128,6 +129,21 @@ const routes: readonly NavItem[] = [
128129
},
129130
],
130131
},
132+
{
133+
href: "/migration-guides",
134+
children: "Migration Guides",
135+
leftAddon: <TrendingUpSVGIcon />,
136+
routes: [
137+
{
138+
href: "/v3-to-v4",
139+
children: "v3 to v4",
140+
},
141+
{
142+
href: "/v2-to-v3",
143+
children: "v2 to v3",
144+
},
145+
],
146+
},
131147
{
132148
href: "/colors-and-theming",
133149
children: "Colors and Theming",
@@ -238,7 +254,10 @@ function createNavItem(
238254
}
239255

240256
const { href: currentItemId, routes = [], ...item } = navItem;
241-
const itemId = `${parentHref || ""}${currentItemId}`;
257+
const itemId = `${(parentHref || "").replace(
258+
/\/migration$/,
259+
""
260+
)}${currentItemId}`;
242261
const lastSlashIndex = itemId.lastIndexOf("/");
243262

244263
let href: string | undefined = itemId;
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Migrate from v2 to v3
2+
3+
#### Change node-sass to sass
4+
5+
Since
6+
[node-sass has been deprecated](https://github.com/sass/node-sass#node-sass) and
7+
[a new module system has been introduced](https://sass-lang.com/blog/the-module-system-is-launched)
8+
users must switch from `node-sass` to `sass` to use the latest features within
9+
`react-md`.
10+
11+
```sh
12+
npm update react-md
13+
npm uninstall node-sass
14+
npm install sass
15+
```
16+
17+
or with `yarn`
18+
19+
```sh
20+
yarn add react-md
21+
yarn remove node-sass
22+
yarn add sass
23+
```
24+
25+
#### Rename InteractionModeListener to UserInteractionModeListener
26+
27+
The `InteractionModeListener` was an alias for `UserInteractionModeListener` and
28+
has been removed.
29+
30+
#### Remove ResizeObserver
31+
32+
The `ResizeObserver` component has been removed in favor of using the
33+
`useResizeObserver` hook.
34+
35+
#### Update useResizeObserver to use the new API
36+
37+
```diff
38+
-const ref = useRef()
39+
-useResizeObserver({
40+
- target: ref,
41+
- onResize({ height, width, scrollHeight, scrollWidth, element }) {
42+
- // Do something
43+
- }
44+
- disableHeight: true,
45+
- disableWidth: true
46+
-});
47+
+const [ref] = useResizeObserver((resizeEvent) => {
48+
+ const { height, width, scrollHeight, scrollWidth, element } = resizeEvent
49+
+ // do something
50+
+}, { disableHeight: true, disableWidth: true });
51+
52+
return (
53+
<div ref={ref}>
54+
{children}
55+
</div>
56+
);
57+
```
58+
59+
#### Remove deprecated props from Tooltipped component
60+
61+
Since the `Tooltip` components now use the `HoverModeProvider`, the following
62+
props should be removed from the `Tooltipped` component:
63+
64+
- `onHide`
65+
- `onShow`
66+
- `tooltipId`
67+
- `hoverDelay`
68+
- `focusDelay`
69+
- `touchTimeout`
70+
- `positionThreshold`
71+
72+
#### Remove TooltipHoverModeConfig
73+
74+
This component has been removed since the `Tooltip` uses the
75+
`HoverModeProvider`.
76+
77+
#### Update useIndeterminateChecked to use an object as the second argument
78+
79+
```diff
80+
const {
81+
getProps,
82+
rootProps,
83+
// checkedValues,
84+
// setCheckedValues,
85+
-} = useIndeterminateChecked(condiments, ["Sprouts"], customOnChange);
86+
+} = useIndeterminateChecked(condiments, {
87+
+ onChange: customOnChange,
88+
+ defaultCheckedValues: ["Sprouts"],
89+
});
90+
```
91+
92+
#### Improve build performance by using the new react-md sass file
93+
94+
Part of the v3.0.0 release was to create a
95+
[new Sass import](https://github.com/mlaursen/react-md/blob/a9995e084480006a77f9123b95ce7275998fb406/packages/react-md/package.json#L9)
96+
that
97+
[merges all the .scss files into one](https://github.com/mlaursen/react-md/blob/3e738b4ab14fd7b4aab4f104b0d4120d226b7747/packages/dev-utils/src/utils/styles/combineAllFiles.ts#L105-L109)
98+
for two reasons:
99+
100+
1. This simplifies importing things from react-md into a single `@use` statement
101+
instead of multiple lines
102+
2. Drastically improves build performance in large projects because only one
103+
`.scss` file needs to be resolved.
104+
105+
`sass-loader` with `webpack` does not maintain context of other `.scss` files in
106+
your app so each time you `import './path/to/my.scss';` or
107+
`import styles from './path/to/my.module.scss';`, `sass-loader` will need to
108+
resolve every `@import` or `@use` statement found in that file recursively. The
109+
IO required for this is the whole reason build times can get slow in larger
110+
projects since there are about 200 `.scss` files within react-md that would need
111+
to be resolved. Combining all the files as a build step within react-md removes
112+
this issue and drastically increases build performance.
113+
114+
To get started, update your main `.scss` file that imports all the packages
115+
within `react-md` and generates the styles:
116+
117+
```diff
118+
-@import '~@react-md/alert/dist/mixins';
119+
-@import '~@react-md/app-bar/dist/mixins';
120+
-@import '~@react-md/avatar/dist/mixins';
121+
-@import '~@react-md/badge/dist/mixins';
122+
-@import '~@react-md/button/dist/mixins';
123+
-@import '~@react-md/card/dist/mixins';
124+
-@import '~@react-md/chip/dist/mixins';
125+
-@import '~@react-md/dialog/dist/mixins';
126+
-@import '~@react-md/divider/dist/mixins';
127+
-@import '~@react-md/elevation/dist/mixins';
128+
-@import '~@react-md/expansion-panel/dist/mixins';
129+
-@import '~@react-md/form/dist/mixins';
130+
-@import '~@react-md/icon/dist/mixins';
131+
-@import '~@react-md/layout/dist/mixins';
132+
-@import '~@react-md/link/dist/mixins';
133+
-@import '~@react-md/list/dist/mixins';
134+
-@import '~@react-md/media/dist/mixins';
135+
-@import '~@react-md/menu/dist/mixins';
136+
-@import '~@react-md/overlay/dist/mixins';
137+
-@import '~@react-md/progress/dist/mixins';
138+
-@import '~@react-md/sheet/dist/mixins';
139+
-@import '~@react-md/states/dist/mixins';
140+
-@import '~@react-md/table/dist/mixins';
141+
-@import '~@react-md/tabs/dist/mixins';
142+
-@import '~@react-md/theme/dist/mixins';
143+
-@import '~@react-md/tooltip/dist/mixins';
144+
-@import '~@react-md/transition/dist/mixins';
145+
-@import '~@react-md/tree/dist/mixins';
146+
-@import '~@react-md/typography/dist/mixins';
147+
-@import '~@react-md/utils/dist/mixins';
148+
+@use 'react-md' as *;
149+
150+
@include react-md-utils;
151+
```
152+
153+
Once the main styles have been generated, update the remaining `.scss` files in
154+
your app replacing `@import` statements of `react-md` packages to be
155+
`@use 'react-md' as *;`.
156+
157+
#### Overriding react-md Sass variables with the new module system
158+
159+
Check out the new #customizing-your-theme documentation to see how you can
160+
override `react-md` Sass variables with the new module system and a recommended
161+
setup.

0 commit comments

Comments
 (0)