@agg-build/ui 1.2.10 → 1.2.12

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.
Files changed (140) hide show
  1. package/dist/{chunk-K23CJ5UP.mjs → chunk-3JXBOU24.mjs} +580 -307
  2. package/dist/{chunk-5MTIBPDY.mjs → chunk-4WBQTUPW.mjs} +1091 -441
  3. package/dist/{chunk-5PSAIGOT.mjs → chunk-IBOE7DRY.mjs} +137 -61
  4. package/dist/{chunk-XKADJNAJ.mjs → chunk-J6WELNCX.mjs} +601 -326
  5. package/dist/{chunk-7JKGAWU5.mjs → chunk-U55T5BPE.mjs} +1802 -1564
  6. package/dist/{chunk-QFW5NDJ6.mjs → chunk-X3KCFWXN.mjs} +1312 -1040
  7. package/dist/{chunk-5MDFM2MX.mjs → chunk-YSW4ULL5.mjs} +1 -1
  8. package/dist/events.js +2892 -1746
  9. package/dist/events.mjs +3 -3
  10. package/dist/index.js +7085 -4956
  11. package/dist/index.mjs +520 -139
  12. package/dist/modals.js +3434 -2315
  13. package/dist/modals.mjs +3 -3
  14. package/dist/pages.js +4175 -2764
  15. package/dist/pages.mjs +6 -6
  16. package/dist/primitives.js +1295 -942
  17. package/dist/primitives.mjs +5 -1
  18. package/dist/styles.css +1 -1
  19. package/dist/tailwind.css +1 -1
  20. package/dist/trading.js +1677 -1249
  21. package/dist/trading.mjs +4 -4
  22. package/dist/types/agg-provider.d.mts +27 -0
  23. package/dist/types/agg-provider.d.ts +27 -0
  24. package/dist/types/deposit/deposit-modal.types.d.mts +10 -1
  25. package/dist/types/deposit/deposit-modal.types.d.ts +10 -1
  26. package/dist/types/deposit/index.d.mts +1 -1
  27. package/dist/types/deposit/index.d.ts +1 -1
  28. package/dist/types/deposit/steps/crypto-transfer.d.mts +1 -2
  29. package/dist/types/deposit/steps/crypto-transfer.d.ts +1 -2
  30. package/dist/types/deposit/steps/deposit-method.d.mts +2 -1
  31. package/dist/types/deposit/steps/deposit-method.d.ts +2 -1
  32. package/dist/types/events/item/event-list-item.types.d.mts +3 -1
  33. package/dist/types/events/item/event-list-item.types.d.ts +3 -1
  34. package/dist/types/events/item/event-list-item.utils.d.mts +26 -2
  35. package/dist/types/events/item/event-list-item.utils.d.ts +26 -2
  36. package/dist/types/events/item-details/event-list-item-details.types.d.mts +30 -1
  37. package/dist/types/events/item-details/event-list-item-details.types.d.ts +30 -1
  38. package/dist/types/events/list/event-list-tabs.d.mts +6 -1
  39. package/dist/types/events/list/event-list-tabs.d.ts +6 -1
  40. package/dist/types/events/market-details/index.d.mts +1 -1
  41. package/dist/types/events/market-details/index.d.ts +1 -1
  42. package/dist/types/events/market-details/market-details.types.d.mts +27 -2
  43. package/dist/types/events/market-details/market-details.types.d.ts +27 -2
  44. package/dist/types/events/market-details/market-details.utils.d.mts +18 -4
  45. package/dist/types/events/market-details/market-details.utils.d.ts +18 -4
  46. package/dist/types/events/market-details/orderbook-aggregation.d.mts +30 -10
  47. package/dist/types/events/market-details/orderbook-aggregation.d.ts +30 -10
  48. package/dist/types/events/shared/chart-auto-fallback.d.mts +43 -0
  49. package/dist/types/events/shared/chart-auto-fallback.d.ts +43 -0
  50. package/dist/types/events/shared/display-outcome-price.d.mts +14 -0
  51. package/dist/types/events/shared/display-outcome-price.d.ts +14 -0
  52. package/dist/types/events/shared/display-outcome-venue.d.mts +30 -0
  53. package/dist/types/events/shared/display-outcome-venue.d.ts +30 -0
  54. package/dist/types/events/shared/display-reference-price.d.mts +4 -0
  55. package/dist/types/events/shared/display-reference-price.d.ts +4 -0
  56. package/dist/types/events/shared/select-outcome-price.d.mts +21 -0
  57. package/dist/types/events/shared/select-outcome-price.d.ts +21 -0
  58. package/dist/types/index.d.mts +2 -0
  59. package/dist/types/index.d.ts +2 -0
  60. package/dist/types/notifications/agg-notification-events-provider.d.mts +35 -0
  61. package/dist/types/notifications/agg-notification-events-provider.d.ts +35 -0
  62. package/dist/types/notifications/agg-toast-provider.d.mts +27 -0
  63. package/dist/types/notifications/agg-toast-provider.d.ts +27 -0
  64. package/dist/types/notifications/deposit-notification-events.d.mts +10 -0
  65. package/dist/types/notifications/deposit-notification-events.d.ts +10 -0
  66. package/dist/types/notifications/index.d.mts +2 -0
  67. package/dist/types/notifications/index.d.ts +2 -0
  68. package/dist/types/pages/user-profile/components/available-balance-card.d.mts +2 -1
  69. package/dist/types/pages/user-profile/components/available-balance-card.d.ts +2 -1
  70. package/dist/types/pages/user-profile/components/positions-value-card.d.mts +2 -1
  71. package/dist/types/pages/user-profile/components/positions-value-card.d.ts +2 -1
  72. package/dist/types/pages/user-profile/index.d.mts +2 -2
  73. package/dist/types/pages/user-profile/index.d.ts +2 -2
  74. package/dist/types/pages/user-profile/user-profile.types.d.mts +54 -1
  75. package/dist/types/pages/user-profile/user-profile.types.d.ts +54 -1
  76. package/dist/types/primitives/button/button.types.d.mts +4 -0
  77. package/dist/types/primitives/button/button.types.d.ts +4 -0
  78. package/dist/types/primitives/button/index.d.mts +1 -1
  79. package/dist/types/primitives/button/index.d.ts +1 -1
  80. package/dist/types/primitives/chart/chart.utils.d.mts +9 -10
  81. package/dist/types/primitives/chart/chart.utils.d.ts +9 -10
  82. package/dist/types/primitives/icon/index.d.mts +2 -1
  83. package/dist/types/primitives/icon/index.d.ts +2 -1
  84. package/dist/types/primitives/icon/registry.d.mts +24 -0
  85. package/dist/types/primitives/icon/registry.d.ts +24 -0
  86. package/dist/types/primitives/icon/svg/circle-xmark.d.mts +5 -0
  87. package/dist/types/primitives/icon/svg/circle-xmark.d.ts +5 -0
  88. package/dist/types/primitives/icon/svg/sort-end-date.d.mts +5 -0
  89. package/dist/types/primitives/icon/svg/sort-end-date.d.ts +5 -0
  90. package/dist/types/primitives/icon/svg/sort-top-arbitrage.d.mts +5 -0
  91. package/dist/types/primitives/icon/svg/sort-top-arbitrage.d.ts +5 -0
  92. package/dist/types/primitives/icon/svg/sort-volume-24hr.d.mts +5 -0
  93. package/dist/types/primitives/icon/svg/sort-volume-24hr.d.ts +5 -0
  94. package/dist/types/primitives/icon/svg/sort-volume.d.mts +5 -0
  95. package/dist/types/primitives/icon/svg/sort-volume.d.ts +5 -0
  96. package/dist/types/primitives/icon/svg/spinner.d.mts +5 -0
  97. package/dist/types/primitives/icon/svg/spinner.d.ts +5 -0
  98. package/dist/types/primitives/select/index.d.mts +1 -1
  99. package/dist/types/primitives/select/index.d.ts +1 -1
  100. package/dist/types/primitives/select/select.types.d.mts +9 -0
  101. package/dist/types/primitives/select/select.types.d.ts +9 -0
  102. package/dist/types/primitives/toast/index.d.mts +2 -0
  103. package/dist/types/primitives/toast/index.d.ts +2 -0
  104. package/dist/types/primitives/toast/toast.types.d.mts +3 -0
  105. package/dist/types/primitives/toast/toast.types.d.ts +3 -0
  106. package/dist/types/primitives/tooltip/tooltip.types.d.mts +1 -0
  107. package/dist/types/primitives/tooltip/tooltip.types.d.ts +1 -0
  108. package/dist/types/primitives/typography/index.d.mts +1 -1
  109. package/dist/types/primitives/typography/index.d.ts +1 -1
  110. package/dist/types/primitives/typography/typography.types.d.mts +2 -0
  111. package/dist/types/primitives/typography/typography.types.d.ts +2 -0
  112. package/dist/types/profile/index.d.mts +1 -1
  113. package/dist/types/profile/index.d.ts +1 -1
  114. package/dist/types/profile/profile-modal.constants.d.mts +2 -2
  115. package/dist/types/profile/profile-modal.constants.d.ts +2 -2
  116. package/dist/types/profile/tabs/accounts-wallets-tab.d.mts +2 -17
  117. package/dist/types/profile/tabs/accounts-wallets-tab.d.ts +2 -17
  118. package/dist/types/profile/tabs/trading-access-tab.d.mts +15 -0
  119. package/dist/types/profile/tabs/trading-access-tab.d.ts +15 -0
  120. package/dist/types/shared/transfer-fee-summary.d.mts +10 -0
  121. package/dist/types/shared/transfer-fee-summary.d.ts +10 -0
  122. package/dist/types/shared/utils.d.mts +3 -0
  123. package/dist/types/shared/utils.d.ts +3 -0
  124. package/dist/types/trading/place-order/index.d.mts +1 -1
  125. package/dist/types/trading/place-order/index.d.ts +1 -1
  126. package/dist/types/trading/place-order/index.place-order.execution-steps.d.mts +9 -0
  127. package/dist/types/trading/place-order/index.place-order.execution-steps.d.ts +9 -0
  128. package/dist/types/trading/place-order/index.place-order.types.d.mts +15 -2
  129. package/dist/types/trading/place-order/index.place-order.types.d.ts +15 -2
  130. package/dist/types/trading/place-order/index.place-order.utils.d.mts +49 -6
  131. package/dist/types/trading/place-order/index.place-order.utils.d.ts +49 -6
  132. package/dist/types/withdraw/index.d.mts +1 -1
  133. package/dist/types/withdraw/index.d.ts +1 -1
  134. package/dist/types/withdraw/steps/withdraw-success.d.mts +13 -7
  135. package/dist/types/withdraw/steps/withdraw-success.d.ts +13 -7
  136. package/dist/types/withdraw/steps/withdraw-success.utils.d.mts +2 -0
  137. package/dist/types/withdraw/steps/withdraw-success.utils.d.ts +2 -0
  138. package/dist/types/withdraw/withdraw-modal.types.d.mts +5 -0
  139. package/dist/types/withdraw/withdraw-modal.types.d.ts +5 -0
  140. package/package.json +3 -3
@@ -4,8 +4,8 @@ import {
4
4
  buildMarketDetailsModel,
5
5
  formatProbabilityCents,
6
6
  formatProbabilityPercent,
7
+ getDisplayOutcomePrice,
7
8
  getFirstSettlementParagraph,
8
- getTimeWindowByRange,
9
9
  resolveHeaderOutcomeItems,
10
10
  resolveInitialOutcomeLabel,
11
11
  resolveInitialTab,
@@ -15,25 +15,28 @@ import {
15
15
  resolveMarketFromVenueMarkets,
16
16
  resolveOtherTabRows,
17
17
  resolveOutcomesByVenue,
18
+ resolveScopedSelectedOutcome,
18
19
  resolveSeriesColor,
19
20
  resolveTradingStateBadgeClassName,
20
21
  resolveTradingStatePresentation,
21
22
  resolveUnifiedOrderBookEntries,
23
+ selectOutcomePrice,
22
24
  sortOutcomeSelectorOutcomes,
23
25
  useEventTradingContext
24
- } from "./chunk-5PSAIGOT.mjs";
26
+ } from "./chunk-IBOE7DRY.mjs";
25
27
  import {
26
28
  AutocompleteSelect,
27
29
  Badge,
28
30
  Button,
29
31
  Card,
30
- DEFAULT_EVENTS_LIMIT,
31
32
  Icon,
32
33
  LineChart,
33
34
  MOBILE_TABS_MEDIA_QUERY,
34
35
  MarketDetailsOderbookSkeleton,
36
+ Modal,
35
37
  RemoteImage,
36
38
  SearchEmptyIcon,
39
+ Select,
37
40
  Skeleton,
38
41
  StateMessage,
39
42
  SwitchButton,
@@ -46,7 +49,6 @@ import {
46
49
  __spreadProps,
47
50
  __spreadValues,
48
51
  baseCardClassName,
49
- buildSpreadByVenueMarketId,
50
52
  cn,
51
53
  dedupeVenueMarketsById,
52
54
  detailsBaseCardClassName,
@@ -54,17 +56,14 @@ import {
54
56
  formatCountLabel,
55
57
  formatMarketProbabilityPercent,
56
58
  formatPriceGapPercent,
57
- getDefaultEventListTabs,
58
59
  getMarketDetailsTabs,
59
60
  getMotionClassName,
60
- isYesLabel,
61
61
  mapEventToEventListItemEvent,
62
62
  marketDetailsBaseCardClassName,
63
63
  marketDetailsDefaultIsOpened,
64
64
  normalizeProbability,
65
65
  normalizeVenueMarketCluster,
66
66
  orderBookRowLimitDefault,
67
- resolveBestMidpointForMarket,
68
67
  resolveDisplayVolume,
69
68
  resolveEventListItemEvent,
70
69
  resolveOutcomeTitle,
@@ -73,14 +72,16 @@ import {
73
72
  sortMarketsByYesOddsDesc,
74
73
  sortOutcomes,
75
74
  splitEventsByLifecycle
76
- } from "./chunk-QFW5NDJ6.mjs";
75
+ } from "./chunk-X3KCFWXN.mjs";
77
76
 
78
77
  // src/events/item/index.tsx
79
78
  import {
80
79
  computePriceGaps,
81
80
  optimizedImageUrl,
82
81
  sortVenues,
82
+ useEventTradingContext as useEventTradingContext2,
83
83
  useLabels,
84
+ useMidpoints,
84
85
  useSdkUiConfig,
85
86
  useVenueEvent,
86
87
  useVenueMarketMidpoints,
@@ -98,6 +99,32 @@ var isErrorWithStatus = (error, status) => {
98
99
  return getErrorStatus(error) === status;
99
100
  };
100
101
 
102
+ // src/events/shared/display-outcome-venue.ts
103
+ var normalizeOutcomeLabel = (label) => {
104
+ return typeof label === "string" ? label.trim().toLowerCase() : "";
105
+ };
106
+ var getDisplayOutcomeVenue = ({
107
+ outcomeId,
108
+ outcomeLabel,
109
+ selection,
110
+ bestMidpointVenue,
111
+ bestVenueByOutcomeId,
112
+ bestPriceVenuesByOutcomeId,
113
+ fallbackVenue
114
+ }) => {
115
+ var _a;
116
+ if (selection && outcomeId) {
117
+ const sideVenues = bestPriceVenuesByOutcomeId == null ? void 0 : bestPriceVenuesByOutcomeId.get(outcomeId);
118
+ if (selection === "buy" && (sideVenues == null ? void 0 : sideVenues.bestAskVenue)) return sideVenues.bestAskVenue;
119
+ if (selection === "sell" && (sideVenues == null ? void 0 : sideVenues.bestBidVenue)) return sideVenues.bestBidVenue;
120
+ }
121
+ if (normalizeOutcomeLabel(outcomeLabel) === "yes" && bestMidpointVenue) {
122
+ return bestMidpointVenue;
123
+ }
124
+ const bestVenue = outcomeId ? bestVenueByOutcomeId == null ? void 0 : bestVenueByOutcomeId.get(outcomeId) : void 0;
125
+ return (_a = bestVenue != null ? bestVenue : fallbackVenue) != null ? _a : void 0;
126
+ };
127
+
101
128
  // src/events/item/index.tsx
102
129
  import { jsx, jsxs } from "react/jsx-runtime";
103
130
  var EventListItemLoadingState = ({
@@ -159,7 +186,6 @@ var EventListItemNotFoundState = ({
159
186
  );
160
187
  };
161
188
  var OUTCOMES_SCROLL_LOAD_THRESHOLD_PX = 16;
162
- var isNoLabel = (label) => label.trim().toLowerCase() === "no";
163
189
  var MARKET_ID_QUERY_PARAM = "marketId";
164
190
  var OUTCOME_ID_QUERY_PARAM = "outcomeId";
165
191
  var resolveMarketHrefFromEventHref = (eventHref, marketId, outcomeId) => {
@@ -182,18 +208,20 @@ var EventListItemContent = ({
182
208
  onMarketClick,
183
209
  getMarketHref,
184
210
  href,
185
- ariaLabel
211
+ ariaLabel,
212
+ marketStatus
186
213
  }) => {
214
+ var _a;
187
215
  const config = useSdkUiConfig();
188
216
  const labels = useLabels();
189
- const allVenueMarkets = useMemo(() => {
190
- return dedupeVenueMarketsById(event.venueMarkets);
191
- }, [event.venueMarkets]);
217
+ const tradingContext = useEventTradingContext2();
218
+ const tradeSide = (_a = tradingContext == null ? void 0 : tradingContext.tradeSide) != null ? _a : "buy";
219
+ const allVenueMarkets = useMemo(() => event.venueMarkets, [event.venueMarkets]);
192
220
  const resolvedTitle = event.title;
193
221
  const resolvedImage = event.image;
194
222
  const visibleVenueLogos = useMemo(() => {
195
- var _a;
196
- return sortVenues(Array.from(new Set(((_a = event.venues) != null ? _a : []).map((venue) => venue))));
223
+ var _a2;
224
+ return sortVenues(Array.from(new Set(((_a2 = event.venues) != null ? _a2 : []).map((venue) => venue))));
197
225
  }, [event.venues]);
198
226
  const resolvedMarketCount = typeof event.marketCount === "number" && Number.isFinite(event.marketCount) ? Math.max(0, Math.floor(event.marketCount)) : allVenueMarkets.length;
199
227
  const resolvedVenueCount = typeof event.venueCount === "number" && Number.isFinite(event.venueCount) ? Math.max(0, Math.floor(event.venueCount)) : visibleVenueLogos.length;
@@ -216,18 +244,19 @@ var EventListItemContent = ({
216
244
  venueEventId: event.id,
217
245
  enabled: shouldEnableLazyMarketLoading && isLazyMarketsQueryEnabled,
218
246
  sortBy: "yesPrice",
219
- sortDir: "desc"
247
+ sortDir: "desc",
248
+ status: marketStatus
220
249
  });
221
250
  const resolvedOutcomeMarkets = useMemo(() => {
222
251
  if (!isLazyMarketsQueryEnabled || lazyLoadedMarkets.length === 0) return allVenueMarkets;
223
252
  return dedupeVenueMarketsById([...allVenueMarkets, ...lazyLoadedMarkets]);
224
253
  }, [allVenueMarkets, isLazyMarketsQueryEnabled, lazyLoadedMarkets]);
225
254
  const midpointVenueMarketIds = useMemo(() => {
226
- var _a;
255
+ var _a2;
227
256
  const ids = [];
228
257
  for (const market of resolvedOutcomeMarkets) {
229
258
  ids.push(market.id);
230
- for (const sibling of (_a = market.matchedVenueMarkets) != null ? _a : []) {
259
+ for (const sibling of (_a2 = market.matchedVenueMarkets) != null ? _a2 : []) {
231
260
  ids.push(sibling.id);
232
261
  }
233
262
  }
@@ -235,17 +264,19 @@ var EventListItemContent = ({
235
264
  }, [resolvedOutcomeMarkets]);
236
265
  const {
237
266
  midpointsByVenueMarketId,
238
- midpointRows,
239
267
  isLoading: isLoadingMidpoints,
240
268
  isFetching: isFetchingMidpoints
241
269
  } = useVenueMarketMidpoints({
242
270
  venueMarketIds: midpointVenueMarketIds,
243
271
  enabled: midpointVenueMarketIds.length > 0
244
272
  });
245
- const spreadByVenueMarketId = useMemo(
246
- () => buildSpreadByVenueMarketId(midpointRows),
247
- [midpointRows]
248
- );
273
+ const {
274
+ prices: displayMidpointsByOutcomeId,
275
+ venueByOutcomeId: displayMidpointVenueByOutcomeId,
276
+ bestPrices: displayBestPricesByOutcomeId,
277
+ bestPriceVenuesByOutcomeId: displayBestPriceVenuesByOutcomeId,
278
+ isLoading: isDisplayMidpointsLoading
279
+ } = useMidpoints(resolvedOutcomeMarkets);
249
280
  const gapsByVenueMarketId = useMemo(
250
281
  () => computePriceGaps({
251
282
  markets: resolvedOutcomeMarkets,
@@ -253,7 +284,7 @@ var EventListItemContent = ({
253
284
  }),
254
285
  [resolvedOutcomeMarkets, midpointsByVenueMarketId]
255
286
  );
256
- const isMidpointQueryInFlight = isLoadingMidpoints || isFetchingMidpoints;
287
+ const isMidpointQueryInFlight = isLoadingMidpoints || isFetchingMidpoints || isDisplayMidpointsLoading;
257
288
  const shouldRenderLoadingOutcomeRow = shouldEnableLazyMarketLoading && (!isLazyMarketsQueryEnabled || isLoadingLazyMarkets || isFetchingNextLazyMarketsPage || hasNextLazyMarketsPage);
258
289
  const resolvedVolume = resolveDisplayVolume(event.volume, allVenueMarkets);
259
290
  const volumeLabel = typeof resolvedVolume === "number" ? `${config.formatting.formatCompactCurrency(resolvedVolume)} ${labels.eventItem.volumeSuffix}` : "";
@@ -366,7 +397,7 @@ var EventListItemContent = ({
366
397
  );
367
398
  };
368
399
  const renderOutcomePriceBadge = (probability, venue, shouldRenderLoadingSkeleton, market, outcome) => {
369
- var _a;
400
+ var _a2;
370
401
  if (shouldRenderLoadingSkeleton) {
371
402
  return /* @__PURE__ */ jsx(
372
403
  "div",
@@ -379,7 +410,7 @@ var EventListItemContent = ({
379
410
  );
380
411
  }
381
412
  if (typeof probability !== "number") return null;
382
- const marketHref = (_a = getMarketHref == null ? void 0 : getMarketHref(event, market, outcome)) != null ? _a : resolveMarketHrefFromEventHref(href, market.id, outcome.id);
413
+ const marketHref = (_a2 = getMarketHref == null ? void 0 : getMarketHref(event, market, outcome)) != null ? _a2 : resolveMarketHrefFromEventHref(href, market.id, outcome.id);
383
414
  const isInteractive = Boolean(onMarketClick || marketHref);
384
415
  return /* @__PURE__ */ jsx(
385
416
  Badge,
@@ -460,39 +491,26 @@ var EventListItemContent = ({
460
491
  ),
461
492
  onScroll: handleOutcomesScroll,
462
493
  children: [
463
- resolvedOutcomeMarkets.length === 1 ? (() => {
464
- var _a;
494
+ resolvedMarketCount === 1 && resolvedOutcomeMarkets.length === 1 ? (() => {
465
495
  const market = resolvedOutcomeMarkets[0];
466
- const bestMidpoint = resolveBestMidpointForMarket(
467
- market,
468
- midpointsByVenueMarketId,
469
- spreadByVenueMarketId
470
- );
471
- const marketMidpoint = bestMidpoint != null ? normalizeProbability(bestMidpoint.midpoint) : void 0;
472
- const bestVenue = (_a = bestMidpoint == null ? void 0 : bestMidpoint.venue) != null ? _a : market.venue;
473
- const hasYesOutcome = market.venueMarketOutcomes.some(
474
- (item) => isYesLabel(item.label)
475
- );
476
- const hasNoOutcome = market.venueMarketOutcomes.some((item) => isNoLabel(item.label));
477
- const shouldUseMidpoint = hasYesOutcome && hasNoOutcome;
478
496
  return sortOutcomes(market.venueMarketOutcomes).map((outcome) => {
479
- const probability = (() => {
480
- if (!shouldUseMidpoint) {
481
- return normalizeProbability(outcome.price);
482
- }
483
- if (marketMidpoint == null) {
484
- if (isMidpointQueryInFlight) return void 0;
485
- return normalizeProbability(outcome.price);
486
- }
487
- if (isYesLabel(outcome.label)) {
488
- return marketMidpoint;
489
- }
490
- if (isNoLabel(outcome.label)) {
491
- return normalizeProbability(1 - marketMidpoint);
492
- }
493
- return normalizeProbability(outcome.price);
494
- })();
495
- const shouldRenderMidpointSkeleton = shouldUseMidpoint && marketMidpoint == null && isMidpointQueryInFlight;
497
+ var _a2;
498
+ const resolvedDisplayPrice = selectOutcomePrice({
499
+ outcomeId: outcome.id,
500
+ selection: tradeSide,
501
+ bestPrices: displayBestPricesByOutcomeId,
502
+ bestMidpointsByOutcomeId: displayMidpointsByOutcomeId
503
+ });
504
+ const midpointProbability = resolvedDisplayPrice;
505
+ const probability = midpointProbability != null ? normalizeProbability(midpointProbability) : isMidpointQueryInFlight ? void 0 : normalizeProbability(outcome.price);
506
+ const displayVenue = (_a2 = getDisplayOutcomeVenue({
507
+ outcomeId: outcome.id,
508
+ selection: tradeSide,
509
+ bestVenueByOutcomeId: displayMidpointVenueByOutcomeId,
510
+ bestPriceVenuesByOutcomeId: displayBestPriceVenuesByOutcomeId,
511
+ fallbackVenue: market.venue
512
+ })) != null ? _a2 : market.venue;
513
+ const shouldRenderMidpointSkeleton = midpointProbability == null && isMidpointQueryInFlight;
496
514
  const arbitragePercent = arbitrageByOutcomeId == null ? void 0 : arbitrageByOutcomeId[outcome.id];
497
515
  const _priceGapPct = gapsByVenueMarketId.get(market.id);
498
516
  return /* @__PURE__ */ jsxs(
@@ -516,7 +534,7 @@ var EventListItemContent = ({
516
534
  renderArbitrage(arbitragePercent),
517
535
  renderOutcomePriceBadge(
518
536
  probability,
519
- bestVenue,
537
+ displayVenue,
520
538
  shouldRenderMidpointSkeleton,
521
539
  market,
522
540
  outcome
@@ -528,21 +546,27 @@ var EventListItemContent = ({
528
546
  );
529
547
  });
530
548
  })() : sortMarketsByYesOddsDesc(resolvedOutcomeMarkets).map((market) => {
531
- var _a, _b, _c;
549
+ var _a2, _b, _c;
532
550
  const yesOutcome = resolveYesOutcome(market);
533
551
  const displayOutcome = yesOutcome != null ? yesOutcome : (_b = market.venueMarketOutcomes) == null ? void 0 : _b.reduce(
534
552
  (acc, o) => o.price > acc.price ? o : acc,
535
- (_a = market.venueMarketOutcomes) == null ? void 0 : _a[0]
536
- );
537
- const bestMidpoint = resolveBestMidpointForMarket(
538
- market,
539
- midpointsByVenueMarketId,
540
- spreadByVenueMarketId
553
+ (_a2 = market.venueMarketOutcomes) == null ? void 0 : _a2[0]
541
554
  );
542
- const marketMidpoint = bestMidpoint != null ? normalizeProbability(bestMidpoint.midpoint) : void 0;
543
- const bestVenue = (_c = bestMidpoint == null ? void 0 : bestMidpoint.venue) != null ? _c : market.venue;
544
- const probability = marketMidpoint != null ? marketMidpoint : isMidpointQueryInFlight ? void 0 : normalizeProbability(displayOutcome == null ? void 0 : displayOutcome.price);
545
- const shouldRenderMidpointSkeleton = marketMidpoint == null && isMidpointQueryInFlight;
555
+ const midpointProbability = displayOutcome != null ? selectOutcomePrice({
556
+ outcomeId: displayOutcome.id,
557
+ selection: tradeSide,
558
+ bestPrices: displayBestPricesByOutcomeId,
559
+ bestMidpointsByOutcomeId: displayMidpointsByOutcomeId
560
+ }) : void 0;
561
+ const bestVenue = (_c = displayOutcome != null ? getDisplayOutcomeVenue({
562
+ outcomeId: displayOutcome.id,
563
+ selection: tradeSide,
564
+ bestVenueByOutcomeId: displayMidpointVenueByOutcomeId,
565
+ bestPriceVenuesByOutcomeId: displayBestPriceVenuesByOutcomeId,
566
+ fallbackVenue: market.venue
567
+ }) : void 0) != null ? _c : market.venue;
568
+ const probability = midpointProbability != null ? normalizeProbability(midpointProbability) : isMidpointQueryInFlight ? void 0 : normalizeProbability(displayOutcome == null ? void 0 : displayOutcome.price);
569
+ const shouldRenderMidpointSkeleton = midpointProbability == null && isMidpointQueryInFlight;
546
570
  const arbitragePercent = arbitrageByOutcomeId == null ? void 0 : arbitrageByOutcomeId[market.id];
547
571
  const outcomeTitle = market.question;
548
572
  const _priceGapPct = gapsByVenueMarketId.get(market.id);
@@ -720,12 +744,12 @@ var fromScaled = (value, precision) => {
720
744
  var toPriceKey = (price) => {
721
745
  return String(toScaled(price, PRICE_PRECISION));
722
746
  };
723
- var normalizeOutcomeLabel = (value) => {
747
+ var normalizeOutcomeLabel2 = (value) => {
724
748
  if (typeof value !== "string") return "";
725
749
  return value.trim().toLowerCase().replace(/[_-]+/g, " ").replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ");
726
750
  };
727
751
  var toSemanticOutcomeLabel = (value) => {
728
- const normalizedValue = normalizeOutcomeLabel(value);
752
+ const normalizedValue = normalizeOutcomeLabel2(value);
729
753
  if (!normalizedValue) return "";
730
754
  if (POSITIVE_OUTCOME_KEYS.has(normalizedValue)) return "yes";
731
755
  if (NEGATIVE_OUTCOME_KEYS.has(normalizedValue)) return "no";
@@ -739,10 +763,10 @@ var getOutcomeLabelCandidates = (outcome) => {
739
763
  );
740
764
  };
741
765
  var matchesSelectedOutcomeLabel = (outcome, selectedOutcomeLabel) => {
742
- const normalizedSelectedLabel = normalizeOutcomeLabel(selectedOutcomeLabel);
766
+ const normalizedSelectedLabel = normalizeOutcomeLabel2(selectedOutcomeLabel);
743
767
  const semanticSelectedLabel = toSemanticOutcomeLabel(selectedOutcomeLabel);
744
768
  return getOutcomeLabelCandidates(outcome).some((candidate) => {
745
- const normalizedCandidate = normalizeOutcomeLabel(candidate);
769
+ const normalizedCandidate = normalizeOutcomeLabel2(candidate);
746
770
  if (!normalizedCandidate) return false;
747
771
  return normalizedCandidate === normalizedSelectedLabel || toSemanticOutcomeLabel(candidate) === semanticSelectedLabel;
748
772
  });
@@ -882,21 +906,78 @@ var accumulateSideLevels = ({
882
906
  };
883
907
  var collectEligibleVenueOutcomes = ({
884
908
  venueMarkets,
885
- selectedOutcomeLabel
909
+ selectedOutcomeLabel,
910
+ selectedOutcomeId
886
911
  }) => {
887
- var _a;
912
+ var _a, _b, _c;
888
913
  if (!selectedOutcomeLabel) return [];
889
914
  const semanticLabel = toSemanticOutcomeLabel(selectedOutcomeLabel);
890
915
  const seenMarketIds = /* @__PURE__ */ new Set();
891
916
  const seenOutcomeIds = /* @__PURE__ */ new Set();
892
917
  const result = [];
918
+ if (selectedOutcomeId) {
919
+ for (const market of venueMarkets) {
920
+ const outcome = market.venueMarketOutcomes.find((o) => o.id === selectedOutcomeId);
921
+ if (!outcome) continue;
922
+ const refs = (_a = outcome.matchedVenueMarketOutcomes) != null ? _a : [];
923
+ if (refs.length > 0) {
924
+ seenMarketIds.add(market.id);
925
+ seenOutcomeIds.add(outcome.id);
926
+ result.push({
927
+ venue: market.venue,
928
+ market,
929
+ outcome,
930
+ outcomeId: outcome.id,
931
+ semanticLabel
932
+ });
933
+ for (const ref of refs) {
934
+ if (seenMarketIds.has(ref.venueMarketId)) continue;
935
+ const sibling = venueMarkets.find((m) => m.id === ref.venueMarketId);
936
+ if (!sibling) continue;
937
+ const siblingOutcome = sibling.venueMarketOutcomes.find(
938
+ (o) => o.id === ref.venueMarketOutcomeId
939
+ );
940
+ if (!siblingOutcome || seenOutcomeIds.has(siblingOutcome.id)) continue;
941
+ seenMarketIds.add(sibling.id);
942
+ seenOutcomeIds.add(siblingOutcome.id);
943
+ result.push({
944
+ venue: sibling.venue,
945
+ market: sibling,
946
+ outcome: siblingOutcome,
947
+ outcomeId: siblingOutcome.id,
948
+ semanticLabel
949
+ });
950
+ }
951
+ return result;
952
+ }
953
+ const hasOtherMarketWithRefs = venueMarkets.some((m) => {
954
+ var _a2, _b2;
955
+ if (m.id === market.id) return false;
956
+ const o = sortOutcomes(m.venueMarketOutcomes).find(
957
+ (o2) => matchesSelectedOutcomeLabel(o2, selectedOutcomeLabel)
958
+ );
959
+ return ((_b2 = (_a2 = o == null ? void 0 : o.matchedVenueMarketOutcomes) == null ? void 0 : _a2.length) != null ? _b2 : 0) > 0;
960
+ });
961
+ if (hasOtherMarketWithRefs) {
962
+ result.push({
963
+ venue: market.venue,
964
+ market,
965
+ outcome,
966
+ outcomeId: outcome.id,
967
+ semanticLabel
968
+ });
969
+ return result;
970
+ }
971
+ break;
972
+ }
973
+ }
893
974
  for (const market of venueMarkets) {
894
975
  if (seenMarketIds.has(market.id)) continue;
895
976
  const parentOutcome = sortOutcomes(market.venueMarketOutcomes).find(
896
977
  (outcome) => matchesSelectedOutcomeLabel(outcome, selectedOutcomeLabel)
897
978
  );
898
979
  if (!parentOutcome) continue;
899
- const refs = (_a = parentOutcome.matchedVenueMarketOutcomes) != null ? _a : [];
980
+ const refs = (_b = parentOutcome.matchedVenueMarketOutcomes) != null ? _b : [];
900
981
  if (refs.length === 0) continue;
901
982
  seenMarketIds.add(market.id);
902
983
  seenOutcomeIds.add(parentOutcome.id);
@@ -933,6 +1014,13 @@ var collectEligibleVenueOutcomes = ({
933
1014
  (outcome) => matchesSelectedOutcomeLabel(outcome, selectedOutcomeLabel)
934
1015
  );
935
1016
  if (!matchedOutcome || seenOutcomeIds.has(matchedOutcome.id)) continue;
1017
+ const candidateRefs = (_c = matchedOutcome.matchedVenueMarketOutcomes) != null ? _c : [];
1018
+ if (candidateRefs.length > 0) {
1019
+ const sharesAnchor = candidateRefs.some(
1020
+ (ref) => seenOutcomeIds.has(ref.venueMarketOutcomeId)
1021
+ );
1022
+ if (!sharesAnchor) continue;
1023
+ }
936
1024
  seenMarketIds.add(market.id);
937
1025
  seenOutcomeIds.add(matchedOutcome.id);
938
1026
  result.push({
@@ -947,11 +1035,14 @@ var collectEligibleVenueOutcomes = ({
947
1035
  };
948
1036
  var collectEligibleVenueOutcomeIds = ({
949
1037
  venueMarkets,
950
- selectedOutcomeLabel
1038
+ selectedOutcomeLabel,
1039
+ selectedOutcomeId
951
1040
  }) => {
952
- return collectEligibleVenueOutcomes({ venueMarkets, selectedOutcomeLabel }).map(
953
- (eligibleOutcome) => eligibleOutcome.outcomeId
954
- );
1041
+ return collectEligibleVenueOutcomes({
1042
+ venueMarkets,
1043
+ selectedOutcomeLabel,
1044
+ selectedOutcomeId
1045
+ }).map((eligibleOutcome) => eligibleOutcome.outcomeId);
955
1046
  };
956
1047
  var mergeVenueOutcomeOrderbooks = ({
957
1048
  eligibleOutcomes,
@@ -1058,14 +1149,15 @@ SettlementSummary.displayName = "SettlementSummary";
1058
1149
  // src/events/item-details/index.tsx
1059
1150
  import {
1060
1151
  CHART_TIME_RANGES,
1152
+ mergeBestPricesPreferringLive,
1061
1153
  optimizedImageUrl as optimizedImageUrl2,
1062
1154
  resolveEventTradingState,
1063
- timeRangeToInterval,
1064
1155
  useEventOrderbookData,
1065
1156
  useLabels as useLabels5,
1157
+ useLiveBestPrices,
1066
1158
  useLiveOutcomePrices,
1067
1159
  useMarketChart,
1068
- useMidpoints,
1160
+ useRollingChartWindow,
1069
1161
  useSdkUiConfig as useSdkUiConfig2,
1070
1162
  useVenueEvent as useVenueEvent2
1071
1163
  } from "@agg-build/hooks";
@@ -1179,6 +1271,35 @@ var ChartTypeSwitch = ({
1179
1271
  };
1180
1272
  ChartTypeSwitch.displayName = "ChartTypeSwitch";
1181
1273
 
1274
+ // src/events/shared/chart-auto-fallback.ts
1275
+ var isMarketChartEmpty = (data, options = {}) => {
1276
+ if (!data) return true;
1277
+ const minTime = options.minTimeSec;
1278
+ return !Object.values(data.venues).some((venue) => {
1279
+ const hasInWindowCandle = minTime != null ? venue.candles.some((candle) => candle.time >= minTime) : venue.candles.length > 0;
1280
+ if (hasInWindowCandle) return true;
1281
+ const live = venue.liveCandle;
1282
+ if (live == null) return false;
1283
+ if (minTime != null && live.time < minTime) return false;
1284
+ return true;
1285
+ });
1286
+ };
1287
+ var shouldAutoFallbackToAllRange = ({
1288
+ chartData,
1289
+ isLoading,
1290
+ error,
1291
+ currentRange,
1292
+ hasAlreadyFallenBack,
1293
+ domainStartTs
1294
+ }) => {
1295
+ if (hasAlreadyFallenBack) return false;
1296
+ if (currentRange === "ALL") return false;
1297
+ if (error != null) return false;
1298
+ if (isLoading) return false;
1299
+ if (!chartData) return false;
1300
+ return isMarketChartEmpty(chartData, { minTimeSec: domainStartTs });
1301
+ };
1302
+
1182
1303
  // src/events/shared/chart-venue-selection.ts
1183
1304
  import { sortVenues as sortVenues2 } from "@agg-build/hooks";
1184
1305
  var resolveChartVenueOutcomes = ({
@@ -1835,12 +1956,17 @@ var EventListItemDetailsGraphSection = ({
1835
1956
  classNames,
1836
1957
  selectedChartType,
1837
1958
  venueMarkets,
1959
+ selectedMarketId,
1838
1960
  livePrices,
1839
1961
  wsLivePrices,
1840
1962
  restMidpoints,
1841
- live
1963
+ bestMidpoint,
1964
+ bestPrices,
1965
+ live,
1966
+ rangeOverride,
1967
+ onRangeOverrideChange
1842
1968
  }) => {
1843
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1969
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
1844
1970
  const labels = useLabels5();
1845
1971
  const tradingContext = useEventTradingContext();
1846
1972
  const [selectedGraphVenue, setSelectedGraphVenue] = useState3(null);
@@ -1861,24 +1987,33 @@ var EventListItemDetailsGraphSection = ({
1861
1987
  general: { theme }
1862
1988
  } = useSdkUiConfig2();
1863
1989
  const isDarkTheme = theme === "dark";
1864
- const timeWindow = useMemo5(() => {
1865
- return getTimeWindowByRange(selectedChartTimeRange);
1866
- }, [selectedChartTimeRange]);
1990
+ const effectiveChartTimeRange = rangeOverride != null ? rangeOverride : selectedChartTimeRange;
1991
+ const rollingWindow = useRollingChartWindow({ range: effectiveChartTimeRange });
1867
1992
  const availableMarkets = useMemo5(() => {
1993
+ var _a2, _b2, _c2, _d2;
1868
1994
  if (venueMarkets.length === 0) return [];
1869
- return normalizeVenueMarketCluster(venueMarkets, tradingContext == null ? void 0 : tradingContext.selectedMarketId);
1870
- }, [tradingContext == null ? void 0 : tradingContext.selectedMarketId, venueMarkets]);
1871
- const resolvedChartOutcomeLabel = (_g = chartOutcomeLabel != null ? chartOutcomeLabel : (_f = (_e = tradingContext == null ? void 0 : tradingContext.selectedOutcome) == null ? void 0 : _e.label) == null ? void 0 : _f.trim()) != null ? _g : null;
1995
+ const resolvedSelectedMarketId = (_d2 = (_c2 = (_a2 = tradingContext == null ? void 0 : tradingContext.selectedMarketId) != null ? _a2 : selectedMarketId) != null ? _c2 : (_b2 = venueMarkets[0]) == null ? void 0 : _b2.id) != null ? _d2 : null;
1996
+ return normalizeVenueMarketCluster(venueMarkets, resolvedSelectedMarketId);
1997
+ }, [selectedMarketId, tradingContext == null ? void 0 : tradingContext.selectedMarketId, venueMarkets]);
1998
+ const fallbackOutcomeLabel = useMemo5(() => {
1999
+ var _a2, _b2, _c2, _d2, _e2;
2000
+ const fallbackMarket = (_b2 = (_a2 = tradingContext == null ? void 0 : tradingContext.selectedMarket) != null ? _a2 : availableMarkets[0]) != null ? _b2 : null;
2001
+ if (!fallbackMarket) return null;
2002
+ return (_e2 = (_d2 = (_c2 = sortOutcomeSelectorOutcomes(fallbackMarket.venueMarketOutcomes)[0]) == null ? void 0 : _c2.label) == null ? void 0 : _d2.trim()) != null ? _e2 : null;
2003
+ }, [availableMarkets, tradingContext == null ? void 0 : tradingContext.selectedMarket]);
2004
+ const resolvedChartOutcomeLabel = (_h = (_g = chartOutcomeLabel != null ? chartOutcomeLabel : (_f = (_e = tradingContext == null ? void 0 : tradingContext.selectedOutcome) == null ? void 0 : _e.label) == null ? void 0 : _f.trim()) != null ? _g : fallbackOutcomeLabel) != null ? _h : null;
2005
+ const chartScopedOutcomeId = ((_i = tradingContext == null ? void 0 : tradingContext.selectedOutcome) == null ? void 0 : _i.id) && ((_j = tradingContext.selectedOutcome.label) == null ? void 0 : _j.trim()) === resolvedChartOutcomeLabel ? tradingContext.selectedOutcome.id : null;
1872
2006
  const availableVenueOutcomes = useMemo5(() => {
1873
2007
  return resolveChartVenueOutcomes({
1874
2008
  eligibleVenueOutcomes: collectEligibleVenueOutcomes({
1875
2009
  venueMarkets: availableMarkets,
1876
- selectedOutcomeLabel: resolvedChartOutcomeLabel
2010
+ selectedOutcomeLabel: resolvedChartOutcomeLabel,
2011
+ selectedOutcomeId: chartScopedOutcomeId
1877
2012
  }),
1878
2013
  livePrices
1879
2014
  });
1880
- }, [availableMarkets, livePrices, resolvedChartOutcomeLabel]);
1881
- const chartPrimaryOutcomeId = (_i = (_h = availableVenueOutcomes[0]) == null ? void 0 : _h.outcome.id) != null ? _i : null;
2015
+ }, [availableMarkets, livePrices, resolvedChartOutcomeLabel, chartScopedOutcomeId]);
2016
+ const chartPrimaryOutcomeId = (_l = (_k = availableVenueOutcomes[0]) == null ? void 0 : _k.outcome.id) != null ? _l : null;
1882
2017
  const {
1883
2018
  data: scopedMarketChartData,
1884
2019
  isLoading: isScopedMarketChartLoading,
@@ -1887,17 +2022,56 @@ var EventListItemDetailsGraphSection = ({
1887
2022
  } = useMarketChart({
1888
2023
  marketId: chartPrimaryOutcomeId,
1889
2024
  venueMarketIds: availableVenueOutcomes.map((item) => item.outcome.id),
1890
- interval: timeRangeToInterval(selectedChartTimeRange),
1891
- startTs: timeWindow.startTs * 1e3,
1892
- endTs: timeWindow.endTs * 1e3,
2025
+ interval: rollingWindow.interval,
2026
+ startTs: rollingWindow.startTs * 1e3,
2027
+ endTs: rollingWindow.endTs * 1e3,
1893
2028
  enabled: availableVenueOutcomes.length > 0,
1894
- live
2029
+ live,
2030
+ refetchIntervalMs: rollingWindow.refetchIntervalMs,
2031
+ // Stable cache key per user-selected range so revisits hit cache instead
2032
+ // of refetching every time the bucket boundary advances.
2033
+ rangeKey: rollingWindow.range
1895
2034
  });
2035
+ const hasAutoFallenBackRangeRef = useRef2(false);
2036
+ useEffect2(() => {
2037
+ hasAutoFallenBackRangeRef.current = false;
2038
+ }, [chartPrimaryOutcomeId]);
2039
+ useEffect2(() => {
2040
+ if (!shouldAutoFallbackToAllRange({
2041
+ chartData: scopedMarketChartData,
2042
+ isLoading: isScopedMarketChartLoading,
2043
+ error: scopedMarketChartError,
2044
+ currentRange: effectiveChartTimeRange,
2045
+ hasAlreadyFallenBack: hasAutoFallenBackRangeRef.current,
2046
+ // Ignore stale "courtesy" bars the API returns outside the
2047
+ // rolling window (e.g. a market that last traded 11h ago — its
2048
+ // last bar is in `candles` but our visible 1H window can't show
2049
+ // it, so for fallback purposes it doesn't count as data).
2050
+ domainStartTs: rollingWindow.startTs
2051
+ })) {
2052
+ return;
2053
+ }
2054
+ hasAutoFallenBackRangeRef.current = true;
2055
+ onRangeOverrideChange("ALL");
2056
+ }, [
2057
+ scopedMarketChartData,
2058
+ isScopedMarketChartLoading,
2059
+ scopedMarketChartError,
2060
+ effectiveChartTimeRange,
2061
+ onRangeOverrideChange,
2062
+ rollingWindow.startTs
2063
+ ]);
1896
2064
  const selectedMarketOutcomes = useMemo5(() => {
1897
2065
  var _a2, _b2;
1898
2066
  const selectedMarket = (_b2 = (_a2 = tradingContext == null ? void 0 : tradingContext.selectedMarket) != null ? _a2 : availableMarkets[0]) != null ? _b2 : null;
1899
2067
  if (!selectedMarket) return [];
1900
- return sortOutcomeSelectorOutcomes(selectedMarket.venueMarketOutcomes);
2068
+ return sortOutcomeSelectorOutcomes(selectedMarket.venueMarketOutcomes).map((outcome) => {
2069
+ var _a3;
2070
+ return __spreadProps(__spreadValues({}, outcome), {
2071
+ label: outcome.label,
2072
+ title: (_a3 = outcome.title) != null ? _a3 : null
2073
+ });
2074
+ });
1901
2075
  }, [availableMarkets, tradingContext == null ? void 0 : tradingContext.selectedMarket]);
1902
2076
  const resolvedVenueChartSeries = useMemo5(() => {
1903
2077
  return resolveMarketChartVenueSeries({
@@ -1924,11 +2098,12 @@ var EventListItemDetailsGraphSection = ({
1924
2098
  }, [availableVenueOutcomes, chartAvailableVenueOutcomes, tradingContext == null ? void 0 : tradingContext.selectedVenue]);
1925
2099
  const activeGraphVenue = selectedChartType === "candlestick" ? selectedGraphVenue != null ? selectedGraphVenue : defaultCandlestickVenue : selectedGraphVenue;
1926
2100
  const visibleChartSeries = useMemo5(() => {
1927
- if (!activeGraphVenue) {
1928
- return resolvedVenueChartSeries;
1929
- }
1930
- return resolvedVenueChartSeries.filter((seriesItem) => seriesItem.venue === activeGraphVenue);
1931
- }, [activeGraphVenue, resolvedVenueChartSeries]);
2101
+ const venueFiltered = activeGraphVenue ? resolvedVenueChartSeries.filter((seriesItem) => seriesItem.venue === activeGraphVenue) : resolvedVenueChartSeries;
2102
+ const domainStartTs = rollingWindow.startTs;
2103
+ return venueFiltered.map((seriesItem) => __spreadProps(__spreadValues({}, seriesItem), {
2104
+ points: seriesItem.points.filter((point) => point.time >= domainStartTs)
2105
+ }));
2106
+ }, [activeGraphVenue, resolvedVenueChartSeries, rollingWindow.startTs]);
1932
2107
  const chartLiveState = useMemo5(() => {
1933
2108
  return resolveMarketChartLiveState({
1934
2109
  chartData: scopedMarketChartData,
@@ -1968,7 +2143,7 @@ var EventListItemDetailsGraphSection = ({
1968
2143
  height: 300,
1969
2144
  isLoading: isScopedMarketChartLoading,
1970
2145
  chartType: selectedChartType,
1971
- liveCandle: selectedChartType === "candlestick" ? (_j = chartLiveState.liveCandle) != null ? _j : void 0 : void 0,
2146
+ liveCandle: selectedChartType === "candlestick" ? (_m = chartLiveState.liveCandle) != null ? _m : void 0 : void 0,
1972
2147
  lineValue: chartLiveState.lineValue,
1973
2148
  showSeriesControls: selectedMarketOutcomes.length > 0,
1974
2149
  renderSeriesControls: ({ handleSeriesChange }) => {
@@ -2057,12 +2232,21 @@ var EventListItemDetailsGraphSection = ({
2057
2232
  tradingContext == null ? void 0 : tradingContext.selectOutcome(outcomeId);
2058
2233
  },
2059
2234
  options: selectedMarketOutcomes.map((outcome) => {
2060
- var _a3, _b3;
2061
- const price = (_b3 = (_a3 = restMidpoints.get(outcome.id)) != null ? _a3 : livePrices.get(outcome.id)) != null ? _b3 : outcome.price;
2235
+ var _a3, _b3, _c3;
2236
+ const price = getDisplayOutcomePrice({
2237
+ outcomeId: outcome.id,
2238
+ outcomeLabel: outcome.label,
2239
+ selection: (_a3 = tradingContext == null ? void 0 : tradingContext.tradeSide) != null ? _a3 : "buy",
2240
+ bestPrices,
2241
+ bestMidpoint,
2242
+ bestMidpointsByOutcomeId: restMidpoints,
2243
+ livePrices,
2244
+ fallbackPrice: outcome.price
2245
+ });
2062
2246
  return {
2063
2247
  value: outcome.id,
2064
- label: `${outcome.label} ${formatProbabilityCents(price)}`,
2065
- ariaLabel: `${outcome.label} ${formatProbabilityCents(price)}`
2248
+ label: `${(_b3 = outcome.title) != null ? _b3 : outcome.label} ${formatProbabilityCents(price)}`,
2249
+ ariaLabel: `${(_c3 = outcome.title) != null ? _c3 : outcome.label} ${formatProbabilityCents(price)}`
2066
2250
  };
2067
2251
  })
2068
2252
  }
@@ -2083,12 +2267,17 @@ var EventListItemDetailsContent = ({
2083
2267
  detailsStats,
2084
2268
  eventTradingState,
2085
2269
  ariaLabel,
2086
- onClick
2270
+ onClick,
2271
+ midpointsResult
2087
2272
  }) => {
2088
- var _a, _b;
2273
+ var _a, _b, _c, _d;
2089
2274
  const [selectedChartType, setSelectedChartType] = useState3("line");
2090
2275
  const lastAppliedEventSyncKeyRef = useRef2(null);
2091
2276
  const lastAppliedDefaultRef = useRef2(null);
2277
+ const [chartRangeOverride, setChartRangeOverride] = useState3(null);
2278
+ useEffect2(() => {
2279
+ setChartRangeOverride(null);
2280
+ }, [event.id]);
2092
2281
  const config = useSdkUiConfig2();
2093
2282
  const labels = useLabels5();
2094
2283
  const tradingContext = useEventTradingContext();
@@ -2103,18 +2292,24 @@ var EventListItemDetailsContent = ({
2103
2292
  scopedSelectedMarketId
2104
2293
  );
2105
2294
  const wsLivePrices = useLiveOutcomePrices(resolvedEventTradingState.displayMarkets);
2106
- const midpointsClusterMarkets = useMemo5(() => {
2107
- if (resolvedEventTradingState.isTradingDisabled) return [];
2108
- return normalizeVenueMarketCluster(
2109
- resolvedEventTradingState.displayMarkets,
2110
- scopedSelectedMarketId
2111
- );
2112
- }, [
2113
- resolvedEventTradingState.displayMarkets,
2114
- resolvedEventTradingState.isTradingDisabled,
2115
- scopedSelectedMarketId
2116
- ]);
2117
- const { prices: restMidpoints } = useMidpoints(midpointsClusterMarkets);
2295
+ const wsBestPrices = useLiveBestPrices(resolvedEventTradingState.displayMarkets);
2296
+ const resolvedMidpointsResult = midpointsResult != null ? midpointsResult : {
2297
+ prices: /* @__PURE__ */ new Map(),
2298
+ bestMidpointsByOutcomeId: /* @__PURE__ */ new Map(),
2299
+ venueByOutcomeId: /* @__PURE__ */ new Map(),
2300
+ bestPrices: /* @__PURE__ */ new Map(),
2301
+ bestPriceVenuesByOutcomeId: /* @__PURE__ */ new Map(),
2302
+ isLoading: false,
2303
+ bestMidpoint: void 0,
2304
+ bestMidpointVenue: void 0
2305
+ };
2306
+ const restMidpoints = (_b = resolvedMidpointsResult.bestMidpointsByOutcomeId) != null ? _b : resolvedMidpointsResult.prices;
2307
+ const bestMidpoint = resolvedMidpointsResult.bestMidpoint;
2308
+ const restBestPrices = resolvedMidpointsResult.bestPrices;
2309
+ const bestPrices = useMemo5(
2310
+ () => mergeBestPricesPreferringLive(restBestPrices, wsBestPrices),
2311
+ [restBestPrices, wsBestPrices]
2312
+ );
2118
2313
  const livePrices = useMemo5(() => {
2119
2314
  if (!restMidpoints.size) return wsLivePrices;
2120
2315
  if (!wsLivePrices.size) return restMidpoints;
@@ -2223,7 +2418,7 @@ var EventListItemDetailsContent = ({
2223
2418
  {
2224
2419
  className: classNames == null ? void 0 : classNames.headerPills,
2225
2420
  options: marketOptions,
2226
- selectedValue: (_b = scopedSelectedMarket == null ? void 0 : scopedSelectedMarket.id) != null ? _b : "",
2421
+ selectedValue: (_c = scopedSelectedMarket == null ? void 0 : scopedSelectedMarket.id) != null ? _c : "",
2227
2422
  onChange: (marketId) => {
2228
2423
  tradingContext == null ? void 0 : tradingContext.selectMarket(marketId);
2229
2424
  }
@@ -2274,10 +2469,15 @@ var EventListItemDetailsContent = ({
2274
2469
  selectedChartType,
2275
2470
  venueInfo,
2276
2471
  venueMarkets,
2472
+ selectedMarketId: (_d = scopedSelectedMarket == null ? void 0 : scopedSelectedMarket.id) != null ? _d : null,
2277
2473
  livePrices,
2278
2474
  wsLivePrices,
2279
2475
  restMidpoints,
2280
- live: false
2476
+ bestMidpoint,
2477
+ bestPrices,
2478
+ live: false,
2479
+ rangeOverride: chartRangeOverride,
2480
+ onRangeOverrideChange: setChartRangeOverride
2281
2481
  }
2282
2482
  ),
2283
2483
  /* @__PURE__ */ jsxs4(
@@ -2307,7 +2507,8 @@ var EventListItemDetailsContent = ({
2307
2507
  ),
2308
2508
  /* @__PURE__ */ jsx5("span", { "aria-hidden": "true", className: "hidden h-4 w-px bg-agg-separator md:block" }),
2309
2509
  CHART_TIME_RANGES.map((timeRange) => {
2310
- const isActive = timeRange === config.chart.selectedChartTimeRange;
2510
+ const effectiveRange = chartRangeOverride != null ? chartRangeOverride : config.chart.selectedChartTimeRange;
2511
+ const isActive = timeRange === effectiveRange;
2311
2512
  return /* @__PURE__ */ jsx5(
2312
2513
  Button,
2313
2514
  {
@@ -2324,6 +2525,7 @@ var EventListItemDetailsContent = ({
2324
2525
  onClick: (e) => {
2325
2526
  e.stopPropagation();
2326
2527
  e.preventDefault();
2528
+ setChartRangeOverride(null);
2327
2529
  config.chart.setSelectedChartTimeRange(timeRange);
2328
2530
  },
2329
2531
  children: timeRange === "ALL" ? labels.eventItemDetails.allTimeRange : timeRange
@@ -2459,30 +2661,23 @@ var useCenterOrderbookSpread = ({
2459
2661
  rowCount,
2460
2662
  enabled = true
2461
2663
  }) => {
2462
- const hasAutoCenteredRef = useRef3(false);
2463
2664
  const hasUserScrolledRef = useRef3(false);
2464
2665
  const animationFrameRef = useRef3(null);
2465
2666
  const retryCountRef = useRef3(0);
2466
2667
  const resetKey = marketId != null ? marketId : "";
2668
+ const cancelPendingFrame = useCallback2(() => {
2669
+ if (animationFrameRef.current === null) return;
2670
+ window.cancelAnimationFrame(animationFrameRef.current);
2671
+ animationFrameRef.current = null;
2672
+ }, []);
2467
2673
  useLayoutEffect2(() => {
2468
- const cancelPendingFrame = () => {
2469
- if (animationFrameRef.current === null) return;
2470
- window.cancelAnimationFrame(animationFrameRef.current);
2471
- animationFrameRef.current = null;
2472
- };
2473
- hasAutoCenteredRef.current = false;
2474
2674
  hasUserScrolledRef.current = false;
2475
2675
  retryCountRef.current = 0;
2476
2676
  cancelPendingFrame();
2477
- }, [resetKey]);
2677
+ }, [cancelPendingFrame, resetKey]);
2478
2678
  useLayoutEffect2(() => {
2479
2679
  const container = containerRef.current;
2480
2680
  if (!container) return;
2481
- const cancelPendingFrame = () => {
2482
- if (animationFrameRef.current === null) return;
2483
- window.cancelAnimationFrame(animationFrameRef.current);
2484
- animationFrameRef.current = null;
2485
- };
2486
2681
  const handleUserScrollIntent = () => {
2487
2682
  hasUserScrolledRef.current = true;
2488
2683
  cancelPendingFrame();
@@ -2502,93 +2697,81 @@ var useCenterOrderbookSpread = ({
2502
2697
  container.removeEventListener("keydown", handleKeyDown);
2503
2698
  cancelPendingFrame();
2504
2699
  };
2505
- }, [containerRef]);
2700
+ }, [cancelPendingFrame, containerRef]);
2506
2701
  useLayoutEffect2(() => {
2507
2702
  if (!enabled) return;
2508
- if (hasAutoCenteredRef.current || hasUserScrolledRef.current) return;
2509
2703
  let isCancelled = false;
2510
- let resizeObserver = null;
2511
- const cancelPendingFrame = () => {
2512
- if (animationFrameRef.current === null) return;
2513
- window.cancelAnimationFrame(animationFrameRef.current);
2514
- animationFrameRef.current = null;
2515
- };
2516
- const disconnectResizeObserver = () => {
2517
- resizeObserver == null ? void 0 : resizeObserver.disconnect();
2518
- resizeObserver = null;
2519
- };
2520
- const scheduleMeasurement = () => {
2521
- cancelPendingFrame();
2522
- animationFrameRef.current = window.requestAnimationFrame(measureAndCenter);
2523
- };
2524
- const setupResizeObserverFallback = () => {
2525
- if (resizeObserver) return;
2526
- const container = containerRef.current;
2527
- if (!container) return;
2528
- resizeObserver = new ResizeObserver(() => {
2529
- if (isCancelled || hasAutoCenteredRef.current || hasUserScrolledRef.current) {
2530
- disconnectResizeObserver();
2531
- return;
2532
- }
2533
- if (container.clientHeight <= 0) return;
2534
- disconnectResizeObserver();
2535
- retryCountRef.current = 0;
2536
- scheduleMeasurement();
2537
- });
2538
- resizeObserver.observe(container);
2539
- };
2540
- const scheduleRetry = () => {
2541
- if (isCancelled || hasUserScrolledRef.current || hasAutoCenteredRef.current) return;
2542
- if (retryCountRef.current >= maxAutoCenterAttempts) {
2543
- setupResizeObserverFallback();
2544
- return;
2545
- }
2546
- retryCountRef.current += 1;
2547
- scheduleMeasurement();
2548
- };
2549
2704
  const measureAndCenter = () => {
2550
- if (isCancelled) return;
2551
- const container = containerRef.current;
2705
+ animationFrameRef.current = null;
2706
+ if (isCancelled || hasUserScrolledRef.current) return;
2707
+ const container2 = containerRef.current;
2552
2708
  const spread = spreadRef.current;
2553
- if (!container || !spread) {
2709
+ if (!container2 || !spread) {
2554
2710
  scheduleRetry();
2555
2711
  return;
2556
2712
  }
2557
- const containerHeight = container.clientHeight;
2713
+ const containerHeight = container2.clientHeight;
2558
2714
  if (containerHeight <= 0) {
2559
2715
  scheduleRetry();
2560
2716
  return;
2561
2717
  }
2562
- const containerRect = container.getBoundingClientRect();
2718
+ const containerRect = container2.getBoundingClientRect();
2563
2719
  const spreadRect = spread.getBoundingClientRect();
2564
2720
  if (containerRect.height <= 0 || spreadRect.height <= 0) {
2565
2721
  scheduleRetry();
2566
2722
  return;
2567
2723
  }
2568
- const spreadOffsetTop = container.scrollTop + (spreadRect.top - containerRect.top);
2569
- const maxScrollTop = Math.max(0, container.scrollHeight - containerHeight);
2724
+ const spreadOffsetTop = container2.scrollTop + (spreadRect.top - containerRect.top);
2725
+ const maxScrollTop = Math.max(0, container2.scrollHeight - containerHeight);
2570
2726
  if (maxScrollTop === 0) {
2571
2727
  retryCountRef.current = 0;
2572
- animationFrameRef.current = null;
2573
2728
  return;
2574
2729
  }
2575
2730
  const targetScrollTop = Math.max(
2576
2731
  0,
2577
2732
  Math.min(maxScrollTop, spreadOffsetTop - containerHeight / 2 + spreadRect.height / 2)
2578
2733
  );
2579
- container.scrollTo({ top: targetScrollTop, behavior: "auto" });
2580
- hasAutoCenteredRef.current = true;
2734
+ container2.scrollTop = targetScrollTop;
2581
2735
  retryCountRef.current = 0;
2582
- animationFrameRef.current = null;
2583
- disconnectResizeObserver();
2584
2736
  };
2737
+ const scheduleMeasurement = () => {
2738
+ if (isCancelled || hasUserScrolledRef.current) return;
2739
+ if (animationFrameRef.current !== null) return;
2740
+ animationFrameRef.current = window.requestAnimationFrame(measureAndCenter);
2741
+ };
2742
+ const scheduleRetry = () => {
2743
+ if (isCancelled || hasUserScrolledRef.current) return;
2744
+ if (retryCountRef.current >= maxAutoCenterAttempts) return;
2745
+ retryCountRef.current += 1;
2746
+ if (animationFrameRef.current !== null) return;
2747
+ animationFrameRef.current = window.requestAnimationFrame(measureAndCenter);
2748
+ };
2749
+ const container = containerRef.current;
2750
+ let resizeObserver = null;
2751
+ let mutationObserver = null;
2752
+ if (container) {
2753
+ resizeObserver = new ResizeObserver(() => {
2754
+ if (isCancelled || hasUserScrolledRef.current) return;
2755
+ retryCountRef.current = 0;
2756
+ scheduleMeasurement();
2757
+ });
2758
+ resizeObserver.observe(container);
2759
+ mutationObserver = new MutationObserver(() => {
2760
+ if (isCancelled || hasUserScrolledRef.current) return;
2761
+ retryCountRef.current = 0;
2762
+ scheduleMeasurement();
2763
+ });
2764
+ mutationObserver.observe(container, { childList: true, subtree: true });
2765
+ }
2766
+ retryCountRef.current = 0;
2585
2767
  scheduleMeasurement();
2586
2768
  return () => {
2587
2769
  isCancelled = true;
2588
2770
  cancelPendingFrame();
2589
- disconnectResizeObserver();
2771
+ resizeObserver == null ? void 0 : resizeObserver.disconnect();
2772
+ mutationObserver == null ? void 0 : mutationObserver.disconnect();
2590
2773
  };
2591
- }, [containerRef, enabled, resetKey, rowCount, spreadRef]);
2774
+ }, [cancelPendingFrame, containerRef, enabled, resetKey, rowCount, spreadRef]);
2592
2775
  const recenter = useCallback2(() => {
2593
2776
  const container = containerRef.current;
2594
2777
  const spread = spreadRef.current;
@@ -2924,15 +3107,16 @@ import {
2924
3107
  CHART_TIME_RANGES as CHART_TIME_RANGES2,
2925
3108
  findLivePriceById,
2926
3109
  MarketStatus,
3110
+ mergeBestPricesPreferringLive as mergeBestPricesPreferringLive2,
2927
3111
  optimizedImageUrl as optimizedImageUrl3,
2928
3112
  resolveMarketTradingState,
2929
- timeRangeToInterval as timeRangeToInterval2,
2930
- useEventTradingContext as useEventTradingContext2,
3113
+ useEventTradingContext as useEventTradingContext3,
2931
3114
  useLabels as useLabels6,
3115
+ useLiveBestPrices as useLiveBestPrices2,
2932
3116
  useLiveOutcomePrices as useLiveOutcomePrices2,
2933
3117
  useMarketChart as useMarketChart2,
2934
3118
  useMarketOrderbook,
2935
- useMidpoints as useMidpoints2,
3119
+ useRollingChartWindow as useRollingChartWindow2,
2936
3120
  useSdkUiConfig as useSdkUiConfig3,
2937
3121
  useVenueMarkets as useVenueMarkets2,
2938
3122
  useViewportMidpoints
@@ -2945,17 +3129,17 @@ var marketDetailsOutcomeButtonToneClasses = {
2945
3129
  positive: {
2946
3130
  activeSurface: "bg-agg-success/15",
2947
3131
  border: "border-agg-success/50",
2948
- defaultSurface: "bg-agg-success/5",
2949
- hoverSurface: "hover:bg-agg-success/10",
2950
- pressedSurface: "active:bg-agg-success/15",
3132
+ defaultSurface: "bg-agg-secondary-hover",
3133
+ hoverSurface: "hover:bg-agg-tertiary",
3134
+ pressedSurface: "active:bg-agg-success/10",
2951
3135
  text: "text-agg-success!"
2952
3136
  },
2953
3137
  negative: {
2954
3138
  activeSurface: "bg-agg-error/15",
2955
3139
  border: "border-agg-error/50",
2956
- defaultSurface: "bg-agg-error/5",
2957
- hoverSurface: "hover:bg-agg-error/10",
2958
- pressedSurface: "active:bg-agg-error/15",
3140
+ defaultSurface: "bg-agg-secondary-hover",
3141
+ hoverSurface: "hover:bg-agg-tertiary",
3142
+ pressedSurface: "active:bg-agg-error/10",
2959
3143
  text: "text-agg-error!"
2960
3144
  }
2961
3145
  };
@@ -2988,6 +3172,7 @@ var MarketDetailsOutcomeButton = ({
2988
3172
  item,
2989
3173
  onSelect
2990
3174
  }) => {
3175
+ var _a;
2991
3176
  const classNames = getMarketDetailsOutcomeButtonClassNames({
2992
3177
  enableAnimations,
2993
3178
  isSelected,
@@ -3014,7 +3199,7 @@ var MarketDetailsOutcomeButton = ({
3014
3199
  as: "span",
3015
3200
  variant: isSelected ? "body-strong" : "body",
3016
3201
  className: cn("whitespace-nowrap truncate", classNames.text),
3017
- children: item.title
3202
+ children: (_a = item.title) != null ? _a : item.label
3018
3203
  }
3019
3204
  ),
3020
3205
  /* @__PURE__ */ jsx8(
@@ -3035,21 +3220,6 @@ MarketDetailsOutcomeButton.displayName = "MarketDetailsOutcomeButton";
3035
3220
 
3036
3221
  // src/events/market-details/index.tsx
3037
3222
  import { Fragment, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
3038
- var MarketDetailsLoadingState = ({
3039
- isOpened = marketDetailsDefaultIsOpened,
3040
- ariaLabel,
3041
- classNames
3042
- }) => {
3043
- const labels = useLabels6();
3044
- return /* @__PURE__ */ jsx9(
3045
- Skeleton,
3046
- {
3047
- view: isOpened ? "market-details-detailed" : "market-details-minified",
3048
- className: classNames == null ? void 0 : classNames.root,
3049
- ariaLabel: ariaLabel != null ? ariaLabel : labels.marketDetails.loading
3050
- }
3051
- );
3052
- };
3053
3223
  var MarketDetailsUnavailableState = ({
3054
3224
  ariaLabel,
3055
3225
  classNames
@@ -3103,9 +3273,11 @@ var MarketDetailsContent = ({
3103
3273
  onOutcomeSelect,
3104
3274
  live,
3105
3275
  midpointsFallback,
3106
- midpointsFallbackVenues
3276
+ midpointsFallbackVenues,
3277
+ suppressOutcomeFallbackSelection,
3278
+ midpointsResult
3107
3279
  }) => {
3108
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
3280
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
3109
3281
  const config = useSdkUiConfig3();
3110
3282
  const {
3111
3283
  features: { enableAnimations },
@@ -3114,9 +3286,61 @@ var MarketDetailsContent = ({
3114
3286
  } = config;
3115
3287
  const isDarkTheme = theme === "dark";
3116
3288
  const labels = useLabels6();
3117
- const tradingContext = useEventTradingContext2();
3289
+ const tradingContext = useEventTradingContext3();
3118
3290
  const detailsContentId = useId();
3291
+ const tradeSide = (_a = tradingContext == null ? void 0 : tradingContext.tradeSide) != null ? _a : "buy";
3119
3292
  const wsLivePrices = useLiveOutcomePrices2(venueMarkets);
3293
+ const wsBestPrices = useLiveBestPrices2(venueMarkets);
3294
+ const resolvedMarket = useMemo6(() => {
3295
+ return resolveMarketFromVenueMarkets(venueMarkets, marketId);
3296
+ }, [venueMarkets, marketId]);
3297
+ const scopedResolvedMarket = useMemo6(() => {
3298
+ var _a2, _b2;
3299
+ if (!resolvedMarket) return null;
3300
+ return (_b2 = (_a2 = resolvedMarket.venueMarkets.find((venueMarket) => venueMarket.id === resolvedMarket.id)) != null ? _a2 : resolvedMarket.venueMarkets[0]) != null ? _b2 : null;
3301
+ }, [resolvedMarket]);
3302
+ const isResolvedMarket = resolveMarketTradingState(scopedResolvedMarket).kind === "resolved";
3303
+ const clusterMidpointResult = midpointsResult != null ? midpointsResult : {
3304
+ prices: /* @__PURE__ */ new Map(),
3305
+ bestMidpointsByOutcomeId: /* @__PURE__ */ new Map(),
3306
+ venueByOutcomeId: /* @__PURE__ */ new Map(),
3307
+ bestPrices: /* @__PURE__ */ new Map(),
3308
+ bestPriceVenuesByOutcomeId: /* @__PURE__ */ new Map(),
3309
+ isLoading: false,
3310
+ bestMidpoint: void 0,
3311
+ bestMidpointVenue: void 0
3312
+ };
3313
+ const clusterMidpoints = (_b = clusterMidpointResult.bestMidpointsByOutcomeId) != null ? _b : clusterMidpointResult.prices;
3314
+ const clusterBestMidpointsByOutcomeId = clusterMidpoints;
3315
+ const clusterVenueByOutcomeId = clusterMidpointResult.venueByOutcomeId;
3316
+ const clusterBestMidpoint = clusterMidpointResult.bestMidpoint;
3317
+ const clusterBestMidpointVenue = clusterMidpointResult.bestMidpointVenue;
3318
+ const clusterBestPricesRest = clusterMidpointResult.bestPrices;
3319
+ const clusterBestPrices = useMemo6(
3320
+ () => mergeBestPricesPreferringLive2(clusterBestPricesRest, wsBestPrices),
3321
+ [clusterBestPricesRest, wsBestPrices]
3322
+ );
3323
+ const clusterBestPriceVenuesByOutcomeId = clusterMidpointResult.bestPriceVenuesByOutcomeId;
3324
+ const clusterMidpointMarkets = useMemo6(() => {
3325
+ var _a2;
3326
+ if (!resolvedMarket) return [];
3327
+ return (_a2 = resolvedMarket.venueMarkets) != null ? _a2 : [];
3328
+ }, [resolvedMarket]);
3329
+ const tradableVenues = useMemo6(() => {
3330
+ var _a2;
3331
+ if (clusterMidpointMarkets.length === 0) return null;
3332
+ if (clusterMidpoints.size === 0) return null;
3333
+ const set = /* @__PURE__ */ new Set();
3334
+ for (const market of clusterMidpointMarkets) {
3335
+ for (const outcome of (_a2 = market.venueMarketOutcomes) != null ? _a2 : []) {
3336
+ if (clusterMidpoints.has(outcome.id)) {
3337
+ set.add(market.venue);
3338
+ break;
3339
+ }
3340
+ }
3341
+ }
3342
+ return set;
3343
+ }, [clusterMidpointMarkets, clusterMidpoints]);
3120
3344
  const model = useMemo6(() => {
3121
3345
  return buildMarketDetailsModel({
3122
3346
  venueMarkets,
@@ -3124,17 +3348,18 @@ var MarketDetailsContent = ({
3124
3348
  title,
3125
3349
  image,
3126
3350
  formatCompactCurrency: config.formatting.formatCompactCurrency,
3127
- labels
3351
+ labels,
3352
+ tradableVenues
3128
3353
  });
3129
- }, [config.formatting.formatCompactCurrency, venueMarkets, image, labels, marketId, title]);
3130
- const resolvedMarket = useMemo6(() => {
3131
- return resolveMarketFromVenueMarkets(venueMarkets, marketId);
3132
- }, [venueMarkets, marketId]);
3133
- const clusterMidpointMarkets = useMemo6(() => {
3134
- if (!controlledIsOpened || !resolvedMarket) return [];
3135
- return resolvedMarket.venueMarkets;
3136
- }, [controlledIsOpened, resolvedMarket]);
3137
- const { prices: clusterMidpoints, venueByOutcomeId: clusterVenueByOutcomeId } = useMidpoints2(clusterMidpointMarkets);
3354
+ }, [
3355
+ config.formatting.formatCompactCurrency,
3356
+ venueMarkets,
3357
+ image,
3358
+ labels,
3359
+ marketId,
3360
+ title,
3361
+ tradableVenues
3362
+ ]);
3138
3363
  const livePrices = useMemo6(() => {
3139
3364
  const merged = /* @__PURE__ */ new Map();
3140
3365
  if (midpointsFallback == null ? void 0 : midpointsFallback.size) {
@@ -3158,7 +3383,6 @@ var MarketDetailsContent = ({
3158
3383
  const marketTradingState = useMemo6(() => {
3159
3384
  return resolveMarketTradingState(scopedMarketForCard);
3160
3385
  }, [scopedMarketForCard]);
3161
- const isResolvedMarket = marketTradingState.kind === "resolved";
3162
3386
  const isOutcomeSelectionLocked = marketTradingState.isTradingDisabled;
3163
3387
  const isUpcomingMarket = marketTradingState.kind === "unopened";
3164
3388
  const marketStatePresentation = resolveTradingStatePresentation(labels, marketTradingState);
@@ -3178,11 +3402,30 @@ var MarketDetailsContent = ({
3178
3402
  const selectedTimeRange = config.chart.selectedChartTimeRange;
3179
3403
  const setSelectedTimeRange = config.chart.setSelectedChartTimeRange;
3180
3404
  const effectiveSelectedTab = isResolvedMarket ? "graph" : selectedTab;
3181
- const effectiveChartTimeRange = isResolvedMarket ? "ALL" : selectedTimeRange;
3405
+ const [chartRangeOverride, setChartRangeOverride] = useState4(null);
3406
+ const effectiveChartTimeRange = isResolvedMarket ? "ALL" : chartRangeOverride != null ? chartRangeOverride : selectedTimeRange;
3182
3407
  const [selectedChartType, setSelectedChartType] = useState4("line");
3183
- const scopedSelectedOutcome = (_a = tradingContext == null ? void 0 : tradingContext.selectedOutcome) != null ? _a : null;
3184
- const selectedOutcomeId = (_b = scopedSelectedOutcome == null ? void 0 : scopedSelectedOutcome.id) != null ? _b : null;
3185
- const selectedOutcomeLabel = (_c = scopedSelectedOutcome == null ? void 0 : scopedSelectedOutcome.label) != null ? _c : null;
3408
+ const scopedSelectedOutcomeState = useMemo6(() => {
3409
+ if (!model) {
3410
+ return {
3411
+ outcomeId: null,
3412
+ outcomeLabel: void 0
3413
+ };
3414
+ }
3415
+ return resolveScopedSelectedOutcome({
3416
+ venueMarkets: model.market.venueMarkets,
3417
+ selectedOutcomeId: tradingContext == null ? void 0 : tradingContext.selectedOutcomeId,
3418
+ defaultOutcomeLabel,
3419
+ suppressFallbackWhenSelectedOutcomeOutOfScope: suppressOutcomeFallbackSelection
3420
+ });
3421
+ }, [
3422
+ defaultOutcomeLabel,
3423
+ model,
3424
+ suppressOutcomeFallbackSelection,
3425
+ tradingContext == null ? void 0 : tradingContext.selectedOutcomeId
3426
+ ]);
3427
+ const selectedOutcomeId = scopedSelectedOutcomeState.outcomeId;
3428
+ const selectedOutcomeLabel = (_c = scopedSelectedOutcomeState.outcomeLabel) != null ? _c : null;
3186
3429
  const selectOutcome = tradingContext == null ? void 0 : tradingContext.selectOutcome;
3187
3430
  const [selectedGraphVenue, setSelectedGraphVenue] = useState4(null);
3188
3431
  const [chartOutcomeLabel, setChartOutcomeLabel] = useState4(selectedOutcomeLabel);
@@ -3196,6 +3439,9 @@ var MarketDetailsContent = ({
3196
3439
  var _a2;
3197
3440
  if (!isOpened || !model) return;
3198
3441
  if (isOutcomeSelectionLocked) return;
3442
+ if ((tradingContext == null ? void 0 : tradingContext.selectedMarketId) && tradingContext.selectedMarketId !== model.market.id) {
3443
+ return;
3444
+ }
3199
3445
  if (selectedOutcomeId) return;
3200
3446
  const initialLabel = resolveInitialOutcomeLabel(model.outcomeLabels, defaultOutcomeLabel);
3201
3447
  if (!initialLabel) return;
@@ -3210,71 +3456,130 @@ var MarketDetailsContent = ({
3210
3456
  isOutcomeSelectionLocked,
3211
3457
  model,
3212
3458
  selectedOutcomeId,
3459
+ tradingContext == null ? void 0 : tradingContext.selectedMarketId,
3213
3460
  selectOutcome
3214
3461
  ]);
3215
3462
  const headerOutcomeItems = useMemo6(() => {
3216
3463
  if (!model) return [];
3217
- const items = resolveHeaderOutcomeItems(model.market.venueMarkets);
3464
+ const items = resolveHeaderOutcomeItems(model.market.venueMarkets, scopedMarketForCard);
3218
3465
  return items.map((item) => {
3219
- const clusterPrice = clusterMidpoints.get(item.id);
3220
- if (clusterPrice != null) {
3221
- const bestVenue = clusterVenueByOutcomeId.get(item.id);
3222
- return __spreadValues(__spreadProps(__spreadValues({}, item), { probability: clusterPrice }), bestVenue ? { venue: bestVenue } : {});
3223
- }
3466
+ var _a2;
3224
3467
  const fallbackPrice = midpointsFallback == null ? void 0 : midpointsFallback.get(item.id);
3225
- if (fallbackPrice != null) {
3226
- const bestVenue = midpointsFallbackVenues == null ? void 0 : midpointsFallbackVenues.get(item.id);
3227
- return __spreadValues(__spreadProps(__spreadValues({}, item), { probability: fallbackPrice }), bestVenue ? { venue: bestVenue } : {});
3468
+ const bestVenue = getDisplayOutcomeVenue({
3469
+ outcomeId: item.id,
3470
+ outcomeLabel: item.label,
3471
+ selection: tradeSide,
3472
+ bestMidpointVenue: clusterBestMidpointVenue,
3473
+ bestVenueByOutcomeId: clusterVenueByOutcomeId,
3474
+ bestPriceVenuesByOutcomeId: clusterBestPriceVenuesByOutcomeId,
3475
+ fallbackVenue: midpointsFallbackVenues == null ? void 0 : midpointsFallbackVenues.get(item.id)
3476
+ });
3477
+ const outcomeBestPrice = getDisplayOutcomePrice({
3478
+ outcomeId: item.id,
3479
+ outcomeLabel: item.label,
3480
+ selection: tradeSide,
3481
+ bestPrices: clusterBestPrices,
3482
+ bestMidpoint: clusterBestMidpoint,
3483
+ bestMidpointsByOutcomeId: clusterBestMidpointsByOutcomeId,
3484
+ livePrices: wsLivePrices,
3485
+ fallbackPrice
3486
+ });
3487
+ if (isResolvedMarket) {
3488
+ const isWinningOutcome = item.id === ((_a2 = marketTradingState.winningOutcome) == null ? void 0 : _a2.id);
3489
+ return __spreadValues(__spreadProps(__spreadValues({}, item), {
3490
+ probability: isWinningOutcome ? 1 : 0
3491
+ }), bestVenue ? { venue: bestVenue } : {});
3228
3492
  }
3229
- const wsPrice = findLivePriceById(wsLivePrices, item.id);
3230
- return wsPrice != null ? __spreadProps(__spreadValues({}, item), { probability: wsPrice }) : item;
3493
+ if (outcomeBestPrice != null) {
3494
+ return __spreadValues(__spreadProps(__spreadValues({}, item), {
3495
+ probability: outcomeBestPrice
3496
+ }), bestVenue ? { venue: bestVenue } : {});
3497
+ }
3498
+ return item;
3231
3499
  });
3232
3500
  }, [
3501
+ clusterBestMidpoint,
3502
+ clusterBestMidpointVenue,
3503
+ clusterBestMidpointsByOutcomeId,
3504
+ clusterBestPrices,
3505
+ clusterBestPriceVenuesByOutcomeId,
3233
3506
  model,
3234
- clusterMidpoints,
3507
+ scopedMarketForCard,
3235
3508
  clusterVenueByOutcomeId,
3509
+ isResolvedMarket,
3510
+ (_d = marketTradingState.winningOutcome) == null ? void 0 : _d.id,
3236
3511
  midpointsFallback,
3237
3512
  midpointsFallbackVenues,
3513
+ tradeSide,
3238
3514
  wsLivePrices
3239
3515
  ]);
3240
3516
  const headlineProbability = useMemo6(() => {
3241
3517
  var _a2, _b2, _c2, _d2;
3242
3518
  if (!model || !scopedMarketForCard) return void 0;
3519
+ if (isResolvedMarket) {
3520
+ const yesOutcome2 = resolveYesOutcome(scopedMarketForCard);
3521
+ if (!yesOutcome2) return void 0;
3522
+ return yesOutcome2.winner === true ? 1 : 0;
3523
+ }
3243
3524
  const yesOutcome = resolveYesOutcome(scopedMarketForCard);
3244
3525
  const displayOutcome = yesOutcome != null ? yesOutcome : (_b2 = scopedMarketForCard.venueMarketOutcomes) == null ? void 0 : _b2.reduce(
3245
3526
  (acc, outcome) => outcome.price > acc.price ? outcome : acc,
3246
3527
  (_a2 = scopedMarketForCard.venueMarketOutcomes) == null ? void 0 : _a2[0]
3247
3528
  );
3248
- const restPrice = (_c2 = clusterMidpoints.get(displayOutcome.id)) != null ? _c2 : midpointsFallback == null ? void 0 : midpointsFallback.get(displayOutcome.id);
3249
- if (restPrice != null) return restPrice;
3529
+ if (displayOutcome == null) return void 0;
3530
+ const referencePrice = getDisplayOutcomePrice({
3531
+ outcomeId: displayOutcome.id,
3532
+ outcomeLabel: displayOutcome.label,
3533
+ selection: "buy",
3534
+ bestPrices: clusterBestPrices,
3535
+ bestMidpoint: clusterBestMidpoint,
3536
+ bestMidpointsByOutcomeId: clusterBestMidpointsByOutcomeId,
3537
+ livePrices: wsLivePrices,
3538
+ fallbackPrice: (_c2 = midpointsFallback == null ? void 0 : midpointsFallback.get(displayOutcome.id)) != null ? _c2 : displayOutcome.price
3539
+ });
3540
+ if (referencePrice != null) return referencePrice;
3250
3541
  return (_d2 = findLivePriceById(wsLivePrices, displayOutcome.id)) != null ? _d2 : displayOutcome.price;
3251
- }, [model, scopedMarketForCard, clusterMidpoints, midpointsFallback, wsLivePrices]);
3542
+ }, [
3543
+ clusterBestMidpoint,
3544
+ clusterBestMidpointsByOutcomeId,
3545
+ clusterBestPrices,
3546
+ model,
3547
+ scopedMarketForCard,
3548
+ isResolvedMarket,
3549
+ midpointsFallback,
3550
+ wsLivePrices
3551
+ ]);
3252
3552
  const selectedOutcomesByVenue = useMemo6(() => {
3253
3553
  if (!model) return [];
3254
3554
  return collectEligibleVenueOutcomes({
3255
3555
  venueMarkets: model.market.venueMarkets,
3256
- selectedOutcomeLabel
3556
+ selectedOutcomeLabel,
3557
+ // Critical for inversely-framed binaries: pass the exact outcome id so
3558
+ // collectEligibleVenueOutcomes pins to the user's chosen semantic side
3559
+ // instead of falling through to label-matching across other markets
3560
+ // (which surfaces opposite-side outcomes for kalshi per-team No-side).
3561
+ selectedOutcomeId
3257
3562
  });
3258
- }, [model, selectedOutcomeLabel]);
3563
+ }, [model, selectedOutcomeLabel, selectedOutcomeId]);
3259
3564
  const resolvedChartOutcomeLabel = chartOutcomeLabel != null ? chartOutcomeLabel : selectedOutcomeLabel;
3565
+ const chartSelectedOutcomeId = selectedOutcomeId && resolvedChartOutcomeLabel === selectedOutcomeLabel ? selectedOutcomeId : null;
3260
3566
  const chartOutcomesByVenue = useMemo6(() => {
3261
3567
  if (!model) return [];
3262
3568
  return resolveChartVenueOutcomes({
3263
3569
  eligibleVenueOutcomes: collectEligibleVenueOutcomes({
3264
3570
  venueMarkets: model.market.venueMarkets,
3265
- selectedOutcomeLabel: resolvedChartOutcomeLabel
3571
+ selectedOutcomeLabel: resolvedChartOutcomeLabel,
3572
+ selectedOutcomeId: chartSelectedOutcomeId
3266
3573
  }),
3267
3574
  livePrices
3268
3575
  });
3269
- }, [livePrices, model, resolvedChartOutcomeLabel]);
3576
+ }, [livePrices, model, resolvedChartOutcomeLabel, chartSelectedOutcomeId]);
3270
3577
  const chartEnabled = isOpened && effectiveSelectedTab === "graph";
3271
3578
  const orderBookEnabled = isOpened && effectiveSelectedTab === "order-book" && !marketTradingState.isTradingDisabled;
3272
- const timeWindow = useMemo6(() => {
3273
- return getTimeWindowByRange(effectiveChartTimeRange);
3274
- }, [effectiveChartTimeRange]);
3275
- const primaryVenueMarketId = (_e = (_d = selectedOutcomesByVenue[0]) == null ? void 0 : _d.market.id) != null ? _e : null;
3276
- const primaryOutcomeId = (_g = (_f = selectedOutcomesByVenue[0]) == null ? void 0 : _f.outcome.id) != null ? _g : null;
3277
- const chartPrimaryOutcomeId = (_i = (_h = chartOutcomesByVenue[0]) == null ? void 0 : _h.outcome.id) != null ? _i : null;
3579
+ const rollingWindow = useRollingChartWindow2({ range: effectiveChartTimeRange });
3580
+ const primaryVenueMarketId = (_f = (_e = selectedOutcomesByVenue[0]) == null ? void 0 : _e.market.id) != null ? _f : null;
3581
+ const primaryOutcomeId = (_h = (_g = selectedOutcomesByVenue[0]) == null ? void 0 : _g.outcome.id) != null ? _h : null;
3582
+ const chartPrimaryOutcomeId = (_j = (_i = chartOutcomesByVenue[0]) == null ? void 0 : _i.outcome.id) != null ? _j : null;
3278
3583
  const chartVenueOutcomeIds = useMemo6(() => {
3279
3584
  return chartOutcomesByVenue.map((item) => item.outcome.id);
3280
3585
  }, [chartOutcomesByVenue]);
@@ -3286,12 +3591,43 @@ var MarketDetailsContent = ({
3286
3591
  } = useMarketChart2({
3287
3592
  marketId: chartPrimaryOutcomeId,
3288
3593
  venueMarketIds: chartVenueOutcomeIds,
3289
- interval: timeRangeToInterval2(effectiveChartTimeRange),
3290
- startTs: timeWindow.startTs * 1e3,
3291
- endTs: timeWindow.endTs * 1e3,
3594
+ interval: rollingWindow.interval,
3595
+ startTs: rollingWindow.startTs * 1e3,
3596
+ endTs: rollingWindow.endTs * 1e3,
3292
3597
  enabled: chartEnabled && !!chartPrimaryOutcomeId,
3293
- live
3598
+ live,
3599
+ refetchIntervalMs: rollingWindow.refetchIntervalMs,
3600
+ // Stable cache key per user-selected range so tab/page revisits hit cache
3601
+ // instead of refetching on every bucket-boundary rollover.
3602
+ rangeKey: rollingWindow.range
3294
3603
  });
3604
+ const hasAutoFallenBackRangeRef = useRef5(false);
3605
+ useEffect4(() => {
3606
+ hasAutoFallenBackRangeRef.current = false;
3607
+ setChartRangeOverride(null);
3608
+ }, [chartPrimaryOutcomeId]);
3609
+ useEffect4(() => {
3610
+ if (!shouldAutoFallbackToAllRange({
3611
+ chartData: marketChartData,
3612
+ isLoading: isMarketChartLoading,
3613
+ error: marketChartError,
3614
+ currentRange: effectiveChartTimeRange,
3615
+ hasAlreadyFallenBack: hasAutoFallenBackRangeRef.current,
3616
+ // Ignore stale bars outside the rolling window — see comment on the
3617
+ // matching effect in event-list-item-details.
3618
+ domainStartTs: rollingWindow.startTs
3619
+ })) {
3620
+ return;
3621
+ }
3622
+ hasAutoFallenBackRangeRef.current = true;
3623
+ setChartRangeOverride("ALL");
3624
+ }, [
3625
+ marketChartData,
3626
+ isMarketChartLoading,
3627
+ marketChartError,
3628
+ effectiveChartTimeRange,
3629
+ rollingWindow.startTs
3630
+ ]);
3295
3631
  const marketOrderbookResult = useMarketOrderbook({
3296
3632
  marketId: primaryVenueMarketId,
3297
3633
  enabled: orderBookEnabled && !!primaryVenueMarketId,
@@ -3345,6 +3681,7 @@ var MarketDetailsContent = ({
3345
3681
  0,
3346
3682
  isDarkTheme
3347
3683
  );
3684
+ const domainStartTs = rollingWindow.startTs;
3348
3685
  return resolveMarketChartDisplaySeries({
3349
3686
  chartData: marketChartData,
3350
3687
  selectedVenue: selectedGraphVenue,
@@ -3354,13 +3691,16 @@ var MarketDetailsContent = ({
3354
3691
  id: `${resolvedChartOutcomeLabel != null ? resolvedChartOutcomeLabel : "graph"}-${seriesItem.venue}-${chartPrimaryOutcomeId != null ? chartPrimaryOutcomeId : "chart"}`,
3355
3692
  venue: selectedGraphVenue != null ? selectedGraphVenue : seriesItem.venue,
3356
3693
  color: seriesItem.venue === "aggregate" ? baseColor : resolveSeriesColor(seriesItem.venue, 0, isDarkTheme),
3357
- points: seriesItem.points
3694
+ // Constrain to the rolling [nowSec - rangeSeconds, …] domain so stale
3695
+ // bars don't bleed in across a range shrink or long mount.
3696
+ points: seriesItem.points.filter((point) => point.time >= domainStartTs)
3358
3697
  };
3359
3698
  });
3360
3699
  }, [
3361
3700
  isDarkTheme,
3362
3701
  chartPrimaryOutcomeId,
3363
3702
  marketChartData,
3703
+ rollingWindow.startTs,
3364
3704
  selectedGraphVenue,
3365
3705
  resolvedChartOutcomeLabel,
3366
3706
  chartAvailableOutcomesByVenue,
@@ -3388,11 +3728,19 @@ var MarketDetailsContent = ({
3388
3728
  item,
3389
3729
  shouldNotifyOutcomeSelect = false
3390
3730
  }) => {
3731
+ var _a2, _b2;
3391
3732
  if (isOutcomeSelectionLocked) return;
3392
3733
  if (item == null ? void 0 : item.id) {
3393
- tradingContext == null ? void 0 : tradingContext.selectOutcome(item.id);
3734
+ const targetMarket = (_a2 = model == null ? void 0 : model.market.venueMarkets.find(
3735
+ (venueMarket) => venueMarket.venueMarketOutcomes.some((outcome) => outcome.id === item.id)
3736
+ )) != null ? _a2 : null;
3737
+ if ((targetMarket == null ? void 0 : targetMarket.id) && targetMarket.id !== (tradingContext == null ? void 0 : tradingContext.selectedMarketId)) {
3738
+ tradingContext == null ? void 0 : tradingContext.selectMarketAndOutcome(targetMarket.id, item.id);
3739
+ } else {
3740
+ tradingContext == null ? void 0 : tradingContext.selectOutcome(item.id);
3741
+ }
3394
3742
  if (shouldNotifyOutcomeSelect && model) {
3395
- onOutcomeSelect == null ? void 0 : onOutcomeSelect({ marketId: model.market.id, outcomeId: item.id });
3743
+ onOutcomeSelect == null ? void 0 : onOutcomeSelect({ marketId: (_b2 = targetMarket == null ? void 0 : targetMarket.id) != null ? _b2 : model.market.id, outcomeId: item.id });
3396
3744
  }
3397
3745
  }
3398
3746
  };
@@ -3487,26 +3835,24 @@ var MarketDetailsContent = ({
3487
3835
  {
3488
3836
  className: cn(
3489
3837
  "agg-market-card-header",
3490
- "cursor-pointer",
3491
3838
  "flex flex-col items-stretch gap-3 px-5 py-3 md:flex-row md:flex-nowrap md:items-center md:justify-between",
3492
3839
  isOpened && "pb-3",
3493
3840
  classNames == null ? void 0 : classNames.header
3494
3841
  ),
3495
- onClick: handleToggleExpanded,
3496
3842
  children: [
3497
3843
  /* @__PURE__ */ jsxs7(
3498
3844
  "button",
3499
3845
  {
3500
- type: "button",
3501
3846
  className: cn(
3502
3847
  "agg-market-card-summary",
3503
3848
  "flex min-w-0 w-full items-center justify-between gap-4 text-left md:flex-1",
3504
3849
  "cursor-pointer rounded-agg-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-agg-primary focus-visible:ring-offset-0 focus-visible:ring-offset-agg-secondary"
3505
3850
  ),
3851
+ type: "button",
3852
+ onClick: handleToggleExpanded,
3506
3853
  "aria-expanded": isOpened,
3507
3854
  "aria-controls": detailsContentId,
3508
3855
  "aria-label": isOpened ? labels.marketDetails.toggleCloseDetailsAria(model.title) : labels.marketDetails.toggleOpenDetailsAria(model.title),
3509
- onClick: handleToggleExpanded,
3510
3856
  children: [
3511
3857
  /* @__PURE__ */ jsxs7("div", { className: "agg-market-summary flex min-w-24 flex-1 items-center gap-3 md:gap-4", children: [
3512
3858
  /* @__PURE__ */ jsx9(
@@ -3535,7 +3881,7 @@ var MarketDetailsContent = ({
3535
3881
  children: model.subtitle
3536
3882
  }
3537
3883
  ) }),
3538
- marketTradingState.isTradingDisabled && marketTradingState.kind !== "resolved" && !isUpcomingMarket ? /* @__PURE__ */ jsxs7("div", { className: "mt-2 flex flex-wrap items-center gap-2", children: [
3884
+ marketTradingState.isTradingDisabled && marketTradingState.kind !== "resolved" && !isUpcomingMarket ? /* @__PURE__ */ jsxs7("div", { className: "mt-2 flex flex-wrap items-center gap-2 justify-center md:justify-start", children: [
3539
3885
  /* @__PURE__ */ jsxs7(
3540
3886
  "span",
3541
3887
  {
@@ -3565,75 +3911,60 @@ var MarketDetailsContent = ({
3565
3911
  ]
3566
3912
  }
3567
3913
  ),
3568
- marketTradingState.kind === "resolved" && marketTradingState.winningOutcome ? /* @__PURE__ */ jsx9(
3569
- "div",
3914
+ marketTradingState.kind === "resolved" && marketTradingState.winningOutcome ? /* @__PURE__ */ jsx9("div", { className: "agg-outcomes flex w-full items-center justify-end md:w-auto md:shrink-0", children: /* @__PURE__ */ jsxs7(
3915
+ "span",
3570
3916
  {
3571
- className: "agg-outcomes flex w-full items-center justify-end md:w-auto md:shrink-0",
3572
- onClick: (e) => e.stopPropagation(),
3573
- children: /* @__PURE__ */ jsxs7(
3574
- "span",
3575
- {
3576
- className: cn(
3577
- "w-full md:w-auto md:min-w-35 inline-flex h-9 items-center justify-center gap-2 rounded-agg-full",
3578
- "border px-5 py-1.5 text-agg-sm font-agg-bold",
3579
- getMotionClassName(
3580
- enableAnimations,
3581
- "transition-[background-color,border-color,color] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)]"
3582
- ),
3583
- "border-transparent bg-agg-secondary-hover"
3584
- ),
3585
- children: [
3586
- /* @__PURE__ */ jsx9(
3587
- Icon,
3588
- {
3589
- name: marketTradingState.winningOutcome.label.trim().toLowerCase() === "yes" ? "check-circle" : "cross-circle",
3590
- size: "small",
3591
- className: cn(
3592
- "h-4 w-4",
3593
- marketTradingState.winningOutcome.label.trim().toLowerCase() === "yes" ? "text-agg-success" : "text-agg-error"
3594
- )
3595
- }
3596
- ),
3597
- /* @__PURE__ */ jsx9(Typography, { variant: "body", children: labels.eventMarketPage.resolvedOutcome(marketTradingState.winningOutcome.label) })
3598
- ]
3599
- }
3600
- )
3917
+ className: cn(
3918
+ "w-full md:w-auto md:min-w-35 inline-flex h-9 items-center justify-center gap-2 rounded-agg-full",
3919
+ "border px-5 py-1.5 text-agg-sm font-agg-bold",
3920
+ getMotionClassName(
3921
+ enableAnimations,
3922
+ "transition-[background-color,border-color,color] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)]"
3923
+ ),
3924
+ "border-transparent bg-agg-secondary-hover"
3925
+ ),
3926
+ children: [
3927
+ /* @__PURE__ */ jsx9(
3928
+ Icon,
3929
+ {
3930
+ name: marketTradingState.winningOutcome.label.trim().toLowerCase() === "yes" ? "check-circle" : "cross-circle",
3931
+ size: "small",
3932
+ className: cn(
3933
+ "h-4 w-4",
3934
+ marketTradingState.winningOutcome.label.trim().toLowerCase() === "yes" ? "text-agg-success" : "text-agg-error"
3935
+ )
3936
+ }
3937
+ ),
3938
+ /* @__PURE__ */ jsx9(Typography, { variant: "body", children: labels.eventMarketPage.resolvedOutcome(marketTradingState.winningOutcome.label) })
3939
+ ]
3601
3940
  }
3602
- ) : isUpcomingMarket ? /* @__PURE__ */ jsx9(
3603
- "div",
3941
+ ) }) : isUpcomingMarket ? /* @__PURE__ */ jsx9("div", { className: "agg-outcomes flex w-full items-center justify-end md:w-auto md:shrink-0", children: /* @__PURE__ */ jsxs7(
3942
+ "span",
3604
3943
  {
3605
- className: "agg-outcomes flex w-full items-center justify-end md:w-auto md:shrink-0",
3606
- onClick: (e) => e.stopPropagation(),
3607
- children: /* @__PURE__ */ jsxs7(
3608
- "span",
3609
- {
3610
- className: cn(
3611
- "min-w-35 inline-flex h-9 items-center justify-center gap-2 rounded-agg-full",
3612
- "border px-5 py-1.5 text-agg-xs font-agg-bold uppercase tracking-[0.08em]",
3613
- resolveTradingStateBadgeClassName(marketTradingState.kind)
3614
- ),
3615
- children: [
3616
- /* @__PURE__ */ jsx9(
3617
- Icon,
3618
- {
3619
- name: marketStatePresentation.iconName,
3620
- size: "small",
3621
- className: "h-3.5 w-3.5",
3622
- "aria-hidden": "true"
3623
- }
3624
- ),
3625
- /* @__PURE__ */ jsx9("span", { children: marketStatePresentation.badgeLabel })
3626
- ]
3627
- }
3628
- )
3944
+ className: cn(
3945
+ "min-w-35 inline-flex h-9 items-center justify-center gap-2 rounded-agg-full",
3946
+ "border px-5 py-1.5 text-agg-xs font-agg-bold uppercase tracking-[0.08em]",
3947
+ resolveTradingStateBadgeClassName(marketTradingState.kind)
3948
+ ),
3949
+ children: [
3950
+ /* @__PURE__ */ jsx9(
3951
+ Icon,
3952
+ {
3953
+ name: marketStatePresentation.iconName,
3954
+ size: "small",
3955
+ className: "h-3.5 w-3.5",
3956
+ "aria-hidden": "true"
3957
+ }
3958
+ ),
3959
+ /* @__PURE__ */ jsx9("span", { children: marketStatePresentation.badgeLabel })
3960
+ ]
3629
3961
  }
3630
- ) : /* @__PURE__ */ jsx9(
3962
+ ) }) : /* @__PURE__ */ jsx9(
3631
3963
  "div",
3632
3964
  {
3633
3965
  className: "agg-outcomes flex w-full flex-wrap gap-2 md:w-auto md:shrink-0 md:flex-nowrap",
3634
3966
  role: "tablist",
3635
3967
  "aria-label": labels.marketDetails.marketOutcomesAria,
3636
- onClick: (e) => e.stopPropagation(),
3637
3968
  onKeyDown: (eventToHandle) => handleOutcomeKeyDown(eventToHandle),
3638
3969
  children: headerOutcomeItems.map((item) => {
3639
3970
  const isActiveOutcome = item.id === selectedOutcomeId;
@@ -3751,7 +4082,7 @@ var MarketDetailsContent = ({
3751
4082
  height: 260,
3752
4083
  isLoading: isMarketChartLoading,
3753
4084
  chartType: selectedChartType,
3754
- liveCandle: selectedChartType === "candlestick" ? (_j = graphLiveState.liveCandle) != null ? _j : void 0 : void 0,
4085
+ liveCandle: selectedChartType === "candlestick" ? (_k = graphLiveState.liveCandle) != null ? _k : void 0 : void 0,
3755
4086
  lineValue: graphLiveState.lineValue,
3756
4087
  classNames: { root: "agg-chart-region w-full" },
3757
4088
  showSeriesControls: chartAvailableOutcomesByVenue.length > 0 || headerOutcomeItems.length > 0,
@@ -3807,12 +4138,12 @@ var MarketDetailsContent = ({
3807
4138
  setChartOutcomeLabel(outcome.label);
3808
4139
  },
3809
4140
  options: headerOutcomeItems.map((outcome) => {
4141
+ var _a3, _b3;
3810
4142
  const price = outcome.probability;
3811
- const outcomeLabel = `${outcome.label} ${formatProbabilityCents(price)}`;
3812
4143
  return {
3813
4144
  value: outcome.id,
3814
- label: outcomeLabel,
3815
- ariaLabel: outcomeLabel
4145
+ label: `${(_a3 = outcome == null ? void 0 : outcome.title) != null ? _a3 : outcome.label} ${formatProbabilityCents(price)}`,
4146
+ ariaLabel: `${(_b3 = outcome == null ? void 0 : outcome.title) != null ? _b3 : outcome.label} ${formatProbabilityCents(price)}`
3816
4147
  };
3817
4148
  })
3818
4149
  }
@@ -3867,6 +4198,7 @@ var MarketDetailsContent = ({
3867
4198
  e.preventDefault();
3868
4199
  e.stopPropagation();
3869
4200
  if (isDisabled) return;
4201
+ setChartRangeOverride(null);
3870
4202
  setSelectedTimeRange(timeRange);
3871
4203
  },
3872
4204
  children: timeRange === "ALL" ? labels.eventItemDetails.allTimeRange : timeRange
@@ -3903,8 +4235,16 @@ var MarketDetailsContent = ({
3903
4235
  };
3904
4236
  var MarketDetails = (_a) => {
3905
4237
  var _b = _a, { isOpened } = _b, props = __objRest(_b, ["isOpened"]);
4238
+ const labels = useLabels6();
3906
4239
  if (props.isLoading) {
3907
- return /* @__PURE__ */ jsx9(MarketDetailsLoadingState, { isOpened, classNames: props.classNames });
4240
+ return /* @__PURE__ */ jsx9(
4241
+ Skeleton,
4242
+ {
4243
+ view: "market-details-minified",
4244
+ className: cn("agg-market-list-item"),
4245
+ ariaLabel: labels.marketDetails.loading
4246
+ }
4247
+ );
3908
4248
  }
3909
4249
  if ("venueMarkets" in props && props.venueMarkets) {
3910
4250
  return /* @__PURE__ */ jsx9(
@@ -3969,16 +4309,17 @@ var MarketDetailsList = ({
3969
4309
  onClick,
3970
4310
  onOutcomeSelect,
3971
4311
  onExpandedMarketChange,
4312
+ autoSelectFallbackMarket = true,
3972
4313
  defaultTab,
3973
4314
  classNames,
3974
- live
4315
+ live,
4316
+ midpointsResult
3975
4317
  }) => {
3976
4318
  var _a, _b;
3977
4319
  const labels = useLabels6();
3978
- const tradingContext = useEventTradingContext2();
4320
+ const tradingContext = useEventTradingContext3();
3979
4321
  const selectedMarketId = (_a = tradingContext == null ? void 0 : tradingContext.selectedMarketId) != null ? _a : null;
3980
- const [expandedMarketId, setExpandedMarketId] = useState4(selectedMarketId);
3981
- const previousSelectedMarketIdRef = useRef5(selectedMarketId);
4322
+ const [expandedMarketId, setExpandedMarketId] = useState4(null);
3982
4323
  const [areResolvedMarketsVisible, setAreResolvedMarketsVisible] = useState4(false);
3983
4324
  const resolvedEventId = eventId || "";
3984
4325
  const {
@@ -4052,7 +4393,12 @@ var MarketDetailsList = ({
4052
4393
  return [...groupedMarkets.primary, ...visibleResolvedMarkets];
4053
4394
  }, [groupedMarkets.primary, visibleResolvedMarkets]);
4054
4395
  const hasPrefetchedMarkets = !!providedMarkets || !!((_b = eventTradingState == null ? void 0 : eventTradingState.marketStates) == null ? void 0 : _b.length);
4055
- const { prices: midpointsFallback, venueByOutcomeId: midpointsFallbackVenues } = useViewportMidpoints(displayedMarkets);
4396
+ const midpointEligibleMarkets = useMemo6(() => {
4397
+ return displayedMarkets.filter(
4398
+ (market) => resolveMarketTradingState(market).kind !== "resolved"
4399
+ );
4400
+ }, [displayedMarkets]);
4401
+ const { prices: midpointsFallback, venueByOutcomeId: midpointsFallbackVenues } = useViewportMidpoints(midpointEligibleMarkets);
4056
4402
  useEffect4(() => {
4057
4403
  if (isResolvedEvent) {
4058
4404
  setAreResolvedMarketsVisible(false);
@@ -4062,13 +4408,6 @@ var MarketDetailsList = ({
4062
4408
  setAreResolvedMarketsVisible(false);
4063
4409
  }
4064
4410
  }, [groupedMarkets.resolved.length, isResolvedEvent]);
4065
- useEffect4(() => {
4066
- if (previousSelectedMarketIdRef.current === selectedMarketId) return;
4067
- previousSelectedMarketIdRef.current = selectedMarketId;
4068
- if (!selectedMarketId) return;
4069
- if (!displayedMarkets.some((market) => market.id === selectedMarketId)) return;
4070
- setExpandedMarketId(selectedMarketId);
4071
- }, [displayedMarkets, selectedMarketId]);
4072
4411
  useEffect4(() => {
4073
4412
  if (displayedMarkets.length === 0) return;
4074
4413
  if (selectedMarketId && displayedMarkets.some((market) => market.id === selectedMarketId)) {
@@ -4083,21 +4422,14 @@ var MarketDetailsList = ({
4083
4422
  if (!fallbackSelectableMarket) {
4084
4423
  return;
4085
4424
  }
4086
- if (!expandedMarketId) {
4087
- setExpandedMarketId(fallbackSelectableMarket.id);
4088
- }
4425
+ if (!autoSelectFallbackMarket) return;
4089
4426
  tradingContext == null ? void 0 : tradingContext.selectMarket(fallbackSelectableMarket.id, fallbackSelectableMarket);
4090
- }, [displayedMarkets, expandedMarketId, selectedMarketId, sourceMarkets, tradingContext]);
4427
+ }, [autoSelectFallbackMarket, displayedMarkets, selectedMarketId, sourceMarkets, tradingContext]);
4091
4428
  useEffect4(() => {
4092
- var _a2, _b2;
4093
4429
  if (!expandedMarketId) return;
4094
4430
  if (displayedMarkets.some((market) => market.id === expandedMarketId)) return;
4095
- if (selectedMarketId && displayedMarkets.some((market) => market.id === selectedMarketId)) {
4096
- setExpandedMarketId(selectedMarketId);
4097
- return;
4098
- }
4099
- setExpandedMarketId((_b2 = (_a2 = displayedMarkets[0]) == null ? void 0 : _a2.id) != null ? _b2 : null);
4100
- }, [displayedMarkets, expandedMarketId, selectedMarketId]);
4431
+ setExpandedMarketId(null);
4432
+ }, [displayedMarkets, expandedMarketId]);
4101
4433
  const handleToggle = (marketId, market) => {
4102
4434
  if (marketId === expandedMarketId) {
4103
4435
  setExpandedMarketId(null);
@@ -4111,22 +4443,14 @@ var MarketDetailsList = ({
4111
4443
  tradingContext == null ? void 0 : tradingContext.selectMarket(market.id, market);
4112
4444
  };
4113
4445
  if (!hasPrefetchedMarkets && isLoading) {
4114
- return /* @__PURE__ */ jsxs7("div", { className: cn("agg-market-list flex flex-col gap-3", classNames == null ? void 0 : classNames.root), children: [
4115
- /* @__PURE__ */ jsx9(
4116
- MarketDetailsLoadingState,
4117
- {
4118
- isOpened: true,
4119
- classNames: { root: cn("agg-market-list-item", classNames == null ? void 0 : classNames.item) }
4120
- }
4121
- ),
4122
- /* @__PURE__ */ jsx9(
4123
- MarketDetailsLoadingState,
4124
- {
4125
- isOpened: false,
4126
- classNames: { root: cn("agg-market-list-item", classNames == null ? void 0 : classNames.item) }
4127
- }
4128
- )
4129
- ] });
4446
+ return /* @__PURE__ */ jsx9(
4447
+ Skeleton,
4448
+ {
4449
+ view: "market-details-minified",
4450
+ className: cn("agg-market-list-item"),
4451
+ ariaLabel: labels.marketDetails.loading
4452
+ }
4453
+ );
4130
4454
  }
4131
4455
  if (!hasPrefetchedMarkets && error) {
4132
4456
  return /* @__PURE__ */ jsx9(
@@ -4157,17 +4481,25 @@ var MarketDetailsList = ({
4157
4481
  marketId: market.id,
4158
4482
  venueMarkets: sourceMarkets,
4159
4483
  isOpened: expandedMarketId === market.id,
4484
+ suppressOutcomeFallbackSelection: market.id !== selectedMarketId,
4160
4485
  onOpenChange: (marketId) => {
4161
4486
  onClick == null ? void 0 : onClick(market);
4162
4487
  handleToggle(marketId, market);
4163
4488
  },
4164
- onOutcomeSelect,
4489
+ onOutcomeSelect: (selection) => {
4490
+ if (selection.marketId !== expandedMarketId) {
4491
+ setExpandedMarketId(selection.marketId);
4492
+ onExpandedMarketChange == null ? void 0 : onExpandedMarketChange(selection.marketId);
4493
+ }
4494
+ onOutcomeSelect == null ? void 0 : onOutcomeSelect(selection);
4495
+ },
4165
4496
  defaultTab,
4166
4497
  ariaLabel: market.question,
4167
4498
  classNames: { root: cn("agg-market-list-item", classNames == null ? void 0 : classNames.item) },
4168
4499
  live,
4169
4500
  midpointsFallback,
4170
- midpointsFallbackVenues
4501
+ midpointsFallbackVenues,
4502
+ midpointsResult
4171
4503
  }
4172
4504
  ) }, market.id);
4173
4505
  return /* @__PURE__ */ jsxs7("div", { className: cn("agg-market-list flex flex-col gap-3", classNames == null ? void 0 : classNames.root), children: [
@@ -4177,7 +4509,7 @@ var MarketDetailsList = ({
4177
4509
  {
4178
4510
  variant: "tertiary",
4179
4511
  size: "small",
4180
- className: "agg-market-view-resolved-toggle self-start",
4512
+ className: "agg-market-view-resolved-toggle self-start my-2",
4181
4513
  onClick: () => {
4182
4514
  setAreResolvedMarketsVisible((isVisible) => !isVisible);
4183
4515
  },
@@ -4200,13 +4532,87 @@ var MarketDetailsList = ({
4200
4532
  MarketDetailsList.displayName = "MarketDetailsList";
4201
4533
 
4202
4534
  // src/events/list/index.tsx
4203
- import { MarketStatus as MarketStatus2, useAppConfig as useAppConfig2, useLabels as useLabels8, useVenueEvents } from "@agg-build/hooks";
4535
+ import {
4536
+ MarketStatus as MarketStatus2,
4537
+ useAppConfig as useAppConfig2,
4538
+ useCategories,
4539
+ useLabels as useLabels8,
4540
+ useSdkUiConfig as useSdkUiConfig4,
4541
+ useVenueEvents
4542
+ } from "@agg-build/hooks";
4204
4543
  import { VENUES } from "@agg-build/sdk";
4544
+ import * as Dialog from "@radix-ui/react-dialog";
4205
4545
  import { useEffect as useEffect6, useMemo as useMemo8, useRef as useRef7, useState as useState6 } from "react";
4206
4546
 
4207
4547
  // src/events/list/event-list-tabs.tsx
4208
4548
  import { useAppConfig, useLabels as useLabels7 } from "@agg-build/hooks";
4209
4549
  import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo7, useRef as useRef6, useState as useState5 } from "react";
4550
+
4551
+ // src/events/list/event-list.constants.ts
4552
+ import { MatchStatus, Venue as Venue2 } from "@agg-build/sdk";
4553
+ var DEFAULT_EVENTS_LIMIT = 50;
4554
+ var getDefaultEventListTabs = (labels) => {
4555
+ return [
4556
+ {
4557
+ value: "matched",
4558
+ label: labels.eventList.matchedTab,
4559
+ iconName: "circle-overlap",
4560
+ matchStatus: [MatchStatus.matched, MatchStatus.verified]
4561
+ },
4562
+ {
4563
+ value: "all",
4564
+ label: labels.eventList.allTab,
4565
+ iconName: "apps"
4566
+ },
4567
+ {
4568
+ value: Venue2.polymarket,
4569
+ label: labels.venues.polymarket,
4570
+ venueLogo: Venue2.polymarket,
4571
+ venues: [Venue2.polymarket]
4572
+ },
4573
+ {
4574
+ value: Venue2.kalshi,
4575
+ label: labels.venues.kalshi,
4576
+ venueLogo: Venue2.kalshi,
4577
+ venues: [Venue2.kalshi]
4578
+ },
4579
+ {
4580
+ value: Venue2.limitless,
4581
+ label: labels.venues.limitless,
4582
+ venueLogo: Venue2.limitless,
4583
+ venues: [Venue2.limitless]
4584
+ },
4585
+ {
4586
+ value: Venue2.predict,
4587
+ label: labels.venues.predict,
4588
+ venueLogo: Venue2.predict,
4589
+ venues: [Venue2.predict]
4590
+ },
4591
+ {
4592
+ value: Venue2.hyperliquid,
4593
+ label: labels.venues.hyperliquid,
4594
+ venueLogo: Venue2.hyperliquid,
4595
+ venues: [Venue2.hyperliquid]
4596
+ // isComingSoon: true,
4597
+ },
4598
+ {
4599
+ value: Venue2.myriad,
4600
+ label: labels.venues.myriad,
4601
+ venueLogo: Venue2.myriad,
4602
+ venues: [Venue2.myriad]
4603
+ // isComingSoon: true,
4604
+ },
4605
+ {
4606
+ value: Venue2.opinion,
4607
+ label: labels.venues.opinion,
4608
+ venueLogo: Venue2.opinion,
4609
+ venues: [Venue2.opinion],
4610
+ isComingSoon: true
4611
+ }
4612
+ ];
4613
+ };
4614
+
4615
+ // src/events/list/event-list-tabs.tsx
4210
4616
  import { jsx as jsx10 } from "react/jsx-runtime";
4211
4617
  var renderTabIcon = (tab, isActive) => {
4212
4618
  if (tab.venueLogo) {
@@ -4274,12 +4680,13 @@ var EventListTabs = ({
4274
4680
  );
4275
4681
  };
4276
4682
  EventListTabs.displayName = "EventListTabs";
4277
- var useEventListTabsHeaderOverflow = (recomputeOn) => {
4683
+ var useEventListTabsHeaderOverflow = (recomputeOn, options) => {
4278
4684
  const headerRef = useRef6(null);
4279
4685
  const titleRef = useRef6(null);
4280
4686
  const requiredTabsWidthRef = useRef6(0);
4281
4687
  const [shouldUseSelectOverflow, setShouldUseSelectOverflow] = useState5(false);
4282
4688
  const updateTabsOverflowBehavior = useCallback3(() => {
4689
+ var _a;
4283
4690
  if (typeof window === "undefined") return;
4284
4691
  const headerElement = headerRef.current;
4285
4692
  const titleElement = titleRef.current;
@@ -4292,6 +4699,16 @@ var useEventListTabsHeaderOverflow = (recomputeOn) => {
4292
4699
  setShouldUseSelectOverflow(true);
4293
4700
  return;
4294
4701
  }
4702
+ const minTabsInlineWidthForSelect = options == null ? void 0 : options.minTabsInlineWidthForSelect;
4703
+ if (typeof minTabsInlineWidthForSelect === "number" && availableTabsWidth < minTabsInlineWidthForSelect) {
4704
+ setShouldUseSelectOverflow(true);
4705
+ return;
4706
+ }
4707
+ const preferSelectOnOverflow = (_a = options == null ? void 0 : options.preferSelectOnOverflow) != null ? _a : true;
4708
+ if (!preferSelectOnOverflow) {
4709
+ setShouldUseSelectOverflow(false);
4710
+ return;
4711
+ }
4295
4712
  const tabListElement = headerElement.querySelector(".agg-tab-list");
4296
4713
  if (tabListElement) {
4297
4714
  const currentRequiredWidth = tabListElement.scrollWidth;
@@ -4304,7 +4721,7 @@ var useEventListTabsHeaderOverflow = (recomputeOn) => {
4304
4721
  }
4305
4722
  if (requiredTabsWidthRef.current <= 0) return;
4306
4723
  setShouldUseSelectOverflow(requiredTabsWidthRef.current > availableTabsWidth);
4307
- }, []);
4724
+ }, [options == null ? void 0 : options.minTabsInlineWidthForSelect, options == null ? void 0 : options.preferSelectOnOverflow]);
4308
4725
  useEffect5(() => {
4309
4726
  updateTabsOverflowBehavior();
4310
4727
  }, [recomputeOn, updateTabsOverflowBehavior]);
@@ -4336,7 +4753,25 @@ var useEventListTabsHeaderOverflow = (recomputeOn) => {
4336
4753
  };
4337
4754
 
4338
4755
  // src/events/list/index.tsx
4339
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
4756
+ import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
4757
+ var SORT_ICON_BY_VALUE = {
4758
+ volume24hr: "sort-volume-24hr",
4759
+ topArbitrage: "sort-top-arbitrage",
4760
+ volume: "sort-volume",
4761
+ endDate: "sort-end-date"
4762
+ };
4763
+ var resolveSortQueryParams = (value) => {
4764
+ if (value === "volume") {
4765
+ return { sortBy: "volume", sortDir: "desc" };
4766
+ }
4767
+ if (value === "endDate") {
4768
+ return { sortBy: "endDate", sortDir: "asc" };
4769
+ }
4770
+ if (value === "topArbitrage") {
4771
+ return {};
4772
+ }
4773
+ return { sortBy: "volume24hr", sortDir: "desc" };
4774
+ };
4340
4775
  var EventList = ({
4341
4776
  title,
4342
4777
  limit = DEFAULT_EVENTS_LIMIT,
@@ -4351,9 +4786,13 @@ var EventList = ({
4351
4786
  initialLoadedPageCount,
4352
4787
  stateRef
4353
4788
  }) => {
4354
- var _a, _b;
4789
+ var _a, _b, _c;
4355
4790
  const labels = useLabels8();
4356
4791
  const { disabledVenues } = useAppConfig2();
4792
+ const {
4793
+ features: { enableVenueEventDiscoveryFilters }
4794
+ } = useSdkUiConfig4();
4795
+ const isDiscoveryFiltersEnabled = enableVenueEventDiscoveryFilters && !search;
4357
4796
  const resolvedTabs = useEventListTabs();
4358
4797
  const visibleVenues = useMemo8(
4359
4798
  () => disabledVenues.length === 0 ? void 0 : VENUES.filter(
@@ -4364,7 +4803,90 @@ var EventList = ({
4364
4803
  const [activeTabValue, setActiveTabValue] = useState6(
4365
4804
  (_b = initialVenueTab != null ? initialVenueTab : (_a = resolvedTabs[0]) == null ? void 0 : _a.value) != null ? _b : "matched"
4366
4805
  );
4367
- const { headerRef, titleRef, shouldUseSelectOverflow } = useEventListTabsHeaderOverflow(resolvedTabs);
4806
+ const [selectedSort, setSelectedSort] = useState6("volume24hr");
4807
+ const [isSubcategoriesModalOpen, setIsSubcategoriesModalOpen] = useState6(false);
4808
+ const [selectedParentCategoryId, setSelectedParentCategoryId] = useState6(null);
4809
+ const [selectedSubcategoryId, setSelectedSubcategoryId] = useState6(null);
4810
+ const { headerRef, titleRef, shouldUseSelectOverflow } = useEventListTabsHeaderOverflow(resolvedTabs, { minTabsInlineWidthForSelect: 400, preferSelectOnOverflow: false });
4811
+ const sortItems = useMemo8(() => {
4812
+ return [
4813
+ {
4814
+ value: "volume24hr",
4815
+ label: labels.eventList.sortBy24hVolume,
4816
+ icon: /* @__PURE__ */ jsx11(Icon, { name: SORT_ICON_BY_VALUE.volume24hr, size: "small", color: "currentColor" })
4817
+ },
4818
+ {
4819
+ value: "topArbitrage",
4820
+ label: labels.eventList.sortByTopArbitrage,
4821
+ icon: /* @__PURE__ */ jsx11(Icon, { name: SORT_ICON_BY_VALUE.topArbitrage, size: "small", color: "currentColor" }),
4822
+ disabled: true,
4823
+ hidden: true
4824
+ },
4825
+ {
4826
+ value: "volume",
4827
+ label: labels.eventList.sortByTotalVolume,
4828
+ icon: /* @__PURE__ */ jsx11(Icon, { name: SORT_ICON_BY_VALUE.volume, size: "small", color: "currentColor" })
4829
+ },
4830
+ {
4831
+ value: "endDate",
4832
+ label: labels.eventList.sortByEndingSoon,
4833
+ icon: /* @__PURE__ */ jsx11(Icon, { name: SORT_ICON_BY_VALUE.endDate, size: "small", color: "currentColor" })
4834
+ }
4835
+ ];
4836
+ }, [
4837
+ labels.eventList.sortBy24hVolume,
4838
+ labels.eventList.sortByEndingSoon,
4839
+ labels.eventList.sortByTopArbitrage,
4840
+ labels.eventList.sortByTotalVolume
4841
+ ]);
4842
+ const baseCategoryId = (_c = categoryIds == null ? void 0 : categoryIds[0]) != null ? _c : null;
4843
+ useEffect6(() => {
4844
+ if (!isDiscoveryFiltersEnabled) return;
4845
+ setSelectedParentCategoryId(baseCategoryId);
4846
+ setSelectedSubcategoryId(null);
4847
+ }, [baseCategoryId, isDiscoveryFiltersEnabled]);
4848
+ const { categories: topLevelCategories } = useCategories({
4849
+ queryKeyScope: "event-list-top-categories",
4850
+ enabled: isDiscoveryFiltersEnabled,
4851
+ limit: 100
4852
+ });
4853
+ const { categories: subcategories } = useCategories({
4854
+ queryKeyScope: "event-list-subcategories",
4855
+ enabled: isDiscoveryFiltersEnabled && Boolean(baseCategoryId),
4856
+ parentId: baseCategoryId,
4857
+ limit: 100
4858
+ });
4859
+ const shouldRenderSubcategoryFilters = isDiscoveryFiltersEnabled && Boolean(baseCategoryId) && subcategories.length > 0;
4860
+ console.log({
4861
+ enableVenueEventDiscoveryFilters,
4862
+ shouldRenderSubcategoryFilters,
4863
+ isDiscoveryFiltersEnabled,
4864
+ baseCategoryId,
4865
+ subcategories
4866
+ });
4867
+ const totalTopLevelEventCount = useMemo8(() => {
4868
+ return topLevelCategories.reduce((accumulator, category) => {
4869
+ var _a2;
4870
+ return accumulator + ((_a2 = category.eventCount) != null ? _a2 : 0);
4871
+ }, 0);
4872
+ }, [topLevelCategories]);
4873
+ const selectedParentEventCount = useMemo8(() => {
4874
+ var _a2;
4875
+ if (!baseCategoryId) return totalTopLevelEventCount;
4876
+ const selectedParentCategory = topLevelCategories.find(
4877
+ (category) => category.id === baseCategoryId
4878
+ );
4879
+ return (_a2 = selectedParentCategory == null ? void 0 : selectedParentCategory.eventCount) != null ? _a2 : totalTopLevelEventCount;
4880
+ }, [baseCategoryId, topLevelCategories, totalTopLevelEventCount]);
4881
+ const resolvedCategoryIds = useMemo8(() => {
4882
+ if (!isDiscoveryFiltersEnabled) return categoryIds;
4883
+ if (selectedSubcategoryId) return [selectedSubcategoryId];
4884
+ if (selectedParentCategoryId) return [selectedParentCategoryId];
4885
+ return categoryIds;
4886
+ }, [categoryIds, isDiscoveryFiltersEnabled, selectedParentCategoryId, selectedSubcategoryId]);
4887
+ const sortQueryParams = useMemo8(() => {
4888
+ return resolveSortQueryParams(selectedSort);
4889
+ }, [selectedSort]);
4368
4890
  const activeTab = useMemo8(() => {
4369
4891
  return resolvedTabs.find((tab) => tab.value === activeTabValue);
4370
4892
  }, [activeTabValue, resolvedTabs]);
@@ -4396,23 +4918,19 @@ var EventList = ({
4396
4918
  isFetchingNextPage,
4397
4919
  isPlaceholderData,
4398
4920
  loadedPageCount
4399
- } = useVenueEvents(__spreadProps(__spreadValues({
4921
+ } = useVenueEvents({
4400
4922
  queryKeyScope: "event-list",
4401
4923
  venues,
4402
4924
  search,
4403
- categoryIds,
4925
+ categoryIds: resolvedCategoryIds,
4404
4926
  matchStatus,
4405
4927
  limit: requestLimit,
4406
4928
  status: [MarketStatus2.open],
4407
- sortBy: "volume24hr",
4408
- sortDir: "desc",
4409
- endDateFrom
4410
- }, !search ? {
4411
- minYesPrice: 0.03,
4412
- maxYesPrice: 0.97
4413
- } : {}), {
4929
+ sortBy: sortQueryParams.sortBy,
4930
+ sortDir: sortQueryParams.sortDir,
4931
+ endDateFrom,
4414
4932
  initialPages: initialLoadedPageCount
4415
- }));
4933
+ });
4416
4934
  useEffect6(() => {
4417
4935
  if (stateRef) {
4418
4936
  stateRef.current = { venueTab: activeTabValue, loadedPageCount };
@@ -4461,6 +4979,54 @@ var EventList = ({
4461
4979
  const gridClassName = cn(
4462
4980
  "grid grid-cols-[repeat(auto-fill,minmax(240px,1fr))] md:grid-cols-[repeat(auto-fill,minmax(360px,1fr))] gap-4"
4463
4981
  );
4982
+ const isAllSubcategoriesSelected = shouldRenderSubcategoryFilters && !selectedSubcategoryId;
4983
+ const handleSelectAllCategories = () => {
4984
+ setSelectedParentCategoryId(baseCategoryId);
4985
+ setSelectedSubcategoryId(null);
4986
+ setIsSubcategoriesModalOpen(false);
4987
+ };
4988
+ const handleSelectSubcategory = (subcategoryId) => {
4989
+ setSelectedSubcategoryId(subcategoryId);
4990
+ setIsSubcategoriesModalOpen(false);
4991
+ };
4992
+ const subcategoriesListContent = /* @__PURE__ */ jsxs8(Fragment2, { children: [
4993
+ /* @__PURE__ */ jsxs8(
4994
+ "button",
4995
+ {
4996
+ type: "button",
4997
+ className: cn(
4998
+ "flex w-full items-center justify-between rounded-[6px] px-3 py-3 text-left text-agg-sm leading-agg-5",
4999
+ isAllSubcategoriesSelected ? "bg-agg-primary/10 font-agg-normal text-agg-primary" : "font-agg-normal text-agg-foreground"
5000
+ ),
5001
+ onClick: handleSelectAllCategories,
5002
+ children: [
5003
+ /* @__PURE__ */ jsx11("span", { children: labels.eventList.subcategoriesAll }),
5004
+ /* @__PURE__ */ jsx11("span", { className: "text-agg-muted-foreground", children: selectedParentEventCount })
5005
+ ]
5006
+ }
5007
+ ),
5008
+ subcategories.map((subcategory) => {
5009
+ var _a2;
5010
+ const isSubcategorySelected = selectedSubcategoryId === subcategory.id;
5011
+ return /* @__PURE__ */ jsxs8(
5012
+ "button",
5013
+ {
5014
+ type: "button",
5015
+ className: cn(
5016
+ "flex w-full items-center justify-between rounded-[6px] px-3 py-3 text-left text-agg-sm leading-agg-5",
5017
+ "cursor-pointer",
5018
+ isSubcategorySelected ? "bg-agg-secondary-hover font-agg-bold text-agg-foreground" : "font-agg-normal text-agg-foreground"
5019
+ ),
5020
+ onClick: () => handleSelectSubcategory(subcategory.id),
5021
+ children: [
5022
+ /* @__PURE__ */ jsx11("span", { className: "truncate first-letter:uppercase", children: subcategory.name }),
5023
+ /* @__PURE__ */ jsx11("span", { className: "text-agg-muted-foreground", children: (_a2 = subcategory.eventCount) != null ? _a2 : 0 })
5024
+ ]
5025
+ },
5026
+ subcategory.id
5027
+ );
5028
+ })
5029
+ ] });
4464
5030
  if (shouldRenderLoadingState) {
4465
5031
  return /* @__PURE__ */ jsx11(Skeleton, { view: "event-list", ariaLabel: labels.eventList.loading(title) });
4466
5032
  }
@@ -4476,61 +5042,144 @@ var EventList = ({
4476
5042
  ),
4477
5043
  children: [
4478
5044
  /* @__PURE__ */ jsx11("div", { ref: titleRef, className: "agg-event-list-title min-w-32", children: /* @__PURE__ */ jsx11(Typography, { as: "h2", variant: "title", className: "truncate first-letter:uppercase", children: title }) }),
4479
- /* @__PURE__ */ jsx11(
4480
- EventListTabs,
4481
- {
4482
- ariaLabel: labels.eventList.tabsAria(title),
4483
- className: "agg-event-list-tabs min-w-0 max-w-full",
4484
- activeTab: activeTabValue,
4485
- onTabChange: setActiveTabValue,
4486
- overflowBehavior: shouldUseSelectOverflow ? "select" : void 0
4487
- }
4488
- )
5045
+ /* @__PURE__ */ jsxs8("div", { className: "hidden min-w-0 max-w-full items-center gap-3 md:flex", children: [
5046
+ /* @__PURE__ */ jsx11(
5047
+ EventListTabs,
5048
+ {
5049
+ ariaLabel: labels.eventList.tabsAria(title),
5050
+ className: cn(
5051
+ "agg-event-list-tabs w-fit max-w-full flex-1",
5052
+ shouldUseSelectOverflow ? "min-w-[220px]" : "min-w-[400px]"
5053
+ ),
5054
+ activeTab: activeTabValue,
5055
+ onTabChange: setActiveTabValue,
5056
+ overflowBehavior: shouldUseSelectOverflow ? "select" : "scroll"
5057
+ }
5058
+ ),
5059
+ /* @__PURE__ */ jsx11(
5060
+ Select,
5061
+ {
5062
+ ariaLabel: labels.eventList.sortByLabel,
5063
+ className: "min-w-[160px] w-auto! shrink-0 min-h-10.5",
5064
+ value: selectedSort,
5065
+ onChange: setSelectedSort,
5066
+ items: sortItems,
5067
+ contentClassName: "py-2"
5068
+ }
5069
+ )
5070
+ ] })
4489
5071
  ]
4490
5072
  }
4491
5073
  ),
4492
- /* @__PURE__ */ jsxs8("div", { className: cn("agg-event-list-grid", isPlaceholderData && "opacity-60", gridClassName), children: [
4493
- tileEvents.map((event) => /* @__PURE__ */ jsx11(
4494
- EventListItem,
4495
- {
4496
- event,
4497
- classNames: {
4498
- root: "agg-event-list-item w-full min-w-0 max-w-none"
4499
- },
4500
- onEventClick,
4501
- onMarketClick,
4502
- getMarketHref,
4503
- href: getEventHref == null ? void 0 : getEventHref(event)
4504
- },
4505
- event.id
4506
- )),
4507
- shouldRenderPaginationLoadingItems ? Array.from({ length: 6 }).map((_, index) => /* @__PURE__ */ jsx11(
4508
- EventListItem,
5074
+ /* @__PURE__ */ jsxs8("div", { className: "flex w-full gap-2 md:hidden", children: [
5075
+ /* @__PURE__ */ jsx11(
5076
+ EventListTabs,
4509
5077
  {
4510
- isLoading: true,
4511
- classNames: {
4512
- root: "agg-event-list-item w-full min-w-0 max-w-none"
4513
- }
4514
- },
4515
- `loading-${index}`
4516
- )) : null,
4517
- shouldRenderEmptyState ? /* @__PURE__ */ jsx11("div", { className: "col-span-full w-full", children: /* @__PURE__ */ jsx11(
4518
- StateMessage,
5078
+ ariaLabel: labels.eventList.tabsAria(title),
5079
+ className: "agg-event-list-tabs min-w-0 flex-1",
5080
+ activeTab: activeTabValue,
5081
+ onTabChange: setActiveTabValue,
5082
+ overflowBehavior: "select"
5083
+ }
5084
+ ),
5085
+ /* @__PURE__ */ jsx11(
5086
+ Select,
4519
5087
  {
4520
- title: labels.eventList.emptyTitle,
4521
- description: labels.eventList.emptyDescription,
4522
- icon: /* @__PURE__ */ jsx11(Icon, { name: "search-empty" })
5088
+ ariaLabel: labels.eventList.sortByLabel,
5089
+ className: "min-w-0 flex-1 md:min-w-[144px]",
5090
+ value: selectedSort,
5091
+ onChange: setSelectedSort,
5092
+ items: sortItems,
5093
+ contentClassName: "rounded-[12px] py-2 shadow-[0_8px_16px_rgba(0,0,0,0.1)]"
4523
5094
  }
4524
- ) }) : null,
4525
- isError ? /* @__PURE__ */ jsx11(
4526
- StateMessage,
5095
+ ),
5096
+ shouldRenderSubcategoryFilters ? /* @__PURE__ */ jsx11(
5097
+ "button",
4527
5098
  {
4528
- title: labels.eventList.errorTitle,
4529
- description: labels.eventList.errorDescription,
4530
- icon: /* @__PURE__ */ jsx11(Icon, { name: "warning" })
5099
+ type: "button",
5100
+ className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-[8px] border-2 border-agg-primary bg-agg-secondary text-agg-foreground cursor-pointer",
5101
+ "aria-label": labels.eventList.subcategoriesOpenAria,
5102
+ onClick: () => setIsSubcategoriesModalOpen(true),
5103
+ children: /* @__PURE__ */ jsx11(Icon, { name: "apps", size: "small", color: "currentColor" })
4531
5104
  }
4532
5105
  ) : null
4533
5106
  ] }),
5107
+ /* @__PURE__ */ jsxs8(
5108
+ "div",
5109
+ {
5110
+ className: cn("flex w-full gap-6", shouldRenderSubcategoryFilters ? "md:items-start" : ""),
5111
+ children: [
5112
+ shouldRenderSubcategoryFilters ? /* @__PURE__ */ jsx11("aside", { className: "hidden w-[200px] shrink-0 md:block", children: /* @__PURE__ */ jsx11("div", { className: "flex w-full flex-col gap-1 rounded-[8px] border border-agg-separator bg-agg-secondary p-2", children: subcategoriesListContent }) }) : null,
5113
+ /* @__PURE__ */ jsxs8(
5114
+ "div",
5115
+ {
5116
+ className: cn(
5117
+ "agg-event-list-grid",
5118
+ "w-full",
5119
+ isPlaceholderData && "opacity-60",
5120
+ gridClassName
5121
+ ),
5122
+ children: [
5123
+ tileEvents.map((event) => /* @__PURE__ */ jsx11(
5124
+ EventListItem,
5125
+ {
5126
+ event,
5127
+ classNames: {
5128
+ root: "agg-event-list-item w-full min-w-0 max-w-none"
5129
+ },
5130
+ onEventClick,
5131
+ onMarketClick,
5132
+ getMarketHref,
5133
+ href: getEventHref == null ? void 0 : getEventHref(event),
5134
+ marketStatus: MarketStatus2.open
5135
+ },
5136
+ event.id
5137
+ )),
5138
+ shouldRenderPaginationLoadingItems ? Array.from({ length: 6 }).map((_, index) => /* @__PURE__ */ jsx11(
5139
+ EventListItem,
5140
+ {
5141
+ isLoading: true,
5142
+ classNames: {
5143
+ root: "agg-event-list-item w-full min-w-0 max-w-none"
5144
+ }
5145
+ },
5146
+ `loading-${index}`
5147
+ )) : null,
5148
+ shouldRenderEmptyState ? /* @__PURE__ */ jsx11("div", { className: "col-span-full w-full", children: /* @__PURE__ */ jsx11(
5149
+ StateMessage,
5150
+ {
5151
+ title: labels.eventList.emptyTitle,
5152
+ description: labels.eventList.emptyDescription,
5153
+ icon: /* @__PURE__ */ jsx11(Icon, { name: "search-empty" })
5154
+ }
5155
+ ) }) : null,
5156
+ isError ? /* @__PURE__ */ jsx11("div", { className: "col-span-full w-full", children: /* @__PURE__ */ jsx11(
5157
+ StateMessage,
5158
+ {
5159
+ title: labels.eventList.errorTitle,
5160
+ description: labels.eventList.errorDescription,
5161
+ icon: /* @__PURE__ */ jsx11(Icon, { name: "warning" })
5162
+ }
5163
+ ) }) : null
5164
+ ]
5165
+ }
5166
+ )
5167
+ ]
5168
+ }
5169
+ ),
5170
+ shouldRenderSubcategoryFilters ? /* @__PURE__ */ jsx11(Modal, { open: isSubcategoriesModalOpen, onOpenChange: setIsSubcategoriesModalOpen, children: /* @__PURE__ */ jsxs8(
5171
+ Modal.Container,
5172
+ {
5173
+ classNames: {
5174
+ content: "items-end p-0",
5175
+ container: "w-full max-w-none border-0 bg-transparent shadow-none"
5176
+ },
5177
+ children: [
5178
+ /* @__PURE__ */ jsx11(Dialog.Title, { className: "sr-only", children: labels.eventList.subcategoriesLabel }),
5179
+ /* @__PURE__ */ jsx11("div", { className: "w-full rounded-t-[12px] border border-agg-separator bg-agg-secondary p-4", children: /* @__PURE__ */ jsx11("div", { className: "flex flex-col gap-1", children: subcategoriesListContent }) })
5180
+ ]
5181
+ }
5182
+ ) }) : null,
4534
5183
  shouldPaginate && hasNextPage ? /* @__PURE__ */ jsx11("div", { ref: loadMoreRef, className: "agg-event-list-sentinel h-px w-full", "aria-hidden": true }) : null
4535
5184
  ] });
4536
5185
  };
@@ -4550,6 +5199,7 @@ export {
4550
5199
  Orderbook,
4551
5200
  MarketDetails,
4552
5201
  MarketDetailsList,
5202
+ DEFAULT_EVENTS_LIMIT,
4553
5203
  useEventListTabs,
4554
5204
  EventListTabs,
4555
5205
  useEventListTabsHeaderOverflow,