From 543ecc4d3902c3af3936f1b2e281ccb63cf96332 Mon Sep 17 00:00:00 2001 From: Andriy Zaleskyy Date: Fri, 8 Oct 2021 13:44:54 +0300 Subject: [PATCH 1/7] fix: No maxLength label is displayed for arrays of items #1701 --- src/components/Fields/FieldDetails.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/Fields/FieldDetails.tsx b/src/components/Fields/FieldDetails.tsx index 1aad8c6182..bbd522bc50 100644 --- a/src/components/Fields/FieldDetails.tsx +++ b/src/components/Fields/FieldDetails.tsx @@ -26,6 +26,7 @@ import { l } from '../../services/Labels'; import { OptionsContext } from '../OptionsProvider'; import { FieldModel } from '../../services/models/Field'; import styled from '../../styled-components'; +import { ArraySchema } from '../Schema'; const MAX_PATTERN_LENGTH = 45; @@ -63,11 +64,19 @@ export class FieldDetails extends React.PureComponent
- {schema.typePrefix} - {schema.displayType} + {schema.type === 'array' ? + + : + (<> + {schema.typePrefix} + {schema.displayType} + + ) + } {schema.displayFormat && ( {' '} From b5fb40747061d3e3b5afa907d8cd56d84a4a706c Mon Sep 17 00:00:00 2001 From: Andriy Zaleskyy Date: Tue, 12 Oct 2021 11:05:24 +0300 Subject: [PATCH 2/7] Revert "fix: No maxLength label is displayed for arrays of items #1701" This reverts commit 543ecc4d3902c3af3936f1b2e281ccb63cf96332. --- src/components/Fields/FieldDetails.tsx | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/components/Fields/FieldDetails.tsx b/src/components/Fields/FieldDetails.tsx index bbd522bc50..1aad8c6182 100644 --- a/src/components/Fields/FieldDetails.tsx +++ b/src/components/Fields/FieldDetails.tsx @@ -26,7 +26,6 @@ import { l } from '../../services/Labels'; import { OptionsContext } from '../OptionsProvider'; import { FieldModel } from '../../services/models/Field'; import styled from '../../styled-components'; -import { ArraySchema } from '../Schema'; const MAX_PATTERN_LENGTH = 45; @@ -64,19 +63,11 @@ export class FieldDetails extends React.PureComponent
- {schema.type === 'array' ? - - : - (<> - {schema.typePrefix} - {schema.displayType} - - ) - } + {schema.typePrefix} + {schema.displayType} {schema.displayFormat && ( {' '} From 74bcf11514d0b7b0351adce6bafff6526f07802f Mon Sep 17 00:00:00 2001 From: Andriy Zaleskyy Date: Tue, 12 Oct 2021 14:58:12 +0300 Subject: [PATCH 3/7] fix: No maxLength label is displayed for arrays of items #1701 --- src/components/Fields/ArrayItemDetails.tsx | 27 +++++++ src/components/Fields/EnumValues.tsx | 6 +- src/components/Fields/Examples.tsx | 35 +++++++++ src/components/Fields/FieldDetails.tsx | 83 +++------------------- src/components/Fields/Pattern.tsx | 30 ++++++++ src/utils/openapi.ts | 9 +++ 6 files changed, 114 insertions(+), 76 deletions(-) create mode 100644 src/components/Fields/ArrayItemDetails.tsx create mode 100644 src/components/Fields/Examples.tsx create mode 100644 src/components/Fields/Pattern.tsx diff --git a/src/components/Fields/ArrayItemDetails.tsx b/src/components/Fields/ArrayItemDetails.tsx new file mode 100644 index 0000000000..8d9c5e2a0d --- /dev/null +++ b/src/components/Fields/ArrayItemDetails.tsx @@ -0,0 +1,27 @@ +import * as React from 'react'; +import { TypeFormat, TypeName, 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 ( + + {schema.typePrefix} + {schema.displayType} + {schema.displayFormat && ( + {` <${schema.displayFormat}> `} + )} + + + {schema.items && } + + ); +} + + const ArrayItemDetailsStyled = styled.div` + padding-left: 7px; +`; diff --git a/src/components/Fields/EnumValues.tsx b/src/components/Fields/EnumValues.tsx index d10f9f692a..43e5c73b50 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 0000000000..690ecb9a87 --- /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/FieldDetails.tsx b/src/components/Fields/FieldDetails.tsx index 1aad8c6182..64a0f99a40 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,30 +21,19 @@ 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'; - -const MAX_PATTERN_LENGTH = 45; +import { Pattern } from './Pattern'; +import { ArrayItemDetails } from './ArrayItemDetails'; export class FieldDetails extends React.PureComponent { - state = { - patternShown: false, - }; - static contextType = OptionsContext; - 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 { enumSkipQuotes, hideSchemaTitles } = this.context; const { schema, description, example, deprecated, examples } = field; + const { type } = schema; + const isArrayType = type === 'array'; const rawDefault = !!enumSkipQuotes || field.in === 'header'; // having quotes around header field default values is confusing and inappropriate @@ -92,20 +78,7 @@ export class FieldDetails extends React.PureComponent ({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 && ( @@ -114,7 +87,7 @@ export class FieldDetails extends React.PureComponent )} - {!renderDiscriminatorSwitch && }{' '} + {!renderDiscriminatorSwitch && }{' '} {renderedExamples} {}
    @@ -125,44 +98,8 @@ export class FieldDetails extends React.PureComponent) || null} + {isArrayType && schema.items && }
    ); } } - -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} -
  • - ); - })} -
    - - ); -} - -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; -`; diff --git a/src/components/Fields/Pattern.tsx b/src/components/Fields/Pattern.tsx new file mode 100644 index 0000000000..8fdeea8b1a --- /dev/null +++ b/src/components/Fields/Pattern.tsx @@ -0,0 +1,30 @@ +import { PatternLabel, ToggleButton } from '../../common-elements/fields'; +import * as React from 'react'; +import { OptionsContext } from '../OptionsProvider'; +import { useCallback, useContext, useState } from 'react'; +import { SchemaModel } from '../../services'; + +const MAX_PATTERN_LENGTH = 45; + +export function Pattern(props: {schema: SchemaModel}) { + const pattern = props.schema.pattern; + const { hideSchemaPattern } = useContext(OptionsContext); + const [patternShown, usePatternShown] = useState(false); + const togglePattern = useCallback(() => usePatternShown(!patternShown), [patternShown]); + + if (!pattern || hideSchemaPattern) return null; + + return <> + + {patternShown || pattern.length < MAX_PATTERN_LENGTH + ? pattern + : `${pattern.substr(0, MAX_PATTERN_LENGTH)}...`} + + {pattern.length > MAX_PATTERN_LENGTH && ( + + {patternShown ? 'Hide pattern' : 'Show pattern'} + + )} + +} + diff --git a/src/utils/openapi.ts b/src/utils/openapi.ts index d0b081f535..6696e478b8 100644 --- a/src/utils/openapi.ts +++ b/src/utils/openapi.ts @@ -362,6 +362,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'; From 2fa1db4045120b4a67112ae62036791ce2f29e5c Mon Sep 17 00:00:00 2001 From: Oprysk Date: Wed, 5 Jan 2022 15:49:53 +0200 Subject: [PATCH 4/7] change array items display --- .eslintrc.js | 4 +- demo/webpack.config.ts | 1 + package-lock.json | 392 +++++++++++++++------ package.json | 3 +- src/common-elements/linkify.tsx | 2 +- src/components/Fields/ArrayItemDetails.tsx | 26 +- src/components/Fields/FieldDetail.tsx | 26 +- src/components/Fields/FieldDetails.tsx | 145 ++++---- src/components/Fields/Pattern.tsx | 36 +- src/components/StoreBuilder.ts | 1 + tsconfig.json | 22 +- 11 files changed, 404 insertions(+), 254 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 524f435e58..94d167b862 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/demo/webpack.config.ts b/demo/webpack.config.ts index 6317ba77b2..3edd4af80b 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/package-lock.json b/package-lock.json index 6a8142152e..2746ce1eca 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 14d3f995f1..5434949c41 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/linkify.tsx b/src/common-elements/linkify.tsx index fe8f942b29..4ace029e9c 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 index 8d9c5e2a0d..7a00d322fe 100644 --- a/src/components/Fields/ArrayItemDetails.tsx +++ b/src/components/Fields/ArrayItemDetails.tsx @@ -1,27 +1,27 @@ import * as React from 'react'; -import { TypeFormat, TypeName, TypePrefix } from '../../common-elements/fields'; +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; + if (!schema || (schema.type === 'string' && !schema.constraints.length)) return null; return ( - - {schema.typePrefix} - {schema.displayType} - {schema.displayFormat && ( - {` <${schema.displayFormat}> `} - )} + + [ items + {schema.displayFormat && {` <${schema.displayFormat}> `}} - - {schema.items && } - + + {schema.items && } ] + ); } - const ArrayItemDetailsStyled = styled.div` - padding-left: 7px; +const Wrapper = styled(TypePrefix)` + display: inline-block; + margin: 0 5px; + + height: calc(${({ theme }) => theme.typography.code.fontSize} + 4px); `; diff --git a/src/components/Fields/FieldDetail.tsx b/src/components/Fields/FieldDetail.tsx index e5b2818969..a14cfb1d47 100644 --- a/src/components/Fields/FieldDetail.tsx +++ b/src/components/Fields/FieldDetail.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import React from 'react'; import { ExampleValue, FieldLabel } from '../../common-elements/fields'; export interface FieldDetailProps { @@ -7,18 +7,18 @@ export interface FieldDetailProps { raw?: boolean; } -export class FieldDetail extends React.PureComponent { - render() { - if (this.props.value === undefined) { - return null; - } +function FieldDetailComponent({ value, label, raw }: FieldDetailProps) { + if (value === undefined) { + return null; + } - const value = this.props.raw ? String(this.props.value) : JSON.stringify(this.props.value); + const stringifyValue = raw ? String(value) : JSON.stringify(value); - return ( -
    - {this.props.label} {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 3d943c8362..80d35cee88 100644 --- a/src/components/Fields/FieldDetails.tsx +++ b/src/components/Fields/FieldDetails.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import React, { useContext, useMemo } from 'react'; import { RecursiveLabel, @@ -24,88 +24,89 @@ import { OptionsContext } from '../OptionsProvider'; import { Pattern } from './Pattern'; import { ArrayItemDetails } from './ArrayItemDetails'; -export class FieldDetails extends React.PureComponent { - static contextType = OptionsContext; +function FieldDetailsComponent(props: FieldProps) { + const { enumSkipQuotes, hideSchemaTitles } = useContext(OptionsContext); - render() { - const { showExamples, field, renderDiscriminatorSwitch } = this.props; - const { enumSkipQuotes, hideSchemaTitles } = this.context; + const { showExamples, field, renderDiscriminatorSwitch } = props; + const { schema, description, deprecated, extensions, in: _in, const: _const } = field; + const isArrayType = schema.type === 'array'; - const { schema, description, example, deprecated, examples } = field; - const { type } = schema; - const isArrayType = type === 'array'; + const rawDefault = enumSkipQuotes || _in === 'header'; // having quotes around header field default values is confusing and inappropriate - 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 = 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 ( + return null; + }, [field, showExamples]); + + return ( +
    -
    - {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')} } -
    - {deprecated && ( -
    - {l('deprecated')} -
    + {schema.typePrefix} + {schema.displayType} + {schema.displayFormat && ( + + {' '} + < + {schema.displayFormat} + >{' '} + )} - - {!renderDiscriminatorSwitch && ( - - )}{' '} - {renderedExamples} - {} -
    - -
    - {schema.externalDocs && ( - + {schema.contentEncoding && ( + + {' '} + < + {schema.contentEncoding} + >{' '} + )} - {(renderDiscriminatorSwitch && renderDiscriminatorSwitch(this.props)) || null} - {(field.const && ) || null} + {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} +
    + ); } + +export const FieldDetails = React.memo(FieldDetailsComponent); diff --git a/src/components/Fields/Pattern.tsx b/src/components/Fields/Pattern.tsx index 8fdeea8b1a..56542b5bd4 100644 --- a/src/components/Fields/Pattern.tsx +++ b/src/components/Fields/Pattern.tsx @@ -1,30 +1,30 @@ +import React, { useCallback, useContext, useState } from 'react'; import { PatternLabel, ToggleButton } from '../../common-elements/fields'; -import * as React from 'react'; import { OptionsContext } from '../OptionsProvider'; -import { useCallback, useContext, useState } from 'react'; import { SchemaModel } from '../../services'; const MAX_PATTERN_LENGTH = 45; -export function Pattern(props: {schema: SchemaModel}) { +export function Pattern(props: { schema: SchemaModel }) { const pattern = props.schema.pattern; const { hideSchemaPattern } = useContext(OptionsContext); - const [patternShown, usePatternShown] = useState(false); - const togglePattern = useCallback(() => usePatternShown(!patternShown), [patternShown]); + const [isPatternShown, setIsPatternShown] = useState(false); + const togglePattern = useCallback(() => setIsPatternShown(!isPatternShown), [isPatternShown]); if (!pattern || hideSchemaPattern) return null; - return <> - - {patternShown || pattern.length < MAX_PATTERN_LENGTH - ? pattern - : `${pattern.substr(0, MAX_PATTERN_LENGTH)}...`} - - {pattern.length > MAX_PATTERN_LENGTH && ( - - {patternShown ? 'Hide pattern' : 'Show pattern'} - - )} - + 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 7c12784cef..df8b23b0b8 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/tsconfig.json b/tsconfig.json index 18a22b364f..32bd4f3a32 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,27 +13,13 @@ "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"], + "allowSyntheticDefaultImports": true }, "compileOnSave": false, - "exclude": [ - "node_modules", - ".tmp", - "lib", - "e2e/**" - ], + "exclude": ["node_modules", ".tmp", "lib", "e2e/**"], "include": [ "cli/index.ts", "./custom.d.ts", From bc020f49dbddbfd5abf4c4db0b1d886a77f9e8b5 Mon Sep 17 00:00:00 2001 From: Oprysk Date: Wed, 5 Jan 2022 16:02:17 +0200 Subject: [PATCH 5/7] fix alignment --- src/components/Fields/ArrayItemDetails.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/Fields/ArrayItemDetails.tsx b/src/components/Fields/ArrayItemDetails.tsx index 7a00d322fe..0c2716b13d 100644 --- a/src/components/Fields/ArrayItemDetails.tsx +++ b/src/components/Fields/ArrayItemDetails.tsx @@ -20,8 +20,6 @@ export function ArrayItemDetails({ schema }: { schema: SchemaModel }) { } const Wrapper = styled(TypePrefix)` - display: inline-block; margin: 0 5px; - - height: calc(${({ theme }) => theme.typography.code.fontSize} + 4px); + vertical-align: text-top; `; From 60de0c7aad44289b27f79f31df84847dd922c69b Mon Sep 17 00:00:00 2001 From: Oprysk Date: Wed, 5 Jan 2022 16:49:01 +0200 Subject: [PATCH 6/7] remove theme font from labels --- src/common-elements/fields.ts | 1 - src/components/Fields/FieldDetail.tsx | 2 +- src/components/Fields/FieldDetails.tsx | 6 +- src/components/Fields/Pattern.tsx | 11 ++- .../loadAndBundleSpec.test.ts.snap | 96 ++++++++++++++++++- tsconfig.json | 3 +- 6 files changed, 106 insertions(+), 13 deletions(-) diff --git a/src/common-elements/fields.ts b/src/common-elements/fields.ts index c8d0df1b0d..2fbac2cba8 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/components/Fields/FieldDetail.tsx b/src/components/Fields/FieldDetail.tsx index a14cfb1d47..53fb89bfc6 100644 --- a/src/components/Fields/FieldDetail.tsx +++ b/src/components/Fields/FieldDetail.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import * as React from 'react'; import { ExampleValue, FieldLabel } from '../../common-elements/fields'; export interface FieldDetailProps { diff --git a/src/components/Fields/FieldDetails.tsx b/src/components/Fields/FieldDetails.tsx index 80d35cee88..c04a5b0fc4 100644 --- a/src/components/Fields/FieldDetails.tsx +++ b/src/components/Fields/FieldDetails.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useMemo } from 'react'; +import * as React from 'react'; import { RecursiveLabel, @@ -25,7 +25,7 @@ import { Pattern } from './Pattern'; import { ArrayItemDetails } from './ArrayItemDetails'; function FieldDetailsComponent(props: FieldProps) { - const { enumSkipQuotes, hideSchemaTitles } = useContext(OptionsContext); + const { enumSkipQuotes, hideSchemaTitles } = React.useContext(OptionsContext); const { showExamples, field, renderDiscriminatorSwitch } = props; const { schema, description, deprecated, extensions, in: _in, const: _const } = field; @@ -33,7 +33,7 @@ function FieldDetailsComponent(props: FieldProps) { const rawDefault = enumSkipQuotes || _in === 'header'; // having quotes around header field default values is confusing and inappropriate - const renderedExamples = useMemo(() => { + const renderedExamples = React.useMemo(() => { if (showExamples && (field.example !== undefined || field.examples !== undefined)) { if (field.examples !== undefined) { return ; diff --git a/src/components/Fields/Pattern.tsx b/src/components/Fields/Pattern.tsx index 56542b5bd4..3b0c17ea10 100644 --- a/src/components/Fields/Pattern.tsx +++ b/src/components/Fields/Pattern.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useContext, useState } from 'react'; +import * as React from 'react'; import { PatternLabel, ToggleButton } from '../../common-elements/fields'; import { OptionsContext } from '../OptionsProvider'; import { SchemaModel } from '../../services'; @@ -7,9 +7,12 @@ const MAX_PATTERN_LENGTH = 45; export function Pattern(props: { schema: SchemaModel }) { const pattern = props.schema.pattern; - const { hideSchemaPattern } = useContext(OptionsContext); - const [isPatternShown, setIsPatternShown] = useState(false); - const togglePattern = useCallback(() => setIsPatternShown(!isPatternShown), [isPatternShown]); + const { hideSchemaPattern } = React.useContext(OptionsContext); + const [isPatternShown, setIsPatternShown] = React.useState(false); + const togglePattern = React.useCallback( + () => setIsPatternShown(!isPatternShown), + [isPatternShown], + ); if (!pattern || hideSchemaPattern) return null; diff --git a/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap b/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap index 6cd0a034df..5d30e78a44 100644 --- a/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap +++ b/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap @@ -277,10 +277,102 @@ Object { }, }, "name": Object { - "description": "The name given to a pet", - "example": "Guru", + "description": "this is a description", + "items": Object { + "maxLength": 80, + "type": "string", + }, + "type": "array", + }, + "name1": Object { + "description": "this is a description", + "items": Object { + "pattern": "^[a-z]$", + "type": "string", + }, + "type": "array", + }, + "name10": Object { + "description": "description", + "maxLength": 80, + "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$", "type": "string", }, + "name2": Object { + "description": "this is a description", + "items": Object { + "maxLength": 80, + "minLength": 2, + "type": "string", + }, + "type": "array", + }, + "name3": Object { + "description": "this is a description", + "items": Object { + "maxLength": 80, + "minLength": 2, + "pattern": "^[a-z]$", + "type": "string", + }, + "type": "array", + }, + "name4": Object { + "description": "this is a description", + "items": Object { + "multipleOf": 5, + "type": "integer", + }, + "maxItems": 5, + "type": "array", + }, + "name5": Object { + "description": "this is a description", + "items": Object { + "maximum": 10, + "multipleOf": 5, + "type": "integer", + }, + "type": "array", + }, + "name6": Object { + "description": "this is a description", + "items": Object { + "maximum": 10, + "minimum": 5, + "multipleOf": 5, + "type": "integer", + }, + "type": "array", + }, + "name7": Object { + "description": "this is a description", + "items": Object { + "maximum": 100, + "minimum": 1, + "type": "integer", + }, + "type": "array", + }, + "name8": Object { + "description": "this is a description", + "items": Object { + "exclusiveMaximum": true, + "maximum": 100, + "minimum": 1, + "type": "integer", + }, + "type": "array", + }, + "name9": Object { + "description": "this is a description", + "items": Object { + "exclusiveMaximum": 100, + "minimum": 1, + "type": "integer", + }, + "type": "array", + }, "petType": Object { "description": "Type of a pet", "type": "string", diff --git a/tsconfig.json b/tsconfig.json index 32bd4f3a32..21dbb32607 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,8 +15,7 @@ "pretty": true, "lib": ["es2015", "es2016", "es2017", "dom", "WebWorker.ImportScripts"], "jsx": "react", - "types": ["webpack", "webpack-env", "jest"], - "allowSyntheticDefaultImports": true + "types": ["webpack", "webpack-env", "jest"] }, "compileOnSave": false, "exclude": ["node_modules", ".tmp", "lib", "e2e/**"], From 5aea27aae291006141692768d24539effca7e0c3 Mon Sep 17 00:00:00 2001 From: Oprysk Date: Wed, 5 Jan 2022 16:52:54 +0200 Subject: [PATCH 7/7] update snapshot --- .../loadAndBundleSpec.test.ts.snap | 96 +------------------ 1 file changed, 2 insertions(+), 94 deletions(-) diff --git a/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap b/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap index 5d30e78a44..6cd0a034df 100644 --- a/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap +++ b/src/utils/__tests__/__snapshots__/loadAndBundleSpec.test.ts.snap @@ -277,102 +277,10 @@ Object { }, }, "name": Object { - "description": "this is a description", - "items": Object { - "maxLength": 80, - "type": "string", - }, - "type": "array", - }, - "name1": Object { - "description": "this is a description", - "items": Object { - "pattern": "^[a-z]$", - "type": "string", - }, - "type": "array", - }, - "name10": Object { - "description": "description", - "maxLength": 80, - "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}$", + "description": "The name given to a pet", + "example": "Guru", "type": "string", }, - "name2": Object { - "description": "this is a description", - "items": Object { - "maxLength": 80, - "minLength": 2, - "type": "string", - }, - "type": "array", - }, - "name3": Object { - "description": "this is a description", - "items": Object { - "maxLength": 80, - "minLength": 2, - "pattern": "^[a-z]$", - "type": "string", - }, - "type": "array", - }, - "name4": Object { - "description": "this is a description", - "items": Object { - "multipleOf": 5, - "type": "integer", - }, - "maxItems": 5, - "type": "array", - }, - "name5": Object { - "description": "this is a description", - "items": Object { - "maximum": 10, - "multipleOf": 5, - "type": "integer", - }, - "type": "array", - }, - "name6": Object { - "description": "this is a description", - "items": Object { - "maximum": 10, - "minimum": 5, - "multipleOf": 5, - "type": "integer", - }, - "type": "array", - }, - "name7": Object { - "description": "this is a description", - "items": Object { - "maximum": 100, - "minimum": 1, - "type": "integer", - }, - "type": "array", - }, - "name8": Object { - "description": "this is a description", - "items": Object { - "exclusiveMaximum": true, - "maximum": 100, - "minimum": 1, - "type": "integer", - }, - "type": "array", - }, - "name9": Object { - "description": "this is a description", - "items": Object { - "exclusiveMaximum": 100, - "minimum": 1, - "type": "integer", - }, - "type": "array", - }, "petType": Object { "description": "Type of a pet", "type": "string",