From d03bb8cdd09fb245ae474051fb1d10272660cf6e Mon Sep 17 00:00:00 2001 From: Gabe Rodriguez <grod220@gmail.com> Date: Tue, 30 Apr 2024 14:04:46 +0200 Subject: [PATCH] Connect wallet button [interchain UI part 2] (#1014) * Add ibc in slice * Connect wallet * Update dropdown * cleanup --- apps/minifront/package.json | 15 +- .../components/ibc/ibc-in/chain-dropdown.tsx | 165 +++---- .../components/ibc/ibc-in/chain-picker.tsx | 13 - .../components/ibc/ibc-in/chain-provider.tsx | 1 + .../ibc/ibc-in/cosmos-wallet-connector.tsx | 30 ++ .../src/components/ibc/ibc-in/ibc-in-form.tsx | 2 +- .../components/ibc/ibc-in/interchain-ui.tsx | 9 +- .../ibc/ibc-in/wallet-addr-card.tsx | 16 + .../ibc/ibc-in/wallet-connect-button.tsx | 69 +++ .../src/components/ibc/ibc-loader.ts | 6 +- .../components/ibc/ibc-out/chain-selector.tsx | 4 +- .../components/ibc/ibc-out/ibc-out-form.tsx | 8 +- apps/minifront/src/components/ibc/layout.tsx | 6 +- apps/minifront/src/state/ibc-in.ts | 20 + .../state/{ibc.test.ts => ibc-out.test.ts} | 16 +- .../src/state/{ibc.ts => ibc-out.ts} | 30 +- apps/minifront/src/state/index.ts | 9 +- packages/ui/components/ui/avatar.tsx | 46 ++ packages/ui/components/ui/command.tsx | 145 ++++++ packages/ui/components/ui/popover.tsx | 4 +- packages/ui/package.json | 2 + pnpm-lock.yaml | 433 ++++++++++++++---- 22 files changed, 807 insertions(+), 242 deletions(-) delete mode 100644 apps/minifront/src/components/ibc/ibc-in/chain-picker.tsx create mode 100644 apps/minifront/src/components/ibc/ibc-in/cosmos-wallet-connector.tsx create mode 100644 apps/minifront/src/components/ibc/ibc-in/wallet-addr-card.tsx create mode 100644 apps/minifront/src/components/ibc/ibc-in/wallet-connect-button.tsx create mode 100644 apps/minifront/src/state/ibc-in.ts rename apps/minifront/src/state/{ibc.test.ts => ibc-out.test.ts} (89%) rename apps/minifront/src/state/{ibc.ts => ibc-out.ts} (90%) create mode 100644 packages/ui/components/ui/avatar.tsx create mode 100644 packages/ui/components/ui/command.tsx diff --git a/apps/minifront/package.json b/apps/minifront/package.json index 65a4042e53..c030db0eb0 100644 --- a/apps/minifront/package.json +++ b/apps/minifront/package.json @@ -20,8 +20,9 @@ "@bufbuild/protobuf": "^1.9.0", "@cosmjs/proto-signing": "^0.32.3", "@cosmjs/stargate": "^0.32.3", - "@cosmos-kit/react": "^2.11.0", - "@interchain-ui/react": "^1.23.3", + "@cosmos-kit/core": "^2.9.2", + "@cosmos-kit/react": "^2.11.2", + "@interchain-ui/react": "^1.23.10", "@penumbra-labs/registry": "^5.1.0", "@penumbra-zone/bech32m": "workspace:*", "@penumbra-zone/client": "workspace:*", @@ -36,14 +37,14 @@ "@tanstack/react-query": "^5.28.9", "bech32": "^2.0.0", "bignumber.js": "^9.1.2", - "chain-registry": "^1.41.9", - "cosmos-kit": "^2.10.0", + "chain-registry": "^1.45.5", + "cosmos-kit": "^2.10.2", "date-fns": "^3.6.0", "framer-motion": "^11.0.22", "immer": "^10.0.4", "lodash": "^4.17.21", - "match-sorter": "^6.3.4", - "osmo-query": "^16.11.0", + "lucide-react": "^0.363.0", + "osmo-query": "^16.12.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-helmet": "^6.1.0", @@ -55,7 +56,7 @@ "zustand": "^4.5.2" }, "devDependencies": { - "@chain-registry/types": "^0.25.7", + "@chain-registry/types": "^0.28.4", "@penumbra-zone/polyfills": "workspace:*", "@testing-library/jest-dom": "^6.4.2", "@testing-library/react": "^14.2.2", diff --git a/apps/minifront/src/components/ibc/ibc-in/chain-dropdown.tsx b/apps/minifront/src/components/ibc/ibc-in/chain-dropdown.tsx index 62bff84454..8d20ef047c 100644 --- a/apps/minifront/src/components/ibc/ibc-in/chain-dropdown.tsx +++ b/apps/minifront/src/components/ibc/ibc-in/chain-dropdown.tsx @@ -1,13 +1,20 @@ import * as React from 'react'; import { useMemo } from 'react'; -import { Avatar, Box, Combobox, Skeleton, Stack, Text } from '@interchain-ui/react'; -import { matchSorter } from 'match-sorter'; import { useManager } from '@cosmos-kit/react'; - -interface Option { - label: string; - value: string; -} +import { Popover, PopoverContent, PopoverTrigger } from '@penumbra-zone/ui/components/ui/popover'; +import { ChevronsUpDown } from 'lucide-react'; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, +} from '@penumbra-zone/ui/components/ui/command'; +import { Button } from '@penumbra-zone/ui/components/ui/button'; +import { ibcInSelector } from '../../../state/ibc-in'; +import { useStore } from '../../../state'; +import { Avatar, AvatarImage } from '@penumbra-zone/ui/components/ui/avatar'; +import { Identicon } from '@penumbra-zone/ui/components/ui/identicon'; export interface ChainInfo { chainName: string; @@ -16,26 +23,6 @@ export interface ChainInfo { icon?: string; } -export interface ChooseChainProps { - onChange: (selectedItem: Option) => void; -} - -const ChainOption = ({ chainInfo: { label, icon } }: { chainInfo: ChainInfo }) => { - return ( - <Stack aria-label={`Chain option: ${label}`}> - <Avatar - name={label} - className='mr-2' - getInitials={name => name[0]!} - size='xs' - src={icon} - fallbackMode='bg' - /> - <Text>{label}</Text> - </Stack> - ); -}; - const useChainInfos = (): ChainInfo[] => { const { chainRecords, getChainLogo } = useManager(); return useMemo( @@ -54,80 +41,66 @@ const useChainInfos = (): ChainInfo[] => { // Note the console will display aria-label warnings (despite them being present). // The cosmology team has been notified of the issue. -export const ChainDropdown = ({ onChange }: ChooseChainProps) => { +export const ChainDropdown = () => { const chainInfos = useChainInfos(); + const { setSelectedChain } = useStore(ibcInSelector); - const [selectedKey, setSelectedKey] = React.useState<string>(); - const [filterValue, setFilterValue] = React.useState<string>(''); - - const filteredItems = React.useMemo(() => { - return matchSorter(chainInfos, filterValue, { - keys: ['label', 'value'], - }); - }, [chainInfos, filterValue]); + const [open, setOpen] = React.useState(false); + const [value, setValue] = React.useState(''); - const avatarUrl = filteredItems.find(i => i.value === selectedKey)?.icon ?? undefined; + const selected = chainInfos.find(c => c.value === value); return ( - <Box className='flex flex-col items-center justify-center'> - <div className='font-bold text-stone-700'>Select chain</div> - <Combobox - aria-label='Select a chain' - items={filteredItems} - inputValue={filterValue} - openOnFocus - onInputChange={value => { - setFilterValue(value); - if (!value) { - setSelectedKey(undefined); - } - }} - selectedKey={selectedKey} - onSelectionChange={item => { - if (item) { - setSelectedKey(item as string); - - const found = chainInfos.find(options => options.value === item) ?? null; - - if (found) { - onChange(found); - setFilterValue(found.label); - } - } - }} - inputAddonStart={ - selectedKey && avatarUrl ? ( - <Avatar - name={selectedKey.toString()} - getInitials={name => name[0]!} - size='xs' - src={avatarUrl} - fallbackMode='bg' - className='px-2' - /> + <Popover open={open} onOpenChange={setOpen}> + <PopoverTrigger asChild> + <Button variant='onLight' role='combobox' aria-expanded={open} className='w-[300px]'> + {value ? ( + <div className='flex gap-2'> + <Avatar className='size-6'> + <AvatarImage src={selected?.icon} /> + <Identicon uniqueIdentifier={selected?.label ?? ''} type='gradient' size={22} /> + </Avatar> + <span className='mt-0.5'>{selected?.label}</span> + </div> ) : ( - <Box className='flex items-center justify-center px-2'> - <Skeleton width='24px' height='24px' className='rounded-full' /> - </Box> - ) - } - styleProps={{ - width: { - mobile: '100%', - mdMobile: '350px', - }, - }} - > - {filteredItems.map(info => ( - <Combobox.Item - key={info.value} - textValue={info.label} - aria-label={`Select ${info.label}`} - > - <ChainOption chainInfo={info} /> - </Combobox.Item> - ))} - </Combobox> - </Box> + 'Select a chain' + )} + <ChevronsUpDown className='ml-2 size-4 shrink-0 opacity-50' /> + </Button> + </PopoverTrigger> + <PopoverContent className='w-[300px] p-0'> + <Command> + <CommandInput placeholder='Search chains...' /> + <CommandEmpty>No framework found.</CommandEmpty> + <CommandGroup> + {chainInfos.map(chain => ( + <CommandItem + key={chain.value} + value={chain.value} + onSelect={currentValue => { + setOpen(false); + + if (currentValue === value) { + setValue(''); + setSelectedChain(undefined); + } else { + setValue(currentValue); + const match = chainInfos.find(options => options.value === currentValue); + setSelectedChain(match); + } + }} + className='flex gap-2' + > + <Avatar className='size-6'> + <AvatarImage src={chain.icon} /> + <Identicon uniqueIdentifier={chain.label} type='gradient' size={22} /> + </Avatar> + {chain.label} + </CommandItem> + ))} + </CommandGroup> + </Command> + </PopoverContent> + </Popover> ); }; diff --git a/apps/minifront/src/components/ibc/ibc-in/chain-picker.tsx b/apps/minifront/src/components/ibc/ibc-in/chain-picker.tsx deleted file mode 100644 index 5740f06e8f..0000000000 --- a/apps/minifront/src/components/ibc/ibc-in/chain-picker.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { useEffect, useState } from 'react'; -import { ChainName } from 'cosmos-kit'; -import { ChainDropdown } from './chain-dropdown'; - -export const ChainPicker = () => { - // Temp until slices are setup - const [chainName, setChainName] = useState<ChainName>(); - useEffect(() => { - console.log(`You chose: ${chainName}`); - }, [chainName]); - - return <ChainDropdown onChange={e => setChainName(e.value)} />; -}; diff --git a/apps/minifront/src/components/ibc/ibc-in/chain-provider.tsx b/apps/minifront/src/components/ibc/ibc-in/chain-provider.tsx index 919da2ee4d..244a8e3af5 100644 --- a/apps/minifront/src/components/ibc/ibc-in/chain-provider.tsx +++ b/apps/minifront/src/components/ibc/ibc-in/chain-provider.tsx @@ -55,6 +55,7 @@ export const IbcChainProvider = ({ registry, children }: IbcProviderProps) => { }, }} signerOptions={signerOptions} + modalTheme={{ defaultTheme: 'light' }} > {children} </ChainProvider> diff --git a/apps/minifront/src/components/ibc/ibc-in/cosmos-wallet-connector.tsx b/apps/minifront/src/components/ibc/ibc-in/cosmos-wallet-connector.tsx new file mode 100644 index 0000000000..810e67de36 --- /dev/null +++ b/apps/minifront/src/components/ibc/ibc-in/cosmos-wallet-connector.tsx @@ -0,0 +1,30 @@ +import { useStore } from '../../../state'; +import { ibcInSelector } from '../../../state/ibc-in'; +import { useChain, useManager } from '@cosmos-kit/react'; +import { WalletStatus } from '@cosmos-kit/core'; +import { WalletAddrCard } from './wallet-addr-card'; +import { ConnectWalletButton } from './wallet-connect-button'; + +export const useChainConnector = () => { + const { selectedChain } = useStore(ibcInSelector); + const { chainRecords } = useManager(); + const defaultChain = chainRecords[0]!.name; + return useChain(selectedChain?.chainName ?? defaultChain); +}; + +export const CosmosWalletConnector = () => { + const { selectedChain } = useStore(ibcInSelector); + const { username, address, status, message } = useChainConnector(); + + return ( + <div className='flex flex-col items-center justify-center gap-4'> + {address && selectedChain && <WalletAddrCard username={username} address={address} />} + <div className='w-52'> + <ConnectWalletButton /> + </div> + {(status === WalletStatus.Rejected || status === WalletStatus.Error) && ( + <div className='text-purple-500'>{message}</div> + )} + </div> + ); +}; diff --git a/apps/minifront/src/components/ibc/ibc-in/ibc-in-form.tsx b/apps/minifront/src/components/ibc/ibc-in/ibc-in-form.tsx index 40958dc8f9..7a185f9f08 100644 --- a/apps/minifront/src/components/ibc/ibc-in/ibc-in-form.tsx +++ b/apps/minifront/src/components/ibc/ibc-in/ibc-in-form.tsx @@ -11,7 +11,7 @@ export const IbcInForm = () => { }} > <InterchainUi /> - <Button type='submit' variant='onLight'> + <Button type='submit' variant='onLight' disabled> <div className='flex items-center gap-2'> <LockClosedIcon /> <span className='-mb-1'>Shield Assets</span> diff --git a/apps/minifront/src/components/ibc/ibc-in/interchain-ui.tsx b/apps/minifront/src/components/ibc/ibc-in/interchain-ui.tsx index 65e3f8a607..97a21dbce5 100644 --- a/apps/minifront/src/components/ibc/ibc-in/interchain-ui.tsx +++ b/apps/minifront/src/components/ibc/ibc-in/interchain-ui.tsx @@ -1,6 +1,7 @@ import { IbcChainProvider } from './chain-provider'; import { useRegistry } from '../../../fetchers/registry'; -import { ChainPicker } from './chain-picker'; +import { ChainDropdown } from './chain-dropdown'; +import { CosmosWalletConnector } from './cosmos-wallet-connector'; export const InterchainUi = () => { const { data, isLoading, error } = useRegistry(); @@ -12,10 +13,10 @@ export const InterchainUi = () => { return ( <IbcChainProvider registry={data}> {/* negative margin offsets div inserted by provider */} - <div className='-mt-4'> - <ChainPicker /> + <div className='-mt-4 flex justify-center'> + <ChainDropdown /> </div> - {/* WalletSection to go here */} + <CosmosWalletConnector /> </IbcChainProvider> ); }; diff --git a/apps/minifront/src/components/ibc/ibc-in/wallet-addr-card.tsx b/apps/minifront/src/components/ibc/ibc-in/wallet-addr-card.tsx new file mode 100644 index 0000000000..3c34414c6e --- /dev/null +++ b/apps/minifront/src/components/ibc/ibc-in/wallet-addr-card.tsx @@ -0,0 +1,16 @@ +import { Identicon } from '@penumbra-zone/ui/components/ui/identicon'; + +interface UserInfoProps { + address: string; + username?: string; +} + +export const WalletAddrCard = ({ address, username }: UserInfoProps) => { + return ( + <div className='flex flex-col items-center gap-2 space-y-1 rounded-lg bg-white p-6'> + <Identicon uniqueIdentifier={address} type='gradient' size={42} /> + <div className='flex items-center justify-center gap-4 text-gray-500'>{address}</div> + <span className='text-sm font-semibold text-stone-700 sm:text-xl'>{username}</span> + </div> + ); +}; diff --git a/apps/minifront/src/components/ibc/ibc-in/wallet-connect-button.tsx b/apps/minifront/src/components/ibc/ibc-in/wallet-connect-button.tsx new file mode 100644 index 0000000000..a4e51d4855 --- /dev/null +++ b/apps/minifront/src/components/ibc/ibc-in/wallet-connect-button.tsx @@ -0,0 +1,69 @@ +import { Button } from '@interchain-ui/react'; +import { WalletStatus } from 'cosmos-kit'; +import { WalletIcon } from '@penumbra-zone/ui/components/ui/icons/wallet'; +import { MouseEventHandler } from 'react'; +import { useStore } from '../../../state'; +import { ibcInSelector } from '../../../state/ibc-in'; +import { useChainConnector } from './cosmos-wallet-connector'; + +export const ConnectWalletButton = () => { + const { connect, openView, status } = useChainConnector(); + const { selectedChain } = useStore(ibcInSelector); + + if (!selectedChain) { + return <WalletButtonBase buttonText='Connect Wallet' isDisabled={true} />; + } + + const onClickConnect: MouseEventHandler = e => { + e.preventDefault(); + void connect(); + }; + + const onClickOpenView: MouseEventHandler = e => { + e.preventDefault(); + openView(); + }; + + switch (status) { + case WalletStatus.Disconnected: + return <WalletButtonBase buttonText='Connect Wallet' onClick={onClickConnect} />; + case WalletStatus.Connecting: + return <WalletButtonBase isLoading={true} />; + case WalletStatus.Connected: + return <WalletButtonBase buttonText='My Wallet' onClick={onClickOpenView} />; + case WalletStatus.Rejected: + return <WalletButtonBase buttonText='Reconnect' onClick={onClickConnect} />; + case WalletStatus.Error: + return <WalletButtonBase buttonText='Change Wallet' onClick={onClickOpenView} />; + case WalletStatus.NotExist: + return <WalletButtonBase buttonText='Install Wallet' onClick={onClickOpenView} />; + default: + return <WalletButtonBase buttonText='Connect Wallet' onClick={onClickConnect} />; + } +}; + +interface BaseProps { + buttonText?: string; + isLoading?: boolean; + isDisabled?: boolean; + onClick?: MouseEventHandler<HTMLButtonElement>; +} + +const WalletButtonBase = ({ buttonText, isLoading, isDisabled, onClick }: BaseProps) => { + return ( + <Button + fluidWidth + size='md' + isLoading={isLoading} + disabled={isDisabled} + onClick={onClick} + className='relative' + > + <div className='absolute inset-0 z-0 -m-px rounded-lg bg-gradient-to-r from-[rgba(157,75,199,1)] via-[rgba(138,78,201.5,1)] to-[rgba(119,81,204,1)]'></div> + <div className='relative z-10 flex items-center justify-center gap-1 rounded p-2'> + <WalletIcon /> + <span className='font-bold'>{buttonText ? buttonText : 'Connect Wallet'}</span> + </div> + </Button> + ); +}; diff --git a/apps/minifront/src/components/ibc/ibc-loader.ts b/apps/minifront/src/components/ibc/ibc-loader.ts index c98409ff0a..f220273bac 100644 --- a/apps/minifront/src/components/ibc/ibc-loader.ts +++ b/apps/minifront/src/components/ibc/ibc-loader.ts @@ -2,11 +2,11 @@ import { LoaderFunction } from 'react-router-dom'; import { BalancesResponse } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; import { getBalances } from '../../fetchers/balances'; import { useStore } from '../../state'; -import { filterBalancesPerChain } from '../../state/ibc'; import { Chain } from '@penumbra-labs/registry'; import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; import { getIbcConnections, getStakingTokenMetadata } from '../../fetchers/registry'; import { getAllAssets } from '../../fetchers/assets'; +import { filterBalancesPerChain } from '../../state/ibc-out'; export interface IbcLoaderResponse { balances: BalancesResponse[]; @@ -32,8 +32,8 @@ export const IbcLoader: LoaderFunction = async (): Promise<IbcLoaderResponse> => // set initial account if accounts exist and asset if account has asset list useStore.setState(state => { - state.ibc.selection = initialSelection; - state.ibc.chain = initialChain; + state.ibcOut.selection = initialSelection; + state.ibcOut.chain = initialChain; }); } diff --git a/apps/minifront/src/components/ibc/ibc-out/chain-selector.tsx b/apps/minifront/src/components/ibc/ibc-out/chain-selector.tsx index ba7f461a33..ef137ab3e7 100644 --- a/apps/minifront/src/components/ibc/ibc-out/chain-selector.tsx +++ b/apps/minifront/src/components/ibc/ibc-out/chain-selector.tsx @@ -8,13 +8,13 @@ import { import { cn } from '@penumbra-zone/ui/lib/utils'; import { useState } from 'react'; import { useStore } from '../../../state'; -import { ibcSelector } from '../../../state/ibc'; +import { ibcOutSelector } from '../../../state/ibc-out'; import { useLoaderData } from 'react-router-dom'; import { IbcLoaderResponse } from '../ibc-loader'; import { Chain } from '@penumbra-labs/registry'; export const ChainSelector = () => { - const { chain, setChain } = useStore(ibcSelector); + const { chain, setChain } = useStore(ibcOutSelector); const { chains: ibcConnections } = useLoaderData() as IbcLoaderResponse; const [openSelect, setOpenSelect] = useState(false); diff --git a/apps/minifront/src/components/ibc/ibc-out/ibc-out-form.tsx b/apps/minifront/src/components/ibc/ibc-out/ibc-out-form.tsx index c519218736..96dc542b5d 100644 --- a/apps/minifront/src/components/ibc/ibc-out/ibc-out-form.tsx +++ b/apps/minifront/src/components/ibc/ibc-out/ibc-out-form.tsx @@ -3,7 +3,11 @@ import { Input } from '@penumbra-zone/ui/components/ui/input'; import { ChainSelector } from './chain-selector'; import { useLoaderData } from 'react-router-dom'; import { useStore } from '../../../state'; -import { filterBalancesPerChain, ibcSelector, ibcValidationErrors } from '../../../state/ibc'; +import { + filterBalancesPerChain, + ibcOutSelector, + ibcValidationErrors, +} from '../../../state/ibc-out'; import InputToken from '../../shared/input-token'; import { InputBlock } from '../../shared/input-block'; import { IbcLoaderResponse } from '../ibc-loader'; @@ -20,7 +24,7 @@ export const IbcOutForm = () => { selection, setSelection, chain, - } = useStore(ibcSelector); + } = useStore(ibcOutSelector); const filteredBalances = filterBalancesPerChain(balances, chain, stakingTokenMetadata, assets); const validationErrors = useStore(ibcValidationErrors); diff --git a/apps/minifront/src/components/ibc/layout.tsx b/apps/minifront/src/components/ibc/layout.tsx index a97afc40c8..1e7bbdcd50 100644 --- a/apps/minifront/src/components/ibc/layout.tsx +++ b/apps/minifront/src/components/ibc/layout.tsx @@ -8,12 +8,12 @@ export const IbcLayout = () => { <> <div className="fixed inset-0 z-[-100] size-full bg-[url('penumbra-logo.svg')] bg-[length:160vmax] bg-fixed bg-[top_50%_left_25vw] bg-no-repeat" /> <div className='flex flex-1 flex-col gap-4 md:flex-row md:place-content-around'> - <Card light className='relative overflow-visible md:self-start'> + <Card light className='relative z-10 overflow-visible md:self-start'> <LongArrowIcon direction='right' // Negative calculated margin giving lint issue /* eslint-disable-next-line tailwindcss/enforces-negative-arbitrary-values */ - className='invisible absolute inset-y-0 right-0 my-auto -mr-[calc(30vw-3px)] size-[30vw] text-stone-300 md:visible' + className='invisible absolute -top-44 right-0 z-0 -mr-[calc(30vw-3px)] size-[30vw] text-stone-300 md:visible' /> <IbcInForm /> </Card> @@ -22,7 +22,7 @@ export const IbcLayout = () => { direction='left' // Negative calculated margin giving lint issue /* eslint-disable-next-line tailwindcss/enforces-negative-arbitrary-values */ - className='invisible absolute inset-y-0 left-0 my-auto -ml-[calc(30vw-3px)] size-[30vw] text-stone-700 md:visible' + className='invisible absolute -bottom-44 left-0 z-0 my-auto -ml-[calc(30vw-3px)] size-[30vw] text-stone-700 md:visible' /> <IbcOutForm /> </Card> diff --git a/apps/minifront/src/state/ibc-in.ts b/apps/minifront/src/state/ibc-in.ts new file mode 100644 index 0000000000..91f3113f50 --- /dev/null +++ b/apps/minifront/src/state/ibc-in.ts @@ -0,0 +1,20 @@ +import { AllSlices, SliceCreator } from '.'; +import { ChainInfo } from '../components/ibc/ibc-in/chain-dropdown'; + +export interface IbcInSlice { + selectedChain?: ChainInfo; + setSelectedChain: (chain?: ChainInfo) => void; +} + +export const createIbcInSlice = (): SliceCreator<IbcInSlice> => set => { + return { + selectedChain: undefined, + setSelectedChain: chain => { + set(state => { + state.ibcIn.selectedChain = chain; + }); + }, + }; +}; + +export const ibcInSelector = (state: AllSlices) => state.ibcIn; diff --git a/apps/minifront/src/state/ibc.test.ts b/apps/minifront/src/state/ibc-out.test.ts similarity index 89% rename from apps/minifront/src/state/ibc.test.ts rename to apps/minifront/src/state/ibc-out.test.ts index 78050c89ab..f9bfdf31eb 100644 --- a/apps/minifront/src/state/ibc.test.ts +++ b/apps/minifront/src/state/ibc-out.test.ts @@ -12,7 +12,7 @@ import { produce } from 'immer'; import { BalancesResponse } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/view/v1/view_pb'; import { addressFromBech32m } from '@penumbra-zone/bech32m/penumbra'; import { Chain } from '@penumbra-labs/registry'; -import { currentTimePlusTwoDaysRounded } from './ibc'; +import { currentTimePlusTwoDaysRounded } from './ibc-out'; describe.skip('IBC Slice', () => { const selectionExample = new BalancesResponse({ @@ -47,15 +47,15 @@ describe.skip('IBC Slice', () => { }); test('the default is empty, false or undefined', () => { - expect(useStore.getState().ibc.amount).toBe(''); - expect(useStore.getState().ibc.selection).toBeUndefined(); - expect(useStore.getState().ibc.chain).toBeUndefined(); + expect(useStore.getState().ibcOut.amount).toBe(''); + expect(useStore.getState().ibcOut.selection).toBeUndefined(); + expect(useStore.getState().ibcOut.chain).toBeUndefined(); }); describe('setAmount', () => { test('amount can be set', () => { - useStore.getState().ibc.setAmount('2'); - expect(useStore.getState().ibc.amount).toBe('2'); + useStore.getState().ibcOut.setAmount('2'); + expect(useStore.getState().ibcOut.amount).toBe('2'); }); test('validate high enough amount validates', () => { @@ -94,8 +94,8 @@ describe.skip('IBC Slice', () => { addressPrefix: 'osmo', } satisfies Chain; - useStore.getState().ibc.setChain(chain); - expect(useStore.getState().ibc.chain).toBe(chain); + useStore.getState().ibcOut.setChain(chain); + expect(useStore.getState().ibcOut.chain).toBe(chain); }); }); diff --git a/apps/minifront/src/state/ibc.ts b/apps/minifront/src/state/ibc-out.ts similarity index 90% rename from apps/minifront/src/state/ibc.ts rename to apps/minifront/src/state/ibc-out.ts index fa003f351f..950a6421c2 100644 --- a/apps/minifront/src/state/ibc.ts +++ b/apps/minifront/src/state/ibc-out.ts @@ -22,7 +22,7 @@ import { errorToast } from '@penumbra-zone/ui/lib/toast/presets'; import { Chain } from '@penumbra-labs/registry'; import { Metadata } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/asset/v1/asset_pb'; -export interface IbcSendSlice { +export interface IbcOutSlice { selection: BalancesResponse | undefined; setSelection: (selection: BalancesResponse) => void; amount: string; @@ -35,7 +35,7 @@ export interface IbcSendSlice { txInProgress: boolean; } -export const createIbcSendSlice = (): SliceCreator<IbcSendSlice> => (set, get) => { +export const createIbcOutSlice = (): SliceCreator<IbcOutSlice> => (set, get) => { return { amount: '', selection: undefined, @@ -44,22 +44,22 @@ export const createIbcSendSlice = (): SliceCreator<IbcSendSlice> => (set, get) = txInProgress: false, setSelection: selection => { set(state => { - state.ibc.selection = selection; + state.ibcOut.selection = selection; }); }, setAmount: amount => { set(state => { - state.ibc.amount = amount; + state.ibcOut.amount = amount; }); }, setChain: chain => { set(state => { - state.ibc.chain = chain; + state.ibcOut.chain = chain; }); }, setDestinationChainAddress: addr => { set(state => { - state.ibc.destinationChainAddress = addr; + state.ibcOut.destinationChainAddress = addr; }); }, sendIbcWithdraw: async () => { @@ -68,18 +68,18 @@ export const createIbcSendSlice = (): SliceCreator<IbcSendSlice> => (set, get) = }); try { - const req = await getPlanRequest(get().ibc); + const req = await getPlanRequest(get().ibcOut); await planBuildBroadcast('ics20Withdrawal', req); // Reset form set(state => { - state.ibc.amount = ''; + state.ibcOut.amount = ''; }); } catch (e) { errorToast(e, 'Ics20 withdrawal error').render(); } finally { set(state => { - state.ibc.txInProgress = false; + state.ibcOut.txInProgress = false; }); } }, @@ -154,7 +154,7 @@ const getPlanRequest = async ({ selection, chain, destinationChainAddress, -}: IbcSendSlice): Promise<TransactionPlannerRequest> => { +}: IbcOutSlice): Promise<TransactionPlannerRequest> => { if (!destinationChainAddress) throw new Error('no destination chain address set'); if (!chain) throw new Error('Chain not set'); if (!selection) throw new Error('No asset selected'); @@ -184,16 +184,16 @@ const getPlanRequest = async ({ }); }; -export const ibcSelector = (state: AllSlices) => state.ibc; +export const ibcOutSelector = (state: AllSlices) => state.ibcOut; export const ibcValidationErrors = (state: AllSlices) => { return { - recipientErr: !state.ibc.destinationChainAddress + recipientErr: !state.ibcOut.destinationChainAddress ? false - : !validateUnknownAddress(state.ibc.chain, state.ibc.destinationChainAddress), - amountErr: !state.ibc.selection + : !validateUnknownAddress(state.ibcOut.chain, state.ibcOut.destinationChainAddress), + amountErr: !state.ibcOut.selection ? false - : amountMoreThanBalance(state.ibc.selection, state.ibc.amount), + : amountMoreThanBalance(state.ibcOut.selection, state.ibcOut.amount), }; }; diff --git a/apps/minifront/src/state/index.ts b/apps/minifront/src/state/index.ts index 695b9fe60e..a975e71358 100644 --- a/apps/minifront/src/state/index.ts +++ b/apps/minifront/src/state/index.ts @@ -2,11 +2,12 @@ import { create, StateCreator } from 'zustand'; import { enableMapSet } from 'immer'; import { immer } from 'zustand/middleware/immer'; import { createSwapSlice, SwapSlice } from './swap'; -import { createIbcSendSlice, IbcSendSlice } from './ibc'; +import { createIbcOutSlice, IbcOutSlice } from './ibc-out'; import { createSendSlice, SendSlice } from './send'; import { createStakingSlice, StakingSlice } from './staking'; import { createUnclaimedSwapsSlice, UnclaimedSwapsSlice } from './unclaimed-swaps'; import { createTransactionsSlice, TransactionsSlice } from './transactions'; +import { createIbcInSlice, IbcInSlice } from './ibc-in'; /** * Required to enable use of `Map`s in Zustand state when using Immer @@ -16,7 +17,8 @@ import { createTransactionsSlice, TransactionsSlice } from './transactions'; enableMapSet(); export interface AllSlices { - ibc: IbcSendSlice; + ibcIn: IbcInSlice; + ibcOut: IbcOutSlice; send: SendSlice; staking: StakingSlice; swap: SwapSlice; @@ -33,7 +35,8 @@ export type SliceCreator<SliceInterface> = StateCreator< export const initializeStore = () => { return immer((setState, getState: () => AllSlices, store) => ({ - ibc: createIbcSendSlice()(setState, getState, store), + ibcIn: createIbcInSlice()(setState, getState, store), + ibcOut: createIbcOutSlice()(setState, getState, store), send: createSendSlice()(setState, getState, store), staking: createStakingSlice()(setState, getState, store), swap: createSwapSlice()(setState, getState, store), diff --git a/packages/ui/components/ui/avatar.tsx b/packages/ui/components/ui/avatar.tsx new file mode 100644 index 0000000000..5b6d80ea87 --- /dev/null +++ b/packages/ui/components/ui/avatar.tsx @@ -0,0 +1,46 @@ +'use client'; + +import * as React from 'react'; +import * as AvatarPrimitive from '@radix-ui/react-avatar'; +import { cn } from '../../lib/utils'; + +const Avatar = React.forwardRef< + React.ElementRef<typeof AvatarPrimitive.Root>, + React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> +>(({ className, ...props }, ref) => ( + <AvatarPrimitive.Root + ref={ref} + className={cn('relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full', className)} + {...props} + /> +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; + +const AvatarImage = React.forwardRef< + React.ElementRef<typeof AvatarPrimitive.Image>, + React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image> +>(({ className, ...props }, ref) => ( + <AvatarPrimitive.Image + ref={ref} + className={cn('aspect-square h-full w-full', className)} + {...props} + /> +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; + +const AvatarFallback = React.forwardRef< + React.ElementRef<typeof AvatarPrimitive.Fallback>, + React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> +>(({ className, ...props }, ref) => ( + <AvatarPrimitive.Fallback + ref={ref} + className={cn( + 'flex h-full w-full items-center justify-center rounded-full bg-muted', + className, + )} + {...props} + /> +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; + +export { Avatar, AvatarImage, AvatarFallback }; diff --git a/packages/ui/components/ui/command.tsx b/packages/ui/components/ui/command.tsx new file mode 100644 index 0000000000..d5bb1c872a --- /dev/null +++ b/packages/ui/components/ui/command.tsx @@ -0,0 +1,145 @@ +'use client'; + +import * as React from 'react'; +import { type DialogProps } from '@radix-ui/react-dialog'; +import { Command as CommandPrimitive } from 'cmdk'; +import { Search } from 'lucide-react'; +import { cn } from '../../lib/utils'; +import { Dialog, DialogContent } from './dialog'; + +const Command = React.forwardRef< + React.ElementRef<typeof CommandPrimitive>, + React.ComponentPropsWithoutRef<typeof CommandPrimitive> +>(({ className, ...props }, ref) => ( + <CommandPrimitive + ref={ref} + className={cn( + 'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground', + className, + )} + {...props} + /> +)); +Command.displayName = CommandPrimitive.displayName; + +type CommandDialogProps = DialogProps; + +const CommandDialog = ({ children, ...props }: CommandDialogProps) => { + return ( + <Dialog {...props}> + <DialogContent> + <Command className='[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:size-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:size-5'> + {children} + </Command> + </DialogContent> + </Dialog> + ); +}; + +const CommandInput = React.forwardRef< + React.ElementRef<typeof CommandPrimitive.Input>, + React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input> +>(({ className, ...props }, ref) => ( + // eslint-disable-next-line react/no-unknown-property + <div className='flex items-center border-b px-3' cmdk-input-wrapper=''> + <Search className='mr-2 size-4 shrink-0 opacity-50' /> + <CommandPrimitive.Input + ref={ref} + className={cn( + 'flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', + className, + )} + {...props} + /> + </div> +)); + +CommandInput.displayName = CommandPrimitive.Input.displayName; + +const CommandList = React.forwardRef< + React.ElementRef<typeof CommandPrimitive.List>, + React.ComponentPropsWithoutRef<typeof CommandPrimitive.List> +>(({ className, ...props }, ref) => ( + <CommandPrimitive.List + ref={ref} + className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)} + {...props} + /> +)); + +CommandList.displayName = CommandPrimitive.List.displayName; + +const CommandEmpty = React.forwardRef< + React.ElementRef<typeof CommandPrimitive.Empty>, + React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty> +>((props, ref) => ( + <CommandPrimitive.Empty ref={ref} className='py-6 text-center text-sm' {...props} /> +)); + +CommandEmpty.displayName = CommandPrimitive.Empty.displayName; + +const CommandGroup = React.forwardRef< + React.ElementRef<typeof CommandPrimitive.Group>, + React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group> +>(({ className, ...props }, ref) => ( + <CommandPrimitive.Group + ref={ref} + className={cn( + 'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground', + className, + )} + {...props} + /> +)); + +CommandGroup.displayName = CommandPrimitive.Group.displayName; + +const CommandSeparator = React.forwardRef< + React.ElementRef<typeof CommandPrimitive.Separator>, + React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator> +>(({ className, ...props }, ref) => ( + <CommandPrimitive.Separator + ref={ref} + className={cn('-mx-1 h-px bg-border', className)} + {...props} + /> +)); +CommandSeparator.displayName = CommandPrimitive.Separator.displayName; + +const CommandItem = React.forwardRef< + React.ElementRef<typeof CommandPrimitive.Item>, + React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item> +>(({ className, ...props }, ref) => ( + <CommandPrimitive.Item + ref={ref} + className={cn( + 'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50', + className, + )} + {...props} + /> +)); + +CommandItem.displayName = CommandPrimitive.Item.displayName; + +const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => { + return ( + <span + className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)} + {...props} + /> + ); +}; +CommandShortcut.displayName = 'CommandShortcut'; + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +}; diff --git a/packages/ui/components/ui/popover.tsx b/packages/ui/components/ui/popover.tsx index 7941208a2e..14a71f2cd0 100644 --- a/packages/ui/components/ui/popover.tsx +++ b/packages/ui/components/ui/popover.tsx @@ -11,14 +11,14 @@ const PopoverTrigger = PopoverPrimitive.Trigger; const PopoverContent = React.forwardRef< React.ElementRef<typeof PopoverPrimitive.Content>, React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> ->(({ className, align = 'start', sideOffset = 4, ...props }, ref) => ( +>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => ( <PopoverPrimitive.Portal> <PopoverPrimitive.Content ref={ref} align={align} sideOffset={sideOffset} className={cn( - 'z-50 w-[240px] rounded-lg bg-background p-4 text-muted-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:fill-mode-forwards data-[state=open]:fill-mode-forwards', + 'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2', className, )} {...props} diff --git a/packages/ui/package.json b/packages/ui/package.json index e98f29541f..c47d95e614 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -20,6 +20,7 @@ "@penumbra-zone/getters": "workspace:*", "@penumbra-zone/perspective": "workspace:*", "@penumbra-zone/types": "workspace:*", + "@radix-ui/react-avatar": "^1.0.4", "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-dialog": "1.0.5", "@radix-ui/react-icons": "^1.3.0", @@ -37,6 +38,7 @@ "@textea/json-viewer": "^3.4.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", + "cmdk": "0.2.0", "djb2a": "^2.0.0", "framer-motion": "^11.0.22", "humanize-duration": "^3.31.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf3ed4ab55..65644311c4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -370,11 +370,14 @@ importers: '@cosmjs/stargate': specifier: ^0.32.3 version: 0.32.3 + '@cosmos-kit/core': + specifier: ^2.9.2 + version: 2.9.2 '@cosmos-kit/react': - specifier: ^2.11.0 + specifier: ^2.11.2 version: 2.11.2(@interchain-ui/react@1.23.10)(react-dom@18.3.1)(react@18.3.1) '@interchain-ui/react': - specifier: ^1.23.3 + specifier: ^1.23.10 version: 1.23.10(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) '@penumbra-labs/registry': specifier: ^5.1.0 @@ -419,10 +422,10 @@ importers: specifier: ^9.1.2 version: 9.1.2 chain-registry: - specifier: ^1.41.9 + specifier: ^1.45.5 version: 1.45.5 cosmos-kit: - specifier: ^2.10.0 + specifier: ^2.10.2 version: 2.10.2(@cosmjs/amino@0.32.3)(@cosmjs/proto-signing@0.32.3)(@terra-money/terra.js@3.1.10)(@walletconnect/types@2.11.0)(axios@0.27.2)(cosmjs-types@0.9.0)(react@18.3.1) date-fns: specifier: ^3.6.0 @@ -436,11 +439,11 @@ importers: lodash: specifier: ^4.17.21 version: 4.17.21 - match-sorter: - specifier: ^6.3.4 - version: 6.3.4 + lucide-react: + specifier: ^0.363.0 + version: 0.363.0(react@18.3.1) osmo-query: - specifier: ^16.11.0 + specifier: ^16.12.0 version: 16.12.0 react: specifier: ^18.2.0 @@ -471,8 +474,8 @@ importers: version: 4.5.2(@types/react@18.3.1)(immer@10.1.1)(react@18.3.1) devDependencies: '@chain-registry/types': - specifier: ^0.25.7 - version: 0.25.8 + specifier: ^0.28.4 + version: 0.28.4 '@penumbra-zone/polyfills': specifier: workspace:* version: link:../../packages/polyfills @@ -929,6 +932,9 @@ importers: '@penumbra-zone/types': specifier: workspace:* version: link:../types + '@radix-ui/react-avatar': + specifier: ^1.0.4 + version: 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-checkbox': specifier: ^1.0.4 version: 1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) @@ -980,6 +986,9 @@ importers: clsx: specifier: ^2.1.0 version: 2.1.1 + cmdk: + specifier: 0.2.0 + version: 0.2.0(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) djb2a: specifier: ^2.0.0 version: 2.0.0 @@ -1364,6 +1373,11 @@ packages: resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} + /@babel/helper-validator-identifier@7.24.5: + resolution: {integrity: sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-validator-option@7.23.5: resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} @@ -1406,6 +1420,14 @@ packages: '@babel/types': 7.24.0 dev: true + /@babel/parser@7.24.5: + resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.24.5 + dev: true + /@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.4(@babel/core@7.24.4): resolution: {integrity: sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA==} engines: {node: '>=6.9.0'} @@ -2394,6 +2416,12 @@ packages: dependencies: regenerator-runtime: 0.14.1 + /@babel/runtime@7.24.5: + resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + /@babel/template@7.24.0: resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} engines: {node: '>=6.9.0'} @@ -2429,6 +2457,15 @@ packages: '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 + /@babel/types@7.24.5: + resolution: {integrity: sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.1 + '@babel/helper-validator-identifier': 7.24.5 + to-fast-properties: 2.0.0 + dev: true + /@base2/pretty-print-object@1.0.1: resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==} dev: true @@ -2840,7 +2877,7 @@ packages: /@chain-registry/cosmostation@1.26.0: resolution: {integrity: sha512-MmjThpQ0U0EJF66UJzPy67iKC9hY7ljrpGtQOPfeYGB/lUlKZTsE/mgF2XkKGUf7wJK8LugOqU5Zul7C1/ZA4Q==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@chain-registry/types': 0.17.1 '@chain-registry/utils': 1.29.4 '@cosmostation/extension-client': 0.1.15 @@ -2857,7 +2894,7 @@ packages: /@chain-registry/keplr@1.28.0: resolution: {integrity: sha512-MRAEgUpafyGLRDQc4SPB+R/If4CL2SREqdbxZMKHX9aeqzKXhJlEM5IPjJTZCWTbUP/eGXC9JNjxPNUYd92PqQ==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@chain-registry/types': 0.17.1 '@keplr-wallet/cosmos': 0.12.28 '@keplr-wallet/crypto': 0.12.28 @@ -2867,22 +2904,17 @@ packages: /@chain-registry/types@0.17.0: resolution: {integrity: sha512-lavACU4oDxioUy8lZOFZN0Vrr2qR+Dg2yEh/mkrPfOldcioavREXJou0elDyyXwq4pGLC5YQ+IISCtQ4Du0bdw==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 dev: false /@chain-registry/types@0.17.1: resolution: {integrity: sha512-O0CgrtJgIlqXvZm1CqDZe/7jZz068O/uuCIoyDXCegFHK03rdHacKcDGwEIUuI0MNUf8YV3jdE4xHQMSAX+79w==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 dev: false - /@chain-registry/types@0.25.8: - resolution: {integrity: sha512-5fLZ7hwkBUsH/jfJhg7SxkTrR6cQUGiolnbYqikliEb2UlxJG+PZ2d49R/xEZg3NA7j+j4PqsdaGETwwTsIadg==} - dev: true - /@chain-registry/types@0.28.4: resolution: {integrity: sha512-nmQFud4YQfT8U3dFjWgIhNgtelvWmGvcCRbrnAaxMs24ePFYWmh+tBnGSseS8bZtYqDaYVRUMEOpl3TRjgUfbQ==} - dev: false /@chain-registry/utils@1.29.4: resolution: {integrity: sha512-Da7Qx59ELMV+g7pseg7/HAZclF3T4WZF1UR5anpJJ7WtsKfs51q3ocWYC7J6Z+U2zGg2XmWvJh+AFYydzSav1A==} @@ -2895,7 +2927,7 @@ packages: /@changesets/apply-release-plan@7.0.0: resolution: {integrity: sha512-vfi69JR416qC9hWmFGSxj7N6wA5J222XNBmezSVATPWDVPIF7gkd4d8CpbEbXmRWbVrkoli3oerGS6dcL/BGsQ==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@changesets/config': 3.0.0 '@changesets/get-version-range-type': 0.4.0 '@changesets/git': 3.0.0 @@ -2913,7 +2945,7 @@ packages: /@changesets/assemble-release-plan@6.0.0: resolution: {integrity: sha512-4QG7NuisAjisbW4hkLCmGW2lRYdPrKzro+fCtZaILX+3zdUELSvYjpL4GTv0E4aM9Mef3PuIQp89VmHJ4y2bfw==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.0.0 '@changesets/types': 6.0.0 @@ -2996,7 +3028,7 @@ packages: /@changesets/get-release-plan@4.0.0: resolution: {integrity: sha512-9L9xCUeD/Tb6L/oKmpm8nyzsOzhdNBBbt/ZNcjynbHC07WW4E1eX8NMGC5g5SbM5z/V+MOrYsJ4lRW41GCbg3w==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@changesets/assemble-release-plan': 6.0.0 '@changesets/config': 3.0.0 '@changesets/pre': 2.0.0 @@ -3012,7 +3044,7 @@ packages: /@changesets/git@3.0.0: resolution: {integrity: sha512-vvhnZDHe2eiBNRFHEgMiGd2CT+164dfYyrJDhwwxTVD/OW0FUD6G7+4DIx1dNwkwjHyzisxGAU96q0sVNBns0w==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@changesets/errors': 0.2.0 '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 @@ -3037,7 +3069,7 @@ packages: /@changesets/pre@2.0.0: resolution: {integrity: sha512-HLTNYX/A4jZxc+Sq8D1AMBsv+1qD6rmmJtjsCJa/9MSRybdxh0mjbTvE6JYZQ/ZiQ0mMlDOlGPXTm9KLTU3jyw==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@changesets/errors': 0.2.0 '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 @@ -3047,7 +3079,7 @@ packages: /@changesets/read@0.6.0: resolution: {integrity: sha512-ZypqX8+/im1Fm98K4YcZtmLKgjs1kDQ5zHpc2U1qdtNBmZZfo/IBiG162RoP0CUF05tvp2y4IspH11PLnPxuuw==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@changesets/git': 3.0.0 '@changesets/logger': 0.1.0 '@changesets/parse': 0.4.0 @@ -3068,7 +3100,7 @@ packages: /@changesets/write@0.3.0: resolution: {integrity: sha512-slGLb21fxZVUYbyea+94uFiD6ntQW0M2hIKNznFizDhZPDgn2c/fv1UzzlW43RVzh1BEDuIqW6hzlJ1OflNmcw==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@changesets/types': 6.0.0 fs-extra: 7.0.1 human-id: 1.0.2 @@ -4645,7 +4677,7 @@ packages: resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==} dependencies: '@babel/helper-module-imports': 7.24.3 - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@emotion/hash': 0.9.1 '@emotion/memoize': 0.8.1 '@emotion/serialize': 1.1.4 @@ -5956,7 +5988,7 @@ packages: /@manypkg/find-root@1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 @@ -5965,7 +5997,7 @@ packages: /@manypkg/get-packages@1.1.3: resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 @@ -6074,7 +6106,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@floating-ui/react-dom': 2.0.9(react-dom@18.3.1)(react@18.3.1) '@mui/types': 7.2.14(@types/react@18.3.1) '@mui/utils': 5.15.14(@types/react@18.3.1)(react@18.3.1) @@ -6136,7 +6168,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@mui/utils': 5.15.14(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 prop-types: 15.8.1 @@ -6156,7 +6188,7 @@ packages: '@emotion/styled': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@emotion/cache': 11.11.0 '@emotion/react': 11.11.4(@types/react@18.3.1)(react@18.3.1) '@emotion/styled': 11.11.5(@emotion/react@11.11.4)(@types/react@18.3.1)(react@18.3.1) @@ -6181,7 +6213,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@emotion/react': 11.11.4(@types/react@18.3.1)(react@18.3.1) '@emotion/styled': 11.11.5(@emotion/react@11.11.4)(@types/react@18.3.1)(react@18.3.1) '@mui/private-theming': 5.15.14(@types/react@18.3.1)(react@18.3.1) @@ -6216,7 +6248,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@types/prop-types': 15.7.12 '@types/react': 18.3.1 prop-types: 15.8.1 @@ -6505,13 +6537,19 @@ packages: /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 + dev: false + + /@radix-ui/primitive@1.0.0: + resolution: {integrity: sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==} + dependencies: + '@babel/runtime': 7.24.5 dev: false /@radix-ui/primitive@1.0.1: resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 dev: false /@radix-ui/react-arrow@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): @@ -6527,8 +6565,32 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.1 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-avatar@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-kVK2K7ZD3wwj3qhle0ElXhOjbezIgyl2hVvgwfIdexL3rN6zJmy5AqqIf+D31lxVppdzV8CjAfZ6PklkmInZLw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.5 + '@radix-ui/react-context': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.1)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 '@types/react-dom': 18.3.0 react: 18.3.1 @@ -6576,7 +6638,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@radix-ui/react-context': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) @@ -6587,6 +6649,15 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-compose-refs@1.0.0(react@18.3.1): + resolution: {integrity: sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + react: 18.3.1 + dev: false + /@radix-ui/react-compose-refs@1.0.1(@types/react@18.3.1)(react@18.3.1): resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: @@ -6596,10 +6667,19 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 + /@radix-ui/react-context@1.0.0(react@18.3.1): + resolution: {integrity: sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + react: 18.3.1 + dev: false + /@radix-ui/react-context@1.0.1(@types/react@18.3.1)(react@18.3.1): resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} peerDependencies: @@ -6609,11 +6689,38 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 dev: false + /@radix-ui/react-dialog@1.0.0(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-Yn9YU+QlHYLWwV1XfKiqnGVpWYWk6MeBVM6x/bcoyPvxgjQGoeT35482viLPctTMWoMw0PoHgqfSox7Ig+957Q==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + '@radix-ui/primitive': 1.0.0 + '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) + '@radix-ui/react-context': 1.0.0(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.0.0(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-focus-guards': 1.0.0(react@18.3.1) + '@radix-ui/react-focus-scope': 1.0.0(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.0.0(react@18.3.1) + '@radix-ui/react-portal': 1.0.0(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.0.0(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.0(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.0.0(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.0(react@18.3.1) + aria-hidden: 1.2.4 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.5.4(@types/react@18.3.1)(react@18.3.1) + transitivePeerDependencies: + - '@types/react' + dev: false + /@radix-ui/react-dialog@1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==} peerDependencies: @@ -6657,11 +6764,27 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 dev: false + /@radix-ui/react-dismissable-layer@1.0.0(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-n7kDRfx+LB1zLueRDvZ1Pd0bxdJWDUZNQ/GWoxDn2prnuJKRdxsjulejX/ePkOsLi2tTm6P24mDqlMSgQpsT6g==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + '@radix-ui/primitive': 1.0.0 + '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) + '@radix-ui/react-primitive': 1.0.0(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.0.0(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==} peerDependencies: @@ -6675,7 +6798,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) @@ -6687,6 +6810,15 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-focus-guards@1.0.0(react@18.3.1): + resolution: {integrity: sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + react: 18.3.1 + dev: false + /@radix-ui/react-focus-guards@1.0.1(@types/react@18.3.1)(react@18.3.1): resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} peerDependencies: @@ -6696,11 +6828,25 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 dev: false + /@radix-ui/react-focus-scope@1.0.0(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-C4SWtsULLGf/2L4oGeIHlvWQx7Rf+7cX/vKOAD2dXW0A1b5QXwi3wWeaEgW+wn+SEVrraMUk05vLU9fZZz5HbQ==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) + '@radix-ui/react-primitive': 1.0.0(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==} peerDependencies: @@ -6714,7 +6860,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.1)(react@18.3.1) @@ -6731,6 +6877,16 @@ packages: dependencies: react: 18.3.1 + /@radix-ui/react-id@1.0.0(react@18.3.1): + resolution: {integrity: sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + '@radix-ui/react-use-layout-effect': 1.0.0(react@18.3.1) + react: 18.3.1 + dev: false + /@radix-ui/react-id@1.0.1(@types/react@18.3.1)(react@18.3.1): resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} peerDependencies: @@ -6740,7 +6896,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 react: 18.3.1 @@ -6828,7 +6984,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@floating-ui/react-dom': 2.0.9(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) @@ -6845,6 +7001,18 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-portal@1.0.0(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-a8qyFO/Xb99d8wQdu4o7qnigNjTPG123uADNecz0eX4usnQEj7o+cG4ZX4zkqq98NYekT7UoEQIjxBNWIFuqTA==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + '@radix-ui/react-primitive': 1.0.0(react-dom@18.3.1)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /@radix-ui/react-portal@1.0.4(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==} peerDependencies: @@ -6858,7 +7026,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) '@types/react': 18.3.1 '@types/react-dom': 18.3.0 @@ -6866,6 +7034,19 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-presence@1.0.0(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.0.0(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /@radix-ui/react-presence@1.0.1(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} peerDependencies: @@ -6879,7 +7060,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 @@ -6888,6 +7069,18 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-primitive@1.0.0(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-EyXe6mnRlHZ8b6f4ilTDrXmkLShICIuOTTj0GX4w1rp+wSxf3+TD05u1UOITC8VsJ2a9nwHvdXtOXEOl0Cw/zQ==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + '@radix-ui/react-slot': 1.0.0(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: @@ -6901,7 +7094,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/react-slot': 1.0.2(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 '@types/react-dom': 18.3.0 @@ -6944,7 +7137,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.3.1)(react@18.3.1) @@ -7001,6 +7194,16 @@ packages: react-remove-scroll: 2.5.5(@types/react@18.3.1)(react@18.3.1) dev: false + /@radix-ui/react-slot@1.0.0(react@18.3.1): + resolution: {integrity: sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + '@radix-ui/react-compose-refs': 1.0.0(react@18.3.1) + react: 18.3.1 + dev: false + /@radix-ui/react-slot@1.0.2(@types/react@18.3.1)(react@18.3.1): resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} peerDependencies: @@ -7157,6 +7360,15 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-use-callback-ref@1.0.0(react@18.3.1): + resolution: {integrity: sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + react: 18.3.1 + dev: false + /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.3.1)(react@18.3.1): resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} peerDependencies: @@ -7166,11 +7378,21 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 dev: false + /@radix-ui/react-use-controllable-state@1.0.0(react@18.3.1): + resolution: {integrity: sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1) + react: 18.3.1 + dev: false + /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.3.1)(react@18.3.1): resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} peerDependencies: @@ -7180,12 +7402,22 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 react: 18.3.1 dev: false + /@radix-ui/react-use-escape-keydown@1.0.0(react@18.3.1): + resolution: {integrity: sha512-JwfBCUIfhXRxKExgIqGa4CQsiMemo1Xt0W/B4ei3fpzpvPENKpMKQ8mZSB6Acj3ebrAEgi2xiQvcI1PAAodvyg==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + '@radix-ui/react-use-callback-ref': 1.0.0(react@18.3.1) + react: 18.3.1 + dev: false + /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.3.1)(react@18.3.1): resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} peerDependencies: @@ -7195,12 +7427,21 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 react: 18.3.1 dev: false + /@radix-ui/react-use-layout-effect@1.0.0(react@18.3.1): + resolution: {integrity: sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.5 + react: 18.3.1 + dev: false + /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.3.1)(react@18.3.1): resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} peerDependencies: @@ -7210,7 +7451,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 dev: false @@ -7224,7 +7465,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@types/react': 18.3.1 react: 18.3.1 dev: false @@ -7238,7 +7479,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/rect': 1.0.1 '@types/react': 18.3.1 react: 18.3.1 @@ -7253,7 +7494,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.3.1)(react@18.3.1) '@types/react': 18.3.1 react: 18.3.1 @@ -7272,7 +7513,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.3.0)(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) '@types/react': 18.3.1 '@types/react-dom': 18.3.0 @@ -7283,7 +7524,7 @@ packages: /@radix-ui/rect@1.0.1: resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 dev: false /@react-aria/breadcrumbs@3.5.11(react@18.3.1): @@ -10049,7 +10290,7 @@ packages: engines: {node: '>=14'} dependencies: '@babel/code-frame': 7.24.2 - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@types/aria-query': 5.0.4 aria-query: 5.1.3 chalk: 4.1.2 @@ -10080,7 +10321,7 @@ packages: optional: true dependencies: '@adobe/css-tools': 4.3.3 - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 aria-query: 5.3.0 chalk: 3.0.0 css.escape: 1.5.1 @@ -10096,7 +10337,7 @@ packages: react: ^18.0.0 react-dom: ^18.0.0 dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 '@testing-library/dom': 9.3.4 '@types/react-dom': 18.3.0 react: 18.3.1 @@ -12005,7 +12246,7 @@ packages: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 cosmiconfig: 7.1.0 resolve: 1.22.8 dev: false @@ -12320,7 +12561,7 @@ packages: hasBin: true dependencies: caniuse-lite: 1.0.30001614 - electron-to-chromium: 1.4.750 + electron-to-chromium: 1.4.751 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.23.0) dev: true @@ -12755,6 +12996,20 @@ packages: engines: {node: '>=6'} dev: false + /cmdk@0.2.0(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-JQpKvEOb86SnvMZbYaFKYhvzFntWBeSZdyii0rZPhKJj9uwJBxu4DaVYDrRN7r3mPop56oPhRw+JYWTKs66TYw==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + dependencies: + '@radix-ui/react-dialog': 1.0.0(@types/react@18.3.1)(react-dom@18.3.1)(react@18.3.1) + command-score: 0.1.2 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - '@types/react' + dev: false + /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: @@ -12813,6 +13068,10 @@ packages: dependencies: delayed-stream: 1.0.0 + /command-score@0.1.2: + resolution: {integrity: sha512-VtDvQpIJBvBatnONUsPzXYFVKQQAhuf3XTNOAsdBxCNO/QCtUUd8LSgjn0GVarBkCad6aJCZfXgrjYbl/KRr7w==} + dev: false + /commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} @@ -13754,7 +14013,7 @@ packages: /dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 csstype: 3.1.3 dev: false @@ -13867,8 +14126,8 @@ packages: jake: 10.8.7 dev: true - /electron-to-chromium@1.4.750: - resolution: {integrity: sha512-9ItEpeu15hW5m8jKdriL+BQrgwDTXEL9pn4SkillWFu73ZNNNQ2BKKLS+ZHv2vC9UkNhosAeyfxOf/5OSeTCPA==} + /electron-to-chromium@1.4.751: + resolution: {integrity: sha512-2DEPi++qa89SMGRhufWTiLmzqyuGmNF3SK4+PQetW1JKiZdEpF4XQonJXJCzyuYSA6mauiMhbyVhqYAP45Hvfw==} dev: true /elliptic@6.5.4: @@ -16793,7 +17052,7 @@ packages: engines: {node: '>=12.0.0'} hasBin: true dependencies: - '@babel/parser': 7.24.4 + '@babel/parser': 7.24.5 '@jsdoc/salty': 0.2.8 '@types/markdown-it': 12.2.3 bluebird: 3.7.2 @@ -17528,13 +17787,6 @@ packages: hasBin: true dev: true - /match-sorter@6.3.4: - resolution: {integrity: sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==} - dependencies: - '@babel/runtime': 7.24.4 - remove-accents: 0.5.0 - dev: false - /md5.js@1.3.5: resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} dependencies: @@ -17549,7 +17801,7 @@ packages: /media-query-parser@2.0.2: resolution: {integrity: sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 dev: false /media-typer@0.3.0: @@ -18746,7 +18998,7 @@ packages: resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==} engines: {node: '>=10'} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 dev: true /portfinder@1.0.32: @@ -19526,6 +19778,25 @@ packages: tslib: 2.6.2 dev: false + /react-remove-scroll@2.5.4(@types/react@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.1 + react: 18.3.1 + react-remove-scroll-bar: 2.3.6(@types/react@18.3.1)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.3.1)(react@18.3.1) + tslib: 2.6.2 + use-callback-ref: 1.3.2(@types/react@18.3.1)(react@18.3.1) + use-sidecar: 1.1.2(@types/react@18.3.1)(react@18.3.1) + dev: false + /react-remove-scroll@2.5.5(@types/react@18.3.1)(react@18.3.1): resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} engines: {node: '>=10'} @@ -19630,7 +19901,7 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 dom-helpers: 5.2.1 loose-envify: 1.4.0 prop-types: 15.8.1 @@ -19798,7 +20069,7 @@ packages: /regenerator-transform@0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} dependencies: - '@babel/runtime': 7.24.4 + '@babel/runtime': 7.24.5 dev: true /regexp.prototype.flags@1.5.2: @@ -19884,10 +20155,6 @@ packages: engines: {node: '>= 0.10'} dev: true - /remove-accents@0.5.0: - resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==} - dev: false - /renderkid@3.0.0: resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==} dependencies: