diff --git a/docs/pages/base-ui/api/button.json b/docs/pages/base-ui/api/button.json
index d72db39a0f1984..54360651da6723 100644
--- a/docs/pages/base-ui/api/button.json
+++ b/docs/pages/base-ui/api/button.json
@@ -1,11 +1,6 @@
{
"props": {
- "action": {
- "type": {
- "name": "union",
- "description": "func
| { current?: { focusVisible: func } }"
- }
- },
+ "action": { "type": { "name": "custom", "description": "ref" } },
"disabled": { "type": { "name": "bool" }, "default": "false" },
"focusableWhenDisabled": { "type": { "name": "bool" }, "default": "false" },
"slotProps": {
diff --git a/docs/pages/base-ui/api/tab.json b/docs/pages/base-ui/api/tab.json
index 16d505a50d9b90..93500b1926bae0 100644
--- a/docs/pages/base-ui/api/tab.json
+++ b/docs/pages/base-ui/api/tab.json
@@ -1,11 +1,6 @@
{
"props": {
- "action": {
- "type": {
- "name": "union",
- "description": "func
| { current?: { focusVisible: func } }"
- }
- },
+ "action": { "type": { "name": "custom", "description": "ref" } },
"disabled": { "type": { "name": "bool" }, "default": "false" },
"onChange": { "type": { "name": "func" } },
"slotProps": {
diff --git a/docs/pages/joy-ui/api/button.json b/docs/pages/joy-ui/api/button.json
index 0f5a178a82b022..c5e61d3252e72e 100644
--- a/docs/pages/joy-ui/api/button.json
+++ b/docs/pages/joy-ui/api/button.json
@@ -1,11 +1,6 @@
{
"props": {
- "action": {
- "type": {
- "name": "union",
- "description": "func
| { current?: { focusVisible: func } }"
- }
- },
+ "action": { "type": { "name": "custom", "description": "ref" } },
"color": {
"type": {
"name": "union",
diff --git a/docs/pages/joy-ui/api/icon-button.json b/docs/pages/joy-ui/api/icon-button.json
index 7e938464261723..04d01296bbe717 100644
--- a/docs/pages/joy-ui/api/icon-button.json
+++ b/docs/pages/joy-ui/api/icon-button.json
@@ -1,11 +1,6 @@
{
"props": {
- "action": {
- "type": {
- "name": "union",
- "description": "func
| { current?: { focusVisible: func } }"
- }
- },
+ "action": { "type": { "name": "custom", "description": "ref" } },
"color": {
"type": {
"name": "union",
diff --git a/docs/pages/joy-ui/api/list-item-button.json b/docs/pages/joy-ui/api/list-item-button.json
index 88108c69a213d6..2757a522f168e3 100644
--- a/docs/pages/joy-ui/api/list-item-button.json
+++ b/docs/pages/joy-ui/api/list-item-button.json
@@ -1,11 +1,6 @@
{
"props": {
- "action": {
- "type": {
- "name": "union",
- "description": "func
| { current?: { focusVisible: func } }"
- }
- },
+ "action": { "type": { "name": "custom", "description": "ref" } },
"autoFocus": { "type": { "name": "bool" }, "default": "false" },
"children": { "type": { "name": "node" } },
"color": {
diff --git a/docs/pages/joy-ui/api/select.json b/docs/pages/joy-ui/api/select.json
index af8f6611339328..ef30d73f5dc632 100644
--- a/docs/pages/joy-ui/api/select.json
+++ b/docs/pages/joy-ui/api/select.json
@@ -1,11 +1,6 @@
{
"props": {
- "action": {
- "type": {
- "name": "union",
- "description": "func
| { current?: { focusVisible: func } }"
- }
- },
+ "action": { "type": { "name": "custom", "description": "ref" } },
"autoFocus": { "type": { "name": "bool" } },
"color": {
"type": {
diff --git a/docs/pages/joy-ui/api/tab.json b/docs/pages/joy-ui/api/tab.json
index 43cf0eca137669..c8b5c92b395664 100644
--- a/docs/pages/joy-ui/api/tab.json
+++ b/docs/pages/joy-ui/api/tab.json
@@ -1,11 +1,6 @@
{
"props": {
- "action": {
- "type": {
- "name": "union",
- "description": "func
| { current?: { focusVisible: func } }"
- }
- },
+ "action": { "type": { "name": "custom", "description": "ref" } },
"color": {
"type": {
"name": "union",
diff --git a/docs/pages/material-ui/api/button-base.json b/docs/pages/material-ui/api/button-base.json
index e383c1ff531d6d..fee7a61f961964 100644
--- a/docs/pages/material-ui/api/button-base.json
+++ b/docs/pages/material-ui/api/button-base.json
@@ -20,12 +20,7 @@
"additionalInfo": { "sx": true }
},
"TouchRippleProps": { "type": { "name": "object" } },
- "touchRippleRef": {
- "type": {
- "name": "union",
- "description": "func
| { current?: { pulsate: func, start: func, stop: func } }"
- }
- }
+ "touchRippleRef": { "type": { "name": "custom", "description": "ref" } }
},
"name": "ButtonBase",
"imports": [
diff --git a/packages/mui-base/src/Button/Button.tsx b/packages/mui-base/src/Button/Button.tsx
index 6be0c51d98f9c3..fd12f5c90249c2 100644
--- a/packages/mui-base/src/Button/Button.tsx
+++ b/packages/mui-base/src/Button/Button.tsx
@@ -1,5 +1,6 @@
'use client';
import * as React from 'react';
+import { refType } from '@mui/utils';
import PropTypes from 'prop-types';
import { PolymorphicComponent } from '../utils/PolymorphicComponent';
import { unstable_composeClasses as composeClasses } from '../composeClasses';
@@ -97,14 +98,7 @@ Button.propTypes /* remove-proptypes */ = {
/**
* A ref for imperative actions. It currently only supports `focusVisible()` action.
*/
- action: PropTypes.oneOfType([
- PropTypes.func,
- PropTypes.shape({
- current: PropTypes.shape({
- focusVisible: PropTypes.func.isRequired,
- }),
- }),
- ]),
+ action: refType,
/**
* @ignore
*/
diff --git a/packages/mui-base/src/Input/Input.tsx b/packages/mui-base/src/Input/Input.tsx
index 5614847edd287e..16534896ac7a00 100644
--- a/packages/mui-base/src/Input/Input.tsx
+++ b/packages/mui-base/src/Input/Input.tsx
@@ -1,5 +1,6 @@
'use client';
import * as React from 'react';
+import { refType } from '@mui/utils';
import PropTypes from 'prop-types';
import { PolymorphicComponent } from '../utils/PolymorphicComponent';
import { isHostComponent } from '../utils/isHostComponent';
@@ -244,12 +245,7 @@ Input.propTypes /* remove-proptypes */ = {
/**
* @ignore
*/
- inputRef: PropTypes.oneOfType([
- PropTypes.func,
- PropTypes.shape({
- current: PropTypes.object,
- }),
- ]),
+ inputRef: refType,
/**
* Maximum number of rows to display when multiline option is set to true.
*/
diff --git a/packages/mui-base/src/Tab/Tab.tsx b/packages/mui-base/src/Tab/Tab.tsx
index 5d728e4e9ef5c9..e3978d9dabc577 100644
--- a/packages/mui-base/src/Tab/Tab.tsx
+++ b/packages/mui-base/src/Tab/Tab.tsx
@@ -1,7 +1,7 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
-import { unstable_useForkRef as useForkRef } from '@mui/utils';
+import { unstable_useForkRef as useForkRef, refType } from '@mui/utils';
import { unstable_composeClasses as composeClasses } from '../composeClasses';
import { getTabUtilityClass } from './tabClasses';
import { TabProps, TabTypeMap, TabRootSlotProps, TabOwnerState } from './Tab.types';
@@ -87,14 +87,7 @@ Tab.propTypes /* remove-proptypes */ = {
/**
* A ref for imperative actions. It currently only supports `focusVisible()` action.
*/
- action: PropTypes.oneOfType([
- PropTypes.func,
- PropTypes.shape({
- current: PropTypes.shape({
- focusVisible: PropTypes.func.isRequired,
- }),
- }),
- ]),
+ action: refType,
/**
* @ignore
*/
diff --git a/packages/mui-joy/src/Button/Button.tsx b/packages/mui-joy/src/Button/Button.tsx
index 89d5067fdb3d2a..31ffe63ab9442a 100644
--- a/packages/mui-joy/src/Button/Button.tsx
+++ b/packages/mui-joy/src/Button/Button.tsx
@@ -4,7 +4,11 @@ import PropTypes from 'prop-types';
import { useButton } from '@mui/base/useButton';
import { unstable_composeClasses as composeClasses } from '@mui/base/composeClasses';
import { Interpolation } from '@mui/system';
-import { unstable_capitalize as capitalize, unstable_useForkRef as useForkRef } from '@mui/utils';
+import {
+ unstable_capitalize as capitalize,
+ unstable_useForkRef as useForkRef,
+ refType,
+} from '@mui/utils';
import { styled, Theme, useThemeProps } from '../styles';
import { useColorInversion } from '../styles/ColorInversion';
import useSlot from '../utils/useSlot';
@@ -325,14 +329,7 @@ Button.propTypes /* remove-proptypes */ = {
/**
* A ref for imperative actions. It currently only supports `focusVisible()` action.
*/
- action: PropTypes.oneOfType([
- PropTypes.func,
- PropTypes.shape({
- current: PropTypes.shape({
- focusVisible: PropTypes.func.isRequired,
- }),
- }),
- ]),
+ action: refType,
/**
* @ignore
*/
diff --git a/packages/mui-joy/src/IconButton/IconButton.tsx b/packages/mui-joy/src/IconButton/IconButton.tsx
index 8a169ab2d456c1..bc84ac3b9ad6f5 100644
--- a/packages/mui-joy/src/IconButton/IconButton.tsx
+++ b/packages/mui-joy/src/IconButton/IconButton.tsx
@@ -1,7 +1,11 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
-import { unstable_capitalize as capitalize, unstable_useForkRef as useForkRef } from '@mui/utils';
+import {
+ unstable_capitalize as capitalize,
+ unstable_useForkRef as useForkRef,
+ refType,
+} from '@mui/utils';
import { useButton } from '@mui/base/useButton';
import { unstable_composeClasses as composeClasses } from '@mui/base/composeClasses';
import { styled, useThemeProps } from '../styles';
@@ -201,14 +205,7 @@ IconButton.propTypes /* remove-proptypes */ = {
/**
* A ref for imperative actions. It currently only supports `focusVisible()` action.
*/
- action: PropTypes.oneOfType([
- PropTypes.func,
- PropTypes.shape({
- current: PropTypes.shape({
- focusVisible: PropTypes.func.isRequired,
- }),
- }),
- ]),
+ action: refType,
/**
* @ignore
*/
diff --git a/packages/mui-joy/src/ListItemButton/ListItemButton.tsx b/packages/mui-joy/src/ListItemButton/ListItemButton.tsx
index 0463696dac13a6..5cda7fe8e20770 100644
--- a/packages/mui-joy/src/ListItemButton/ListItemButton.tsx
+++ b/packages/mui-joy/src/ListItemButton/ListItemButton.tsx
@@ -2,7 +2,11 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
-import { unstable_capitalize as capitalize, unstable_useForkRef as useForkRef } from '@mui/utils';
+import {
+ unstable_capitalize as capitalize,
+ unstable_useForkRef as useForkRef,
+ refType,
+} from '@mui/utils';
import { unstable_composeClasses as composeClasses } from '@mui/base/composeClasses';
import { useButton } from '@mui/base/useButton';
import { styled, useThemeProps } from '../styles';
@@ -213,14 +217,7 @@ ListItemButton.propTypes /* remove-proptypes */ = {
/**
* A ref for imperative actions. It currently only supports `focusVisible()` action.
*/
- action: PropTypes.oneOfType([
- PropTypes.func,
- PropTypes.shape({
- current: PropTypes.shape({
- focusVisible: PropTypes.func.isRequired,
- }),
- }),
- ]),
+ action: refType,
/**
* If `true`, the list item is focused during the first mount.
* Focus will also be triggered if the value changes from false to true.
diff --git a/packages/mui-joy/src/Select/Select.tsx b/packages/mui-joy/src/Select/Select.tsx
index 2b3f19a198941f..4389a017dbf3a8 100644
--- a/packages/mui-joy/src/Select/Select.tsx
+++ b/packages/mui-joy/src/Select/Select.tsx
@@ -3,7 +3,11 @@ import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { OverrideProps, DefaultComponentProps } from '@mui/types';
-import { unstable_capitalize as capitalize, unstable_useForkRef as useForkRef } from '@mui/utils';
+import {
+ unstable_capitalize as capitalize,
+ unstable_useForkRef as useForkRef,
+ refType,
+} from '@mui/utils';
import { Popper, PopperProps } from '@mui/base/Popper';
import { useSelect, SelectProvider } from '@mui/base/useSelect';
import { SelectOption } from '@mui/base/useOption';
@@ -625,14 +629,7 @@ Select.propTypes /* remove-proptypes */ = {
/**
* A ref for imperative actions. It currently only supports `focusVisible()` action.
*/
- action: PropTypes.oneOfType([
- PropTypes.func,
- PropTypes.shape({
- current: PropTypes.shape({
- focusVisible: PropTypes.func.isRequired,
- }),
- }),
- ]),
+ action: refType,
/**
* If `true`, the select element is focused during the first mount
* @default false
diff --git a/packages/mui-joy/src/Tab/Tab.tsx b/packages/mui-joy/src/Tab/Tab.tsx
index c9d8342d03b361..e369fabf05ab31 100644
--- a/packages/mui-joy/src/Tab/Tab.tsx
+++ b/packages/mui-joy/src/Tab/Tab.tsx
@@ -2,7 +2,11 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { OverridableComponent } from '@mui/types';
-import { unstable_capitalize as capitalize, unstable_useForkRef as useForkRef } from '@mui/utils';
+import {
+ unstable_capitalize as capitalize,
+ unstable_useForkRef as useForkRef,
+ refType,
+} from '@mui/utils';
import { unstable_composeClasses as composeClasses } from '@mui/base';
import { useTab } from '@mui/base/useTab';
import { StyledListItemButton } from '../ListItemButton/ListItemButton';
@@ -215,14 +219,7 @@ Tab.propTypes /* remove-proptypes */ = {
/**
* A ref for imperative actions. It currently only supports `focusVisible()` action.
*/
- action: PropTypes.oneOfType([
- PropTypes.func,
- PropTypes.shape({
- current: PropTypes.shape({
- focusVisible: PropTypes.func.isRequired,
- }),
- }),
- ]),
+ action: refType,
/**
* @ignore
*/
diff --git a/packages/mui-material-next/src/ButtonBase/ButtonBase.tsx b/packages/mui-material-next/src/ButtonBase/ButtonBase.tsx
index de46813447ad93..1f0913e15c9c53 100644
--- a/packages/mui-material-next/src/ButtonBase/ButtonBase.tsx
+++ b/packages/mui-material-next/src/ButtonBase/ButtonBase.tsx
@@ -299,15 +299,7 @@ ButtonBase.propTypes /* remove-proptypes */ = {
/**
* A ref that points to the `TouchRipple` element.
*/
- touchRippleRef: PropTypes.oneOfType([
- PropTypes.func,
- PropTypes.shape({
- current: PropTypes.shape({
- start: PropTypes.func.isRequired,
- stop: PropTypes.func.isRequired,
- }),
- }),
- ]),
+ touchRippleRef: refType,
/**
* Type attribute applied to the root component.
* @default 'button'
diff --git a/packages/mui-material/src/ButtonBase/ButtonBase.js b/packages/mui-material/src/ButtonBase/ButtonBase.js
index 49366647405411..e3124655f2a1fe 100644
--- a/packages/mui-material/src/ButtonBase/ButtonBase.js
+++ b/packages/mui-material/src/ButtonBase/ButtonBase.js
@@ -521,16 +521,7 @@ ButtonBase.propTypes /* remove-proptypes */ = {
/**
* A ref that points to the `TouchRipple` element.
*/
- touchRippleRef: PropTypes.oneOfType([
- PropTypes.func,
- PropTypes.shape({
- current: PropTypes.shape({
- pulsate: PropTypes.func.isRequired,
- start: PropTypes.func.isRequired,
- stop: PropTypes.func.isRequired,
- }),
- }),
- ]),
+ touchRippleRef: refType,
/**
* @ignore
*/
diff --git a/packages/typescript-to-proptypes/src/createType.ts b/packages/typescript-to-proptypes/src/createType.ts
index 4ca05ed12f4549..cdb36e84731d42 100644
--- a/packages/typescript-to-proptypes/src/createType.ts
+++ b/packages/typescript-to-proptypes/src/createType.ts
@@ -15,6 +15,7 @@ import {
StringType,
ObjectType,
NumericType,
+ ReactRefType,
} from './models';
export function createAnyType(init: { jsDoc: string | undefined }): AnyType {
@@ -64,6 +65,13 @@ export function createElementType(init: {
};
}
+export function createReactRefType(init: { jsDoc: string | undefined }): ReactRefType {
+ return {
+ type: 'ReactRefNode',
+ jsDoc: init.jsDoc,
+ };
+}
+
export function createFunctionType(init: { jsDoc: string | undefined }): FunctionType {
return {
type: 'FunctionNode',
diff --git a/packages/typescript-to-proptypes/src/generatePropTypes.ts b/packages/typescript-to-proptypes/src/generatePropTypes.ts
index 004fbb17ab1416..3993562c907170 100644
--- a/packages/typescript-to-proptypes/src/generatePropTypes.ts
+++ b/packages/typescript-to-proptypes/src/generatePropTypes.ts
@@ -155,6 +155,10 @@ export function generatePropTypes(
return `${importedName}.bool`;
}
+ if (propType.type === 'ReactRefNode') {
+ return 'refType';
+ }
+
if (propType.type === 'NumericNode') {
return `${importedName}.number`;
}
diff --git a/packages/typescript-to-proptypes/src/getPropTypesFromFile.ts b/packages/typescript-to-proptypes/src/getPropTypesFromFile.ts
index 0da13bc41aaac8..5623ed5631a6c1 100644
--- a/packages/typescript-to-proptypes/src/getPropTypesFromFile.ts
+++ b/packages/typescript-to-proptypes/src/getPropTypesFromFile.ts
@@ -19,6 +19,7 @@ import {
createNumericType,
createObjectType,
createStringType,
+ createReactRefType,
} from './createType';
import { PropTypeDefinition, PropTypesComponent, PropType } from './models';
@@ -291,6 +292,23 @@ function checkSymbol({
ts.isTypeReferenceNode(declaration.type)
) {
const name = declaration.type.typeName.getText();
+
+ if (name === 'React.Ref') {
+ return {
+ $$id: project.createPropTypeId(symbol),
+ name: symbol.getName(),
+ jsDoc,
+ filenames: symbolFilenames,
+ propType: createUnionType({
+ jsDoc,
+ types: [
+ createUndefinedType({ jsDoc: undefined }),
+ createReactRefType({ jsDoc: undefined }),
+ ],
+ }),
+ };
+ }
+
if (
name === 'React.ElementType' ||
name === 'React.JSXElementConstructor' ||
diff --git a/packages/typescript-to-proptypes/src/injectPropTypesInFile.ts b/packages/typescript-to-proptypes/src/injectPropTypesInFile.ts
index 33be76a163c5ad..b8dfba90b8a09f 100644
--- a/packages/typescript-to-proptypes/src/injectPropTypesInFile.ts
+++ b/packages/typescript-to-proptypes/src/injectPropTypesInFile.ts
@@ -170,9 +170,11 @@ function createBabelPlugin({
return includeUnusedProps ? true : data.usedProps.includes(data.prop.name);
};
- let importName = '';
- let needImport = false;
- let alreadyImported = false;
+ let importNodeFromMuiUtils: babel.NodePath | null = null;
+ let hasRefTypeImportFromMuiUtils = false;
+ let needRefTypeImportFromMuiUtils = false;
+ let alreadyImportedPropTypesName: string | null = null;
+ let needImportFromPropTypePackage = false;
let originalPropTypesPath: null | babel.NodePath = null;
const previousPropTypesSource = new Map();
@@ -186,7 +188,7 @@ function createBabelPlugin({
const source = generatePropTypes(props, {
...otherOptions,
- importedName: importName,
+ importedName: alreadyImportedPropTypesName ?? 'PropTypes',
previousPropTypesSource,
reconcilePropTypes,
shouldInclude: (prop) => shouldInclude({ component: props, prop, usedProps }),
@@ -194,7 +196,13 @@ function createBabelPlugin({
const emptyPropTypes = source === '';
if (!emptyPropTypes) {
- needImport = true;
+ needImportFromPropTypePackage = true;
+ }
+
+ // TODO: If we filter the injected proptypes in this file instead of in generatePropTypes.
+ // Then we could check correctly if some prop-type is a ref and not just rely on some string analysis.
+ if (source.includes(': refType')) {
+ needRefTypeImportFromMuiUtils = true;
}
const placeholder = `const a${uuid().replace(/-/g, '_')} = null;`;
@@ -233,25 +241,23 @@ function createBabelPlugin({
visitor: {
Program: {
enter(path, state: any) {
- if (
- !path.node.body.some((n) => {
- if (
- babelTypes.isImportDeclaration(n) &&
- n.source.value === 'prop-types' &&
- n.specifiers.length
- ) {
- importName = n.specifiers[0].local.name;
- alreadyImported = true;
- return true;
- }
- return false;
- })
- ) {
- importName = 'PropTypes';
- }
-
path.get('body').forEach((nodePath) => {
const { node } = nodePath;
+
+ if (babelTypes.isImportDeclaration(node) && node.specifiers.length) {
+ if (node.source.value === 'prop-types') {
+ alreadyImportedPropTypesName = node.specifiers[0].local.name;
+ } else if (node.source.value === '@mui/utils') {
+ importNodeFromMuiUtils = nodePath;
+ const specifier = node.specifiers.find(
+ (el) => babelTypes.isImportSpecifier(el) && el.local.name === 'refType',
+ );
+ if (specifier) {
+ hasRefTypeImportFromMuiUtils = true;
+ }
+ }
+ }
+
if (
babelTypes.isExpressionStatement(node) &&
babelTypes.isAssignmentExpression(node.expression, { operator: '=' }) &&
@@ -293,23 +299,54 @@ function createBabelPlugin({
});
},
exit(path) {
- if (alreadyImported || !needImport) {
- return;
+ if (alreadyImportedPropTypesName == null && needImportFromPropTypePackage) {
+ const propTypesImport = babel.template.ast(
+ `import PropTypes from 'prop-types'`,
+ ) as babel.types.ImportDeclaration;
+
+ const firstImport = path
+ .get('body')
+ .find((nodePath) => babelTypes.isImportDeclaration(nodePath.node));
+
+ // Insert import after the first one to avoid issues with comment flags
+ if (firstImport) {
+ firstImport.insertAfter(propTypesImport);
+ } else {
+ path.node.body = [propTypesImport, ...path.node.body];
+ }
}
- const propTypesImport = babel.template.ast(
- `import ${importName} from 'prop-types'`,
- ) as babel.types.ImportDeclaration;
-
- const firstImport = path
- .get('body')
- .find((nodePath) => babelTypes.isImportDeclaration(nodePath.node));
-
- // Insert import after the first one to avoid issues with comment flags
- if (firstImport) {
- firstImport.insertAfter(propTypesImport);
- } else {
- path.node.body = [propTypesImport, ...path.node.body];
+ if (needRefTypeImportFromMuiUtils && !hasRefTypeImportFromMuiUtils) {
+ if (importNodeFromMuiUtils) {
+ const node = importNodeFromMuiUtils.node as babel.types.ImportDeclaration;
+ importNodeFromMuiUtils.replaceWith(
+ babelTypes.importDeclaration(
+ [
+ ...node.specifiers,
+ babelTypes.importSpecifier(
+ babelTypes.identifier('refType'),
+ babelTypes.identifier('refType'),
+ ),
+ ],
+ babelTypes.stringLiteral('@mui/utils'),
+ ),
+ );
+ } else {
+ const refTypeImport = babel.template.ast(
+ `import { refType } from '@mui/utils'`,
+ ) as babel.types.ImportDeclaration;
+
+ const firstImport = path
+ .get('body')
+ .find((nodePath) => babelTypes.isImportDeclaration(nodePath.node));
+
+ // Insert import after the first one to avoid issues with comment flags
+ if (firstImport) {
+ firstImport.insertAfter(refTypeImport);
+ } else {
+ path.node.body = [refTypeImport, ...path.node.body];
+ }
+ }
}
},
},
diff --git a/packages/typescript-to-proptypes/src/models.ts b/packages/typescript-to-proptypes/src/models.ts
index 626461883336f1..df7b36c1ce649f 100644
--- a/packages/typescript-to-proptypes/src/models.ts
+++ b/packages/typescript-to-proptypes/src/models.ts
@@ -21,6 +21,7 @@ export type PropType =
| BooleanType
| DOMElementType
| ElementType
+ | ReactRefType
| FunctionType
| InstanceOfType
| InterfaceType
@@ -63,6 +64,10 @@ export interface ElementType extends BasePropType {
type: 'ElementNode';
}
+export interface ReactRefType extends BasePropType {
+ type: 'ReactRefNode';
+}
+
export interface FunctionType extends BasePropType {
type: 'FunctionNode';
}
diff --git a/scripts/generateProptypes.ts b/scripts/generateProptypes.ts
index 09b923a9b33b79..e4bf0ed659c4e6 100644
--- a/scripts/generateProptypes.ts
+++ b/scripts/generateProptypes.ts
@@ -248,7 +248,10 @@ async function generateProptypes(
ensureBabelPluginTransformReactRemovePropTypesIntegration: true,
getSortLiteralUnions,
reconcilePropTypes: (prop, previous, generated) => {
- const usedCustomValidator = previous !== undefined && !previous.startsWith('PropTypes');
+ const usedCustomValidator =
+ previous !== undefined &&
+ !previous.startsWith('PropTypes') &&
+ !previous.startsWith('refType');
const ignoreGenerated =
previous !== undefined &&
previous.startsWith('PropTypes /* @typescript-to-proptypes-ignore */');