Bridge Comparison
diff --git a/libs/ui-components/src/components/BridgeHistory/BridgeHistory.tsx b/libs/ui-components/src/components/BridgeHistory/BridgeHistory.tsx
index 5e76f73..c83f777 100644
--- a/libs/ui-components/src/components/BridgeHistory/BridgeHistory.tsx
+++ b/libs/ui-components/src/components/BridgeHistory/BridgeHistory.tsx
@@ -19,6 +19,8 @@ export interface BridgeHistoryProps {
includeBackend?: boolean;
historyConfig?: TransactionHistoryConfig;
emptyStateMessage?: string;
+ className?: string;
+ style?: React.CSSProperties;
}
export const BridgeHistory: React.FC = ({
@@ -32,6 +34,8 @@ export const BridgeHistory: React.FC = ({
includeBackend = false,
historyConfig,
emptyStateMessage = 'No transactions found for this account.',
+ className,
+ style,
}) => {
const filter: TransactionHistoryFilter = {
chain,
@@ -51,30 +55,28 @@ export const BridgeHistory: React.FC = ({
historyConfig,
);
- if (!account) {
- return Connect a wallet to view transaction history.
;
- }
+ return (
+
+ {!account &&
Connect a wallet to view transaction history.
}
- if (loading) {
- return
Loading transaction history...
;
- }
+ {account && loading &&
Loading transaction history...
}
- if (transactions.length === 0) {
- return
{emptyStateMessage}
;
- }
+ {account && !loading && transactions.length === 0 &&
{emptyStateMessage}
}
- return (
-
-
Bridge History
-
- {transactions.map((transaction) => (
- -
- {transaction.bridgeName} • {transaction.sourceChain} →{' '}
- {transaction.destinationChain} • {transaction.amount} {transaction.sourceToken} •{' '}
- {transaction.status} • {transaction.timestamp.toLocaleString()}
-
- ))}
-
+ {account && !loading && transactions.length > 0 && (
+ <>
+
Bridge History
+
+ {transactions.map((transaction) => (
+ -
+ {transaction.bridgeName} • {transaction.sourceChain} →{' '}
+ {transaction.destinationChain} • {transaction.amount} {transaction.sourceToken} •{' '}
+ {transaction.status} • {transaction.timestamp.toLocaleString()}
+
+ ))}
+
+ >
+ )}
);
};
diff --git a/libs/ui-components/src/components/TransactionHeartbeat/TransactionHeartbeat.tsx b/libs/ui-components/src/components/TransactionHeartbeat/TransactionHeartbeat.tsx
index ca43221..50f3997 100644
--- a/libs/ui-components/src/components/TransactionHeartbeat/TransactionHeartbeat.tsx
+++ b/libs/ui-components/src/components/TransactionHeartbeat/TransactionHeartbeat.tsx
@@ -9,6 +9,11 @@
import React from 'react';
import { TransactionHeartbeatHeadless } from './TransactionHeartbeat.headless';
+export interface TransactionHeartbeatProps {
+ className?: string;
+ style?: React.CSSProperties;
+}
+
/**
* Transaction heartbeat notification component
* Displays transaction progress with themed styling
@@ -27,12 +32,15 @@ import { TransactionHeartbeatHeadless } from './TransactionHeartbeat.headless';
* }
* ```
*/
-export const TransactionHeartbeat: React.FC = () => {
+export const TransactionHeartbeat: React.FC
= ({
+ className,
+ style,
+}) => {
return (
{({ state, clearState, isSuccess, isFailed, isPending }) => (
{
border: `1px solid var(--bw-colors-transaction-border)`,
transition: `all var(--bw-transitions-base)`,
fontFamily: 'var(--bw-typography-font-family-sans)',
+ ...style,
}}
>
diff --git a/libs/ui-components/src/components/TransactionHeartbeat/index.ts b/libs/ui-components/src/components/TransactionHeartbeat/index.ts
index 240eb29..75ff95d 100644
--- a/libs/ui-components/src/components/TransactionHeartbeat/index.ts
+++ b/libs/ui-components/src/components/TransactionHeartbeat/index.ts
@@ -11,3 +11,4 @@ export type {
TransactionHeartbeatHeadlessProps,
TransactionHeartbeatRenderProps,
} from './TransactionHeartbeat.headless';
+export type { TransactionHeartbeatProps } from './TransactionHeartbeat';
diff --git a/libs/ui-components/src/index.ts b/libs/ui-components/src/index.ts
index 2544251..999277b 100644
--- a/libs/ui-components/src/index.ts
+++ b/libs/ui-components/src/index.ts
@@ -7,6 +7,7 @@
export {
ThemeProvider,
useTheme,
+ BridgeWiseProvider,
ThemeScript,
defaultTheme,
darkTheme,
@@ -27,6 +28,7 @@ export type {
ThemeContextValue,
DeepPartial,
ThemeConfig,
+ BridgeWiseTheme,
CSSVariables,
} from './theme';
diff --git a/libs/ui-components/src/theme/BridgeWiseProvider.tsx b/libs/ui-components/src/theme/BridgeWiseProvider.tsx
new file mode 100644
index 0000000..4d2ca09
--- /dev/null
+++ b/libs/ui-components/src/theme/BridgeWiseProvider.tsx
@@ -0,0 +1,104 @@
+'use client';
+
+import React from 'react';
+import { ThemeProvider, ThemeProviderProps } from './ThemeProvider';
+import type { BridgeWiseTheme, DeepPartial, Theme } from './types';
+
+function normalizeBridgeWiseTheme(theme: BridgeWiseTheme): DeepPartial {
+ const normalized: DeepPartial = {};
+
+ if (theme.backgroundColor || theme.secondaryColor) {
+ normalized.colors = {
+ ...normalized.colors,
+ background: {
+ primary: theme.backgroundColor,
+ secondary: theme.secondaryColor,
+ },
+ } as any;
+ }
+
+ if (theme.textColor || theme.primaryColor) {
+ normalized.colors = {
+ ...normalized.colors,
+ foreground: {
+ primary: theme.textColor,
+ link: theme.primaryColor,
+ },
+ } as any;
+ }
+
+ if (theme.primaryColor || theme.secondaryColor) {
+ normalized.colors = {
+ ...normalized.colors,
+ status: {
+ pending: theme.primaryColor,
+ success: theme.primaryColor,
+ },
+ transaction: {
+ progressBar: {
+ pending: theme.primaryColor,
+ },
+ },
+ } as any;
+ }
+
+ if (theme.borderRadius) {
+ normalized.radii = {
+ lg: theme.borderRadius,
+ md: theme.borderRadius,
+ xl: theme.borderRadius,
+ };
+ }
+
+ if (theme.fontFamily) {
+ normalized.typography = {
+ fontFamily: {
+ sans: theme.fontFamily,
+ },
+ } as any;
+ }
+
+ if (theme.spacingUnit) {
+ normalized.spacing = {
+ xs: theme.spacingUnit,
+ sm: theme.spacingUnit,
+ md: theme.spacingUnit,
+ lg: theme.spacingUnit,
+ xl: theme.spacingUnit,
+ '2xl': theme.spacingUnit,
+ };
+ }
+
+ return normalized;
+}
+
+export interface BridgeWiseProviderProps extends Omit {
+ theme?: BridgeWiseTheme | DeepPartial;
+}
+
+export const BridgeWiseProvider: React.FC = ({
+ theme,
+ ...rest
+}) => {
+ let normalizedTheme: DeepPartial | undefined;
+
+ if (theme) {
+ const maybeTheme = theme as BridgeWiseTheme;
+ if (
+ 'primaryColor' in maybeTheme ||
+ 'secondaryColor' in maybeTheme ||
+ 'backgroundColor' in maybeTheme ||
+ 'textColor' in maybeTheme ||
+ 'borderRadius' in maybeTheme ||
+ 'fontFamily' in maybeTheme ||
+ 'spacingUnit' in maybeTheme
+ ) {
+ normalizedTheme = normalizeBridgeWiseTheme(maybeTheme);
+ } else {
+ normalizedTheme = theme as DeepPartial;
+ }
+ }
+
+ return ;
+};
+
diff --git a/libs/ui-components/src/theme/__tests__/theme-provider.spec.ts b/libs/ui-components/src/theme/__tests__/theme-provider.spec.ts
new file mode 100644
index 0000000..5a00585
--- /dev/null
+++ b/libs/ui-components/src/theme/__tests__/theme-provider.spec.ts
@@ -0,0 +1,35 @@
+import { mergeTheme, generateCSSVariables } from '../utils';
+import { defaultTheme, darkTheme } from '../tokens';
+import type { DeepPartial, Theme } from '../types';
+
+describe('BridgeWise theme utilities', () => {
+ it('merges custom theme overrides with defaults', () => {
+ const override: DeepPartial = {
+ colors: {
+ background: {
+ primary: '#000000',
+ },
+ },
+ };
+
+ const merged = mergeTheme(defaultTheme, override);
+
+ expect(merged.colors.background.primary).toBe('#000000');
+ expect(merged.colors.background.secondary).toBe(defaultTheme.colors.background.secondary);
+ });
+
+ it('generates CSS variables from a theme object', () => {
+ const cssVars = generateCSSVariables(defaultTheme);
+
+ expect(cssVars['--bw-colors-background-primary']).toBe(defaultTheme.colors.background.primary);
+ expect(cssVars['--bw-typography-font-size-base']).toBe(defaultTheme.typography.fontSize.base);
+ });
+
+ it('applies dark theme overrides on top of defaults', () => {
+ const merged = mergeTheme(defaultTheme, darkTheme);
+
+ expect(merged.colors.background.primary).toBe(darkTheme.colors?.background?.primary);
+ expect(merged.colors.foreground.primary).toBe(darkTheme.colors?.foreground?.primary);
+ });
+});
+
diff --git a/libs/ui-components/src/theme/index.ts b/libs/ui-components/src/theme/index.ts
index ac114b6..a953726 100644
--- a/libs/ui-components/src/theme/index.ts
+++ b/libs/ui-components/src/theme/index.ts
@@ -4,6 +4,7 @@
*/
export { ThemeProvider, useTheme } from './ThemeProvider';
+export { BridgeWiseProvider } from './BridgeWiseProvider';
export { ThemeScript } from './ThemeScript';
export { defaultTheme, darkTheme, primitiveColors } from './tokens';
export { mergeTheme, generateCSSVariables } from './utils';
@@ -19,5 +20,6 @@ export type {
ThemeContextValue,
DeepPartial,
ThemeConfig,
+ BridgeWiseTheme,
CSSVariables,
} from './types';
diff --git a/libs/ui-components/src/theme/types.ts b/libs/ui-components/src/theme/types.ts
index ce39d4c..a228274 100644
--- a/libs/ui-components/src/theme/types.ts
+++ b/libs/ui-components/src/theme/types.ts
@@ -162,6 +162,16 @@ export interface Theme {
transitions: ThemeTransitions;
}
+export interface BridgeWiseTheme {
+ primaryColor?: string;
+ secondaryColor?: string;
+ backgroundColor?: string;
+ textColor?: string;
+ borderRadius?: string;
+ fontFamily?: string;
+ spacingUnit?: string;
+}
+
/**
* Deep partial utility type
* Allows partial theme customization at any depth