diff --git a/packages/staking/src/features/delegation-card/DelegationCard.tsx b/packages/staking/src/features/delegation-card/DelegationCard.tsx
index 1b0865d2d..a5e4b9ce8 100644
--- a/packages/staking/src/features/delegation-card/DelegationCard.tsx
+++ b/packages/staking/src/features/delegation-card/DelegationCard.tsx
@@ -3,8 +3,9 @@ import cn from 'classnames';
import { Fragment, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { TranslationKey } from '../i18n';
-// import { PERCENTAGE_SCALE_MAX } from '../store';
import * as styles from './DelegationCard.css';
+import { DelegationTooltip } from './DelegationTooltip';
+import { DistributionItem } from './types';
// TODO
const PERCENTAGE_SCALE_MAX = 100;
@@ -15,17 +16,11 @@ export type DelegationStatus =
| 'under-allocated'
| 'no-selection';
-type Distribution = Array<{
- name: string;
- percentage: number;
- color: PieChartColor;
-}>;
-
type DelegationCardProps = {
arrangement?: 'vertical' | 'horizontal';
balance: string;
cardanoCoinSymbol: string;
- distribution: Distribution;
+ distribution: DistributionItem[];
status: DelegationStatus;
showDistribution?: boolean;
};
@@ -72,7 +67,7 @@ export const DelegationCard = ({
const { data, colorSet = PIE_CHART_DEFAULT_COLOR_SET } = useMemo((): {
colorSet?: PieChartColor[];
- data: Distribution;
+ data: DistributionItem[];
} => {
const GREY_COLOR: PieChartColor = '#C0C0C0';
const RED_COLOR: PieChartColor = '#FF5470';
@@ -118,7 +113,7 @@ export const DelegationCard = ({
data-testid="delegation-info-card"
>
>): ReactElement | null => {
+ const { t } = useTranslation();
+ if (active && payload) {
+ const { apy, saturation, fill } = payload;
+
+ return (
+
+
+
+ {t('browsePools.stakePoolTableBrowser.tableHeader.ros.title')}
+ {apy ? `${apy}%` : '-'}
+
+
+ {t('browsePools.stakePoolTableBrowser.tableHeader.saturation.title')}
+ {saturation ? `${saturation}%` : '-'}
+
+
+ }
+ />
+
+ );
+ }
+
+ // eslint-disable-next-line unicorn/no-null
+ return null;
+};
diff --git a/packages/staking/src/features/delegation-card/types.ts b/packages/staking/src/features/delegation-card/types.ts
new file mode 100644
index 000000000..5a987de47
--- /dev/null
+++ b/packages/staking/src/features/delegation-card/types.ts
@@ -0,0 +1,9 @@
+import { PieChartColor } from '@lace/ui';
+
+export type DistributionItem = {
+ name: string;
+ percentage: number;
+ color: PieChartColor;
+ apy?: string;
+ saturation?: string;
+};
diff --git a/packages/staking/src/features/drawer/preferences/StepPreferencesContent.tsx b/packages/staking/src/features/drawer/preferences/StepPreferencesContent.tsx
index 5eed8c21f..390b839ce 100644
--- a/packages/staking/src/features/drawer/preferences/StepPreferencesContent.tsx
+++ b/packages/staking/src/features/drawer/preferences/StepPreferencesContent.tsx
@@ -48,18 +48,20 @@ export const StepPreferencesContent = () => {
const displayData = draftPortfolio.map((draftPool, i) => {
const {
- displayData: { name },
+ displayData: { name, apy, saturation },
id,
sliderIntegerPercentage,
} = draftPool;
return {
+ apy: apy ? String(apy) : undefined,
cardanoCoinSymbol,
color: PIE_CHART_DEFAULT_COLOR_SET[i] as PieChartColor,
id,
name: name || '-',
onChainPercentage: draftPool.basedOnCurrentPortfolio ? draftPool.onChainPercentage : undefined,
percentage: sliderIntegerPercentage,
+ saturation: saturation ? String(saturation) : undefined,
savedIntegerPercentage: draftPool.basedOnCurrentPortfolio ? draftPool.savedIntegerPercentage : undefined,
// TODO
sliderIntegerPercentage,
diff --git a/packages/staking/src/features/overview/Overview.tsx b/packages/staking/src/features/overview/Overview.tsx
index 9abe204d2..4163bb5a0 100644
--- a/packages/staking/src/features/overview/Overview.tsx
+++ b/packages/staking/src/features/overview/Overview.tsx
@@ -95,10 +95,12 @@ export const Overview = () => {
({
+ distribution={displayData.map(({ color, name = '-', onChainPercentage, apy, saturation }) => ({
+ apy: apy ? String(apy) : undefined,
color,
name,
percentage: onChainPercentage,
+ saturation: saturation ? String(saturation) : undefined,
}))}
status={currentPortfolio.length === 1 ? 'simple-delegation' : 'multi-delegation'}
/>
diff --git a/packages/staking/src/features/overview/OverviewPopup.tsx b/packages/staking/src/features/overview/OverviewPopup.tsx
index 4bf20e17e..24cd9c472 100644
--- a/packages/staking/src/features/overview/OverviewPopup.tsx
+++ b/packages/staking/src/features/overview/OverviewPopup.tsx
@@ -98,10 +98,12 @@ export const OverviewPopup = () => {
balance={compactNumber(balancesBalance.available.coinBalance)}
cardanoCoinSymbol={walletStoreWalletUICardanoCoin.symbol}
arrangement="vertical"
- distribution={displayData.map(({ color, name = '-', onChainPercentage }) => ({
+ distribution={displayData.map(({ color, name = '-', onChainPercentage, apy, saturation }) => ({
+ apy: apy ? String(apy) : undefined,
color,
name,
percentage: onChainPercentage,
+ saturation: saturation ? String(saturation) : undefined,
}))}
status={currentPortfolio.length === 1 ? 'simple-delegation' : 'multi-delegation'}
/>
diff --git a/packages/staking/src/features/theme/colors.ts b/packages/staking/src/features/theme/colors.ts
index f07e7605d..08336b600 100644
--- a/packages/staking/src/features/theme/colors.ts
+++ b/packages/staking/src/features/theme/colors.ts
@@ -23,6 +23,7 @@ export const colorsContract = {
$sliderFillSecondary: '',
$sliderKnobFill: '',
$sliderRailFill: '',
+ $tooltipBgColor: '',
};
export const lightThemeColors: typeof colorsContract = {
@@ -48,6 +49,7 @@ export const lightThemeColors: typeof colorsContract = {
$sliderFillSecondary: lightColorScheme.$primary_dark_grey,
$sliderKnobFill: lightColorScheme.$primary_white,
$sliderRailFill: lightColorScheme.$primary_light_grey_plus,
+ $tooltipBgColor: lightColorScheme.$primary_white,
};
export const darkThemeColors: typeof colorsContract = {
@@ -78,4 +80,5 @@ export const darkThemeColors: typeof colorsContract = {
$sliderFillSecondary: darkColorScheme.$primary_light_grey,
$sliderKnobFill: lightColorScheme.$primary_black,
$sliderRailFill: darkColorScheme.$primary_dark_grey_plus,
+ $tooltipBgColor: darkColorScheme.$primary_mid_grey,
};
diff --git a/packages/ui/src/design-system/index.ts b/packages/ui/src/design-system/index.ts
index 8ce8e96a4..69b4af6b6 100644
--- a/packages/ui/src/design-system/index.ts
+++ b/packages/ui/src/design-system/index.ts
@@ -21,7 +21,7 @@ export * as FlowCard from './flow-card';
export * as IconButton from './icon-buttons';
export * as TransactionSummary from './transaction-summary';
export { ToastBar } from './toast-bar';
-export { Tooltip } from './tooltip';
+export * from './tooltip';
export { Message } from './message';
export { PasswordBox } from './password-box';
export { Metadata } from './metadata';
diff --git a/packages/ui/src/design-system/pie-chart/index.ts b/packages/ui/src/design-system/pie-chart/index.ts
index 1ce2905df..11f173fba 100644
--- a/packages/ui/src/design-system/pie-chart/index.ts
+++ b/packages/ui/src/design-system/pie-chart/index.ts
@@ -1,4 +1,8 @@
-export type { PieChartColor, PieChartProps } from './pie-chart.component';
+export type {
+ PieChartColor,
+ PieChartProps,
+ TooltipContentRendererProps,
+} from './pie-chart.component';
export { PieChart } from './pie-chart.component';
export {
PIE_CHART_DEFAULT_COLOR_SET,
diff --git a/packages/ui/src/design-system/pie-chart/pie-chart.component.tsx b/packages/ui/src/design-system/pie-chart/pie-chart.component.tsx
index 76e98218f..d0520448f 100644
--- a/packages/ui/src/design-system/pie-chart/pie-chart.component.tsx
+++ b/packages/ui/src/design-system/pie-chart/pie-chart.component.tsx
@@ -1,6 +1,8 @@
/* eslint-disable functional/prefer-immutable-types */
-import React from 'react';
+import type { ReactElement, ReactNode } from 'react';
+import React, { isValidElement, useMemo, useState } from 'react';
+import isFunction from 'lodash/isFunction';
import {
Cell,
Pie,
@@ -15,20 +17,58 @@ import {
} from './pie-chart.data';
import type { ColorValueHex } from '../../types';
-import type { CellProps, TooltipProps } from 'recharts';
+import type { CellProps } from 'recharts';
import type { PickByValue } from 'utility-types';
type PieChartDataProps = Partial<{
overrides: CellProps;
}>;
export type PieChartColor = ColorValueHex | PieChartGradientColor;
+
+export interface TooltipContentRendererProps {
+ active?: boolean;
+ name?: string;
+ payload?: T;
+}
+export type TooltipContentRenderer = (
+ props: TooltipContentRendererProps,
+) => ReactNode;
+type TooltipContent = ReactElement | TooltipContentRenderer;
+
+interface RechartTooltipContentRendererProps {
+ name?: string;
+ active?: boolean;
+ payload?: { name?: string; payload?: T }[];
+}
+
+type RechartTooltipContentRenderer = (
+ props: RechartTooltipContentRendererProps,
+) => ReactNode;
+
+// Recharts passes to the renderer for some reason the payload as
+// a list which is a bit cumbersome because in practice we care just about the
+// first element and the adapter below removes this inconvenience
+const transformTooltipContentRenderer =
+ (
+ tooltipContentRenderer: TooltipContentRenderer,
+ ): RechartTooltipContentRenderer =>
+ ({
+ active,
+ payload,
+ }: {
+ active?: boolean;
+ payload?: { name?: string; payload?: T }[];
+ }) =>
+ tooltipContentRenderer({ active, ...payload?.[0] });
+
interface PieChartBaseProps {
animate?: boolean;
colors?: PieChartColor[];
data: (PieChartDataProps & T)[];
direction?: 'clockwise' | 'counterclockwise';
- tooltip?: TooltipProps['content'];
+ tooltip?: TooltipContent;
}
+
interface PieChartCustomKeyProps
extends PieChartBaseProps {
nameKey: keyof PickByValue;
@@ -63,6 +103,7 @@ const formatPieColor = (color: PieChartColor): string =>
* @param tooltip component accepted by Recharts Tooltip `content` prop
* @param valueKey object key of a `data` item that will be used as value (displayed in the tooltip)
*/
+
export const PieChart = ({
animate = true,
colors = PIE_CHART_DEFAULT_COLOR_SET,
@@ -73,17 +114,46 @@ export const PieChart = ({
valueKey = 'value',
}: PieChartProps): JSX.Element => {
const data = inputData.slice(0, colors.length);
+ const [tooltipPosition, setTooltipPosition] = useState({ x: 0, y: 0 });
+
+ const tooltipContent = useMemo(() => {
+ if (!tooltip || isValidElement(tooltip)) {
+ return tooltip;
+ }
+
+ if (isFunction(tooltip)) {
+ return transformTooltipContentRenderer(tooltip);
+ }
+ }, [tooltip]);
+
+ const handleMouseMove = (event: React.MouseEvent): void => {
+ const clientWidth = window.innerWidth;
+ if (event.target instanceof SVGSVGElement && clientWidth > 360) {
+ const { x, y } = event.target.getBoundingClientRect();
+ setTooltipPosition({ x: event.clientX - x, y: event.clientY - y });
+ }
+ };
return (
-
+ {
+ handleMouseMove(event as React.MouseEvent);
+ }}
+ >
- {Boolean(tooltip) && }
+ {tooltipContent && (
+
+ )}
= {
export default meta;
+const CustomTooltip = (): ReactElement => (
+
+
+
+);
+
export const Overview = (): JSX.Element => (
@@ -231,12 +239,13 @@ export const Overview = (): JSX.Element => (
type ConfigurableStoryProps = Pick<
PieChartProps<{ name: string; value: number }>,
- 'colors' | 'data' | 'direction' | 'tooltip'
->;
+ 'colors' | 'data' | 'direction'
+> & { tooltip: boolean };
export const Controls = ({
colors,
data,
+ tooltip,
...props
}: Readonly): JSX.Element => (
@@ -245,6 +254,7 @@ export const Controls = ({
animate={isNotInChromatic}
colors={colors}
data={data}
+ tooltip={tooltip ? CustomTooltip : undefined}
{...props}
/>
|
diff --git a/packages/ui/src/design-system/tooltip/rich-tooltip-content-inner.component.tsx b/packages/ui/src/design-system/tooltip/rich-tooltip-content-inner.component.tsx
index d94b8845d..6d72a8d4a 100644
--- a/packages/ui/src/design-system/tooltip/rich-tooltip-content-inner.component.tsx
+++ b/packages/ui/src/design-system/tooltip/rich-tooltip-content-inner.component.tsx
@@ -10,16 +10,21 @@ import * as cx from './rich-tooltip-content-inner.css';
export interface RichContentInnerProps {
title: string;
description: ReactNode;
+ dotColor?: string;
}
export const RichContentInner = ({
title,
description,
+ dotColor,
}: Readonly): JSX.Element => {
+ const customDotStyle =
+ dotColor == undefined ? {} : { backgroundColor: dotColor };
+
return (
-
+
diff --git a/packages/ui/src/design-tokens/elevation.data.ts b/packages/ui/src/design-tokens/elevation.data.ts
index 3e716303b..ba5f2371d 100644
--- a/packages/ui/src/design-tokens/elevation.data.ts
+++ b/packages/ui/src/design-tokens/elevation.data.ts
@@ -1,5 +1,6 @@
export const elevation = {
- $tooltip: '',
+ $tooltip:
+ '0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05)',
$dialog: '',
$primaryButton: '',
$assets: '',