Merge pull request #209 from XRPLF/feat/json-in-ui

Display tx json in UI inside textarea.
This commit is contained in:
muzamil
2022-06-10 16:50:28 +05:30
committed by GitHub
2 changed files with 157 additions and 22 deletions

115
components/Textarea.tsx Normal file
View File

@@ -0,0 +1,115 @@
import { styled } from "../stitches.config";
export const Textarea = styled("textarea", {
// Reset
appearance: "none",
borderWidth: "0",
boxSizing: "border-box",
fontFamily: "inherit",
outline: "none",
width: "100%",
flex: "1",
backgroundColor: "$mauve4",
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
borderRadius: "$sm",
p: "$2",
fontSize: "$md",
lineHeight: 1,
color: "$mauve12",
boxShadow: `0 0 0 1px $colors$mauve8`,
WebkitTapHighlightColor: "rgba(0,0,0,0)",
"&::before": {
boxSizing: "border-box",
},
"&::after": {
boxSizing: "border-box",
},
fontVariantNumeric: "tabular-nums",
"&:-webkit-autofill": {
boxShadow: "inset 0 0 0 1px $colors$blue6, inset 0 0 0 100px $colors$blue3",
},
"&:-webkit-autofill::first-line": {
fontFamily: "$untitled",
color: "$mauve12",
},
"&:focus": {
boxShadow: `0 0 0 1px $colors$mauve10`,
"&:-webkit-autofill": {
boxShadow: `0 0 0 1px $colors$mauve10`,
},
},
"&::placeholder": {
color: "$mauve9",
},
"&:disabled": {
pointerEvents: "none",
backgroundColor: "$mauve2",
color: "$mauve8",
cursor: "not-allowed",
"&::placeholder": {
color: "$mauve7",
},
},
variants: {
variant: {
ghost: {
boxShadow: "none",
backgroundColor: "transparent",
"@hover": {
"&:hover": {
boxShadow: "inset 0 0 0 1px $colors$mauve7",
},
},
"&:focus": {
backgroundColor: "$loContrast",
boxShadow: `0 0 0 1px $colors$mauve10`,
},
"&:disabled": {
backgroundColor: "transparent",
},
"&:read-only": {
backgroundColor: "transparent",
},
},
deep: {
backgroundColor: "$deep",
boxShadow: "none",
},
},
state: {
invalid: {
boxShadow: "inset 0 0 0 1px $colors$crimson7",
"&:focus": {
boxShadow:
"inset 0px 0px 0px 1px $colors$crimson8, 0px 0px 0px 1px $colors$crimson8",
},
},
valid: {
boxShadow: "inset 0 0 0 1px $colors$grass7",
"&:focus": {
boxShadow:
"inset 0px 0px 0px 1px $colors$grass8, 0px 0px 0px 1px $colors$grass8",
},
},
},
cursor: {
default: {
cursor: "default",
"&:focus": {
cursor: "text",
},
},
text: {
cursor: "text",
},
},
},
});
export default Textarea;

View File

@@ -15,6 +15,7 @@ import { useSnapshot } from "valtio";
import state from "../../state"; import state from "../../state";
import { streamState } from "../DebugStream"; import { streamState } from "../DebugStream";
import { Button } from ".."; import { Button } from "..";
import Textarea from "../Textarea";
interface UIProps { interface UIProps {
setState: ( setState: (
@@ -37,22 +38,22 @@ export const TxUI: FC<UIProps> = ({
txFields, txFields,
} = txState; } = txState;
const transactionsOptions = transactionsData.map((tx) => ({ const transactionsOptions = transactionsData.map(tx => ({
value: tx.TransactionType, value: tx.TransactionType,
label: tx.TransactionType, label: tx.TransactionType,
})); }));
const accountOptions: SelectOption[] = accounts.map((acc) => ({ const accountOptions: SelectOption[] = accounts.map(acc => ({
label: acc.name, label: acc.name,
value: acc.address, value: acc.address,
})); }));
const destAccountOptions: SelectOption[] = accounts const destAccountOptions: SelectOption[] = accounts
.map((acc) => ({ .map(acc => ({
label: acc.name, label: acc.name,
value: acc.address, value: acc.address,
})) }))
.filter((acc) => acc.value !== selectedAccount?.value); .filter(acc => acc.value !== selectedAccount?.value);
const [feeLoading, setFeeLoading] = useState(false); const [feeLoading, setFeeLoading] = useState(false);
@@ -107,9 +108,12 @@ export const TxUI: FC<UIProps> = ({
const specialFields = ["TransactionType", "Account", "Destination"]; const specialFields = ["TransactionType", "Account", "Destination"];
const otherFields = Object.keys(txFields).filter( const otherFields = Object.keys(txFields).filter(
(k) => !specialFields.includes(k) k => !specialFields.includes(k)
) as [keyof TxFields]; ) as [keyof TxFields];
const switchToJson = () =>
setState({ editorSavedValue: null, viewType: "json" });
useEffect(() => { useEffect(() => {
const defaultOption = transactionsOptions.find( const defaultOption = transactionsOptions.find(
tt => tt.value === "Payment" tt => tt.value === "Payment"
@@ -117,7 +121,7 @@ export const TxUI: FC<UIProps> = ({
if (defaultOption) { if (defaultOption) {
handleChangeTxType(defaultOption); handleChangeTxType(defaultOption);
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
return ( return (
@@ -200,13 +204,13 @@ export const TxUI: FC<UIProps> = ({
/> />
</Flex> </Flex>
)} )}
{otherFields.map((field) => { {otherFields.map(field => {
let _value = txFields[field]; let _value = txFields[field];
let value: string | undefined; let value: string | undefined;
if (typeof _value === "object") { if (typeof _value === "object") {
if (_value.$type === "json" && typeof _value.$value === "object") { if (_value.$type === "json" && typeof _value.$value === "object") {
value = JSON.stringify(_value.$value); value = JSON.stringify(_value.$value, null, 2);
} else { } else {
value = _value.$value.toString(); value = _value.$value.toString();
} }
@@ -214,9 +218,13 @@ export const TxUI: FC<UIProps> = ({
value = _value?.toString(); value = _value?.toString();
} }
let isXrp = typeof _value === "object" && _value.$type === "xrp"; const isXrp = typeof _value === "object" && _value.$type === "xrp";
const isJson = typeof _value === "object" && _value.$type === "json";
const isFee = field === "Fee"; const isFee = field === "Fee";
let rows = isJson
? (value?.match(/\n/gm)?.length || 0) + 1
: undefined;
if (rows && rows > 5) rows = 5;
return ( return (
<Flex column key={field} css={{ mb: "$2", pr: "1px" }}> <Flex column key={field} css={{ mb: "$2", pr: "1px" }}>
<Flex <Flex
@@ -231,18 +239,30 @@ export const TxUI: FC<UIProps> = ({
<Text muted css={{ mr: "$3" }}> <Text muted css={{ mr: "$3" }}>
{field + (isXrp ? " (XRP)" : "")}:{" "} {field + (isXrp ? " (XRP)" : "")}:{" "}
</Text> </Text>
<Input {isJson ? (
value={value} <Textarea
onChange={(e) => { rows={rows}
let value = e.target.value; value={value}
if (value && (value.includes(".") || value.includes(","))) { spellCheck={false}
value = value.replaceAll(".", "").replaceAll(",", ""); onChange={switchToJson}
} css={{
width: "70%",
handleSetField(field, value); flex: "inherit",
}} resize: "vertical",
css={{ width: "70%", flex: "inherit" }} }}
/> />
) : (
<Input
value={value}
onChange={e => {
handleSetField(field, e.target.value);
}}
css={{
width: "70%",
flex: "inherit",
}}
/>
)}
{isFee && ( {isFee && (
<Button <Button
size="xs" size="xs"