Skip to content

Commit 6f0972f

Browse files
[lab] Migrate Timeline to TypeScript
1 parent 06ac77b commit 6f0972f

File tree

15 files changed

+85
-67
lines changed

15 files changed

+85
-67
lines changed

docs/pages/api-docs/timeline.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
filename: /packages/material-ui-lab/src/Timeline/Timeline.js
2+
filename: /packages/material-ui-lab/src/Timeline/Timeline.tsx
33
---
44

55
<!--- This documentation is automatically generated, do not try to edit it. -->
@@ -51,7 +51,7 @@ You can override the style of the component thanks to one of these customization
5151
- With a [global class name](/customization/components/#overriding-styles-with-global-class-names).
5252
- With a theme and an [`overrides` property](/customization/globals/#css).
5353

54-
If that's not sufficient, you can check the [implementation of the component](https://github.com/mui-org/material-ui/blob/next/packages/material-ui-lab/src/Timeline/Timeline.js) for more detail.
54+
If that's not sufficient, you can check the [implementation of the component](https://github.com/mui-org/material-ui/blob/next/packages/material-ui-lab/src/Timeline/Timeline.tsx) for more detail.
5555

5656
## Demos
5757

docs/scripts/buildApi.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ async function annotateComponentDefinition(context: {
134134
}
135135

136136
const { leadingComments } = node;
137-
const jsdocBlock = leadingComments !== null ? leadingComments[0] : null;
138-
if (leadingComments !== null && leadingComments.length > 1) {
137+
const jsdocBlock = leadingComments != null ? leadingComments[0] : null;
138+
if (leadingComments != null && leadingComments.length > 1) {
139139
throw new Error('Should only have a single leading jsdoc block');
140140
}
141141
if (jsdocBlock != null) {
@@ -372,7 +372,7 @@ async function buildDocs(options: {
372372
// no Object.assign to visually check for collisions
373373
reactAPI.forwardsRefTo = testInfo.forwardsRefTo;
374374

375-
// if (reactAPI.name !== 'TableCell') {
375+
// if (reactAPI.name !== 'Timeline') {
376376
// return;
377377
// }
378378

docs/src/modules/utils/find.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ function findPagesMarkdown(
4646
return pagesMarkdown;
4747
}
4848

49-
const componentRegex = /^(Unstable_)?([A-Z][a-z]+)+\.js/;
49+
const componentRegex = /^(Unstable_)?([A-Z][a-z]+)+\.(js|tsx)/;
5050

5151
/**
5252
* Returns the component source in a flat array.

docs/src/modules/utils/generateMarkdown.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ function generateImportStatement(reactAPI: ReactApi): string {
540540
(match, dash, pkg) => `@material-ui/${pkg || 'core'}`,
541541
)
542542
// convert things like `/Table/Table.js` to ``
543-
.replace(/\/([^/]+)\/\1\.js$/, '');
543+
.replace(/\/([^/]+)\/\1\.(js|tsx)$/, '');
544544
return `## Import
545545
546546
\`\`\`js

packages/material-ui-lab/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"build:node": "node ../../scripts/build node",
3030
"build:stable": "node ../../scripts/build stable",
3131
"build:copy-files": "node ../../scripts/copy-files.js",
32+
"build:types": "tsc -p tsconfig.build.json",
3233
"prebuild": "rimraf build",
3334
"release": "yarn build && npm publish build --tag next",
3435
"test": "cd ../../ && cross-env NODE_ENV=test mocha 'packages/material-ui-lab/**/*.test.{js,ts,tsx}'",

packages/material-ui-lab/src/Timeline/Timeline.d.ts

Lines changed: 0 additions & 41 deletions
This file was deleted.

packages/material-ui-lab/src/Timeline/Timeline.test.js renamed to packages/material-ui-lab/src/Timeline/Timeline.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Timeline from './Timeline';
44

55
describe('<Timeline />', () => {
66
const mount = createMount();
7-
let classes;
7+
let classes: Record<string, string>;
88

99
before(() => {
1010
classes = getClasses(<Timeline />);

packages/material-ui-lab/src/Timeline/Timeline.js renamed to packages/material-ui-lab/src/Timeline/Timeline.tsx

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import * as React from 'react';
22
import PropTypes from 'prop-types';
33
import clsx from 'clsx';
4+
import { InternalStandardProps as StandardProps } from '@material-ui/core';
45
import { capitalize } from '@material-ui/core/utils';
5-
import { withStyles } from '@material-ui/core/styles';
6+
import { withStyles, createStyles, WithStyles } from '@material-ui/core/styles';
67
import TimelineContext from './TimelineContext';
78

8-
export const styles = () => ({
9+
export const styles = createStyles({
910
/* Styles applied to the root element. */
1011
root: {
1112
display: 'flex',
@@ -21,12 +22,41 @@ export const styles = () => ({
2122
alignAlternate: {},
2223
});
2324

24-
const Timeline = React.forwardRef(function Timeline(props, ref) {
25+
export type TimelineClassKey = keyof WithStyles<typeof styles>['classes'];
26+
27+
export interface TimelineProps extends StandardProps<React.HTMLAttributes<HTMLUListElement>> {
28+
/**
29+
* The position where the timeline's content should appear.
30+
* @default 'left'
31+
*/
32+
align?: 'left' | 'right' | 'alternate';
33+
/**
34+
* The content of the component.
35+
*/
36+
children?: React.ReactNode;
37+
/**
38+
* Override or extend the styles applied to the component.
39+
*/
40+
classes?: {
41+
/** Styles applied to the root element. */
42+
root?: string;
43+
/** Styles applied to the root element if `align="left"`. */
44+
alignLeft?: string;
45+
/** Styles applied to the root element if `align="right"`. */
46+
alignRight?: string;
47+
/** Styles applied to the root element if `align="alternate"`. */
48+
alignAlternate?: string;
49+
};
50+
ref?: React.Ref<HTMLUListElement>;
51+
}
52+
53+
const Timeline = React.forwardRef<HTMLUListElement, TimelineProps>(function Timeline(props, ref) {
2554
const { align = 'left', classes, className, ...other } = props;
2655

2756
return (
2857
<TimelineContext.Provider value={{ align }}>
2958
<ul
59+
// @ts-expect-error unsafe string concat
3060
className={clsx(classes.root, classes[`align${capitalize(align)}`], className)}
3161
ref={ref}
3262
{...other}
@@ -38,7 +68,7 @@ const Timeline = React.forwardRef(function Timeline(props, ref) {
3868
Timeline.propTypes = {
3969
// ----------------------------- Warning --------------------------------
4070
// | These PropTypes are generated from the TypeScript type definitions |
41-
// | To update them edit the d.ts file and run "yarn proptypes" |
71+
// | To update them edit TypeScript types and run "yarn proptypes" |
4272
// ----------------------------------------------------------------------
4373
/**
4474
* The position where the timeline's content should appear.
@@ -59,4 +89,14 @@ Timeline.propTypes = {
5989
className: PropTypes.string,
6090
};
6191

92+
/**
93+
*
94+
* Demos:
95+
*
96+
* - [Timeline](https://material-ui.com/components/timeline/)
97+
*
98+
* API:
99+
*
100+
* - [Timeline API](https://material-ui.com/api/timeline/)
101+
*/
62102
export default withStyles(styles, { name: 'MuiTimeline' })(Timeline);

packages/material-ui-lab/src/Timeline/index.js

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"noEmit": false,
5+
"declaration": true,
6+
"rootDir": "./src",
7+
"outDir": "./build",
8+
"emitDeclarationOnly": true
9+
},
10+
"include": ["src/**/*.ts*"],
11+
"exclude": ["src/**/*.d.ts", "src/**/*.test.*", "./**/*.spec.*", "**/test-utils.tsx"],
12+
"references": [{ "path": "../material-ui/tsconfig.build.json" }]
13+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"extends": "../../tsconfig",
3-
"include": ["src/**/*", "test/**/*", "../material-ui/src/internal/svg-icons/Add.js"]
3+
"include": ["src/**/*", "test/**/*"]
44
}

packages/typescript-to-proptypes/src/injector.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ export function inject(
381381
plugins: [
382382
require.resolve('@babel/plugin-syntax-class-properties'),
383383
require.resolve('@babel/plugin-syntax-jsx'),
384+
[require.resolve('@babel/plugin-syntax-typescript'), { isTSX: true }],
384385
plugin(propTypes, options, propTypesToInject),
385386
...(babelPlugins || []),
386387
],

scripts/generateProptypes.ts

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,9 @@ const prettierConfig = prettier.resolveConfig.sync(process.cwd(), {
152152
});
153153

154154
async function generateProptypes(
155-
tsFile: string,
156-
jsFile: string,
157155
program: ttp.ts.Program,
156+
sourceFile: string,
157+
tsFile: string = sourceFile,
158158
): Promise<GenerateResult> {
159159
const proptypes = ttp.parseFromProgram(tsFile, program, {
160160
shouldResolveObject: ({ name }) => {
@@ -182,7 +182,9 @@ async function generateProptypes(
182182
});
183183
});
184184

185-
const jsContent = await fse.readFile(jsFile, 'utf8');
185+
const sourceContent = await fse.readFile(sourceFile, 'utf8');
186+
187+
const isTsFile = /(\.(ts|tsx))/.test(sourceFile);
186188

187189
const unstyledFile = tsFile.endsWith('Styled.d.ts')
188190
? tsFile.replace(/material-ui-lab|material-ui-core|Styled/g, (matched) => {
@@ -191,15 +193,17 @@ async function generateProptypes(
191193
})
192194
: null;
193195

194-
const result = ttp.inject(proptypes, jsContent, {
196+
const result = ttp.inject(proptypes, sourceContent, {
195197
removeExistingPropTypes: true,
196198
babelOptions: {
197-
filename: jsFile,
199+
filename: sourceFile,
198200
},
199201
comment: [
200202
'----------------------------- Warning --------------------------------',
201203
'| These PropTypes are generated from the TypeScript type definitions |',
202-
'| To update them edit the d.ts file and run "yarn proptypes" |',
204+
isTsFile
205+
? '| To update them edit TypeScript types and run "yarn proptypes" |'
206+
: '| To update them edit the d.ts file and run "yarn proptypes" |',
203207
'----------------------------------------------------------------------',
204208
].join('\n'),
205209
getSortLiteralUnions,
@@ -258,11 +262,11 @@ async function generateProptypes(
258262
return GenerateResult.Failed;
259263
}
260264

261-
const prettified = prettier.format(result, { ...prettierConfig, filepath: jsFile });
265+
const prettified = prettier.format(result, { ...prettierConfig, filepath: sourceFile });
262266
const formatted = fixBabelGeneratorIssues(prettified);
263-
const correctedLineEndings = fixLineEndings(jsContent, formatted);
267+
const correctedLineEndings = fixLineEndings(sourceContent, formatted);
264268

265-
await fse.writeFile(jsFile, correctedLineEndings);
269+
await fse.writeFile(sourceFile, correctedLineEndings);
266270
return GenerateResult.Success;
267271
}
268272

@@ -287,7 +291,7 @@ async function run(argv: HandlerArgv) {
287291
path.resolve(__dirname, '../packages/material-ui/src'),
288292
path.resolve(__dirname, '../packages/material-ui-lab/src'),
289293
].map((folderPath) =>
290-
glob('+([A-Z])*/+([A-Z])*.d.ts', {
294+
glob('+([A-Z])*/+([A-Z])*.*@(d.ts|ts|tsx)', {
291295
absolute: true,
292296
cwd: folderPath,
293297
}),
@@ -299,7 +303,7 @@ async function run(argv: HandlerArgv) {
299303
// Example: Modal/ModalManager.d.ts
300304
.filter((filePath) => {
301305
const folderName = path.basename(path.dirname(filePath));
302-
const fileName = path.basename(filePath, '.d.ts');
306+
const fileName = path.basename(filePath).replace(/(\.d\.ts|\.tsx|\.ts)/g, '');
303307

304308
return fileName === folderName;
305309
})
@@ -315,7 +319,8 @@ async function run(argv: HandlerArgv) {
315319
return GenerateResult.TODO;
316320
}
317321

318-
return generateProptypes(tsFile, jsFile, program);
322+
const sourceFile = tsFile.includes('.d.ts') ? tsFile.replace('.d.ts', '.js') : tsFile;
323+
return generateProptypes(program, sourceFile, tsFile);
319324
});
320325

321326
const results = await Promise.all(promises);

0 commit comments

Comments
 (0)