From b1d6fdff3c1eeb086cca6a45689541df15137851 Mon Sep 17 00:00:00 2001 From: Iveta Date: Wed, 6 Mar 2024 15:22:57 -0500 Subject: [PATCH 1/2] Explore Endpoints: Params tab view --- .../explore-endpoints/[[...pages]]/page.tsx | 182 +++++++++++++----- src/components/TabView/index.tsx | 117 +++++++++++ src/components/TabView/styles.scss | 30 +++ src/components/Tabs/index.tsx | 31 +++ src/components/Tabs/styles.scss | 37 ++++ src/components/WithInfoText/index.tsx | 57 ++++++ src/components/WithInfoText/styles.scss | 34 ++++ src/styles/globals.scss | 50 +++++ 8 files changed, 494 insertions(+), 44 deletions(-) create mode 100644 src/components/TabView/index.tsx create mode 100644 src/components/TabView/styles.scss create mode 100644 src/components/Tabs/index.tsx create mode 100644 src/components/Tabs/styles.scss create mode 100644 src/components/WithInfoText/index.tsx create mode 100644 src/components/WithInfoText/styles.scss diff --git a/src/app/(sidebar)/explore-endpoints/[[...pages]]/page.tsx b/src/app/(sidebar)/explore-endpoints/[[...pages]]/page.tsx index f9fed4b7..33b49d27 100644 --- a/src/app/(sidebar)/explore-endpoints/[[...pages]]/page.tsx +++ b/src/app/(sidebar)/explore-endpoints/[[...pages]]/page.tsx @@ -1,61 +1,155 @@ "use client"; +import { useState } from "react"; import { usePathname } from "next/navigation"; -import { Card, Icon, Text } from "@stellar/design-system"; +import { + Alert, + Button, + Card, + Checkbox, + CopyText, + Icon, + Input, + Text, +} from "@stellar/design-system"; import { InfoCards } from "@/components/InfoCards"; +import { TabView } from "@/components/TabView"; +import { SdsLink } from "@/components/SdsLink"; import { Routes } from "@/constants/routes"; - -const infoCards = [ - { - id: "soroban-rpc", - title: "RPC Endpoints", - description: "TODO: add text", - buttonLabel: "See docs", - buttonIcon: , - buttonAction: () => - window.open("https://soroban.stellar.org/api/methods", "_blank"), - }, - { - id: "horizon", - title: "Horizon Endpoints", - description: "TODO: add text", - buttonLabel: "See docs", - buttonIcon: , - buttonAction: () => - window.open( - "https://developers.stellar.org/api/horizon/resources/", - "_blank", - ), - }, -]; +import { WithInfoText } from "@/components/WithInfoText"; export default function ExploreEndpoints() { const pathname = usePathname(); + const [activeTab, setActiveTab] = useState("endpoints-tab-params"); + if (pathname === Routes.EXPLORE_ENDPOINTS) { + return ; + } + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + // TODO: handle submit + }; + + const renderEndpointUrl = () => { return ( - <> - -
- - Endpoints - - - - TODO: add text - -
-
- - +
+ GET
} + /> + {/* TODO: disable if can't submit */} + + {/* TODO: add text to copy */} + + + + ); - } + }; - return renderPage(pathname); + const renderFields = () => { + return ( +
+
+ {/* TODO: render fields for path */} + {`Explore Endpoints: ${pathname}`} +
+ + + + +
+ ); + }; + + return ( + <> +
+ TODO: render JSON, + }} + onTabChange={(id) => { + setActiveTab(id); + }} + activeTabId={activeTab} + /> + + + This tool can be used to run queries against the{" "} + + REST API endpoints + {" "} + on the Horizon server. Horizon is the client facing library for the + Stellar ecosystem. + + + ); } -const renderPage = (pathname: string) => { - // TODO: add switch to render path component - return
{`Explore Endpoints: ${pathname}`}
; +const ExploreEndpointsLandingPage = () => { + const infoCards = [ + { + id: "soroban-rpc", + title: "RPC Endpoints", + description: "TODO: add text", + buttonLabel: "See docs", + buttonIcon: , + buttonAction: () => + window.open("https://soroban.stellar.org/api/methods", "_blank"), + }, + { + id: "horizon", + title: "Horizon Endpoints", + description: "TODO: add text", + buttonLabel: "See docs", + buttonIcon: , + buttonAction: () => + window.open( + "https://developers.stellar.org/api/horizon/resources/", + "_blank", + ), + }, + ]; + + return ( + <> + +
+ + Endpoints + + + + TODO: add text + +
+
+ + + ); }; diff --git a/src/components/TabView/index.tsx b/src/components/TabView/index.tsx new file mode 100644 index 00000000..5bf39448 --- /dev/null +++ b/src/components/TabView/index.tsx @@ -0,0 +1,117 @@ +import { Card, Text } from "@stellar/design-system"; +import { WithInfoText } from "@/components/WithInfoText"; +import { Tabs } from "@/components/Tabs"; +import "./styles.scss"; + +type Tab = { + id: string; + label: string; + content: React.ReactNode; +}; + +type TabViewProps = { + heading: TabViewHeadingProps; + tab1: Tab; + tab2: Tab; + tab3?: Tab; + tab4?: Tab; + tab5?: Tab; + tab6?: Tab; + onTabChange: (id: string) => void; + activeTabId: string; + staticTop?: React.ReactNode; +}; + +export const TabView = ({ + heading, + onTabChange, + activeTabId, + staticTop, + ...tabs +}: TabViewProps) => { + const tabItems = Object.values(tabs).map((t) => ({ + id: t.id, + label: t.label, + })); + + const tabContent = Object.values(tabs).map((t) => ({ + id: t.id, + content: t.content, + })); + + return ( +
+
+ + +
+ +
+
+ + +
+ {staticTop ?? null} + +
+ {tabContent.map((tc) => ( +
+ {tc.content} +
+ ))} +
+
+
+
+ ); +}; + +type TabViewHeadingProps = ( + | { + infoText: React.ReactNode | string; + href?: undefined; + } + | { + infoText?: undefined; + href: string; + } + | { infoText?: undefined; href?: undefined } +) & { + title: string; + infoHoverText?: string; +}; + +const TabViewHeading = ({ + title, + infoHoverText, + infoText, + href, +}: TabViewHeadingProps) => { + const renderTitle = () => ( + + {title} + + ); + + if (href || infoText) { + if (href) { + return ( + + {renderTitle()} + + ); + } + + return ( + + {renderTitle()} + + ); + } + + return renderTitle(); +}; diff --git a/src/components/TabView/styles.scss b/src/components/TabView/styles.scss new file mode 100644 index 00000000..10316d91 --- /dev/null +++ b/src/components/TabView/styles.scss @@ -0,0 +1,30 @@ +@use "../../styles/utils.scss" as *; + +.TabView { + display: flex; + flex-direction: column; + gap: pxToRem(12px); + + &__heading { + display: flex; + justify-content: space-between; + align-items: center; + gap: pxToRem(24px); + } + + &__body { + display: flex; + flex-direction: column; + gap: pxToRem(12px); + } + + &__content { + & > [data-is-active="false"] { + display: none; + } + + & > [data-is-active="true"] { + display: block; + } + } +} diff --git a/src/components/Tabs/index.tsx b/src/components/Tabs/index.tsx new file mode 100644 index 00000000..2c3f31e9 --- /dev/null +++ b/src/components/Tabs/index.tsx @@ -0,0 +1,31 @@ +import "./styles.scss"; + +type Tab = { + id: string; + label: string; +}; + +export const Tabs = ({ + tabs, + activeTabId, + onChange, +}: { + tabs: Tab[]; + activeTabId: string; + onChange: (id: string) => void; +}) => { + return ( +
+ {tabs.map((t) => ( +
onChange(t.id)} + > + {t.label} +
+ ))} +
+ ); +}; diff --git a/src/components/Tabs/styles.scss b/src/components/Tabs/styles.scss new file mode 100644 index 00000000..86cf646f --- /dev/null +++ b/src/components/Tabs/styles.scss @@ -0,0 +1,37 @@ +@use "../../styles/utils.scss" as *; + +.Tabs { + --Tabs-default-text: var(--sds-clr-gray-11); + --Tabs-default-background: transparent; + + display: flex; + align-items: center; + gap: pxToRem(8px); + + .Tab { + font-size: pxToRem(14px); + line-height: pxToRem(20px); + font-weight: var(--sds-fw-medium); + color: var(--Tabs-default-text); + background-color: var(--Tabs-default-background); + border-radius: pxToRem(6px); + padding: pxToRem(6px) pxToRem(10px); + cursor: pointer; + transition: + color var(--sds-anim-transition-default), + background-color var(--sds-anim-transition-default); + + @media (hover: hover) { + &:hover { + --Tabs-default-text: var(--sds-clr-lilac-11); + --Tabs-default-background: var(--sds-clr-lilac-04); + } + } + + &[data-is-active="true"] { + --Tabs-default-text: var(--sds-clr-lilac-11); + --Tabs-default-background: var(--sds-clr-lilac-04); + cursor: default; + } + } +} diff --git a/src/components/WithInfoText/index.tsx b/src/components/WithInfoText/index.tsx new file mode 100644 index 00000000..60f8ac0d --- /dev/null +++ b/src/components/WithInfoText/index.tsx @@ -0,0 +1,57 @@ +import { Icon, Tooltip } from "@stellar/design-system"; +import { NextLink } from "@/components/NextLink"; +import "./styles.scss"; + +type WithInfoTextProps = ( + | { + infoText: React.ReactNode | string; + href?: undefined; + } + | { + infoText?: undefined; + href: string; + } +) & { + children: React.ReactNode; + infoHoverText?: string; +}; + +export const WithInfoText = ({ + children, + infoText, + infoHoverText, + href, +}: WithInfoTextProps) => { + const buttonBaseProps = { + className: "WithInfoText__button", + title: infoHoverText || "Learn more", + }; + + if (href) { + return ( +
+ {children} + + + + +
+ ); + } + + return ( +
+ {children} + + + + + } + > + {infoText} + +
+ ); +}; diff --git a/src/components/WithInfoText/styles.scss b/src/components/WithInfoText/styles.scss new file mode 100644 index 00000000..46049279 --- /dev/null +++ b/src/components/WithInfoText/styles.scss @@ -0,0 +1,34 @@ +@use "../../styles/utils.scss" as *; + +.WithInfoText { + --WithInfoText-icon-color: var(--sds-clr-gray-08); + + display: inline-flex; + gap: pxToRem(2px); + align-items: center; + + &__button { + display: block; + + text-decoration: none; + cursor: pointer; + border: none; + background: none; + padding: pxToRem(2px); + margin: 0; + + svg { + display: block; + width: pxToRem(12px); + height: pxToRem(12px); + transition: stroke var(--sds-anim-transition-default); + stroke: var(--WithInfoText-icon-color); + } + + @media (hover: hover) { + &:hover { + --WithInfoText-icon-color: var(--sds-clr-gray-11); + } + } + } +} diff --git a/src/styles/globals.scss b/src/styles/globals.scss index fcb80fe4..6c159fcf 100644 --- a/src/styles/globals.scss +++ b/src/styles/globals.scss @@ -309,3 +309,53 @@ font-size: pxToRem(14px); line-height: pxToRem(20px); } + +// Endpoint Explorer +.Endpoints { + &__urlBar { + display: flex; + align-items: center; + justify-content: space-between; + gap: pxToRem(8px); + } + + &__input__requestType { + font-size: pxToRem(14px); + line-height: pxToRem(20px); + font-weight: var(--sds-fw-semi-bold); + color: var(--sds-clr-gray-12); + background-color: var(--sds-clr-gray-01); + height: 100%; + display: flex; + align-items: center; + flex-shrink: 0; + flex-grow: 0; + padding: pxToRem(6px) pxToRem(10px); + + border-right: 1px solid var(--Input-color-border); + margin-left: calc(var(--Input-padding-horizontal) * -1); + border-top-left-radius: var(--Input-border-radius); + border-bottom-left-radius: var(--Input-border-radius); + } + + &__content { + display: flex; + flex-direction: column; + gap: pxToRem(12px); + + &__inputs { + display: flex; + flex-direction: column; + gap: pxToRem(16px); + padding: pxToRem(16px); + background-color: var(--sds-clr-gray-03); + border-radius: pxToRem(8px); + } + } + + .Input--disabled { + input:read-only { + cursor: default; + } + } +} From 263feb0b597e27302e7ae15a2cac4777b5bc89af Mon Sep 17 00:00:00 2001 From: Iveta Date: Thu, 14 Mar 2024 09:45:24 -0400 Subject: [PATCH 2/2] Picker components (#777) * RadioPicker * OrderPicker * IncludeFailedPicker * AssetPicker + PubKeyPicker * Update hover color + expand transition speed * Cleanup * Tweaks and cleanup * Cleanup --- package.json | 3 +- src/components/ExpandBox/index.tsx | 34 ++ src/components/ExpandBox/styles.scss | 19 ++ src/components/FormElements/AssetPicker.tsx | 309 ++++++++++++++++++ .../FormElements/IncludeFailedPicker.tsx | 27 ++ src/components/FormElements/OrderPicker.tsx | 27 ++ src/components/FormElements/PubKeyPicker.tsx | 64 ++++ src/components/RadioPicker/index.tsx | 70 ++++ src/components/RadioPicker/styles.scss | 97 ++++++ src/types/types.ts | 38 +++ yarn.lock | 183 ++++++++++- 11 files changed, 864 insertions(+), 7 deletions(-) create mode 100644 src/components/ExpandBox/index.tsx create mode 100644 src/components/ExpandBox/styles.scss create mode 100644 src/components/FormElements/AssetPicker.tsx create mode 100644 src/components/FormElements/IncludeFailedPicker.tsx create mode 100644 src/components/FormElements/OrderPicker.tsx create mode 100644 src/components/FormElements/PubKeyPicker.tsx create mode 100644 src/components/RadioPicker/index.tsx create mode 100644 src/components/RadioPicker/styles.scss diff --git a/package.json b/package.json index 3fc73bfc..2ae0db22 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "git-info": "rm -rf src/generated/ && mkdir src/generated/ && echo export default \"{\\\"commitHash\\\": \\\"$(git rev-parse --short HEAD)\\\", \\\"version\\\": \\\"$(git describe --tags --always)\\\"};\" > src/generated/gitInfo.ts" }, "dependencies": { - "@stellar/design-system": "^2.0.0-beta.5", + "@stellar/design-system": "^2.0.0-beta.6", "@tanstack/react-query": "^5.24.1", "@tanstack/react-query-devtools": "^5.24.1", "dompurify": "^3.0.9", @@ -24,6 +24,7 @@ "next": "14.1.0", "react": "^18", "react-dom": "^18", + "stellar-sdk": "^11.2.2", "zustand": "^4.5.1", "zustand-querystring": "^0.0.19" }, diff --git a/src/components/ExpandBox/index.tsx b/src/components/ExpandBox/index.tsx new file mode 100644 index 00000000..a88d9e57 --- /dev/null +++ b/src/components/ExpandBox/index.tsx @@ -0,0 +1,34 @@ +import { useLayoutEffect, useState } from "react"; +import "./styles.scss"; + +export const ExpandBox = ({ + children, + isExpanded, +}: { + children: React.ReactNode; + isExpanded: boolean; +}) => { + const [isOpen, setIsOpen] = useState(false); + + // We need a bit of delay to enable overflow visible when the section is expanded + useLayoutEffect(() => { + if (isExpanded) { + const t = setTimeout(() => { + setIsOpen(true); + clearTimeout(t); + }, 200); + } else { + setIsOpen(false); + } + }, [isExpanded]); + + return ( +
+
{children}
+
+ ); +}; diff --git a/src/components/ExpandBox/styles.scss b/src/components/ExpandBox/styles.scss new file mode 100644 index 00000000..46816284 --- /dev/null +++ b/src/components/ExpandBox/styles.scss @@ -0,0 +1,19 @@ +.ExpandBox { + display: grid; + grid-template-rows: 0fr; + transition: grid-template-rows 200ms ease-out; + + &[data-is-expanded="true"] { + grid-template-rows: 1fr; + } + + &[data-is-open="true"] { + .ExpandBox__inset { + overflow: visible; + } + } + + &__inset { + overflow: hidden; + } +} diff --git a/src/components/FormElements/AssetPicker.tsx b/src/components/FormElements/AssetPicker.tsx new file mode 100644 index 00000000..5ceda7b9 --- /dev/null +++ b/src/components/FormElements/AssetPicker.tsx @@ -0,0 +1,309 @@ +import { useState } from "react"; +import { Input } from "@stellar/design-system"; + +import { ExpandBox } from "@/components/ExpandBox"; +import { RadioPicker } from "@/components/RadioPicker"; +import { PubKeyPicker } from "@/components/FormElements/PubKeyPicker"; + +import { + AssetObject, + AssetObjectValue, + AssetString, + AssetType, +} from "@/types/types"; + +type AssetPickerProps = ( + | { + variant: "string"; + value: string | undefined; + includeNone?: boolean; + includeNative?: undefined; + onChange: ( + optionId: AssetType | undefined, + optionValue: string | undefined, + ) => void; + } + | { + variant: "object"; + value: AssetObjectValue | undefined; + includeNone?: undefined; + includeNative?: boolean; + onChange: ( + optionId: AssetType | undefined, + optionValue: AssetObjectValue | undefined, + ) => void; + } +) & { + id: string; + selectedOption: AssetType | undefined; + label: string; + labelSuffix?: string | React.ReactNode; + fitContent?: boolean; +}; + +export const AssetPicker = ({ + id, + variant, + selectedOption, + label, + value, + includeNone, + includeNative = true, + onChange, + labelSuffix, + fitContent, +}: AssetPickerProps) => { + const initErrorState = { + code: "", + issuer: "", + }; + + const getInitialValue = () => { + if (variant === "string") { + const assetString = value?.split(":"); + return { + type: undefined, + code: assetString?.[0] ?? "", + issuer: assetString?.[1] ?? "", + }; + } + + return { + type: value?.type, + code: value?.code ?? "", + issuer: value?.issuer ?? "", + }; + }; + + const [stateValue, setStateValue] = useState(getInitialValue()); + const [error, setError] = useState(initErrorState); + + let stringOptions: AssetString[] = [ + { + id: "native", + label: "Native", + value: "native", + }, + { + id: "issued", + label: "Issued", + value: "", + }, + ]; + + if (includeNone) { + stringOptions = [ + { + id: "none", + label: "None", + value: "", + }, + ...stringOptions, + ]; + } + + let objectOptions: AssetObject[] = [ + { + id: "credit_alphanum4", + label: "Alphanumeric 4", + value: { + type: "credit_alphanum4", + code: "", + issuer: "", + }, + }, + { + id: "credit_alphanum12", + label: "Alphanumeric 12", + value: { + type: "credit_alphanum12", + code: "", + issuer: "", + }, + }, + // TODO: add Liquidity Pool shares (for Change Trust operation) + ]; + + if (includeNative) { + objectOptions = [ + { + id: "native", + label: "Native", + value: { + type: "native", + code: "", + issuer: "", + }, + }, + ...objectOptions, + ]; + } + + // Extra helper function to make TypeScript happy to get the right type + const handleOnChange = ( + id: AssetType | undefined, + value: string | AssetObjectValue | undefined, + ) => { + if (!value) { + onChange(id, undefined); + } + + if (variant === "string") { + onChange(id, value as string); + } else { + onChange(id, value as AssetObjectValue); + } + }; + + const handleOptionChange = ( + optionId: AssetType | undefined, + optionValue: string | AssetObjectValue | undefined, + ) => { + handleOnChange(optionId, optionValue); + setStateValue({ type: optionId, code: "", issuer: "" }); + setError(initErrorState); + }; + + const validateCode = (code: string, assetType: AssetType | undefined) => { + if (!code) { + return "Asset code is required."; + } + + let minLength; + let maxLength; + + switch (assetType) { + case "credit_alphanum4": + minLength = 1; + maxLength = 4; + break; + case "credit_alphanum12": + minLength = 5; + maxLength = 12; + break; + default: + minLength = 1; + maxLength = 12; + } + + if (!code.match(/^[a-zA-Z0-9]+$/g)) { + return "Asset code must consist of only letters and numbers."; + } else if (code.length < minLength || code.length > maxLength) { + return `Asset code must be between ${minLength} and ${maxLength} characters long.`; + } + + return undefined; + }; + + const handleCodeError = (value: string) => { + const codeError = validateCode(value, stateValue.type); + setError({ ...error, code: codeError || "" }); + return codeError; + }; + + return ( +
+ + + + ) => { + setStateValue({ ...stateValue, code: e.target.value }); + handleCodeError(e.target.value); + }, + onBlur: (e) => { + const codeError = handleCodeError(e.target.value); + + if (!codeError && stateValue.issuer) { + handleOnChange( + selectedOption, + variant === "string" + ? `${stateValue.code}:${stateValue.issuer}` + : stateValue, + ); + } + }, + error: error.code, + }} + issuer={{ + value: stateValue.issuer, + onChange: (value: string, issuerError: string) => { + setStateValue({ ...stateValue, issuer: value }); + setError({ ...error, issuer: issuerError }); + }, + onBlur: (value, issuerError) => { + setError({ ...error, issuer: issuerError }); + + if (!issuerError && stateValue.code) { + handleOnChange( + selectedOption, + variant === "string" + ? `${stateValue.code}:${value}` + : stateValue, + ); + } + }, + error: error.issuer, + }} + /> + +
+ ); +}; + +type AssetPickerFieldsProps = { + id: string; + code: { + value: string; + error: string; + onChange: (e: React.ChangeEvent) => void; + onBlur: (e: React.ChangeEvent) => void; + }; + issuer: { + value: string; + error: string; + onChange: (value: string, issuerError: string) => void; + onBlur: (value: string, issuerError: string) => void; + }; +}; + +const AssetPickerFields = ({ id, code, issuer }: AssetPickerFieldsProps) => ( +
+ + +
+); diff --git a/src/components/FormElements/IncludeFailedPicker.tsx b/src/components/FormElements/IncludeFailedPicker.tsx new file mode 100644 index 00000000..f15bedb7 --- /dev/null +++ b/src/components/FormElements/IncludeFailedPicker.tsx @@ -0,0 +1,27 @@ +import { RadioPicker } from "@/components/RadioPicker"; + +type IncludeFailedPickerProps = { + id: string; + selectedOption: string | undefined; + onChange: (optionId: string | undefined, optionValue?: boolean) => void; + labelSuffix?: string | React.ReactNode; +}; + +export const IncludeFailedPicker = ({ + id, + selectedOption, + onChange, + labelSuffix, +}: IncludeFailedPickerProps) => ( + +); diff --git a/src/components/FormElements/OrderPicker.tsx b/src/components/FormElements/OrderPicker.tsx new file mode 100644 index 00000000..fc6e7ae6 --- /dev/null +++ b/src/components/FormElements/OrderPicker.tsx @@ -0,0 +1,27 @@ +import { RadioPicker } from "@/components/RadioPicker"; + +type OrderPickerProps = { + id: string; + selectedOption: string | undefined; + onChange: (optionId: string | undefined, optionValue?: string) => void; + labelSuffix?: string | React.ReactNode; +}; + +export const OrderPicker = ({ + id, + selectedOption, + onChange, + labelSuffix, +}: OrderPickerProps) => ( + +); diff --git a/src/components/FormElements/PubKeyPicker.tsx b/src/components/FormElements/PubKeyPicker.tsx new file mode 100644 index 00000000..53dd4a58 --- /dev/null +++ b/src/components/FormElements/PubKeyPicker.tsx @@ -0,0 +1,64 @@ +import { StrKey } from "stellar-sdk"; +import { Input, InputProps } from "@stellar/design-system"; + +interface PubKeyPickerProps extends Omit { + id: string; + fieldSize?: "sm" | "md" | "lg"; + label: string; + labelSuffix?: string | React.ReactNode; + placeholder?: string; + value: string; + error: string | ""; + onChange: (value: string, error: string) => void; + onBlur: (value: string, error: string) => void; +} + +export const PubKeyPicker = ({ + id, + fieldSize = "md", + label, + labelSuffix, + placeholder = "Example: GCEXAMPLE5HWNK4AYSTEQ4UWDKHTCKADVS2AHF3UI2ZMO3DPUSM6Q4UG", + value, + error, + onChange, + onBlur, + ...props +}: PubKeyPickerProps) => { + const validatePublicKey = (issuer: string) => { + if (!issuer) { + return "Asset issuer is required."; + } + + if (issuer.startsWith("M")) { + if (!StrKey.isValidMed25519PublicKey(issuer)) { + return "Muxed account address is invalid."; + } + } else if (!StrKey.isValidEd25519PublicKey(issuer)) { + return "Public key is invalid."; + } + + return ""; + }; + + return ( + { + const error = validatePublicKey(e.target.value); + onChange(e.target.value, error); + }} + onBlur={(e) => { + const error = validatePublicKey(e.target.value); + onBlur(e.target.value, error); + }} + error={error} + {...props} + /> + ); +}; diff --git a/src/components/RadioPicker/index.tsx b/src/components/RadioPicker/index.tsx new file mode 100644 index 00000000..36125a85 --- /dev/null +++ b/src/components/RadioPicker/index.tsx @@ -0,0 +1,70 @@ +import { Label } from "@stellar/design-system"; +import { AssetType } from "@/types/types"; +import "./styles.scss"; + +interface RadioPickerProps { + id: string; + selectedOption: string | undefined; + label?: string | React.ReactNode; + labelSuffix?: string | React.ReactNode; + onChange: ( + optionId: AssetType | undefined, + optionValue?: TOptionValue, + ) => void; + options: { + id: string; + label: string; + value?: TOptionValue; + }[]; + fitContent?: boolean; +} + +export const RadioPicker = ({ + id, + selectedOption, + label, + labelSuffix, + onChange, + options, + fitContent, +}: RadioPickerProps) => { + const customStyle = { + ...(fitContent ? { "--RadioPicker-width": "fit-content" } : {}), + } as React.CSSProperties; + + return ( +
+ {label ? ( + + ) : null} +
+ {options.map((o) => { + const opId = `${o.id}-${id}`; + const curId = opId.split("-")[0]; + + return ( +
+ { + onChange(o.id as AssetType, o.value); + }} + onClick={() => { + if (curId === selectedOption) { + // Clear selection if selected the same + onChange(undefined); + } + }} + /> + +
+ ); + })} +
+
+ ); +}; diff --git a/src/components/RadioPicker/styles.scss b/src/components/RadioPicker/styles.scss new file mode 100644 index 00000000..85f9e4d5 --- /dev/null +++ b/src/components/RadioPicker/styles.scss @@ -0,0 +1,97 @@ +@use "../../styles/utils.scss" as *; + +.RadioPicker { + --RadioPicker-width: 100%; + --RadioPicker-color-text: var(--sds-clr-gray-12); + --RadioPicker-color-background: var(--sds-clr-gray-01); + --RadioPicker-color-border: var(--sds-clr-gray-06); + --RadioPicker-box-shadow-size: 0; + --RadioPicker-box-shadow-color: var(--sds-clr-lilac-06); + + display: flex; + flex-direction: column; + gap: pxToRem(8px); + width: var(--RadioPicker-width); + + &__inset { + display: grid; + gap: pxToRem(8px); + } + + &__options { + display: flex; + align-items: center; + justify-content: stretch; + } + + &__item { + flex: 1; + + input[type="radio"] { + opacity: 0; + position: absolute; + z-index: -1; + + &:checked + label { + --RadioPicker-color-text: var(--sds-clr-base-00); + --RadioPicker-color-background: var(--sds-clr-lilac-09); + --RadioPicker-color-border: var(--sds-clr-lilac-09); + } + + &:focus + label { + --RadioPicker-box-shadow-size: #{pxToRem(2px)}; + z-index: 1000; + } + } + + label { + position: relative; + display: block; + font-size: pxToRem(12px); + line-height: pxToRem(18px); + font-weight: var(--sds-fw-semi-bold); + color: var(--RadioPicker-color-text); + text-align: center; + padding: pxToRem(4px) pxToRem(16px); + width: 100%; + background-color: var(--RadioPicker-color-background); + border: 1px solid var(--RadioPicker-color-border); + cursor: pointer; + transition: + color var(--sds-anim-transition-default), + background-color var(--sds-anim-transition-default), + border-color var(--sds-anim-transition-default), + box-shadow var(--sds-anim-transition-default); + box-shadow: 0 0 0 var(--RadioPicker-box-shadow-size) + var(--RadioPicker-box-shadow-color); + } + + &:not(:first-child) { + label { + border-left: none; + } + } + + &:first-child { + label { + border-top-left-radius: pxToRem(4px); + border-bottom-left-radius: pxToRem(4px); + } + } + + &:last-child { + label { + border-top-right-radius: pxToRem(4px); + border-bottom-right-radius: pxToRem(4px); + } + } + + @media (hover: hover) { + &:hover { + --RadioPicker-color-text: var(--sds-clr-base-01); + --RadioPicker-color-background: var(--sds-clr-gray-04); + --RadioPicker-color-border: var(--sds-clr-gray-04); + } + } + } +} diff --git a/src/types/types.ts b/src/types/types.ts index f3b1ea07..d621088f 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1,5 +1,11 @@ +// ============================================================================= +// Generic +// ============================================================================= export type EmptyObj = Record; +// ============================================================================= +// Network +// ============================================================================= export type NetworkType = "testnet" | "mainnet" | "futurenet" | "custom"; export type Network = { @@ -32,6 +38,38 @@ export type StatusPageScheduled = { incident_updates: StatusPageIncident[]; }; +// ============================================================================= +// Asset +// ============================================================================= +export type AssetType = + | "none" + | "native" + | "issued" + | "credit_alphanum4" + | "credit_alphanum12" + | "liquidity_pool_shares"; + +export type AssetString = { + id: AssetType; + label: string; + value: string | undefined; +}; + +export type AssetObjectValue = { + type: AssetType | undefined; + code: string; + issuer: string; +}; + +export type AssetObject = { + id: AssetType; + label: string; + value: AssetObjectValue; +}; + +// ============================================================================= +// Component +// ============================================================================= export type InfoCard = { id: string; title: string; diff --git a/yarn.lock b/yarn.lock index bd132e26..70dc3b49 100644 --- a/yarn.lock +++ b/yarn.lock @@ -192,10 +192,10 @@ resolved "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.6.1.tgz" integrity sha512-UY+FGM/2jjMkzQLn8pxcHGMaVLh9aEitG3zY2CiY7XHdLiz3bZOwa6oDxNqEMv7zZkV+cj5DOdz0cQ1BP5Hjgw== -"@stellar/design-system@^2.0.0-beta.5": - version "2.0.0-beta.5" - resolved "https://registry.npmjs.org/@stellar/design-system/-/design-system-2.0.0-beta.5.tgz" - integrity sha512-fnFZq+doZcqeX2hTgKUVT6SbSmFaZx6tahBl+qN0z6EuxusNbA29HcWNsptwiZK3lLlqm88Wu3jWcVmhvB6zzg== +"@stellar/design-system@^2.0.0-beta.6": + version "2.0.0-beta.6" + resolved "https://registry.yarnpkg.com/@stellar/design-system/-/design-system-2.0.0-beta.6.tgz#81ec445fb01b99cd886d9b6790ba5bd242dc523f" + integrity sha512-8xIMYH+pIcNnmwk9rOqhnj7aPqz8FUEgvae/89zctPpo0UhfJ7wLsHn8WTKwLR2ZWmnqmStCjXXeGPtxisuFcA== dependencies: "@floating-ui/dom" "^1.5.3" bignumber.js "^9.1.1" @@ -203,6 +203,26 @@ react-copy-to-clipboard "^5.1.0" tslib "^2.5.0" +"@stellar/js-xdr@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@stellar/js-xdr/-/js-xdr-3.1.0.tgz#37c23e6c913d011f750808f3d8b60174b633e137" + integrity sha512-mYTyFnhgyQgyvpAYZRO1LurUn2MxcIZRj74zZz/BxKEk7zrL4axhQ1ez0HL2BRi0wlG6cHn5BeD/t9Xcyp7CSQ== + +"@stellar/stellar-base@^11.0.0": + version "11.0.0" + resolved "https://registry.yarnpkg.com/@stellar/stellar-base/-/stellar-base-11.0.0.tgz#9c2595f0aa1fe955191656fe9bda7a6b34ef82f0" + integrity sha512-KPTjaWJCG2m7hMCPRWFGGPaG5qOkgPLWvFVOhe1HUy7dlE4MxxPfdusz0mcLkf6VT7doqhLB1rIt0D9M2GgQcQ== + dependencies: + "@stellar/js-xdr" "^3.1.0" + base32.js "^0.1.0" + bignumber.js "^9.1.2" + buffer "^6.0.3" + sha.js "^2.3.6" + tweetnacl "^1.0.3" + typescript "^5.3.3" + optionalDependencies: + sodium-native "^4.0.8" + "@swc/helpers@0.5.2": version "0.5.2" resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz" @@ -504,6 +524,11 @@ asynciterator.prototype@^1.0.0: dependencies: has-symbols "^1.0.3" +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + available-typed-arrays@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" @@ -514,6 +539,15 @@ axe-core@=4.7.0: resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz" integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== +axios@^1.6.7: + version "1.6.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.7.tgz#7b48c2e27c96f9c68a2f8f31e2ab19f59b06b0a7" + integrity sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA== + dependencies: + follow-redirects "^1.15.4" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + axobject-query@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz" @@ -526,7 +560,17 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -bignumber.js@^9.1.1: +base32.js@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/base32.js/-/base32.js-0.1.0.tgz#b582dec693c2f11e893cf064ee6ac5b6131a2202" + integrity sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bignumber.js@^9.1.1, bignumber.js@^9.1.2: version "9.1.2" resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz" integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== @@ -558,6 +602,14 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + busboy@1.6.0: version "1.6.0" resolved "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz" @@ -658,6 +710,13 @@ colorette@^2.0.20: resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@11.1.0: version "11.1.0" resolved "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz" @@ -753,6 +812,11 @@ 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" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + dequal@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz" @@ -1163,6 +1227,11 @@ eventemitter3@^5.0.1: resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz" integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== +eventsource@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-2.0.2.tgz#76dfcc02930fb2ff339520b6d290da573a9e8508" + integrity sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA== + execa@8.0.1: version "8.0.1" resolved "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz" @@ -1247,6 +1316,11 @@ flatted@^3.2.9: resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz" integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== +follow-redirects@^1.15.4: + version "1.15.5" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" + integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" @@ -1262,6 +1336,15 @@ foreground-child@^3.1.0: cross-spawn "^7.0.0" signal-exit "^4.0.1" +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" @@ -1496,6 +1579,11 @@ husky@^9.0.11: resolved "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz" integrity sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw== +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore@^5.2.0: version "5.3.0" resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz" @@ -1532,7 +1620,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@^2.0.1: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1948,6 +2036,18 @@ micromatch@4.0.5, micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" @@ -2025,6 +2125,11 @@ next@14.1.0: "@next/swc-win32-ia32-msvc" "14.1.0" "@next/swc-win32-x64-msvc" "14.1.0" +node-gyp-build@^4.6.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd" + integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== + normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" @@ -2256,6 +2361,11 @@ prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + punycode@^2.1.0: version "2.3.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" @@ -2266,6 +2376,13 @@ queue-microtask@^1.2.2: resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + react-copy-to-clipboard@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.1.0.tgz" @@ -2414,6 +2531,11 @@ safe-array-concat@^1.0.1: has-symbols "^1.0.3" isarray "^2.0.5" +safe-buffer@^5.0.1, safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex-test@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz" @@ -2470,6 +2592,14 @@ set-function-name@^2.0.0, set-function-name@^2.0.1: functions-have-names "^1.2.3" has-property-descriptors "^1.0.0" +sha.js@^2.3.6: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" @@ -2527,6 +2657,13 @@ slice-ansi@^7.0.0: ansi-styles "^6.2.1" is-fullwidth-code-point "^5.0.0" +sodium-native@^4.0.8: + version "4.0.10" + resolved "https://registry.yarnpkg.com/sodium-native/-/sodium-native-4.0.10.tgz#24af8db06518807a8ddf4e5143d819f14bf7a837" + integrity sha512-vrJQt4gASntDbnltRRk9vN4rks1SehjM12HkqQtu250JtWT+/lo8oEOa1HvSq3+8hzJdYcCJuLR5qRGxoRDjAg== + dependencies: + node-gyp-build "^4.6.0" + "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" @@ -2537,6 +2674,20 @@ spawn-command@0.0.2: resolved "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz" integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== +stellar-sdk@^11.2.2: + version "11.2.2" + resolved "https://registry.yarnpkg.com/stellar-sdk/-/stellar-sdk-11.2.2.tgz#930ba86e10bdc71b2ad7a3f0bd60323ff708e12a" + integrity sha512-xecQW4gkPIxAvxcVFcw4ZSTtzpUmJPd4A4e4Mr3EkOdyWnshMIZQMzFox5DuAikrThofgihScJGYrDCmo3I/BA== + dependencies: + "@stellar/stellar-base" "^11.0.0" + axios "^1.6.7" + bignumber.js "^9.1.2" + eventsource "^2.0.2" + randombytes "^2.1.0" + toml "^3.0.0" + typescript "^5.3.3" + urijs "^1.19.1" + streamsearch@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz" @@ -2707,6 +2858,11 @@ toggle-selection@^1.0.6: resolved "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz" integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ== +toml@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee" + integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== + tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz" @@ -2732,6 +2888,11 @@ tslib@^2.1.0, tslib@^2.4.0, tslib@^2.5.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tweetnacl@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" @@ -2793,6 +2954,11 @@ typescript@^5: resolved "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz" integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== +typescript@^5.3.3: + version "5.4.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" + integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== + unbox-primitive@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" @@ -2815,6 +2981,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +urijs@^1.19.1: + version "1.19.11" + resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.11.tgz#204b0d6b605ae80bea54bea39280cdb7c9f923cc" + integrity sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ== + use-sync-external-store@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz"