diff --git a/packages/react-devtools-shared/src/__tests__/utils-test.js b/packages/react-devtools-shared/src/__tests__/utils-test.js
index b035ce012b023..e481ff8b66f52 100644
--- a/packages/react-devtools-shared/src/__tests__/utils-test.js
+++ b/packages/react-devtools-shared/src/__tests__/utils-test.js
@@ -23,7 +23,7 @@ import {
REACT_SUSPENSE_LIST_TYPE as SuspenseList,
REACT_STRICT_MODE_TYPE as StrictMode,
} from 'shared/ReactSymbols';
-import {createElement} from 'react/src/ReactElement';
+import {createElement} from 'react';
describe('utils', () => {
describe('getDisplayName', () => {
diff --git a/packages/react/src/ReactChildren.js b/packages/react/src/ReactChildren.js
index adddda2ff3210..8b9219b9fb1f0 100644
--- a/packages/react/src/ReactChildren.js
+++ b/packages/react/src/ReactChildren.js
@@ -24,7 +24,7 @@ import {
} from 'shared/ReactSymbols';
import {checkKeyStringCoercion} from 'shared/CheckStringCoercion';
-import {isValidElement, cloneAndReplaceKey} from './ReactElement';
+import {isValidElement, cloneAndReplaceKey} from './jsx/ReactJSXElement';
const SEPARATOR = '.';
const SUBSEPARATOR = ':';
diff --git a/packages/react/src/ReactClient.js b/packages/react/src/ReactClient.js
index 85a9c1d692696..ff988a2a2cf3d 100644
--- a/packages/react/src/ReactClient.js
+++ b/packages/react/src/ReactClient.js
@@ -30,7 +30,7 @@ import {
createFactory,
cloneElement,
isValidElement,
-} from './ReactElement';
+} from './jsx/ReactJSXElement';
import {createContext} from './ReactContext';
import {lazy} from './ReactLazy';
import {forwardRef} from './ReactForwardRef';
diff --git a/packages/react/src/ReactElement.js b/packages/react/src/ReactElement.js
deleted file mode 100644
index ab3df9600ab86..0000000000000
--- a/packages/react/src/ReactElement.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
-
-import {
- createElement as createElementProd,
- createFactory as createFactoryProd,
- cloneElement as cloneElementProd,
-} from './ReactElementProd';
-
-import {
- createElementWithValidation,
- createFactoryWithValidation,
- cloneElementWithValidation,
-} from './ReactElementValidator';
-
-export {isValidElement, cloneAndReplaceKey} from './ReactElementProd';
-
-export const createElement: any = __DEV__
- ? createElementWithValidation
- : createElementProd;
-export const cloneElement: any = __DEV__
- ? cloneElementWithValidation
- : cloneElementProd;
-export const createFactory: any = __DEV__
- ? createFactoryWithValidation
- : createFactoryProd;
diff --git a/packages/react/src/ReactElementProd.js b/packages/react/src/ReactElementProd.js
deleted file mode 100644
index 36c9381ef1ff4..0000000000000
--- a/packages/react/src/ReactElementProd.js
+++ /dev/null
@@ -1,406 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-import getComponentNameFromType from 'shared/getComponentNameFromType';
-import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
-import assign from 'shared/assign';
-import hasOwnProperty from 'shared/hasOwnProperty';
-import {checkKeyStringCoercion} from 'shared/CheckStringCoercion';
-
-import ReactCurrentOwner from './ReactCurrentOwner';
-
-let specialPropKeyWarningShown,
- specialPropRefWarningShown,
- didWarnAboutStringRefs;
-
-if (__DEV__) {
- didWarnAboutStringRefs = {};
-}
-
-function hasValidRef(config) {
- if (__DEV__) {
- if (hasOwnProperty.call(config, 'ref')) {
- const getter = Object.getOwnPropertyDescriptor(config, 'ref').get;
- if (getter && getter.isReactWarning) {
- return false;
- }
- }
- }
- return config.ref !== undefined;
-}
-
-function hasValidKey(config) {
- if (__DEV__) {
- if (hasOwnProperty.call(config, 'key')) {
- const getter = Object.getOwnPropertyDescriptor(config, 'key').get;
- if (getter && getter.isReactWarning) {
- return false;
- }
- }
- }
- return config.key !== undefined;
-}
-
-function defineKeyPropWarningGetter(props, displayName) {
- const warnAboutAccessingKey = function () {
- if (__DEV__) {
- if (!specialPropKeyWarningShown) {
- specialPropKeyWarningShown = true;
- console.error(
- '%s: `key` is not a prop. Trying to access it will result ' +
- 'in `undefined` being returned. If you need to access the same ' +
- 'value within the child component, you should pass it as a different ' +
- 'prop. (https://reactjs.org/link/special-props)',
- displayName,
- );
- }
- }
- };
- warnAboutAccessingKey.isReactWarning = true;
- Object.defineProperty(props, 'key', {
- get: warnAboutAccessingKey,
- configurable: true,
- });
-}
-
-function defineRefPropWarningGetter(props, displayName) {
- const warnAboutAccessingRef = function () {
- if (__DEV__) {
- if (!specialPropRefWarningShown) {
- specialPropRefWarningShown = true;
- console.error(
- '%s: `ref` is not a prop. Trying to access it will result ' +
- 'in `undefined` being returned. If you need to access the same ' +
- 'value within the child component, you should pass it as a different ' +
- 'prop. (https://reactjs.org/link/special-props)',
- displayName,
- );
- }
- }
- };
- warnAboutAccessingRef.isReactWarning = true;
- Object.defineProperty(props, 'ref', {
- get: warnAboutAccessingRef,
- configurable: true,
- });
-}
-
-function warnIfStringRefCannotBeAutoConverted(config) {
- if (__DEV__) {
- if (
- typeof config.ref === 'string' &&
- ReactCurrentOwner.current &&
- config.__self &&
- ReactCurrentOwner.current.stateNode !== config.__self
- ) {
- const componentName = getComponentNameFromType(
- ReactCurrentOwner.current.type,
- );
-
- if (!didWarnAboutStringRefs[componentName]) {
- console.error(
- 'Component "%s" contains the string ref "%s". ' +
- 'Support for string refs will be removed in a future major release. ' +
- 'This case cannot be automatically converted to an arrow function. ' +
- 'We ask you to manually fix this case by using useRef() or createRef() instead. ' +
- 'Learn more about using refs safely here: ' +
- 'https://reactjs.org/link/strict-mode-string-ref',
- componentName,
- config.ref,
- );
- didWarnAboutStringRefs[componentName] = true;
- }
- }
- }
-}
-
-/**
- * Factory method to create a new React element. This no longer adheres to
- * the class pattern, so do not use new to call it. Also, instanceof check
- * will not work. Instead test $$typeof field against Symbol.for('react.element') to check
- * if something is a React Element.
- *
- * @param {*} type
- * @param {*} props
- * @param {*} key
- * @param {string|object} ref
- * @param {*} owner
- * @param {*} self A *temporary* helper to detect places where `this` is
- * different from the `owner` when React.createElement is called, so that we
- * can warn. We want to get rid of owner and replace string `ref`s with arrow
- * functions, and as long as `this` and owner are the same, there will be no
- * change in behavior.
- * @param {*} source An annotation object (added by a transpiler or otherwise)
- * indicating filename, line number, and/or other information.
- * @internal
- */
-function ReactElement(type, key, ref, owner, props) {
- const element = {
- // This tag allows us to uniquely identify this as a React Element
- $$typeof: REACT_ELEMENT_TYPE,
-
- // Built-in properties that belong on the element
- type: type,
- key: key,
- ref: ref,
- props: props,
-
- // Record the component responsible for creating this element.
- _owner: owner,
- };
-
- if (__DEV__) {
- // The validation flag is currently mutative. We put it on
- // an external backing store so that we can freeze the whole object.
- // This can be replaced with a WeakMap once they are implemented in
- // commonly used development environments.
- element._store = {};
-
- // To make comparing ReactElements easier for testing purposes, we make
- // the validation flag non-enumerable (where possible, which should
- // include every environment we run tests in), so the test framework
- // ignores it.
- Object.defineProperty(element._store, 'validated', {
- configurable: false,
- enumerable: false,
- writable: true,
- value: false,
- });
- // debugInfo contains Server Component debug information.
- Object.defineProperty(element, '_debugInfo', {
- configurable: false,
- enumerable: false,
- writable: true,
- value: null,
- });
- if (Object.freeze) {
- Object.freeze(element.props);
- Object.freeze(element);
- }
- }
-
- return element;
-}
-
-/**
- * Create and return a new ReactElement of the given type.
- * See https://reactjs.org/docs/react-api.html#createelement
- */
-export function createElement(type, config, children) {
- let propName;
-
- // Reserved names are extracted
- const props = {};
-
- let key = null;
- let ref = null;
-
- if (config != null) {
- if (hasValidRef(config)) {
- ref = config.ref;
-
- if (__DEV__) {
- warnIfStringRefCannotBeAutoConverted(config);
- }
- }
- if (hasValidKey(config)) {
- if (__DEV__) {
- checkKeyStringCoercion(config.key);
- }
- key = '' + config.key;
- }
-
- // Remaining properties are added to a new props object
- for (propName in config) {
- if (
- hasOwnProperty.call(config, propName) &&
- // Skip over reserved prop names
- propName !== 'key' &&
- // TODO: `ref` will no longer be reserved in the next major
- propName !== 'ref' &&
- // ...and maybe these, too, though we currently rely on them for
- // warnings and debug information in dev. Need to decide if we're OK
- // with dropping them. In the jsx() runtime it's not an issue because
- // the data gets passed as separate arguments instead of props, but
- // it would be nice to stop relying on them entirely so we can drop
- // them from the internal Fiber field.
- propName !== '__self' &&
- propName !== '__source'
- ) {
- props[propName] = config[propName];
- }
- }
- }
-
- // Children can be more than one argument, and those are transferred onto
- // the newly allocated props object.
- const childrenLength = arguments.length - 2;
- if (childrenLength === 1) {
- props.children = children;
- } else if (childrenLength > 1) {
- const childArray = Array(childrenLength);
- for (let i = 0; i < childrenLength; i++) {
- childArray[i] = arguments[i + 2];
- }
- if (__DEV__) {
- if (Object.freeze) {
- Object.freeze(childArray);
- }
- }
- props.children = childArray;
- }
-
- // Resolve default props
- if (type && type.defaultProps) {
- const defaultProps = type.defaultProps;
- for (propName in defaultProps) {
- if (props[propName] === undefined) {
- props[propName] = defaultProps[propName];
- }
- }
- }
- if (__DEV__) {
- if (key || ref) {
- const displayName =
- typeof type === 'function'
- ? type.displayName || type.name || 'Unknown'
- : type;
- if (key) {
- defineKeyPropWarningGetter(props, displayName);
- }
- if (ref) {
- defineRefPropWarningGetter(props, displayName);
- }
- }
- }
- return ReactElement(type, key, ref, ReactCurrentOwner.current, props);
-}
-
-/**
- * Return a function that produces ReactElements of a given type.
- * See https://reactjs.org/docs/react-api.html#createfactory
- */
-export function createFactory(type) {
- const factory = createElement.bind(null, type);
- // Expose the type on the factory and the prototype so that it can be
- // easily accessed on elements. E.g. `.type === Foo`.
- // This should not be named `constructor` since this may not be the function
- // that created the element, and it may not even be a constructor.
- // Legacy hook: remove it
- factory.type = type;
- return factory;
-}
-
-export function cloneAndReplaceKey(oldElement, newKey) {
- const newElement = ReactElement(
- oldElement.type,
- newKey,
- oldElement.ref,
- oldElement._owner,
- oldElement.props,
- );
-
- return newElement;
-}
-
-/**
- * Clone and return a new ReactElement using element as the starting point.
- * See https://reactjs.org/docs/react-api.html#cloneelement
- */
-export function cloneElement(element, config, children) {
- if (element === null || element === undefined) {
- throw new Error(
- `React.cloneElement(...): The argument must be a React element, but you passed ${element}.`,
- );
- }
-
- let propName;
-
- // Original props are copied
- const props = assign({}, element.props);
-
- // Reserved names are extracted
- let key = element.key;
- let ref = element.ref;
-
- // Owner will be preserved, unless ref is overridden
- let owner = element._owner;
-
- if (config != null) {
- if (hasValidRef(config)) {
- // Silently steal the ref from the parent.
- ref = config.ref;
- owner = ReactCurrentOwner.current;
- }
- if (hasValidKey(config)) {
- if (__DEV__) {
- checkKeyStringCoercion(config.key);
- }
- key = '' + config.key;
- }
-
- // Remaining properties override existing props
- let defaultProps;
- if (element.type && element.type.defaultProps) {
- defaultProps = element.type.defaultProps;
- }
- for (propName in config) {
- if (
- hasOwnProperty.call(config, propName) &&
- // Skip over reserved prop names
- propName !== 'key' &&
- // TODO: `ref` will no longer be reserved in the next major
- propName !== 'ref' &&
- // ...and maybe these, too, though we currently rely on them for
- // warnings and debug information in dev. Need to decide if we're OK
- // with dropping them. In the jsx() runtime it's not an issue because
- // the data gets passed as separate arguments instead of props, but
- // it would be nice to stop relying on them entirely so we can drop
- // them from the internal Fiber field.
- propName !== '__self' &&
- propName !== '__source'
- ) {
- if (config[propName] === undefined && defaultProps !== undefined) {
- // Resolve default props
- props[propName] = defaultProps[propName];
- } else {
- props[propName] = config[propName];
- }
- }
- }
- }
-
- // Children can be more than one argument, and those are transferred onto
- // the newly allocated props object.
- const childrenLength = arguments.length - 2;
- if (childrenLength === 1) {
- props.children = children;
- } else if (childrenLength > 1) {
- const childArray = Array(childrenLength);
- for (let i = 0; i < childrenLength; i++) {
- childArray[i] = arguments[i + 2];
- }
- props.children = childArray;
- }
-
- return ReactElement(element.type, key, ref, owner, props);
-}
-
-/**
- * Verifies the object is a ReactElement.
- * See https://reactjs.org/docs/react-api.html#isvalidelement
- * @param {?object} object
- * @return {boolean} True if `object` is a ReactElement.
- * @final
- */
-export function isValidElement(object) {
- return (
- typeof object === 'object' &&
- object !== null &&
- object.$$typeof === REACT_ELEMENT_TYPE
- );
-}
diff --git a/packages/react/src/ReactElementValidator.js b/packages/react/src/ReactElementValidator.js
deleted file mode 100644
index 275be8efe2d66..0000000000000
--- a/packages/react/src/ReactElementValidator.js
+++ /dev/null
@@ -1,395 +0,0 @@
-/**
- * Copyright (c) Meta Platforms, Inc. and affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-/**
- * ReactElementValidator provides a wrapper around an element factory
- * which validates the props passed to the element. This is intended to be
- * used only in DEV and could be replaced by a static type checker for languages
- * that support it.
- */
-
-import isValidElementType from 'shared/isValidElementType';
-import getComponentNameFromType from 'shared/getComponentNameFromType';
-import {
- getIteratorFn,
- REACT_FORWARD_REF_TYPE,
- REACT_MEMO_TYPE,
- REACT_FRAGMENT_TYPE,
- REACT_ELEMENT_TYPE,
-} from 'shared/ReactSymbols';
-import checkPropTypes from 'shared/checkPropTypes';
-import isArray from 'shared/isArray';
-
-import ReactCurrentOwner from './ReactCurrentOwner';
-import {isValidElement, createElement, cloneElement} from './ReactElementProd';
-import {setExtraStackFrame} from './ReactDebugCurrentFrame';
-import {describeUnknownElementTypeFrameInDEV} from 'shared/ReactComponentStackFrame';
-
-const REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference');
-
-function setCurrentlyValidatingElement(element) {
- if (__DEV__) {
- if (element) {
- const owner = element._owner;
- const stack = describeUnknownElementTypeFrameInDEV(
- element.type,
- owner ? owner.type : null,
- );
- setExtraStackFrame(stack);
- } else {
- setExtraStackFrame(null);
- }
- }
-}
-
-let propTypesMisspellWarningShown;
-
-if (__DEV__) {
- propTypesMisspellWarningShown = false;
-}
-
-function getDeclarationErrorAddendum() {
- if (ReactCurrentOwner.current) {
- const name = getComponentNameFromType(ReactCurrentOwner.current.type);
- if (name) {
- return '\n\nCheck the render method of `' + name + '`.';
- }
- }
- return '';
-}
-
-function getSourceInfoErrorAddendum(source) {
- if (source !== undefined) {
- const fileName = source.fileName.replace(/^.*[\\\/]/, '');
- const lineNumber = source.lineNumber;
- return '\n\nCheck your code at ' + fileName + ':' + lineNumber + '.';
- }
- return '';
-}
-
-function getSourceInfoErrorAddendumForProps(elementProps) {
- if (elementProps !== null && elementProps !== undefined) {
- return getSourceInfoErrorAddendum(elementProps.__source);
- }
- return '';
-}
-
-/**
- * Warn if there's no key explicitly set on dynamic arrays of children or
- * object keys are not valid. This allows us to keep track of children between
- * updates.
- */
-const ownerHasKeyUseWarning = {};
-
-function getCurrentComponentErrorInfo(parentType) {
- let info = getDeclarationErrorAddendum();
-
- if (!info) {
- const parentName = getComponentNameFromType(parentType);
- if (parentName) {
- info = `\n\nCheck the top-level render call using <${parentName}>.`;
- }
- }
- return info;
-}
-
-/**
- * Warn if the element doesn't have an explicit key assigned to it.
- * This element is in an array. The array could grow and shrink or be
- * reordered. All children that haven't already been validated are required to
- * have a "key" property assigned to it. Error statuses are cached so a warning
- * will only be shown once.
- *
- * @internal
- * @param {ReactElement} element Element that requires a key.
- * @param {*} parentType element's parent's type.
- */
-function validateExplicitKey(element, parentType) {
- if (!element._store || element._store.validated || element.key != null) {
- return;
- }
- element._store.validated = true;
-
- const currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType);
- if (ownerHasKeyUseWarning[currentComponentErrorInfo]) {
- return;
- }
- ownerHasKeyUseWarning[currentComponentErrorInfo] = true;
-
- // Usually the current owner is the offender, but if it accepts children as a
- // property, it may be the creator of the child that's responsible for
- // assigning it a key.
- let childOwner = '';
- if (
- element &&
- element._owner &&
- element._owner !== ReactCurrentOwner.current
- ) {
- // Give the component that originally created this child.
- childOwner = ` It was passed a child from ${getComponentNameFromType(
- element._owner.type,
- )}.`;
- }
-
- if (__DEV__) {
- setCurrentlyValidatingElement(element);
- console.error(
- 'Each child in a list should have a unique "key" prop.' +
- '%s%s See https://reactjs.org/link/warning-keys for more information.',
- currentComponentErrorInfo,
- childOwner,
- );
- setCurrentlyValidatingElement(null);
- }
-}
-
-/**
- * Ensure that every element either is passed in a static location, in an
- * array with an explicit keys property defined, or in an object literal
- * with valid key property.
- *
- * @internal
- * @param {ReactNode} node Statically passed child of any type.
- * @param {*} parentType node's parent's type.
- */
-function validateChildKeys(node, parentType) {
- if (typeof node !== 'object' || !node) {
- return;
- }
- if (node.$$typeof === REACT_CLIENT_REFERENCE) {
- // This is a reference to a client component so it's unknown.
- } else if (isArray(node)) {
- for (let i = 0; i < node.length; i++) {
- const child = node[i];
- if (isValidElement(child)) {
- validateExplicitKey(child, parentType);
- }
- }
- } else if (isValidElement(node)) {
- // This element was passed in a valid location.
- if (node._store) {
- node._store.validated = true;
- }
- } else {
- const iteratorFn = getIteratorFn(node);
- if (typeof iteratorFn === 'function') {
- // Entry iterators used to provide implicit keys,
- // but now we print a separate warning for them later.
- if (iteratorFn !== node.entries) {
- const iterator = iteratorFn.call(node);
- let step;
- while (!(step = iterator.next()).done) {
- if (isValidElement(step.value)) {
- validateExplicitKey(step.value, parentType);
- }
- }
- }
- }
- }
-}
-
-/**
- * Given an element, validate that its props follow the propTypes definition,
- * provided by the type.
- *
- * @param {ReactElement} element
- */
-function validatePropTypes(element) {
- if (__DEV__) {
- const type = element.type;
- if (type === null || type === undefined || typeof type === 'string') {
- return;
- }
- if (type.$$typeof === REACT_CLIENT_REFERENCE) {
- return;
- }
- let propTypes;
- if (typeof type === 'function') {
- propTypes = type.propTypes;
- } else if (
- typeof type === 'object' &&
- (type.$$typeof === REACT_FORWARD_REF_TYPE ||
- // Note: Memo only checks outer props here.
- // Inner props are checked in the reconciler.
- type.$$typeof === REACT_MEMO_TYPE)
- ) {
- propTypes = type.propTypes;
- } else {
- return;
- }
- if (propTypes) {
- // Intentionally inside to avoid triggering lazy initializers:
- const name = getComponentNameFromType(type);
- checkPropTypes(propTypes, element.props, 'prop', name, element);
- } else if (type.PropTypes !== undefined && !propTypesMisspellWarningShown) {
- propTypesMisspellWarningShown = true;
- // Intentionally inside to avoid triggering lazy initializers:
- const name = getComponentNameFromType(type);
- console.error(
- 'Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?',
- name || 'Unknown',
- );
- }
- if (
- typeof type.getDefaultProps === 'function' &&
- !type.getDefaultProps.isReactClassApproved
- ) {
- console.error(
- 'getDefaultProps is only used on classic React.createClass ' +
- 'definitions. Use a static property named `defaultProps` instead.',
- );
- }
- }
-}
-
-/**
- * Given a fragment, validate that it can only be provided with fragment props
- * @param {ReactElement} fragment
- */
-function validateFragmentProps(fragment) {
- if (__DEV__) {
- const keys = Object.keys(fragment.props);
- for (let i = 0; i < keys.length; i++) {
- const key = keys[i];
- if (key !== 'children' && key !== 'key') {
- setCurrentlyValidatingElement(fragment);
- console.error(
- 'Invalid prop `%s` supplied to `React.Fragment`. ' +
- 'React.Fragment can only have `key` and `children` props.',
- key,
- );
- setCurrentlyValidatingElement(null);
- break;
- }
- }
-
- if (fragment.ref !== null) {
- setCurrentlyValidatingElement(fragment);
- console.error('Invalid attribute `ref` supplied to `React.Fragment`.');
- setCurrentlyValidatingElement(null);
- }
- }
-}
-
-export function createElementWithValidation(type, props, children) {
- const validType = isValidElementType(type);
-
- // We warn in this case but don't throw. We expect the element creation to
- // succeed and there will likely be errors in render.
- if (!validType) {
- let info = '';
- if (
- type === undefined ||
- (typeof type === 'object' &&
- type !== null &&
- Object.keys(type).length === 0)
- ) {
- info +=
- ' You likely forgot to export your component from the file ' +
- "it's defined in, or you might have mixed up default and named imports.";
- }
-
- const sourceInfo = getSourceInfoErrorAddendumForProps(props);
- if (sourceInfo) {
- info += sourceInfo;
- } else {
- info += getDeclarationErrorAddendum();
- }
-
- let typeString;
- if (type === null) {
- typeString = 'null';
- } else if (isArray(type)) {
- typeString = 'array';
- } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) {
- typeString = `<${getComponentNameFromType(type.type) || 'Unknown'} />`;
- info =
- ' Did you accidentally export a JSX literal instead of a component?';
- } else {
- typeString = typeof type;
- }
-
- if (__DEV__) {
- console.error(
- 'React.createElement: type is invalid -- expected a string (for ' +
- 'built-in components) or a class/function (for composite ' +
- 'components) but got: %s.%s',
- typeString,
- info,
- );
- }
- }
-
- const element = createElement.apply(this, arguments);
-
- // The result can be nullish if a mock or a custom function is used.
- // TODO: Drop this when these are no longer allowed as the type argument.
- if (element == null) {
- return element;
- }
-
- // Skip key warning if the type isn't valid since our key validation logic
- // doesn't expect a non-string/function type and can throw confusing errors.
- // We don't want exception behavior to differ between dev and prod.
- // (Rendering will throw with a helpful message and as soon as the type is
- // fixed, the key warnings will appear.)
- if (validType) {
- for (let i = 2; i < arguments.length; i++) {
- validateChildKeys(arguments[i], type);
- }
- }
-
- if (type === REACT_FRAGMENT_TYPE) {
- validateFragmentProps(element);
- } else {
- validatePropTypes(element);
- }
-
- return element;
-}
-
-let didWarnAboutDeprecatedCreateFactory = false;
-
-export function createFactoryWithValidation(type) {
- const validatedFactory = createElementWithValidation.bind(null, type);
- validatedFactory.type = type;
- if (__DEV__) {
- if (!didWarnAboutDeprecatedCreateFactory) {
- didWarnAboutDeprecatedCreateFactory = true;
- console.warn(
- 'React.createFactory() is deprecated and will be removed in ' +
- 'a future major release. Consider using JSX ' +
- 'or use React.createElement() directly instead.',
- );
- }
- // Legacy hook: remove it
- Object.defineProperty(validatedFactory, 'type', {
- enumerable: false,
- get: function () {
- console.warn(
- 'Factory.type is deprecated. Access the class directly ' +
- 'before passing it to createFactory.',
- );
- Object.defineProperty(this, 'type', {
- value: type,
- });
- return type;
- },
- });
- }
-
- return validatedFactory;
-}
-
-export function cloneElementWithValidation(element, props, children) {
- const newElement = cloneElement.apply(this, arguments);
- for (let i = 2; i < arguments.length; i++) {
- validateChildKeys(arguments[i], newElement.type);
- }
- validatePropTypes(newElement);
- return newElement;
-}
diff --git a/packages/react/src/ReactServer.experimental.js b/packages/react/src/ReactServer.experimental.js
index 159391a28b262..ccc6de20eca34 100644
--- a/packages/react/src/ReactServer.experimental.js
+++ b/packages/react/src/ReactServer.experimental.js
@@ -22,7 +22,11 @@ import {
REACT_SUSPENSE_TYPE,
REACT_DEBUG_TRACING_MODE_TYPE,
} from 'shared/ReactSymbols';
-import {cloneElement, createElement, isValidElement} from './ReactElement';
+import {
+ cloneElement,
+ createElement,
+ isValidElement,
+} from './jsx/ReactJSXElement';
import {createRef} from './ReactCreateRef';
import {
use,
diff --git a/packages/react/src/ReactServer.js b/packages/react/src/ReactServer.js
index 9715e0d94f8e1..cc7e2c1847e5a 100644
--- a/packages/react/src/ReactServer.js
+++ b/packages/react/src/ReactServer.js
@@ -21,7 +21,11 @@ import {
REACT_STRICT_MODE_TYPE,
REACT_SUSPENSE_TYPE,
} from 'shared/ReactSymbols';
-import {cloneElement, createElement, isValidElement} from './ReactElement';
+import {
+ cloneElement,
+ createElement,
+ isValidElement,
+} from './jsx/ReactJSXElement';
import {createRef} from './ReactCreateRef';
import {use, useId, useCallback, useDebugValue, useMemo} from './ReactHooks';
import {forwardRef} from './ReactForwardRef';
diff --git a/packages/react/src/jsx/ReactJSXElement.js b/packages/react/src/jsx/ReactJSXElement.js
index d955dcf13222e..4e546963292a3 100644
--- a/packages/react/src/jsx/ReactJSXElement.js
+++ b/packages/react/src/jsx/ReactJSXElement.js
@@ -8,6 +8,7 @@
import getComponentNameFromType from 'shared/getComponentNameFromType';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import hasOwnProperty from 'shared/hasOwnProperty';
+import assign from 'shared/assign';
import {
getIteratorFn,
REACT_ELEMENT_TYPE,
@@ -512,6 +513,331 @@ export function jsxDEV(type, config, maybeKey, isStaticChildren, source, self) {
}
}
+/**
+ * Create and return a new ReactElement of the given type.
+ * See https://reactjs.org/docs/react-api.html#createelement
+ */
+export function createElement(type, config, children) {
+ if (__DEV__) {
+ if (!isValidElementType(type)) {
+ // This is an invalid element type.
+ //
+ // We warn in this case but don't throw. We expect the element creation to
+ // succeed and there will likely be errors in render.
+ let info = '';
+ if (
+ type === undefined ||
+ (typeof type === 'object' &&
+ type !== null &&
+ Object.keys(type).length === 0)
+ ) {
+ info +=
+ ' You likely forgot to export your component from the file ' +
+ "it's defined in, or you might have mixed up default and named imports.";
+ }
+
+ const sourceInfo = getSourceInfoErrorAddendumForProps(config);
+ if (sourceInfo) {
+ info += sourceInfo;
+ } else {
+ info += getDeclarationErrorAddendum();
+ }
+
+ let typeString;
+ if (type === null) {
+ typeString = 'null';
+ } else if (isArray(type)) {
+ typeString = 'array';
+ } else if (type !== undefined && type.$$typeof === REACT_ELEMENT_TYPE) {
+ typeString = `<${getComponentNameFromType(type.type) || 'Unknown'} />`;
+ info =
+ ' Did you accidentally export a JSX literal instead of a component?';
+ } else {
+ typeString = typeof type;
+ }
+
+ console.error(
+ 'React.createElement: type is invalid -- expected a string (for ' +
+ 'built-in components) or a class/function (for composite ' +
+ 'components) but got: %s.%s',
+ typeString,
+ info,
+ );
+ } else {
+ // This is a valid element type.
+
+ // Skip key warning if the type isn't valid since our key validation logic
+ // doesn't expect a non-string/function type and can throw confusing
+ // errors. We don't want exception behavior to differ between dev and
+ // prod. (Rendering will throw with a helpful message and as soon as the
+ // type is fixed, the key warnings will appear.)
+ for (let i = 2; i < arguments.length; i++) {
+ validateChildKeys(arguments[i], type);
+ }
+ }
+
+ // Unlike the jsx() runtime, createElement() doesn't warn about key spread.
+ }
+
+ let propName;
+
+ // Reserved names are extracted
+ const props = {};
+
+ let key = null;
+ let ref = null;
+
+ if (config != null) {
+ if (hasValidRef(config)) {
+ ref = config.ref;
+
+ if (__DEV__) {
+ warnIfStringRefCannotBeAutoConverted(config, config.__self);
+ }
+ }
+ if (hasValidKey(config)) {
+ if (__DEV__) {
+ checkKeyStringCoercion(config.key);
+ }
+ key = '' + config.key;
+ }
+
+ // Remaining properties are added to a new props object
+ for (propName in config) {
+ if (
+ hasOwnProperty.call(config, propName) &&
+ // Skip over reserved prop names
+ propName !== 'key' &&
+ // TODO: `ref` will no longer be reserved in the next major
+ propName !== 'ref' &&
+ // ...and maybe these, too, though we currently rely on them for
+ // warnings and debug information in dev. Need to decide if we're OK
+ // with dropping them. In the jsx() runtime it's not an issue because
+ // the data gets passed as separate arguments instead of props, but
+ // it would be nice to stop relying on them entirely so we can drop
+ // them from the internal Fiber field.
+ propName !== '__self' &&
+ propName !== '__source'
+ ) {
+ props[propName] = config[propName];
+ }
+ }
+ }
+
+ // Children can be more than one argument, and those are transferred onto
+ // the newly allocated props object.
+ const childrenLength = arguments.length - 2;
+ if (childrenLength === 1) {
+ props.children = children;
+ } else if (childrenLength > 1) {
+ const childArray = Array(childrenLength);
+ for (let i = 0; i < childrenLength; i++) {
+ childArray[i] = arguments[i + 2];
+ }
+ if (__DEV__) {
+ if (Object.freeze) {
+ Object.freeze(childArray);
+ }
+ }
+ props.children = childArray;
+ }
+
+ // Resolve default props
+ if (type && type.defaultProps) {
+ const defaultProps = type.defaultProps;
+ for (propName in defaultProps) {
+ if (props[propName] === undefined) {
+ props[propName] = defaultProps[propName];
+ }
+ }
+ }
+ if (__DEV__) {
+ if (key || ref) {
+ const displayName =
+ typeof type === 'function'
+ ? type.displayName || type.name || 'Unknown'
+ : type;
+ if (key) {
+ defineKeyPropWarningGetter(props, displayName);
+ }
+ if (ref) {
+ defineRefPropWarningGetter(props, displayName);
+ }
+ }
+ }
+
+ const element = ReactElement(
+ type,
+ key,
+ ref,
+ undefined,
+ undefined,
+ ReactCurrentOwner.current,
+ props,
+ );
+
+ if (type === REACT_FRAGMENT_TYPE) {
+ validateFragmentProps(element);
+ } else {
+ validatePropTypes(element);
+ }
+
+ return element;
+}
+
+let didWarnAboutDeprecatedCreateFactory = false;
+
+/**
+ * Return a function that produces ReactElements of a given type.
+ * See https://reactjs.org/docs/react-api.html#createfactory
+ */
+export function createFactory(type) {
+ const factory = createElement.bind(null, type);
+ // Expose the type on the factory and the prototype so that it can be
+ // easily accessed on elements. E.g. `.type === Foo`.
+ // This should not be named `constructor` since this may not be the function
+ // that created the element, and it may not even be a constructor.
+ // Legacy hook: remove it
+ factory.type = type;
+
+ if (__DEV__) {
+ if (!didWarnAboutDeprecatedCreateFactory) {
+ didWarnAboutDeprecatedCreateFactory = true;
+ console.warn(
+ 'React.createFactory() is deprecated and will be removed in ' +
+ 'a future major release. Consider using JSX ' +
+ 'or use React.createElement() directly instead.',
+ );
+ }
+ // Legacy hook: remove it
+ Object.defineProperty(factory, 'type', {
+ enumerable: false,
+ get: function () {
+ console.warn(
+ 'Factory.type is deprecated. Access the class directly ' +
+ 'before passing it to createFactory.',
+ );
+ Object.defineProperty(this, 'type', {
+ value: type,
+ });
+ return type;
+ },
+ });
+ }
+
+ return factory;
+}
+
+export function cloneAndReplaceKey(oldElement, newKey) {
+ return ReactElement(
+ oldElement.type,
+ newKey,
+ oldElement.ref,
+ undefined,
+ undefined,
+ oldElement._owner,
+ oldElement.props,
+ );
+}
+
+/**
+ * Clone and return a new ReactElement using element as the starting point.
+ * See https://reactjs.org/docs/react-api.html#cloneelement
+ */
+export function cloneElement(element, config, children) {
+ if (element === null || element === undefined) {
+ throw new Error(
+ `React.cloneElement(...): The argument must be a React element, but you passed ${element}.`,
+ );
+ }
+
+ let propName;
+
+ // Original props are copied
+ const props = assign({}, element.props);
+
+ // Reserved names are extracted
+ let key = element.key;
+ let ref = element.ref;
+
+ // Owner will be preserved, unless ref is overridden
+ let owner = element._owner;
+
+ if (config != null) {
+ if (hasValidRef(config)) {
+ // Silently steal the ref from the parent.
+ ref = config.ref;
+ owner = ReactCurrentOwner.current;
+ }
+ if (hasValidKey(config)) {
+ if (__DEV__) {
+ checkKeyStringCoercion(config.key);
+ }
+ key = '' + config.key;
+ }
+
+ // Remaining properties override existing props
+ let defaultProps;
+ if (element.type && element.type.defaultProps) {
+ defaultProps = element.type.defaultProps;
+ }
+ for (propName in config) {
+ if (
+ hasOwnProperty.call(config, propName) &&
+ // Skip over reserved prop names
+ propName !== 'key' &&
+ // TODO: `ref` will no longer be reserved in the next major
+ propName !== 'ref' &&
+ // ...and maybe these, too, though we currently rely on them for
+ // warnings and debug information in dev. Need to decide if we're OK
+ // with dropping them. In the jsx() runtime it's not an issue because
+ // the data gets passed as separate arguments instead of props, but
+ // it would be nice to stop relying on them entirely so we can drop
+ // them from the internal Fiber field.
+ propName !== '__self' &&
+ propName !== '__source'
+ ) {
+ if (config[propName] === undefined && defaultProps !== undefined) {
+ // Resolve default props
+ props[propName] = defaultProps[propName];
+ } else {
+ props[propName] = config[propName];
+ }
+ }
+ }
+ }
+
+ // Children can be more than one argument, and those are transferred onto
+ // the newly allocated props object.
+ const childrenLength = arguments.length - 2;
+ if (childrenLength === 1) {
+ props.children = children;
+ } else if (childrenLength > 1) {
+ const childArray = Array(childrenLength);
+ for (let i = 0; i < childrenLength; i++) {
+ childArray[i] = arguments[i + 2];
+ }
+ props.children = childArray;
+ }
+
+ const clonedElement = ReactElement(
+ element.type,
+ key,
+ ref,
+ undefined,
+ undefined,
+ owner,
+ props,
+ );
+
+ for (let i = 2; i < arguments.length; i++) {
+ validateChildKeys(arguments[i], clonedElement.type);
+ }
+ validatePropTypes(clonedElement);
+
+ return clonedElement;
+}
+
function getDeclarationErrorAddendum() {
if (__DEV__) {
if (ReactCurrentOwner.current) {
@@ -524,6 +850,13 @@ function getDeclarationErrorAddendum() {
}
}
+function getSourceInfoErrorAddendumForProps(elementProps) {
+ if (elementProps !== null && elementProps !== undefined) {
+ return getSourceInfoErrorAddendum(elementProps.__source);
+ }
+ return '';
+}
+
function getSourceInfoErrorAddendum(source) {
if (__DEV__) {
if (source !== undefined) {
@@ -590,13 +923,11 @@ function validateChildKeys(node, parentType) {
* @final
*/
export function isValidElement(object) {
- if (__DEV__) {
- return (
- typeof object === 'object' &&
- object !== null &&
- object.$$typeof === REACT_ELEMENT_TYPE
- );
- }
+ return (
+ typeof object === 'object' &&
+ object !== null &&
+ object.$$typeof === REACT_ELEMENT_TYPE
+ );
}
const ownerHasKeyUseWarning = {};