@gluwa/connect-kit 0.2.0-next.1 → 0.2.0-next.3

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 (89) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/assets/creditwallet.png +0 -0
  3. package/assets/fonts/Inter-Medium.ttf +0 -0
  4. package/assets/fonts/Inter-Medium.woff2 +0 -0
  5. package/assets/fonts/Inter-Regular.ttf +0 -0
  6. package/assets/fonts/Inter-Regular.woff2 +0 -0
  7. package/assets/fonts/Inter-SemiBold.ttf +0 -0
  8. package/assets/fonts/Inter-SemiBold.woff2 +0 -0
  9. package/assets/graphic.png +0 -0
  10. package/assets/metamask.png +0 -0
  11. package/assets/wc-logo.svg +3 -0
  12. package/assets/wc-search.png +0 -0
  13. package/dist/chunk-EDNRW47A.js +401 -0
  14. package/dist/credit-connect.js +2 -409
  15. package/dist/index.css +1903 -390
  16. package/dist/index.d.ts +16 -10
  17. package/dist/index.js +1110 -870
  18. package/dist/package.json +7 -6
  19. package/package.json +8 -8
  20. package/src/ConnectKitProvider.tsx +90 -65
  21. package/src/assets.d.ts +5 -0
  22. package/src/components/actionItem/index.tsx +50 -0
  23. package/src/components/actionItem/style.scss +47 -0
  24. package/src/components/copyLink/index.tsx +16 -0
  25. package/src/components/copyLink/style.scss +16 -0
  26. package/src/components/qrArea/index.tsx +70 -0
  27. package/src/components/qrArea/style.scss +130 -0
  28. package/src/components/searchBar/asset/Search.tsx +20 -0
  29. package/src/components/searchBar/asset/XMarkCircle.tsx +24 -0
  30. package/src/components/searchBar/index.tsx +44 -0
  31. package/src/components/searchBar/style.scss +58 -0
  32. package/src/components/snackbar/index.tsx +25 -0
  33. package/src/components/snackbar/style.scss +51 -0
  34. package/src/components/toggle/index.tsx +27 -0
  35. package/src/components/toggle/style.scss +53 -0
  36. package/src/components/walletGrid/index.tsx +64 -0
  37. package/src/components/walletGrid/style.scss +108 -0
  38. package/src/components/walletItem/index.tsx +49 -0
  39. package/src/components/walletItem/style.scss +70 -0
  40. package/src/connector-meta.ts +12 -7
  41. package/src/core/config.ts +20 -1
  42. package/src/creditConnectConnector.ts +17 -25
  43. package/src/hooks/useWCState.ts +22 -5
  44. package/src/hooks/useWagmiConnect.ts +0 -1
  45. package/src/index.ts +2 -2
  46. package/src/layout/allWallets/index.tsx +52 -0
  47. package/src/layout/allWallets/style.scss +62 -0
  48. package/src/layout/connectDialog/asset/backIcon.tsx +24 -0
  49. package/src/layout/connectDialog/asset/checkIcon.tsx +28 -0
  50. package/src/layout/connectDialog/asset/closeIcon.tsx +21 -0
  51. package/src/layout/connectDialog/asset/copyIcon.tsx +28 -0
  52. package/src/layout/connectDialog/asset/linkIcon.tsx +24 -0
  53. package/src/layout/connectDialog/asset/spinner.tsx +21 -0
  54. package/src/layout/connectDialog/idle/index.tsx +32 -0
  55. package/src/layout/connectDialog/idle/style.scss +61 -0
  56. package/src/layout/connectDialog/index.tsx +286 -0
  57. package/src/layout/connectDialog/loading/index.tsx +13 -0
  58. package/src/layout/connectDialog/loading/style.scss +19 -0
  59. package/src/layout/connectDialog/metaMask/index.tsx +61 -0
  60. package/src/layout/connectDialog/metaMask/style.scss +65 -0
  61. package/src/layout/connectDialog/qr/index.tsx +33 -0
  62. package/src/layout/connectDialog/style.scss +95 -0
  63. package/src/layout/connectDialog/timeout/index.tsx +31 -0
  64. package/src/layout/connectDialog/timeout/style.scss +64 -0
  65. package/src/layout/connectDialog/walletConnect/index.tsx +45 -0
  66. package/src/layout/connectDialog/walletConnect/style.scss +48 -0
  67. package/src/layout/connectDialog/walletQR/index.tsx +37 -0
  68. package/src/layout/detailPanel/index.tsx +147 -0
  69. package/src/layout/detailPanel/style.scss +64 -0
  70. package/src/layout/selectorPanel/index.tsx +100 -0
  71. package/src/layout/selectorPanel/style.scss +113 -0
  72. package/src/style/color.scss +417 -0
  73. package/src/style/font.scss +28 -0
  74. package/src/style/index.scss +5 -0
  75. package/src/style/mixin.scss +217 -0
  76. package/src/style/reset.scss +110 -0
  77. package/src/style/variables.scss +13 -0
  78. package/src/types.ts +11 -8
  79. package/src/utils/platform.ts +6 -0
  80. package/tsup.config.ts +32 -2
  81. package/dist/chunk-DDA6FP6U.js +0 -7
  82. package/src/ConnectModal.scss +0 -665
  83. package/src/ConnectModal.tsx +0 -573
  84. package/src/components/QRFrame.tsx +0 -43
  85. package/src/views/CreditWalletView.tsx +0 -58
  86. package/src/views/IdleView.tsx +0 -10
  87. package/src/views/MetaMaskView.tsx +0 -66
  88. package/src/views/SwitchChainView.tsx +0 -72
  89. package/src/views/WalletConnectView.tsx +0 -206
@@ -0,0 +1,130 @@
1
+ @use '../../style/mixin.scss' as *;
2
+
3
+ .ck-qr-area {
4
+ display: flex;
5
+ align-items: center;
6
+ justify-content: center;
7
+ flex: 1;
8
+ width: 100%;
9
+ padding-bottom: 32px;
10
+ }
11
+
12
+ // .ck-qr-group {
13
+ // display: flex;
14
+ // flex-direction: column;
15
+ // align-items: center;
16
+ // gap: 24px;
17
+ // }
18
+
19
+ // ── Text ──────────────────────────────────────────────────────────────────────
20
+ .ck-qr-text {
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: center;
24
+ gap: 6px;
25
+ width: 100%;
26
+ margin-top: 24px;
27
+ }
28
+
29
+ .ck-qr-label {
30
+ @include textToken('subtitle2-bold');
31
+ color: var(--scale-gray-900);
32
+ text-align: center;
33
+ }
34
+
35
+ .ck-qr {
36
+ display: flex;
37
+ flex-direction: column;
38
+ align-items: center;
39
+ margin: 0;
40
+ border-radius: 20px;
41
+ overflow: hidden;
42
+ outline: none;
43
+ }
44
+
45
+ .ck-qr-loading {
46
+ border: 1px solid var(--semantic-divider-divider-1);
47
+ }
48
+
49
+ .ck-qr-timeout {
50
+ border: 1px solid var(--semantic-divider-divider-1);
51
+ }
52
+
53
+ // ── Skeleton ──────────────────────────────────────────────────────────────────
54
+ .ck-qr-skeleton {
55
+ width: 248px;
56
+ height: 248px;
57
+ background: linear-gradient(
58
+ 132deg,
59
+ var(--scale-gray-100) 36%,
60
+ var(--scale-gray-200) 51%,
61
+ var(--scale-gray-100) 66%
62
+ );
63
+ background-size: 200% 100%;
64
+ animation: ck-qr-shimmer 1.5s linear infinite;
65
+
66
+ @include tablet {
67
+ width: 200px;
68
+ height: 200px;
69
+ }
70
+ }
71
+
72
+ @keyframes ck-qr-shimmer {
73
+ 0% { background-position: 200% 0; }
74
+ 100% { background-position: -200% 0; }
75
+ }
76
+
77
+ // ── Ready ─────────────────────────────────────────────────────────────────────
78
+ .ck-qr-frame {
79
+ --ck-qr-bg: transparent;
80
+ padding: 20px;
81
+ border-radius: 20px;
82
+ border: 1px solid var(--semantic-divider-divider-1);
83
+
84
+ svg {
85
+ display: block;
86
+ width: 246px;
87
+ height: 246px;
88
+
89
+ @include tablet {
90
+ width: 198px;
91
+ height: 198px;
92
+ }
93
+ }
94
+ }
95
+
96
+ // ── Timeout ───────────────────────────────────────────────────────────────────
97
+ .ck-qr-timeout {
98
+ width: 248px;
99
+ height: 248px;
100
+ background: var(--scale-gray-100);
101
+ display: flex;
102
+ align-items: center;
103
+ justify-content: center;
104
+
105
+ @include tablet {
106
+ width: 200px;
107
+ height: 200px;
108
+ }
109
+ }
110
+
111
+ .ck-qr-timeout-inner {
112
+ display: flex;
113
+ flex-direction: column;
114
+ align-items: center;
115
+ gap: 8px;
116
+ }
117
+
118
+ .ck-qr-timeout-icon {
119
+ display: block;
120
+ width: 32px;
121
+ height: 32px;
122
+ background: var(--scale-gray-400);
123
+ border-radius: 50%;
124
+ }
125
+
126
+ .ck-qr-timeout-text {
127
+ @include textToken('label5-regular');
128
+ color: var(--scale-gray-600);
129
+ text-align: center;
130
+ }
@@ -0,0 +1,20 @@
1
+ import { type FC, type SVGProps } from 'react';
2
+
3
+ export const SearchIcon: FC<SVGProps<SVGSVGElement>> = (props) => {
4
+ return (
5
+ <svg
6
+ xmlns="http://www.w3.org/2000/svg"
7
+ width="20"
8
+ height="19"
9
+ viewBox="0 0 20 19"
10
+ fill="none"
11
+ aria-hidden="true"
12
+ {...props}
13
+ >
14
+ <path
15
+ d="M14.4688 8.03418C14.4688 4.48066 11.5877 1.59961 8.03418 1.59961C4.48068 1.59963 1.59961 4.48067 1.59961 8.03418C1.59963 11.5877 4.48069 14.4688 8.03418 14.4688C11.5877 14.4688 14.4688 11.5877 14.4688 8.03418ZM16.0577 8.44726C15.9732 10.1146 15.3799 11.6473 14.4307 12.8946L19.0674 17.5108L19.1221 17.5713C19.3788 17.8848 19.3608 18.3474 19.0674 18.6397C18.7738 18.9319 18.3091 18.95 17.9942 18.6944L17.9336 18.6397L13.3389 14.0645C12.0201 15.2255 10.3191 15.9628 8.44726 16.0576L8.03418 16.0684C3.59703 16.0684 1.9e-05 12.4714 0 8.03418L0.010742 7.62109C0.225741 3.3759 3.73556 1.8e-05 8.03418 0L8.44726 0.010742C12.6925 0.225746 16.0684 3.73555 16.0684 8.03418L16.0577 8.44726Z"
16
+ fill="currentColor"
17
+ />
18
+ </svg>
19
+ );
20
+ };
@@ -0,0 +1,24 @@
1
+ import { type FC, type SVGProps } from 'react';
2
+
3
+ export const XMarkCircleIcon: FC<SVGProps<SVGSVGElement>> = (props) => {
4
+ return (
5
+ <svg
6
+ width={20}
7
+ height={20}
8
+ viewBox="0 0 20 20"
9
+ fill="none"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ aria-hidden="true"
12
+ focusable="false"
13
+ {...props}
14
+ >
15
+ <circle cx="10" cy="10" r="10" fill="currentColor" />
16
+ <path
17
+ d="M6.5 6.5L13.5 13.5M13.5 6.5L6.5 13.5"
18
+ stroke="var(--semantic-paper-sheet)"
19
+ strokeWidth="1.5"
20
+ strokeLinecap="round"
21
+ />
22
+ </svg>
23
+ );
24
+ };
@@ -0,0 +1,44 @@
1
+ import { type FC, type ChangeEvent } from 'react';
2
+ import './style.scss';
3
+ import { SearchIcon } from './asset/Search';
4
+ import { XMarkCircleIcon } from './asset/XMarkCircle';
5
+
6
+ interface SearchBarProps {
7
+ value: string;
8
+ placeholder?: string;
9
+ onChange: (value: string) => void;
10
+ onClear: () => void;
11
+ }
12
+
13
+ export const SearchBar: FC<SearchBarProps> = ({
14
+ value,
15
+ placeholder = 'Search wallet',
16
+ onChange,
17
+ onClear,
18
+ }) => {
19
+ const handleChange = (e: ChangeEvent<HTMLInputElement>) => onChange(e.target.value);
20
+
21
+ return (
22
+ <div className="ck-search">
23
+ <SearchIcon className="ck-search-icon" />
24
+ <input
25
+ className="ck-search-input"
26
+ type="search"
27
+ value={value}
28
+ placeholder={placeholder}
29
+ onChange={handleChange}
30
+ aria-label="Search wallet"
31
+ />
32
+ <button
33
+ type="button"
34
+ className="ck-search-clear"
35
+ onClick={onClear}
36
+ aria-label="Clear search"
37
+ aria-hidden={!value || undefined}
38
+ tabIndex={value ? 0 : -1}
39
+ >
40
+ <XMarkCircleIcon />
41
+ </button>
42
+ </div>
43
+ );
44
+ };
@@ -0,0 +1,58 @@
1
+ @use '../../style/mixin.scss' as *;
2
+
3
+ .ck-root .ck-search {
4
+ display: flex;
5
+ align-items: center;
6
+ gap: 6px;
7
+ flex: 1;
8
+ padding: 12px 16px;
9
+ border-radius: 100px;
10
+ background: var(--scale-gray-100);
11
+ border: 1px solid transparent;
12
+ transition: border-color 0.15s ease;
13
+
14
+ &:focus-within {
15
+ border-color: var(--semantic-brand-trugi-primary);
16
+ }
17
+ }
18
+
19
+ .ck-search-icon {
20
+ display: block;
21
+ flex-shrink: 0;
22
+ color: var(--scale-gray-500);
23
+ width: 20px;
24
+ height: 19px;
25
+ }
26
+
27
+ .ck-root .ck-search-input {
28
+ flex: 1;
29
+ @include textToken('body4-l2-regular');
30
+ color: var(--scale-gray-900);
31
+ caret-color: var(--semantic-brand-trugi-primary);
32
+ background: none;
33
+ min-width: 0;
34
+
35
+ &::placeholder {
36
+ color: var(--scale-gray-500);
37
+ }
38
+
39
+ &::-webkit-search-cancel-button {
40
+ display: none;
41
+ }
42
+ }
43
+
44
+ .ck-root .ck-search-clear {
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ width: 20px;
49
+ height: 20px;
50
+ flex-shrink: 0;
51
+ color: var(--scale-gray-500);
52
+ cursor: pointer;
53
+ visibility: hidden;
54
+
55
+ &:not([aria-hidden]) {
56
+ visibility: visible;
57
+ }
58
+ }
@@ -0,0 +1,25 @@
1
+ import { type FC } from 'react';
2
+ import './style.scss';
3
+ import { CloseIcon } from '../../layout/connectDialog/asset/closeIcon';
4
+ import { CheckIcon } from '../../layout/connectDialog/asset/checkIcon';
5
+
6
+ interface SnackbarProps {
7
+ message: string;
8
+ onClose?: () => void;
9
+ }
10
+
11
+ export const Snackbar: FC<SnackbarProps> = ({ message, onClose }) => {
12
+ return (
13
+ <div className="ck-snackbar" role="status" aria-live="polite">
14
+ <div className="ck-snackbar-content">
15
+ <CheckIcon className="ck-snackbar-check" />
16
+ <p className="ck-snackbar-message">{message}</p>
17
+ </div>
18
+ {onClose && (
19
+ <button type="button" className="ck-snackbar-close" onClick={onClose} aria-label="Close">
20
+ <CloseIcon width={20} height={20} />
21
+ </button>
22
+ )}
23
+ </div>
24
+ );
25
+ };
@@ -0,0 +1,51 @@
1
+ @use '../../style/mixin.scss' as *;
2
+
3
+ .ck-snackbar {
4
+ display: flex;
5
+ align-items: center;
6
+ gap: 16px;
7
+ padding: 12px 16px;
8
+ border-radius: 8px;
9
+ background: var(--semantic-paper-sheet);
10
+ border: 1px solid var(--semantic-divider-divider-1);
11
+ width: 100%;
12
+ max-width: 400px;
13
+
14
+ @include tablet {
15
+ max-width: none;
16
+ }
17
+ }
18
+
19
+ .ck-snackbar-content {
20
+ display: flex;
21
+ align-items: center;
22
+ gap: 8px;
23
+ flex: 1;
24
+ min-width: 0;
25
+ }
26
+
27
+ .ck-snackbar-check {
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: center;
31
+ width: 24px;
32
+ height: 24px;
33
+ flex-shrink: 0;
34
+ color: var(--semantic-information-success);
35
+ }
36
+
37
+ .ck-snackbar-message {
38
+ @include textToken('body3-l1-medium');
39
+ color: var(--scale-gray-900);
40
+ flex: 1;
41
+ min-width: 0;
42
+ }
43
+
44
+ .ck-root .ck-snackbar-close {
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ flex-shrink: 0;
49
+ color: var(--scale-gray-700);
50
+ cursor: pointer;
51
+ }
@@ -0,0 +1,27 @@
1
+ import './style.scss';
2
+ import { type FC } from 'react';
3
+
4
+ interface ToggleProps {
5
+ checked: boolean;
6
+ label: string;
7
+ onChange: (checked: boolean) => void;
8
+ }
9
+
10
+ export const Toggle: FC<ToggleProps> = ({ checked, label, onChange }) => {
11
+ return (
12
+ <label className="ck-toggle">
13
+ <input
14
+ className="ck-toggle-input"
15
+ type="checkbox"
16
+ role="switch"
17
+ checked={checked}
18
+ onChange={(e) => onChange(e.target.checked)}
19
+ aria-label={label}
20
+ />
21
+ <span className="ck-toggle-track" aria-hidden="true">
22
+ <span className="ck-toggle-thumb" />
23
+ </span>
24
+ <span className="ck-toggle-label">{label}</span>
25
+ </label>
26
+ );
27
+ };
@@ -0,0 +1,53 @@
1
+ @use '../../style/mixin.scss' as *;
2
+
3
+ .ck-toggle {
4
+ display: inline-flex;
5
+ align-items: center;
6
+ gap: 6px;
7
+ cursor: pointer;
8
+ flex-shrink: 0;
9
+ }
10
+
11
+ .ck-toggle-input {
12
+ position: absolute;
13
+ opacity: 0;
14
+ width: 0;
15
+ height: 0;
16
+ pointer-events: none;
17
+ }
18
+
19
+ .ck-toggle-track {
20
+ position: relative;
21
+ width: 40px;
22
+ height: 24px;
23
+ border-radius: 100px;
24
+ background: var(--scale-gray-400);
25
+ transition: background 0.2s;
26
+ flex-shrink: 0;
27
+
28
+ .ck-toggle-input:checked + & {
29
+ background: var(--semantic-brand-trugi-primary);
30
+ }
31
+ }
32
+
33
+ .ck-toggle-thumb {
34
+ position: absolute;
35
+ top: 3px;
36
+ left: 2.4px;
37
+ width: 19.2px;
38
+ height: 19.2px;
39
+ border-radius: 50%;
40
+ background: var(--static-white-main);
41
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
42
+ transition: transform 0.2s;
43
+
44
+ .ck-toggle-input:checked ~ .ck-toggle-track & {
45
+ transform: translateX(16px);
46
+ }
47
+ }
48
+
49
+ .ck-toggle-label {
50
+ @include textToken('body4-l2-regular');
51
+ color: var(--scale-gray-700);
52
+ white-space: nowrap;
53
+ }
@@ -0,0 +1,64 @@
1
+ import { type FC } from 'react';
2
+ import './style.scss';
3
+ import { type WCWallet } from '../../types';
4
+ import wcBadge from '../../../assets/wc-search.png';
5
+
6
+ interface WalletGridProps {
7
+ wallets: WCWallet[];
8
+ isLoading: boolean;
9
+ onSelect: (wallet: WCWallet) => void;
10
+ }
11
+
12
+ export const WalletGrid: FC<WalletGridProps> = ({ wallets, isLoading, onSelect }) => {
13
+ if (isLoading) {
14
+ return (
15
+ <div className="ck-wallet-grid-scroll">
16
+ <ul className="ck-wallet-grid ck-wallet-grid--loading" role="list" aria-busy="true">
17
+ {Array.from({ length: 8 }).map((_, i) => (
18
+ <li key={i} className="ck-wallet-grid-item">
19
+ <span className="ck-wallet-grid-icon ck-wallet-grid-icon--skeleton" />
20
+ <span className="ck-wallet-grid-name ck-wallet-grid-name--skeleton" />
21
+ </li>
22
+ ))}
23
+ </ul>
24
+ </div>
25
+ );
26
+ }
27
+
28
+ return (
29
+ <div className="ck-wallet-grid-scroll">
30
+ <ul className="ck-wallet-grid" role="list">
31
+ {wallets.map((wallet) => (
32
+ <li key={wallet.id}>
33
+ <button type="button" className="ck-wallet-grid-item" onClick={() => onSelect(wallet)}>
34
+ {wallet.imageUrl ? (
35
+ <img
36
+ className="ck-wallet-grid-icon"
37
+ src={wallet.imageUrl}
38
+ alt=""
39
+ aria-hidden="true"
40
+ />
41
+ ) : (
42
+ <span className="ck-wallet-grid-icon" aria-hidden="true" />
43
+ )}
44
+ <span className="ck-wallet-grid-name-wrap">
45
+ <span className="ck-wallet-grid-name">{wallet.name}</span>
46
+ {(wallet.mobileNative ||
47
+ wallet.mobileUniversal ||
48
+ wallet.desktopNative ||
49
+ wallet.desktopUniversal) && (
50
+ <img
51
+ className="ck-wallet-grid-wc-badge"
52
+ src={wcBadge}
53
+ alt=""
54
+ aria-hidden="true"
55
+ />
56
+ )}
57
+ </span>
58
+ </button>
59
+ </li>
60
+ ))}
61
+ </ul>
62
+ </div>
63
+ );
64
+ };
@@ -0,0 +1,108 @@
1
+ @use '../../style/mixin.scss' as *;
2
+
3
+ .ck-wallet-grid-scroll {
4
+ flex: 1;
5
+ min-height: 0;
6
+ overflow-y: auto;
7
+ overflow-x: hidden;
8
+ width: 100%;
9
+ @include themedScrollbar;
10
+ }
11
+
12
+ .ck-wallet-grid {
13
+ display: grid;
14
+ grid-template-columns: repeat(4, minmax(0, 1fr));
15
+ grid-auto-rows: auto;
16
+ column-gap: 16px;
17
+ row-gap: 16px;
18
+ list-style: none;
19
+ margin: 0;
20
+ padding: 0;
21
+ width: 100%;
22
+
23
+ @include small-mobile {
24
+ row-gap: 3px;
25
+ }
26
+ @include max-width(392px) {
27
+ grid-template-columns: repeat(3, minmax(0, 1fr));
28
+ }
29
+ }
30
+
31
+ .ck-root .ck-wallet-grid-item {
32
+ display: flex;
33
+ flex-direction: column;
34
+ align-items: center;
35
+ justify-content: center;
36
+ gap: 6px;
37
+ padding: 20px 12px;
38
+ width: 100%;
39
+ cursor: pointer;
40
+ }
41
+
42
+ .ck-wallet-grid-icon {
43
+ width: 54px;
44
+ height: 54px;
45
+ max-width: none;
46
+ border-radius: 12px;
47
+ flex-shrink: 0;
48
+ background: var(--scale-gray-200);
49
+ overflow: hidden;
50
+ cursor: pointer;
51
+
52
+ img {
53
+ width: 100%;
54
+ height: 100%;
55
+ object-fit: cover;
56
+ display: block;
57
+ }
58
+ }
59
+
60
+ .ck-wallet-grid-name-wrap {
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: center;
64
+ gap: 2px;
65
+ width: 100%;
66
+ min-width: 0;
67
+ }
68
+
69
+ .ck-wallet-grid-name {
70
+ @include textToken('label6-bold');
71
+ color: var(--scale-gray-900);
72
+ text-align: center;
73
+ overflow: hidden;
74
+ text-overflow: ellipsis;
75
+ white-space: nowrap;
76
+ min-width: 0;
77
+ flex-shrink: 1;
78
+ }
79
+
80
+ .ck-wallet-grid-wc-badge {
81
+ width: 16px;
82
+ height: 16px;
83
+ flex-shrink: 0;
84
+ }
85
+
86
+ // ── Skeleton ──────────────────────────────────────────────────────────────────
87
+ .ck-wallet-grid-loading .ck-wallet-grid-item {
88
+ cursor: default;
89
+ }
90
+
91
+ .ck-wallet-grid-icon-skeleton {
92
+ background: var(--scale-gray-100);
93
+ animation: ck-grid-pulse 1.5s ease-in-out infinite;
94
+ }
95
+
96
+ .ck-wallet-grid-name-skeleton {
97
+ height: 12px;
98
+ border-radius: 4px;
99
+ background: var(--scale-gray-100);
100
+ width: 60%;
101
+ margin: 0 auto;
102
+ animation: ck-grid-pulse 1.5s ease-in-out infinite;
103
+ }
104
+
105
+ @keyframes ck-grid-pulse {
106
+ 0%, 100% { opacity: 1; }
107
+ 50% { opacity: 0.4; }
108
+ }
@@ -0,0 +1,49 @@
1
+ import { type FC } from 'react';
2
+ import './style.scss';
3
+ import { type ConnectorId } from '../../types';
4
+
5
+ interface WalletItemProps {
6
+ id: ConnectorId;
7
+ label: string;
8
+ logoUrl?: string;
9
+ isSelected: boolean;
10
+ isRecent?: boolean;
11
+ onSelect: (id: ConnectorId) => void;
12
+ }
13
+
14
+ export const WalletItem: FC<WalletItemProps> = ({
15
+ id,
16
+ label,
17
+ logoUrl,
18
+ isSelected,
19
+ isRecent = false,
20
+ onSelect,
21
+ }) => {
22
+ return (
23
+ <button
24
+ type="button"
25
+ className={`ck-wallet-item${isSelected ? ' is-selected' : ''}`}
26
+ onClick={() => onSelect(id)}
27
+ aria-pressed={isSelected}
28
+ >
29
+ {logoUrl ? (
30
+ <img
31
+ className={`ck-wallet-item-icon${id === 'METAMASK' ? ' has-bg' : ''}`}
32
+ src={logoUrl}
33
+ alt=""
34
+ aria-hidden="true"
35
+ />
36
+ ) : (
37
+ <span className="ck-wallet-item-icon" aria-hidden="true" />
38
+ )}
39
+ <span className="ck-wallet-item-txt">
40
+ <span className="ck-wallet-item-label">{label}</span>
41
+ {isRecent && (
42
+ <span className="ck-wallet-item-badge" aria-label="Recently used">
43
+ Recent
44
+ </span>
45
+ )}
46
+ </span>
47
+ </button>
48
+ );
49
+ };