@agg-build/ui 2.4.2 → 2.4.3

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.
@@ -2,7 +2,9 @@
2
2
  import {
3
3
  Card,
4
4
  DEFAULT_VENUE_COLOR,
5
+ Icon,
5
6
  Skeleton,
7
+ VenueLogo,
6
8
  __spreadProps,
7
9
  __spreadValues,
8
10
  cn,
@@ -18,7 +20,7 @@ import {
18
20
  selectPrimaryVenueMarket,
19
21
  skeletonViews,
20
22
  sortOutcomes
21
- } from "./chunk-2ET5CXOU.mjs";
23
+ } from "./chunk-WZ55ERDO.mjs";
22
24
 
23
25
  // src/trading/trading-context/index.tsx
24
26
  import { useEventTradingContext } from "@agg-build/hooks";
@@ -166,8 +168,10 @@ var getTradingSlippageLabel = (value) => {
166
168
  };
167
169
 
168
170
  // src/trading/settlement/index.tsx
169
- import { useLabels } from "@agg-build/hooks";
170
- import { useMemo } from "react";
171
+ import {
172
+ useLabels
173
+ } from "@agg-build/hooks";
174
+ import { useEffect, useMemo, useState } from "react";
171
175
 
172
176
  // src/trading/settlement/settlement-text-renderer.tsx
173
177
  import { Fragment } from "react";
@@ -367,8 +371,139 @@ var SettlementTextRenderer = ({
367
371
  SettlementTextRenderer.displayName = "SettlementTextRenderer";
368
372
 
369
373
  // src/trading/settlement/index.tsx
370
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
374
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
371
375
  var SETTLEMENT_SECTION_ID = "agg-settlement-section";
376
+ var getSettlementDifferenceId = (sectionId, canonicalKey) => {
377
+ return `${sectionId}-difference-${canonicalKey}`;
378
+ };
379
+ var dateOnlyRegex = /^(\d{4})-(\d{2})-(\d{2})$/;
380
+ var isoTimestampWithTimezoneRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:?\d{2})$/i;
381
+ var normalizeDifferenceText = (value) => {
382
+ return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
383
+ };
384
+ var resolveCanonicalDifferenceKey = (difference) => {
385
+ const normalizedType = normalizeDifferenceText(difference.type);
386
+ const combined = normalizeDifferenceText(`${difference.type} ${difference.title}`);
387
+ if (combined.includes("start_date") || combined.includes("open_date")) return "start_date";
388
+ if (combined.includes("end_date") || combined.includes("close_date") || combined.includes("closing_date") || combined.includes("expiration_date") || combined.includes("expiry_date")) {
389
+ return "end_date";
390
+ }
391
+ if (combined.includes("resolution_timing") || combined.includes("resolution_date") || combined.includes("resolution_deadline") || combined.includes("settlement_date") || combined.includes("settlement_deadline") || combined.includes("settlement_timing")) {
392
+ return "resolution_timing";
393
+ }
394
+ return normalizedType || "other";
395
+ };
396
+ var parseSettlementDateMs = (value) => {
397
+ const trimmed = value.trim();
398
+ const dateOnlyMatch = dateOnlyRegex.exec(trimmed);
399
+ if (dateOnlyMatch) {
400
+ const [, year, month, day] = dateOnlyMatch;
401
+ return Date.UTC(Number(year), Number(month) - 1, Number(day));
402
+ }
403
+ if (!isoTimestampWithTimezoneRegex.test(trimmed)) return null;
404
+ const ms = Date.parse(trimmed);
405
+ return Number.isNaN(ms) ? null : ms;
406
+ };
407
+ var isDateLikeDifference = (canonicalKey) => {
408
+ return canonicalKey === "resolution_timing" || canonicalKey === "start_date" || canonicalKey === "end_date";
409
+ };
410
+ var hasEqualNormalizedDateValues = (difference, canonicalKey) => {
411
+ if (!isDateLikeDifference(canonicalKey)) return false;
412
+ const values = Object.values(difference.perVenue);
413
+ if (values.length < 2) return false;
414
+ const timestamps = values.map(parseSettlementDateMs);
415
+ if (timestamps.some((timestamp) => timestamp === null)) return false;
416
+ return new Set(timestamps).size === 1;
417
+ };
418
+ var resolveDifferenceSeverity = (difference, canonicalKey) => {
419
+ var _a;
420
+ const combined = normalizeDifferenceText(
421
+ `${difference.type} ${difference.title} ${(_a = difference.summary) != null ? _a : ""}`
422
+ );
423
+ if (isDateLikeDifference(canonicalKey)) return "critical";
424
+ if (canonicalKey === "scope" || canonicalKey === "threshold" || canonicalKey === "edge_cases") {
425
+ return "critical";
426
+ }
427
+ if (combined.includes("conflict") || combined.includes("void") || combined.includes("cancel") || combined.includes("postpone") || combined.includes("recount") || combined.includes("overtime") || combined.includes("extra_time")) {
428
+ return "critical";
429
+ }
430
+ return "informational";
431
+ };
432
+ var mergePerVenueValues = (current, next) => {
433
+ return Object.entries(next).reduce(
434
+ (merged, [venue, value]) => {
435
+ if (merged[venue] === void 0) merged[venue] = value;
436
+ return merged;
437
+ },
438
+ __spreadValues({}, current)
439
+ );
440
+ };
441
+ var prepareSettlementDifferences = (differences) => {
442
+ const byCanonicalKey = /* @__PURE__ */ new Map();
443
+ for (const [originalIndex, difference] of (differences != null ? differences : []).entries()) {
444
+ const canonicalKey = resolveCanonicalDifferenceKey(difference);
445
+ if (hasEqualNormalizedDateValues(difference, canonicalKey)) continue;
446
+ const existing = byCanonicalKey.get(canonicalKey);
447
+ if (existing) {
448
+ byCanonicalKey.set(canonicalKey, __spreadProps(__spreadValues({}, existing), {
449
+ perVenue: mergePerVenueValues(existing.perVenue, difference.perVenue)
450
+ }));
451
+ continue;
452
+ }
453
+ byCanonicalKey.set(canonicalKey, __spreadProps(__spreadValues({}, difference), {
454
+ canonicalKey,
455
+ severity: resolveDifferenceSeverity(difference, canonicalKey),
456
+ originalIndex
457
+ }));
458
+ }
459
+ return Array.from(byCanonicalKey.values()).sort((left, right) => {
460
+ const severityDelta = Number(right.severity === "critical") - Number(left.severity === "critical");
461
+ if (severityDelta !== 0) return severityDelta;
462
+ return left.originalIndex - right.originalIndex;
463
+ });
464
+ };
465
+ var formatVenueFallbackLabel = (venue) => {
466
+ return venue.split(/[-_\s]+/).filter(Boolean).map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
467
+ };
468
+ var resolveSettlementVenueLabel = (venue, labels) => {
469
+ var _a;
470
+ return (_a = labels.venues[venue]) != null ? _a : formatVenueFallbackLabel(venue);
471
+ };
472
+ var resolveDifferenceVenueKeys = (difference, settlementVenues) => {
473
+ const explicitVenues = Object.keys(difference.perVenue);
474
+ if (!isDateLikeDifference(difference.canonicalKey)) return explicitVenues;
475
+ const allVenues = [...settlementVenues != null ? settlementVenues : [], ...explicitVenues];
476
+ return Array.from(new Set(allVenues.filter((venue) => venue.trim().length > 0)));
477
+ };
478
+ var resolveDifferenceIconClassName = (canonicalKey) => {
479
+ if (canonicalKey.includes("source") || canonicalKey.includes("url")) return "fi-rr-world";
480
+ if (canonicalKey === "resolution_timing" || canonicalKey.includes("timing")) {
481
+ return "fi-rr-clock";
482
+ }
483
+ if (canonicalKey === "start_date" || canonicalKey.includes("start"))
484
+ return "fi-rr-calendar-clock";
485
+ if (canonicalKey === "end_date" || canonicalKey.includes("end")) return "fi-rr-calendar-clock";
486
+ if (canonicalKey.includes("cancel") || canonicalKey.includes("void") || canonicalKey.includes("postpone")) {
487
+ return "fi-rr-ban";
488
+ }
489
+ if (canonicalKey === "edge_cases" || canonicalKey.includes("edge")) {
490
+ return "fi-rr-triangle-warning";
491
+ }
492
+ if (canonicalKey === "scope") return "fi-rr-layers";
493
+ if (canonicalKey === "threshold") return "fi-rr-tachometer-alt-fastest";
494
+ if (canonicalKey.includes("wording")) return "fi-rr-document";
495
+ return "fi-rr-info";
496
+ };
497
+ var buildSettlementVenueRules = ({
498
+ eventBlock,
499
+ marketBlock,
500
+ primaryRulesBlock,
501
+ settlementVenueRules
502
+ }) => {
503
+ if (settlementVenueRules) return settlementVenueRules;
504
+ const content = [marketBlock == null ? void 0 : marketBlock.content, primaryRulesBlock == null ? void 0 : primaryRulesBlock.content, eventBlock == null ? void 0 : eventBlock.content].filter((value) => typeof value === "string" && value.trim().length > 0).join("\n\n");
505
+ return content ? [{ venue: "polymarket", content }] : [];
506
+ };
372
507
  var getSettlementHeaderClassName = () => {
373
508
  return "flex items-center justify-between gap-4";
374
509
  };
@@ -380,9 +515,12 @@ var Settlement = ({
380
515
  eventDescription,
381
516
  marketDescription,
382
517
  primaryRules,
518
+ settlementDiff,
519
+ settlementVenues,
520
+ settlementVenueRules,
383
521
  isLoading = false
384
522
  }) => {
385
- var _a, _b, _c;
523
+ var _a, _b, _c, _d, _e;
386
524
  const labels = useLabels();
387
525
  const blocks = useMemo(
388
526
  () => dedupeSettlementSources({
@@ -392,9 +530,34 @@ var Settlement = ({
392
530
  }),
393
531
  [eventDescription, marketDescription, primaryRules]
394
532
  );
533
+ const settlementDifferences = useMemo(
534
+ () => prepareSettlementDifferences(settlementDiff == null ? void 0 : settlementDiff.differences),
535
+ [settlementDiff == null ? void 0 : settlementDiff.differences]
536
+ );
395
537
  const eventBlock = (_a = blocks.find((block) => block.key === "eventDescription")) != null ? _a : null;
396
538
  const marketBlock = (_b = blocks.find((block) => block.key === "marketDescription")) != null ? _b : null;
397
539
  const primaryRulesBlock = (_c = blocks.find((block) => block.key === "primaryRules")) != null ? _c : null;
540
+ const venueRuleBlocks = useMemo(
541
+ () => buildSettlementVenueRules({
542
+ eventBlock,
543
+ marketBlock,
544
+ primaryRulesBlock,
545
+ settlementVenueRules
546
+ }),
547
+ [eventBlock, marketBlock, primaryRulesBlock, settlementVenueRules]
548
+ );
549
+ const defaultOpenDifferenceKey = (_e = (_d = settlementDifferences[0]) == null ? void 0 : _d.canonicalKey) != null ? _e : null;
550
+ const [openDifferenceKeys, setOpenDifferenceKeys] = useState(
551
+ () => defaultOpenDifferenceKey ? [defaultOpenDifferenceKey] : []
552
+ );
553
+ useEffect(() => {
554
+ setOpenDifferenceKeys(defaultOpenDifferenceKey ? [defaultOpenDifferenceKey] : []);
555
+ }, [defaultOpenDifferenceKey]);
556
+ const handleToggleDifference = (canonicalKey) => {
557
+ setOpenDifferenceKeys(
558
+ (currentKeys) => currentKeys.includes(canonicalKey) ? currentKeys.filter((currentKey) => currentKey !== canonicalKey) : [...currentKeys, canonicalKey]
559
+ );
560
+ };
398
561
  if (isLoading) {
399
562
  return /* @__PURE__ */ jsx2(
400
563
  Skeleton,
@@ -406,6 +569,124 @@ var Settlement = ({
406
569
  );
407
570
  }
408
571
  const resolvedSectionLabel = sectionLabel === defaultSettlementSectionLabel ? labels.trading.settlementSection : sectionLabel;
572
+ if (settlementDifferences.length > 0) {
573
+ return /* @__PURE__ */ jsxs2(
574
+ Card,
575
+ {
576
+ id,
577
+ className: cn(
578
+ "group/agg-settlement-card",
579
+ "flex w-full flex-col items-start gap-4 rounded-agg-xl border border-agg-separator bg-agg-secondary p-5 shadow-none hover:shadow-none sm:gap-5",
580
+ className
581
+ ),
582
+ children: [
583
+ /* @__PURE__ */ jsxs2("div", { className: "agg-settlement-header flex w-full flex-col items-start gap-1 text-agg-muted-foreground sm:flex-row sm:items-center sm:justify-between sm:gap-4", children: [
584
+ /* @__PURE__ */ jsx2("p", { className: "shrink-0 text-agg-xs font-agg-bold leading-agg-4 uppercase", children: resolvedSectionLabel }),
585
+ question ? /* @__PURE__ */ jsx2("p", { className: "agg-settlement-question min-w-0 text-agg-sm font-agg-normal leading-agg-5 sm:max-w-[314px] sm:truncate", children: question }) : null
586
+ ] }),
587
+ /* @__PURE__ */ jsxs2("div", { className: "agg-settlement-differences flex w-full flex-col items-start gap-5", children: [
588
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
589
+ /* @__PURE__ */ jsx2("p", { className: "text-agg-sm font-agg-bold leading-agg-5 text-agg-foreground", children: "Key differences" }),
590
+ /* @__PURE__ */ jsx2("span", { className: "flex size-4 shrink-0 items-center justify-center rounded-agg-full bg-agg-primary text-[10px] font-agg-bold leading-[14px] text-agg-on-primary", children: settlementDifferences.length })
591
+ ] }),
592
+ /* @__PURE__ */ jsx2("div", { className: "flex w-full flex-col items-start gap-5", children: settlementDifferences.map((difference) => {
593
+ const venueKeys = resolveDifferenceVenueKeys(difference, settlementVenues);
594
+ const isExpanded = openDifferenceKeys.includes(difference.canonicalKey) && venueKeys.length > 0;
595
+ return /* @__PURE__ */ jsxs2(
596
+ "div",
597
+ {
598
+ id: getSettlementDifferenceId(id, difference.canonicalKey),
599
+ className: "agg-settlement-difference flex w-full flex-col items-start gap-2 rounded-agg-lg",
600
+ children: [
601
+ /* @__PURE__ */ jsxs2(
602
+ "button",
603
+ {
604
+ type: "button",
605
+ className: "flex w-full cursor-pointer items-start gap-2 text-left",
606
+ "aria-expanded": isExpanded,
607
+ onClick: () => handleToggleDifference(difference.canonicalKey),
608
+ children: [
609
+ /* @__PURE__ */ jsx2(
610
+ "i",
611
+ {
612
+ className: cn(
613
+ "fi",
614
+ resolveDifferenceIconClassName(difference.canonicalKey),
615
+ "inline-flex size-4! shrink-0 items-center justify-center text-[16px] leading-none text-agg-muted-foreground"
616
+ ),
617
+ "aria-hidden": "true"
618
+ }
619
+ ),
620
+ /* @__PURE__ */ jsx2("p", { className: "min-w-0 text-agg-sm font-agg-normal leading-agg-5 text-agg-foreground break-words [overflow-wrap:anywhere]", children: difference.title }),
621
+ /* @__PURE__ */ jsx2(
622
+ Icon,
623
+ {
624
+ name: isExpanded ? "chevron-up" : "chevron-down",
625
+ className: "size-4! mt-0.5 shrink-0 text-agg-foreground",
626
+ "aria-hidden": "true"
627
+ }
628
+ )
629
+ ]
630
+ }
631
+ ),
632
+ isExpanded ? /* @__PURE__ */ jsx2("dl", { className: "flex w-full flex-col items-start gap-1 px-6", children: venueKeys.map((venue) => {
633
+ var _a2;
634
+ const venueValue = (_a2 = difference.perVenue[venue]) != null ? _a2 : labels.trading.settlementValueUnavailable;
635
+ const venueLabel = resolveSettlementVenueLabel(venue, labels);
636
+ return /* @__PURE__ */ jsxs2("div", { className: "flex w-full items-start gap-2", children: [
637
+ /* @__PURE__ */ jsx2(
638
+ VenueLogo,
639
+ {
640
+ venue,
641
+ size: "small",
642
+ className: "mt-0.5 size-4",
643
+ ariaLabel: venueLabel
644
+ }
645
+ ),
646
+ /* @__PURE__ */ jsx2("dt", { className: "w-[88px] shrink-0 text-agg-sm font-agg-normal leading-agg-5 text-agg-foreground", children: venueLabel }),
647
+ /* @__PURE__ */ jsx2("dd", { className: "min-w-0 flex-1 text-agg-sm font-agg-normal leading-agg-5 text-agg-muted-foreground break-words [overflow-wrap:anywhere]", children: venueValue })
648
+ ] }, venue);
649
+ }) }) : null
650
+ ]
651
+ },
652
+ difference.canonicalKey
653
+ );
654
+ }) }),
655
+ venueRuleBlocks.length > 0 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
656
+ /* @__PURE__ */ jsx2("div", { className: "h-px w-full bg-agg-separator" }),
657
+ /* @__PURE__ */ jsx2("p", { className: "text-agg-sm font-agg-bold leading-agg-5 text-agg-foreground", children: "Full rules by venue" }),
658
+ /* @__PURE__ */ jsx2("div", { className: "flex w-full flex-col items-start gap-4", children: venueRuleBlocks.map((rule) => {
659
+ const venueLabel = resolveSettlementVenueLabel(rule.venue, labels);
660
+ return /* @__PURE__ */ jsxs2("details", { className: "group/agg-settlement-rule w-full", children: [
661
+ /* @__PURE__ */ jsxs2("summary", { className: "flex cursor-pointer list-none items-center gap-2 text-agg-sm font-agg-normal leading-agg-5 text-agg-foreground marker:hidden", children: [
662
+ /* @__PURE__ */ jsx2(
663
+ VenueLogo,
664
+ {
665
+ venue: rule.venue,
666
+ size: "small",
667
+ className: "size-4",
668
+ ariaLabel: venueLabel
669
+ }
670
+ ),
671
+ /* @__PURE__ */ jsx2("span", { children: venueLabel }),
672
+ /* @__PURE__ */ jsx2(
673
+ Icon,
674
+ {
675
+ name: "chevron-down",
676
+ className: "size-4! shrink-0 text-agg-foreground transition-transform group-open/agg-settlement-rule:rotate-180",
677
+ "aria-hidden": "true"
678
+ }
679
+ )
680
+ ] }),
681
+ /* @__PURE__ */ jsx2("div", { className: "mt-3 pl-6", children: /* @__PURE__ */ jsx2(SettlementTextRenderer, { content: rule.content }) })
682
+ ] }, rule.venue);
683
+ }) })
684
+ ] }) : null
685
+ ] })
686
+ ]
687
+ }
688
+ );
689
+ }
409
690
  return /* @__PURE__ */ jsxs2(
410
691
  Card,
411
692
  {
@@ -420,7 +701,7 @@ var Settlement = ({
420
701
  /* @__PURE__ */ jsx2("p", { className: "text-agg-xs font-agg-bold leading-agg-4 uppercase text-agg-muted-foreground", children: resolvedSectionLabel }),
421
702
  question ? /* @__PURE__ */ jsx2("p", { className: "agg-settlement-question text-agg-sm font-agg-bold leading-agg-5 text-agg-foreground", children: question }) : null
422
703
  ] }),
423
- blocks.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "agg-settlement-empty text-agg-sm leading-agg-5 text-agg-muted-foreground", children: labels.trading.settlementEmpty }) : /* @__PURE__ */ jsxs2("div", { className: "agg-settlement-sections flex flex-col gap-4", children: [
704
+ blocks.length === 0 && settlementDifferences.length === 0 ? /* @__PURE__ */ jsx2("p", { className: "agg-settlement-empty text-agg-sm leading-agg-5 text-agg-muted-foreground", children: labels.trading.settlementEmpty }) : /* @__PURE__ */ jsxs2("div", { className: "agg-settlement-sections flex flex-col gap-4", children: [
424
705
  eventBlock || marketBlock ? /* @__PURE__ */ jsxs2(
425
706
  "div",
426
707
  {
@@ -1320,6 +1601,9 @@ export {
1320
1601
  getTradingSlippageLabel,
1321
1602
  getFirstSettlementParagraph,
1322
1603
  SETTLEMENT_SECTION_ID,
1604
+ getSettlementDifferenceId,
1605
+ prepareSettlementDifferences,
1606
+ resolveDifferenceIconClassName,
1323
1607
  Settlement,
1324
1608
  resolveTradingStatePresentation,
1325
1609
  resolveTradingStateBadgeClassName,
@@ -5886,17 +5886,10 @@ var SettlementSkeletonView = ({
5886
5886
  children: [
5887
5887
  /* @__PURE__ */ jsxs102("div", { className: "flex w-full items-center justify-between gap-4", children: [
5888
5888
  /* @__PURE__ */ jsx105(SkeletonBlock, { className: "h-4 w-[81px] rounded-agg-sm" }),
5889
- /* @__PURE__ */ jsx105(SkeletonBlock, { className: "h-5 w-full max-w-[240px] rounded-agg-sm" })
5889
+ /* @__PURE__ */ jsx105(SkeletonBlock, { className: "h-5 w-[240px] max-w-[60%] rounded-agg-sm" })
5890
5890
  ] }),
5891
- /* @__PURE__ */ jsxs102("div", { className: "flex w-full flex-col gap-3", children: [
5892
- /* @__PURE__ */ jsx105(SkeletonBlock, { className: "h-5 w-[200px] rounded-agg-sm" }),
5893
- /* @__PURE__ */ jsxs102("div", { className: "flex flex-col gap-2", children: [
5894
- /* @__PURE__ */ jsx105(SkeletonBlock, { className: "h-4 w-full max-w-[320px] rounded-agg-sm" }),
5895
- /* @__PURE__ */ jsx105(SkeletonBlock, { className: "h-4 w-full max-w-[280px] rounded-agg-sm" })
5896
- ] })
5897
- ] }),
5898
- /* @__PURE__ */ jsx105("div", { className: "h-px w-full bg-agg-separator" }),
5899
- /* @__PURE__ */ jsxs102("div", { className: "flex w-full flex-col gap-3", children: [
5891
+ /* @__PURE__ */ jsx105(SkeletonBlock, { className: "h-5 w-[200px] rounded-agg-sm" }),
5892
+ /* @__PURE__ */ jsxs102("div", { className: "flex w-full flex-col gap-4", children: [
5900
5893
  /* @__PURE__ */ jsxs102("div", { className: "flex items-center gap-2", children: [
5901
5894
  /* @__PURE__ */ jsx105(SkeletonBlock, { className: "size-4 rounded-agg-sm" }),
5902
5895
  /* @__PURE__ */ jsx105(SkeletonBlock, { className: "h-5 w-[100px] rounded-agg-sm" })