diff --git a/package.json b/package.json index ed590b14..da9bb1f8 100644 --- a/package.json +++ b/package.json @@ -16,14 +16,17 @@ "eslint-plugin-jest": "^23.20.0", "eslint-plugin-prettier": "^3.1.4", "eslint-plugin-react": "^7.20.5", - "husky": "^4.2.5", "jest": "^26.2.2", "lerna": "^3.22.1", - "lint-staged": "^10.2.11", "prettier": "^2.0.5", + "react": "^16.13.1", + "react-dom": "^16.13.1", + "react-test-renderer": "^16.13.1", "rimraf": "^3.0.2", "ts-jest": "^26.2.0", - "typescript": "^3.9.7" + "typescript": "^3.9.7", + "webpack": "^4.44.1", + "webpack-cli": "^3.3.12" }, "scripts": { "lerna": "lerna", @@ -49,19 +52,5 @@ ], "engines": { "node": ">=10.13.0" - }, - "husky": { - "hooks": { - "pre-commit": "lint-staged" - } - }, - "lint-staged": { - "*.{js,jsx,ts,tsx}": [ - "prettier --write", - "yarn lint:fix" - ], - "*.{json,css,html,md}": [ - "prettier --write" - ] } } diff --git a/packages/react-base16-styling/src/index.ts b/packages/react-base16-styling/src/index.ts index 382fcec3..8542d58d 100644 --- a/packages/react-base16-styling/src/index.ts +++ b/packages/react-base16-styling/src/index.ts @@ -288,3 +288,6 @@ export const invertTheme = (theme: Theme): Theme => { return theme; }; + +export { Base16Theme }; +export * from './types'; diff --git a/packages/react-json-tree/package.json b/packages/react-json-tree/package.json index 675ec010..ce606f4e 100644 --- a/packages/react-json-tree/package.json +++ b/packages/react-json-tree/package.json @@ -30,36 +30,27 @@ "url": "https://github.com/reduxjs/redux-devtools.git" }, "scripts": { - "clean": "rimraf lib", - "build": "babel src --out-dir lib", + "start": "cd examples && npm start", + "build": "npm run build:types && npm run build:js && npm build:umd && npm build:umd:min", + "build:types": "tsc --emitDeclarationOnly", + "build:js": "babel src --out-dir lib --extensions \".ts,.tsx\" --source-maps inline", "build:umd": "rimraf ./umd && webpack --progress --config webpack.config.umd.js", "build:umd:min": "webpack --env.production --progress --config webpack.config.umd.js", + "clean": "rimraf lib umd", "test": "jest", - "prepare": "npm run build", - "prepublishOnly": "npm run test && npm run clean && npm run build && npm run build:umd && npm run build:umd:min", - "start": "cd examples && npm start" - }, - "devDependencies": { - "@babel/cli": "^7.10.5", - "@babel/core": "^7.11.1", - "@babel/plugin-proposal-class-properties": "^7.10.4", - "@babel/preset-env": "^7.11.0", - "@babel/preset-react": "^7.10.4", - "babel-loader": "^8.1.0", - "jest": "^26.2.2", - "react": "^16.13.1", - "react-dom": "^16.13.1", - "react-test-renderer": "^16.13.1", - "rimraf": "^3.0.2", - "webpack": "^4.44.1", - "webpack-cli": "^3.3.12" - }, - "peerDependencies": { - "react": "^16.3.0", - "react-dom": "^16.3.0" + "lint": "eslint . --ext .ts,.tsx", + "lint:fix": "eslint . --ext .ts,.tsx --fix", + "type-check": "tsc --noEmit", + "type-check:watch": "npm run type-check -- --watch", + "preversion": "npm run type-check && npm run lint && npm run test", + "prepublishOnly": "npm run clean && npm run build" }, "dependencies": { "prop-types": "^15.7.2", "react-base16-styling": "^0.7.0" + }, + "peerDependencies": { + "react": "^16.3.0", + "react-dom": "^16.3.0" } } diff --git a/packages/react-json-tree/src/ItemRange.js b/packages/react-json-tree/src/ItemRange.tsx similarity index 70% rename from packages/react-json-tree/src/ItemRange.js rename to packages/react-json-tree/src/ItemRange.tsx index 5af82f0d..3848783e 100644 --- a/packages/react-json-tree/src/ItemRange.js +++ b/packages/react-json-tree/src/ItemRange.tsx @@ -1,8 +1,21 @@ import React from 'react'; import PropTypes from 'prop-types'; import JSONArrow from './JSONArrow'; +import { CircularPropsPassedThroughItemRange } from './types'; -export default class ItemRange extends React.Component { +interface Props extends CircularPropsPassedThroughItemRange { + data: any; + nodeType: string; + from: number; + to: number; + renderChildNodes: (props: Props, from: number, to: number) => React.ReactNode; +} + +interface State { + expanded: boolean; +} + +export default class ItemRange extends React.Component { static propTypes = { styling: PropTypes.func.isRequired, from: PropTypes.number.isRequired, @@ -11,11 +24,9 @@ export default class ItemRange extends React.Component { nodeType: PropTypes.string.isRequired, }; - constructor(props) { + constructor(props: Props) { super(props); this.state = { expanded: false }; - - this.handleClick = this.handleClick.bind(this); } render() { @@ -42,7 +53,7 @@ export default class ItemRange extends React.Component { ); } - handleClick() { + handleClick = () => { this.setState({ expanded: !this.state.expanded }); - } + }; } diff --git a/packages/react-json-tree/src/JSONArrayNode.js b/packages/react-json-tree/src/JSONArrayNode.tsx similarity index 68% rename from packages/react-json-tree/src/JSONArrayNode.js rename to packages/react-json-tree/src/JSONArrayNode.tsx index f07ae3c3..71fb7f2a 100644 --- a/packages/react-json-tree/src/JSONArrayNode.js +++ b/packages/react-json-tree/src/JSONArrayNode.tsx @@ -1,15 +1,21 @@ import React from 'react'; import PropTypes from 'prop-types'; import JSONNestedNode from './JSONNestedNode'; +import { CircularPropsPassedThroughJSONNode } from './types'; // Returns the "n Items" string for this node, // generating and caching it if it hasn't been created yet. -function createItemString(data) { +function createItemString(data: any) { return `${data.length} ${data.length !== 1 ? 'items' : 'item'}`; } +interface Props extends CircularPropsPassedThroughJSONNode { + data: any; + nodeType: string; +} + // Configures to render an Array -const JSONArrayNode = ({ data, ...props }) => ( +const JSONArrayNode: React.FunctionComponent = ({ data, ...props }) => ( ( +interface Props { + styling: StylingFunction; + arrowStyle?: 'single' | 'double'; + expanded: boolean; + nodeType: string; + onClick: React.MouseEventHandler; +} + +const JSONArrow: React.FunctionComponent = ({ + styling, + arrowStyle, + expanded, + nodeType, + onClick, +}) => (
{'\u25B6'} diff --git a/packages/react-json-tree/src/JSONIterableNode.js b/packages/react-json-tree/src/JSONIterableNode.tsx similarity index 70% rename from packages/react-json-tree/src/JSONIterableNode.js rename to packages/react-json-tree/src/JSONIterableNode.tsx index f252481c..dff51ad5 100644 --- a/packages/react-json-tree/src/JSONIterableNode.js +++ b/packages/react-json-tree/src/JSONIterableNode.tsx @@ -1,9 +1,10 @@ import React from 'react'; import JSONNestedNode from './JSONNestedNode'; +import { CircularPropsPassedThroughJSONNode } from './types'; // Returns the "n Items" string for this node, // generating and caching it if it hasn't been created yet. -function createItemString(data, limit) { +function createItemString(data: any, limit: number) { let count = 0; let hasMore = false; if (Number.isSafeInteger(data.size)) { @@ -21,8 +22,13 @@ function createItemString(data, limit) { return `${hasMore ? '>' : ''}${count} ${count !== 1 ? 'entries' : 'entry'}`; } +interface Props extends CircularPropsPassedThroughJSONNode { + data: any; + nodeType: string; +} + // Configures to render an iterable -export default function JSONIterableNode({ ...props }) { +const JSONIterableNode: React.FunctionComponent = ({ ...props }) => { return ( ); -} +}; + +export default JSONIterableNode; diff --git a/packages/react-json-tree/src/JSONNestedNode.js b/packages/react-json-tree/src/JSONNestedNode.tsx similarity index 78% rename from packages/react-json-tree/src/JSONNestedNode.js rename to packages/react-json-tree/src/JSONNestedNode.tsx index 289afc2b..e8dbb261 100644 --- a/packages/react-json-tree/src/JSONNestedNode.js +++ b/packages/react-json-tree/src/JSONNestedNode.tsx @@ -4,12 +4,40 @@ import JSONArrow from './JSONArrow'; import getCollectionEntries from './getCollectionEntries'; import JSONNode from './JSONNode'; import ItemRange from './ItemRange'; +import { + CircularPropsPassedThroughJSONNestedNode, + CircularPropsPassedThroughRenderChildNodes, +} from './types'; /** * Renders nested values (eg. objects, arrays, lists, etc.) */ -function renderChildNodes(props, from, to) { +export interface RenderChildNodesProps + extends CircularPropsPassedThroughRenderChildNodes { + data: any; + nodeType: string; +} + +interface Range { + from: number; + to: number; +} + +interface Entry { + key: string | number; + value: any; +} + +function isRange(rangeOrEntry: Range | Entry): rangeOrEntry is Range { + return (rangeOrEntry as Range).to !== undefined; +} + +function renderChildNodes( + props: RenderChildNodesProps, + from?: number, + to?: number +) { const { nodeType, data, @@ -19,7 +47,7 @@ function renderChildNodes(props, from, to) { postprocessValue, sortObjectKeys, } = props; - const childNodes = []; + const childNodes: React.ReactNode[] = []; getCollectionEntries( nodeType, @@ -29,7 +57,7 @@ function renderChildNodes(props, from, to) { from, to ).forEach((entry) => { - if (entry.to) { + if (isRange(entry)) { childNodes.push( ); - - if (node !== false) { - childNodes.push(node); - } } }); return childNodes; } -function getStateFromProps(props) { +interface Props extends CircularPropsPassedThroughJSONNestedNode { + data: any; + nodeType: string; + nodeTypeIndicator: string; + createItemString: (data: any, collectionLimit: number) => string; + expandable: boolean; +} + +interface State { + expanded: boolean; +} + +function getStateFromProps(props: Props) { // calculate individual node expansion if necessary const expanded = props.shouldExpandNode && !props.isCircular @@ -76,7 +112,7 @@ function getStateFromProps(props) { }; } -export default class JSONNestedNode extends React.Component { +export default class JSONNestedNode extends React.Component { static propTypes = { getItemString: PropTypes.func.isRequired, nodeTypeIndicator: PropTypes.any, @@ -104,26 +140,26 @@ export default class JSONNestedNode extends React.Component { expandable: true, }; - constructor(props) { + constructor(props: Props) { super(props); this.state = getStateFromProps(props); } - UNSAFE_componentWillReceiveProps(nextProps) { + UNSAFE_componentWillReceiveProps(nextProps: Props) { const nextState = getStateFromProps(nextProps); if (getStateFromProps(this.props).expanded !== nextState.expanded) { this.setState(nextState); } } - shouldComponentUpdate(nextProps, nextState) { + shouldComponentUpdate(nextProps: Props, nextState: State) { return ( !!Object.keys(nextProps).find( (key) => key !== 'circularCache' && (key === 'keyPath' ? nextProps[key].join('/') !== this.props[key].join('/') - : nextProps[key] !== this.props[key]) + : nextProps[key as keyof Props] !== this.props[key as keyof Props]) ) || nextState.expanded !== this.state.expanded ); } @@ -159,7 +195,7 @@ export default class JSONNestedNode extends React.Component { itemType, createItemString(data, collectionLimit) ); - const stylingArgs = [keyPath, nodeType, expanded, expandable]; + const stylingArgs = [keyPath, nodeType, expanded, expandable] as const; return hideRoot ? (
  • diff --git a/packages/react-json-tree/src/JSONNode.js b/packages/react-json-tree/src/JSONNode.tsx similarity index 88% rename from packages/react-json-tree/src/JSONNode.js rename to packages/react-json-tree/src/JSONNode.tsx index de05f6fc..bedeeee3 100644 --- a/packages/react-json-tree/src/JSONNode.js +++ b/packages/react-json-tree/src/JSONNode.tsx @@ -5,8 +5,15 @@ import JSONObjectNode from './JSONObjectNode'; import JSONArrayNode from './JSONArrayNode'; import JSONIterableNode from './JSONIterableNode'; import JSONValueNode from './JSONValueNode'; +import { CircularPropsPassedThroughJSONNode } from './types'; -const JSONNode = ({ +interface Props extends CircularPropsPassedThroughJSONNode { + keyPath: (string | number)[]; + value: any; + isCustomNode: (value: any) => boolean; +} + +const JSONNode: React.FunctionComponent = ({ getItemString, keyPath, labelRenderer, @@ -97,7 +104,7 @@ const JSONNode = ({ JSONNode.propTypes = { getItemString: PropTypes.func.isRequired, keyPath: PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]) + PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired ).isRequired, labelRenderer: PropTypes.func.isRequired, styling: PropTypes.func.isRequired, diff --git a/packages/react-json-tree/src/JSONObjectNode.js b/packages/react-json-tree/src/JSONObjectNode.tsx similarity index 69% rename from packages/react-json-tree/src/JSONObjectNode.js rename to packages/react-json-tree/src/JSONObjectNode.tsx index 027715ef..6cfcbe06 100644 --- a/packages/react-json-tree/src/JSONObjectNode.js +++ b/packages/react-json-tree/src/JSONObjectNode.tsx @@ -1,16 +1,22 @@ import React from 'react'; import PropTypes from 'prop-types'; import JSONNestedNode from './JSONNestedNode'; +import { CircularPropsPassedThroughJSONNode } from './types'; // Returns the "n Items" string for this node, // generating and caching it if it hasn't been created yet. -function createItemString(data) { +function createItemString(data: any) { const len = Object.getOwnPropertyNames(data).length; return `${len} ${len !== 1 ? 'keys' : 'key'}`; } +interface Props extends CircularPropsPassedThroughJSONNode { + data: any; + nodeType: string; +} + // Configures to render an Object -const JSONObjectNode = ({ data, ...props }) => ( +const JSONObjectNode: React.FunctionComponent = ({ data, ...props }) => ( ( JSONObjectNode.propTypes = { data: PropTypes.object, - nodeType: PropTypes.string, + nodeType: PropTypes.string.isRequired, }; export default JSONObjectNode; diff --git a/packages/react-json-tree/src/JSONValueNode.js b/packages/react-json-tree/src/JSONValueNode.tsx similarity index 69% rename from packages/react-json-tree/src/JSONValueNode.js rename to packages/react-json-tree/src/JSONValueNode.tsx index 40cd679e..c7754256 100644 --- a/packages/react-json-tree/src/JSONValueNode.js +++ b/packages/react-json-tree/src/JSONValueNode.tsx @@ -1,18 +1,25 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { JSONValueNodeCircularPropsProvidedByJSONNode } from './types'; /** * Renders simple values (eg. strings, numbers, booleans, etc) */ -const JSONValueNode = ({ +interface Props extends JSONValueNodeCircularPropsProvidedByJSONNode { + nodeType: string; + value: any; + valueGetter?: (value: any) => any; +} + +const JSONValueNode: React.FunctionComponent = ({ nodeType, styling, labelRenderer, keyPath, valueRenderer, value, - valueGetter, + valueGetter = (value) => value, }) => (