diff --git a/.changeset/itchy-waves-think.md b/.changeset/itchy-waves-think.md new file mode 100644 index 00000000..24b496e4 --- /dev/null +++ b/.changeset/itchy-waves-think.md @@ -0,0 +1,5 @@ +--- +'@relayprotocol/relay-kit-ui': patch +--- + +Add onHapticEvent callback to RelayKitProvider diff --git a/demo/components/providers/RelayKitProviderWrapper.tsx b/demo/components/providers/RelayKitProviderWrapper.tsx index 586a7e79..831c4ed2 100644 --- a/demo/components/providers/RelayKitProviderWrapper.tsx +++ b/demo/components/providers/RelayKitProviderWrapper.tsx @@ -4,10 +4,12 @@ import { RelayChain } from '@relayprotocol/relay-sdk' import { RelayKitProvider } from '@relayprotocol/relay-kit-ui' +import type { HapticEventType } from '@relayprotocol/relay-kit-ui' import { useTheme } from 'next-themes' import { useRouter } from 'next/router' -import { FC, ReactNode, useMemo } from 'react' +import { FC, ReactNode, useCallback, useMemo } from 'react' import { useCustomize } from 'context/customizeContext' +import { useWebHaptics } from 'web-haptics/react' const DEFAULT_APP_FEES = [ { @@ -30,6 +32,19 @@ export const RelayKitProviderWrapper: FC<{ const router = useRouter() const { themeOverrides, websocketsEnabled } = useCustomize() const appFeesEnabled = router.query.appFees === 'true' + const { trigger } = useWebHaptics({ + // enables audio feedback for testing on desktop + // debug: true + }) + + // web-haptics presets match our HapticEventType names exactly + const onHapticEvent = useCallback( + (type: HapticEventType) => { + console.log(`[haptic] ${type}`) + trigger(type) + }, + [trigger] + ) const mergedTheme = useMemo( () => ({ @@ -62,6 +77,7 @@ export const RelayKitProviderWrapper: FC<{ }, secureBaseUrl: process.env.NEXT_PUBLIC_RELAY_SECURE_API_URL, appFees: appFeesEnabled ? DEFAULT_APP_FEES : undefined, + onHapticEvent, logger: (message, level) => { window.dispatchEvent( new CustomEvent('relay-kit-logger', { diff --git a/demo/package.json b/demo/package.json index 72f2750a..df9d1b75 100644 --- a/demo/package.json +++ b/demo/package.json @@ -47,7 +47,8 @@ "tronweb": "^6.0.4", "usehooks-ts": "^3.1.0", "viem": ">=2.26.0", - "wagmi": "^2.15.6" + "wagmi": "^2.15.6", + "web-haptics": "^0.0.6" }, "devDependencies": { "@dynamic-labs/types": "4.10.4", diff --git a/packages/ui/src/components/common/CustomAddressModal.tsx b/packages/ui/src/components/common/CustomAddressModal.tsx index 23f77e48..97a5162e 100644 --- a/packages/ui/src/components/common/CustomAddressModal.tsx +++ b/packages/ui/src/components/common/CustomAddressModal.tsx @@ -21,7 +21,10 @@ import type { AdaptedWallet, RelayChain } from '@relayprotocol/relay-sdk' import type { LinkedWallet } from '../../types/index.js' import { truncateAddress } from '../../utils/truncate.js' import { isValidAddress } from '../../utils/address.js' -import { ProviderOptionsContext } from '../../providers/RelayKitProvider.js' +import { + ProviderOptionsContext, + useHapticEvent +} from '../../providers/RelayKitProvider.js' import { addCustomAddress, getCustomAddresses @@ -56,6 +59,7 @@ export const CustomAddressModal: FC = ({ onConfirmed, onClear }) => { + const haptic = useHapticEvent() const connectedAddress = useWalletAddress(wallet, linkedWallets) const [address, setAddress] = useState('') const [input, setInput] = useState('') @@ -316,6 +320,7 @@ export const CustomAddressModal: FC = ({ radius="squared" className="relay:flex relay:items-center relay:gap-[6px] relay:cursor-pointer relay:px-2" onClick={() => { + haptic('light') onConfirmed(address) onOpenChange(false) onAnalyticEvent?.(EventNames.ADDRESS_MODAL_CONFIRMED, { @@ -354,6 +359,7 @@ export const CustomAddressModal: FC = ({ setRecentCustomAddresses(getCustomAddresses()) } + haptic('light') onConfirmed(address) onAnalyticEvent?.(EventNames.ADDRESS_MODAL_CONFIRMED, { address: address, diff --git a/packages/ui/src/components/common/PercentageButtons.tsx b/packages/ui/src/components/common/PercentageButtons.tsx index 76b3962e..6c589cf5 100644 --- a/packages/ui/src/components/common/PercentageButtons.tsx +++ b/packages/ui/src/components/common/PercentageButtons.tsx @@ -59,7 +59,8 @@ export const PercentageButtons: FC = ({ isMobile ? 'relay:rounded-[6px]' : 'relay:rounded-[12px]', isMobile ? 'relay:flex-1' : '', 'relay:justify-center', - 'relay:hover:bg-[var(--relay-colors-widget-selector-hover-background)]' + 'relay:hover:bg-[var(--relay-colors-widget-selector-hover-background)]', + 'relay:active:bg-[var(--relay-colors-gray5)]' ) const buttonFontSize = isMobile ? '14px' : '12px' diff --git a/packages/ui/src/components/common/SlippageToleranceConfig.tsx b/packages/ui/src/components/common/SlippageToleranceConfig.tsx index ec2bb609..d2b93ac0 100644 --- a/packages/ui/src/components/common/SlippageToleranceConfig.tsx +++ b/packages/ui/src/components/common/SlippageToleranceConfig.tsx @@ -29,6 +29,7 @@ const tokenToColor = (token: string | undefined): string | undefined => { return `var(--relay-colors-${token})` } import { EventNames } from '../../constants/events.js' +import { useHapticEvent } from '../../providers/RelayKitProvider.js' import { useDebounceValue, useMediaQuery } from 'usehooks-ts' import useFallbackState from '../../hooks/useFallbackState.js' import { Modal } from './Modal.js' @@ -73,11 +74,13 @@ const SlippageTabs: FC = ({ slippageRatingColor, inputRef }) => { + const haptic = useHapticEvent() const isMobile = useMediaQuery('(max-width: 520px)') return ( { + haptic('selection') setMode(value as SlippageToleranceMode) if (value === 'Auto') { setDisplayValue(undefined) @@ -115,7 +118,7 @@ const SlippageTabs: FC = ({