mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-07-27 00:19:55 +03:00
Do it
This commit is contained in:
parent
469cf7cb2c
commit
460b20369a
3
.prettierrc
Normal file
3
.prettierrc
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"singleQuote": true
|
||||
}
|
1
packages/react-json-tree/.eslintignore
Normal file
1
packages/react-json-tree/.eslintignore
Normal file
|
@ -0,0 +1 @@
|
|||
lib
|
|
@ -12,6 +12,8 @@
|
|||
"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.minimize --progress --config webpack.config.umd.js",
|
||||
"lint": "eslint . --ext .ts,.tsx",
|
||||
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
||||
"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",
|
||||
|
@ -49,11 +51,12 @@
|
|||
"@babel/preset-env": "^7.3.1",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/preset-typescript": "^7.9.0",
|
||||
"@types/react": "^15.0.0 || ^16.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.31.0",
|
||||
"@typescript-eslint/parser": "^2.31.0",
|
||||
"babel-loader": "^8.0.5",
|
||||
"jest": "^24.1.0",
|
||||
"react": "^16.0.0",
|
||||
"react": "^15.0.0 || ^16.0.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-test-renderer": "^16.0.0",
|
||||
"rimraf": "^2.5.2",
|
||||
|
|
|
@ -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<Props, State> {
|
||||
static propTypes = {
|
||||
styling: PropTypes.func.isRequired,
|
||||
from: PropTypes.number.isRequired,
|
||||
|
@ -11,7 +24,7 @@ export default class ItemRange extends React.Component {
|
|||
nodeType: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = { expanded: false };
|
||||
|
||||
|
@ -42,7 +55,7 @@ export default class ItemRange extends React.Component {
|
|||
);
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
handleClick = () => {
|
||||
this.setState({ expanded: !this.state.expanded });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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 <JSONNestedNode> to render an Array
|
||||
const JSONArrayNode = ({ data, ...props }) => (
|
||||
const JSONArrayNode: React.FunctionComponent<Props> = ({ data, ...props }) => (
|
||||
<JSONNestedNode
|
||||
{...props}
|
||||
data={data}
|
||||
|
|
|
@ -1,7 +1,22 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StylingFunction } from 'react-base16-styling';
|
||||
|
||||
const JSONArrow = ({ styling, arrowStyle, expanded, nodeType, onClick }) => (
|
||||
interface Props {
|
||||
styling: StylingFunction;
|
||||
arrowStyle?: 'single' | 'double';
|
||||
expanded: boolean;
|
||||
nodeType: string;
|
||||
onClick: React.MouseEventHandler<HTMLDivElement>;
|
||||
}
|
||||
|
||||
const JSONArrow: React.FunctionComponent<Props> = ({
|
||||
styling,
|
||||
arrowStyle,
|
||||
expanded,
|
||||
nodeType,
|
||||
onClick
|
||||
}) => (
|
||||
<div {...styling('arrowContainer', arrowStyle)} onClick={onClick}>
|
||||
<div {...styling(['arrow', 'arrowSign'], nodeType, expanded, arrowStyle)}>
|
||||
{'\u25B6'}
|
||||
|
|
|
@ -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 <JSONNestedNode> to render an iterable
|
||||
export default function JSONIterableNode({ ...props }) {
|
||||
const JSONIterableNode: React.FunctionComponent<Props> = ({ ...props }) => {
|
||||
return (
|
||||
<JSONNestedNode
|
||||
{...props}
|
||||
|
@ -31,4 +37,6 @@ export default function JSONIterableNode({ ...props }) {
|
|||
createItemString={createItemString}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default JSONIterableNode;
|
||||
|
|
|
@ -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(
|
||||
<ItemRange
|
||||
{...props}
|
||||
|
@ -41,9 +69,9 @@ function renderChildNodes(props, from, to) {
|
|||
);
|
||||
} else {
|
||||
const { key, value } = entry;
|
||||
const isCircular = circularCache.indexOf(value) !== -1;
|
||||
const isCircular = circularCache.includes(value);
|
||||
|
||||
const node = (
|
||||
childNodes.push(
|
||||
<JSONNode
|
||||
{...props}
|
||||
{...{ postprocessValue, collectionLimit }}
|
||||
|
@ -55,17 +83,25 @@ function renderChildNodes(props, from, to) {
|
|||
hideRoot={false}
|
||||
/>
|
||||
);
|
||||
|
||||
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<Props, State> {
|
||||
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 ? (
|
||||
<li {...styling('rootNode', ...stylingArgs)}>
|
||||
|
|
|
@ -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<Props> = ({
|
||||
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,
|
||||
|
|
|
@ -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 <JSONNestedNode> to render an Object
|
||||
const JSONObjectNode = ({ data, ...props }) => (
|
||||
const JSONObjectNode: React.FunctionComponent<Props> = ({ data, ...props }) => (
|
||||
<JSONNestedNode
|
||||
{...props}
|
||||
data={data}
|
||||
|
@ -23,7 +29,7 @@ const JSONObjectNode = ({ data, ...props }) => (
|
|||
|
||||
JSONObjectNode.propTypes = {
|
||||
data: PropTypes.object,
|
||||
nodeType: PropTypes.string
|
||||
nodeType: PropTypes.string.isRequired
|
||||
};
|
||||
|
||||
export default JSONObjectNode;
|
||||
|
|
|
@ -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<Props> = ({
|
||||
nodeType,
|
||||
styling,
|
||||
labelRenderer,
|
||||
keyPath,
|
||||
valueRenderer,
|
||||
value,
|
||||
valueGetter
|
||||
valueGetter = value => value
|
||||
}) => (
|
||||
<li {...styling('value', nodeType, keyPath)}>
|
||||
<label {...styling(['label', 'valueLabel'], nodeType, keyPath)}>
|
||||
|
@ -29,15 +36,11 @@ JSONValueNode.propTypes = {
|
|||
styling: PropTypes.func.isRequired,
|
||||
labelRenderer: PropTypes.func.isRequired,
|
||||
keyPath: PropTypes.arrayOf(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
|
||||
).isRequired,
|
||||
valueRenderer: PropTypes.func.isRequired,
|
||||
value: PropTypes.any,
|
||||
valueGetter: PropTypes.func
|
||||
};
|
||||
|
||||
JSONValueNode.defaultProps = {
|
||||
valueGetter: value => value
|
||||
};
|
||||
|
||||
export default JSONValueNode;
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import { createStyling } from 'react-base16-styling';
|
||||
import {
|
||||
createStyling,
|
||||
Base16Theme,
|
||||
StylingConfig
|
||||
} from 'react-base16-styling';
|
||||
import solarized from './themes/solarized';
|
||||
|
||||
const colorMap = theme => ({
|
||||
const colorMap = (theme: Base16Theme) => ({
|
||||
BACKGROUND_COLOR: theme.base00,
|
||||
TEXT_COLOR: theme.base07,
|
||||
STRING_COLOR: theme.base0B,
|
||||
|
@ -18,7 +22,12 @@ const colorMap = theme => ({
|
|||
ITEM_STRING_EXPANDED_COLOR: theme.base03
|
||||
});
|
||||
|
||||
const valueColorMap = colors => ({
|
||||
type Color = keyof ReturnType<typeof colorMap>;
|
||||
type Colors = {
|
||||
[color in Color]: string;
|
||||
};
|
||||
|
||||
const valueColorMap = (colors: Colors) => ({
|
||||
String: colors.STRING_COLOR,
|
||||
Date: colors.DATE_COLOR,
|
||||
Number: colors.NUMBER_COLOR,
|
||||
|
@ -29,7 +38,7 @@ const valueColorMap = colors => ({
|
|||
Symbol: colors.SYMBOL_COLOR
|
||||
});
|
||||
|
||||
const getDefaultThemeStyling = theme => {
|
||||
const getDefaultThemeStyling = (theme: Base16Theme): StylingConfig => {
|
||||
const colors = colorMap(theme);
|
||||
|
||||
return {
|
||||
|
@ -73,7 +82,9 @@ const getDefaultThemeStyling = theme => {
|
|||
valueText: ({ style }, nodeType) => ({
|
||||
style: {
|
||||
...style,
|
||||
color: valueColorMap(colors)[nodeType]
|
||||
color: valueColorMap(colors)[
|
||||
nodeType as keyof ReturnType<typeof valueColorMap>
|
||||
]
|
||||
}
|
||||
}),
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
function getLength(type, collection) {
|
||||
function getLength(type: string, collection: any) {
|
||||
if (type === 'Object') {
|
||||
return Object.keys(collection).length;
|
||||
} else if (type === 'Array') {
|
||||
|
@ -8,11 +8,17 @@ function getLength(type, collection) {
|
|||
return Infinity;
|
||||
}
|
||||
|
||||
function isIterableMap(collection) {
|
||||
function isIterableMap(collection: any) {
|
||||
return typeof collection.set === 'function';
|
||||
}
|
||||
|
||||
function getEntries(type, collection, sortObjectKeys, from = 0, to = Infinity) {
|
||||
function getEntries(
|
||||
type: string,
|
||||
collection: any,
|
||||
sortObjectKeys?: ((a: any, b: any) => number) | boolean | undefined,
|
||||
from = 0,
|
||||
to = Infinity
|
||||
): { entries: { key: string | number; value: any }[]; hasMore?: boolean } {
|
||||
let res;
|
||||
|
||||
if (type === 'Object') {
|
||||
|
@ -31,7 +37,7 @@ function getEntries(type, collection, sortObjectKeys, from = 0, to = Infinity) {
|
|||
res = {
|
||||
entries: collection
|
||||
.slice(from, to + 1)
|
||||
.map((val, idx) => ({ key: idx + from, value: val }))
|
||||
.map((val: any, idx: number) => ({ key: idx + from, value: val }))
|
||||
};
|
||||
} else {
|
||||
let idx = 0;
|
||||
|
@ -74,7 +80,7 @@ function getEntries(type, collection, sortObjectKeys, from = 0, to = Infinity) {
|
|||
return res;
|
||||
}
|
||||
|
||||
function getRanges(from, to, limit) {
|
||||
function getRanges(from: number, to: number, limit: number) {
|
||||
const ranges = [];
|
||||
while (to - from > limit * limit) {
|
||||
limit = limit * limit;
|
||||
|
@ -87,10 +93,10 @@ function getRanges(from, to, limit) {
|
|||
}
|
||||
|
||||
export default function getCollectionEntries(
|
||||
type,
|
||||
collection,
|
||||
sortObjectKeys,
|
||||
limit,
|
||||
type: string,
|
||||
collection: any,
|
||||
sortObjectKeys: ((a: any, b: any) => number) | boolean | undefined,
|
||||
limit: number,
|
||||
from = 0,
|
||||
to = Infinity
|
||||
) {
|
||||
|
|
|
@ -7,19 +7,47 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import JSONNode from './JSONNode';
|
||||
import createStylingFromTheme from './createStylingFromTheme';
|
||||
import { invertTheme } from 'react-base16-styling';
|
||||
import {
|
||||
Base16Theme,
|
||||
invertTheme,
|
||||
StylingConfig,
|
||||
StylingFunction,
|
||||
Theme
|
||||
} from 'react-base16-styling';
|
||||
import { CircularPropsPassedThroughJSONTree } from './types';
|
||||
|
||||
const identity = value => value;
|
||||
const expandRootNode = (keyName, data, level) => level === 0;
|
||||
const defaultItemString = (type, data, itemType, itemString) => (
|
||||
interface Props extends CircularPropsPassedThroughJSONTree {
|
||||
theme: Theme;
|
||||
invertTheme: boolean;
|
||||
data: any;
|
||||
}
|
||||
|
||||
interface State {
|
||||
styling: StylingFunction;
|
||||
}
|
||||
|
||||
const identity = (value: any) => value;
|
||||
const expandRootNode = (
|
||||
keyPath: (string | number)[],
|
||||
data: any,
|
||||
level: number
|
||||
) => level === 0;
|
||||
const defaultItemString = (
|
||||
type: string,
|
||||
data: any,
|
||||
itemType: React.ReactNode,
|
||||
itemString: string
|
||||
) => (
|
||||
<span>
|
||||
{itemType} {itemString}
|
||||
</span>
|
||||
);
|
||||
const defaultLabelRenderer = ([label]) => <span>{label}:</span>;
|
||||
const defaultLabelRenderer = ([label]: (string | number)[]) => (
|
||||
<span>{label}:</span>
|
||||
);
|
||||
const noCustomNode = () => false;
|
||||
|
||||
function checkLegacyTheming(theme, props) {
|
||||
function checkLegacyTheming(theme: Theme, props: Props) {
|
||||
const deprecatedStylingMethodsMap = {
|
||||
getArrowStyle: 'arrow',
|
||||
getListStyle: 'nestedNodeChildren',
|
||||
|
@ -30,7 +58,7 @@ function checkLegacyTheming(theme, props) {
|
|||
|
||||
const deprecatedStylingMethods = Object.keys(
|
||||
deprecatedStylingMethodsMap
|
||||
).filter(name => props[name]);
|
||||
).filter(name => props[name as keyof Props]);
|
||||
|
||||
if (deprecatedStylingMethods.length > 0) {
|
||||
if (typeof theme === 'string') {
|
||||
|
@ -47,10 +75,14 @@ function checkLegacyTheming(theme, props) {
|
|||
`Styling method "${name}" is deprecated, use "theme" property instead`
|
||||
);
|
||||
|
||||
theme[deprecatedStylingMethodsMap[name]] = ({ style }, ...args) => ({
|
||||
(theme as StylingConfig)[
|
||||
deprecatedStylingMethodsMap[
|
||||
name as keyof typeof deprecatedStylingMethodsMap
|
||||
]
|
||||
] = ({ style }, ...args) => ({
|
||||
style: {
|
||||
...style,
|
||||
...props[name](...args)
|
||||
...props[name as keyof Props](...args)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -59,19 +91,28 @@ function checkLegacyTheming(theme, props) {
|
|||
return theme;
|
||||
}
|
||||
|
||||
function getStateFromProps(props) {
|
||||
function isStylingConfig(
|
||||
themeOrStyling: Base16Theme | StylingConfig
|
||||
): themeOrStyling is StylingConfig {
|
||||
return (themeOrStyling as StylingConfig).extend !== undefined;
|
||||
}
|
||||
|
||||
function getStateFromProps(props: Props) {
|
||||
let theme = checkLegacyTheming(props.theme, props);
|
||||
if (props.invertTheme) {
|
||||
if (typeof theme === 'string') {
|
||||
theme = `${theme}:inverted`;
|
||||
} else if (theme && theme.extend) {
|
||||
if (typeof theme === 'string') {
|
||||
} else if (theme && isStylingConfig(theme) && theme.extend) {
|
||||
if (typeof theme.extend === 'string') {
|
||||
theme = { ...theme, extend: `${theme.extend}:inverted` };
|
||||
} else {
|
||||
theme = { ...theme, extend: invertTheme(theme.extend) };
|
||||
theme = {
|
||||
...theme,
|
||||
extend: invertTheme(theme.extend)
|
||||
} as StylingConfig;
|
||||
}
|
||||
} else if (theme) {
|
||||
theme = invertTheme(theme);
|
||||
theme = invertTheme(theme as Base16Theme);
|
||||
}
|
||||
}
|
||||
return {
|
||||
|
@ -79,7 +120,7 @@ function getStateFromProps(props) {
|
|||
};
|
||||
}
|
||||
|
||||
export default class JSONTree extends React.Component {
|
||||
export default class JSONTree extends React.Component<Props, State> {
|
||||
static propTypes = {
|
||||
data: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
|
||||
hideRoot: PropTypes.bool,
|
||||
|
@ -105,22 +146,26 @@ export default class JSONTree extends React.Component {
|
|||
invertTheme: true
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = getStateFromProps(props);
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
if (['theme', 'invertTheme'].find(k => nextProps[k] !== this.props[k])) {
|
||||
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
if (
|
||||
['theme', 'invertTheme'].find(
|
||||
k => nextProps[k as keyof Props] !== this.props[k as keyof Props]
|
||||
)
|
||||
) {
|
||||
this.setState(getStateFromProps(nextProps));
|
||||
}
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
return !!Object.keys(nextProps).find(k =>
|
||||
k === 'keyPath'
|
||||
? nextProps[k].join('/') !== this.props[k].join('/')
|
||||
: nextProps[k] !== this.props[k]
|
||||
: nextProps[k as keyof Props] !== this.props[k as keyof Props]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export default function objType(obj) {
|
||||
export default function objType(obj: any) {
|
||||
const type = Object.prototype.toString.call(obj).slice(8, -1);
|
||||
if (type === 'Object' && typeof obj[Symbol.iterator] === 'function') {
|
||||
return 'Iterable';
|
||||
|
|
52
packages/react-json-tree/src/react-base16-styling.d.ts
vendored
Normal file
52
packages/react-json-tree/src/react-base16-styling.d.ts
vendored
Normal file
|
@ -0,0 +1,52 @@
|
|||
declare module 'react-base16-styling' {
|
||||
import React from 'react';
|
||||
|
||||
export interface Styling {
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export interface Base16Theme {
|
||||
scheme?: string;
|
||||
author?: string;
|
||||
base00: string;
|
||||
base01: string;
|
||||
base02: string;
|
||||
base03: string;
|
||||
base04: string;
|
||||
base05: string;
|
||||
base06: string;
|
||||
base07: string;
|
||||
base08: string;
|
||||
base09: string;
|
||||
base0A: string;
|
||||
base0B: string;
|
||||
base0C: string;
|
||||
base0D: string;
|
||||
base0E: string;
|
||||
base0F: string;
|
||||
}
|
||||
|
||||
export type StylingValue =
|
||||
| string
|
||||
| React.CSSProperties
|
||||
| ((styling: Styling, ...rest: any[]) => Styling);
|
||||
|
||||
export type StylingConfig = { [name: string]: StylingValue } & {
|
||||
extend?: string | Base16Theme;
|
||||
};
|
||||
|
||||
export type Theme = string | Base16Theme | StylingConfig;
|
||||
|
||||
export type StylingFunction = (
|
||||
keys: string | Array<string | undefined | null>,
|
||||
...rest: any[]
|
||||
) => Styling;
|
||||
|
||||
export function invertTheme(base16Theme: Base16Theme): Base16Theme;
|
||||
|
||||
export function createStyling(
|
||||
getDefaultStyling: (base16Theme: Base16Theme) => StylingConfig,
|
||||
options?: { defaultBase16?: Theme; base16Themes?: Theme[] }
|
||||
): (theme: Theme, invertTheme?: boolean) => StylingFunction;
|
||||
}
|
74
packages/react-json-tree/src/types.ts
Normal file
74
packages/react-json-tree/src/types.ts
Normal file
|
@ -0,0 +1,74 @@
|
|||
import React from 'react';
|
||||
import { StylingFunction } from 'react-base16-styling';
|
||||
|
||||
interface SharedCircularPropsPassedThroughJSONTree {
|
||||
keyPath: (string | number)[];
|
||||
labelRenderer: (
|
||||
keyPath: (string | number)[],
|
||||
nodeType: string,
|
||||
expanded: boolean,
|
||||
expandable: boolean
|
||||
) => React.ReactNode;
|
||||
}
|
||||
interface SharedCircularPropsProvidedByJSONTree
|
||||
extends SharedCircularPropsPassedThroughJSONTree {
|
||||
styling: StylingFunction;
|
||||
}
|
||||
interface JSONValueNodeCircularPropsPassedThroughJSONTree {
|
||||
valueRenderer: (
|
||||
valueAsString: any,
|
||||
value: any,
|
||||
...keyPath: (string | number)[]
|
||||
) => React.ReactNode;
|
||||
}
|
||||
export type JSONValueNodeCircularPropsProvidedByJSONNode = SharedCircularPropsProvidedByJSONTree &
|
||||
JSONValueNodeCircularPropsPassedThroughJSONTree;
|
||||
|
||||
interface JSONNestedNodeCircularPropsPassedThroughJSONTree {
|
||||
shouldExpandNode: (
|
||||
keyPath: (string | number)[],
|
||||
data: any,
|
||||
level: number
|
||||
) => boolean;
|
||||
hideRoot: boolean;
|
||||
getItemString: (
|
||||
nodeType: string,
|
||||
data: any,
|
||||
itemType: React.ReactNode,
|
||||
itemString: string
|
||||
) => React.ReactNode;
|
||||
postprocessValue: (value: any) => any;
|
||||
isCustomNode: (value: any) => boolean;
|
||||
collectionLimit: number;
|
||||
sortObjectKeys?: (a: any, b: any) => number | boolean;
|
||||
}
|
||||
export type CircularPropsPassedThroughJSONTree = SharedCircularPropsPassedThroughJSONTree &
|
||||
JSONValueNodeCircularPropsPassedThroughJSONTree &
|
||||
JSONNestedNodeCircularPropsPassedThroughJSONTree;
|
||||
|
||||
interface JSONNestedNodeCircularPropsPassedThroughJSONNode
|
||||
extends JSONNestedNodeCircularPropsPassedThroughJSONTree {
|
||||
circularCache?: any[];
|
||||
isCircular?: boolean;
|
||||
level?: number;
|
||||
}
|
||||
export type CircularPropsPassedThroughJSONNode = SharedCircularPropsProvidedByJSONTree &
|
||||
JSONValueNodeCircularPropsPassedThroughJSONTree &
|
||||
JSONNestedNodeCircularPropsPassedThroughJSONNode;
|
||||
|
||||
export interface JSONNestedNodeCircularPropsPassedThroughJSONNestedNode
|
||||
extends JSONNestedNodeCircularPropsPassedThroughJSONNode {
|
||||
circularCache: any[];
|
||||
level: number;
|
||||
}
|
||||
export type CircularPropsPassedThroughJSONNestedNode = SharedCircularPropsProvidedByJSONTree &
|
||||
JSONValueNodeCircularPropsPassedThroughJSONTree &
|
||||
JSONNestedNodeCircularPropsPassedThroughJSONNestedNode;
|
||||
|
||||
export type CircularPropsPassedThroughRenderChildNodes = SharedCircularPropsProvidedByJSONTree &
|
||||
JSONValueNodeCircularPropsPassedThroughJSONTree &
|
||||
JSONNestedNodeCircularPropsPassedThroughJSONNestedNode;
|
||||
|
||||
export type CircularPropsPassedThroughItemRange = SharedCircularPropsProvidedByJSONTree &
|
||||
JSONValueNodeCircularPropsPassedThroughJSONTree &
|
||||
JSONNestedNodeCircularPropsPassedThroughJSONNestedNode;
|
|
@ -1,10 +0,0 @@
|
|||
export default function(hex) {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result
|
||||
? {
|
||||
r: parseInt(result[1], 16),
|
||||
g: parseInt(result[2], 16),
|
||||
b: parseInt(result[3], 16)
|
||||
}
|
||||
: null;
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "commonjs",
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"outDir": "lib",
|
||||
"strict": true,
|
||||
|
|
17
yarn.lock
17
yarn.lock
|
@ -2652,6 +2652,19 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
||||
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
|
||||
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
|
||||
|
||||
"@types/react@^15.0.0 || ^16.0.0":
|
||||
version "16.9.34"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.34.tgz#f7d5e331c468f53affed17a8a4d488cd44ea9349"
|
||||
integrity sha512-8AJlYMOfPe1KGLKyHpflCg5z46n0b5DbRfqDksxBLBTUpB75ypDBAO9eCUcjNwE6LCUslwTz00yyG/X9gaVtow==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
csstype "^2.2.0"
|
||||
|
||||
"@types/source-list-map@*":
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
|
||||
|
@ -5625,7 +5638,7 @@ cssstyle@^1.0.0:
|
|||
dependencies:
|
||||
cssom "0.3.x"
|
||||
|
||||
csstype@^2.5.7:
|
||||
csstype@^2.2.0, csstype@^2.5.7:
|
||||
version "2.6.10"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b"
|
||||
integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w==
|
||||
|
@ -13857,7 +13870,7 @@ react-treebeard@^3.1.0:
|
|||
shallowequal "^1.1.0"
|
||||
velocity-react "^1.4.1"
|
||||
|
||||
react@^16.0.0, react@^16.4.0, react@^16.4.2, react@^16.7.0:
|
||||
"react@^15.0.0 || ^16.0.0", react@^16.0.0, react@^16.4.0, react@^16.4.2, react@^16.7.0:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e"
|
||||
integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==
|
||||
|
|
Loading…
Reference in New Issue
Block a user