@monygroupcorp/micro-web3 1.2.3 → 1.3.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.
@@ -1,4 +1,4 @@
1
- import { Component, eventBus } from '@monygroupcorp/microact';
1
+ import { Component, h, render, eventBus } from '@monygroupcorp/microact';
2
2
  import WalletModal from '../Wallet/WalletModal.js';
3
3
  import { SettingsModal } from '../SettingsModal/SettingsModal.js';
4
4
  import { ethers } from 'ethers';
@@ -10,7 +10,7 @@ import { ethers } from 'ethers';
10
10
  */
11
11
  export class FloatingWalletButton extends Component {
12
12
  constructor(props) {
13
- super();
13
+ super(props);
14
14
  this.walletService = props.walletService;
15
15
  this.walletModal = null;
16
16
  this.settingsModal = null;
@@ -26,10 +26,10 @@ export class FloatingWalletButton extends Component {
26
26
  };
27
27
  }
28
28
 
29
- onMount() {
30
- console.log('[FloatingWalletButton] onMount called');
31
- this.initialize();
32
- this.setupDOMEventListeners();
29
+ didMount() {
30
+ console.log('[FloatingWalletButton] didMount called');
31
+ this.initialize();
32
+ this.setupClickOutsideHandler();
33
33
  }
34
34
 
35
35
  async initialize() {
@@ -171,12 +171,12 @@ export class FloatingWalletButton extends Component {
171
171
 
172
172
  setupEventListeners() {
173
173
  // Listen for wallet connection
174
- const unsubscribeConnected = eventBus.on('wallet:connected', async (data) => {
174
+ this.subscribe('wallet:connected', async (data) => {
175
175
  await this.loadWalletInfo(data.address);
176
176
  });
177
177
 
178
178
  // Listen for wallet disconnection
179
- const unsubscribeDisconnected = eventBus.on('wallet:disconnected', () => {
179
+ this.subscribe('wallet:disconnected', () => {
180
180
  this.setState({
181
181
  walletConnected: false,
182
182
  address: null,
@@ -188,16 +188,9 @@ export class FloatingWalletButton extends Component {
188
188
  });
189
189
 
190
190
  // Listen for wallet/account change
191
- const unsubscribeChanged = eventBus.on('wallet:changed', async (data) => {
191
+ this.subscribe('wallet:changed', async (data) => {
192
192
  await this.loadWalletInfo(data.address);
193
193
  });
194
-
195
- // Register cleanup
196
- this.registerCleanup(() => {
197
- unsubscribeConnected();
198
- unsubscribeDisconnected();
199
- unsubscribeChanged();
200
- });
201
194
  }
202
195
 
203
196
  setupClickOutsideHandler() {
@@ -217,7 +210,7 @@ export class FloatingWalletButton extends Component {
217
210
  });
218
211
  }
219
212
 
220
- async handleButtonClick(e) {
213
+ handleButtonClick(e) {
221
214
  e.preventDefault();
222
215
  e.stopPropagation();
223
216
 
@@ -226,11 +219,11 @@ export class FloatingWalletButton extends Component {
226
219
  this.setState({ menuOpen: !this.state.menuOpen });
227
220
  } else {
228
221
  // Show wallet connection modal
229
- await this.showWalletModal();
222
+ this.showWalletModal();
230
223
  }
231
224
  }
232
225
 
233
- async showWalletModal() {
226
+ showWalletModal() {
234
227
  // Get provider map and icons from this.walletService
235
228
  const providerMap = {
236
229
  rabby: () => window.ethereum?.isRabby ? window.ethereum : null,
@@ -248,22 +241,21 @@ export class FloatingWalletButton extends Component {
248
241
 
249
242
  // Create WalletModal if not exists
250
243
  if (!this.walletModal) {
251
- this.walletModal = new WalletModal({
244
+ if (!this.modalRoot) {
245
+ this.modalRoot = document.createElement('div');
246
+ document.body.appendChild(this.modalRoot);
247
+ }
248
+ render(h(WalletModal, {
252
249
  providerMap,
253
250
  walletIcons,
254
251
  onWalletSelected: async (walletType) => {
255
252
  await this.handleWalletSelection(walletType);
256
253
  },
257
- });
258
-
259
- if (!this.modalRoot) {
260
- this.modalRoot = document.createElement('div');
261
- document.body.appendChild(this.modalRoot);
262
- }
263
- this.walletModal.mount(this.modalRoot);
254
+ ref: instance => this.walletModal = instance
255
+ }), this.modalRoot);
264
256
  }
265
257
 
266
- this.walletModal.show();
258
+ this.walletModal?.show();
267
259
  }
268
260
 
269
261
  async handleWalletSelection(walletType) {
@@ -297,12 +289,12 @@ export class FloatingWalletButton extends Component {
297
289
  }
298
290
  }
299
291
 
300
- async handleDisconnect(e) {
292
+ handleDisconnect(e) {
301
293
  e.preventDefault();
302
294
  e.stopPropagation();
303
295
 
304
296
  try {
305
- await this.walletService.disconnect();
297
+ this.walletService.disconnect();
306
298
  this.setState({ menuOpen: false });
307
299
  } catch (error) {
308
300
  console.error('[FloatingWalletButton] Failed to disconnect:', error);
@@ -544,142 +536,105 @@ export class FloatingWalletButton extends Component {
544
536
  render() {
545
537
  console.log('[FloatingWalletButton] render called, loading:', this.state.loading, 'walletConnected:', this.state.walletConnected);
546
538
  if (this.state.loading) {
547
- return `
548
- <div class="floating-wallet-button loading">
549
- <div class="wallet-spinner"></div>
550
- </div>
551
- `;
539
+ return h('div', { className: 'floating-wallet-button loading' },
540
+ h('div', { className: 'wallet-spinner' })
541
+ );
552
542
  }
553
543
 
554
544
  const { walletConnected, address, balance, menuOpen, hasExecTokens, isVaultBenefactor } = this.state;
555
545
 
556
546
  if (!walletConnected) {
557
547
  // Not connected - show "Connect" button
558
- return `
559
- <div class="floating-wallet-button disconnected" data-ref="wallet-button">
560
- <button class="wallet-btn" data-ref="connect-btn">
561
- <span class="wallet-icon">🦊</span>
562
- <span class="wallet-text">Connect</span>
563
- </button>
564
- </div>
565
- `;
548
+ return h('div', { className: 'floating-wallet-button disconnected', ref: el => this.element = el },
549
+ h('button', {
550
+ className: 'wallet-btn',
551
+ onClick: this.bind(this.handleButtonClick)
552
+ },
553
+ h('span', { className: 'wallet-icon' }, '\uD83E\uDD8A'),
554
+ h('span', { className: 'wallet-text' }, 'Connect')
555
+ )
556
+ );
566
557
  }
567
558
 
568
559
  // Connected - show abbreviated address
569
560
  const truncatedAddress = `${address.slice(0, 6)}...${address.slice(-4)}`;
570
561
 
571
- return `
572
- <div class="floating-wallet-button connected ${menuOpen ? 'menu-open' : ''}" data-ref="wallet-button">
573
- <button class="wallet-btn" data-ref="wallet-btn" title="${this.escapeHtml(address)}\nBalance: ${balance} ETH">
574
- <span class="wallet-icon">🦊</span>
575
- <span class="wallet-address">${this.escapeHtml(truncatedAddress)}</span>
576
- </button>
577
-
578
- ${menuOpen ? this.renderDropdownMenu(address, balance, hasExecTokens, isVaultBenefactor) : ''}
579
- </div>
580
- `;
562
+ return h('div', {
563
+ className: `floating-wallet-button connected ${menuOpen ? 'menu-open' : ''}`,
564
+ ref: el => this.element = el
565
+ },
566
+ h('button', {
567
+ className: 'wallet-btn',
568
+ title: `${this.escapeHtml(address)}\nBalance: ${balance} ETH`,
569
+ onClick: this.bind(this.handleButtonClick)
570
+ },
571
+ h('span', { className: 'wallet-icon' }, '\uD83E\uDD8A'),
572
+ h('span', { className: 'wallet-address' }, this.escapeHtml(truncatedAddress))
573
+ ),
574
+ menuOpen && this.renderDropdownMenu(address, balance, hasExecTokens, isVaultBenefactor)
575
+ );
581
576
  }
582
577
 
583
578
  renderDropdownMenu(address, balance, hasExecTokens, isVaultBenefactor) {
584
579
  const truncatedAddress = `${address.slice(0, 6)}...${address.slice(-4)}`;
585
580
 
586
- return `
587
- <div class="wallet-dropdown-menu" data-ref="dropdown-menu">
588
- <div class="dropdown-header">
589
- <div class="dropdown-address">${this.escapeHtml(truncatedAddress)}</div>
590
- <div class="dropdown-balance">${balance} ETH</div>
591
- </div>
592
-
593
- <div class="dropdown-divider"></div>
594
-
595
- <div class="dropdown-items">
596
- <button class="dropdown-item" data-route="/portfolio" data-ref="menu-item">
597
- <span class="item-icon">📊</span>
598
- <span class="item-label">Portfolio</span>
599
- </button>
600
-
601
- ${hasExecTokens ? `
602
- <button class="dropdown-item" data-route="/governance" data-ref="menu-item">
603
- <span class="item-icon">🗳️</span>
604
- <span class="item-label">Governance</span>
605
- </button>
606
- ` : ''}
607
-
608
- <button class="dropdown-item" data-route="/staking" data-ref="menu-item">
609
- <span class="item-icon">🎯</span>
610
- <span class="item-label">Staking</span>
611
- </button>
612
-
613
- ${isVaultBenefactor ? `
614
- <button class="dropdown-item" data-route="/portfolio?filter=vaults" data-ref="menu-item">
615
- <span class="item-icon">💰</span>
616
- <span class="item-label">Vault Positions</span>
617
- </button>
618
- ` : ''}
619
- </div>
620
-
621
- <div class="dropdown-divider"></div>
622
-
623
- <div class="dropdown-items">
624
- <button class="dropdown-item" data-action="settings" data-ref="menu-item">
625
- <span class="item-icon">⚙️</span>
626
- <span class="item-label">Settings</span>
627
- </button>
628
-
629
- <button class="dropdown-item disconnect" data-ref="disconnect-btn">
630
- <span class="item-icon">🔌</span>
631
- <span class="item-label">Disconnect</span>
632
- </button>
633
- </div>
634
- </div>
635
- `;
636
- }
637
-
638
- setupDOMEventListeners() {
639
- console.log('[FloatingWalletButton] setupDOMEventListeners called, element:', this.element);
640
- if (!this.element) return;
641
-
642
- // Main button click handler - use querySelector directly since getRef only takes one param
643
- const mainBtn = this.element.querySelector('.wallet-btn');
644
- console.log('[FloatingWalletButton] mainBtn found:', mainBtn);
645
-
646
- if (mainBtn) {
647
- mainBtn.addEventListener('click', (e) => this.handleButtonClick(e));
648
- }
649
-
650
- // Menu item click handlers
651
- const menuItems = Array.from(this.element.querySelectorAll('.dropdown-item[data-route], .dropdown-item[data-action]'));
652
- menuItems.forEach(item => {
653
- item.addEventListener('click', (e) => {
654
- e.preventDefault();
655
- e.stopPropagation();
656
-
657
- const route = item.getAttribute('data-route');
658
- const action = item.getAttribute('data-action');
659
-
660
- if (route) {
661
- this.handleMenuItemClick(route);
662
- } else if (action === 'settings') {
663
- this.setState({ menuOpen: false });
664
- this.openSettings();
665
- }
666
- });
667
- });
668
-
669
- // Disconnect button handler
670
- const disconnectBtn = this.element.querySelector('.dropdown-item.disconnect');
671
- if (disconnectBtn) {
672
- disconnectBtn.addEventListener('click', (e) => this.handleDisconnect(e));
673
- }
674
- }
675
-
676
- onStateUpdate(oldState, newState) {
677
- // Re-setup DOM listeners when state changes
678
- if (oldState.menuOpen !== newState.menuOpen) {
679
- this.setTimeout(() => {
680
- this.setupDOMEventListeners();
681
- }, 0);
682
- }
581
+ return h('div', { className: 'wallet-dropdown-menu' },
582
+ h('div', { className: 'dropdown-header' },
583
+ h('div', { className: 'dropdown-address' }, this.escapeHtml(truncatedAddress)),
584
+ h('div', { className: 'dropdown-balance' }, `${balance} ETH`)
585
+ ),
586
+ h('div', { className: 'dropdown-divider' }),
587
+ h('div', { className: 'dropdown-items' },
588
+ h('button', {
589
+ className: 'dropdown-item',
590
+ onClick: () => this.handleMenuItemClick('/portfolio')
591
+ },
592
+ h('span', { className: 'item-icon' }, '\uD83D\uDCCA'),
593
+ h('span', { className: 'item-label' }, 'Portfolio')
594
+ ),
595
+ hasExecTokens && h('button', {
596
+ className: 'dropdown-item',
597
+ onClick: () => this.handleMenuItemClick('/governance')
598
+ },
599
+ h('span', { className: 'item-icon' }, '\uD83D\uDDF3\uFE0F'),
600
+ h('span', { className: 'item-label' }, 'Governance')
601
+ ),
602
+ h('button', {
603
+ className: 'dropdown-item',
604
+ onClick: () => this.handleMenuItemClick('/staking')
605
+ },
606
+ h('span', { className: 'item-icon' }, '\uD83C\uDFAF'),
607
+ h('span', { className: 'item-label' }, 'Staking')
608
+ ),
609
+ isVaultBenefactor && h('button', {
610
+ className: 'dropdown-item',
611
+ onClick: () => this.handleMenuItemClick('/portfolio?filter=vaults')
612
+ },
613
+ h('span', { className: 'item-icon' }, '\uD83D\uDCB0'),
614
+ h('span', { className: 'item-label' }, 'Vault Positions')
615
+ )
616
+ ),
617
+ h('div', { className: 'dropdown-divider' }),
618
+ h('div', { className: 'dropdown-items' },
619
+ h('button', {
620
+ className: 'dropdown-item',
621
+ onClick: () => {
622
+ this.setState({ menuOpen: false });
623
+ this.openSettings();
624
+ }
625
+ },
626
+ h('span', { className: 'item-icon' }, '\u2699\uFE0F'),
627
+ h('span', { className: 'item-label' }, 'Settings')
628
+ ),
629
+ h('button', {
630
+ className: 'dropdown-item disconnect',
631
+ onClick: this.bind(this.handleDisconnect)
632
+ },
633
+ h('span', { className: 'item-icon' }, '\uD83D\uDD0C'),
634
+ h('span', { className: 'item-label' }, 'Disconnect')
635
+ )
636
+ )
637
+ );
683
638
  }
684
639
 
685
640
  openSettings() {
@@ -689,7 +644,7 @@ export class FloatingWalletButton extends Component {
689
644
  this.settingsModal.show();
690
645
  }
691
646
 
692
- onUnmount() {
647
+ willUnmount() {
693
648
  // Clean up wallet modal
694
649
  if (this.walletModal) {
695
650
  this.walletModal.hide();