mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2025-02-18 12:30:50 +03:00
Merge branch 'main' into state-filter
This commit is contained in:
commit
e1cd49dcc8
|
@ -1,5 +1,19 @@
|
|||
# remotedev-redux-devtools-extension
|
||||
|
||||
## 3.0.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 450cde6e: Fix responsive layout
|
||||
|
||||
## 3.0.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [81926f32]
|
||||
- react-json-tree@0.18.0
|
||||
- @redux-devtools/app@2.2.1
|
||||
|
||||
## 3.0.17
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "3.0.17",
|
||||
"version": "3.0.19",
|
||||
"name": "Redux DevTools",
|
||||
"description": "Redux DevTools for debugging application's state changes.",
|
||||
"homepage_url": "https://github.com/reduxjs/redux-devtools",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "3.0.17",
|
||||
"version": "3.0.19",
|
||||
"name": "Redux DevTools",
|
||||
"description": "Redux DevTools for debugging application's state changes.",
|
||||
"homepage_url": "https://github.com/reduxjs/redux-devtools",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": "3.0.17",
|
||||
"version": "3.0.19",
|
||||
"name": "Redux DevTools",
|
||||
"manifest_version": 2,
|
||||
"description": "Redux Developer Tools for debugging application state changes.",
|
||||
|
|
|
@ -5,5 +5,7 @@ module.exports = {
|
|||
moduleNameMapper: {
|
||||
'\\.css$': '<rootDir>/test/__mocks__/styleMock.ts',
|
||||
},
|
||||
resolver: '<rootDir>/jestResolver.js',
|
||||
transformIgnorePatterns: [
|
||||
'node_modules/(?!.pnpm|d3|dateformat|delaunator|internmap|nanoid|robust-predicates|uuid)',
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
module.exports = (path, options) => {
|
||||
return options.defaultResolver(path, {
|
||||
...options,
|
||||
packageFilter: (pkg) => {
|
||||
if (pkg.name === 'nanoid') {
|
||||
pkg.exports['.'].browser = pkg.exports['.'].require;
|
||||
}
|
||||
if (pkg.name === 'uuid' && pkg.version.startsWith('8.')) {
|
||||
delete pkg.exports;
|
||||
delete pkg.module;
|
||||
}
|
||||
return pkg;
|
||||
},
|
||||
});
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"private": true,
|
||||
"name": "remotedev-redux-devtools-extension",
|
||||
"version": "3.0.17",
|
||||
"version": "3.0.19",
|
||||
"description": "Redux Developer Tools for debugging application state changes.",
|
||||
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/extension",
|
||||
"license": "MIT",
|
||||
|
@ -28,7 +28,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"@redux-devtools/app": "^2.2.0",
|
||||
"@redux-devtools/app": "^2.2.1",
|
||||
"@redux-devtools/core": "^3.13.0",
|
||||
"@redux-devtools/instrument": "^2.1.0",
|
||||
"@redux-devtools/serialize": "^0.4.1",
|
||||
|
@ -43,53 +43,53 @@
|
|||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^4.7.1",
|
||||
"react-is": "^18.2.0",
|
||||
"react-json-tree": "^0.17.0",
|
||||
"react-json-tree": "^0.18.0",
|
||||
"react-redux": "^8.0.5",
|
||||
"redux": "^4.2.0",
|
||||
"redux": "^4.2.1",
|
||||
"redux-persist": "^6.0.0",
|
||||
"styled-components": "^5.3.6"
|
||||
"styled-components": "^5.3.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/register": "^7.18.9",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@babel/register": "^7.21.0",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@types/chrome": "^0.0.206",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@types/chrome": "^0.0.218",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"babel-loader": "^9.1.0",
|
||||
"chromedriver": "^108.0.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"chromedriver": "^110.0.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"cpy-cli": "^4.2.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^6.7.3",
|
||||
"electron": "^22.0.0",
|
||||
"eslint": "^8.30.0",
|
||||
"electron": "^23.1.1",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.6.1",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"fork-ts-checker-webpack-plugin": "^7.2.14",
|
||||
"immutable": "^4.1.0",
|
||||
"jest": "^29.3.1",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"fork-ts-checker-webpack-plugin": "^8.0.0",
|
||||
"immutable": "^4.2.4",
|
||||
"jest": "^29.4.3",
|
||||
"jest-environment-jsdom": "^29.4.3",
|
||||
"pug-html-loader": "^1.1.5",
|
||||
"raw-loader": "^4.0.2",
|
||||
"react-transform-catch-errors": "^1.0.2",
|
||||
"react-transform-hmr": "^1.0.4",
|
||||
"rimraf": "^3.0.2",
|
||||
"selenium-webdriver": "^4.7.1",
|
||||
"rimraf": "^4.1.3",
|
||||
"selenium-webdriver": "^4.8.1",
|
||||
"sinon-chrome": "^3.0.1",
|
||||
"style-loader": "^3.3.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "~4.9.4",
|
||||
"ts-jest": "^29.0.5",
|
||||
"typescript": "~4.9.5",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1"
|
||||
}
|
||||
|
|
|
@ -591,12 +591,25 @@ const preEnhancer =
|
|||
} as any;
|
||||
};
|
||||
|
||||
export type InferComposedStoreExt<StoreEnhancers> = StoreEnhancers extends [
|
||||
infer HeadStoreEnhancer,
|
||||
...infer RestStoreEnhancers
|
||||
]
|
||||
? HeadStoreEnhancer extends StoreEnhancer<infer StoreExt>
|
||||
? StoreExt & InferComposedStoreExt<RestStoreEnhancers>
|
||||
: never
|
||||
: unknown;
|
||||
|
||||
const extensionCompose =
|
||||
(config: Config) =>
|
||||
(...funcs: StoreEnhancer[]): StoreEnhancer => {
|
||||
<StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
||||
...funcs: StoreEnhancers
|
||||
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>> => {
|
||||
// @ts-ignore FIXME
|
||||
return (...args) => {
|
||||
const instanceId = generateId(config.instanceId);
|
||||
return [preEnhancer(instanceId), ...funcs].reduceRight(
|
||||
// @ts-ignore FIXME
|
||||
(composed, f) => f(composed),
|
||||
__REDUX_DEVTOOLS_EXTENSION__({ ...config, instanceId })(...args)
|
||||
);
|
||||
|
@ -604,8 +617,12 @@ const extensionCompose =
|
|||
};
|
||||
|
||||
interface ReduxDevtoolsExtensionCompose {
|
||||
(config: Config): (...funcs: StoreEnhancer[]) => StoreEnhancer;
|
||||
(...funcs: StoreEnhancer[]): StoreEnhancer;
|
||||
(config: Config): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
||||
...funcs: StoreEnhancers
|
||||
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
<StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
||||
...funcs: StoreEnhancers
|
||||
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -616,18 +633,24 @@ declare global {
|
|||
|
||||
function reduxDevtoolsExtensionCompose(
|
||||
config: Config
|
||||
): (...funcs: StoreEnhancer[]) => StoreEnhancer;
|
||||
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
||||
...funcs: StoreEnhancers
|
||||
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
function reduxDevtoolsExtensionCompose<
|
||||
StoreEnhancers extends readonly StoreEnhancer<unknown>[]
|
||||
>(
|
||||
...funcs: StoreEnhancers
|
||||
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
function reduxDevtoolsExtensionCompose(
|
||||
...funcs: StoreEnhancer[]
|
||||
): StoreEnhancer;
|
||||
function reduxDevtoolsExtensionCompose(...funcs: [Config] | StoreEnhancer[]) {
|
||||
...funcs: [Config] | StoreEnhancer<unknown>[]
|
||||
) {
|
||||
if (funcs.length === 0) {
|
||||
return __REDUX_DEVTOOLS_EXTENSION__();
|
||||
}
|
||||
if (funcs.length === 1 && typeof funcs[0] === 'object') {
|
||||
return extensionCompose(funcs[0]);
|
||||
}
|
||||
return extensionCompose({})(...(funcs as StoreEnhancer[]));
|
||||
return extensionCompose({})(...(funcs as StoreEnhancer<unknown>[]));
|
||||
}
|
||||
|
||||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ = reduxDevtoolsExtensionCompose;
|
||||
|
|
|
@ -7,7 +7,7 @@ style.
|
|||
overflow: hidden;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
min-width: 760px;
|
||||
min-width: 350px;
|
||||
min-height: 400px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
@ -17,7 +17,6 @@ style.
|
|||
color: #fff;
|
||||
}
|
||||
#root {
|
||||
min-width: 760px;
|
||||
height: 100%;
|
||||
}
|
||||
#root > div {
|
||||
|
|
26
package.json
26
package.json
|
@ -1,21 +1,21 @@
|
|||
{
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@changesets/cli": "^2.26.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-jest": "^27.1.7",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"jest": "^29.3.1",
|
||||
"prettier": "2.8.1",
|
||||
"typescript": "~4.9.4",
|
||||
"nx": "^15.3.3",
|
||||
"@nrwl/nx-cloud": "^15.0.2"
|
||||
"jest": "^29.4.3",
|
||||
"prettier": "2.8.4",
|
||||
"typescript": "~4.9.5",
|
||||
"nx": "^15.8.1",
|
||||
"@nrwl/nx-cloud": "^15.1.1"
|
||||
},
|
||||
"scripts": {
|
||||
"format": "prettier --write .",
|
||||
|
@ -39,7 +39,7 @@
|
|||
"packages/redux-devtools-rtk-query-monitor/demo",
|
||||
"packages/redux-devtools-slider-monitor/examples/todomvc"
|
||||
],
|
||||
"packageManager": "pnpm@7.19.0",
|
||||
"packageManager": "pnpm@7.28.0",
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"@babel/highlight>chalk": "Methuselah96/chalk#v2-without-process"
|
||||
|
|
|
@ -1,5 +1,23 @@
|
|||
# Change Log
|
||||
|
||||
## 2.0.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- b323f77d: Upgrade D3
|
||||
|
||||
- Remove UMD build.
|
||||
- Split `style` option into `chartStyles`, `nodeStyleOptions`, `textStyleOptions`, and `linkStyles`.
|
||||
- The shape of the argument passed to the `onClickText` option has been updated.
|
||||
- Rename `InputOptions` to `Options`, `Primitive` to `StyleValue`, and `NodeWithId` to `HierarchyPointNode<Node>`.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b323f77d]
|
||||
- Updated dependencies [b323f77d]
|
||||
- d3tooltip@3.0.0
|
||||
- map2tree@3.0.0
|
||||
|
||||
## [1.4.0](https://github.com/reduxjs/redux-devtools/compare/d3-state-visualizer@1.3.4...d3-state-visualizer@1.4.0) (2021-03-06)
|
||||
|
||||
### Features
|
||||
|
|
|
@ -35,7 +35,7 @@ const render = tree(document.getElementById('root'), {
|
|||
isSorted: false,
|
||||
widthBetweenNodesCoeff: 1.5,
|
||||
heightBetweenNodesCoeff: 2,
|
||||
style: { border: '1px solid black' },
|
||||
chartStyles: { border: '1px solid black' },
|
||||
tooltipOptions: { offset: { left: 30, top: 10 }, indentationSize: 2 },
|
||||
});
|
||||
|
||||
|
@ -61,7 +61,7 @@ Other options are listed below and have reasonable default values if you want to
|
|||
| Option | Type | Default | Description |
|
||||
| ------------------------- | ------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `id` | String | `'d3svg'` | Sets the identifier of the SVG element —i.e your chart— that will be added to the DOM element you passed as first argument |
|
||||
| `style` | Object | `{}` | Sets the CSS style of the chart |
|
||||
| `chartStyles` | Object | `{}` | Sets the CSS style of the chart |
|
||||
| `size` | Number | `500` | Sets size of the chart in pixels |
|
||||
| `aspectRatio` | Float | `1.0` | Sets the chart height to `size * aspectRatio` and [viewBox](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox) in order to preserve the aspect ratio of the chart. [Great video](https://www.youtube.com/watch?v=FCOeMy7HrBc) if you want to learn more about how SVG works |
|
||||
| `widthBetweenNodesCoeff` | Float | `1.0` | Alters the horizontal space between each node |
|
||||
|
@ -74,12 +74,6 @@ Other options are listed below and have reasonable default values if you want to
|
|||
|
||||
More to come...
|
||||
|
||||
## Bindings
|
||||
|
||||
### React
|
||||
|
||||
[example](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3-state-visualizer/examples/react-tree) implementation.
|
||||
|
||||
## Roadmap
|
||||
|
||||
- Threshold for large arrays so only a single node is displayed instead of all the children. That single node would be exclude from searching until selected.
|
||||
|
|
10
packages/d3-state-visualizer/examples/tree/CHANGELOG.md
Normal file
10
packages/d3-state-visualizer/examples/tree/CHANGELOG.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# d3-state-visualizer-tree-example
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b323f77d]
|
||||
- Updated dependencies [b323f77d]
|
||||
- d3-state-visualizer@2.0.0
|
||||
- map2tree@3.0.0
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"private": true,
|
||||
"name": "d3-state-visualizer-tree-example",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.5",
|
||||
"description": "Visualize your app state as a tree",
|
||||
"keywords": [
|
||||
"d3",
|
||||
|
@ -25,24 +25,24 @@
|
|||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"d3-state-visualizer": "^1.6.0",
|
||||
"map2tree": "^2.1.0"
|
||||
"d3-state-visualizer": "^2.0.0",
|
||||
"map2tree": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@types/node": "^18.11.17",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"babel-loader": "^9.1.0",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@types/node": "^18.14.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"fork-ts-checker-webpack-plugin": "^7.2.14",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"fork-ts-checker-webpack-plugin": "^8.0.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "~4.9.4",
|
||||
"typescript": "~4.9.5",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.11.1"
|
||||
|
|
|
@ -28,7 +28,7 @@ const render = tree(document.getElementById('root')!, {
|
|||
isSorted: false,
|
||||
widthBetweenNodesCoeff: 1.5,
|
||||
heightBetweenNodesCoeff: 2,
|
||||
style: { border: '1px solid black' },
|
||||
chartStyles: { border: '1px solid black' },
|
||||
tooltipOptions: { offset: { left: 30, top: 10 }, indentationSize: 2 },
|
||||
});
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "d3-state-visualizer",
|
||||
"version": "1.6.0",
|
||||
"version": "2.0.0",
|
||||
"description": "Visualize your app state with a range of reusable charts",
|
||||
"keywords": [
|
||||
"d3",
|
||||
|
@ -23,18 +23,16 @@
|
|||
"main": "lib/cjs/index.js",
|
||||
"module": "lib/esm/index.js",
|
||||
"types": "lib/types/index.d.ts",
|
||||
"unpkg": "dist/d3-state-visualizer.umd.js",
|
||||
"sideEffects": false,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reduxjs/redux-devtools.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types && pnpm run build:umd",
|
||||
"build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types",
|
||||
"build:cjs": "babel src --extensions \".ts\" --out-dir lib/cjs",
|
||||
"build:esm": "babel src --config-file ./babel.config.esm.json --extensions \".ts\" --out-dir lib/esm",
|
||||
"build:types": "tsc --emitDeclarationOnly",
|
||||
"build:umd": "rollup -c",
|
||||
"clean": "rimraf lib",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"type-check": "tsc --noEmit",
|
||||
|
@ -42,35 +40,26 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@types/d3": "^3.5.47",
|
||||
"d3": "^3.5.17",
|
||||
"d3tooltip": "^2.1.0",
|
||||
"deepmerge": "^4.2.2",
|
||||
"map2tree": "^2.1.0",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@types/d3": "^7.4.0",
|
||||
"d3": "^7.8.2",
|
||||
"d3tooltip": "^3.0.0",
|
||||
"deepmerge": "^4.3.0",
|
||||
"map2tree": "^3.0.0",
|
||||
"ramda": "^0.28.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@rollup/plugin-babel": "^6.0.3",
|
||||
"@rollup/plugin-commonjs": "^24.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@rollup/plugin-terser": "^0.2.1",
|
||||
"@types/node": "^18.11.17",
|
||||
"@types/ramda": "^0.28.20",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^3.7.5",
|
||||
"rollup-plugin-typescript2": "^0.34.1",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "~4.9.4"
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@types/ramda": "^0.28.23",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"rimraf": "^4.1.3",
|
||||
"typescript": "~4.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
import typescript from 'rollup-plugin-typescript2';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import babel from '@rollup/plugin-babel';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
|
||||
const config = [
|
||||
{
|
||||
input: 'src/index.ts',
|
||||
output: {
|
||||
name: 'd3-state-visualizer',
|
||||
file: 'lib/umd/d3-state-visualizer.js',
|
||||
format: 'umd',
|
||||
},
|
||||
plugins: [
|
||||
typescript({
|
||||
tsconfigOverride: { compilerOptions: { declaration: false } },
|
||||
}),
|
||||
resolve(),
|
||||
commonjs(),
|
||||
babel({
|
||||
babelHelpers: 'runtime',
|
||||
extensions: ['.ts'],
|
||||
plugins: ['@babel/plugin-transform-runtime'],
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
input: 'src/index.ts',
|
||||
output: {
|
||||
name: 'd3-state-visualizer',
|
||||
file: 'lib/umd/d3-state-visualizer.min.js',
|
||||
format: 'umd',
|
||||
},
|
||||
plugins: [
|
||||
typescript({
|
||||
tsconfigOverride: { compilerOptions: { declaration: false } },
|
||||
}),
|
||||
resolve(),
|
||||
commonjs(),
|
||||
babel({
|
||||
babelHelpers: 'runtime',
|
||||
extensions: ['.ts'],
|
||||
plugins: ['@babel/plugin-transform-runtime'],
|
||||
}),
|
||||
terser(),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default config;
|
|
@ -1,2 +1,4 @@
|
|||
export type { HierarchyPointNode } from 'd3';
|
||||
export type { StyleValue } from 'd3tooltip';
|
||||
export { default as tree } from './tree/tree';
|
||||
export type { InputOptions, NodeWithId, Primitive } from './tree/tree';
|
||||
export type { Node, Options } from './tree/tree';
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import d3, { ZoomEvent, Primitive } from 'd3';
|
||||
import * as d3 from 'd3';
|
||||
import type { D3ZoomEvent, HierarchyPointLink, HierarchyPointNode } from 'd3';
|
||||
import { isEmpty } from 'ramda';
|
||||
import { map2tree } from 'map2tree';
|
||||
import type { Node } from 'map2tree';
|
||||
import deepmerge from 'deepmerge';
|
||||
import {
|
||||
getTooltipString,
|
||||
|
@ -9,17 +11,33 @@ import {
|
|||
getNodeGroupByDepthCount,
|
||||
} from './utils';
|
||||
import { tooltip } from 'd3tooltip';
|
||||
import type { StyleValue } from 'd3tooltip';
|
||||
|
||||
export interface InputOptions {
|
||||
export interface Options {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
state?: {} | null;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
tree?: NodeWithId | {};
|
||||
tree?: Node | {};
|
||||
|
||||
rootKeyName: string;
|
||||
pushMethod: 'push' | 'unshift';
|
||||
id: string;
|
||||
style: { [key: string]: Primitive };
|
||||
chartStyles: { [key: string]: StyleValue };
|
||||
nodeStyleOptions: {
|
||||
colors: {
|
||||
default: string;
|
||||
collapsed: string;
|
||||
parent: string;
|
||||
};
|
||||
radius: number;
|
||||
};
|
||||
textStyleOptions: {
|
||||
colors: {
|
||||
default: string;
|
||||
hover: string;
|
||||
};
|
||||
};
|
||||
linkStyles: { [key: string]: StyleValue };
|
||||
size: number;
|
||||
aspectRatio: number;
|
||||
initialZoom: number;
|
||||
|
@ -34,7 +52,7 @@ export interface InputOptions {
|
|||
widthBetweenNodesCoeff: number;
|
||||
transitionDuration: number;
|
||||
blinkDuration: number;
|
||||
onClickText: (datum: NodeWithId) => void;
|
||||
onClickText: (datum: HierarchyPointNode<Node>) => void;
|
||||
tooltipOptions: {
|
||||
disabled?: boolean;
|
||||
left?: number | undefined;
|
||||
|
@ -43,64 +61,7 @@ export interface InputOptions {
|
|||
left: number;
|
||||
top: number;
|
||||
};
|
||||
style?: { [key: string]: Primitive } | undefined;
|
||||
indentationSize?: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface Options {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
state?: {} | null;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
tree?: NodeWithId | {};
|
||||
|
||||
rootKeyName: string;
|
||||
pushMethod: 'push' | 'unshift';
|
||||
id: string;
|
||||
style: {
|
||||
node: {
|
||||
colors: {
|
||||
default: string;
|
||||
collapsed: string;
|
||||
parent: string;
|
||||
};
|
||||
radius: number;
|
||||
};
|
||||
text: {
|
||||
colors: {
|
||||
default: string;
|
||||
hover: string;
|
||||
};
|
||||
};
|
||||
link: {
|
||||
stroke: string;
|
||||
fill: string;
|
||||
};
|
||||
};
|
||||
size: number;
|
||||
aspectRatio: number;
|
||||
initialZoom: number;
|
||||
margin: {
|
||||
top: number;
|
||||
right: number;
|
||||
bottom: number;
|
||||
left: number;
|
||||
};
|
||||
isSorted: boolean;
|
||||
heightBetweenNodesCoeff: number;
|
||||
widthBetweenNodesCoeff: number;
|
||||
transitionDuration: number;
|
||||
blinkDuration: number;
|
||||
onClickText: () => void;
|
||||
tooltipOptions: {
|
||||
disabled: boolean;
|
||||
left: number | undefined;
|
||||
top: number | undefined;
|
||||
offset: {
|
||||
left: number;
|
||||
top: number;
|
||||
};
|
||||
style: { [key: string]: Primitive } | undefined;
|
||||
styles?: { [key: string]: StyleValue } | undefined;
|
||||
indentationSize?: number;
|
||||
};
|
||||
}
|
||||
|
@ -111,26 +72,25 @@ const defaultOptions: Options = {
|
|||
pushMethod: 'push',
|
||||
tree: undefined,
|
||||
id: 'd3svg',
|
||||
style: {
|
||||
node: {
|
||||
colors: {
|
||||
default: '#ccc',
|
||||
collapsed: 'lightsteelblue',
|
||||
parent: 'white',
|
||||
},
|
||||
radius: 7,
|
||||
chartStyles: {},
|
||||
nodeStyleOptions: {
|
||||
colors: {
|
||||
default: '#ccc',
|
||||
collapsed: 'lightsteelblue',
|
||||
parent: 'white',
|
||||
},
|
||||
text: {
|
||||
colors: {
|
||||
default: 'black',
|
||||
hover: 'skyblue',
|
||||
},
|
||||
},
|
||||
link: {
|
||||
stroke: '#000',
|
||||
fill: 'none',
|
||||
radius: 7,
|
||||
},
|
||||
textStyleOptions: {
|
||||
colors: {
|
||||
default: 'black',
|
||||
hover: 'skyblue',
|
||||
},
|
||||
},
|
||||
linkStyles: {
|
||||
stroke: '#000',
|
||||
fill: 'none',
|
||||
},
|
||||
size: 500,
|
||||
aspectRatio: 1.0,
|
||||
initialZoom: 1,
|
||||
|
@ -156,37 +116,29 @@ const defaultOptions: Options = {
|
|||
left: 0,
|
||||
top: 0,
|
||||
},
|
||||
style: undefined,
|
||||
styles: undefined,
|
||||
},
|
||||
};
|
||||
} satisfies Options;
|
||||
|
||||
export interface NodeWithId {
|
||||
name: string;
|
||||
children?: NodeWithId[] | null;
|
||||
_children?: NodeWithId[] | null;
|
||||
value?: unknown;
|
||||
id: string;
|
||||
|
||||
parent?: NodeWithId;
|
||||
depth?: number;
|
||||
x?: number;
|
||||
y?: number;
|
||||
export interface InternalNode extends Node {
|
||||
_children?: this[] | undefined;
|
||||
id: string | number;
|
||||
}
|
||||
|
||||
interface NodePosition {
|
||||
parentId: string | null | undefined;
|
||||
id: string;
|
||||
x: number | undefined;
|
||||
y: number | undefined;
|
||||
parentId: string | number | null;
|
||||
id: string | number;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export default function (
|
||||
DOMNode: HTMLElement,
|
||||
options: Partial<InputOptions> = {}
|
||||
) {
|
||||
export default function (DOMNode: HTMLElement, options: Partial<Options> = {}) {
|
||||
const {
|
||||
id,
|
||||
style,
|
||||
chartStyles,
|
||||
nodeStyleOptions,
|
||||
textStyleOptions,
|
||||
linkStyles,
|
||||
size,
|
||||
aspectRatio,
|
||||
initialZoom,
|
||||
|
@ -202,64 +154,50 @@ export default function (
|
|||
tree,
|
||||
tooltipOptions,
|
||||
onClickText,
|
||||
} = deepmerge(defaultOptions, options) as Options;
|
||||
} = deepmerge(defaultOptions, options);
|
||||
|
||||
const width = size - margin.left - margin.right;
|
||||
const height = size * aspectRatio - margin.top - margin.bottom;
|
||||
const fullWidth = size;
|
||||
const fullHeight = size * aspectRatio;
|
||||
|
||||
const attr: { [key: string]: Primitive } = {
|
||||
id,
|
||||
preserveAspectRatio: 'xMinYMin slice',
|
||||
};
|
||||
|
||||
if (!(style as unknown as { [key: string]: Primitive }).width) {
|
||||
attr.width = fullWidth;
|
||||
}
|
||||
|
||||
if (
|
||||
!(style as unknown as { [key: string]: Primitive }).width ||
|
||||
!(style as unknown as { [key: string]: Primitive }).height
|
||||
) {
|
||||
attr.viewBox = `0 0 ${fullWidth} ${fullHeight}`;
|
||||
}
|
||||
|
||||
const root = d3.select(DOMNode);
|
||||
const zoom = d3.behavior.zoom().scaleExtent([0.1, 3]).scale(initialZoom);
|
||||
const vis = root
|
||||
const zoom = d3.zoom<SVGSVGElement, unknown>().scaleExtent([0.1, 3]);
|
||||
|
||||
const svgElement = root
|
||||
.append('svg')
|
||||
.attr(attr)
|
||||
.style({ cursor: '-webkit-grab', ...style } as unknown as {
|
||||
[key: string]: Primitive;
|
||||
})
|
||||
.attr('id', id)
|
||||
.attr('preserveAspectRatio', 'xMinYMin slice')
|
||||
.style('cursor', '-webkit-grab');
|
||||
|
||||
if (!chartStyles.width) {
|
||||
svgElement.attr('width', fullWidth);
|
||||
}
|
||||
|
||||
if (!chartStyles.width || !chartStyles.height) {
|
||||
svgElement.attr('viewBox', `0 0 ${fullWidth} ${fullHeight}`);
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(chartStyles)) {
|
||||
svgElement.style(key, value);
|
||||
}
|
||||
|
||||
const vis = svgElement
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
.call(zoom.scaleTo, initialZoom)
|
||||
.call(
|
||||
zoom.on('zoom', () => {
|
||||
const { translate, scale } = d3.event as ZoomEvent;
|
||||
vis.attr(
|
||||
'transform',
|
||||
`translate(${translate.toString()})scale(${scale})`
|
||||
);
|
||||
zoom.on('zoom', (event) => {
|
||||
const { transform } = event as D3ZoomEvent<SVGSVGElement, unknown>;
|
||||
vis.attr('transform', transform.toString());
|
||||
})
|
||||
)
|
||||
.append('g')
|
||||
.attr({
|
||||
transform: `translate(${margin.left + style.node.radius}, ${
|
||||
.attr(
|
||||
'transform',
|
||||
`translate(${margin.left + nodeStyleOptions.radius}, ${
|
||||
margin.top
|
||||
}) scale(${initialZoom})`,
|
||||
});
|
||||
|
||||
let layout = d3.layout.tree().size([width, height]);
|
||||
let data: NodeWithId;
|
||||
|
||||
if (isSorted) {
|
||||
layout.sort((a, b) =>
|
||||
(b as NodeWithId).name.toLowerCase() <
|
||||
(a as NodeWithId).name.toLowerCase()
|
||||
? 1
|
||||
: -1
|
||||
}) scale(${initialZoom})`
|
||||
);
|
||||
}
|
||||
|
||||
// previousNodePositionsById stores node x and y
|
||||
// as well as hierarchy (id / parentId);
|
||||
|
@ -277,8 +215,8 @@ export default function (
|
|||
// of parent ids; once a parent that matches the given filter is found,
|
||||
// the parent position gets returned
|
||||
function findParentNodePosition(
|
||||
nodePositionsById: { [nodeId: string]: NodePosition },
|
||||
nodeId: string,
|
||||
nodePositionsById: { [nodeId: string | number]: NodePosition },
|
||||
nodeId: string | number,
|
||||
filter: (nodePosition: NodePosition) => boolean
|
||||
) {
|
||||
let currentPosition = nodePositionsById[nodeId];
|
||||
|
@ -294,19 +232,18 @@ export default function (
|
|||
}
|
||||
|
||||
return function renderChart(nextState = tree || state) {
|
||||
data = !tree
|
||||
? // eslint-disable-next-line @typescript-eslint/ban-types
|
||||
(map2tree(nextState as {}, {
|
||||
let data = !tree
|
||||
? (map2tree(nextState, {
|
||||
key: rootKeyName,
|
||||
pushMethod,
|
||||
}) as NodeWithId)
|
||||
: (nextState as NodeWithId);
|
||||
}) as InternalNode)
|
||||
: (nextState as InternalNode);
|
||||
|
||||
if (isEmpty(data) || !data.name) {
|
||||
data = {
|
||||
name: 'error',
|
||||
message: 'Please provide a state map or a tree structure',
|
||||
} as unknown as NodeWithId;
|
||||
} as unknown as InternalNode;
|
||||
}
|
||||
|
||||
let nodeIndex = 0;
|
||||
|
@ -334,76 +271,94 @@ export default function (
|
|||
|
||||
function update() {
|
||||
// path generator for links
|
||||
const diagonal = d3.svg
|
||||
.diagonal<NodePosition>()
|
||||
.projection((d) => [d.y!, d.x!]);
|
||||
const linkHorizontal = d3
|
||||
.linkHorizontal<
|
||||
{
|
||||
source: { x: number; y: number };
|
||||
target: { x: number; y: number };
|
||||
},
|
||||
{ x: number; y: number }
|
||||
>()
|
||||
.x((d) => d.y)
|
||||
.y((d) => d.x);
|
||||
// set tree dimensions and spacing between branches and nodes
|
||||
const maxNodeCountByLevel = Math.max(...getNodeGroupByDepthCount(data));
|
||||
|
||||
layout = layout.size([
|
||||
maxNodeCountByLevel * 25 * heightBetweenNodesCoeff,
|
||||
width,
|
||||
]);
|
||||
const layout = d3
|
||||
.tree<InternalNode>()
|
||||
.size([maxNodeCountByLevel * 25 * heightBetweenNodesCoeff, width]);
|
||||
|
||||
const nodes = layout.nodes(data as d3.layout.tree.Node) as NodeWithId[];
|
||||
const links = layout.links(nodes as d3.layout.tree.Node[]);
|
||||
const rootNode = d3.hierarchy(data);
|
||||
if (isSorted) {
|
||||
rootNode.sort((a, b) =>
|
||||
b.data.name.toLowerCase() < a.data.name.toLowerCase() ? 1 : -1
|
||||
);
|
||||
}
|
||||
|
||||
nodes.forEach(
|
||||
const rootPointNode = layout(rootNode);
|
||||
const links = rootPointNode.links();
|
||||
|
||||
rootPointNode.each(
|
||||
(node) =>
|
||||
(node.y = node.depth! * (maxLabelLength * 7 * widthBetweenNodesCoeff))
|
||||
(node.y = node.depth * (maxLabelLength * 7 * widthBetweenNodesCoeff))
|
||||
);
|
||||
|
||||
const nodes = rootPointNode.descendants();
|
||||
|
||||
const nodePositions = nodes.map((n) => ({
|
||||
parentId: n.parent && n.parent.id,
|
||||
id: n.id,
|
||||
parentId: n.parent && n.parent.data.id,
|
||||
id: n.data.id,
|
||||
x: n.x,
|
||||
y: n.y,
|
||||
}));
|
||||
const nodePositionsById: { [nodeId: string]: NodePosition } = {};
|
||||
const nodePositionsById: { [nodeId: string | number]: NodePosition } = {};
|
||||
nodePositions.forEach((node) => (nodePositionsById[node.id] = node));
|
||||
|
||||
// process the node selection
|
||||
const node = vis
|
||||
.selectAll('g.node')
|
||||
.property('__oldData__', (d: NodeWithId) => d)
|
||||
.data(nodes, (d) => d.id || (d.id = ++nodeIndex as unknown as string));
|
||||
.selectAll<SVGGElement, HierarchyPointNode<InternalNode>>('g.node')
|
||||
.property('__oldData__', (d) => d)
|
||||
.data(nodes, (d) => d.data.id || (d.data.id = ++nodeIndex));
|
||||
const nodeEnter = node
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr({
|
||||
class: 'node',
|
||||
transform: (d) => {
|
||||
const position = findParentNodePosition(
|
||||
nodePositionsById,
|
||||
d.id,
|
||||
(n) => !!previousNodePositionsById[n.id]
|
||||
);
|
||||
const previousPosition =
|
||||
(position && previousNodePositionsById[position.id]) ||
|
||||
previousNodePositionsById.root;
|
||||
return `translate(${previousPosition.y!},${previousPosition.x!})`;
|
||||
},
|
||||
.attr('class', 'node')
|
||||
.attr('transform', (d) => {
|
||||
const position = findParentNodePosition(
|
||||
nodePositionsById,
|
||||
d.data.id,
|
||||
(n) => !!previousNodePositionsById[n.id]
|
||||
);
|
||||
const previousPosition =
|
||||
(position && previousNodePositionsById[position.id]) ||
|
||||
previousNodePositionsById.root;
|
||||
return `translate(${previousPosition.y},${previousPosition.x})`;
|
||||
})
|
||||
.style({
|
||||
fill: style.text.colors.default,
|
||||
cursor: 'pointer',
|
||||
.style('fill', textStyleOptions.colors.default)
|
||||
.style('cursor', 'pointer')
|
||||
.on('mouseover', function mouseover() {
|
||||
d3.select(this).style('fill', textStyleOptions.colors.hover);
|
||||
})
|
||||
.on('mouseover', function mouseover(this: EventTarget) {
|
||||
d3.select(this).style({
|
||||
fill: style.text.colors.hover,
|
||||
});
|
||||
})
|
||||
.on('mouseout', function mouseout(this: EventTarget) {
|
||||
d3.select(this).style({
|
||||
fill: style.text.colors.default,
|
||||
});
|
||||
.on('mouseout', function mouseout() {
|
||||
d3.select(this).style('fill', textStyleOptions.colors.default);
|
||||
});
|
||||
|
||||
if (!tooltipOptions.disabled) {
|
||||
nodeEnter.call(
|
||||
tooltip<NodeWithId>(d3, 'tooltip', { ...tooltipOptions, root })
|
||||
.text((d, i) => getTooltipString(d, i, tooltipOptions))
|
||||
.style(tooltipOptions.style)
|
||||
tooltip<
|
||||
SVGGElement,
|
||||
HierarchyPointNode<InternalNode>,
|
||||
SVGGElement,
|
||||
unknown,
|
||||
HTMLElement,
|
||||
unknown,
|
||||
null,
|
||||
undefined
|
||||
>('tooltip', {
|
||||
...tooltipOptions,
|
||||
root,
|
||||
text: (d) => getTooltipString(d.data, tooltipOptions),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -412,77 +367,81 @@ export default function (
|
|||
const nodeEnterInnerGroup = nodeEnter.append('g');
|
||||
nodeEnterInnerGroup
|
||||
.append('circle')
|
||||
.attr({
|
||||
class: 'nodeCircle',
|
||||
r: 0,
|
||||
})
|
||||
.on('click', (clickedNode) => {
|
||||
if ((d3.event as Event).defaultPrevented) return;
|
||||
toggleChildren(clickedNode);
|
||||
.attr('class', 'nodeCircle')
|
||||
.attr('r', 0)
|
||||
.on('click', (event, clickedNode) => {
|
||||
if ((event as Event).defaultPrevented) return;
|
||||
toggleChildren(clickedNode.data);
|
||||
update();
|
||||
});
|
||||
|
||||
nodeEnterInnerGroup
|
||||
.append('text')
|
||||
.attr({
|
||||
class: 'nodeText',
|
||||
'text-anchor': 'middle',
|
||||
transform: 'translate(0,0)',
|
||||
dy: '.35em',
|
||||
})
|
||||
.style({
|
||||
'fill-opacity': 0,
|
||||
})
|
||||
.text((d) => d.name)
|
||||
.on('click', onClickText);
|
||||
|
||||
// update the text to reflect whether node has children or not
|
||||
node.select('text').text((d) => d.name);
|
||||
|
||||
// change the circle fill depending on whether it has children and is collapsed
|
||||
node.select('circle').style({
|
||||
stroke: 'black',
|
||||
'stroke-width': '1.5px',
|
||||
fill: (d) =>
|
||||
d._children
|
||||
? style.node.colors.collapsed
|
||||
: d.children
|
||||
? style.node.colors.parent
|
||||
: style.node.colors.default,
|
||||
});
|
||||
|
||||
// transition nodes to their new position
|
||||
const nodeUpdate = node
|
||||
.transition()
|
||||
.duration(transitionDuration)
|
||||
.attr({
|
||||
transform: (d) => `translate(${d.y!},${d.x!})`,
|
||||
.attr('class', 'nodeText')
|
||||
.attr('text-anchor', 'middle')
|
||||
.attr('transform', 'translate(0,0)')
|
||||
.attr('dy', '.35em')
|
||||
.style('fill-opacity', 0)
|
||||
.text((d) => d.data.name)
|
||||
.on('click', (_, datum) => {
|
||||
onClickText(datum as unknown as HierarchyPointNode<Node>);
|
||||
});
|
||||
|
||||
const nodeEnterAndUpdate = nodeEnter.merge(node);
|
||||
|
||||
// update the text to reflect whether node has children or not
|
||||
nodeEnterAndUpdate.select('text').text((d) => d.data.name);
|
||||
|
||||
// change the circle fill depending on whether it has children and is collapsed
|
||||
nodeEnterAndUpdate
|
||||
.select('circle')
|
||||
.style('stroke', 'black')
|
||||
.style('stroke-width', '1.5px')
|
||||
.style('fill', (d) =>
|
||||
d.data._children && d.data._children.length > 0
|
||||
? nodeStyleOptions.colors.collapsed
|
||||
: d.data.children && d.data.children.length > 0
|
||||
? nodeStyleOptions.colors.parent
|
||||
: nodeStyleOptions.colors.default
|
||||
);
|
||||
|
||||
// transition nodes to their new position
|
||||
const nodeUpdate = nodeEnterAndUpdate
|
||||
.transition()
|
||||
.duration(transitionDuration)
|
||||
.attr('transform', (d) => `translate(${d.y},${d.x})`);
|
||||
|
||||
// ensure circle radius is correct
|
||||
nodeUpdate.select('circle').attr('r', style.node.radius);
|
||||
nodeUpdate.select('circle').attr('r', nodeStyleOptions.radius);
|
||||
|
||||
// fade the text in and align it
|
||||
nodeUpdate
|
||||
.select('text')
|
||||
.select<SVGTextElement>('text')
|
||||
.style('fill-opacity', 1)
|
||||
.attr({
|
||||
transform: function transform(this: SVGGraphicsElement, d) {
|
||||
const x =
|
||||
(d.children || d._children ? -1 : 1) *
|
||||
(this.getBBox().width / 2 + style.node.radius + 5);
|
||||
return `translate(${x},0)`;
|
||||
},
|
||||
.attr('transform', function transform(d) {
|
||||
const x =
|
||||
(((d.data.children ?? d.data._children)?.length ?? 0) > 0
|
||||
? -1
|
||||
: 1) *
|
||||
(this.getBBox().width / 2 + nodeStyleOptions.radius + 5);
|
||||
return `translate(${x},0)`;
|
||||
});
|
||||
|
||||
// blink updated nodes
|
||||
node
|
||||
.filter(function flick(this: any, d) {
|
||||
nodeEnterAndUpdate
|
||||
.filter(function flick(
|
||||
this: SVGGElement & {
|
||||
__oldData__?: HierarchyPointNode<InternalNode>;
|
||||
},
|
||||
d
|
||||
) {
|
||||
// test whether the relevant properties of d match
|
||||
// the equivalent property of the oldData
|
||||
// also test whether the old data exists,
|
||||
// to catch the entering elements!
|
||||
return this.__oldData__ && d.value !== this.__oldData__.value;
|
||||
return (
|
||||
!!this.__oldData__ && d.data.value !== this.__oldData__.data.value
|
||||
);
|
||||
})
|
||||
.select('g')
|
||||
.style('opacity', '0.3')
|
||||
|
@ -492,21 +451,19 @@ export default function (
|
|||
|
||||
// transition exiting nodes to the parent's new position
|
||||
const nodeExit = node
|
||||
.exit()
|
||||
.exit<HierarchyPointNode<InternalNode>>()
|
||||
.transition()
|
||||
.duration(transitionDuration)
|
||||
.attr({
|
||||
transform: (d) => {
|
||||
const position = findParentNodePosition(
|
||||
previousNodePositionsById,
|
||||
d.id,
|
||||
(n) => !!nodePositionsById[n.id]
|
||||
);
|
||||
const futurePosition =
|
||||
(position && nodePositionsById[position.id]) ||
|
||||
nodePositionsById.root;
|
||||
return `translate(${futurePosition.y!},${futurePosition.x!})`;
|
||||
},
|
||||
.attr('transform', (d) => {
|
||||
const position = findParentNodePosition(
|
||||
previousNodePositionsById,
|
||||
d.data.id,
|
||||
(n) => !!nodePositionsById[n.id]
|
||||
);
|
||||
const futurePosition =
|
||||
(position && nodePositionsById[position.id]) ||
|
||||
nodePositionsById.root;
|
||||
return `translate(${futurePosition.y},${futurePosition.x})`;
|
||||
})
|
||||
.remove();
|
||||
|
||||
|
@ -516,65 +473,66 @@ export default function (
|
|||
|
||||
// update the links
|
||||
const link = vis
|
||||
.selectAll('path.link')
|
||||
.data(links, (d) => (d.target as NodeWithId).id);
|
||||
.selectAll<SVGPathElement, HierarchyPointLink<InternalNode>>(
|
||||
'path.link'
|
||||
)
|
||||
.data(links, (d) => d.target.data.id);
|
||||
|
||||
// enter any new links at the parent's previous position
|
||||
link
|
||||
const linkEnter = link
|
||||
.enter()
|
||||
.insert('path', 'g')
|
||||
.attr({
|
||||
class: 'link',
|
||||
d: (d) => {
|
||||
const position = findParentNodePosition(
|
||||
nodePositionsById,
|
||||
(d.target as NodeWithId).id,
|
||||
(n) => !!previousNodePositionsById[n.id]
|
||||
);
|
||||
const previousPosition =
|
||||
(position && previousNodePositionsById[position.id]) ||
|
||||
previousNodePositionsById.root;
|
||||
return diagonal({
|
||||
source: previousPosition,
|
||||
target: previousPosition,
|
||||
} as d3.svg.diagonal.Link<NodePosition>);
|
||||
},
|
||||
})
|
||||
.style(style.link);
|
||||
.attr('class', 'link')
|
||||
.attr('d', (d) => {
|
||||
const position = findParentNodePosition(
|
||||
nodePositionsById,
|
||||
d.target.data.id,
|
||||
(n) => !!previousNodePositionsById[n.id]
|
||||
);
|
||||
const previousPosition =
|
||||
(position && previousNodePositionsById[position.id]) ||
|
||||
previousNodePositionsById.root;
|
||||
return linkHorizontal({
|
||||
source: previousPosition,
|
||||
target: previousPosition,
|
||||
});
|
||||
});
|
||||
|
||||
for (const [key, value] of Object.entries(linkStyles)) {
|
||||
linkEnter.style(key, value);
|
||||
}
|
||||
|
||||
const linkEnterAndUpdate = linkEnter.merge(link);
|
||||
|
||||
// transition links to their new position
|
||||
link
|
||||
linkEnterAndUpdate
|
||||
.transition()
|
||||
.duration(transitionDuration)
|
||||
.attr({
|
||||
d: diagonal as unknown as Primitive,
|
||||
});
|
||||
.attr('d', linkHorizontal);
|
||||
|
||||
// transition exiting nodes to the parent's new position
|
||||
link
|
||||
.exit()
|
||||
.exit<HierarchyPointLink<InternalNode>>()
|
||||
.transition()
|
||||
.duration(transitionDuration)
|
||||
.attr({
|
||||
d: (d) => {
|
||||
const position = findParentNodePosition(
|
||||
previousNodePositionsById,
|
||||
(d.target as NodeWithId).id,
|
||||
(n) => !!nodePositionsById[n.id]
|
||||
);
|
||||
const futurePosition =
|
||||
(position && nodePositionsById[position.id]) ||
|
||||
nodePositionsById.root;
|
||||
return diagonal({
|
||||
source: futurePosition,
|
||||
target: futurePosition,
|
||||
});
|
||||
},
|
||||
.attr('d', (d) => {
|
||||
const position = findParentNodePosition(
|
||||
previousNodePositionsById,
|
||||
d.target.data.id,
|
||||
(n) => !!nodePositionsById[n.id]
|
||||
);
|
||||
const futurePosition =
|
||||
(position && nodePositionsById[position.id]) ||
|
||||
nodePositionsById.root;
|
||||
return linkHorizontal({
|
||||
source: futurePosition,
|
||||
target: futurePosition,
|
||||
});
|
||||
})
|
||||
.remove();
|
||||
|
||||
// delete the old data once it's no longer needed
|
||||
node.property('__oldData__', null);
|
||||
nodeEnterAndUpdate.property('__oldData__', null);
|
||||
|
||||
// stash the old positions for transition
|
||||
previousNodePositionsById = nodePositionsById;
|
||||
|
@ -582,4 +540,4 @@ export default function (
|
|||
};
|
||||
}
|
||||
|
||||
export { Primitive };
|
||||
export type { Node };
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
import { is, join, pipe, replace } from 'ramda';
|
||||
import sortAndSerialize from './sortAndSerialize';
|
||||
import { NodeWithId } from './tree';
|
||||
import type { InternalNode } from './tree';
|
||||
|
||||
export function collapseChildren(node: NodeWithId) {
|
||||
export function collapseChildren(node: InternalNode) {
|
||||
if (node.children) {
|
||||
node._children = node.children;
|
||||
node._children.forEach(collapseChildren);
|
||||
node.children = null;
|
||||
node.children = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function expandChildren(node: NodeWithId) {
|
||||
export function expandChildren(node: InternalNode) {
|
||||
if (node._children) {
|
||||
node.children = node._children;
|
||||
node.children.forEach(expandChildren);
|
||||
node._children = null;
|
||||
node._children = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function toggleChildren(node: NodeWithId) {
|
||||
export function toggleChildren(node: InternalNode) {
|
||||
if (node.children) {
|
||||
node._children = node.children;
|
||||
node.children = null;
|
||||
node.children = undefined;
|
||||
} else if (node._children) {
|
||||
node.children = node._children;
|
||||
node._children = null;
|
||||
node._children = undefined;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
export function visit(
|
||||
parent: NodeWithId,
|
||||
visitFn: (parent: NodeWithId) => void,
|
||||
childrenFn: (parent: NodeWithId) => NodeWithId[] | null | undefined
|
||||
parent: InternalNode,
|
||||
visitFn: (parent: InternalNode) => void,
|
||||
childrenFn: (parent: InternalNode) => InternalNode[] | null | undefined
|
||||
) {
|
||||
if (!parent) {
|
||||
return;
|
||||
|
@ -50,10 +50,10 @@ export function visit(
|
|||
}
|
||||
}
|
||||
|
||||
export function getNodeGroupByDepthCount(rootNode: NodeWithId) {
|
||||
export function getNodeGroupByDepthCount(rootNode: InternalNode) {
|
||||
const nodeGroupByDepthCount = [1];
|
||||
|
||||
const traverseFrom = function traverseFrom(node: NodeWithId, depth = 0) {
|
||||
const traverseFrom = function traverseFrom(node: InternalNode, depth = 0) {
|
||||
if (!node.children || node.children.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -73,11 +73,7 @@ export function getNodeGroupByDepthCount(rootNode: NodeWithId) {
|
|||
return nodeGroupByDepthCount;
|
||||
}
|
||||
|
||||
export function getTooltipString(
|
||||
node: unknown,
|
||||
i: number | undefined,
|
||||
{ indentationSize = 4 }
|
||||
) {
|
||||
export function getTooltipString(node: InternalNode, { indentationSize = 4 }) {
|
||||
if (!is(Object, node)) return '';
|
||||
|
||||
const spacer = join(' ');
|
||||
|
@ -89,7 +85,6 @@ export function getTooltipString(
|
|||
|
||||
if (typeof node.value !== 'undefined') return json2html(node.value);
|
||||
if (typeof node.object !== 'undefined') return json2html(node.object);
|
||||
if (children && children.length)
|
||||
return `childrenCount: ${(children as unknown[]).length}`;
|
||||
if (children && children.length) return `childrenCount: ${children.length}`;
|
||||
return 'empty';
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
export { tree } from './charts';
|
||||
export type { InputOptions, NodeWithId, Primitive } from './charts';
|
||||
export type { HierarchyPointNode, Node, Options, StyleValue } from './charts';
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
# Change Log
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- b323f77d: Upgrade D3
|
||||
|
||||
- Remove UMD build.
|
||||
- Upgrade d3 peer dependency from v3 to v7.
|
||||
- Remove `attr` configuration method.
|
||||
- Rename `style` configuration method to `styles` and move to options.
|
||||
- Move `text` configuration method to options.
|
||||
- Remove d3 parameter as first parameter for `tooltip`.
|
||||
|
||||
## 2.0.0
|
||||
|
||||
- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):
|
||||
|
|
|
@ -10,45 +10,45 @@ It was created by [@romseguy](https://github.com/romseguy) and merged from [`rom
|
|||
## Quick usage
|
||||
|
||||
```javascript
|
||||
import d3 from 'd3';
|
||||
import * as d3 from 'd3';
|
||||
import { tooltip } from 'd3tooltip';
|
||||
|
||||
const DOMNode = document.getElementById('chart');
|
||||
const root = d3.select(DOMNode);
|
||||
const vis = root.append('svg');
|
||||
|
||||
let options = {
|
||||
offset: {left: 30, top: 10}
|
||||
const options = {
|
||||
offset: { left: 30, top: 10 },
|
||||
styles: { 'min-width': '50px', 'border-radius': '5px' },
|
||||
};
|
||||
|
||||
vis.selectAll('circle').data(someData).enter()
|
||||
vis
|
||||
.selectAll('circle')
|
||||
.data(someData)
|
||||
.enter()
|
||||
.append('circle')
|
||||
.attr('r', 10)
|
||||
.call(
|
||||
d3tooltip(d3, 'tooltipClassName', options)
|
||||
.text((d, i) => toStringOrHtml(d))
|
||||
.attr({ 'class': 'anotherClassName' })
|
||||
.style({ 'min-width': '50px', 'border-radius: 5px' })
|
||||
d3tooltip('tooltipClassName', {
|
||||
...options,
|
||||
text: (d) => toStringOrHtml(d),
|
||||
})
|
||||
)
|
||||
.on({
|
||||
mouseover(d, i) {
|
||||
d3.select(this).style({
|
||||
fill: 'skyblue'
|
||||
});
|
||||
},
|
||||
mouseout(d, i) {
|
||||
d3.select(this).style({
|
||||
fill: 'black'
|
||||
});
|
||||
}
|
||||
.on('mouseover', function () {
|
||||
d3.select(this).style('fill', 'skyblue');
|
||||
})
|
||||
.on('mouseout', function () {
|
||||
d3.select(this).style('fill', 'black');
|
||||
});
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
| -------- | ----------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `root` | DOM.Element | `body` | The tooltip will be added as a child of that element. You can also use a D3 [selection](https://github.com/mbostock/d3/wiki/Selections#d3_select) |
|
||||
| `left` | Number | `undefined` | Sets the tooltip `x` absolute position instead of the mouse `x` position, relative to the `root` element |
|
||||
| `top` | Number | `undefined` | Sets the tooltip `y` absolute position instead of the mouse `y` position, relative to the `root` element |
|
||||
| `offset` | Object | `{left: 0, top: 0}` | Sets the distance, starting from the cursor position, until the tooltip is rendered. **Warning**: only applicable if you don't provide a `left` or `top` option |
|
||||
| Option | Type | Default | Description |
|
||||
| -------- | ------------------ | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `root` | DOM.Element | `body` | The tooltip will be added as a child of that element. You can also use a D3 [selection](https://github.com/mbostock/d3/wiki/Selections#d3_select). |
|
||||
| `left` | Number | `undefined` | Sets the tooltip `x` absolute position instead of the mouse `x` position, relative to the `root` element. |
|
||||
| `top` | Number | `undefined` | Sets the tooltip `y` absolute position instead of the mouse `y` position, relative to the `root` element. |
|
||||
| `offset` | Object | `{left: 0, top: 0}` | Sets the distance, starting from the cursor position, until the tooltip is rendered. **Warning**: only applicable if you don't provide a `left` or `top` option. |
|
||||
| `styles` | Object | `{}` | Sets the styles of the tooltip element. |
|
||||
| `text` | String or Function | `''` | Sets the text of the tooltip. Can be a constant `string` or a function that takes the datum and returns a `string`. |
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "d3tooltip",
|
||||
"version": "2.1.0",
|
||||
"version": "3.0.0",
|
||||
"description": "A highly configurable tooltip for d3",
|
||||
"keywords": [
|
||||
"d3",
|
||||
|
@ -19,18 +19,16 @@
|
|||
"main": "lib/cjs/index.js",
|
||||
"module": "lib/esm/index.js",
|
||||
"types": "lib/types/index.d.ts",
|
||||
"unpkg": "lib/umd/d3tooltip.umd.js",
|
||||
"sideEffects": false,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reduxjs/redux-devtools.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types && pnpm run build:umd",
|
||||
"build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types",
|
||||
"build:cjs": "babel src --extensions \".ts\" --out-dir lib/cjs",
|
||||
"build:esm": "babel src --config-file ./babel.config.esm.json --extensions \".ts\" --out-dir lib/esm",
|
||||
"build:types": "tsc --emitDeclarationOnly",
|
||||
"build:umd": "rollup -c",
|
||||
"clean": "rimraf lib",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"type-check": "tsc --noEmit",
|
||||
|
@ -38,36 +36,25 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"ramda": "^0.28.0"
|
||||
"@babel/runtime": "^7.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@rollup/plugin-babel": "^6.0.3",
|
||||
"@rollup/plugin-commonjs": "^24.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@rollup/plugin-terser": "^0.2.1",
|
||||
"@types/d3": "^3.5.47",
|
||||
"@types/node": "^18.11.17",
|
||||
"@types/ramda": "^0.28.20",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"d3": "^3.5.17",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^3.7.5",
|
||||
"rollup-plugin-typescript2": "^0.34.1",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "~4.9.4"
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@types/d3": "^7.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"d3": "^7.8.2",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"rimraf": "^4.1.3",
|
||||
"typescript": "~4.9.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/d3": "^3.5.47",
|
||||
"d3": "^3.5.17"
|
||||
"@types/d3": "^7.4.0",
|
||||
"d3": "^7.8.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
import typescript from 'rollup-plugin-typescript2';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import babel from '@rollup/plugin-babel';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
|
||||
const config = [
|
||||
{
|
||||
input: 'src/index.ts',
|
||||
output: {
|
||||
name: 'd3tooltip',
|
||||
file: 'lib/umd/d3tooltip.js',
|
||||
format: 'umd',
|
||||
},
|
||||
plugins: [
|
||||
typescript({
|
||||
tsconfigOverride: { compilerOptions: { declaration: false } },
|
||||
}),
|
||||
resolve(),
|
||||
commonjs(),
|
||||
babel({
|
||||
babelHelpers: 'runtime',
|
||||
extensions: ['.ts'],
|
||||
plugins: ['@babel/plugin-transform-runtime'],
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
input: 'src/index.ts',
|
||||
output: {
|
||||
name: 'd3tooltip',
|
||||
file: 'lib/umd/d3tooltip.min.js',
|
||||
format: 'umd',
|
||||
},
|
||||
plugins: [
|
||||
typescript({
|
||||
tsconfigOverride: { compilerOptions: { declaration: false } },
|
||||
}),
|
||||
resolve(),
|
||||
commonjs(),
|
||||
babel({
|
||||
babelHelpers: 'runtime',
|
||||
extensions: ['.ts'],
|
||||
plugins: ['@babel/plugin-transform-runtime'],
|
||||
}),
|
||||
terser(),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default config;
|
|
@ -1,161 +1,102 @@
|
|||
import d3Package, { Primitive, Selection } from 'd3';
|
||||
import { is } from 'ramda';
|
||||
import utils from './utils';
|
||||
const { prependClass, functor } = utils;
|
||||
import * as d3 from 'd3';
|
||||
import type { BaseType, Selection } from 'd3';
|
||||
|
||||
interface Options<Datum> {
|
||||
export type StyleValue = string | number | boolean;
|
||||
|
||||
interface Options<
|
||||
Datum,
|
||||
RootGElement extends BaseType,
|
||||
RootDatum,
|
||||
RootPElement extends BaseType,
|
||||
RootPDatum
|
||||
> {
|
||||
left: number | undefined;
|
||||
top: number | undefined;
|
||||
offset: {
|
||||
left: number;
|
||||
top: number;
|
||||
};
|
||||
root: Selection<Datum> | undefined;
|
||||
root:
|
||||
| Selection<RootGElement, RootDatum, RootPElement, RootPDatum>
|
||||
| undefined;
|
||||
styles: { [key: string]: StyleValue };
|
||||
text: string | ((datum: Datum) => string);
|
||||
}
|
||||
|
||||
const defaultOptions: Options<unknown> = {
|
||||
const defaultOptions: Options<unknown, BaseType, unknown, BaseType, unknown> = {
|
||||
left: undefined, // mouseX
|
||||
top: undefined, // mouseY
|
||||
offset: { left: 0, top: 0 },
|
||||
root: undefined,
|
||||
styles: {},
|
||||
text: '',
|
||||
};
|
||||
|
||||
interface Tip<Datum> {
|
||||
(selection: Selection<Datum>): void;
|
||||
attr: (
|
||||
this: this,
|
||||
d:
|
||||
| string
|
||||
| {
|
||||
[key: string]:
|
||||
| Primitive
|
||||
| ((datum: Datum, index: number, outerIndex: number) => Primitive);
|
||||
}
|
||||
) => this;
|
||||
style: (
|
||||
this: this,
|
||||
d:
|
||||
| string
|
||||
| {
|
||||
[key: string]:
|
||||
| Primitive
|
||||
| ((datum: Datum, index: number, outerIndex: number) => Primitive);
|
||||
}
|
||||
| undefined
|
||||
) => this;
|
||||
text: (
|
||||
this: this,
|
||||
d: string | ((datum: Datum, index?: number, outerIndex?: number) => string)
|
||||
) => this;
|
||||
}
|
||||
|
||||
export function tooltip<Datum>(
|
||||
d3: typeof d3Package,
|
||||
export function tooltip<
|
||||
GElement extends BaseType,
|
||||
Datum,
|
||||
PElement extends BaseType,
|
||||
PDatum,
|
||||
RootGElement extends BaseType,
|
||||
RootDatum,
|
||||
RootPElement extends BaseType,
|
||||
RootPDatum
|
||||
>(
|
||||
className = 'tooltip',
|
||||
options: Partial<Options<Datum>> = {}
|
||||
): Tip<Datum> {
|
||||
const { left, top, offset, root } = {
|
||||
options: Partial<
|
||||
Options<Datum, RootGElement, RootDatum, RootPElement, RootPDatum>
|
||||
> = {}
|
||||
) {
|
||||
const { left, top, offset, root, styles, text } = {
|
||||
...defaultOptions,
|
||||
...options,
|
||||
} as Options<Datum>;
|
||||
} as Options<Datum, RootGElement, RootDatum, RootPElement, RootPDatum>;
|
||||
|
||||
let attrs = { class: className };
|
||||
let text: (datum: Datum, index?: number, outerIndex?: number) => string = (
|
||||
node: Datum
|
||||
) => '';
|
||||
let styles = {};
|
||||
let el: Selection<HTMLDivElement, RootDatum, BaseType, unknown>;
|
||||
const anchor: Selection<
|
||||
RootGElement,
|
||||
RootDatum,
|
||||
RootPElement | HTMLElement,
|
||||
RootPDatum
|
||||
> = root || d3.select<RootGElement, RootDatum>('body');
|
||||
const rootNode = anchor.node()!;
|
||||
|
||||
let el: Selection<Datum>;
|
||||
const anchor = root || d3.select('body');
|
||||
const rootNode = anchor.node();
|
||||
|
||||
function tip(selection: Selection<Datum>) {
|
||||
selection.on('mouseover.tip', (node) => {
|
||||
const [mouseX, mouseY] = d3.mouse(rootNode);
|
||||
const [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top];
|
||||
return function tip(selection: Selection<GElement, Datum, PElement, PDatum>) {
|
||||
selection.on('mouseover.tip', (event, datum) => {
|
||||
const [pointerX, pointerY] = d3.pointer(event, rootNode);
|
||||
const [x, y] = [
|
||||
left || pointerX + offset.left,
|
||||
top || pointerY - offset.top,
|
||||
];
|
||||
|
||||
anchor.selectAll(`div.${className}`).remove();
|
||||
|
||||
el = anchor
|
||||
.append('div')
|
||||
.attr(prependClass(className)(attrs))
|
||||
.style({
|
||||
position: 'absolute',
|
||||
'z-index': 1001,
|
||||
left: `${x}px`,
|
||||
top: `${y}px`,
|
||||
...styles,
|
||||
})
|
||||
.html(() => text(node)) as Selection<Datum>;
|
||||
.attr('class', className)
|
||||
.style('position', 'absolute')
|
||||
.style('z-index', 1001)
|
||||
.style('left', `${x}px`)
|
||||
.style('top', `${y}px`)
|
||||
.html(typeof text === 'function' ? () => text(datum) : () => text);
|
||||
|
||||
for (const [key, value] of Object.entries(styles)) {
|
||||
el.style(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
selection.on('mousemove.tip', (node) => {
|
||||
const [mouseX, mouseY] = d3.mouse(rootNode);
|
||||
const [x, y] = [left || mouseX + offset.left, top || mouseY - offset.top];
|
||||
selection.on('mousemove.tip', (event, datum) => {
|
||||
const [pointerX, pointerY] = d3.pointer(event, rootNode);
|
||||
const [x, y] = [
|
||||
left || pointerX + offset.left,
|
||||
top || pointerY - offset.top,
|
||||
];
|
||||
|
||||
el.style({
|
||||
left: `${x}px`,
|
||||
top: `${y}px`,
|
||||
}).html(() => text(node));
|
||||
el.style('left', `${x}px`)
|
||||
.style('top', `${y}px`)
|
||||
.html(typeof text === 'function' ? () => text(datum) : () => text);
|
||||
});
|
||||
|
||||
selection.on('mouseout.tip', () => el.remove());
|
||||
}
|
||||
|
||||
tip.attr = function setAttr(
|
||||
this: typeof tip,
|
||||
d:
|
||||
| string
|
||||
| {
|
||||
[key: string]:
|
||||
| Primitive
|
||||
| ((datum: Datum, index: number, outerIndex: number) => Primitive);
|
||||
}
|
||||
) {
|
||||
if (is(Object, d)) {
|
||||
attrs = {
|
||||
...attrs,
|
||||
...(d as {
|
||||
[key: string]:
|
||||
| Primitive
|
||||
| ((datum: Datum, index: number, outerIndex: number) => Primitive);
|
||||
}),
|
||||
};
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
tip.style = function setStyle(
|
||||
this: typeof tip,
|
||||
d:
|
||||
| string
|
||||
| {
|
||||
[key: string]:
|
||||
| Primitive
|
||||
| ((datum: Datum, index: number, outerIndex: number) => Primitive);
|
||||
}
|
||||
| undefined
|
||||
) {
|
||||
if (is(Object, d)) {
|
||||
styles = {
|
||||
...styles,
|
||||
...(d as {
|
||||
[key: string]:
|
||||
| Primitive
|
||||
| ((datum: Datum, index: number, outerIndex: number) => Primitive);
|
||||
}),
|
||||
};
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
tip.text = function setText(
|
||||
this: typeof tip,
|
||||
d: string | ((datum: Datum, index?: number, outerIndex?: number) => string)
|
||||
) {
|
||||
text = functor(d);
|
||||
return this;
|
||||
};
|
||||
|
||||
return tip;
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
import { is } from 'ramda';
|
||||
import { Primitive } from 'd3';
|
||||
|
||||
export default function functor<Datum>(
|
||||
v: string | ((datum: Datum, index?: number, outerIndex?: number) => string)
|
||||
): (datum: Datum, index?: number, outerIndex?: number) => string;
|
||||
export default function functor<Datum>(
|
||||
v:
|
||||
| Primitive
|
||||
| ((datum: Datum, index: number, outerIndex?: number) => Primitive)
|
||||
): (datum: Datum, index?: number, outerIndex?: number) => Primitive;
|
||||
export default function functor<Datum>(
|
||||
v:
|
||||
| Primitive
|
||||
| ((datum: Datum, index: number, outerIndex?: number) => Primitive)
|
||||
): (datum: Datum, index: number, outerIndex?: number) => Primitive {
|
||||
return is(Function, v)
|
||||
? (v as (datum: Datum, index: number, outerIndex?: number) => Primitive)
|
||||
: () => v;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
import prependClass from './prependClass';
|
||||
import functor from './functor';
|
||||
|
||||
export default {
|
||||
prependClass,
|
||||
functor,
|
||||
};
|
|
@ -1,28 +0,0 @@
|
|||
import { mapObjIndexed, join } from 'ramda';
|
||||
import functor from './functor';
|
||||
import { Primitive } from 'd3';
|
||||
|
||||
export default function prependClass<Datum>(className: string) {
|
||||
return mapObjIndexed(
|
||||
(
|
||||
value:
|
||||
| Primitive
|
||||
| ((datum: Datum, index: number, outerIndex?: number) => Primitive),
|
||||
key
|
||||
) => {
|
||||
if (key === 'class') {
|
||||
const fn = functor(value);
|
||||
|
||||
return (d: Datum, i: number) => {
|
||||
const classNames = fn(d, i);
|
||||
if (classNames !== className) {
|
||||
return join(' ', [className, classNames]);
|
||||
}
|
||||
return classNames;
|
||||
};
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
);
|
||||
}
|
|
@ -1,5 +1,11 @@
|
|||
# Change Log
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- b323f77d: Remove UMD build.
|
||||
|
||||
## 2.0.0
|
||||
|
||||
- Adds ESM build (https://github.com/reduxjs/redux-devtools/pull/997) and switches the default export to a named export in order to ensure that the CommonJS output and the ESM output are [interchangeable](https://rollupjs.org/guide/en/#outputexports):
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "map2tree",
|
||||
"version": "2.1.0",
|
||||
"version": "3.0.0",
|
||||
"description": "Utility for mapping maps to trees",
|
||||
"keywords": [
|
||||
"map2tree",
|
||||
|
@ -22,18 +22,16 @@
|
|||
"main": "lib/cjs/index.js",
|
||||
"module": "lib/esm/index.js",
|
||||
"types": "lib/types/index.d.ts",
|
||||
"unpkg": "lib/umd/map2tree.umd.js",
|
||||
"sideEffects": false,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/reduxjs/redux-devtools.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types && pnpm run build:umd",
|
||||
"build": "pnpm run build:cjs && pnpm run build:esm && pnpm run build:types",
|
||||
"build:cjs": "babel src --extensions \".ts\" --out-dir lib/cjs",
|
||||
"build:esm": "babel src --config-file ./babel.config.esm.json --extensions \".ts\" --out-dir lib/esm",
|
||||
"build:types": "tsc --emitDeclarationOnly",
|
||||
"build:umd": "rollup -c",
|
||||
"clean": "rimraf lib",
|
||||
"test": "jest",
|
||||
"lint": "eslint . --ext .ts",
|
||||
|
@ -42,35 +40,26 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint && pnpm run test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"lodash": "^4.17.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@rollup/plugin-babel": "^6.0.3",
|
||||
"@rollup/plugin-commonjs": "^24.0.0",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@rollup/plugin-terser": "^0.2.1",
|
||||
"@types/jest": "^29.2.4",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/node": "^18.11.17",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-jest": "^27.1.7",
|
||||
"immutable": "^4.1.0",
|
||||
"jest": "^29.3.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^3.7.5",
|
||||
"rollup-plugin-typescript2": "^0.34.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "~4.9.4"
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"immutable": "^4.2.4",
|
||||
"jest": "^29.4.3",
|
||||
"rimraf": "^4.1.3",
|
||||
"ts-jest": "^29.0.5",
|
||||
"typescript": "~4.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
import typescript from 'rollup-plugin-typescript2';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import babel from '@rollup/plugin-babel';
|
||||
import terser from '@rollup/plugin-terser';
|
||||
|
||||
const config = [
|
||||
{
|
||||
input: 'src/index.ts',
|
||||
output: {
|
||||
name: 'map2tree',
|
||||
file: 'lib/umd/map2tree.js',
|
||||
format: 'umd',
|
||||
},
|
||||
plugins: [
|
||||
typescript({
|
||||
tsconfigOverride: { compilerOptions: { declaration: false } },
|
||||
}),
|
||||
resolve(),
|
||||
commonjs(),
|
||||
babel({
|
||||
babelHelpers: 'runtime',
|
||||
extensions: ['.ts'],
|
||||
plugins: ['@babel/plugin-transform-runtime'],
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
input: 'src/index.ts',
|
||||
output: {
|
||||
name: 'map2tree',
|
||||
file: 'lib/umd/map2tree.min.js',
|
||||
format: 'umd',
|
||||
},
|
||||
plugins: [
|
||||
typescript({
|
||||
tsconfigOverride: { compilerOptions: { declaration: false } },
|
||||
}),
|
||||
resolve(),
|
||||
commonjs(),
|
||||
babel({
|
||||
babelHelpers: 'runtime',
|
||||
extensions: ['.ts'],
|
||||
plugins: ['@babel/plugin-transform-runtime'],
|
||||
}),
|
||||
terser(),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default config;
|
|
@ -4,7 +4,8 @@ import mapValues from 'lodash/mapValues';
|
|||
|
||||
export interface Node {
|
||||
name: string;
|
||||
children?: Node[] | null;
|
||||
children?: this[];
|
||||
object?: unknown;
|
||||
value?: unknown;
|
||||
}
|
||||
|
||||
|
@ -43,7 +44,6 @@ function getNode(tree: Node, key: string): Node | null {
|
|||
}
|
||||
|
||||
export function map2tree(
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
root: unknown,
|
||||
options: { key?: string; pushMethod?: 'push' | 'unshift' } = {},
|
||||
tree: Node = { name: options.key || 'state', children: [] }
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint && pnpm run test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@types/base16": "^1.0.2",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"base16": "^1.0.0",
|
||||
|
@ -48,24 +48,24 @@
|
|||
"lodash.curry": "^4.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/plugin-transform-runtime": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@types/color": "^3.0.3",
|
||||
"@types/jest": "^29.2.4",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/lodash.curry": "^4.1.7",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-jest": "^27.1.7",
|
||||
"jest": "^29.3.1",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "~4.9.4"
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"jest": "^29.4.3",
|
||||
"jest-environment-jsdom": "^29.4.3",
|
||||
"rimraf": "^4.1.3",
|
||||
"ts-jest": "^29.0.5",
|
||||
"typescript": "~4.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,34 +11,34 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.7.0",
|
||||
"react-bootstrap": "^2.7.2",
|
||||
"react-dock": "^0.6.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^4.7.1",
|
||||
"react-is": "^18.2.0",
|
||||
"styled-components": "^5.3.6"
|
||||
"styled-components": "^5.3.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@types/node": "^18.11.17",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@types/node": "^18.14.4",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"babel-loader": "^9.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"fork-ts-checker-webpack-plugin": "^7.2.14",
|
||||
"fork-ts-checker-webpack-plugin": "^8.0.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "~4.9.4",
|
||||
"typescript": "~4.9.5",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.11.1"
|
||||
|
|
|
@ -39,38 +39,38 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint && pnpm run test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/prop-types": "^15.7.5",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"prop-types": "^15.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/plugin-transform-runtime": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@types/jest": "^29.2.4",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/lodash.debounce": "^4.0.7",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-test-renderer": "^18.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-jest": "^27.1.7",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"jest": "^29.3.1",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"jest": "^29.4.3",
|
||||
"jest-environment-jsdom": "^29.4.3",
|
||||
"react": "^18.2.0",
|
||||
"react-test-renderer": "^18.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "~4.9.4"
|
||||
"rimraf": "^4.1.3",
|
||||
"ts-jest": "^29.0.5",
|
||||
"typescript": "~4.9.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0",
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
# Change Log
|
||||
|
||||
## 0.18.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 81926f32: Remove UNSAFE method from react-json-tree
|
||||
|
||||
- Replace `shouldExpandNode` with `shouldExpandNodeInitially`. This function is now only called when a node in the tree is first rendered, when before it would update the expanded state of the node if the results of calling `shouldExpandNode` changed between renders. There is no way to replicate the old behavior exactly, but the new behavior is the intended behavior for the use cases within Redux DevTools. Please open an issue if you need a way to programatically control the expanded state of nodes.
|
||||
- Bump the minimum React version from `16.3.0` to `16.8.0` so that `react-json-tree` can use hooks.
|
||||
- Tightened TypeScript prop types to use `unknown` instead of `any` where possible and make the key path array `readonly`.
|
||||
|
||||
## 0.17.0
|
||||
|
||||
### Minor Changes
|
||||
|
|
|
@ -139,7 +139,7 @@ Their full signatures are:
|
|||
|
||||
#### More Options
|
||||
|
||||
- `shouldExpandNode: function(keyPath, data, level)` - determines if node should be expanded (root is expanded by default)
|
||||
- `shouldExpandNodeInitially: function(keyPath, data, level)` - determines if node should be expanded when it first renders (root is expanded by default)
|
||||
- `hideRoot: boolean` - if `true`, the root node is hidden.
|
||||
- `sortObjectKeys: boolean | function(a, b)` - sorts object keys with compare function (optional). Isn't applied to iterable maps like `Immutable.Map`.
|
||||
- `postprocessValue: function(value)` - maps `value` to a new `value`
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
# react-json-tree-example
|
||||
|
||||
## 1.1.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [81926f32]
|
||||
- react-json-tree@0.18.0
|
||||
|
||||
## 1.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"private": true,
|
||||
"name": "react-json-tree-example",
|
||||
"version": "1.1.7",
|
||||
"version": "1.1.8",
|
||||
"description": "React-Json-Tree example",
|
||||
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/react-json-tree/examples",
|
||||
"bugs": {
|
||||
|
@ -19,32 +19,32 @@
|
|||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"immutable": "^4.1.0",
|
||||
"immutable": "^4.2.4",
|
||||
"react": "^18.2.0",
|
||||
"react-base16-styling": "^0.9.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-json-tree": "^0.17.0"
|
||||
"react-json-tree": "^0.18.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@types/node": "^18.11.17",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"babel-loader": "^9.1.0",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@types/node": "^18.14.4",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"fork-ts-checker-webpack-plugin": "^7.2.14",
|
||||
"fork-ts-checker-webpack-plugin": "^8.0.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "~4.9.4",
|
||||
"typescript": "~4.9.5",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.11.1"
|
||||
|
|
|
@ -178,7 +178,7 @@ const App = () => (
|
|||
<span role="img" aria-label="mellow">
|
||||
😐
|
||||
</span>{' '}
|
||||
{raw}{' '}
|
||||
{raw as string}{' '}
|
||||
<span role="img" aria-label="mellow">
|
||||
😐
|
||||
</span>
|
||||
|
@ -194,7 +194,11 @@ const App = () => (
|
|||
</div>
|
||||
<p>Collapsed root node</p>
|
||||
<div>
|
||||
<JSONTree data={data} theme={theme} shouldExpandNode={() => false} />
|
||||
<JSONTree
|
||||
data={data}
|
||||
theme={theme}
|
||||
shouldExpandNodeInitially={() => false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "react-json-tree",
|
||||
"version": "0.17.0",
|
||||
"version": "0.18.0",
|
||||
"description": "React JSON Viewer Component, Extracted from redux-devtools",
|
||||
"keywords": [
|
||||
"react",
|
||||
|
@ -45,47 +45,45 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint && pnpm run test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/prop-types": "^15.7.5",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-base16-styling": "^0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/plugin-transform-runtime": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@rollup/plugin-babel": "^6.0.3",
|
||||
"@rollup/plugin-commonjs": "^24.0.0",
|
||||
"@rollup/plugin-commonjs": "^24.0.1",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@rollup/plugin-terser": "^0.2.1",
|
||||
"@types/jest": "^29.2.4",
|
||||
"@types/node": "^18.11.17",
|
||||
"@types/react": "^18.0.26",
|
||||
"@rollup/plugin-terser": "^0.4.0",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/node": "^18.14.4",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-test-renderer": "^18.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-jest": "^27.1.7",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"jest": "^29.3.1",
|
||||
"jest": "^29.4.3",
|
||||
"react": "^18.2.0",
|
||||
"react-test-renderer": "^18.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^3.7.5",
|
||||
"rimraf": "^4.1.3",
|
||||
"rollup": "^3.18.0",
|
||||
"rollup-plugin-typescript2": "^0.34.1",
|
||||
"ts-jest": "^29.0.3",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "~4.9.4"
|
||||
"ts-jest": "^29.0.5",
|
||||
"tslib": "^2.5.0",
|
||||
"typescript": "~4.9.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0",
|
||||
"react": "^16.3.0 || ^17.0.0 || ^18.0.0"
|
||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +1,39 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import JSONArrow from './JSONArrow';
|
||||
import { CircularPropsPassedThroughItemRange } from './types';
|
||||
import type { CircularCache, CommonInternalProps } from './types';
|
||||
|
||||
interface Props extends CircularPropsPassedThroughItemRange {
|
||||
data: any;
|
||||
interface Props extends CommonInternalProps {
|
||||
data: unknown;
|
||||
nodeType: string;
|
||||
from: number;
|
||||
to: number;
|
||||
renderChildNodes: (props: Props, from: number, to: number) => React.ReactNode;
|
||||
circularCache: CircularCache;
|
||||
level: number;
|
||||
}
|
||||
|
||||
interface State {
|
||||
expanded: boolean;
|
||||
}
|
||||
|
||||
export default class ItemRange extends React.Component<Props, State> {
|
||||
static propTypes = {
|
||||
styling: PropTypes.func.isRequired,
|
||||
from: PropTypes.number.isRequired,
|
||||
to: PropTypes.number.isRequired,
|
||||
renderChildNodes: PropTypes.func.isRequired,
|
||||
nodeType: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = { expanded: false };
|
||||
}
|
||||
|
||||
render() {
|
||||
const { styling, from, to, renderChildNodes, nodeType } = this.props;
|
||||
|
||||
return this.state.expanded ? (
|
||||
<div {...styling('itemRange', this.state.expanded)}>
|
||||
{renderChildNodes(this.props, from, to)}
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
{...styling('itemRange', this.state.expanded)}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
<JSONArrow
|
||||
nodeType={nodeType}
|
||||
styling={styling}
|
||||
expanded={false}
|
||||
onClick={this.handleClick}
|
||||
arrowStyle="double"
|
||||
/>
|
||||
{`${from} ... ${to}`}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
this.setState({ expanded: !this.state.expanded });
|
||||
};
|
||||
export default function ItemRange(props: Props) {
|
||||
const { styling, from, to, renderChildNodes, nodeType } = props;
|
||||
|
||||
const [expanded, setExpanded] = useState<boolean>(false);
|
||||
const handleClick = useCallback(() => {
|
||||
setExpanded(!expanded);
|
||||
}, [expanded]);
|
||||
|
||||
return expanded ? (
|
||||
<div {...styling('itemRange', expanded)}>
|
||||
{renderChildNodes(props, from, to)}
|
||||
</div>
|
||||
) : (
|
||||
<div {...styling('itemRange', expanded)} onClick={handleClick}>
|
||||
<JSONArrow
|
||||
nodeType={nodeType}
|
||||
styling={styling}
|
||||
expanded={false}
|
||||
onClick={handleClick}
|
||||
arrowStyle="double"
|
||||
/>
|
||||
{`${from} ... ${to}`}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,35 +1,30 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import JSONNestedNode from './JSONNestedNode';
|
||||
import { CircularPropsPassedThroughJSONNode } from './types';
|
||||
import type { CommonInternalProps } from './types';
|
||||
|
||||
// Returns the "n Items" string for this node,
|
||||
// generating and caching it if it hasn't been created yet.
|
||||
function createItemString(data: any) {
|
||||
function createItemString(data: unknown) {
|
||||
return `${(data as unknown[]).length} ${
|
||||
(data as unknown[]).length !== 1 ? 'items' : 'item'
|
||||
}`;
|
||||
}
|
||||
|
||||
interface Props extends CircularPropsPassedThroughJSONNode {
|
||||
data: any;
|
||||
interface Props extends CommonInternalProps {
|
||||
data: unknown;
|
||||
nodeType: string;
|
||||
}
|
||||
|
||||
// Configures <JSONNestedNode> to render an Array
|
||||
const JSONArrayNode: React.FunctionComponent<Props> = ({ data, ...props }) => (
|
||||
<JSONNestedNode
|
||||
{...props}
|
||||
data={data}
|
||||
nodeType="Array"
|
||||
nodeTypeIndicator="[]"
|
||||
createItemString={createItemString}
|
||||
expandable={data.length > 0}
|
||||
/>
|
||||
);
|
||||
|
||||
JSONArrayNode.propTypes = {
|
||||
data: PropTypes.array,
|
||||
};
|
||||
|
||||
export default JSONArrayNode;
|
||||
export default function JSONArrayNode({ data, ...props }: Props) {
|
||||
return (
|
||||
<JSONNestedNode
|
||||
{...props}
|
||||
data={data}
|
||||
nodeType="Array"
|
||||
nodeTypeIndicator="[]"
|
||||
createItemString={createItemString}
|
||||
expandable={(data as unknown[]).length > 0}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { StylingFunction } from 'react-base16-styling';
|
||||
import type { StylingFunction } from 'react-base16-styling';
|
||||
|
||||
interface Props {
|
||||
styling: StylingFunction;
|
||||
|
@ -10,33 +9,21 @@ interface Props {
|
|||
onClick: React.MouseEventHandler<HTMLDivElement>;
|
||||
}
|
||||
|
||||
const JSONArrow: React.FunctionComponent<Props> = ({
|
||||
export default function JSONArrow({
|
||||
styling,
|
||||
arrowStyle,
|
||||
arrowStyle = 'single',
|
||||
expanded,
|
||||
nodeType,
|
||||
onClick,
|
||||
}) => (
|
||||
<div {...styling('arrowContainer', arrowStyle)} onClick={onClick}>
|
||||
<div {...styling(['arrow', 'arrowSign'], nodeType, expanded, arrowStyle)}>
|
||||
{'\u25B6'}
|
||||
{arrowStyle === 'double' && (
|
||||
<div {...styling(['arrowSign', 'arrowSignInner'])}>{'\u25B6'}</div>
|
||||
)}
|
||||
}: Props) {
|
||||
return (
|
||||
<div {...styling('arrowContainer', arrowStyle)} onClick={onClick}>
|
||||
<div {...styling(['arrow', 'arrowSign'], nodeType, expanded, arrowStyle)}>
|
||||
{'\u25B6'}
|
||||
{arrowStyle === 'double' && (
|
||||
<div {...styling(['arrowSign', 'arrowSignInner'])}>{'\u25B6'}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
JSONArrow.propTypes = {
|
||||
styling: PropTypes.func.isRequired,
|
||||
arrowStyle: PropTypes.oneOf(['single', 'double']),
|
||||
expanded: PropTypes.bool.isRequired,
|
||||
nodeType: PropTypes.string.isRequired,
|
||||
onClick: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
JSONArrow.defaultProps = {
|
||||
arrowStyle: 'single',
|
||||
};
|
||||
|
||||
export default JSONArrow;
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import JSONNestedNode from './JSONNestedNode';
|
||||
import { CircularPropsPassedThroughJSONNode } from './types';
|
||||
import type { CommonInternalProps } from './types';
|
||||
|
||||
// Returns the "n Items" string for this node,
|
||||
// generating and caching it if it hasn't been created yet.
|
||||
|
@ -22,21 +22,20 @@ function createItemString(data: any, limit: number) {
|
|||
return `${hasMore ? '>' : ''}${count} ${count !== 1 ? 'entries' : 'entry'}`;
|
||||
}
|
||||
|
||||
interface Props extends CircularPropsPassedThroughJSONNode {
|
||||
data: any;
|
||||
interface Props extends CommonInternalProps {
|
||||
data: unknown;
|
||||
nodeType: string;
|
||||
}
|
||||
|
||||
// Configures <JSONNestedNode> to render an iterable
|
||||
const JSONIterableNode: React.FunctionComponent<Props> = ({ ...props }) => {
|
||||
export default function JSONIterableNode(props: Props) {
|
||||
return (
|
||||
<JSONNestedNode
|
||||
{...props}
|
||||
nodeType="Iterable"
|
||||
nodeTypeIndicator="()"
|
||||
createItemString={createItemString}
|
||||
expandable
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default JSONIterableNode;
|
||||
}
|
||||
|
|
|
@ -1,22 +1,19 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import JSONArrow from './JSONArrow';
|
||||
import getCollectionEntries from './getCollectionEntries';
|
||||
import JSONNode from './JSONNode';
|
||||
import ItemRange from './ItemRange';
|
||||
import {
|
||||
CircularPropsPassedThroughJSONNestedNode,
|
||||
CircularPropsPassedThroughRenderChildNodes,
|
||||
} from './types';
|
||||
import type { CircularCache, CommonInternalProps } from './types';
|
||||
|
||||
/**
|
||||
* Renders nested values (eg. objects, arrays, lists, etc.)
|
||||
*/
|
||||
|
||||
export interface RenderChildNodesProps
|
||||
extends CircularPropsPassedThroughRenderChildNodes {
|
||||
data: any;
|
||||
export interface RenderChildNodesProps extends CommonInternalProps {
|
||||
data: unknown;
|
||||
nodeType: string;
|
||||
circularCache: CircularCache;
|
||||
level: number;
|
||||
}
|
||||
|
||||
interface Range {
|
||||
|
@ -26,7 +23,7 @@ interface Range {
|
|||
|
||||
interface Entry {
|
||||
key: string | number;
|
||||
value: any;
|
||||
value: unknown;
|
||||
}
|
||||
|
||||
function isRange(rangeOrEntry: Range | Entry): rangeOrEntry is Range {
|
||||
|
@ -89,152 +86,92 @@ function renderChildNodes(
|
|||
return childNodes;
|
||||
}
|
||||
|
||||
interface Props extends CircularPropsPassedThroughJSONNestedNode {
|
||||
data: any;
|
||||
interface Props extends CommonInternalProps {
|
||||
data: unknown;
|
||||
nodeType: string;
|
||||
nodeTypeIndicator: string;
|
||||
createItemString: (data: any, collectionLimit: number) => string;
|
||||
createItemString: (data: unknown, collectionLimit: number) => string;
|
||||
expandable: boolean;
|
||||
}
|
||||
|
||||
interface State {
|
||||
expanded: boolean;
|
||||
}
|
||||
export default function JSONNestedNode(props: Props) {
|
||||
const {
|
||||
circularCache = [],
|
||||
collectionLimit,
|
||||
createItemString,
|
||||
data,
|
||||
expandable,
|
||||
getItemString,
|
||||
hideRoot,
|
||||
isCircular,
|
||||
keyPath,
|
||||
labelRenderer,
|
||||
level = 0,
|
||||
nodeType,
|
||||
nodeTypeIndicator,
|
||||
shouldExpandNodeInitially,
|
||||
styling,
|
||||
} = props;
|
||||
|
||||
function getStateFromProps(props: Props) {
|
||||
// calculate individual node expansion if necessary
|
||||
const expanded = !props.isCircular
|
||||
? props.shouldExpandNode(props.keyPath, props.data, props.level)
|
||||
: false;
|
||||
return {
|
||||
expanded,
|
||||
};
|
||||
}
|
||||
const [expanded, setExpanded] = useState<boolean>(
|
||||
// calculate individual node expansion if necessary
|
||||
isCircular ? false : shouldExpandNodeInitially(keyPath, data, level)
|
||||
);
|
||||
|
||||
export default class JSONNestedNode extends React.Component<Props, State> {
|
||||
static propTypes = {
|
||||
getItemString: PropTypes.func.isRequired,
|
||||
nodeTypeIndicator: PropTypes.any,
|
||||
nodeType: PropTypes.string.isRequired,
|
||||
data: PropTypes.any,
|
||||
hideRoot: PropTypes.bool.isRequired,
|
||||
createItemString: PropTypes.func.isRequired,
|
||||
styling: PropTypes.func.isRequired,
|
||||
collectionLimit: PropTypes.number,
|
||||
keyPath: PropTypes.arrayOf(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
||||
).isRequired,
|
||||
labelRenderer: PropTypes.func.isRequired,
|
||||
shouldExpandNode: PropTypes.func,
|
||||
level: PropTypes.number.isRequired,
|
||||
sortObjectKeys: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
|
||||
isCircular: PropTypes.bool,
|
||||
expandable: PropTypes.bool,
|
||||
};
|
||||
const handleClick = useCallback(() => {
|
||||
if (expandable) setExpanded(!expanded);
|
||||
}, [expandable, expanded]);
|
||||
|
||||
static defaultProps = {
|
||||
data: [],
|
||||
circularCache: [],
|
||||
level: 0,
|
||||
expandable: true,
|
||||
};
|
||||
const renderedChildren =
|
||||
expanded || (hideRoot && level === 0)
|
||||
? renderChildNodes({ ...props, circularCache, level: level + 1 })
|
||||
: null;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = getStateFromProps(props);
|
||||
}
|
||||
const itemType = (
|
||||
<span {...styling('nestedNodeItemType', expanded)}>
|
||||
{nodeTypeIndicator}
|
||||
</span>
|
||||
);
|
||||
const renderedItemString = getItemString(
|
||||
nodeType,
|
||||
data,
|
||||
itemType,
|
||||
createItemString(data, collectionLimit),
|
||||
keyPath
|
||||
);
|
||||
const stylingArgs = [keyPath, nodeType, expanded, expandable] as const;
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||
const nextState = getStateFromProps(nextProps);
|
||||
if (getStateFromProps(this.props).expanded !== nextState.expanded) {
|
||||
this.setState(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 as keyof Props] !== this.props[key as keyof Props])
|
||||
) || nextState.expanded !== this.state.expanded
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
getItemString,
|
||||
nodeTypeIndicator,
|
||||
nodeType,
|
||||
data,
|
||||
hideRoot,
|
||||
createItemString,
|
||||
styling,
|
||||
collectionLimit,
|
||||
keyPath,
|
||||
labelRenderer,
|
||||
expandable,
|
||||
} = this.props;
|
||||
const { expanded } = this.state;
|
||||
const renderedChildren =
|
||||
expanded || (hideRoot && this.props.level === 0)
|
||||
? renderChildNodes({ ...this.props, level: this.props.level + 1 })
|
||||
: null;
|
||||
|
||||
const itemType = (
|
||||
<span {...styling('nestedNodeItemType', expanded)}>
|
||||
{nodeTypeIndicator}
|
||||
return hideRoot ? (
|
||||
<li {...styling('rootNode', ...stylingArgs)}>
|
||||
<ul {...styling('rootNodeChildren', ...stylingArgs)}>
|
||||
{renderedChildren}
|
||||
</ul>
|
||||
</li>
|
||||
) : (
|
||||
<li {...styling('nestedNode', ...stylingArgs)}>
|
||||
{expandable && (
|
||||
<JSONArrow
|
||||
styling={styling}
|
||||
nodeType={nodeType}
|
||||
expanded={expanded}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
)}
|
||||
<label
|
||||
{...styling(['label', 'nestedNodeLabel'], ...stylingArgs)}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{labelRenderer(...stylingArgs)}
|
||||
</label>
|
||||
<span
|
||||
{...styling('nestedNodeItemString', ...stylingArgs)}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{renderedItemString}
|
||||
</span>
|
||||
);
|
||||
const renderedItemString = getItemString(
|
||||
nodeType,
|
||||
data,
|
||||
itemType,
|
||||
createItemString(data, collectionLimit),
|
||||
keyPath
|
||||
);
|
||||
const stylingArgs = [keyPath, nodeType, expanded, expandable] as const;
|
||||
|
||||
return hideRoot ? (
|
||||
<li {...styling('rootNode', ...stylingArgs)}>
|
||||
<ul {...styling('rootNodeChildren', ...stylingArgs)}>
|
||||
{renderedChildren}
|
||||
</ul>
|
||||
</li>
|
||||
) : (
|
||||
<li {...styling('nestedNode', ...stylingArgs)}>
|
||||
{expandable && (
|
||||
<JSONArrow
|
||||
styling={styling}
|
||||
nodeType={nodeType}
|
||||
expanded={expanded}
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
)}
|
||||
<label
|
||||
{...styling(['label', 'nestedNodeLabel'], ...stylingArgs)}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{labelRenderer(...stylingArgs)}
|
||||
</label>
|
||||
<span
|
||||
{...styling('nestedNodeItemString', ...stylingArgs)}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
{renderedItemString}
|
||||
</span>
|
||||
<ul {...styling('nestedNodeChildren', ...stylingArgs)}>
|
||||
{renderedChildren}
|
||||
</ul>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
handleClick = () => {
|
||||
if (this.props.expandable) {
|
||||
this.setState({ expanded: !this.state.expanded });
|
||||
}
|
||||
};
|
||||
<ul {...styling('nestedNodeChildren', ...stylingArgs)}>
|
||||
{renderedChildren}
|
||||
</ul>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import objType from './objType';
|
||||
import JSONObjectNode from './JSONObjectNode';
|
||||
import JSONArrayNode from './JSONArrayNode';
|
||||
import JSONIterableNode from './JSONIterableNode';
|
||||
import JSONValueNode from './JSONValueNode';
|
||||
import { CircularPropsPassedThroughJSONNode } from './types';
|
||||
import type { CommonInternalProps } from './types';
|
||||
|
||||
interface Props extends CircularPropsPassedThroughJSONNode {
|
||||
keyPath: (string | number)[];
|
||||
value: any;
|
||||
isCustomNode: (value: any) => boolean;
|
||||
interface Props extends CommonInternalProps {
|
||||
value: unknown;
|
||||
}
|
||||
|
||||
const JSONNode: React.FunctionComponent<Props> = ({
|
||||
export default function JSONNode({
|
||||
getItemString,
|
||||
keyPath,
|
||||
labelRenderer,
|
||||
|
@ -22,7 +19,7 @@ const JSONNode: React.FunctionComponent<Props> = ({
|
|||
valueRenderer,
|
||||
isCustomNode,
|
||||
...rest
|
||||
}) => {
|
||||
}: Props) {
|
||||
const nodeType = isCustomNode(value) ? 'Custom' : objType(value);
|
||||
|
||||
const simpleNodeProps = {
|
||||
|
@ -102,18 +99,4 @@ const JSONNode: React.FunctionComponent<Props> = ({
|
|||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
JSONNode.propTypes = {
|
||||
getItemString: PropTypes.func.isRequired,
|
||||
keyPath: PropTypes.arrayOf(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
|
||||
).isRequired,
|
||||
labelRenderer: PropTypes.func.isRequired,
|
||||
styling: PropTypes.func.isRequired,
|
||||
value: PropTypes.any,
|
||||
valueRenderer: PropTypes.func.isRequired,
|
||||
isCustomNode: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default JSONNode;
|
||||
}
|
||||
|
|
|
@ -1,35 +1,29 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import JSONNestedNode from './JSONNestedNode';
|
||||
import { CircularPropsPassedThroughJSONNode } from './types';
|
||||
import type { CommonInternalProps } from './types';
|
||||
|
||||
// Returns the "n Items" string for this node,
|
||||
// generating and caching it if it hasn't been created yet.
|
||||
function createItemString(data: any) {
|
||||
function createItemString(data: unknown) {
|
||||
const len = Object.getOwnPropertyNames(data).length;
|
||||
return `${len} ${len !== 1 ? 'keys' : 'key'}`;
|
||||
}
|
||||
|
||||
interface Props extends CircularPropsPassedThroughJSONNode {
|
||||
data: any;
|
||||
interface Props extends CommonInternalProps {
|
||||
data: unknown;
|
||||
nodeType: string;
|
||||
}
|
||||
|
||||
// Configures <JSONNestedNode> to render an Object
|
||||
const JSONObjectNode: React.FunctionComponent<Props> = ({ data, ...props }) => (
|
||||
<JSONNestedNode
|
||||
{...props}
|
||||
data={data}
|
||||
nodeType="Object"
|
||||
nodeTypeIndicator={props.nodeType === 'Error' ? 'Error()' : '{}'}
|
||||
createItemString={createItemString}
|
||||
expandable={Object.getOwnPropertyNames(data).length > 0}
|
||||
/>
|
||||
);
|
||||
|
||||
JSONObjectNode.propTypes = {
|
||||
data: PropTypes.object,
|
||||
nodeType: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default JSONObjectNode;
|
||||
export default function JSONObjectNode({ data, ...props }: Props) {
|
||||
return (
|
||||
<JSONNestedNode
|
||||
{...props}
|
||||
data={data}
|
||||
nodeType="Object"
|
||||
nodeTypeIndicator={props.nodeType === 'Error' ? 'Error()' : '{}'}
|
||||
createItemString={createItemString}
|
||||
expandable={Object.getOwnPropertyNames(data).length > 0}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,30 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { JSONValueNodeCircularPropsProvidedByJSONNode } from './types';
|
||||
import type {
|
||||
GetItemString,
|
||||
Key,
|
||||
KeyPath,
|
||||
LabelRenderer,
|
||||
Styling,
|
||||
ValueRenderer,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* Renders simple values (eg. strings, numbers, booleans, etc)
|
||||
*/
|
||||
|
||||
interface Props extends JSONValueNodeCircularPropsProvidedByJSONNode {
|
||||
interface Props {
|
||||
getItemString: GetItemString;
|
||||
key: Key;
|
||||
keyPath: KeyPath;
|
||||
labelRenderer: LabelRenderer;
|
||||
nodeType: string;
|
||||
value: any;
|
||||
valueGetter?: (value: any) => any;
|
||||
styling: Styling;
|
||||
value: unknown;
|
||||
valueRenderer: ValueRenderer;
|
||||
valueGetter?: (value: any) => unknown;
|
||||
}
|
||||
|
||||
const JSONValueNode: React.FunctionComponent<Props> = ({
|
||||
export default function JSONValueNode({
|
||||
nodeType,
|
||||
styling,
|
||||
labelRenderer,
|
||||
|
@ -20,27 +32,15 @@ const JSONValueNode: React.FunctionComponent<Props> = ({
|
|||
valueRenderer,
|
||||
value,
|
||||
valueGetter = (value) => value,
|
||||
}) => (
|
||||
<li {...styling('value', nodeType, keyPath)}>
|
||||
<label {...styling(['label', 'valueLabel'], nodeType, keyPath)}>
|
||||
{labelRenderer(keyPath, nodeType, false, false)}
|
||||
</label>
|
||||
<span {...styling('valueText', nodeType, keyPath)}>
|
||||
{valueRenderer(valueGetter(value), value, ...keyPath)}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
|
||||
JSONValueNode.propTypes = {
|
||||
nodeType: PropTypes.string.isRequired,
|
||||
styling: PropTypes.func.isRequired,
|
||||
labelRenderer: PropTypes.func.isRequired,
|
||||
keyPath: PropTypes.arrayOf(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
|
||||
).isRequired,
|
||||
valueRenderer: PropTypes.func.isRequired,
|
||||
value: PropTypes.any,
|
||||
valueGetter: PropTypes.func,
|
||||
};
|
||||
|
||||
export default JSONValueNode;
|
||||
}: Props) {
|
||||
return (
|
||||
<li {...styling('value', nodeType, keyPath)}>
|
||||
<label {...styling(['label', 'valueLabel'], nodeType, keyPath)}>
|
||||
{labelRenderer(keyPath, nodeType, false, false)}
|
||||
</label>
|
||||
<span {...styling('valueText', nodeType, keyPath)}>
|
||||
{valueRenderer(valueGetter(value), value, ...keyPath)}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import type { CurriedFunction1 } from 'lodash';
|
||||
import {
|
||||
import { createStyling } from 'react-base16-styling';
|
||||
import type {
|
||||
Base16Theme,
|
||||
createStyling,
|
||||
StylingConfig,
|
||||
StylingFunction,
|
||||
Theme,
|
||||
} from 'react-base16-styling';
|
||||
import solarized from './themes/solarized';
|
||||
import { StylingFunction, Theme } from 'react-base16-styling/src';
|
||||
|
||||
const colorMap = (theme: Base16Theme) => ({
|
||||
BACKGROUND_COLOR: theme.base00,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
function getLength(type: string, collection: any) {
|
||||
import type { SortObjectKeys } from './types';
|
||||
|
||||
function getLength(type: string, collection: unknown) {
|
||||
if (type === 'Object') {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
return Object.keys(collection as {}).length;
|
||||
|
@ -9,17 +11,17 @@ function getLength(type: string, collection: any) {
|
|||
return Infinity;
|
||||
}
|
||||
|
||||
function isIterableMap(collection: any) {
|
||||
return typeof (collection as Map<any, any>).set === 'function';
|
||||
function isIterableMap(collection: unknown) {
|
||||
return typeof (collection as Map<unknown, unknown>).set === 'function';
|
||||
}
|
||||
|
||||
function getEntries(
|
||||
type: string,
|
||||
collection: any,
|
||||
sortObjectKeys?: ((a: any, b: any) => number) | boolean | undefined,
|
||||
sortObjectKeys: SortObjectKeys,
|
||||
from = 0,
|
||||
to = Infinity
|
||||
): { entries: { key: string | number; value: any }[]; hasMore?: boolean } {
|
||||
): { entries: { key: string | number; value: unknown }[]; hasMore?: boolean } {
|
||||
let res;
|
||||
|
||||
if (type === 'Object') {
|
||||
|
@ -95,8 +97,8 @@ function getRanges(from: number, to: number, limit: number) {
|
|||
|
||||
export default function getCollectionEntries(
|
||||
type: string,
|
||||
collection: any,
|
||||
sortObjectKeys: ((a: any, b: any) => number) | boolean | undefined,
|
||||
collection: unknown,
|
||||
sortObjectKeys: SortObjectKeys,
|
||||
limit: number,
|
||||
from = 0,
|
||||
to = Infinity
|
||||
|
|
|
@ -3,177 +3,88 @@
|
|||
// Dave Vedder <veddermatic@gmail.com> http://www.eskimospy.com/
|
||||
// port by Daniele Zannotti http://www.github.com/dzannotti <dzannotti@me.com>
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useMemo } from 'react';
|
||||
import JSONNode from './JSONNode';
|
||||
import createStylingFromTheme from './createStylingFromTheme';
|
||||
import { invertTheme } from 'react-base16-styling';
|
||||
import type { StylingValue, Theme } from 'react-base16-styling';
|
||||
import type {
|
||||
StylingConfig,
|
||||
StylingFunction,
|
||||
StylingValue,
|
||||
Theme,
|
||||
} from 'react-base16-styling';
|
||||
import { CircularPropsPassedThroughJSONTree } from './types';
|
||||
CommonExternalProps,
|
||||
GetItemString,
|
||||
IsCustomNode,
|
||||
LabelRenderer,
|
||||
ShouldExpandNodeInitially,
|
||||
} from './types';
|
||||
|
||||
interface Props extends CircularPropsPassedThroughJSONTree {
|
||||
data: any;
|
||||
interface Props extends Partial<CommonExternalProps> {
|
||||
data: unknown;
|
||||
theme?: Theme;
|
||||
invertTheme: boolean;
|
||||
}
|
||||
|
||||
interface State {
|
||||
styling: StylingFunction;
|
||||
invertTheme?: boolean;
|
||||
}
|
||||
|
||||
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
|
||||
) => (
|
||||
const expandRootNode: ShouldExpandNodeInitially = (keyPath, data, level) =>
|
||||
level === 0;
|
||||
const defaultItemString: GetItemString = (type, data, itemType, itemString) => (
|
||||
<span>
|
||||
{itemType} {itemString}
|
||||
</span>
|
||||
);
|
||||
const defaultLabelRenderer = ([label]: (string | number)[]) => (
|
||||
<span>{label}:</span>
|
||||
);
|
||||
const noCustomNode = () => false;
|
||||
const defaultLabelRenderer: LabelRenderer = ([label]) => <span>{label}:</span>;
|
||||
const noCustomNode: IsCustomNode = () => false;
|
||||
|
||||
function checkLegacyTheming(theme: Theme | undefined, props: Props) {
|
||||
const deprecatedStylingMethodsMap = {
|
||||
getArrowStyle: 'arrow',
|
||||
getListStyle: 'nestedNodeChildren',
|
||||
getItemStringStyle: 'nestedNodeItemString',
|
||||
getLabelStyle: 'label',
|
||||
getValueStyle: 'valueText',
|
||||
};
|
||||
export function JSONTree({
|
||||
data: value,
|
||||
theme,
|
||||
invertTheme: shouldInvertTheme,
|
||||
keyPath = ['root'],
|
||||
labelRenderer = defaultLabelRenderer,
|
||||
valueRenderer = identity,
|
||||
shouldExpandNodeInitially = expandRootNode,
|
||||
hideRoot = false,
|
||||
getItemString = defaultItemString,
|
||||
postprocessValue = identity,
|
||||
isCustomNode = noCustomNode,
|
||||
collectionLimit = 50,
|
||||
sortObjectKeys = false,
|
||||
}: Props) {
|
||||
const styling = useMemo(
|
||||
() =>
|
||||
createStylingFromTheme(shouldInvertTheme ? invertTheme(theme) : theme),
|
||||
[theme, shouldInvertTheme]
|
||||
);
|
||||
|
||||
const deprecatedStylingMethods = Object.keys(
|
||||
deprecatedStylingMethodsMap
|
||||
).filter((name) => props[name as keyof Props]);
|
||||
|
||||
if (deprecatedStylingMethods.length > 0) {
|
||||
if (typeof theme === 'string') {
|
||||
theme = {
|
||||
extend: theme,
|
||||
};
|
||||
} else {
|
||||
theme = { ...theme };
|
||||
}
|
||||
|
||||
deprecatedStylingMethods.forEach((name) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
`Styling method "${name}" is deprecated, use "theme" property instead`
|
||||
);
|
||||
|
||||
(theme as StylingConfig)[
|
||||
deprecatedStylingMethodsMap[
|
||||
name as keyof typeof deprecatedStylingMethodsMap
|
||||
]
|
||||
] = ({ style }, ...args) => ({
|
||||
style: {
|
||||
...style,
|
||||
...props[name as keyof Props](...args),
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return theme;
|
||||
return (
|
||||
<ul {...styling('tree')}>
|
||||
<JSONNode
|
||||
keyPath={hideRoot ? [] : keyPath}
|
||||
value={postprocessValue(value)}
|
||||
isCustomNode={isCustomNode}
|
||||
styling={styling}
|
||||
labelRenderer={labelRenderer}
|
||||
valueRenderer={valueRenderer}
|
||||
shouldExpandNodeInitially={shouldExpandNodeInitially}
|
||||
hideRoot={hideRoot}
|
||||
getItemString={getItemString}
|
||||
postprocessValue={postprocessValue}
|
||||
collectionLimit={collectionLimit}
|
||||
sortObjectKeys={sortObjectKeys}
|
||||
/>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
function getStateFromProps(props: Props) {
|
||||
let theme = checkLegacyTheming(props.theme, props);
|
||||
if (props.invertTheme) {
|
||||
theme = invertTheme(theme);
|
||||
}
|
||||
|
||||
return {
|
||||
styling: createStylingFromTheme(theme),
|
||||
};
|
||||
}
|
||||
|
||||
export class JSONTree extends React.Component<Props, State> {
|
||||
static propTypes = {
|
||||
data: PropTypes.any,
|
||||
hideRoot: PropTypes.bool,
|
||||
theme: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
|
||||
invertTheme: PropTypes.bool,
|
||||
keyPath: PropTypes.arrayOf(
|
||||
PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
||||
),
|
||||
postprocessValue: PropTypes.func,
|
||||
sortObjectKeys: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
shouldExpandNode: expandRootNode,
|
||||
hideRoot: false,
|
||||
keyPath: ['root'],
|
||||
getItemString: defaultItemString,
|
||||
labelRenderer: defaultLabelRenderer,
|
||||
valueRenderer: identity,
|
||||
postprocessValue: identity,
|
||||
isCustomNode: noCustomNode,
|
||||
collectionLimit: 50,
|
||||
invertTheme: true,
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = getStateFromProps(props);
|
||||
}
|
||||
|
||||
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: Props) {
|
||||
return !!Object.keys(nextProps).find((k) =>
|
||||
k === 'keyPath'
|
||||
? nextProps[k].join('/') !== this.props[k].join('/')
|
||||
: nextProps[k as keyof Props] !== this.props[k as keyof Props]
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
data: value,
|
||||
keyPath,
|
||||
postprocessValue,
|
||||
hideRoot,
|
||||
theme, // eslint-disable-line no-unused-vars
|
||||
invertTheme: _, // eslint-disable-line no-unused-vars
|
||||
...rest
|
||||
} = this.props;
|
||||
|
||||
const { styling } = this.state;
|
||||
|
||||
return (
|
||||
<ul {...styling('tree')}>
|
||||
<JSONNode
|
||||
{...{ postprocessValue, hideRoot, styling, ...rest }}
|
||||
keyPath={hideRoot ? [] : keyPath}
|
||||
value={postprocessValue(value)}
|
||||
/>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { StylingValue };
|
||||
export type {
|
||||
Key,
|
||||
KeyPath,
|
||||
GetItemString,
|
||||
LabelRenderer,
|
||||
ValueRenderer,
|
||||
ShouldExpandNodeInitially,
|
||||
PostprocessValue,
|
||||
IsCustomNode,
|
||||
SortObjectKeys,
|
||||
Styling,
|
||||
CommonExternalProps,
|
||||
} from './types';
|
||||
export type { StylingValue };
|
||||
|
|
|
@ -1,81 +1,63 @@
|
|||
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;
|
||||
export type Key = string | number;
|
||||
|
||||
interface JSONNestedNodeCircularPropsPassedThroughJSONTree {
|
||||
shouldExpandNode: (
|
||||
keyPath: (string | number)[],
|
||||
data: any,
|
||||
level: number
|
||||
) => boolean;
|
||||
export type KeyPath = readonly (string | number)[];
|
||||
|
||||
export type GetItemString = (
|
||||
nodeType: string,
|
||||
data: unknown,
|
||||
itemType: React.ReactNode,
|
||||
itemString: string,
|
||||
keyPath: KeyPath
|
||||
) => React.ReactNode;
|
||||
|
||||
export type LabelRenderer = (
|
||||
keyPath: KeyPath,
|
||||
nodeType: string,
|
||||
expanded: boolean,
|
||||
expandable: boolean
|
||||
) => React.ReactNode;
|
||||
|
||||
export type ValueRenderer = (
|
||||
valueAsString: unknown,
|
||||
value: unknown,
|
||||
...keyPath: KeyPath
|
||||
) => React.ReactNode;
|
||||
|
||||
export type ShouldExpandNodeInitially = (
|
||||
keyPath: KeyPath,
|
||||
data: unknown,
|
||||
level: number
|
||||
) => boolean;
|
||||
|
||||
export type PostprocessValue = (value: unknown) => unknown;
|
||||
|
||||
export type IsCustomNode = (value: unknown) => boolean;
|
||||
|
||||
export type SortObjectKeys = ((a: unknown, b: unknown) => number) | boolean;
|
||||
|
||||
export type Styling = StylingFunction;
|
||||
|
||||
export type CircularCache = unknown[];
|
||||
|
||||
export interface CommonExternalProps {
|
||||
keyPath: KeyPath;
|
||||
labelRenderer: LabelRenderer;
|
||||
valueRenderer: ValueRenderer;
|
||||
shouldExpandNodeInitially: ShouldExpandNodeInitially;
|
||||
hideRoot: boolean;
|
||||
getItemString: (
|
||||
nodeType: string,
|
||||
data: any,
|
||||
itemType: React.ReactNode,
|
||||
itemString: string,
|
||||
keyPath: (string | number)[]
|
||||
) => React.ReactNode;
|
||||
postprocessValue: (value: any) => any;
|
||||
isCustomNode: (value: any) => boolean;
|
||||
getItemString: GetItemString;
|
||||
postprocessValue: PostprocessValue;
|
||||
isCustomNode: IsCustomNode;
|
||||
collectionLimit: number;
|
||||
sortObjectKeys?: ((a: any, b: any) => number) | boolean;
|
||||
sortObjectKeys: SortObjectKeys;
|
||||
}
|
||||
export type CircularPropsPassedThroughJSONTree =
|
||||
SharedCircularPropsPassedThroughJSONTree &
|
||||
JSONValueNodeCircularPropsPassedThroughJSONTree &
|
||||
JSONNestedNodeCircularPropsPassedThroughJSONTree;
|
||||
|
||||
interface JSONNestedNodeCircularPropsPassedThroughJSONNode
|
||||
extends JSONNestedNodeCircularPropsPassedThroughJSONTree {
|
||||
circularCache?: any[];
|
||||
isCircular?: boolean;
|
||||
export interface CommonInternalProps extends CommonExternalProps {
|
||||
styling: StylingFunction;
|
||||
circularCache?: CircularCache;
|
||||
level?: number;
|
||||
isCircular?: boolean;
|
||||
}
|
||||
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,5 +1,17 @@
|
|||
# Change Log
|
||||
|
||||
## 2.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b323f77d]
|
||||
- Updated dependencies [b323f77d]
|
||||
- d3-state-visualizer@2.0.0
|
||||
- @redux-devtools/chart-monitor@4.0.0
|
||||
- @redux-devtools/inspector-monitor@3.0.2
|
||||
- @redux-devtools/log-monitor@4.0.2
|
||||
- @redux-devtools/rtk-query-monitor@3.1.1
|
||||
|
||||
## 2.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
|
|
@ -6,7 +6,10 @@ module.exports = {
|
|||
'\\.css$': '<rootDir>/test/__mocks__/styleMock.ts',
|
||||
},
|
||||
transform: {
|
||||
'^.+\\.jsx?$': 'babel-jest',
|
||||
'^.+\\.tsx?$': ['ts-jest', { tsconfig: 'tsconfig.test.json' }],
|
||||
},
|
||||
resolver: '<rootDir>/jestResolver.js',
|
||||
transformIgnorePatterns: [
|
||||
'node_modules/(?!.pnpm|d3|dateformat|delaunator|internmap|nanoid|robust-predicates|uuid)',
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
module.exports = (path, options) => {
|
||||
return options.defaultResolver(path, {
|
||||
...options,
|
||||
packageFilter: (pkg) => {
|
||||
if (pkg.name === 'nanoid') {
|
||||
pkg.exports['.'].browser = pkg.exports['.'].require;
|
||||
}
|
||||
if (pkg.name === 'uuid' && pkg.version.startsWith('8.')) {
|
||||
delete pkg.exports;
|
||||
delete pkg.module;
|
||||
}
|
||||
return pkg;
|
||||
},
|
||||
});
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@redux-devtools/app",
|
||||
"version": "2.2.0",
|
||||
"version": "2.2.1",
|
||||
"description": "Redux DevTools app",
|
||||
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-app",
|
||||
"bugs": {
|
||||
|
@ -40,19 +40,19 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint && pnpm run test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@redux-devtools/chart-monitor": "^3.0.0",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@redux-devtools/chart-monitor": "^4.0.0",
|
||||
"@redux-devtools/core": "^3.13.0",
|
||||
"@redux-devtools/inspector-monitor": "^3.0.0",
|
||||
"@redux-devtools/inspector-monitor": "^3.0.2",
|
||||
"@redux-devtools/inspector-monitor-test-tab": "^1.0.0",
|
||||
"@redux-devtools/inspector-monitor-trace-tab": "^1.0.0",
|
||||
"@redux-devtools/log-monitor": "^4.0.0",
|
||||
"@redux-devtools/rtk-query-monitor": "^3.0.0",
|
||||
"@redux-devtools/log-monitor": "^4.0.2",
|
||||
"@redux-devtools/rtk-query-monitor": "^3.1.1",
|
||||
"@redux-devtools/slider-monitor": "^4.0.0",
|
||||
"@redux-devtools/ui": "^1.3.0",
|
||||
"@reduxjs/toolkit": "^1.9.1",
|
||||
"@reduxjs/toolkit": "^1.9.3",
|
||||
"@types/prop-types": "^15.7.5",
|
||||
"d3-state-visualizer": "^1.6.0",
|
||||
"d3-state-visualizer": "^2.0.0",
|
||||
"javascript-stringify": "^2.1.0",
|
||||
"jsan": "^3.1.14",
|
||||
"jsondiffpatch": "^0.4.1",
|
||||
|
@ -63,55 +63,55 @@
|
|||
"react-icons": "^4.7.1",
|
||||
"react-is": "^18.2.0",
|
||||
"react-redux": "^8.0.5",
|
||||
"redux": "^4.2.0",
|
||||
"redux": "^4.2.1",
|
||||
"redux-persist": "^6.0.0",
|
||||
"socketcluster-client": "^17.1.0"
|
||||
"socketcluster-client": "^17.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/plugin-transform-runtime": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@rjsf/core": "^4.2.3",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@types/jest": "^29.2.4",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/jsan": "^3.1.2",
|
||||
"@types/json-schema": "^7.0.11",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/node": "^18.11.17",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@types/node": "^18.14.4",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/socketcluster-client": "^16.0.0",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"@types/testing-library__jest-dom": "^5.14.5",
|
||||
"@types/webpack-env": "^1.18.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"babel-loader": "^9.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^6.7.3",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-jest": "^27.1.7",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"fork-ts-checker-webpack-plugin": "^7.2.14",
|
||||
"fork-ts-checker-webpack-plugin": "^8.0.0",
|
||||
"html-loader": "^4.2.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"jest": "^29.3.1",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"jest": "^29.4.3",
|
||||
"jest-environment-jsdom": "^29.4.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"rimraf": "^4.1.3",
|
||||
"style-loader": "^3.3.1",
|
||||
"styled-components": "^5.3.6",
|
||||
"ts-jest": "^29.0.3",
|
||||
"styled-components": "^5.3.8",
|
||||
"ts-jest": "^29.0.5",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "~4.9.4",
|
||||
"typescript": "~4.9.5",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.11.1"
|
||||
|
@ -120,6 +120,6 @@
|
|||
"@types/react": "^16.3.0 || ^17.0.0 || ^18.0.0",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"react": "^16.3.0 || ^17.0.0 || ^18.0.0",
|
||||
"styled-components": "^5.3.6"
|
||||
"styled-components": "^5.3.8"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import React, { Component } from 'react';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { ChartMonitor } from '@redux-devtools/chart-monitor';
|
||||
import { NodeWithId } from 'd3-state-visualizer';
|
||||
import type { HierarchyPointNode, Node } from 'd3-state-visualizer';
|
||||
import { selectMonitorWithState } from '../../actions';
|
||||
|
||||
export function getPath(obj: NodeWithId, inspectedStatePath: string[]) {
|
||||
export function getPath(
|
||||
obj: HierarchyPointNode<Node>,
|
||||
inspectedStatePath: string[]
|
||||
) {
|
||||
const parent = obj.parent;
|
||||
if (!parent) return;
|
||||
getPath(parent, inspectedStatePath);
|
||||
let name = obj.name;
|
||||
let name = obj.data.name;
|
||||
const item = /.+\[(\d+)]/.exec(name);
|
||||
if (item) name = item[1];
|
||||
inspectedStatePath.push(name);
|
||||
|
@ -20,7 +23,7 @@ type Props = DispatchProps;
|
|||
class ChartMonitorWrapper extends Component<Props> {
|
||||
static update = ChartMonitor.update;
|
||||
|
||||
onClickText = (data: NodeWithId) => {
|
||||
onClickText = (data: HierarchyPointNode<Node>) => {
|
||||
const inspectedStatePath: string[] = [];
|
||||
getPath(data, inspectedStatePath);
|
||||
this.props.selectMonitorWithState('InspectorMonitor', {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import React, { Component, RefCallback } from 'react';
|
||||
import { connect, ResolveThunks } from 'react-redux';
|
||||
import { withTheme } from 'styled-components';
|
||||
import { InputOptions, NodeWithId, tree } from 'd3-state-visualizer';
|
||||
import { tree } from 'd3-state-visualizer';
|
||||
import type { HierarchyPointNode, Node, Options } from 'd3-state-visualizer';
|
||||
import { getPath } from '../ChartMonitorWrapper';
|
||||
import { updateMonitorState } from '../../../actions';
|
||||
import { ThemeFromProvider } from '@redux-devtools/ui';
|
||||
|
@ -54,12 +55,12 @@ class ChartTab extends Component<Props> {
|
|||
this.renderChart(props.data as {} | null | undefined);
|
||||
}
|
||||
|
||||
getChartTheme(theme: ThemeFromProvider): Partial<InputOptions> {
|
||||
getChartTheme(theme: ThemeFromProvider): Partial<Options> {
|
||||
return {
|
||||
heightBetweenNodesCoeff: 1,
|
||||
widthBetweenNodesCoeff: 1.3,
|
||||
tooltipOptions: {
|
||||
style: {
|
||||
styles: {
|
||||
color: theme.base06,
|
||||
'background-color': theme.base01,
|
||||
opacity: '0.9',
|
||||
|
@ -69,29 +70,29 @@ class ChartTab extends Component<Props> {
|
|||
offset: { left: 30, top: 10 },
|
||||
indentationSize: 2,
|
||||
},
|
||||
style: {
|
||||
chartStyles: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
node: {
|
||||
colors: {
|
||||
default: theme.base0B,
|
||||
collapsed: theme.base0B,
|
||||
parent: theme.base0E,
|
||||
},
|
||||
radius: 7,
|
||||
} as unknown as string,
|
||||
text: {
|
||||
colors: {
|
||||
default: theme.base0D,
|
||||
hover: theme.base06,
|
||||
},
|
||||
} as unknown as string,
|
||||
},
|
||||
nodeStyleOptions: {
|
||||
colors: {
|
||||
default: theme.base0B,
|
||||
collapsed: theme.base0B,
|
||||
parent: theme.base0E,
|
||||
},
|
||||
radius: 7,
|
||||
},
|
||||
textStyleOptions: {
|
||||
colors: {
|
||||
default: theme.base0D,
|
||||
hover: theme.base06,
|
||||
},
|
||||
},
|
||||
onClickText: this.onClickText,
|
||||
};
|
||||
}
|
||||
|
||||
onClickText = (data: NodeWithId) => {
|
||||
onClickText = (data: HierarchyPointNode<Node>) => {
|
||||
const inspectedStatePath: string[] = [];
|
||||
getPath(data, inspectedStatePath);
|
||||
this.props.updateMonitorState({
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
# Change Log
|
||||
|
||||
## 4.0.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- b323f77d: Upgrade D3
|
||||
|
||||
- Split `style` option into `chartStyles`, `nodeStyleOptions`, `textStyleOptions`, and `linkStyles`.
|
||||
- The shape of the argument passed to the `onClickText` option has been updated.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b323f77d]
|
||||
- d3-state-visualizer@2.0.0
|
||||
|
||||
## 3.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -47,16 +47,18 @@ Consult the [`DockMonitor` README](https://github.com/reduxjs/redux-devtools/tre
|
|||
|
||||
You can read the React component [propTypes](https://github.com/reduxjs/redux-devtools/blob/master/packages/redux-devtools-chart-monitor/src/Chart.js#L11) in addition to the details below:
|
||||
|
||||
| Name | Description |
|
||||
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `defaultIsVisible` | By default, set to `true`. |
|
||||
| `transitionDuration` | By default, set to `750`, in milliseconds. |
|
||||
| `heightBetweenNodesCoeff` | By default, set to `1`. |
|
||||
| `widthBetweenNodesCoeff` | By default, set to `1.3`. |
|
||||
| `isSorted` | By default, set to `false`. |
|
||||
| `style` | {<br> width: '100%', height: '100%', // i.e fullscreen for [`DockMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor)<br> text: {<br> colors: {<br> 'default': `theme.base0D`,<br> hover: `theme.base06`<br> }<br> },<br> node: {<br> colors: {<br> 'default': `theme.base0B`,<br> collapsed: `theme.base0B`,<br> parent: `theme.base0E`<br> },<br> radius: 7<br> }<br>} |
|
||||
| `onClickText` | Function called with a reference to the clicked node as first argument when clicking on the text next to a node. |
|
||||
| `tooltipOptions` | {<br> disabled: false,<br> indentationSize: 2,<br> style: {<br> 'background-color': `theme.base06`,<br> 'opacity': '0.7',<br> 'border-radius': '5px',<br> 'padding': '5px'<br> }<br>}<br>[More info](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip#api). |
|
||||
| Name | Description |
|
||||
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `defaultIsVisible` | By default, set to `true`. |
|
||||
| `transitionDuration` | By default, set to `750`, in milliseconds. |
|
||||
| `heightBetweenNodesCoeff` | By default, set to `1`. |
|
||||
| `widthBetweenNodesCoeff` | By default, set to `1.3`. |
|
||||
| `isSorted` | By default, set to `false`. |
|
||||
| `chartStyles` | {<br> width: '100%', height: '100%', // i.e fullscreen for [`DockMonitor`](https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-dock-monitor)<br>} |
|
||||
| `textStyleOptions` | {<br> colors: {<br> default: `theme.base0D`,<br> hover: `theme.base06`,<br> },<br>} |
|
||||
| `nodeStyleOptions` | {<br> colors: {<br> default: `theme.base0B`,<br> collapsed: `theme.base0B`,<br> parent: `theme.base0E`,<br> },<br> radius: 7,<br>} |
|
||||
| `onClickText` | Function called with a reference to the clicked node as first argument when clicking on the text next to a node. |
|
||||
| `tooltipOptions` | {<br> disabled: false,<br> indentationSize: 2,<br> styles: {<br> 'background-color': `theme.base06`,<br> 'opacity': '0.7',<br> 'border-radius': '5px',<br> 'padding': '5px',<br> },<br>}<br>[More info](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip#api). |
|
||||
|
||||
#### Redux DevTools props
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@redux-devtools/chart-monitor",
|
||||
"version": "3.0.1",
|
||||
"version": "4.0.0",
|
||||
"description": "Chart monitor for Redux DevTools",
|
||||
"keywords": [
|
||||
"redux",
|
||||
|
@ -39,34 +39,32 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@types/prop-types": "^15.7.5",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@types/redux-devtools-themes": "^1.0.0",
|
||||
"d3-state-visualizer": "^1.6.0",
|
||||
"deepmerge": "^4.2.2",
|
||||
"prop-types": "^15.8.1",
|
||||
"d3-state-visualizer": "^2.0.0",
|
||||
"deepmerge": "^4.3.0",
|
||||
"redux-devtools-themes": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/plugin-transform-runtime": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@redux-devtools/core": "^3.13.1",
|
||||
"@types/react": "^18.0.26",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"@types/react": "^18.0.28",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"react": "^18.2.0",
|
||||
"redux": "^4.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "~4.9.4"
|
||||
"redux": "^4.2.1",
|
||||
"rimraf": "^4.1.3",
|
||||
"typescript": "~4.9.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redux-devtools/core": "^3.13.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React, { Component, createRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { tree, NodeWithId, Primitive } from 'd3-state-visualizer';
|
||||
import { tree } from 'd3-state-visualizer';
|
||||
import type { Options } from 'd3-state-visualizer';
|
||||
import { Action, Dispatch } from 'redux';
|
||||
import { LiftedAction, LiftedState } from '@redux-devtools/core';
|
||||
import * as themes from 'redux-devtools-themes';
|
||||
|
@ -12,7 +12,8 @@ const wrapperStyle = {
|
|||
};
|
||||
|
||||
export interface Props<S, A extends Action<unknown>>
|
||||
extends LiftedState<S, A, ChartMonitorState> {
|
||||
extends LiftedState<S, A, ChartMonitorState>,
|
||||
Options {
|
||||
dispatch: Dispatch<LiftedAction<S, A, ChartMonitorState>>;
|
||||
preserveScrollTop: boolean;
|
||||
select: (state: S) => unknown;
|
||||
|
@ -20,76 +21,10 @@ export interface Props<S, A extends Action<unknown>>
|
|||
invertTheme: boolean;
|
||||
|
||||
state: S | null;
|
||||
isSorted: boolean;
|
||||
heightBetweenNodesCoeff: number;
|
||||
widthBetweenNodesCoeff: number;
|
||||
onClickText: (datum: NodeWithId) => void;
|
||||
tooltipOptions: {
|
||||
disabled: boolean;
|
||||
offset: {
|
||||
left: number;
|
||||
top: number;
|
||||
};
|
||||
indentationSize: number;
|
||||
style: { [key: string]: Primitive } | undefined;
|
||||
};
|
||||
style: { [key: string]: Primitive } | undefined;
|
||||
defaultIsVisible?: boolean;
|
||||
}
|
||||
|
||||
class Chart<S, A extends Action<unknown>> extends Component<Props<S, A>> {
|
||||
static propTypes = {
|
||||
state: PropTypes.object,
|
||||
rootKeyName: PropTypes.string,
|
||||
pushMethod: PropTypes.oneOf(['push', 'unshift']),
|
||||
tree: PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
children: PropTypes.array,
|
||||
}),
|
||||
id: PropTypes.string,
|
||||
style: PropTypes.shape({
|
||||
node: PropTypes.shape({
|
||||
colors: PropTypes.shape({
|
||||
default: PropTypes.string,
|
||||
parent: PropTypes.string,
|
||||
collapsed: PropTypes.string,
|
||||
}),
|
||||
radius: PropTypes.number,
|
||||
}),
|
||||
text: PropTypes.shape({
|
||||
colors: PropTypes.shape({
|
||||
default: PropTypes.string,
|
||||
hover: PropTypes.string,
|
||||
}),
|
||||
}),
|
||||
link: PropTypes.object,
|
||||
}),
|
||||
size: PropTypes.number,
|
||||
aspectRatio: PropTypes.number,
|
||||
margin: PropTypes.shape({
|
||||
top: PropTypes.number,
|
||||
right: PropTypes.number,
|
||||
bottom: PropTypes.number,
|
||||
left: PropTypes.number,
|
||||
}),
|
||||
isSorted: PropTypes.bool,
|
||||
heightBetweenNodesCoeff: PropTypes.number,
|
||||
widthBetweenNodesCoeff: PropTypes.number,
|
||||
transitionDuration: PropTypes.number,
|
||||
onClickText: PropTypes.func,
|
||||
tooltipOptions: PropTypes.shape({
|
||||
disabled: PropTypes.bool,
|
||||
left: PropTypes.number,
|
||||
top: PropTypes.number,
|
||||
offset: PropTypes.shape({
|
||||
left: PropTypes.number,
|
||||
top: PropTypes.number,
|
||||
}),
|
||||
indentationSize: PropTypes.number,
|
||||
style: PropTypes.object,
|
||||
}),
|
||||
};
|
||||
|
||||
divRef = createRef<HTMLDivElement>();
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
renderChart?: (state?: {} | null | undefined) => void;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import React, { CSSProperties, PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import * as themes from 'redux-devtools-themes';
|
||||
import {
|
||||
ActionCreators,
|
||||
|
@ -8,7 +7,7 @@ import {
|
|||
} from '@redux-devtools/core';
|
||||
import deepmerge from 'deepmerge';
|
||||
import { Action, Dispatch } from 'redux';
|
||||
import { NodeWithId, Primitive } from 'd3-state-visualizer';
|
||||
import type { Options } from 'd3-state-visualizer';
|
||||
|
||||
import reducer, { ChartMonitorState } from './reducers';
|
||||
import Chart, { Props } from './Chart';
|
||||
|
@ -41,37 +40,14 @@ function invertColors(theme: themes.Base16Theme) {
|
|||
}
|
||||
|
||||
export interface ChartMonitorProps<S, A extends Action<unknown>>
|
||||
extends LiftedState<S, A, ChartMonitorState> {
|
||||
extends LiftedState<S, A, ChartMonitorState>,
|
||||
Options {
|
||||
dispatch: Dispatch<LiftedAction<S, A, ChartMonitorState>>;
|
||||
preserveScrollTop: boolean;
|
||||
select: (state: S) => unknown;
|
||||
theme: keyof typeof themes | themes.Base16Theme;
|
||||
invertTheme: boolean;
|
||||
|
||||
state: S | null;
|
||||
isSorted: boolean;
|
||||
heightBetweenNodesCoeff: number;
|
||||
widthBetweenNodesCoeff: number;
|
||||
onClickText: (datum: NodeWithId) => void;
|
||||
tooltipOptions: unknown;
|
||||
style: {
|
||||
width: number;
|
||||
height: number;
|
||||
node: {
|
||||
colors: {
|
||||
default: string;
|
||||
collapsed: string;
|
||||
parent: string;
|
||||
};
|
||||
radius: number;
|
||||
};
|
||||
text: {
|
||||
colors: {
|
||||
default: string;
|
||||
hover: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
defaultIsVisible?: boolean;
|
||||
}
|
||||
|
||||
|
@ -80,23 +56,6 @@ class ChartMonitor<S, A extends Action<unknown>> extends PureComponent<
|
|||
> {
|
||||
static update = reducer;
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func,
|
||||
computedStates: PropTypes.array,
|
||||
currentStateIndex: PropTypes.number,
|
||||
actionsById: PropTypes.object,
|
||||
stagedActionIds: PropTypes.array,
|
||||
skippedActionIds: PropTypes.array,
|
||||
monitorState: PropTypes.shape({
|
||||
initialScrollTop: PropTypes.number,
|
||||
}),
|
||||
|
||||
preserveScrollTop: PropTypes.bool,
|
||||
select: PropTypes.func.isRequired,
|
||||
theme: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
|
||||
invertTheme: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
select: (state: unknown) => state,
|
||||
theme: 'nicinabox',
|
||||
|
@ -140,45 +99,10 @@ class ChartMonitor<S, A extends Action<unknown>> extends PureComponent<
|
|||
return invertTheme ? invertColors(themes.nicinabox) : themes.nicinabox;
|
||||
}
|
||||
|
||||
getChartStyle() {
|
||||
const theme = this.getTheme();
|
||||
|
||||
return {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
node: {
|
||||
colors: {
|
||||
default: theme.base0B,
|
||||
collapsed: theme.base0B,
|
||||
parent: theme.base0E,
|
||||
},
|
||||
radius: 7,
|
||||
},
|
||||
text: {
|
||||
colors: {
|
||||
default: theme.base0D,
|
||||
hover: theme.base06,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
getChartOptions(props = this.props): Props<S, A> {
|
||||
const { computedStates } = props;
|
||||
const theme = this.getTheme();
|
||||
|
||||
const tooltipOptions = {
|
||||
disabled: false,
|
||||
offset: { left: 30, top: 10 },
|
||||
indentationSize: 2,
|
||||
style: {
|
||||
'background-color': theme.base06,
|
||||
opacity: '0.7',
|
||||
'border-radius': '5px',
|
||||
padding: '5px',
|
||||
},
|
||||
};
|
||||
|
||||
const defaultOptions = {
|
||||
state: computedStates.length
|
||||
? computedStates[props.currentStateIndex].state
|
||||
|
@ -186,10 +110,35 @@ class ChartMonitor<S, A extends Action<unknown>> extends PureComponent<
|
|||
isSorted: false,
|
||||
heightBetweenNodesCoeff: 1,
|
||||
widthBetweenNodesCoeff: 1.3,
|
||||
tooltipOptions,
|
||||
style: this.getChartStyle() as unknown as
|
||||
| { [key: string]: Primitive }
|
||||
| undefined,
|
||||
tooltipOptions: {
|
||||
disabled: false,
|
||||
offset: { left: 30, top: 10 },
|
||||
indentationSize: 2,
|
||||
styles: {
|
||||
'background-color': theme.base06,
|
||||
opacity: '0.7',
|
||||
'border-radius': '5px',
|
||||
padding: '5px',
|
||||
},
|
||||
},
|
||||
chartStyles: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
nodeStyleOptions: {
|
||||
colors: {
|
||||
default: theme.base0B,
|
||||
collapsed: theme.base0B,
|
||||
parent: theme.base0E,
|
||||
},
|
||||
radius: 7,
|
||||
},
|
||||
textStyleOptions: {
|
||||
colors: {
|
||||
default: theme.base0D,
|
||||
hover: theme.base06,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return deepmerge(defaultOptions, props);
|
||||
|
@ -198,10 +147,9 @@ class ChartMonitor<S, A extends Action<unknown>> extends PureComponent<
|
|||
render() {
|
||||
const theme = this.getTheme();
|
||||
|
||||
const ChartAsAny = Chart as any;
|
||||
return (
|
||||
<div style={{ ...styles.container, backgroundColor: theme.base07 }}>
|
||||
<ChartAsAny {...this.getChartOptions()} />
|
||||
<Chart {...this.getChartOptions()} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
# Change Log
|
||||
|
||||
## 2.0.0
|
||||
|
||||
### Major Changes
|
||||
|
||||
- 7e129988: Convert @redux-devtools/cli to ESM. Please [read this](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c) for more info about ESM.
|
||||
Update supported Node versions from `>=14.15.0` to `^14.13.1 || ^16.13.0 || >=18.12.0`.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a7729dae: Updates `--open` flag to respect protocol and host when provided
|
||||
|
||||
## 1.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -9,7 +9,11 @@ function createWindow() {
|
|||
height: 600,
|
||||
});
|
||||
|
||||
mainWindow.loadURL('http://localhost:' + (argv.port ? argv.port : 8000));
|
||||
const port = argv.port ? argv.port : 8000;
|
||||
const host = argv.host ? argv.host : 'localhost';
|
||||
const protocol = argv.protocol ? argv.protocol : 'http';
|
||||
|
||||
mainWindow.loadURL(protocol + '://' + host + ':' + port);
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#! /usr/bin/env node
|
||||
|
||||
require('../dist/bin/redux-devtools.js');
|
||||
import '../dist/bin/redux-devtools.js';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module.exports = {
|
||||
export default {
|
||||
preset: 'ts-jest',
|
||||
transform: {
|
||||
'^.+\\.tsx?$': ['ts-jest', { tsconfig: 'tsconfig.test.json' }],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@redux-devtools/cli",
|
||||
"version": "1.0.7",
|
||||
"version": "2.0.0",
|
||||
"description": "CLI for remote debugging with Redux DevTools.",
|
||||
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-cli",
|
||||
"bugs": {
|
||||
|
@ -16,6 +16,7 @@
|
|||
"index.js",
|
||||
"defaultDbOptions.json"
|
||||
],
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"bin": {
|
||||
|
@ -37,61 +38,61 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint && pnpm run test"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.15.0"
|
||||
"node": "^14.13.1 || ^16.13.0 || >= 18.12.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/server": "^4.4.0",
|
||||
"@redux-devtools/app": "^2.1.3",
|
||||
"@types/react": "^18.0.26",
|
||||
"apollo-server-express": "^3.11.1",
|
||||
"body-parser": "^1.20.1",
|
||||
"chalk": "^4.1.2",
|
||||
"@types/react": "^18.0.28",
|
||||
"body-parser": "^1.20.2",
|
||||
"chalk": "^5.2.0",
|
||||
"cors": "^2.8.5",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"electron": "^22.0.0",
|
||||
"electron": "^23.1.1",
|
||||
"express": "^4.18.2",
|
||||
"getport": "^0.1.0",
|
||||
"get-port": "^6.1.2",
|
||||
"graphql": "^16.6.0",
|
||||
"knex": "^2.3.0",
|
||||
"lodash": "^4.17.21",
|
||||
"minimist": "^1.2.7",
|
||||
"knex": "^2.4.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"minimist": "^1.2.8",
|
||||
"morgan": "^1.10.0",
|
||||
"open": "^8.4.0",
|
||||
"open": "^8.4.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-is": "^18.2.0",
|
||||
"semver": "^7.3.8",
|
||||
"socketcluster-server": "^17.2.0",
|
||||
"socketcluster-server": "^17.3.1",
|
||||
"sqlite3": "^5.1.4",
|
||||
"styled-components": "^5.3.6",
|
||||
"styled-components": "^5.3.8",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/body-parser": "^1.19.2",
|
||||
"@types/cors": "^2.8.13",
|
||||
"@types/cross-spawn": "^6.0.2",
|
||||
"@types/express": "^4.17.15",
|
||||
"@types/jest": "^29.2.4",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/lodash-es": "^4.17.6",
|
||||
"@types/minimist": "^1.2.2",
|
||||
"@types/morgan": "^1.9.3",
|
||||
"@types/node": "^18.11.17",
|
||||
"@types/morgan": "^1.9.4",
|
||||
"@types/node": "^18.14.4",
|
||||
"@types/semver": "^7.3.13",
|
||||
"@types/socketcluster-client": "^16.0.0",
|
||||
"@types/socketcluster-server": "^16.1.0",
|
||||
"@types/socketcluster-server": "^17.3.0",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-jest": "^27.1.7",
|
||||
"jest": "^29.3.1",
|
||||
"@types/uuid": "^9.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"jest": "^29.4.3",
|
||||
"ncp": "^2.0.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"socketcluster-client": "^17.1.0",
|
||||
"rimraf": "^4.1.3",
|
||||
"socketcluster-client": "^17.1.1",
|
||||
"supertest": "^6.3.3",
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "~4.9.4"
|
||||
"ts-jest": "^29.0.5",
|
||||
"typescript": "~4.9.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import fs from 'fs';
|
||||
import { Store } from '../store';
|
||||
import type { Store } from '../store.js';
|
||||
|
||||
export const schema = fs
|
||||
.readFileSync(require.resolve('./schema_def.graphql'))
|
||||
.toString();
|
||||
export const schema = fs.readFileSync(
|
||||
new URL('./schema_def.graphql', import.meta.url),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
export const resolvers = {
|
||||
Query: {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import semver from 'semver';
|
||||
import { Options } from '../options';
|
||||
import type { Options } from '../options.js';
|
||||
|
||||
const name = '@redux-devtools/cli';
|
||||
const startFlag = '/* ' + name + ' start */';
|
||||
|
@ -56,7 +56,7 @@ export function inject(
|
|||
startFlag,
|
||||
' require("' + name + '")(' + JSON.stringify(options) + ')',
|
||||
' .then(_remotedev =>',
|
||||
' _remotedev.on("ready", () => {',
|
||||
' _remotedev.ready.then(() => {',
|
||||
' if (!_remotedev.portAlreadyUsed) console.log("-".repeat(80));',
|
||||
' ' + serverFlag,
|
||||
' })',
|
||||
|
|
|
@ -1,16 +1,30 @@
|
|||
import open from 'open';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { createRequire } from 'module';
|
||||
import spawn from 'cross-spawn';
|
||||
import { Options } from '../options';
|
||||
import type { Options } from '../options.js';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
export default async function openApp(app: true | string, options: Options) {
|
||||
if (app === true || app === 'electron') {
|
||||
try {
|
||||
const port = options.port ? `--port=${options.port}` : '';
|
||||
const host = options.host ? `--host=${options.host}` : '';
|
||||
const protocol = options.protocol ? `--protocol=${options.protocol}` : '';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
spawn.sync(require('electron') as string, [
|
||||
path.join(__dirname, '..', '..', 'app'),
|
||||
spawn(require('electron') as string, [
|
||||
path.join(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'..',
|
||||
'..',
|
||||
'app'
|
||||
),
|
||||
port,
|
||||
host,
|
||||
protocol,
|
||||
]);
|
||||
} catch (error) {
|
||||
/* eslint-disable no-console */
|
||||
|
@ -33,7 +47,7 @@ export default async function openApp(app: true | string, options: Options) {
|
|||
}
|
||||
|
||||
await open(
|
||||
`http://localhost:${options.port}/`,
|
||||
`${options.protocol}://${options.host ?? 'localhost'}:${options.port}/`,
|
||||
app !== 'browser' ? { app: { name: app } } : undefined
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@ import fs from 'fs';
|
|||
import path from 'path';
|
||||
import parseArgs from 'minimist';
|
||||
import chalk from 'chalk';
|
||||
import * as injectServer from './injectServer';
|
||||
import getOptions from '../options';
|
||||
import server from '../index';
|
||||
import openApp from './openApp';
|
||||
import * as injectServer from './injectServer.js';
|
||||
import getOptions from '../options.js';
|
||||
import server from '../index.js';
|
||||
import openApp from './openApp.js';
|
||||
|
||||
const argv = parseArgs(process.argv.slice(2));
|
||||
|
||||
|
@ -87,10 +87,8 @@ if (argv.injectserver) {
|
|||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
server(argv).then(async function (r) {
|
||||
if (argv.open && argv.open !== 'false') {
|
||||
await r.listener('ready').once();
|
||||
await openApp(argv.open as string, options);
|
||||
}
|
||||
});
|
||||
const response = await server(argv);
|
||||
if (argv.open && argv.open !== 'false') {
|
||||
await response.ready;
|
||||
await openApp(argv.open as string, options);
|
||||
}
|
||||
|
|
|
@ -1,23 +1,37 @@
|
|||
import path from 'path';
|
||||
import knexModule, { Knex } from 'knex';
|
||||
import { fileURLToPath } from 'url';
|
||||
import knex from 'knex';
|
||||
import type { Knex } from 'knex';
|
||||
import { AGServer } from 'socketcluster-server';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
type KnexFunction = <TRecord extends {} = any, TResult = unknown[]>(
|
||||
config: Knex.Config | string
|
||||
) => Knex<TRecord, TResult>;
|
||||
|
||||
export default function connector(options: AGServer.AGServerOptions) {
|
||||
const dbOptions = options.dbOptions as Knex.Config;
|
||||
dbOptions.useNullAsDefault = true;
|
||||
if (!(dbOptions as any).migrate) {
|
||||
return knexModule(dbOptions);
|
||||
return (knex as unknown as KnexFunction)(dbOptions);
|
||||
}
|
||||
|
||||
dbOptions.migrations = { directory: path.resolve(__dirname, 'migrations') };
|
||||
dbOptions.seeds = { directory: path.resolve(__dirname, 'seeds') };
|
||||
const knex = knexModule(dbOptions);
|
||||
dbOptions.migrations = {
|
||||
directory: path.join(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'migrations'
|
||||
),
|
||||
};
|
||||
dbOptions.seeds = {
|
||||
directory: path.join(path.dirname(fileURLToPath(import.meta.url)), 'seeds'),
|
||||
};
|
||||
const knexInstance = (knex as unknown as KnexFunction)(dbOptions);
|
||||
|
||||
/* eslint-disable no-console */
|
||||
knex.migrate
|
||||
knexInstance.migrate
|
||||
.latest({ loadExtensions: ['.js'] })
|
||||
.then(function () {
|
||||
return knex.seed.run({ loadExtensions: ['.js'] });
|
||||
return knexInstance.seed.run({ loadExtensions: ['.js'] });
|
||||
})
|
||||
.then(function () {
|
||||
console.log(' \x1b[0;32m[Done]\x1b[0m Migrations are finished\n');
|
||||
|
@ -27,5 +41,5 @@ export default function connector(options: AGServer.AGServerOptions) {
|
|||
});
|
||||
/* eslint-enable no-console */
|
||||
|
||||
return knex;
|
||||
return knexInstance;
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
declare module 'getport' {
|
||||
export default function getport(
|
||||
start: number,
|
||||
callback: (e: Error | undefined, port: number) => void
|
||||
): void;
|
||||
}
|
|
@ -1,23 +1,19 @@
|
|||
import express from 'express';
|
||||
import http from 'http';
|
||||
import getPort from 'getport';
|
||||
import getPort from 'get-port';
|
||||
import socketClusterServer from 'socketcluster-server';
|
||||
import getOptions, { Options } from './options';
|
||||
import routes from './routes';
|
||||
import createStore from './store';
|
||||
import getOptions from './options.js';
|
||||
import routes from './routes.js';
|
||||
import createStore from './store.js';
|
||||
|
||||
// var LOG_LEVEL_NONE = 0;
|
||||
const LOG_LEVEL_ERROR = 1;
|
||||
// const LOG_LEVEL_NONE = 0;
|
||||
// const LOG_LEVEL_ERROR = 1;
|
||||
const LOG_LEVEL_WARN = 2;
|
||||
const LOG_LEVEL_INFO = 3;
|
||||
|
||||
export interface ExtendedOptions extends Options {
|
||||
allowClientPublish: boolean;
|
||||
}
|
||||
|
||||
export default function (argv: { [arg: string]: any }): Promise<{
|
||||
export default async function (argv: { [arg: string]: any }): Promise<{
|
||||
portAlreadyUsed?: boolean;
|
||||
listener: (eventName: 'ready') => { once(): Promise<void> };
|
||||
ready: Promise<void>;
|
||||
}> {
|
||||
const options = Object.assign(getOptions(argv), {
|
||||
allowClientPublish: false,
|
||||
|
@ -25,131 +21,117 @@ export default function (argv: { [arg: string]: any }): Promise<{
|
|||
const port = options.port;
|
||||
const logLevel =
|
||||
options.logLevel === undefined ? LOG_LEVEL_INFO : options.logLevel;
|
||||
return new Promise(function (resolve) {
|
||||
// Check port already used
|
||||
getPort(port, function (err, p) {
|
||||
/* eslint-disable no-console */
|
||||
if (err) {
|
||||
if (logLevel >= LOG_LEVEL_ERROR) {
|
||||
console.error(err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (port !== p) {
|
||||
if (logLevel >= LOG_LEVEL_WARN) {
|
||||
console.log(`[ReduxDevTools] Server port ${port} is already used.`);
|
||||
}
|
||||
resolve({
|
||||
portAlreadyUsed: true,
|
||||
listener: function (eventName: 'ready') {
|
||||
return {
|
||||
once() {
|
||||
return Promise.resolve();
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
} else {
|
||||
if (logLevel >= LOG_LEVEL_INFO) {
|
||||
console.log('[ReduxDevTools] Start server...');
|
||||
console.log('-'.repeat(80) + '\n');
|
||||
}
|
||||
const httpServer = http.createServer();
|
||||
const agServer = socketClusterServer.attach(httpServer, options);
|
||||
// Check port already used
|
||||
const p = await getPort({ port });
|
||||
if (port !== p) {
|
||||
if (logLevel >= LOG_LEVEL_WARN) {
|
||||
console.log(`[ReduxDevTools] Server port ${port} is already used.`);
|
||||
}
|
||||
return {
|
||||
portAlreadyUsed: true,
|
||||
ready: Promise.resolve(),
|
||||
};
|
||||
}
|
||||
|
||||
const app = express();
|
||||
httpServer.on('request', app);
|
||||
const store = createStore(options);
|
||||
app.use(routes(options, store, agServer));
|
||||
if (logLevel >= LOG_LEVEL_INFO) {
|
||||
console.log('[ReduxDevTools] Start server...');
|
||||
console.log('-'.repeat(80) + '\n');
|
||||
}
|
||||
const httpServer = http.createServer();
|
||||
const agServer = socketClusterServer.attach(httpServer, options);
|
||||
|
||||
agServer.setMiddleware(
|
||||
agServer.MIDDLEWARE_INBOUND,
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
async (middlewareStream) => {
|
||||
for await (const action of middlewareStream) {
|
||||
if (action.type === action.TRANSMIT) {
|
||||
const channel = action.receiver;
|
||||
const data = action.data;
|
||||
if (
|
||||
channel.substring(0, 3) === 'sc-' ||
|
||||
channel === 'respond' ||
|
||||
channel === 'log'
|
||||
) {
|
||||
void agServer.exchange.transmitPublish(channel, data);
|
||||
} else if (channel === 'log-noid') {
|
||||
void agServer.exchange.transmitPublish('log', {
|
||||
id: action.socket.id,
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
} else if (action.type === action.SUBSCRIBE) {
|
||||
if (action.channel === 'report') {
|
||||
store
|
||||
.list()
|
||||
.then(function (data) {
|
||||
void agServer.exchange.transmitPublish('report', {
|
||||
type: 'list',
|
||||
data: data,
|
||||
});
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error); // eslint-disable-line no-console
|
||||
});
|
||||
}
|
||||
}
|
||||
action.allow();
|
||||
}
|
||||
const app = express();
|
||||
httpServer.on('request', app);
|
||||
const store = createStore(options);
|
||||
app.use(routes(options, store, agServer));
|
||||
|
||||
agServer.setMiddleware(
|
||||
agServer.MIDDLEWARE_INBOUND,
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
async (middlewareStream) => {
|
||||
for await (const action of middlewareStream) {
|
||||
if (action.type === action.TRANSMIT) {
|
||||
const channel = action.receiver;
|
||||
const data = action.data;
|
||||
if (
|
||||
channel.substring(0, 3) === 'sc-' ||
|
||||
channel === 'respond' ||
|
||||
channel === 'log'
|
||||
) {
|
||||
void agServer.exchange.transmitPublish(channel, data);
|
||||
} else if (channel === 'log-noid') {
|
||||
void agServer.exchange.transmitPublish('log', {
|
||||
id: action.socket.id,
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
void (async () => {
|
||||
for await (const { socket } of agServer.listener('connection')) {
|
||||
let channelToWatch: string, channelToEmit: string;
|
||||
void (async () => {
|
||||
for await (const request of socket.procedure('login')) {
|
||||
const credentials = request.data;
|
||||
if (credentials === 'master') {
|
||||
channelToWatch = 'respond';
|
||||
channelToEmit = 'log';
|
||||
} else {
|
||||
channelToWatch = 'log';
|
||||
channelToEmit = 'respond';
|
||||
}
|
||||
request.end(channelToWatch);
|
||||
}
|
||||
})();
|
||||
void (async () => {
|
||||
for await (const request of socket.procedure('getReport')) {
|
||||
const id = request.data as string;
|
||||
store
|
||||
.get(id)
|
||||
.then(function (data) {
|
||||
request.end(data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error); // eslint-disable-line no-console
|
||||
});
|
||||
}
|
||||
})();
|
||||
void (async () => {
|
||||
for await (const data of socket.listener('disconnect')) {
|
||||
const channel = agServer.exchange.channel('sc-' + socket.id);
|
||||
channel.unsubscribe();
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
void agServer.exchange.transmitPublish(channelToEmit!, {
|
||||
id: socket.id,
|
||||
type: 'DISCONNECTED',
|
||||
} else if (action.type === action.SUBSCRIBE) {
|
||||
if (action.channel === 'report') {
|
||||
store
|
||||
.list()
|
||||
.then(function (data) {
|
||||
void agServer.exchange.transmitPublish('report', {
|
||||
type: 'list',
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
})();
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error); // eslint-disable-line no-console
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
httpServer.listen(options.port);
|
||||
// @ts-expect-error Shouldn't there be a 'ready' event?
|
||||
resolve(agServer);
|
||||
}
|
||||
action.allow();
|
||||
}
|
||||
/* eslint-enable no-console */
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
void (async () => {
|
||||
for await (const { socket } of agServer.listener('connection')) {
|
||||
let channelToWatch: string, channelToEmit: string;
|
||||
void (async () => {
|
||||
for await (const request of socket.procedure('login')) {
|
||||
const credentials = request.data;
|
||||
if (credentials === 'master') {
|
||||
channelToWatch = 'respond';
|
||||
channelToEmit = 'log';
|
||||
} else {
|
||||
channelToWatch = 'log';
|
||||
channelToEmit = 'respond';
|
||||
}
|
||||
request.end(channelToWatch);
|
||||
}
|
||||
})();
|
||||
void (async () => {
|
||||
for await (const request of socket.procedure('getReport')) {
|
||||
const id = request.data as string;
|
||||
store
|
||||
.get(id)
|
||||
.then(function (data) {
|
||||
request.end(data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error(error); // eslint-disable-line no-console
|
||||
});
|
||||
}
|
||||
})();
|
||||
void (async () => {
|
||||
for await (const data of socket.listener('disconnect')) {
|
||||
const channel = agServer.exchange.channel('sc-' + socket.id);
|
||||
channel.unsubscribe();
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
void agServer.exchange.transmitPublish(channelToEmit!, {
|
||||
id: socket.id,
|
||||
type: 'DISCONNECTED',
|
||||
});
|
||||
}
|
||||
})();
|
||||
}
|
||||
})();
|
||||
|
||||
httpServer.listen(options.port);
|
||||
return {
|
||||
ready: (async () => {
|
||||
await agServer.listener('ready' as 'error').once();
|
||||
})(),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
import { ApolloServer } from 'apollo-server-express';
|
||||
import { schema, resolvers } from '../api/schema';
|
||||
import { Store } from '../store';
|
||||
|
||||
export default function (store: Store) {
|
||||
return new ApolloServer({
|
||||
typeDefs: schema,
|
||||
resolvers,
|
||||
context: {
|
||||
store: store,
|
||||
},
|
||||
});
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
interface ProtocolOptions {
|
||||
key: string | undefined;
|
||||
|
@ -31,9 +31,14 @@ export interface Options {
|
|||
export default function getOptions(argv: { [arg: string]: any }): Options {
|
||||
let dbOptions = argv.dbOptions;
|
||||
if (typeof dbOptions === 'string') {
|
||||
dbOptions = require(path.resolve(process.cwd(), argv.dbOptions as string));
|
||||
dbOptions = JSON.parse(fs.readFileSync(dbOptions, 'utf8'));
|
||||
} else if (typeof dbOptions === 'undefined') {
|
||||
dbOptions = require('../defaultDbOptions.json');
|
||||
dbOptions = JSON.parse(
|
||||
fs.readFileSync(
|
||||
new URL('../defaultDbOptions.json', import.meta.url),
|
||||
'utf8'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import path from 'path';
|
||||
import { createRequire } from 'module';
|
||||
import { fileURLToPath } from 'url';
|
||||
import express from 'express';
|
||||
import type { Router } from 'express';
|
||||
import morgan from 'morgan';
|
||||
|
@ -6,12 +8,15 @@ import * as http from 'http';
|
|||
import bodyParser from 'body-parser';
|
||||
import cors from 'cors';
|
||||
import { AGServer } from 'socketcluster-server';
|
||||
import { ApolloServer } from 'apollo-server-express';
|
||||
import { AddData, ReportBaseFields, Store } from './store';
|
||||
import { resolvers, schema } from './api/schema';
|
||||
import { ApolloServer } from '@apollo/server';
|
||||
import { expressMiddleware } from '@apollo/server/express4';
|
||||
import type { AddData, ReportBaseFields, Store } from './store.js';
|
||||
import { resolvers, schema } from './api/schema.js';
|
||||
|
||||
const app = express.Router();
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
function serveUmdModule(name: string) {
|
||||
app.use(
|
||||
express.static(
|
||||
|
@ -20,6 +25,10 @@ function serveUmdModule(name: string) {
|
|||
);
|
||||
}
|
||||
|
||||
interface Context {
|
||||
store?: Store;
|
||||
}
|
||||
|
||||
function routes(
|
||||
options: AGServer.AGServerOptions,
|
||||
store: Store,
|
||||
|
@ -42,19 +51,19 @@ function routes(
|
|||
else app.use(morgan('combined'));
|
||||
}
|
||||
|
||||
const server = new ApolloServer({
|
||||
const server = new ApolloServer<Context>({
|
||||
typeDefs: schema,
|
||||
resolvers,
|
||||
context: {
|
||||
store: store,
|
||||
},
|
||||
});
|
||||
server
|
||||
.start()
|
||||
.then(() => {
|
||||
server.applyMiddleware({ app } as {
|
||||
app: express.Application;
|
||||
});
|
||||
app.use(
|
||||
'/graphql',
|
||||
cors<cors.CorsRequest>(),
|
||||
bodyParser.json(),
|
||||
expressMiddleware(server, { context: () => Promise.resolve({ store }) })
|
||||
);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error); // eslint-disable-line no-console
|
||||
|
@ -69,7 +78,12 @@ function routes(
|
|||
res.send(`reduxDevToolsPort = ${options.port}`);
|
||||
});
|
||||
app.get('*', function (req, res) {
|
||||
res.sendFile(path.join(__dirname, '../app/index.html'));
|
||||
res.sendFile(
|
||||
path.join(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'../app/index.html'
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
app.use(cors({ methods: 'POST' }));
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { v4 as uuidV4 } from 'uuid';
|
||||
import pick from 'lodash/pick';
|
||||
import { pick } from 'lodash-es';
|
||||
import { AGServer } from 'socketcluster-server';
|
||||
import { Knex } from 'knex';
|
||||
import connector from './db/connector';
|
||||
import connector from './db/connector.js';
|
||||
|
||||
const reports = 'remotedev_reports';
|
||||
// var payloads = 'remotedev_payloads';
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "CommonJS",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src"]
|
||||
|
|
|
@ -41,33 +41,33 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@types/prop-types": "^15.7.5",
|
||||
"parse-key": "^0.2.1",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-dock": "^0.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/plugin-transform-runtime": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@redux-devtools/core": "^3.13.1",
|
||||
"@types/parse-key": "^0.2.0",
|
||||
"@types/react": "^18.0.26",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"@types/react": "^18.0.28",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"react": "^18.2.0",
|
||||
"redux": "^4.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "~4.9.4"
|
||||
"redux": "^4.2.1",
|
||||
"rimraf": "^4.1.3",
|
||||
"typescript": "~4.9.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redux-devtools/core": "^3.13.1",
|
||||
|
|
|
@ -1,5 +1,17 @@
|
|||
# Change Log
|
||||
|
||||
## 3.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- a0716740: Fix types for other exports from `@redux-devtools/extension`.
|
||||
|
||||
## 3.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 07456db4: Propagate store enhancer generic type when using composeWithDevTools
|
||||
|
||||
## 3.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@redux-devtools/extension",
|
||||
"version": "3.2.3",
|
||||
"version": "3.2.5",
|
||||
"description": "Wrappers for Redux DevTools Extension.",
|
||||
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-extension",
|
||||
"license": "MIT",
|
||||
|
@ -29,23 +29,23 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"immutable": "^4.1.0"
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"immutable": "^4.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/plugin-transform-runtime": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"redux": "^4.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "~4.9.4"
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"redux": "^4.2.1",
|
||||
"rimraf": "^4.1.3",
|
||||
"typescript": "~4.9.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"redux": "^3.1.0 || ^4.0.0"
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import { compose, StoreEnhancer } from 'redux';
|
||||
import { Config, EnhancerOptions } from './index';
|
||||
import { compose } from 'redux';
|
||||
import type { StoreEnhancer } from 'redux';
|
||||
import type {
|
||||
Config,
|
||||
EnhancerOptions,
|
||||
InferComposedStoreExt,
|
||||
ReduxDevtoolsExtensionCompose,
|
||||
} from './index';
|
||||
|
||||
declare const process: {
|
||||
env: {
|
||||
|
@ -9,15 +15,21 @@ declare const process: {
|
|||
|
||||
function extensionComposeStub(
|
||||
config: Config
|
||||
): (...funcs: StoreEnhancer[]) => StoreEnhancer;
|
||||
function extensionComposeStub(...funcs: StoreEnhancer[]): StoreEnhancer;
|
||||
function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {
|
||||
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
||||
...funcs: StoreEnhancers
|
||||
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
function extensionComposeStub<
|
||||
StoreEnhancers extends readonly StoreEnhancer<unknown>[]
|
||||
>(
|
||||
...funcs: StoreEnhancers
|
||||
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
function extensionComposeStub(...funcs: [Config] | StoreEnhancer<unknown>[]) {
|
||||
if (funcs.length === 0) return undefined;
|
||||
if (typeof funcs[0] === 'object') return compose;
|
||||
return compose(...(funcs as StoreEnhancer[]));
|
||||
return compose(...(funcs as StoreEnhancer<unknown>[]));
|
||||
}
|
||||
|
||||
export const composeWithDevTools =
|
||||
export const composeWithDevTools: ReduxDevtoolsExtensionCompose =
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
typeof window !== 'undefined' &&
|
||||
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Immutable from 'immutable';
|
||||
import { Action, ActionCreator, compose, StoreEnhancer } from 'redux';
|
||||
import type Immutable from 'immutable';
|
||||
import { compose } from 'redux';
|
||||
import type { Action, ActionCreator, StoreEnhancer } from 'redux';
|
||||
|
||||
export interface EnhancerOptions {
|
||||
/**
|
||||
|
@ -227,9 +228,22 @@ interface ReduxDevtoolsExtension {
|
|||
connect: (preConfig: Config) => ConnectResponse;
|
||||
}
|
||||
|
||||
export type InferComposedStoreExt<StoreEnhancers> = StoreEnhancers extends [
|
||||
infer HeadStoreEnhancer,
|
||||
...infer RestStoreEnhancers
|
||||
]
|
||||
? HeadStoreEnhancer extends StoreEnhancer<infer StoreExt>
|
||||
? StoreExt & InferComposedStoreExt<RestStoreEnhancers>
|
||||
: never
|
||||
: unknown;
|
||||
|
||||
export interface ReduxDevtoolsExtensionCompose {
|
||||
(config: Config): (...funcs: StoreEnhancer[]) => StoreEnhancer;
|
||||
(...funcs: StoreEnhancer[]): StoreEnhancer;
|
||||
(config: Config): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
||||
...funcs: StoreEnhancers
|
||||
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
<StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
||||
...funcs: StoreEnhancers
|
||||
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -241,12 +255,18 @@ declare global {
|
|||
|
||||
function extensionComposeStub(
|
||||
config: Config
|
||||
): (...funcs: StoreEnhancer[]) => StoreEnhancer;
|
||||
function extensionComposeStub(...funcs: StoreEnhancer[]): StoreEnhancer;
|
||||
function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {
|
||||
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
||||
...funcs: StoreEnhancers
|
||||
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
function extensionComposeStub<
|
||||
StoreEnhancers extends readonly StoreEnhancer<unknown>[]
|
||||
>(
|
||||
...funcs: StoreEnhancers
|
||||
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
function extensionComposeStub(...funcs: [Config] | StoreEnhancer<unknown>[]) {
|
||||
if (funcs.length === 0) return undefined;
|
||||
if (typeof funcs[0] === 'object') return compose;
|
||||
return compose(...(funcs as StoreEnhancer[]));
|
||||
return compose(...(funcs as StoreEnhancer<unknown>[]));
|
||||
}
|
||||
|
||||
export const composeWithDevTools: ReduxDevtoolsExtensionCompose =
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import assign from './utils/assign';
|
||||
import {
|
||||
import { compose } from 'redux';
|
||||
import type {
|
||||
Action,
|
||||
compose,
|
||||
Dispatch,
|
||||
PreloadedState,
|
||||
Reducer,
|
||||
StoreEnhancer,
|
||||
} from 'redux';
|
||||
import { Config, EnhancerOptions } from './index';
|
||||
import type { Config, EnhancerOptions, InferComposedStoreExt } from './index';
|
||||
|
||||
function enhancer(options?: EnhancerOptions): StoreEnhancer {
|
||||
const config: Config = options || {};
|
||||
|
@ -40,20 +40,28 @@ function enhancer(options?: EnhancerOptions): StoreEnhancer {
|
|||
}
|
||||
|
||||
function composeWithEnhancer(config?: EnhancerOptions) {
|
||||
return function (...funcs: StoreEnhancer[]) {
|
||||
return function (...funcs: StoreEnhancer<unknown>[]) {
|
||||
return compose(compose(...funcs), enhancer(config));
|
||||
};
|
||||
}
|
||||
|
||||
export function composeWithDevTools(
|
||||
config: Config
|
||||
): (...funcs: StoreEnhancer[]) => StoreEnhancer;
|
||||
export function composeWithDevTools(...funcs: StoreEnhancer[]): StoreEnhancer;
|
||||
export function composeWithDevTools(...funcs: [Config] | StoreEnhancer[]) {
|
||||
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
||||
...funcs: StoreEnhancers
|
||||
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
export function composeWithDevTools<
|
||||
StoreEnhancers extends readonly StoreEnhancer<unknown>[]
|
||||
>(
|
||||
...funcs: StoreEnhancers
|
||||
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
export function composeWithDevTools(
|
||||
...funcs: [Config] | StoreEnhancer<unknown>[]
|
||||
) {
|
||||
if (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION__) {
|
||||
if (funcs.length === 0) return enhancer();
|
||||
if (typeof funcs[0] === 'object') return composeWithEnhancer(funcs[0]);
|
||||
return composeWithEnhancer()(...(funcs as StoreEnhancer[]));
|
||||
return composeWithEnhancer()(...(funcs as StoreEnhancer<unknown>[]));
|
||||
}
|
||||
|
||||
if (funcs.length === 0) return undefined;
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import { compose, StoreEnhancer } from 'redux';
|
||||
import { compose } from 'redux';
|
||||
import type { StoreEnhancer } from 'redux';
|
||||
import * as logOnly from './logOnly';
|
||||
import { Config, EnhancerOptions } from './index';
|
||||
import type {
|
||||
Config,
|
||||
EnhancerOptions,
|
||||
InferComposedStoreExt,
|
||||
ReduxDevtoolsExtensionCompose,
|
||||
} from './index';
|
||||
|
||||
declare const process: {
|
||||
env: {
|
||||
|
@ -10,15 +16,21 @@ declare const process: {
|
|||
|
||||
function extensionComposeStub(
|
||||
config: Config
|
||||
): (...funcs: StoreEnhancer[]) => StoreEnhancer;
|
||||
function extensionComposeStub(...funcs: StoreEnhancer[]): StoreEnhancer;
|
||||
function extensionComposeStub(...funcs: [Config] | StoreEnhancer[]) {
|
||||
): <StoreEnhancers extends readonly StoreEnhancer<unknown>[]>(
|
||||
...funcs: StoreEnhancers
|
||||
) => StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
function extensionComposeStub<
|
||||
StoreEnhancers extends readonly StoreEnhancer<unknown>[]
|
||||
>(
|
||||
...funcs: StoreEnhancers
|
||||
): StoreEnhancer<InferComposedStoreExt<StoreEnhancers>>;
|
||||
function extensionComposeStub(...funcs: [Config] | StoreEnhancer<unknown>[]) {
|
||||
if (funcs.length === 0) return undefined;
|
||||
if (typeof funcs[0] === 'object') return compose;
|
||||
return compose(...(funcs as StoreEnhancer[]));
|
||||
return compose(...(funcs as StoreEnhancer<unknown>[]));
|
||||
}
|
||||
|
||||
export const composeWithDevTools =
|
||||
export const composeWithDevTools: ReduxDevtoolsExtensionCompose =
|
||||
process.env.NODE_ENV === 'production'
|
||||
? logOnly.composeWithDevTools
|
||||
: typeof window !== 'undefined' &&
|
||||
|
|
|
@ -15,43 +15,43 @@
|
|||
"@redux-devtools/inspector-monitor": "^3.0.0",
|
||||
"@redux-devtools/inspector-monitor-test-tab": "^1.0.0",
|
||||
"@redux-devtools/ui": "^1.3.0",
|
||||
"immutable": "^4.1.0",
|
||||
"immutable": "^4.2.4",
|
||||
"lodash.shuffle": "^4.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-is": "^18.2.0",
|
||||
"react-redux": "^8.0.5",
|
||||
"react-router-dom": "^6.6.0",
|
||||
"redux": "^4.2.0",
|
||||
"react-router-dom": "^6.8.2",
|
||||
"redux": "^4.2.1",
|
||||
"redux-logger": "^3.0.6",
|
||||
"styled-components": "^5.3.6"
|
||||
"styled-components": "^5.3.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@types/lodash.shuffle": "^4.2.7",
|
||||
"@types/node": "^18.11.17",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@types/node": "^18.14.4",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/redux-logger": "^3.0.9",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"@types/webpack-env": "^1.18.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"babel-loader": "^9.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^6.7.3",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"fork-ts-checker-webpack-plugin": "^7.2.14",
|
||||
"fork-ts-checker-webpack-plugin": "^8.0.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"style-loader": "^3.3.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "~4.9.4",
|
||||
"typescript": "~4.9.5",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.11.1"
|
||||
|
|
|
@ -5,7 +5,8 @@ module.exports = {
|
|||
'\\.css$': '<rootDir>/test/__mocks__/styleMock.ts',
|
||||
},
|
||||
transform: {
|
||||
'^.+\\.jsx?$': 'babel-jest',
|
||||
'^.+\\.tsx?$': ['ts-jest', { tsconfig: 'tsconfig.test.json' }],
|
||||
},
|
||||
resolver: '<rootDir>/jestResolver.js',
|
||||
transformIgnorePatterns: ['node_modules/(?!.pnpm|nanoid)'],
|
||||
};
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
module.exports = (path, options) => {
|
||||
return options.defaultResolver(path, {
|
||||
...options,
|
||||
packageFilter: (pkg) => {
|
||||
if (pkg.name === 'nanoid') {
|
||||
pkg.exports['.'].browser = pkg.exports['.'].require;
|
||||
}
|
||||
return pkg;
|
||||
},
|
||||
});
|
||||
};
|
|
@ -43,7 +43,7 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint && pnpm run test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@redux-devtools/ui": "^1.3.0",
|
||||
"@types/prop-types": "^15.7.5",
|
||||
"es6template": "^1.0.5",
|
||||
|
@ -55,37 +55,37 @@
|
|||
"simple-diff": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/plugin-transform-runtime": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@redux-devtools/core": "^3.13.0",
|
||||
"@redux-devtools/inspector-monitor": "^3.0.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@types/es6template": "^1.0.0",
|
||||
"@types/jest": "^29.2.4",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@types/es6template": "^1.0.1",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/jsan": "^3.1.2",
|
||||
"@types/object-path": "^0.11.1",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/simple-diff": "^1.6.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-jest": "^27.1.7",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"jest": "^29.3.1",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"jest": "^29.4.3",
|
||||
"jest-environment-jsdom": "^29.4.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"redux": "^4.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "~4.9.4"
|
||||
"redux": "^4.2.1",
|
||||
"rimraf": "^4.1.3",
|
||||
"ts-jest": "^29.0.5",
|
||||
"typescript": "~4.9.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redux-devtools/inspector-monitor": "^3.0.0",
|
||||
|
@ -93,6 +93,6 @@
|
|||
"@types/styled-components": "^5.1.26",
|
||||
"react": "^16.3.0 || ^17.0.0 || ^18.0.0",
|
||||
"redux": "^3.4.0 || ^4.0.0",
|
||||
"styled-components": "^5.3.6"
|
||||
"styled-components": "^5.3.8"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.18.6",
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@types/chrome": "^0.0.206",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@types/chrome": "^0.0.218",
|
||||
"anser": "^2.1.1",
|
||||
"html-entities": "^2.3.3",
|
||||
"path-browserify": "^1.0.1",
|
||||
|
@ -40,40 +40,40 @@
|
|||
"source-map": "^0.5.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/plugin-transform-runtime": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@redux-devtools/core": "^3.13.0",
|
||||
"@redux-devtools/inspector-monitor": "^3.0.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@types/babel__code-frame": "^7.0.3",
|
||||
"@types/html-entities": "^1.3.4",
|
||||
"@types/jest": "^29.2.4",
|
||||
"@types/node": "^18.11.17",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/node": "^18.14.4",
|
||||
"@types/path-browserify": "^1.0.0",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/redux-devtools-themes": "^1.0.0",
|
||||
"@types/source-map": "0.5.2",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-jest": "^27.1.7",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"jest": "^29.3.1",
|
||||
"jest-environment-jsdom": "^29.3.1",
|
||||
"jest": "^29.4.3",
|
||||
"jest-environment-jsdom": "^29.4.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-test-renderer": "^18.2.0",
|
||||
"redux": "^4.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "~4.9.4"
|
||||
"redux": "^4.2.1",
|
||||
"rimraf": "^4.1.3",
|
||||
"ts-jest": "^29.0.5",
|
||||
"typescript": "~4.9.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redux-devtools/inspector-monitor": "^3.0.0",
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
import typescript from 'rollup-plugin-typescript2';
|
||||
import babel from '@rollup/plugin-babel';
|
||||
import nodePolyfills from 'rollup-plugin-node-polyfills';
|
||||
|
||||
const config = [
|
||||
{
|
||||
input: 'src/StackTraceTab.tsx',
|
||||
output: [
|
||||
{
|
||||
file: 'dist/redux-devtools-inspector-monitor-trace-tab.cjs.js',
|
||||
format: 'cjs',
|
||||
},
|
||||
{
|
||||
file: 'dist/redux-devtools-inspector-monitor-trace-tab.esm.js',
|
||||
format: 'esm',
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
typescript(),
|
||||
babel({
|
||||
babelHelpers: 'runtime',
|
||||
extensions: ['.ts', '.tsx'],
|
||||
plugins: ['@babel/plugin-transform-runtime'],
|
||||
}),
|
||||
nodePolyfills(),
|
||||
],
|
||||
external: [
|
||||
/@babel\/runtime/,
|
||||
'react',
|
||||
'redux-devtools-themes',
|
||||
'source-map',
|
||||
'@babel/code-frame',
|
||||
'anser',
|
||||
'html-entities',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default config;
|
|
@ -1,5 +1,12 @@
|
|||
# Change Log
|
||||
|
||||
## 3.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [81926f32]
|
||||
- react-json-tree@0.18.0
|
||||
|
||||
## 3.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -14,40 +14,40 @@
|
|||
"@redux-devtools/dock-monitor": "^3.0.0",
|
||||
"@redux-devtools/inspector-monitor": "^3.0.0",
|
||||
"base16": "^1.0.0",
|
||||
"immutable": "^4.1.0",
|
||||
"immutable": "^4.2.4",
|
||||
"lodash.shuffle": "^4.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.7.0",
|
||||
"react-bootstrap": "^2.7.2",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-redux": "^8.0.5",
|
||||
"react-router-dom": "^6.6.0",
|
||||
"redux": "^4.2.0",
|
||||
"react-router-dom": "^6.8.2",
|
||||
"redux": "^4.2.1",
|
||||
"redux-logger": "^3.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@types/base16": "^1.0.2",
|
||||
"@types/lodash.shuffle": "^4.2.7",
|
||||
"@types/node": "^18.11.17",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@types/node": "^18.14.4",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/redux-logger": "^3.0.9",
|
||||
"@types/webpack-env": "^1.18.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"babel-loader": "^9.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"fork-ts-checker-webpack-plugin": "^7.2.14",
|
||||
"fork-ts-checker-webpack-plugin": "^8.0.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "~4.9.4",
|
||||
"typescript": "~4.9.5",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.11.1"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@redux-devtools/inspector-monitor",
|
||||
"version": "3.0.1",
|
||||
"version": "3.0.2",
|
||||
"description": "Redux DevTools Diff Monitor",
|
||||
"homepage": "https://github.com/reduxjs/redux-devtools/tree/master/packages/redux-devtools-inspector-monitor",
|
||||
"bugs": {
|
||||
|
@ -35,50 +35,50 @@
|
|||
"prepublish": "pnpm run type-check && pnpm run lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.6",
|
||||
"@babel/runtime": "^7.21.0",
|
||||
"@types/dragula": "^3.7.1",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/prop-types": "^15.7.5",
|
||||
"dateformat": "^4.6.3",
|
||||
"dateformat": "^5.0.3",
|
||||
"hex-rgba": "^1.0.2",
|
||||
"immutable": "^4.1.0",
|
||||
"immutable": "^4.2.4",
|
||||
"javascript-stringify": "^2.1.0",
|
||||
"jsondiffpatch": "^0.4.1",
|
||||
"jss": "^10.9.2",
|
||||
"jss-preset-default": "^10.9.2",
|
||||
"jss": "^10.10.0",
|
||||
"jss-preset-default": "^10.10.0",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"prop-types": "^15.8.1",
|
||||
"react-base16-styling": "^0.9.1",
|
||||
"react-dragula": "^1.1.17",
|
||||
"react-json-tree": "^0.17.0",
|
||||
"react-json-tree": "^0.18.0",
|
||||
"redux-devtools-themes": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.19.3",
|
||||
"@babel/core": "^7.20.5",
|
||||
"@babel/cli": "^7.21.0",
|
||||
"@babel/core": "^7.21.0",
|
||||
"@babel/eslint-parser": "^7.19.1",
|
||||
"@babel/plugin-transform-runtime": "^7.19.6",
|
||||
"@babel/plugin-transform-runtime": "^7.21.0",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.21.0",
|
||||
"@redux-devtools/core": "^3.13.1",
|
||||
"@types/dateformat": "^3.0.1",
|
||||
"@types/dateformat": "^5.0.0",
|
||||
"@types/hex-rgba": "^1.0.1",
|
||||
"@types/history": "^4.7.11",
|
||||
"@types/lodash.debounce": "^4.0.7",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dragula": "^1.1.0",
|
||||
"@types/redux-devtools-themes": "^1.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.47.0",
|
||||
"@typescript-eslint/parser": "^5.47.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-react": "^7.31.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
||||
"@typescript-eslint/parser": "^5.54.0",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-config-prettier": "^8.6.0",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"react": "^18.2.0",
|
||||
"redux": "^4.2.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "~4.9.4"
|
||||
"redux": "^4.2.1",
|
||||
"rimraf": "^4.1.3",
|
||||
"typescript": "~4.9.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@redux-devtools/core": "^3.13.1",
|
||||
|
|
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
|||
import { Base16Theme } from 'redux-devtools-themes';
|
||||
import { Action } from 'redux';
|
||||
import type { StylingFunction } from 'react-base16-styling';
|
||||
import type { LabelRenderer } from 'react-json-tree';
|
||||
import { PerformAction } from '@redux-devtools/core';
|
||||
import { Delta } from 'jsondiffpatch';
|
||||
import { DEFAULT_STATE, DevtoolsInspectorState } from './redux';
|
||||
|
@ -11,12 +12,7 @@ import StateTab from './tabs/StateTab';
|
|||
import ActionTab from './tabs/ActionTab';
|
||||
|
||||
export interface TabComponentProps<S, A extends Action<unknown>> {
|
||||
labelRenderer: (
|
||||
keyPath: (string | number)[],
|
||||
nodeType: string,
|
||||
expanded: boolean,
|
||||
expandable: boolean
|
||||
) => React.ReactNode;
|
||||
labelRenderer: LabelRenderer;
|
||||
styling: StylingFunction;
|
||||
computedStates: { state: S; error?: string }[];
|
||||
actions: { [actionId: number]: PerformAction<A> };
|
||||
|
@ -152,11 +148,7 @@ class ActionPreview<S, A extends Action<unknown>> extends Component<
|
|||
);
|
||||
}
|
||||
|
||||
labelRenderer = (
|
||||
[key, ...rest]: (string | number)[],
|
||||
nodeType: string,
|
||||
expanded: boolean
|
||||
) => {
|
||||
labelRenderer: LabelRenderer = ([key, ...rest], nodeType, expanded) => {
|
||||
const { styling, onInspectPath, inspectedPath } = this.props;
|
||||
|
||||
return (
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user