diff --git a/.eslintrc.js b/.eslintrc.js index 524f435e..94d167b8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -17,7 +17,7 @@ module.exports = { version: 'detect', }, }, - plugins: ['@typescript-eslint', 'import'], + plugins: ['react', 'react-hooks', '@typescript-eslint', 'import'], rules: { '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', @@ -31,6 +31,8 @@ module.exports = { '@typescript-eslint/no-var-requires': 'off', 'react/prop-types': 'off', + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', 'import/no-extraneous-dependencies': 'error', 'import/no-internal-modules': [ diff --git a/.github/workflows/publish-cli.yml b/.github/workflows/publish-cli.yml index ea39efae..91d3daf4 100644 --- a/.github/workflows/publish-cli.yml +++ b/.github/workflows/publish-cli.yml @@ -5,53 +5,52 @@ on: branches: - master - jobs: bundle: - needs: [ check-version-cli ] + needs: [check-version-cli] if: needs.check-version-cli.outputs.changed == 'true' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - - name: Cache node modules - uses: actions/cache@v2 - with: - path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS - key: npm-${{ hashFiles('package-lock.json') }} - restore-keys: | - npm-${{ hashFiles('package-lock.json') }} - npm- - - run: npm ci - - run: npm run bundle - - name: Store bundle artifact - uses: actions/upload-artifact@v2 - with: - name: bundles-cli - path: bundles - retention-days: 1 + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + - name: Cache node modules + uses: actions/cache@v2 + with: + path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS + key: npm-${{ hashFiles('package-lock.json') }} + restore-keys: | + npm-${{ hashFiles('package-lock.json') }} + npm- + - run: npm ci + - run: npm run bundle + - name: Store bundle artifact + uses: actions/upload-artifact@v2 + with: + name: bundles-cli + path: bundles + retention-days: 1 unit-tests: - needs: [ check-version-cli ] + needs: [check-version-cli] if: needs.check-version-cli.outputs.changed == 'true' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - run: npm ci - - run: npm test + - uses: actions/checkout@v1 + - run: npm ci + - run: npm test e2e-tests: - needs: [ bundle ] + needs: [bundle] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - run: npm ci - - name: Download bundled artifact - uses: actions/download-artifact@v2 - with: - name: bundles-cli - path: bundles - - run: npm run e2e + - uses: actions/checkout@v1 + - run: npm ci + - name: Download bundled artifact + uses: actions/download-artifact@v2 + with: + name: bundles-cli + path: bundles + - run: npm run e2e bundle-cli: - needs: [ check-version-cli ] + needs: [check-version-cli] if: needs.check-version-cli.outputs.changed == 'true' runs-on: ubuntu-latest steps: @@ -99,7 +98,7 @@ jobs: steps: - uses: actions/setup-node@v1 with: - node-version: "14.x" + node-version: '14.x' registry-url: 'https://registry.npmjs.org' - uses: actions/checkout@v2 - name: Download cli bundled artifact diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b6d05316..cd5b34de 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -9,42 +9,42 @@ jobs: bundle: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 - - name: Cache node modules - uses: actions/cache@v2 - with: - path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS - key: npm-${{ hashFiles('package-lock.json') }} - restore-keys: | - npm-${{ hashFiles('package-lock.json') }} - npm- - - run: npm ci - - run: npm run bundle - - name: Store bundle artifact - uses: actions/upload-artifact@v2 - with: - name: bundles - path: bundles - retention-days: 1 + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + - name: Cache node modules + uses: actions/cache@v2 + with: + path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS + key: npm-${{ hashFiles('package-lock.json') }} + restore-keys: | + npm-${{ hashFiles('package-lock.json') }} + npm- + - run: npm ci + - run: npm run bundle + - name: Store bundle artifact + uses: actions/upload-artifact@v2 + with: + name: bundles + path: bundles + retention-days: 1 unit-tests: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - run: npm ci - - run: npm test + - uses: actions/checkout@v1 + - run: npm ci + - run: npm test e2e-tests: needs: [bundle] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - run: npm ci - - name: Download bundled artifact - uses: actions/download-artifact@v2 - with: - name: bundles - path: bundles - - run: npm run e2e + - uses: actions/checkout@v1 + - run: npm ci + - name: Download bundled artifact + uses: actions/download-artifact@v2 + with: + name: bundles + path: bundles + - run: npm run e2e # disable this for now # deploy-demo: # needs: [bundle, unit-tests, e2e-tests] @@ -76,7 +76,7 @@ jobs: steps: - uses: actions/setup-node@v1 with: - node-version: "14.x" + node-version: '14.x' registry-url: 'https://registry.npmjs.org' - uses: actions/checkout@v2 - name: Download bundled artifacts diff --git a/demo/webpack.config.ts b/demo/webpack.config.ts index 6317ba77..3edd4af8 100644 --- a/demo/webpack.config.ts +++ b/demo/webpack.config.ts @@ -37,6 +37,7 @@ export default (env: { playground?: boolean; bench?: boolean } = {}, { mode }) = port: 9090, hot: true, historyApiFallback: true, + open: true, }, stats: { children: true, diff --git a/e2e/integration/search.e2e.ts b/e2e/integration/search.e2e.ts index b1a7d4a7..dfc38b03 100644 --- a/e2e/integration/search.e2e.ts +++ b/e2e/integration/search.e2e.ts @@ -56,7 +56,7 @@ describe('Search', () => { it('should show proper message when no search results are found', () => { getSearchResults().should('not.exist'); - getSearchInput().type('xzss', {force: true}); + getSearchInput().type('xzss', { force: true }); getSearchResults().should('exist').should('contain', 'No results found'); - }) + }); }); diff --git a/package-lock.json b/package-lock.json index 6a814215..2746ce1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -86,7 +86,8 @@ "enzyme-to-json": "^3.6.2", "eslint": "^7.27.0", "eslint-plugin-import": "^2.23.4", - "eslint-plugin-react": "^7.24.0", + "eslint-plugin-react": "^7.25.1", + "eslint-plugin-react-hooks": "^4.2.0", "fork-ts-checker-webpack-plugin": "^6.2.10", "html-webpack-plugin": "^5.3.1", "husky": "^7.0.0", @@ -3968,16 +3969,16 @@ "dev": true }, "node_modules/array-includes": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", - "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", + "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", - "is-string": "^1.0.5" + "is-string": "^1.0.7" }, "engines": { "node": ">= 0.4" @@ -4032,15 +4033,14 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", - "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", + "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", "dev": true, "dependencies": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "function-bind": "^1.1.1" + "es-abstract": "^1.19.0" }, "engines": { "node": ">= 0.4" @@ -6642,22 +6642,26 @@ } }, "node_modules/es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", "string.prototype.trimend": "^1.0.4", @@ -6979,29 +6983,43 @@ "dev": true }, "node_modules/eslint-plugin-react": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz", - "integrity": "sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", + "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", "dev": true, "dependencies": { - "array-includes": "^3.1.3", - "array.prototype.flatmap": "^1.2.4", + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", "doctrine": "^2.1.0", - "has": "^1.0.3", + "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.0.4", - "object.entries": "^1.1.4", - "object.fromentries": "^2.0.4", - "object.values": "^1.1.4", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", "prop-types": "^15.7.2", "resolve": "^2.0.0-next.3", - "string.prototype.matchall": "^4.0.5" + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.6" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz", + "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" } }, "node_modules/eslint-plugin-react/node_modules/doctrine": { @@ -7016,6 +7034,15 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/eslint-plugin-react/node_modules/resolve": { "version": "2.0.0-next.3", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", @@ -8578,6 +8605,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/getos": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", @@ -8898,6 +8941,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -9472,9 +9530,9 @@ } }, "node_modules/is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true, "engines": { "node": ">= 0.4" @@ -9688,13 +9746,13 @@ "dev": true }, "node_modules/is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -9703,6 +9761,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -9713,10 +9780,13 @@ } }, "node_modules/is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -9781,6 +9851,18 @@ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -13661,9 +13743,9 @@ } }, "node_modules/object-inspect": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -13713,29 +13795,28 @@ } }, "node_modules/object.entries": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz", - "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" + "es-abstract": "^1.19.1" }, "engines": { "node": ">= 0.4" } }, "node_modules/object.fromentries": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", - "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" + "es-abstract": "^1.19.1" }, "engines": { "node": ">= 0.4" @@ -13744,15 +13825,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object.values": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" + "es-abstract": "^1.19.1" }, "engines": { "node": ">= 0.4" @@ -16426,14 +16520,14 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz", - "integrity": "sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", + "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2", + "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", "has-symbols": "^1.0.2", "internal-slot": "^1.0.3", @@ -21770,16 +21864,16 @@ "dev": true }, "array-includes": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", - "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", + "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", - "is-string": "^1.0.5" + "is-string": "^1.0.7" } }, "array-union": { @@ -21813,15 +21907,14 @@ } }, "array.prototype.flatmap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", - "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", + "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", "dev": true, "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "function-bind": "^1.1.1" + "es-abstract": "^1.19.0" } }, "arrify": { @@ -23852,22 +23945,26 @@ } }, "es-abstract": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", - "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", "string.prototype.trimend": "^1.0.4", @@ -24282,23 +24379,25 @@ } }, "eslint-plugin-react": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz", - "integrity": "sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", + "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", "dev": true, "requires": { - "array-includes": "^3.1.3", - "array.prototype.flatmap": "^1.2.4", + "array-includes": "^3.1.4", + "array.prototype.flatmap": "^1.2.5", "doctrine": "^2.1.0", - "has": "^1.0.3", + "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.0.4", - "object.entries": "^1.1.4", - "object.fromentries": "^2.0.4", - "object.values": "^1.1.4", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.0", + "object.values": "^1.1.5", "prop-types": "^15.7.2", "resolve": "^2.0.0-next.3", - "string.prototype.matchall": "^4.0.5" + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.6" }, "dependencies": { "doctrine": { @@ -24310,6 +24409,12 @@ "esutils": "^2.0.2" } }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, "resolve": { "version": "2.0.0-next.3", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", @@ -24322,6 +24427,13 @@ } } }, + "eslint-plugin-react-hooks": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz", + "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==", + "dev": true, + "requires": {} + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -25338,6 +25450,16 @@ "pump": "^3.0.0" } }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "getos": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", @@ -25579,6 +25701,15 @@ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -26006,9 +26137,9 @@ } }, "is-callable": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", - "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true }, "is-ci": { @@ -26141,15 +26272,21 @@ "dev": true }, "is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "requires": { "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" + "has-tostringtag": "^1.0.0" } }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "dev": true + }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -26157,10 +26294,13 @@ "dev": true }, "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", - "dev": true + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-subset": { "version": "0.1.1", @@ -26204,6 +26344,15 @@ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -29133,9 +29282,9 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", "dev": true }, "object-is": { @@ -29167,37 +29316,46 @@ } }, "object.entries": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz", - "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" + "es-abstract": "^1.19.1" } }, "object.fromentries": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", - "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" + "es-abstract": "^1.19.1" + } + }, + "object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" } }, "object.values": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", - "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2" + "es-abstract": "^1.19.1" } }, "obuf": { @@ -31313,14 +31471,14 @@ } }, "string.prototype.matchall": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz", - "integrity": "sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", + "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.2", + "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", "has-symbols": "^1.0.2", "internal-slot": "^1.0.3", diff --git a/package.json b/package.json index 14d3f995..5434949c 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,8 @@ "enzyme-to-json": "^3.6.2", "eslint": "^7.27.0", "eslint-plugin-import": "^2.23.4", - "eslint-plugin-react": "^7.24.0", + "eslint-plugin-react": "^7.25.1", + "eslint-plugin-react-hooks": "^4.2.0", "fork-ts-checker-webpack-plugin": "^6.2.10", "html-webpack-plugin": "^5.3.1", "husky": "^7.0.0", diff --git a/src/common-elements/fields.ts b/src/common-elements/fields.ts index c8d0df1b..2fbac2cb 100644 --- a/src/common-elements/fields.ts +++ b/src/common-elements/fields.ts @@ -96,7 +96,6 @@ export const ConstraintItem = styled(FieldLabel)` margin: 0 ${theme.spacing.unit}px; padding: 0 ${theme.spacing.unit}px; border: 1px solid ${transparentize(0.9, theme.colors.primary.main)}; - font-family: ${theme.typography.code.fontFamily}; }`}; & + & { margin-left: 0; diff --git a/src/common-elements/linkify.tsx b/src/common-elements/linkify.tsx index fe8f942b..4ace029e 100644 --- a/src/common-elements/linkify.tsx +++ b/src/common-elements/linkify.tsx @@ -43,7 +43,7 @@ export function Link(props: { to: string; className?: string; children?: any }) if (!store) return; navigate(store.menu.history, event, props.to); }, - [store], + [store, props.to], ); if (!store) return null; diff --git a/src/components/Fields/ArrayItemDetails.tsx b/src/components/Fields/ArrayItemDetails.tsx new file mode 100644 index 00000000..0c2716b1 --- /dev/null +++ b/src/components/Fields/ArrayItemDetails.tsx @@ -0,0 +1,25 @@ +import * as React from 'react'; +import { TypeFormat, TypePrefix } from '../../common-elements/fields'; +import { ConstraintsView } from './FieldContstraints'; +import { Pattern } from './Pattern'; +import { SchemaModel } from '../../services'; +import styled from '../../styled-components'; + +export function ArrayItemDetails({ schema }: { schema: SchemaModel }) { + if (!schema || (schema.type === 'string' && !schema.constraints.length)) return null; + + return ( + + [ items + {schema.displayFormat && {` <${schema.displayFormat}> `}} + + + {schema.items && } ] + + ); +} + +const Wrapper = styled(TypePrefix)` + margin: 0 5px; + vertical-align: text-top; +`; diff --git a/src/components/Fields/EnumValues.tsx b/src/components/Fields/EnumValues.tsx index 05bb8072..21448ea5 100644 --- a/src/components/Fields/EnumValues.tsx +++ b/src/components/Fields/EnumValues.tsx @@ -8,7 +8,7 @@ import { RedocRawOptions } from '../../services/RedocNormalizedOptions'; export interface EnumValuesProps { values: string[]; - type: string | string[]; + isArrayType: boolean; } export interface EnumValuesState { @@ -27,7 +27,7 @@ export class EnumValues extends React.PureComponent - {type === 'array' ? l('enumArray') : ''}{' '} + {isArrayType ? l('enumArray') : ''}{' '} {values.length === 1 ? l('enumSingleValue') : l('enum')}: {' '} {displayedItems.map((value, idx) => { diff --git a/src/components/Fields/Examples.tsx b/src/components/Fields/Examples.tsx new file mode 100644 index 00000000..690ecb9a --- /dev/null +++ b/src/components/Fields/Examples.tsx @@ -0,0 +1,35 @@ +import * as React from 'react'; + +import { FieldLabel, ExampleValue } from '../../common-elements/fields'; +import { getSerializedValue } from '../../utils'; + +import { l } from '../../services/Labels'; +import { FieldModel } from '../../services'; +import styled from '../../styled-components'; + +export function Examples({ field }: { field: FieldModel }) { + if (!field.examples) { + return null; + } + + return ( + <> + {l('examples')}: + + {Object.values(field.examples).map((example, idx) => { + return ( +
  • + {getSerializedValue(field, example.value)} - {example.summary || example.description} +
  • + ); + })} +
    + + ); +} + +const ExamplesList = styled.ul` + margin-top: 1em; + padding-left: 0; + list-style-position: inside; +`; diff --git a/src/components/Fields/FieldDetail.tsx b/src/components/Fields/FieldDetail.tsx index e5b28189..53fb89bf 100644 --- a/src/components/Fields/FieldDetail.tsx +++ b/src/components/Fields/FieldDetail.tsx @@ -7,18 +7,18 @@ export interface FieldDetailProps { raw?: boolean; } -export class FieldDetail extends React.PureComponent { - render() { - if (this.props.value === undefined) { - return null; - } - - const value = this.props.raw ? String(this.props.value) : JSON.stringify(this.props.value); - - return ( -
    - {this.props.label} {value} -
    - ); +function FieldDetailComponent({ value, label, raw }: FieldDetailProps) { + if (value === undefined) { + return null; } + + const stringifyValue = raw ? String(value) : JSON.stringify(value); + + return ( +
    + {label} {stringifyValue} +
    + ); } + +export const FieldDetail = React.memo(FieldDetailComponent); diff --git a/src/components/Fields/FieldDetails.tsx b/src/components/Fields/FieldDetails.tsx index 3df94ded..c04a5b0f 100644 --- a/src/components/Fields/FieldDetails.tsx +++ b/src/components/Fields/FieldDetails.tsx @@ -1,22 +1,19 @@ import * as React from 'react'; import { - PatternLabel, RecursiveLabel, TypeFormat, TypeName, TypePrefix, TypeTitle, - ToggleButton, - FieldLabel, - ExampleValue, } from '../../common-elements/fields'; -import { serializeParameterValue } from '../../utils/openapi'; +import { getSerializedValue } from '../../utils'; import { ExternalDocumentation } from '../ExternalDocumentation/ExternalDocumentation'; import { Markdown } from '../Markdown/Markdown'; import { EnumValues } from './EnumValues'; import { Extensions } from './Extensions'; import { FieldProps } from './Field'; +import { Examples } from './Examples'; import { ConstraintsView } from './FieldContstraints'; import { FieldDetail } from './FieldDetail'; @@ -24,149 +21,92 @@ import { Badge } from '../../common-elements/'; import { l } from '../../services/Labels'; import { OptionsContext } from '../OptionsProvider'; -import { FieldModel } from '../../services/models/Field'; -import styled from '../../styled-components'; +import { Pattern } from './Pattern'; +import { ArrayItemDetails } from './ArrayItemDetails'; -const MAX_PATTERN_LENGTH = 45; +function FieldDetailsComponent(props: FieldProps) { + const { enumSkipQuotes, hideSchemaTitles } = React.useContext(OptionsContext); -export class FieldDetails extends React.PureComponent { - state = { - patternShown: false, - }; + const { showExamples, field, renderDiscriminatorSwitch } = props; + const { schema, description, deprecated, extensions, in: _in, const: _const } = field; + const isArrayType = schema.type === 'array'; - static contextType = OptionsContext; + const rawDefault = enumSkipQuotes || _in === 'header'; // having quotes around header field default values is confusing and inappropriate - togglePattern = () => { - this.setState({ - patternShown: !this.state.patternShown, - }); - }; - - render() { - const { showExamples, field, renderDiscriminatorSwitch } = this.props; - const { patternShown } = this.state; - const { enumSkipQuotes, hideSchemaTitles, hideSchemaPattern } = this.context; - - const { schema, description, example, deprecated, examples } = field; - - const rawDefault = !!enumSkipQuotes || field.in === 'header'; // having quotes around header field default values is confusing and inappropriate - - let renderedExamples: JSX.Element | null = null; - - if (showExamples && (example !== undefined || examples !== undefined)) { - if (examples !== undefined) { - renderedExamples = ; + const renderedExamples = React.useMemo(() => { + if (showExamples && (field.example !== undefined || field.examples !== undefined)) { + if (field.examples !== undefined) { + return ; } else { - const label = l('example') + ':'; - const raw = !!field.in; - renderedExamples = ( - + return ( + ); } } - return ( -
    -
    - {schema.typePrefix} - {schema.displayType} - {schema.displayFormat && ( - - {' '} - < - {schema.displayFormat} - >{' '} - - )} - {schema.contentEncoding && ( - - {' '} - < - {schema.contentEncoding} - >{' '} - - )} - {schema.contentMediaType && ( - - {' '} - < - {schema.contentMediaType} - >{' '} - - )} - {schema.title && !hideSchemaTitles && ({schema.title}) } - - {schema.pattern && !hideSchemaPattern && ( - <> - - {patternShown || schema.pattern.length < MAX_PATTERN_LENGTH - ? schema.pattern - : `${schema.pattern.substr(0, MAX_PATTERN_LENGTH)}...`} - - {schema.pattern.length > MAX_PATTERN_LENGTH && ( - - {patternShown ? 'Hide pattern' : 'Show pattern'} - - )} - - )} - {schema.isCircular && {l('recursive')} } -
    - {deprecated && ( -
    - {l('deprecated')} -
    - )} - - {!renderDiscriminatorSwitch && }{' '} - {renderedExamples} - {} -
    - -
    - {schema.externalDocs && ( - - )} - {(renderDiscriminatorSwitch && renderDiscriminatorSwitch(this.props)) || null} - {(field.const && ) || null} -
    - ); - } -} - -function Examples({ field }: { field: FieldModel }) { - if (!field.examples) { return null; - } + }, [field, showExamples]); return ( - <> - {l('examples')}: - - {Object.values(field.examples).map((example, idx) => { - return ( -
  • - {getSerializedValue(field, example.value)} -{' '} - {example.summary || example.description} -
  • - ); - })} -
    - +
    +
    + {schema.typePrefix} + {schema.displayType} + {schema.displayFormat && ( + + {' '} + < + {schema.displayFormat} + >{' '} + + )} + {schema.contentEncoding && ( + + {' '} + < + {schema.contentEncoding} + >{' '} + + )} + {schema.contentMediaType && ( + + {' '} + < + {schema.contentMediaType} + >{' '} + + )} + {schema.title && !hideSchemaTitles && ({schema.title}) } + + + {schema.isCircular && {l('recursive')} } + {isArrayType && schema.items && } +
    + {deprecated && ( +
    + {l('deprecated')} +
    + )} + + {!renderDiscriminatorSwitch && ( + + )}{' '} + {renderedExamples} + +
    + +
    + {schema.externalDocs && ( + + )} + {(renderDiscriminatorSwitch && renderDiscriminatorSwitch(props)) || null} + {(_const && ) || null} +
    ); } -function getSerializedValue(field: FieldModel, example: any) { - if (field.in) { - // decode for better readability in examples: see https://github.com/Redocly/redoc/issues/1138 - return decodeURIComponent(serializeParameterValue(field, example)); - } else { - return example; - } -} - -const ExamplesList = styled.ul` - margin-top: 1em; - padding-left: 0; - list-style-position: inside; -`; +export const FieldDetails = React.memo(FieldDetailsComponent); diff --git a/src/components/Fields/Pattern.tsx b/src/components/Fields/Pattern.tsx new file mode 100644 index 00000000..3b0c17ea --- /dev/null +++ b/src/components/Fields/Pattern.tsx @@ -0,0 +1,33 @@ +import * as React from 'react'; +import { PatternLabel, ToggleButton } from '../../common-elements/fields'; +import { OptionsContext } from '../OptionsProvider'; +import { SchemaModel } from '../../services'; + +const MAX_PATTERN_LENGTH = 45; + +export function Pattern(props: { schema: SchemaModel }) { + const pattern = props.schema.pattern; + const { hideSchemaPattern } = React.useContext(OptionsContext); + const [isPatternShown, setIsPatternShown] = React.useState(false); + const togglePattern = React.useCallback( + () => setIsPatternShown(!isPatternShown), + [isPatternShown], + ); + + if (!pattern || hideSchemaPattern) return null; + + return ( + <> + + {isPatternShown || pattern.length < MAX_PATTERN_LENGTH + ? pattern + : `${pattern.substr(0, MAX_PATTERN_LENGTH)}...`} + + {pattern.length > MAX_PATTERN_LENGTH && ( + + {isPatternShown ? 'Hide pattern' : 'Show pattern'} + + )} + + ); +} diff --git a/src/components/StoreBuilder.ts b/src/components/StoreBuilder.ts index 7c12784c..df8b23b0 100644 --- a/src/components/StoreBuilder.ts +++ b/src/components/StoreBuilder.ts @@ -56,6 +56,7 @@ export function StoreBuilder(props: StoreBuilderProps) { } throw e; } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [resolvedSpec, specUrl, options]); React.useEffect(() => { diff --git a/src/utils/openapi.ts b/src/utils/openapi.ts index 72bc44f8..9312e3fb 100644 --- a/src/utils/openapi.ts +++ b/src/utils/openapi.ts @@ -368,6 +368,15 @@ export function serializeParameterValue( } } +export function getSerializedValue(field: FieldModel, example: any) { + if (field.in) { + // decode for better readability in examples: see https://github.com/Redocly/redoc/issues/1138 + return decodeURIComponent(serializeParameterValue(field, example)); + } else { + return example; + } +} + export function langFromMime(contentType: string): string { if (contentType.search(/xml/i) !== -1) { return 'xml'; diff --git a/tsconfig.json b/tsconfig.json index 18a22b36..21dbb326 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,27 +13,12 @@ "importHelpers": true, "outDir": "lib", "pretty": true, - "lib": [ - "es2015", - "es2016", - "es2017", - "dom", - "WebWorker.ImportScripts" - ], + "lib": ["es2015", "es2016", "es2017", "dom", "WebWorker.ImportScripts"], "jsx": "react", - "types": [ - "webpack", - "webpack-env", - "jest" - ] + "types": ["webpack", "webpack-env", "jest"] }, "compileOnSave": false, - "exclude": [ - "node_modules", - ".tmp", - "lib", - "e2e/**" - ], + "exclude": ["node_modules", ".tmp", "lib", "e2e/**"], "include": [ "cli/index.ts", "./custom.d.ts", diff --git a/webpack.config.ts b/webpack.config.ts index c5778b4d..217efcd5 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -32,10 +32,14 @@ const BANNER = `ReDoc - OpenAPI/Swagger-generated API Reference Documentation Version: ${VERSION} Repo: https://github.com/Redocly/redoc`; -export default (env: { standalone?: boolean, browser?: boolean } = {}) => ({ +export default (env: { standalone?: boolean; browser?: boolean } = {}) => ({ entry: env.standalone ? ['./src/polyfills.ts', './src/standalone.tsx'] : './src/index.ts', output: { - filename: env.standalone ? 'redoc.standalone.js' : env.browser ? 'redoc.browser.lib.js' : 'redoc.lib.js', + filename: env.standalone + ? 'redoc.standalone.js' + : env.browser + ? 'redoc.browser.lib.js' + : 'redoc.lib.js', path: path.join(__dirname, '/bundles'), library: 'Redoc', libraryTarget: 'umd', @@ -50,7 +54,7 @@ export default (env: { standalone?: boolean, browser?: boolean } = {}) => ({ fs: path.resolve(__dirname, 'src/empty.js'), os: path.resolve(__dirname, 'src/empty.js'), tty: path.resolve(__dirname, 'src/empty.js'), - } + }, }, performance: false, externalsPresets: env.standalone || env.browser ? {} : { node: true }, @@ -74,7 +78,7 @@ export default (env: { standalone?: boolean, browser?: boolean } = {}) => ({ rules: [ { test: /\.(tsx?|[cm]?js)$/, - use: [getBabelLoader({useBuiltIns: !!env.standalone})], + use: [getBabelLoader({ useBuiltIns: !!env.standalone })], exclude: { and: [/node_modules/], not: {