From 5bbb410ce90a827c91d634b8323371bf5750f067 Mon Sep 17 00:00:00 2001 From: samsiegart Date: Wed, 6 Mar 2024 01:23:37 -0800 Subject: [PATCH 1/2] chore: fix eslint yarn error --- packages/react-components/package.json | 2 +- packages/rpc/package.json | 6 +- yarn.lock | 94 -------------------------- 3 files changed, 4 insertions(+), 98 deletions(-) diff --git a/packages/react-components/package.json b/packages/react-components/package.json index f934947..fc400f8 100644 --- a/packages/react-components/package.json +++ b/packages/react-components/package.json @@ -45,7 +45,7 @@ "@types/node": "20.4.9", "@types/react": "18.2.20", "@types/react-dom": "18.2.7", - "@typescript-eslint/eslint-plugin": "5.60.0", + "@typescript-eslint/eslint-plugin": "^7.1.0", "@vitejs/plugin-react": "4.0.4", "@vitest/coverage-v8": "0.34.1", "autoprefixer": "10.4.14", diff --git a/packages/rpc/package.json b/packages/rpc/package.json index ea5884f..d11f976 100644 --- a/packages/rpc/package.json +++ b/packages/rpc/package.json @@ -24,8 +24,8 @@ }, "devDependencies": { "@endo/init": "^0.5.60", - "@typescript-eslint/eslint-plugin": "^5.35.1", - "@typescript-eslint/parser": "^5.35.1", + "@typescript-eslint/eslint-plugin": "^7.1.0", + "@typescript-eslint/parser": "^7.1.0", "@vitest/coverage-c8": "^0.25.3", "axios-mock-adapter": "^1.22.0", "eslint": "^8.22.0", @@ -42,7 +42,7 @@ "plugin:require-extensions/recommended" ], "plugins": [ - "require-extensions" + "require-extensions" ] } } diff --git a/yarn.lock b/yarn.lock index 7deced4..a9e8d02 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6666,22 +6666,6 @@ resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.2.tgz#38ecb64f01aa0d02b7c8f4222d7c38af6316fef8" integrity sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g== -"@typescript-eslint/eslint-plugin@5.60.0", "@typescript-eslint/eslint-plugin@^5.35.1": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.60.0.tgz#2f4bea6a3718bed2ba52905358d0f45cd3620d31" - integrity sha512-78B+anHLF1TI8Jn/cD0Q00TBYdMgjdOn980JfAVa9yw5sop8nyTfVOQAv6LWywkOGLclDBtv5z3oxN4w7jxyNg== - dependencies: - "@eslint-community/regexpp" "^4.4.0" - "@typescript-eslint/scope-manager" "5.60.0" - "@typescript-eslint/type-utils" "5.60.0" - "@typescript-eslint/utils" "5.60.0" - debug "^4.3.4" - grapheme-splitter "^1.0.4" - ignore "^5.2.0" - natural-compare-lite "^1.4.0" - semver "^7.3.7" - tsutils "^3.21.0" - "@typescript-eslint/eslint-plugin@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz#22bb999a8d59893c0ea07923e8a21f9d985ad740" @@ -6699,16 +6683,6 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/parser@^5.35.1": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.60.0.tgz#08f4daf5fc6548784513524f4f2f359cebb4068a" - integrity sha512-jBONcBsDJ9UoTWrARkRRCgDz6wUggmH5RpQVlt7BimSwaTkTjwypGzKORXbR4/2Hqjk9hgwlon2rVQAjWNpkyQ== - dependencies: - "@typescript-eslint/scope-manager" "5.60.0" - "@typescript-eslint/types" "5.60.0" - "@typescript-eslint/typescript-estree" "5.60.0" - debug "^4.3.4" - "@typescript-eslint/parser@^5.52.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7" @@ -6738,14 +6712,6 @@ "@typescript-eslint/types" "5.53.0" "@typescript-eslint/visitor-keys" "5.53.0" -"@typescript-eslint/scope-manager@5.60.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.60.0.tgz#ae511967b4bd84f1d5e179bb2c82857334941c1c" - integrity sha512-hakuzcxPwXi2ihf9WQu1BbRj1e/Pd8ZZwVTG9kfbxAMZstKz8/9OoexIwnmLzShtsdap5U/CoQGRCWlSuPbYxQ== - dependencies: - "@typescript-eslint/types" "5.60.0" - "@typescript-eslint/visitor-keys" "5.60.0" - "@typescript-eslint/scope-manager@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" @@ -6762,16 +6728,6 @@ "@typescript-eslint/types" "7.1.0" "@typescript-eslint/visitor-keys" "7.1.0" -"@typescript-eslint/type-utils@5.60.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.60.0.tgz#69b09087eb12d7513d5b07747e7d47f5533aa228" - integrity sha512-X7NsRQddORMYRFH7FWo6sA9Y/zbJ8s1x1RIAtnlj6YprbToTiQnM6vxcMu7iYhdunmoC0rUWlca13D5DVHkK2g== - dependencies: - "@typescript-eslint/typescript-estree" "5.60.0" - "@typescript-eslint/utils" "5.60.0" - debug "^4.3.4" - tsutils "^3.21.0" - "@typescript-eslint/type-utils@7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz#372dfa470df181bcee0072db464dc778b75ed722" @@ -6787,11 +6743,6 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.53.0.tgz#f79eca62b97e518ee124086a21a24f3be267026f" integrity sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A== -"@typescript-eslint/types@5.60.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.60.0.tgz#3179962b28b4790de70e2344465ec97582ce2558" - integrity sha512-ascOuoCpNZBccFVNJRSC6rPq4EmJ2NkuoKnd6LDNyAQmdDnziAtxbCGWCbefG1CNzmDvd05zO36AmB7H8RzKPA== - "@typescript-eslint/types@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" @@ -6815,19 +6766,6 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/typescript-estree@5.60.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.60.0.tgz#4ddf1a81d32a850de66642d9b3ad1e3254fb1600" - integrity sha512-R43thAuwarC99SnvrBmh26tc7F6sPa2B3evkXp/8q954kYL6Ro56AwASYWtEEi+4j09GbiNAHqYwNNZuNlARGQ== - dependencies: - "@typescript-eslint/types" "5.60.0" - "@typescript-eslint/visitor-keys" "5.60.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - "@typescript-eslint/typescript-estree@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" @@ -6855,20 +6793,6 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@5.60.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.60.0.tgz#4667c5aece82f9d4f24a667602f0f300864b554c" - integrity sha512-ba51uMqDtfLQ5+xHtwlO84vkdjrqNzOnqrnwbMHMRY8Tqeme8C2Q8Fc7LajfGR+e3/4LoYiWXUM6BpIIbHJ4hQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@types/json-schema" "^7.0.9" - "@types/semver" "^7.3.12" - "@typescript-eslint/scope-manager" "5.60.0" - "@typescript-eslint/types" "5.60.0" - "@typescript-eslint/typescript-estree" "5.60.0" - eslint-scope "^5.1.1" - semver "^7.3.7" - "@typescript-eslint/utils@7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.1.0.tgz#710ecda62aff4a3c8140edabf3c5292d31111ddd" @@ -6918,14 +6842,6 @@ "@typescript-eslint/types" "5.53.0" eslint-visitor-keys "^3.3.0" -"@typescript-eslint/visitor-keys@5.60.0": - version "5.60.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.60.0.tgz#b48b29da3f5f31dd1656281727004589d2722a66" - integrity sha512-wm9Uz71SbCyhUKgcaPRauBdTegUyY/ZWl8gLwD/i/ybJqscrrdVSFImpvUz16BLPChIeKBK5Fa9s6KDQjsjyWw== - dependencies: - "@typescript-eslint/types" "5.60.0" - eslint-visitor-keys "^3.3.0" - "@typescript-eslint/visitor-keys@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" @@ -11582,11 +11498,6 @@ graceful-fs@4.2.11, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2 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== -grapheme-splitter@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" - integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== - graphemer@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" @@ -13945,11 +13856,6 @@ napi-wasm@^1.1.0: resolved "https://registry.yarnpkg.com/napi-wasm/-/napi-wasm-1.1.0.tgz#bbe617823765ae9c1bc12ff5942370eae7b2ba4e" integrity sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg== -natural-compare-lite@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" - integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== - natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" From 5f66d9cfd5a7b3b9334896566988c1ea76f6e0ca Mon Sep 17 00:00:00 2001 From: samsiegart Date: Wed, 6 Mar 2024 02:20:14 -0800 Subject: [PATCH 2/2] feat: amount input hook and component --- packages/react-components/package.json | 4 +- .../src/lib/components/AmountInput.tsx | 41 ++++++++++++++++ .../src/lib/components/index.ts | 1 + .../react-components/src/lib/hooks/agoric.ts | 4 ++ .../src/lib/hooks/amountInput.ts | 49 +++++++++++++++++++ .../react-components/src/lib/hooks/index.ts | 6 +-- yarn.lock | 16 +++--- 7 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 packages/react-components/src/lib/components/AmountInput.tsx create mode 100644 packages/react-components/src/lib/hooks/agoric.ts create mode 100644 packages/react-components/src/lib/hooks/amountInput.ts diff --git a/packages/react-components/package.json b/packages/react-components/package.json index fc400f8..2c30ee6 100644 --- a/packages/react-components/package.json +++ b/packages/react-components/package.json @@ -43,8 +43,8 @@ "@headlessui/react": "^1.7.18", "@testing-library/react": "14.0.0", "@types/node": "20.4.9", - "@types/react": "18.2.20", - "@types/react-dom": "18.2.7", + "@types/react": "18.2.63", + "@types/react-dom": "18.2.20", "@typescript-eslint/eslint-plugin": "^7.1.0", "@vitejs/plugin-react": "4.0.4", "@vitest/coverage-v8": "0.34.1", diff --git a/packages/react-components/src/lib/components/AmountInput.tsx b/packages/react-components/src/lib/components/AmountInput.tsx new file mode 100644 index 0000000..93530e3 --- /dev/null +++ b/packages/react-components/src/lib/components/AmountInput.tsx @@ -0,0 +1,41 @@ +import React, { type Ref, forwardRef } from 'react'; +import type { NatValue } from '@agoric/ertp/src/types'; +import { useAmountInput } from '../hooks/amountInput.js'; + +const noop = () => { + /* no-op */ +}; + +type Props = { + value: NatValue | null; + decimalPlaces: number; + className?: React.HtmlHTMLAttributes['className']; + onChange?: (value: NatValue) => void; + disabled?: boolean; +}; + +const RenderAmountInput = ( + { value, decimalPlaces, className, onChange = noop, disabled = false }: Props, + ref?: Ref, +) => { + const { displayString, handleInputChange } = useAmountInput({ + value, + decimalPlaces, + onChange, + }); + + return ( + + ); +}; + +export const AmountInput = forwardRef(RenderAmountInput); diff --git a/packages/react-components/src/lib/components/index.ts b/packages/react-components/src/lib/components/index.ts index 6d70ab3..5c77cfd 100644 --- a/packages/react-components/src/lib/components/index.ts +++ b/packages/react-components/src/lib/components/index.ts @@ -1,2 +1,3 @@ export * from './ConnectWalletButton'; export * from './NodeSelectorModal'; +export * from './AmountInput'; diff --git a/packages/react-components/src/lib/hooks/agoric.ts b/packages/react-components/src/lib/hooks/agoric.ts new file mode 100644 index 0000000..a39159f --- /dev/null +++ b/packages/react-components/src/lib/hooks/agoric.ts @@ -0,0 +1,4 @@ +import { useContext } from 'react'; +import { AgoricContext } from '../context'; + +export const useAgoric = () => useContext(AgoricContext); diff --git a/packages/react-components/src/lib/hooks/amountInput.ts b/packages/react-components/src/lib/hooks/amountInput.ts new file mode 100644 index 0000000..0e444b0 --- /dev/null +++ b/packages/react-components/src/lib/hooks/amountInput.ts @@ -0,0 +1,49 @@ +import type { NatValue } from '@agoric/ertp/src/types'; +import { AssetKind } from '@agoric/ertp'; +import { parseAsValue, stringifyValue } from '@agoric/web-components'; +import { useState } from 'react'; + +type Args = { + value: NatValue | null; + decimalPlaces: number; + onChange: (value: NatValue) => void; +}; + +export const useAmountInput = ({ value, decimalPlaces, onChange }: Args) => { + const amountString = stringifyValue(value, AssetKind.NAT, decimalPlaces); + + const [fieldString, setFieldString] = useState( + value === null ? '' : amountString, + ); + + const handleInputChange: React.ChangeEventHandler = ev => { + // Inputs with type "number" allow these characters which don't apply to + // Amounts, just strip them. + const str = ev.target?.value + ?.replace('-', '') + .replace('e', '') + .replace('E', ''); + setFieldString(str); + + try { + const parsed = parseAsValue(str, AssetKind.NAT, decimalPlaces); + onChange(parsed); + } catch { + console.debug('Invalid input', str); + } + }; + + // Use the `fieldString` as an input buffer so the user can type values that + // would be overwritten by `stringifyValue`. For example, if the current + // input is "1.05", and you tried to change it to "1.25", on hitting + // backspace, `stringifyValue` would change it from "1.0" to "1.00", + // preventing you from ever editing it. Only let `amountString` override + // `fieldString` if the controlled input is trying to change it to a truly + // different value. + const displayString = + value === parseAsValue(fieldString, AssetKind.NAT, decimalPlaces) + ? fieldString + : amountString; + + return { displayString, handleInputChange }; +}; diff --git a/packages/react-components/src/lib/hooks/index.ts b/packages/react-components/src/lib/hooks/index.ts index a39159f..d050a89 100644 --- a/packages/react-components/src/lib/hooks/index.ts +++ b/packages/react-components/src/lib/hooks/index.ts @@ -1,4 +1,2 @@ -import { useContext } from 'react'; -import { AgoricContext } from '../context'; - -export const useAgoric = () => useContext(AgoricContext); +export * from './agoric.js'; +export * from './amountInput.js'; diff --git a/yarn.lock b/yarn.lock index a9e8d02..ddb4390 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6586,10 +6586,10 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== -"@types/react-dom@18.2.7": - version "18.2.7" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.7.tgz#67222a08c0a6ae0a0da33c3532348277c70abb63" - integrity sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA== +"@types/react-dom@18.2.20": + version "18.2.20" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.20.tgz#cbdf7abb3cc2377980bb1294bc51375016a8320f" + integrity sha512-HXN/biJY8nv20Cn9ZbCFq3liERd4CozVZmKbaiZ9KiKTrWqsP7eoGDO6OOGvJQwoVFuiXaiJ7nBBjiFFbRmQMQ== dependencies: "@types/react" "*" @@ -6609,10 +6609,10 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@18.2.20": - version "18.2.20" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.20.tgz#1605557a83df5c8a2cc4eeb743b3dfc0eb6aaeb2" - integrity sha512-WKNtmsLWJM/3D5mG4U84cysVY31ivmyw85dE84fOCk5Hx78wezB/XEjVPWl2JTZ5FkEeaTJf+VgUAUn3PE7Isw== +"@types/react@18.2.63": + version "18.2.63" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.63.tgz#4637c56146ad90f96d0583171edab953f7e6fe57" + integrity sha512-ppaqODhs15PYL2nGUOaOu2RSCCB4Difu4UFrP4I3NHLloXC/ESQzQMi9nvjfT1+rudd0d2L3fQPJxRSey+rGlQ== dependencies: "@types/prop-types" "*" "@types/scheduler" "*"