Skip to content

Commit 5622494

Browse files
authored
add: "recent" badge (#176)
* localstorage abstraction * uselocalstorage hook * "recent wallet" tag * change random ID generation to support node14 * recent page animation * update useConnect wrapper * useWalletConnectUri to use useConnect abstraction * shimmer animation adjustments * use accent color * add hideRecentBadge option * nudge and lighten tone * lighten * softer shimmer * badge styles * slight opacity tweaks * tweak badge * stronker shineys * remove half-pixel * text offset * further cleanup
1 parent f190a49 commit 5622494

File tree

18 files changed

+282
-30
lines changed

18 files changed

+282
-30
lines changed

examples/testbench/src/components/inputs.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,20 @@ export const Select = ({
5656
onChange: (e: React.ChangeEvent<HTMLSelectElement>) => void;
5757
}) => {
5858
return (
59-
<label className="select">
59+
<label
60+
className="select"
61+
style={{
62+
width: '100%',
63+
}}
64+
>
6065
<span>{label}</span>
61-
<select value={value} onChange={onChange}>
66+
<select
67+
value={value}
68+
onChange={onChange}
69+
style={{
70+
boxShadow: '0 0 0 1px #ccc',
71+
}}
72+
>
6273
{options.map((option) => (
6374
<option key={option.value} value={option.value}>
6475
{option.label}

examples/testbench/src/pages/_app.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { mainnet, polygon } from 'wagmi/chains';
77
import { ConnectKitProvider, getDefaultClient, SIWESession } from 'connectkit';
88
import { TestBenchProvider, useTestBench } from '../TestbenchProvider';
99
import { siweClient } from '../utils/siweClient';
10+
import { useEffect } from 'react';
1011

1112
const client = createClient(
1213
getDefaultClient({
@@ -22,9 +23,15 @@ const client = createClient(
2223
function App({ Component, pageProps }: AppProps) {
2324
const { theme, mode, options, customTheme } = useTestBench();
2425

26+
const key = JSON.stringify({ customTheme });
27+
2528
// SIWE provider needs to be the outer-most provider because the connect kit
2629
// provider depends on some of the state
2730

31+
useEffect(() => {
32+
console.log('App rendered');
33+
}, [customTheme]);
34+
2835
return (
2936
<siweClient.Provider
3037
onSignIn={(data?: SIWESession) => {
@@ -35,6 +42,7 @@ function App({ Component, pageProps }: AppProps) {
3542
}}
3643
>
3744
<ConnectKitProvider
45+
key={key}
3846
theme={theme}
3947
mode={mode}
4048
options={options}

examples/testbench/src/pages/index.tsx

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -448,15 +448,40 @@ const Home: NextPage = () => {
448448
/>
449449
<Checkbox
450450
label="Custom Font"
451-
value="customTheme"
451+
value="customFont"
452452
checked={customTheme['--ck-font-family'] !== undefined}
453453
onChange={() => {
454-
setCustomTheme(
455-
customTheme['--ck-font-family'] !== undefined
456-
? {}
457-
: { '--ck-font-family': 'monospace' }
458-
);
454+
const name = '--ck-font-family';
455+
if (customTheme[name] !== undefined) {
456+
const { [name]: _, ...rest } = customTheme;
457+
setCustomTheme(rest);
458+
} else {
459+
setCustomTheme({
460+
...customTheme,
461+
[name]: 'monospace',
462+
});
463+
}
464+
}}
465+
/>
466+
<Select
467+
label={'Custom Accent'}
468+
value={customTheme['--ck-accent-color'] ?? ''}
469+
onChange={(e) => {
470+
const name = '--ck-accent-color';
471+
setCustomTheme({
472+
...customTheme,
473+
[name]: e.target.value,
474+
});
459475
}}
476+
options={[
477+
{ label: 'none', value: '' },
478+
{ label: 'red', value: 'red' },
479+
{ label: 'blue', value: 'blue' },
480+
{ label: 'green', value: 'green' },
481+
{ label: 'yellow', value: 'yellow' },
482+
{ label: 'purple', value: 'purple' },
483+
{ label: 'orange', value: 'orange' },
484+
]}
460485
/>
461486
<Checkbox
462487
label="reduceMotion"

packages/connectkit/src/components/ConnectKit.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export type ConnectKitOptions = {
7373
hideTooltips?: boolean;
7474
hideQuestionMarkCTA?: boolean;
7575
hideNoWalletCTA?: boolean;
76+
hideRecentBadge?: boolean;
7677
walletConnectCTA?: 'link' | 'modal' | 'both';
7778
avoidLayoutShift?: boolean; // Avoids layout shift when the ConnectKit modal is open by adding padding to the body
7879
embedGoogleFonts?: boolean; // Automatically embeds Google Font of the current theme. Does not work with custom themes
@@ -132,6 +133,7 @@ export const ConnectKitProvider: React.FC<ConnectKitProviderProps> = ({
132133
hideQuestionMarkCTA: false,
133134
hideNoWalletCTA: false,
134135
walletConnectCTA: 'link',
136+
hideRecentBadge: false,
135137
avoidLayoutShift: true,
136138
embedGoogleFonts: false,
137139
truncateLongENSAddress: true,

packages/connectkit/src/components/ConnectModal/ConnectWithInjector/index.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import {
99
Content,
1010
} from './styles';
1111

12-
import { useContext } from '../../ConnectKit';
13-
import { useConnect } from '../../../hooks/useConnect';
1412
import supportedConnectors from '../../../constants/supportedConnectors';
1513

1614
import {
@@ -33,6 +31,7 @@ import BrowserIcon from '../../Common/BrowserIcon';
3331
import { AlertIcon, TickIcon } from '../../../assets/icons';
3432
import { detectBrowser, isWalletConnectConnector } from '../../../utils';
3533
import useLocales from '../../../hooks/useLocales';
34+
import { useConnect } from '../../../hooks/useConnect';
3635

3736
export const states = {
3837
CONNECTED: 'connected',
@@ -78,8 +77,6 @@ const ConnectWithInjector: React.FC<{
7877
switchConnectMethod: (id?: string) => void;
7978
forceState?: typeof states;
8079
}> = ({ connectorId, switchConnectMethod, forceState }) => {
81-
const context = useContext();
82-
8380
const { connect, connectors } = useConnect({
8481
onMutate: (connector?: any) => {
8582
if (connector.connector) {
@@ -170,9 +167,7 @@ const ConnectWithInjector: React.FC<{
170167

171168
const con: any = connectors.find((c) => c.id === id);
172169
if (con) {
173-
connect({
174-
connector: con,
175-
});
170+
connect({ connector: con });
176171
} else {
177172
setStatus(states.UNAVAILABLE);
178173
}

packages/connectkit/src/components/Pages/Connectors/index.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
MobileConnectorIcon,
3434
InfoBox,
3535
InfoBoxButtons,
36+
ConnectorRecentlyUsed,
3637
} from './styles';
3738

3839
import { isMobile, isAndroid } from '../../../utils';
@@ -41,6 +42,7 @@ import Button from '../../Common/Button';
4142
import useDefaultWallets from '../../../wallets/useDefaultWallets';
4243
import { Connector } from 'wagmi';
4344
import useLocales from '../../../hooks/useLocales';
45+
import { useLastConnector } from '../../../hooks/useLastConnector';
4446
import { useWalletConnectUri } from '../../../hooks/connectors/useWalletConnectUri';
4547

4648
const Wallets: React.FC = () => {
@@ -50,6 +52,7 @@ const Wallets: React.FC = () => {
5052

5153
const { uri: wcUri } = useWalletConnectUri();
5254
const { connectAsync, connectors } = useConnect();
55+
const { lastConnectorId } = useLastConnector();
5356

5457
const openDefaultConnect = async (connector: Connector) => {
5558
// @TODO: use the MetaMask config
@@ -241,7 +244,15 @@ const Wallets: React.FC = () => {
241244
}}
242245
>
243246
<ConnectorIcon>{logo}</ConnectorIcon>
244-
<ConnectorLabel>{name}</ConnectorLabel>
247+
<ConnectorLabel>
248+
{name}
249+
{!context.options?.hideRecentBadge &&
250+
lastConnectorId === connector.id && (
251+
<ConnectorRecentlyUsed>
252+
<span>Recent</span>
253+
</ConnectorRecentlyUsed>
254+
)}
255+
</ConnectorLabel>
245256
</ConnectorButton>
246257
);
247258
})}

packages/connectkit/src/components/Pages/Connectors/styles.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import styled from './../../../styles/styled';
2+
import { keyframes } from 'styled-components';
3+
24
import { motion } from 'framer-motion';
35
import { ModalBody } from '../../Common/Modal/styles';
46

7+
const Shimmer = keyframes`
8+
0%{ transform: translate(-100%) rotate(-45deg); }
9+
100%{ transform: translate(100%) rotate(-80deg); }
10+
`;
11+
512
export const InfoBox = styled.div`
613
padding: 24px 24px 28px;
714
border-radius: var(--ck-tertiary-border-radius, 24px);
@@ -150,34 +157,87 @@ export const ConnectorButton = styled(motion.button)`
150157
transition: 180ms ease;
151158
}
152159
160+
--bg: var(--background);
153161
&:not(:disabled) {
154162
&:hover {
155163
color: var(--hover-color);
156164
background: var(--hover-background);
157165
box-shadow: var(--hover-box-shadow);
158166
border-radius: var(--hover-border-radius);
167+
--bg: var(--hover-background, var(--background));
159168
}
160169
&:focus-visible {
161170
transition-duration: 100ms;
162171
color: var(--hover-color);
163172
background: var(--hover-background);
164173
box-shadow: var(--hover-box-shadow);
165174
border-radius: var(--hover-border-radius);
175+
--bg: var(--hover-background, var(--background));
166176
}
167177
&:active {
168178
color: var(--active-color);
169179
background: var(--active-background);
170180
box-shadow: var(--active-box-shadow);
171181
border-radius: var(--active-border-radius);
182+
--bg: var(--active-background, var(--background));
172183
}
173184
}
174185
`;
186+
export const ConnectorRecentlyUsed = styled(motion.span)`
187+
position: relative;
188+
top: var(--ck-recent-badge-top-offset, 0.5px);
189+
display: inline-block;
190+
padding: 10px 7px;
191+
line-height: 0;
192+
font-size: 13px;
193+
font-weight: 400;
194+
border-radius: var(--ck-recent-badge-border-radius, var(--border-radius));
195+
color: var(
196+
--ck-recent-badge-color,
197+
var(--ck-accent-color, var(--ck-body-color-muted, currentColor))
198+
);
199+
background: var(--ck-recent-badge-background, transparent);
200+
overflow: hidden;
201+
span {
202+
display: inline-block;
203+
position: relative;
204+
}
205+
&:before {
206+
z-index: 1;
207+
content: '';
208+
position: absolute;
209+
inset: 0;
210+
opacity: 0.4;
211+
box-shadow: var(--ck-recent-badge-box-shadow, inset 0 0 0 1px currentColor);
212+
border-radius: inherit;
213+
}
214+
&:after {
215+
z-index: 2;
216+
content: '';
217+
position: absolute;
218+
inset: -10%;
219+
top: -110%;
220+
aspect-ratio: 1/1;
221+
opacity: 0.7;
222+
background: linear-gradient(
223+
170deg,
224+
transparent 10%,
225+
var(--ck-recent-badge-background, var(--bg)) 50%,
226+
transparent 90%
227+
);
228+
animation: ${Shimmer} 2s linear infinite;
229+
}
230+
`;
175231

176232
export const ConnectorLabel = styled(motion.span)`
233+
display: flex;
234+
align-items: center;
235+
gap: 9px;
177236
width: 100%;
178237
overflow: hidden;
179238
white-space: nowrap;
180239
text-overflow: ellipsis;
240+
padding: 2px 0;
181241
padding-right: 38px;
182242
`;
183243

packages/connectkit/src/hooks/connectors/useWalletConnectUri.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { useState, useEffect } from 'react';
22

3-
import { Connector, useAccount, useConnect } from 'wagmi';
3+
import { Connector, useAccount } from 'wagmi';
44
import { useContext } from '../../components/ConnectKit';
5+
import { useConnect } from '../useConnect';
56
import { useWalletConnectConnector } from './../useConnectors';
67

78
export function useWalletConnectUri() {
@@ -13,12 +14,7 @@ export function useWalletConnectUri() {
1314
const isWalletConnectLegacy = connector?.id === 'walletConnectLegacy';
1415

1516
const { isConnected } = useAccount();
16-
const { connectAsync } = useConnect({
17-
onError: (error: any) => log('error', error),
18-
onSuccess: (result: any) => log('success', result),
19-
onMutate: () => log('mutate'),
20-
onSettled: () => log('settled'),
21-
});
17+
const { connectAsync } = useConnect();
2218

2319
useEffect(() => {
2420
async function handleMessage({ type, data }: any) {

packages/connectkit/src/hooks/useConnect.tsx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
1+
/**
2+
* This is a wrapper around wagmi's useConnect hook that adds some
3+
* additional functionality.
4+
*/
5+
16
import { useConnect as wagmiUseConnect } from 'wagmi';
27
import { useContext } from '../components/ConnectKit';
8+
import { useLastConnector } from './useLastConnector';
39

4-
export function useConnect(...props) {
10+
export function useConnect({ ...props } = {}) {
511
const context = useContext();
612

13+
const connectProps = {
14+
chainId: context.options?.initialChainId,
15+
};
16+
17+
const { updateLastConnectorId } = useLastConnector();
18+
719
const { connect, connectAsync, connectors, ...rest } = wagmiUseConnect({
820
onError(err) {
921
if (err.message) {
@@ -14,6 +26,9 @@ export function useConnect(...props) {
1426
context.log(`Could not connect.`, err);
1527
}
1628
},
29+
onSuccess(data: any) {
30+
updateLastConnectorId(data?.connector?.id ?? '');
31+
},
1732
...props,
1833
/*
1934
onSuccess: (data) => {
@@ -27,16 +42,16 @@ export function useConnect(...props) {
2742
});
2843

2944
return {
30-
connect: ({ ...props }) => {
45+
connect: ({ ...opts }) => {
3146
return connect({
32-
...props,
33-
chainId: context.options?.initialChainId,
47+
...opts,
48+
...connectProps,
3449
});
3550
},
36-
connectAsync: async ({ ...props }) => {
51+
connectAsync: async ({ ...opts }) => {
3752
return await connectAsync({
38-
...props,
39-
chainId: context.options?.initialChainId,
53+
...opts,
54+
...connectProps,
4055
});
4156
},
4257
connectors,

0 commit comments

Comments
 (0)