diff --git a/docs/pages/api-docs/timeline.md b/docs/pages/api-docs/timeline.md
index a9b65b1a809d7b..5dfc02e404734e 100644
--- a/docs/pages/api-docs/timeline.md
+++ b/docs/pages/api-docs/timeline.md
@@ -1,5 +1,5 @@
---
-filename: /packages/material-ui-lab/src/Timeline/Timeline.js
+filename: /packages/material-ui-lab/src/Timeline/Timeline.tsx
---
@@ -11,9 +11,9 @@ filename: /packages/material-ui-lab/src/Timeline/Timeline.js
## Import
```js
-import Timeline from '@material-ui/lab/Timeline';
+import Timeline from '@material-ui/lab/Timeline/Timeline.tsx/Timeline';
// or
-import { Timeline } from '@material-ui/lab';
+import { Timeline } from '@material-ui/lab/Timeline/Timeline.tsx';
```
You can learn more about the difference by [reading this guide](/guides/minimizing-bundle-size/).
@@ -28,9 +28,6 @@ The `MuiTimeline` name can be used for providing [default props](/customization/
| Name | Type | Default | Description |
|:-----|:-----|:--------|:------------|
-| align | 'alternate'
| 'left'
| 'right' | 'left' | The position where the timeline's content should appear. |
-| children | node | | The content of the component. |
-| classes | object | | Override or extend the styles applied to the component. See [CSS API](#css) below for more details. |
The `ref` is forwarded to the root element.
@@ -51,7 +48,7 @@ You can override the style of the component thanks to one of these customization
- With a [global class name](/customization/components/#overriding-styles-with-global-class-names).
- With a theme and an [`overrides` property](/customization/globals/#css).
-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.
+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.
## Demos
diff --git a/docs/scripts/buildApi.ts b/docs/scripts/buildApi.ts
index 543fd7d1483765..a91bdfab8f28f1 100644
--- a/docs/scripts/buildApi.ts
+++ b/docs/scripts/buildApi.ts
@@ -134,8 +134,8 @@ async function annotateComponentDefinition(context: {
}
const { leadingComments } = node;
- const jsdocBlock = leadingComments !== null ? leadingComments[0] : null;
- if (leadingComments !== null && leadingComments.length > 1) {
+ const jsdocBlock = leadingComments != null ? leadingComments[0] : null;
+ if (leadingComments != null && leadingComments.length > 1) {
throw new Error('Should only have a single leading jsdoc block');
}
if (jsdocBlock != null) {
@@ -372,7 +372,7 @@ async function buildDocs(options: {
// no Object.assign to visually check for collisions
reactAPI.forwardsRefTo = testInfo.forwardsRefTo;
- // if (reactAPI.name !== 'TableCell') {
+ // if (reactAPI.name !== 'Timeline') {
// return;
// }
diff --git a/docs/src/modules/utils/find.js b/docs/src/modules/utils/find.js
index d41c5e368873f3..60ef8d9a6ae72e 100644
--- a/docs/src/modules/utils/find.js
+++ b/docs/src/modules/utils/find.js
@@ -46,7 +46,7 @@ function findPagesMarkdown(
return pagesMarkdown;
}
-const componentRegex = /^(Unstable_)?([A-Z][a-z]+)+\.js/;
+const componentRegex = /^(Unstable_)?([A-Z][a-z]+)+\.(js|tsx)/;
/**
* Returns the component source in a flat array.
diff --git a/packages/material-ui-lab/package.json b/packages/material-ui-lab/package.json
index 6252a7d11d41c7..f16178a554c06a 100644
--- a/packages/material-ui-lab/package.json
+++ b/packages/material-ui-lab/package.json
@@ -29,6 +29,7 @@
"build:node": "node ../../scripts/build node",
"build:stable": "node ../../scripts/build stable",
"build:copy-files": "node ../../scripts/copy-files.js",
+ "build:types": "tsc -p tsconfig.build.json",
"prebuild": "rimraf build",
"release": "yarn build && npm publish build --tag next",
"test": "cd ../../ && cross-env NODE_ENV=test mocha 'packages/material-ui-lab/**/*.test.{js,ts,tsx}'",
diff --git a/packages/material-ui-lab/src/Timeline/Timeline.d.ts b/packages/material-ui-lab/src/Timeline/Timeline.d.ts
deleted file mode 100644
index 0b4606c05a79ff..00000000000000
--- a/packages/material-ui-lab/src/Timeline/Timeline.d.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import * as React from 'react';
-import { InternalStandardProps as StandardProps } from '@material-ui/core';
-
-export interface TimelineProps extends StandardProps> {
- /**
- * The content of the component.
- */
- children?: React.ReactNode;
- /**
- * Override or extend the styles applied to the component.
- */
- classes?: {
- /** Styles applied to the root element. */
- root?: string;
- /** Styles applied to the root element if `align="left"`. */
- alignLeft?: string;
- /** Styles applied to the root element if `align="right"`. */
- alignRight?: string;
- /** Styles applied to the root element if `align="alternate"`. */
- alignAlternate?: string;
- };
- /**
- * The position where the timeline's content should appear.
- * @default 'left'
- */
- align?: 'left' | 'right' | 'alternate';
-}
-
-export type TimelineClassKey = keyof NonNullable;
-
-/**
- *
- * Demos:
- *
- * - [Timeline](https://material-ui.com/components/timeline/)
- *
- * API:
- *
- * - [Timeline API](https://material-ui.com/api/timeline/)
- */
-export default function Timeline(props: TimelineProps): JSX.Element;
diff --git a/packages/material-ui-lab/src/Timeline/Timeline.test.js b/packages/material-ui-lab/src/Timeline/Timeline.test.tsx
similarity index 92%
rename from packages/material-ui-lab/src/Timeline/Timeline.test.js
rename to packages/material-ui-lab/src/Timeline/Timeline.test.tsx
index 1010bc3754d6c4..ffdbc7dd48d813 100644
--- a/packages/material-ui-lab/src/Timeline/Timeline.test.js
+++ b/packages/material-ui-lab/src/Timeline/Timeline.test.tsx
@@ -4,7 +4,7 @@ import Timeline from './Timeline';
describe('', () => {
const mount = createMount();
- let classes;
+ let classes: Record;
before(() => {
classes = getClasses();
diff --git a/packages/material-ui-lab/src/Timeline/Timeline.js b/packages/material-ui-lab/src/Timeline/Timeline.tsx
similarity index 51%
rename from packages/material-ui-lab/src/Timeline/Timeline.js
rename to packages/material-ui-lab/src/Timeline/Timeline.tsx
index b862e2b5a4e648..5515cc72ad2f7d 100644
--- a/packages/material-ui-lab/src/Timeline/Timeline.js
+++ b/packages/material-ui-lab/src/Timeline/Timeline.tsx
@@ -1,11 +1,12 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
+import { InternalStandardProps as StandardProps } from '@material-ui/core';
import { capitalize } from '@material-ui/core/utils';
-import { withStyles } from '@material-ui/core/styles';
+import { withStyles, createStyles, WithStyles } from '@material-ui/core/styles';
import TimelineContext from './TimelineContext';
-export const styles = () => ({
+export const styles = createStyles({
/* Styles applied to the root element. */
root: {
display: 'flex',
@@ -21,12 +22,41 @@ export const styles = () => ({
alignAlternate: {},
});
-const Timeline = React.forwardRef(function Timeline(props, ref) {
+export type TimelineClassKey = keyof WithStyles['classes'];
+
+export interface TimelineProps extends StandardProps> {
+ /**
+ * The content of the component.
+ */
+ children?: React.ReactNode;
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: {
+ /** Styles applied to the root element. */
+ root?: string;
+ /** Styles applied to the root element if `align="left"`. */
+ alignLeft?: string;
+ /** Styles applied to the root element if `align="right"`. */
+ alignRight?: string;
+ /** Styles applied to the root element if `align="alternate"`. */
+ alignAlternate?: string;
+ };
+
+ /**
+ * The position where the timeline's content should appear.
+ * @default 'left'
+ */
+ align?: 'left' | 'right' | 'alternate';
+}
+
+const Timeline = React.forwardRef(function Timeline(props, ref) {
const { align = 'left', classes, className, ...other } = props;
return (
= Omit<
> &
// each component declares it's classes in a separate interface for proper JSDOC
StyledComponentProps & {
- ref?: C extends { ref?: infer RefType } ? RefType : React.Ref;
+ ref?: C extends { ref?: infer RefType } ? RefType : React.Ref;
// TODO: Remove implicit props. Up to each component.
className?: string;
style?: React.CSSProperties;
diff --git a/packages/typescript-to-proptypes/src/generator.ts b/packages/typescript-to-proptypes/src/generator.ts
index 5eb978145978aa..78e0582d1392c2 100644
--- a/packages/typescript-to-proptypes/src/generator.ts
+++ b/packages/typescript-to-proptypes/src/generator.ts
@@ -2,6 +2,14 @@ import _ from 'lodash';
import * as t from './types';
export interface GenerateOptions {
+ /**
+ * If source itself written in typescript prop-types disable prop-types validation
+ * by injecting propTypes as
+ * ```jsx
+ * .propTypes = { ... } as any
+ * ```
+ */
+ disableTypescriptPropTypesValidation?: boolean;
/**
* Enable/disable the default sorting (ascending) or provide your own sort function
* @default true
@@ -86,6 +94,7 @@ function defaultSortLiteralUnions(a: t.LiteralType, b: t.LiteralType) {
*/
export function generate(component: t.Component, options: GenerateOptions = {}): string {
const {
+ disableTypescriptPropTypesValidation = false,
sortProptypes = true,
importedName = 'PropTypes',
includeJSDoc = true,
@@ -304,5 +313,11 @@ export function generate(component: t.Component, options: GenerateOptions = {}):
options.comment &&
`// ${options.comment.split(/\r?\n/gm).reduce((prev, curr) => `${prev}\n// ${curr}`)}\n`;
- return `${component.name}.propTypes = {\n${comment !== undefined ? comment : ''}${generated}\n}`;
+ const componentNameNode = disableTypescriptPropTypesValidation
+ ? `(${component.name} as any)`
+ : component.name;
+
+ return `${componentNameNode}.propTypes = {\n${
+ comment !== undefined ? comment : ''
+ }${generated}\n}`;
}
diff --git a/packages/typescript-to-proptypes/src/injector.ts b/packages/typescript-to-proptypes/src/injector.ts
index d4a56931b95d3c..239daec0b5f8b1 100644
--- a/packages/typescript-to-proptypes/src/injector.ts
+++ b/packages/typescript-to-proptypes/src/injector.ts
@@ -381,6 +381,7 @@ export function inject(
plugins: [
require.resolve('@babel/plugin-syntax-class-properties'),
require.resolve('@babel/plugin-syntax-jsx'),
+ [require.resolve('@babel/plugin-syntax-typescript'), { isTSX: true }],
plugin(propTypes, options, propTypesToInject),
...(babelPlugins || []),
],
diff --git a/scripts/generateProptypes.ts b/scripts/generateProptypes.ts
index 035ed8d2c9b843..1f7d84d9cb9fde 100644
--- a/scripts/generateProptypes.ts
+++ b/scripts/generateProptypes.ts
@@ -152,9 +152,9 @@ const prettierConfig = prettier.resolveConfig.sync(process.cwd(), {
});
async function generateProptypes(
- tsFile: string,
- jsFile: string,
program: ttp.ts.Program,
+ sourceFile: string,
+ tsFile: string = sourceFile,
): Promise {
const proptypes = ttp.parseFromProgram(tsFile, program, {
shouldResolveObject: ({ name }) => {
@@ -182,7 +182,9 @@ async function generateProptypes(
});
});
- const jsContent = await fse.readFile(jsFile, 'utf8');
+ const sourceContent = await fse.readFile(sourceFile, 'utf8');
+
+ const isTsFile = /(\.(ts|tsx))/.test(sourceFile);
const unstyledFile = tsFile.endsWith('Styled.d.ts')
? tsFile.replace(/material-ui-lab|material-ui-core|Styled/g, (matched) => {
@@ -191,15 +193,18 @@ async function generateProptypes(
})
: null;
- const result = ttp.inject(proptypes, jsContent, {
+ const result = ttp.inject(proptypes, sourceContent, {
removeExistingPropTypes: true,
+ disableTypescriptPropTypesValidation: isTsFile,
babelOptions: {
- filename: jsFile,
+ filename: sourceFile,
},
comment: [
'----------------------------- Warning --------------------------------',
'| These PropTypes are generated from the TypeScript type definitions |',
- '| To update them edit the d.ts file and run "yarn proptypes" |',
+ isTsFile
+ ? '| To update them edit TypeScript types and run "yarn proptypes" |'
+ : '| To update them edit the d.ts file and run "yarn proptypes" |',
'----------------------------------------------------------------------',
].join('\n'),
getSortLiteralUnions,
@@ -258,11 +263,11 @@ async function generateProptypes(
return GenerateResult.Failed;
}
- const prettified = prettier.format(result, { ...prettierConfig, filepath: jsFile });
+ const prettified = prettier.format(result, { ...prettierConfig, filepath: sourceFile });
const formatted = fixBabelGeneratorIssues(prettified);
- const correctedLineEndings = fixLineEndings(jsContent, formatted);
+ const correctedLineEndings = fixLineEndings(sourceContent, formatted);
- await fse.writeFile(jsFile, correctedLineEndings);
+ await fse.writeFile(sourceFile, correctedLineEndings);
return GenerateResult.Success;
}
@@ -287,7 +292,7 @@ async function run(argv: HandlerArgv) {
path.resolve(__dirname, '../packages/material-ui/src'),
path.resolve(__dirname, '../packages/material-ui-lab/src'),
].map((folderPath) =>
- glob('+([A-Z])*/+([A-Z])*.d.ts', {
+ glob('+([A-Z])*/+([A-Z])*.*@(d.ts|ts|tsx)', {
absolute: true,
cwd: folderPath,
}),
@@ -299,13 +304,14 @@ async function run(argv: HandlerArgv) {
// Example: Modal/ModalManager.d.ts
.filter((filePath) => {
const folderName = path.basename(path.dirname(filePath));
- const fileName = path.basename(filePath, '.d.ts');
+ const fileName = path.basename(filePath).replace(/(\.d\.ts|\.tsx|\.ts)/g, '');
return fileName === folderName;
})
.filter((filePath) => {
return filePattern.test(filePath);
});
+
const program = ttp.createTSProgram(files, tsconfig);
const promises = files.map>(async (tsFile) => {
@@ -315,7 +321,8 @@ async function run(argv: HandlerArgv) {
return GenerateResult.TODO;
}
- return generateProptypes(tsFile, jsFile, program);
+ const sourceFile = tsFile.includes('.d.ts') ? tsFile.replace('.d.ts', '.js') : tsFile;
+ return generateProptypes(program, sourceFile, tsFile);
});
const results = await Promise.all(promises);