courthive-components 6.2.1 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -54,9 +54,11 @@ interface MatchUpFormatConfig {
54
54
  text: string;
55
55
  }>;
56
56
  }
57
- export declare function getMatchUpFormatModal({ existingMatchUpFormat, callback, config, modalConfig }?: {
57
+ export declare function getMatchUpFormatModal({ existingMatchUpFormat, callback, onClose, config, modalConfig }?: {
58
58
  existingMatchUpFormat?: string;
59
59
  callback?: (format: string) => void;
60
+ /** Called however the modal closes — Select, Cancel, or anything else that closes it. */
61
+ onClose?: () => void;
60
62
  config?: MatchUpFormatConfig;
61
63
  modalConfig?: any;
62
64
  }): {
@@ -69,10 +69,25 @@ export declare function isSetTiebreakOnly(format?: SetFormat): boolean;
69
69
  */
70
70
  export declare function isSetTimed(format?: SetFormat): boolean;
71
71
  /**
72
- * Calculate the maximum allowed score for a regular set game score
73
- * based on the opponent's score and set rules
72
+ * The highest game (or tiebreak-point) score one side may enter, given the opponent's.
74
73
  *
75
- * For timed sets, returns Infinity (no maximum) since scores don't need relationships
74
+ * ── Delegated to the factory ──
75
+ *
76
+ * `scoreGovernor.getMaxSetScore` answers for a games set from the format alone: the tiebreak games,
77
+ * `tiebreakAt` above or below `setTo`, a declared `winBy`. It answers `undefined` where the format has no
78
+ * ceiling — a timed set, an advantage set past the tiebreak-less `setTo`, or a tiebreak-only set, whose
79
+ * points are not games — and each of those is handled here by the factory's own tiebreak complement or
80
+ * by the set's margin, not by recomputing tennis.
81
+ *
82
+ * The hand-rolled body this replaced read a tiebreak-only set as a six-game set: `SET1-S:TB10` with no
83
+ * opponent score was capped at **7** — a match tiebreak to ten that could not be entered (measured
84
+ * 2026-10-08, live in the shipping dialog). It now caps at the complement of the opponent's points: 10,
85
+ * then 12 against 10, and `NoAD` ends it at the target.
86
+ *
87
+ * One convention of the calling dialog is kept: an opponent score of 0 means "not entered yet" and allows
88
+ * the format's ceiling. Where the opponent's games already hold the set, the answer is the factory's
89
+ * ceiling (CA, 2026-10-08: "follow the factory") — 7 under `S:6/TB7`, 5 under `S:5/TB9@4` — and the old
90
+ * "extended play" read of 9, a tiebreak set running on like an advantage set, is gone.
76
91
  */
77
92
  export declare function getMaxAllowedScore(setIndex: number, side: 1 | 2, currentScores: {
78
93
  side1: number;
@@ -0,0 +1,28 @@
1
+ import { SetScore } from '../types';
2
+ /** What the card reports on Submit, with the sets the dialog adds. */
3
+ export type ReportedOutcome = {
4
+ matchUpStatus?: string;
5
+ winningSide?: number;
6
+ reasonCode?: string;
7
+ score?: string;
8
+ cleared?: boolean;
9
+ sets?: SetScore[];
10
+ };
11
+ /** The outcome in the shape `tournamentEngine.setMatchUpStatus({ drawId, matchUpId, outcome })` reads. */
12
+ export type EngineOutcome = {
13
+ matchUpStatus?: string;
14
+ winningSide?: number;
15
+ matchUpFormat?: string;
16
+ matchUpStatusCodes?: string[];
17
+ score: {
18
+ sets: SetScore[];
19
+ };
20
+ };
21
+ export declare function toEngineOutcome(outcome: ReportedOutcome, matchUpFormat?: string): EngineOutcome;
22
+ /**
23
+ * The positional array the engine reads a reason from.
24
+ *
25
+ * A single exit: the side that did NOT win, at its index. A double exit: both. An ending that resolves
26
+ * nobody: index 0, since there is no side — the engine files that one as `matchUpStatusCode`.
27
+ */
28
+ export declare function positionalCodes({ reasonCode, matchUpStatus, winningSide }: ReportedOutcome): string[] | undefined;
@@ -156,10 +156,14 @@ export type ScoreEntryCardParams = {
156
156
  initialState?: ScoreEntryState;
157
157
  onClear?: () => void;
158
158
  onSubmit?: (outcome: ScoreEntryOutcome) => void;
159
- onClose?: () => void;
160
159
  };
161
160
  export type ScoreEntryCard = {
162
161
  element: HTMLElement;
162
+ /**
163
+ * Close an open menu (the approach switcher's or Other's) and report whether one was open. The dialog's
164
+ * Escape calls it first, wherever focus is, so one Escape closes the menu and a second one cancels.
165
+ */
166
+ closeMenus: () => boolean;
163
167
  /** Re-render the band and the submit gate. Call when the score region's value changes. */
164
168
  refresh: () => void;
165
169
  /** Rebuild everything, including the region's cells. Call when the region's COLUMNS change. */
@@ -1,16 +1,24 @@
1
+ import { EngineOutcome } from './logic/engineOutcome';
1
2
  import { SetScore } from './types';
2
3
  import { ScoreEntryCard, ScoreEntryCardParams, ScoreEntryOutcome } from './scoreEntryCard';
3
4
  /** The three entry approaches. The key is what `onSelectApproach` reports and what a host persists. */
4
5
  export type ScoreEntryApproach = 'dynamicSets' | 'freeScore' | 'dialPad';
5
- export type ScoreEntryDialogParams = Omit<ScoreEntryCardParams, 'region' | 'approachLabel' | 'approaches' | 'onSelectApproach' | 'onSwitchApproach' | 'onEditFormat' | 'onClose' | 'onSubmit'> & {
6
+ export type ScoreEntryDialogParams = Omit<ScoreEntryCardParams, 'region' | 'approachLabel' | 'approaches' | 'onSelectApproach' | 'onSwitchApproach' | 'onEditFormat' | 'onSubmit'> & {
6
7
  /**
7
8
  * Called with the outcome, then the dialog closes.
8
9
  *
9
10
  * `sets` is added to what the card reports, because the dialog knows its regions carry them and a
10
11
  * host saving to the factory needs the structured sets rather than only the formatted string.
12
+ *
13
+ * `outcome` is the same result in the shape the factory reads — hand it to
14
+ * `tournamentEngine.setMatchUpStatus({ drawId, matchUpId, outcome })` as is (pass a copy if you keep
15
+ * what you sent: the engine writes its derived score strings into it). The score as `score.sets`, a
16
+ * chosen reason as positional `matchUpStatusCodes`, a clear as the empty-sets outcome that actually
17
+ * clears, and a format changed through the chip as `matchUpFormat`. See `logic/engineOutcome.ts`.
11
18
  */
12
19
  onSubmit?: (outcome: ScoreEntryOutcome & {
13
20
  sets: SetScore[];
21
+ outcome: EngineOutcome;
14
22
  }) => void;
15
23
  /** Which approach opens. Defaults to Dynamic Sets. */
16
24
  approach?: ScoreEntryApproach;
@@ -77,6 +85,8 @@ export type ScoreEntryDialogParams = Omit<ScoreEntryCardParams, 'region' | 'appr
77
85
  openFormatPicker?: (params: {
78
86
  existingMatchUpFormat: string;
79
87
  callback: (matchUpFormat: string) => void;
88
+ /** Called however the picker closes; the dialog is inert until then. */
89
+ onClose?: () => void;
80
90
  }) => void;
81
91
  };
82
92
  export type ScoreEntryDialog = {
@@ -6,6 +6,8 @@ export interface TopologyNode {
6
6
  structureType: string;
7
7
  drawSize: number;
8
8
  qualifyingPositions?: number;
9
+ /** QUALIFYING nodes: seeds to place in the structure (0 = unseeded). */
10
+ seedsCount?: number;
9
11
  matchUpFormat?: string;
10
12
  structureOptions?: any;
11
13
  position: {