@ckb-ccc/connector-react 1.1.9 → 2.0.0

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @ckb-ccc/connector-react
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#503](https://github.com/ckb-devrel/ccc/pull/503) [`2001c3b`](https://github.com/ckb-devrel/ccc/commit/2001c3b47c1eca82485621e3541c393b5ccf6a3e) Thanks [@Hanssen0](https://github.com/Hanssen0)! - refactor(connector): emit owned wallet and signer connections, remove deprecated compatibility APIs, require setClient callers to transfer Client ownership, and release connections from the React Provider.
8
+
9
+ See the [Connector 2.0 migration guide](https://docs.ckbccc.com/en/docs/migration/connector-v2)
10
+ for the required `setClient`, connection event, Client ownership, and removed
11
+ property changes.
12
+
13
+ ### Minor Changes
14
+
15
+ - [#498](https://github.com/ckb-devrel/ccc/pull/498) [`c75b49e`](https://github.com/ckb-devrel/ccc/commit/c75b49e282991949e2240779608a4c5b2277a34e) Thanks [@Hanssen0](https://github.com/Hanssen0)! - feat(connector-react): control Web Component Client requests in the Provider, manage ownership transferred through setClient, and add useBorrowedOrOwned for an internally owned fallback to an optional borrowed value
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies [[`2001c3b`](https://github.com/ckb-devrel/ccc/commit/2001c3b47c1eca82485621e3541c393b5ccf6a3e), [`230cf6c`](https://github.com/ckb-devrel/ccc/commit/230cf6c870680faeb560628aa989d92ba66ddf10), [`251232a`](https://github.com/ckb-devrel/ccc/commit/251232abcae0320eb9b991b5f8a05b655f45d426), [`7e38c51`](https://github.com/ckb-devrel/ccc/commit/7e38c51a38d45e92b96639bdce575880ba88ee9b)]:
20
+ - @ckb-ccc/connector@2.0.0
21
+
3
22
  ## 1.1.9
4
23
 
5
24
  ### Patch Changes
@@ -1,6 +1,8 @@
1
1
  import { ccc } from "@ckb-ccc/connector";
2
+ import { EventName } from "@lit/react";
2
3
  export declare const Connector: import("@lit/react").ReactWebComponent<ccc.WebComponentConnector, {
3
- onWillUpdate: string;
4
- onClose: string;
4
+ onClose: EventName<ccc.ConnectorCloseEvent>;
5
+ onSelectClient: EventName<ccc.SelectClientEvent>;
6
+ onConnection: EventName<ccc.ConnectorConnectionEvent>;
5
7
  }>;
6
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAIzC,eAAO,MAAM,SAAS;;;EAQpB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,EAAE,SAAS,EAAmB,MAAM,YAAY,CAAC;AAGxD,eAAO,MAAM,SAAS;aAMF,SAAS,CAAC,GAAG,CAAC,mBAAmB,CAAC;oBAElC,SAAS,CAAC,GAAG,CAAC,iBAAiB,CAAC;kBAEhC,SAAS,CAAC,GAAG,CAAC,wBAAwB,CAAC;EAEzD,CAAC"}
@@ -7,7 +7,11 @@ export const Connector = createComponent({
7
7
  elementClass: ccc.WebComponentConnector,
8
8
  react: React,
9
9
  events: {
10
- onWillUpdate: "willUpdate",
11
- onClose: "close",
10
+ onClose: ccc.ConnectorCloseEvent
11
+ .eventName,
12
+ onSelectClient: ccc.SelectClientEvent
13
+ .eventName,
14
+ onConnection: ccc.ConnectorConnectionEvent
15
+ .eventName,
12
16
  },
13
17
  });
@@ -1,3 +1,4 @@
1
+ export * from "./useBorrowedOrOwned.js";
1
2
  export * from "./useCcc.js";
2
3
  export * from "./useSigner.js";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC"}
@@ -1,2 +1,3 @@
1
+ export * from "./useBorrowedOrOwned.js";
1
2
  export * from "./useCcc.js";
2
3
  export * from "./useSigner.js";
@@ -0,0 +1,7 @@
1
+ import { ccc } from "@ckb-ccc/connector";
2
+ /**
3
+ * Opens and owns a fallback value after the component commits, while returning
4
+ * a borrowed value whenever one is provided.
5
+ */
6
+ export declare function useBorrowedOrOwned<T>(borrowed: T | undefined, open: () => ccc.Owner<T>): T | undefined;
7
+ //# sourceMappingURL=useBorrowedOrOwned.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBorrowedOrOwned.d.ts","sourceRoot":"","sources":["../../src/hooks/useBorrowedOrOwned.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAGzC;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,QAAQ,EAAE,CAAC,GAAG,SAAS,EACvB,IAAI,EAAE,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GACvB,CAAC,GAAG,SAAS,CAUf"}
@@ -0,0 +1,14 @@
1
+ import { useEffect, useState } from "react";
2
+ /**
3
+ * Opens and owns a fallback value after the component commits, while returning
4
+ * a borrowed value whenever one is provided.
5
+ */
6
+ export function useBorrowedOrOwned(borrowed, open) {
7
+ const [owned, setOwned] = useState();
8
+ useEffect(() => {
9
+ const owner = open();
10
+ setOwned(owner.value);
11
+ return () => void owner.dispose().catch(() => { });
12
+ }, [open]);
13
+ return borrowed ?? owned;
14
+ }
@@ -1,6 +1,6 @@
1
1
  import { ccc } from "@ckb-ccc/connector";
2
2
  import React, { HTMLAttributes, ReactNode } from "react";
3
- export declare function Provider({ children, connectorProps, hideMark, name, icon, signerFilter, signersController, defaultClient, clientOptions, preferredNetworks, }: {
3
+ export declare function Provider({ children, connectorProps, hideMark, name, icon, signerFilter, signersController, defaultClient, clientOptions, }: {
4
4
  children: ReactNode;
5
5
  connectorProps?: HTMLAttributes<{}>;
6
6
  hideMark?: boolean;
@@ -14,14 +14,13 @@ export declare function Provider({ children, connectorProps, hideMark, name, ico
14
14
  client: ccc.Client;
15
15
  name: string;
16
16
  }[];
17
- preferredNetworks?: ccc.NetworkPreference[];
18
- }): React.JSX.Element;
17
+ }): React.JSX.Element | null;
19
18
  export declare function useCcc(): {
20
19
  isOpen: boolean;
21
20
  open: () => unknown;
22
21
  close: () => unknown;
23
22
  disconnect: () => unknown;
24
- setClient: (client: ccc.Client) => unknown;
23
+ setClient: (owner: ccc.Owner<ccc.Client>) => void;
25
24
  client: ccc.Client;
26
25
  wallet?: ccc.Wallet;
27
26
  signerInfo?: ccc.SignerInfo;
@@ -1 +1 @@
1
- {"version":3,"file":"useCcc.d.ts","sourceRoot":"","sources":["../../src/hooks/useCcc.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,KAAK,EAAE,EAEZ,cAAc,EACd,SAAS,EAQV,MAAM,OAAO,CAAC;AA4Cf,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,IAAI,EACJ,IAAI,EACJ,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,iBAAiB,GAClB,EAAE;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,cAAc,CAAC,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,CACb,UAAU,EAAE,GAAG,CAAC,UAAU,EAC1B,MAAM,EAAE,GAAG,CAAC,MAAM,KACf,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,iBAAiB,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC;IAC1C,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACtE,iBAAiB,CAAC,EAAE,GAAG,CAAC,iBAAiB,EAAE,CAAC;CAC7C,qBAiGA;AAED,wBAAgB,MAAM;YAnKR,OAAO;UACT,MAAM,OAAO;WACZ,MAAM,OAAO;gBACR,MAAM,OAAO;eACd,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,OAAO;YAClC,GAAG,CAAC,MAAM;aACT,GAAG,CAAC,MAAM;iBACN,GAAG,CAAC,UAAU;EAoKhC"}
1
+ {"version":3,"file":"useCcc.d.ts","sourceRoot":"","sources":["../../src/hooks/useCcc.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AACzC,OAAO,KAAK,EAAE,EAEZ,cAAc,EACd,SAAS,EAQV,MAAM,OAAO,CAAC;AAiDf,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,IAAI,EACJ,IAAI,EACJ,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,aAAa,GACd,EAAE;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,cAAc,CAAC,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,CACb,UAAU,EAAE,GAAG,CAAC,UAAU,EAC1B,MAAM,EAAE,GAAG,CAAC,MAAM,KACf,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,iBAAiB,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC;IAC1C,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACvE,4BAuIA;AAED,wBAAgB,MAAM;YAvMR,OAAO;UACT,MAAM,OAAO;WACZ,MAAM,OAAO;gBACR,MAAM,OAAO;eACd,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI;YACzC,GAAG,CAAC,MAAM;aACT,GAAG,CAAC,MAAM;iBACN,GAAG,CAAC,UAAU;EAwMhC"}
@@ -1,6 +1,10 @@
1
1
  import { ccc } from "@ckb-ccc/connector";
2
2
  import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
3
3
  import { Connector } from "../components/index.js";
4
+ import { useBorrowedOrOwned } from "./useBorrowedOrOwned.js";
5
+ function openDefaultClient() {
6
+ return ccc.ClientPublicTestnet.open();
7
+ }
4
8
  const CCC_CONTEXT = createContext(undefined);
5
9
  class SignersControllerWithFilter extends ccc.SignersController {
6
10
  constructor(filter) {
@@ -15,12 +19,55 @@ class SignersControllerWithFilter extends ccc.SignersController {
15
19
  return super.addSigner(walletName, icon, signerInfo, context);
16
20
  }
17
21
  }
18
- export function Provider({ children, connectorProps, hideMark, name, icon, signerFilter, signersController, defaultClient, clientOptions, preferredNetworks, }) {
22
+ export function Provider({ children, connectorProps, hideMark, name, icon, signerFilter, signersController, defaultClient, clientOptions, }) {
19
23
  const [ref, setRef] = useState(null);
24
+ const connectionOwner = useRef(undefined);
25
+ const [connection, setConnection] = useState();
20
26
  const [isOpen, setIsOpen] = useState(false);
21
- const [_, setFlag] = useState(0);
22
- const defaultSignersController = useRef(undefined);
23
- const client = useMemo(() => ref?.client ?? new ccc.ClientPublicTestnet(), [ref?.client]);
27
+ const defaultSignersController = useMemo(() => new SignersControllerWithFilter(signerFilter), [signerFilter]);
28
+ const initialClient = useBorrowedOrOwned(defaultClient ?? clientOptions?.[0]?.client, openDefaultClient);
29
+ const [selectedClient, setSelectedClient] = useState();
30
+ const adoptedClientOwner = useRef(undefined);
31
+ const client = selectedClient ?? initialClient;
32
+ const setClient = useCallback((resource) => {
33
+ const owner = resource.map((value) => value);
34
+ const previous = adoptedClientOwner.current;
35
+ adoptedClientOwner.current = owner;
36
+ if (previous)
37
+ void previous.dispose().catch(() => { });
38
+ setSelectedClient(owner.value);
39
+ }, []);
40
+ const onSelectClient = useCallback((event) => {
41
+ setSelectedClient(event.client);
42
+ }, []);
43
+ const onConnection = useCallback((event) => {
44
+ event.stopPropagation();
45
+ if (event.connectionOwner && !event.connectionOwner.isValid) {
46
+ return;
47
+ }
48
+ const owner = event.connectionOwner?.map((connection) => connection);
49
+ const previous = connectionOwner.current;
50
+ connectionOwner.current = owner;
51
+ const connection = owner?.value;
52
+ setConnection(connection);
53
+ connection?.signerInfo.signer.onReplaced(() => {
54
+ if (connectionOwner.current === owner) {
55
+ connectionOwner.current = undefined;
56
+ setConnection(undefined);
57
+ }
58
+ void owner?.dispose().catch(() => { });
59
+ });
60
+ if (previous) {
61
+ void previous.dispose().catch(() => { });
62
+ }
63
+ }, []);
64
+ useEffect(() => () => {
65
+ const owner = connectionOwner.current;
66
+ connectionOwner.current = undefined;
67
+ void owner?.dispose().catch(() => { });
68
+ void adoptedClientOwner.current?.dispose().catch(() => { });
69
+ adoptedClientOwner.current = undefined;
70
+ }, []);
24
71
  const open = useCallback(() => {
25
72
  setIsOpen(true);
26
73
  ref?.requestUpdate();
@@ -30,20 +77,8 @@ export function Provider({ children, connectorProps, hideMark, name, icon, signe
30
77
  ref?.requestUpdate();
31
78
  }, [setIsOpen, ref, ref?.requestUpdate]);
32
79
  const disconnect = useMemo(() => ref?.disconnect.bind(ref) ?? (() => { }), [ref, ref?.disconnect]);
33
- const setClient = useMemo(() => ref?.setClient.bind(ref) ?? (() => { }), [ref, ref?.setClient]);
34
- useEffect(() => {
35
- if (defaultClient) {
36
- setClient(defaultClient);
37
- }
38
- }, [setClient]);
39
- useEffect(() => {
40
- if (!defaultSignersController.current) {
41
- defaultSignersController.current = new SignersControllerWithFilter(signerFilter);
42
- }
43
- else {
44
- defaultSignersController.current.filter = signerFilter;
45
- }
46
- }, [signerFilter]);
80
+ if (!client)
81
+ return null;
47
82
  return (React.createElement(CCC_CONTEXT.Provider, { value: {
48
83
  isOpen,
49
84
  open,
@@ -51,10 +86,10 @@ export function Provider({ children, connectorProps, hideMark, name, icon, signe
51
86
  disconnect,
52
87
  setClient,
53
88
  client,
54
- wallet: ref?.wallet,
55
- signerInfo: ref?.signer,
89
+ wallet: connection?.wallet,
90
+ signerInfo: connection?.signerInfo,
56
91
  } },
57
- React.createElement(Connector, { hideMark: hideMark, name: name, icon: icon, signersController: signersController ?? defaultSignersController.current, ref: setRef, onWillUpdate: () => setFlag((f) => f + 1), onClose: close, preferredNetworks: preferredNetworks, clientOptions: clientOptions, ...connectorProps,
92
+ React.createElement(Connector, { client: client, hideMark: hideMark, name: name, icon: icon, signersController: signersController ?? defaultSignersController, ref: setRef, onClose: close, onConnection: onConnection, clientOptions: clientOptions, ...connectorProps,
58
93
  style: {
59
94
  zIndex: 999,
60
95
  ...(isOpen ? {} : { display: "none" }),
@@ -74,7 +109,7 @@ export function Provider({ children, connectorProps, hideMark, name, icon, signe
74
109
  "--tip-color-hover": "var(--tip-color)",
75
110
  },
76
111
  ...connectorProps?.style,
77
- } }),
112
+ }, onSelectClient: onSelectClient }),
78
113
  children));
79
114
  }
80
115
  export function useCcc() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckb-ccc/connector-react",
3
- "version": "1.1.9",
3
+ "version": "2.0.0",
4
4
  "description": "CCC - CKBer's Codebase. Common Chains Connector UI Component for React",
5
5
  "author": "Hanssen0 <hanssen0@hanssen0.com>",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@lit/react": "^1.0.8",
37
- "@ckb-ccc/connector": "1.3.0"
37
+ "@ckb-ccc/connector": "2.0.0"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@types/react": ">=16",
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { ccc } from "@ckb-ccc/connector";
4
- import { createComponent } from "@lit/react";
4
+ import { EventName, createComponent } from "@lit/react";
5
5
  import * as React from "react";
6
6
 
7
7
  export const Connector = createComponent({
@@ -9,7 +9,11 @@ export const Connector = createComponent({
9
9
  elementClass: ccc.WebComponentConnector,
10
10
  react: React,
11
11
  events: {
12
- onWillUpdate: "willUpdate",
13
- onClose: "close",
12
+ onClose: ccc.ConnectorCloseEvent
13
+ .eventName as EventName<ccc.ConnectorCloseEvent>,
14
+ onSelectClient: ccc.SelectClientEvent
15
+ .eventName as EventName<ccc.SelectClientEvent>,
16
+ onConnection: ccc.ConnectorConnectionEvent
17
+ .eventName as EventName<ccc.ConnectorConnectionEvent>,
14
18
  },
15
19
  });
@@ -1,2 +1,3 @@
1
+ export * from "./useBorrowedOrOwned.js";
1
2
  export * from "./useCcc.js";
2
3
  export * from "./useSigner.js";
@@ -0,0 +1,21 @@
1
+ import { ccc } from "@ckb-ccc/connector";
2
+ import { useEffect, useState } from "react";
3
+
4
+ /**
5
+ * Opens and owns a fallback value after the component commits, while returning
6
+ * a borrowed value whenever one is provided.
7
+ */
8
+ export function useBorrowedOrOwned<T>(
9
+ borrowed: T | undefined,
10
+ open: () => ccc.Owner<T>,
11
+ ): T | undefined {
12
+ const [owned, setOwned] = useState<T>();
13
+
14
+ useEffect(() => {
15
+ const owner = open();
16
+ setOwned(owner.value);
17
+ return () => void owner.dispose().catch(() => {});
18
+ }, [open]);
19
+
20
+ return borrowed ?? owned;
21
+ }
@@ -12,6 +12,11 @@ import React, {
12
12
  useState,
13
13
  } from "react";
14
14
  import { Connector } from "../components/index.js";
15
+ import { useBorrowedOrOwned } from "./useBorrowedOrOwned.js";
16
+
17
+ function openDefaultClient(): ccc.Owner<ccc.Client> {
18
+ return ccc.ClientPublicTestnet.open();
19
+ }
15
20
 
16
21
  const CCC_CONTEXT = createContext<
17
22
  | {
@@ -19,7 +24,7 @@ const CCC_CONTEXT = createContext<
19
24
  open: () => unknown;
20
25
  close: () => unknown;
21
26
  disconnect: () => unknown;
22
- setClient: (client: ccc.Client) => unknown;
27
+ setClient: (owner: ccc.Owner<ccc.Client>) => void;
23
28
  client: ccc.Client;
24
29
  wallet?: ccc.Wallet;
25
30
  signerInfo?: ccc.SignerInfo;
@@ -29,7 +34,7 @@ const CCC_CONTEXT = createContext<
29
34
 
30
35
  class SignersControllerWithFilter extends ccc.SignersController {
31
36
  constructor(
32
- public filter?: (
37
+ public readonly filter?: (
33
38
  signerInfo: ccc.SignerInfo,
34
39
  wallet: ccc.Wallet,
35
40
  ) => Promise<boolean>,
@@ -64,7 +69,6 @@ export function Provider({
64
69
  signersController,
65
70
  defaultClient,
66
71
  clientOptions,
67
- preferredNetworks,
68
72
  }: {
69
73
  children: ReactNode;
70
74
  connectorProps?: HTMLAttributes<{}>;
@@ -78,19 +82,75 @@ export function Provider({
78
82
  signersController?: ccc.SignersController;
79
83
  defaultClient?: ccc.Client;
80
84
  clientOptions?: { icon?: string; client: ccc.Client; name: string }[];
81
- preferredNetworks?: ccc.NetworkPreference[];
82
85
  }) {
83
86
  const [ref, setRef] = useState<ccc.WebComponentConnector | null>(null);
84
- const [isOpen, setIsOpen] = useState(false);
85
- const [_, setFlag] = useState(0);
86
- const defaultSignersController = useRef<
87
- SignersControllerWithFilter | undefined
87
+ const connectionOwner = useRef<
88
+ ccc.Owner<ccc.ConnectorConnection> | undefined
88
89
  >(undefined);
90
+ const [connection, setConnection] = useState<ccc.ConnectorConnection>();
91
+ const [isOpen, setIsOpen] = useState(false);
92
+ const defaultSignersController = useMemo(
93
+ () => new SignersControllerWithFilter(signerFilter),
94
+ [signerFilter],
95
+ );
89
96
 
90
- const client = useMemo(
91
- () => ref?.client ?? new ccc.ClientPublicTestnet(),
92
- [ref?.client],
97
+ const initialClient = useBorrowedOrOwned(
98
+ defaultClient ?? clientOptions?.[0]?.client,
99
+ openDefaultClient,
100
+ );
101
+ const [selectedClient, setSelectedClient] = useState<ccc.Client>();
102
+ const adoptedClientOwner = useRef<ccc.Owner<ccc.Client> | undefined>(
103
+ undefined,
93
104
  );
105
+ const client = selectedClient ?? initialClient;
106
+
107
+ const setClient = useCallback((resource: ccc.Owner<ccc.Client>) => {
108
+ const owner = resource.map((value) => value);
109
+
110
+ const previous = adoptedClientOwner.current;
111
+ adoptedClientOwner.current = owner;
112
+ if (previous) void previous.dispose().catch(() => {});
113
+ setSelectedClient(owner.value);
114
+ }, []);
115
+
116
+ const onSelectClient = useCallback((event: ccc.SelectClientEvent) => {
117
+ setSelectedClient(event.client);
118
+ }, []);
119
+
120
+ const onConnection = useCallback((event: ccc.ConnectorConnectionEvent) => {
121
+ event.stopPropagation();
122
+ if (event.connectionOwner && !event.connectionOwner.isValid) {
123
+ return;
124
+ }
125
+ const owner = event.connectionOwner?.map((connection) => connection);
126
+ const previous = connectionOwner.current;
127
+ connectionOwner.current = owner;
128
+ const connection = owner?.value;
129
+ setConnection(connection);
130
+
131
+ connection?.signerInfo.signer.onReplaced(() => {
132
+ if (connectionOwner.current === owner) {
133
+ connectionOwner.current = undefined;
134
+ setConnection(undefined);
135
+ }
136
+ void owner?.dispose().catch(() => {});
137
+ });
138
+ if (previous) {
139
+ void previous.dispose().catch(() => {});
140
+ }
141
+ }, []);
142
+
143
+ useEffect(
144
+ () => () => {
145
+ const owner = connectionOwner.current;
146
+ connectionOwner.current = undefined;
147
+ void owner?.dispose().catch(() => {});
148
+ void adoptedClientOwner.current?.dispose().catch(() => {});
149
+ adoptedClientOwner.current = undefined;
150
+ },
151
+ [],
152
+ );
153
+
94
154
  const open = useCallback(() => {
95
155
  setIsOpen(true);
96
156
  ref?.requestUpdate();
@@ -103,25 +163,7 @@ export function Provider({
103
163
  () => ref?.disconnect.bind(ref) ?? (() => {}),
104
164
  [ref, ref?.disconnect],
105
165
  );
106
- const setClient = useMemo(
107
- () => ref?.setClient.bind(ref) ?? (() => {}),
108
- [ref, ref?.setClient],
109
- );
110
-
111
- useEffect(() => {
112
- if (defaultClient) {
113
- setClient(defaultClient);
114
- }
115
- }, [setClient]);
116
- useEffect(() => {
117
- if (!defaultSignersController.current) {
118
- defaultSignersController.current = new SignersControllerWithFilter(
119
- signerFilter,
120
- );
121
- } else {
122
- defaultSignersController.current.filter = signerFilter;
123
- }
124
- }, [signerFilter]);
166
+ if (!client) return null;
125
167
 
126
168
  return (
127
169
  <CCC_CONTEXT.Provider
@@ -133,21 +175,19 @@ export function Provider({
133
175
  setClient,
134
176
 
135
177
  client,
136
- wallet: ref?.wallet,
137
- signerInfo: ref?.signer,
178
+ wallet: connection?.wallet,
179
+ signerInfo: connection?.signerInfo,
138
180
  }}
139
181
  >
140
182
  <Connector
183
+ client={client}
141
184
  hideMark={hideMark}
142
185
  name={name}
143
186
  icon={icon}
144
- signersController={
145
- signersController ?? defaultSignersController.current
146
- }
187
+ signersController={signersController ?? defaultSignersController}
147
188
  ref={setRef}
148
- onWillUpdate={() => setFlag((f) => f + 1)}
149
189
  onClose={close}
150
- preferredNetworks={preferredNetworks}
190
+ onConnection={onConnection}
151
191
  clientOptions={clientOptions}
152
192
  {...{
153
193
  ...connectorProps,
@@ -172,6 +212,7 @@ export function Provider({
172
212
  ...connectorProps?.style,
173
213
  },
174
214
  }}
215
+ onSelectClient={onSelectClient}
175
216
  />
176
217
  {children}
177
218
  </CCC_CONTEXT.Provider>