@multiplatform.one/web3 8.2.1 → 8.2.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiplatform.one/web3",
3
- "version": "8.2.1",
3
+ "version": "8.2.2",
4
4
  "description": "Web3 wallet integration for multiplatform.one ecosystem with ConnectKit and wagmi",
5
5
  "keywords": [
6
6
  "connectkit",
@@ -120,10 +120,10 @@
120
120
  "@aave/account": "^0.2.1",
121
121
  "@coinbase/wallet-sdk": "^4.4.0",
122
122
  "@metamask/connect-evm": "^2.1.1",
123
- "@multiplatform.one/connectkit": "^8.2.1",
124
- "@multiplatform.one/gpg": "^8.2.1",
125
- "@multiplatform.one/platform": "^8.2.1",
126
- "@multiplatform.one/theme": "^8.2.1",
123
+ "@multiplatform.one/connectkit": "^8.2.2",
124
+ "@multiplatform.one/gpg": "^8.2.2",
125
+ "@multiplatform.one/platform": "^8.2.2",
126
+ "@multiplatform.one/theme": "^8.2.2",
127
127
  "@noble/ciphers": "^1.3.0",
128
128
  "@noble/curves": "^1.9.7",
129
129
  "@phosphor-icons/react": "^2.1.10",
@@ -147,8 +147,8 @@
147
147
  "wagmi": "^3.7.1"
148
148
  },
149
149
  "devDependencies": {
150
- "@multiplatform.one/config": "8.2.1",
151
- "@multiplatform.one/test-utils": "8.2.1",
150
+ "@multiplatform.one/config": "8.2.2",
151
+ "@multiplatform.one/test-utils": "8.2.2",
152
152
  "@tamagui/build": "2.7.6",
153
153
  "@tanstack/react-query": "^5.104.3",
154
154
  "@testing-library/jest-dom": "^7.0.1",
@@ -0,0 +1,118 @@
1
+ // @vitest-environment happy-dom
2
+ import { cleanup, render } from "@testing-library/react";
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { createConfig, createStorage, http } from "wagmi";
5
+ import { mainnet } from "wagmi/chains";
6
+ import { mock } from "wagmi/connectors";
7
+ import { KeycloakWalletLogin, type KeycloakWalletLoginProps } from "./KeycloakWalletLogin";
8
+
9
+ const ACCOUNT = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
10
+
11
+ type ColorScheme = "light" | "dark";
12
+
13
+ function memoryStorage() {
14
+ const map = new Map<string, string>();
15
+ return {
16
+ getItem: (key: string) => map.get(key) ?? null,
17
+ setItem: (key: string, value: string) => void map.set(key, value),
18
+ removeItem: (key: string) => void map.delete(key),
19
+ clear: () => map.clear(),
20
+ };
21
+ }
22
+
23
+ function setColorScheme(scheme: ColorScheme) {
24
+ const happy = (window as unknown as { happyDOM: { settings: { device: object } } }).happyDOM;
25
+ Object.assign(happy.settings.device, { prefersColorScheme: scheme });
26
+ }
27
+
28
+ function renderLogin(props: KeycloakWalletLoginProps = {}) {
29
+ const config = createConfig({
30
+ chains: [mainnet],
31
+ connectors: [mock({ accounts: [ACCOUNT] })],
32
+ transports: { [mainnet.id]: http() },
33
+ storage: createStorage({ storage: memoryStorage() }),
34
+ });
35
+ render(
36
+ <KeycloakWalletLogin
37
+ baseUrl="https://kc.example.com"
38
+ realm="main"
39
+ resource="wallet"
40
+ wagmiConfig={config}
41
+ {...props}
42
+ />,
43
+ );
44
+ return {
45
+ wallet: document.getElementById("mpo-wallet-login") as HTMLButtonElement,
46
+ gpg: document.getElementById("mpo-gpg-login") as HTMLButtonElement,
47
+ };
48
+ }
49
+
50
+ /**
51
+ * happy-dom resolves a custom property only on the element that declares it,
52
+ * so a `var()` in the button's style is looked up the ancestor chain here, the
53
+ * way a browser's cascade inherits it.
54
+ */
55
+ function computed(element: HTMLElement, property: string) {
56
+ const declared = element.style.getPropertyValue(property);
57
+ const name = /^var\((--[\w-]+)\)$/.exec(declared)?.[1];
58
+ if (!name) return window.getComputedStyle(element).getPropertyValue(property);
59
+ for (let node: HTMLElement | null = element; node; node = node.parentElement) {
60
+ const value = window.getComputedStyle(node).getPropertyValue(name).trim();
61
+ if (value) return value;
62
+ }
63
+ return "";
64
+ }
65
+
66
+ function painted(button: HTMLElement) {
67
+ return { background: computed(button, "background"), color: computed(button, "color") };
68
+ }
69
+
70
+ /** ConnectKit writes each colour token in display-p3 where the engine supports it. */
71
+ function p3(hex: string) {
72
+ const [r, g, b] = [1, 3, 5].map((at) => Number.parseInt(hex.slice(at, at + 2), 16) / 255);
73
+ return `color(display-p3 ${r} ${g} ${b})`;
74
+ }
75
+
76
+ beforeEach(() => {
77
+ vi.stubGlobal("localStorage", memoryStorage());
78
+ vi.stubGlobal(
79
+ "fetch",
80
+ vi.fn(async () => new Response("not found", { status: 404 })),
81
+ );
82
+ });
83
+
84
+ afterEach(() => {
85
+ cleanup();
86
+ vi.unstubAllGlobals();
87
+ setColorScheme("light");
88
+ });
89
+
90
+ describe("KeycloakWalletLogin buttons follow the ConnectKit theme", () => {
91
+ it("paint the dark primary-button surface and ink in a dark scheme", () => {
92
+ setColorScheme("dark");
93
+ const { wallet, gpg } = renderLogin();
94
+
95
+ for (const button of [wallet, gpg]) {
96
+ expect(painted(button)).toEqual({ background: p3("#383838"), color: p3("#ffffff") });
97
+ }
98
+ });
99
+
100
+ it("paint the light primary-button surface and ink in a light scheme", () => {
101
+ setColorScheme("light");
102
+ const { wallet, gpg } = renderLogin();
103
+
104
+ for (const button of [wallet, gpg]) {
105
+ expect(painted(button)).toEqual({ background: p3("#F6F7F9"), color: p3("#373737") });
106
+ }
107
+ });
108
+
109
+ it("a buttonClassName keeps the host's look and takes no theme paint", () => {
110
+ setColorScheme("dark");
111
+ const { wallet, gpg } = renderLogin({ buttonClassName: "kc-button" });
112
+
113
+ for (const button of [wallet, gpg]) {
114
+ expect(button.getAttribute("style")).toBeNull();
115
+ expect(button.closest("[data-mpo-wallet-theme]")).toBeNull();
116
+ }
117
+ });
118
+ });
@@ -1,6 +1,7 @@
1
+ import { ResetContainer, useContext as useConnectKit } from "@multiplatform.one/connectkit";
1
2
  import { GpgProvider } from "@multiplatform.one/gpg";
2
3
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3
- import { type CSSProperties, useMemo } from "react";
4
+ import { type CSSProperties, type ReactNode, useMemo } from "react";
4
5
  import type { Chain } from "viem";
5
6
  import { type Config, WagmiProvider, createConfig } from "wagmi";
6
7
  import { arbitrum, mainnet, optimism, polygon } from "wagmi/chains";
@@ -87,13 +88,18 @@ const buttonStyle: CSSProperties = {
87
88
  marginTop: 8,
88
89
  fontSize: 14,
89
90
  cursor: "pointer",
90
- border: "1px solid #c4c4c4",
91
+ border: "none",
91
92
  borderRadius: 4,
92
- background: "#fff",
93
+ background: "var(--ck-primary-button-background)",
94
+ color: "var(--ck-primary-button-color)",
93
95
  };
94
96
 
97
+ const themeScopeStyle: CSSProperties = { display: "block" };
98
+
95
99
  const noticeStyle: CSSProperties = { margin: "8px 0 0", fontSize: 13 };
96
100
 
101
+ const themedNoticeStyle: CSSProperties = { ...noticeStyle, color: "var(--ck-body-color)" };
102
+
97
103
  /**
98
104
  * Wallet and GPG sign-in for a Keycloak login page, on the browser flow: the
99
105
  * signed credential posts to the page's authenticator. Carries its own wagmi,
@@ -179,7 +185,7 @@ function LoginButtons({
179
185
  const { openGpg } = useWeb3Modal();
180
186
  const style = buttonClassName ? undefined : buttonStyle;
181
187
  const busy = status === StatusState.LOADING || status === StatusState.SUCCESS;
182
- return (
188
+ const buttons = (
183
189
  <div className={className ?? "mpo-keycloak-wallet-login"}>
184
190
  <button
185
191
  type="button"
@@ -196,7 +202,11 @@ function LoginButtons({
196
202
  <span>{busy ? "Signing…" : walletLabel}</span>
197
203
  </button>
198
204
  {dropped && !busy && (
199
- <p id="mpo-wallet-login-dropped" role="status" style={noticeStyle}>
205
+ <p
206
+ id="mpo-wallet-login-dropped"
207
+ role="status"
208
+ style={style ? themedNoticeStyle : noticeStyle}
209
+ >
200
210
  The wallet connection was lost. Tap {walletLabel} to connect again.
201
211
  </p>
202
212
  )}
@@ -217,6 +227,22 @@ function LoginButtons({
217
227
  )}
218
228
  </div>
219
229
  );
230
+ return buttonClassName ? buttons : <ThemeScope>{buttons}</ThemeScope>;
231
+ }
232
+
233
+ function ThemeScope({ children }: { children: ReactNode }) {
234
+ const { theme, mode, customTheme } = useConnectKit();
235
+ return (
236
+ <ResetContainer
237
+ data-mpo-wallet-theme=""
238
+ $useTheme={theme}
239
+ $useMode={mode}
240
+ $customTheme={customTheme}
241
+ style={themeScopeStyle}
242
+ >
243
+ {children}
244
+ </ResetContainer>
245
+ );
220
246
  }
221
247
 
222
248
  function WalletIcon() {
@@ -1 +1 @@
1
- {"version":3,"file":"KeycloakWalletLogin.d.ts","sourceRoot":"","sources":["../../src/keycloak/KeycloakWalletLogin.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,KAAK,MAAM,EAA+B,MAAM,OAAO,CAAC;AAOjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAExE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAGtD,MAAM,WAAW,wBAAwB;IACvC,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,CAAC,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IACtC,kFAAkF;IAClF,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wFAAwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,6EAA6E;AAC7E,wBAAgB,0BAA0B,CAAC,EACzC,OAAmB,EACnB,cAA2C,EAC3C,MAAuE,EACvE,OAAO,EACP,MAAsB,GACvB,GAAE,IAAI,CACL,wBAAwB,EACxB,SAAS,GAAG,gBAAgB,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAC1D,GAAG,MAAM,CAgBd;AAmBD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,2CAkElE"}
1
+ {"version":3,"file":"KeycloakWalletLogin.d.ts","sourceRoot":"","sources":["../../src/keycloak/KeycloakWalletLogin.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,KAAK,MAAM,EAA+B,MAAM,OAAO,CAAC;AAOjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAExE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAGtD,MAAM,WAAW,wBAAwB;IACvC,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,CAAC,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IACtC,kFAAkF;IAClF,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wFAAwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,6EAA6E;AAC7E,wBAAgB,0BAA0B,CAAC,EACzC,OAAmB,EACnB,cAA2C,EAC3C,MAAuE,EACvE,OAAO,EACP,MAAsB,GACvB,GAAE,IAAI,CACL,wBAAwB,EACxB,SAAS,GAAG,gBAAgB,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAC1D,GAAG,MAAM,CAgBd;AAwBD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,2CAkElE"}