UNPKG

@hyperlane-xyz/widgets

Version:

Common react components for Hyperlane projects

155 lines 10.5 kB
import React from 'react'; import { Tooltip as ReactTooltip } from 'react-tooltip'; import { ColorPalette } from '../color.js'; import { AirplaneIcon } from '../icons/Airplane.js'; import { EnvelopeIcon } from '../icons/Envelope.js'; import { LockIcon } from '../icons/Lock.js'; import { ShieldIcon } from '../icons/Shield.js'; import { WideChevronIcon } from '../icons/WideChevron.js'; import { MessageStatus, MessageStage as Stage } from './types.js'; const STAGE_TOOLTIPS = { [Stage.Preparing]: 'Preparing transaction', [Stage.Sent]: 'Waiting for origin transaction', [Stage.Finalized]: 'Origin transaction has sufficient confirmations', [Stage.Validated]: 'Validators have signed the message bundle', [Stage.Relayed]: 'Destination transaction has been confirmed', }; export function MessageTimeline({ status, stage: _stage, timings, timestampSent, hideDescriptions, iconPosition = 'above', barClassName, chevronColor, iconColor = ColorPalette.White, showTooltips, }) { // Ignore stage value if status shows as delivered const stage = status === MessageStatus.Delivered ? Stage.Relayed : _stage; const isInline = iconPosition === 'inline'; const timeSent = timestampSent ? new Date(timestampSent) : null; const timeSentStr = timeSent ? `${timeSent.toLocaleDateString()} ${timeSent.toLocaleTimeString()}` : null; return (React.createElement("div", { className: isInline ? 'htw-pb-1 htw-flex htw-w-full' : 'htw-pt-14 htw-pb-1 htw-flex htw-w-full' }, React.createElement("div", { className: styles.stageContainer }, React.createElement("div", { className: `${styles.stageBar} ${barClassName ?? ''} htw-rounded-l ${getStageOpacityClass(Stage.Sent, stage, status)}`, ...(showTooltips ? { 'data-tooltip-id': 'timeline-tooltip', 'data-tooltip-content': STAGE_TOOLTIPS[Stage.Sent], } : {}) }, isInline ? (React.createElement(InlineIcon, { Icon: AirplaneIcon, color: iconColor })) : (React.createElement(React.Fragment, null, React.createElement("div", { className: styles.stageHole }), React.createElement("div", { className: styles.stageIconContainer }, React.createElement(StageIcon, { Icon: AirplaneIcon }), React.createElement("div", { className: styles.stageIconCircle })))), React.createElement(Chevron, { side: "right", color: chevronColor })), React.createElement("h4", { className: styles.stageHeader }, getStageHeader(Stage.Sent, stage, timings, status)), !hideDescriptions && (React.createElement("p", { className: styles.stageDesc }, timeSentStr ? `Origin transaction sent at ${timeSentStr}` : 'Waiting for origin transaction'))), React.createElement("div", { className: isInline ? styles.stageSpacerInline : styles.stageSpacer }), React.createElement("div", { className: styles.stageContainer }, React.createElement("div", { className: `${styles.stageBar} ${barClassName ?? ''} ${getStageOpacityClass(Stage.Finalized, stage, status)}`, ...(showTooltips ? { 'data-tooltip-id': 'timeline-tooltip', 'data-tooltip-content': STAGE_TOOLTIPS[Stage.Finalized], } : {}) }, isInline ? (React.createElement(InlineIcon, { Icon: LockIcon, size: 14, color: iconColor, isMiddle: true })) : (React.createElement(React.Fragment, null, React.createElement("div", { className: styles.stageHole }), React.createElement("div", { className: styles.stageIconContainer }, React.createElement(StageIcon, { Icon: LockIcon, size: 14 }), React.createElement("div", { className: styles.stageIconCircle })))), React.createElement(Chevron, { side: "left", color: ColorPalette.White }), React.createElement(Chevron, { side: "right", color: chevronColor })), React.createElement("h4", { className: styles.stageHeader }, getStageHeader(Stage.Finalized, stage, timings, status)), !hideDescriptions && (React.createElement("p", { className: styles.stageDesc }, "Origin transaction has sufficient confirmations"))), React.createElement("div", { className: isInline ? styles.stageSpacerInline : styles.stageSpacer }), React.createElement("div", { className: styles.stageContainer }, React.createElement("div", { className: `${styles.stageBar} ${barClassName ?? ''} ${getStageOpacityClass(Stage.Validated, stage, status)}`, ...(showTooltips ? { 'data-tooltip-id': 'timeline-tooltip', 'data-tooltip-content': STAGE_TOOLTIPS[Stage.Validated], } : {}) }, isInline ? (React.createElement(InlineIcon, { Icon: ShieldIcon, color: iconColor, isMiddle: true })) : (React.createElement(React.Fragment, null, React.createElement("div", { className: styles.stageHole }), React.createElement("div", { className: styles.stageIconContainer }, React.createElement(StageIcon, { Icon: ShieldIcon }), React.createElement("div", { className: styles.stageIconCircle })))), React.createElement(Chevron, { side: "left", color: ColorPalette.White }), React.createElement(Chevron, { side: "right", color: chevronColor })), React.createElement("h4", { className: styles.stageHeader }, getStageHeader(Stage.Validated, stage, timings, status)), !hideDescriptions && (React.createElement("p", { className: styles.stageDesc }, "Validators have signed the message bundle"))), React.createElement("div", { className: isInline ? styles.stageSpacerInline : styles.stageSpacer }), React.createElement("div", { className: styles.stageContainer }, React.createElement("div", { className: `${styles.stageBar} ${barClassName ?? ''} htw-rounded-r ${getStageOpacityClass(Stage.Relayed, stage, status)}`, ...(showTooltips ? { 'data-tooltip-id': 'timeline-tooltip', 'data-tooltip-content': STAGE_TOOLTIPS[Stage.Relayed], } : {}) }, isInline ? (React.createElement(InlineIcon, { Icon: EnvelopeIcon, color: iconColor })) : (React.createElement(React.Fragment, null, React.createElement("div", { className: styles.stageHole }), React.createElement("div", { className: styles.stageIconContainer }, React.createElement(StageIcon, { Icon: EnvelopeIcon }), React.createElement("div", { className: styles.stageIconCircle })))), React.createElement(Chevron, { side: "left", color: ColorPalette.White })), React.createElement("h4", { className: styles.stageHeader }, getStageHeader(Stage.Relayed, stage, timings, status)), !hideDescriptions && (React.createElement("p", { className: styles.stageDesc }, "Destination transaction has been confirmed"))), showTooltips && (React.createElement(ReactTooltip, { id: "timeline-tooltip", positionStrategy: "fixed" })))); } function StageIcon({ Icon, size }) { return (React.createElement("div", { className: "htw-h-9 htw-w-9 htw-flex htw-items-center htw-justify-center htw-rounded-full htw-bg-blue-500" }, React.createElement(Icon, { width: size ?? 14, height: size ?? 14, alt: "", color: ColorPalette.White }))); } function InlineIcon({ Icon, size, color = ColorPalette.White, isMiddle, }) { return (React.createElement("div", { className: `htw-flex htw-items-center htw-justify-center htw-z-10${isMiddle ? ' htw-pl-2' : ''}` }, React.createElement(Icon, { width: size ?? 14, height: size ?? 14, color: color }))); } function Chevron({ side, color = ColorPalette.Blue, }) { const posClass = side === 'left' ? 'htw--left-3' : 'htw--right-3'; return (React.createElement("div", { className: `htw-absolute ${posClass} htw-top-0 htw-h-6` }, React.createElement(WideChevronIcon, { direction: "e", height: "100%", color: color, style: { display: 'block', width: 'auto' } }))); } function getStageHeader(targetStage, currentStage, timings, status) { let label = ''; if (targetStage === Stage.Finalized) { label = currentStage >= targetStage ? 'Finalized' : 'Finalizing'; } else if (targetStage === Stage.Validated) { label = currentStage >= targetStage ? 'Validated' : 'Validating'; } else if (targetStage === Stage.Relayed) { label = currentStage >= targetStage ? 'Relayed' : 'Relaying'; } else if (targetStage === Stage.Sent) { label = currentStage >= targetStage ? 'Sent' : 'Sending'; } const timing = timings[targetStage]; if (status === MessageStatus.Failing) { if (targetStage === currentStage + 1) return `${label}: failed`; if (targetStage > currentStage + 1) return label; } if (timing) return `${label}: ${timing} sec`; else return label; } function getStageOpacityClass(targetStage, currentStage, messageStatus) { if (currentStage >= targetStage) return ''; if (currentStage === targetStage - 1 && messageStatus !== MessageStatus.Failing) return 'htw-animate-pulse-slow'; return 'htw-opacity-50'; } const styles = { stageContainer: 'htw-flex-1 htw-flex htw-flex-col htw-items-center', stageSpacer: 'htw-flex-0 htw-w-1 xs:htw-w-2 sm:htw-w-3', stageSpacerInline: 'htw-flex-0 htw-w-3', stageBar: 'htw-w-full htw-h-6 htw-flex htw-items-center htw-justify-center htw-bg-blue-500 htw-relative', stageHole: 'htw-w-3 htw-h-3 htw-rounded-full htw-bg-white', stageIconContainer: 'htw-absolute htw--top-12 htw-flex htw-flex-col htw-items-center', stageIconCircle: 'htw-w-0.5 htw-h-4 htw-bg-blue-500', stageHeader: 'htw-mt-2.5 htw-text-gray-700 htw-text-xs xs:htw-text-sm sm:htw-text-base', stageDesc: 'htw-mt-1 sm:htw-px-4 htw-text-xs htw-text-gray-500 htw-text-center', }; //# sourceMappingURL=MessageTimeline.js.map