feat: widget update for de-duplication (#4771)

### Description

Update widgets with new components from the hyperlane explorer and warp
UI. These will be used to replace the current components from both
mentioned repo

### Drive-by changes

None

### Backward compatibility

Not exactly, Spinner and WideChevron were renamed to SpinnerIcon and
WideChevronIcon, these must be updated accordingly

### Testing

Manual and Visual Testing with storybook
pull/4781/head
Jason Guo 3 weeks ago committed by GitHub
parent 8ff194dc47
commit f438d442a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 11
      .changeset/plenty-pens-peel.md
  2. 28
      typescript/widgets/src/animations/Fade.tsx
  3. 4
      typescript/widgets/src/chains/ChainDetailsMenu.tsx
  4. 36
      typescript/widgets/src/components/DatetimeField.tsx
  5. 45
      typescript/widgets/src/components/SelectField.tsx
  6. 10
      typescript/widgets/src/icons/Arrow.tsx
  7. 25
      typescript/widgets/src/icons/Discord.tsx
  8. 18
      typescript/widgets/src/icons/Docs.tsx
  9. 18
      typescript/widgets/src/icons/Github.tsx
  10. 18
      typescript/widgets/src/icons/History.tsx
  11. 16
      typescript/widgets/src/icons/LinkedIn.tsx
  12. 24
      typescript/widgets/src/icons/Medium.tsx
  13. 2
      typescript/widgets/src/icons/Spinner.tsx
  14. 18
      typescript/widgets/src/icons/Twitter.tsx
  15. 18
      typescript/widgets/src/icons/Wallet.tsx
  16. 68
      typescript/widgets/src/icons/Web.tsx
  17. 2
      typescript/widgets/src/icons/WideChevron.tsx
  18. 21
      typescript/widgets/src/index.ts
  19. 11
      typescript/widgets/src/messages/MessageTimeline.tsx
  20. 21
      typescript/widgets/src/stories/Fade.stories.tsx
  21. 102
      typescript/widgets/src/stories/IconList.stories.tsx
  22. 12
      typescript/widgets/src/stories/WideChevron.stories.tsx

@ -0,0 +1,11 @@
---
'@hyperlane-xyz/widgets': minor
---
Update widgets with components from explorer and warp ui
- Add icons: Discord, Docs, Github, History, LinkedIn, Medium, Twitter, Wallet and Web
- Add animation component: Fade component
- Add components: DatetimeField and SelectField
- New stories: IconList and Fade
- Add "Icon" suffix for icons that did not have it

@ -0,0 +1,28 @@
import React, { PropsWithChildren, useEffect, useState } from 'react';
export function Fade(props: PropsWithChildren<{ show: boolean }>) {
const { show, children } = props;
const [render, setRender] = useState(show);
useEffect(() => {
if (show) setRender(true);
}, [show]);
const onAnimationEnd = () => {
if (!show) setRender(false);
};
return render ? (
<div
style={{
animationName: show ? 'fadeIn' : 'fadeOut',
animationDuration: '1s',
//https://github.com/radix-ui/primitives/issues/1074#issuecomment-1089555751
animationFillMode: 'forwards',
}}
onAnimationEnd={onAnimationEnd}
>
{children}
</div>
) : null;
}

@ -30,7 +30,7 @@ import { CheckmarkIcon } from '../icons/Checkmark.js';
import { ChevronIcon } from '../icons/Chevron.js';
import { Circle } from '../icons/Circle.js';
import { PlusCircleIcon } from '../icons/PlusCircle.js';
import { Spinner } from '../icons/Spinner.js';
import { SpinnerIcon } from '../icons/Spinner.js';
import { XIcon } from '../icons/X.js';
import { useConnectionHealthTest } from '../utils/useChainConnectionTest.js';
@ -450,7 +450,7 @@ function ConnectionRow({
return (
<div className="htw-flex htw-items-center htw-gap-3">
{isNullish(isHealthy) && type == ChainConnectionType.RPC && (
<Spinner width={14} height={14} />
<SpinnerIcon width={14} height={14} />
)}
{isNullish(isHealthy) && type == ChainConnectionType.Explorer && (
<Circle size={14} className="htw-bg-gray-400" />

@ -0,0 +1,36 @@
import React, { ChangeEvent } from 'react';
interface Props {
className?: string;
timestamp: number | null;
onChange: (t: number | null) => void;
name?: string;
}
export function DatetimeField({ className, timestamp, onChange, name }: Props) {
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
if (!e.target['validity'].valid) {
onChange(null);
} else {
const datetime = e.target['value'] + ':00Z';
const newTimestamp = new Date(datetime).getTime();
onChange(newTimestamp);
}
};
return (
<input
type="datetime-local"
value={toShortIsoString(timestamp)}
onChange={handleChange}
name={name}
className={className}
/>
);
}
function toShortIsoString(timestamp: number | null) {
if (!timestamp) return '';
// Trim milliseconds and timezone to match input field format
return new Date(timestamp).toISOString().split('.')[0];
}

@ -0,0 +1,45 @@
import React, { ChangeEvent } from 'react';
export type SelectOption = {
display: string;
value: string;
};
type Props = React.DetailedHTMLProps<
React.SelectHTMLAttributes<HTMLSelectElement>,
HTMLSelectElement
> & {
options: Array<SelectOption>;
value: string;
onValueSelect: (value: string) => void;
classes?: string;
};
export function SelectField({
options,
value,
onValueSelect,
classes,
...passThruProps
}: Props) {
const onChangeSelect = (event: ChangeEvent<HTMLSelectElement>) => {
onValueSelect(event?.target?.value || '');
};
return (
<select
className={`htw-rounded htw-border htw-border-gray-400 htw-bg-transparent htw-px-2 htw-py-1 htw-text-sm htw-font-light invalid:htw-text-gray-400 ${
classes || ''
}`}
{...passThruProps}
value={value}
onChange={onChangeSelect}
>
{options.map((o, i) => (
<option key={`option-${i}`} value={o.value}>
{o.display}
</option>
))}
</select>
);
}

@ -1,12 +1,14 @@
import React, { SVGProps, memo } from 'react';
import React, { memo } from 'react';
import { ColorPalette } from '../color.js';
type Props = SVGProps<SVGSVGElement> & {
import { DefaultIconProps } from './types.js';
type Props = DefaultIconProps & {
direction: 'n' | 'e' | 's' | 'w';
};
function _ArrowIcon({ fill, className, direction, ...rest }: Props) {
function _ArrowIcon({ color, className, direction, ...rest }: Props) {
let directionClass;
switch (direction) {
case 'n':
@ -36,7 +38,7 @@ function _ArrowIcon({ fill, className, direction, ...rest }: Props) {
<path
fillRule="evenodd"
d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1"
fill={fill || ColorPalette.Black}
fill={color || ColorPalette.Black}
/>
</svg>
);

@ -0,0 +1,25 @@
import React, { memo } from 'react';
import { ColorPalette } from '../color.js';
import { DefaultIconProps } from './types.js';
function _Discord({ color, ...rest }: DefaultIconProps) {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 71 55" {...rest}>
<g clipPath="url(#a)">
<path
d="M60.1 4.9A58.5 58.5 0 0 0 45.4.5l-1.8 3.7a54 54 0 0 0-16.2 0 37.4 37.4 0 0 0-2-3.8A58.4 58.4 0 0 0 10.7 5 60 60 0 0 0 .4 45.6a58.9 58.9 0 0 0 18 8.8 42 42 0 0 0 3.6-5.9l-.1-.3c-2-.7-3.8-1.6-5.6-2.6a.2.2 0 0 1 0-.4 30.3 30.3 0 0 0 1.3-.9 42 42 0 0 0 36 0l1 1c.2 0 .2.2 0 .3-1.7 1-3.6 1.9-5.5 2.6a47.2 47.2 0 0 0 3.8 6.3 58.7 58.7 0 0 0 17.8-9.1A59.5 59.5 0 0 0 60 4.9ZM23.7 37.3c-3.5 0-6.4-3.2-6.4-7.1 0-4 2.9-7.2 6.4-7.2 3.6 0 6.5 3.3 6.4 7.2 0 4-2.8 7.1-6.4 7.1Zm23.6 0c-3.5 0-6.4-3.2-6.4-7.1 0-4 2.9-7.2 6.4-7.2 3.6 0 6.5 3.3 6.4 7.2 0 4-2.8 7.1-6.4 7.1Z"
fill={color || ColorPalette.Black}
/>
</g>
<defs>
<clipPath id="a">
<path fill={color || ColorPalette.Black} d="M0 0h71v55H0z" />
</clipPath>
</defs>
</svg>
);
}
export const DiscordIcon = memo(_Discord);

@ -0,0 +1,18 @@
import React, { memo } from 'react';
import { ColorPalette } from '../color.js';
import { DefaultIconProps } from './types.js';
function _DocsIcon({ color, ...rest }: DefaultIconProps) {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" {...rest}>
<path
fill={color || ColorPalette.Black}
d="M320-440h320v-80H320v80Zm0 120h320v-80H320v80Zm0 120h200v-80H320v80ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"
/>
</svg>
);
}
export const DocsIcon = memo(_DocsIcon);

@ -0,0 +1,18 @@
import React, { memo } from 'react';
import { ColorPalette } from '../color.js';
import { DefaultIconProps } from './types.js';
function _Github({ color, ...rest }: DefaultIconProps) {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" {...rest}>
<path
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"
fill={color || ColorPalette.Black}
/>
</svg>
);
}
export const GithubIcon = memo(_Github);

@ -0,0 +1,18 @@
import React, { memo } from 'react';
import { ColorPalette } from '../color.js';
import { DefaultIconProps } from './types.js';
function _HistoryIcon({ color, ...rest }: DefaultIconProps) {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" {...rest}>
<path
fill={color || ColorPalette.Black}
d="M480-120q-138 0-240.5-91.5T122-440h82q14 104 92.5 172T480-200q117 0 198.5-81.5T760-480q0-117-81.5-198.5T480-760q-69 0-129 32t-101 88h110v80H120v-240h80v94q51-64 124.5-99T480-840q75 0 140.5 28.5t114 77q48.5 48.5 77 114T840-480q0 75-28.5 140.5t-77 114q-48.5 48.5-114 77T480-120Zm112-192L440-464v-216h80v184l128 128-56 56Z"
/>
</svg>
);
}
export const HistoryIcon = memo(_HistoryIcon);

@ -0,0 +1,16 @@
import React, { memo } from 'react';
import { DefaultIconProps } from './types.js';
function _Linkedin({ color, ...rest }: DefaultIconProps) {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30" {...rest}>
<path
d="M9 25H4V10h5v15zM6.5 8a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5zM27 25h-4.8v-7.3c0-1.74-.04-3.98-2.5-3.98-2.5 0-2.9 1.9-2.9 3.85V25H12V9.99h4.61v2.05h.07a5.08 5.08 0 0 1 4.55-2.42c4.87 0 5.77 3.1 5.77 7.15V25z"
fill={color}
/>
</svg>
);
}
export const LinkedInIcon = memo(_Linkedin);

@ -0,0 +1,24 @@
import React, { memo } from 'react';
import { ColorPalette } from '../color.js';
import { DefaultIconProps } from './types.js';
function _Medium({ color, ...rest }: DefaultIconProps) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -55 256 256"
preserveAspectRatio="xMidYMid"
fill="none"
{...rest}
>
<path
fill={color || ColorPalette.Black}
d="M72.2 0c39.88 0 72.2 32.55 72.2 72.7 0 40.14-32.33 72.69-72.2 72.69-39.87 0-72.2-32.55-72.2-72.7C0 32.56 32.33 0 72.2 0Zm115.3 4.26c19.94 0 36.1 30.64 36.1 68.44 0 37.79-16.16 68.43-36.1 68.43-19.93 0-36.1-30.64-36.1-68.43 0-37.8 16.16-68.44 36.1-68.44Zm55.8 7.13c7.01 0 12.7 27.45 12.7 61.3 0 33.86-5.68 61.32-12.7 61.32-7.01 0-12.7-27.46-12.7-61.31 0-33.86 5.7-61.31 12.7-61.31Z"
/>
</svg>
);
}
export const MediumIcon = memo(_Medium);

@ -30,4 +30,4 @@ function _Spinner({ color, className, ...rest }: DefaultIconProps) {
);
}
export const Spinner = memo(_Spinner);
export const SpinnerIcon = memo(_Spinner);

@ -0,0 +1,18 @@
import React, { memo } from 'react';
import { ColorPalette } from '../color.js';
import { DefaultIconProps } from './types.js';
function _Twitter({ color, ...rest }: DefaultIconProps) {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" {...rest}>
<path
d="M5.026 15c6.038 0 9.341-5.003 9.341-9.334 0-.14 0-.282-.006-.422A6.685 6.685 0 0 0 16 3.542a6.658 6.658 0 0 1-1.889.518 3.301 3.301 0 0 0 1.447-1.817 6.533 6.533 0 0 1-2.087.793A3.286 3.286 0 0 0 7.875 6.03a9.325 9.325 0 0 1-6.767-3.429 3.289 3.289 0 0 0 1.018 4.382A3.323 3.323 0 0 1 .64 6.575v.045a3.288 3.288 0 0 0 2.632 3.218 3.203 3.203 0 0 1-.865.115 3.23 3.23 0 0 1-.614-.057 3.283 3.283 0 0 0 3.067 2.277A6.588 6.588 0 0 1 .78 13.58a6.32 6.32 0 0 1-.78-.045A9.344 9.344 0 0 0 5.026 15z"
fill={color || ColorPalette.Black}
/>
</svg>
);
}
export const TwitterIcon = memo(_Twitter);

@ -0,0 +1,18 @@
import React, { memo } from 'react';
import { ColorPalette } from '../color.js';
import { DefaultIconProps } from './types.js';
function _WalletIcon({ color, ...rest }: DefaultIconProps) {
return (
<svg viewBox="0 0 17 14" xmlns="http://www.w3.org/2000/svg" {...rest}>
<path
d="M3.33333 13.4737C2.41667 13.4737 1.63194 13.1439 0.979167 12.4842C0.326389 11.8246 0 11.0316 0 10.1053V3.36842C0 2.44211 0.326389 1.64912 0.979167 0.989474C1.63194 0.329825 2.41667 0 3.33333 0H13.3333C14.25 0 15.0347 0.329825 15.6875 0.989474C16.3403 1.64912 16.6667 2.44211 16.6667 3.36842V10.1053C16.6667 11.0316 16.3403 11.8246 15.6875 12.4842C15.0347 13.1439 14.25 13.4737 13.3333 13.4737H3.33333ZM3.33333 3.57895H13.3333C13.7361 3.57895 14.1146 3.64211 14.4687 3.76842C14.8229 3.89474 15.1389 4.07719 15.4167 4.31579V3.36842C15.4167 2.77895 15.2153 2.2807 14.8125 1.87368C14.4097 1.46667 13.9167 1.26316 13.3333 1.26316H3.33333C2.75 1.26316 2.25694 1.46667 1.85417 1.87368C1.45139 2.2807 1.25 2.77895 1.25 3.36842V4.31579C1.52778 4.07719 1.84375 3.89474 2.19792 3.76842C2.55208 3.64211 2.93056 3.57895 3.33333 3.57895ZM1.3125 6.4421L11.25 8.86316C11.3472 8.89123 11.4479 8.89474 11.5521 8.87368C11.6562 8.85263 11.7431 8.80702 11.8125 8.73684L15.1458 5.91579C14.9653 5.59298 14.7153 5.33333 14.3958 5.13684C14.0764 4.94035 13.7222 4.84211 13.3333 4.84211H3.33333C2.84722 4.84211 2.41667 4.99298 2.04167 5.29474C1.66667 5.59649 1.42361 5.97895 1.3125 6.4421Z"
fill={color || ColorPalette.Black}
/>
</svg>
);
}
export const WalletIcon = memo(_WalletIcon);

@ -0,0 +1,68 @@
import React, { memo } from 'react';
import { ColorPalette } from '../color.js';
import { DefaultIconProps } from './types.js';
function _Web({ color = ColorPalette.Black, ...rest }: DefaultIconProps) {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 29 29" {...rest}>
<path
fill={color}
d="m11 18.6-.39.17a13.45 13.45 0 0 0 1.12 2.9 5.25 5.25 0 0 0 2.08 2.24c.36.18.7.26 1.03.26.95 0 2.1-.71 3.1-2.5.46-.82.85-1.8 1.13-2.9a10.3 10.3 0 0 0-8.06-.17Z"
/>
<path
fill={color}
d="M20.34 19.46a11.88 11.88 0 0 1-1.88 3.99 9.63 9.63 0 0 0 3.63-2.6 10.3 10.3 0 0 0-1.75-1.4Z"
/>
<path
fill={color}
d="M24.41 15.27a9.55 9.55 0 0 1-1.48 4.45l-.53-.49c-.54-.45-1.12-.86-1.74-1.22.08-.45.15-.9.2-1.38l.05-.61c.02-.25.04-.5.04-.75h3.46Z"
/>
<path
fill={color}
d="M22.96 9.45a9.55 9.55 0 0 1 1.45 4.42h-3.46a19 19 0 0 0-.28-2.7c.83-.47 1.6-1.06 2.3-1.72Z"
/>
<path
fill={color}
d="m22.05 8.24.07.08c-.54.54-1.14 1.01-1.78 1.42a11.84 11.84 0 0 0-1.91-4.08 9.63 9.63 0 0 1 3.62 2.58Z"
/>
<path
fill={color}
d="M16.35 5.53a2.55 2.55 0 0 0-1.51-.57c-.96 0-2.11.72-3.11 2.5-.15.28-.3.57-.43.88l-.24.58c-.17.47-.33.97-.46 1.5a10.24 10.24 0 0 0 8.47 0 12.18 12.18 0 0 0-1.12-2.95 6.02 6.02 0 0 0-1.6-1.94Z"
/>
<path
fill={color}
d="M7.54 8.3a9.68 9.68 0 0 1 3.7-2.63 11.9 11.9 0 0 0-1.9 4.07 10.4 10.4 0 0 1-1.8-1.44Z"
/>
<path
fill={color}
d="M5.26 13.87A9.53 9.53 0 0 1 6.7 9.45c.69.67 1.46 1.25 2.3 1.73a19 19 0 0 0-.29 2.69H5.26Z"
/>
<path
fill={color}
d="M6.73 19.72a9.53 9.53 0 0 1-1.47-4.45h3.46c.03.95.14 1.87.3 2.74a11.33 11.33 0 0 0-2.29 1.7Z"
/>
<path
fill={color}
d="M11.24 23.47a9.62 9.62 0 0 1-3.66-2.61c.53-.54 1.12-1.01 1.76-1.41.45 1.6 1.1 2.98 1.9 4.02Z"
/>
<path
fill={color}
d="M19.55 15.27a14 14 0 0 1-.2 2.1 11.66 11.66 0 0 0-9.03 0c-.1-.67-.17-1.38-.2-2.1h9.43Z"
/>
<path
fill={color}
d="M19.55 13.87h-9.43c.03-.71.1-1.4.2-2.05a11.78 11.78 0 0 0 9.04 0 18.37 18.37 0 0 1 .2 2.05Z"
/>
<path
fill={color}
fill-rule="evenodd"
d="M28.84 14.57a14 14 0 1 0-14 14 14 14 0 0 0 14-14Zm-3 0a11 11 0 1 0-22 0 11 11 0 0 0 22 0Z"
clip-rule="evenodd"
/>
</svg>
);
}
export const WebIcon = memo(_Web);

@ -69,4 +69,4 @@ function _WideChevron({
}
}
export const WideChevron = memo(_WideChevron);
export const WideChevronIcon = memo(_WideChevron);

@ -1,3 +1,4 @@
export { Fade } from './animations/Fade.js';
export {
ChainDetailsMenu,
type ChainDetailsMenuProps,
@ -8,13 +9,16 @@ export {
type ChainSearchMenuProps,
} from './chains/ChainSearchMenu.js';
export { ColorPalette, seedToBgColor } from './color.js';
export { Button } from './components/Button.js';
export { CopyButton } from './components/CopyButton.js';
export { DatetimeField } from './components/DatetimeField.js';
export { IconButton } from './components/IconButton.js';
export { LinkButton } from './components/LinkButton.js';
export { SegmentedControl } from './components/SegmentedControl.js';
export { SelectField, type SelectOption } from './components/SelectField.js';
export { TextInput } from './components/TextInput.js';
export { Tooltip } from './components/Tooltip.js';
export * from './consts.js';
export { HYPERLANE_EXPLORER_API_URL } from './consts.js';
export { AirplaneIcon } from './icons/Airplane.js';
export { ArrowIcon } from './icons/Arrow.js';
export { BoxArrowIcon } from './icons/BoxArrow.js';
@ -22,20 +26,31 @@ export { CheckmarkIcon } from './icons/Checkmark.js';
export { ChevronIcon } from './icons/Chevron.js';
export { Circle } from './icons/Circle.js';
export { CopyIcon } from './icons/Copy.js';
export { DiscordIcon } from './icons/Discord.js';
export { DocsIcon } from './icons/Docs.js';
export { EnvelopeIcon } from './icons/Envelope.js';
export { FilterIcon } from './icons/Filter.js';
export { FunnelIcon } from './icons/Funnel.js';
export { GearIcon } from './icons/Gear.js';
export { GithubIcon } from './icons/Github.js';
export { HistoryIcon } from './icons/History.js';
export { LinkedInIcon } from './icons/LinkedIn.js';
export { LockIcon } from './icons/Lock.js';
export { MediumIcon } from './icons/Medium.js';
export { PencilIcon } from './icons/Pencil.js';
export { PlusIcon } from './icons/Plus.js';
export { PlusCircleIcon } from './icons/PlusCircle.js';
export { QuestionMarkIcon } from './icons/QuestionMark.js';
export { SearchIcon } from './icons/Search.js';
export { ShieldIcon } from './icons/Shield.js';
export { Spinner } from './icons/Spinner.js';
export { SpinnerIcon } from './icons/Spinner.js';
export { TwitterIcon } from './icons/Twitter.js';
export { UpDownArrowsIcon } from './icons/UpDownArrows.js';
export { WideChevron } from './icons/WideChevron.js';
export { WalletIcon } from './icons/Wallet.js';
export { WebIcon } from './icons/Web.js';
export { WideChevronIcon } from './icons/WideChevron.js';
export { XIcon } from './icons/X.js';
export { type DefaultIconProps } from './icons/types.js';
export { DropdownMenu, type DropdownMenuProps } from './layout/DropdownMenu.js';
export { Modal, useModal, type ModalProps } from './layout/Modal.js';
export { Popover, type PopoverProps } from './layout/Popover.js';

@ -5,7 +5,7 @@ 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 { WideChevron } from '../icons/WideChevron.js';
import { WideChevronIcon } from '../icons/WideChevron.js';
import { MessageStatus, MessageStage as Stage, StageTimings } from './types.js';
@ -157,7 +157,12 @@ function StageIcon({ Icon, size }: { Icon: any; size?: number }) {
function ChevronWhite() {
return (
<div className="htw-absolute htw--left-3 htw-top-0 htw-h-6">
<WideChevron direction="e" height="100%" width="auto" color="#ffffff" />
<WideChevronIcon
direction="e"
height="100%"
width="auto"
color="#ffffff"
/>
</div>
);
}
@ -165,7 +170,7 @@ function ChevronWhite() {
function ChevronBlue() {
return (
<div className="htw-absolute htw--right-3 htw-top-0 htw-h-6">
<WideChevron direction="e" height="100%" width="auto" />
<WideChevronIcon direction="e" height="100%" width="auto" />
</div>
);
}

@ -0,0 +1,21 @@
import { Meta, StoryObj } from '@storybook/react';
import React from 'react';
import { Fade } from '../animations/Fade';
function MyFadeAnimation({ show }: { show: boolean }) {
return (
<Fade show={show}>
<div>Hello Fade</div>
</Fade>
);
}
const meta = {
title: 'Fade',
component: MyFadeAnimation,
} satisfies Meta<typeof MyFadeAnimation>;
export default meta;
type Story = StoryObj<typeof meta>;
export const BaseFadeAnimation = { args: { show: false } } satisfies Story;

@ -0,0 +1,102 @@
import { Meta, StoryObj } from '@storybook/react';
import React from 'react';
import * as Hyperlane from '../index';
interface StoryIconProps {
width?: number;
height?: number;
color?: string;
direction?: 'n' | 'e' | 's' | 'w';
rounded?: boolean;
}
const iconList = Object.entries(Hyperlane)
.filter(([name]) => name.includes('Icon') && !name.includes('IconButton'))
.map(([_, Component]) => Component as React.ComponentType<StoryIconProps>);
function IconList({
width,
height,
color,
direction,
bgColorSeed,
roundedWideChevron,
}: {
width: number;
height: number;
color: string;
direction: 'n' | 'e' | 's' | 'w';
bgColorSeed: number | undefined;
roundedWideChevron: boolean;
}) {
return (
<>
<div
style={{
display: 'flex',
gap: '1rem',
textAlign: 'center',
flexWrap: 'wrap',
}}
>
{iconList.map((Icon) => (
<IconContainer>
<span>{Icon.displayName}</span>
<Icon
width={width}
height={height}
color={color}
direction={direction}
rounded={roundedWideChevron}
/>
</IconContainer>
))}
<IconContainer>
<span>Circle</span>
<Hyperlane.Circle size={width} bgColorSeed={bgColorSeed} />
</IconContainer>
</div>
</>
);
}
function IconContainer({ children }: { children: React.ReactNode }) {
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '0.5rem',
alignItems: 'center',
width: '120px',
}}
>
{children}
</div>
);
}
const meta = {
title: 'Icon List',
component: IconList,
argTypes: {
direction: {
options: ['n', 'e', 's', 'w'],
control: { type: 'select' },
},
},
} satisfies Meta<typeof IconList>;
export default meta;
type Story = StoryObj<typeof meta>;
export const DefaultIconList = {
args: {
width: 24,
height: 24,
color: Hyperlane.ColorPalette.Black,
direction: 's',
bgColorSeed: 0,
roundedWideChevron: false,
},
} satisfies Story;

@ -1,16 +1,16 @@
import { ComponentMeta, ComponentStory } from '@storybook/react';
import { Meta, StoryFn } from '@storybook/react';
import React from 'react';
import { ColorPalette } from '../color.js';
import { WideChevron } from '../icons/WideChevron.js';
import { WideChevronIcon } from '../icons/WideChevron.js';
export default {
title: 'WideChevron',
component: WideChevron,
} as ComponentMeta<typeof WideChevron>;
component: WideChevronIcon,
} as Meta<typeof WideChevronIcon>;
const Template: ComponentStory<typeof WideChevron> = (args) => (
<WideChevron {...args} />
const Template: StoryFn<typeof WideChevronIcon> = (args) => (
<WideChevronIcon {...args} />
);
export const BlueEastRounded = Template.bind({});

Loading…
Cancel
Save