@agg-build/ui 1.2.12 → 2.0.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-U55T5BPE.mjs → chunk-2UKDQ7WP.mjs} +44 -13
  3. package/dist/{chunk-X3KCFWXN.mjs → chunk-2ZS3BPSF.mjs} +1433 -1349
  4. package/dist/{chunk-IBOE7DRY.mjs → chunk-4CM4F4S6.mjs} +26 -27
  5. package/dist/{chunk-YSW4ULL5.mjs → chunk-HH7L3KLS.mjs} +1 -1
  6. package/dist/{chunk-3JXBOU24.mjs → chunk-R3U6YXSQ.mjs} +146 -81
  7. package/dist/{chunk-J6WELNCX.mjs → chunk-RF2EPYLN.mjs} +572 -181
  8. package/dist/{chunk-4WBQTUPW.mjs → chunk-RWOF44TC.mjs} +606 -324
  9. package/dist/events.js +2081 -1727
  10. package/dist/events.mjs +5 -3
  11. package/dist/index.js +4535 -3695
  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 +3945 -3123
  16. package/dist/pages.mjs +6 -6
  17. package/dist/primitives.js +1344 -1251
  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 +17 -2
  32. package/dist/types/events/list/event-list.utils.d.ts +17 -2
  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-4CM4F4S6.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,22 @@ 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,
72
- sortMarketsByYesOddsDesc,
71
+ sortCategoriesForNavigation,
73
72
  sortOutcomes,
74
73
  splitEventsByLifecycle
75
- } from "./chunk-X3KCFWXN.mjs";
74
+ } from "./chunk-2ZS3BPSF.mjs";
76
75
 
77
76
  // src/events/item/index.tsx
78
77
  import {
79
- computePriceGaps,
80
78
  optimizedImageUrl,
81
79
  sortVenues,
82
- useEventTradingContext as useEventTradingContext2,
83
80
  useLabels,
84
81
  useMidpoints,
85
82
  useSdkUiConfig,
@@ -99,34 +96,155 @@ var isErrorWithStatus = (error, status) => {
99
96
  return getErrorStatus(error) === status;
100
97
  };
101
98
 
102
- // src/events/shared/display-outcome-venue.ts
103
- var normalizeOutcomeLabel = (label) => {
104
- return typeof label === "string" ? label.trim().toLowerCase() : "";
99
+ // src/events/item/event-list-item-v2.utils.ts
100
+ var isNonEmptyString = (value) => {
101
+ return typeof value === "string" && value.trim().length > 0;
105
102
  };
106
- var getDisplayOutcomeVenue = ({
107
- outcomeId,
108
- outcomeLabel,
109
- selection,
110
- bestMidpointVenue,
111
- bestVenueByOutcomeId,
112
- bestPriceVenuesByOutcomeId,
113
- fallbackVenue
114
- }) => {
103
+ var getOutcomeSortPrice = (outcome) => {
115
104
  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;
105
+ return (_a = normalizeProbability(outcome.price)) != null ? _a : -1;
106
+ };
107
+ var MAX_VISIBLE_OUTCOME_PRICE_PILLS = 3;
108
+ var resolveDisplayOutcome = (market) => {
109
+ var _a;
110
+ return (_a = resolveYesOutcome(market)) != null ? _a : [...market.venueMarketOutcomes].sort((left, right) => {
111
+ return getOutcomeSortPrice(right) - getOutcomeSortPrice(left);
112
+ })[0];
113
+ };
114
+ var resolveOutcomeRows = ({
115
+ venueMarkets,
116
+ marketCount
117
+ }) => {
118
+ if (venueMarkets.length === 0) return [];
119
+ if (marketCount === 1 && venueMarkets.length === 1) {
120
+ const [market] = venueMarkets;
121
+ return sortOutcomes(market.venueMarketOutcomes).map((outcome) => ({
122
+ id: outcome.id,
123
+ label: resolveOutcomeTitle(outcome),
124
+ market,
125
+ outcome
126
+ }));
120
127
  }
121
- if (normalizeOutcomeLabel(outcomeLabel) === "yes" && bestMidpointVenue) {
122
- return bestMidpointVenue;
128
+ return venueMarkets.map((market) => {
129
+ const outcome = resolveDisplayOutcome(market);
130
+ if (!outcome) return void 0;
131
+ return {
132
+ id: market.id,
133
+ label: isNonEmptyString(market.question) ? market.question : resolveOutcomeTitle(outcome),
134
+ market,
135
+ outcome
136
+ };
137
+ }).filter((row) => row != null);
138
+ };
139
+ var collectOutcomePrices = (market, outcome, priceByOutcomeId) => {
140
+ var _a, _b, _c;
141
+ const prices = [];
142
+ const seenOutcomeKeys = /* @__PURE__ */ new Set();
143
+ const addPrice = (priceMarket, priceOutcome) => {
144
+ var _a2;
145
+ if (!priceMarket || !priceOutcome) return;
146
+ const resolvedPrice = (_a2 = priceByOutcomeId == null ? void 0 : priceByOutcomeId.get(priceOutcome.id)) != null ? _a2 : priceOutcome.price;
147
+ const normalizedPrice = normalizeProbability(resolvedPrice);
148
+ if (normalizedPrice == null) return;
149
+ const key = `${priceMarket.id}:${priceOutcome.id}`;
150
+ if (seenOutcomeKeys.has(key)) return;
151
+ seenOutcomeKeys.add(key);
152
+ prices.push({
153
+ venue: priceMarket.venue,
154
+ market: priceMarket,
155
+ outcome: priceOutcome,
156
+ price: normalizedPrice,
157
+ isBest: false
158
+ });
159
+ };
160
+ addPrice(market, outcome);
161
+ for (const matchedOutcomeRef of (_a = outcome.matchedVenueMarketOutcomes) != null ? _a : []) {
162
+ const matchedMarket = (_b = market.matchedVenueMarkets) == null ? void 0 : _b.find((candidate) => {
163
+ return candidate.id === matchedOutcomeRef.venueMarketId;
164
+ });
165
+ const matchedOutcome = (_c = matchedMarket == null ? void 0 : matchedMarket.venueMarketOutcomes) == null ? void 0 : _c.find((candidate) => {
166
+ return candidate.id === matchedOutcomeRef.venueMarketOutcomeId;
167
+ });
168
+ addPrice(matchedMarket, matchedOutcome);
123
169
  }
124
- const bestVenue = outcomeId ? bestVenueByOutcomeId == null ? void 0 : bestVenueByOutcomeId.get(outcomeId) : void 0;
125
- return (_a = bestVenue != null ? bestVenue : fallbackVenue) != null ? _a : void 0;
170
+ if (prices.length === 0) return [];
171
+ const bestPriceByVenue = /* @__PURE__ */ new Map();
172
+ for (const price of prices) {
173
+ const existing = bestPriceByVenue.get(price.venue);
174
+ if (!existing || price.price < existing.price) {
175
+ bestPriceByVenue.set(price.venue, price);
176
+ }
177
+ }
178
+ const dedupedPrices = Array.from(bestPriceByVenue.values());
179
+ const sortedPricesByBestOdds = [...dedupedPrices].sort((left, right) => {
180
+ return left.price - right.price;
181
+ });
182
+ const bestPrice = sortedPricesByBestOdds[0];
183
+ if (!bestPrice) return [];
184
+ const visiblePrices = [
185
+ sortedPricesByBestOdds.at(-1),
186
+ sortedPricesByBestOdds[1],
187
+ bestPrice
188
+ ].reduce((accumulator, price) => {
189
+ if (!price) return accumulator;
190
+ const isDuplicate = accumulator.some((candidate) => {
191
+ return candidate.market.id === price.market.id && candidate.outcome.id === price.outcome.id;
192
+ });
193
+ if (isDuplicate) return accumulator;
194
+ accumulator.push(price);
195
+ return accumulator;
196
+ }, []);
197
+ return visiblePrices.slice(0, MAX_VISIBLE_OUTCOME_PRICE_PILLS).map((price) => __spreadProps(__spreadValues({}, price), {
198
+ isBest: price.market.id === bestPrice.market.id && price.outcome.id === bestPrice.outcome.id
199
+ }));
200
+ };
201
+ var collectMatchedVenues = (rows) => {
202
+ const venues = /* @__PURE__ */ new Set();
203
+ for (const row of rows) {
204
+ if (row.prices.length < 2) continue;
205
+ for (const price of row.prices) {
206
+ venues.add(price.venue);
207
+ }
208
+ }
209
+ return Array.from(venues);
210
+ };
211
+ var computePriceGapsFromComparisonRows = (rows) => {
212
+ const gapsByVenueMarketId = /* @__PURE__ */ new Map();
213
+ for (const row of rows) {
214
+ if (row.prices.length < 2) continue;
215
+ const prices = row.prices.map((price) => price.price);
216
+ const minPrice = Math.min(...prices);
217
+ const maxPrice = Math.max(...prices);
218
+ if (minPrice <= 0 || maxPrice <= minPrice) continue;
219
+ gapsByVenueMarketId.set(row.market.id, (maxPrice - minPrice) * 100);
220
+ }
221
+ return gapsByVenueMarketId;
222
+ };
223
+ var normalizeEventListItemV2Comparison = ({
224
+ venueMarkets,
225
+ marketCount,
226
+ priceByOutcomeId
227
+ }) => {
228
+ const outcomeRows = resolveOutcomeRows({ venueMarkets, marketCount });
229
+ const rows = outcomeRows.map((row) => {
230
+ const prices = collectOutcomePrices(row.market, row.outcome, priceByOutcomeId);
231
+ return __spreadProps(__spreadValues({}, row), {
232
+ prices
233
+ });
234
+ });
235
+ const matchedVenues = collectMatchedVenues(rows);
236
+ return {
237
+ rows,
238
+ matchedVenues,
239
+ hasVenueCompetition: matchedVenues.length > 1
240
+ };
126
241
  };
127
242
 
243
+ // src/events/item/event-list-item.constants.ts
244
+ var baseCardClassName = "gap-3 overflow-hidden p-4 w-full";
245
+
128
246
  // src/events/item/index.tsx
129
- import { jsx, jsxs } from "react/jsx-runtime";
247
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
130
248
  var EventListItemLoadingState = ({
131
249
  classNames,
132
250
  ariaLabel
@@ -188,6 +306,25 @@ var EventListItemNotFoundState = ({
188
306
  var OUTCOMES_SCROLL_LOAD_THRESHOLD_PX = 16;
189
307
  var MARKET_ID_QUERY_PARAM = "marketId";
190
308
  var OUTCOME_ID_QUERY_PARAM = "outcomeId";
309
+ var buildOutcomeMidpointsByOutcomeId = (midpointRows) => {
310
+ const outcomeMidpointsByOutcomeId = /* @__PURE__ */ new Map();
311
+ const addOutcomeMidpoints = (value) => {
312
+ var _a, _b;
313
+ if (!value || typeof value !== "object") return;
314
+ const row = value;
315
+ for (const outcome of (_a = row.outcomes) != null ? _a : []) {
316
+ if (outcome.midpoint == null) continue;
317
+ outcomeMidpointsByOutcomeId.set(outcome.venueMarketOutcomeId, outcome.midpoint);
318
+ }
319
+ for (const matchedRow of (_b = row.matched) != null ? _b : []) {
320
+ addOutcomeMidpoints(matchedRow);
321
+ }
322
+ };
323
+ for (const row of midpointRows) {
324
+ addOutcomeMidpoints(row);
325
+ }
326
+ return outcomeMidpointsByOutcomeId;
327
+ };
191
328
  var resolveMarketHrefFromEventHref = (eventHref, marketId, outcomeId) => {
192
329
  if (!eventHref) return void 0;
193
330
  if (typeof window === "undefined") return void 0;
@@ -214,8 +351,6 @@ var EventListItemContent = ({
214
351
  var _a;
215
352
  const config = useSdkUiConfig();
216
353
  const labels = useLabels();
217
- const tradingContext = useEventTradingContext2();
218
- const tradeSide = (_a = tradingContext == null ? void 0 : tradingContext.tradeSide) != null ? _a : "buy";
219
354
  const allVenueMarkets = useMemo(() => event.venueMarkets, [event.venueMarkets]);
220
355
  const resolvedTitle = event.title;
221
356
  const resolvedImage = event.image;
@@ -262,32 +397,42 @@ var EventListItemContent = ({
262
397
  }
263
398
  return [...new Set(ids)];
264
399
  }, [resolvedOutcomeMarkets]);
265
- const {
266
- midpointsByVenueMarketId,
267
- isLoading: isLoadingMidpoints,
268
- isFetching: isFetchingMidpoints
269
- } = useVenueMarketMidpoints({
400
+ const { midpointRows, isLoading: isVenueMarketMidpointsLoading } = useVenueMarketMidpoints({
270
401
  venueMarketIds: midpointVenueMarketIds,
271
402
  enabled: midpointVenueMarketIds.length > 0
272
403
  });
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;
404
+ const { prices: displayMidpointsByOutcomeId, isLoading: isOutcomeMidpointsLoading } = useMidpoints(resolvedOutcomeMarkets);
405
+ const isAwaitingMidpoints = isOutcomeMidpointsLoading || midpointVenueMarketIds.length > 0 && isVenueMarketMidpointsLoading;
406
+ const displayPriceByOutcomeId = useMemo(() => {
407
+ const priceByOutcomeId = new Map(displayMidpointsByOutcomeId);
408
+ for (const [outcomeId, price] of buildOutcomeMidpointsByOutcomeId(midpointRows)) {
409
+ priceByOutcomeId.set(outcomeId, price);
410
+ }
411
+ return priceByOutcomeId;
412
+ }, [displayMidpointsByOutcomeId, midpointRows]);
413
+ const comparison = useMemo(() => {
414
+ return normalizeEventListItemV2Comparison({
415
+ venueMarkets: resolvedOutcomeMarkets,
416
+ marketCount: resolvedMarketCount,
417
+ priceByOutcomeId: displayPriceByOutcomeId
418
+ });
419
+ }, [displayPriceByOutcomeId, resolvedMarketCount, resolvedOutcomeMarkets]);
420
+ const gapsByVenueMarketId = useMemo(() => {
421
+ return computePriceGapsFromComparisonRows(comparison.rows);
422
+ }, [comparison.rows]);
288
423
  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}` : "";
424
+ const resolvedVolume = (_a = resolveDisplayVolume(event.volume, allVenueMarkets)) != null ? _a : 0;
425
+ const volumeLabel = `${config.formatting.formatCompactCurrency(resolvedVolume)} ${labels.eventItem.volumeSuffix}`;
426
+ const orderedFooterVenues = useMemo(() => {
427
+ const venues = visibleVenueLogos.length > 0 ? visibleVenueLogos : comparison.matchedVenues.length > 0 ? comparison.matchedVenues : event.venue ? [event.venue] : [];
428
+ return Array.from(new Set(venues));
429
+ }, [comparison.matchedVenues, event.venue, visibleVenueLogos]);
430
+ const shouldShowMatchedVenueSummary = resolvedVenueCount > 1 || orderedFooterVenues.length > 1;
431
+ const visibleFooterVenues = shouldShowMatchedVenueSummary ? orderedFooterVenues : orderedFooterVenues.slice(0, 1);
432
+ const singleFooterVenue = shouldShowMatchedVenueSummary ? void 0 : visibleFooterVenues[0];
433
+ const matchedCountLabel = labels.eventItem.matchedCount(
434
+ Math.max(resolvedVenueCount, visibleFooterVenues.length)
435
+ );
291
436
  const shouldUseNativeLinkNavigation = (eventToHandle) => {
292
437
  return eventToHandle.metaKey || eventToHandle.ctrlKey || eventToHandle.shiftKey || eventToHandle.altKey || eventToHandle.button === 1;
293
438
  };
@@ -378,62 +523,116 @@ var EventListItemContent = ({
378
523
  )
379
524
  ] });
380
525
  };
381
- const _renderPriceGapPill = (value) => {
526
+ const renderPriceStripSkeleton = (count) => {
527
+ const safeCount = Math.max(1, Math.min(count || 1, 3));
528
+ const collapsedCount = safeCount - 1;
529
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
530
+ Array.from({ length: collapsedCount }).map((_, index) => /* @__PURE__ */ jsx(
531
+ "span",
532
+ {
533
+ "aria-hidden": "true",
534
+ className: cn(
535
+ "agg-outcome-price-loading agg-outcome-price-loading-collapsed",
536
+ "h-[30px] w-[30px] shrink-0 rounded-agg-full bg-agg-separator animate-pulse",
537
+ index > 0 && "-ml-3"
538
+ )
539
+ },
540
+ `agg-outcome-price-loading-collapsed-${index}`
541
+ )),
542
+ /* @__PURE__ */ jsx(
543
+ "span",
544
+ {
545
+ "aria-hidden": "true",
546
+ className: cn(
547
+ "agg-outcome-price-loading agg-outcome-price-loading-best",
548
+ "ml-1.5 h-[30px] w-[68px] shrink-0 rounded-agg-full bg-agg-separator animate-pulse"
549
+ )
550
+ }
551
+ )
552
+ ] });
553
+ };
554
+ const renderPriceGapPill = (value) => {
555
+ if (!config.features.enablePriceGap) return null;
556
+ if (isAwaitingMidpoints) return null;
382
557
  const formattedPriceGap = formatPriceGapPercent(value);
383
558
  if (!formattedPriceGap) return null;
384
559
  return /* @__PURE__ */ jsxs(
385
- "div",
560
+ "span",
386
561
  {
387
562
  className: cn(
388
563
  "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"
564
+ "inline-flex max-w-[52px] shrink-0 items-center gap-1 overflow-hidden whitespace-nowrap",
565
+ "text-agg-2xs font-agg-bold leading-agg-14 text-agg-success",
566
+ "opacity-100 transition-all duration-200 ease-out",
567
+ "group-hover/agg-event-card:mr-0 group-hover/agg-event-card:max-w-0 group-hover/agg-event-card:opacity-0"
391
568
  ),
569
+ title: labels.eventItem.priceGap,
570
+ "aria-label": `${formattedPriceGap} ${labels.eventItem.priceGap}`,
392
571
  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 })
572
+ /* @__PURE__ */ jsx(
573
+ "i",
574
+ {
575
+ "aria-hidden": "true",
576
+ className: "fi-rr-arrow-down inline-flex size-3! shrink-0 items-center justify-center text-agg-xs text-agg-success"
577
+ }
578
+ ),
579
+ /* @__PURE__ */ jsx("span", { children: formattedPriceGap })
395
580
  ]
396
581
  }
397
582
  );
398
583
  };
399
- const renderOutcomePriceBadge = (probability, venue, shouldRenderLoadingSkeleton, market, outcome) => {
584
+ const renderComparisonPriceBadge = (row, price, priceIndex) => {
400
585
  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);
586
+ const marketHref = (_a2 = getMarketHref == null ? void 0 : getMarketHref(event, row.market, row.outcome)) != null ? _a2 : resolveMarketHrefFromEventHref(href, row.market.id, row.outcome.id);
414
587
  const isInteractive = Boolean(onMarketClick || marketHref);
588
+ const hasVenueCompetition = row.prices.length > 1;
589
+ const isHighlightedBestPrice = hasVenueCompetition && price.isBest;
590
+ const shouldCollapsePriceText = hasVenueCompetition && !isHighlightedBestPrice;
415
591
  return /* @__PURE__ */ jsx(
416
592
  Badge,
417
593
  {
418
- text: formatMarketProbabilityPercent(probability, config.formatting.formatPercent),
419
- prefix: /* @__PURE__ */ jsx(VenueLogo, { venue, size: "small" }),
594
+ text: formatMarketProbabilityPercent(price.price, config.formatting.formatPercent),
595
+ prefix: /* @__PURE__ */ jsx(
596
+ VenueLogo,
597
+ {
598
+ venue: price.venue,
599
+ size: "small",
600
+ isMonochromatic: !isHighlightedBestPrice,
601
+ className: cn(!isHighlightedBestPrice && "text-agg-muted-foreground!")
602
+ }
603
+ ),
420
604
  size: "small",
421
605
  classNames: {
422
606
  root: cn(
423
607
  "agg-outcome-price",
424
- "h-8 min-w-25 justify-center px-4 text-agg-base leading-agg-6",
608
+ "h-[30px] justify-center overflow-hidden px-0 text-agg-sm leading-agg-5",
609
+ "shrink-0 p-0! transition-all duration-300 ease-out",
610
+ isHighlightedBestPrice ? "agg-outcome-price-best ml-2 w-[68px] min-w-[68px] shadow-none" : cn(
611
+ "bg-agg-secondary-hover hover:bg-agg-tertiary",
612
+ 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]",
613
+ hasVenueCompetition && priceIndex > 0 && "-ml-3 group-hover/agg-event-card:ml-2"
614
+ ),
425
615
  isInteractive && "cursor-pointer",
426
616
  classNames == null ? void 0 : classNames.badge
427
617
  ),
428
- text: "text-agg-foreground"
618
+ prefix: cn(
619
+ "flex shrink-0 items-center justify-center [&>svg]:size-3.5",
620
+ 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"
621
+ ),
622
+ text: cn(
623
+ "transition-[max-width,opacity] duration-300 ease-in",
624
+ price.isBest ? "text-agg-foreground" : "text-agg-muted-foreground",
625
+ shouldCollapsePriceText && "max-w-0 overflow-hidden! opacity-0 group-hover/agg-event-card:max-w-[40px] group-hover/agg-event-card:opacity-100"
626
+ )
429
627
  },
430
628
  onClick: isInteractive ? (eventToHandle) => {
431
- handleOutcomeBadgeClick(eventToHandle, market, outcome, marketHref);
629
+ handleOutcomeBadgeClick(eventToHandle, row.market, row.outcome, marketHref);
432
630
  } : void 0,
433
631
  onAuxClick: isInteractive ? (eventToHandle) => {
434
- handleOutcomeBadgeClick(eventToHandle, market, outcome, marketHref);
632
+ handleOutcomeBadgeClick(eventToHandle, row.market, row.outcome, marketHref);
435
633
  } : void 0
436
- }
634
+ },
635
+ `${price.market.id}:${price.outcome.id}`
437
636
  );
438
637
  };
439
638
  return /* @__PURE__ */ jsxs(
@@ -453,153 +652,72 @@ var EventListItemContent = ({
453
652
  "aria-label": ariaLabel != null ? ariaLabel : resolvedTitle,
454
653
  withGradient: true,
455
654
  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
- }
655
+ /* @__PURE__ */ jsxs("div", { className: cn("agg-event-card-header flex h-12 items-center gap-4", classNames == null ? void 0 : classNames.header), children: [
656
+ /* @__PURE__ */ jsx(
657
+ RemoteImage,
658
+ {
659
+ src: optimizedImageUrl(resolvedImage, 40),
660
+ alt: "",
661
+ classNames: {
662
+ root: "agg-event-image h-10 w-10 shrink-0 rounded-agg-lg object-cover",
663
+ image: "transition-transform duration-300 group-hover/agg-event-card:scale-110"
664
+ }
665
+ }
666
+ ),
667
+ /* @__PURE__ */ jsx(
668
+ Typography,
669
+ {
670
+ variant: "body-strong",
671
+ className: cn(
672
+ "agg-event-title",
673
+ "min-w-0 flex-1 text-agg-base font-agg-bold leading-agg-6",
674
+ "truncate text-wrap wrap-break-word line-clamp-2",
675
+ classNames == null ? void 0 : classNames.title
468
676
  ),
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
- ),
677
+ children: resolvedTitle
678
+ }
679
+ )
680
+ ] }),
485
681
  /* @__PURE__ */ jsxs(
486
682
  "div",
487
683
  {
488
684
  className: cn(
489
- "agg-outcomes flex flex-col gap-3 max-h-20 overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
685
+ "agg-outcomes flex max-h-[76px] flex-col gap-4 overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
490
686
  classNames == null ? void 0 : classNames.outcomes
491
687
  ),
492
688
  onScroll: handleOutcomesScroll,
493
689
  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);
690
+ comparison.rows.map((row) => {
691
+ var _a2;
692
+ const arbitragePercent = (_a2 = arbitrageByOutcomeId == null ? void 0 : arbitrageByOutcomeId[row.outcome.id]) != null ? _a2 : arbitrageByOutcomeId == null ? void 0 : arbitrageByOutcomeId[row.market.id];
693
+ const priceGapPercent = gapsByVenueMarketId.get(row.market.id);
573
694
  return /* @__PURE__ */ jsxs(
574
695
  "div",
575
696
  {
576
697
  className: cn(
577
698
  "agg-outcome-row",
578
- "flex flex-row gap-3 w-full items-center justify-between",
699
+ "flex h-10 w-full flex-row items-center justify-between gap-3",
579
700
  classNames == null ? void 0 : classNames.outcomeRow
580
701
  ),
581
702
  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(
703
+ /* @__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
704
  Typography,
584
705
  {
585
706
  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
707
+ className: "agg-outcome-label min-w-0 truncate text-agg-xs leading-agg-5 md:text-agg-base md:leading-agg-6",
708
+ children: row.label
588
709
  }
589
710
  ) }),
590
- /* @__PURE__ */ jsxs("div", { className: "agg-outcome-meta flex flex-row items-center justify-end gap-3", children: [
711
+ /* @__PURE__ */ jsxs("div", { className: "agg-outcome-meta flex shrink-0 flex-row items-center justify-end gap-2", children: [
591
712
  renderArbitrage(arbitragePercent),
592
- renderOutcomePriceBadge(
593
- probability,
594
- bestVenue,
595
- shouldRenderMidpointSkeleton,
596
- market,
597
- displayOutcome
598
- )
713
+ renderPriceGapPill(priceGapPercent),
714
+ /* @__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(
715
+ (price, priceIndex) => renderComparisonPriceBadge(row, price, priceIndex)
716
+ ) })
599
717
  ] })
600
718
  ]
601
719
  },
602
- `${market.id}`
720
+ row.id
603
721
  );
604
722
  }),
605
723
  shouldRenderLoadingOutcomeRow ? /* @__PURE__ */ jsxs("div", { className: "agg-outcome-row-loading flex w-full items-center justify-between gap-3", children: [
@@ -626,7 +744,7 @@ var EventListItemContent = ({
626
744
  {
627
745
  className: cn(
628
746
  "agg-event-card-footer",
629
- "flex items-center justify-between gap-2",
747
+ "flex items-center justify-between gap-5",
630
748
  "text-agg-muted-foreground",
631
749
  classNames == null ? void 0 : classNames.footer
632
750
  ),
@@ -635,41 +753,43 @@ var EventListItemContent = ({
635
753
  "div",
636
754
  {
637
755
  className: cn(
638
- "agg-event-meta flex items-center gap-1 text-agg-sm leading-agg-5 truncate"
756
+ "agg-event-meta flex min-w-0 flex-1 items-center gap-2 text-agg-sm leading-agg-5 truncate"
639
757
  ),
640
758
  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(
759
+ 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,
760
+ singleFooterVenue ? /* @__PURE__ */ jsxs("span", { className: "agg-event-single-venue flex min-w-0 items-center gap-1 overflow-hidden", children: [
761
+ /* @__PURE__ */ jsx(
762
+ VenueLogo,
763
+ {
764
+ venue: singleFooterVenue,
765
+ size: "small",
766
+ isMonochromatic: true,
767
+ className: "text-agg-muted-foreground! size-[14px]!"
768
+ }
769
+ ),
770
+ /* @__PURE__ */ jsx("span", { className: "truncate text-agg-muted-foreground", children: resolveVenueLabel(singleFooterVenue, void 0, labels) })
771
+ ] }) : null,
772
+ 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
773
  VenueLogo,
654
774
  {
655
775
  venue,
656
776
  size: "small",
657
777
  isMonochromatic: true,
658
- className: "text-agg-muted-foreground! size-[14px]!"
778
+ className: "text-agg-muted-foreground! size-3.5!"
659
779
  },
660
780
  venue
661
781
  )) }) : null
662
782
  ]
663
783
  }
664
784
  ),
665
- volumeLabel ? /* @__PURE__ */ jsx(
785
+ /* @__PURE__ */ jsx(
666
786
  Typography,
667
787
  {
668
788
  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",
789
+ className: "agg-event-volume min-w-fit shrink-0 truncate whitespace-pre text-agg-sm text-agg-muted-foreground line-clamp-1",
670
790
  children: volumeLabel
671
791
  }
672
- ) : null
792
+ )
673
793
  ]
674
794
  }
675
795
  )
@@ -723,6 +843,10 @@ var EventListItem = (props) => {
723
843
  return /* @__PURE__ */ jsx(EventListItemByEventId, __spreadValues({}, props));
724
844
  };
725
845
  EventListItem.displayName = "EventListItem";
846
+ var EventListItemV2 = (props) => {
847
+ return /* @__PURE__ */ jsx(EventListItem, __spreadValues({}, props));
848
+ };
849
+ EventListItemV2.displayName = "EventListItemV2";
726
850
 
727
851
  // src/events/market-details/orderbook-aggregation.ts
728
852
  import {
@@ -744,12 +868,12 @@ var fromScaled = (value, precision) => {
744
868
  var toPriceKey = (price) => {
745
869
  return String(toScaled(price, PRICE_PRECISION));
746
870
  };
747
- var normalizeOutcomeLabel2 = (value) => {
871
+ var normalizeOutcomeLabel = (value) => {
748
872
  if (typeof value !== "string") return "";
749
873
  return value.trim().toLowerCase().replace(/[_-]+/g, " ").replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ");
750
874
  };
751
875
  var toSemanticOutcomeLabel = (value) => {
752
- const normalizedValue = normalizeOutcomeLabel2(value);
876
+ const normalizedValue = normalizeOutcomeLabel(value);
753
877
  if (!normalizedValue) return "";
754
878
  if (POSITIVE_OUTCOME_KEYS.has(normalizedValue)) return "yes";
755
879
  if (NEGATIVE_OUTCOME_KEYS.has(normalizedValue)) return "no";
@@ -763,10 +887,10 @@ var getOutcomeLabelCandidates = (outcome) => {
763
887
  );
764
888
  };
765
889
  var matchesSelectedOutcomeLabel = (outcome, selectedOutcomeLabel) => {
766
- const normalizedSelectedLabel = normalizeOutcomeLabel2(selectedOutcomeLabel);
890
+ const normalizedSelectedLabel = normalizeOutcomeLabel(selectedOutcomeLabel);
767
891
  const semanticSelectedLabel = toSemanticOutcomeLabel(selectedOutcomeLabel);
768
892
  return getOutcomeLabelCandidates(outcome).some((candidate) => {
769
- const normalizedCandidate = normalizeOutcomeLabel2(candidate);
893
+ const normalizedCandidate = normalizeOutcomeLabel(candidate);
770
894
  if (!normalizedCandidate) return false;
771
895
  return normalizedCandidate === normalizedSelectedLabel || toSemanticOutcomeLabel(candidate) === semanticSelectedLabel;
772
896
  });
@@ -2358,13 +2482,12 @@ var EventListItemDetailsContent = ({
2358
2482
  () => resolvedEventTradingState.displayMarkets,
2359
2483
  [resolvedEventTradingState.displayMarkets]
2360
2484
  );
2361
- const sortedVenueMarkets = useMemo5(() => sortMarketsByYesOddsDesc(venueMarkets), [venueMarkets]);
2362
2485
  const marketOptions = useMemo5(
2363
- () => sortedVenueMarkets.map((vm) => ({
2486
+ () => venueMarkets.map((vm) => ({
2364
2487
  value: vm.id,
2365
2488
  label: vm.question
2366
2489
  })),
2367
- [sortedVenueMarkets]
2490
+ [venueMarkets]
2368
2491
  );
2369
2492
  const volumeLabel = useMemo5(() => {
2370
2493
  const resolvedVolume = resolveDisplayVolume(event.volume, venueMarkets);
@@ -3110,7 +3233,7 @@ import {
3110
3233
  mergeBestPricesPreferringLive as mergeBestPricesPreferringLive2,
3111
3234
  optimizedImageUrl as optimizedImageUrl3,
3112
3235
  resolveMarketTradingState,
3113
- useEventTradingContext as useEventTradingContext3,
3236
+ useEventTradingContext as useEventTradingContext2,
3114
3237
  useLabels as useLabels6,
3115
3238
  useLiveBestPrices as useLiveBestPrices2,
3116
3239
  useLiveOutcomePrices as useLiveOutcomePrices2,
@@ -3123,6 +3246,32 @@ import {
3123
3246
  } from "@agg-build/hooks";
3124
3247
  import { useEffect as useEffect4, useId, useMemo as useMemo6, useRef as useRef5, useState as useState4 } from "react";
3125
3248
 
3249
+ // src/events/shared/display-outcome-venue.ts
3250
+ var normalizeOutcomeLabel2 = (label) => {
3251
+ return typeof label === "string" ? label.trim().toLowerCase() : "";
3252
+ };
3253
+ var getDisplayOutcomeVenue = ({
3254
+ outcomeId,
3255
+ outcomeLabel,
3256
+ selection,
3257
+ bestMidpointVenue,
3258
+ bestVenueByOutcomeId,
3259
+ bestPriceVenuesByOutcomeId,
3260
+ fallbackVenue
3261
+ }) => {
3262
+ var _a;
3263
+ if (selection && outcomeId) {
3264
+ const sideVenues = bestPriceVenuesByOutcomeId == null ? void 0 : bestPriceVenuesByOutcomeId.get(outcomeId);
3265
+ if (selection === "buy" && (sideVenues == null ? void 0 : sideVenues.bestAskVenue)) return sideVenues.bestAskVenue;
3266
+ if (selection === "sell" && (sideVenues == null ? void 0 : sideVenues.bestBidVenue)) return sideVenues.bestBidVenue;
3267
+ }
3268
+ if (normalizeOutcomeLabel2(outcomeLabel) === "yes" && bestMidpointVenue) {
3269
+ return bestMidpointVenue;
3270
+ }
3271
+ const bestVenue = outcomeId ? bestVenueByOutcomeId == null ? void 0 : bestVenueByOutcomeId.get(outcomeId) : void 0;
3272
+ return (_a = bestVenue != null ? bestVenue : fallbackVenue) != null ? _a : void 0;
3273
+ };
3274
+
3126
3275
  // src/events/market-details/market-details-outcome-button.tsx
3127
3276
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
3128
3277
  var marketDetailsOutcomeButtonToneClasses = {
@@ -3219,7 +3368,7 @@ var MarketDetailsOutcomeButton = ({
3219
3368
  MarketDetailsOutcomeButton.displayName = "MarketDetailsOutcomeButton";
3220
3369
 
3221
3370
  // src/events/market-details/index.tsx
3222
- import { Fragment, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
3371
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
3223
3372
  var MarketDetailsUnavailableState = ({
3224
3373
  ariaLabel,
3225
3374
  classNames
@@ -3286,7 +3435,7 @@ var MarketDetailsContent = ({
3286
3435
  } = config;
3287
3436
  const isDarkTheme = theme === "dark";
3288
3437
  const labels = useLabels6();
3289
- const tradingContext = useEventTradingContext3();
3438
+ const tradingContext = useEventTradingContext2();
3290
3439
  const detailsContentId = useId();
3291
3440
  const tradeSide = (_a = tradingContext == null ? void 0 : tradingContext.tradeSide) != null ? _a : "buy";
3292
3441
  const wsLivePrices = useLiveOutcomePrices2(venueMarkets);
@@ -4024,7 +4173,7 @@ var MarketDetailsContent = ({
4024
4173
  ) : "translate-y-5 opacity-0"
4025
4174
  ),
4026
4175
  children: [
4027
- !isResolvedMarket ? /* @__PURE__ */ jsxs7(Fragment, { children: [
4176
+ !isResolvedMarket ? /* @__PURE__ */ jsxs7(Fragment2, { children: [
4028
4177
  /* @__PURE__ */ jsx9("div", { className: cn("block", classNames == null ? void 0 : classNames.tabs), children: /* @__PURE__ */ jsx9(
4029
4178
  Tabs,
4030
4179
  {
@@ -4317,7 +4466,7 @@ var MarketDetailsList = ({
4317
4466
  }) => {
4318
4467
  var _a, _b;
4319
4468
  const labels = useLabels6();
4320
- const tradingContext = useEventTradingContext3();
4469
+ const tradingContext = useEventTradingContext2();
4321
4470
  const selectedMarketId = (_a = tradingContext == null ? void 0 : tradingContext.selectedMarketId) != null ? _a : null;
4322
4471
  const [expandedMarketId, setExpandedMarketId] = useState4(null);
4323
4472
  const [areResolvedMarketsVisible, setAreResolvedMarketsVisible] = useState4(false);
@@ -4345,8 +4494,7 @@ var MarketDetailsList = ({
4345
4494
  return resolveIsResolvedEvent(sourceMarkets, eventTradingState);
4346
4495
  }, [eventTradingState, sourceMarkets]);
4347
4496
  const groupedMarkets = useMemo6(() => {
4348
- const sortedMarkets = sortMarketsByYesOddsDesc(sourceMarkets);
4349
- if (sortedMarkets.length === 0) {
4497
+ if (sourceMarkets.length === 0) {
4350
4498
  return {
4351
4499
  primary: [],
4352
4500
  closed: [],
@@ -4355,9 +4503,9 @@ var MarketDetailsList = ({
4355
4503
  };
4356
4504
  }
4357
4505
  if (isResolvedEvent) {
4358
- const winnerMarketId = resolveResolvedWinnerMarketId(sortedMarkets, eventTradingState);
4506
+ const winnerMarketId = resolveResolvedWinnerMarketId(sourceMarkets, eventTradingState);
4359
4507
  return {
4360
- primary: moveMarketToFront(sortedMarkets, winnerMarketId),
4508
+ primary: moveMarketToFront(sourceMarkets, winnerMarketId),
4361
4509
  upcoming: [],
4362
4510
  resolved: []
4363
4511
  };
@@ -4366,7 +4514,7 @@ var MarketDetailsList = ({
4366
4514
  const upcoming = [];
4367
4515
  const resolved = [];
4368
4516
  const closed = [];
4369
- sortedMarkets.forEach((market) => {
4517
+ sourceMarkets.forEach((market) => {
4370
4518
  const marketStateKind = resolveMarketTradingState(market).kind;
4371
4519
  if (marketStateKind === "resolved") {
4372
4520
  resolved.push(market);
@@ -4534,8 +4682,10 @@ MarketDetailsList.displayName = "MarketDetailsList";
4534
4682
  // src/events/list/index.tsx
4535
4683
  import {
4536
4684
  MarketStatus as MarketStatus2,
4685
+ getVisibleVenueIdsByConfig,
4537
4686
  useAppConfig as useAppConfig2,
4538
4687
  useCategories,
4688
+ useCategoryChildren,
4539
4689
  useLabels as useLabels8,
4540
4690
  useSdkUiConfig as useSdkUiConfig4,
4541
4691
  useVenueEvents
@@ -4545,7 +4695,7 @@ import * as Dialog from "@radix-ui/react-dialog";
4545
4695
  import { useEffect as useEffect6, useMemo as useMemo8, useRef as useRef7, useState as useState6 } from "react";
4546
4696
 
4547
4697
  // src/events/list/event-list-tabs.tsx
4548
- import { useAppConfig, useLabels as useLabels7 } from "@agg-build/hooks";
4698
+ import { getVenueAvailabilityState, useAppConfig, useGeoBlock, useLabels as useLabels7 } from "@agg-build/hooks";
4549
4699
  import { useCallback as useCallback3, useEffect as useEffect5, useMemo as useMemo7, useRef as useRef6, useState as useState5 } from "react";
4550
4700
 
4551
4701
  // src/events/list/event-list.constants.ts
@@ -4615,6 +4765,9 @@ var getDefaultEventListTabs = (labels) => {
4615
4765
  // src/events/list/event-list-tabs.tsx
4616
4766
  import { jsx as jsx10 } from "react/jsx-runtime";
4617
4767
  var renderTabIcon = (tab, isActive) => {
4768
+ if (tab.iconName === "warning-filled") {
4769
+ return /* @__PURE__ */ jsx10(Icon, { name: "warning-filled", size: "small", color: "currentColor" });
4770
+ }
4618
4771
  if (tab.venueLogo) {
4619
4772
  return /* @__PURE__ */ jsx10(VenueLogo, { venue: tab.venueLogo, size: "small" });
4620
4773
  }
@@ -4631,15 +4784,26 @@ var renderTabIcon = (tab, isActive) => {
4631
4784
  var useEventListTabs = (tabs) => {
4632
4785
  const labels = useLabels7();
4633
4786
  const { disabledVenues } = useAppConfig();
4787
+ const { isLocationBlocked } = useGeoBlock();
4634
4788
  return useMemo7(() => {
4635
4789
  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);
4790
+ return baseTabs.flatMap((tab) => {
4791
+ if (!tab.venueLogo) return [tab];
4792
+ const availabilityState = getVenueAvailabilityState({
4793
+ venueId: tab.venueLogo,
4794
+ disabledVenues,
4795
+ isLocationBlocked
4796
+ });
4797
+ if (availabilityState === "hidden") return [];
4798
+ return [
4799
+ __spreadProps(__spreadValues({}, tab), {
4800
+ disabled: tab.disabled || availabilityState === "geoblocked",
4801
+ label: availabilityState === "geoblocked" ? `${tab.label} (${labels.trading.venueUnavailableInRegion})` : tab.label,
4802
+ iconName: availabilityState === "geoblocked" ? "warning-filled" : tab.iconName
4803
+ })
4804
+ ];
4641
4805
  });
4642
- }, [tabs, labels, disabledVenues]);
4806
+ }, [tabs, labels, disabledVenues, isLocationBlocked]);
4643
4807
  };
4644
4808
  var EventListTabs = ({
4645
4809
  tabs,
@@ -4651,9 +4815,10 @@ var EventListTabs = ({
4651
4815
  }) => {
4652
4816
  const resolvedTabs = useEventListTabs(tabs);
4653
4817
  useEffect5(() => {
4654
- if (resolvedTabs.length === 0) return;
4655
- if (resolvedTabs.some((tab) => tab.value === activeTab)) return;
4656
- onTabChange(resolvedTabs[0].value);
4818
+ const fallbackTab = resolvedTabs.find((tab) => !tab.disabled);
4819
+ if (!fallbackTab) return;
4820
+ if (resolvedTabs.some((tab) => tab.value === activeTab && !tab.disabled)) return;
4821
+ onTabChange(fallbackTab.value);
4657
4822
  }, [activeTab, onTabChange, resolvedTabs]);
4658
4823
  const items = useMemo7(() => {
4659
4824
  return resolvedTabs.map((tab) => {
@@ -4753,7 +4918,20 @@ var useEventListTabsHeaderOverflow = (recomputeOn, options) => {
4753
4918
  };
4754
4919
 
4755
4920
  // src/events/list/index.tsx
4756
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
4921
+ import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
4922
+ var subcategoryMenuRowClassName = cn(
4923
+ "flex min-h-11 w-full items-center justify-between rounded-[6px] px-3 py-3",
4924
+ "text-left text-agg-sm font-agg-normal leading-agg-5",
4925
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-agg-primary focus-visible:ring-offset-1 focus-visible:ring-offset-agg-secondary"
4926
+ );
4927
+ var subcategoryMenuIdleRowClassName = cn(
4928
+ subcategoryMenuRowClassName,
4929
+ "cursor-pointer text-agg-foreground hover:bg-agg-secondary-hover"
4930
+ );
4931
+ var subcategoryMenuSelectedRowClassName = cn(
4932
+ subcategoryMenuRowClassName,
4933
+ "cursor-pointer bg-agg-primary/10 text-agg-primary"
4934
+ );
4757
4935
  var SORT_ICON_BY_VALUE = {
4758
4936
  volume24hr: "sort-volume-24hr",
4759
4937
  topArbitrage: "sort-top-arbitrage",
@@ -4768,7 +4946,10 @@ var resolveSortQueryParams = (value) => {
4768
4946
  return { sortBy: "endDate", sortDir: "asc" };
4769
4947
  }
4770
4948
  if (value === "topArbitrage") {
4771
- return {};
4949
+ return {
4950
+ sortBy: "arbReturn",
4951
+ sortDir: "desc"
4952
+ };
4772
4953
  }
4773
4954
  return { sortBy: "volume24hr", sortDir: "desc" };
4774
4955
  };
@@ -4778,6 +4959,7 @@ var EventList = ({
4778
4959
  maxVisibleItems,
4779
4960
  search,
4780
4961
  categoryIds,
4962
+ onCategoryRootChange,
4781
4963
  onEventClick,
4782
4964
  onMarketClick,
4783
4965
  getMarketHref,
@@ -4795,9 +4977,7 @@ var EventList = ({
4795
4977
  const isDiscoveryFiltersEnabled = enableVenueEventDiscoveryFilters && !search;
4796
4978
  const resolvedTabs = useEventListTabs();
4797
4979
  const visibleVenues = useMemo8(
4798
- () => disabledVenues.length === 0 ? void 0 : VENUES.filter(
4799
- (v) => !disabledVenues.includes(v)
4800
- ),
4980
+ () => disabledVenues.length === 0 ? void 0 : getVisibleVenueIdsByConfig(VENUES, disabledVenues),
4801
4981
  [disabledVenues]
4802
4982
  );
4803
4983
  const [activeTabValue, setActiveTabValue] = useState6(
@@ -4805,8 +4985,8 @@ var EventList = ({
4805
4985
  );
4806
4986
  const [selectedSort, setSelectedSort] = useState6("volume24hr");
4807
4987
  const [isSubcategoriesModalOpen, setIsSubcategoriesModalOpen] = useState6(false);
4808
- const [selectedParentCategoryId, setSelectedParentCategoryId] = useState6(null);
4809
- const [selectedSubcategoryId, setSelectedSubcategoryId] = useState6(null);
4988
+ const [categoryPath, setCategoryPath] = useState6([]);
4989
+ const [collapsedCategoryIds, setCollapsedCategoryIds] = useState6(() => /* @__PURE__ */ new Set());
4810
4990
  const { headerRef, titleRef, shouldUseSelectOverflow } = useEventListTabsHeaderOverflow(resolvedTabs, { minTabsInlineWidthForSelect: 400, preferSelectOnOverflow: false });
4811
4991
  const sortItems = useMemo8(() => {
4812
4992
  return [
@@ -4818,9 +4998,7 @@ var EventList = ({
4818
4998
  {
4819
4999
  value: "topArbitrage",
4820
5000
  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
5001
+ icon: /* @__PURE__ */ jsx11(Icon, { name: SORT_ICON_BY_VALUE.topArbitrage, size: "small", color: "currentColor" })
4824
5002
  },
4825
5003
  {
4826
5004
  value: "volume",
@@ -4842,48 +5020,86 @@ var EventList = ({
4842
5020
  const baseCategoryId = (_c = categoryIds == null ? void 0 : categoryIds[0]) != null ? _c : null;
4843
5021
  useEffect6(() => {
4844
5022
  if (!isDiscoveryFiltersEnabled) return;
4845
- setSelectedParentCategoryId(baseCategoryId);
4846
- setSelectedSubcategoryId(null);
5023
+ if (!baseCategoryId) {
5024
+ setCategoryPath([]);
5025
+ setCollapsedCategoryIds(/* @__PURE__ */ new Set());
5026
+ return;
5027
+ }
5028
+ setCategoryPath([{ id: baseCategoryId, label: baseCategoryId, eventCount: 0 }]);
5029
+ setCollapsedCategoryIds(/* @__PURE__ */ new Set());
4847
5030
  }, [baseCategoryId, isDiscoveryFiltersEnabled]);
4848
5031
  const { categories: topLevelCategories } = useCategories({
4849
5032
  queryKeyScope: "event-list-top-categories",
4850
5033
  enabled: isDiscoveryFiltersEnabled,
4851
5034
  limit: 100
4852
5035
  });
4853
- const { categories: subcategories } = useCategories({
4854
- queryKeyScope: "event-list-subcategories",
4855
- enabled: isDiscoveryFiltersEnabled && Boolean(baseCategoryId),
4856
- parentId: baseCategoryId,
5036
+ const sortedTopLevelCategories = useMemo8(() => {
5037
+ return sortCategoriesForNavigation(topLevelCategories);
5038
+ }, [topLevelCategories]);
5039
+ const baseCategoryChildPrefetchIds = useMemo8(() => {
5040
+ return Array.from(
5041
+ /* @__PURE__ */ new Set([
5042
+ ...sortedTopLevelCategories.map((category) => category.id),
5043
+ ...categoryPath.map((category) => category.id)
5044
+ ])
5045
+ );
5046
+ }, [categoryPath, sortedTopLevelCategories]);
5047
+ const { childrenByParentId: baseChildrenByParentId } = useCategoryChildren({
5048
+ queryKeyScope: "event-list-category-children",
5049
+ enabled: isDiscoveryFiltersEnabled,
5050
+ parentIds: baseCategoryChildPrefetchIds,
4857
5051
  limit: 100
4858
5052
  });
4859
- const shouldRenderSubcategoryFilters = isDiscoveryFiltersEnabled && Boolean(baseCategoryId) && subcategories.length > 0;
4860
- console.log({
4861
- enableVenueEventDiscoveryFilters,
4862
- shouldRenderSubcategoryFilters,
4863
- isDiscoveryFiltersEnabled,
4864
- baseCategoryId,
4865
- subcategories
5053
+ const visibleChildPrefetchIds = useMemo8(() => {
5054
+ var _a2;
5055
+ const ids = /* @__PURE__ */ new Set();
5056
+ for (const expandedCategory of categoryPath) {
5057
+ for (const childCategory of (_a2 = baseChildrenByParentId.get(expandedCategory.id)) != null ? _a2 : []) {
5058
+ ids.add(childCategory.id);
5059
+ }
5060
+ }
5061
+ return Array.from(ids);
5062
+ }, [baseChildrenByParentId, categoryPath]);
5063
+ const { childrenByParentId: visibleChildrenByParentId } = useCategoryChildren({
5064
+ queryKeyScope: "event-list-category-children",
5065
+ enabled: isDiscoveryFiltersEnabled,
5066
+ parentIds: visibleChildPrefetchIds,
5067
+ limit: 100
5068
+ });
5069
+ const visibleGrandchildPrefetchIds = useMemo8(() => {
5070
+ var _a2;
5071
+ const ids = /* @__PURE__ */ new Set();
5072
+ for (const expandedCategory of categoryPath) {
5073
+ for (const childCategory of (_a2 = visibleChildrenByParentId.get(expandedCategory.id)) != null ? _a2 : []) {
5074
+ ids.add(childCategory.id);
5075
+ }
5076
+ }
5077
+ return Array.from(ids);
5078
+ }, [categoryPath, visibleChildrenByParentId]);
5079
+ const { childrenByParentId: visibleGrandchildrenByParentId } = useCategoryChildren({
5080
+ queryKeyScope: "event-list-category-children",
5081
+ enabled: isDiscoveryFiltersEnabled,
5082
+ parentIds: visibleGrandchildPrefetchIds,
5083
+ limit: 100
4866
5084
  });
5085
+ const childrenByParentId = useMemo8(() => {
5086
+ return new Map([
5087
+ ...baseChildrenByParentId,
5088
+ ...visibleChildrenByParentId,
5089
+ ...visibleGrandchildrenByParentId
5090
+ ]);
5091
+ }, [baseChildrenByParentId, visibleChildrenByParentId, visibleGrandchildrenByParentId]);
5092
+ const shouldRenderSubcategoryFilters = isDiscoveryFiltersEnabled && (sortedTopLevelCategories.length > 0 || categoryPath.length > 0);
4867
5093
  const totalTopLevelEventCount = useMemo8(() => {
4868
- return topLevelCategories.reduce((accumulator, category) => {
5094
+ return sortedTopLevelCategories.reduce((accumulator, category) => {
4869
5095
  var _a2;
4870
5096
  return accumulator + ((_a2 = category.eventCount) != null ? _a2 : 0);
4871
5097
  }, 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]);
5098
+ }, [sortedTopLevelCategories]);
4881
5099
  const resolvedCategoryIds = useMemo8(() => {
4882
5100
  if (!isDiscoveryFiltersEnabled) return categoryIds;
4883
- if (selectedSubcategoryId) return [selectedSubcategoryId];
4884
- if (selectedParentCategoryId) return [selectedParentCategoryId];
4885
- return categoryIds;
4886
- }, [categoryIds, isDiscoveryFiltersEnabled, selectedParentCategoryId, selectedSubcategoryId]);
5101
+ return resolveCategoryIdsFromPath(categoryPath, void 0);
5102
+ }, [categoryIds, categoryPath, isDiscoveryFiltersEnabled]);
4887
5103
  const sortQueryParams = useMemo8(() => {
4888
5104
  return resolveSortQueryParams(selectedSort);
4889
5105
  }, [selectedSort]);
@@ -4979,58 +5195,121 @@ var EventList = ({
4979
5195
  const gridClassName = cn(
4980
5196
  "grid grid-cols-[repeat(auto-fill,minmax(240px,1fr))] md:grid-cols-[repeat(auto-fill,minmax(360px,1fr))] gap-4"
4981
5197
  );
4982
- const isAllSubcategoriesSelected = shouldRenderSubcategoryFilters && !selectedSubcategoryId;
5198
+ const isDrilledIn = categoryPath.length > 0;
4983
5199
  const handleSelectAllCategories = () => {
4984
- setSelectedParentCategoryId(baseCategoryId);
4985
- setSelectedSubcategoryId(null);
5200
+ setCategoryPath([]);
5201
+ setCollapsedCategoryIds(/* @__PURE__ */ new Set());
5202
+ onCategoryRootChange == null ? void 0 : onCategoryRootChange(void 0);
4986
5203
  setIsSubcategoriesModalOpen(false);
4987
5204
  };
4988
- const handleSelectSubcategory = (subcategoryId) => {
4989
- setSelectedSubcategoryId(subcategoryId);
4990
- setIsSubcategoriesModalOpen(false);
5205
+ const handleToggleSubcategory = ({
5206
+ entry,
5207
+ depth,
5208
+ hasKnownChildren,
5209
+ isExpanded,
5210
+ isSelected
5211
+ }) => {
5212
+ var _a2;
5213
+ setCategoryPath((prev) => [...prev.slice(0, depth), entry]);
5214
+ setCollapsedCategoryIds((prev) => {
5215
+ const next = new Set(prev);
5216
+ if (hasKnownChildren && isExpanded && isSelected) {
5217
+ next.add(entry.id);
5218
+ return next;
5219
+ }
5220
+ next.delete(entry.id);
5221
+ return next;
5222
+ });
5223
+ onCategoryRootChange == null ? void 0 : onCategoryRootChange(depth === 0 ? entry.id : (_a2 = categoryPath[0]) == null ? void 0 : _a2.id);
5224
+ };
5225
+ const renderSubcategoryTreeRow = ({
5226
+ entry,
5227
+ isExpanded,
5228
+ isSelected,
5229
+ onClick
5230
+ }) => {
5231
+ var _a2, _b2;
5232
+ const hasKnownChildren = ((_b2 = (_a2 = childrenByParentId.get(entry.id)) == null ? void 0 : _a2.length) != null ? _b2 : 0) > 0;
5233
+ return /* @__PURE__ */ jsxs8(
5234
+ "button",
5235
+ {
5236
+ type: "button",
5237
+ "aria-current": isSelected ? "true" : void 0,
5238
+ className: isSelected ? subcategoryMenuSelectedRowClassName : subcategoryMenuIdleRowClassName,
5239
+ onClick,
5240
+ children: [
5241
+ /* @__PURE__ */ jsx11("span", { className: "min-w-0 truncate first-letter:uppercase", children: entry.label }),
5242
+ hasKnownChildren ? /* @__PURE__ */ jsx11(
5243
+ Icon,
5244
+ {
5245
+ name: isExpanded ? "chevron-up" : "chevron-down",
5246
+ size: "small",
5247
+ color: "currentColor",
5248
+ className: "shrink-0 text-agg-muted-foreground"
5249
+ }
5250
+ ) : /* @__PURE__ */ jsx11("span", { className: "shrink-0 text-agg-muted-foreground", children: entry.eventCount })
5251
+ ]
5252
+ },
5253
+ entry.id
5254
+ );
4991
5255
  };
4992
- const subcategoriesListContent = /* @__PURE__ */ jsxs8(Fragment2, { children: [
5256
+ const renderSubcategoryBranch = (category, depth) => {
5257
+ var _a2, _b2, _c2, _d, _e;
5258
+ const label = (_a2 = category.displayName) != null ? _a2 : category.name;
5259
+ const entry = {
5260
+ id: category.id,
5261
+ label,
5262
+ eventCount: (_b2 = category.eventCount) != null ? _b2 : 0
5263
+ };
5264
+ const childCategories = (_c2 = childrenByParentId.get(category.id)) != null ? _c2 : [];
5265
+ const hasKnownChildren = childCategories.length > 0;
5266
+ const isExpanded = ((_d = categoryPath[depth]) == null ? void 0 : _d.id) === category.id && !collapsedCategoryIds.has(category.id);
5267
+ const isSelected = ((_e = categoryPath[depth]) == null ? void 0 : _e.id) === category.id && categoryPath.length === depth + 1;
5268
+ return /* @__PURE__ */ jsxs8("div", { className: "flex w-full flex-col gap-1", children: [
5269
+ renderSubcategoryTreeRow({
5270
+ entry,
5271
+ isExpanded,
5272
+ isSelected,
5273
+ onClick: () => handleToggleSubcategory({
5274
+ entry,
5275
+ depth,
5276
+ hasKnownChildren,
5277
+ isExpanded,
5278
+ isSelected
5279
+ })
5280
+ }),
5281
+ isExpanded ? /* @__PURE__ */ jsx11("div", { className: "flex w-full flex-col gap-1 pl-4", children: childCategories.map(
5282
+ (childCategory) => renderSubcategoryBranch(childCategory, depth + 1)
5283
+ ) }) : null
5284
+ ] }, category.id);
5285
+ };
5286
+ const subcategoriesListContent = /* @__PURE__ */ jsxs8(Fragment3, { children: [
4993
5287
  /* @__PURE__ */ jsxs8(
4994
5288
  "button",
4995
5289
  {
4996
5290
  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
- ),
5291
+ "aria-current": !isDrilledIn ? "true" : void 0,
5292
+ className: !isDrilledIn ? subcategoryMenuSelectedRowClassName : subcategoryMenuIdleRowClassName,
5001
5293
  onClick: handleSelectAllCategories,
5002
5294
  children: [
5003
- /* @__PURE__ */ jsx11("span", { children: labels.eventList.subcategoriesAll }),
5004
- /* @__PURE__ */ jsx11("span", { className: "text-agg-muted-foreground", children: selectedParentEventCount })
5295
+ /* @__PURE__ */ jsx11("span", { className: "min-w-0 truncate", children: labels.eventList.subcategoriesAll }),
5296
+ /* @__PURE__ */ jsx11("span", { className: "text-agg-muted-foreground", children: totalTopLevelEventCount })
5005
5297
  ]
5006
5298
  }
5007
5299
  ),
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
- })
5300
+ sortedTopLevelCategories.map((category) => renderSubcategoryBranch(category, 0))
5029
5301
  ] });
5030
5302
  if (shouldRenderLoadingState) {
5031
- return /* @__PURE__ */ jsx11(Skeleton, { view: "event-list", ariaLabel: labels.eventList.loading(title) });
5303
+ return /* @__PURE__ */ jsx11(
5304
+ Skeleton,
5305
+ {
5306
+ view: "event-list",
5307
+ ariaLabel: labels.eventList.loading(title),
5308
+ withSidebar: isDiscoveryFiltersEnabled
5309
+ }
5310
+ );
5032
5311
  }
5033
- return /* @__PURE__ */ jsxs8("section", { className: "agg-event-list flex w-full flex-col gap-5", children: [
5312
+ return /* @__PURE__ */ jsxs8("section", { className: "agg-event-list flex w-full flex-col gap-2 md:gap-5 t", children: [
5034
5313
  /* @__PURE__ */ jsxs8(
5035
5314
  "header",
5036
5315
  {
@@ -5060,18 +5339,19 @@ var EventList = ({
5060
5339
  Select,
5061
5340
  {
5062
5341
  ariaLabel: labels.eventList.sortByLabel,
5063
- className: "min-w-[160px] w-auto! shrink-0 min-h-10.5",
5342
+ className: "min-w-[200px] w-auto! shrink-0 min-h-10.5",
5064
5343
  value: selectedSort,
5065
5344
  onChange: setSelectedSort,
5066
5345
  items: sortItems,
5067
- contentClassName: "py-2"
5346
+ contentClassName: "py-2",
5347
+ triggerClassName: "rounded-agg-lg!"
5068
5348
  }
5069
5349
  )
5070
5350
  ] })
5071
5351
  ]
5072
5352
  }
5073
5353
  ),
5074
- /* @__PURE__ */ jsxs8("div", { className: "flex w-full gap-2 md:hidden", children: [
5354
+ /* @__PURE__ */ jsxs8("div", { className: "flex w-full gap-2 md:hidden mb-3", children: [
5075
5355
  /* @__PURE__ */ jsx11(
5076
5356
  EventListTabs,
5077
5357
  {
@@ -5115,6 +5395,7 @@ var EventList = ({
5115
5395
  {
5116
5396
  className: cn(
5117
5397
  "agg-event-list-grid",
5398
+ "grid grid-cols-[repeat(auto-fill,minmax(240px,1fr))] md:grid-cols-[repeat(auto-fill,minmax(360px,1fr))] gap-4",
5118
5399
  "w-full",
5119
5400
  isPlaceholderData && "opacity-60",
5120
5401
  gridClassName
@@ -5125,7 +5406,7 @@ var EventList = ({
5125
5406
  {
5126
5407
  event,
5127
5408
  classNames: {
5128
- root: "agg-event-list-item w-full min-w-0 max-w-none"
5409
+ root: "agg-event-list-item w-full min-w-0! max-w-none justify-between!"
5129
5410
  },
5130
5411
  onEventClick,
5131
5412
  onMarketClick,
@@ -5140,7 +5421,7 @@ var EventList = ({
5140
5421
  {
5141
5422
  isLoading: true,
5142
5423
  classNames: {
5143
- root: "agg-event-list-item w-full min-w-0 max-w-none"
5424
+ root: "agg-event-list-item w-full min-w-0! max-w-none justify-between!"
5144
5425
  }
5145
5426
  },
5146
5427
  `loading-${index}`
@@ -5188,6 +5469,7 @@ EventList.displayName = "EventList";
5188
5469
  export {
5189
5470
  isErrorWithStatus,
5190
5471
  EventListItem,
5472
+ EventListItemV2,
5191
5473
  collectEligibleVenueOutcomes,
5192
5474
  collectEligibleVenueOutcomeIds,
5193
5475
  mergeVenueOutcomeOrderbooks,