Skip to content

Commit

Permalink
feat: amount input hook and component
Browse files Browse the repository at this point in the history
  • Loading branch information
samsiegart committed Mar 6, 2024
1 parent 41e2585 commit 09ca26c
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 14 deletions.
4 changes: 2 additions & 2 deletions packages/react-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
41 changes: 41 additions & 0 deletions packages/react-components/src/lib/components/AmountInput.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLInputElement>['className'];
onChange?: (value: NatValue) => void;
disabled?: boolean;
};

const RenderAmountInput = (
{ value, decimalPlaces, className, onChange = noop, disabled = false }: Props,
ref?: Ref<HTMLInputElement>,
) => {
const { displayString, handleInputChange } = useAmountInput({
value,
decimalPlaces,
onChange,
});

return (
<input
className={className}
type="number"
placeholder="0"
min="0"
disabled={disabled}
value={displayString}
onChange={handleInputChange}
ref={ref}
/>
);
};

export const AmountInput = forwardRef(RenderAmountInput);
1 change: 1 addition & 0 deletions packages/react-components/src/lib/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './ConnectWalletButton';
export * from './NodeSelectorModal';
export * from './AmountInput';
4 changes: 4 additions & 0 deletions packages/react-components/src/lib/hooks/agoric.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { useContext } from 'react';
import { AgoricContext } from '../context';

export const useAgoric = () => useContext(AgoricContext);
49 changes: 49 additions & 0 deletions packages/react-components/src/lib/hooks/amountInput.ts
Original file line number Diff line number Diff line change
@@ -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<HTMLInputElement> = 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 };
};
6 changes: 2 additions & 4 deletions packages/react-components/src/lib/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -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';
16 changes: 8 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6586,10 +6586,10 @@
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==

"@types/[email protected].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/[email protected].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" "*"

Expand All @@ -6609,10 +6609,10 @@
"@types/scheduler" "*"
csstype "^3.0.2"

"@types/[email protected].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/[email protected].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" "*"
Expand Down

0 comments on commit 09ca26c

Please sign in to comment.