@0xsquid/ui 0.20.0 → 0.20.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -2637,24 +2637,41 @@ const mainImageSizeClassMap = {
2637
2637
  md: 'tw-w-10 tw-h-10',
2638
2638
  };
2639
2639
  const loadingSkeletonClassName = 'tw-bg-grey-500';
2640
- function BadgeImage({ imageUrl, badgeUrl, size = 'sm', extraMarginForBadge, rounded = false, }) {
2640
+ var ImageState;
2641
+ (function (ImageState) {
2642
+ ImageState[ImageState["LOADING"] = 0] = "LOADING";
2643
+ ImageState[ImageState["LOADED"] = 1] = "LOADED";
2644
+ ImageState[ImageState["ERROR"] = 2] = "ERROR";
2645
+ })(ImageState || (ImageState = {}));
2646
+ function BadgeImage({ imageUrl: _imageUrl, badgeUrl, size = 'sm', extraMarginForBadge, rounded = false, placeholderImageUrl, }) {
2647
+ const imageUrl = (_imageUrl === null || _imageUrl === void 0 ? void 0 : _imageUrl.trim()) || placeholderImageUrl;
2641
2648
  const [imagesLoadState, setImageLoadState] = React.useState({
2642
- badgeLoaded: false,
2643
- mainImageLoaded: false,
2649
+ badge: ImageState.LOADING,
2650
+ mainImage: ImageState.LOADING,
2644
2651
  });
2645
2652
  const badgeImageClassName = cn('tw-absolute -tw-right-1/3 tw-bottom-0 tw-z-10 tw-m-0 -tw-translate-x-1/3 tw-rounded-md tw-border-[1px] tw-border-grey-800', badgeSizeClassMap[size]);
2646
2653
  const mainImageClassName = cn('tw-h-full tw-w-full tw-absolute', rounded ? ' tw-rounded-full' : 'tw-rounded-squid-xs');
2647
- return imageUrl ? (jsxRuntime.jsxs("div", { className: cn('tw-relative', extraMarginForBadge && badgeUrl ? 'tw-mr-1.5' : null, mainImageSizeClassMap[size]), children: [!imagesLoadState.mainImageLoaded && (jsxRuntime.jsx("div", { className: cn(mainImageClassName, loadingSkeletonClassName) })), jsxRuntime.jsx("img", { src: imageUrl, alt: "", onLoad: () => {
2654
+ return imageUrl ? (jsxRuntime.jsxs("div", { className: cn('tw-relative', extraMarginForBadge && badgeUrl ? 'tw-mr-1.5' : null, mainImageSizeClassMap[size]), children: [imagesLoadState.mainImage !== ImageState.LOADED &&
2655
+ (placeholderImageUrl ? (jsxRuntime.jsx("img", { src: placeholderImageUrl, alt: "", className: mainImageClassName })) : (jsxRuntime.jsx("div", { className: cn(mainImageClassName, loadingSkeletonClassName) }))), jsxRuntime.jsx("img", { src: imageUrl, alt: "", onError: () => {
2656
+ setImageLoadState((prevState) => (Object.assign(Object.assign({}, prevState), { mainImage: ImageState.ERROR })));
2657
+ }, onLoad: () => {
2648
2658
  // update state when image is fully loaded
2649
- setImageLoadState((prevState) => (Object.assign(Object.assign({}, prevState), { mainImageLoaded: true })));
2659
+ setImageLoadState((prevState) => (Object.assign(Object.assign({}, prevState), { mainImage: ImageState.LOADED })));
2650
2660
  }, className: cn(mainImageClassName,
2651
2661
  // hide main image while it is loading, and display it when it is loaded
2652
- imagesLoadState.mainImageLoaded ? 'tw-block' : 'tw-hidden') }), badgeUrl ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [!imagesLoadState.badgeLoaded && (jsxRuntime.jsx("div", { className: cn(badgeImageClassName, loadingSkeletonClassName) })), jsxRuntime.jsx("img", { src: badgeUrl, alt: "", onLoad: () => {
2662
+ imagesLoadState.mainImage === ImageState.LOADED
2663
+ ? 'tw-block'
2664
+ : 'tw-hidden') }), badgeUrl ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [imagesLoadState.badge !== ImageState.LOADED &&
2665
+ (placeholderImageUrl ? (jsxRuntime.jsx("img", { src: placeholderImageUrl, alt: "", className: badgeImageClassName })) : (jsxRuntime.jsx("div", { className: cn(badgeImageClassName, loadingSkeletonClassName) }))), jsxRuntime.jsx("img", { src: badgeUrl, alt: "", onError: () => {
2666
+ setImageLoadState((prevState) => (Object.assign(Object.assign({}, prevState), { badge: ImageState.ERROR })));
2667
+ }, onLoad: () => {
2653
2668
  // update state when badge image is fully loaded
2654
- setImageLoadState((prevState) => (Object.assign(Object.assign({}, prevState), { badgeLoaded: true })));
2669
+ setImageLoadState((prevState) => (Object.assign(Object.assign({}, prevState), { badge: ImageState.LOADED })));
2655
2670
  }, className: cn(badgeImageClassName,
2656
2671
  // hide badge image while it is loading, and display it when it is loaded
2657
- imagesLoadState.badgeLoaded ? 'tw-block' : 'tw-hidden') })] })) : null] })) : null;
2672
+ imagesLoadState.badge === ImageState.LOADED
2673
+ ? 'tw-block'
2674
+ : 'tw-hidden') })] })) : null] })) : null;
2658
2675
  }
2659
2676
 
2660
2677
  /******************************************************************************
@@ -17068,7 +17085,7 @@ const collapsedListItemClassMap = {
17068
17085
  large: 'tw-w-[80px]',
17069
17086
  };
17070
17087
  function ListItem(_a) {
17071
- var { itemTitle, mainImageUrl, subtitle, subtitleOnHover, detail, icon, secondaryImageUrl, size = 'large', mainIcon, className, isSelected, onDetailClick, showDetailOnHoverOnly, rounded = false, detailButtonClassName, loading, containerProps, compactOnMobile } = _a, props = __rest$1(_a, ["itemTitle", "mainImageUrl", "subtitle", "subtitleOnHover", "detail", "icon", "secondaryImageUrl", "size", "mainIcon", "className", "isSelected", "onDetailClick", "showDetailOnHoverOnly", "rounded", "detailButtonClassName", "loading", "containerProps", "compactOnMobile"]);
17088
+ var { itemTitle, mainImageUrl, subtitle, subtitleOnHover, detail, icon, secondaryImageUrl, placeholderImageUrl, size = 'large', mainIcon, className, isSelected, onDetailClick, showDetailOnHoverOnly, rounded = false, detailButtonClassName, loading, containerProps, compactOnMobile } = _a, props = __rest$1(_a, ["itemTitle", "mainImageUrl", "subtitle", "subtitleOnHover", "detail", "icon", "secondaryImageUrl", "placeholderImageUrl", "size", "mainIcon", "className", "isSelected", "onDetailClick", "showDetailOnHoverOnly", "rounded", "detailButtonClassName", "loading", "containerProps", "compactOnMobile"]);
17072
17089
  const subtitleClassName = cn('tw-h-[14px] tw-max-w-full tw-truncate !tw-leading-[16px] tw-text-grey-500', compactOnMobile ? 'tw-hidden mobile-lg:tw-block' : 'tw-block');
17073
17090
  // 'small' variant does not have detail
17074
17091
  const showDetail = size === 'large' && (!!detail || !!icon || showDetailOnHoverOnly);
@@ -17101,7 +17118,7 @@ function ListItem(_a) {
17101
17118
  const itemProps = isInteractive ? props : {};
17102
17119
  return (jsxRuntime.jsx("li", Object.assign({}, containerProps, { className: cn('tw-flex tw-max-w-full tw-bg-grey-900 tw-text-grey-300', listItemSizeMap[size], compactOnMobile
17103
17120
  ? `${collapsedListItemClassMap[size]} mobile-lg:tw-w-full`
17104
- : 'tw-w-full', className), children: jsxRuntime.jsxs(ItemTag, Object.assign({}, itemProps, { className: cn('tw-group/list-item tw-flex tw-w-full tw-max-w-full tw-items-center tw-justify-start tw-gap-squid-xs tw-rounded-squid-s tw-px-squid-xs tw-py-squid-xxs', isSelected && 'tw-bg-material-light-thin', isInteractive && 'hover:tw-bg-material-light-thin'), children: [size === 'large' ? (jsxRuntime.jsx("div", { className: "tw-h-10 tw-w-10", children: mainIcon ? (mainIcon) : (jsxRuntime.jsx(BadgeImage, { extraMarginForBadge: false, imageUrl: mainImageUrl, badgeUrl: secondaryImageUrl, size: "md", rounded: rounded })) })) : (jsxRuntime.jsx("div", { className: "tw-flex tw-min-h-[30px] tw-min-w-[30px] tw-items-center tw-justify-center", children: mainIcon ? (mainIcon) : (jsxRuntime.jsx("img", { src: mainImageUrl, className: "tw-h-[30px] tw-w-[30px] tw-rounded-squid-xs" })) })), jsxRuntime.jsxs("div", { className: cn('tw-flex tw-h-[40px] tw-flex-1 tw-flex-col tw-items-start tw-justify-center tw-gap-squid-xxs',
17121
+ : 'tw-w-full', className), children: jsxRuntime.jsxs(ItemTag, Object.assign({}, itemProps, { className: cn('tw-group/list-item tw-flex tw-w-full tw-max-w-full tw-items-center tw-justify-start tw-gap-squid-xs tw-rounded-squid-s tw-px-squid-xs tw-py-squid-xxs', isSelected && 'tw-bg-material-light-thin', isInteractive && 'hover:tw-bg-material-light-thin'), children: [size === 'large' ? (jsxRuntime.jsx("div", { className: "tw-h-10 tw-w-10", children: mainIcon ? (mainIcon) : (jsxRuntime.jsx(BadgeImage, { extraMarginForBadge: false, imageUrl: mainImageUrl, badgeUrl: secondaryImageUrl, placeholderImageUrl: placeholderImageUrl, size: "md", rounded: rounded })) })) : (jsxRuntime.jsx("div", { className: "tw-flex tw-min-h-[30px] tw-min-w-[30px] tw-items-center tw-justify-center", children: mainIcon ? (mainIcon) : (jsxRuntime.jsx("img", { src: mainImageUrl, className: "tw-h-[30px] tw-w-[30px] tw-rounded-squid-xs" })) })), jsxRuntime.jsxs("div", { className: cn('tw-flex tw-h-[40px] tw-flex-1 tw-flex-col tw-items-start tw-justify-center tw-gap-squid-xxs',
17105
17122
  // 'large' variant has extra padding
17106
17123
  size === 'large' ? 'tw-w-[56%] tw-pl-squid-xxs' : 'tw-w-[67%]'), children: [typeof itemTitle === 'string' ? (jsxRuntime.jsx(BodyText, { size: "small", className: cn('tw-max-w-full tw-truncate', subtitle && 'tw-h-[17px] !tw-leading-[17px]', compactOnMobile ? 'tw-hidden mobile-lg:tw-block' : 'tw-block'), children: itemTitle })) : (itemTitle), size === 'large' &&
17107
17124
  ((loading === null || loading === void 0 ? void 0 : loading.subtitle) ? (loadingComponent()) : subtitle ? (jsxRuntime.jsxs(CaptionText, { className: subtitleClassName, children: [subtitleOnHover && (jsxRuntime.jsx(CaptionText, { className: cn(subtitleClassName, 'tw-hidden group-hover/list-item:tw-block'), children: subtitleOnHover })), subtitle] })) : null)] }), showDetail && (jsxRuntime.jsxs(DetailTag, Object.assign({}, detailProps, { className: cn('tw-flex tw-w-fit tw-items-center tw-justify-center tw-rounded-squid-xs', size === 'large' ? 'tw-h-squid-xl' : 'tw-h-squid-l', showDetailOnHoverOnly
@@ -60273,6 +60290,7 @@ exports.InteractionTransactionView = InteractionTransactionView;
60273
60290
  exports.Join = Join;
60274
60291
  exports.List = List;
60275
60292
  exports.ListItem = ListItem;
60293
+ exports.Loader = Loader;
60276
60294
  exports.LoadingProvider = LoadingProvider;
60277
60295
  exports.LoadingSkeleton = LoadingSkeleton;
60278
60296
  exports.MEDIA_QUERIES = MEDIA_QUERIES;
@@ -4,7 +4,12 @@ interface BadgeImageProps {
4
4
  size?: BadgeSize;
5
5
  extraMarginForBadge?: boolean;
6
6
  rounded?: boolean;
7
+ /**
8
+ * The URL of the placeholder image. Will be displayed while the images are loading
9
+ * or if there's an error loading them.
10
+ */
11
+ placeholderImageUrl?: string;
7
12
  }
8
13
  type BadgeSize = 'sm' | 'md';
9
- export declare function BadgeImage({ imageUrl, badgeUrl, size, extraMarginForBadge, rounded, }: BadgeImageProps): import("react/jsx-runtime").JSX.Element | null;
14
+ export declare function BadgeImage({ imageUrl: _imageUrl, badgeUrl, size, extraMarginForBadge, rounded, placeholderImageUrl, }: BadgeImageProps): import("react/jsx-runtime").JSX.Element | null;
10
15
  export {};
@@ -0,0 +1 @@
1
+ export { Loader } from './Loader';
@@ -5,3 +5,4 @@ export * from './layout';
5
5
  export * from './lists';
6
6
  export * from './typography';
7
7
  export * from './views';
8
+ export * from './icons';
@@ -3,6 +3,7 @@ interface ListItemProps extends React.HTMLAttributes<HTMLButtonElement> {
3
3
  itemTitle: string | React.ReactNode;
4
4
  mainImageUrl?: string;
5
5
  secondaryImageUrl?: string;
6
+ placeholderImageUrl?: string;
6
7
  subtitle?: string;
7
8
  subtitleOnHover?: React.ReactNode;
8
9
  detail?: string;
@@ -22,5 +23,5 @@ interface ListItemProps extends React.HTMLAttributes<HTMLButtonElement> {
22
23
  compactOnMobile?: boolean;
23
24
  }
24
25
  type ListItemSize = 'small' | 'large';
25
- export declare function ListItem({ itemTitle, mainImageUrl, subtitle, subtitleOnHover, detail, icon, secondaryImageUrl, size, mainIcon, className, isSelected, onDetailClick, showDetailOnHoverOnly, rounded, detailButtonClassName, loading, containerProps, compactOnMobile, ...props }: ListItemProps): import("react/jsx-runtime").JSX.Element;
26
+ export declare function ListItem({ itemTitle, mainImageUrl, subtitle, subtitleOnHover, detail, icon, secondaryImageUrl, placeholderImageUrl, size, mainIcon, className, isSelected, onDetailClick, showDetailOnHoverOnly, rounded, detailButtonClassName, loading, containerProps, compactOnMobile, ...props }: ListItemProps): import("react/jsx-runtime").JSX.Element;
26
27
  export {};
@@ -9,3 +9,7 @@ export declare const ExtraMarginForBadge: Story;
9
9
  export declare const Rounded: Story;
10
10
  export declare const SizeMedium: Story;
11
11
  export declare const SizeSmall: Story;
12
+ export declare const CustomPlaceholderForBrokenImage: Story;
13
+ export declare const CustomPlaceholderForLoadingImage: Story;
14
+ export declare const CustomPlaceholderForBrokenBadgeImage: Story;
15
+ export declare const CustomPlaceholderForLoadingBadgeImage: Story;
package/dist/esm/index.js CHANGED
@@ -2617,24 +2617,41 @@ const mainImageSizeClassMap = {
2617
2617
  md: 'tw-w-10 tw-h-10',
2618
2618
  };
2619
2619
  const loadingSkeletonClassName = 'tw-bg-grey-500';
2620
- function BadgeImage({ imageUrl, badgeUrl, size = 'sm', extraMarginForBadge, rounded = false, }) {
2620
+ var ImageState;
2621
+ (function (ImageState) {
2622
+ ImageState[ImageState["LOADING"] = 0] = "LOADING";
2623
+ ImageState[ImageState["LOADED"] = 1] = "LOADED";
2624
+ ImageState[ImageState["ERROR"] = 2] = "ERROR";
2625
+ })(ImageState || (ImageState = {}));
2626
+ function BadgeImage({ imageUrl: _imageUrl, badgeUrl, size = 'sm', extraMarginForBadge, rounded = false, placeholderImageUrl, }) {
2627
+ const imageUrl = (_imageUrl === null || _imageUrl === void 0 ? void 0 : _imageUrl.trim()) || placeholderImageUrl;
2621
2628
  const [imagesLoadState, setImageLoadState] = useState({
2622
- badgeLoaded: false,
2623
- mainImageLoaded: false,
2629
+ badge: ImageState.LOADING,
2630
+ mainImage: ImageState.LOADING,
2624
2631
  });
2625
2632
  const badgeImageClassName = cn('tw-absolute -tw-right-1/3 tw-bottom-0 tw-z-10 tw-m-0 -tw-translate-x-1/3 tw-rounded-md tw-border-[1px] tw-border-grey-800', badgeSizeClassMap[size]);
2626
2633
  const mainImageClassName = cn('tw-h-full tw-w-full tw-absolute', rounded ? ' tw-rounded-full' : 'tw-rounded-squid-xs');
2627
- return imageUrl ? (jsxs("div", { className: cn('tw-relative', extraMarginForBadge && badgeUrl ? 'tw-mr-1.5' : null, mainImageSizeClassMap[size]), children: [!imagesLoadState.mainImageLoaded && (jsx("div", { className: cn(mainImageClassName, loadingSkeletonClassName) })), jsx("img", { src: imageUrl, alt: "", onLoad: () => {
2634
+ return imageUrl ? (jsxs("div", { className: cn('tw-relative', extraMarginForBadge && badgeUrl ? 'tw-mr-1.5' : null, mainImageSizeClassMap[size]), children: [imagesLoadState.mainImage !== ImageState.LOADED &&
2635
+ (placeholderImageUrl ? (jsx("img", { src: placeholderImageUrl, alt: "", className: mainImageClassName })) : (jsx("div", { className: cn(mainImageClassName, loadingSkeletonClassName) }))), jsx("img", { src: imageUrl, alt: "", onError: () => {
2636
+ setImageLoadState((prevState) => (Object.assign(Object.assign({}, prevState), { mainImage: ImageState.ERROR })));
2637
+ }, onLoad: () => {
2628
2638
  // update state when image is fully loaded
2629
- setImageLoadState((prevState) => (Object.assign(Object.assign({}, prevState), { mainImageLoaded: true })));
2639
+ setImageLoadState((prevState) => (Object.assign(Object.assign({}, prevState), { mainImage: ImageState.LOADED })));
2630
2640
  }, className: cn(mainImageClassName,
2631
2641
  // hide main image while it is loading, and display it when it is loaded
2632
- imagesLoadState.mainImageLoaded ? 'tw-block' : 'tw-hidden') }), badgeUrl ? (jsxs(Fragment, { children: [!imagesLoadState.badgeLoaded && (jsx("div", { className: cn(badgeImageClassName, loadingSkeletonClassName) })), jsx("img", { src: badgeUrl, alt: "", onLoad: () => {
2642
+ imagesLoadState.mainImage === ImageState.LOADED
2643
+ ? 'tw-block'
2644
+ : 'tw-hidden') }), badgeUrl ? (jsxs(Fragment, { children: [imagesLoadState.badge !== ImageState.LOADED &&
2645
+ (placeholderImageUrl ? (jsx("img", { src: placeholderImageUrl, alt: "", className: badgeImageClassName })) : (jsx("div", { className: cn(badgeImageClassName, loadingSkeletonClassName) }))), jsx("img", { src: badgeUrl, alt: "", onError: () => {
2646
+ setImageLoadState((prevState) => (Object.assign(Object.assign({}, prevState), { badge: ImageState.ERROR })));
2647
+ }, onLoad: () => {
2633
2648
  // update state when badge image is fully loaded
2634
- setImageLoadState((prevState) => (Object.assign(Object.assign({}, prevState), { badgeLoaded: true })));
2649
+ setImageLoadState((prevState) => (Object.assign(Object.assign({}, prevState), { badge: ImageState.LOADED })));
2635
2650
  }, className: cn(badgeImageClassName,
2636
2651
  // hide badge image while it is loading, and display it when it is loaded
2637
- imagesLoadState.badgeLoaded ? 'tw-block' : 'tw-hidden') })] })) : null] })) : null;
2652
+ imagesLoadState.badge === ImageState.LOADED
2653
+ ? 'tw-block'
2654
+ : 'tw-hidden') })] })) : null] })) : null;
2638
2655
  }
2639
2656
 
2640
2657
  /******************************************************************************
@@ -17048,7 +17065,7 @@ const collapsedListItemClassMap = {
17048
17065
  large: 'tw-w-[80px]',
17049
17066
  };
17050
17067
  function ListItem(_a) {
17051
- var { itemTitle, mainImageUrl, subtitle, subtitleOnHover, detail, icon, secondaryImageUrl, size = 'large', mainIcon, className, isSelected, onDetailClick, showDetailOnHoverOnly, rounded = false, detailButtonClassName, loading, containerProps, compactOnMobile } = _a, props = __rest$1(_a, ["itemTitle", "mainImageUrl", "subtitle", "subtitleOnHover", "detail", "icon", "secondaryImageUrl", "size", "mainIcon", "className", "isSelected", "onDetailClick", "showDetailOnHoverOnly", "rounded", "detailButtonClassName", "loading", "containerProps", "compactOnMobile"]);
17068
+ var { itemTitle, mainImageUrl, subtitle, subtitleOnHover, detail, icon, secondaryImageUrl, placeholderImageUrl, size = 'large', mainIcon, className, isSelected, onDetailClick, showDetailOnHoverOnly, rounded = false, detailButtonClassName, loading, containerProps, compactOnMobile } = _a, props = __rest$1(_a, ["itemTitle", "mainImageUrl", "subtitle", "subtitleOnHover", "detail", "icon", "secondaryImageUrl", "placeholderImageUrl", "size", "mainIcon", "className", "isSelected", "onDetailClick", "showDetailOnHoverOnly", "rounded", "detailButtonClassName", "loading", "containerProps", "compactOnMobile"]);
17052
17069
  const subtitleClassName = cn('tw-h-[14px] tw-max-w-full tw-truncate !tw-leading-[16px] tw-text-grey-500', compactOnMobile ? 'tw-hidden mobile-lg:tw-block' : 'tw-block');
17053
17070
  // 'small' variant does not have detail
17054
17071
  const showDetail = size === 'large' && (!!detail || !!icon || showDetailOnHoverOnly);
@@ -17081,7 +17098,7 @@ function ListItem(_a) {
17081
17098
  const itemProps = isInteractive ? props : {};
17082
17099
  return (jsx("li", Object.assign({}, containerProps, { className: cn('tw-flex tw-max-w-full tw-bg-grey-900 tw-text-grey-300', listItemSizeMap[size], compactOnMobile
17083
17100
  ? `${collapsedListItemClassMap[size]} mobile-lg:tw-w-full`
17084
- : 'tw-w-full', className), children: jsxs(ItemTag, Object.assign({}, itemProps, { className: cn('tw-group/list-item tw-flex tw-w-full tw-max-w-full tw-items-center tw-justify-start tw-gap-squid-xs tw-rounded-squid-s tw-px-squid-xs tw-py-squid-xxs', isSelected && 'tw-bg-material-light-thin', isInteractive && 'hover:tw-bg-material-light-thin'), children: [size === 'large' ? (jsx("div", { className: "tw-h-10 tw-w-10", children: mainIcon ? (mainIcon) : (jsx(BadgeImage, { extraMarginForBadge: false, imageUrl: mainImageUrl, badgeUrl: secondaryImageUrl, size: "md", rounded: rounded })) })) : (jsx("div", { className: "tw-flex tw-min-h-[30px] tw-min-w-[30px] tw-items-center tw-justify-center", children: mainIcon ? (mainIcon) : (jsx("img", { src: mainImageUrl, className: "tw-h-[30px] tw-w-[30px] tw-rounded-squid-xs" })) })), jsxs("div", { className: cn('tw-flex tw-h-[40px] tw-flex-1 tw-flex-col tw-items-start tw-justify-center tw-gap-squid-xxs',
17101
+ : 'tw-w-full', className), children: jsxs(ItemTag, Object.assign({}, itemProps, { className: cn('tw-group/list-item tw-flex tw-w-full tw-max-w-full tw-items-center tw-justify-start tw-gap-squid-xs tw-rounded-squid-s tw-px-squid-xs tw-py-squid-xxs', isSelected && 'tw-bg-material-light-thin', isInteractive && 'hover:tw-bg-material-light-thin'), children: [size === 'large' ? (jsx("div", { className: "tw-h-10 tw-w-10", children: mainIcon ? (mainIcon) : (jsx(BadgeImage, { extraMarginForBadge: false, imageUrl: mainImageUrl, badgeUrl: secondaryImageUrl, placeholderImageUrl: placeholderImageUrl, size: "md", rounded: rounded })) })) : (jsx("div", { className: "tw-flex tw-min-h-[30px] tw-min-w-[30px] tw-items-center tw-justify-center", children: mainIcon ? (mainIcon) : (jsx("img", { src: mainImageUrl, className: "tw-h-[30px] tw-w-[30px] tw-rounded-squid-xs" })) })), jsxs("div", { className: cn('tw-flex tw-h-[40px] tw-flex-1 tw-flex-col tw-items-start tw-justify-center tw-gap-squid-xxs',
17085
17102
  // 'large' variant has extra padding
17086
17103
  size === 'large' ? 'tw-w-[56%] tw-pl-squid-xxs' : 'tw-w-[67%]'), children: [typeof itemTitle === 'string' ? (jsx(BodyText, { size: "small", className: cn('tw-max-w-full tw-truncate', subtitle && 'tw-h-[17px] !tw-leading-[17px]', compactOnMobile ? 'tw-hidden mobile-lg:tw-block' : 'tw-block'), children: itemTitle })) : (itemTitle), size === 'large' &&
17087
17104
  ((loading === null || loading === void 0 ? void 0 : loading.subtitle) ? (loadingComponent()) : subtitle ? (jsxs(CaptionText, { className: subtitleClassName, children: [subtitleOnHover && (jsx(CaptionText, { className: cn(subtitleClassName, 'tw-hidden group-hover/list-item:tw-block'), children: subtitleOnHover })), subtitle] })) : null)] }), showDetail && (jsxs(DetailTag, Object.assign({}, detailProps, { className: cn('tw-flex tw-w-fit tw-items-center tw-justify-center tw-rounded-squid-xs', size === 'large' ? 'tw-h-squid-xl' : 'tw-h-squid-l', showDetailOnHoverOnly
@@ -60197,4 +60214,4 @@ function SquidConfigProvider({ theme = lightTheme, children, themeType = 'light'
60197
60214
  return (jsx("div", { style: parsedStyle, "data-squid-theme-type": themeType, className: "tw-group tw-relative tw-h-screen tw-font-geist mobile-lg:tw-h-auto", children: children }));
60198
60215
  }
60199
60216
 
60200
- export { ActionLayout, ActionLineOutRow, ActionProperties, ActionRow, ActionStatusRow, ActionWrapper, AddressButton, AnimationWrapper, AppContainer, ApproveAction, ArrowButton, AssetsButton, AssetsView, BadgeImage, BlockSkeleton, BodyText, Boost, BoostButton, BorderedContainer, Breadcrumb, BridgeAction, BridgeHeader, BridgeProperties, BridgeTransactionView, Button$1 as Button, BuyNFTHeader, BuyNFTProperties, BuyNFTTransactionView, CaptionText, Chip, Collapse, DescriptionBlocks, DetailsToolbar, DropdownMenu, DropdownMenuItem, ErrorMessage, FeeButton, FeesAction, FeesLines, FeesTotal, FilterButton, HashLink, HeadingText, HistoryItem, IconLabel, ImageIcon, IncompleteAction, InfoBox, Inline, Input, InteractionHeader, InteractionProperties, InteractionTransactionView, Join, List, ListItem, LoadingProvider, LoadingSkeleton, MEDIA_QUERIES, MainView, Menu, MenuItem, Modal, ModalContent, ModalContentDivider, NavigationBar, NumericInput, PipeSeparator, ProductCard, ProfileHeader, ProfileHeaderBackground, PropertiesLayout, PropertyListItem, ReceiveNFTAction, ReceiveTokensAction, RecipientView, STEP_ITEM_HEIGHT, SectionTitle, SendTokensAction, SettingsButton, SettingsItem, SettingsSlider, SizeTransition, SquidConfigProvider, StakeAction, StartAction, SuccessAction, SwapAction, SwapConfiguration, SwapDetailsView, SwapHeader, SwapProgressView, SwapProgressViewHeader, SwapProperties, SwapStepItem, SwapStepsCollapsed, SwapTransactionView, Switch, TextSkeleton, Timestamp, Toast, TokenPair, Tooltip, TransactionAction, TransactionFilters, TransactionHeader, TransactionHeaderLayout, TransactionItem, TransactionProperties, TransactionSearch, TransactionState, TransactionView, TransactionViewLayout, Transfer, UsdAmount, WalletLink, WalletsView, WrapAction, linkActionTimelineProps, statusBgClassMap$1 as statusBgClassMap, statusColorClassMap, statusTextClassMap, useDropdownMenu, useMediaQuery };
60217
+ export { ActionLayout, ActionLineOutRow, ActionProperties, ActionRow, ActionStatusRow, ActionWrapper, AddressButton, AnimationWrapper, AppContainer, ApproveAction, ArrowButton, AssetsButton, AssetsView, BadgeImage, BlockSkeleton, BodyText, Boost, BoostButton, BorderedContainer, Breadcrumb, BridgeAction, BridgeHeader, BridgeProperties, BridgeTransactionView, Button$1 as Button, BuyNFTHeader, BuyNFTProperties, BuyNFTTransactionView, CaptionText, Chip, Collapse, DescriptionBlocks, DetailsToolbar, DropdownMenu, DropdownMenuItem, ErrorMessage, FeeButton, FeesAction, FeesLines, FeesTotal, FilterButton, HashLink, HeadingText, HistoryItem, IconLabel, ImageIcon, IncompleteAction, InfoBox, Inline, Input, InteractionHeader, InteractionProperties, InteractionTransactionView, Join, List, ListItem, Loader, LoadingProvider, LoadingSkeleton, MEDIA_QUERIES, MainView, Menu, MenuItem, Modal, ModalContent, ModalContentDivider, NavigationBar, NumericInput, PipeSeparator, ProductCard, ProfileHeader, ProfileHeaderBackground, PropertiesLayout, PropertyListItem, ReceiveNFTAction, ReceiveTokensAction, RecipientView, STEP_ITEM_HEIGHT, SectionTitle, SendTokensAction, SettingsButton, SettingsItem, SettingsSlider, SizeTransition, SquidConfigProvider, StakeAction, StartAction, SuccessAction, SwapAction, SwapConfiguration, SwapDetailsView, SwapHeader, SwapProgressView, SwapProgressViewHeader, SwapProperties, SwapStepItem, SwapStepsCollapsed, SwapTransactionView, Switch, TextSkeleton, Timestamp, Toast, TokenPair, Tooltip, TransactionAction, TransactionFilters, TransactionHeader, TransactionHeaderLayout, TransactionItem, TransactionProperties, TransactionSearch, TransactionState, TransactionView, TransactionViewLayout, Transfer, UsdAmount, WalletLink, WalletsView, WrapAction, linkActionTimelineProps, statusBgClassMap$1 as statusBgClassMap, statusColorClassMap, statusTextClassMap, useDropdownMenu, useMediaQuery };
@@ -4,7 +4,12 @@ interface BadgeImageProps {
4
4
  size?: BadgeSize;
5
5
  extraMarginForBadge?: boolean;
6
6
  rounded?: boolean;
7
+ /**
8
+ * The URL of the placeholder image. Will be displayed while the images are loading
9
+ * or if there's an error loading them.
10
+ */
11
+ placeholderImageUrl?: string;
7
12
  }
8
13
  type BadgeSize = 'sm' | 'md';
9
- export declare function BadgeImage({ imageUrl, badgeUrl, size, extraMarginForBadge, rounded, }: BadgeImageProps): import("react/jsx-runtime").JSX.Element | null;
14
+ export declare function BadgeImage({ imageUrl: _imageUrl, badgeUrl, size, extraMarginForBadge, rounded, placeholderImageUrl, }: BadgeImageProps): import("react/jsx-runtime").JSX.Element | null;
10
15
  export {};
@@ -0,0 +1 @@
1
+ export { Loader } from './Loader';
@@ -5,3 +5,4 @@ export * from './layout';
5
5
  export * from './lists';
6
6
  export * from './typography';
7
7
  export * from './views';
8
+ export * from './icons';
@@ -3,6 +3,7 @@ interface ListItemProps extends React.HTMLAttributes<HTMLButtonElement> {
3
3
  itemTitle: string | React.ReactNode;
4
4
  mainImageUrl?: string;
5
5
  secondaryImageUrl?: string;
6
+ placeholderImageUrl?: string;
6
7
  subtitle?: string;
7
8
  subtitleOnHover?: React.ReactNode;
8
9
  detail?: string;
@@ -22,5 +23,5 @@ interface ListItemProps extends React.HTMLAttributes<HTMLButtonElement> {
22
23
  compactOnMobile?: boolean;
23
24
  }
24
25
  type ListItemSize = 'small' | 'large';
25
- export declare function ListItem({ itemTitle, mainImageUrl, subtitle, subtitleOnHover, detail, icon, secondaryImageUrl, size, mainIcon, className, isSelected, onDetailClick, showDetailOnHoverOnly, rounded, detailButtonClassName, loading, containerProps, compactOnMobile, ...props }: ListItemProps): import("react/jsx-runtime").JSX.Element;
26
+ export declare function ListItem({ itemTitle, mainImageUrl, subtitle, subtitleOnHover, detail, icon, secondaryImageUrl, placeholderImageUrl, size, mainIcon, className, isSelected, onDetailClick, showDetailOnHoverOnly, rounded, detailButtonClassName, loading, containerProps, compactOnMobile, ...props }: ListItemProps): import("react/jsx-runtime").JSX.Element;
26
27
  export {};
@@ -9,3 +9,7 @@ export declare const ExtraMarginForBadge: Story;
9
9
  export declare const Rounded: Story;
10
10
  export declare const SizeMedium: Story;
11
11
  export declare const SizeSmall: Story;
12
+ export declare const CustomPlaceholderForBrokenImage: Story;
13
+ export declare const CustomPlaceholderForLoadingImage: Story;
14
+ export declare const CustomPlaceholderForBrokenBadgeImage: Story;
15
+ export declare const CustomPlaceholderForLoadingBadgeImage: Story;
package/dist/index.d.ts CHANGED
@@ -11,9 +11,14 @@ interface BadgeImageProps {
11
11
  size?: BadgeSize;
12
12
  extraMarginForBadge?: boolean;
13
13
  rounded?: boolean;
14
+ /**
15
+ * The URL of the placeholder image. Will be displayed while the images are loading
16
+ * or if there's an error loading them.
17
+ */
18
+ placeholderImageUrl?: string;
14
19
  }
15
20
  type BadgeSize = 'sm' | 'md';
16
- declare function BadgeImage({ imageUrl, badgeUrl, size, extraMarginForBadge, rounded, }: BadgeImageProps): react_jsx_runtime.JSX.Element | null;
21
+ declare function BadgeImage({ imageUrl: _imageUrl, badgeUrl, size, extraMarginForBadge, rounded, placeholderImageUrl, }: BadgeImageProps): react_jsx_runtime.JSX.Element | null;
17
22
 
18
23
  type TextSize = 'small' | 'medium' | 'large';
19
24
  type SwitchSize = 'small' | 'large';
@@ -905,6 +910,7 @@ interface ListItemProps extends React.HTMLAttributes<HTMLButtonElement> {
905
910
  itemTitle: string | React.ReactNode;
906
911
  mainImageUrl?: string;
907
912
  secondaryImageUrl?: string;
913
+ placeholderImageUrl?: string;
908
914
  subtitle?: string;
909
915
  subtitleOnHover?: React.ReactNode;
910
916
  detail?: string;
@@ -924,7 +930,7 @@ interface ListItemProps extends React.HTMLAttributes<HTMLButtonElement> {
924
930
  compactOnMobile?: boolean;
925
931
  }
926
932
  type ListItemSize = 'small' | 'large';
927
- declare function ListItem({ itemTitle, mainImageUrl, subtitle, subtitleOnHover, detail, icon, secondaryImageUrl, size, mainIcon, className, isSelected, onDetailClick, showDetailOnHoverOnly, rounded, detailButtonClassName, loading, containerProps, compactOnMobile, ...props }: ListItemProps): react_jsx_runtime.JSX.Element;
933
+ declare function ListItem({ itemTitle, mainImageUrl, subtitle, subtitleOnHover, detail, icon, secondaryImageUrl, placeholderImageUrl, size, mainIcon, className, isSelected, onDetailClick, showDetailOnHoverOnly, rounded, detailButtonClassName, loading, containerProps, compactOnMobile, ...props }: ListItemProps): react_jsx_runtime.JSX.Element;
928
934
 
929
935
  interface MenuItemProps {
930
936
  label: string;
@@ -1949,6 +1955,13 @@ declare function TransactionViewLayout({ isLoading, header, properties, actions,
1949
1955
 
1950
1956
  declare function WalletsView(): react_jsx_runtime.JSX.Element;
1951
1957
 
1958
+ interface LoaderProps extends ComponentProps<'svg'> {
1959
+ size?: string;
1960
+ strokeWidth?: string;
1961
+ rotateDuration?: string;
1962
+ }
1963
+ declare function Loader({ size, strokeWidth, className, rotateDuration, ...props }: LoaderProps): react_jsx_runtime.JSX.Element;
1964
+
1952
1965
  type SquidTheme = {
1953
1966
  'content-100': string;
1954
1967
  'content-200': string;
@@ -2015,4 +2028,4 @@ declare const MEDIA_QUERIES: Record<MediaQuery, {
2015
2028
  value: string;
2016
2029
  }>;
2017
2030
 
2018
- export { ActionLayout, ActionLineOutRow, ActionProperties, ActionRow, type ActionStatus, ActionStatusRow, ActionWrapper, AddressButton, AnimationWrapper, AppContainer, ApproveAction, ArrowButton, AssetsButton, type AssetsButtonVariant, AssetsView, BadgeImage, type BaseActionProps, type BaseTransactionViewProps, BlockSkeleton, BodyText, Boost, BoostButton, BorderedContainer, Breadcrumb, BridgeAction, BridgeHeader, BridgeProperties, BridgeTransactionView, Button, BuyNFTHeader, BuyNFTProperties, BuyNFTTransactionView, CaptionText, Chip, Collapse, DescriptionBlocks, DetailsToolbar, DropdownMenu, DropdownMenuItem, type DropdownMenuItemProps, ErrorMessage, FeeButton, FeesAction, type FeesActionProps, FeesLines, FeesTotal, FilterButton, HashLink, HeadingText, HistoryItem, type HistoryItemStatus, IconLabel, ImageIcon, IncompleteAction, InfoBox, Inline, Input, InteractionHeader, InteractionProperties, InteractionTransactionView, Join, List, ListItem, LoadingProvider, LoadingSkeleton, MEDIA_QUERIES, MainView, Menu, MenuItem, Modal, ModalContent, ModalContentDivider, NavigationBar, NumericInput, PipeSeparator, ProductCard, ProfileHeader, ProfileHeaderBackground, PropertiesLayout, PropertyListItem, type PropertyListItemProps, ReceiveNFTAction, ReceiveTokensAction, RecipientView, STEP_ITEM_HEIGHT, SectionTitle, SendTokensAction, SettingsButton, type SettingsButtonProps, type SettingsControl, SettingsItem, type SettingsItemProps, SettingsSlider, type SettingsSliderProps, SizeTransition, SquidConfigProvider, type SquidTheme, StakeAction, StartAction, SuccessAction, SwapAction, SwapConfiguration, SwapDetailsView, SwapHeader, type SwapHeaderProps, SwapProgressView, SwapProgressViewHeader, SwapProperties, type SwapPropertiesProps, SwapState, type SwapStep, SwapStepItem, SwapStepsCollapsed, type SwapStepsCollapsedFooterButton, SwapTransactionView, Switch, TextSkeleton, type ThemeType, Timestamp, Toast, TokenPair, Tooltip, type TooltipProps, type TooltipThreshold, type TooltipWidth, TransactionAction, type TransactionActionProps, type TransactionActionType, TransactionFilters, TransactionHeader, TransactionHeaderLayout, type TransactionHeaderProps, type TransactionHeaderType, TransactionItem, TransactionProperties, type TransactionPropertiesProps, type TransactionPropertiesType, TransactionSearch, TransactionState, TransactionView, TransactionViewLayout, type TransactionViewProps, type TransactionViewType, Transfer, UsdAmount, WalletLink, WalletsView, WrapAction, linkActionTimelineProps, statusBgClassMap, statusColorClassMap, statusTextClassMap, useDropdownMenu, useMediaQuery };
2031
+ export { ActionLayout, ActionLineOutRow, ActionProperties, ActionRow, type ActionStatus, ActionStatusRow, ActionWrapper, AddressButton, AnimationWrapper, AppContainer, ApproveAction, ArrowButton, AssetsButton, type AssetsButtonVariant, AssetsView, BadgeImage, type BaseActionProps, type BaseTransactionViewProps, BlockSkeleton, BodyText, Boost, BoostButton, BorderedContainer, Breadcrumb, BridgeAction, BridgeHeader, BridgeProperties, BridgeTransactionView, Button, BuyNFTHeader, BuyNFTProperties, BuyNFTTransactionView, CaptionText, Chip, Collapse, DescriptionBlocks, DetailsToolbar, DropdownMenu, DropdownMenuItem, type DropdownMenuItemProps, ErrorMessage, FeeButton, FeesAction, type FeesActionProps, FeesLines, FeesTotal, FilterButton, HashLink, HeadingText, HistoryItem, type HistoryItemStatus, IconLabel, ImageIcon, IncompleteAction, InfoBox, Inline, Input, InteractionHeader, InteractionProperties, InteractionTransactionView, Join, List, ListItem, Loader, LoadingProvider, LoadingSkeleton, MEDIA_QUERIES, MainView, Menu, MenuItem, Modal, ModalContent, ModalContentDivider, NavigationBar, NumericInput, PipeSeparator, ProductCard, ProfileHeader, ProfileHeaderBackground, PropertiesLayout, PropertyListItem, type PropertyListItemProps, ReceiveNFTAction, ReceiveTokensAction, RecipientView, STEP_ITEM_HEIGHT, SectionTitle, SendTokensAction, SettingsButton, type SettingsButtonProps, type SettingsControl, SettingsItem, type SettingsItemProps, SettingsSlider, type SettingsSliderProps, SizeTransition, SquidConfigProvider, type SquidTheme, StakeAction, StartAction, SuccessAction, SwapAction, SwapConfiguration, SwapDetailsView, SwapHeader, type SwapHeaderProps, SwapProgressView, SwapProgressViewHeader, SwapProperties, type SwapPropertiesProps, SwapState, type SwapStep, SwapStepItem, SwapStepsCollapsed, type SwapStepsCollapsedFooterButton, SwapTransactionView, Switch, TextSkeleton, type ThemeType, Timestamp, Toast, TokenPair, Tooltip, type TooltipProps, type TooltipThreshold, type TooltipWidth, TransactionAction, type TransactionActionProps, type TransactionActionType, TransactionFilters, TransactionHeader, TransactionHeaderLayout, type TransactionHeaderProps, type TransactionHeaderType, TransactionItem, TransactionProperties, type TransactionPropertiesProps, type TransactionPropertiesType, TransactionSearch, TransactionState, TransactionView, TransactionViewLayout, type TransactionViewProps, type TransactionViewType, Transfer, UsdAmount, WalletLink, WalletsView, WrapAction, linkActionTimelineProps, statusBgClassMap, statusColorClassMap, statusTextClassMap, useDropdownMenu, useMediaQuery };
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "url": "git+https://github.com/0xsquid/squid-ui.git"
6
6
  },
7
7
  "description": "Squid's UI components",
8
- "version": "0.20.0",
8
+ "version": "0.20.1-beta.0",
9
9
  "author": "",
10
10
  "license": "MIT",
11
11
  "resolutions": {