@rainlanguage/ui-components 0.0.1-alpha.61 → 0.0.1-alpha.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,6 @@
1
1
  import type { ConfigSource } from '@rainlanguage/orderbook';
2
2
  import { type Config } from '@wagmi/core';
3
3
  import type { Page } from '@sveltejs/kit';
4
- export declare const mockWalletAddressMatchesOrBlankStore: {
5
- subscribe: (this: void, run: import("svelte/store").Subscriber<() => boolean>, invalidate?: import("svelte/store").Invalidator<() => boolean> | undefined) => import("svelte/store").Unsubscriber;
6
- set: (this: void, value: () => boolean) => void;
7
- mockSetSubscribeValue: (value: () => boolean) => void;
8
- };
9
4
  export declare const mockSettingsStore: {
10
5
  subscribe: (this: void, run: import("svelte/store").Subscriber<ConfigSource | undefined>, invalidate?: import("svelte/store").Invalidator<ConfigSource | undefined> | undefined) => import("svelte/store").Unsubscriber;
11
6
  set: (this: void, value: ConfigSource | undefined) => void;
@@ -13,17 +13,11 @@ const mockActiveNetworkRefWritable = writable('');
13
13
  const mockActiveOrderbookRefWritable = writable('');
14
14
  const mockActiveAccountsWritable = writable({});
15
15
  const mockSubgraphUrlWritable = writable('');
16
- const mockWalletAddressMatchesOrBlankWritable = writable(() => false);
17
16
  const mockChainIdWritable = writable(0);
18
17
  const mockConnectedWritable = writable(true);
19
18
  const mockWagmiConfigWritable = writable(mockWeb3Config);
20
19
  const mockShowMyItemsOnlyWritable = writable(false);
21
20
  const mockPageWritable = writable();
22
- export const mockWalletAddressMatchesOrBlankStore = {
23
- subscribe: mockWalletAddressMatchesOrBlankWritable.subscribe,
24
- set: mockWalletAddressMatchesOrBlankWritable.set,
25
- mockSetSubscribeValue: (value) => mockWalletAddressMatchesOrBlankWritable.set(value)
26
- };
27
21
  export const mockSettingsStore = {
28
22
  subscribe: mockSettingsWritable.subscribe,
29
23
  set: mockSettingsWritable.set,
@@ -1,4 +1,4 @@
1
- <script generics="T">import { invalidateIdQuery } from "../queries/queryClient";
1
+ <script generics="T">import { invalidateTanstackQueries } from "../queries/queryClient";
2
2
  import Refresh from "./icon/Refresh.svelte";
3
3
  import { Button, Table, TableBody, TableBodyRow, TableHead } from "flowbite-svelte";
4
4
  import { createEventDispatcher } from "svelte";
@@ -21,9 +21,8 @@ export let rowHoverable = true;
21
21
  spin={$query.isLoading || $query.isFetching}
22
22
  on:click={async () => {
23
23
  if (queryKey) {
24
- await invalidateIdQuery(queryClient, queryKey);
24
+ invalidateTanstackQueries(queryClient, [queryKey]);
25
25
  }
26
- $query.refetch();
27
26
  }}
28
27
  />
29
28
  </div>
@@ -2,7 +2,7 @@ import { SvelteComponent } from "svelte";
2
2
  import type { CreateInfiniteQueryResult, InfiniteData } from '@tanstack/svelte-query';
3
3
  declare class __sveltets_Render<T> {
4
4
  props(): {
5
- queryKey: string | undefined;
5
+ queryKey: string;
6
6
  query: CreateInfiniteQueryResult<InfiniteData<T[], unknown>, Error>;
7
7
  emptyMessage?: string;
8
8
  rowHoverable?: boolean;
@@ -10,19 +10,18 @@ import ButtonVaultLink from "../ButtonVaultLink.svelte";
10
10
  import OrderVaultsVolTable from "../tables/OrderVaultsVolTable.svelte";
11
11
  import { QKEY_ORDER } from "../../queries/keys";
12
12
  import CodeMirrorRainlang from "../CodeMirrorRainlang.svelte";
13
- import {
14
- getOrderByHash
15
- } from "@rainlanguage/orderbook";
16
13
  import { createQuery, useQueryClient } from "@tanstack/svelte-query";
17
14
  import { Button, TabItem, Tabs, Tooltip } from "flowbite-svelte";
18
15
  import { onDestroy } from "svelte";
19
16
  import OrderApy from "../tables/OrderAPY.svelte";
20
17
  import { page } from "$app/stores";
21
18
  import Refresh from "../icon/Refresh.svelte";
22
- import { invalidateIdQuery } from "../../queries/queryClient";
19
+ import { invalidateTanstackQueries } from "../../queries/queryClient";
23
20
  import { ArrowDownOutline, ArrowUpOutline, InfoCircleOutline } from "flowbite-svelte-icons";
24
21
  import { useAccount } from "../../providers/wallet/useAccount";
25
- import { isAddressEqual, isAddress } from "viem";
22
+ import {
23
+ getOrderByHash
24
+ } from "@rainlanguage/orderbook";
26
25
  export let handleQuoteDebugModal = void 0;
27
26
  export const handleDebugTradeModal = void 0;
28
27
  export let colorTheme;
@@ -32,14 +31,13 @@ export let orderbookAddress;
32
31
  export let orderHash;
33
32
  export let rpcUrl;
34
33
  export let subgraphUrl;
35
- export let chainId;
36
34
  export let onRemove;
37
35
  export let onDeposit;
38
36
  export let onWithdraw;
39
37
  let codeMirrorDisabled = true;
40
38
  let codeMirrorStyles = {};
41
39
  const queryClient = useQueryClient();
42
- const { account } = useAccount();
40
+ const { matchesAccount } = useAccount();
43
41
  $: orderDetailQuery = createQuery({
44
42
  queryKey: [orderHash, QKEY_ORDER + orderHash],
45
43
  queryFn: () => {
@@ -48,7 +46,7 @@ $: orderDetailQuery = createQuery({
48
46
  enabled: !!subgraphUrl
49
47
  });
50
48
  const interval = setInterval(async () => {
51
- await invalidateIdQuery(queryClient, orderHash);
49
+ await invalidateTanstackQueries(queryClient, [orderHash]);
52
50
  }, 1e4);
53
51
  onDestroy(() => {
54
52
  clearInterval(interval);
@@ -70,7 +68,7 @@ $: subgraphName = $page.url.pathname.split("/")[2]?.split("-")[0];
70
68
  </div>
71
69
 
72
70
  <div class="flex items-center gap-2">
73
- {#if $account && isAddress($account) && isAddress(data.order.owner) && isAddressEqual($account, data.order.owner)}
71
+ {#if matchesAccount(data.order.owner)}
74
72
  {#if data.order.active}
75
73
  <Button
76
74
  on:click={() => onRemove(data.order)}
@@ -82,7 +80,7 @@ $: subgraphName = $page.url.pathname.split("/")[2]?.split("-")[0];
82
80
 
83
81
  <Refresh
84
82
  testId="top-refresh"
85
- on:click={async () => await invalidateIdQuery(queryClient, orderHash)}
83
+ on:click={() => invalidateTanstackQueries(queryClient, [orderHash])}
86
84
  spin={$orderDetailQuery.isLoading || $orderDetailQuery.isFetching}
87
85
  />
88
86
  </div>
@@ -128,7 +126,7 @@ $: subgraphName = $page.url.pathname.split("/")[2]?.split("-")[0];
128
126
  {#each data.vaults.get(type) || [] as vault}
129
127
  <ButtonVaultLink tokenVault={vault} {subgraphName}>
130
128
  <svelte:fragment slot="buttons">
131
- {#if $account && isAddress($account) && isAddress(vault.owner) && isAddressEqual($account, vault.owner) && chainId}
129
+ {#if matchesAccount(vault.owner)}
132
130
  <div class="flex gap-1">
133
131
  <Button
134
132
  color="light"
@@ -1,8 +1,7 @@
1
1
  import { SvelteComponent } from "svelte";
2
- import { type SgOrder } from '@rainlanguage/orderbook';
3
2
  import type { Hex } from 'viem';
4
3
  import type { QuoteDebugModalHandler, DebugTradeModalHandler } from '../../types/modal';
5
- import type { SgVault } from '@rainlanguage/orderbook';
4
+ import { type SgOrder, type SgVault } from '@rainlanguage/orderbook';
6
5
  declare const __propDef: {
7
6
  props: {
8
7
  handleQuoteDebugModal?: QuoteDebugModalHandler | undefined;
@@ -14,7 +13,6 @@ declare const __propDef: {
14
13
  orderHash: string;
15
14
  rpcUrl: string;
16
15
  subgraphUrl: string;
17
- chainId: number | undefined;
18
16
  /** Callback function when remove action is triggered for an order
19
17
  * @param order The order to remove
20
18
  */ onRemove: (order: SgOrder) => void;
@@ -1,4 +1,4 @@
1
- <script generics="T">import { invalidateIdQuery } from "../../queries/queryClient";
1
+ <script generics="T">import { invalidateTanstackQueries } from "../../queries/queryClient";
2
2
  import Refresh from "../icon/Refresh.svelte";
3
3
  import EditableSpan from "../EditableSpan.svelte";
4
4
  import { getOrderQuote } from "@rainlanguage/orderbook";
@@ -23,7 +23,7 @@ export let handleQuoteDebugModal = void 0;
23
23
  let enabled = true;
24
24
  const queryClient = useQueryClient();
25
25
  const refreshQuotes = async () => {
26
- await invalidateIdQuery(queryClient, id);
26
+ invalidateTanstackQueries(queryClient, [id, QKEY_ORDER_QUOTE + id]);
27
27
  };
28
28
  $: orderQuoteQuery = createQuery({
29
29
  queryKey: [id, QKEY_ORDER_QUOTE + id],
@@ -6,13 +6,13 @@ import TanstackPageContentDetail from "./TanstackPageContentDetail.svelte";
6
6
  import CardProperty from "../CardProperty.svelte";
7
7
  import { QKEY_VAULT } from "../../queries/keys";
8
8
  import { getVault } from "@rainlanguage/orderbook";
9
- import { formatUnits, isAddress, isAddressEqual } from "viem";
9
+ import { formatUnits } from "viem";
10
10
  import { createQuery } from "@tanstack/svelte-query";
11
11
  import { onDestroy } from "svelte";
12
12
  import { useQueryClient } from "@tanstack/svelte-query";
13
13
  import OrderOrVaultHash from "../OrderOrVaultHash.svelte";
14
14
  import Refresh from "../icon/Refresh.svelte";
15
- import { invalidateIdQuery } from "../../queries/queryClient";
15
+ import { invalidateTanstackQueries } from "../../queries/queryClient";
16
16
  import { useAccount } from "../../providers/wallet/useAccount";
17
17
  import { Button } from "flowbite-svelte";
18
18
  import { ArrowDownOutline, ArrowUpOutline } from "flowbite-svelte-icons";
@@ -26,7 +26,7 @@ export let onDeposit;
26
26
  export let onWithdraw;
27
27
  const subgraphUrl = $settings?.subgraphs?.[network] || "";
28
28
  const queryClient = useQueryClient();
29
- const { account } = useAccount();
29
+ const { matchesAccount } = useAccount();
30
30
  $: vaultDetailQuery = createQuery({
31
31
  queryKey: [id, QKEY_VAULT + id],
32
32
  queryFn: () => {
@@ -39,11 +39,7 @@ const updateActiveNetworkAndOrderbook = (subgraphName) => {
39
39
  activeOrderbookRef.set(subgraphName);
40
40
  };
41
41
  const interval = setInterval(async () => {
42
- await queryClient.invalidateQueries({
43
- queryKey: [id],
44
- refetchType: "active",
45
- exact: false
46
- });
42
+ invalidateTanstackQueries(queryClient, [id, QKEY_VAULT + id]);
47
43
  }, 5e3);
48
44
  onDestroy(() => {
49
45
  clearInterval(interval);
@@ -59,7 +55,7 @@ onDestroy(() => {
59
55
  {data.token.name}
60
56
  </div>
61
57
  <div class="flex items-center gap-2">
62
- {#if $account && isAddress($account) && isAddress(data.owner) && isAddressEqual($account, data.owner)}
58
+ {#if matchesAccount(data.owner)}
63
59
  <Button
64
60
  color="light"
65
61
  size="xs"
@@ -81,7 +77,8 @@ onDestroy(() => {
81
77
  {/if}
82
78
 
83
79
  <Refresh
84
- on:click={async () => await invalidateIdQuery(queryClient, id)}
80
+ testId="top-refresh"
81
+ on:click={() => invalidateTanstackQueries(queryClient, [id, QKEY_VAULT + id])}
85
82
  spin={$vaultDetailQuery.isLoading || $vaultDetailQuery.isFetching}
86
83
  />
87
84
  </div>
@@ -1,8 +1,9 @@
1
1
  <script generics="T">import { goto } from "$app/navigation";
2
2
  import { DotsVerticalOutline } from "flowbite-svelte-icons";
3
- import {} from "@rainlanguage/orderbook";
4
3
  import { createInfiniteQuery } from "@tanstack/svelte-query";
5
- import { getOrders } from "@rainlanguage/orderbook";
4
+ import {
5
+ getOrders
6
+ } from "@rainlanguage/orderbook";
6
7
  import TanstackAppTable from "../TanstackAppTable.svelte";
7
8
  import { formatTimestampSecondsAsLocal } from "../../utils/time";
8
9
  import ListViewOrderbookFilters from "../ListViewOrderbookFilters.svelte";
@@ -18,8 +19,7 @@ import {
18
19
  TableHeadCell
19
20
  } from "flowbite-svelte";
20
21
  import { useAccount } from "../../providers/wallet/useAccount";
21
- export const walletAddressMatchesOrBlank = void 0;
22
- export const handleOrderRemoveModal = void 0;
22
+ export let handleOrderRemoveModal = void 0;
23
23
  export let activeSubgraphs;
24
24
  export let settings;
25
25
  export let accounts;
@@ -31,7 +31,7 @@ export let showMyItemsOnly;
31
31
  export let currentRoute;
32
32
  export let activeNetworkRef;
33
33
  export let activeOrderbookRef;
34
- const { account } = useAccount();
34
+ const { matchesAccount, account } = useAccount();
35
35
  $: multiSubgraphArgs = Object.entries(
36
36
  Object.keys($activeSubgraphs ?? {}).length ? $activeSubgraphs : $settings?.subgraphs ?? {}
37
37
  ).map(([name, url]) => ({
@@ -87,7 +87,7 @@ $: isOrdersPage = currentRoute.startsWith("/orders");
87
87
 
88
88
  <AppTable
89
89
  {query}
90
- queryKey={undefined}
90
+ queryKey={QKEY_ORDERS}
91
91
  emptyMessage="No Orders Found"
92
92
  on:clickRow={(e) => {
93
93
  activeNetworkRef.set(e.detail.item.subgraphName);
@@ -150,10 +150,10 @@ $: isOrdersPage = currentRoute.startsWith("/orders");
150
150
  <TableBodyCell data-testid="orderListRowTrades" tdClass="break-word p-2"
151
151
  >{item.order.trades.length > 99 ? '>99' : item.order.trades.length}</TableBodyCell
152
152
  >
153
- {#if walletAddressMatchesOrBlank && handleOrderRemoveModal}
153
+ {#if matchesAccount(item.order.owner) && handleOrderRemoveModal}
154
154
  <div data-testid="wallet-actions">
155
155
  <TableBodyCell tdClass="px-0 text-right">
156
- {#if $walletAddressMatchesOrBlank(item.order.owner) && item.order.active}
156
+ {#if item.order.active}
157
157
  <Button
158
158
  color="alternative"
159
159
  outline={false}
@@ -168,7 +168,7 @@ $: isOrdersPage = currentRoute.startsWith("/orders");
168
168
  </Button>
169
169
  {/if}
170
170
  </TableBodyCell>
171
- {#if $walletAddressMatchesOrBlank(item.order.owner) && item.order.active}
171
+ {#if item.order.active}
172
172
  <Dropdown placement="bottom-end" triggeredBy={`#order-menu-${item.order.id}`}>
173
173
  <DropdownItem
174
174
  on:click={(e) => {
@@ -2,7 +2,6 @@ import { SvelteComponent } from "svelte";
2
2
  import type { AppStoresInterface } from '../../types/appStores';
3
3
  declare class __sveltets_Render<T> {
4
4
  props(): {
5
- walletAddressMatchesOrBlank?: any;
6
5
  handleOrderRemoveModal?: any;
7
6
  activeSubgraphs: AppStoresInterface["activeSubgraphs"];
8
7
  settings: AppStoresInterface["settings"];
@@ -27,7 +26,5 @@ export type OrdersListTableProps<T> = ReturnType<__sveltets_Render<T>['props']>;
27
26
  export type OrdersListTableEvents<T> = ReturnType<__sveltets_Render<T>['events']>;
28
27
  export type OrdersListTableSlots<T> = ReturnType<__sveltets_Render<T>['slots']>;
29
28
  export default class OrdersListTable<T> extends SvelteComponent<OrdersListTableProps<T>, OrdersListTableEvents<T>, OrdersListTableSlots<T>> {
30
- get walletAddressMatchesOrBlank(): any;
31
- get handleOrderRemoveModal(): any;
32
29
  }
33
30
  export {};
@@ -30,7 +30,7 @@ const AppTable = TanstackAppTable;
30
30
 
31
31
  <AppTable
32
32
  query={balanceChangesQuery}
33
- queryKey={undefined}
33
+ queryKey={id}
34
34
  emptyMessage="No deposits or withdrawals found"
35
35
  rowHoverable={false}
36
36
  >
@@ -29,13 +29,12 @@ export let hideZeroBalanceVaults;
29
29
  export let activeNetworkRef;
30
30
  export let activeOrderbookRef;
31
31
  export let activeAccounts;
32
- export let walletAddressMatchesOrBlank;
33
32
  export let handleDepositGenericModal = void 0;
34
33
  export let handleDepositModal = void 0;
35
34
  export let handleWithdrawModal = void 0;
36
35
  export let currentRoute;
37
36
  export let showMyItemsOnly;
38
- const { account } = useAccount();
37
+ const { account, matchesAccount } = useAccount();
39
38
  $: multiSubgraphArgs = Object.entries(
40
39
  Object.keys($activeSubgraphs ?? {}).length ? $activeSubgraphs : $settings?.subgraphs ?? {}
41
40
  ).map(([name, url]) => ({
@@ -94,7 +93,7 @@ const AppTable = TanstackAppTable;
94
93
  />
95
94
  <AppTable
96
95
  {query}
97
- queryKey={undefined}
96
+ queryKey={QKEY_VAULTS}
98
97
  emptyMessage="No Vaults Found"
99
98
  on:clickRow={(e) => {
100
99
  updateActiveNetworkAndOrderbook(e.detail.item.subgraphName);
@@ -182,47 +181,44 @@ const AppTable = TanstackAppTable;
182
181
  </div>
183
182
  {/if}
184
183
  </TableBodyCell>
185
- {#if handleDepositModal && handleWithdrawModal && $walletAddressMatchesOrBlank(item.vault.owner)}
184
+ {#if handleDepositModal && handleWithdrawModal && matchesAccount(item.vault.owner)}
186
185
  <TableBodyCell tdClass="px-0 text-right">
187
- {#if $walletAddressMatchesOrBlank(item.vault.owner)}
188
- <Button
189
- color="alternative"
190
- outline={false}
191
- data-testid="vault-menu"
192
- id={`vault-menu-${item.vault.id}`}
193
- class="mr-2 border-none px-2"
194
- on:click={(e) => {
195
- e.stopPropagation();
196
- }}
197
- >
198
- <DotsVerticalOutline class="dark:text-white" />
199
- </Button>
200
- {/if}
201
- </TableBodyCell>
202
- {#if $walletAddressMatchesOrBlank(item.vault.owner)}
203
- <Dropdown
204
- data-testid="dropdown"
205
- placement="bottom-end"
206
- triggeredBy={`#vault-menu-${item.vault.id}`}
186
+ <Button
187
+ color="alternative"
188
+ outline={false}
189
+ data-testid="vault-menu"
190
+ id={`vault-menu-${item.vault.id}`}
191
+ class="mr-2 border-none px-2"
192
+ on:click={(e) => {
193
+ e.stopPropagation();
194
+ }}
207
195
  >
208
- <DropdownItem
209
- data-testid="deposit-button"
210
- on:click={(e) => {
211
- e.stopPropagation();
212
- handleDepositModal(item.vault, $query.refetch);
213
- }}
214
- >Deposit
215
- </DropdownItem>
216
- <DropdownItem
217
- data-testid="withdraw-button"
218
- on:click={(e) => {
219
- e.stopPropagation();
220
- handleWithdrawModal(item.vault, $query.refetch);
221
- }}
222
- >Withdraw
223
- </DropdownItem>
224
- </Dropdown>
225
- {/if}
196
+ <DotsVerticalOutline class="dark:text-white" />
197
+ </Button>
198
+ </TableBodyCell>
199
+
200
+ <Dropdown
201
+ data-testid="dropdown"
202
+ placement="bottom-end"
203
+ triggeredBy={`#vault-menu-${item.vault.id}`}
204
+ >
205
+ <DropdownItem
206
+ data-testid="deposit-button"
207
+ on:click={(e) => {
208
+ e.stopPropagation();
209
+ handleDepositModal(item.vault, $query.refetch);
210
+ }}
211
+ >Deposit
212
+ </DropdownItem>
213
+ <DropdownItem
214
+ data-testid="withdraw-button"
215
+ on:click={(e) => {
216
+ e.stopPropagation();
217
+ handleWithdrawModal(item.vault, $query.refetch);
218
+ }}
219
+ >Withdraw
220
+ </DropdownItem>
221
+ </Dropdown>
226
222
  {/if}
227
223
  </svelte:fragment>
228
224
  </AppTable>
@@ -19,7 +19,6 @@ declare class __sveltets_Render<T> {
19
19
  activeAccounts: Readable<{
20
20
  [k: string]: string;
21
21
  }>;
22
- walletAddressMatchesOrBlank: Readable<(otherAddress: string) => boolean>;
23
22
  handleDepositGenericModal?: (() => void) | undefined;
24
23
  handleDepositModal?: ((vault: SgVault, refetch: () => void) => void) | undefined;
25
24
  handleWithdrawModal?: ((vault: SgVault, refetch: () => void) => void) | undefined;
package/dist/index.d.ts CHANGED
@@ -76,6 +76,7 @@ export { bigintStringToHex, HEX_INPUT_REGEX } from './utils/hex';
76
76
  export { vaultBalanceDisplay } from './utils/vault';
77
77
  export { bigintToFloat } from './utils/number';
78
78
  export { getExplorerLink } from './services/getExplorerLink';
79
+ export { invalidateTanstackQueries } from './queries/queryClient';
79
80
  export { DEFAULT_PAGE_SIZE, DEFAULT_REFRESH_INTERVAL } from './queries/constants';
80
81
  export { QKEY_VAULTS, QKEY_VAULT, QKEY_VAULT_CHANGES, QKEY_ORDERS, QKEY_ORDER, QKEY_ORDER_TRADES_LIST, QKEY_ORDER_QUOTE, QKEY_VAULTS_VOL_LIST, QKEY_ORDER_APY } from './queries/keys';
81
82
  export { darkChartTheme, lightChartTheme } from './utils/lightweightChartsThemes';
package/dist/index.js CHANGED
@@ -73,6 +73,7 @@ export { bigintStringToHex, HEX_INPUT_REGEX } from './utils/hex';
73
73
  export { vaultBalanceDisplay } from './utils/vault';
74
74
  export { bigintToFloat } from './utils/number';
75
75
  export { getExplorerLink } from './services/getExplorerLink';
76
+ export { invalidateTanstackQueries } from './queries/queryClient';
76
77
  // Constants
77
78
  export { DEFAULT_PAGE_SIZE, DEFAULT_REFRESH_INTERVAL } from './queries/constants';
78
79
  export { QKEY_VAULTS, QKEY_VAULT, QKEY_VAULT_CHANGES, QKEY_ORDERS, QKEY_ORDER, QKEY_ORDER_TRADES_LIST, QKEY_ORDER_QUOTE, QKEY_VAULTS_VOL_LIST, QKEY_ORDER_APY } from './queries/keys';
@@ -4,4 +4,5 @@
4
4
  */
5
5
  export declare function useAccount(): {
6
6
  account: import("../../types/account").Account;
7
+ matchesAccount: (otherAddress: string) => boolean;
7
8
  };
@@ -1,3 +1,5 @@
1
+ import { get } from 'svelte/store';
2
+ import { isAddress, isAddressEqual } from 'viem';
1
3
  import { getAccountContext } from './context';
2
4
  import { readable } from 'svelte/store';
3
5
  /**
@@ -5,28 +7,141 @@ import { readable } from 'svelte/store';
5
7
  * Must be used within a component that is a child of WalletProvider
6
8
  */
7
9
  export function useAccount() {
10
+ /**
11
+ * The account store containing the current wallet address (as a Hex string) or null if not connected.
12
+ * This is a readable Svelte store that can be subscribed to for reactive updates.
13
+ * @type {import('svelte/store').Readable<Hex | null>}
14
+ */
8
15
  const account = getAccountContext();
16
+ /**
17
+ * Checks if the provided address matches the currently connected account.
18
+ * Returns false if no account is connected or if the provided address is invalid.
19
+ */
20
+ const matchesAccount = (otherAddress) => {
21
+ if (!otherAddress)
22
+ return false;
23
+ const currentAccount = get(account);
24
+ if (!currentAccount) {
25
+ return false;
26
+ }
27
+ if (isAddress(currentAccount) &&
28
+ isAddress(otherAddress) &&
29
+ isAddressEqual(currentAccount, otherAddress)) {
30
+ return true;
31
+ }
32
+ return false;
33
+ };
9
34
  return {
10
- account
35
+ account,
36
+ matchesAccount
11
37
  };
12
38
  }
13
39
  if (import.meta.vitest) {
14
40
  const { describe, it, expect, vi, beforeEach } = import.meta.vitest;
41
+ vi.mock('viem', async () => {
42
+ const actual = await vi.importActual('viem');
43
+ return {
44
+ ...actual,
45
+ isAddress: vi.fn(),
46
+ isAddressEqual: vi.fn()
47
+ };
48
+ });
15
49
  vi.mock('./context', () => ({
16
50
  getAccountContext: vi.fn()
17
51
  }));
52
+ vi.mock('svelte/store', async () => {
53
+ const actual = await vi.importActual('svelte/store');
54
+ return {
55
+ ...actual,
56
+ get: vi.fn()
57
+ };
58
+ });
18
59
  describe('useAccount', () => {
19
60
  const mockGetAccountContext = vi.mocked(getAccountContext);
61
+ const mockGet = vi.mocked(get);
62
+ const mockIsAddress = vi.mocked(isAddress);
63
+ const mockIsAddressEqual = vi.mocked(isAddressEqual);
20
64
  beforeEach(() => {
21
- mockGetAccountContext.mockReset();
65
+ vi.clearAllMocks();
22
66
  });
23
67
  it('should return account wrapped in an object', () => {
24
- const mockAccount = readable('0x123');
25
- mockGetAccountContext.mockReturnValue(mockAccount);
68
+ const mockAccountStore = readable('0x123');
69
+ mockGetAccountContext.mockReturnValue(mockAccountStore);
26
70
  const result = useAccount();
27
71
  expect(mockGetAccountContext).toHaveBeenCalled();
28
- expect(result).toEqual({
29
- account: mockAccount
72
+ expect(result.account).toBe(mockAccountStore);
73
+ expect(result.matchesAccount).toBeInstanceOf(Function);
74
+ });
75
+ describe('matchesAccount', () => {
76
+ const mockAccountStore = readable('0x123');
77
+ const currentAccount = '0x123';
78
+ const testAddress1 = '0x123';
79
+ const testAddress2 = '0xdef';
80
+ const invalidAddress = 'invalid';
81
+ beforeEach(() => {
82
+ mockGetAccountContext.mockReturnValue(mockAccountStore);
83
+ });
84
+ it('should return true if addresses are valid and equal', () => {
85
+ // Setup mocks
86
+ mockGet.mockReturnValue(currentAccount);
87
+ mockIsAddress.mockReturnValue(true);
88
+ mockIsAddressEqual.mockReturnValue(true);
89
+ const { matchesAccount } = useAccount();
90
+ const result = matchesAccount(testAddress1);
91
+ expect(mockGet).toHaveBeenCalledWith(mockAccountStore);
92
+ expect(mockIsAddress).toHaveBeenCalledWith(currentAccount);
93
+ expect(mockIsAddress).toHaveBeenCalledWith(testAddress1);
94
+ expect(mockIsAddressEqual).toHaveBeenCalledWith(currentAccount, testAddress1);
95
+ expect(result).toBe(true);
96
+ });
97
+ it('should return false if addresses are valid but not equal', () => {
98
+ // Setup mocks
99
+ mockGet.mockReturnValue(currentAccount);
100
+ mockIsAddress.mockReturnValue(true);
101
+ mockIsAddressEqual.mockReturnValue(false);
102
+ const { matchesAccount } = useAccount();
103
+ const result = matchesAccount(testAddress2);
104
+ expect(mockGet).toHaveBeenCalledWith(mockAccountStore);
105
+ expect(mockIsAddress).toHaveBeenCalledWith(currentAccount);
106
+ expect(mockIsAddress).toHaveBeenCalledWith(testAddress2);
107
+ expect(mockIsAddressEqual).toHaveBeenCalledWith(currentAccount, testAddress2);
108
+ expect(result).toBe(false);
109
+ });
110
+ it('should return false if current account is not set', () => {
111
+ // Setup mocks
112
+ mockGet.mockReturnValue(null);
113
+ const { matchesAccount } = useAccount();
114
+ const result = matchesAccount(testAddress1);
115
+ expect(mockGet).toHaveBeenCalledWith(mockAccountStore);
116
+ expect(mockIsAddress).not.toHaveBeenCalled();
117
+ expect(mockIsAddressEqual).not.toHaveBeenCalled();
118
+ expect(result).toBe(false);
119
+ });
120
+ it('should return false if provided address is invalid', () => {
121
+ // Setup mocks
122
+ mockGet.mockReturnValue(currentAccount);
123
+ // This is crucial: we need to ensure short-circuit evaluation works correctly
124
+ mockIsAddress.mockImplementation((address) => {
125
+ return address !== invalidAddress; // Only the invalid address returns false
126
+ });
127
+ // This should never be called due to short-circuit evaluation
128
+ mockIsAddressEqual.mockReturnValue(false);
129
+ const { matchesAccount } = useAccount();
130
+ const result = matchesAccount(invalidAddress);
131
+ expect(mockGet).toHaveBeenCalledWith(mockAccountStore);
132
+ expect(mockIsAddress).toHaveBeenCalledWith(currentAccount);
133
+ expect(mockIsAddress).toHaveBeenCalledWith(invalidAddress);
134
+ expect(mockIsAddressEqual).not.toHaveBeenCalled(); // This should now pass
135
+ expect(result).toBe(false);
136
+ });
137
+ it('should return false if provided address is null', () => {
138
+ // Setup mocks
139
+ mockGet.mockReturnValue(currentAccount);
140
+ const { matchesAccount } = useAccount();
141
+ const result = matchesAccount(null);
142
+ expect(mockIsAddress).not.toHaveBeenCalled();
143
+ expect(mockIsAddressEqual).not.toHaveBeenCalled();
144
+ expect(result).toBe(false);
30
145
  });
31
146
  });
32
147
  });
@@ -1,3 +1,3 @@
1
1
  import { QueryClient } from '@tanstack/svelte-query';
2
2
  export declare const queryClient: QueryClient;
3
- export declare const invalidateIdQuery: (queryClient: QueryClient, id: string) => Promise<void>;
3
+ export declare const invalidateTanstackQueries: (queryClient: QueryClient, queryKey: string[]) => void;
@@ -7,9 +7,9 @@ export const queryClient = new QueryClient({
7
7
  }
8
8
  }
9
9
  });
10
- export const invalidateIdQuery = async (queryClient, id) => {
11
- await queryClient.invalidateQueries({
12
- queryKey: [id],
10
+ export const invalidateTanstackQueries = (queryClient, queryKey) => {
11
+ queryClient.invalidateQueries({
12
+ queryKey,
13
13
  refetchType: 'all',
14
14
  exact: false
15
15
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainlanguage/ui-components",
3
- "version": "0.0.1-alpha.61",
3
+ "version": "0.0.1-alpha.63",
4
4
  "description": "A component library for building Svelte applications to be used with Raindex.",
5
5
  "license": "LicenseRef-DCL-1.0",
6
6
  "author": "Rain Open Source Software Ltd",
@@ -53,7 +53,7 @@
53
53
  "@fontsource/dm-sans": "5.1.0",
54
54
  "@imask/svelte": "7.6.1",
55
55
  "@observablehq/plot": "0.6.16",
56
- "@rainlanguage/orderbook": "0.0.1-alpha.61",
56
+ "@rainlanguage/orderbook": "0.0.1-alpha.63",
57
57
  "@reown/appkit": "1.6.4",
58
58
  "@reown/appkit-adapter-wagmi": "1.6.4",
59
59
  "@sentry/sveltekit": "7.120.0",