@loafmarkets/ui 0.1.409 → 0.1.411

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/index.d.mts CHANGED
@@ -57,6 +57,23 @@ interface PortfolioSummaryProps extends React$1.HTMLAttributes<HTMLDivElement> {
57
57
  }
58
58
  declare const PortfolioSummary: React$1.ForwardRefExoticComponent<PortfolioSummaryProps & React$1.RefAttributes<HTMLDivElement>>;
59
59
 
60
+ /**
61
+ * The market maker's real state for this market — never decorative:
62
+ * active → green (quoting both sides)
63
+ * reduced → gold (one-sided / throttled)
64
+ * free → red (not quoting — peer-to-peer only)
65
+ * unknown → grey (no status from the API; NEVER a fabricated green)
66
+ * Same vocabulary as the consuming app's liquidityDotState() SSOT, which maps the
67
+ * API `liquidity.status` ('active' | 'limited' | 'inactive').
68
+ */
69
+ type LoafLiquidityDotState = "active" | "reduced" | "free" | "unknown";
70
+ interface LoafLiquidityBadgeProps extends React$1.HTMLAttributes<HTMLSpanElement> {
71
+ isGlowing?: boolean;
72
+ /** Market-maker state driving the dot colour. Omitted → grey "unknown". */
73
+ status?: LoafLiquidityDotState;
74
+ }
75
+ declare const LoafLiquidityBadge: React$1.ForwardRefExoticComponent<LoafLiquidityBadgeProps & React$1.RefAttributes<HTMLSpanElement>>;
76
+
60
77
  type OrderbookSide = "ask" | "bid";
61
78
  type OrderbookLevel = {
62
79
  price: number;
@@ -105,6 +122,13 @@ interface OrderbookProps extends React$1.HTMLAttributes<HTMLDivElement> {
105
122
  * a custom `rightHeader` is supplied.
106
123
  */
107
124
  onLoafLiquidityClick?: () => void;
125
+ /**
126
+ * Market-maker state for THIS market, driving the Loaf Liquidity badge dot.
127
+ * Consumers map the API `liquidity.status` ('active' | 'limited' | 'inactive')
128
+ * through their liquidityDotState() SSOT. Omitted → grey "unknown" — the dot is
129
+ * never a decorative green.
130
+ */
131
+ liquidityStatus?: LoafLiquidityDotState;
108
132
  /** Given a trade's txHash, returns the full explorer URL to link to. Defaults to Sepolia Etherscan. */
109
133
  tradeExplorerUrl?: (txHash: string) => string;
110
134
  /** Override the number of visible price levels per side (default 5). */
@@ -329,11 +353,6 @@ type TradeConfirmationModalProps = {
329
353
  };
330
354
  declare function TradeConfirmationModal({ isOpen, onClose, onConfirm, orderDetails, className, estimatedFeeUsd: _estimatedFeeUsd, estimatedFeeBps: _estimatedFeeBps, totalWithFeesUsd, confirmDisabled, confirmLoading, rememberChoiceChecked, rememberChoiceLabel, onRememberChoiceChange, }: TradeConfirmationModalProps): React$1.ReactElement | null;
331
355
 
332
- interface LoafLiquidityBadgeProps extends React$1.HTMLAttributes<HTMLSpanElement> {
333
- isGlowing?: boolean;
334
- }
335
- declare const LoafLiquidityBadge: React$1.ForwardRefExoticComponent<LoafLiquidityBadgeProps & React$1.RefAttributes<HTMLSpanElement>>;
336
-
337
356
  type LoafLiquidityLogoProps = {
338
357
  onClick?: () => void;
339
358
  isGlowing?: boolean;
@@ -1356,4 +1375,4 @@ declare function extractSparkline(candles: ReadonlyArray<{
1356
1375
  }>, maxPoints?: number): number[];
1357
1376
  declare const SparklineChart: React__default.NamedExoticComponent<SparklineChartProps>;
1358
1377
 
1359
- export { type ActivityTabId, AssetSelectorBar, type AssetSelectorBarProps, type AssetSelectorMetric, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, type CardContentProps, CardDescription, type CardDescriptionProps, CardFooter, type CardFooterProps, CardHeader, type CardHeaderProps, type CardProps, CardTitle, type CardTitleProps, ContactPopup, type ContactPopupProps, type FinancialItem, type FundWalletParams, type FundWalletResult, Header, type HeaderNavItem, type HeaderPortfolioData, type HeaderProps, type HousePositionOrderbook, type HousePositionPendingOrder, HousePositionSlider, HousePositionSliderMobile, type HousePositionSliderMobileOrderPayload, type HousePositionSliderMobileOrderbook, type HousePositionSliderMobileProps, type HousePositionSliderOrderPayload, type HousePositionSliderProps, type InspectionSlot, LoafLiquidityBadge, LoafLiquidityLogo, type LoafLiquidityLogoProps, LoginPopup, type LoginPopupProps, MobileTradeNav, type MobileTradeNavItem, type MobileTradeNavProps, type OfferStatus, OfferingProgressCard, type OfferingProgressCardProps, OnboardingGuide, type OnboardingGuideProps, Orderbook, type OrderbookLevel, type OrderbookProps, type OrderbookSide, type OrderbookTrade, type OverviewImage, type OverviewResponse, OwnerBooking, type OwnerBookingProps, PaymentPopup, type PaymentPopupProps, PortfolioActivityPanel, type PortfolioActivityPanelProps, type PortfolioPosition, PortfolioSummary, type PortfolioSummaryProps, PriceChart, type PriceChartCandle, type PriceChartProps, type PriceChartRange, type PropertyAddressOption, PropertyBuy, PropertyCompareBar, type PropertyCompareBarProps, PropertyDocuments, type PropertyGalleryHotspot, type PropertyGalleryImage, PropertyHeroHeader, type PropertyHeroHeaderProps, PropertyHistory, type PropertyInfoItem, PropertyInspectionTimes, PropertyMediaRow, type PropertyMediaRowProps, type PropertyNewsItem, type PropertyNewsType, PropertyNewsUpdates, type PropertyNewsUpdatesProps, type PropertyOffer, PropertyOffers, type PropertyOffersProps, PropertyOverview, type PropertyOverviewProps, PropertyPhotoGallery, type PropertyPriceSummary, PropertySubheader, type PropertySubheaderAction, type PropertySubheaderProps, type PropertySubheaderTab, PropertyTour, type PropertyTourProps, PropertyValuation, type PropertyValuationProps, type PropertyValueSummary, type PurchaseFeedItem, type SelectorItem, SiteFooter, Skeleton, type SkeletonProps, SlideDigit, SparklineChart, type SparklineChartProps, type ToastData, ToastProvider, type ToastVariant, TradeConfirmationModal, type TradeConfirmationModalDetails, type TradeConfirmationModalProps, TradingSlider, type TradingSliderProps, type YourOrder, type YourOrderSide, YourOrders, type YourOrdersProps, badgeVariants, buttonVariants, extractSparkline, hasPendingActivity, useAdaptivePolling, useToast };
1378
+ export { type ActivityTabId, AssetSelectorBar, type AssetSelectorBarProps, type AssetSelectorMetric, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, type CardContentProps, CardDescription, type CardDescriptionProps, CardFooter, type CardFooterProps, CardHeader, type CardHeaderProps, type CardProps, CardTitle, type CardTitleProps, ContactPopup, type ContactPopupProps, type FinancialItem, type FundWalletParams, type FundWalletResult, Header, type HeaderNavItem, type HeaderPortfolioData, type HeaderProps, type HousePositionOrderbook, type HousePositionPendingOrder, HousePositionSlider, HousePositionSliderMobile, type HousePositionSliderMobileOrderPayload, type HousePositionSliderMobileOrderbook, type HousePositionSliderMobileProps, type HousePositionSliderOrderPayload, type HousePositionSliderProps, type InspectionSlot, LoafLiquidityBadge, type LoafLiquidityDotState, LoafLiquidityLogo, type LoafLiquidityLogoProps, LoginPopup, type LoginPopupProps, MobileTradeNav, type MobileTradeNavItem, type MobileTradeNavProps, type OfferStatus, OfferingProgressCard, type OfferingProgressCardProps, OnboardingGuide, type OnboardingGuideProps, Orderbook, type OrderbookLevel, type OrderbookProps, type OrderbookSide, type OrderbookTrade, type OverviewImage, type OverviewResponse, OwnerBooking, type OwnerBookingProps, PaymentPopup, type PaymentPopupProps, PortfolioActivityPanel, type PortfolioActivityPanelProps, type PortfolioPosition, PortfolioSummary, type PortfolioSummaryProps, PriceChart, type PriceChartCandle, type PriceChartProps, type PriceChartRange, type PropertyAddressOption, PropertyBuy, PropertyCompareBar, type PropertyCompareBarProps, PropertyDocuments, type PropertyGalleryHotspot, type PropertyGalleryImage, PropertyHeroHeader, type PropertyHeroHeaderProps, PropertyHistory, type PropertyInfoItem, PropertyInspectionTimes, PropertyMediaRow, type PropertyMediaRowProps, type PropertyNewsItem, type PropertyNewsType, PropertyNewsUpdates, type PropertyNewsUpdatesProps, type PropertyOffer, PropertyOffers, type PropertyOffersProps, PropertyOverview, type PropertyOverviewProps, PropertyPhotoGallery, type PropertyPriceSummary, PropertySubheader, type PropertySubheaderAction, type PropertySubheaderProps, type PropertySubheaderTab, PropertyTour, type PropertyTourProps, PropertyValuation, type PropertyValuationProps, type PropertyValueSummary, type PurchaseFeedItem, type SelectorItem, SiteFooter, Skeleton, type SkeletonProps, SlideDigit, SparklineChart, type SparklineChartProps, type ToastData, ToastProvider, type ToastVariant, TradeConfirmationModal, type TradeConfirmationModalDetails, type TradeConfirmationModalProps, TradingSlider, type TradingSliderProps, type YourOrder, type YourOrderSide, YourOrders, type YourOrdersProps, badgeVariants, buttonVariants, extractSparkline, hasPendingActivity, useAdaptivePolling, useToast };
package/dist/index.d.ts CHANGED
@@ -57,6 +57,23 @@ interface PortfolioSummaryProps extends React$1.HTMLAttributes<HTMLDivElement> {
57
57
  }
58
58
  declare const PortfolioSummary: React$1.ForwardRefExoticComponent<PortfolioSummaryProps & React$1.RefAttributes<HTMLDivElement>>;
59
59
 
60
+ /**
61
+ * The market maker's real state for this market — never decorative:
62
+ * active → green (quoting both sides)
63
+ * reduced → gold (one-sided / throttled)
64
+ * free → red (not quoting — peer-to-peer only)
65
+ * unknown → grey (no status from the API; NEVER a fabricated green)
66
+ * Same vocabulary as the consuming app's liquidityDotState() SSOT, which maps the
67
+ * API `liquidity.status` ('active' | 'limited' | 'inactive').
68
+ */
69
+ type LoafLiquidityDotState = "active" | "reduced" | "free" | "unknown";
70
+ interface LoafLiquidityBadgeProps extends React$1.HTMLAttributes<HTMLSpanElement> {
71
+ isGlowing?: boolean;
72
+ /** Market-maker state driving the dot colour. Omitted → grey "unknown". */
73
+ status?: LoafLiquidityDotState;
74
+ }
75
+ declare const LoafLiquidityBadge: React$1.ForwardRefExoticComponent<LoafLiquidityBadgeProps & React$1.RefAttributes<HTMLSpanElement>>;
76
+
60
77
  type OrderbookSide = "ask" | "bid";
61
78
  type OrderbookLevel = {
62
79
  price: number;
@@ -105,6 +122,13 @@ interface OrderbookProps extends React$1.HTMLAttributes<HTMLDivElement> {
105
122
  * a custom `rightHeader` is supplied.
106
123
  */
107
124
  onLoafLiquidityClick?: () => void;
125
+ /**
126
+ * Market-maker state for THIS market, driving the Loaf Liquidity badge dot.
127
+ * Consumers map the API `liquidity.status` ('active' | 'limited' | 'inactive')
128
+ * through their liquidityDotState() SSOT. Omitted → grey "unknown" — the dot is
129
+ * never a decorative green.
130
+ */
131
+ liquidityStatus?: LoafLiquidityDotState;
108
132
  /** Given a trade's txHash, returns the full explorer URL to link to. Defaults to Sepolia Etherscan. */
109
133
  tradeExplorerUrl?: (txHash: string) => string;
110
134
  /** Override the number of visible price levels per side (default 5). */
@@ -329,11 +353,6 @@ type TradeConfirmationModalProps = {
329
353
  };
330
354
  declare function TradeConfirmationModal({ isOpen, onClose, onConfirm, orderDetails, className, estimatedFeeUsd: _estimatedFeeUsd, estimatedFeeBps: _estimatedFeeBps, totalWithFeesUsd, confirmDisabled, confirmLoading, rememberChoiceChecked, rememberChoiceLabel, onRememberChoiceChange, }: TradeConfirmationModalProps): React$1.ReactElement | null;
331
355
 
332
- interface LoafLiquidityBadgeProps extends React$1.HTMLAttributes<HTMLSpanElement> {
333
- isGlowing?: boolean;
334
- }
335
- declare const LoafLiquidityBadge: React$1.ForwardRefExoticComponent<LoafLiquidityBadgeProps & React$1.RefAttributes<HTMLSpanElement>>;
336
-
337
356
  type LoafLiquidityLogoProps = {
338
357
  onClick?: () => void;
339
358
  isGlowing?: boolean;
@@ -1356,4 +1375,4 @@ declare function extractSparkline(candles: ReadonlyArray<{
1356
1375
  }>, maxPoints?: number): number[];
1357
1376
  declare const SparklineChart: React__default.NamedExoticComponent<SparklineChartProps>;
1358
1377
 
1359
- export { type ActivityTabId, AssetSelectorBar, type AssetSelectorBarProps, type AssetSelectorMetric, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, type CardContentProps, CardDescription, type CardDescriptionProps, CardFooter, type CardFooterProps, CardHeader, type CardHeaderProps, type CardProps, CardTitle, type CardTitleProps, ContactPopup, type ContactPopupProps, type FinancialItem, type FundWalletParams, type FundWalletResult, Header, type HeaderNavItem, type HeaderPortfolioData, type HeaderProps, type HousePositionOrderbook, type HousePositionPendingOrder, HousePositionSlider, HousePositionSliderMobile, type HousePositionSliderMobileOrderPayload, type HousePositionSliderMobileOrderbook, type HousePositionSliderMobileProps, type HousePositionSliderOrderPayload, type HousePositionSliderProps, type InspectionSlot, LoafLiquidityBadge, LoafLiquidityLogo, type LoafLiquidityLogoProps, LoginPopup, type LoginPopupProps, MobileTradeNav, type MobileTradeNavItem, type MobileTradeNavProps, type OfferStatus, OfferingProgressCard, type OfferingProgressCardProps, OnboardingGuide, type OnboardingGuideProps, Orderbook, type OrderbookLevel, type OrderbookProps, type OrderbookSide, type OrderbookTrade, type OverviewImage, type OverviewResponse, OwnerBooking, type OwnerBookingProps, PaymentPopup, type PaymentPopupProps, PortfolioActivityPanel, type PortfolioActivityPanelProps, type PortfolioPosition, PortfolioSummary, type PortfolioSummaryProps, PriceChart, type PriceChartCandle, type PriceChartProps, type PriceChartRange, type PropertyAddressOption, PropertyBuy, PropertyCompareBar, type PropertyCompareBarProps, PropertyDocuments, type PropertyGalleryHotspot, type PropertyGalleryImage, PropertyHeroHeader, type PropertyHeroHeaderProps, PropertyHistory, type PropertyInfoItem, PropertyInspectionTimes, PropertyMediaRow, type PropertyMediaRowProps, type PropertyNewsItem, type PropertyNewsType, PropertyNewsUpdates, type PropertyNewsUpdatesProps, type PropertyOffer, PropertyOffers, type PropertyOffersProps, PropertyOverview, type PropertyOverviewProps, PropertyPhotoGallery, type PropertyPriceSummary, PropertySubheader, type PropertySubheaderAction, type PropertySubheaderProps, type PropertySubheaderTab, PropertyTour, type PropertyTourProps, PropertyValuation, type PropertyValuationProps, type PropertyValueSummary, type PurchaseFeedItem, type SelectorItem, SiteFooter, Skeleton, type SkeletonProps, SlideDigit, SparklineChart, type SparklineChartProps, type ToastData, ToastProvider, type ToastVariant, TradeConfirmationModal, type TradeConfirmationModalDetails, type TradeConfirmationModalProps, TradingSlider, type TradingSliderProps, type YourOrder, type YourOrderSide, YourOrders, type YourOrdersProps, badgeVariants, buttonVariants, extractSparkline, hasPendingActivity, useAdaptivePolling, useToast };
1378
+ export { type ActivityTabId, AssetSelectorBar, type AssetSelectorBarProps, type AssetSelectorMetric, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, type CardContentProps, CardDescription, type CardDescriptionProps, CardFooter, type CardFooterProps, CardHeader, type CardHeaderProps, type CardProps, CardTitle, type CardTitleProps, ContactPopup, type ContactPopupProps, type FinancialItem, type FundWalletParams, type FundWalletResult, Header, type HeaderNavItem, type HeaderPortfolioData, type HeaderProps, type HousePositionOrderbook, type HousePositionPendingOrder, HousePositionSlider, HousePositionSliderMobile, type HousePositionSliderMobileOrderPayload, type HousePositionSliderMobileOrderbook, type HousePositionSliderMobileProps, type HousePositionSliderOrderPayload, type HousePositionSliderProps, type InspectionSlot, LoafLiquidityBadge, type LoafLiquidityDotState, LoafLiquidityLogo, type LoafLiquidityLogoProps, LoginPopup, type LoginPopupProps, MobileTradeNav, type MobileTradeNavItem, type MobileTradeNavProps, type OfferStatus, OfferingProgressCard, type OfferingProgressCardProps, OnboardingGuide, type OnboardingGuideProps, Orderbook, type OrderbookLevel, type OrderbookProps, type OrderbookSide, type OrderbookTrade, type OverviewImage, type OverviewResponse, OwnerBooking, type OwnerBookingProps, PaymentPopup, type PaymentPopupProps, PortfolioActivityPanel, type PortfolioActivityPanelProps, type PortfolioPosition, PortfolioSummary, type PortfolioSummaryProps, PriceChart, type PriceChartCandle, type PriceChartProps, type PriceChartRange, type PropertyAddressOption, PropertyBuy, PropertyCompareBar, type PropertyCompareBarProps, PropertyDocuments, type PropertyGalleryHotspot, type PropertyGalleryImage, PropertyHeroHeader, type PropertyHeroHeaderProps, PropertyHistory, type PropertyInfoItem, PropertyInspectionTimes, PropertyMediaRow, type PropertyMediaRowProps, type PropertyNewsItem, type PropertyNewsType, PropertyNewsUpdates, type PropertyNewsUpdatesProps, type PropertyOffer, PropertyOffers, type PropertyOffersProps, PropertyOverview, type PropertyOverviewProps, PropertyPhotoGallery, type PropertyPriceSummary, PropertySubheader, type PropertySubheaderAction, type PropertySubheaderProps, type PropertySubheaderTab, PropertyTour, type PropertyTourProps, PropertyValuation, type PropertyValuationProps, type PropertyValueSummary, type PurchaseFeedItem, type SelectorItem, SiteFooter, Skeleton, type SkeletonProps, SlideDigit, SparklineChart, type SparklineChartProps, type ToastData, ToastProvider, type ToastVariant, TradeConfirmationModal, type TradeConfirmationModalDetails, type TradeConfirmationModalProps, TradingSlider, type TradingSliderProps, type YourOrder, type YourOrderSide, YourOrders, type YourOrdersProps, badgeVariants, buttonVariants, extractSparkline, hasPendingActivity, useAdaptivePolling, useToast };
package/dist/index.js CHANGED
@@ -1640,12 +1640,23 @@ var StatusDot = styled10__default.default.span`
1640
1640
  width: 6px;
1641
1641
  height: 6px;
1642
1642
  border-radius: 50%;
1643
- background: #0ecb81;
1644
1643
  flex-shrink: 0;
1645
- animation: ${breathe} 3s ease-in-out infinite;
1644
+
1645
+ ${({ $state }) => $state === "active" ? styled10.css`
1646
+ background: #0ecb81;
1647
+ animation: ${breathe} 3s ease-in-out infinite;
1648
+ ` : $state === "reduced" ? styled10.css`
1649
+ background: #e6c87e;
1650
+ box-shadow: 0 0 4px rgba(240, 185, 11, 0.4);
1651
+ ` : $state === "free" ? styled10.css`
1652
+ background: #f6465d;
1653
+ box-shadow: 0 0 4px rgba(246, 70, 93, 0.4);
1654
+ ` : styled10.css`
1655
+ background: rgba(255, 255, 255, 0.3);
1656
+ `}
1646
1657
  `;
1647
1658
  var LoafLiquidityBadge = React5__namespace.forwardRef(
1648
- ({ className, isGlowing, onClick, children, ...props }, ref) => {
1659
+ ({ className, isGlowing, status = "unknown", onClick, children, ...props }, ref) => {
1649
1660
  return /* @__PURE__ */ jsxRuntime.jsxs(
1650
1661
  LogoContainer,
1651
1662
  {
@@ -1656,11 +1667,11 @@ var LoafLiquidityBadge = React5__namespace.forwardRef(
1656
1667
  role: onClick ? "button" : void 0,
1657
1668
  ...props,
1658
1669
  children: [
1659
- /* @__PURE__ */ jsxRuntime.jsxs(LogoText, { children: [
1670
+ /* @__PURE__ */ jsxRuntime.jsxs(LogoText, { className: "loaf-ll-label", children: [
1660
1671
  /* @__PURE__ */ jsxRuntime.jsx(LoafLogoImage, { src: Loaf_logo_Banner_default, alt: "Loaf" }),
1661
1672
  /* @__PURE__ */ jsxRuntime.jsx(LiquidityText, { children: children ?? "Liquidity" })
1662
1673
  ] }),
1663
- /* @__PURE__ */ jsxRuntime.jsx(StatusDot, {})
1674
+ /* @__PURE__ */ jsxRuntime.jsx(StatusDot, { $state: status, "data-liquidity": status })
1664
1675
  ]
1665
1676
  }
1666
1677
  );
@@ -1907,13 +1918,21 @@ var Orderbook = React5__namespace.forwardRef(
1907
1918
  isLoading = false,
1908
1919
  onPriceClick,
1909
1920
  onLoafLiquidityClick,
1921
+ liquidityStatus,
1910
1922
  tradeExplorerUrl,
1911
1923
  maxLevels,
1912
1924
  fillHeight = false,
1913
1925
  className,
1914
1926
  ...props
1915
1927
  }, ref) => {
1916
- const resolvedRightHeader = rightHeader ?? /* @__PURE__ */ jsxRuntime.jsx(LoafLiquidityBadge, { className: "text-[0.6rem] orderbook-ll-badge", onClick: onLoafLiquidityClick });
1928
+ const resolvedRightHeader = rightHeader ?? /* @__PURE__ */ jsxRuntime.jsx(
1929
+ LoafLiquidityBadge,
1930
+ {
1931
+ className: "text-[0.6rem] orderbook-ll-badge",
1932
+ onClick: onLoafLiquidityClick,
1933
+ status: liquidityStatus
1934
+ }
1935
+ );
1917
1936
  const [tab, setTabState] = React5__namespace.useState(defaultTab);
1918
1937
  const setTab = setTabState;
1919
1938
  const effectiveTab = showTradesTab ? tab : "orderbook";
@@ -2669,6 +2688,22 @@ var PropertyTour = React5__namespace.forwardRef(
2669
2688
  }
2670
2689
  );
2671
2690
  PropertyTour.displayName = "PropertyTour";
2691
+
2692
+ // src/lib/isSafeUrl.ts
2693
+ var CONTROL_CHARS = /[\u0000-\u001F\u007F]/g;
2694
+ function isSafeUrl(url) {
2695
+ if (!url) return false;
2696
+ const cleaned = url.replace(CONTROL_CHARS, "").replace(/\\/g, "/").trim();
2697
+ if (cleaned === "") return false;
2698
+ if (cleaned.startsWith("//")) return false;
2699
+ if (cleaned.startsWith("/")) return true;
2700
+ try {
2701
+ const { protocol } = new URL(cleaned);
2702
+ return protocol === "http:" || protocol === "https:";
2703
+ } catch {
2704
+ return false;
2705
+ }
2706
+ }
2672
2707
  var ITEMS_PER_PAGE = 5;
2673
2708
  var ITEMS_PER_PAGE_MOBILE = 5;
2674
2709
  var ensureAnimationsInjected = () => {
@@ -2864,7 +2899,7 @@ function NewsArticleModal({ item, onClose }) {
2864
2899
  ] }),
2865
2900
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: { height: "1px", background: "rgba(255,255,255,0.08)", marginBottom: "1.25rem" } }),
2866
2901
  item.summary ? /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.875rem", color: "rgba(255,255,255,0.8)", lineHeight: 1.75, margin: 0 }, children: item.summary }) : /* @__PURE__ */ jsxRuntime.jsx("p", { style: { fontSize: "0.8rem", color: "rgba(255,255,255,0.35)", fontStyle: "italic", margin: 0 }, children: "Summary not available for this article." }),
2867
- item.url && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: "1.25rem", paddingTop: "1rem", borderTop: "1px solid rgba(255,255,255,0.08)" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
2902
+ item.url && isSafeUrl(item.url) && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: "1.25rem", paddingTop: "1rem", borderTop: "1px solid rgba(255,255,255,0.08)" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
2868
2903
  "a",
2869
2904
  {
2870
2905
  href: item.url,
@@ -6640,6 +6675,16 @@ var PropertySubheader = React5__namespace.forwardRef(
6640
6675
  }
6641
6676
  );
6642
6677
  PropertySubheader.displayName = "PropertySubheader";
6678
+
6679
+ // src/lib/isTrustedTransakOrigin.ts
6680
+ function isTrustedTransakOrigin(eventOrigin, widgetUrl) {
6681
+ if (!widgetUrl) return false;
6682
+ try {
6683
+ return eventOrigin === new URL(widgetUrl).origin;
6684
+ } catch {
6685
+ return false;
6686
+ }
6687
+ }
6643
6688
  var DEFAULT_LOGO_SRC = Loaf_logo_Banner_default;
6644
6689
  var DEFAULT_LOGO_ALT = "Loaf";
6645
6690
  var OTP_INPUT_LENGTH = 6;
@@ -6780,7 +6825,7 @@ var LoginPopup = ({
6780
6825
  React5.useEffect(() => {
6781
6826
  if (!transakWidgetUrl) return;
6782
6827
  const handleTransakMessage = (event) => {
6783
- if (!event.origin.includes("transak.com") && !event.origin.includes("global.transak.com")) {
6828
+ if (!isTrustedTransakOrigin(event.origin, transakWidgetUrl)) {
6784
6829
  return;
6785
6830
  }
6786
6831
  try {
@@ -12297,7 +12342,7 @@ function PropertyDocuments({ documentsData, highlightDocument, onClearHighlight
12297
12342
  const [previewTitle, setPreviewTitle] = React5.useState(null);
12298
12343
  const backendDocuments = Array.isArray(documentsData?.documents) ? documentsData.documents : [];
12299
12344
  const liveDocs = backendDocuments.filter(
12300
- (d) => Boolean(d.documentUrl) && LIVE_TITLE_PATTERNS.some((rx) => rx.test(d.title))
12345
+ (d) => Boolean(d.documentUrl) && isSafeUrl(d.documentUrl) && LIVE_TITLE_PATTERNS.some((rx) => rx.test(d.title))
12301
12346
  );
12302
12347
  const comingSoonDocs = COMING_SOON_TITLES.filter(
12303
12348
  (title) => !liveDocs.some((d) => d.title.toLowerCase().includes(title.toLowerCase()) || title.toLowerCase().includes(d.title.toLowerCase()))