@agg-build/ui 4.11.3 → 4.13.2

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.
@@ -1039,6 +1039,8 @@ import {
1039
1039
  } from "@agg-build/hooks";
1040
1040
  var PRICE_PRECISION = 1e6;
1041
1041
  var SIZE_PRECISION = 1e8;
1042
+ var DISPLAY_PRICE_BUCKETS_PER_UNIT = 1e3;
1043
+ var DISPLAY_ROUNDING_PRECISION = 1e9;
1042
1044
  var POSITIVE_OUTCOME_KEYS = /* @__PURE__ */ new Set(["yes", "y", "true", "up", "buy", "long"]);
1043
1045
  var NEGATIVE_OUTCOME_KEYS = /* @__PURE__ */ new Set(["no", "n", "false", "down", "sell", "short"]);
1044
1046
  var roundTo = (value, precision) => {
@@ -1053,6 +1055,10 @@ var fromScaled = (value, precision) => {
1053
1055
  var toPriceKey = (price) => {
1054
1056
  return String(toScaled(price, PRICE_PRECISION));
1055
1057
  };
1058
+ var toDisplayPrice = (price) => {
1059
+ const bucketSize = DISPLAY_ROUNDING_PRECISION / DISPLAY_PRICE_BUCKETS_PER_UNIT;
1060
+ return Math.round(toScaled(price, DISPLAY_ROUNDING_PRECISION) / bucketSize) / DISPLAY_PRICE_BUCKETS_PER_UNIT;
1061
+ };
1056
1062
  var normalizeOutcomeLabel = (value) => {
1057
1063
  if (typeof value !== "string") return "";
1058
1064
  return value.trim().toLowerCase().replace(/[_-]+/g, " ").replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ");
@@ -1166,7 +1172,7 @@ var buildRowsFromAccumulator = ({
1166
1172
  venues,
1167
1173
  price: roundTo(level.price, PRICE_PRECISION),
1168
1174
  size,
1169
- total: roundTo(level.price * size, SIZE_PRECISION),
1175
+ total: roundTo(level.notional, SIZE_PRECISION),
1170
1176
  tone,
1171
1177
  barScale: 0,
1172
1178
  venueBreakdown,
@@ -1184,6 +1190,7 @@ var accumulateSideLevels = ({
1184
1190
  orderbooksByOutcomeId
1185
1191
  }) => {
1186
1192
  const levelsByPrice = /* @__PURE__ */ new Map();
1193
+ let bestPrice = null;
1187
1194
  const includedOutcomeIds = /* @__PURE__ */ new Set();
1188
1195
  const missingOutcomeIds = /* @__PURE__ */ new Set();
1189
1196
  eligibleOutcomes.forEach((eligibleOutcome) => {
@@ -1199,18 +1206,25 @@ var accumulateSideLevels = ({
1199
1206
  includedOutcomeIds.add(eligibleOutcome.outcomeId);
1200
1207
  venueLevels.forEach((level) => {
1201
1208
  var _a;
1202
- const priceKey = toPriceKey(level.price);
1209
+ if (bestPrice == null || (side === "asks" ? level.price < bestPrice : level.price > bestPrice)) {
1210
+ bestPrice = level.price;
1211
+ }
1212
+ const displayPrice = toDisplayPrice(level.price);
1213
+ const priceKey = toPriceKey(displayPrice);
1203
1214
  const scaledSize = toScaled(level.size, SIZE_PRECISION);
1215
+ const notional = level.price * level.size;
1204
1216
  const currentLevel = levelsByPrice.get(priceKey);
1205
1217
  if (currentLevel) {
1206
1218
  currentLevel.sizeScaled += scaledSize;
1219
+ currentLevel.notional += notional;
1207
1220
  currentLevel.venueBreakdownScaled[eligibleOutcome.venue] = ((_a = currentLevel.venueBreakdownScaled[eligibleOutcome.venue]) != null ? _a : 0) + scaledSize;
1208
1221
  currentLevel.sourceOutcomeIds.add(eligibleOutcome.outcomeId);
1209
1222
  return;
1210
1223
  }
1211
1224
  levelsByPrice.set(priceKey, {
1212
- price: level.price,
1225
+ price: displayPrice,
1213
1226
  sizeScaled: scaledSize,
1227
+ notional,
1214
1228
  venueBreakdownScaled: {
1215
1229
  [eligibleOutcome.venue]: scaledSize
1216
1230
  },
@@ -1220,6 +1234,7 @@ var accumulateSideLevels = ({
1220
1234
  });
1221
1235
  return {
1222
1236
  levelsByPrice,
1237
+ bestPrice,
1223
1238
  includedOutcomeIds,
1224
1239
  missingOutcomeIds
1225
1240
  };
@@ -1387,7 +1402,7 @@ var mergeVenueOutcomeOrderbooks = ({
1387
1402
  eligibleOutcomes,
1388
1403
  orderbooksByOutcomeId
1389
1404
  }) => {
1390
- var _a, _b, _c, _d, _e, _f;
1405
+ var _a, _b;
1391
1406
  const bidState = accumulateSideLevels({
1392
1407
  side: "bids",
1393
1408
  eligibleOutcomes,
@@ -1410,8 +1425,8 @@ var mergeVenueOutcomeOrderbooks = ({
1410
1425
  levelsByPrice: askState.levelsByPrice,
1411
1426
  fallbackVenue: (_b = eligibleOutcomes[0]) == null ? void 0 : _b.venue
1412
1427
  });
1413
- const bestBid = (_d = (_c = bidRows[0]) == null ? void 0 : _c.price) != null ? _d : null;
1414
- const bestAsk = (_f = (_e = askRows[0]) == null ? void 0 : _e.price) != null ? _f : null;
1428
+ const bestBid = bidState.bestPrice;
1429
+ const bestAsk = askState.bestPrice;
1415
1430
  return {
1416
1431
  askRows,
1417
1432
  bidRows,
@@ -3056,7 +3056,9 @@ var TRADING_ACCESS_VENUES = [
3056
3056
  "limitless",
3057
3057
  "predict",
3058
3058
  "myriad",
3059
- "hyperliquid"
3059
+ "hyperliquid",
3060
+ "novig",
3061
+ "prophetx"
3060
3062
  ];
3061
3063
  var TRADING_ACCESS_VENUE_ITEMS = TRADING_ACCESS_VENUES.map((id) => ({ id }));
3062
3064
  var SectionTitle2 = ({ children }) => /* @__PURE__ */ jsx22("h3", { className: "text-agg-sm font-agg-bold leading-agg-5 text-agg-foreground", children });
@@ -12,7 +12,7 @@ import {
12
12
  isErrorWithStatus,
13
13
  useEventListTabs,
14
14
  useEventListTabsHeaderOverflow
15
- } from "./chunk-EYJS45RP.mjs";
15
+ } from "./chunk-IS45S6R3.mjs";
16
16
  import {
17
17
  DEPOSIT_MODAL_OPEN_EVENT,
18
18
  PlaceOrder,
@@ -1341,6 +1341,16 @@ var aggregateSportsLineStops = (markets, isSpread = false) => {
1341
1341
  (left, right) => left.lineValue !== right.lineValue ? left.lineValue - right.lineValue : left.value.localeCompare(right.value)
1342
1342
  );
1343
1343
  };
1344
+ var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1345
+ var resolveSportsLadderTitle = (group, selectedLineDisplay) => {
1346
+ var _a;
1347
+ const anchorLineValue = (_a = group.markets[0]) == null ? void 0 : _a.lineValue;
1348
+ if (anchorLineValue == null || !selectedLineDisplay) return group.title;
1349
+ const anchorDisplay = resolveSelectedSportsLineValue(anchorLineValue);
1350
+ if (anchorDisplay === selectedLineDisplay) return group.title;
1351
+ const pattern = new RegExp(`(^|[^\\d.])${escapeRegExp(anchorDisplay)}(?![\\d.])`);
1352
+ return pattern.test(group.title) ? group.title.replace(pattern, (_match, prefix) => `${prefix}${selectedLineDisplay}`) : group.title;
1353
+ };
1344
1354
  var buildSportsSlideFromGroup = (group) => {
1345
1355
  const lineStops = group.hasLineVariants ? aggregateSportsLineStops(group.markets, group.sportsMarketType === "spread") : [];
1346
1356
  const hasLadder = lineStops.length > 1;
@@ -1855,6 +1865,8 @@ var SportsMarketCard = ({
1855
1865
  });
1856
1866
  }, [slide.kind, activeMarket, group.markets, midpointsResult]);
1857
1867
  if (!activeMarket) return null;
1868
+ const selectedStop = slide.hasLadder ? slide.stops[selectedLineIndex] : void 0;
1869
+ const cardTitle = selectedStop ? resolveSportsLadderTitle(group, selectedStop.value) : group.title;
1858
1870
  const activeOutcome = (_h = activeMarket.venueMarketOutcomes.find(
1859
1871
  (outcome) => outcome.id === (tradingContext == null ? void 0 : tradingContext.selectedOutcomeId)
1860
1872
  )) != null ? _h : activeDefaultOutcome;
@@ -1915,7 +1927,7 @@ var SportsMarketCard = ({
1915
1927
  {
1916
1928
  marketId: activeMarket.id,
1917
1929
  venueMarkets,
1918
- title: group.title,
1930
+ title: cardTitle,
1919
1931
  compactHeader: true,
1920
1932
  subtitleOverride: compactSubtitle,
1921
1933
  headerOutcomeVariant,
@@ -1934,9 +1946,9 @@ var SportsMarketCard = ({
1934
1946
  })),
1935
1947
  selectedIndex: selectedLineIndex,
1936
1948
  onSelect: handleLineSelect,
1937
- ariaLabel: labels.eventMarketPage.sports.lineSelectorAria(group.title),
1938
- previousAriaLabel: labels.eventMarketPage.sports.previousLineAria(group.title),
1939
- nextAriaLabel: labels.eventMarketPage.sports.nextLineAria(group.title)
1949
+ ariaLabel: labels.eventMarketPage.sports.lineSelectorAria(cardTitle),
1950
+ previousAriaLabel: labels.eventMarketPage.sports.previousLineAria(cardTitle),
1951
+ nextAriaLabel: labels.eventMarketPage.sports.nextLineAria(cardTitle)
1940
1952
  }
1941
1953
  ) : void 0,
1942
1954
  classNames: { root: "agg-market-list-item agg-sports-market-card" },
package/dist/events.js CHANGED
@@ -9866,6 +9866,8 @@ var buildMarketDetailsModel = ({
9866
9866
  var import_hooks38 = require("@agg-build/hooks");
9867
9867
  var PRICE_PRECISION = 1e6;
9868
9868
  var SIZE_PRECISION = 1e8;
9869
+ var DISPLAY_PRICE_BUCKETS_PER_UNIT = 1e3;
9870
+ var DISPLAY_ROUNDING_PRECISION = 1e9;
9869
9871
  var POSITIVE_OUTCOME_KEYS = /* @__PURE__ */ new Set(["yes", "y", "true", "up", "buy", "long"]);
9870
9872
  var NEGATIVE_OUTCOME_KEYS = /* @__PURE__ */ new Set(["no", "n", "false", "down", "sell", "short"]);
9871
9873
  var roundTo = (value, precision) => {
@@ -9880,6 +9882,10 @@ var fromScaled = (value, precision) => {
9880
9882
  var toPriceKey = (price) => {
9881
9883
  return String(toScaled(price, PRICE_PRECISION));
9882
9884
  };
9885
+ var toDisplayPrice = (price) => {
9886
+ const bucketSize = DISPLAY_ROUNDING_PRECISION / DISPLAY_PRICE_BUCKETS_PER_UNIT;
9887
+ return Math.round(toScaled(price, DISPLAY_ROUNDING_PRECISION) / bucketSize) / DISPLAY_PRICE_BUCKETS_PER_UNIT;
9888
+ };
9883
9889
  var normalizeOutcomeLabel = (value) => {
9884
9890
  if (typeof value !== "string") return "";
9885
9891
  return value.trim().toLowerCase().replace(/[_-]+/g, " ").replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ");
@@ -9993,7 +9999,7 @@ var buildRowsFromAccumulator = ({
9993
9999
  venues,
9994
10000
  price: roundTo(level.price, PRICE_PRECISION),
9995
10001
  size,
9996
- total: roundTo(level.price * size, SIZE_PRECISION),
10002
+ total: roundTo(level.notional, SIZE_PRECISION),
9997
10003
  tone,
9998
10004
  barScale: 0,
9999
10005
  venueBreakdown,
@@ -10011,6 +10017,7 @@ var accumulateSideLevels = ({
10011
10017
  orderbooksByOutcomeId
10012
10018
  }) => {
10013
10019
  const levelsByPrice = /* @__PURE__ */ new Map();
10020
+ let bestPrice = null;
10014
10021
  const includedOutcomeIds = /* @__PURE__ */ new Set();
10015
10022
  const missingOutcomeIds = /* @__PURE__ */ new Set();
10016
10023
  eligibleOutcomes.forEach((eligibleOutcome) => {
@@ -10026,18 +10033,25 @@ var accumulateSideLevels = ({
10026
10033
  includedOutcomeIds.add(eligibleOutcome.outcomeId);
10027
10034
  venueLevels.forEach((level) => {
10028
10035
  var _a;
10029
- const priceKey = toPriceKey(level.price);
10036
+ if (bestPrice == null || (side === "asks" ? level.price < bestPrice : level.price > bestPrice)) {
10037
+ bestPrice = level.price;
10038
+ }
10039
+ const displayPrice = toDisplayPrice(level.price);
10040
+ const priceKey = toPriceKey(displayPrice);
10030
10041
  const scaledSize = toScaled(level.size, SIZE_PRECISION);
10042
+ const notional = level.price * level.size;
10031
10043
  const currentLevel = levelsByPrice.get(priceKey);
10032
10044
  if (currentLevel) {
10033
10045
  currentLevel.sizeScaled += scaledSize;
10046
+ currentLevel.notional += notional;
10034
10047
  currentLevel.venueBreakdownScaled[eligibleOutcome.venue] = ((_a = currentLevel.venueBreakdownScaled[eligibleOutcome.venue]) != null ? _a : 0) + scaledSize;
10035
10048
  currentLevel.sourceOutcomeIds.add(eligibleOutcome.outcomeId);
10036
10049
  return;
10037
10050
  }
10038
10051
  levelsByPrice.set(priceKey, {
10039
- price: level.price,
10052
+ price: displayPrice,
10040
10053
  sizeScaled: scaledSize,
10054
+ notional,
10041
10055
  venueBreakdownScaled: {
10042
10056
  [eligibleOutcome.venue]: scaledSize
10043
10057
  },
@@ -10047,6 +10061,7 @@ var accumulateSideLevels = ({
10047
10061
  });
10048
10062
  return {
10049
10063
  levelsByPrice,
10064
+ bestPrice,
10050
10065
  includedOutcomeIds,
10051
10066
  missingOutcomeIds
10052
10067
  };
@@ -10214,7 +10229,7 @@ var mergeVenueOutcomeOrderbooks = ({
10214
10229
  eligibleOutcomes,
10215
10230
  orderbooksByOutcomeId
10216
10231
  }) => {
10217
- var _a, _b, _c, _d, _e, _f;
10232
+ var _a, _b;
10218
10233
  const bidState = accumulateSideLevels({
10219
10234
  side: "bids",
10220
10235
  eligibleOutcomes,
@@ -10237,8 +10252,8 @@ var mergeVenueOutcomeOrderbooks = ({
10237
10252
  levelsByPrice: askState.levelsByPrice,
10238
10253
  fallbackVenue: (_b = eligibleOutcomes[0]) == null ? void 0 : _b.venue
10239
10254
  });
10240
- const bestBid = (_d = (_c = bidRows[0]) == null ? void 0 : _c.price) != null ? _d : null;
10241
- const bestAsk = (_f = (_e = askRows[0]) == null ? void 0 : _e.price) != null ? _f : null;
10255
+ const bestBid = bidState.bestPrice;
10256
+ const bestAsk = askState.bestPrice;
10242
10257
  return {
10243
10258
  askRows,
10244
10259
  bidRows,
package/dist/events.mjs CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  orderbookRowLimitDefault,
18
18
  resolveEventDetailsSyncKey,
19
19
  useCenterOrderbookSpread
20
- } from "./chunk-EYJS45RP.mjs";
20
+ } from "./chunk-IS45S6R3.mjs";
21
21
  import {
22
22
  formatProbabilityCents,
23
23
  resolveOrderBookRows,
package/dist/index.js CHANGED
@@ -13754,6 +13754,8 @@ var buildMarketDetailsModel = ({
13754
13754
  var import_hooks46 = require("@agg-build/hooks");
13755
13755
  var PRICE_PRECISION = 1e6;
13756
13756
  var SIZE_PRECISION = 1e8;
13757
+ var DISPLAY_PRICE_BUCKETS_PER_UNIT = 1e3;
13758
+ var DISPLAY_ROUNDING_PRECISION = 1e9;
13757
13759
  var POSITIVE_OUTCOME_KEYS = /* @__PURE__ */ new Set(["yes", "y", "true", "up", "buy", "long"]);
13758
13760
  var NEGATIVE_OUTCOME_KEYS = /* @__PURE__ */ new Set(["no", "n", "false", "down", "sell", "short"]);
13759
13761
  var roundTo = (value, precision) => {
@@ -13768,6 +13770,10 @@ var fromScaled = (value, precision) => {
13768
13770
  var toPriceKey = (price) => {
13769
13771
  return String(toScaled(price, PRICE_PRECISION));
13770
13772
  };
13773
+ var toDisplayPrice = (price) => {
13774
+ const bucketSize = DISPLAY_ROUNDING_PRECISION / DISPLAY_PRICE_BUCKETS_PER_UNIT;
13775
+ return Math.round(toScaled(price, DISPLAY_ROUNDING_PRECISION) / bucketSize) / DISPLAY_PRICE_BUCKETS_PER_UNIT;
13776
+ };
13771
13777
  var normalizeOutcomeLabel = (value) => {
13772
13778
  if (typeof value !== "string") return "";
13773
13779
  return value.trim().toLowerCase().replace(/[_-]+/g, " ").replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ");
@@ -13881,7 +13887,7 @@ var buildRowsFromAccumulator = ({
13881
13887
  venues,
13882
13888
  price: roundTo(level.price, PRICE_PRECISION),
13883
13889
  size,
13884
- total: roundTo(level.price * size, SIZE_PRECISION),
13890
+ total: roundTo(level.notional, SIZE_PRECISION),
13885
13891
  tone,
13886
13892
  barScale: 0,
13887
13893
  venueBreakdown,
@@ -13899,6 +13905,7 @@ var accumulateSideLevels = ({
13899
13905
  orderbooksByOutcomeId
13900
13906
  }) => {
13901
13907
  const levelsByPrice = /* @__PURE__ */ new Map();
13908
+ let bestPrice = null;
13902
13909
  const includedOutcomeIds = /* @__PURE__ */ new Set();
13903
13910
  const missingOutcomeIds = /* @__PURE__ */ new Set();
13904
13911
  eligibleOutcomes.forEach((eligibleOutcome) => {
@@ -13914,18 +13921,25 @@ var accumulateSideLevels = ({
13914
13921
  includedOutcomeIds.add(eligibleOutcome.outcomeId);
13915
13922
  venueLevels.forEach((level) => {
13916
13923
  var _a;
13917
- const priceKey = toPriceKey(level.price);
13924
+ if (bestPrice == null || (side === "asks" ? level.price < bestPrice : level.price > bestPrice)) {
13925
+ bestPrice = level.price;
13926
+ }
13927
+ const displayPrice = toDisplayPrice(level.price);
13928
+ const priceKey = toPriceKey(displayPrice);
13918
13929
  const scaledSize = toScaled(level.size, SIZE_PRECISION);
13930
+ const notional = level.price * level.size;
13919
13931
  const currentLevel = levelsByPrice.get(priceKey);
13920
13932
  if (currentLevel) {
13921
13933
  currentLevel.sizeScaled += scaledSize;
13934
+ currentLevel.notional += notional;
13922
13935
  currentLevel.venueBreakdownScaled[eligibleOutcome.venue] = ((_a = currentLevel.venueBreakdownScaled[eligibleOutcome.venue]) != null ? _a : 0) + scaledSize;
13923
13936
  currentLevel.sourceOutcomeIds.add(eligibleOutcome.outcomeId);
13924
13937
  return;
13925
13938
  }
13926
13939
  levelsByPrice.set(priceKey, {
13927
- price: level.price,
13940
+ price: displayPrice,
13928
13941
  sizeScaled: scaledSize,
13942
+ notional,
13929
13943
  venueBreakdownScaled: {
13930
13944
  [eligibleOutcome.venue]: scaledSize
13931
13945
  },
@@ -13935,6 +13949,7 @@ var accumulateSideLevels = ({
13935
13949
  });
13936
13950
  return {
13937
13951
  levelsByPrice,
13952
+ bestPrice,
13938
13953
  includedOutcomeIds,
13939
13954
  missingOutcomeIds
13940
13955
  };
@@ -14102,7 +14117,7 @@ var mergeVenueOutcomeOrderbooks = ({
14102
14117
  eligibleOutcomes,
14103
14118
  orderbooksByOutcomeId
14104
14119
  }) => {
14105
- var _a, _b, _c, _d, _e, _f;
14120
+ var _a, _b;
14106
14121
  const bidState = accumulateSideLevels({
14107
14122
  side: "bids",
14108
14123
  eligibleOutcomes,
@@ -14125,8 +14140,8 @@ var mergeVenueOutcomeOrderbooks = ({
14125
14140
  levelsByPrice: askState.levelsByPrice,
14126
14141
  fallbackVenue: (_b = eligibleOutcomes[0]) == null ? void 0 : _b.venue
14127
14142
  });
14128
- const bestBid = (_d = (_c = bidRows[0]) == null ? void 0 : _c.price) != null ? _d : null;
14129
- const bestAsk = (_f = (_e = askRows[0]) == null ? void 0 : _e.price) != null ? _f : null;
14143
+ const bestBid = bidState.bestPrice;
14144
+ const bestAsk = askState.bestPrice;
14130
14145
  return {
14131
14146
  askRows,
14132
14147
  bidRows,
@@ -29301,6 +29316,16 @@ var aggregateSportsLineStops = (markets, isSpread = false) => {
29301
29316
  (left, right) => left.lineValue !== right.lineValue ? left.lineValue - right.lineValue : left.value.localeCompare(right.value)
29302
29317
  );
29303
29318
  };
29319
+ var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
29320
+ var resolveSportsLadderTitle = (group, selectedLineDisplay) => {
29321
+ var _a;
29322
+ const anchorLineValue = (_a = group.markets[0]) == null ? void 0 : _a.lineValue;
29323
+ if (anchorLineValue == null || !selectedLineDisplay) return group.title;
29324
+ const anchorDisplay = resolveSelectedSportsLineValue(anchorLineValue);
29325
+ if (anchorDisplay === selectedLineDisplay) return group.title;
29326
+ const pattern = new RegExp(`(^|[^\\d.])${escapeRegExp(anchorDisplay)}(?![\\d.])`);
29327
+ return pattern.test(group.title) ? group.title.replace(pattern, (_match, prefix) => `${prefix}${selectedLineDisplay}`) : group.title;
29328
+ };
29304
29329
  var buildSportsSlideFromGroup = (group) => {
29305
29330
  const lineStops = group.hasLineVariants ? aggregateSportsLineStops(group.markets, group.sportsMarketType === "spread") : [];
29306
29331
  const hasLadder = lineStops.length > 1;
@@ -29809,6 +29834,8 @@ var SportsMarketCard = ({
29809
29834
  });
29810
29835
  }, [slide.kind, activeMarket, group.markets, midpointsResult]);
29811
29836
  if (!activeMarket) return null;
29837
+ const selectedStop = slide.hasLadder ? slide.stops[selectedLineIndex] : void 0;
29838
+ const cardTitle = selectedStop ? resolveSportsLadderTitle(group, selectedStop.value) : group.title;
29812
29839
  const activeOutcome = (_h = activeMarket.venueMarketOutcomes.find(
29813
29840
  (outcome) => outcome.id === (tradingContext == null ? void 0 : tradingContext.selectedOutcomeId)
29814
29841
  )) != null ? _h : activeDefaultOutcome;
@@ -29869,7 +29896,7 @@ var SportsMarketCard = ({
29869
29896
  {
29870
29897
  marketId: activeMarket.id,
29871
29898
  venueMarkets,
29872
- title: group.title,
29899
+ title: cardTitle,
29873
29900
  compactHeader: true,
29874
29901
  subtitleOverride: compactSubtitle,
29875
29902
  headerOutcomeVariant,
@@ -29888,9 +29915,9 @@ var SportsMarketCard = ({
29888
29915
  })),
29889
29916
  selectedIndex: selectedLineIndex,
29890
29917
  onSelect: handleLineSelect,
29891
- ariaLabel: labels.eventMarketPage.sports.lineSelectorAria(group.title),
29892
- previousAriaLabel: labels.eventMarketPage.sports.previousLineAria(group.title),
29893
- nextAriaLabel: labels.eventMarketPage.sports.nextLineAria(group.title)
29918
+ ariaLabel: labels.eventMarketPage.sports.lineSelectorAria(cardTitle),
29919
+ previousAriaLabel: labels.eventMarketPage.sports.previousLineAria(cardTitle),
29920
+ nextAriaLabel: labels.eventMarketPage.sports.nextLineAria(cardTitle)
29894
29921
  }
29895
29922
  ) : void 0,
29896
29923
  classNames: { root: "agg-market-list-item agg-sports-market-card" },
@@ -39154,7 +39181,9 @@ var TRADING_ACCESS_VENUES = [
39154
39181
  "limitless",
39155
39182
  "predict",
39156
39183
  "myriad",
39157
- "hyperliquid"
39184
+ "hyperliquid",
39185
+ "novig",
39186
+ "prophetx"
39158
39187
  ];
39159
39188
  var TRADING_ACCESS_VENUE_ITEMS = TRADING_ACCESS_VENUES.map((id) => ({ id }));
39160
39189
  var SectionTitle2 = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime217.jsx)("h3", { className: "text-agg-sm font-agg-bold leading-agg-5 text-agg-foreground", children });
package/dist/index.mjs CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  formatRecurringCountdown,
15
15
  formatShareAmount,
16
16
  useHomePageModals
17
- } from "./chunk-5D36HPOG.mjs";
17
+ } from "./chunk-VAL2IB3M.mjs";
18
18
  import {
19
19
  EventList,
20
20
  EventListItem,
@@ -32,7 +32,7 @@ import {
32
32
  orderbookRowLimitDefault,
33
33
  resolveEventDetailsSyncKey,
34
34
  useCenterOrderbookSpread
35
- } from "./chunk-EYJS45RP.mjs";
35
+ } from "./chunk-IS45S6R3.mjs";
36
36
  import {
37
37
  CARD_NETWORK_OPTIONS,
38
38
  DepositModal,
@@ -45,7 +45,7 @@ import {
45
45
  buildTerminalSummary,
46
46
  clearPendingCardSession,
47
47
  getPendingCardSession
48
- } from "./chunk-I72YHWOI.mjs";
48
+ } from "./chunk-UVJ5FBZF.mjs";
49
49
  import {
50
50
  AggNotificationEventsProvider,
51
51
  DEPOSIT_MODAL_OPEN_EVENT,
package/dist/modals.js CHANGED
@@ -9892,7 +9892,9 @@ var TRADING_ACCESS_VENUES = [
9892
9892
  "limitless",
9893
9893
  "predict",
9894
9894
  "myriad",
9895
- "hyperliquid"
9895
+ "hyperliquid",
9896
+ "novig",
9897
+ "prophetx"
9896
9898
  ];
9897
9899
  var TRADING_ACCESS_VENUE_ITEMS = TRADING_ACCESS_VENUES.map((id) => ({ id }));
9898
9900
  var SectionTitle2 = ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime145.jsx)("h3", { className: "text-agg-sm font-agg-bold leading-agg-5 text-agg-foreground", children });
package/dist/modals.mjs CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  buildTerminalSummary,
12
12
  clearPendingCardSession,
13
13
  getPendingCardSession
14
- } from "./chunk-I72YHWOI.mjs";
14
+ } from "./chunk-UVJ5FBZF.mjs";
15
15
  import {
16
16
  ConnectAccountsStep,
17
17
  ConnectKalshiModal,
package/dist/pages.js CHANGED
@@ -12344,6 +12344,8 @@ var buildMarketDetailsModel = ({
12344
12344
  var import_hooks44 = require("@agg-build/hooks");
12345
12345
  var PRICE_PRECISION = 1e6;
12346
12346
  var SIZE_PRECISION = 1e8;
12347
+ var DISPLAY_PRICE_BUCKETS_PER_UNIT = 1e3;
12348
+ var DISPLAY_ROUNDING_PRECISION = 1e9;
12347
12349
  var POSITIVE_OUTCOME_KEYS = /* @__PURE__ */ new Set(["yes", "y", "true", "up", "buy", "long"]);
12348
12350
  var NEGATIVE_OUTCOME_KEYS = /* @__PURE__ */ new Set(["no", "n", "false", "down", "sell", "short"]);
12349
12351
  var roundTo = (value, precision) => {
@@ -12358,6 +12360,10 @@ var fromScaled = (value, precision) => {
12358
12360
  var toPriceKey = (price) => {
12359
12361
  return String(toScaled(price, PRICE_PRECISION));
12360
12362
  };
12363
+ var toDisplayPrice = (price) => {
12364
+ const bucketSize = DISPLAY_ROUNDING_PRECISION / DISPLAY_PRICE_BUCKETS_PER_UNIT;
12365
+ return Math.round(toScaled(price, DISPLAY_ROUNDING_PRECISION) / bucketSize) / DISPLAY_PRICE_BUCKETS_PER_UNIT;
12366
+ };
12361
12367
  var normalizeOutcomeLabel = (value) => {
12362
12368
  if (typeof value !== "string") return "";
12363
12369
  return value.trim().toLowerCase().replace(/[_-]+/g, " ").replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\s+/g, " ");
@@ -12471,7 +12477,7 @@ var buildRowsFromAccumulator = ({
12471
12477
  venues,
12472
12478
  price: roundTo(level.price, PRICE_PRECISION),
12473
12479
  size,
12474
- total: roundTo(level.price * size, SIZE_PRECISION),
12480
+ total: roundTo(level.notional, SIZE_PRECISION),
12475
12481
  tone,
12476
12482
  barScale: 0,
12477
12483
  venueBreakdown,
@@ -12489,6 +12495,7 @@ var accumulateSideLevels = ({
12489
12495
  orderbooksByOutcomeId
12490
12496
  }) => {
12491
12497
  const levelsByPrice = /* @__PURE__ */ new Map();
12498
+ let bestPrice = null;
12492
12499
  const includedOutcomeIds = /* @__PURE__ */ new Set();
12493
12500
  const missingOutcomeIds = /* @__PURE__ */ new Set();
12494
12501
  eligibleOutcomes.forEach((eligibleOutcome) => {
@@ -12504,18 +12511,25 @@ var accumulateSideLevels = ({
12504
12511
  includedOutcomeIds.add(eligibleOutcome.outcomeId);
12505
12512
  venueLevels.forEach((level) => {
12506
12513
  var _a;
12507
- const priceKey = toPriceKey(level.price);
12514
+ if (bestPrice == null || (side === "asks" ? level.price < bestPrice : level.price > bestPrice)) {
12515
+ bestPrice = level.price;
12516
+ }
12517
+ const displayPrice = toDisplayPrice(level.price);
12518
+ const priceKey = toPriceKey(displayPrice);
12508
12519
  const scaledSize = toScaled(level.size, SIZE_PRECISION);
12520
+ const notional = level.price * level.size;
12509
12521
  const currentLevel = levelsByPrice.get(priceKey);
12510
12522
  if (currentLevel) {
12511
12523
  currentLevel.sizeScaled += scaledSize;
12524
+ currentLevel.notional += notional;
12512
12525
  currentLevel.venueBreakdownScaled[eligibleOutcome.venue] = ((_a = currentLevel.venueBreakdownScaled[eligibleOutcome.venue]) != null ? _a : 0) + scaledSize;
12513
12526
  currentLevel.sourceOutcomeIds.add(eligibleOutcome.outcomeId);
12514
12527
  return;
12515
12528
  }
12516
12529
  levelsByPrice.set(priceKey, {
12517
- price: level.price,
12530
+ price: displayPrice,
12518
12531
  sizeScaled: scaledSize,
12532
+ notional,
12519
12533
  venueBreakdownScaled: {
12520
12534
  [eligibleOutcome.venue]: scaledSize
12521
12535
  },
@@ -12525,6 +12539,7 @@ var accumulateSideLevels = ({
12525
12539
  });
12526
12540
  return {
12527
12541
  levelsByPrice,
12542
+ bestPrice,
12528
12543
  includedOutcomeIds,
12529
12544
  missingOutcomeIds
12530
12545
  };
@@ -12681,7 +12696,7 @@ var mergeVenueOutcomeOrderbooks = ({
12681
12696
  eligibleOutcomes,
12682
12697
  orderbooksByOutcomeId
12683
12698
  }) => {
12684
- var _a, _b, _c, _d, _e, _f;
12699
+ var _a, _b;
12685
12700
  const bidState = accumulateSideLevels({
12686
12701
  side: "bids",
12687
12702
  eligibleOutcomes,
@@ -12704,8 +12719,8 @@ var mergeVenueOutcomeOrderbooks = ({
12704
12719
  levelsByPrice: askState.levelsByPrice,
12705
12720
  fallbackVenue: (_b = eligibleOutcomes[0]) == null ? void 0 : _b.venue
12706
12721
  });
12707
- const bestBid = (_d = (_c = bidRows[0]) == null ? void 0 : _c.price) != null ? _d : null;
12708
- const bestAsk = (_f = (_e = askRows[0]) == null ? void 0 : _e.price) != null ? _f : null;
12722
+ const bestBid = bidState.bestPrice;
12723
+ const bestAsk = askState.bestPrice;
12709
12724
  return {
12710
12725
  askRows,
12711
12726
  bidRows,
@@ -26976,6 +26991,16 @@ var aggregateSportsLineStops = (markets, isSpread = false) => {
26976
26991
  (left, right) => left.lineValue !== right.lineValue ? left.lineValue - right.lineValue : left.value.localeCompare(right.value)
26977
26992
  );
26978
26993
  };
26994
+ var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
26995
+ var resolveSportsLadderTitle = (group, selectedLineDisplay) => {
26996
+ var _a;
26997
+ const anchorLineValue = (_a = group.markets[0]) == null ? void 0 : _a.lineValue;
26998
+ if (anchorLineValue == null || !selectedLineDisplay) return group.title;
26999
+ const anchorDisplay = resolveSelectedSportsLineValue(anchorLineValue);
27000
+ if (anchorDisplay === selectedLineDisplay) return group.title;
27001
+ const pattern = new RegExp(`(^|[^\\d.])${escapeRegExp(anchorDisplay)}(?![\\d.])`);
27002
+ return pattern.test(group.title) ? group.title.replace(pattern, (_match, prefix) => `${prefix}${selectedLineDisplay}`) : group.title;
27003
+ };
26979
27004
  var buildSportsSlideFromGroup = (group) => {
26980
27005
  const lineStops = group.hasLineVariants ? aggregateSportsLineStops(group.markets, group.sportsMarketType === "spread") : [];
26981
27006
  const hasLadder = lineStops.length > 1;
@@ -27484,6 +27509,8 @@ var SportsMarketCard = ({
27484
27509
  });
27485
27510
  }, [slide.kind, activeMarket, group.markets, midpointsResult]);
27486
27511
  if (!activeMarket) return null;
27512
+ const selectedStop = slide.hasLadder ? slide.stops[selectedLineIndex] : void 0;
27513
+ const cardTitle = selectedStop ? resolveSportsLadderTitle(group, selectedStop.value) : group.title;
27487
27514
  const activeOutcome = (_h = activeMarket.venueMarketOutcomes.find(
27488
27515
  (outcome) => outcome.id === (tradingContext == null ? void 0 : tradingContext.selectedOutcomeId)
27489
27516
  )) != null ? _h : activeDefaultOutcome;
@@ -27544,7 +27571,7 @@ var SportsMarketCard = ({
27544
27571
  {
27545
27572
  marketId: activeMarket.id,
27546
27573
  venueMarkets,
27547
- title: group.title,
27574
+ title: cardTitle,
27548
27575
  compactHeader: true,
27549
27576
  subtitleOverride: compactSubtitle,
27550
27577
  headerOutcomeVariant,
@@ -27563,9 +27590,9 @@ var SportsMarketCard = ({
27563
27590
  })),
27564
27591
  selectedIndex: selectedLineIndex,
27565
27592
  onSelect: handleLineSelect,
27566
- ariaLabel: labels.eventMarketPage.sports.lineSelectorAria(group.title),
27567
- previousAriaLabel: labels.eventMarketPage.sports.previousLineAria(group.title),
27568
- nextAriaLabel: labels.eventMarketPage.sports.nextLineAria(group.title)
27593
+ ariaLabel: labels.eventMarketPage.sports.lineSelectorAria(cardTitle),
27594
+ previousAriaLabel: labels.eventMarketPage.sports.previousLineAria(cardTitle),
27595
+ nextAriaLabel: labels.eventMarketPage.sports.nextLineAria(cardTitle)
27569
27596
  }
27570
27597
  ) : void 0,
27571
27598
  classNames: { root: "agg-market-list-item agg-sports-market-card" },
package/dist/pages.mjs CHANGED
@@ -11,8 +11,8 @@ import {
11
11
  formatRecurringCountdown,
12
12
  formatShareAmount,
13
13
  useHomePageModals
14
- } from "./chunk-5D36HPOG.mjs";
15
- import "./chunk-EYJS45RP.mjs";
14
+ } from "./chunk-VAL2IB3M.mjs";
15
+ import "./chunk-IS45S6R3.mjs";
16
16
  import {
17
17
  DEPOSIT_MODAL_OPEN_EVENT,
18
18
  WITHDRAW_MODAL_OPEN_EVENT,
@@ -30,6 +30,11 @@ export type SportsSectionTab = {
30
30
  export type SportsMarketCardVariant = "outcome" | "line" | "yes_no";
31
31
  export type SportsMarketDisplayGroup = {
32
32
  id: string;
33
+ /**
34
+ * Wording for the whole group, derived from `markets[0]`. On a line ladder that
35
+ * is the LOWEST rung, so any line it names is the lowest one — the card swaps
36
+ * in the selected rung's number via {@link resolveSportsLadderTitle}.
37
+ */
33
38
  title: string;
34
39
  questionKey: string;
35
40
  sportsMarketType: SportsMarketTypeKey | null;
@@ -184,6 +189,28 @@ export type SportsCombinedLeg = {
184
189
  * ponytail: O(n) map build over one group's markets (a handful of rows).
185
190
  */
186
191
  export declare const resolveSportsCombinedLegs: (group: Pick<SportsMarketDisplayGroup, "markets" | "sportsMarketType">) => SportsCombinedLeg[] | null;
192
+ /**
193
+ * The group's wording with the SELECTED rung's number in it.
194
+ *
195
+ * `group.title` is derived once, from `markets[0]` — the lowest rung — while the
196
+ * card renders whichever rung the rail has selected (by default the
197
+ * highest-volume one). Where a venue spells the line into its question and our
198
+ * cleaner can't strip it (kalshi's "Kentucky over 2.5 points scored" keeps its
199
+ * line because the strip is anchored to the END of the string), the heading
200
+ * quoted a line the card was not showing — contradicting its own chip, its
201
+ * Yes/No pills and the trade panel.
202
+ *
203
+ * Only the digits move. Re-deriving the title from the selected market instead
204
+ * would reword the card rung to rung, because the ladder is stocked from
205
+ * whichever venue lists each line and they phrase the same bet differently
206
+ * ("Kentucky O/U 23.5" strips down to a bare "Kentucky Totals", and prophetx
207
+ * would put "ALA: Team Points Fixed" in the header). One wording, one number.
208
+ *
209
+ * A title with no line in it — "Spreads", "Total Points", or a ladder whose
210
+ * lowest rung came from a venue we DO strip cleanly — has nothing to swap and is
211
+ * returned untouched.
212
+ */
213
+ export declare const resolveSportsLadderTitle: (group: SportsMarketDisplayGroup, selectedLineDisplay: string) => string;
187
214
  export declare const buildSportsSlideFromGroup: (group: SportsMarketDisplayGroup) => SportsGameLineSlide;
188
215
  /**
189
216
  * Derive the Moneyline / Spreads / Total game-line slides (in that order) from a
@@ -30,6 +30,11 @@ export type SportsSectionTab = {
30
30
  export type SportsMarketCardVariant = "outcome" | "line" | "yes_no";
31
31
  export type SportsMarketDisplayGroup = {
32
32
  id: string;
33
+ /**
34
+ * Wording for the whole group, derived from `markets[0]`. On a line ladder that
35
+ * is the LOWEST rung, so any line it names is the lowest one — the card swaps
36
+ * in the selected rung's number via {@link resolveSportsLadderTitle}.
37
+ */
33
38
  title: string;
34
39
  questionKey: string;
35
40
  sportsMarketType: SportsMarketTypeKey | null;
@@ -184,6 +189,28 @@ export type SportsCombinedLeg = {
184
189
  * ponytail: O(n) map build over one group's markets (a handful of rows).
185
190
  */
186
191
  export declare const resolveSportsCombinedLegs: (group: Pick<SportsMarketDisplayGroup, "markets" | "sportsMarketType">) => SportsCombinedLeg[] | null;
192
+ /**
193
+ * The group's wording with the SELECTED rung's number in it.
194
+ *
195
+ * `group.title` is derived once, from `markets[0]` — the lowest rung — while the
196
+ * card renders whichever rung the rail has selected (by default the
197
+ * highest-volume one). Where a venue spells the line into its question and our
198
+ * cleaner can't strip it (kalshi's "Kentucky over 2.5 points scored" keeps its
199
+ * line because the strip is anchored to the END of the string), the heading
200
+ * quoted a line the card was not showing — contradicting its own chip, its
201
+ * Yes/No pills and the trade panel.
202
+ *
203
+ * Only the digits move. Re-deriving the title from the selected market instead
204
+ * would reword the card rung to rung, because the ladder is stocked from
205
+ * whichever venue lists each line and they phrase the same bet differently
206
+ * ("Kentucky O/U 23.5" strips down to a bare "Kentucky Totals", and prophetx
207
+ * would put "ALA: Team Points Fixed" in the header). One wording, one number.
208
+ *
209
+ * A title with no line in it — "Spreads", "Total Points", or a ladder whose
210
+ * lowest rung came from a venue we DO strip cleanly — has nothing to swap and is
211
+ * returned untouched.
212
+ */
213
+ export declare const resolveSportsLadderTitle: (group: SportsMarketDisplayGroup, selectedLineDisplay: string) => string;
187
214
  export declare const buildSportsSlideFromGroup: (group: SportsMarketDisplayGroup) => SportsGameLineSlide;
188
215
  /**
189
216
  * Derive the Moneyline / Spreads / Total game-line slides (in that order) from a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agg-build/ui",
3
- "version": "4.11.3",
3
+ "version": "4.13.2",
4
4
  "description": "Pre-built React component library for the AGG prediction market aggregator. Tailwind-based, themeable, with primitives, event surfaces, trading flows, full pages, and modals.",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",
@@ -101,7 +101,7 @@
101
101
  "react": "^18.0.0 || ^19.0.0",
102
102
  "react-dom": "^18.0.0 || ^19.0.0",
103
103
  "@agg-build/hooks": "^4.11.0",
104
- "@agg-build/sdk": "^4.11.3"
104
+ "@agg-build/sdk": "^4.13.1"
105
105
  },
106
106
  "dependencies": {
107
107
  "@number-flow/react": "^0.6.0",