@lukso/up-connector 0.4.0-dev.a8c9315

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.
Files changed (109) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +280 -0
  3. package/dist/account-modal.cjs +9 -0
  4. package/dist/account-modal.cjs.map +1 -0
  5. package/dist/account-modal.d.cts +16 -0
  6. package/dist/account-modal.d.ts +16 -0
  7. package/dist/account-modal.js +9 -0
  8. package/dist/account-modal.js.map +1 -0
  9. package/dist/auto-setup.cjs +17 -0
  10. package/dist/auto-setup.cjs.map +1 -0
  11. package/dist/auto-setup.d.cts +123 -0
  12. package/dist/auto-setup.d.ts +123 -0
  13. package/dist/auto-setup.js +17 -0
  14. package/dist/auto-setup.js.map +1 -0
  15. package/dist/avatar-CmUCtW_w.d.cts +205 -0
  16. package/dist/avatar-CmUCtW_w.d.ts +205 -0
  17. package/dist/avatar.cjs +12 -0
  18. package/dist/avatar.cjs.map +1 -0
  19. package/dist/avatar.d.cts +1 -0
  20. package/dist/avatar.d.ts +1 -0
  21. package/dist/avatar.js +12 -0
  22. package/dist/avatar.js.map +1 -0
  23. package/dist/backup-modal.cjs +9 -0
  24. package/dist/backup-modal.cjs.map +1 -0
  25. package/dist/backup-modal.d.cts +41 -0
  26. package/dist/backup-modal.d.ts +41 -0
  27. package/dist/backup-modal.js +9 -0
  28. package/dist/backup-modal.js.map +1 -0
  29. package/dist/chunk-3SGSPHOZ.js +595 -0
  30. package/dist/chunk-3SGSPHOZ.js.map +1 -0
  31. package/dist/chunk-6AYZOIFY.js +181 -0
  32. package/dist/chunk-6AYZOIFY.js.map +1 -0
  33. package/dist/chunk-6N35TCFT.js +852 -0
  34. package/dist/chunk-6N35TCFT.js.map +1 -0
  35. package/dist/chunk-7ETKG6KR.cjs +387 -0
  36. package/dist/chunk-7ETKG6KR.cjs.map +1 -0
  37. package/dist/chunk-EUXUH3YW.js +15 -0
  38. package/dist/chunk-EUXUH3YW.js.map +1 -0
  39. package/dist/chunk-GFVUWAG4.cjs +158 -0
  40. package/dist/chunk-GFVUWAG4.cjs.map +1 -0
  41. package/dist/chunk-IAKQFHFD.cjs +595 -0
  42. package/dist/chunk-IAKQFHFD.cjs.map +1 -0
  43. package/dist/chunk-MH7MP7XK.cjs +181 -0
  44. package/dist/chunk-MH7MP7XK.cjs.map +1 -0
  45. package/dist/chunk-NWCNJSG3.js +387 -0
  46. package/dist/chunk-NWCNJSG3.js.map +1 -0
  47. package/dist/chunk-NXU2DQAV.js +1128 -0
  48. package/dist/chunk-NXU2DQAV.js.map +1 -0
  49. package/dist/chunk-ORJK2YGG.cjs +852 -0
  50. package/dist/chunk-ORJK2YGG.cjs.map +1 -0
  51. package/dist/chunk-RFA6SEIS.cjs +1128 -0
  52. package/dist/chunk-RFA6SEIS.cjs.map +1 -0
  53. package/dist/chunk-XGIT7YUY.js +31 -0
  54. package/dist/chunk-XGIT7YUY.js.map +1 -0
  55. package/dist/chunk-XOKG3KIL.cjs +31 -0
  56. package/dist/chunk-XOKG3KIL.cjs.map +1 -0
  57. package/dist/chunk-YIWSPI4I.js +158 -0
  58. package/dist/chunk-YIWSPI4I.js.map +1 -0
  59. package/dist/chunk-ZBDE64SD.cjs +15 -0
  60. package/dist/chunk-ZBDE64SD.cjs.map +1 -0
  61. package/dist/connect-modal/index.cjs +20 -0
  62. package/dist/connect-modal/index.cjs.map +1 -0
  63. package/dist/connect-modal/index.d.cts +9 -0
  64. package/dist/connect-modal/index.d.ts +9 -0
  65. package/dist/connect-modal/index.js +20 -0
  66. package/dist/connect-modal/index.js.map +1 -0
  67. package/dist/index-D2orHGFi.d.cts +8 -0
  68. package/dist/index-D2orHGFi.d.ts +8 -0
  69. package/dist/index.cjs +793 -0
  70. package/dist/index.cjs.map +1 -0
  71. package/dist/index.d.cts +189 -0
  72. package/dist/index.d.ts +189 -0
  73. package/dist/index.js +793 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/restore-modal.cjs +9 -0
  76. package/dist/restore-modal.cjs.map +1 -0
  77. package/dist/restore-modal.d.cts +68 -0
  78. package/dist/restore-modal.d.ts +68 -0
  79. package/dist/restore-modal.js +9 -0
  80. package/dist/restore-modal.js.map +1 -0
  81. package/dist/wagmi-CVuDs_0h.d.cts +386 -0
  82. package/dist/wagmi-CVuDs_0h.d.ts +386 -0
  83. package/package.json +158 -0
  84. package/src/account-modal.ts +142 -0
  85. package/src/auto-setup.ts +362 -0
  86. package/src/avatar.ts +1135 -0
  87. package/src/backup-modal.ts +439 -0
  88. package/src/connect-modal/components/connection-view.ts +398 -0
  89. package/src/connect-modal/components/eoa-connection-view.ts +408 -0
  90. package/src/connect-modal/components/qr-code-view.ts +71 -0
  91. package/src/connect-modal/connect-modal.base.ts +18 -0
  92. package/src/connect-modal/connect-modal.config.ts +27 -0
  93. package/src/connect-modal/connect-modal.templates.ts +21 -0
  94. package/src/connect-modal/connect-modal.ts +270 -0
  95. package/src/connect-modal/connect-modal.types.ts +104 -0
  96. package/src/connect-modal/images/up-cube-glass.png +0 -0
  97. package/src/connect-modal/index.ts +23 -0
  98. package/src/connect-modal/services/wagmi.ts +266 -0
  99. package/src/connect-modal/styles/styles.css +1 -0
  100. package/src/connect-modal/utils/walletConnectDeepLinkUrl.ts +43 -0
  101. package/src/connector.ts +544 -0
  102. package/src/index.ts +62 -0
  103. package/src/popup-instance.ts +537 -0
  104. package/src/restore-modal.ts +702 -0
  105. package/src/styles/index.ts +28 -0
  106. package/src/styles/styles.css +1 -0
  107. package/src/types/css-raw.d.ts +4 -0
  108. package/src/types/images.d.ts +4 -0
  109. package/src/types.ts +168 -0
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Connect Modal - Lit Component
3
+ *
4
+ * Framework-agnostic connection modal for wallet/profile connections.
5
+ */
6
+
7
+ import { withDeviceService } from '@lukso/core/mixins'
8
+ import debug from 'debug'
9
+ import { html, type TemplateResult } from 'lit'
10
+ import { property, state } from 'lit/decorators.js'
11
+
12
+ import { ConnectModalBase } from './connect-modal.base.js'
13
+ import type {
14
+ ConnectionModalView,
15
+ ConnectModalTheme,
16
+ WalletConnector,
17
+ } from './connect-modal.types'
18
+ import { fromWagmiConnectors, getWagmiSetup } from './services/wagmi'
19
+
20
+ import '@lukso/web-components/dist/components/lukso-modal'
21
+ import './components/eoa-connection-view'
22
+ import './components/connection-view'
23
+ import './components/qr-code-view'
24
+
25
+ const logInfo = debug('connect-modal:info')
26
+
27
+ export class ConnectModal extends withDeviceService(ConnectModalBase) {
28
+ // Public properties
29
+ @property({ type: Boolean, reflect: true }) open = false
30
+ @property({ type: String, reflect: true }) theme: ConnectModalTheme = 'light'
31
+
32
+ // Private state
33
+ @state() private connectors: WalletConnector[] = []
34
+ @state() private isDark = false
35
+ @state() private modalView: ConnectionModalView = 'up_connection'
36
+ @state() private qrCodeData: string | undefined = undefined
37
+
38
+ private mediaQueryList: MediaQueryList | null = null
39
+
40
+ updated(changedProperties: Map<string, any>): void {
41
+ // Reset view and load connectors when modal opens
42
+ if (changedProperties.has('open') && this.open) {
43
+ this.modalView = 'up_connection' // Reset to main view when modal opens
44
+ this.loadConnectors()
45
+ }
46
+
47
+ // Handle theme changes
48
+ if (changedProperties.has('theme')) {
49
+ this.updateTheme()
50
+ }
51
+ }
52
+
53
+ connectedCallback(): void {
54
+ super.connectedCallback()
55
+ this.updateTheme()
56
+
57
+ // Listen for system theme changes when in 'auto' mode
58
+ if (this.theme === 'auto') {
59
+ this.mediaQueryList = window.matchMedia('(prefers-color-scheme: dark)')
60
+ this.mediaQueryList.addEventListener(
61
+ 'change',
62
+ this.handleMediaQueryChange
63
+ )
64
+ }
65
+ }
66
+
67
+ disconnectedCallback(): void {
68
+ super.disconnectedCallback()
69
+
70
+ if (this.mediaQueryList) {
71
+ this.mediaQueryList.removeEventListener(
72
+ 'change',
73
+ this.handleMediaQueryChange
74
+ )
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Handle system theme changes
80
+ *
81
+ * @param event
82
+ */
83
+ private handleMediaQueryChange = (event: MediaQueryListEvent): void => {
84
+ this.isDark = event.matches
85
+ }
86
+
87
+ /**
88
+ * Close modal
89
+ */
90
+ handleClose(): void {
91
+ this.open = false
92
+
93
+ this.dispatchEvent(
94
+ new CustomEvent('on-close', { bubbles: true, composed: true })
95
+ )
96
+ }
97
+
98
+ /**
99
+ * Update isDark state based on theme property
100
+ */
101
+ private updateTheme(): void {
102
+ if (this.theme === 'auto') {
103
+ this.isDark = window.matchMedia('(prefers-color-scheme: dark)').matches
104
+ } else {
105
+ this.isDark = this.theme === 'dark'
106
+ }
107
+ }
108
+
109
+ private async loadConnectors(): Promise<void> {
110
+ const globalWagmiSetup = getWagmiSetup()
111
+ logInfo('Global wagmi setup:', globalWagmiSetup)
112
+
113
+ if (!globalWagmiSetup) {
114
+ console.warn(
115
+ 'No global wagmi setup found! Call setupConnectModal() first.'
116
+ )
117
+ this.connectors = []
118
+ return
119
+ }
120
+
121
+ try {
122
+ const { wagmiConfig, chainId, embeddedWalletId } = globalWagmiSetup
123
+
124
+ // Get connectors from wagmi config
125
+ const wagmiConnectors = wagmiConfig?.connectors || []
126
+ logInfo('Initial connectors:', wagmiConnectors)
127
+
128
+ // Dynamically import wagmi's connect function to avoid bundling if not used
129
+ // Use dynamic import to keep @wagmi/core as an optional peer dependency
130
+ const wagmiCore = await import('@wagmi/core').catch((error) => {
131
+ throw new Error('@wagmi/core is required when using wagmi connectors', {
132
+ cause: error,
133
+ })
134
+ })
135
+
136
+ // Convert to WalletConnector format using the adapter
137
+ this.connectors = fromWagmiConnectors(
138
+ wagmiConnectors,
139
+ async (options: any) => {
140
+ await wagmiCore.connect(wagmiConfig, {
141
+ connector: options.connector,
142
+ chainId: options.chainId || chainId,
143
+ })
144
+ },
145
+ chainId,
146
+ embeddedWalletId
147
+ )
148
+ logInfo('Converted connectors:', this.connectors)
149
+ } catch (error) {
150
+ console.warn('Failed to load connectors', error)
151
+ this.connectors = []
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Successful connection handler
157
+ *
158
+ * @param connector
159
+ */
160
+ private handleOnConnectSuccess(event: CustomEvent): void {
161
+ event.stopPropagation() // Prevent event bubbling
162
+ const connector = event.detail.connector as WalletConnector
163
+ logInfo('Connection success:', connector)
164
+ this.open = false
165
+
166
+ // Dispatch connect event
167
+ this.dispatchEvent(
168
+ new CustomEvent('on-connect', {
169
+ detail: { connector },
170
+ bubbles: true,
171
+ composed: true,
172
+ })
173
+ )
174
+ }
175
+
176
+ /**
177
+ * Error connection handler
178
+ *
179
+ * @param error
180
+ */
181
+ private handleOnConnectError(event: CustomEvent): void {
182
+ event.stopPropagation() // Prevent event bubbling
183
+ const error = event.detail.error as Error
184
+ logInfo('Connection error:', error)
185
+
186
+ // Dispatch error event
187
+ this.dispatchEvent(
188
+ new CustomEvent('on-error', {
189
+ detail: { error },
190
+ bubbles: true,
191
+ composed: true,
192
+ })
193
+ )
194
+ }
195
+
196
+ private handleBackToConnectionView(event: CustomEvent): void {
197
+ event.stopPropagation() // Prevent event bubbling
198
+ this.modalView = 'up_connection'
199
+ }
200
+
201
+ private handleShowEoaConnectionsView = (event: CustomEvent): void => {
202
+ event.stopPropagation() // Prevent event bubbling
203
+ this.modalView = 'eoa_connection'
204
+ }
205
+
206
+ private handleShowQrCodeView = (event: CustomEvent): void => {
207
+ event.stopPropagation() // Prevent event bubbling
208
+ this.qrCodeData = event.detail.data
209
+ this.modalView = 'qr_code'
210
+ }
211
+
212
+ // ===== Template Methods =====
213
+
214
+ /**
215
+ * Render modal content based on current view flag
216
+ */
217
+ private renderModalContent(): TemplateResult<1> {
218
+ switch (this.modalView) {
219
+ case 'qr_code':
220
+ return html`<qr-code-view .data=${this.qrCodeData} @on-back=${this.handleBackToConnectionView}
221
+ @on-close=${this.handleClose}></qr-code-view>`
222
+ case 'eoa_connection':
223
+ return html`
224
+ <eoa-connection-view
225
+ .connectors=${this.connectors}
226
+ @on-back=${this.handleBackToConnectionView}
227
+ @on-close=${this.handleClose}
228
+ @on-connect=${this.handleOnConnectSuccess}
229
+ @on-error=${this.handleOnConnectError}
230
+ ></eoa-connection-view>
231
+ `
232
+ default: // up_connection
233
+ return html`
234
+ <connection-view
235
+ .connectors=${this.connectors}
236
+ @on-back=${this.handleBackToConnectionView}
237
+ @on-close=${this.handleClose}
238
+ @on-connect=${this.handleOnConnectSuccess}
239
+ @on-error=${this.handleOnConnectError}
240
+ @on-show-eoa-connections-view=${this.handleShowEoaConnectionsView}
241
+ @on-show-qr-code=${this.handleShowQrCodeView}
242
+ ></connection-view>
243
+ `
244
+ }
245
+ }
246
+
247
+ render(): TemplateResult<1> {
248
+ return html`
249
+ <lukso-modal
250
+ ?is-open=${this.open}
251
+ ?has-bottom-padding=${!!(this.device?.isIOS && this.device?.isSafari)}
252
+ size="auto"
253
+ @on-backdrop-click=${this.handleClose}
254
+ >
255
+ <div class="p-6 ${this.isDark ? 'dark' : ''} w-full sm:w-[372px] text-neutral-20">
256
+ ${this.renderModalContent()}
257
+ </div>
258
+ </lukso-modal>
259
+ `
260
+ }
261
+ }
262
+
263
+ // Register custom element
264
+ customElements.define('connect-modal', ConnectModal as any)
265
+
266
+ declare global {
267
+ interface HTMLElementTagNameMap {
268
+ 'connect-modal': ConnectModal
269
+ }
270
+ }
@@ -0,0 +1,104 @@
1
+ export interface WalletConnector {
2
+ id: string
3
+ name?: string
4
+ rdns?: string // Reverse DNS identifier (e.g., 'io.metamask')
5
+ slug?: string
6
+ type: 'embedded' | 'extension' | 'mobile' | 'injected' | 'walletconnect'
7
+ connect: () => Promise<void>
8
+ getProvider?: () => Promise<any>
9
+ }
10
+
11
+ export interface ConnectModalSetup {
12
+ /**
13
+ * Wagmi config instance
14
+ */
15
+ wagmiConfig: any
16
+
17
+ /**
18
+ * Optional chain ID to use for connections (defaults to first chain in config)
19
+ */
20
+ chainId?: number
21
+
22
+ /**
23
+ * Optional embedded wallet ID (to identify it in wagmi connectors)
24
+ * If provided, this connector will be shown first as "Create Passkey Wallet"
25
+ * Example: 'dev.lukso.auth'
26
+ */
27
+ embeddedWalletId?: string
28
+ }
29
+
30
+ // Minimal wagmi Connector interface (to avoid importing @wagmi/core)
31
+ export interface WagmiConnector {
32
+ uid: string
33
+ name: string
34
+ id: string
35
+ type: string
36
+ icon?: string
37
+ // Other wagmi connector properties...
38
+ [key: string]: any
39
+ }
40
+
41
+ export type ConnectModalTheme = 'light' | 'dark' | 'auto'
42
+
43
+ export type ConnectionModalView = 'up_connection' | 'qr_code' | 'eoa_connection'
44
+
45
+ export type WalletResponse = {
46
+ listings: {
47
+ [key in string]: Wallet
48
+ }
49
+ count: number
50
+ total: number
51
+ }
52
+
53
+ export type Wallet = {
54
+ id: string
55
+ name: string
56
+ slug: string
57
+ description: string
58
+ homepage: string
59
+ chains: string[]
60
+ versions: string[]
61
+ sdks: string[]
62
+ app_type: string
63
+ category: string
64
+ image_id: string
65
+ image_url: WalletImageUrl
66
+ app: WalletApp
67
+ rdns: string
68
+ mobile: WalletMobile
69
+ desktop: WalletDesktop
70
+ isInstalled: boolean
71
+ connector: WalletConnector | undefined
72
+ }
73
+
74
+ export type WalletImageUrl = {
75
+ sm: string
76
+ md: string
77
+ lg: string
78
+ }
79
+ export type WalletAppType =
80
+ | 'browser'
81
+ | 'ios'
82
+ | 'android'
83
+ | 'mac'
84
+ | 'windows'
85
+ | 'linux'
86
+ | 'chrome'
87
+ | 'firefox'
88
+ | 'safari'
89
+ | 'edge'
90
+ | 'opera'
91
+
92
+ export type WalletApp = {
93
+ [key in WalletAppType]?: string
94
+ }
95
+
96
+ export interface WalletMobile {
97
+ native?: string
98
+ universal?: string
99
+ }
100
+
101
+ export interface WalletDesktop {
102
+ native?: string
103
+ universal?: string
104
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Connect Modal - Barrel Export
3
+ *
4
+ * Exports the connect modal component and all related types and utilities
5
+ */
6
+
7
+ export { ConnectModalBase } from './connect-modal.base.js'
8
+ export { ConnectModal } from './connect-modal.js'
9
+ export type {
10
+ ConnectionModalView,
11
+ ConnectModalSetup,
12
+ ConnectModalTheme,
13
+ WagmiConnector,
14
+ Wallet,
15
+ WalletConnector,
16
+ } from './connect-modal.types'
17
+ export {
18
+ disconnectWagmi,
19
+ getWagmiAccount,
20
+ getWagmiSetup,
21
+ setupConnectModal,
22
+ watchWagmiAccount,
23
+ } from './services/wagmi'
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Wagmi Connector Adapter
3
+ * Converts wagmi/viem connectors to our WalletConnector format
4
+ */
5
+
6
+ import { slug } from '@lukso/core/utils'
7
+ import type {
8
+ ConnectModalSetup,
9
+ WagmiConnector,
10
+ } from '../connect-modal.types.js'
11
+ import type { WalletConnector } from '../index.js'
12
+
13
+ // UP Extension ID
14
+ const UP_EXTENSION_ID = 'cloud.universalprofile'
15
+
16
+ // Global wagmi setup storage
17
+ let globalWagmiSetup: ConnectModalSetup | null = null
18
+
19
+ /**
20
+ * Convert a wagmi connector to our WalletConnector format
21
+ * @param connector - Wagmi connector instance
22
+ * @param connectFn - Function to call connect (from wagmi's useConnect)
23
+ * @param chainId - Optional chain ID to use for connection
24
+ */
25
+ export function fromWagmiConnector(
26
+ connector: WagmiConnector,
27
+ connectFn: (options: {
28
+ connector: WagmiConnector
29
+ chainId?: number
30
+ }) => Promise<any>,
31
+ chainId?: number
32
+ ): WalletConnector {
33
+ // Determine connector type based on connector.id
34
+ let type: WalletConnector['type'] = 'injected'
35
+
36
+ // Extract rdns from connector (EIP-6963 providers expose this)
37
+ const rdns: string | undefined = connector.id
38
+
39
+ // Map wagmi connector types to our types
40
+ if (connector.id === 'walletConnect' || connector.type === 'walletConnect') {
41
+ type = 'walletconnect'
42
+ } else if (connector.id === 'injected' || connector.type === 'injected') {
43
+ type = 'injected'
44
+
45
+ // Check if this is UP Extension via ID
46
+ if (
47
+ connector.id === UP_EXTENSION_ID ||
48
+ connector.id.includes(UP_EXTENSION_ID)
49
+ ) {
50
+ type = 'extension'
51
+ }
52
+ }
53
+
54
+ return {
55
+ id: connector.uid || connector.id,
56
+ name: connector.name,
57
+ rdns,
58
+ type,
59
+ slug: slug(connector.name),
60
+ connect: async () => {
61
+ await connectFn({ connector, chainId })
62
+ },
63
+ getProvider: connector.getProvider
64
+ ? () => connector.getProvider()
65
+ : undefined,
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Convert array of wagmi connectors to WalletConnector array
71
+ * @param connectors - Array of wagmi connectors
72
+ * @param connectFn - Function to call connect (from wagmi's useConnect)
73
+ * @param chainId - Optional chain ID to use for connection
74
+ * @param embeddedWalletId - Optional embedded wallet ID to identify it (e.g., 'dev.lukso.auth')
75
+ */
76
+ export function fromWagmiConnectors(
77
+ connectors: WagmiConnector[],
78
+ connectFn: (options: {
79
+ connector: WagmiConnector
80
+ chainId?: number
81
+ }) => Promise<any>,
82
+ chainId?: number,
83
+ embeddedWalletId?: string
84
+ ): WalletConnector[] {
85
+ const result: WalletConnector[] = []
86
+
87
+ // 1. Find and add embedded wallet first (if ID provided)
88
+ // Check against original wagmi connector.id (not the converted UID)
89
+ let embeddedWalletConnector: WagmiConnector | undefined
90
+ let embeddedWallet: WalletConnector | undefined
91
+ if (embeddedWalletId) {
92
+ embeddedWalletConnector = connectors.find(
93
+ (connector) =>
94
+ connector.id === embeddedWalletId ||
95
+ connector.id.includes(embeddedWalletId)
96
+ )
97
+
98
+ if (embeddedWalletConnector) {
99
+ embeddedWallet = fromWagmiConnector(
100
+ embeddedWalletConnector,
101
+ connectFn,
102
+ chainId
103
+ )
104
+
105
+ // Customize for embedded wallet display
106
+ result.push({
107
+ ...embeddedWallet,
108
+ type: 'embedded',
109
+ slug: 'passkey-wallet',
110
+ })
111
+ }
112
+ }
113
+
114
+ // 2. Find and add UP Extension next (using ID)
115
+ const UP_EXTENSION_ID = 'cloud.universalprofile'
116
+ const upExtensionConnector = connectors.find(
117
+ (connector) =>
118
+ connector !== embeddedWalletConnector &&
119
+ (connector.id === UP_EXTENSION_ID ||
120
+ connector.id.includes(UP_EXTENSION_ID))
121
+ )
122
+
123
+ let upExtension: WalletConnector | undefined
124
+ if (upExtensionConnector) {
125
+ upExtension = fromWagmiConnector(upExtensionConnector, connectFn, chainId)
126
+ }
127
+
128
+ // Convert remaining wagmi connectors
129
+ const walletConnectors = connectors
130
+ .filter(
131
+ (connector) =>
132
+ connector !== embeddedWalletConnector &&
133
+ connector !== upExtensionConnector
134
+ )
135
+ .map((connector) => fromWagmiConnector(connector, connectFn, chainId))
136
+
137
+ if (upExtension) {
138
+ result.push(upExtension)
139
+ }
140
+
141
+ // 3. Find and add WalletConnect (for mobile)
142
+ const walletConnect = walletConnectors.find(
143
+ (connector) => connector.type === 'walletconnect'
144
+ )
145
+
146
+ if (walletConnect) {
147
+ result.push({
148
+ ...walletConnect,
149
+ type: 'mobile',
150
+ slug: 'up-mobile',
151
+ })
152
+ }
153
+
154
+ // 4. Add other wallets
155
+ const others = walletConnectors.filter(
156
+ (connector) =>
157
+ connector !== embeddedWallet &&
158
+ connector !== upExtension &&
159
+ connector !== walletConnect
160
+ )
161
+ result.push(...others)
162
+
163
+ return result
164
+ }
165
+
166
+ /**
167
+ * Setup wagmi for connect modal
168
+ * Call this once from your app initialization with wagmi config
169
+ *
170
+ * @example
171
+ * ```typescript
172
+ * import { setupConnectModal } from '@lukso/up-connector'
173
+ * import { wagmiConfig } from './wagmi-config'
174
+ *
175
+ * setupConnectModal({
176
+ * wagmiConfig,
177
+ * chainId: 42, // Optional: LUKSO mainnet
178
+ * embeddedWalletConnect: async () => {
179
+ * // Your passkey wallet logic
180
+ * }
181
+ * })
182
+ * ```
183
+ */
184
+ export function setupConnectModal(setup: ConnectModalSetup): void {
185
+ globalWagmiSetup = setup
186
+ }
187
+
188
+ /**
189
+ * Get the current wagmi setup (for internal use by connector)
190
+ */
191
+ export function getWagmiSetup(): ConnectModalSetup | null {
192
+ return globalWagmiSetup
193
+ }
194
+
195
+ /**
196
+ * Get current wagmi account state
197
+ * Returns null if wagmi is not set up
198
+ */
199
+ export async function getWagmiAccount(): Promise<{
200
+ isConnected: boolean
201
+ address?: string
202
+ chainId?: number
203
+ connector?: any
204
+ } | null> {
205
+ if (!globalWagmiSetup) {
206
+ return null
207
+ }
208
+
209
+ try {
210
+ const { getAccount } = await import('@wagmi/core')
211
+ const account = getAccount(globalWagmiSetup.wagmiConfig)
212
+ return account
213
+ } catch (_error) {
214
+ return null
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Subscribe to wagmi account changes
220
+ * Returns unsubscribe function
221
+ */
222
+ export async function watchWagmiAccount(
223
+ callback: (account: {
224
+ isConnected: boolean
225
+ address?: string
226
+ chainId?: number
227
+ connector?: any
228
+ }) => void
229
+ ): Promise<(() => void) | null> {
230
+ if (!globalWagmiSetup) {
231
+ return null
232
+ }
233
+
234
+ try {
235
+ const { watchAccount } = await import('@wagmi/core')
236
+
237
+ const unsubscribe = watchAccount(globalWagmiSetup.wagmiConfig, {
238
+ onChange: (account) => {
239
+ callback(account)
240
+ },
241
+ })
242
+
243
+ return unsubscribe
244
+ } catch (_error) {
245
+ return null
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Disconnect from wagmi
251
+ * Returns true if disconnect was successful
252
+ */
253
+ export async function disconnectWagmi(): Promise<boolean> {
254
+ if (!globalWagmiSetup) {
255
+ return false
256
+ }
257
+
258
+ try {
259
+ const { disconnect } = await import('@wagmi/core')
260
+ await disconnect(globalWagmiSetup.wagmiConfig)
261
+ return true
262
+ } catch (error) {
263
+ console.warn('Failed to disconnect from wagmi', error)
264
+ return false
265
+ }
266
+ }
@@ -0,0 +1 @@
1
+ @import "@lukso/web-components/dist/styles/main.css";
@@ -0,0 +1,43 @@
1
+ import { MOBILE_APP_DEEP_LINK_PREFIX } from '../connect-modal.config'
2
+
3
+ /**
4
+ * URL to Mobile App deep link used by Wallet Connect
5
+ *
6
+ * @param data
7
+ */
8
+ export const walletConnectDeepLinkUrl = (
9
+ data?: string,
10
+ options?: {
11
+ withRedirectUrl?: boolean
12
+ }
13
+ ) => {
14
+ try {
15
+ if (!data || typeof data !== 'string') {
16
+ return ''
17
+ }
18
+
19
+ const dataUrl = new URL(data)
20
+
21
+ // add redirectUrl to deep link
22
+ if (options?.withRedirectUrl) {
23
+ const redirectUrl = new URL(location.href)
24
+
25
+ // remove modal query params so we don't re-open the modal
26
+ redirectUrl.searchParams.delete('modalTemplate')
27
+ redirectUrl.searchParams.delete('modalSize')
28
+
29
+ // add redirectUrl to dataUrl
30
+ dataUrl.searchParams.append(
31
+ 'redirectUrl',
32
+ `${redirectUrl.origin}${redirectUrl.pathname}${redirectUrl.search}`
33
+ )
34
+ }
35
+
36
+ const deepLink = `${MOBILE_APP_DEEP_LINK_PREFIX}://wallet-connect/${dataUrl.pathname}${dataUrl.search}`
37
+
38
+ return deepLink
39
+ } catch (error: unknown) {
40
+ console.warn(error)
41
+ return ''
42
+ }
43
+ }