From eb394081670de7ca46ea8a74bbee93cdfd646c00 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Mon, 23 Dec 2024 16:24:41 +1300 Subject: [PATCH 01/23] Tab functionality --- .eslintignore | 2 + demo/src/_imports.ts | 4 +- jest.config.js | 9 + package.json | 4 + src/CollectionNode.tsx | 1 - src/ValueNodeWrapper.tsx | 2 +- src/ValueNodes.tsx | 16 +- src/helpers.ts | 59 ++ src/types.ts | 2 + test/nextPrevious.test.ts | 78 ++ yarn.lock | 1784 ++++++++++++++++++++++++++++++++++++- 11 files changed, 1940 insertions(+), 21 deletions(-) create mode 100644 jest.config.js create mode 100644 test/nextPrevious.test.ts diff --git a/.eslintignore b/.eslintignore index 0e7b3a9c..6235b6c2 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,4 @@ *.css .eslintrc.js +*.test.* +jest.config.js diff --git a/demo/src/_imports.ts b/demo/src/_imports.ts index 295d8b6f..ccb43158 100644 --- a/demo/src/_imports.ts +++ b/demo/src/_imports.ts @@ -3,10 +3,10 @@ */ /* Installed package */ -export * from 'json-edit-react' +// export * from 'json-edit-react' /* Local src */ -// export * from './json-edit-react/src' +export * from './json-edit-react/src' /* Compiled local package */ // export * from './package/build' diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..fcaac7c0 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,9 @@ +module.exports = { + roots: ['/test'], + testMatch: ['**/__tests__/**/*.+(ts|tsx|js)', '**/?(*.)+(spec|test).+(ts|tsx|js)'], + transform: { + '^.+\\.(ts|tsx)$': 'ts-jest', + }, + verbose: true, + testTimeout: 10000, +} diff --git a/package.json b/package.json index 86551abf..6e05518b 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "homepage": "https://carlosnz.github.io/json-edit-react", "scripts": { "setup": "yarn install && cd demo && yarn install", + "test": "jest", "demo": "cd demo && node ./scripts/getVersion.js && yarn && yarn start", "build": "rimraf ./build && rollup -c && rimraf ./build/dts", "lint": "npx eslint \"src/**\"", @@ -48,6 +49,7 @@ "@rollup/plugin-node-resolve": "^16.0.0", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.6", + "@types/jest": "^29.5.14", "@types/node": "^20.11.17", "@types/react": ">=16.0.0", "@typescript-eslint/eslint-plugin": "^6.4.0", @@ -60,6 +62,7 @@ "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "fs-extra": "^11.2.0", + "jest": "^29.7.0", "react-dom": ">=16.0.0", "rimraf": "^5.0.5", "rollup": "^4.10.0", @@ -68,6 +71,7 @@ "rollup-plugin-peer-deps-external": "^2.2.4", "rollup-plugin-sizes": "^1.0.6", "rollup-plugin-styles": "^4.0.0", + "ts-jest": "^29.2.5", "ts-node": "^10.9.2", "tslib": "^2.6.2", "typescript": "^5.3.3" diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index d8cba36c..ecc4bb58 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -1,5 +1,4 @@ import React, { useEffect, useState, useMemo, useRef } from 'react' -import extractProperty from 'object-property-extractor' import { ValueNodeWrapper } from './ValueNodeWrapper' import { EditButtons, InputButtons } from './ButtonPanels' import { getCustomNode } from './CustomNode' diff --git a/src/ValueNodeWrapper.tsx b/src/ValueNodeWrapper.tsx index 402d7ee9..2f1c791e 100644 --- a/src/ValueNodeWrapper.tsx +++ b/src/ValueNodeWrapper.tsx @@ -19,7 +19,7 @@ import { } from './types' import { useTheme, useTreeState } from './contexts' import { getCustomNode, type CustomNodeData } from './CustomNode' -import { filterNode } from './helpers' +import { filterNode, getNextOrPrevious, getPrevious } from './helpers' import { useCommon, useDragNDrop } from './hooks' export const ValueNodeWrapper: React.FC = (props) => { diff --git a/src/ValueNodes.tsx b/src/ValueNodes.tsx index c166a6bc..1f4ea6bb 100644 --- a/src/ValueNodes.tsx +++ b/src/ValueNodes.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from 'react' import { AutogrowTextArea } from './AutogrowTextArea' -import { toPathString, truncate } from './helpers' -import { useTheme } from './contexts' +import { getNextOrPrevious, getPrevious, toPathString, truncate } from './helpers' +import { useTheme, useTreeState } from './contexts' import { type InputProps } from './types' export const INVALID_FUNCTION_STRING = '**INVALID_FUNCTION**' @@ -20,6 +20,7 @@ export const StringValue: React.FC = ({ handleKeyboard, }) => { const { getStyles } = useTheme() + const { setCurrentlyEditingElement } = useTreeState() const pathString = toPathString(path) @@ -53,6 +54,17 @@ export const StringValue: React.FC = ({ setValue(strStart + '\n' + strEnd) } }, + tabForward: () => { + const next = getNextOrPrevious(nodeData.fullData, path) + // if (next) { + // handleEdit() + // setCurrentlyEditingElement(toPathString(next)) + // } + console.log('NExt', next) + }, + tabBack: () => { + console.log('PReb', getNextOrPrevious(nodeData.fullData, path, 'prev')) + }, }) }} styles={getStyles('input', nodeData)} diff --git a/src/helpers.ts b/src/helpers.ts index 47764b30..6981d1fc 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -1,3 +1,4 @@ +import extractProperty from 'object-property-extractor' import { type SearchFilterFunction, type NodeData, @@ -5,6 +6,9 @@ import { type KeyboardControls, type KeyEvent, type KeyboardControlsFull, + type JsonData, + type CollectionKey, + type CollectionData, } from './types' export const isCollection = (value: unknown): value is Record | unknown[] => @@ -202,6 +206,8 @@ const defaultKeyboardControls: KeyboardControlsFull = { numberConfirm: ENTER, numberUp: { key: 'ArrowUp' }, numberDown: { key: 'ArrowDown' }, + tabForward: { key: 'Tab' }, + tabBack: { key: 'Tab', modifier: 'Shift' }, booleanConfirm: ENTER, clipboardModifier: ['Meta', 'Control'], collapseModifier: ['Alt'], @@ -239,3 +245,56 @@ export const getFullKeyboardControlMap = (userControls: KeyboardControls): Keybo return controls } + +/** + * TAB key helpers + */ + +export const getNextOrPrevious = ( + fullData: JsonData, + path: CollectionKey[], + nextOrPrev: 'next' | 'prev' = 'next' +): CollectionKey[] | null => { + const parentPath = path.slice(0, path.length - 1) + const thisKey = path.slice(-1)[0] + if (thisKey === undefined) return null + + const parentData = extractProperty(fullData, parentPath) + const collection = transformCollection(parentData as JsonData) + + const thisIndex = collection.findIndex((el) => el.key === thisKey) + const destinationIndex = nextOrPrev === 'next' ? thisIndex + 1 : thisIndex - 1 + + const destination = collection[destinationIndex] + + if (!destination) { + if (parentPath.length === 0) return null + return getNextOrPrevious(fullData, parentPath, nextOrPrev) + } + + if (isCollection(destination.value)) { + return getChildRecursive(fullData, [...parentPath, destination.key], nextOrPrev) + } else return [...parentPath, destination.key] +} + +// If the node at "path" is a collection, tries the first/last child of that +// collection recursively until a Value node is found +const getChildRecursive = ( + fullData: JsonData, + path: CollectionKey[], + nextOrPrev: 'next' | 'prev' = 'next' +) => { + const node = extractProperty(fullData, path) + if (!isCollection(node)) return path + const keys = Array.isArray(node) ? node.map((_, index) => index) : Object.keys(node) + const child = nextOrPrev === 'next' ? keys[0] : keys[keys.length - 1] + return getChildRecursive(fullData, [...path, child], nextOrPrev) +} + +// Transform a collections (Array or Object) into a structure that is easier to +// navigate forward and back within +const transformCollection = (collection: JsonData) => { + if (Array.isArray(collection)) + return collection.map((value, index) => ({ index, value, key: index })) + return Object.entries(collection).map(([key, value], index) => ({ key, value, index })) +} diff --git a/src/types.ts b/src/types.ts index e31f0841..4a9191c2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -169,6 +169,8 @@ export interface KeyboardControls { numberConfirm?: KeyEvent | string numberUp?: KeyEvent | string numberDown?: KeyEvent | string + tabForward?: KeyEvent | string + tabBack?: KeyEvent | string clipboardModifier?: React.ModifierKey | React.ModifierKey[] collapseModifier?: React.ModifierKey | React.ModifierKey[] } diff --git a/test/nextPrevious.test.ts b/test/nextPrevious.test.ts new file mode 100644 index 00000000..083dee97 --- /dev/null +++ b/test/nextPrevious.test.ts @@ -0,0 +1,78 @@ +import { getNextOrPrevious } from '../demo/src/json-edit-react/src/helpers' + +const getNext = getNextOrPrevious +const getPrevious = (data: object, path: (string | number)[]) => + getNextOrPrevious(data, path, 'prev') + +const data = { + a: 1, + b: 'something', + cee: 99, + dee: { + inner: 'value', + inner2: 45, + inner3: { + innerDeep: 2.4, + innerDeep2: [1, 2, 3], + innerBool: false, + innerArray: [ + { one: 1, two: 'two', three: true, four: null, five: true }, + { one: 'one', two: 2, three: 3, four: { one: 1 }, 45: 'Number' }, + ], + }, + }, + obj2: { 1: true, 2: 'two' }, + arr: [1, 'two', { three: 4 }, false, undefined, null, 7, 8, 9, 10, 11, 12], +} + +test('Root level', () => { + const curr = ['a'] + expect(getNext(data, curr)).toEqual(['b']) + expect(getPrevious(data, curr)).toEqual(null) +}) + +test('Inside object', () => { + expect(getNext(data, ['dee', 'inner'])).toEqual(['dee', 'inner2']) + expect(getPrevious(data, ['dee', 'inner2'])).toEqual(['dee', 'inner']) +}) + +test('Next traverses object, one level', () => { + expect(getNext(data, ['dee', 'inner2'])).toEqual(['dee', 'inner3', 'innerDeep']) + expect(getPrevious(data, ['dee', 'inner3', 'innerDeep'])).toEqual(['dee', 'inner2']) +}) + +test('Next traverses object, multi-level, incl. Array', () => { + expect(getNext(data, ['dee', 'inner3', 'innerBool'])).toEqual([ + 'dee', + 'inner3', + 'innerArray', + 0, + 'one', + ]) + expect(getPrevious(data, ['dee', 'inner3', 'innerArray', 0, 'one'])).toEqual([ + 'dee', + 'inner3', + 'innerBool', + ]) +}) + +test('Traverse from within array', () => { + expect(getNext(data, ['dee', 'inner3', 'innerDeep2', 1])).toEqual([ + 'dee', + 'inner3', + 'innerDeep2', + 2, + ]) + expect(getPrevious(data, ['dee', 'inner3', 'innerDeep2', 1])).toEqual([ + 'dee', + 'inner3', + 'innerDeep2', + 0, + ]) + expect(getNext(data, ['dee', 'inner3', 'innerDeep2', 2])).toEqual(['dee', 'inner3', 'innerBool']) + expect(getPrevious(data, ['dee', 'inner3', 'innerDeep2', 0])).toEqual([ + 'dee', + 'inner3', + 'innerDeep', + ]) +}) diff --git a/yarn.lock b/yarn.lock index ae83c175..364dfb57 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + "@babel/code-frame@^7.0.0": version "7.23.5" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" @@ -10,6 +18,15 @@ "@babel/highlight" "^7.23.4" chalk "^2.4.2" +"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" + "@babel/code-frame@^7.24.2": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" @@ -18,11 +35,104 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" +"@babel/compat-data@^7.25.9": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.3.tgz#99488264a56b2aded63983abd6a417f03b92ed02" + integrity sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40" + integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.26.0" + "@babel/generator" "^7.26.0" + "@babel/helper-compilation-targets" "^7.25.9" + "@babel/helper-module-transforms" "^7.26.0" + "@babel/helpers" "^7.26.0" + "@babel/parser" "^7.26.0" + "@babel/template" "^7.25.9" + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.26.0" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.26.0", "@babel/generator@^7.26.3", "@babel/generator@^7.7.2": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.3.tgz#ab8d4360544a425c90c248df7059881f4b2ce019" + integrity sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ== + dependencies: + "@babel/parser" "^7.26.3" + "@babel/types" "^7.26.3" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz#55af025ce365be3cdc0c1c1e56c6af617ce88875" + integrity sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ== + dependencies: + "@babel/compat-data" "^7.25.9" + "@babel/helper-validator-option" "^7.25.9" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-module-imports@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" + integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/helper-module-transforms@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae" + integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== + dependencies: + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.8.0": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz#9cbdd63a9443a2c92a725cca7ebca12cc8dd9f46" + integrity sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw== + +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + "@babel/helper-validator-identifier@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@babel/helper-validator-option@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" + integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== + +"@babel/helpers@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4" + integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw== + dependencies: + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.0" + "@babel/highlight@^7.23.4", "@babel/highlight@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" @@ -33,6 +143,167 @@ js-tokens "^4.0.0" picocolors "^1.0.0" +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234" + integrity sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA== + dependencies: + "@babel/types" "^7.26.3" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz#3b1412847699eea739b4f2602c74ce36f6b0b0f7" + integrity sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz#a34313a178ea56f1951599b929c1ceacee719290" + integrity sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz#67dda2b74da43727cf21d46cf9afef23f4365399" + integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/template@^7.25.9", "@babel/template@^7.3.3": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" + integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg== + dependencies: + "@babel/code-frame" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/types" "^7.25.9" + +"@babel/traverse@^7.25.9": + version "7.26.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.4.tgz#ac3a2a84b908dde6d463c3bfa2c5fdc1653574bd" + integrity sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.3" + "@babel/parser" "^7.26.3" + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.3" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.3", "@babel/types@^7.3.3": + version "7.26.3" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0" + integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" @@ -108,6 +379,214 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jridgewell/gen-mapping@^0.3.0": version "0.3.3" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" @@ -117,6 +596,15 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" + integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.1" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" @@ -127,6 +615,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + "@jridgewell/source-map@^0.3.3": version "0.3.5" resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" @@ -153,6 +646,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@jridgewell/trace-mapping@^0.3.9": version "0.3.22" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz#72a621e5de59f5f1ef792d0793a82ee20f645e4c" @@ -326,6 +827,25 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + "@trysound/sax@0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" @@ -351,6 +871,39 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== + dependencies: + "@babel/types" "^7.20.7" + "@types/cssnano@^5.0.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@types/cssnano/-/cssnano-5.1.0.tgz#a83529c148dccc984bccbe33563941f0fa6bd1e9" @@ -363,6 +916,40 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.5.14": + version "29.5.14" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5" + integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + "@types/json-schema@^7.0.12": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" @@ -373,6 +960,13 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/node@*": + version "22.10.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.2.tgz#a485426e6d1fdafc7b0d4c7b24e2c78182ddabb9" + integrity sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ== + dependencies: + undici-types "~6.20.0" + "@types/node@^20.11.17": version "20.16.5" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.16.5.tgz#d43c7f973b32ffdf9aa7bd4f80e1072310fd7a53" @@ -408,6 +1002,23 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.7.tgz#326f5fdda70d13580777bcaa1bc6fa772a5aef0e" integrity sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg== +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== + dependencies: + "@types/yargs-parser" "*" + "@typescript-eslint/eslint-plugin@^6.4.0": version "6.21.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz#30830c1ca81fd5f3c2714e524c4303e0194f9cd3" @@ -529,6 +1140,13 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -558,11 +1176,31 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -662,6 +1300,11 @@ arraybuffer.prototype.slice@^1.0.3: is-array-buffer "^3.0.4" is-shared-array-buffer "^1.0.2" +async@^3.2.3: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== + available-typed-arrays@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" @@ -669,6 +1312,69 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30" + integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -711,6 +1417,30 @@ browserslist@^4.0.0, browserslist@^4.21.4, browserslist@^4.22.2: node-releases "^2.0.14" update-browserslist-db "^1.0.13" +browserslist@^4.24.0: + version "4.24.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.3.tgz#5fc2725ca8fb3c1432e13dac278c7cc103e026d2" + integrity sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA== + dependencies: + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" + update-browserslist-db "^1.1.1" + +bs-logger@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -744,6 +1474,16 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" @@ -759,6 +1499,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001580: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001660.tgz" integrity sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg== +caniuse-lite@^1.0.30001688: + version "1.0.30001690" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz#f2d15e3aaf8e18f76b2b8c1481abde063b8104c8" + integrity sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w== + chalk@^1.0.0, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -779,7 +1524,7 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0: +chalk@^4.0.0, chalk@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -787,6 +1532,40 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" + integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -831,6 +1610,11 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + cosmiconfig@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" @@ -842,6 +1626,19 @@ cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -856,6 +1653,15 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +cross-spawn@^7.0.3: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + css-declaration-sorter@^6.3.1: version "6.4.1" resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71" @@ -1072,6 +1878,13 @@ debug@^3.2.7: dependencies: ms "^2.1.1" +debug@^4.1.0, debug@^4.1.1: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + debug@^4.3.1, debug@^4.3.2: version "4.3.6" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" @@ -1091,6 +1904,11 @@ decode-uri-component@^0.2.2: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== +dedent@^1.0.0: + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== + deep-is@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" @@ -1119,6 +1937,16 @@ define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -1205,11 +2033,28 @@ duplexer@^0.1.1: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== +ejs@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== + dependencies: + jake "^10.8.5" + electron-to-chromium@^1.4.648: version "1.4.668" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.668.tgz#5cfed14f3240cdc70a359a49790cb295b1f097f1" integrity sha512-ZOBocMYCehr9W31+GpMclR+KBaDZOoAEabLdhpZ8oU1JFDwIaFY0UDbpXVEUFc0BIP2O2Qn3rkfCjQmMR4T/bQ== +electron-to-chromium@^1.5.73: + version "1.5.75" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.75.tgz#bba96eabf0e8ca36324679caa38b982800acc87d" + integrity sha512-Lf3++DumRE/QmweGjU+ZcKqQ+3bKkU/qjaKYhIJKEOhgIO9Xs6IiAQFkfFoj+RhgDk4LUeNsLo6plExHqSyu6Q== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -1353,11 +2198,21 @@ escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" @@ -1552,6 +2407,11 @@ espree@^9.6.0, espree@^9.6.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + esquery@^1.4.2: version "1.6.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" @@ -1586,6 +2446,37 @@ eventemitter3@^4.0.4: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -1602,7 +2493,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -1619,6 +2510,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + figures@^1.0.1: version "1.7.0" resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" @@ -1634,6 +2532,13 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +filelist@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" + integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== + dependencies: + minimatch "^5.0.1" + filesize@^9.0.0: version "9.0.11" resolved "https://registry.yarnpkg.com/filesize/-/filesize-9.0.11.tgz#4ac3a42c084232dd9b2a1da0107f32d42fcfa5e4" @@ -1651,6 +2556,14 @@ filter-obj@^1.1.0: resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ== +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" @@ -1711,7 +2624,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2: +fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -1736,6 +2649,16 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" @@ -1747,6 +2670,16 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" @@ -1789,7 +2722,7 @@ glob@^10.3.7: package-json-from-dist "^1.0.0" path-scurry "^1.11.1" -glob@^7.1.3: +glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -1801,6 +2734,11 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + globals@^13.19.0, globals@^13.24.0: version "13.24.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" @@ -1835,7 +2773,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.6, graceful-fs@^4.2.0: +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -1905,6 +2843,16 @@ hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: dependencies: function-bind "^1.1.2" +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" @@ -1928,6 +2876,14 @@ import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" +import-local@^3.0.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -2016,6 +2972,13 @@ is-core-module@^2.13.0, is-core-module@^2.15.1: dependencies: hasown "^2.0.2" +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + is-data-view@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" @@ -2047,6 +3010,11 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + is-generator-function@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" @@ -2113,6 +3081,11 @@ is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: dependencies: call-bind "^1.0.7" +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -2164,6 +3137,59 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-instrument@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + iterator.prototype@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" @@ -2184,11 +3210,387 @@ jackspeak@^3.1.2: optionalDependencies: "@pkgjs/parseargs" "^0.11.0" +jake@^10.8.5: + version "10.9.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.2.tgz#6ae487e6a69afec3a5e167628996b59f35ae2b7f" + integrity sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA== + dependencies: + async "^3.2.3" + chalk "^4.0.2" + filelist "^1.0.4" + minimatch "^3.1.2" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -2196,6 +3598,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -2223,6 +3630,11 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -2249,6 +3661,16 @@ keyv@^4.5.3: dependencies: json-buffer "3.0.1" +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -2272,6 +3694,13 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -2306,6 +3735,13 @@ lru-cache@^10.2.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -2320,11 +3756,25 @@ magic-string@^0.30.10: dependencies: "@jridgewell/sourcemap-codec" "^1.5.0" -make-error@^1.1.1: +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@^1.1.1, make-error@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + maxmin@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/maxmin/-/maxmin-2.1.0.tgz#4d3b220903d95eee7eb7ac7fa864e72dc09a3166" @@ -2350,6 +3800,11 @@ mdn-data@2.0.30: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -2375,6 +3830,11 @@ mime-types@^2.1.34: dependencies: mime-db "1.52.0" +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + minimatch@9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" @@ -2382,13 +3842,20 @@ minimatch@9.0.3: dependencies: brace-expansion "^2.0.1" -minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + minimatch@^9.0.4: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" @@ -2416,7 +3883,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: +ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -2431,16 +3898,38 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + node-releases@^2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + nth-check@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" @@ -2532,6 +4021,13 @@ once@^1.3.0: dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -2549,13 +4045,27 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== -p-limit@^3.0.2: +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-locate@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -2578,6 +4088,11 @@ p-timeout@^3.2.0: dependencies: p-finally "^1.0.0" +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + package-json-from-dist@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" @@ -2590,7 +4105,7 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^5.0.0: +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -2610,7 +4125,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -2638,7 +4153,12 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.2.2, picomatch@^2.3.1: +picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -2648,6 +4168,18 @@ picomatch@^4.0.2: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + possible-typed-array-names@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" @@ -3108,6 +4640,23 @@ pretty-bytes@^3.0.0: dependencies: number-is-nan "^1.0.0" +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" @@ -3122,6 +4671,11 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +pure-rand@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== + query-string@^7.1.0: version "7.1.3" resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328" @@ -3157,6 +4711,11 @@ react-is@^16.13.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + reflect.getprototypeof@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" @@ -3180,16 +4739,47 @@ regexp.prototype.flags@^1.5.2: es-errors "^1.3.0" set-function-name "^2.0.1" +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + resolve-pkg-maps@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== +resolve.exports@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.3.tgz#41955e6f1b4013b7586f873749a635dea07ebe3f" + integrity sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== + +resolve@^1.20.0: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + resolve@^1.21.0, resolve@^1.22.1, resolve@^1.22.2, resolve@^1.22.4: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" @@ -3344,7 +4934,7 @@ scheduler@^0.23.2: dependencies: loose-envify "^1.1.0" -semver@^6.3.1: +semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -3356,6 +4946,11 @@ semver@^7.0.0, semver@^7.5.3, semver@^7.5.4: dependencies: lru-cache "^6.0.0" +semver@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + serialize-javascript@^6.0.1: version "6.0.2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" @@ -3407,11 +5002,21 @@ side-channel@^1.0.4, side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -3427,6 +5032,14 @@ source-map-js@^1.0.1, source-map-js@^1.0.2: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -3445,16 +5058,36 @@ split-on-first@^1.0.0: resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + stable@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + strict-uri-encode@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -3464,7 +5097,7 @@ strict-uri-encode@^2.0.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@4.2.2, string-width@^4.1.0, string-width@^5.1.2: +string-width@4.2.2, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3, string-width@^5.1.2: version "4.2.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== @@ -3546,6 +5179,16 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -3586,6 +5229,13 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -3627,11 +5277,25 @@ terser@^5.17.4: commander "^2.20.0" source-map-support "~0.5.20" +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -3644,6 +5308,21 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.2.1.tgz#f716c7e027494629485b21c0df6180f4d08f5e8b" integrity sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA== +ts-jest@^29.2.5: + version "29.2.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.5.tgz#591a3c108e1f5ebd013d3152142cb5472b399d63" + integrity sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA== + dependencies: + bs-logger "^0.2.6" + ejs "^3.1.10" + fast-json-stable-stringify "^2.1.0" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.6.3" + yargs-parser "^21.1.1" + ts-node@^10.9.2: version "10.9.2" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" @@ -3690,11 +5369,21 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + type-fest@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + typed-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" @@ -3759,6 +5448,11 @@ undici-types@~6.19.2: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== + universalify@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" @@ -3772,6 +5466,14 @@ update-browserslist-db@^1.0.13: escalade "^3.1.1" picocolors "^1.0.0" +update-browserslist-db@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.0" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -3789,6 +5491,22 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== +v8-to-istanbul@^9.0.1: + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -3860,7 +5578,7 @@ word-wrap@^1.2.5: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@7.0.0, wrap-ansi@^8.1.0: +wrap-ansi@7.0.0, wrap-ansi@^7.0.0, wrap-ansi@^8.1.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -3874,6 +5592,24 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" @@ -3884,6 +5620,24 @@ yaml@^1.10.0, yaml@^1.10.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" From 6fbedeb947e42c2038085ca64a121218d14f8fa3 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Mon, 23 Dec 2024 16:47:46 +1300 Subject: [PATCH 02/23] Pass common keyboard events from Wrapper --- src/ValueNodeWrapper.tsx | 19 ++++++++++++++++++- src/ValueNodes.tsx | 31 ++++++++++--------------------- src/types.ts | 1 + 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/ValueNodeWrapper.tsx b/src/ValueNodeWrapper.tsx index 2f1c791e..8f783e1b 100644 --- a/src/ValueNodeWrapper.tsx +++ b/src/ValueNodeWrapper.tsx @@ -19,7 +19,7 @@ import { } from './types' import { useTheme, useTreeState } from './contexts' import { getCustomNode, type CustomNodeData } from './CustomNode' -import { filterNode, getNextOrPrevious, getPrevious } from './helpers' +import { filterNode, getNextOrPrevious, toPathString } from './helpers' import { useCommon, useDragNDrop } from './hooks' export const ValueNodeWrapper: React.FC = (props) => { @@ -214,6 +214,23 @@ export const ValueNodeWrapper: React.FC = (props) => { nodeData, translate, handleKeyboard, + keyboardCommon: { + cancel: handleCancel, + tabForward: () => { + const next = getNextOrPrevious(nodeData.fullData, path) + if (next) { + handleEdit() + setCurrentlyEditingElement(toPathString(next)) + } + }, + tabBack: () => { + const prev = getNextOrPrevious(nodeData.fullData, path, 'prev') + if (prev) { + handleEdit() + setCurrentlyEditingElement(toPathString(prev)) + } + }, + }, } const ValueComponent = showCustomNode ? ( diff --git a/src/ValueNodes.tsx b/src/ValueNodes.tsx index 1f4ea6bb..ab824420 100644 --- a/src/ValueNodes.tsx +++ b/src/ValueNodes.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from 'react' import { AutogrowTextArea } from './AutogrowTextArea' -import { getNextOrPrevious, getPrevious, toPathString, truncate } from './helpers' -import { useTheme, useTreeState } from './contexts' +import { toPathString, truncate } from './helpers' +import { useTheme } from './contexts' import { type InputProps } from './types' export const INVALID_FUNCTION_STRING = '**INVALID_FUNCTION**' @@ -18,9 +18,9 @@ export const StringValue: React.FC = ({ showStringQuotes, nodeData, handleKeyboard, + keyboardCommon, }) => { const { getStyles } = useTheme() - const { setCurrentlyEditingElement } = useTreeState() const pathString = toPathString(path) @@ -36,7 +36,6 @@ export const StringValue: React.FC = ({ handleKeyPress={(e) => { handleKeyboard(e, { stringConfirm: handleEdit, - cancel: handleCancel, stringLineBreak: () => { const textArea = document.getElementById( `${pathString}_textarea` @@ -54,17 +53,7 @@ export const StringValue: React.FC = ({ setValue(strStart + '\n' + strEnd) } }, - tabForward: () => { - const next = getNextOrPrevious(nodeData.fullData, path) - // if (next) { - // handleEdit() - // setCurrentlyEditingElement(toPathString(next)) - // } - console.log('NExt', next) - }, - tabBack: () => { - console.log('PReb', getNextOrPrevious(nodeData.fullData, path, 'prev')) - }, + ...keyboardCommon, }) }} styles={getStyles('input', nodeData)} @@ -93,9 +82,9 @@ export const NumberValue: React.FC = ({ path, setIsEditing, handleEdit, - handleCancel, nodeData, handleKeyboard, + keyboardCommon, }) => { const { getStyles } = useTheme() @@ -115,9 +104,9 @@ export const NumberValue: React.FC = ({ onKeyDown={(e) => handleKeyboard(e, { numberConfirm: handleEdit, - cancel: handleCancel, numberUp: () => setValue(Number(value) + 1), numberDown: () => setValue(Number(value) - 1), + ...keyboardCommon, }) } style={{ width: `${String(value).length / 1.5 + 2}em`, ...getStyles('input', nodeData) }} @@ -140,9 +129,9 @@ export const BooleanValue: React.FC = ({ path, setIsEditing, handleEdit, - handleCancel, nodeData, handleKeyboard, + keyboardCommon, }) => { const { getStyles } = useTheme() @@ -156,7 +145,7 @@ export const BooleanValue: React.FC = ({ onKeyDown={(e) => handleKeyboard(e, { booleanConfirm: handleEdit, - cancel: handleCancel, + ...keyboardCommon, }) } autoFocus @@ -177,9 +166,9 @@ export const NullValue: React.FC = ({ isEditing, setIsEditing, handleEdit, - handleCancel, nodeData, handleKeyboard, + keyboardCommon, }) => { const { getStyles } = useTheme() @@ -189,7 +178,7 @@ export const NullValue: React.FC = ({ }, [isEditing]) const listenForSubmit = (e: unknown) => - handleKeyboard(e as React.KeyboardEvent, { confirm: handleEdit, cancel: handleCancel }) + handleKeyboard(e as React.KeyboardEvent, { confirm: handleEdit, ...keyboardCommon }) return (
void>> ) => void + keyboardCommon: Partial void>> } /** From 5ed41190e1ef88999f81ec781eb6ff5f00550152 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Mon, 23 Dec 2024 17:11:56 +1300 Subject: [PATCH 03/23] TIdy --- demo/src/demoData/dataDefinitions.tsx | 2 +- src/ValueNodes.tsx | 1 - src/types.ts | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/demo/src/demoData/dataDefinitions.tsx b/demo/src/demoData/dataDefinitions.tsx index fe399269..0aab8748 100644 --- a/demo/src/demoData/dataDefinitions.tsx +++ b/demo/src/demoData/dataDefinitions.tsx @@ -21,7 +21,7 @@ import { UpdateFunction, UpdateFunctionProps, } from '../json-edit-react/src/types' -import { Input } from 'object-property-assigner/build' +import { type Input } from 'object-property-assigner' import jsonSchema from './jsonSchema.json' import customNodesSchema from './customNodesSchema.json' import Ajv from 'ajv' diff --git a/src/ValueNodes.tsx b/src/ValueNodes.tsx index ab824420..dc511b10 100644 --- a/src/ValueNodes.tsx +++ b/src/ValueNodes.tsx @@ -13,7 +13,6 @@ export const StringValue: React.FC = ({ path, setIsEditing, handleEdit, - handleCancel, stringTruncate, showStringQuotes, nodeData, diff --git a/src/types.ts b/src/types.ts index 0a5ef604..88fbc6e5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -296,7 +296,6 @@ export interface InputProps { isEditing: boolean setIsEditing: React.Dispatch> handleEdit: () => void - handleCancel: () => void path: CollectionKey[] stringTruncate: number showStringQuotes: boolean From c6dcd27e0f0d6569a7da5fdc71895d7c6d9d36fb Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Tue, 24 Dec 2024 00:01:33 +1300 Subject: [PATCH 04/23] Skip over hidden elements when tabbing --- src/ValueNodeWrapper.tsx | 11 +++++++++-- src/ValueNodes.tsx | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/ValueNodeWrapper.tsx b/src/ValueNodeWrapper.tsx index 0d406c46..ce87931c 100644 --- a/src/ValueNodeWrapper.tsx +++ b/src/ValueNodeWrapper.tsx @@ -45,7 +45,7 @@ export const ValueNodeWrapper: React.FC = (props) => { keyboardControls, } = props const { getStyles } = useTheme() - const { setCurrentlyEditingElement, setCollapseState } = useTreeState() + const { setCurrentlyEditingElement, setCollapseState, currentlyEditingElement } = useTreeState() const [value, setValue] = useState( // Bad things happen when you put a function into useState typeof data === 'function' ? INVALID_FUNCTION_STRING : data @@ -126,7 +126,14 @@ export const ValueNodeWrapper: React.FC = (props) => { }, [nodeData, restrictTypeSelection]) // Early return if this node is filtered out - if (!filterNode('value', nodeData, searchFilter, searchText)) return null + const isVisible = filterNode('value', nodeData, searchFilter, searchText) + if (!isVisible) { + if (currentlyEditingElement === pathString) { + const next = getNextOrPrevious(nodeData.fullData, path) + setCurrentlyEditingElement(next ? toPathString(next) : next) + } + return null + } const handleChangeDataType = (type: DataType) => { const customNode = customNodeDefinitions.find((customNode) => customNode.name === type) diff --git a/src/ValueNodes.tsx b/src/ValueNodes.tsx index dc511b10..663ec547 100644 --- a/src/ValueNodes.tsx +++ b/src/ValueNodes.tsx @@ -172,12 +172,19 @@ export const NullValue: React.FC = ({ const { getStyles } = useTheme() useEffect(() => { - if (isEditing) document.addEventListener('keydown', listenForSubmit) + if (isEditing) { + // Small delay to prevent registering keyboard input from previous element + // if switched using "Tab" + setTimeout(() => document.addEventListener('keydown', listenForSubmit), 50) + } return () => document.removeEventListener('keydown', listenForSubmit) }, [isEditing]) const listenForSubmit = (e: unknown) => - handleKeyboard(e as React.KeyboardEvent, { confirm: handleEdit, ...keyboardCommon }) + handleKeyboard(e as React.KeyboardEvent, { + confirm: handleEdit, + ...keyboardCommon, + }) return (
Date: Fri, 27 Dec 2024 10:06:19 +1300 Subject: [PATCH 05/23] Expand collection if children are editing --- src/CollectionNode.tsx | 12 ++++++++---- src/ValueNodeWrapper.tsx | 12 ++++++------ src/contexts/TreeStateProvider.tsx | 13 +++++++++---- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index ecc4bb58..30109d40 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -119,6 +119,8 @@ export const CollectionNode: React.FC = (props) => { showCollectionWrapper = true, } = useMemo(() => getCustomNode(customNodeDefinitions, nodeData), []) + const childrenEditing = areChildrenBeingEdited(pathString) + // Early return if this node is filtered out if (!filterNode('collection', nodeData, searchFilter, searchText) && nodeData.level > 0) return null @@ -288,7 +290,9 @@ export const CollectionNode: React.FC = (props) => { // no way to open a collapsed custom node, so this ensures it will stay open. // It can still be displayed collapsed by handling it internally if this is // desired. - const isCollapsed = !showCollectionWrapper ? false : collapsed + // Also, if the node is editing via "Tab" key, it's parent must be opened, + // hence `childrenEditing` check + const isCollapsed = !showCollectionWrapper ? false : collapsed && !childrenEditing if (!isCollapsed) hasBeenOpened.current = true const customNodeAllProps = { @@ -302,7 +306,7 @@ export const CollectionNode: React.FC = (props) => { handleCancel, handleKeyPress: handleKeyPressEdit, isEditing, - setIsEditing: () => setCurrentlyEditingElement(pathString), + setIsEditing: () => setCurrentlyEditingElement(path), getStyles, canDragOnto: canEdit, } @@ -356,7 +360,7 @@ export const CollectionNode: React.FC = (props) => { canEdit ? () => { hasBeenOpened.current = true - setCurrentlyEditingElement(pathString) + setCurrentlyEditingElement(path) } : undefined } @@ -449,7 +453,7 @@ export const CollectionNode: React.FC = (props) => { style={{ overflowY: isCollapsed || isAnimating ? 'clip' : 'visible', // Prevent collapse if this node or any children are being edited - maxHeight: areChildrenBeingEdited(pathString) ? undefined : maxHeight, + maxHeight: childrenEditing ? undefined : maxHeight, ...getStyles('collectionInner', nodeData), }} ref={contentRef} diff --git a/src/ValueNodeWrapper.tsx b/src/ValueNodeWrapper.tsx index ce87931c..d54444ae 100644 --- a/src/ValueNodeWrapper.tsx +++ b/src/ValueNodeWrapper.tsx @@ -130,7 +130,7 @@ export const ValueNodeWrapper: React.FC = (props) => { if (!isVisible) { if (currentlyEditingElement === pathString) { const next = getNextOrPrevious(nodeData.fullData, path) - setCurrentlyEditingElement(next ? toPathString(next) : next) + setCurrentlyEditingElement(next) } return null } @@ -212,7 +212,7 @@ export const ValueNodeWrapper: React.FC = (props) => { parentData, setValue: updateValue, isEditing, - setIsEditing: canEdit ? () => setCurrentlyEditingElement(pathString) : () => {}, + setIsEditing: canEdit ? () => setCurrentlyEditingElement(path) : () => {}, handleEdit, handleCancel, path, @@ -227,14 +227,14 @@ export const ValueNodeWrapper: React.FC = (props) => { const next = getNextOrPrevious(nodeData.fullData, path) if (next) { handleEdit() - setCurrentlyEditingElement(toPathString(next)) + setCurrentlyEditingElement(next) } }, tabBack: () => { const prev = getNextOrPrevious(nodeData.fullData, path, 'prev') if (prev) { handleEdit() - setCurrentlyEditingElement(toPathString(prev)) + setCurrentlyEditingElement(prev) } }, }, @@ -252,7 +252,7 @@ export const ValueNodeWrapper: React.FC = (props) => { handleKeyboard(e, { stringConfirm: handleEdit, cancel: handleCancel }) } isEditing={isEditing} - setIsEditing={() => setCurrentlyEditingElement(pathString)} + setIsEditing={() => setCurrentlyEditingElement(path)} getStyles={getStyles} /> ) : ( @@ -324,7 +324,7 @@ export const ValueNodeWrapper: React.FC = (props) => { showEditButtons && ( setCurrentlyEditingElement(pathString, handleCancel) : undefined + canEdit ? () => setCurrentlyEditingElement(path, handleCancel) : undefined } handleDelete={canDelete ? handleDelete : undefined} enableClipboard={enableClipboard} diff --git a/src/contexts/TreeStateProvider.tsx b/src/contexts/TreeStateProvider.tsx index db0d5f12..649e218d 100644 --- a/src/contexts/TreeStateProvider.tsx +++ b/src/contexts/TreeStateProvider.tsx @@ -9,6 +9,7 @@ import React, { createContext, useContext, useRef, useState } from 'react' import { type CollectionKey } from '../types' +import { toPathString } from '../helpers' interface CollapseAllState { path: CollectionKey[] @@ -25,7 +26,7 @@ interface TreeStateContext { setCollapseState: (collapseState: CollapseAllState | null) => void doesPathMatch: (path: CollectionKey[]) => boolean currentlyEditingElement: string | null - setCurrentlyEditingElement: (newElement: string | null, cancelOp?: () => void) => void + setCurrentlyEditingElement: (path: CollectionKey[] | null, cancelOp?: () => void) => void areChildrenBeingEdited: (pathString: string) => boolean dragSource: DragSource setDragSource: (newState: DragSource) => void @@ -52,13 +53,17 @@ export const TreeStateProvider = ({ children }: { children: React.ReactNode }) = }) const cancelOp = useRef<(() => void) | null>(null) - const updateCurrentlyEditingElement = (newElement: string | null, newCancel?: () => void) => { + const updateCurrentlyEditingElement = (path: CollectionKey[] | null, newCancel?: () => void) => { + const pathString = path === null ? null : toPathString(path) + // TO-DO: Ensure new element is definitely open + // if (path !== null) setCollapseState({ path: path.slice(0, path.length - 1), collapsed: false }) + // The "Cancel" allows the UI to reset the element that was previously being // edited if the user clicks another "Edit" button elsewhere - if (currentlyEditingElement !== null && newElement !== null && cancelOp.current !== null) { + if (currentlyEditingElement !== null && pathString !== null && cancelOp.current !== null) { cancelOp.current() } - setCurrentlyEditingElement(newElement) + setCurrentlyEditingElement(pathString) cancelOp.current = newCancel ?? null } From 3431c9a9784a3ef85d3f6adc78133d3802179dac Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Fri, 27 Dec 2024 10:48:30 +1300 Subject: [PATCH 06/23] Fix for key edit --- src/CollectionNode.tsx | 2 +- src/ValueNodeWrapper.tsx | 2 +- src/contexts/TreeStateProvider.tsx | 24 ++++++++++++++++-------- src/helpers.ts | 3 ++- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index 30109d40..47ea4b83 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -341,7 +341,7 @@ export const CollectionNode: React.FC = (props) => { className="jer-key-text" style={getStyles('property', nodeData)} onClick={(e) => e.stopPropagation()} - onDoubleClick={() => canEditKey && setCurrentlyEditingElement(`key_${pathString}`)} + onDoubleClick={() => canEditKey && setCurrentlyEditingElement(path, 'key')} > {name === '' ? ( 0 ? 'jer-empty-string' : undefined}> diff --git a/src/ValueNodeWrapper.tsx b/src/ValueNodeWrapper.tsx index d54444ae..c657f6cc 100644 --- a/src/ValueNodeWrapper.tsx +++ b/src/ValueNodeWrapper.tsx @@ -288,7 +288,7 @@ export const ValueNodeWrapper: React.FC = (props) => { minWidth: `${Math.min(String(name).length + 1, 5)}ch`, flexShrink: (name as string).length > 10 ? 1 : 0, }} - onDoubleClick={() => canEditKey && setCurrentlyEditingElement(`key_${pathString}`)} + onDoubleClick={() => canEditKey && setCurrentlyEditingElement(path, 'key')} > {name === '' ? ( 0 ? 'jer-empty-string' : undefined}> diff --git a/src/contexts/TreeStateProvider.tsx b/src/contexts/TreeStateProvider.tsx index 649e218d..e74130b9 100644 --- a/src/contexts/TreeStateProvider.tsx +++ b/src/contexts/TreeStateProvider.tsx @@ -26,7 +26,10 @@ interface TreeStateContext { setCollapseState: (collapseState: CollapseAllState | null) => void doesPathMatch: (path: CollectionKey[]) => boolean currentlyEditingElement: string | null - setCurrentlyEditingElement: (path: CollectionKey[] | null, cancelOp?: () => void) => void + setCurrentlyEditingElement: ( + path: CollectionKey[] | null, + cancelOpOrKey?: (() => void) | 'key' + ) => void areChildrenBeingEdited: (pathString: string) => boolean dragSource: DragSource setDragSource: (newState: DragSource) => void @@ -53,18 +56,23 @@ export const TreeStateProvider = ({ children }: { children: React.ReactNode }) = }) const cancelOp = useRef<(() => void) | null>(null) - const updateCurrentlyEditingElement = (path: CollectionKey[] | null, newCancel?: () => void) => { - const pathString = path === null ? null : toPathString(path) - // TO-DO: Ensure new element is definitely open - // if (path !== null) setCollapseState({ path: path.slice(0, path.length - 1), collapsed: false }) + const updateCurrentlyEditingElement = ( + path: CollectionKey[] | null, + newCancelOrKey?: (() => void) | 'key' + ) => { + const pathString = + path === null ? null : toPathString(path, newCancelOrKey === 'key' ? 'key_' : undefined) - // The "Cancel" allows the UI to reset the element that was previously being - // edited if the user clicks another "Edit" button elsewhere + console.log('pathString', pathString) + + // The "Cancel" function allows the UI to reset the element that was + // previously being edited if the user clicks another "Edit" button + // elsewhere if (currentlyEditingElement !== null && pathString !== null && cancelOp.current !== null) { cancelOp.current() } setCurrentlyEditingElement(pathString) - cancelOp.current = newCancel ?? null + cancelOp.current = typeof newCancelOrKey === 'function' ? newCancelOrKey : null } const doesPathMatch = (path: CollectionKey[]) => { diff --git a/src/helpers.ts b/src/helpers.ts index 6981d1fc..da28dee6 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -122,7 +122,8 @@ export const truncate = (string: string, length = 200) => /** * Converts a part expressed as an array of properties to a single string */ -export const toPathString = (path: Array) => +export const toPathString = (path: Array, key?: 'key_') => + (key ?? '') + path // An empty string in a part will "disappear", so replace it with a // non-printable char From 89cf321ff63088c3549a16e2d0aa1a50feca9103 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Thu, 23 Jan 2025 23:25:03 +1300 Subject: [PATCH 07/23] WIP --- demo/src/demoData/dataDefinitions.tsx | 1 + src/CollectionNode.tsx | 11 ++++++++++- src/ValueNodeWrapper.tsx | 8 ++++++++ src/ValueNodes.tsx | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/demo/src/demoData/dataDefinitions.tsx b/demo/src/demoData/dataDefinitions.tsx index 0aab8748..e0d0a651 100644 --- a/demo/src/demoData/dataDefinitions.tsx +++ b/demo/src/demoData/dataDefinitions.tsx @@ -91,6 +91,7 @@ export const demoDataDefinitions: Record = { collapse: 2, data: data.intro, customNodeDefinitions: [dateNodeDefinition], + // restrictEdit: ({ key }) => key === 'number', }, starWars: { name: '🚀 Star Wars', diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index 8c190ba9..3af3b3c4 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -4,7 +4,7 @@ import { EditButtons, InputButtons } from './ButtonPanels' import { getCustomNode } from './CustomNode' import { type CollectionNodeProps, type NodeData, type CollectionData } from './types' import { Icon } from './Icons' -import { filterNode, getModifier, isCollection } from './helpers' +import { filterNode, getModifier, getNextOrPrevious, isCollection } from './helpers' import { AutogrowTextArea } from './AutogrowTextArea' import { useTheme, useTreeState } from './contexts' import { useCollapseTransition, useCommon, useDragNDrop } from './hooks' @@ -333,6 +333,15 @@ export const CollectionNode: React.FC = (props) => { handleKeyboard(e, { stringConfirm: () => handleEditKey((e.target as HTMLInputElement).value), cancel: handleCancel, + tabForward: () => { + const next = getNextOrPrevious(nodeData.fullData, path) + console.log('Next', next) + if (next) { + handleEditKey((e.target as HTMLInputElement).value) + setCurrentlyEditingElement(next, 'key') + } + }, + tabBack: () => console.log(path), }) } style={{ width: `${String(name).length / 1.5 + 0.5}em` }} diff --git a/src/ValueNodeWrapper.tsx b/src/ValueNodeWrapper.tsx index c657f6cc..6f69fed1 100644 --- a/src/ValueNodeWrapper.tsx +++ b/src/ValueNodeWrapper.tsx @@ -134,6 +134,10 @@ export const ValueNodeWrapper: React.FC = (props) => { } return null } + if (!canEdit && currentlyEditingElement === pathString) { + const next = getNextOrPrevious(nodeData.fullData, path) + setCurrentlyEditingElement(next) + } const handleChangeDataType = (type: DataType) => { const customNode = customNodeDefinitions.find((customNode) => customNode.name === type) @@ -311,6 +315,10 @@ export const ValueNodeWrapper: React.FC = (props) => { handleKeyboard(e, { stringConfirm: () => handleEditKey((e.target as HTMLInputElement).value), cancel: handleCancel, + tabForward: () => { + handleEditKey((e.target as HTMLInputElement).value) + setCurrentlyEditingElement(path) + }, }) } style={{ width: `${String(name).length / 1.5 + 0.5}em` }} diff --git a/src/ValueNodes.tsx b/src/ValueNodes.tsx index 2569efd5..852aff34 100644 --- a/src/ValueNodes.tsx +++ b/src/ValueNodes.tsx @@ -147,6 +147,7 @@ export const BooleanValue: React.FC = ({ handleKeyboard(e, { booleanConfirm: handleEdit, booleanToggle: () => setValue(!value), + ...keyboardCommon, }) }} autoFocus From 771f895bf7c9dded3b899620d1609c818bd30982 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Fri, 24 Jan 2025 11:07:50 +1300 Subject: [PATCH 08/23] Correctly handle hidden elements --- src/CollectionNode.tsx | 6 +++--- src/JsonEditor.tsx | 4 +++- src/ValueNodeWrapper.tsx | 5 ++++- src/contexts/TreeStateProvider.tsx | 2 -- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index 3af3b3c4..feddeb3b 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -124,8 +124,9 @@ export const CollectionNode: React.FC = (props) => { const childrenEditing = areChildrenBeingEdited(pathString) // Early return if this node is filtered out - if (!filterNode('collection', nodeData, searchFilter, searchText) && nodeData.level > 0) - return null + const isVisible = + filterNode('collection', nodeData, searchFilter, searchText) || nodeData.level === 0 + if (!isVisible && !childrenEditing) return null const collectionType = Array.isArray(data) ? 'array' : 'object' const brackets = @@ -335,7 +336,6 @@ export const CollectionNode: React.FC = (props) => { cancel: handleCancel, tabForward: () => { const next = getNextOrPrevious(nodeData.fullData, path) - console.log('Next', next) if (next) { handleEditKey((e.target as HTMLInputElement).value) setCurrentlyEditingElement(next, 'key') diff --git a/src/JsonEditor.tsx b/src/JsonEditor.tsx index 97c371f3..82195dd0 100644 --- a/src/JsonEditor.tsx +++ b/src/JsonEditor.tsx @@ -23,7 +23,7 @@ import { type JsonData, type KeyboardControls, } from './types' -import { useTheme, ThemeProvider, TreeStateProvider, defaultTheme } from './contexts' +import { useTheme, ThemeProvider, TreeStateProvider, defaultTheme, useTreeState } from './contexts' import { useData } from './hooks/useData' import { getTranslateFunction } from './localisation' import { ValueNodeWrapper } from './ValueNodeWrapper' @@ -75,6 +75,7 @@ const Editor: React.FC = ({ insertAtTop = false, }) => { const { getStyles } = useTheme() + const { setCurrentlyEditingElement } = useTreeState() const collapseFilter = useCallback(getFilterFunction(collapse), [collapse]) const translate = useCallback(getTranslateFunction(translations, customText), [ translations, @@ -87,6 +88,7 @@ const Editor: React.FC = ({ const mainContainerRef = useRef(null) useEffect(() => { + setCurrentlyEditingElement(null) const debounce = setTimeout(() => setDebouncedSearchText(searchText), searchDebounceTime) return () => clearTimeout(debounce) }, [searchText, searchDebounceTime]) diff --git a/src/ValueNodeWrapper.tsx b/src/ValueNodeWrapper.tsx index 6f69fed1..07cdc417 100644 --- a/src/ValueNodeWrapper.tsx +++ b/src/ValueNodeWrapper.tsx @@ -19,7 +19,7 @@ import { } from './types' import { useTheme, useTreeState } from './contexts' import { getCustomNode, type CustomNodeData } from './CustomNode' -import { filterNode, getNextOrPrevious, toPathString } from './helpers' +import { filterNode, getNextOrPrevious } from './helpers' import { useCommon, useDragNDrop } from './hooks' export const ValueNodeWrapper: React.FC = (props) => { @@ -127,10 +127,13 @@ export const ValueNodeWrapper: React.FC = (props) => { // Early return if this node is filtered out const isVisible = filterNode('value', nodeData, searchFilter, searchText) + console.log('currentlyEditingElement', currentlyEditingElement) + if (currentlyEditingElement === pathString) console.log(pathString, 'Visible?', isVisible) if (!isVisible) { if (currentlyEditingElement === pathString) { const next = getNextOrPrevious(nodeData.fullData, path) setCurrentlyEditingElement(next) + console.log('NEXT', next) } return null } diff --git a/src/contexts/TreeStateProvider.tsx b/src/contexts/TreeStateProvider.tsx index e74130b9..bcb21d47 100644 --- a/src/contexts/TreeStateProvider.tsx +++ b/src/contexts/TreeStateProvider.tsx @@ -63,8 +63,6 @@ export const TreeStateProvider = ({ children }: { children: React.ReactNode }) = const pathString = path === null ? null : toPathString(path, newCancelOrKey === 'key' ? 'key_' : undefined) - console.log('pathString', pathString) - // The "Cancel" function allows the UI to reset the element that was // previously being edited if the user clicks another "Edit" button // elsewhere From 4c2d4ac8f4ec6013e21c6555b141c4fcba48c512 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Fri, 24 Jan 2025 14:58:00 +1300 Subject: [PATCH 09/23] Fix a number of problems --- src/CollectionNode.tsx | 18 ++++++++----- src/ValueNodeWrapper.tsx | 43 +++++++++++++++++++----------- src/ValueNodes.tsx | 16 ++++++++--- src/contexts/TreeStateProvider.tsx | 35 +++++++++++++++++++++--- src/helpers.ts | 6 ++--- src/types.ts | 2 ++ 6 files changed, 88 insertions(+), 32 deletions(-) diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index feddeb3b..e0447db4 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -123,6 +123,9 @@ export const CollectionNode: React.FC = (props) => { const childrenEditing = areChildrenBeingEdited(pathString) + // For when children are accessed via Tab + if (childrenEditing && collapsed) animateCollapse(false) + // Early return if this node is filtered out const isVisible = filterNode('collection', nodeData, searchFilter, searchText) || nodeData.level === 0 @@ -335,13 +338,16 @@ export const CollectionNode: React.FC = (props) => { stringConfirm: () => handleEditKey((e.target as HTMLInputElement).value), cancel: handleCancel, tabForward: () => { - const next = getNextOrPrevious(nodeData.fullData, path) - if (next) { - handleEditKey((e.target as HTMLInputElement).value) - setCurrentlyEditingElement(next, 'key') - } + handleEditKey((e.target as HTMLInputElement).value) + const firstChildKey = Object.keys(data)[0] + setCurrentlyEditingElement( + firstChildKey ? [...path, firstChildKey] : getNextOrPrevious(nodeData.fullData, path) + ) + }, + tabBack: () => { + handleEditKey((e.target as HTMLInputElement).value) + setCurrentlyEditingElement(getNextOrPrevious(nodeData.fullData, path, 'prev')) }, - tabBack: () => console.log(path), }) } style={{ width: `${String(name).length / 1.5 + 0.5}em` }} diff --git a/src/ValueNodeWrapper.tsx b/src/ValueNodeWrapper.tsx index 07cdc417..457bb970 100644 --- a/src/ValueNodeWrapper.tsx +++ b/src/ValueNodeWrapper.tsx @@ -45,7 +45,14 @@ export const ValueNodeWrapper: React.FC = (props) => { keyboardControls, } = props const { getStyles } = useTheme() - const { setCurrentlyEditingElement, setCollapseState, currentlyEditingElement } = useTreeState() + const { + setCurrentlyEditingElement, + setCollapseState, + previouslyEditedElement, + setPreviouslyEditedElement, + tabDirection, + setTabDirection, + } = useTreeState() const [value, setValue] = useState( // Bad things happen when you put a function into useState typeof data === 'function' ? INVALID_FUNCTION_STRING : data @@ -125,23 +132,21 @@ export const ValueNodeWrapper: React.FC = (props) => { return result }, [nodeData, restrictTypeSelection]) + const { isEditing } = derivedValues + // Early return if this node is filtered out const isVisible = filterNode('value', nodeData, searchFilter, searchText) - console.log('currentlyEditingElement', currentlyEditingElement) - if (currentlyEditingElement === pathString) console.log(pathString, 'Visible?', isVisible) - if (!isVisible) { - if (currentlyEditingElement === pathString) { - const next = getNextOrPrevious(nodeData.fullData, path) - setCurrentlyEditingElement(next) - console.log('NEXT', next) - } - return null - } - if (!canEdit && currentlyEditingElement === pathString) { - const next = getNextOrPrevious(nodeData.fullData, path) - setCurrentlyEditingElement(next) + + // This prevents hidden or uneditable nodes being set to editing via Tab + // navigation + if (isEditing && (!isVisible || !canEdit)) { + const next = getNextOrPrevious(nodeData.fullData, path, tabDirection) + if (next) setCurrentlyEditingElement(next) + else setCurrentlyEditingElement(previouslyEditedElement) } + if (!isVisible) return null + const handleChangeDataType = (type: DataType) => { const customNode = customNodeDefinitions.find((customNode) => customNode.name === type) if (customNode) { @@ -206,7 +211,7 @@ export const ValueNodeWrapper: React.FC = (props) => { } // DERIVED VALUES (this makes the JSX logic less messy) - const { isEditing, isEditingKey, canEditKey } = derivedValues + const { isEditingKey, canEditKey } = derivedValues const showErrorString = !isEditing && error const showTypeSelector = isEditing && allowedDataTypes.length > 0 const showEditButtons = dataType !== 'invalid' && !error && showEditTools @@ -231,6 +236,8 @@ export const ValueNodeWrapper: React.FC = (props) => { keyboardCommon: { cancel: handleCancel, tabForward: () => { + setTabDirection('next') + setPreviouslyEditedElement(pathString) const next = getNextOrPrevious(nodeData.fullData, path) if (next) { handleEdit() @@ -238,6 +245,8 @@ export const ValueNodeWrapper: React.FC = (props) => { } }, tabBack: () => { + setTabDirection('prev') + setPreviouslyEditedElement(pathString) const prev = getNextOrPrevious(nodeData.fullData, path, 'prev') if (prev) { handleEdit() @@ -322,6 +331,10 @@ export const ValueNodeWrapper: React.FC = (props) => { handleEditKey((e.target as HTMLInputElement).value) setCurrentlyEditingElement(path) }, + tabBack: () => { + handleEditKey((e.target as HTMLInputElement).value) + setCurrentlyEditingElement(getNextOrPrevious(nodeData.fullData, path, 'prev')) + }, }) } style={{ width: `${String(name).length / 1.5 + 0.5}em` }} diff --git a/src/ValueNodes.tsx b/src/ValueNodes.tsx index 852aff34..affa784c 100644 --- a/src/ValueNodes.tsx +++ b/src/ValueNodes.tsx @@ -173,13 +173,21 @@ export const NullValue: React.FC = ({ keyboardCommon, }) => { const { getStyles } = useTheme() + const timer = useRef() useEffect(() => { - if (isEditing) { - // Small delay to prevent registering keyboard input from previous element - // if switched using "Tab" - setTimeout(() => window.addEventListener('keydown', listenForSubmit), 50) + if (!isEditing) { + // The listener messes with other elements when switching rapidly (e.g. when "getNext" called repeatedly on inaccessible elements), so we cancel the listener load before it even happens if this node gets switched from isEditing to not in less than 100ms + window.clearTimeout(timer.current) + return } + // Small delay to prevent registering keyboard input from previous element + // if switched using "Tab" + timer.current = window.setTimeout( + () => window.addEventListener('keydown', listenForSubmit), + 100 + ) + return () => window.removeEventListener('keydown', listenForSubmit) }, [isEditing]) diff --git a/src/contexts/TreeStateProvider.tsx b/src/contexts/TreeStateProvider.tsx index bcb21d47..0fd4472b 100644 --- a/src/contexts/TreeStateProvider.tsx +++ b/src/contexts/TreeStateProvider.tsx @@ -8,7 +8,7 @@ */ import React, { createContext, useContext, useRef, useState } from 'react' -import { type CollectionKey } from '../types' +import { type TabDirection, type CollectionKey } from '../types' import { toPathString } from '../helpers' interface CollapseAllState { @@ -27,12 +27,16 @@ interface TreeStateContext { doesPathMatch: (path: CollectionKey[]) => boolean currentlyEditingElement: string | null setCurrentlyEditingElement: ( - path: CollectionKey[] | null, + path: CollectionKey[] | string | null, cancelOpOrKey?: (() => void) | 'key' ) => void + previouslyEditedElement: string | null + setPreviouslyEditedElement: (path: string) => void areChildrenBeingEdited: (pathString: string) => boolean dragSource: DragSource setDragSource: (newState: DragSource) => void + tabDirection: TabDirection + setTabDirection: (dir: TabDirection) => void } const initialContext: TreeStateContext = { collapseState: null, @@ -40,9 +44,13 @@ const initialContext: TreeStateContext = { doesPathMatch: () => false, currentlyEditingElement: null, setCurrentlyEditingElement: () => {}, + previouslyEditedElement: null, + setPreviouslyEditedElement: () => {}, areChildrenBeingEdited: () => false, dragSource: { path: null, pathString: null }, setDragSource: () => {}, + tabDirection: 'next', + setTabDirection: () => {}, } const TreeStateProviderContext = createContext(initialContext) @@ -56,12 +64,23 @@ export const TreeStateProvider = ({ children }: { children: React.ReactNode }) = }) const cancelOp = useRef<(() => void) | null>(null) + // tabDirection and previouslyEdited are used in Tab navigation. Each node can + // find the "previous" or "next" node on Tab detection, but has no way to know + // whether that node is actually visible or editable. So each node runs this + // check on itself on render, and if it has been set to "isEditing" when it + // shouldn't be, it immediately goes to the next (and the next, etc...). These + // two values hold some state which is useful in this slightly messy process. + const tabDirection = useRef('next') + const previouslyEdited = useRef(null) + const updateCurrentlyEditingElement = ( - path: CollectionKey[] | null, + path: CollectionKey[] | string | null, newCancelOrKey?: (() => void) | 'key' ) => { const pathString = - path === null ? null : toPathString(path, newCancelOrKey === 'key' ? 'key_' : undefined) + typeof path === 'string' || path === null + ? path + : toPathString(path, newCancelOrKey === 'key' ? 'key_' : undefined) // The "Cancel" function allows the UI to reset the element that was // previously being edited if the user clicks another "Edit" button @@ -103,6 +122,14 @@ export const TreeStateProvider = ({ children }: { children: React.ReactNode }) = currentlyEditingElement, setCurrentlyEditingElement: updateCurrentlyEditingElement, areChildrenBeingEdited, + previouslyEditedElement: previouslyEdited.current, + setPreviouslyEditedElement: (path: string) => { + previouslyEdited.current = path + }, + tabDirection: tabDirection.current, + setTabDirection: (dir: TabDirection) => { + tabDirection.current = dir + }, // Drag-n-drop dragSource, setDragSource, diff --git a/src/helpers.ts b/src/helpers.ts index e42d9a7d..1c5cf6c6 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -8,7 +8,7 @@ import { type KeyboardControlsFull, type JsonData, type CollectionKey, - type CollectionData, + type TabDirection, } from './types' export const isCollection = (value: unknown): value is Record | unknown[] => @@ -255,7 +255,7 @@ export const getFullKeyboardControlMap = (userControls: KeyboardControls): Keybo export const getNextOrPrevious = ( fullData: JsonData, path: CollectionKey[], - nextOrPrev: 'next' | 'prev' = 'next' + nextOrPrev: TabDirection = 'next' ): CollectionKey[] | null => { const parentPath = path.slice(0, path.length - 1) const thisKey = path.slice(-1)[0] @@ -284,7 +284,7 @@ export const getNextOrPrevious = ( const getChildRecursive = ( fullData: JsonData, path: CollectionKey[], - nextOrPrev: 'next' | 'prev' = 'next' + nextOrPrev: TabDirection = 'next' ) => { const node = extractProperty(fullData, path) if (!isCollection(node)) return path diff --git a/src/types.ts b/src/types.ts index 175621b0..5c5a6c2b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -62,6 +62,8 @@ export type CollectionData = object | unknown[] export type ErrorString = string +export type TabDirection = 'next' | 'prev' + export interface IconReplacements { add?: JSX.Element edit?: JSX.Element From f3bb4dffe093103f2cc16e676e01e49792554191 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Sat, 25 Jan 2025 17:04:44 +1300 Subject: [PATCH 10/23] Generalise "sort" function --- src/CollectionNode.tsx | 32 +++++++++++++++++--------------- src/JsonEditor.tsx | 29 +++++++++++++++++++++++++++++ src/ValueNodeWrapper.tsx | 11 +++++++---- src/helpers.ts | 36 +++++++++++++++++++++++++++++------- src/types.ts | 10 ++++++++-- 5 files changed, 90 insertions(+), 28 deletions(-) diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index e0447db4..49de50ab 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -2,7 +2,12 @@ import React, { useEffect, useState, useMemo, useRef } from 'react' import { ValueNodeWrapper } from './ValueNodeWrapper' import { EditButtons, InputButtons } from './ButtonPanels' import { getCustomNode } from './CustomNode' -import { type CollectionNodeProps, type NodeData, type CollectionData } from './types' +import { + type CollectionNodeProps, + type NodeData, + type CollectionData, + type ValueData, +} from './types' import { Icon } from './Icons' import { filterNode, getModifier, getNextOrPrevious, isCollection } from './helpers' import { AutogrowTextArea } from './AutogrowTextArea' @@ -36,7 +41,7 @@ export const CollectionNode: React.FC = (props) => { searchFilter, searchText, indent, - keySort, + sort, showArrayIndices, defaultValue, translate, @@ -218,18 +223,13 @@ export const CollectionNode: React.FC = (props) => { const showKey = showLabel && !hideKey && name !== undefined const showCustomNodeContents = CustomNode && ((isEditing && showOnEdit) || (!isEditing && showOnView)) - const sortKeys = keySort && collectionType === 'object' - const keyValueArray = Object.entries(data).map(([key, value]) => [ - collectionType === 'array' ? Number(key) : key, - value, - ]) + const keyValueArray = Object.entries(data).map( + ([key, value]) => + [collectionType === 'array' ? Number(key) : key, value] as [string | number, ValueData] + ) - if (sortKeys) { - keyValueArray.sort( - typeof keySort === 'function' ? (a: string[], b) => keySort(a[0], b[0] as string) : undefined - ) - } + if (collectionType === 'object') sort<[string | number, ValueData]>(keyValueArray, (_) => _) const CollectionChildren = !hasBeenOpened.current ? null : !isEditing ? ( keyValueArray.map(([key, value], index) => { @@ -339,14 +339,16 @@ export const CollectionNode: React.FC = (props) => { cancel: handleCancel, tabForward: () => { handleEditKey((e.target as HTMLInputElement).value) - const firstChildKey = Object.keys(data)[0] + const firstChildKey = keyValueArray?.[0][0] setCurrentlyEditingElement( - firstChildKey ? [...path, firstChildKey] : getNextOrPrevious(nodeData.fullData, path) + firstChildKey + ? [...path, firstChildKey] + : getNextOrPrevious(nodeData.fullData, path, 'next', sort) ) }, tabBack: () => { handleEditKey((e.target as HTMLInputElement).value) - setCurrentlyEditingElement(getNextOrPrevious(nodeData.fullData, path, 'prev')) + setCurrentlyEditingElement(getNextOrPrevious(nodeData.fullData, path, 'prev', sort)) }, }) } diff --git a/src/JsonEditor.tsx b/src/JsonEditor.tsx index 82195dd0..09a78836 100644 --- a/src/JsonEditor.tsx +++ b/src/JsonEditor.tsx @@ -265,6 +265,34 @@ const Editor: React.FC = ({ [keyboardControls] ) + // Common "sort" method for ordering nodes, based on the `keySort` prop + // - If it's false (the default), we do nothing + // - If true, use default array sort on the node's key + // - Otherwise sort via the defined comparison function + // The "nodeMap" is due to the fact that this sort is performed on different + // shaped arrays in different places, so in each implementation we pass a + // function to convert each element into a [key, value] tuple, the shape + // expected by the comparison function + const sort = useCallback( + (arr: T[], nodeMap: (input: T) => [string | number, unknown]) => { + if (keySort === false) return + + if (typeof keySort === 'function') { + arr.sort((a, b) => keySort(nodeMap(a), nodeMap(b))) + return + } + + arr.sort((a, b) => { + const A = nodeMap(a)[0] + const B = nodeMap(b)[0] + if (A < B) return -1 + if (A > B) return 1 + return 0 + }) + }, + [keySort] + ) + const otherProps = { mainContainerRef: mainContainerRef as React.MutableRefObject, name: rootName, @@ -289,6 +317,7 @@ const Editor: React.FC = ({ searchText: debouncedSearchText, enableClipboard, keySort, + sort, showArrayIndices, showStringQuotes, indent, diff --git a/src/ValueNodeWrapper.tsx b/src/ValueNodeWrapper.tsx index 457bb970..fc294538 100644 --- a/src/ValueNodeWrapper.tsx +++ b/src/ValueNodeWrapper.tsx @@ -43,6 +43,7 @@ export const ValueNodeWrapper: React.FC = (props) => { customNodeDefinitions, handleKeyboard, keyboardControls, + sort, } = props const { getStyles } = useTheme() const { @@ -140,7 +141,7 @@ export const ValueNodeWrapper: React.FC = (props) => { // This prevents hidden or uneditable nodes being set to editing via Tab // navigation if (isEditing && (!isVisible || !canEdit)) { - const next = getNextOrPrevious(nodeData.fullData, path, tabDirection) + const next = getNextOrPrevious(nodeData.fullData, path, tabDirection, sort) if (next) setCurrentlyEditingElement(next) else setCurrentlyEditingElement(previouslyEditedElement) } @@ -238,7 +239,7 @@ export const ValueNodeWrapper: React.FC = (props) => { tabForward: () => { setTabDirection('next') setPreviouslyEditedElement(pathString) - const next = getNextOrPrevious(nodeData.fullData, path) + const next = getNextOrPrevious(nodeData.fullData, path, 'next', sort) if (next) { handleEdit() setCurrentlyEditingElement(next) @@ -247,7 +248,7 @@ export const ValueNodeWrapper: React.FC = (props) => { tabBack: () => { setTabDirection('prev') setPreviouslyEditedElement(pathString) - const prev = getNextOrPrevious(nodeData.fullData, path, 'prev') + const prev = getNextOrPrevious(nodeData.fullData, path, 'prev', sort) if (prev) { handleEdit() setCurrentlyEditingElement(prev) @@ -333,7 +334,9 @@ export const ValueNodeWrapper: React.FC = (props) => { }, tabBack: () => { handleEditKey((e.target as HTMLInputElement).value) - setCurrentlyEditingElement(getNextOrPrevious(nodeData.fullData, path, 'prev')) + setCurrentlyEditingElement( + getNextOrPrevious(nodeData.fullData, path, 'prev', sort) + ) }, }) } diff --git a/src/helpers.ts b/src/helpers.ts index 1c5cf6c6..7947f31c 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -9,6 +9,8 @@ import { type JsonData, type CollectionKey, type TabDirection, + type SortFunction, + ValueData, } from './types' export const isCollection = (value: unknown): value is Record | unknown[] => @@ -255,7 +257,8 @@ export const getFullKeyboardControlMap = (userControls: KeyboardControls): Keybo export const getNextOrPrevious = ( fullData: JsonData, path: CollectionKey[], - nextOrPrev: TabDirection = 'next' + nextOrPrev: TabDirection = 'next', + sort: SortFunction ): CollectionKey[] | null => { const parentPath = path.slice(0, path.length - 1) const thisKey = path.slice(-1)[0] @@ -264,6 +267,9 @@ export const getNextOrPrevious = ( const parentData = extractProperty(fullData, parentPath) const collection = transformCollection(parentData as JsonData) + if (!Array.isArray(parentData)) + sort(collection, ({ key, value }) => [key, value]) + const thisIndex = collection.findIndex((el) => el.key === thisKey) const destinationIndex = nextOrPrev === 'next' ? thisIndex + 1 : thisIndex - 1 @@ -271,12 +277,12 @@ export const getNextOrPrevious = ( if (!destination) { if (parentPath.length === 0) return null - return getNextOrPrevious(fullData, parentPath, nextOrPrev) + return getNextOrPrevious(fullData, parentPath, nextOrPrev, sort) } - if (isCollection(destination.value)) { - return getChildRecursive(fullData, [...parentPath, destination.key], nextOrPrev) - } else return [...parentPath, destination.key] + if (isCollection(destination.value)) + return getChildRecursive(fullData, [...parentPath, destination.key], nextOrPrev, sort) + else return [...parentPath, destination.key] } // If the node at "path" is a collection, tries the first/last child of that @@ -284,13 +290,17 @@ export const getNextOrPrevious = ( const getChildRecursive = ( fullData: JsonData, path: CollectionKey[], - nextOrPrev: TabDirection = 'next' + nextOrPrev: TabDirection = 'next', + sort: SortFunction ) => { const node = extractProperty(fullData, path) if (!isCollection(node)) return path const keys = Array.isArray(node) ? node.map((_, index) => index) : Object.keys(node) + + sort(keys, (key) => [key, extractProperty(fullData, path)]) + const child = nextOrPrev === 'next' ? keys[0] : keys[keys.length - 1] - return getChildRecursive(fullData, [...path, child], nextOrPrev) + return getChildRecursive(fullData, [...path, child], nextOrPrev, sort) } // Transform a collections (Array or Object) into a structure that is easier to @@ -300,3 +310,15 @@ const transformCollection = (collection: JsonData) => { return collection.map((value, index) => ({ index, value, key: index })) return Object.entries(collection).map(([key, value], index) => ({ key, value, index })) } + +type TransformedCollection = + | { + index: number + value: any + key: number + } + | { + key: string + value: any + index: number + } diff --git a/src/types.ts b/src/types.ts index 5c5a6c2b..e24e7c1b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -139,7 +139,13 @@ export type CopyFunction = (input: { type: CopyType }) => void -export type CompareFunction = (a: string, b: string) => number +// Only using `any` here as that's the type expected by the JS "sort" method. +export type CompareFunction = ( + a: [string | number, unknown], + b: [string | number, unknown] +) => number + +export type SortFunction = (arr: T[], nodeMap: (input: T) => [string | number, unknown]) => void // Internal update export type InternalUpdateFunction = ( @@ -221,6 +227,7 @@ interface BaseNodeProps { restrictTypeSelection: boolean | DataType[] | TypeFilterFunction stringTruncate: number indent: number + sort: SortFunction translate: TranslateFunction customNodeDefinitions: CustomNodeDefinition[] customButtons: CustomButtonDefinition[] @@ -238,7 +245,6 @@ export interface CollectionNodeProps extends BaseNodeProps { collapseFilter: FilterFunction collapseAnimationTime: number onAdd: InternalUpdateFunction - keySort: boolean | CompareFunction showArrayIndices: boolean showCollectionCount: boolean | 'when-closed' showStringQuotes: boolean From c33672247fd21ec8084a3a8e7b6ee4a9429c5a54 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Sat, 25 Jan 2025 17:05:24 +1300 Subject: [PATCH 11/23] Update App.tsx --- demo/src/App.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 1604750c..1547db26 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -367,6 +367,7 @@ function App() { : false } restrictEdit={restrictEdit} + // restrictEdit={(nodeData) => !(typeof nodeData.value === 'string')} restrictDelete={restrictDelete} restrictAdd={restrictAdd} restrictTypeSelection={dataDefinition?.restrictTypeSelection} @@ -374,6 +375,21 @@ function App() { searchFilter={dataDefinition?.searchFilter} searchText={searchText} keySort={sortKeys} + // keySort={ + // sortKeys + // ? (a, b) => { + // const nameRev1 = String(a[0]).length + // const nameRev2 = String(b[0]).length + // if (nameRev1 < nameRev2) { + // return -1 + // } + // if (nameRev1 > nameRev2) { + // return 1 + // } + // return 0 + // } + // : false + // } defaultValue={dataDefinition?.defaultValue ?? defaultNewValue} showArrayIndices={showIndices} showStringQuotes={showStringQuotes} From d89c0ff772d4ec5831dacb35830d84ea5fde3a66 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Sat, 25 Jan 2025 17:08:51 +1300 Subject: [PATCH 12/23] Fix tests --- test/nextPrevious.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/nextPrevious.test.ts b/test/nextPrevious.test.ts index 083dee97..ad3f915a 100644 --- a/test/nextPrevious.test.ts +++ b/test/nextPrevious.test.ts @@ -1,8 +1,9 @@ import { getNextOrPrevious } from '../demo/src/json-edit-react/src/helpers' -const getNext = getNextOrPrevious +const getNext = (data: object, path: (string | number)[]) => + getNextOrPrevious(data, path, 'next', () => {}) const getPrevious = (data: object, path: (string | number)[]) => - getNextOrPrevious(data, path, 'prev') + getNextOrPrevious(data, path, 'prev', () => {}) const data = { a: 1, From 48e8883f87024cadf856d4bf1f1f0e3f74ab1573 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Sat, 25 Jan 2025 17:42:25 +1300 Subject: [PATCH 13/23] Update README.md --- README.md | 98 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index d6be9ee2..4ef6c3f5 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,6 @@ A [React](https://github.com/facebook/react) component for editing or viewing JS - [Inspiration](#inspiration) - [Changelog](#changelog) - ## Installation `npm i json-edit-react` @@ -107,6 +106,7 @@ It's pretty self explanatory (click the "edit" icon to edit, etc.), but there ar - When opening/closing a node, hold down "Alt/Option" to open/close *all* child nodes at once - For Number inputs, arrow-up and down keys will increment/decrement the value - For Boolean inputs, space bar will toggle the value +- Easily move to the next/previous node (for editing) using the `Tab`/`Shift-Tab` key - Drag and drop items to change the structure or modify display order - JSON text input can accept "looser" input, if an additional JSON parsing method is provided (e.g. [JSON5](https://json5.org/)). See `jsonParse` prop. @@ -114,52 +114,52 @@ It's pretty self explanatory (click the "edit" icon to edit, etc.), but there ar The only *required* value is `data` (although you will need to provide a `setData` method to update your data). -| prop | type | default | description | -| ----------------------- | --------------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `data` | `object\|array` | | The data to be displayed / edited | -| `setData` | `object\|array => void` | | Method to update your `data` object. See [Managing state](#managing-state) below for additional notes. | -| `rootName` | `string` | `"data"` | A name to display in the editor as the root of the data object. | -| `onUpdate` | `UpdateFunction` | | A function to run whenever a value is **updated** (edit, delete *or* add) in the editor. See [Update functions](#update-functions). | -| `onEdit` | `UpdateFunction` | | A function to run whenever a value is **edited**. | -| `onDelete` | `UpdateFunction` | | A function to run whenever a value is **deleted**. | -| `onAdd` | `UpdateFunction` | | A function to run whenever a new property is **added**. | -| `onChange` | `OnChangeFunction` | | A function to modify/constrain user input as they type -- see [OnChange functions](#onchange-function). | -| `onError` | `OnErrorFunction` | | A function to run whenever the component reports an error -- see [OnErrorFunction](#onerror-function). | -| `showErrorMessages` | `boolean ` | `true` | Whether or not the component should display its own error messages (you'd probably only want to disable this if you provided your own `onError` function) | -| `enableClipboard` | `boolean\|CopyFunction` | `true` | Whether or not to enable the "Copy to clipboard" button in the UI. If a function is provided, `true` is assumed and this function will be run whenever an item is copied. | -| `indent` | `number` | `3` | Specify the amount of indentation for each level of nesting in the displayed data. | -| `collapse` | `boolean\|number\|FilterFunction` | `false` | Defines which nodes of the JSON tree will be displayed "opened" in the UI on load. If `boolean`, it'll be either all or none. A `number` specifies a nesting depth after which nodes will be closed. For more fine control a function can be provided — see [Filter functions](#filter-functions). | -| `collapseAnimationTime` | `number` | `300` | Time (in milliseconds) for the transition animation when collapsing collection nodes. | -| `restrictEdit` | `boolean\|FilterFunction` | `false` | If `true`, no editing is permitted. A function can be provided for more specificity — see [Filter functions](#filter-functions) | -| `restrictDelete` | `boolean\|FilterFunction` | `false` | As with `restrictEdit` but for deletion | -| `restrictAdd` | `boolean\|FilterFunction` | `false` | As with `restrictEdit` but for adding new properties | -| `restrictTypeSelection` | `boolean\|DataType[]\|TypeFilterFunction` | `true` | For restricting the data types the user can select. Can be a list of data types (e.g. `[ 'string', 'number', 'boolean', 'array', 'object', 'null' ]`) or a boolean. A function can be provided -- it should take the same input as the above `FilterFunction`s, but output should be `boolean \| DataType[]`. | -| `restrictDrag` | `boolean\|FilterFunction` | `true` | Set to `false` to enable drag and drop functionality. See [Drag-n-drop](#drag-n-drop) | -| `searchText` | `string` | `undefined` | Data visibility will be filtered by matching against value, using the method defined below in `searchFilter` | -| `searchFilter` | `"key"\|"value"\|"all"\|SearchFilterFunction` | `undefined` | Define how `searchText` should be matched to filter the visible items. See [Search/Filtering](#searchfiltering) | -| `searchDebounceTime` | `number` | `350` | Debounce time when `searchText` changes | -| `keySort` | `boolean\|CompareFunction` | `false` | If `true`, object keys will be ordered (using default JS `.sort()`). A [compare function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) can also be provided to define sorting behaviour. | -| `showArrayIndices` | `boolean` | `true` | Whether or not to display the index (as a property key) for array elements. | -| `showStringQuotes` | `boolean` | `true` | Whether or not to display string values in "quotes". | -| `showCollectionCount` | `boolean\|"when-closed"` | `true` | Whether or not to display the number of items in each collection (object or array). | -| `defaultValue` | `any\|DefaultValueFilterFunction` | `null` | When a new property is added, it is initialised with this value. A [function can be provided](#filter-functions) with the almost the same input as the `FilterFunction`s, but should output a value. This allows a different default value to be used depending on the data state (e.g. default for top level is an object, but a string elsewhere.) | -| `stringTruncate` | `number` | `250` | String values longer than this many characters will be displayed truncated (with `...`). The full string will always be visible when editing. | -| `translations` | `LocalisedStrings` object | `{ }` | UI strings (such as error messages) can be translated by passing an object containing localised string values (there are only a few). See [Localisation](#localisation) | -| `theme` | `ThemeInput` | `default` | Either one of the built-in themes (imported separately), or an object specifying some or all theme properties. See [Themes](#themes--styles). | -| `className` | `string` | | Name of a CSS class to apply to the component. In most cases, specifying `theme` properties will be more straightforward. | -| `id` | `string` | | Name for the HTML `id` attribute on the main component container. | -| `icons` | `{[iconName]: JSX.Element, ... }` | `{ }` | Replace the built-in icons by specifying them here. See [Themes](#themes--styles). | | -| `minWidth` | `number\|string` (CSS value) | `250` | Minimum width for the editor container. | -| `maxWidth` | `number\|string` (CSS value) | `600` | Maximum width for the editor container. | -| `rootFontSize` | `number\|string` (CSS value) | `16px` | The "base" font size from which all other sizings are derived (in `em`s). By changing this you will scale the entire component. container. | -| `customNodeDefinitions` | `CustomNodeDefinition[]` | | You can provide customised components to override specific nodes in the data tree, according to a condition function. See see [Custom nodes](#custom-nodes) for more detail. (A simple custom component to turn url strings into active links is provided in the main package -- see [here](#active-hyperlinks)) | -| `customText` | `CustomTextDefinitions` | | In addition to [localising the component](#localisation) text strings, you can also *dynamically* alter it, depending on the data. See [Custom Text](#custom-text) for more detail. | -| `customButtons` | `CustomButtonDefinition[]` | `[]` | You can add your own buttons to the Edit Buttons panel if you'd like to be able to perform a custom operation on the data. See [Custom Buttons](#custom-buttons) | -| `jsonParse` | `(input: string) => JsonData` | `JSON.parse` | When editing a block of JSON directly, you may wish to allow some "looser" input -- e.g. 'single quotes', trailing commas, or unquoted field names. In this case, you can provide a third-party JSON parsing method. I recommend [JSON5](https://json5.org/), which is what is used in the [Demo](https://carlosnz.github.io/json-edit-react/) | -| `jsonStringify` | `(data: JsonData) => string` | `(data) => JSON.stringify(data, null, 2)` | Similarly, you can override the default presentation of the JSON string when starting editing JSON. You can supply different formatting parameters to the native `JSON.stringify()`, or provide a third-party option, like the aforementioned JSON5. | -| `errorMessageTimeout` | `number` | `2500` | Time (in milliseconds) to display the error message in the UI. | | -| `keyboardControls` | `KeyboardControls` | As explained [above](#usage) | Override some or all of the keyboard controls. See [Keyboard customisation](#keyboard-customisation) for details. | | -| `insertAtTop` | `boolean\| "object \| "array"` | `false` | If `true`, inserts new values at the *top* rather than bottom. Can set the behaviour just for arrays or objects by setting to `"object"` or `"array"` respectively. | | +| prop | type | default | description | +| ----------------------- | --------------------------------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `data` | `object\|array` | | The data to be displayed / edited | +| `setData` | `object\|array => void` | | Method to update your `data` object. See [Managing state](#managing-state) below for additional notes. | +| `rootName` | `string` | `"data"` | A name to display in the editor as the root of the data object. | +| `onUpdate` | `UpdateFunction` | | A function to run whenever a value is **updated** (edit, delete *or* add) in the editor. See [Update functions](#update-functions). | +| `onEdit` | `UpdateFunction` | | A function to run whenever a value is **edited**. | +| `onDelete` | `UpdateFunction` | | A function to run whenever a value is **deleted**. | +| `onAdd` | `UpdateFunction` | | A function to run whenever a new property is **added**. | +| `onChange` | `OnChangeFunction` | | A function to modify/constrain user input as they type -- see [OnChange functions](#onchange-function). | +| `onError` | `OnErrorFunction` | | A function to run whenever the component reports an error -- see [OnErrorFunction](#onerror-function). | +| `showErrorMessages` | `boolean ` | `true` | Whether or not the component should display its own error messages (you'd probably only want to disable this if you provided your own `onError` function) | +| `enableClipboard` | `boolean\|CopyFunction` | `true` | Whether or not to enable the "Copy to clipboard" button in the UI. If a function is provided, `true` is assumed and this function will be run whenever an item is copied. | +| `indent` | `number` | `3` | Specify the amount of indentation for each level of nesting in the displayed data. | +| `collapse` | `boolean\|number\|FilterFunction` | `false` | Defines which nodes of the JSON tree will be displayed "opened" in the UI on load. If `boolean`, it'll be either all or none. A `number` specifies a nesting depth after which nodes will be closed. For more fine control a function can be provided — see [Filter functions](#filter-functions). | +| `collapseAnimationTime` | `number` | `300` | Time (in milliseconds) for the transition animation when collapsing collection nodes. | +| `restrictEdit` | `boolean\|FilterFunction` | `false` | If `true`, no editing is permitted. A function can be provided for more specificity — see [Filter functions](#filter-functions) | +| `restrictDelete` | `boolean\|FilterFunction` | `false` | As with `restrictEdit` but for deletion | +| `restrictAdd` | `boolean\|FilterFunction` | `false` | As with `restrictEdit` but for adding new properties | +| `restrictTypeSelection` | `boolean\|DataType[]\|TypeFilterFunction` | `true` | For restricting the data types the user can select. Can be a list of data types (e.g. `[ 'string', 'number', 'boolean', 'array', 'object', 'null' ]`) or a boolean. A function can be provided -- it should take the same input as the above `FilterFunction`s, but output should be `boolean \| DataType[]`. | +| `restrictDrag` | `boolean\|FilterFunction` | `true` | Set to `false` to enable drag and drop functionality. See [Drag-n-drop](#drag-n-drop) | +| `searchText` | `string` | `undefined` | Data visibility will be filtered by matching against value, using the method defined below in `searchFilter` | +| `searchFilter` | `"key"\|"value"\|"all"\|SearchFilterFunction` | `undefined` | Define how `searchText` should be matched to filter the visible items. See [Search/Filtering](#searchfiltering) | +| `searchDebounceTime` | `number` | `350` | Debounce time when `searchText` changes | +| `keySort` | `boolean\|CompareFunction` | `false` | If `true`, object keys will be ordered (using default JS `.sort()`). A [compare function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) can also be provided to define sorting behaviour, except the input type should be a tuple of the key and the value of a node i.e. `(a: [string \| number, ValueData], b: [string \| number, ValueData]) => number` | +| `showArrayIndices` | `boolean` | `true` | Whether or not to display the index (as a property key) for array elements. | +| `showStringQuotes` | `boolean` | `true` | Whether or not to display string values in "quotes". | +| `showCollectionCount` | `boolean\|"when-closed"` | `true` | Whether or not to display the number of items in each collection (object or array). | +| `defaultValue` | `any\|DefaultValueFilterFunction` | `null` | When a new property is added, it is initialised with this value. A [function can be provided](#filter-functions) with the almost the same input as the `FilterFunction`s, but should output a value. This allows a different default value to be used depending on the data state (e.g. default for top level is an object, but a string elsewhere.) | +| `stringTruncate` | `number` | `250` | String values longer than this many characters will be displayed truncated (with `...`). The full string will always be visible when editing. | +| `translations` | `LocalisedStrings` object | `{ }` | UI strings (such as error messages) can be translated by passing an object containing localised string values (there are only a few). See [Localisation](#localisation) | +| `theme` | `ThemeInput` | `default` | Either one of the built-in themes (imported separately), or an object specifying some or all theme properties. See [Themes](#themes--styles). | +| `className` | `string` | | Name of a CSS class to apply to the component. In most cases, specifying `theme` properties will be more straightforward. | +| `id` | `string` | | Name for the HTML `id` attribute on the main component container. | +| `icons` | `{[iconName]: JSX.Element, ... }` | `{ }` | Replace the built-in icons by specifying them here. See [Themes](#themes--styles). | | +| `minWidth` | `number\|string` (CSS value) | `250` | Minimum width for the editor container. | +| `maxWidth` | `number\|string` (CSS value) | `600` | Maximum width for the editor container. | +| `rootFontSize` | `number\|string` (CSS value) | `16px` | The "base" font size from which all other sizings are derived (in `em`s). By changing this you will scale the entire component. container. | +| `customNodeDefinitions` | `CustomNodeDefinition[]` | | You can provide customised components to override specific nodes in the data tree, according to a condition function. See see [Custom nodes](#custom-nodes) for more detail. (A simple custom component to turn url strings into active links is provided in the main package -- see [here](#active-hyperlinks)) | +| `customText` | `CustomTextDefinitions` | | In addition to [localising the component](#localisation) text strings, you can also *dynamically* alter it, depending on the data. See [Custom Text](#custom-text) for more detail. | +| `customButtons` | `CustomButtonDefinition[]` | `[]` | You can add your own buttons to the Edit Buttons panel if you'd like to be able to perform a custom operation on the data. See [Custom Buttons](#custom-buttons) | +| `jsonParse` | `(input: string) => JsonData` | `JSON.parse` | When editing a block of JSON directly, you may wish to allow some "looser" input -- e.g. 'single quotes', trailing commas, or unquoted field names. In this case, you can provide a third-party JSON parsing method. I recommend [JSON5](https://json5.org/), which is what is used in the [Demo](https://carlosnz.github.io/json-edit-react/) | +| `jsonStringify` | `(data: JsonData) => string` | `(data) => JSON.stringify(data, null, 2)` | Similarly, you can override the default presentation of the JSON string when starting editing JSON. You can supply different formatting parameters to the native `JSON.stringify()`, or provide a third-party option, like the aforementioned JSON5. | +| `errorMessageTimeout` | `number` | `2500` | Time (in milliseconds) to display the error message in the UI. | | +| `keyboardControls` | `KeyboardControls` | As explained [above](#usage) | Override some or all of the keyboard controls. See [Keyboard customisation](#keyboard-customisation) for details. | | +| `insertAtTop` | `boolean\| "object \| "array"` | `false` | If `true`, inserts new values at the *top* rather than bottom. Can set the behaviour just for arrays or objects by setting to `"object"` or `"array"` respectively. | | ## Managing state @@ -780,7 +780,9 @@ This component is heavily inspired by [react-json-view](https://github.com/mac-s ## Changelog -- **1.20.0**: Refactor out direct access of global `document` object, which allows component to work with server-side rendering +- **1.20.0**: + - Implement navigation using the "Tab" key + - Refactor out direct access of global `document` object, which allows component to work with server-side rendering - **1.19.2**: - Boolean toggle key can be customised [#150](https://github.com/CarlosNZ/json-edit-react/issues/150) - Pass `nodeData` to [custom buttons](#custom-buttons) [#146](https://github.com/CarlosNZ/json-edit-react/issues/146) From 249802f95f99bb3a16f325f34008f8f11a530d63 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Sat, 25 Jan 2025 19:55:35 +1300 Subject: [PATCH 14/23] Handle "Tab" key correctly in JSON editing Text Area --- src/CollectionNode.tsx | 27 +++++++++++++++++++++++++-- src/ValueNodes.tsx | 15 ++++++--------- src/helpers.ts | 20 +++++++++++++++++++- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index 49de50ab..d37e4539 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -9,7 +9,13 @@ import { type ValueData, } from './types' import { Icon } from './Icons' -import { filterNode, getModifier, getNextOrPrevious, isCollection } from './helpers' +import { + filterNode, + getModifier, + getNextOrPrevious, + insertCharInTextArea, + isCollection, +} from './helpers' import { AutogrowTextArea } from './AutogrowTextArea' import { useTheme, useTreeState } from './contexts' import { useCollapseTransition, useCommon, useDragNDrop } from './hooks' @@ -106,6 +112,9 @@ export const CollectionNode: React.FC = (props) => { } }, [collapseState]) + // For JSON-editing TextArea + const textAreaRef = useRef(null) + const getDefaultNewValue = useMemo( () => (nodeData: NodeData, newKey: string) => { if (typeof defaultValue !== 'function') return defaultValue @@ -140,11 +149,24 @@ export const CollectionNode: React.FC = (props) => { const brackets = collectionType === 'array' ? { open: '[', close: ']' } : { open: '{', close: '}' } - const handleKeyPressEdit = (e: React.KeyboardEvent) => + const handleKeyPressEdit = (e: React.KeyboardEvent) => { + // Normal "Tab" key functionality in TextArea + // Defined here explicitly rather than in handleKeyboard as we *don't* want + // to override the normal Tab key with the custom "Tab" key value + if (e.key === 'Tab' && !e.getModifierState('Shift')) { + e.preventDefault() + const newValue = insertCharInTextArea( + textAreaRef as React.MutableRefObject, + '\t' + ) + setStringifiedValue(newValue) + return + } handleKeyboard(e, { objectConfirm: handleEdit, cancel: handleCancel, }) + } const handleCollapse = (e: React.MouseEvent) => { const modifier = getModifier(e) @@ -277,6 +299,7 @@ export const CollectionNode: React.FC = (props) => {
= ({ handleKeyboard(e, { stringConfirm: handleEdit, stringLineBreak: () => { - const textArea = textAreaRef.current // Simulates standard text-area line break behaviour. Only // required when control key is not "standard" text-area // behaviour ("Shift-Enter" or "Enter") - const startPos: number = textArea?.selectionStart ?? Infinity - const endPos: number = textArea?.selectionEnd ?? Infinity - const strStart = value.slice(0, startPos) - const strEnd = value.slice(endPos) - ;(e.target as HTMLInputElement).value = strStart + '\n' + strEnd - textArea?.setSelectionRange(startPos + 1, startPos + 1) - setValue(strStart + '\n' + strEnd) + const newValue = insertCharInTextArea( + textAreaRef as React.MutableRefObject, + '\n' + ) + setValue(newValue) }, ...keyboardCommon, }) diff --git a/src/helpers.ts b/src/helpers.ts index 7947f31c..4a1c7ae6 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -10,7 +10,6 @@ import { type CollectionKey, type TabDirection, type SortFunction, - ValueData, } from './types' export const isCollection = (value: unknown): value is Record | unknown[] => @@ -322,3 +321,22 @@ type TransformedCollection = value: any index: number } + +// Manipulates a TextArea (ref) directly by inserting a string at the current +// cursor/selection position. Used to insert Line break and Tab characters via +// keyboard control. +export const insertCharInTextArea = ( + textAreaRef: React.MutableRefObject, + insertionString: string +) => { + const textArea = textAreaRef.current + const startPos: number = textArea?.selectionStart ?? Infinity + const endPos: number = textArea?.selectionEnd ?? Infinity + const strStart = textArea?.textContent?.slice(0, startPos) + const strEnd = textArea?.textContent?.slice(endPos) + + const newString = strStart + insertionString + strEnd + textArea.value = newString + textArea?.setSelectionRange(startPos + 1, startPos + 1) + return newString +} From 022a703e12e0789766d60aa7504ec7f857d2fe19 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Mon, 27 Jan 2025 18:04:03 +1300 Subject: [PATCH 15/23] Basic implementation --- demo/package.json | 2 + demo/src/App.tsx | 22 +++- demo/src/CodeEditor.tsx | 16 +++ demo/src/demoData/dataDefinitions.tsx | 5 + demo/src/style.css | 9 ++ demo/yarn.lock | 177 ++++++++++++++++++++++++++ src/CollectionNode.tsx | 20 ++- src/JsonEditor.tsx | 2 + src/index.ts | 1 + src/types.ts | 8 ++ 10 files changed, 257 insertions(+), 5 deletions(-) create mode 100644 demo/src/CodeEditor.tsx diff --git a/demo/package.json b/demo/package.json index 6707dfd0..637e1336 100644 --- a/demo/package.json +++ b/demo/package.json @@ -6,6 +6,7 @@ "dependencies": { "@chakra-ui/icons": "^2.1.1", "@chakra-ui/react": "^2.8.2", + "@codemirror/lang-json": "^6.0.1", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@testing-library/jest-dom": "^6.3.0", @@ -15,6 +16,7 @@ "@types/node": "^20.11.6", "@types/react": "^18.2.48", "@types/react-dom": "^18.2.18", + "@uiw/react-codemirror": "^4.23.7", "ajv": "^8.16.0", "firebase": "^10.13.0", "framer-motion": "^11.0.3", diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 1547db26..4e9db423 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -45,13 +45,15 @@ import { NumberIncrementStepper, NumberDecrementStepper, useToast, + Tooltip, } from '@chakra-ui/react' import logo from './image/logo_400.png' -import { ArrowBackIcon, ArrowForwardIcon } from '@chakra-ui/icons' +import { ArrowBackIcon, ArrowForwardIcon, InfoIcon } from '@chakra-ui/icons' import { demoDataDefinitions } from './demoData' import { useDatabase } from './useDatabase' import './style.css' import { version } from './version' +import { CodeEditor } from './CodeEditor' interface AppState { rootName: string @@ -69,6 +71,7 @@ interface AppState { showStringQuotes: boolean defaultNewValue: string searchText: string + customTextEditor: boolean } const themes = [ @@ -104,6 +107,7 @@ function App() { showStringQuotes: true, defaultNewValue: 'New data!', searchText: '', + customTextEditor: false, }) const [isSaving, setIsSaving] = useState(false) @@ -144,6 +148,7 @@ function App() { allowEdit, allowDelete, allowAdd, + customTextEditor, } = state const restrictEdit: FilterFunction | boolean = (() => { @@ -178,6 +183,7 @@ function App() { searchText: '', collapseLevel: newDataDefinition.collapse ?? state.collapseLevel, rootName: newDataDefinition.rootName ?? 'data', + customTextEditor: false, }) switch (selected) { @@ -431,6 +437,7 @@ function App() { // }} // insertAtBeginning="object" // rootFontSize={20} + TextEditor={customTextEditor ? CodeEditor : undefined} /> @@ -666,6 +673,19 @@ function App() { > Sort Object keys + + toggleState('customTextEditor')} + disabled={!dataDefinition.customTextEditorAvailable} + > + Custom Text Editor + + + + + diff --git a/demo/src/CodeEditor.tsx b/demo/src/CodeEditor.tsx new file mode 100644 index 00000000..77888550 --- /dev/null +++ b/demo/src/CodeEditor.tsx @@ -0,0 +1,16 @@ +import React from 'react' +import CodeMirror from '@uiw/react-codemirror' +import { json } from '@codemirror/lang-json' +import { TextEditorProps } from './_imports' + +export const CodeEditor: React.FC = ({ value, onChange, onKeyDown }) => { + return ( + + ) +} diff --git a/demo/src/demoData/dataDefinitions.tsx b/demo/src/demoData/dataDefinitions.tsx index e0d0a651..fe423630 100644 --- a/demo/src/demoData/dataDefinitions.tsx +++ b/demo/src/demoData/dataDefinitions.tsx @@ -55,6 +55,7 @@ export interface DemoData { customNodeDefinitions?: CustomNodeDefinition[] customTextDefinitions?: CustomTextDefinitions styles?: Partial + customTextEditorAvailable?: boolean } export const demoDataDefinitions: Record = { @@ -92,6 +93,7 @@ export const demoDataDefinitions: Record = { data: data.intro, customNodeDefinitions: [dateNodeDefinition], // restrictEdit: ({ key }) => key === 'number', + customTextEditorAvailable: true, }, starWars: { name: '🚀 Star Wars', @@ -280,6 +282,7 @@ export const demoDataDefinitions: Record = { return 'JSON Schema error' } }, + customTextEditorAvailable: true, }, liveData: { name: '📖 Live Data (from database)', @@ -441,6 +444,7 @@ export const demoDataDefinitions: Record = { searchFilter: 'key', searchPlaceholder: 'Search Theme keys', data: {}, + customTextEditorAvailable: true, }, customNodes: { name: '🔧 Custom Nodes', @@ -626,5 +630,6 @@ export const demoDataDefinitions: Record = { styles: { string: ({ key }) => (key === 'name' ? { fontWeight: 'bold', fontSize: '120%' } : null), }, + customTextEditorAvailable: true, }, } diff --git a/demo/src/style.css b/demo/src/style.css index 81726876..69c17270 100644 --- a/demo/src/style.css +++ b/demo/src/style.css @@ -44,3 +44,12 @@ footer { font-weight: 600; color: dimgray; } + +.cm-theme-light { + width: 100%; +} + +.cm-content, +.cm-gutters { + font-size: 80%; +} diff --git a/demo/yarn.lock b/demo/yarn.lock index 0b963f0f..0202f084 100644 --- a/demo/yarn.lock +++ b/demo/yarn.lock @@ -1168,6 +1168,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.18.6": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.7.tgz#f4e7fe527cd710f8dc0618610b61b4b060c3c341" + integrity sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" @@ -2060,6 +2067,90 @@ resolved "https://registry.yarnpkg.com/@chakra-ui/visually-hidden/-/visually-hidden-2.2.0.tgz#9b0ecef8f01263ab808ba3bda7b36a0d91b4d5c1" integrity sha512-KmKDg01SrQ7VbTD3+cPWf/UfpF5MSwm3v7MWi0n5t8HnnadT13MF0MJCDSXbBWnzLv1ZKJ6zlyAOeARWX+DpjQ== +"@codemirror/autocomplete@^6.0.0": + version "6.18.4" + resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.18.4.tgz#4394f55d6771727179f2e28a871ef46bbbeb11b1" + integrity sha512-sFAphGQIqyQZfP2ZBsSHV7xQvo9Py0rV0dW7W3IMRdS+zDuNb2l3no78CvUaWKGfzFjI4FTrLdUSj86IGb2hRA== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.17.0" + "@lezer/common" "^1.0.0" + +"@codemirror/commands@^6.0.0", "@codemirror/commands@^6.1.0": + version "6.8.0" + resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.8.0.tgz#92f200b66f852939bd6ebb90d48c2d9e9c813d64" + integrity sha512-q8VPEFaEP4ikSlt6ZxjB3zW72+7osfAYW9i8Zu943uqbKuz6utc1+F170hyLUCUltXORjQXRyYQNfkckzA/bPQ== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.4.0" + "@codemirror/view" "^6.27.0" + "@lezer/common" "^1.1.0" + +"@codemirror/lang-json@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@codemirror/lang-json/-/lang-json-6.0.1.tgz#0a0be701a5619c4b0f8991f9b5e95fe33f462330" + integrity sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ== + dependencies: + "@codemirror/language" "^6.0.0" + "@lezer/json" "^1.0.0" + +"@codemirror/language@^6.0.0": + version "6.10.8" + resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.10.8.tgz#3e3a346a2b0a8cf63ee1cfe03349eb1965dce5f9" + integrity sha512-wcP8XPPhDH2vTqf181U8MbZnW+tDyPYy0UzVOa+oHORjyT+mhhom9vBd7dApJwoDz9Nb/a8kHjJIsuA/t8vNFw== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.23.0" + "@lezer/common" "^1.1.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + style-mod "^4.0.0" + +"@codemirror/lint@^6.0.0": + version "6.8.4" + resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.8.4.tgz#7d8aa5d1a6dec89ffcc23ad45ddca2e12e90982d" + integrity sha512-u4q7PnZlJUojeRe8FJa/njJcMctISGgPQ4PnWsd9268R4ZTtU+tfFYmwkBvgcrK2+QQ8tYFVALVb5fVJykKc5A== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.35.0" + crelt "^1.0.5" + +"@codemirror/search@^6.0.0": + version "6.5.8" + resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.5.8.tgz#b59b3659b46184cc75d6108d7c050a4ca344c3a0" + integrity sha512-PoWtZvo7c1XFeZWmmyaOp2G0XVbOnm+fJzvghqGAktBW3cufwJUWvSCcNG0ppXiBEM05mZu6RhMtXPv2hpllig== + dependencies: + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + crelt "^1.0.5" + +"@codemirror/state@^6.0.0", "@codemirror/state@^6.1.1", "@codemirror/state@^6.4.0", "@codemirror/state@^6.5.0": + version "6.5.1" + resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.5.1.tgz#e5c0599f7b43cf03f19e05861317df5425c07904" + integrity sha512-3rA9lcwciEB47ZevqvD8qgbzhM9qMb8vCcQCNmDfVRPQG4JT9mSb0Jg8H7YjKGGQcFnLN323fj9jdnG59Kx6bg== + dependencies: + "@marijn/find-cluster-break" "^1.0.0" + +"@codemirror/theme-one-dark@^6.0.0": + version "6.1.2" + resolved "https://registry.yarnpkg.com/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz#fcef9f9cfc17a07836cb7da17c9f6d7231064df8" + integrity sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA== + dependencies: + "@codemirror/language" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + "@lezer/highlight" "^1.0.0" + +"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0", "@codemirror/view@^6.27.0", "@codemirror/view@^6.35.0": + version "6.36.2" + resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.36.2.tgz#aeb644e161440734ac5a153bf6e5b4a4355047be" + integrity sha512-DZ6ONbs8qdJK0fdN7AB82CgI6tYXf4HWk1wSVa0+9bhVznCuuvhQtX8bFBoy3dv8rZSQqUd8GvhVAcielcidrA== + dependencies: + "@codemirror/state" "^6.5.0" + style-mod "^4.1.0" + w3c-keyname "^2.2.4" + "@csstools/normalize.css@*": version "12.1.1" resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-12.1.1.tgz#f0ad221b7280f3fc814689786fd9ee092776ef8f" @@ -3076,6 +3167,39 @@ resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz#4fc56c15c580b9adb7dc3c333a134e540b44bfb1" integrity sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw== +"@lezer/common@^1.0.0", "@lezer/common@^1.1.0", "@lezer/common@^1.2.0": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.2.3.tgz#138fcddab157d83da557554851017c6c1e5667fd" + integrity sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA== + +"@lezer/highlight@^1.0.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.2.1.tgz#596fa8f9aeb58a608be0a563e960c373cbf23f8b" + integrity sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA== + dependencies: + "@lezer/common" "^1.0.0" + +"@lezer/json@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@lezer/json/-/json-1.0.3.tgz#e773a012ad0088fbf07ce49cfba875cc9e5bc05f" + integrity sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ== + dependencies: + "@lezer/common" "^1.2.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + +"@lezer/lr@^1.0.0": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-1.4.2.tgz#931ea3dea8e9de84e90781001dae30dea9ff1727" + integrity sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA== + dependencies: + "@lezer/common" "^1.0.0" + +"@marijn/find-cluster-break@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz#775374306116d51c0c500b8c4face0f9a04752d8" + integrity sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g== + "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": version "5.1.1-v1" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129" @@ -3858,6 +3982,31 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" +"@uiw/codemirror-extensions-basic-setup@4.23.7": + version "4.23.7" + resolved "https://registry.yarnpkg.com/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.23.7.tgz#8fce5d6190a755c889805d2edc5b85d7f29cd322" + integrity sha512-9/2EUa1Lck4kFKkR2BkxlZPpgD/EWuKHnOlysf1yHKZGraaZmZEaUw+utDK4QcuJc8Iz097vsLz4f4th5EU27g== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/commands" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/lint" "^6.0.0" + "@codemirror/search" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + +"@uiw/react-codemirror@^4.23.7": + version "4.23.7" + resolved "https://registry.yarnpkg.com/@uiw/react-codemirror/-/react-codemirror-4.23.7.tgz#b7fe2085936c593514f5e238865989bfef65e504" + integrity sha512-Nh/0P6W+kWta+ARp9YpnKPD9ick5teEnwmtNoPQnyd6NPv0EQP3Ui4YmRVNj1nkUEo+QjrAUaEfcejJ2up/HZA== + dependencies: + "@babel/runtime" "^7.18.6" + "@codemirror/commands" "^6.1.0" + "@codemirror/state" "^6.1.1" + "@codemirror/theme-one-dark" "^6.0.0" + "@uiw/codemirror-extensions-basic-setup" "4.23.7" + codemirror "^6.0.0" + "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" @@ -4860,6 +5009,19 @@ coa@^2.0.2: chalk "^2.4.1" q "^1.1.2" +codemirror@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-6.0.1.tgz#62b91142d45904547ee3e0e0e4c1a79158035a29" + integrity sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg== + dependencies: + "@codemirror/autocomplete" "^6.0.0" + "@codemirror/commands" "^6.0.0" + "@codemirror/language" "^6.0.0" + "@codemirror/lint" "^6.0.0" + "@codemirror/search" "^6.0.0" + "@codemirror/state" "^6.0.0" + "@codemirror/view" "^6.0.0" + collect-v8-coverage@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" @@ -5084,6 +5246,11 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" +crelt@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72" + integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g== + cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -10866,6 +11033,11 @@ style-loader@^3.3.1: resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.4.tgz#f30f786c36db03a45cbd55b6a70d930c479090e7" integrity sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w== +style-mod@^4.0.0, style-mod@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.1.2.tgz#ca238a1ad4786520f7515a8539d5a63691d7bf67" + integrity sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw== + stylehacks@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9" @@ -11500,6 +11672,11 @@ w3c-hr-time@^1.0.2: dependencies: browser-process-hrtime "^1.0.0" +w3c-keyname@^2.2.4: + version "2.2.8" + resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5" + integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ== + w3c-xmlserializer@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index d37e4539..ee8cd9c3 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -54,6 +54,7 @@ export const CollectionNode: React.FC = (props) => { customNodeDefinitions, jsonParse, jsonStringify, + TextEditor, keyboardControls, handleKeyboard, insertAtTop, @@ -297,7 +298,18 @@ export const CollectionNode: React.FC = (props) => { }) ) : (
-
+ {TextEditor ? ( + + handleKeyboard(e, { + objectConfirm: handleEdit, + cancel: handleCancel, + }) + } + /> + ) : ( = (props) => { handleKeyPress={handleKeyPressEdit} styles={getStyles('input', nodeData)} /> -
- -
+ )} +
+
) diff --git a/src/JsonEditor.tsx b/src/JsonEditor.tsx index 09a78836..c1133961 100644 --- a/src/JsonEditor.tsx +++ b/src/JsonEditor.tsx @@ -70,6 +70,7 @@ const Editor: React.FC = ({ customButtons = [], jsonParse = JSON.parse, jsonStringify = (data: JsonData) => JSON.stringify(data, null, 2), + TextEditor, errorMessageTimeout = 2500, keyboardControls = {}, insertAtTop = false, @@ -329,6 +330,7 @@ const Editor: React.FC = ({ parentData: null, jsonParse, jsonStringify, + TextEditor, errorMessageTimeout, handleKeyboard: handleKeyboardCallback, keyboardControls: fullKeyboardControls, diff --git a/src/index.ts b/src/index.ts index 1da9b40e..3b718028 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,6 +31,7 @@ export { type NodeData, type JsonData, type KeyboardControls, + type TextEditorProps, } from './types' export { type LocalisedStrings, type TranslateFunction } from './localisation' diff --git a/src/types.ts b/src/types.ts index e24e7c1b..a67d298f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -45,6 +45,7 @@ export interface JsonEditorProps { customButtons?: CustomButtonDefinition[] jsonParse?: (input: string) => JsonData jsonStringify?: (input: JsonData) => string + TextEditor?: React.FC errorMessageTimeout?: number // ms keyboardControls?: KeyboardControls insertAtTop?: boolean | 'array' | 'object' @@ -74,6 +75,12 @@ export interface IconReplacements { chevron?: JSX.Element } +export interface TextEditorProps { + value: string + onChange: (value: string) => void + onKeyDown: (e: React.KeyboardEvent) => void +} + /** * FUNCTIONS */ @@ -252,6 +259,7 @@ export interface CollectionNodeProps extends BaseNodeProps { jsonParse: (input: string) => JsonData jsonStringify: (data: JsonData) => string insertAtTop: { object: boolean; array: boolean } + TextEditor?: React.FC } export type ValueData = string | number | boolean From cc7ffeb7747877826e2de3d015417e187d21ad35 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Mon, 27 Jan 2025 23:28:36 +1300 Subject: [PATCH 16/23] Update CollectionNode.tsx --- src/CollectionNode.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index ee8cd9c3..ebbc8fb4 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -98,6 +98,7 @@ export const CollectionNode: React.FC = (props) => { useEffect(() => { setStringifiedValue(jsonStringify(data)) + if (isEditing) setCurrentlyEditingElement(null) }, [data]) useEffect(() => { From 2a51269516837a43839a75b416991db4b82da292 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:28:48 +1300 Subject: [PATCH 17/23] Lazy load code editor --- demo/src/App.tsx | 15 ++++++++++++--- demo/src/CodeEditor.tsx | 4 +++- image/text_edit-new.png | Bin 0 -> 111684 bytes image/text_edit-normal.png | Bin 0 -> 89619 bytes 4 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 image/text_edit-new.png create mode 100644 image/text_edit-normal.png diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 4e9db423..1ce0a801 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from 'react' +import React, { useEffect, useRef, lazy, Suspense } from 'react' import { useSearch, useLocation } from 'wouter' import JSON5 from 'json5' import 'react-datepicker/dist/react-datepicker.css' @@ -53,7 +53,8 @@ import { demoDataDefinitions } from './demoData' import { useDatabase } from './useDatabase' import './style.css' import { version } from './version' -import { CodeEditor } from './CodeEditor' + +const CodeEditor = lazy(() => import('./CodeEditor')) interface AppState { rootName: string @@ -437,7 +438,15 @@ function App() { // }} // insertAtBeginning="object" // rootFontSize={20} - TextEditor={customTextEditor ? CodeEditor : undefined} + TextEditor={ + customTextEditor + ? (props) => ( + + + + ) + : undefined + } /> diff --git a/demo/src/CodeEditor.tsx b/demo/src/CodeEditor.tsx index 77888550..5438b59e 100644 --- a/demo/src/CodeEditor.tsx +++ b/demo/src/CodeEditor.tsx @@ -3,7 +3,7 @@ import CodeMirror from '@uiw/react-codemirror' import { json } from '@codemirror/lang-json' import { TextEditorProps } from './_imports' -export const CodeEditor: React.FC = ({ value, onChange, onKeyDown }) => { +const CodeEditor: React.FC = ({ value, onChange, onKeyDown }) => { return ( = ({ value, onChange, onKeyDo /> ) } + +export default CodeEditor diff --git a/image/text_edit-new.png b/image/text_edit-new.png new file mode 100644 index 0000000000000000000000000000000000000000..22fd4c8c2c78931d14659da538a668aef87560d9 GIT binary patch literal 111684 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 G@P7c!X5IGy literal 0 HcmV?d00001 diff --git a/image/text_edit-normal.png b/image/text_edit-normal.png new file mode 100644 index 0000000000000000000000000000000000000000..3805579d1a6b0be204c723b0b8b230780cf77f18 GIT binary patch literal 89619 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

6N4wj4p)|ywbMw87IcPO=W5a-y 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 Iokvgq52nCUDF6Tf literal 0 HcmV?d00001 From 6e3d21d20750b4a6519eea1f472be9a2a41b8a7c Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Wed, 29 Jan 2025 16:49:51 +1300 Subject: [PATCH 18/23] Add Loading component --- demo/src/App.tsx | 10 +++++++++- demo/src/style.css | 7 +++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 1ce0a801..16f08423 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -441,7 +441,13 @@ function App() { TextEditor={ customTextEditor ? (props) => ( - + + Loading code editor... +

+ } + > ) @@ -729,3 +735,5 @@ export default App export const truncate = (string: string, length = 200) => string.length < length ? string : `${string.slice(0, length - 2).trim()}...` + +const getLineHeight = (data: JsonData) => JSON.stringify(data, null, 2).split('\n').length diff --git a/demo/src/style.css b/demo/src/style.css index 69c17270..f716119b 100644 --- a/demo/src/style.css +++ b/demo/src/style.css @@ -53,3 +53,10 @@ footer { .cm-gutters { font-size: 80%; } + +.loading { + width: 100%; + display: flex; + align-items: center; + justify-content: center; +} From 235eb7f1c1090e6a5dfade6428cb3e44d84a8861 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:08:42 +1300 Subject: [PATCH 19/23] Update README.md --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a5074dfb..1ffa0129 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ A [React](https://github.com/facebook/react) component for editing or viewing JS - [Examples](#examples-1) - [JSON Schema validation](#json-schema-validation) - [Drag-n-drop](#drag-n-drop) +- [Full object editing](#full-object-editing) - [Search/Filtering](#searchfiltering) - [Themes \& Styles](#themes--styles) - [Fragments](#fragments) @@ -157,13 +158,14 @@ The only *required* value is `data` (although you will need to provide a `setDat | `customButtons` | `CustomButtonDefinition[]` | `[]` | You can add your own buttons to the Edit Buttons panel if you'd like to be able to perform a custom operation on the data. See [Custom Buttons](#custom-buttons) | | `jsonParse` | `(input: string) => JsonData` | `JSON.parse` | When editing a block of JSON directly, you may wish to allow some "looser" input -- e.g. 'single quotes', trailing commas, or unquoted field names. In this case, you can provide a third-party JSON parsing method. I recommend [JSON5](https://json5.org/), which is what is used in the [Demo](https://carlosnz.github.io/json-edit-react/) | | `jsonStringify` | `(data: JsonData) => string` | `(data) => JSON.stringify(data, null, 2)` | Similarly, you can override the default presentation of the JSON string when starting editing JSON. You can supply different formatting parameters to the native `JSON.stringify()`, or provide a third-party option, like the aforementioned JSON5. | +| `TextEditor` | `ReactComponent` | | Pass a component to offer a custom text/code editor when editing full JSON object as text. [See details](#full-object-editing) | | `errorMessageTimeout` | `number` | `2500` | Time (in milliseconds) to display the error message in the UI. | | | `keyboardControls` | `KeyboardControls` | As explained [above](#usage) | Override some or all of the keyboard controls. See [Keyboard customisation](#keyboard-customisation) for details. | | | `insertAtTop` | `boolean\| "object \| "array"` | `false` | If `true`, inserts new values at the *top* rather than bottom. Can set the behaviour just for arrays or objects by setting to `"object"` or `"array"` respectively. | | ## Managing state -It is recommended that you manage the `data` state yourself outside this component -- just pass in a `setData` method, which is called internally to update your `data`. However, this is not compulsory -- if you don't provide a `setData` method, the data will be managed internally, which would be fine if you're not doing anything with the data. The alternative is to use the [Update functions](#update-functions) to update your `data` externally, but this is not recommended except in special circumstances as you can run into issues keeping your data in sync with the internal state (which is what is displayed), as well as unnecessary re-renders. Update functions should be ideally be used only for implementing side effects, checking for errors, or mutating the data before setting it with `setData`. +It is recommended that you manage the `data` state yourself outside this component -- just pass in a `setData` method, which is called internally to update your `data`. However, this is not compulsory -- if you don't provide a `setData` method, the data will be managed internally, which would be fine if you're not doing anything with the data. The alternative is to use the [Update functions](#update-functions) to update your `data` externally, but this is not recommended except in special circumstances as you can run into issues keeping your data in sync with the internal state (which is what is displayed), as well as unnecessary re-renders. Update functions should be ideally be used only for implementing side effects (e.g. notifications), validation, or mutating the data before setting it with `setData`. ## Update functions @@ -396,6 +398,24 @@ The `restrictDrag` property controls which items (if any) can be dragged into ne - To be draggable, the node must *also* be delete-able (via the `restrictDelete` prop), as dragging a node to a new destination is essentially just deleting it and adding it back elsewhere. - Similarly, the destination collection must be editable in order to drop it in there. This means that, if you've gone to the trouble of configuring restrictive editing constraints using Filter functions, you can be confident that they can't be circumvented via drag-n-drop. +## Full object editing + +The user can edit the entire JSON object (or a sub-node) as raw text (provided you haven't restricted it using a [`restrictEdit` function](#filter-functions)). By default, we just display a native HTML [textarea](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea) element for plain-text editing. However, you can offer a more sophisticated text/code editor by passing the component into the `TextEditor` prop. Your component must provide the following props for json-edit-react to use: + +- `value: string` // the current text +- `onChange: (value: string) => void` // should be called on every keystroke to update `value` +- `onKeyDown: (e: React.KeyboardEvent) => void` // should be called on every keystroke to detect "Accept"/"Cancel" keys + +You can see an example in the [demo](https://carlosnz.github.io/json-edit-react/) where I have implemented [**CodeMirror**](https://codemirror.net/) when the "Custom Text Editor" option is checked. It changes the native editor (on the left) into the one shown on the right: + +Plain text editor +Plain text editor + +See the codebase for the exact implementation details: + +- [Simple component that wraps CodeMirror](https://github.com/CarlosNZ/json-edit-react/blob/157-custom-text-editor/demo/src/CodeEditor.tsx) +- [Prop passed to json-edit-react](https://github.com/CarlosNZ/json-edit-react/blob/6e3d21d20750b4a6519eea1f472be9a2a41b8a7c/demo/src/App.tsx#L441-L454) + ## Search/Filtering The displayed data can be filtered based on search input from a user. The user input should be captured independently (we don't provide a UI here) and passed in with the `searchText` prop. This input is debounced internally (time can be set with the `searchDebounceTime` prop), so no need for that as well. The values that the `searchText` are tested against is specified with the `searchFilter` prop. By default (no `searchFilter` defined), it will match against the data *values* (with case-insensitive partial matching -- i.e. input "Ilb", will match value "Bilbo"). From 0e136851c65523618efc16fcbe3257fae307e888 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Wed, 29 Jan 2025 19:22:40 +1300 Subject: [PATCH 20/23] Restore nested div to fix button positioning --- src/CollectionNode.tsx | 53 ++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index ebbc8fb4..2a31e277 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -299,31 +299,34 @@ export const CollectionNode: React.FC = (props) => { }) ) : (
- {TextEditor ? ( - - handleKeyboard(e, { - objectConfirm: handleEdit, - cancel: handleCancel, - }) - } - /> - ) : ( - - )} -
- + {/* This single child div is necessary to preserve justification/positioning of buttons */} +
+ {TextEditor ? ( + + handleKeyboard(e, { + objectConfirm: handleEdit, + cancel: handleCancel, + }) + } + /> + ) : ( + + )} +
+ +
) From e70a4e26829a048da891119c34d07e4d54d4b267 Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Wed, 29 Jan 2025 21:32:55 +1300 Subject: [PATCH 21/23] Add themes to Code Editor --- demo/package.json | 4 ++++ demo/src/App.tsx | 2 +- demo/src/CodeEditor.tsx | 23 ++++++++++++++++++++++- demo/yarn.lock | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/demo/package.json b/demo/package.json index 5a522af4..ece7e65b 100644 --- a/demo/package.json +++ b/demo/package.json @@ -16,6 +16,10 @@ "@types/node": "^20.11.6", "@types/react": "^18.2.48", "@types/react-dom": "^18.2.18", + "@uiw/codemirror-theme-console": "^4.23.7", + "@uiw/codemirror-theme-github": "^4.23.7", + "@uiw/codemirror-theme-monokai": "^4.23.7", + "@uiw/codemirror-theme-quietlight": "^4.23.7", "@uiw/react-codemirror": "^4.23.7", "ajv": "^8.16.0", "firebase": "^10.13.0", diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 16f08423..55af2290 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -448,7 +448,7 @@ function App() {
} > - + ) : undefined diff --git a/demo/src/CodeEditor.tsx b/demo/src/CodeEditor.tsx index 5438b59e..98f83272 100644 --- a/demo/src/CodeEditor.tsx +++ b/demo/src/CodeEditor.tsx @@ -2,10 +2,31 @@ import React from 'react' import CodeMirror from '@uiw/react-codemirror' import { json } from '@codemirror/lang-json' import { TextEditorProps } from './_imports' +import { githubLight, githubDark } from '@uiw/codemirror-theme-github' +import { consoleDark } from '@uiw/codemirror-theme-console/dark' +import { consoleLight } from '@uiw/codemirror-theme-console/light' +import { quietlight } from '@uiw/codemirror-theme-quietlight' +import { monokai } from '@uiw/codemirror-theme-monokai' -const CodeEditor: React.FC = ({ value, onChange, onKeyDown }) => { +const themeMap = { + Default: undefined, + 'Github Light': githubLight, + 'Github Dark': githubDark, + 'White & Black': consoleLight, + 'Black & White': consoleDark, + 'Candy Wrapper': quietlight, + Psychedelic: monokai, +} + +const CodeEditor: React.FC = ({ + value, + onChange, + onKeyDown, + theme, +}) => { return ( Date: Wed, 29 Jan 2025 21:52:52 +1300 Subject: [PATCH 22/23] Fix layout --- demo/src/style.css | 3 ++- src/CollectionNode.tsx | 53 ++++++++++++++++++++---------------------- src/style.css | 1 + 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/demo/src/style.css b/demo/src/style.css index f716119b..68953435 100644 --- a/demo/src/style.css +++ b/demo/src/style.css @@ -45,7 +45,8 @@ footer { color: dimgray; } -.cm-theme-light { +.cm-theme-light, +.cm-theme { width: 100%; } diff --git a/src/CollectionNode.tsx b/src/CollectionNode.tsx index 2a31e277..ebbc8fb4 100644 --- a/src/CollectionNode.tsx +++ b/src/CollectionNode.tsx @@ -299,34 +299,31 @@ export const CollectionNode: React.FC = (props) => { }) ) : (
- {/* This single child div is necessary to preserve justification/positioning of buttons */} -
- {TextEditor ? ( - - handleKeyboard(e, { - objectConfirm: handleEdit, - cancel: handleCancel, - }) - } - /> - ) : ( - - )} -
- -
+ {TextEditor ? ( + + handleKeyboard(e, { + objectConfirm: handleEdit, + cancel: handleCancel, + }) + } + /> + ) : ( + + )} +
+
) diff --git a/src/style.css b/src/style.css index d97c4c12..d14a54ac 100644 --- a/src/style.css +++ b/src/style.css @@ -182,6 +182,7 @@ select:focus + .focus { .jer-collection-input-button-row { display: flex; justify-content: flex-end; + width: 100%; font-size: 150%; margin-top: 0.4em; } From db71e5eae23ab39771f1debbb788d7b5623e2c3d Mon Sep 17 00:00:00 2001 From: Carl Smith <5456533+CarlosNZ@users.noreply.github.com> Date: Wed, 29 Jan 2025 21:53:45 +1300 Subject: [PATCH 23/23] Update style.css --- demo/src/style.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/demo/src/style.css b/demo/src/style.css index 68953435..479345f8 100644 --- a/demo/src/style.css +++ b/demo/src/style.css @@ -45,6 +45,7 @@ footer { color: dimgray; } +/* For CodeMirror */ .cm-theme-light, .cm-theme { width: 100%; @@ -55,6 +56,7 @@ footer { font-size: 80%; } +/* Loading component for CodeMirror */ .loading { width: 100%; display: flex;