diff --git a/.gitignore b/.gitignore index 7c8fc1c..9f4aeac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ node_modules -npm-debug.log .DS_Store jsconfig.json @@ -7,3 +6,4 @@ react-codemod gh-pages/ lib build +*.log diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..feb9a63 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "bracketSpacing": true, + "jsxBracketSameLine": true, + "printWidth": 80, + "singleQuote": true, + "trailingComma": "es5" +} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 9ff837e..0000000 --- a/package-lock.json +++ /dev/null @@ -1,791 +0,0 @@ -{ - "name": "react-inspector", - "version": "2.3.1", - "lockfileVersion": 1, - "dependencies": { - "acorn": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", - "integrity": "sha512-vOk6uEMctu0vQrvuSqFdJyqj1Q0S5VTDL79qtjo+DhRr+1mmaD+tluFSCZqhvi/JUhXSzoZN2BhtstaPEeE8cw==", - "dev": true - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "dev": true, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } - } - }, - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true - }, - "ajv-keywords": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", - "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", - "dev": true - }, - "ansi-escapes": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-2.0.0.tgz", - "integrity": "sha1-W65SvkJIeN2Xg+iRDj/Cki6DyBs=", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "argparse": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", - "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", - "dev": true - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "babel-code-frame": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", - "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "dev": true - }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true - }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true - }, - "circular-json": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz", - "integrity": "sha1-vos2rvzN6LPKeqLWr8B6NyQsDS0=", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true - }, - "cli-width": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", - "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=", - "dev": true - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", - "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true - }, - "doctrine": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", - "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.1.1.tgz", - "integrity": "sha1-+svfz+Pg+s06i4DcmMTmwTrlgt8=", - "dev": true - }, - "eslint-plugin-react": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.1.0.tgz", - "integrity": "sha1-J3cKzzn1/UnNCvQIPOWBBOs5DUw=", - "dev": true - }, - "eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", - "dev": true - }, - "espree": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", - "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", - "dev": true - }, - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true - }, - "esquery": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", - "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", - "dev": true - }, - "esrecurse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", - "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", - "dev": true - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "external-editor": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.4.tgz", - "integrity": "sha1-HtkZnanL/i7y96MbL96LDRI2iXI=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dev": true - }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "dev": true - }, - "flat-cache": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", - "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz", - "integrity": "sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E=", - "dev": true - }, - "generate-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", - "dev": true - }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - }, - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true - }, - "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", - "dev": true - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true - }, - "iconv-lite": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz", - "integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==", - "dev": true - }, - "ignore": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz", - "integrity": "sha1-QyNS5XrM2HqzEQ6C0/6g5HgSFW0=", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "inquirer": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.1.1.tgz", - "integrity": "sha512-H50sHQwgvvaTBd3HpKMVtL/u6LoHDvYym51gd7bGQe/+9HkCE+J0/3N5FJLfd6O6oz44hHewC2Pc2LodzWVafQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-my-json-valid": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", - "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", - "dev": true - }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", - "dev": true - }, - "is-path-in-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", - "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", - "dev": true - }, - "is-path-inside": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", - "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", - "dev": true - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", - "dev": true - }, - "is-resolvable": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", - "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "js-yaml": { - "version": "3.8.4", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.4.tgz", - "integrity": "sha1-UgtFZPhlc7qWZir4Woyvp7S1pvY=", - "dev": true - }, - "jschardet": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.4.2.tgz", - "integrity": "sha1-KqEH8UKvQSHRRWWdRPUIMJYeaZo=", - "dev": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true - }, - "jsx-ast-utils": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", - "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true - }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", - "dev": true - }, - "mimic-fn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", - "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true - }, - "pluralize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-4.0.0.tgz", - "integrity": "sha1-WbcIwcAZCi9pLxx2GMRGsFL9F2I=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "progress": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", - "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", - "dev": true - }, - "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "dev": true - }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true - }, - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "dev": true - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true - }, - "rimraf": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", - "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", - "dev": true - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "dev": true - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "dev": true - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true - }, - "string-width": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz", - "integrity": "sha1-AwZkVh/BRslCPsfZeP4kV0N/5tA=", - "dev": true, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "table": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.1.tgz", - "integrity": "sha1-qBFsEz+sLGH0pCCrbN9cTWHw5DU=", - "dev": true - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "tmp": { - "version": "0.0.31", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", - "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", - "dev": true - }, - "tryit": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", - "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dev": true - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - } - } -} diff --git a/package.json b/package.json index f31c0b9..2380001 100644 --- a/package.json +++ b/package.json @@ -65,11 +65,11 @@ "eslint-plugin-react": "^7.7.0", "expect": "^22.4.3", "jest": "^22.4.3", - "prettier": "^1.11.1", - "react": "^16.3.1", - "react-dom": "^16.3.1", + "prettier": "^1.16.3", + "react": "^16.8.2", + "react-dom": "^16.8.2", "react-hot-loader": "^4.0.1", - "react-test-renderer": "^16.3.1", + "react-test-renderer": "^16.8.0-alpha.1", "rebug": "^0.0.3", "rimraf": "^2.6.2", "style-loader": "^0.20.3", @@ -78,6 +78,6 @@ "webpack-dev-server": "^3.1.3" }, "peerDependencies": { - "react": "^0.14.0 || ^15.0.0 || ^16.0.0" + "react": "^16.8.0" } } diff --git a/src/dom-inspector/DOMInspector.js b/src/dom-inspector/DOMInspector.js index d60bd80..551abeb 100644 --- a/src/dom-inspector/DOMInspector.js +++ b/src/dom-inspector/DOMInspector.js @@ -1,10 +1,12 @@ -import React, { Component } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import DOMNodePreview from './DOMNodePreview'; import TreeView from '../tree-view/TreeView'; import shouldInline from './shouldInline'; +import { themeAcceptor } from '../styles'; + const domIterator = function*(data) { if (data && data.childNodes) { const textInlined = shouldInline(data); @@ -16,7 +18,11 @@ const domIterator = function*(data) { for (let i = 0; i < data.childNodes.length; i++) { const node = data.childNodes[i]; - if (node.nodeType === Node.TEXT_NODE && node.textContent.trim().length === 0) continue; + if ( + node.nodeType === Node.TEXT_NODE && + node.textContent.trim().length === 0 + ) + continue; yield { name: `${node.tagName}[${i}]`, @@ -37,27 +43,19 @@ const domIterator = function*(data) { } }; -import ThemeProvider from '../styles/ThemeProvider'; - -class DOMInspector extends Component { - static propTypes = { - /** The DOM Node to inspect */ - data: PropTypes.object.isRequired, - }; - - static defaultProps = { - theme: 'chromeLight', - }; - - render() { - const nodeRenderer = DOMNodePreview; +const DOMInspector = props => { + return ( + + ); +}; - return ( - - - - ); - } -} +DOMInspector.propTypes = { + // The DOM Node to inspect + data: PropTypes.object.isRequired, +}; -export default DOMInspector; +export default themeAcceptor(DOMInspector); diff --git a/src/dom-inspector/DOMNodePreview.js b/src/dom-inspector/DOMNodePreview.js index 0ecae54..ba8bd26 100644 --- a/src/dom-inspector/DOMNodePreview.js +++ b/src/dom-inspector/DOMNodePreview.js @@ -1,16 +1,14 @@ import React from 'react'; import PropTypes from 'prop-types'; -import createStyles from '../styles/createStyles'; +import { useStyles } from '../styles'; import shouldInline from './shouldInline'; const OpenTag = ({ tagName, attributes, styles }) => { return ( {'<'} - - {tagName} - + {tagName} {(() => { if (attributes) { @@ -19,11 +17,12 @@ const OpenTag = ({ tagName, attributes, styles }) => { const attribute = attributes[i]; attributeNodes.push( - {' '}{attribute.name} + {' '} + {attribute.name} {'="'} {attribute.value} {'"'} - , + ); } return attributeNodes; @@ -36,14 +35,14 @@ const OpenTag = ({ tagName, attributes, styles }) => { }; // isChildNode style={{ marginLeft: -12 /* hack: offset placeholder */ }} -const CloseTag = ({ tagName, isChildNode = false, styles }) => - +const CloseTag = ({ tagName, isChildNode = false, styles }) => ( + {' - {tagName} - + {tagName} {'>'} - ; + +); const nameByNodeType = { 1: 'ELEMENT_NODE', @@ -55,11 +54,17 @@ const nameByNodeType = { 11: 'DOCUMENT_FRAGMENT_NODE', }; -const DOMNodePreview = ({ isCloseTag, data, expanded }, { theme }) => { - const styles = createStyles('DOMNodePreview', theme); +const DOMNodePreview = ({ isCloseTag, data, expanded }) => { + const styles = useStyles('DOMNodePreview'); if (isCloseTag) { - return ; + return ( + + ); } switch (data.nodeType) { @@ -74,21 +79,15 @@ const DOMNodePreview = ({ isCloseTag, data, expanded }, { theme }) => { {shouldInline(data) ? data.textContent : !expanded && '…'} - {!expanded && } + {!expanded && ( + + )} ); case Node.TEXT_NODE: - return ( - - {data.textContent} - - ); + return {data.textContent}; case Node.CDATA_SECTION_NODE: - return ( - - {''} - - ); + return {''}; case Node.COMMENT_NODE: return ( @@ -98,11 +97,7 @@ const DOMNodePreview = ({ isCloseTag, data, expanded }, { theme }) => { ); case Node.PROCESSING_INSTRUCTION_NODE: - return ( - - {data.nodeName} - - ); + return {data.nodeName}; case Node.DOCUMENT_TYPE_NODE: return ( @@ -115,23 +110,11 @@ const DOMNodePreview = ({ isCloseTag, data, expanded }, { theme }) => { ); case Node.DOCUMENT_NODE: - return ( - - {data.nodeName} - - ); + return {data.nodeName}; case Node.DOCUMENT_FRAGMENT_NODE: - return ( - - {data.nodeName} - - ); + return {data.nodeName}; default: - return ( - - {nameByNodeType[data.nodeType]} - - ); + return {nameByNodeType[data.nodeType]}; } }; @@ -146,8 +129,4 @@ DOMNodePreview.propTypes = { expanded: PropTypes.bool.isRequired, }; -DOMNodePreview.contextTypes = { - theme: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired, -}; - export default DOMNodePreview; diff --git a/src/object-inspector/ObjectInspector.js b/src/object-inspector/ObjectInspector.js index a6bab27..9f2a2fa 100644 --- a/src/object-inspector/ObjectInspector.js +++ b/src/object-inspector/ObjectInspector.js @@ -1,15 +1,16 @@ -import React, { Component } from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import TreeView from '../tree-view/TreeView'; import ObjectRootLabel from './ObjectRootLabel'; import ObjectLabel from './ObjectLabel'; -import ThemeProvider from '../styles/ThemeProvider'; +import { themeAcceptor } from '../styles'; const createIterator = (showNonenumerable, sortObjectKeys) => { const objectIterator = function*(data) { - const shouldIterate = (typeof data === 'object' && data !== null) || typeof data === 'function'; + const shouldIterate = + (typeof data === 'object' && data !== null) || typeof data === 'function'; if (!shouldIterate) return; const dataIsArray = Array.isArray(data); @@ -85,54 +86,50 @@ const createIterator = (showNonenumerable, sortObjectKeys) => { }; const defaultNodeRenderer = ({ depth, name, data, isNonenumerable }) => - depth === 0 - ? - : ; + depth === 0 ? ( + + ) : ( + + ); /** * Tree-view for objects */ -class ObjectInspector extends Component { - static defaultProps = { - showNonenumerable: false, - - theme: 'chromeLight', - }; - - static propTypes = { - /** An integer specifying to which level the tree should be initially expanded. */ - expandLevel: PropTypes.number, - /** An array containing all the paths that should be expanded when the component is initialized, or a string of just one path */ - expandPaths: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), - - name: PropTypes.string, - /** Not required prop because we also allow undefined value */ - data: PropTypes.any, - - /** A known theme or theme object */ - theme: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), - - /** Show non-enumerable properties */ - showNonenumerable: PropTypes.bool, - /** Sort object keys with optional compare function. */ - sortObjectKeys: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]), +const ObjectInspector = ({ + showNonenumerable = false, + sortObjectKeys, + nodeRenderer, + ...treeViewProps +}) => { + const dataIterator = createIterator(showNonenumerable, sortObjectKeys); + const renderer = nodeRenderer ? nodeRenderer : defaultNodeRenderer; + + return ( + + ); +}; - /** Provide a custom nodeRenderer */ - nodeRenderer: PropTypes.func, - }; +ObjectInspector.propTypes = { + /** An integer specifying to which level the tree should be initially expanded. */ + expandLevel: PropTypes.number, + /** An array containing all the paths that should be expanded when the component is initialized, or a string of just one path */ + expandPaths: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), - render() { - const { showNonenumerable, sortObjectKeys, nodeRenderer, ...rest } = this.props; - const dataIterator = createIterator(showNonenumerable, sortObjectKeys); + name: PropTypes.string, + /** Not required prop because we also allow undefined value */ + data: PropTypes.any, - const renderer = nodeRenderer ? nodeRenderer : defaultNodeRenderer; + /** Show non-enumerable properties */ + showNonenumerable: PropTypes.bool, + /** Sort object keys with optional compare function. */ + sortObjectKeys: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]), - return ( - - - - ); - } -} + /** Provide a custom nodeRenderer */ + nodeRenderer: PropTypes.func, +}; -export default ObjectInspector; +export default themeAcceptor(ObjectInspector); diff --git a/src/object-inspector/ObjectInspector.spec.js b/src/object-inspector/ObjectInspector.spec.js index 87eddd1..1e7d602 100644 --- a/src/object-inspector/ObjectInspector.spec.js +++ b/src/object-inspector/ObjectInspector.spec.js @@ -1,27 +1,20 @@ import React from 'react'; -import ShallowRenderer from 'react-test-renderer/shallow'; +import TestRenderer from 'react-test-renderer'; import ObjectInspector from './ObjectInspector'; -const TestRenderer = new ShallowRenderer(); - describe('ObjectInspector', () => { it('should render', () => { - const tree = TestRenderer.render(); - - expect(tree).toMatchSnapshot(); - - expect(tree.type).toBeInstanceOf(Function); - expect(tree.props.theme).toEqual('testvalue'); + const tree = TestRenderer.create(); + expect(tree).toMatchSnapshot(); }); it('passes `nodeRenderer` prop to ', () => { - // Test that a custom `nodeRenderer` props is passed to const nodeRenderer = () => unit test; - const tree = TestRenderer.render(); - expect(tree).toMatchSnapshot(); - - expect(tree.props.children.type).toBeInstanceOf(Function); - expect(tree.props.children.props.nodeRenderer).toEqual(nodeRenderer); + const tree = TestRenderer.create( + + ); + + expect(tree).toMatchSnapshot(); }); }); diff --git a/src/object-inspector/ObjectLabel.js b/src/object-inspector/ObjectLabel.js index 2b9a8a4..ef3885a 100644 --- a/src/object-inspector/ObjectLabel.js +++ b/src/object-inspector/ObjectLabel.js @@ -6,7 +6,7 @@ import ObjectValue from '../object/ObjectValue'; /** * if isNonenumerable is specified, render the name dimmed */ -const ObjectLabel = ({ name, data, isNonenumerable }) => { +const ObjectLabel = ({ name, data, isNonenumerable = false }) => { const object = data; return ( @@ -23,8 +23,4 @@ ObjectLabel.propTypes = { isNonenumerable: PropTypes.bool, }; -ObjectLabel.defaultProps = { - isNonenumerable: false, -}; - export default ObjectLabel; diff --git a/src/object-inspector/ObjectPreview.js b/src/object-inspector/ObjectPreview.js index 28a902e..99438c2 100644 --- a/src/object-inspector/ObjectPreview.js +++ b/src/object-inspector/ObjectPreview.js @@ -23,7 +23,7 @@ function intersperse(arr, sep) { /** * A preview of the object */ -const ObjectPreview = ({ data, maxProperties }) => { +const ObjectPreview = ({ data, maxProperties = 5 }) => { const object = data; if ( @@ -45,11 +45,7 @@ const ObjectPreview = ({ data, maxProperties }) => { return ( {`Array(${object.length})`} - - [ - {intersperse(previewArray, ",")} - ] - + [{intersperse(previewArray, ',')}] ); } else { @@ -70,7 +66,7 @@ const ObjectPreview = ({ data, maxProperties }) => { :  {ellipsis} - , + ); if (ellipsis) break; } @@ -92,8 +88,5 @@ ObjectPreview.propTypes = { */ maxProperties: PropTypes.number, }; -ObjectPreview.defaultProps = { - maxProperties: 5, -}; export default ObjectPreview; diff --git a/src/object-inspector/__snapshots__/ObjectInspector.spec.js.snap b/src/object-inspector/__snapshots__/ObjectInspector.spec.js.snap index 823860b..c6129da 100644 --- a/src/object-inspector/__snapshots__/ObjectInspector.spec.js.snap +++ b/src/object-inspector/__snapshots__/ObjectInspector.spec.js.snap @@ -1,27 +1,83 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ObjectInspector passes \`nodeRenderer\` prop to 1`] = ` - - + + unit test + + +
    - + `; exports[`ObjectInspector should render 1`] = ` - - + + undefined + + +
      - + `; diff --git a/src/object/ObjectName.js b/src/object/ObjectName.js index 5b23da2..5015e19 100644 --- a/src/object/ObjectName.js +++ b/src/object/ObjectName.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import createStyles from '../styles/createStyles'; +import { useStyles } from '../styles'; /** * A view for object property names. @@ -11,19 +11,15 @@ import createStyles from '../styles/createStyles'; * If the property name is not enumerable (`Object.prototype.propertyIsEnumerable()`), * the property name will be dimmed to show the difference. */ -const ObjectName = ({ name, dimmed, styles }, { theme }) => { - const themeStyles = createStyles('ObjectName', theme); +const ObjectName = ({ name, dimmed = false, styles = {} }) => { + const themeStyles = useStyles('ObjectName'); const appliedStyles = { ...themeStyles.base, ...(dimmed ? themeStyles['dimmed'] : {}), ...styles, }; - return ( - - {name} - - ); + return {name}; }; ObjectName.propTypes = { @@ -33,12 +29,4 @@ ObjectName.propTypes = { dimmed: PropTypes.bool, }; -ObjectName.defaultProps = { - dimmed: false, -}; - -ObjectName.contextTypes = { - theme: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), -}; - export default ObjectName; diff --git a/src/object/ObjectValue.js b/src/object/ObjectValue.js index 91a10e2..df55c84 100644 --- a/src/object/ObjectValue.js +++ b/src/object/ObjectValue.js @@ -1,35 +1,26 @@ import React from 'react'; import PropTypes from 'prop-types'; -import createStyles from '../styles/createStyles'; + +import { useStyles } from '../styles'; /** * A short description of the object values. * Can be used to render tree node in ObjectInspector * or render objects in TableInspector. */ -const ObjectValue = ({ object, styles }, { theme }) => { - const themeStyles = createStyles('ObjectValue', theme); +const ObjectValue = ({ object, styles }) => { + const themeStyles = useStyles('ObjectValue'); const mkStyle = key => ({ ...themeStyles[key], ...styles }); switch (typeof object) { case 'number': - return ( - - {String(object)} - - ); + return {String(object)}; case 'string': - return ( - - "{object}" - - ); + return "{object}"; case 'boolean': return ( - - {String(object)} - + {String(object)} ); case 'undefined': return undefined; @@ -38,17 +29,11 @@ const ObjectValue = ({ object, styles }, { theme }) => { return null; } if (object instanceof Date) { - return ( - - {object.toString()} - - ); + return {object.toString()}; } if (object instanceof RegExp) { return ( - - {object.toString()} - + {object.toString()} ); } if (Array.isArray(object)) { @@ -57,15 +42,14 @@ const ObjectValue = ({ object, styles }, { theme }) => { if (!object.constructor) { return Object; } - if (typeof object.constructor.isBuffer === 'function' && object.constructor.isBuffer(object)) { + if ( + typeof object.constructor.isBuffer === 'function' && + object.constructor.isBuffer(object) + ) { return {`Buffer[${object.length}]`}; } - return ( - - {object.constructor.name} - - ); + return {object.constructor.name}; case 'function': return ( @@ -77,9 +61,7 @@ const ObjectValue = ({ object, styles }, { theme }) => { ); case 'symbol': return ( - - {object.toString()} - + {object.toString()} ); default: return ; @@ -87,12 +69,8 @@ const ObjectValue = ({ object, styles }, { theme }) => { }; ObjectValue.propTypes = { - /** the object to describe */ + // the object to describe object: PropTypes.any, }; -ObjectValue.contextTypes = { - theme: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), -}; - export default ObjectValue; diff --git a/src/object/ObjectValue.spec.js b/src/object/ObjectValue.spec.js index dcb7104..538d944 100644 --- a/src/object/ObjectValue.spec.js +++ b/src/object/ObjectValue.spec.js @@ -15,7 +15,9 @@ describe('ObjectValue', () => { }); it('should render string with quotes', () => { - const tree = TestRenderer.create().toJSON(); + const tree = TestRenderer.create( + + ).toJSON(); expect(tree.type).toBe('span'); expect(tree.children).toEqual(['"', 'octocat', '"']); }); @@ -27,7 +29,9 @@ describe('ObjectValue', () => { }); it('should render undefined', () => { - const tree = TestRenderer.create().toJSON(); + const tree = TestRenderer.create( + + ).toJSON(); expect(tree.type).toBe('span'); expect(tree.children).toEqual(['undefined']); }); @@ -47,7 +51,9 @@ describe('ObjectValue', () => { }); it('should render array with length information', () => { - const tree = TestRenderer.create().toJSON(); + const tree = TestRenderer.create( + + ).toJSON(); expect(tree.type).toBe('span'); expect(tree.children).toEqual(['Array(5)']); }); @@ -59,13 +65,17 @@ describe('ObjectValue', () => { }); it('should render a simple object', () => { - const tree = TestRenderer.create().toJSON(); + const tree = TestRenderer.create( + + ).toJSON(); expect(tree.type).toBe('span'); expect(tree.children).toEqual(['Object']); }); it('should render a null prototyped object', () => { - const tree = TestRenderer.create().toJSON(); + const tree = TestRenderer.create( + + ).toJSON(); expect(tree.type).toBe('span'); expect(tree.children).toEqual(['Object']); }); @@ -97,13 +107,17 @@ describe('ObjectValue', () => { */ it('should render a symbol', () => { - const tree = TestRenderer.create().toJSON(); + const tree = TestRenderer.create( + + ).toJSON(); expect(tree.type).toBe('span'); expect(tree.children).toEqual(['Symbol()']); }); it('should render a symbol foo', () => { - const tree = TestRenderer.create().toJSON(); + const tree = TestRenderer.create( + + ).toJSON(); expect(tree.type).toBe('span'); expect(tree.children).toEqual(['Symbol(foo)']); }); @@ -111,7 +125,9 @@ describe('ObjectValue', () => { it('accepts and applies style from `styles` prop', () => { // Custom `styles` prop gets applied to the element const style = { color: 'blue' }; - const tree = TestRenderer.create().toJSON(); + const tree = TestRenderer.create( + + ).toJSON(); expect(tree.props.style.color).toEqual('blue'); }); }); diff --git a/src/styles/ThemeProvider.js b/src/styles/ThemeProvider.js deleted file mode 100644 index 9f4123e..0000000 --- a/src/styles/ThemeProvider.js +++ /dev/null @@ -1,23 +0,0 @@ -import { Component } from 'react'; -import PropTypes from 'prop-types'; - -class ThemeProvider extends Component { - getChildContext() { - const theme = this.props.theme; - - return { - // createStyles: createStyles - theme: theme, - }; - } - - render() { - return this.props.children; - } -} - -ThemeProvider.childContextTypes = { - theme: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), -}; - -export default ThemeProvider; diff --git a/src/styles/createStyles.js b/src/styles/createStyles.js deleted file mode 100644 index bdf0300..0000000 --- a/src/styles/createStyles.js +++ /dev/null @@ -1,20 +0,0 @@ -import * as themes from './themes'; -import base from './base'; - -const styles = Object.keys(themes).reduce((styles, themeName) => { - styles[themeName] = base(themes[themeName]); - return styles; -}, {}); - -const createStyles = (key, theme) => { - // console.debug(styles, theme, styles[theme]) - if (typeof theme === 'string') { - return styles[theme][key]; - } else if (typeof theme === 'object') { - return base(theme)[key]; - } - // Default styles - return styles['chromeLight'][key]; -}; - -export default createStyles; diff --git a/src/styles/index.js b/src/styles/index.js new file mode 100644 index 0000000..864fe49 --- /dev/null +++ b/src/styles/index.js @@ -0,0 +1 @@ +export { useStyles, themeAcceptor } from './styles'; diff --git a/src/styles/styles.js b/src/styles/styles.js new file mode 100644 index 0000000..fdc9d8d --- /dev/null +++ b/src/styles/styles.js @@ -0,0 +1,51 @@ +import PropTypes from 'prop-types'; +import React, { createContext, useContext, useMemo } from 'react'; + +import * as themes from './themes'; +import base from './base'; + +const DEFAULT_THEME_NAME = 'chromeLight'; + +const ThemeContext = createContext(base(themes[DEFAULT_THEME_NAME])); + +/** + * Hook to get the component styles for the current theme. + * @param {string} baseStylesKey - Name of the component to be styled + */ +export const useStyles = baseStylesKey => { + const themeStyles = useContext(ThemeContext); + return themeStyles[baseStylesKey]; +}; + +/** + * HOC to create a component that accepts a "theme" prop and uses it to set + * the current theme. This is intended to be used by the top-level inspector + * components. + * @param {Object} WrappedComponent - React component to be wrapped + */ +export const themeAcceptor = WrappedComponent => { + const ThemeAcceptor = ({ theme = DEFAULT_THEME_NAME, ...restProps }) => { + const themeStyles = useMemo(() => { + switch (Object.prototype.toString.call(theme)) { + case '[object String]': + return base(themes[theme]); + case '[object Object]': + return base(theme); + default: + return base(themes[DEFAULT_THEME_NAME]); + } + }, [theme]); + + return ( + + + + ); + }; + + ThemeAcceptor.propTypes = { + theme: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), + }; + + return ThemeAcceptor; +}; diff --git a/src/table-inspector/DataContainer.js b/src/table-inspector/DataContainer.js index a52b3da..1395592 100644 --- a/src/table-inspector/DataContainer.js +++ b/src/table-inspector/DataContainer.js @@ -1,22 +1,20 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import createStyles from '../styles/createStyles'; import ObjectValue from '../object/ObjectValue'; -const DataContainer = ({ rows, columns, rowsData }, { theme }) => { - const styles = createStyles('TableInspectorDataContainer', theme); - const borderStyles = createStyles('TableInspectorLeftBorder', theme); +import { useStyles } from '../styles'; + +const DataContainer = ({ rows, columns, rowsData }) => { + const styles = useStyles('TableInspectorDataContainer'); + const borderStyles = useStyles('TableInspectorLeftBorder'); return (
      - {rows.map((row, i) => + {rows.map((row, i) => ( - + {columns.map(column => { const rowData = rowsData[i]; @@ -36,24 +34,27 @@ const DataContainer = ({ rows, columns, rowsData }, { theme }) => { rowData.hasOwnProperty(column) ) { return ( - ); } else { - return , - )} + + ))}
      - {row} - {row} + ; + return ( + + ); } })} -
      ); }; -DataContainer.contextTypes = { - theme: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired, -}; - export default DataContainer; diff --git a/src/table-inspector/HeaderContainer.js b/src/table-inspector/HeaderContainer.js index 9166e7e..64bbc1b 100644 --- a/src/table-inspector/HeaderContainer.js +++ b/src/table-inspector/HeaderContainer.js @@ -1,23 +1,19 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import createStyles from '../styles/createStyles'; +import { useStyles } from '../styles'; import TH from './TH'; -const HeaderContainer = ( - { - indexColumnText, - columns, - sorted, - sortIndexColumn, - sortColumn, - sortAscending, - onTHClick, - onIndexTHClick, - }, - { theme }, -) => { - const styles = createStyles('TableInspectorHeaderContainer', theme); - const borderStyles = createStyles('TableInspectorLeftBorder', theme); +const HeaderContainer = ({ + indexColumnText = '(index)', + columns = [], + sorted, + sortIndexColumn, + sortColumn, + sortAscending, + onTHClick, + onIndexTHClick, +}) => { + const styles = useStyles('TableInspectorHeaderContainer'); + const borderStyles = useStyles('TableInspectorLeftBorder'); return (
      @@ -27,21 +23,19 @@ const HeaderContainer = ( borderStyle={borderStyles.none} sorted={sorted && sortIndexColumn} sortAscending={sortAscending} - onClick={onIndexTHClick} - > + onClick={onIndexTHClick}> {indexColumnText} - {columns.map(column => + {columns.map(column => ( , - )} + + ))}
      + onClick={onTHClick.bind(this, column)}> {column} -
      @@ -49,13 +43,4 @@ const HeaderContainer = ( ); }; -HeaderContainer.defaultProps = { - indexColumnText: '(index)', - columns: [], -}; - -HeaderContainer.contextTypes = { - theme: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired, -}; - export default HeaderContainer; diff --git a/src/table-inspector/TH.js b/src/table-inspector/TH.js index 77788ca..6f6ee2a 100644 --- a/src/table-inspector/TH.js +++ b/src/table-inspector/TH.js @@ -1,9 +1,8 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; +import React, { useCallback, useState } from 'react'; -import createStyles from '../styles/createStyles'; +import { useStyles } from '../styles'; -const SortIconContainer = props => +const SortIconContainer = props => (
      bottom: 1, display: 'flex', alignItems: 'center', - }} - > + }}> {props.children} -
      ; +
      +); -const SortIcon = ({ sortAscending }, { theme }) => { +const SortIcon = ({ sortAscending }) => { + const styles = useStyles('TableInspectorSortIcon'); const glyph = sortAscending ? '▲' : '▼'; - const styles = createStyles('TableInspectorSortIcon', theme); - return ( -
      - {glyph} -
      - ); + return
      {glyph}
      ; }; -SortIcon.contextTypes = { - theme: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired, -}; - -class TH extends Component { - state = { hovered: false }; - - toggleHovered(hovered) { - this.setState({ hovered: hovered }); - } +const TH = ({ + sortAscending = false, + sorted = false, + onClick = undefined, + borderStyle = {}, + children, + ...thProps +}) => { + const styles = useStyles('TableInspectorTH'); + const [hovered, setHovered] = useState(false); - render() { - // either not sorted, sort ascending or sort descending - const { - borderStyle, - children, - onClick, - sortAscending, - sorted, - ...props - } = this.props; - const { theme } = this.context; - const styles = createStyles('TableInspectorTH', theme); + const handleMouseEnter = useCallback(() => setHovered(true), []); + const handleMouseLeave = useCallback(() => setHovered(false), []); - return ( - -
      - {children} -
      - {sorted && ( - - - - )} - - ); - } -} - -TH.contextTypes = { - theme: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired, -}; - -TH.defaultProps = { - sortAscending: false, - sorted: false, - onClick: undefined, + return ( + +
      {children}
      + {sorted && ( + + + + )} + + ); }; export default TH; diff --git a/src/table-inspector/TableInspector.js b/src/table-inspector/TableInspector.js index a4b1ee9..5a290f0 100644 --- a/src/table-inspector/TableInspector.js +++ b/src/table-inspector/TableInspector.js @@ -4,45 +4,49 @@ * https://developer.mozilla.org/en-US/docs/Web/API/Console/table */ -import React, { Component } from 'react'; +import React, { useCallback, useState } from 'react'; import PropTypes from 'prop-types'; -import ThemeProvider from '../styles/ThemeProvider'; -import createStyles from '../styles/createStyles'; import getHeaders from './getHeaders'; import DataContainer from './DataContainer'; import HeaderContainer from './HeaderContainer'; -export default class TableInspector extends Component { - constructor(props) { - super(props); - - this.state = { - sorted: false, // has user ever clicked the tag to sort? - sortIndexColumn: false, // is index column sorted? - sortColumn: undefined, // which column is sorted? - sortAscending: false, // is sorting ascending or descending? - }; - } - - handleIndexTHClick() { - this.setState(({ - sortIndexColumn, - sortAscending - }) => ({ +import { themeAcceptor, useStyles } from '../styles'; + +const TableInspector = ({ + // The JS object you would like to inspect, either an array or an object + data, + // An array of the names of the columns you'd like to display in the table + columns, +}) => { + const styles = useStyles('TableInspector'); + + const [ + { sorted, sortIndexColumn, sortColumn, sortAscending }, + setState, + ] = useState({ + // has user ever clicked the tag to sort? + sorted: false, + // is index column sorted? + sortIndexColumn: false, + // which column is sorted? + sortColumn: undefined, + // is sorting ascending or descending? + sortAscending: false, + }); + + const handleIndexTHClick = useCallback(() => { + setState(({ sortIndexColumn, sortAscending }) => ({ sorted: true, sortIndexColumn: true, sortColumn: undefined, // when changed to a new column, default to asending sortAscending: sortIndexColumn ? !sortAscending : true, })); - } + }, []); - handleTHClick(col) { - this.setState(({ - sortColumn, - sortAscending - }) => ({ + const handleTHClick = useCallback(col => { + setState(({ sortColumn, sortAscending }) => ({ sorted: true, sortIndexColumn: false, // update sort column @@ -50,121 +54,111 @@ export default class TableInspector extends Component { // when changed to a new column, default to asending sortAscending: col === sortColumn ? !sortAscending : true, })); - } - - render() { - const data = this.props.data; - const columns = this.props.columns; + }, []); - const { theme } = this.props; - const styles = createStyles('TableInspector', theme); - - if (typeof data !== 'object' || data === null) { - return
      ; - } - - let { rowHeaders, colHeaders } = getHeaders(data); - - // columns to be displayed are specified - // NOTE: there's some space for optimization here - if (columns !== undefined) { - colHeaders = columns; - } + if (typeof data !== 'object' || data === null) { + return
      ; + } - let rowsData = rowHeaders.map(rowHeader => data[rowHeader]); + let { rowHeaders, colHeaders } = getHeaders(data); - const sortIndexColumn = this.state.sortIndexColumn, - sortColumn = this.state.sortColumn, - sortAscending = this.state.sortAscending; + // columns to be displayed are specified + // NOTE: there's some space for optimization here + if (columns !== undefined) { + colHeaders = columns; + } - let columnDataWithRowIndexes; /* row indexes are [0..nRows-1] */ - // TODO: refactor - if (sortColumn !== undefined) { - // the column to be sorted (rowsData, column) => [[columnData, rowIndex]] - columnDataWithRowIndexes = rowsData.map((rowData, index) => { - // normalize rowData - if ( - typeof rowData === 'object' && - rowData !== null /*&& rowData.hasOwnProperty(sortColumn)*/ - ) { - const columnData = rowData[sortColumn]; - return [columnData, index]; - } - return [undefined, index]; - }); - } else { - if (sortIndexColumn) { - columnDataWithRowIndexes = rowHeaders.map((rowData, index) => { - const columnData = rowHeaders[index]; - return [columnData, index]; - }); + let rowsData = rowHeaders.map(rowHeader => data[rowHeader]); + + let columnDataWithRowIndexes; /* row indexes are [0..nRows-1] */ + // TODO: refactor + if (sortColumn !== undefined) { + // the column to be sorted (rowsData, column) => [[columnData, rowIndex]] + columnDataWithRowIndexes = rowsData.map((rowData, index) => { + // normalize rowData + if ( + typeof rowData === 'object' && + rowData !== null /*&& rowData.hasOwnProperty(sortColumn)*/ + ) { + const columnData = rowData[sortColumn]; + return [columnData, index]; } + return [undefined, index]; + }); + } else { + if (sortIndexColumn) { + columnDataWithRowIndexes = rowHeaders.map((rowData, index) => { + const columnData = rowHeaders[index]; + return [columnData, index]; + }); } - if (columnDataWithRowIndexes !== undefined) { - // apply a mapper before sorting (because we need to access inside a container) - const comparator = (mapper, ascending) => { - return (a, b) => { - const v1 = mapper(a); // the datum - const v2 = mapper(b); - const type1 = typeof v1; - const type2 = typeof v2; - // use '<' operator to compare same type of values or compare type precedence order # - const lt = (v1, v2) => { - if (v1 < v2) { - return -1; - } else if (v1 > v2) { - return 1; - } else { - return 0; - } - }; - let result; - if (type1 === type2) { - result = lt(v1, v2); + } + if (columnDataWithRowIndexes !== undefined) { + // apply a mapper before sorting (because we need to access inside a container) + const comparator = (mapper, ascending) => { + return (a, b) => { + const v1 = mapper(a); // the datum + const v2 = mapper(b); + const type1 = typeof v1; + const type2 = typeof v2; + // use '<' operator to compare same type of values or compare type precedence order # + const lt = (v1, v2) => { + if (v1 < v2) { + return -1; + } else if (v1 > v2) { + return 1; } else { - // order of different types - const order = { - string: 0, - number: 1, - object: 2, - symbol: 3, - boolean: 4, - undefined: 5, - function: 6, - }; - result = lt(order[type1], order[type2]); + return 0; } - // reverse result if descending - if (!ascending) result = -result; - return result; }; + let result; + if (type1 === type2) { + result = lt(v1, v2); + } else { + // order of different types + const order = { + string: 0, + number: 1, + object: 2, + symbol: 3, + boolean: 4, + undefined: 5, + function: 6, + }; + result = lt(order[type1], order[type2]); + } + // reverse result if descending + if (!ascending) result = -result; + return result; }; - const sortedRowIndexes = columnDataWithRowIndexes - .sort(comparator(item => item[0], sortAscending)) - .map(item => item[1]); // sorted row indexes - rowHeaders = sortedRowIndexes.map(i => rowHeaders[i]); - rowsData = sortedRowIndexes.map(i => rowsData[i]); - } - - return ( - -
      - - -
      -
      - ); + }; + const sortedRowIndexes = columnDataWithRowIndexes + .sort(comparator(item => item[0], sortAscending)) + .map(item => item[1]); // sorted row indexes + rowHeaders = sortedRowIndexes.map(i => rowHeaders[i]); + rowsData = sortedRowIndexes.map(i => rowsData[i]); } -} + + return ( +
      + + +
      + ); +}; TableInspector.propTypes = { /** @@ -177,8 +171,4 @@ TableInspector.propTypes = { columns: PropTypes.array, }; -TableInspector.defaultProps = { - data: undefined, - columns: undefined, - theme: 'chromeLight', -}; +export default themeAcceptor(TableInspector); diff --git a/src/tree-view/ExpandedPathsContext.js b/src/tree-view/ExpandedPathsContext.js new file mode 100644 index 0000000..b37cb2c --- /dev/null +++ b/src/tree-view/ExpandedPathsContext.js @@ -0,0 +1,5 @@ +import { createContext } from 'react'; + +const ExpandedPathsContext = createContext([{}, () => {}]); + +export default ExpandedPathsContext; diff --git a/src/tree-view/TreeNode.js b/src/tree-view/TreeNode.js index 8da8cd3..e21f7aa 100644 --- a/src/tree-view/TreeNode.js +++ b/src/tree-view/TreeNode.js @@ -1,77 +1,71 @@ -import React, { createElement, Component, Children } from 'react'; +import React, { Children, memo } from 'react'; import PropTypes from 'prop-types'; - -import createStyles from '../styles/createStyles'; - -const Arrow = ({ expanded, styles }) => - ; - -class TreeNode extends Component { - render() { - const { - expanded, - onClick, - children, - nodeRenderer, - title, - shouldShowArrow, - shouldShowPlaceholder, - } = this.props; - - const { theme } = this.context; - const styles = createStyles('TreeNode', theme); - - const renderedNode = createElement(nodeRenderer, this.props); - const childNodes = expanded ? children : undefined; - - return ( -
    1. -
      - {shouldShowArrow || Children.count(children) > 0 - ? - : shouldShowPlaceholder &&  } - {renderedNode} -
      - -
        - {childNodes} -
      -
    2. - ); - } -} +import { useStyles } from '../styles'; + +const Arrow = ({ expanded, styles }) => ( + + ▶ + +); + +const TreeNode = memo(props => { + props = { + expanded: true, + nodeRenderer: ({ name }) => {name}, + onClick: () => {}, + shouldShowArrow: false, + shouldShowPlaceholder: true, + ...props, + }; + const { + expanded, + onClick, + children, + nodeRenderer, + title, + shouldShowArrow, + shouldShowPlaceholder, + } = props; + + const styles = useStyles('TreeNode'); + const NodeRenderer = nodeRenderer; + + return ( +
    3. +
      + {shouldShowArrow || Children.count(children) > 0 ? ( + + ) : ( + shouldShowPlaceholder && ( +   + ) + )} + +
      + +
        + {expanded ? children : undefined} +
      +
    4. + ); +}); TreeNode.propTypes = { name: PropTypes.string, data: PropTypes.any, - expanded: PropTypes.bool, shouldShowArrow: PropTypes.bool, shouldShowPlaceholder: PropTypes.bool, - nodeRenderer: PropTypes.func, - onClick: PropTypes.func, }; -TreeNode.defaultProps = { - name: undefined, - data: undefined, - expanded: true, - - nodeRenderer: ({ name }) => - - {name} - , - - onClick: () => {}, - - shouldShowArrow: false, - shouldShowPlaceholder: true, -}; - -TreeNode.contextTypes = { - theme: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired, -}; - export default TreeNode; diff --git a/src/tree-view/TreeView.js b/src/tree-view/TreeView.js index 900c80d..b1fe7be 100644 --- a/src/tree-view/TreeView.js +++ b/src/tree-view/TreeView.js @@ -1,192 +1,117 @@ -import React, { Component } from 'react'; +import React, { + useContext, + useCallback, + useLayoutEffect, + useState, + memo, +} from 'react'; import PropTypes from 'prop-types'; - +import ExpandedPathsContext from './ExpandedPathsContext'; import TreeNode from './TreeNode'; - -import { DEFAULT_ROOT_PATH, hasChildNodes, getExpandedPaths } from './pathUtils'; - -const reducer = (state, action) => { - switch (action.type) { - case 'TOGGLE_EXPAND': { - const path = action.path; - const expandedPaths = state.expandedPaths; - const expanded = !!expandedPaths[path]; - - return Object.assign({}, state, { - expandedPaths: Object.assign({}, state.expandedPaths, { [path]: !expanded }), - }); - } - default: - return state; - } -}; - -class ConnectedTreeNode extends Component { - constructor(props, context) { - super(props); - - this.state = context.store.storeState; - } - - shouldComponentUpdate(nextProps, nextState) { - return ( - !!nextState.expandedPaths[nextProps.path] !== !!this.state.expandedPaths[this.props.path] || - nextProps.data !== this.props.data || - nextProps.name !== this.props.name - ); - } - - handleClick(path) { - this.context.store.storeState = reducer(this.context.store.storeState, { - type: 'TOGGLE_EXPAND', - path: path, - }); - this.setState(this.context.store.storeState); - } - - renderChildNodes(parentData, parentPath) { - const { dataIterator } = this.props; - const { depth } = this.props; - - const { nodeRenderer } = this.props; - - let childNodes = []; - for (let { name, data, ...props } of dataIterator(parentData)) { - const key = name; - const path = `${parentPath}.${key}`; - childNodes.push( - , - ); - } - return childNodes; - } - - render() { - const { data, dataIterator, path, depth } = this.props; - - const nodeHasChildNodes = hasChildNodes(data, dataIterator); - const { expandedPaths } = this.state; - const expanded = !!expandedPaths[path]; - - const { nodeRenderer } = this.props; - - return ( - {}} - // show arrow anyway even if not expanded and not rendering children - shouldShowArrow={nodeHasChildNodes} - // show placeholder only for non root nodes - shouldShowPlaceholder={depth > 0} - // Render a node from name and data (or possibly other props like isNonenumerable) - nodeRenderer={nodeRenderer} - {...this.props} - > - {// only render if the node is expanded - expanded ? this.renderChildNodes(data, path) : undefined} - - ); - } -} +import { + DEFAULT_ROOT_PATH, + hasChildNodes, + getExpandedPaths, +} from './pathUtils'; + +const ConnectedTreeNode = memo(props => { + const { data, dataIterator, path, depth, nodeRenderer } = props; + const [expandedPaths, setExpandedPaths] = useContext(ExpandedPathsContext); + const nodeHasChildNodes = hasChildNodes(data, dataIterator); + const expanded = !!expandedPaths[path]; + + const handleClick = useCallback( + () => + nodeHasChildNodes && + setExpandedPaths(prevExpandedPaths => ({ + ...prevExpandedPaths, + [path]: !expanded, + })), + [nodeHasChildNodes, setExpandedPaths, path, expanded] + ); + + return ( + 0} + // Render a node from name and data (or possibly other props like isNonenumerable) + nodeRenderer={nodeRenderer} + {...props}> + {// only render if the node is expanded + expanded + ? [...dataIterator(data)].map(({ name, data, ...renderNodeProps }) => { + return ( + + ); + }) + : null} + + ); +}); ConnectedTreeNode.propTypes = { name: PropTypes.string, data: PropTypes.any, dataIterator: PropTypes.func, - depth: PropTypes.number, expanded: PropTypes.bool, - nodeRenderer: PropTypes.func, }; -ConnectedTreeNode.contextTypes = { - store: PropTypes.any, -}; - -class TreeView extends Component { - static defaultProps = { - expandLevel: 0, - expandPaths: [], - }; - - constructor(props) { - super(props); - - this.store = { - storeState: { - expandedPaths: getExpandedPaths( - props.data, - props.dataIterator, - props.expandPaths, - props.expandLevel, +const TreeView = memo( + ({ name, data, dataIterator, nodeRenderer, expandPaths, expandLevel }) => { + const stateAndSetter = useState({}); + const [, setExpandedPaths] = stateAndSetter; + + useLayoutEffect( + () => + setExpandedPaths(prevExpandedPaths => + getExpandedPaths( + data, + dataIterator, + expandPaths, + expandLevel, + prevExpandedPaths + ) ), - }, - }; - } - - componentWillReceiveProps(nextProps) { - this.store = { - storeState: { - expandedPaths: getExpandedPaths( - nextProps.data, - nextProps.dataIterator, - nextProps.expandPaths, - nextProps.expandLevel, - this.store.storeState.expandedPaths, - ), - }, - }; - } - - getChildContext() { - return { - store: this.store, - }; - } - - static childContextTypes = { - store: PropTypes.any, - }; - - render() { - const { name, data, dataIterator } = this.props; - const { nodeRenderer } = this.props; - - const rootPath = DEFAULT_ROOT_PATH; + [data, dataIterator, expandPaths, expandLevel] + ); return ( - + + + ); } -} +); TreeView.propTypes = { name: PropTypes.string, data: PropTypes.any, dataIterator: PropTypes.func, - nodeRenderer: PropTypes.func, -}; - -TreeView.defaultProps = { - name: undefined, + expandPaths: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), + expandLevel: PropTypes.number, }; export default TreeView; diff --git a/src/tree-view/pathUtils.js b/src/tree-view/pathUtils.js index c95ebc4..f832cf5 100644 --- a/src/tree-view/pathUtils.js +++ b/src/tree-view/pathUtils.js @@ -8,8 +8,8 @@ export function hasChildNodes(data, dataIterator) { export const wildcardPathsFromLevel = level => { // i is depth - return Array.from({ length: level }, (_, i) => - [DEFAULT_ROOT_PATH].concat(Array.from({ length: i }, () => '*')).join('.'), + return Array.from({length: level}, (_, i) => + [DEFAULT_ROOT_PATH].concat(Array.from({length: i}, () => '*')).join('.'), ); }; @@ -18,7 +18,7 @@ export const getExpandedPaths = ( dataIterator, expandPaths, expandLevel, - initialState = {}, + prevExpandedPaths, ) => { let wildcardPaths = [] .concat(wildcardPathsFromLevel(expandLevel)) @@ -43,7 +43,7 @@ export const getExpandedPaths = ( } } else { if (key === WILDCARD) { - for (let { name, data } of dataIterator(curData)) { + for (let {name, data} of dataIterator(curData)) { if (hasChildNodes(data, dataIterator)) { populatePaths(data, `${curPath}.${name}`, depth + 1); } @@ -60,8 +60,11 @@ export const getExpandedPaths = ( populatePaths(data, '', 0); }); - return expandedPaths.reduce((obj, path) => { - obj[path] = true; - return obj; - }, initialState); + return expandedPaths.reduce( + (obj, path) => { + obj[path] = true; + return obj; + }, + {...prevExpandedPaths}, + ); }; diff --git a/yarn.lock b/yarn.lock index 4eabb48..c8606df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7062,7 +7062,12 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -prettier@^1.11.1, prettier@^1.5.3: +prettier@^1.16.3: + version "1.16.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.3.tgz#8c62168453badef702f34b45b6ee899574a6a65d" + integrity sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw== + +prettier@^1.5.3: version "1.11.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.1.tgz#61e43fc4cd44e68f2b0dfc2c38cd4bb0fccdcc75" @@ -7142,6 +7147,14 @@ prop-types@^15.6.1: loose-envify "^1.3.1" object-assign "^4.1.1" +prop-types@^15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" + integrity sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ== + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1" + proxy-addr@~2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec" @@ -7334,7 +7347,7 @@ react-docgen@^3.0.0-beta11: node-dir "^0.1.10" recast "^0.12.6" -react-dom@^16.0.0, react-dom@^16.3.1: +react-dom@^16.0.0: version "16.3.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.3.1.tgz#6a3c90a4fb62f915bdbcf6204422d93a7d4ca573" dependencies: @@ -7343,6 +7356,16 @@ react-dom@^16.0.0, react-dom@^16.3.1: object-assign "^4.1.1" prop-types "^15.6.0" +react-dom@^16.8.2: + version "16.8.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.2.tgz#7c8a69545dd554d45d66442230ba04a6a0a3c3d3" + integrity sha512-cPGfgFfwi+VCZjk73buu14pYkYBR1b/SRMSYqkLDdhSEHnSwcuYTPu6/Bh6ZphJFIk80XLvbSe2azfcRzNF+Xg== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.13.2" + react-error-overlay@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4" @@ -7389,9 +7412,10 @@ react-inspector@^2.2.2: babel-runtime "^6.26.0" is-dom "^1.0.9" -react-is@^16.3.1: - version "16.3.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.1.tgz#ee66e6d8283224a83b3030e110056798488359ba" +react-is@^16.8.0-alpha.1: + version "16.8.0-alpha.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.0-alpha.1.tgz#ac1aed207d6040f002b645af36702edf9ce2c40d" + integrity sha512-Gsh2u4ovhS2DY6fWgie/av5vzrIfW6P0lgWAsAQp9DjOImE0fJ26FfEdpFXtYBwi5s2krT9z0xvcQKvQsi4ekw== react-modal@^3.3.2: version "3.3.2" @@ -7415,14 +7439,15 @@ react-style-proptype@^3.0.0: dependencies: prop-types "^15.5.4" -react-test-renderer@^16.3.1: - version "16.3.1" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.3.1.tgz#d9257936d8535bd40f57f3d5a84e7b0452fb17f2" +react-test-renderer@^16.8.0-alpha.1: + version "16.8.0-alpha.1" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.8.0-alpha.1.tgz#65f09023aeb83cbb1716f2364fed61c0017cd2ba" + integrity sha512-ayhWv47RYZuZ/vY/Asmf2qLgphHtwsq32Y7uNztyO4HcdFh6HrieDioYwbObfxl3+Uf3r4UezJ7uxqT5NndsHw== dependencies: - fbjs "^0.8.16" object-assign "^4.1.1" - prop-types "^15.6.0" - react-is "^16.3.1" + prop-types "^15.6.2" + react-is "^16.8.0-alpha.1" + scheduler "^0.13.0-alpha.1" react-transition-group@^1.1.2: version "1.2.1" @@ -7445,7 +7470,7 @@ react-treebeard@^2.1.0: shallowequal "^0.2.2" velocity-react "^1.3.1" -react@^16.0.0, react@^16.3.1: +react@^16.0.0: version "16.3.1" resolved "https://registry.yarnpkg.com/react/-/react-16.3.1.tgz#4a2da433d471251c69b6033ada30e2ed1202cfd8" dependencies: @@ -7454,6 +7479,16 @@ react@^16.0.0, react@^16.3.1: object-assign "^4.1.1" prop-types "^15.6.0" +react@^16.8.2: + version "16.8.2" + resolved "https://registry.yarnpkg.com/react/-/react-16.8.2.tgz#83064596feaa98d9c2857c4deae1848b542c9c0c" + integrity sha512-aB2ctx9uQ9vo09HVknqv3DGRpI7OIGJhCx3Bt0QqoRluEjHSaObJl+nG12GDdYH6sTgE7YiPJ6ZUyMx9kICdXw== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.13.2" + read-chunk@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-2.1.0.tgz#6a04c0928005ed9d42e1a6ac5600e19cbc7ff655" @@ -7964,6 +7999,22 @@ sax@^1.2.4, sax@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" +scheduler@^0.13.0-alpha.1: + version "0.13.0-alpha.1" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.0-alpha.1.tgz#753977fb4fb35d8cdd559868a11e46b640955556" + integrity sha512-W0sH0848sVuPKg+I18vTYQyzVtA4X1lrVgSeXK6KnOPUltFdJcY5nkbTkjGUeS/E0x+eBsNYfSdhJtGjT95njw== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +scheduler@^0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.2.tgz#969eaee2764a51d2e97b20a60963b2546beff8fa" + integrity sha512-qK5P8tHS7vdEMCW5IPyt8v9MJOHqTrOUgPXib7tqm9vh834ibBX5BNhwkplX/0iOzHW5sXyluehYfS9yrkz9+w== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + schema-utils@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf"