@agg-build/ui 1.2.12 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +34 -1
  2. package/dist/{chunk-YSW4ULL5.mjs → chunk-55ODXLOS.mjs} +1 -1
  3. package/dist/{chunk-4WBQTUPW.mjs → chunk-5ALBEKAT.mjs} +603 -317
  4. package/dist/{chunk-J6WELNCX.mjs → chunk-6PQ6O6M5.mjs} +583 -186
  5. package/dist/{chunk-U55T5BPE.mjs → chunk-ONVP7YWS.mjs} +44 -13
  6. package/dist/{chunk-X3KCFWXN.mjs → chunk-QUZWA34R.mjs} +975 -849
  7. package/dist/{chunk-IBOE7DRY.mjs → chunk-UFC7L74C.mjs} +26 -27
  8. package/dist/{chunk-3JXBOU24.mjs → chunk-YWJIYEJV.mjs} +146 -81
  9. package/dist/events.js +1833 -1435
  10. package/dist/events.mjs +5 -3
  11. package/dist/index.js +4100 -3213
  12. package/dist/index.mjs +13 -9
  13. package/dist/modals.js +964 -899
  14. package/dist/modals.mjs +3 -3
  15. package/dist/pages.js +3593 -2724
  16. package/dist/pages.mjs +6 -6
  17. package/dist/primitives.js +995 -902
  18. package/dist/primitives.mjs +3 -1
  19. package/dist/styles.css +1 -1
  20. package/dist/tailwind.css +1 -1
  21. package/dist/trading.js +828 -688
  22. package/dist/trading.mjs +4 -4
  23. package/dist/types/events/item/event-list-item-v2.utils.d.mts +28 -0
  24. package/dist/types/events/item/event-list-item-v2.utils.d.ts +28 -0
  25. package/dist/types/events/item/event-list-item.constants.d.mts +1 -1
  26. package/dist/types/events/item/event-list-item.constants.d.ts +1 -1
  27. package/dist/types/events/item/index.d.mts +4 -0
  28. package/dist/types/events/item/index.d.ts +4 -0
  29. package/dist/types/events/list/event-list.types.d.mts +2 -0
  30. package/dist/types/events/list/event-list.types.d.ts +2 -0
  31. package/dist/types/events/list/event-list.utils.d.mts +19 -0
  32. package/dist/types/events/list/event-list.utils.d.ts +19 -0
  33. package/dist/types/events/list/index.d.mts +1 -1
  34. package/dist/types/events/list/index.d.ts +1 -1
  35. package/dist/types/pages/home/home.types.d.mts +1 -0
  36. package/dist/types/pages/home/home.types.d.ts +1 -0
  37. package/dist/types/pages/user-profile/user-profile.types.d.mts +30 -4
  38. package/dist/types/pages/user-profile/user-profile.types.d.ts +30 -4
  39. package/dist/types/primitives/icon/index.d.mts +2 -1
  40. package/dist/types/primitives/icon/index.d.ts +2 -1
  41. package/dist/types/primitives/icon/registry.d.mts +4 -0
  42. package/dist/types/primitives/icon/registry.d.ts +4 -0
  43. package/dist/types/primitives/icon/svg/gift-bonus.d.mts +5 -0
  44. package/dist/types/primitives/icon/svg/gift-bonus.d.ts +5 -0
  45. package/dist/types/primitives/search/search.types.d.mts +2 -1
  46. package/dist/types/primitives/search/search.types.d.ts +2 -1
  47. package/dist/types/primitives/skeleton/index.d.mts +1 -1
  48. package/dist/types/primitives/skeleton/index.d.ts +1 -1
  49. package/dist/types/primitives/skeleton/skeleton.types.d.mts +4 -0
  50. package/dist/types/primitives/skeleton/skeleton.types.d.ts +4 -0
  51. package/dist/types/primitives/skeleton/views/event-list-skeleton-view.d.mts +1 -1
  52. package/dist/types/primitives/skeleton/views/event-list-skeleton-view.d.ts +1 -1
  53. package/dist/types/profile/tabs/accounts-wallets-tab.d.mts +1 -1
  54. package/dist/types/profile/tabs/accounts-wallets-tab.d.ts +1 -1
  55. package/dist/types/trading/place-order/index.d.mts +1 -1
  56. package/dist/types/trading/place-order/index.d.ts +1 -1
  57. package/dist/types/trading/place-order/index.place-order.types.d.mts +4 -1
  58. package/dist/types/trading/place-order/index.place-order.types.d.ts +4 -1
  59. package/dist/types/trading/place-order/index.place-order.utils.d.mts +2 -0
  60. package/dist/types/trading/place-order/index.place-order.utils.d.ts +2 -0
  61. package/package.json +3 -3
@@ -20,10 +20,9 @@ import {
20
20
  resolveTradingStateBadgeClassName,
21
21
  resolveTradingStatePresentation,
22
22
  resolveUnifiedOrderBookEntries,
23
- selectOutcomePrice,
24
23
  sortOutcomeSelectorOutcomes,
25
24
  useEventTradingContext
26
- } from "./chunk-IBOE7DRY.mjs";
25
+ } from "./chunk-UFC7L74C.mjs";
27
26
  import {
28
27
  AutocompleteSelect,
29
28
  Badge,
@@ -48,12 +47,10 @@ import {
48
47
  __objRest,
49
48
  __spreadProps,
50
49
  __spreadValues,
51
- baseCardClassName,
52
50
  cn,
53
51
  dedupeVenueMarketsById,
54
52
  detailsBaseCardClassName,
55
53
  filterEventsByTabValue,
56
- formatCountLabel,
57
54
  formatMarketProbabilityPercent,
58
55
  formatPriceGapPercent,
59
56
  getMarketDetailsTabs,
@@ -64,22 +61,24 @@ import {
64
61
  normalizeProbability,
65
62
  normalizeVenueMarketCluster,
66
63
  orderBookRowLimitDefault,
64
+ resolveCategoryIdsFromPath,
67
65
  resolveDisplayVolume,
68
66
  resolveEventListItemEvent,
69
67
  resolveOutcomeTitle,
70
68
  resolveTabVenus,
69
+ resolveVenueLabel,
71
70
  resolveYesOutcome,
71
+ sortCategoriesForNavigation,
72
+ sortMarketsByVolumeDesc,
72
73
  sortMarketsByYesOddsDesc,
73
74
  sortOutcomes,
74
75
  splitEventsByLifecycle
75
- } from "./chunk-X3KCFWXN.mjs";
76
+ } from "./chunk-QUZWA34R.mjs";
76
77
 
77
78
  // src/events/item/index.tsx
78
79
  import {
79
- computePriceGaps,
80
80
  optimizedImageUrl,
81
81
  sortVenues,
82
- useEventTradingContext as useEventTradingContext2,
83
82
  useLabels,
84
83
  useMidpoints,
85
84
  useSdkUiConfig,
@@ -99,34 +98,155 @@ var isErrorWithStatus = (error, status) => {
99
98
  return getErrorStatus(error) === status;
100
99
  };
101
100
 
102
- // src/events/shared/display-outcome-venue.ts
103
- var normalizeOutcomeLabel = (label) => {
104
- return typeof label === "string" ? label.trim().toLowerCase() : "";
101
+ // src/events/item/event-list-item-v2.utils.ts
102
+ var isNonEmptyString = (value) => {
103
+ return typeof value === "string" && value.trim().length > 0;
105
104
  };
106
- var getDisplayOutcomeVenue = ({
107
- outcomeId,
108
- outcomeLabel,
109
- selection,
110
- bestMidpointVenue,
111
- bestVenueByOutcomeId,
112
- bestPriceVenuesByOutcomeId,
113
- fallbackVenue
114
- }) => {
105
+ var getOutcomeSortPrice = (outcome) => {
115
106
  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;
107
+ return (_a = normalizeProbability(outcome.price)) != null ? _a : -1;
108
+ };
109
+ var MAX_VISIBLE_OUTCOME_PRICE_PILLS = 3;
110
+ var resolveDisplayOutcome = (market) => {
111
+ var _a;
112
+ return (_a = resolveYesOutcome(market)) != null ? _a : [...market.venueMarketOutcomes].sort((left, right) => {
113
+ return getOutcomeSortPrice(right) - getOutcomeSortPrice(left);
114
+ })[0];
115
+ };
116
+ var resolveOutcomeRows = ({
117
+ venueMarkets,
118
+ marketCount
119
+ }) => {
120
+ if (venueMarkets.length === 0) return [];
121
+ if (marketCount === 1 && venueMarkets.length === 1) {
122
+ const [market] = venueMarkets;
123
+ return sortOutcomes(market.venueMarketOutcomes).map((outcome) => ({
124
+ id: outcome.id,
125
+ label: resolveOutcomeTitle(outcome),
126
+ market,
127
+ outcome
128
+ }));
120
129
  }
121
- if (normalizeOutcomeLabel(outcomeLabel) === "yes" && bestMidpointVenue) {
122
- return bestMidpointVenue;
130
+ return sortMarketsByYesOddsDesc(venueMarkets).map((market) => {
131
+ const outcome = resolveDisplayOutcome(market);
132
+ if (!outcome) return void 0;
133
+ return {
134
+ id: market.id,
135
+ label: isNonEmptyString(market.question) ? market.question : resolveOutcomeTitle(outcome),
136
+ market,
137
+ outcome
138
+ };
139
+ }).filter((row) => row != null);
140
+ };
141
+ var collectOutcomePrices = (market, outcome, priceByOutcomeId) => {
142
+ var _a, _b, _c;
143
+ const prices = [];
144
+ const seenOutcomeKeys = /* @__PURE__ */ new Set();
145
+ const addPrice = (priceMarket, priceOutcome) => {
146
+ var _a2;
147
+ if (!priceMarket || !priceOutcome) return;
148
+ const resolvedPrice = (_a2 = priceByOutcomeId == null ? void 0 : priceByOutcomeId.get(priceOutcome.id)) != null ? _a2 : priceOutcome.price;
149
+ const normalizedPrice = normalizeProbability(resolvedPrice);
150
+ if (normalizedPrice == null) return;
151
+ const key = `${priceMarket.id}:${priceOutcome.id}`;
152
+ if (seenOutcomeKeys.has(key)) return;
153
+ seenOutcomeKeys.add(key);
154
+ prices.push({
155
+ venue: priceMarket.venue,
156
+ market: priceMarket,
157
+ outcome: priceOutcome,
158
+ price: normalizedPrice,
159
+ isBest: false
160
+ });
161
+ };
162
+ addPrice(market, outcome);
163
+ for (const matchedOutcomeRef of (_a = outcome.matchedVenueMarketOutcomes) != null ? _a : []) {
164
+ const matchedMarket = (_b = market.matchedVenueMarkets) == null ? void 0 : _b.find((candidate) => {
165
+ return candidate.id === matchedOutcomeRef.venueMarketId;
166
+ });
167
+ const matchedOutcome = (_c = matchedMarket == null ? void 0 : matchedMarket.venueMarketOutcomes) == null ? void 0 : _c.find((candidate) => {
168
+ return candidate.id === matchedOutcomeRef.venueMarketOutcomeId;
169
+ });
170
+ addPrice(matchedMarket, matchedOutcome);
123
171
  }
124
- const bestVenue = outcomeId ? bestVenueByOutcomeId == null ? void 0 : bestVenueByOutcomeId.get(outcomeId) : void 0;
125
- return (_a = bestVenue != null ? bestVenue : fallbackVenue) != null ? _a : void 0;
172
+ if (prices.length === 0) return [];
173
+ const bestPriceByVenue = /* @__PURE__ */ new Map();
174
+ for (const price of prices) {
175
+ const existing = bestPriceByVenue.get(price.venue);
176
+ if (!existing || price.price < existing.price) {
177
+ bestPriceByVenue.set(price.venue, price);
178
+ }
179
+ }
180
+ const dedupedPrices = Array.from(bestPriceByVenue.values());
181
+ const sortedPricesByBestOdds = [...dedupedPrices].sort((left, right) => {
182
+ return left.price - right.price;
183
+ });
184
+ const bestPrice = sortedPricesByBestOdds[0];
185
+ if (!bestPrice) return [];
186
+ const visiblePrices = [
187
+ sortedPricesByBestOdds.at(-1),
188
+ sortedPricesByBestOdds[1],
189
+ bestPrice
190
+ ].reduce((accumulator, price) => {
191
+ if (!price) return accumulator;
192
+ const isDuplicate = accumulator.some((candidate) => {
193
+ return candidate.market.id === price.market.id && candidate.outcome.id === price.outcome.id;
194
+ });
195
+ if (isDuplicate) return accumulator;
196
+ accumulator.push(price);
197
+ return accumulator;
198
+ }, []);
199
+ return visiblePrices.slice(0, MAX_VISIBLE_OUTCOME_PRICE_PILLS).map((price) => __spreadProps(__spreadValues({}, price), {
200
+ isBest: price.market.id === bestPrice.market.id && price.outcome.id === bestPrice.outcome.id
201
+ }));
202
+ };
203
+ var collectMatchedVenues = (rows) => {
204
+ const venues = /* @__PURE__ */ new Set();
205
+ for (const row of rows) {
206
+ if (row.prices.length < 2) continue;
207
+ for (const price of row.prices) {
208
+ venues.add(price.venue);
209
+ }
210
+ }
211
+ return Array.from(venues);
212
+ };
213
+ var computePriceGapsFromComparisonRows = (rows) => {
214
+ const gapsByVenueMarketId = /* @__PURE__ */ new Map();
215
+ for (const row of rows) {
216
+ if (row.prices.length < 2) continue;
217
+ const prices = row.prices.map((price) => price.price);
218
+ const minPrice = Math.min(...prices);
219
+ const maxPrice = Math.max(...prices);
220
+ if (minPrice <= 0 || maxPrice <= minPrice) continue;
221
+ gapsByVenueMarketId.set(row.market.id, (maxPrice - minPrice) * 100);
222
+ }
223
+ return gapsByVenueMarketId;
224
+ };
225
+ var normalizeEventListItemV2Comparison = ({
226
+ venueMarkets,
227
+ marketCount,
228
+ priceByOutcomeId
229
+ }) => {
230
+ const outcomeRows = resolveOutcomeRows({ venueMarkets, marketCount });
231
+ const rows = outcomeRows.map((row) => {
232
+ const prices = collectOutcomePrices(row.market, row.outcome, priceByOutcomeId);
233
+ return __spreadProps(__spreadValues({}, row), {
234
+ prices
235
+ });
236
+ });
237
+ const matchedVenues = collectMatchedVenues(rows);
238
+ return {
239
+ rows,
240
+ matchedVenues,
241
+ hasVenueCompetition: matchedVenues.length > 1
242
+ };
126
243
  };
127
244
 
245
+ // src/events/item/event-list-item.constants.ts
246
+ var baseCardClassName = "gap-3 overflow-hidden p-4 w-full";
247
+
128
248
  // src/events/item/index.tsx
129
- import { jsx, jsxs } from "react/jsx-runtime";
249
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
130
250
  var EventListItemLoadingState = ({
131
251
  classNames,
132
252
  ariaLabel
@@ -188,6 +308,25 @@ var EventListItemNotFoundState = ({
188
308
  var OUTCOMES_SCROLL_LOAD_THRESHOLD_PX = 16;
189
309
  var MARKET_ID_QUERY_PARAM = "marketId";
190
310
  var OUTCOME_ID_QUERY_PARAM = "outcomeId";
311
+ var buildOutcomeMidpointsByOutcomeId = (midpointRows) => {
312
+ const outcomeMidpointsByOutcomeId = /* @__PURE__ */ new Map();
313
+ const addOutcomeMidpoints = (value) => {
314
+ var _a, _b;
315
+ if (!value || typeof value !== "object") return;
316
+ const row = value;
317
+ for (const outcome of (_a = row.outcomes) != null ? _a : []) {
318
+ if (outcome.midpoint == null) continue;
319
+ outcomeMidpointsByOutcomeId.set(outcome.venueMarketOutcomeId, outcome.midpoint);
320
+ }
321
+ for (const matchedRow of (_b = row.matched) != null ? _b : []) {
322
+ addOutcomeMidpoints(matchedRow);
323
+ }
324
+ };
325
+ for (const row of midpointRows) {
326
+ addOutcomeMidpoints(row);
327
+ }
328
+ return outcomeMidpointsByOutcomeId;
329
+ };
191
330
  var resolveMarketHrefFromEventHref = (eventHref, marketId, outcomeId) => {
192
331
  if (!eventHref) return void 0;
193
332
  if (typeof window === "undefined") return void 0;
@@ -214,8 +353,6 @@ var EventListItemContent = ({
214
353
  var _a;
215
354
  const config = useSdkUiConfig();
216
355
  const labels = useLabels();
217
- const tradingContext = useEventTradingContext2();
218
- const tradeSide = (_a = tradingContext == null ? void 0 : tradingContext.tradeSide) != null ? _a : "buy";
219
356
  const allVenueMarkets = useMemo(() => event.venueMarkets, [event.venueMarkets]);
220
357
  const resolvedTitle = event.title;
221
358
  const resolvedImage = event.image;
@@ -262,32 +399,42 @@ var EventListItemContent = ({
262
399
  }
263
400
  return [...new Set(ids)];
264
401
  }, [resolvedOutcomeMarkets]);
265
- const {
266
- midpointsByVenueMarketId,
267
- isLoading: isLoadingMidpoints,
268
- isFetching: isFetchingMidpoints
269
- } = useVenueMarketMidpoints({
402
+ const { midpointRows, isLoading: isVenueMarketMidpointsLoading } = useVenueMarketMidpoints({
270
403
  venueMarketIds: midpointVenueMarketIds,
271
404
  enabled: midpointVenueMarketIds.length > 0
272
405
  });
273
- const {
274
- prices: displayMidpointsByOutcomeId,
275
- venueByOutcomeId: displayMidpointVenueByOutcomeId,
276
- bestPrices: displayBestPricesByOutcomeId,
277
- bestPriceVenuesByOutcomeId: displayBestPriceVenuesByOutcomeId,
278
- isLoading: isDisplayMidpointsLoading
279
- } = useMidpoints(resolvedOutcomeMarkets);
280
- const gapsByVenueMarketId = useMemo(
281
- () => computePriceGaps({
282
- markets: resolvedOutcomeMarkets,
283
- midpointsByVenueMarketId
284
- }),
285
- [resolvedOutcomeMarkets, midpointsByVenueMarketId]
286
- );
287
- const isMidpointQueryInFlight = isLoadingMidpoints || isFetchingMidpoints || isDisplayMidpointsLoading;
406
+ const { prices: displayMidpointsByOutcomeId, isLoading: isOutcomeMidpointsLoading } = useMidpoints(resolvedOutcomeMarkets);
407
+ const isAwaitingMidpoints = isOutcomeMidpointsLoading || midpointVenueMarketIds.length > 0 && isVenueMarketMidpointsLoading;
408
+ const displayPriceByOutcomeId = useMemo(() => {
409
+ const priceByOutcomeId = new Map(displayMidpointsByOutcomeId);
410
+ for (const [outcomeId, price] of buildOutcomeMidpointsByOutcomeId(midpointRows)) {
411
+ priceByOutcomeId.set(outcomeId, price);
412
+ }
413
+ return priceByOutcomeId;
414
+ }, [displayMidpointsByOutcomeId, midpointRows]);
415
+ const comparison = useMemo(() => {
416
+ return normalizeEventListItemV2Comparison({
417
+ venueMarkets: resolvedOutcomeMarkets,
418
+ marketCount: resolvedMarketCount,
419
+ priceByOutcomeId: displayPriceByOutcomeId
420
+ });
421
+ }, [displayPriceByOutcomeId, resolvedMarketCount, resolvedOutcomeMarkets]);
422
+ const gapsByVenueMarketId = useMemo(() => {
423
+ return computePriceGapsFromComparisonRows(comparison.rows);
424
+ }, [comparison.rows]);
288
425
  const shouldRenderLoadingOutcomeRow = shouldEnableLazyMarketLoading && (!isLazyMarketsQueryEnabled || isLoadingLazyMarkets || isFetchingNextLazyMarketsPage || hasNextLazyMarketsPage);
289
- const resolvedVolume = resolveDisplayVolume(event.volume, allVenueMarkets);
290
- const volumeLabel = typeof resolvedVolume === "number" ? `${config.formatting.formatCompactCurrency(resolvedVolume)} ${labels.eventItem.volumeSuffix}` : "";
426
+ const resolvedVolume = (_a = resolveDisplayVolume(event.volume, allVenueMarkets)) != null ? _a : 0;
427
+ const volumeLabel = `${config.formatting.formatCompactCurrency(resolvedVolume)} ${labels.eventItem.volumeSuffix}`;
428
+ const orderedFooterVenues = useMemo(() => {
429
+ const venues = visibleVenueLogos.length > 0 ? visibleVenueLogos : comparison.matchedVenues.length > 0 ? comparison.matchedVenues : event.venue ? [event.venue] : [];
430
+ return Array.from(new Set(venues));
431
+ }, [comparison.matchedVenues, event.venue, visibleVenueLogos]);
432
+ const shouldShowMatchedVenueSummary = resolvedVenueCount > 1 || orderedFooterVenues.length > 1;
433
+ const visibleFooterVenues = shouldShowMatchedVenueSummary ? orderedFooterVenues : orderedFooterVenues.slice(0, 1);
434
+ const singleFooterVenue = shouldShowMatchedVenueSummary ? void 0 : visibleFooterVenues[0];
435
+ const matchedCountLabel = labels.eventItem.matchedCount(
436
+ Math.max(resolvedVenueCount, visibleFooterVenues.length)
437
+ );
291
438
  const shouldUseNativeLinkNavigation = (eventToHandle) => {
292
439
  return eventToHandle.metaKey || eventToHandle.ctrlKey || eventToHandle.shiftKey || eventToHandle.altKey || eventToHandle.button === 1;
293
440
  };
@@ -378,62 +525,116 @@ var EventListItemContent = ({
378
525
  )
379
526
  ] });
380
527
  };
381
- const _renderPriceGapPill = (value) => {
528
+ const renderPriceStripSkeleton = (count) => {
529
+ const safeCount = Math.max(1, Math.min(count || 1, 3));
530
+ const collapsedCount = safeCount - 1;
531
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
532
+ Array.from({ length: collapsedCount }).map((_, index) => /* @__PURE__ */ jsx(
533
+ "span",
534
+ {
535
+ "aria-hidden": "true",
536
+ className: cn(
537
+ "agg-outcome-price-loading agg-outcome-price-loading-collapsed",
538
+ "h-[30px] w-[30px] shrink-0 rounded-agg-full bg-agg-separator animate-pulse",
539
+ index > 0 && "-ml-3"
540
+ )
541
+ },
542
+ `agg-outcome-price-loading-collapsed-${index}`
543
+ )),
544
+ /* @__PURE__ */ jsx(
545
+ "span",
546
+ {
547
+ "aria-hidden": "true",
548
+ className: cn(
549
+ "agg-outcome-price-loading agg-outcome-price-loading-best",
550
+ "ml-1.5 h-[30px] w-[68px] shrink-0 rounded-agg-full bg-agg-separator animate-pulse"
551
+ )
552
+ }
553
+ )
554
+ ] });
555
+ };
556
+ const renderPriceGapPill = (value) => {
557
+ if (!config.features.enablePriceGap) return null;
558
+ if (isAwaitingMidpoints) return null;
382
559
  const formattedPriceGap = formatPriceGapPercent(value);
383
560
  if (!formattedPriceGap) return null;
384
561
  return /* @__PURE__ */ jsxs(
385
- "div",
562
+ "span",
386
563
  {
387
564
  className: cn(
388
565
  "agg-price-gap-pill",
389
- "inline-flex shrink-0 items-center gap-1 rounded-agg-sm border border-agg-success/50 px-2 py-0.5",
390
- "bg-agg-success/10"
566
+ "inline-flex max-w-[52px] shrink-0 items-center gap-1 overflow-hidden whitespace-nowrap",
567
+ "text-agg-2xs font-agg-bold leading-agg-14 text-agg-success",
568
+ "opacity-100 transition-all duration-200 ease-out",
569
+ "group-hover/agg-event-card:mr-0 group-hover/agg-event-card:max-w-0 group-hover/agg-event-card:opacity-0"
391
570
  ),
571
+ title: labels.eventItem.priceGap,
572
+ "aria-label": `${formattedPriceGap} ${labels.eventItem.priceGap}`,
392
573
  children: [
393
- /* @__PURE__ */ jsx(Typography, { variant: "overline", className: "text-agg-success", children: formattedPriceGap }),
394
- /* @__PURE__ */ jsx(Typography, { variant: "overline", className: "text-agg-success uppercase", children: labels.eventItem.priceGap })
574
+ /* @__PURE__ */ jsx(
575
+ "i",
576
+ {
577
+ "aria-hidden": "true",
578
+ className: "fi-rr-arrow-down inline-flex size-3! shrink-0 items-center justify-center text-agg-xs text-agg-success"
579
+ }
580
+ ),
581
+ /* @__PURE__ */ jsx("span", { children: formattedPriceGap })
395
582
  ]
396
583
  }
397
584
  );
398
585
  };
399
- const renderOutcomePriceBadge = (probability, venue, shouldRenderLoadingSkeleton, market, outcome) => {
586
+ const renderComparisonPriceBadge = (row, price, priceIndex) => {
400
587
  var _a2;
401
- if (shouldRenderLoadingSkeleton) {
402
- return /* @__PURE__ */ jsx(
403
- "div",
404
- {
405
- "aria-hidden": "true",
406
- className: cn(
407
- "agg-outcome-price-loading bg-agg-separator animate-pulse h-8 w-[100px] rounded-agg-full"
408
- )
409
- }
410
- );
411
- }
412
- if (typeof probability !== "number") return null;
413
- const marketHref = (_a2 = getMarketHref == null ? void 0 : getMarketHref(event, market, outcome)) != null ? _a2 : resolveMarketHrefFromEventHref(href, market.id, outcome.id);
588
+ const marketHref = (_a2 = getMarketHref == null ? void 0 : getMarketHref(event, row.market, row.outcome)) != null ? _a2 : resolveMarketHrefFromEventHref(href, row.market.id, row.outcome.id);
414
589
  const isInteractive = Boolean(onMarketClick || marketHref);
590
+ const hasVenueCompetition = row.prices.length > 1;
591
+ const isHighlightedBestPrice = hasVenueCompetition && price.isBest;
592
+ const shouldCollapsePriceText = hasVenueCompetition && !isHighlightedBestPrice;
415
593
  return /* @__PURE__ */ jsx(
416
594
  Badge,
417
595
  {
418
- text: formatMarketProbabilityPercent(probability, config.formatting.formatPercent),
419
- prefix: /* @__PURE__ */ jsx(VenueLogo, { venue, size: "small" }),
596
+ text: formatMarketProbabilityPercent(price.price, config.formatting.formatPercent),
597
+ prefix: /* @__PURE__ */ jsx(
598
+ VenueLogo,
599
+ {
600
+ venue: price.venue,
601
+ size: "small",
602
+ isMonochromatic: !isHighlightedBestPrice,
603
+ className: cn(!isHighlightedBestPrice && "text-agg-muted-foreground!")
604
+ }
605
+ ),
420
606
  size: "small",
421
607
  classNames: {
422
608
  root: cn(
423
609
  "agg-outcome-price",
424
- "h-8 min-w-25 justify-center px-4 text-agg-base leading-agg-6",
610
+ "h-[30px] justify-center overflow-hidden px-0 text-agg-sm leading-agg-5",
611
+ "shrink-0 p-0! transition-all duration-300 ease-out",
612
+ isHighlightedBestPrice ? "agg-outcome-price-best ml-2 w-[68px] min-w-[68px] shadow-none" : cn(
613
+ "bg-agg-secondary-hover hover:bg-agg-tertiary",
614
+ hasVenueCompetition ? "agg-outcome-price-collapsed relative box-border w-[30px] min-w-[30px] group-hover/agg-event-card:w-[68px] group-hover/agg-event-card:min-w-[68px] group-hover/agg-event-card:gap-1" : "w-[68px] min-w-[68px]",
615
+ hasVenueCompetition && priceIndex > 0 && "-ml-3 group-hover/agg-event-card:ml-2"
616
+ ),
425
617
  isInteractive && "cursor-pointer",
426
618
  classNames == null ? void 0 : classNames.badge
427
619
  ),
428
- text: "text-agg-foreground"
620
+ prefix: cn(
621
+ "flex shrink-0 items-center justify-center [&>svg]:size-3.5",
622
+ shouldCollapsePriceText && "pointer-events-none absolute inset-0 transition-[opacity] duration-300 ease-in group-hover/agg-event-card:pointer-events-auto group-hover/agg-event-card:static group-hover/agg-event-card:inset-auto"
623
+ ),
624
+ text: cn(
625
+ "transition-[max-width,opacity] duration-300 ease-in",
626
+ price.isBest ? "text-agg-foreground" : "text-agg-muted-foreground",
627
+ shouldCollapsePriceText && "max-w-0 overflow-hidden! opacity-0 group-hover/agg-event-card:max-w-[40px] group-hover/agg-event-card:opacity-100"
628
+ )
429
629
  },
430
630
  onClick: isInteractive ? (eventToHandle) => {
431
- handleOutcomeBadgeClick(eventToHandle, market, outcome, marketHref);
631
+ handleOutcomeBadgeClick(eventToHandle, row.market, row.outcome, marketHref);
432
632
  } : void 0,
433
633
  onAuxClick: isInteractive ? (eventToHandle) => {
434
- handleOutcomeBadgeClick(eventToHandle, market, outcome, marketHref);
634
+ handleOutcomeBadgeClick(eventToHandle, row.market, row.outcome, marketHref);
435
635
  } : void 0
436
- }
636
+ },
637
+ `${price.market.id}:${price.outcome.id}`
437
638
  );
438
639
  };
439
640
  return /* @__PURE__ */ jsxs(
@@ -453,153 +654,72 @@ var EventListItemContent = ({
453
654
  "aria-label": ariaLabel != null ? ariaLabel : resolvedTitle,
454
655
  withGradient: true,
455
656
  children: [
456
- /* @__PURE__ */ jsxs(
457
- "div",
458
- {
459
- className: cn("agg-event-card-header min-h-12 flex items-center gap-3", classNames == null ? void 0 : classNames.header),
460
- children: [
461
- /* @__PURE__ */ jsx(
462
- RemoteImage,
463
- {
464
- src: optimizedImageUrl(resolvedImage, 40),
465
- alt: "",
466
- className: cn("agg-event-image h-10 w-10 rounded-agg-lg object-cover")
467
- }
657
+ /* @__PURE__ */ jsxs("div", { className: cn("agg-event-card-header flex h-12 items-center gap-4", classNames == null ? void 0 : classNames.header), children: [
658
+ /* @__PURE__ */ jsx(
659
+ RemoteImage,
660
+ {
661
+ src: optimizedImageUrl(resolvedImage, 40),
662
+ alt: "",
663
+ classNames: {
664
+ root: "agg-event-image h-10 w-10 shrink-0 rounded-agg-lg object-cover",
665
+ image: "transition-transform duration-300 group-hover/agg-event-card:scale-110"
666
+ }
667
+ }
668
+ ),
669
+ /* @__PURE__ */ jsx(
670
+ Typography,
671
+ {
672
+ variant: "body-strong",
673
+ className: cn(
674
+ "agg-event-title",
675
+ "min-w-0 flex-1 text-agg-base font-agg-bold leading-agg-6",
676
+ "truncate text-wrap wrap-break-word line-clamp-2",
677
+ classNames == null ? void 0 : classNames.title
468
678
  ),
469
- /* @__PURE__ */ jsx(
470
- Typography,
471
- {
472
- variant: "body-strong",
473
- className: cn(
474
- "agg-event-title",
475
- "min-w-0 text-agg-base font-agg-bold leading-agg-6 ",
476
- "truncate text-wrap wrap-break-word line-clamp-2",
477
- classNames == null ? void 0 : classNames.title
478
- ),
479
- children: resolvedTitle
480
- }
481
- )
482
- ]
483
- }
484
- ),
679
+ children: resolvedTitle
680
+ }
681
+ )
682
+ ] }),
485
683
  /* @__PURE__ */ jsxs(
486
684
  "div",
487
685
  {
488
686
  className: cn(
489
- "agg-outcomes flex flex-col gap-3 max-h-20 overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
687
+ "agg-outcomes flex max-h-[76px] flex-col gap-4 overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
490
688
  classNames == null ? void 0 : classNames.outcomes
491
689
  ),
492
690
  onScroll: handleOutcomesScroll,
493
691
  children: [
494
- resolvedMarketCount === 1 && resolvedOutcomeMarkets.length === 1 ? (() => {
495
- const market = resolvedOutcomeMarkets[0];
496
- return sortOutcomes(market.venueMarketOutcomes).map((outcome) => {
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;
514
- const arbitragePercent = arbitrageByOutcomeId == null ? void 0 : arbitrageByOutcomeId[outcome.id];
515
- const _priceGapPct = gapsByVenueMarketId.get(market.id);
516
- return /* @__PURE__ */ jsxs(
517
- "div",
518
- {
519
- className: cn(
520
- "agg-outcome-row",
521
- "flex flex-row gap-3 w-full items-center justify-between",
522
- classNames == null ? void 0 : classNames.outcomeRow
523
- ),
524
- children: [
525
- /* @__PURE__ */ jsx("div", { className: "agg-outcome-label-row flex min-w-0 flex-row items-center justify-start gap-2", children: /* @__PURE__ */ jsx(
526
- Typography,
527
- {
528
- variant: "body",
529
- className: "agg-outcome-label min-w-0 truncate text-agg-sm leading-agg-5 md:text-agg-base md:leading-agg-6",
530
- children: resolveOutcomeTitle(outcome)
531
- }
532
- ) }),
533
- /* @__PURE__ */ jsxs("div", { className: "agg-outcome-meta flex flex-row items-center justify-end gap-3", children: [
534
- renderArbitrage(arbitragePercent),
535
- renderOutcomePriceBadge(
536
- probability,
537
- displayVenue,
538
- shouldRenderMidpointSkeleton,
539
- market,
540
- outcome
541
- )
542
- ] })
543
- ]
544
- },
545
- outcome.id
546
- );
547
- });
548
- })() : sortMarketsByYesOddsDesc(resolvedOutcomeMarkets).map((market) => {
549
- var _a2, _b, _c;
550
- const yesOutcome = resolveYesOutcome(market);
551
- const displayOutcome = yesOutcome != null ? yesOutcome : (_b = market.venueMarketOutcomes) == null ? void 0 : _b.reduce(
552
- (acc, o) => o.price > acc.price ? o : acc,
553
- (_a2 = market.venueMarketOutcomes) == null ? void 0 : _a2[0]
554
- );
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;
570
- const arbitragePercent = arbitrageByOutcomeId == null ? void 0 : arbitrageByOutcomeId[market.id];
571
- const outcomeTitle = market.question;
572
- const _priceGapPct = gapsByVenueMarketId.get(market.id);
692
+ comparison.rows.map((row) => {
693
+ var _a2;
694
+ const arbitragePercent = (_a2 = arbitrageByOutcomeId == null ? void 0 : arbitrageByOutcomeId[row.outcome.id]) != null ? _a2 : arbitrageByOutcomeId == null ? void 0 : arbitrageByOutcomeId[row.market.id];
695
+ const priceGapPercent = gapsByVenueMarketId.get(row.market.id);
573
696
  return /* @__PURE__ */ jsxs(
574
697
  "div",
575
698
  {
576
699
  className: cn(
577
700
  "agg-outcome-row",
578
- "flex flex-row gap-3 w-full items-center justify-between",
701
+ "flex h-10 w-full flex-row items-center justify-between gap-3",
579
702
  classNames == null ? void 0 : classNames.outcomeRow
580
703
  ),
581
704
  children: [
582
- /* @__PURE__ */ jsx("div", { className: "agg-outcome-label-row flex min-w-0 flex-row items-center justify-start gap-2", children: /* @__PURE__ */ jsx(
705
+ /* @__PURE__ */ jsx("div", { className: "agg-outcome-label-row flex min-w-0 flex-1 flex-row items-center justify-start gap-2", children: /* @__PURE__ */ jsx(
583
706
  Typography,
584
707
  {
585
708
  variant: "body",
586
- className: "agg-outcome-label min-w-0 truncate text-agg-sm leading-agg-5 md:text-agg-base md:leading-agg-6",
587
- children: outcomeTitle
709
+ className: "agg-outcome-label min-w-0 truncate text-agg-xs leading-agg-5 md:text-agg-base md:leading-agg-6",
710
+ children: row.label
588
711
  }
589
712
  ) }),
590
- /* @__PURE__ */ jsxs("div", { className: "agg-outcome-meta flex flex-row items-center justify-end gap-3", children: [
713
+ /* @__PURE__ */ jsxs("div", { className: "agg-outcome-meta flex shrink-0 flex-row items-center justify-end gap-2", children: [
591
714
  renderArbitrage(arbitragePercent),
592
- renderOutcomePriceBadge(
593
- probability,
594
- bestVenue,
595
- shouldRenderMidpointSkeleton,
596
- market,
597
- displayOutcome
598
- )
715
+ renderPriceGapPill(priceGapPercent),
716
+ /* @__PURE__ */ jsx("div", { className: "agg-outcome-price-strip relative flex shrink-0 items-center justify-end", children: isAwaitingMidpoints ? renderPriceStripSkeleton(row.prices.length) : row.prices.map(
717
+ (price, priceIndex) => renderComparisonPriceBadge(row, price, priceIndex)
718
+ ) })
599
719
  ] })
600
720
  ]
601
721
  },
602
- `${market.id}`
722
+ row.id
603
723
  );
604
724
  }),
605
725
  shouldRenderLoadingOutcomeRow ? /* @__PURE__ */ jsxs("div", { className: "agg-outcome-row-loading flex w-full items-center justify-between gap-3", children: [
@@ -626,7 +746,7 @@ var EventListItemContent = ({
626
746
  {
627
747
  className: cn(
628
748
  "agg-event-card-footer",
629
- "flex items-center justify-between gap-2",
749
+ "flex items-center justify-between gap-5",
630
750
  "text-agg-muted-foreground",
631
751
  classNames == null ? void 0 : classNames.footer
632
752
  ),
@@ -635,41 +755,43 @@ var EventListItemContent = ({
635
755
  "div",
636
756
  {
637
757
  className: cn(
638
- "agg-event-meta flex items-center gap-1 text-agg-sm leading-agg-5 truncate"
758
+ "agg-event-meta flex min-w-0 flex-1 items-center gap-2 text-agg-sm leading-agg-5 truncate"
639
759
  ),
640
760
  children: [
641
- /* @__PURE__ */ jsx("span", { className: "truncate text-agg-muted-foreground", children: formatCountLabel(
642
- resolvedMarketCount,
643
- labels.eventItem.marketSingular,
644
- labels.eventItem.marketPlural
645
- ) }),
646
- /* @__PURE__ */ jsx("span", { className: "text-agg-muted-foreground", children: "\xD7" }),
647
- /* @__PURE__ */ jsx("span", { className: "truncate text-agg-muted-foreground", children: formatCountLabel(
648
- resolvedVenueCount,
649
- labels.eventItem.venueSingular,
650
- labels.eventItem.venuePlural
651
- ) }),
652
- visibleVenueLogos.length > 0 ? /* @__PURE__ */ jsx("span", { className: "agg-event-venues flex items-center gap-1 overflow-hidden", children: visibleVenueLogos.map((venue) => /* @__PURE__ */ jsx(
761
+ shouldShowMatchedVenueSummary ? /* @__PURE__ */ jsx("span", { className: "agg-event-matched-badge rounded-agg-full bg-agg-primary/10 px-2 py-[3px] text-agg-2xs font-agg-bold uppercase leading-agg-14 text-agg-primary", children: matchedCountLabel }) : null,
762
+ singleFooterVenue ? /* @__PURE__ */ jsxs("span", { className: "agg-event-single-venue flex min-w-0 items-center gap-1 overflow-hidden", children: [
763
+ /* @__PURE__ */ jsx(
764
+ VenueLogo,
765
+ {
766
+ venue: singleFooterVenue,
767
+ size: "small",
768
+ isMonochromatic: true,
769
+ className: "text-agg-muted-foreground! size-[14px]!"
770
+ }
771
+ ),
772
+ /* @__PURE__ */ jsx("span", { className: "truncate text-agg-muted-foreground", children: resolveVenueLabel(singleFooterVenue, void 0, labels) })
773
+ ] }) : null,
774
+ shouldShowMatchedVenueSummary && visibleFooterVenues.length > 0 ? /* @__PURE__ */ jsx("span", { className: "agg-event-venues flex items-center gap-1 overflow-hidden", children: visibleFooterVenues.map((venue) => /* @__PURE__ */ jsx(
653
775
  VenueLogo,
654
776
  {
655
777
  venue,
656
778
  size: "small",
657
779
  isMonochromatic: true,
658
- className: "text-agg-muted-foreground! size-[14px]!"
780
+ className: "text-agg-muted-foreground! size-3.5!"
659
781
  },
660
782
  venue
661
783
  )) }) : null
662
784
  ]
663
785
  }
664
786
  ),
665
- volumeLabel ? /* @__PURE__ */ jsx(
787
+ /* @__PURE__ */ jsx(
666
788
  Typography,
667
789
  {
668
790
  variant: "label",
669
- className: "agg-event-volume max-w-16 sm:max-w-20 min-w-12 sm:min-w-14 truncate whitespace-pre text-agg-sm text-agg-muted-foreground line-clamp-1",
791
+ className: "agg-event-volume min-w-fit shrink-0 truncate whitespace-pre text-agg-sm text-agg-muted-foreground line-clamp-1",
670
792
  children: volumeLabel
671
793
  }
672
- ) : null
794
+ )
673
795
  ]
674
796
  }
675
797
  )
@@ -723,6 +845,10 @@ var EventListItem = (props) => {
723
845
  return /* @__PURE__ */ jsx(EventListItemByEventId, __spreadValues({}, props));
724
846
  };
725
847
  EventListItem.displayName = "EventListItem";
848
+ var EventListItemV2 = (props) => {
849
+ return /* @__PURE__ */ jsx(EventListItem, __spreadValues({}, props));
850
+ };
851
+ EventListItemV2.displayName = "EventListItemV2";
726
852
 
727
853
  // src/events/market-details/orderbook-aggregation.ts
728
854
  import {
@@ -744,12 +870,12 @@ var fromScaled = (value, precision) => {
744
870
  var toPriceKey = (price) => {
745
871
  return String(toScaled(price, PRICE_PRECISION));
746
872
  };
747
- var normalizeOutcomeLabel2 = (value) => {
873
+ var normalizeOutcomeLabel = (value) => {
748
874
  if (typeof value !== "string") return "";
749
875
  return value.trim().toLowerCase().replace(/[_-]+/g, " ").replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ");
750
876
  };
751
877
  var toSemanticOutcomeLabel = (value) => {
752
- const normalizedValue = normalizeOutcomeLabel2(value);
878
+ const normalizedValue = normalizeOutcomeLabel(value);
753
879
  if (!normalizedValue) return "";
754
880
  if (POSITIVE_OUTCOME_KEYS.has(normalizedValue)) return "yes";
755
881
  if (NEGATIVE_OUTCOME_KEYS.has(normalizedValue)) return "no";
@@ -763,10 +889,10 @@ var getOutcomeLabelCandidates = (outcome) => {
763
889
  );
764
890
  };
765
891
  var matchesSelectedOutcomeLabel = (outcome, selectedOutcomeLabel) => {
766
- const normalizedSelectedLabel = normalizeOutcomeLabel2(selectedOutcomeLabel);
892
+ const normalizedSelectedLabel = normalizeOutcomeLabel(selectedOutcomeLabel);
767
893
  const semanticSelectedLabel = toSemanticOutcomeLabel(selectedOutcomeLabel);
768
894
  return getOutcomeLabelCandidates(outcome).some((candidate) => {
769
- const normalizedCandidate = normalizeOutcomeLabel2(candidate);
895
+ const normalizedCandidate = normalizeOutcomeLabel(candidate);
770
896
  if (!normalizedCandidate) return false;
771
897
  return normalizedCandidate === normalizedSelectedLabel || toSemanticOutcomeLabel(candidate) === semanticSelectedLabel;
772
898
  });
@@ -2358,7 +2484,7 @@ var EventListItemDetailsContent = ({
2358
2484
  () => resolvedEventTradingState.displayMarkets,
2359
2485
  [resolvedEventTradingState.displayMarkets]
2360
2486
  );
2361
- const sortedVenueMarkets = useMemo5(() => sortMarketsByYesOddsDesc(venueMarkets), [venueMarkets]);
2487
+ const sortedVenueMarkets = useMemo5(() => sortMarketsByVolumeDesc(venueMarkets), [venueMarkets]);
2362
2488
  const marketOptions = useMemo5(
2363
2489
  () => sortedVenueMarkets.map((vm) => ({
2364
2490
  value: vm.id,
@@ -3110,7 +3236,7 @@ import {
3110
3236
  mergeBestPricesPreferringLive as mergeBestPricesPreferringLive2,
3111
3237
  optimizedImageUrl as optimizedImageUrl3,
3112
3238
  resolveMarketTradingState,
3113
- useEventTradingContext as useEventTradingContext3,
3239
+ useEventTradingContext as useEventTradingContext2,
3114
3240
  useLabels as useLabels6,
3115
3241
  useLiveBestPrices as useLiveBestPrices2,
3116
3242
  useLiveOutcomePrices as useLiveOutcomePrices2,
@@ -3123,6 +3249,32 @@ import {
3123
3249
  } from "@agg-build/hooks";
3124
3250
  import { useEffect as useEffect4, useId, useMemo as useMemo6, useRef as useRef5, useState as useState4 } from "react";
3125
3251
 
3252
+ // src/events/shared/display-outcome-venue.ts
3253
+ var normalizeOutcomeLabel2 = (label) => {
3254
+ return typeof label === "string" ? label.trim().toLowerCase() : "";
3255
+ };
3256
+ var getDisplayOutcomeVenue = ({
3257
+ outcomeId,
3258
+ outcomeLabel,
3259
+ selection,
3260
+ bestMidpointVenue,
3261
+ bestVenueByOutcomeId,
3262
+ bestPriceVenuesByOutcomeId,
3263
+ fallbackVenue
3264
+ }) => {
3265
+ var _a;
3266
+ if (selection && outcomeId) {
3267
+ const sideVenues = bestPriceVenuesByOutcomeId == null ? void 0 : bestPriceVenuesByOutcomeId.get(outcomeId);
3268
+ if (selection === "buy" && (sideVenues == null ? void 0 : sideVenues.bestAskVenue)) return sideVenues.bestAskVenue;
3269
+ if (selection === "sell" && (sideVenues == null ? void 0 : sideVenues.bestBidVenue)) return sideVenues.bestBidVenue;
3270
+ }
3271
+ if (normalizeOutcomeLabel2(outcomeLabel) === "yes" && bestMidpointVenue) {
3272
+ return bestMidpointVenue;
3273
+ }
3274
+ const bestVenue = outcomeId ? bestVenueByOutcomeId == null ? void 0 : bestVenueByOutcomeId.get(outcomeId) : void 0;
3275
+ return (_a = bestVenue != null ? bestVenue : fallbackVenue) != null ? _a : void 0;
3276
+ };
3277
+
3126
3278
  // src/events/market-details/market-details-outcome-button.tsx
3127
3279
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
3128
3280
  var marketDetailsOutcomeButtonToneClasses = {
@@ -3219,7 +3371,7 @@ var MarketDetailsOutcomeButton = ({
3219
3371
  MarketDetailsOutcomeButton.displayName = "MarketDetailsOutcomeButton";
3220
3372
 
3221
3373
  // src/events/market-details/index.tsx
3222
- import { Fragment, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
3374
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
3223
3375
  var MarketDetailsUnavailableState = ({
3224
3376
  ariaLabel,
3225
3377
  classNames
@@ -3286,7 +3438,7 @@ var MarketDetailsContent = ({
3286
3438
  } = config;
3287
3439
  const isDarkTheme = theme === "dark";
3288
3440
  const labels = useLabels6();
3289
- const tradingContext = useEventTradingContext3();
3441
+ const tradingContext = useEventTradingContext2();
3290
3442
  const detailsContentId = useId();
3291
3443
  const tradeSide = (_a = tradingContext == null ? void 0 : tradingContext.tradeSide) != null ? _a : "buy";
3292
3444
  const wsLivePrices = useLiveOutcomePrices2(venueMarkets);
@@ -4024,7 +4176,7 @@ var MarketDetailsContent = ({
4024
4176
  ) : "translate-y-5 opacity-0"
4025
4177
  ),
4026
4178
  children: [
4027
- !isResolvedMarket ? /* @__PURE__ */ jsxs7(Fragment, { children: [
4179
+ !isResolvedMarket ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
4028
4180
  /* @__PURE__ */ jsx9("div", { className: cn("block", classNames == null ? void 0 : classNames.tabs), children: /* @__PURE__ */ jsx9(
4029
4181
  Tabs,
4030
4182
  {
@@ -4317,7 +4469,7 @@ var MarketDetailsList = ({
4317
4469
  }) => {
4318
4470
  var _a, _b;
4319
4471
  const labels = useLabels6();
4320
- const tradingContext = useEventTradingContext3();
4472
+ const tradingContext = useEventTradingContext2();
4321
4473
  const selectedMarketId = (_a = tradingContext == null ? void 0 : tradingContext.selectedMarketId) != null ? _a : null;
4322
4474
  const [expandedMarketId, setExpandedMarketId] = useState4(null);
4323
4475
  const [areResolvedMarketsVisible, setAreResolvedMarketsVisible] = useState4(false);
@@ -4345,7 +4497,7 @@ var MarketDetailsList = ({
4345
4497
  return resolveIsResolvedEvent(sourceMarkets, eventTradingState);
4346
4498
  }, [eventTradingState, sourceMarkets]);
4347
4499
  const groupedMarkets = useMemo6(() => {
4348
- const sortedMarkets = sortMarketsByYesOddsDesc(sourceMarkets);
4500
+ const sortedMarkets = sortMarketsByVolumeDesc(sourceMarkets);
4349
4501
  if (sortedMarkets.length === 0) {
4350
4502
  return {
4351
4503
  primary: [],
@@ -4534,8 +4686,10 @@ MarketDetailsList.displayName = "MarketDetailsList";
4534
4686
  // src/events/list/index.tsx
4535
4687
  import {
4536
4688
  MarketStatus as MarketStatus2,
4689
+ getVisibleVenueIdsByConfig,
4537
4690
  useAppConfig as useAppConfig2,
4538
4691
  useCategories,
4692
+ useCategoryChildren,
4539
4693
  useLabels as useLabels8,
4540
4694
  useSdkUiConfig as useSdkUiConfig4,
4541
4695
  useVenueEvents
@@ -4545,7 +4699,7 @@ import * as Dialog from "@radix-ui/react-dialog";
4545
4699
  import { useEffect as useEffect6, useMemo as useMemo8, useRef as useRef7, useState as useState6 } from "react";
4546
4700
 
4547
4701
  // src/events/list/event-list-tabs.tsx
4548
- import { useAppConfig, useLabels as useLabels7 } from "@agg-build/hooks";
4702
+ import { getVenueAvailabilityState, useAppConfig, useGeoBlock, useLabels as useLabels7 } from "@agg-build/hooks";
4549
4703
  import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo7, useRef as useRef6, useState as useState5 } from "react";
4550
4704
 
4551
4705
  // src/events/list/event-list.constants.ts
@@ -4615,6 +4769,9 @@ var getDefaultEventListTabs = (labels) => {
4615
4769
  // src/events/list/event-list-tabs.tsx
4616
4770
  import { jsx as jsx10 } from "react/jsx-runtime";
4617
4771
  var renderTabIcon = (tab, isActive) => {
4772
+ if (tab.iconName === "warning-filled") {
4773
+ return /* @__PURE__ */ jsx10(Icon, { name: "warning-filled", size: "small", color: "currentColor" });
4774
+ }
4618
4775
  if (tab.venueLogo) {
4619
4776
  return /* @__PURE__ */ jsx10(VenueLogo, { venue: tab.venueLogo, size: "small" });
4620
4777
  }
@@ -4631,15 +4788,26 @@ var renderTabIcon = (tab, isActive) => {
4631
4788
  var useEventListTabs = (tabs) => {
4632
4789
  const labels = useLabels7();
4633
4790
  const { disabledVenues } = useAppConfig();
4791
+ const { isLocationBlocked } = useGeoBlock();
4634
4792
  return useMemo7(() => {
4635
4793
  const baseTabs = tabs != null ? tabs : getDefaultEventListTabs(labels);
4636
- if (disabledVenues.length === 0) return baseTabs;
4637
- const disabled = new Set(disabledVenues);
4638
- return baseTabs.filter((tab) => {
4639
- if (!tab.venueLogo) return true;
4640
- return !disabled.has(tab.venueLogo);
4794
+ return baseTabs.flatMap((tab) => {
4795
+ if (!tab.venueLogo) return [tab];
4796
+ const availabilityState = getVenueAvailabilityState({
4797
+ venueId: tab.venueLogo,
4798
+ disabledVenues,
4799
+ isLocationBlocked
4800
+ });
4801
+ if (availabilityState === "hidden") return [];
4802
+ return [
4803
+ __spreadProps(__spreadValues({}, tab), {
4804
+ disabled: tab.disabled || availabilityState === "geoblocked",
4805
+ label: availabilityState === "geoblocked" ? `${tab.label} (${labels.trading.venueUnavailableInRegion})` : tab.label,
4806
+ iconName: availabilityState === "geoblocked" ? "warning-filled" : tab.iconName
4807
+ })
4808
+ ];
4641
4809
  });
4642
- }, [tabs, labels, disabledVenues]);
4810
+ }, [tabs, labels, disabledVenues, isLocationBlocked]);
4643
4811
  };
4644
4812
  var EventListTabs = ({
4645
4813
  tabs,
@@ -4651,9 +4819,10 @@ var EventListTabs = ({
4651
4819
  }) => {
4652
4820
  const resolvedTabs = useEventListTabs(tabs);
4653
4821
  useEffect5(() => {
4654
- if (resolvedTabs.length === 0) return;
4655
- if (resolvedTabs.some((tab) => tab.value === activeTab)) return;
4656
- onTabChange(resolvedTabs[0].value);
4822
+ const fallbackTab = resolvedTabs.find((tab) => !tab.disabled);
4823
+ if (!fallbackTab) return;
4824
+ if (resolvedTabs.some((tab) => tab.value === activeTab && !tab.disabled)) return;
4825
+ onTabChange(fallbackTab.value);
4657
4826
  }, [activeTab, onTabChange, resolvedTabs]);
4658
4827
  const items = useMemo7(() => {
4659
4828
  return resolvedTabs.map((tab) => {
@@ -4753,7 +4922,20 @@ var useEventListTabsHeaderOverflow = (recomputeOn, options) => {
4753
4922
  };
4754
4923
 
4755
4924
  // src/events/list/index.tsx
4756
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
4925
+ import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
4926
+ var subcategoryMenuRowClassName = cn(
4927
+ "flex min-h-11 w-full items-center justify-between rounded-[6px] px-3 py-3",
4928
+ "text-left text-agg-sm font-agg-normal leading-agg-5",
4929
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-agg-primary focus-visible:ring-offset-1 focus-visible:ring-offset-agg-secondary"
4930
+ );
4931
+ var subcategoryMenuIdleRowClassName = cn(
4932
+ subcategoryMenuRowClassName,
4933
+ "cursor-pointer text-agg-foreground hover:bg-agg-secondary-hover"
4934
+ );
4935
+ var subcategoryMenuSelectedRowClassName = cn(
4936
+ subcategoryMenuRowClassName,
4937
+ "cursor-pointer bg-agg-primary/10 text-agg-primary"
4938
+ );
4757
4939
  var SORT_ICON_BY_VALUE = {
4758
4940
  volume24hr: "sort-volume-24hr",
4759
4941
  topArbitrage: "sort-top-arbitrage",
@@ -4768,7 +4950,10 @@ var resolveSortQueryParams = (value) => {
4768
4950
  return { sortBy: "endDate", sortDir: "asc" };
4769
4951
  }
4770
4952
  if (value === "topArbitrage") {
4771
- return {};
4953
+ return {
4954
+ sortBy: "arbReturn",
4955
+ sortDir: "desc"
4956
+ };
4772
4957
  }
4773
4958
  return { sortBy: "volume24hr", sortDir: "desc" };
4774
4959
  };
@@ -4778,6 +4963,7 @@ var EventList = ({
4778
4963
  maxVisibleItems,
4779
4964
  search,
4780
4965
  categoryIds,
4966
+ onCategoryRootChange,
4781
4967
  onEventClick,
4782
4968
  onMarketClick,
4783
4969
  getMarketHref,
@@ -4795,9 +4981,7 @@ var EventList = ({
4795
4981
  const isDiscoveryFiltersEnabled = enableVenueEventDiscoveryFilters && !search;
4796
4982
  const resolvedTabs = useEventListTabs();
4797
4983
  const visibleVenues = useMemo8(
4798
- () => disabledVenues.length === 0 ? void 0 : VENUES.filter(
4799
- (v) => !disabledVenues.includes(v)
4800
- ),
4984
+ () => disabledVenues.length === 0 ? void 0 : getVisibleVenueIdsByConfig(VENUES, disabledVenues),
4801
4985
  [disabledVenues]
4802
4986
  );
4803
4987
  const [activeTabValue, setActiveTabValue] = useState6(
@@ -4805,8 +4989,8 @@ var EventList = ({
4805
4989
  );
4806
4990
  const [selectedSort, setSelectedSort] = useState6("volume24hr");
4807
4991
  const [isSubcategoriesModalOpen, setIsSubcategoriesModalOpen] = useState6(false);
4808
- const [selectedParentCategoryId, setSelectedParentCategoryId] = useState6(null);
4809
- const [selectedSubcategoryId, setSelectedSubcategoryId] = useState6(null);
4992
+ const [categoryPath, setCategoryPath] = useState6([]);
4993
+ const [collapsedCategoryIds, setCollapsedCategoryIds] = useState6(() => /* @__PURE__ */ new Set());
4810
4994
  const { headerRef, titleRef, shouldUseSelectOverflow } = useEventListTabsHeaderOverflow(resolvedTabs, { minTabsInlineWidthForSelect: 400, preferSelectOnOverflow: false });
4811
4995
  const sortItems = useMemo8(() => {
4812
4996
  return [
@@ -4818,9 +5002,7 @@ var EventList = ({
4818
5002
  {
4819
5003
  value: "topArbitrage",
4820
5004
  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
5005
+ icon: /* @__PURE__ */ jsx11(Icon, { name: SORT_ICON_BY_VALUE.topArbitrage, size: "small", color: "currentColor" })
4824
5006
  },
4825
5007
  {
4826
5008
  value: "volume",
@@ -4842,48 +5024,86 @@ var EventList = ({
4842
5024
  const baseCategoryId = (_c = categoryIds == null ? void 0 : categoryIds[0]) != null ? _c : null;
4843
5025
  useEffect6(() => {
4844
5026
  if (!isDiscoveryFiltersEnabled) return;
4845
- setSelectedParentCategoryId(baseCategoryId);
4846
- setSelectedSubcategoryId(null);
5027
+ if (!baseCategoryId) {
5028
+ setCategoryPath([]);
5029
+ setCollapsedCategoryIds(/* @__PURE__ */ new Set());
5030
+ return;
5031
+ }
5032
+ setCategoryPath([{ id: baseCategoryId, label: baseCategoryId, eventCount: 0 }]);
5033
+ setCollapsedCategoryIds(/* @__PURE__ */ new Set());
4847
5034
  }, [baseCategoryId, isDiscoveryFiltersEnabled]);
4848
5035
  const { categories: topLevelCategories } = useCategories({
4849
5036
  queryKeyScope: "event-list-top-categories",
4850
5037
  enabled: isDiscoveryFiltersEnabled,
4851
5038
  limit: 100
4852
5039
  });
4853
- const { categories: subcategories } = useCategories({
4854
- queryKeyScope: "event-list-subcategories",
4855
- enabled: isDiscoveryFiltersEnabled && Boolean(baseCategoryId),
4856
- parentId: baseCategoryId,
5040
+ const sortedTopLevelCategories = useMemo8(() => {
5041
+ return sortCategoriesForNavigation(topLevelCategories);
5042
+ }, [topLevelCategories]);
5043
+ const baseCategoryChildPrefetchIds = useMemo8(() => {
5044
+ return Array.from(
5045
+ /* @__PURE__ */ new Set([
5046
+ ...sortedTopLevelCategories.map((category) => category.id),
5047
+ ...categoryPath.map((category) => category.id)
5048
+ ])
5049
+ );
5050
+ }, [categoryPath, sortedTopLevelCategories]);
5051
+ const { childrenByParentId: baseChildrenByParentId } = useCategoryChildren({
5052
+ queryKeyScope: "event-list-category-children",
5053
+ enabled: isDiscoveryFiltersEnabled,
5054
+ parentIds: baseCategoryChildPrefetchIds,
4857
5055
  limit: 100
4858
5056
  });
4859
- const shouldRenderSubcategoryFilters = isDiscoveryFiltersEnabled && Boolean(baseCategoryId) && subcategories.length > 0;
4860
- console.log({
4861
- enableVenueEventDiscoveryFilters,
4862
- shouldRenderSubcategoryFilters,
4863
- isDiscoveryFiltersEnabled,
4864
- baseCategoryId,
4865
- subcategories
5057
+ const visibleChildPrefetchIds = useMemo8(() => {
5058
+ var _a2;
5059
+ const ids = /* @__PURE__ */ new Set();
5060
+ for (const expandedCategory of categoryPath) {
5061
+ for (const childCategory of (_a2 = baseChildrenByParentId.get(expandedCategory.id)) != null ? _a2 : []) {
5062
+ ids.add(childCategory.id);
5063
+ }
5064
+ }
5065
+ return Array.from(ids);
5066
+ }, [baseChildrenByParentId, categoryPath]);
5067
+ const { childrenByParentId: visibleChildrenByParentId } = useCategoryChildren({
5068
+ queryKeyScope: "event-list-category-children",
5069
+ enabled: isDiscoveryFiltersEnabled,
5070
+ parentIds: visibleChildPrefetchIds,
5071
+ limit: 100
5072
+ });
5073
+ const visibleGrandchildPrefetchIds = useMemo8(() => {
5074
+ var _a2;
5075
+ const ids = /* @__PURE__ */ new Set();
5076
+ for (const expandedCategory of categoryPath) {
5077
+ for (const childCategory of (_a2 = visibleChildrenByParentId.get(expandedCategory.id)) != null ? _a2 : []) {
5078
+ ids.add(childCategory.id);
5079
+ }
5080
+ }
5081
+ return Array.from(ids);
5082
+ }, [categoryPath, visibleChildrenByParentId]);
5083
+ const { childrenByParentId: visibleGrandchildrenByParentId } = useCategoryChildren({
5084
+ queryKeyScope: "event-list-category-children",
5085
+ enabled: isDiscoveryFiltersEnabled,
5086
+ parentIds: visibleGrandchildPrefetchIds,
5087
+ limit: 100
4866
5088
  });
5089
+ const childrenByParentId = useMemo8(() => {
5090
+ return new Map([
5091
+ ...baseChildrenByParentId,
5092
+ ...visibleChildrenByParentId,
5093
+ ...visibleGrandchildrenByParentId
5094
+ ]);
5095
+ }, [baseChildrenByParentId, visibleChildrenByParentId, visibleGrandchildrenByParentId]);
5096
+ const shouldRenderSubcategoryFilters = isDiscoveryFiltersEnabled && (sortedTopLevelCategories.length > 0 || categoryPath.length > 0);
4867
5097
  const totalTopLevelEventCount = useMemo8(() => {
4868
- return topLevelCategories.reduce((accumulator, category) => {
5098
+ return sortedTopLevelCategories.reduce((accumulator, category) => {
4869
5099
  var _a2;
4870
5100
  return accumulator + ((_a2 = category.eventCount) != null ? _a2 : 0);
4871
5101
  }, 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]);
5102
+ }, [sortedTopLevelCategories]);
4881
5103
  const resolvedCategoryIds = useMemo8(() => {
4882
5104
  if (!isDiscoveryFiltersEnabled) return categoryIds;
4883
- if (selectedSubcategoryId) return [selectedSubcategoryId];
4884
- if (selectedParentCategoryId) return [selectedParentCategoryId];
4885
- return categoryIds;
4886
- }, [categoryIds, isDiscoveryFiltersEnabled, selectedParentCategoryId, selectedSubcategoryId]);
5105
+ return resolveCategoryIdsFromPath(categoryPath, void 0);
5106
+ }, [categoryIds, categoryPath, isDiscoveryFiltersEnabled]);
4887
5107
  const sortQueryParams = useMemo8(() => {
4888
5108
  return resolveSortQueryParams(selectedSort);
4889
5109
  }, [selectedSort]);
@@ -4979,58 +5199,121 @@ var EventList = ({
4979
5199
  const gridClassName = cn(
4980
5200
  "grid grid-cols-[repeat(auto-fill,minmax(240px,1fr))] md:grid-cols-[repeat(auto-fill,minmax(360px,1fr))] gap-4"
4981
5201
  );
4982
- const isAllSubcategoriesSelected = shouldRenderSubcategoryFilters && !selectedSubcategoryId;
5202
+ const isDrilledIn = categoryPath.length > 0;
4983
5203
  const handleSelectAllCategories = () => {
4984
- setSelectedParentCategoryId(baseCategoryId);
4985
- setSelectedSubcategoryId(null);
5204
+ setCategoryPath([]);
5205
+ setCollapsedCategoryIds(/* @__PURE__ */ new Set());
5206
+ onCategoryRootChange == null ? void 0 : onCategoryRootChange(void 0);
4986
5207
  setIsSubcategoriesModalOpen(false);
4987
5208
  };
4988
- const handleSelectSubcategory = (subcategoryId) => {
4989
- setSelectedSubcategoryId(subcategoryId);
4990
- setIsSubcategoriesModalOpen(false);
5209
+ const handleToggleSubcategory = ({
5210
+ entry,
5211
+ depth,
5212
+ hasKnownChildren,
5213
+ isExpanded,
5214
+ isSelected
5215
+ }) => {
5216
+ var _a2;
5217
+ setCategoryPath((prev) => [...prev.slice(0, depth), entry]);
5218
+ setCollapsedCategoryIds((prev) => {
5219
+ const next = new Set(prev);
5220
+ if (hasKnownChildren && isExpanded && isSelected) {
5221
+ next.add(entry.id);
5222
+ return next;
5223
+ }
5224
+ next.delete(entry.id);
5225
+ return next;
5226
+ });
5227
+ onCategoryRootChange == null ? void 0 : onCategoryRootChange(depth === 0 ? entry.id : (_a2 = categoryPath[0]) == null ? void 0 : _a2.id);
5228
+ };
5229
+ const renderSubcategoryTreeRow = ({
5230
+ entry,
5231
+ isExpanded,
5232
+ isSelected,
5233
+ onClick
5234
+ }) => {
5235
+ var _a2, _b2;
5236
+ const hasKnownChildren = ((_b2 = (_a2 = childrenByParentId.get(entry.id)) == null ? void 0 : _a2.length) != null ? _b2 : 0) > 0;
5237
+ return /* @__PURE__ */ jsxs8(
5238
+ "button",
5239
+ {
5240
+ type: "button",
5241
+ "aria-current": isSelected ? "true" : void 0,
5242
+ className: isSelected ? subcategoryMenuSelectedRowClassName : subcategoryMenuIdleRowClassName,
5243
+ onClick,
5244
+ children: [
5245
+ /* @__PURE__ */ jsx11("span", { className: "min-w-0 truncate first-letter:uppercase", children: entry.label }),
5246
+ hasKnownChildren ? /* @__PURE__ */ jsx11(
5247
+ Icon,
5248
+ {
5249
+ name: isExpanded ? "chevron-up" : "chevron-down",
5250
+ size: "small",
5251
+ color: "currentColor",
5252
+ className: "shrink-0 text-agg-muted-foreground"
5253
+ }
5254
+ ) : /* @__PURE__ */ jsx11("span", { className: "shrink-0 text-agg-muted-foreground", children: entry.eventCount })
5255
+ ]
5256
+ },
5257
+ entry.id
5258
+ );
4991
5259
  };
4992
- const subcategoriesListContent = /* @__PURE__ */ jsxs8(Fragment2, { children: [
5260
+ const renderSubcategoryBranch = (category, depth) => {
5261
+ var _a2, _b2, _c2, _d, _e;
5262
+ const label = (_a2 = category.displayName) != null ? _a2 : category.name;
5263
+ const entry = {
5264
+ id: category.id,
5265
+ label,
5266
+ eventCount: (_b2 = category.eventCount) != null ? _b2 : 0
5267
+ };
5268
+ const childCategories = (_c2 = childrenByParentId.get(category.id)) != null ? _c2 : [];
5269
+ const hasKnownChildren = childCategories.length > 0;
5270
+ const isExpanded = ((_d = categoryPath[depth]) == null ? void 0 : _d.id) === category.id && !collapsedCategoryIds.has(category.id);
5271
+ const isSelected = ((_e = categoryPath[depth]) == null ? void 0 : _e.id) === category.id && categoryPath.length === depth + 1;
5272
+ return /* @__PURE__ */ jsxs8("div", { className: "flex w-full flex-col gap-1", children: [
5273
+ renderSubcategoryTreeRow({
5274
+ entry,
5275
+ isExpanded,
5276
+ isSelected,
5277
+ onClick: () => handleToggleSubcategory({
5278
+ entry,
5279
+ depth,
5280
+ hasKnownChildren,
5281
+ isExpanded,
5282
+ isSelected
5283
+ })
5284
+ }),
5285
+ isExpanded ? /* @__PURE__ */ jsx11("div", { className: "flex w-full flex-col gap-1 pl-4", children: childCategories.map(
5286
+ (childCategory) => renderSubcategoryBranch(childCategory, depth + 1)
5287
+ ) }) : null
5288
+ ] }, category.id);
5289
+ };
5290
+ const subcategoriesListContent = /* @__PURE__ */ jsxs8(Fragment3, { children: [
4993
5291
  /* @__PURE__ */ jsxs8(
4994
5292
  "button",
4995
5293
  {
4996
5294
  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
- ),
5295
+ "aria-current": !isDrilledIn ? "true" : void 0,
5296
+ className: !isDrilledIn ? subcategoryMenuSelectedRowClassName : subcategoryMenuIdleRowClassName,
5001
5297
  onClick: handleSelectAllCategories,
5002
5298
  children: [
5003
- /* @__PURE__ */ jsx11("span", { children: labels.eventList.subcategoriesAll }),
5004
- /* @__PURE__ */ jsx11("span", { className: "text-agg-muted-foreground", children: selectedParentEventCount })
5299
+ /* @__PURE__ */ jsx11("span", { className: "min-w-0 truncate", children: labels.eventList.subcategoriesAll }),
5300
+ /* @__PURE__ */ jsx11("span", { className: "text-agg-muted-foreground", children: totalTopLevelEventCount })
5005
5301
  ]
5006
5302
  }
5007
5303
  ),
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
- })
5304
+ sortedTopLevelCategories.map((category) => renderSubcategoryBranch(category, 0))
5029
5305
  ] });
5030
5306
  if (shouldRenderLoadingState) {
5031
- return /* @__PURE__ */ jsx11(Skeleton, { view: "event-list", ariaLabel: labels.eventList.loading(title) });
5307
+ return /* @__PURE__ */ jsx11(
5308
+ Skeleton,
5309
+ {
5310
+ view: "event-list",
5311
+ ariaLabel: labels.eventList.loading(title),
5312
+ withSidebar: isDiscoveryFiltersEnabled
5313
+ }
5314
+ );
5032
5315
  }
5033
- return /* @__PURE__ */ jsxs8("section", { className: "agg-event-list flex w-full flex-col gap-5", children: [
5316
+ return /* @__PURE__ */ jsxs8("section", { className: "agg-event-list flex w-full flex-col gap-2 md:gap-5 t", children: [
5034
5317
  /* @__PURE__ */ jsxs8(
5035
5318
  "header",
5036
5319
  {
@@ -5060,18 +5343,19 @@ var EventList = ({
5060
5343
  Select,
5061
5344
  {
5062
5345
  ariaLabel: labels.eventList.sortByLabel,
5063
- className: "min-w-[160px] w-auto! shrink-0 min-h-10.5",
5346
+ className: "min-w-[200px] w-auto! shrink-0 min-h-10.5",
5064
5347
  value: selectedSort,
5065
5348
  onChange: setSelectedSort,
5066
5349
  items: sortItems,
5067
- contentClassName: "py-2"
5350
+ contentClassName: "py-2",
5351
+ triggerClassName: "rounded-agg-lg!"
5068
5352
  }
5069
5353
  )
5070
5354
  ] })
5071
5355
  ]
5072
5356
  }
5073
5357
  ),
5074
- /* @__PURE__ */ jsxs8("div", { className: "flex w-full gap-2 md:hidden", children: [
5358
+ /* @__PURE__ */ jsxs8("div", { className: "flex w-full gap-2 md:hidden mb-3", children: [
5075
5359
  /* @__PURE__ */ jsx11(
5076
5360
  EventListTabs,
5077
5361
  {
@@ -5115,6 +5399,7 @@ var EventList = ({
5115
5399
  {
5116
5400
  className: cn(
5117
5401
  "agg-event-list-grid",
5402
+ "grid grid-cols-[repeat(auto-fill,minmax(240px,1fr))] md:grid-cols-[repeat(auto-fill,minmax(360px,1fr))] gap-4",
5118
5403
  "w-full",
5119
5404
  isPlaceholderData && "opacity-60",
5120
5405
  gridClassName
@@ -5125,7 +5410,7 @@ var EventList = ({
5125
5410
  {
5126
5411
  event,
5127
5412
  classNames: {
5128
- root: "agg-event-list-item w-full min-w-0 max-w-none"
5413
+ root: "agg-event-list-item w-full min-w-0! max-w-none justify-between!"
5129
5414
  },
5130
5415
  onEventClick,
5131
5416
  onMarketClick,
@@ -5140,7 +5425,7 @@ var EventList = ({
5140
5425
  {
5141
5426
  isLoading: true,
5142
5427
  classNames: {
5143
- root: "agg-event-list-item w-full min-w-0 max-w-none"
5428
+ root: "agg-event-list-item w-full min-w-0! max-w-none justify-between!"
5144
5429
  }
5145
5430
  },
5146
5431
  `loading-${index}`
@@ -5188,6 +5473,7 @@ EventList.displayName = "EventList";
5188
5473
  export {
5189
5474
  isErrorWithStatus,
5190
5475
  EventListItem,
5476
+ EventListItemV2,
5191
5477
  collectEligibleVenueOutcomes,
5192
5478
  collectEligibleVenueOutcomeIds,
5193
5479
  mergeVenueOutcomeOrderbooks,