@agg-build/ui 2.2.3 → 2.3.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.
@@ -23,7 +23,7 @@ import {
23
23
  resolveUnifiedOrderBookEntries,
24
24
  sortOutcomeSelectorOutcomes,
25
25
  useEventTradingContext
26
- } from "./chunk-LPIAEKSZ.mjs";
26
+ } from "./chunk-SG573ODC.mjs";
27
27
  import {
28
28
  AutocompleteSelect,
29
29
  Badge,
@@ -53,7 +53,6 @@ import {
53
53
  dedupeVenueMarketsById,
54
54
  detailsBaseCardClassName,
55
55
  filterEventsByTabValue,
56
- formatEventTitleWithDateSuffix,
57
56
  formatMarketProbabilityPercent,
58
57
  formatPriceGapPercent,
59
58
  getMarketDetailsTabs,
@@ -66,6 +65,7 @@ import {
66
65
  orderBookRowLimitDefault,
67
66
  resolveCategoryIdsFromPath,
68
67
  resolveDisplayVolume,
68
+ resolveEventHeading,
69
69
  resolveEventListItemEvent,
70
70
  resolveOutcomeTitle,
71
71
  resolveResolvedOutcomeLabel,
@@ -75,7 +75,7 @@ import {
75
75
  sortCategoriesForNavigation,
76
76
  sortOutcomes,
77
77
  splitEventsByLifecycle
78
- } from "./chunk-UTXQUOU3.mjs";
78
+ } from "./chunk-6Z5GQ3KL.mjs";
79
79
 
80
80
  // src/events/item/index.tsx
81
81
  import {
@@ -376,13 +376,16 @@ var EventListItemContent = ({
376
376
  const config = useSdkUiConfig();
377
377
  const labels = useLabels();
378
378
  const allVenueMarkets = useMemo(() => event.venueMarkets, [event.venueMarkets]);
379
- const resolvedTitle = formatEventTitleWithDateSuffix({
379
+ const eventHeading = resolveEventHeading({
380
380
  title: event.title,
381
381
  categories: event.categories,
382
382
  structureType: event.structureType,
383
383
  gameStartTime: event.gameStartTime,
384
- endDate: event.endDate
384
+ endDate: event.endDate,
385
+ venueMarkets: event.venueMarkets
385
386
  });
387
+ const resolvedTitle = eventHeading.title;
388
+ const resolvedTimestamp = eventHeading.timestampLabel;
386
389
  const resolvedImage = event.image;
387
390
  const visibleVenueLogos = useMemo(() => {
388
391
  var _a2;
@@ -688,10 +691,10 @@ var EventListItemContent = ({
688
691
  href,
689
692
  onClick: handleClick,
690
693
  onKeyDown: handleKeyDown,
691
- "aria-label": ariaLabel != null ? ariaLabel : resolvedTitle,
694
+ "aria-label": ariaLabel != null ? ariaLabel : [resolvedTitle, resolvedTimestamp].filter(Boolean).join(" "),
692
695
  withGradient: true,
693
696
  children: [
694
- /* @__PURE__ */ jsxs("div", { className: cn("agg-event-card-header flex h-12 items-center gap-4", classNames == null ? void 0 : classNames.header), children: [
697
+ /* @__PURE__ */ jsxs("div", { className: cn("agg-event-card-header flex items-center gap-4", classNames == null ? void 0 : classNames.header), children: [
695
698
  /* @__PURE__ */ jsx(
696
699
  RemoteImage,
697
700
  {
@@ -703,19 +706,32 @@ var EventListItemContent = ({
703
706
  }
704
707
  }
705
708
  ),
706
- /* @__PURE__ */ jsx(
707
- Typography,
708
- {
709
- variant: "body-strong",
710
- className: cn(
711
- "agg-event-title",
712
- "min-w-0 flex-1 text-agg-base font-agg-bold leading-agg-6",
713
- "truncate text-wrap wrap-break-word line-clamp-2",
714
- classNames == null ? void 0 : classNames.title
715
- ),
716
- children: resolvedTitle
717
- }
718
- )
709
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1 self-stretch", children: /* @__PURE__ */ jsxs("div", { className: "flex h-12 min-w-0 flex-col justify-center", children: [
710
+ /* @__PURE__ */ jsx(
711
+ Typography,
712
+ {
713
+ variant: "body-strong",
714
+ className: cn(
715
+ "agg-event-title",
716
+ "min-w-0 text-agg-base font-agg-bold leading-agg-6",
717
+ resolvedTimestamp ? "truncate whitespace-nowrap" : "text-wrap wrap-break-word line-clamp-2",
718
+ classNames == null ? void 0 : classNames.title
719
+ ),
720
+ children: resolvedTitle
721
+ }
722
+ ),
723
+ resolvedTimestamp ? /* @__PURE__ */ jsx("div", { className: "agg-event-timestamp-row mt-0.5 h-5 min-w-0", children: /* @__PURE__ */ jsx(
724
+ Typography,
725
+ {
726
+ variant: "body",
727
+ className: cn(
728
+ "agg-event-timestamp min-w-0 truncate",
729
+ "text-agg-sm leading-agg-5 text-agg-muted-foreground"
730
+ ),
731
+ children: resolvedTimestamp
732
+ }
733
+ ) }) : null
734
+ ] }) })
719
735
  ] }),
720
736
  /* @__PURE__ */ jsxs(
721
737
  "div",
@@ -2561,19 +2577,27 @@ var EventListItemDetailsContent = ({
2561
2577
  return `${config.formatting.formatCompactCurrency(resolvedVolume)} ${labels.eventItemDetails.volumeSuffix}`;
2562
2578
  }, [config, event.volume, labels.eventItemDetails.volumeSuffix, venueMarkets]);
2563
2579
  const resolvedTitle = useMemo5(() => {
2564
- return formatEventTitleWithDateSuffix({
2580
+ return resolveEventHeading({
2565
2581
  title: event.title,
2566
2582
  categories: event.categories,
2567
2583
  structureType: event.structureType,
2568
2584
  gameStartTime: event.gameStartTime,
2569
- endDate: event.endDate
2585
+ endDate: event.endDate,
2586
+ venueMarkets: event.venueMarkets
2570
2587
  });
2571
- }, [event.categories, event.gameStartTime, event.endDate, event.structureType, event.title]);
2588
+ }, [
2589
+ event.categories,
2590
+ event.endDate,
2591
+ event.gameStartTime,
2592
+ event.structureType,
2593
+ event.title,
2594
+ event.venueMarkets
2595
+ ]);
2572
2596
  return /* @__PURE__ */ jsxs4(
2573
2597
  Card,
2574
2598
  {
2575
2599
  className: cn("group/agg-event-details", detailsBaseCardClassName, classNames == null ? void 0 : classNames.root),
2576
- "aria-label": ariaLabel != null ? ariaLabel : resolvedTitle,
2600
+ "aria-label": ariaLabel != null ? ariaLabel : [resolvedTitle.title, resolvedTitle.timestampLabel].filter(Boolean).join(" "),
2577
2601
  onClick: () => {
2578
2602
  onClick == null ? void 0 : onClick(event);
2579
2603
  },
@@ -2598,19 +2622,29 @@ var EventListItemDetailsContent = ({
2598
2622
  }
2599
2623
  ),
2600
2624
  /* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 flex-1 flex-col gap-2", children: [
2601
- /* @__PURE__ */ jsx5(
2602
- Typography,
2603
- {
2604
- variant: "body-strong",
2605
- className: cn(
2606
- "agg-event-title",
2607
- "min-w-0 text-agg-base font-agg-bold! leading-agg-6 md:text-agg-2xl md:leading-agg-8",
2608
- "truncate text-wrap wrap-break-word line-clamp-2",
2609
- classNames == null ? void 0 : classNames.title
2610
- ),
2611
- children: resolvedTitle
2612
- }
2613
- ),
2625
+ /* @__PURE__ */ jsxs4("div", { className: "min-w-0", children: [
2626
+ /* @__PURE__ */ jsx5(
2627
+ Typography,
2628
+ {
2629
+ variant: "body-strong",
2630
+ className: cn(
2631
+ "agg-event-title",
2632
+ "min-w-0 text-agg-base font-agg-bold! leading-agg-6 md:text-agg-2xl md:leading-agg-8",
2633
+ resolvedTitle.timestampLabel ? "truncate whitespace-nowrap" : "truncate text-wrap wrap-break-word line-clamp-2",
2634
+ classNames == null ? void 0 : classNames.title
2635
+ ),
2636
+ children: resolvedTitle.title
2637
+ }
2638
+ ),
2639
+ resolvedTitle.timestampLabel ? /* @__PURE__ */ jsx5(
2640
+ Typography,
2641
+ {
2642
+ variant: "body",
2643
+ className: "agg-event-timestamp mt-0.5 min-w-0 truncate text-agg-sm leading-agg-5 text-agg-muted-foreground",
2644
+ children: resolvedTitle.timestampLabel
2645
+ }
2646
+ ) : null
2647
+ ] }),
2614
2648
  venueMarkets.length > 1 ? /* @__PURE__ */ jsx5(
2615
2649
  EventListItemDetailsMarketSelector,
2616
2650
  {
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  dispatchAggDepositNotification
4
- } from "./chunk-4QGZ3FWI.mjs";
4
+ } from "./chunk-7OVSGWI7.mjs";
5
5
  import {
6
6
  BestPricesIcon,
7
7
  BoltIcon,
@@ -41,7 +41,7 @@ import {
41
41
  shortenAddress,
42
42
  useOptionalToast,
43
43
  venueLogoLabels
44
- } from "./chunk-UTXQUOU3.mjs";
44
+ } from "./chunk-6Z5GQ3KL.mjs";
45
45
 
46
46
  // src/deposit/index.tsx
47
47
  import { useAggAuthState, useAggUiConfig, useDepositAddresses, useLabels as useLabels11 } from "@agg-build/hooks";
@@ -6728,23 +6728,69 @@ var isSportEvent = (categories, structureType) => {
6728
6728
  return isSportCategoryToken(categoryEntry.id) || isSportCategoryToken((_a2 = categoryEntry.category) == null ? void 0 : _a2.id) || isSportCategoryToken((_b = categoryEntry.category) == null ? void 0 : _b.name) || isSportCategoryToken((_c = categoryEntry.category) == null ? void 0 : _c.displayName) || isSportCategoryToken((_d = categoryEntry.category) == null ? void 0 : _d.parentId);
6729
6729
  })) != null ? _a : false;
6730
6730
  };
6731
- var formatEventTitleWithDateSuffix = ({
6732
- title: title2,
6731
+ var hasFixtureMarketMetadata = (venueMarkets) => {
6732
+ var _a;
6733
+ return (_a = venueMarkets == null ? void 0 : venueMarkets.some((venueMarket) => {
6734
+ var _a2, _b, _c, _d;
6735
+ return Boolean(
6736
+ ((_a2 = venueMarket.sportsMarketType) == null ? void 0 : _a2.trim()) || ((_b = venueMarket.marketCategory) == null ? void 0 : _b.trim()) || ((_c = venueMarket.marketSubtype) == null ? void 0 : _c.trim()) || ((_d = venueMarket.period) == null ? void 0 : _d.trim()) || venueMarket.lineValue != null
6737
+ );
6738
+ })) != null ? _a : false;
6739
+ };
6740
+ var shouldDisplaySportsEventTimestamp = ({
6733
6741
  categories,
6734
6742
  structureType,
6743
+ venueMarkets
6744
+ }) => {
6745
+ if (!isSportEvent(categories, structureType)) return false;
6746
+ if (structureType === "sport") {
6747
+ return true;
6748
+ }
6749
+ if (typeof structureType === "string" && structureType.trim()) {
6750
+ return false;
6751
+ }
6752
+ return hasFixtureMarketMetadata(venueMarkets);
6753
+ };
6754
+ var resolveSportsEventTimestamp = ({
6735
6755
  gameStartTime,
6736
6756
  endDate
6757
+ }) => {
6758
+ return (gameStartTime == null ? void 0 : gameStartTime.trim()) || (endDate == null ? void 0 : endDate.trim()) || null;
6759
+ };
6760
+ var resolveEventTimestampLabel = ({
6761
+ categories,
6762
+ structureType,
6763
+ gameStartTime,
6764
+ endDate,
6765
+ venueMarkets
6766
+ }) => {
6767
+ if (!shouldDisplaySportsEventTimestamp({ categories, structureType, venueMarkets })) {
6768
+ return null;
6769
+ }
6770
+ const timestamp = resolveSportsEventTimestamp({ gameStartTime, endDate });
6771
+ if (!timestamp) return null;
6772
+ return formatSportsEventTimeEt(timestamp);
6773
+ };
6774
+ var resolveEventHeading = ({
6775
+ title: title2,
6776
+ categories,
6777
+ structureType,
6778
+ gameStartTime,
6779
+ endDate,
6780
+ venueMarkets
6737
6781
  }) => {
6738
6782
  const resolvedTitle = title2.trim();
6739
- if (!resolvedTitle) return resolvedTitle;
6740
- if (!isSportEvent(categories, structureType)) return resolvedTitle;
6741
- const dateSource = gameStartTime != null ? gameStartTime : endDate;
6742
- if (!dateSource) return resolvedTitle;
6743
- const formattedDate = formatSportsEventTimeEt(dateSource);
6744
- if (!formattedDate) return resolvedTitle;
6745
- const suffix = ` - ${formattedDate}`;
6746
- if (resolvedTitle.endsWith(suffix)) return resolvedTitle;
6747
- return `${resolvedTitle}${suffix}`;
6783
+ return {
6784
+ title: resolvedTitle,
6785
+ timestampLabel: resolveEventTimestampLabel({
6786
+ title: resolvedTitle,
6787
+ categories,
6788
+ structureType,
6789
+ gameStartTime,
6790
+ endDate,
6791
+ venueMarkets
6792
+ })
6793
+ };
6748
6794
  };
6749
6795
 
6750
6796
  // src/events/item/event-list-item.utils.ts
@@ -7085,13 +7131,13 @@ var mapVenueEventToSearchResult = (event, labels, formatPercent, formatCompactCu
7085
7131
  const probability = normalizeProbability(
7086
7132
  (_a = options == null ? void 0 : options.priceByOutcomeId) == null ? void 0 : _a.get(visibleOutcome.outcome.id)
7087
7133
  );
7088
- const resolvedTitle = formatEventTitleWithDateSuffix({
7134
+ const resolvedTitle = resolveEventHeading({
7089
7135
  title: (_b = event == null ? void 0 : event.title) != null ? _b : "",
7090
7136
  categories: event.categories,
7091
7137
  structureType: event.structureType,
7092
7138
  gameStartTime: event.gameStartTime,
7093
7139
  endDate: event.endDate
7094
- });
7140
+ }).title;
7095
7141
  if (!resolvedTitle) return null;
7096
7142
  const { marketCount, venueCount } = getVenueSummary(event.venueMarkets);
7097
7143
  const marketSummaryLabel = [
@@ -9839,7 +9885,7 @@ export {
9839
9885
  fallbackLineColors,
9840
9886
  VenueLogo,
9841
9887
  formatSportsEventTimeEt,
9842
- formatEventTitleWithDateSuffix,
9888
+ resolveEventHeading,
9843
9889
  normalizeVenueMarketCluster,
9844
9890
  resolveEventListItemEvent,
9845
9891
  normalizeProbability,
@@ -3,7 +3,7 @@ import {
3
3
  AGG_TERMS_OF_SERVICE_URL,
4
4
  Icon,
5
5
  cn
6
- } from "./chunk-UTXQUOU3.mjs";
6
+ } from "./chunk-6Z5GQ3KL.mjs";
7
7
 
8
8
  // src/geo-block-banner/index.tsx
9
9
  import { useLabels } from "@agg-build/hooks";
@@ -10,7 +10,7 @@ import {
10
10
  isErrorWithStatus,
11
11
  useEventListTabs,
12
12
  useEventListTabsHeaderOverflow
13
- } from "./chunk-QM3WWPCV.mjs";
13
+ } from "./chunk-3R2CQTNM.mjs";
14
14
  import {
15
15
  DEPOSIT_MODAL_OPEN_EVENT,
16
16
  PlaceOrder,
@@ -18,10 +18,10 @@ import {
18
18
  WITHDRAW_MODAL_OPEN_EVENT,
19
19
  useClaimWinnings,
20
20
  useResolvedMarketClaim
21
- } from "./chunk-JOZPXDNZ.mjs";
21
+ } from "./chunk-MXM5PM4A.mjs";
22
22
  import {
23
23
  getDisplayOutcomePrice
24
- } from "./chunk-LPIAEKSZ.mjs";
24
+ } from "./chunk-SG573ODC.mjs";
25
25
  import {
26
26
  AggErrorBoundary,
27
27
  Button,
@@ -52,7 +52,7 @@ import {
52
52
  resolveTabVenus,
53
53
  shortenAddress,
54
54
  sortCategoriesForNavigation
55
- } from "./chunk-UTXQUOU3.mjs";
55
+ } from "./chunk-6Z5GQ3KL.mjs";
56
56
 
57
57
  // src/pages/home/index.tsx
58
58
  import {
@@ -485,7 +485,12 @@ var SPORTS_SECTION_TAB_DEFINITIONS = [
485
485
  { key: "shots", marketCategory: "shots" },
486
486
  {
487
487
  key: "other",
488
- marketGroup: ["other", "team_props", "player_props", "specials", "completion"]
488
+ // `player_props` is deliberately NOT fetched here: goals/assists/shots/corners
489
+ // props already have dedicated tabs (resolveMarketSectionTabKey routes them
490
+ // there by category), so including the group would re-fetch hundreds of props
491
+ // already shown elsewhere. The handful with no stat category (e.g. "saves")
492
+ // are back-filled from the game-wide set in resolveSportsSectionMarkets.
493
+ marketGroup: ["other", "team_props", "specials", "completion"]
489
494
  }
490
495
  ];
491
496
  var SPORTS_NON_STANDARD_VISIBLE_TAB_KEYS = ["game_lines", "other"];
@@ -654,6 +659,13 @@ var resolveSportsSectionMarkets = ({
654
659
  const filteredSectionMarkets = effectiveSectionMarkets.filter(
655
660
  (market) => resolveMarketSectionTabKey(market) === tabKey
656
661
  );
662
+ if (tabKey === "other") {
663
+ const seenIds = new Set(filteredSectionMarkets.map((market) => market.id));
664
+ const strayOtherMarkets = eventMarkets.filter(
665
+ (market) => !seenIds.has(market.id) && resolveMarketSectionTabKey(market) === "other"
666
+ );
667
+ return [...filteredSectionMarkets, ...strayOtherMarkets];
668
+ }
657
669
  if (tabKey !== "game_lines") return filteredSectionMarkets;
658
670
  const eventMoneylineMarkets = (() => {
659
671
  const dedupedMarkets = [];
@@ -709,6 +721,48 @@ var resolveSportsLineFamilyKey = (market) => {
709
721
  const aggKey = resolveSportsMarketAggKey(market);
710
722
  return aggKey ? aggKey.replace(AGGKEY_LINE_TOKEN_PATTERN, "") : "";
711
723
  };
724
+ var resolveSpreadFamilyKey = (market) => {
725
+ const aggKey = resolveSportsMarketAggKey(market);
726
+ return aggKey ? aggKey.replace(/_sp_.+$/i, "_sp") : "";
727
+ };
728
+ var resolveSpreadFavoredToken = (market) => {
729
+ var _a, _b, _c;
730
+ const aggKey = resolveSportsMarketAggKey(market);
731
+ return (_c = (_b = (_a = aggKey.match(/_sp_([a-z0-9]+?)_\d+p\d+/i)) == null ? void 0 : _a[1]) == null ? void 0 : _b.toLowerCase()) != null ? _c : null;
732
+ };
733
+ var resolveSpreadHomeToken = (markets) => {
734
+ var _a;
735
+ const tokens = /* @__PURE__ */ new Set();
736
+ let prefix = "";
737
+ for (const market of markets) {
738
+ const token = resolveSpreadFavoredToken(market);
739
+ if (token) tokens.add(token);
740
+ if (!prefix) prefix = (_a = resolveSportsMarketAggKey(market).split("_sp_")[0]) != null ? _a : "";
741
+ }
742
+ if (tokens.size === 0 || !prefix) return null;
743
+ return Array.from(tokens).sort((left, right) => prefix.indexOf(left) - prefix.indexOf(right))[0];
744
+ };
745
+ var SPREAD_NON_TEAM_TITLE_PATTERN = /\b(?:yes|no|over|under|wins?\s+by|reg\.?\s*time|goal\s*diff|more\s+than|less\s+than|halftime|1st\s+half|2nd\s+half|goals?)\b/i;
746
+ var isSpreadTeamTitle = (title) => {
747
+ const trimmed = toTrimmedString(title);
748
+ if (!trimmed || trimmed.length > 24) return false;
749
+ const normalized = trimmed.toLowerCase();
750
+ if (normalized === "yes" || normalized === "no") return false;
751
+ return !SPREAD_NON_TEAM_TITLE_PATTERN.test(trimmed);
752
+ };
753
+ var resolveSpreadOutcomeTeamNames = (activeMarket, groupMarkets) => {
754
+ const aggKey = resolveSportsMarketAggKey(activeMarket);
755
+ const twins = aggKey ? groupMarkets.filter((market) => resolveSportsMarketAggKey(market) === aggKey) : [activeMarket];
756
+ const pickName = (index) => {
757
+ const cleanTitles = twins.map((market) => {
758
+ var _a, _b;
759
+ return toTrimmedString((_b = (_a = market.venueMarketOutcomes) == null ? void 0 : _a[index]) == null ? void 0 : _b.title);
760
+ }).filter((title) => isSpreadTeamTitle(title));
761
+ if (cleanTitles.length === 0) return null;
762
+ return cleanTitles.reduce((longest, title) => title.length > longest.length ? title : longest);
763
+ };
764
+ return { favored: pickName(0), dog: pickName(1) };
765
+ };
712
766
  var resolveDisplayGroupFamilyKey = (market) => {
713
767
  var _a, _b, _c;
714
768
  const normalizedQuestion = sanitizeFamilyValue(toTrimmedString(market.question));
@@ -723,14 +777,36 @@ var resolveDisplayGroupFamilyKey = (market) => {
723
777
  }
724
778
  const lineFamily = resolveSportsLineFamilyKey(market);
725
779
  if (sportsMarketType === "spread") {
726
- return lineFamily ? `${period}|spread|${lineFamily}` : `${period}|spread|${marketCategory}`;
780
+ const spreadFamily = resolveSpreadFamilyKey(market);
781
+ return spreadFamily ? `${period}|spread|${spreadFamily}` : `${period}|spread|${marketCategory}`;
727
782
  }
728
783
  if (market.lineValue != null || LINE_MARKET_TYPES.has(sportsMarketType)) {
729
784
  return lineFamily ? `${period}|${sportsMarketType}|${lineFamily}` : `${period}|${sportsMarketType}|${marketCategory}|${normalizedQuestion}|${outcomeKey}`;
730
785
  }
731
786
  return `${period}|${sportsMarketType}|${marketCategory}|${toTrimmedString(market.question)}|${outcomeKey}|${market.id}`;
732
787
  };
733
- var resolveDisplayGroupTitle = (market) => {
788
+ var TOTAL_STAT_UNITS = [
789
+ [/\bcorners?\b/i, "Corners"],
790
+ [/\bcards?\b|\bbookings?\b/i, "Cards"],
791
+ [/\bgoals?\b/i, "Goals"],
792
+ [/\bpoints?\b/i, "Points"],
793
+ [/\bruns?\b/i, "Runs"],
794
+ [/\brounds?\b/i, "Rounds"],
795
+ [/\bgames?\b/i, "Games"],
796
+ [/\bsets?\b/i, "Sets"],
797
+ [/\bmaps?\b/i, "Maps"]
798
+ ];
799
+ var resolveTotalStatUnit = (markets, marketCategory) => {
800
+ if (marketCategory === "corners") return "Corners";
801
+ for (const market of markets) {
802
+ const question = toTrimmedString(market.question);
803
+ for (const [pattern, unit] of TOTAL_STAT_UNITS) {
804
+ if (pattern.test(question)) return unit;
805
+ }
806
+ }
807
+ return null;
808
+ };
809
+ var resolveDisplayGroupTitle = (market, groupMarkets = [market]) => {
734
810
  const sportsMarketType = normalizeSportsMarketType(market.sportsMarketType);
735
811
  const question = toTrimmedString(market.question);
736
812
  if (isBinarySportsMoneylineMarket(market)) return "Moneyline";
@@ -739,6 +815,12 @@ var resolveDisplayGroupTitle = (market) => {
739
815
  return sportsMarketType != null ? sportsMarketType : market.id;
740
816
  }
741
817
  if (sportsMarketType === "total") {
818
+ const lineFamily = resolveSportsLineFamilyKey(market);
819
+ const marketCategory = normalizeSportsMarketCategory(market.marketCategory);
820
+ if (/_tot(_corners)?(_\dh)?$/i.test(lineFamily)) {
821
+ const unit = resolveTotalStatUnit(groupMarkets, marketCategory);
822
+ return unit ? `Total ${unit}` : "Totals";
823
+ }
742
824
  const base = stripLineValueFromQuestion(question).replace(/o\s*\/\s*u/gi, " ").replace(/\btotals?\b/gi, " ").replace(/\s+/g, " ").trim();
743
825
  return base ? `${base} Totals` : "Totals";
744
826
  }
@@ -778,7 +860,7 @@ var buildSportsMarketDisplayGroups = (markets) => {
778
860
  const sectionRank = (_a2 = firstMarket == null ? void 0 : firstMarket.sectionRank) != null ? _a2 : Number.MAX_SAFE_INTEGER;
779
861
  return {
780
862
  id,
781
- title: resolveDisplayGroupTitle(firstMarket),
863
+ title: resolveDisplayGroupTitle(firstMarket, orderedMarkets),
782
864
  questionKey: sanitizeFamilyValue(toTrimmedString(firstMarket == null ? void 0 : firstMarket.question)),
783
865
  sportsMarketType,
784
866
  marketCategory,
@@ -883,17 +965,33 @@ var resolveSlideKind = (group) => {
883
965
  if (group.sportsMarketType === "total") return "total";
884
966
  return "other";
885
967
  };
886
- var aggregateSportsLineStops = (markets) => {
968
+ var aggregateSportsLineStops = (markets, isSpread = false) => {
887
969
  var _a;
888
- const marketsByLineValue = /* @__PURE__ */ new Map();
970
+ const homeToken = isSpread ? resolveSpreadHomeToken(markets) : null;
971
+ const axisOf = (market) => {
972
+ var _a2, _b;
973
+ if (homeToken) {
974
+ const favored = resolveSpreadFavoredToken(market);
975
+ if (favored) {
976
+ const magnitude = Math.abs((_a2 = market.lineValue) != null ? _a2 : 0);
977
+ return favored === homeToken ? -magnitude : magnitude;
978
+ }
979
+ }
980
+ return (_b = market.lineValue) != null ? _b : Number.NEGATIVE_INFINITY;
981
+ };
982
+ const displayOf = (market) => {
983
+ var _a2;
984
+ return homeToken ? resolveSelectedSportsLineValue(Math.abs((_a2 = market.lineValue) != null ? _a2 : 0)) : resolveSelectedSportsLineValue(market.lineValue);
985
+ };
986
+ const marketsByAxis = /* @__PURE__ */ new Map();
889
987
  for (const market of markets) {
890
- const value = resolveSelectedSportsLineValue(market.lineValue);
891
- const lineMarkets = (_a = marketsByLineValue.get(value)) != null ? _a : [];
988
+ const axis = axisOf(market);
989
+ const lineMarkets = (_a = marketsByAxis.get(axis)) != null ? _a : [];
892
990
  lineMarkets.push(market);
893
- marketsByLineValue.set(value, lineMarkets);
991
+ marketsByAxis.set(axis, lineMarkets);
894
992
  }
895
- return Array.from(marketsByLineValue.entries()).map(([value, lineMarkets]) => {
896
- var _a2, _b;
993
+ return Array.from(marketsByAxis.entries()).map(([axis, lineMarkets]) => {
994
+ var _a2;
897
995
  const representative = (_a2 = lineMarkets[resolveHighestVolumeIndex(lineMarkets)]) != null ? _a2 : lineMarkets[0];
898
996
  const venues = /* @__PURE__ */ new Set();
899
997
  for (const lineMarket of lineMarkets) {
@@ -902,18 +1000,18 @@ var aggregateSportsLineStops = (markets) => {
902
1000
  }
903
1001
  }
904
1002
  return {
905
- value,
1003
+ value: displayOf(representative),
906
1004
  representative,
907
1005
  venues: Array.from(venues),
908
1006
  volume: resolveTotalGroupVolume(lineMarkets),
909
- lineValue: (_b = representative.lineValue) != null ? _b : Number.NEGATIVE_INFINITY
1007
+ lineValue: axis
910
1008
  };
911
1009
  }).sort(
912
1010
  (left, right) => left.lineValue !== right.lineValue ? left.lineValue - right.lineValue : left.value.localeCompare(right.value)
913
1011
  );
914
1012
  };
915
1013
  var buildSportsSlideFromGroup = (group) => {
916
- const lineStops = group.hasLineVariants ? aggregateSportsLineStops(group.markets) : [];
1014
+ const lineStops = group.hasLineVariants ? aggregateSportsLineStops(group.markets, group.sportsMarketType === "spread") : [];
917
1015
  const hasLadder = lineStops.length > 1;
918
1016
  const stops = hasLadder ? lineStops.map((lineStop) => ({
919
1017
  value: lineStop.value,
@@ -1358,6 +1456,45 @@ var SportsMarketCard = ({
1358
1456
  ];
1359
1457
  });
1360
1458
  }, [combinedMoneylineMarkets, isCombinedMoneylineGroup, midpointsResult]);
1459
+ const spreadHeaderOutcomeItems = useMemo(() => {
1460
+ var _a2;
1461
+ if (slide.kind !== "spread" || !activeMarket) return void 0;
1462
+ const outcomes = (_a2 = activeMarket.venueMarketOutcomes) != null ? _a2 : [];
1463
+ const lineValue = activeMarket.lineValue;
1464
+ if (outcomes.length < 2 || lineValue == null) return void 0;
1465
+ const { favored, dog } = resolveSpreadOutcomeTeamNames(activeMarket, group.markets);
1466
+ if (!favored && !dog) return void 0;
1467
+ const magnitude = Math.abs(lineValue);
1468
+ const formatLine = (value) => `${value > 0 ? "+" : "\u2212"}${Number.isInteger(magnitude) ? String(magnitude) : magnitude.toFixed(1)}`;
1469
+ return [
1470
+ { index: 0, name: favored, signedLine: -magnitude },
1471
+ { index: 1, name: dog, signedLine: magnitude }
1472
+ ].flatMap(({ index, name, signedLine }) => {
1473
+ var _a3;
1474
+ const outcome = outcomes[index];
1475
+ if (!outcome) return [];
1476
+ const label = name != null ? name : outcome.label.trim();
1477
+ const probability = midpointsResult == null ? void 0 : getDisplayOutcomePrice({
1478
+ outcomeId: outcome.id,
1479
+ outcomeLabel: outcome.label,
1480
+ bestMidpointsByOutcomeId: (_a3 = midpointsResult.bestMidpointsByOutcomeId) != null ? _a3 : midpointsResult.prices
1481
+ });
1482
+ return [
1483
+ {
1484
+ id: outcome.id,
1485
+ label,
1486
+ title: label,
1487
+ lineLabel: formatLine(signedLine),
1488
+ probability,
1489
+ isPriceLoading: (midpointsResult == null ? void 0 : midpointsResult.isLoading) === true && probability == null,
1490
+ tone: index === 0 ? "positive" : "negative",
1491
+ variant: "line",
1492
+ venue: activeMarket.venue
1493
+ }
1494
+ ];
1495
+ });
1496
+ }, [slide.kind, activeMarket, group.markets, midpointsResult]);
1497
+ const headerOutcomeItemsOverride = combinedMoneylineHeaderOutcomeItems != null ? combinedMoneylineHeaderOutcomeItems : spreadHeaderOutcomeItems;
1361
1498
  const headerOutcomeVariant = isCombinedMoneylineGroup ? "outcome" : resolveSportsMarketCardVariant(activeMarket);
1362
1499
  const handleLineSelect = (index) => {
1363
1500
  var _a2, _b2;
@@ -1388,7 +1525,7 @@ var SportsMarketCard = ({
1388
1525
  compactHeader: true,
1389
1526
  subtitleOverride: compactSubtitle,
1390
1527
  headerOutcomeVariant,
1391
- headerOutcomeItemsOverride: combinedMoneylineHeaderOutcomeItems,
1528
+ headerOutcomeItemsOverride,
1392
1529
  isOpened: isExpanded,
1393
1530
  suppressOutcomeFallbackSelection: activeMarket.id !== (tradingContext == null ? void 0 : tradingContext.selectedMarketId),
1394
1531
  onOpenChange: () => onToggle(group.id, activeMarket),
@@ -8,11 +8,11 @@ import {
8
8
  getTradingValueLabel,
9
9
  getTradingVenueLabel,
10
10
  resolveOrderEligibilityMessage
11
- } from "./chunk-LPIAEKSZ.mjs";
11
+ } from "./chunk-SG573ODC.mjs";
12
12
  import {
13
13
  GeoBlockBanner,
14
14
  subscribeAggDepositNotification
15
- } from "./chunk-4QGZ3FWI.mjs";
15
+ } from "./chunk-7OVSGWI7.mjs";
16
16
  import {
17
17
  AGG_TERMS_OF_SERVICE_URL,
18
18
  Button,
@@ -44,7 +44,7 @@ import {
44
44
  resolveResolvedOutcomeLabel,
45
45
  skeletonViews,
46
46
  useOptionalToast
47
- } from "./chunk-UTXQUOU3.mjs";
47
+ } from "./chunk-6Z5GQ3KL.mjs";
48
48
 
49
49
  // src/trading/types.ts
50
50
  import { Venue, enumGuard, isFiniteNonNeg, safeParse } from "@agg-build/sdk";
@@ -18,7 +18,7 @@ import {
18
18
  selectPrimaryVenueMarket,
19
19
  skeletonViews,
20
20
  sortOutcomes
21
- } from "./chunk-UTXQUOU3.mjs";
21
+ } from "./chunk-6Z5GQ3KL.mjs";
22
22
 
23
23
  // src/trading/trading-context/index.tsx
24
24
  import { useEventTradingContext } from "@agg-build/hooks";