forked from facebook/react
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add react-is package (facebook#12199)
Authoritative brand checking library. Can be used without any dependency on React. Plausible replacement for `React.isValidElement.`
- Loading branch information
Showing
9 changed files
with
353 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# `react-is` | ||
|
||
This package allows you to test arbitrary values and see if they're a particular React type, e.g. React Elements. | ||
|
||
## Installation | ||
|
||
```sh | ||
# Yarn | ||
yarn add react-is | ||
|
||
# NPM | ||
npm install react-is --save | ||
``` | ||
|
||
## Usage | ||
|
||
### AsyncMode | ||
|
||
```js | ||
import React from "react"; | ||
import * as ReactIs from 'react-is'; | ||
|
||
ReactIs.isAsyncMode(<React.unstable_AsyncMode />); // true | ||
ReactIs.typeOf(<React.unstable_AsyncMode />) === ReactIs.AsyncMode; // true | ||
``` | ||
|
||
### Context | ||
|
||
```js | ||
import React from "react"; | ||
import * as ReactIs from 'react-is'; | ||
|
||
const ThemeContext = React.createContext("blue"); | ||
|
||
ReactIs.isContextConsumer(<ThemeContext.Consumer />); // true | ||
ReactIs.isContextProvider(<ThemeContext.Provider />); // true | ||
ReactIs.typeOf(<ThemeContext.Provider />) === ReactIs.ContextProvider; // true | ||
ReactIs.typeOf(<ThemeContext.Consumer />) === ReactIs.ContextConsumer; // true | ||
``` | ||
|
||
### Element | ||
|
||
```js | ||
import React from "react"; | ||
import * as ReactIs from 'react-is'; | ||
|
||
ReactIs.isElement(<div />); // true | ||
ReactIs.typeOf(<div />) === ReactIs.Element; // true | ||
``` | ||
|
||
### Fragment | ||
|
||
```js | ||
import React from "react"; | ||
import * as ReactIs from 'react-is'; | ||
|
||
ReactIs.isFragment(<></>); // true | ||
ReactIs.typeOf(<></>) === ReactIs.Fragment; // true | ||
``` | ||
|
||
### Portal | ||
|
||
```js | ||
import React from "react"; | ||
import ReactDOM from "react-dom"; | ||
import * as ReactIs from 'react-is'; | ||
|
||
const div = document.createElement("div"); | ||
const portal = ReactDOM.createPortal(<div />, div); | ||
|
||
ReactIs.isPortal(portal); // true | ||
ReactIs.typeOf(portal) === ReactIs.Portal; // true | ||
``` | ||
|
||
### StrictMode | ||
|
||
```js | ||
import React from "react"; | ||
import * as ReactIs from 'react-is'; | ||
|
||
ReactIs.isStrictMode(<React.StrictMode />); // true | ||
ReactIs.typeOf(<React.StrictMode />) === ReactIs.StrictMode; // true | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/** | ||
* Copyright (c) 2013-present, Facebook, Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @flow | ||
*/ | ||
|
||
'use strict'; | ||
|
||
export * from './src/ReactIs'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
|
||
if (process.env.NODE_ENV === 'production') { | ||
module.exports = require('./cjs/react-is.production.min.js'); | ||
} else { | ||
module.exports = require('./cjs/react-is.development.js'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"name": "react-is", | ||
"version": "16.3.0-alpha.0", | ||
"description": "Brand checking of React Elements.", | ||
"main": "index.js", | ||
"repository": "facebook/react", | ||
"keywords": ["react"], | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/facebook/react/issues" | ||
}, | ||
"homepage": "https://reactjs.org/", | ||
"peerDependencies": { | ||
"react": "^16.0.0 || 16.3.0-alpha.0" | ||
}, | ||
"files": [ | ||
"LICENSE", | ||
"README.md", | ||
"index.js", | ||
"cjs/", | ||
"umd/" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/** | ||
* Copyright (c) 2013-present, Facebook, Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @flow | ||
*/ | ||
|
||
'use strict'; | ||
|
||
import { | ||
REACT_ASYNC_MODE_TYPE, | ||
REACT_CONTEXT_TYPE, | ||
REACT_ELEMENT_TYPE, | ||
REACT_FRAGMENT_TYPE, | ||
REACT_PORTAL_TYPE, | ||
REACT_PROVIDER_TYPE, | ||
REACT_STRICT_MODE_TYPE, | ||
} from 'shared/ReactSymbols'; | ||
|
||
export function typeOf(object: any) { | ||
if (typeof object === 'object' && object !== null) { | ||
const $$typeof = object.$$typeof; | ||
|
||
switch ($$typeof) { | ||
case REACT_ELEMENT_TYPE: | ||
const type = object.type; | ||
|
||
switch (type) { | ||
case REACT_ASYNC_MODE_TYPE: | ||
case REACT_FRAGMENT_TYPE: | ||
case REACT_STRICT_MODE_TYPE: | ||
return type; | ||
default: | ||
const $$typeofType = type.$$typeof; | ||
|
||
switch ($$typeofType) { | ||
case REACT_CONTEXT_TYPE: | ||
case REACT_PROVIDER_TYPE: | ||
return $$typeofType; | ||
default: | ||
return $$typeof; | ||
} | ||
} | ||
case REACT_PORTAL_TYPE: | ||
return $$typeof; | ||
} | ||
} | ||
|
||
return undefined; | ||
} | ||
|
||
export const AsyncMode = REACT_ASYNC_MODE_TYPE; | ||
export const ContextConsumer = REACT_CONTEXT_TYPE; | ||
export const ContextProvider = REACT_PROVIDER_TYPE; | ||
export const Element = REACT_ELEMENT_TYPE; | ||
export const Fragment = REACT_FRAGMENT_TYPE; | ||
export const Portal = REACT_PORTAL_TYPE; | ||
export const StrictMode = REACT_STRICT_MODE_TYPE; | ||
|
||
export function isAsyncMode(object: any) { | ||
return typeOf(object) === REACT_ASYNC_MODE_TYPE; | ||
} | ||
export function isContextConsumer(object: any) { | ||
return typeOf(object) === REACT_CONTEXT_TYPE; | ||
} | ||
export function isContextProvider(object: any) { | ||
return typeOf(object) === REACT_PROVIDER_TYPE; | ||
} | ||
export function isElement(object: any) { | ||
return ( | ||
typeof object === 'object' && | ||
object !== null && | ||
object.$$typeof === REACT_ELEMENT_TYPE | ||
); | ||
} | ||
export function isFragment(object: any) { | ||
return typeOf(object) === REACT_FRAGMENT_TYPE; | ||
} | ||
export function isPortal(object: any) { | ||
return typeOf(object) === REACT_PORTAL_TYPE; | ||
} | ||
export function isStrictMode(object: any) { | ||
return typeOf(object) === REACT_STRICT_MODE_TYPE; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/** | ||
* Copyright (c) 2013-present, Facebook, Inc. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @emails react-core | ||
*/ | ||
|
||
'use strict'; | ||
|
||
let React; | ||
let ReactDOM; | ||
let ReactIs; | ||
|
||
describe('ReactIs', () => { | ||
beforeEach(() => { | ||
jest.resetModules(); | ||
|
||
React = require('react'); | ||
ReactDOM = require('react-dom'); | ||
ReactIs = require('react-is'); | ||
}); | ||
|
||
it('should return undefined for unknown/invalid types', () => { | ||
expect(ReactIs.typeOf('abc')).toBe(undefined); | ||
expect(ReactIs.typeOf(true)).toBe(undefined); | ||
expect(ReactIs.typeOf(123)).toBe(undefined); | ||
expect(ReactIs.typeOf({})).toBe(undefined); | ||
expect(ReactIs.typeOf(null)).toBe(undefined); | ||
expect(ReactIs.typeOf(undefined)).toBe(undefined); | ||
}); | ||
|
||
it('should identify async mode', () => { | ||
expect(ReactIs.typeOf(<React.unstable_AsyncMode />)).toBe( | ||
ReactIs.AsyncMode, | ||
); | ||
expect(ReactIs.isAsyncMode(<React.unstable_AsyncMode />)).toBe(true); | ||
expect(ReactIs.isAsyncMode({type: ReactIs.AsyncMode})).toBe(false); | ||
expect(ReactIs.isAsyncMode(<React.StrictMode />)).toBe(false); | ||
expect(ReactIs.isAsyncMode(<div />)).toBe(false); | ||
}); | ||
|
||
it('should identify context consumers', () => { | ||
const Context = React.createContext(false); | ||
expect(ReactIs.typeOf(<Context.Consumer />)).toBe(ReactIs.ContextConsumer); | ||
expect(ReactIs.isContextConsumer(<Context.Consumer />)).toBe(true); | ||
expect(ReactIs.isContextConsumer(<Context.Provider />)).toBe(false); | ||
expect(ReactIs.isContextConsumer(<div />)).toBe(false); | ||
}); | ||
|
||
it('should identify context providers', () => { | ||
const Context = React.createContext(false); | ||
expect(ReactIs.typeOf(<Context.Provider />)).toBe(ReactIs.ContextProvider); | ||
expect(ReactIs.isContextProvider(<Context.Provider />)).toBe(true); | ||
expect(ReactIs.isContextProvider(<Context.Consumer />)).toBe(false); | ||
expect(ReactIs.isContextProvider(<div />)).toBe(false); | ||
}); | ||
|
||
it('should identify elements', () => { | ||
expect(ReactIs.typeOf(<div />)).toBe(ReactIs.Element); | ||
expect(ReactIs.isElement(<div />)).toBe(true); | ||
expect(ReactIs.isElement('div')).toBe(false); | ||
expect(ReactIs.isElement(true)).toBe(false); | ||
expect(ReactIs.isElement(123)).toBe(false); | ||
expect(ReactIs.isElement(null)).toBe(false); | ||
expect(ReactIs.isElement(undefined)).toBe(false); | ||
expect(ReactIs.isElement({})).toBe(false); | ||
|
||
// It should also identify more specific types as elements | ||
const Context = React.createContext(false); | ||
expect(ReactIs.isElement(<Context.Provider />)).toBe(true); | ||
expect(ReactIs.isElement(<Context.Consumer />)).toBe(true); | ||
expect(ReactIs.isElement(<React.Fragment />)).toBe(true); | ||
expect(ReactIs.isElement(<React.unstable_AsyncMode />)).toBe(true); | ||
expect(ReactIs.isElement(<React.StrictMode />)).toBe(true); | ||
}); | ||
|
||
it('should identify fragments', () => { | ||
expect(ReactIs.typeOf(<React.Fragment />)).toBe(ReactIs.Fragment); | ||
expect(ReactIs.isFragment(<React.Fragment />)).toBe(true); | ||
expect(ReactIs.isFragment({type: ReactIs.Fragment})).toBe(false); | ||
expect(ReactIs.isFragment('React.Fragment')).toBe(false); | ||
expect(ReactIs.isFragment(<div />)).toBe(false); | ||
expect(ReactIs.isFragment([])).toBe(false); | ||
}); | ||
|
||
it('should identify portals', () => { | ||
const div = document.createElement('div'); | ||
const portal = ReactDOM.createPortal(<div />, div); | ||
expect(ReactIs.typeOf(portal)).toBe(ReactIs.Portal); | ||
expect(ReactIs.isPortal(portal)).toBe(true); | ||
expect(ReactIs.isPortal(div)).toBe(false); | ||
}); | ||
|
||
it('should identify strict mode', () => { | ||
expect(ReactIs.typeOf(<React.StrictMode />)).toBe(ReactIs.StrictMode); | ||
expect(ReactIs.isStrictMode(<React.StrictMode />)).toBe(true); | ||
expect(ReactIs.isStrictMode({type: ReactIs.StrictMode})).toBe(false); | ||
expect(ReactIs.isStrictMode(<React.unstable_AsyncMode />)).toBe(false); | ||
expect(ReactIs.isStrictMode(<div />)).toBe(false); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters