@agg-build/ui 2.1.4 → 2.2.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 (37) hide show
  1. package/dist/{chunk-T4YZGAYS.mjs → chunk-5MRFY5ZQ.mjs} +1 -1
  2. package/dist/{chunk-BW7S2YR3.mjs → chunk-73MO7MYG.mjs} +21 -17
  3. package/dist/{chunk-TBZWRUFB.mjs → chunk-BTRFSEPC.mjs} +97 -61
  4. package/dist/{chunk-FLESSOSU.mjs → chunk-DTOI4V6P.mjs} +47 -10
  5. package/dist/{chunk-XHE2VO3S.mjs → chunk-HNLA44SY.mjs} +2 -2
  6. package/dist/{chunk-VP76G6PN.mjs → chunk-MIAAL7BL.mjs} +79 -23
  7. package/dist/{chunk-R2YNZJZ3.mjs → chunk-TR7HUVY7.mjs} +1 -1
  8. package/dist/events.js +93 -52
  9. package/dist/events.mjs +3 -3
  10. package/dist/index.js +214 -93
  11. package/dist/index.mjs +7 -7
  12. package/dist/modals.mjs +3 -3
  13. package/dist/pages.js +214 -93
  14. package/dist/pages.mjs +6 -6
  15. package/dist/primitives.js +70 -23
  16. package/dist/primitives.mjs +1 -1
  17. package/dist/trading.js +17 -14
  18. package/dist/trading.mjs +4 -4
  19. package/dist/types/events/item/event-list-item.types.d.mts +2 -2
  20. package/dist/types/events/item/event-list-item.types.d.ts +2 -2
  21. package/dist/types/events/item/event-list-item.utils.d.mts +2 -1
  22. package/dist/types/events/item/event-list-item.utils.d.ts +2 -1
  23. package/dist/types/events/item-details/event-list-item-details.types.d.mts +0 -1
  24. package/dist/types/events/item-details/event-list-item-details.types.d.ts +0 -1
  25. package/dist/types/events/market-details/market-details.types.d.mts +1 -0
  26. package/dist/types/events/market-details/market-details.types.d.ts +1 -0
  27. package/dist/types/events/shared/chart-venue-selection.d.mts +2 -1
  28. package/dist/types/events/shared/chart-venue-selection.d.ts +2 -1
  29. package/dist/types/pages/event-market/sports-event-market.utils.d.mts +15 -1
  30. package/dist/types/pages/event-market/sports-event-market.utils.d.ts +15 -1
  31. package/dist/types/primitives/search/search.types.d.mts +1 -0
  32. package/dist/types/primitives/search/search.types.d.ts +1 -0
  33. package/dist/types/primitives/search/search.utils.d.mts +4 -1
  34. package/dist/types/primitives/search/search.utils.d.ts +4 -1
  35. package/dist/types/trading/types.d.mts +2 -1
  36. package/dist/types/trading/types.d.ts +2 -1
  37. package/package.json +3 -3
@@ -6731,7 +6731,11 @@ var formatMarketProbabilityPercent = (value, formatPercent = formatWholePercent)
6731
6731
  }
6732
6732
  return formattedValue;
6733
6733
  };
6734
- var sortOutcomes = (outcomes) => {
6734
+ var resolveOutcomeProbability = (outcome, priceByOutcomeId) => {
6735
+ const resolvedPrice = priceByOutcomeId === void 0 ? outcome.price : priceByOutcomeId.has(outcome.id) ? priceByOutcomeId.get(outcome.id) : void 0;
6736
+ return normalizeProbability(resolvedPrice);
6737
+ };
6738
+ var sortOutcomesWithPrices = (outcomes, priceByOutcomeId) => {
6735
6739
  if (outcomes.length <= 1) return outcomes;
6736
6740
  if (hasBinaryOutcomes(outcomes)) {
6737
6741
  return sortYesFirst(outcomes);
@@ -6747,38 +6751,41 @@ var sortOutcomes = (outcomes) => {
6747
6751
  }
6748
6752
  return [...outcomes].sort((a, b) => {
6749
6753
  var _a, _b;
6750
- const aPrice = (_a = normalizeProbability(a.price)) != null ? _a : 0;
6751
- const bPrice = (_b = normalizeProbability(b.price)) != null ? _b : 0;
6754
+ const aPrice = (_a = resolveOutcomeProbability(a, priceByOutcomeId)) != null ? _a : 0;
6755
+ const bPrice = (_b = resolveOutcomeProbability(b, priceByOutcomeId)) != null ? _b : 0;
6752
6756
  return bPrice - aPrice;
6753
6757
  });
6754
6758
  };
6755
- var compareVisibleOutcomeRows = (left, right) => {
6759
+ var compareVisibleOutcomeRows = (left, right, priceByOutcomeId) => {
6756
6760
  var _a, _b;
6757
6761
  const leftDate = toDate(resolveOutcomeTitle(left.outcome));
6758
6762
  const rightDate = toDate(resolveOutcomeTitle(right.outcome));
6759
6763
  if (leftDate && rightDate) {
6760
6764
  return leftDate.getTime() - rightDate.getTime();
6761
6765
  }
6762
- const leftProbability = (_a = normalizeProbability(left.outcome.price)) != null ? _a : -1;
6763
- const rightProbability = (_b = normalizeProbability(right.outcome.price)) != null ? _b : -1;
6766
+ const leftProbability = (_a = resolveOutcomeProbability(left.outcome, priceByOutcomeId)) != null ? _a : -1;
6767
+ const rightProbability = (_b = resolveOutcomeProbability(right.outcome, priceByOutcomeId)) != null ? _b : -1;
6764
6768
  return rightProbability - leftProbability;
6765
6769
  };
6766
- var shouldReplaceVisibleOutcome = (current, next) => {
6770
+ var shouldReplaceVisibleOutcome = (current, next, priceByOutcomeId) => {
6767
6771
  var _a, _b;
6768
6772
  const currentVolume = typeof current.market.volume === "number" ? current.market.volume : -1;
6769
6773
  const nextVolume = typeof next.market.volume === "number" ? next.market.volume : -1;
6770
6774
  if (currentVolume !== nextVolume) {
6771
6775
  return nextVolume > currentVolume;
6772
6776
  }
6773
- const currentProbability = (_a = normalizeProbability(current.outcome.price)) != null ? _a : -1;
6774
- const nextProbability = (_b = normalizeProbability(next.outcome.price)) != null ? _b : -1;
6777
+ const currentProbability = (_a = resolveOutcomeProbability(current.outcome, priceByOutcomeId)) != null ? _a : -1;
6778
+ const nextProbability = (_b = resolveOutcomeProbability(next.outcome, priceByOutcomeId)) != null ? _b : -1;
6775
6779
  return nextProbability > currentProbability;
6776
6780
  };
6777
- var resolveVisibleOutcomes = (venueMarkets) => {
6781
+ var resolveVisibleOutcomes = (venueMarkets, priceByOutcomeId) => {
6778
6782
  const visibleOutcomesByLabel = /* @__PURE__ */ new Map();
6779
6783
  venueMarkets.forEach((market) => {
6780
6784
  const title2 = market.question;
6781
- const canonicalOutcome = sortOutcomes(market.venueMarketOutcomes)[0];
6785
+ const canonicalOutcome = sortOutcomesWithPrices(
6786
+ market.venueMarketOutcomes,
6787
+ priceByOutcomeId
6788
+ )[0];
6782
6789
  if (!canonicalOutcome) return;
6783
6790
  const normalizedTitle = title2.trim().toLowerCase();
6784
6791
  const nextVisibleOutcome = {
@@ -6788,11 +6795,11 @@ var resolveVisibleOutcomes = (venueMarkets) => {
6788
6795
  title: title2
6789
6796
  };
6790
6797
  const currentVisibleOutcome = visibleOutcomesByLabel.get(normalizedTitle);
6791
- if (!currentVisibleOutcome || shouldReplaceVisibleOutcome(currentVisibleOutcome, nextVisibleOutcome)) {
6798
+ if (!currentVisibleOutcome || shouldReplaceVisibleOutcome(currentVisibleOutcome, nextVisibleOutcome, priceByOutcomeId)) {
6792
6799
  visibleOutcomesByLabel.set(normalizedTitle, nextVisibleOutcome);
6793
6800
  }
6794
6801
  });
6795
- return [...visibleOutcomesByLabel.values()].sort(compareVisibleOutcomeRows).slice(0, Math.max(1, 2));
6802
+ return [...visibleOutcomesByLabel.values()].sort((left, right) => compareVisibleOutcomeRows(left, right, priceByOutcomeId)).slice(0, Math.max(1, 2));
6796
6803
  };
6797
6804
  var resolveOutcomeTitle = (outcome) => {
6798
6805
  var _a, _b;
@@ -6853,18 +6860,19 @@ var toVenueLogoName = (value) => {
6853
6860
  if (!venueLogoNameSet.has(value)) return null;
6854
6861
  return value;
6855
6862
  };
6856
- var mapVenueEventToSearchResult = (event, labels, formatPercent, formatCompactCurrency) => {
6857
- var _a, _b;
6863
+ var mapVenueEventToSearchResult = (event, labels, formatPercent, formatCompactCurrency, options) => {
6864
+ var _a, _b, _c;
6858
6865
  const primaryVenueMarket = selectPrimaryVenueMarket(event.venueMarkets);
6859
6866
  if (!primaryVenueMarket) return null;
6860
6867
  const primaryVenue = toVenueLogoName(primaryVenueMarket.venue);
6861
6868
  if (!primaryVenue) return null;
6862
- const visibleOutcome = resolveVisibleOutcomes(event.venueMarkets)[0];
6869
+ const visibleOutcome = resolveVisibleOutcomes(event.venueMarkets, options == null ? void 0 : options.priceByOutcomeId)[0];
6863
6870
  if (!visibleOutcome) return null;
6864
- const probability = normalizeProbability(visibleOutcome.outcome.price);
6865
- if (probability == null) return null;
6871
+ const probability = normalizeProbability(
6872
+ (_a = options == null ? void 0 : options.priceByOutcomeId) == null ? void 0 : _a.get(visibleOutcome.outcome.id)
6873
+ );
6866
6874
  const resolvedTitle = formatEventTitleWithDateSuffix({
6867
- title: (_a = event == null ? void 0 : event.title) != null ? _a : "",
6875
+ title: (_b = event == null ? void 0 : event.title) != null ? _b : "",
6868
6876
  categories: event.categories,
6869
6877
  structureType: event.structureType,
6870
6878
  gameStartTime: event.gameStartTime,
@@ -6886,13 +6894,14 @@ var mapVenueEventToSearchResult = (event, labels, formatPercent, formatCompactCu
6886
6894
  return {
6887
6895
  id: event.id,
6888
6896
  title: resolvedTitle,
6889
- thumbnailSrc: (_b = resolveTileImage(event, primaryVenueMarket, void 0)) != null ? _b : "",
6897
+ thumbnailSrc: (_c = resolveTileImage(event, primaryVenueMarket, void 0)) != null ? _c : "",
6890
6898
  thumbnailAlt: resolvedTitle,
6891
6899
  venue: primaryVenue,
6892
6900
  visibleVenues,
6893
6901
  marketSummaryLabel,
6894
6902
  volumeLabel,
6895
6903
  valueLabel: formatMarketProbabilityPercent(probability, formatPercent),
6904
+ isValueLoading: probability == null && (options == null ? void 0 : options.isPriceLoading) === true,
6896
6905
  contextLabel: formatSearchContextLabel(visibleOutcome.title)
6897
6906
  };
6898
6907
  };
@@ -7002,7 +7011,16 @@ var SearchResultRow = ({
7002
7011
  children: [
7003
7012
  /* @__PURE__ */ (0, import_jsx_runtime119.jsx)(VenueLogo, { venue: item.venue, size: "small" }),
7004
7013
  /* @__PURE__ */ (0, import_jsx_runtime119.jsxs)("div", { className: "flex min-w-0 flex-1 items-baseline gap-2", children: [
7005
- /* @__PURE__ */ (0, import_jsx_runtime119.jsx)(
7014
+ item.isValueLoading ? /* @__PURE__ */ (0, import_jsx_runtime119.jsx)(
7015
+ "span",
7016
+ {
7017
+ "aria-hidden": "true",
7018
+ className: cn(
7019
+ "agg-search-result-value-loading",
7020
+ "h-5 w-12 shrink-0 rounded-agg-sm bg-agg-separator animate-pulse"
7021
+ )
7022
+ }
7023
+ ) : /* @__PURE__ */ (0, import_jsx_runtime119.jsx)(
7006
7024
  "p",
7007
7025
  {
7008
7026
  className: cn(
@@ -7115,6 +7133,24 @@ var Search = ({
7115
7133
  () => filterOpenEvents(searchResults),
7116
7134
  [searchResults]
7117
7135
  );
7136
+ const visibleVenueMarkets = (0, import_react9.useMemo)(
7137
+ () => openEvents.flatMap((event) => {
7138
+ var _a;
7139
+ return (_a = event.venueMarkets) != null ? _a : [];
7140
+ }),
7141
+ [openEvents]
7142
+ );
7143
+ const livePrices = (0, import_hooks27.useLiveOutcomePrices)(visibleVenueMarkets);
7144
+ const midpointResult = (0, import_hooks27.useMidpoints)(visibleVenueMarkets);
7145
+ const searchDisplayPrices = (0, import_react9.useMemo)(() => {
7146
+ if (!midpointResult.bestMidpointsByOutcomeId.size) return livePrices;
7147
+ if (!livePrices.size) return midpointResult.bestMidpointsByOutcomeId;
7148
+ const merged = new Map(midpointResult.bestMidpointsByOutcomeId);
7149
+ for (const [outcomeId, price] of livePrices) {
7150
+ merged.set(outcomeId, price);
7151
+ }
7152
+ return merged;
7153
+ }, [livePrices, midpointResult.bestMidpointsByOutcomeId]);
7118
7154
  const { validatedResults, eventsByResultId } = (0, import_react9.useMemo)(() => {
7119
7155
  const nextEventsByResultId = /* @__PURE__ */ new Map();
7120
7156
  const nextResults = openEvents.map((event) => {
@@ -7122,7 +7158,11 @@ var Search = ({
7122
7158
  event,
7123
7159
  labels,
7124
7160
  formatPercent,
7125
- formatCompactCurrency
7161
+ formatCompactCurrency,
7162
+ {
7163
+ priceByOutcomeId: searchDisplayPrices,
7164
+ isPriceLoading: midpointResult.isLoading
7165
+ }
7126
7166
  );
7127
7167
  if (!item) return null;
7128
7168
  nextEventsByResultId.set(item.id, event);
@@ -7132,7 +7172,14 @@ var Search = ({
7132
7172
  validatedResults: nextResults,
7133
7173
  eventsByResultId: nextEventsByResultId
7134
7174
  };
7135
- }, [formatCompactCurrency, formatPercent, labels, openEvents]);
7175
+ }, [
7176
+ formatCompactCurrency,
7177
+ formatPercent,
7178
+ labels,
7179
+ midpointResult.isLoading,
7180
+ openEvents,
7181
+ searchDisplayPrices
7182
+ ]);
7136
7183
  const hasSearchValue = trimmedValue.length > 0;
7137
7184
  const shouldRenderDropdown = isFocused && shouldSearchValue && !searchConfig.result && !searchConfig.isShowingAllResults;
7138
7185
  const resolvedIsActive = isFocused;
@@ -99,7 +99,7 @@ import {
99
99
  useOptionalToast,
100
100
  useToast,
101
101
  venueLogoNames
102
- } from "./chunk-VP76G6PN.mjs";
102
+ } from "./chunk-MIAAL7BL.mjs";
103
103
  export {
104
104
  ActivityChartIcon,
105
105
  AggErrorBoundary,
package/dist/trading.js CHANGED
@@ -6724,7 +6724,7 @@ var mapVenueMarketOutcomesToPlaceOrderOutcomes = (venueMarketOutcomes) => {
6724
6724
  label: outcome.label,
6725
6725
  title: (_a = outcome.title) != null ? _a : null,
6726
6726
  price: outcome.price,
6727
- priceLabel: getTradingPriceLabel(outcome.price)
6727
+ priceLabel: outcome.price != null ? getTradingPriceLabel(outcome.price) : ""
6728
6728
  };
6729
6729
  });
6730
6730
  };
@@ -8944,16 +8944,10 @@ var PlaceOrder = ({
8944
8944
  scopedSelectedMarket ? [scopedSelectedMarket] : void 0
8945
8945
  );
8946
8946
  const wsBestPrices = (0, import_hooks30.useLiveBestPrices)(scopedSelectedMarket ? [scopedSelectedMarket] : void 0);
8947
- const clusterMidpointResult = midpointsResult != null ? midpointsResult : {
8948
- prices: /* @__PURE__ */ new Map(),
8949
- bestMidpointsByOutcomeId: /* @__PURE__ */ new Map(),
8950
- venueByOutcomeId: /* @__PURE__ */ new Map(),
8951
- bestPrices: /* @__PURE__ */ new Map(),
8952
- bestPriceVenuesByOutcomeId: /* @__PURE__ */ new Map(),
8953
- isLoading: false,
8954
- bestMidpoint: void 0,
8955
- bestMidpointVenue: void 0
8956
- };
8947
+ const fetchedClusterMidpointResult = (0, import_hooks30.useMidpoints)(
8948
+ midpointsResult ? [] : scopedSelectedMarket ? [scopedSelectedMarket] : []
8949
+ );
8950
+ const clusterMidpointResult = midpointsResult != null ? midpointsResult : fetchedClusterMidpointResult;
8957
8951
  const clusterBestMidpointsByOutcomeId = (_i = clusterMidpointResult.bestMidpointsByOutcomeId) != null ? _i : clusterMidpointResult.prices;
8958
8952
  const clusterBestMidpoint = clusterMidpointResult.bestMidpoint;
8959
8953
  const clusterBestPricesRest = clusterMidpointResult.bestPrices;
@@ -10136,11 +10130,11 @@ var PlaceOrder = ({
10136
10130
  bestPrices: clusterBestPrices,
10137
10131
  bestMidpoint: clusterBestMidpoint,
10138
10132
  bestMidpointsByOutcomeId: clusterBestMidpointsByOutcomeId,
10139
- livePrices,
10140
- fallbackPrice: outcome.price
10133
+ livePrices
10141
10134
  });
10142
10135
  const isActive = outcome.id === scopedSelectedOutcomeId;
10143
10136
  const isPositive = resolveIsPositiveOutcome(outcome, index);
10137
+ const isPriceLoading = clusterMidpointResult.isLoading && price == null;
10144
10138
  return /* @__PURE__ */ (0, import_jsx_runtime123.jsxs)(
10145
10139
  "button",
10146
10140
  {
@@ -10170,7 +10164,16 @@ var PlaceOrder = ({
10170
10164
  children: (_c2 = outcome.title) != null ? _c2 : outcome.label
10171
10165
  }
10172
10166
  ),
10173
- /* @__PURE__ */ (0, import_jsx_runtime123.jsx)(Typography, { as: "span", variant: isActive ? "body-strong" : "body", children: formatProbabilityCents(price) })
10167
+ isPriceLoading ? /* @__PURE__ */ (0, import_jsx_runtime123.jsx)(
10168
+ "span",
10169
+ {
10170
+ "aria-hidden": "true",
10171
+ className: cn(
10172
+ "agg-place-order-outcome-price-loading",
10173
+ "h-4 w-10 shrink-0 rounded-agg-sm bg-agg-separator animate-pulse"
10174
+ )
10175
+ }
10176
+ ) : /* @__PURE__ */ (0, import_jsx_runtime123.jsx)(Typography, { as: "span", variant: isActive ? "body-strong" : "body", children: formatProbabilityCents(price) })
10174
10177
  ]
10175
10178
  },
10176
10179
  outcome.id
package/dist/trading.mjs CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  parseVenue,
9
9
  useClaimWinnings,
10
10
  useResolvedMarketClaim
11
- } from "./chunk-BW7S2YR3.mjs";
11
+ } from "./chunk-73MO7MYG.mjs";
12
12
  import {
13
13
  SETTLEMENT_SECTION_ID,
14
14
  Settlement,
@@ -23,9 +23,9 @@ import {
23
23
  getTradingValueLabel,
24
24
  getTradingVenueLabel,
25
25
  useEventTradingContext
26
- } from "./chunk-R2YNZJZ3.mjs";
27
- import "./chunk-T4YZGAYS.mjs";
28
- import "./chunk-VP76G6PN.mjs";
26
+ } from "./chunk-TR7HUVY7.mjs";
27
+ import "./chunk-5MRFY5ZQ.mjs";
28
+ import "./chunk-MIAAL7BL.mjs";
29
29
  export {
30
30
  PlaceOrder,
31
31
  PlaceOrderFailureView,
@@ -23,7 +23,7 @@ export type EventListItemBaseProps = {
23
23
  venueInfo?: EventListItemVenueInfoMap;
24
24
  /** Optional arbitrage values keyed by outcome ID for badge rendering. */
25
25
  arbitrageByOutcomeId?: Record<string, number | undefined>;
26
- /** Live midpoint-derived prices keyed by outcome ID. Falls back to outcome.price when absent. */
26
+ /** Live midpoint-derived prices keyed by outcome ID. */
27
27
  midpointPrices?: Map<string, number>;
28
28
  /** True while midpoints are being fetched — show skeleton on price badges. */
29
29
  midpointsLoading?: boolean;
@@ -68,6 +68,6 @@ export type EventListItemProps = EventListItemLoadingProps | EventListItemWithEv
68
68
  export type EventListItemContentProps = EventListItemBaseProps & {
69
69
  /** Resolved event content rendered by the presentational item body. */
70
70
  event: EventListItemEvent;
71
- /** Live midpoint-derived prices keyed by outcome ID. Falls back to outcome.price when absent. */
71
+ /** Live midpoint-derived prices keyed by outcome ID. */
72
72
  midpointPrices?: Map<string, number>;
73
73
  };
@@ -23,7 +23,7 @@ export type EventListItemBaseProps = {
23
23
  venueInfo?: EventListItemVenueInfoMap;
24
24
  /** Optional arbitrage values keyed by outcome ID for badge rendering. */
25
25
  arbitrageByOutcomeId?: Record<string, number | undefined>;
26
- /** Live midpoint-derived prices keyed by outcome ID. Falls back to outcome.price when absent. */
26
+ /** Live midpoint-derived prices keyed by outcome ID. */
27
27
  midpointPrices?: Map<string, number>;
28
28
  /** True while midpoints are being fetched — show skeleton on price badges. */
29
29
  midpointsLoading?: boolean;
@@ -68,6 +68,6 @@ export type EventListItemProps = EventListItemLoadingProps | EventListItemWithEv
68
68
  export type EventListItemContentProps = EventListItemBaseProps & {
69
69
  /** Resolved event content rendered by the presentational item body. */
70
70
  event: EventListItemEvent;
71
- /** Live midpoint-derived prices keyed by outcome ID. Falls back to outcome.price when absent. */
71
+ /** Live midpoint-derived prices keyed by outcome ID. */
72
72
  midpointPrices?: Map<string, number>;
73
73
  };
@@ -8,13 +8,14 @@ export declare const resolveYesOutcomeProbability: (market: Pick<VenueMarket, "v
8
8
  export declare const formatMarketProbabilityPercent: (value: number | null | undefined, formatPercent?: (value: number) => string) => string;
9
9
  export declare const formatPriceGapPercent: (value: number | null | undefined) => string | undefined;
10
10
  export declare const sortOutcomes: (outcomes: VenueMarketOutcome[]) => VenueMarketOutcome[];
11
+ export declare const sortOutcomesWithPrices: (outcomes: VenueMarketOutcome[], priceByOutcomeId?: ReadonlyMap<string, number>) => VenueMarketOutcome[];
11
12
  export type EventListItemVisibleOutcome = {
12
13
  venue: VenueMarket["venue"];
13
14
  market: VenueMarket;
14
15
  outcome: VenueMarketOutcome;
15
16
  title: string;
16
17
  };
17
- export declare const resolveVisibleOutcomes: (venueMarkets: VenueMarket[]) => EventListItemVisibleOutcome[];
18
+ export declare const resolveVisibleOutcomes: (venueMarkets: VenueMarket[], priceByOutcomeId?: ReadonlyMap<string, number>) => EventListItemVisibleOutcome[];
18
19
  /**
19
20
  * Dedupe venue markets while collapsing matched-cluster siblings to a single
20
21
  * row. Walks left-to-right; for each market we see, mark its own id AND every
@@ -8,13 +8,14 @@ export declare const resolveYesOutcomeProbability: (market: Pick<VenueMarket, "v
8
8
  export declare const formatMarketProbabilityPercent: (value: number | null | undefined, formatPercent?: (value: number) => string) => string;
9
9
  export declare const formatPriceGapPercent: (value: number | null | undefined) => string | undefined;
10
10
  export declare const sortOutcomes: (outcomes: VenueMarketOutcome[]) => VenueMarketOutcome[];
11
+ export declare const sortOutcomesWithPrices: (outcomes: VenueMarketOutcome[], priceByOutcomeId?: ReadonlyMap<string, number>) => VenueMarketOutcome[];
11
12
  export type EventListItemVisibleOutcome = {
12
13
  venue: VenueMarket["venue"];
13
14
  market: VenueMarket;
14
15
  outcome: VenueMarketOutcome;
15
16
  title: string;
16
17
  };
17
- export declare const resolveVisibleOutcomes: (venueMarkets: VenueMarket[]) => EventListItemVisibleOutcome[];
18
+ export declare const resolveVisibleOutcomes: (venueMarkets: VenueMarket[], priceByOutcomeId?: ReadonlyMap<string, number>) => EventListItemVisibleOutcome[];
18
19
  /**
19
20
  * Dedupe venue markets while collapsing matched-cluster siblings to a single
20
21
  * row. Walks left-to-right; for each market we see, mark its own id AND every
@@ -120,7 +120,6 @@ export type EventListItemDetailsGraphSectionProps = {
120
120
  /**
121
121
  * WS-only prices keyed by outcome ID. Used for chart venue badges so each
122
122
  * badge shows its own venue's price rather than the cross-venue best.
123
- * Falls back to `outcome.price` when a venue has no WS data yet.
124
123
  */
125
124
  wsLivePrices: Map<string, number>;
126
125
  /**
@@ -120,7 +120,6 @@ export type EventListItemDetailsGraphSectionProps = {
120
120
  /**
121
121
  * WS-only prices keyed by outcome ID. Used for chart venue badges so each
122
122
  * badge shows its own venue's price rather than the cross-venue best.
123
- * Falls back to `outcome.price` when a venue has no WS data yet.
124
123
  */
125
124
  wsLivePrices: Map<string, number>;
126
125
  /**
@@ -181,6 +181,7 @@ export type MarketDetailsHeaderOutcomeItem = {
181
181
  label: string;
182
182
  title?: string | null;
183
183
  probability: number | undefined;
184
+ isPriceLoading?: boolean;
184
185
  tone: MarketDetailsOutcomeTone;
185
186
  venue: VenueLogoName;
186
187
  variant?: "outcome" | "line" | "yes_no";
@@ -181,6 +181,7 @@ export type MarketDetailsHeaderOutcomeItem = {
181
181
  label: string;
182
182
  title?: string | null;
183
183
  probability: number | undefined;
184
+ isPriceLoading?: boolean;
184
185
  tone: MarketDetailsOutcomeTone;
185
186
  venue: VenueLogoName;
186
187
  variant?: "outcome" | "line" | "yes_no";
@@ -3,7 +3,8 @@ type ChartVenueOutcomeLike = {
3
3
  venue: string;
4
4
  outcome: {
5
5
  id: string;
6
- price: number;
6
+ /** No longer returned by discovery endpoints; live prices win when present. */
7
+ price?: number | undefined;
7
8
  };
8
9
  };
9
10
  type LivePriceLookup = {
@@ -3,7 +3,8 @@ type ChartVenueOutcomeLike = {
3
3
  venue: string;
4
4
  outcome: {
5
5
  id: string;
6
- price: number;
6
+ /** No longer returned by discovery endpoints; live prices win when present. */
7
+ price?: number | undefined;
7
8
  };
8
9
  };
9
10
  type LivePriceLookup = {
@@ -4,7 +4,15 @@ export type SportsSectionTabKey = (typeof SPORTS_SECTION_TAB_KEYS)[number];
4
4
  export declare const SPORTS_MARKET_TYPE_KEYS: readonly ["moneyline", "spread", "total", "prop", "completion", "other"];
5
5
  export type SportsMarketTypeKey = (typeof SPORTS_MARKET_TYPE_KEYS)[number];
6
6
  export declare const SPORTS_PERIOD_KEYS: readonly ["full", "1h", "2h", "q1", "q2", "q3", "q4", "ot", "first_inning", "second_inning", "third_inning", "first_5_innings", "other"];
7
- export type SportsPeriodKey = (typeof SPORTS_PERIOD_KEYS)[number];
7
+ /**
8
+ * Known named periods plus the documented open grammar (`set_N`, `map_N`,
9
+ * `game_N`, `period_N`, `inning_N`, `first_N_innings` — see the sports
10
+ * recipe's period vocabulary). Grammar tokens pass through verbatim so
11
+ * tennis sets / esports maps / hockey periods group under their own named
12
+ * period instead of collapsing into "other" (prod 2026-07: set_1 ×1,741,
13
+ * inning_1 ×144 were all landing in the Other bucket).
14
+ */
15
+ export type SportsPeriodKey = (typeof SPORTS_PERIOD_KEYS)[number] | (string & {});
8
16
  export declare const SPORTS_MARKET_CATEGORY_KEYS: readonly ["game_lines", "exact_score", "corners", "goals", "assists", "shots", "other"];
9
17
  export type SportsMarketCategoryKey = (typeof SPORTS_MARKET_CATEGORY_KEYS)[number];
10
18
  export declare const SPORTS_MARKET_GROUP_KEYS: readonly ["game_lines", "spreads", "totals", "period_lines", "exact_score", "team_props", "player_props", "specials", "completion", "other"];
@@ -148,6 +156,12 @@ export type SportsTeams = {
148
156
  };
149
157
  export declare const resolveSportsTeams: (event: Pick<VenueEventWithMarkets, "title">, moneylineMarket?: VenueMarket | null) => SportsTeams | null;
150
158
  export declare const resolveSportsLeagueLabel: (event: Pick<VenueEventWithMarkets, "categories" | "aggKey">) => string | null;
159
+ /**
160
+ * Human label for an open-grammar period token (`set_2` → "Set 2",
161
+ * `inning_4` → "Inning 4", `first_5_innings` → "First 5 Innings").
162
+ * Returns null for anything outside the documented grammar.
163
+ */
164
+ export declare const formatSportsPeriodGrammarLabel: (period: string) => string | null;
151
165
  export declare const isNonStandardSportsLikeEvent: (event: Pick<VenueEventWithMarkets, "categories" | "title" | "venueMarkets">) => boolean;
152
166
  export declare const resolveVisibleSportsSectionTabDefinitions: (event: Pick<VenueEventWithMarkets, "categories" | "title" | "venueMarkets">) => SportsSectionTabDefinition[];
153
167
  export declare const mergeSportsSectionMarketsIntoEvent: ({ event, sectionMarketsByKey, }: {
@@ -4,7 +4,15 @@ export type SportsSectionTabKey = (typeof SPORTS_SECTION_TAB_KEYS)[number];
4
4
  export declare const SPORTS_MARKET_TYPE_KEYS: readonly ["moneyline", "spread", "total", "prop", "completion", "other"];
5
5
  export type SportsMarketTypeKey = (typeof SPORTS_MARKET_TYPE_KEYS)[number];
6
6
  export declare const SPORTS_PERIOD_KEYS: readonly ["full", "1h", "2h", "q1", "q2", "q3", "q4", "ot", "first_inning", "second_inning", "third_inning", "first_5_innings", "other"];
7
- export type SportsPeriodKey = (typeof SPORTS_PERIOD_KEYS)[number];
7
+ /**
8
+ * Known named periods plus the documented open grammar (`set_N`, `map_N`,
9
+ * `game_N`, `period_N`, `inning_N`, `first_N_innings` — see the sports
10
+ * recipe's period vocabulary). Grammar tokens pass through verbatim so
11
+ * tennis sets / esports maps / hockey periods group under their own named
12
+ * period instead of collapsing into "other" (prod 2026-07: set_1 ×1,741,
13
+ * inning_1 ×144 were all landing in the Other bucket).
14
+ */
15
+ export type SportsPeriodKey = (typeof SPORTS_PERIOD_KEYS)[number] | (string & {});
8
16
  export declare const SPORTS_MARKET_CATEGORY_KEYS: readonly ["game_lines", "exact_score", "corners", "goals", "assists", "shots", "other"];
9
17
  export type SportsMarketCategoryKey = (typeof SPORTS_MARKET_CATEGORY_KEYS)[number];
10
18
  export declare const SPORTS_MARKET_GROUP_KEYS: readonly ["game_lines", "spreads", "totals", "period_lines", "exact_score", "team_props", "player_props", "specials", "completion", "other"];
@@ -148,6 +156,12 @@ export type SportsTeams = {
148
156
  };
149
157
  export declare const resolveSportsTeams: (event: Pick<VenueEventWithMarkets, "title">, moneylineMarket?: VenueMarket | null) => SportsTeams | null;
150
158
  export declare const resolveSportsLeagueLabel: (event: Pick<VenueEventWithMarkets, "categories" | "aggKey">) => string | null;
159
+ /**
160
+ * Human label for an open-grammar period token (`set_2` → "Set 2",
161
+ * `inning_4` → "Inning 4", `first_5_innings` → "First 5 Innings").
162
+ * Returns null for anything outside the documented grammar.
163
+ */
164
+ export declare const formatSportsPeriodGrammarLabel: (period: string) => string | null;
151
165
  export declare const isNonStandardSportsLikeEvent: (event: Pick<VenueEventWithMarkets, "categories" | "title" | "venueMarkets">) => boolean;
152
166
  export declare const resolveVisibleSportsSectionTabDefinitions: (event: Pick<VenueEventWithMarkets, "categories" | "title" | "venueMarkets">) => SportsSectionTabDefinition[];
153
167
  export declare const mergeSportsSectionMarketsIntoEvent: ({ event, sectionMarketsByKey, }: {
@@ -12,6 +12,7 @@ export type SearchResultItem = {
12
12
  marketSummaryLabel: string;
13
13
  volumeLabel: string;
14
14
  valueLabel: string;
15
+ isValueLoading?: boolean;
15
16
  contextLabel: string;
16
17
  };
17
18
  export type SearchClassNames = {
@@ -12,6 +12,7 @@ export type SearchResultItem = {
12
12
  marketSummaryLabel: string;
13
13
  volumeLabel: string;
14
14
  valueLabel: string;
15
+ isValueLoading?: boolean;
15
16
  contextLabel: string;
16
17
  };
17
18
  export type SearchClassNames = {
@@ -1,4 +1,7 @@
1
1
  import type { AggUiLabels } from "@agg-build/hooks";
2
2
  import type { VenueEventWithMarkets } from "../../events/item";
3
3
  import type { SearchResultItem } from "./search.types";
4
- export declare const mapVenueEventToSearchResult: (event: VenueEventWithMarkets, labels: AggUiLabels, formatPercent: (value: number) => string, formatCompactCurrency: (value: number) => string) => SearchResultItem | null;
4
+ export declare const mapVenueEventToSearchResult: (event: VenueEventWithMarkets, labels: AggUiLabels, formatPercent: (value: number) => string, formatCompactCurrency: (value: number) => string, options?: {
5
+ priceByOutcomeId?: ReadonlyMap<string, number>;
6
+ isPriceLoading?: boolean;
7
+ }) => SearchResultItem | null;
@@ -1,4 +1,7 @@
1
1
  import type { AggUiLabels } from "@agg-build/hooks";
2
2
  import type { VenueEventWithMarkets } from "../../events/item";
3
3
  import type { SearchResultItem } from "./search.types";
4
- export declare const mapVenueEventToSearchResult: (event: VenueEventWithMarkets, labels: AggUiLabels, formatPercent: (value: number) => string, formatCompactCurrency: (value: number) => string) => SearchResultItem | null;
4
+ export declare const mapVenueEventToSearchResult: (event: VenueEventWithMarkets, labels: AggUiLabels, formatPercent: (value: number) => string, formatCompactCurrency: (value: number) => string, options?: {
5
+ priceByOutcomeId?: ReadonlyMap<string, number>;
6
+ isPriceLoading?: boolean;
7
+ }) => SearchResultItem | null;
@@ -18,7 +18,8 @@ export interface PlaceOrderOutcome {
18
18
  * Polymarket "Trump Wins"). Display this when present, fall back to
19
19
  * `label`. */
20
20
  title: string | null;
21
- price: number;
21
+ /** No longer returned by discovery endpoints; live quotes/midpoints supply prices. */
22
+ price?: number | undefined;
22
23
  priceLabel: string;
23
24
  }
24
25
  export interface PlaceOrderMetric {
@@ -18,7 +18,8 @@ export interface PlaceOrderOutcome {
18
18
  * Polymarket "Trump Wins"). Display this when present, fall back to
19
19
  * `label`. */
20
20
  title: string | null;
21
- price: number;
21
+ /** No longer returned by discovery endpoints; live quotes/midpoints supply prices. */
22
+ price?: number | undefined;
22
23
  priceLabel: string;
23
24
  }
24
25
  export interface PlaceOrderMetric {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agg-build/ui",
3
- "version": "2.1.4",
3
+ "version": "2.2.0",
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",
@@ -100,8 +100,8 @@
100
100
  "liveline": "^0.0.7",
101
101
  "react": "^18.0.0 || ^19.0.0",
102
102
  "react-dom": "^18.0.0 || ^19.0.0",
103
- "@agg-build/hooks": "^2.1.3",
104
- "@agg-build/sdk": "^2.1.3"
103
+ "@agg-build/hooks": "^2.2.0",
104
+ "@agg-build/sdk": "^2.2.0"
105
105
  },
106
106
  "dependencies": {
107
107
  "@number-flow/react": "^0.6.0",