courthive-components 6.14.0 → 7.1.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 (56) hide show
  1. package/README.md +27 -39
  2. package/dist/components/composition-editor/sections/colorsSection.d.ts +1 -1
  3. package/dist/components/composition-editor/sections/layoutSection.d.ts +1 -1
  4. package/dist/components/renderSchematicStructure/index.d.ts +1 -1
  5. package/dist/components/renderSchematicStructure/renderSchematicMatchUp.d.ts +29 -3
  6. package/dist/components/renderSchematicStructure/renderSchematicRound.d.ts +3 -2
  7. package/dist/components/renderSchematicStructure/renderSchematicStructure.d.ts +4 -2
  8. package/dist/components/renderStructure/connectors.d.ts +25 -0
  9. package/dist/components/renderStructure/matchUpState.d.ts +32 -0
  10. package/dist/components/renderStructure/renderMatchUp.d.ts +6 -3
  11. package/dist/components/renderStructure/renderMatchUpActions.d.ts +14 -0
  12. package/dist/components/renderStructure/renderMatchUpInPlace.d.ts +19 -0
  13. package/dist/components/renderStructure/renderOnlineResources.d.ts +20 -0
  14. package/dist/components/renderStructure/renderParticipantDetail.d.ts +1 -1
  15. package/dist/components/renderStructure/renderRound.d.ts +5 -1
  16. package/dist/components/renderStructure/renderRoundHeader.d.ts +3 -2
  17. package/dist/components/renderStructure/renderRoundPager.d.ts +14 -0
  18. package/dist/components/renderStructure/renderSchedule.d.ts +10 -3
  19. package/dist/components/renderStructure/renderSlot.d.ts +7 -0
  20. package/dist/components/renderStructure/renderStructure.d.ts +20 -1
  21. package/dist/components/renderStructure/renderStructureMinimap.d.ts +5 -1
  22. package/dist/components/renderStructure/scoreboardState.d.ts +17 -0
  23. package/dist/components/renderStructure/structurePaths.d.ts +21 -0
  24. package/dist/components/scoring/logic/irregularEnding.d.ts +1 -1
  25. package/dist/components/scoring/logic/scoreEntrySelectors.d.ts +2 -0
  26. package/dist/components/scoring/logic/scoreEntryText.d.ts +93 -0
  27. package/dist/components/scoring/regions/dialPadRegion.d.ts +2 -0
  28. package/dist/components/scoring/regions/dynamicSetsRegion.d.ts +3 -0
  29. package/dist/components/scoring/regions/freeScoreRegion.d.ts +3 -1
  30. package/dist/components/scoring/regions/scoreReadout.d.ts +1 -1
  31. package/dist/components/scoring/scoreEntryCard.d.ts +4 -1
  32. package/dist/courthive-components.css +1 -1
  33. package/dist/courthive-components.es.js +10497 -12368
  34. package/dist/courthive-components.umd.js +77 -113
  35. package/dist/courts.mjs +2 -4
  36. package/dist/{dist-DPnSc4eG.mjs → dist-BuZ2aY07.mjs} +13 -46
  37. package/dist/features.css +1 -1
  38. package/dist/index.d.ts +7 -5
  39. package/dist/{range-C-KhEV-d.mjs → range-5-_fCM2L.mjs} +1 -2
  40. package/dist/segmented-bar.mjs +1 -2
  41. package/dist/styles/themes/createTheme.d.ts +6 -0
  42. package/dist/types.d.ts +297 -4
  43. package/package.json +9 -9
  44. package/dist/components/scoring/approaches/dialPadApproach.d.ts +0 -2
  45. package/dist/components/scoring/approaches/dialPadLogic.d.ts +0 -17
  46. package/dist/components/scoring/approaches/dynamicSetsApproach.d.ts +0 -2
  47. package/dist/components/scoring/approaches/freeScoreApproach.d.ts +0 -2
  48. package/dist/components/scoring/approaches/inlineScoringApproach.d.ts +0 -2
  49. package/dist/components/scoring/config.d.ts +0 -28
  50. package/dist/components/scoring/index.d.ts +0 -6
  51. package/dist/components/scoring/logic/outcomeProjection.d.ts +0 -25
  52. package/dist/components/scoring/scoringModal.d.ts +0 -2
  53. package/dist/components/scoring/statusCodePicker.d.ts +0 -15
  54. package/dist/components/scoring/utils/scoreFormatters.d.ts +0 -12
  55. package/dist/components/scoring/utils/scoreValidator.d.ts +0 -16
  56. package/dist/styles/getLinkStyle.d.ts +0 -25
package/dist/courts.mjs CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/components/courts/courts.ts
1
+ // src/components/courts/courts.ts
2
2
  var e = "court-line";
3
3
  function t(e, t) {
4
4
  let n = document.createElementNS("http://www.w3.org/2000/svg", e);
@@ -325,8 +325,7 @@ function l(r) {
325
325
  }));
326
326
  return i;
327
327
  }
328
- //#endregion
329
- //#region src/components/courts/courtSvgUtil.ts
328
+ // src/components/courts/courtSvgUtil.ts
330
329
  var u = "COURT_SVG", d = {
331
330
  tennis: r,
332
331
  basketball: i,
@@ -371,5 +370,4 @@ function _(e, t = "") {
371
370
  let n = e ? d[e] : void 0;
372
371
  if (n) return g(n(t ? `court--${e} ${t}` : `court--${e}`));
373
372
  }
374
- //#endregion
375
373
  export { u as COURT_SVG_RESOURCE_SUB_TYPE, c as badmintonCourt, a as baseballDiamond, i as basketballCourt, _ as createCourtSvg, o as hockeyRink, l as padelCourt, s as pickleballCourt, h as resolveCourtSport, m as sportFromMatchUpFormat, r as tennisCourt };
@@ -1,4 +1,4 @@
1
- //#region node_modules/.pnpm/timepicker-ui@4.6.0/node_modules/timepicker-ui/dist/index.js
1
+ // node_modules/.pnpm/timepicker-ui@4.6.0/node_modules/timepicker-ui/dist/index.js
2
2
  var e = () => typeof window > "u", t = () => typeof document < "u", n = () => new Intl.DateTimeFormat(void 0, { hour: "numeric" }).resolvedOptions().hour12 ? "12h" : "24h", r = [
3
3
  [
4
4
  "ui",
@@ -1293,11 +1293,7 @@ var St = (e, t) => t === "hour" ? e.options.clock.type === "12h" ? [1, 12] : [0,
1293
1293
  "second"
1294
1294
  ]
1295
1295
  ], Pt = (e) => {
1296
- if (typeof requestAnimationFrame > "u") {
1297
- e();
1298
- return;
1299
- }
1300
- requestAnimationFrame(() => e());
1296
+ typeof requestAnimationFrame > "u" ? e() : requestAnimationFrame(() => e());
1301
1297
  }, G = (e) => {
1302
1298
  e?.classList.remove("mobile"), e?.classList.add("expanded");
1303
1299
  }, Ft = class {
@@ -1336,13 +1332,9 @@ var St = (e, t) => t === "hour" ? e.options.clock.type === "12h" ? [1, 12] : [0,
1336
1332
  }
1337
1333
  switchLandscape(e, t) {
1338
1334
  let { modal: n, wrapper: r, clockWrapper: i, clockFace: a } = e, o = this.core.options.ui.animation && !T();
1339
- if (o && n.classList.add(jt), t ? (a?.classList.remove("scale-in"), i?.classList.add("mobile"), this.finishCollapse(e)) : (this.showClockView(e), G(r), G(i), a?.classList.add("scale-in")), !o) {
1340
- this.release(e);
1341
- return;
1342
- }
1343
- setTimeout(() => {
1335
+ o && n.classList.add(jt), t ? (a?.classList.remove("scale-in"), i?.classList.add("mobile"), this.finishCollapse(e)) : (this.showClockView(e), G(r), G(i), a?.classList.add("scale-in")), o ? setTimeout(() => {
1344
1336
  n.classList.remove(jt), this.release(e);
1345
- }, m.WRAPPER_TRANSITION);
1337
+ }, m.WRAPPER_TRANSITION) : this.release(e);
1346
1338
  }
1347
1339
  collapsePortrait(e) {
1348
1340
  e.clockFace?.classList.toggle("scale-in", !e.isOriginallyMobile), e.clockWrapper?.classList.remove("expanded"), e.isOriginallyMobile && e.clockWrapper?.classList.add("mobile"), Pt(() => {
@@ -1479,14 +1471,10 @@ var Jt = class {
1479
1471
  }
1480
1472
  getDisableTime() {
1481
1473
  let e = Bt(this.core.options) || null, t = this.buildPredicate();
1482
- if (this.core.setTimePredicate(t), !t) {
1483
- this.core.setDisabledTime(e);
1484
- return;
1485
- }
1486
- this.core.setDisabledTime({ value: {
1474
+ this.core.setTimePredicate(t), t ? this.core.setDisabledTime({ value: {
1487
1475
  ...e?.value,
1488
1476
  predicate: t
1489
- } });
1477
+ } }) : this.core.setDisabledTime(e);
1490
1478
  }
1491
1479
  clearPredicateCache() {
1492
1480
  this.core.timePredicate?.clear();
@@ -2053,17 +2041,13 @@ var nn = class {
2053
2041
  let t = this.getClockSystem();
2054
2042
  if (!t) return;
2055
2043
  let n = this.convertDisabledTime();
2056
- if (!e) {
2057
- t.updateDisabledTime(n);
2058
- return;
2059
- }
2060
- t.updateDisabledTime({
2044
+ e ? t.updateDisabledTime({
2061
2045
  ...n,
2062
2046
  rangeFromType: e.fromType,
2063
2047
  rangeFromHour: e.fromHour,
2064
2048
  rangeFromMinute: e.fromMinute ?? _n(e.minutes),
2065
2049
  rangeFromSecond: _n(e.seconds)
2066
- });
2050
+ }) : t.updateDisabledTime(n);
2067
2051
  }
2068
2052
  }, yn = /* @__PURE__ */ new WeakMap(), bn = (e, t) => {
2069
2053
  let n = e.clockType ?? t, r = yn.get(e);
@@ -2213,13 +2197,9 @@ var nn = class {
2213
2197
  }
2214
2198
  animateToAngle(e) {
2215
2199
  let t = Z.calculateShortestPath(this.currentAngle, e);
2216
- if (this.currentAngle = t, T()) {
2217
- this.config.clockHand.style.transform = `rotateZ(${t}deg)`;
2218
- return;
2219
- }
2220
- this.clearSnapTimeout(), this.config.clockHand.classList.add("tp-ui-tips-animation"), this.config.clockHand.style.transform = `rotateZ(${t}deg)`, this.snapTimeout = setTimeout(() => {
2200
+ this.currentAngle = t, T() ? this.config.clockHand.style.transform = `rotateZ(${t}deg)` : (this.clearSnapTimeout(), this.config.clockHand.classList.add("tp-ui-tips-animation"), this.config.clockHand.style.transform = `rotateZ(${t}deg)`, this.snapTimeout = setTimeout(() => {
2221
2201
  this.snapTimeout = null, this.config.clockHand.classList.remove("tp-ui-tips-animation");
2222
- }, m.TIPS_ANIMATION);
2202
+ }, m.TIPS_ANIMATION));
2223
2203
  }
2224
2204
  clearSnapTimeout() {
2225
2205
  this.snapTimeout !== null && (clearTimeout(this.snapTimeout), this.snapTimeout = null);
@@ -3060,11 +3040,7 @@ var er = class {
3060
3040
  this.core.setIsOpen(!1), this.releaseOpenView(), this.core.setIsModalRemove(!0), this.eventsBundle(!0), e !== null && this.managers.modal.restoreFocus(e);
3061
3041
  }
3062
3042
  discardSelection() {
3063
- if (j(this.core.options)) {
3064
- this.rerender(), this.core.getCancelButton()?.focus();
3065
- return;
3066
- }
3067
- this.unmount();
3043
+ j(this.core.options) ? (this.rerender(), this.core.getCancelButton()?.focus()) : this.unmount();
3068
3044
  }
3069
3045
  closeUnlessInline() {
3070
3046
  j(this.core.options) || this.unmount();
@@ -3124,11 +3100,7 @@ var er = class {
3124
3100
  this.managers.modal.setScrollbarOrNot(), this.managers.modal.setModalTemplate(), this.managers.modal.setNormalizeClass(), this.managers.modal.removeBackdrop();
3125
3101
  }
3126
3102
  applyExpandedState() {
3127
- if (this.core.isMobileView) {
3128
- this.managers.config.updateClockFaceAccessibility(!0);
3129
- return;
3130
- }
3131
- this.core.getModalElement()?.querySelectorAll("*").forEach((e) => {
3103
+ this.core.isMobileView ? this.managers.config.updateClockFaceAccessibility(!0) : this.core.getModalElement()?.querySelectorAll("*").forEach((e) => {
3132
3104
  e.classList.contains("tp-ui-select-time") || e.classList.add("expanded");
3133
3105
  });
3134
3106
  }
@@ -3316,11 +3288,7 @@ var $ = /* @__PURE__ */ new Map(), pr = class {
3316
3288
  this.lifecycle.mount(), e && e();
3317
3289
  }
3318
3290
  close(e, t) {
3319
- if (e) {
3320
- this.lifecycle.unmount(t, !0);
3321
- return;
3322
- }
3323
- this.lifecycle.unmount(), t && t();
3291
+ e ? this.lifecycle.unmount(t, !0) : (this.lifecycle.unmount(), t && t());
3324
3292
  }
3325
3293
  destroy(e) {
3326
3294
  $.delete(this.core.instanceId), this.lifecycle.destroy(e);
@@ -3469,5 +3437,4 @@ var $ = /* @__PURE__ */ new Map(), pr = class {
3469
3437
  Array.from($.values()).forEach((e) => e.destroy()), $.clear();
3470
3438
  }
3471
3439
  };
3472
- //#endregion
3473
3440
  export { E as PluginRegistry, pr as TimepickerUI };
package/dist/features.css CHANGED
@@ -1,2 +1,2 @@
1
- .court-line{stroke:#505ab4b3;stroke-width:1.5px;fill:none;vector-effect:non-scaling-stroke}.court--tennis .court-line{stroke:#3c50c8cc}.court--basketball .court-line{stroke:#b450c8b3}.court--baseball .court-line{stroke:#c83246b3}.court--hockey .court-line{stroke:#1e78d2bf}.court--pickleball .court-line{stroke:#14a046b3}.court--badminton .court-line{stroke:#00b4a0b3}.court--padel .court-line{stroke:#c88214bf}@media (prefers-color-scheme:dark){:root:not([data-theme]) .court-line{stroke:#7882ff80}:root:not([data-theme]) .court--tennis .court-line{stroke:#667eea99}:root:not([data-theme]) .court--basketball .court-line{stroke:#f093fb80}:root:not([data-theme]) .court--baseball .court-line{stroke:#f5576c80}:root:not([data-theme]) .court--hockey .court-line{stroke:#4facfe8c}:root:not([data-theme]) .court--pickleball .court-line{stroke:#43e97b80}:root:not([data-theme]) .court--badminton .court-line{stroke:#38f9d780}:root:not([data-theme]) .court--padel .court-line{stroke:#ffb74d8c}}[data-theme=dark] .court-line{stroke:#7882ff80}[data-theme=dark] .court--tennis .court-line{stroke:#667eea99}[data-theme=dark] .court--basketball .court-line{stroke:#f093fb80}[data-theme=dark] .court--baseball .court-line{stroke:#f5576c80}[data-theme=dark] .court--hockey .court-line{stroke:#4facfe8c}[data-theme=dark] .court--pickleball .court-line{stroke:#43e97b80}[data-theme=dark] .court--badminton .court-line{stroke:#38f9d780}[data-theme=dark] .court--padel .court-line{stroke:#ffb74d8c}.chc-sb{flex-direction:row;align-items:stretch;gap:2px;min-width:0;height:1.5em;display:none;overflow:hidden}.chc-sb__seg{background:var(--seg-bg,var(--chc-text-muted,#6b7280));color:#fff;border-radius:2px;flex:0 0 0;justify-content:center;align-items:center;min-width:0;padding:0;font-size:.85em;font-weight:600;line-height:1;transition:opacity .15s;display:flex;overflow:hidden}.chc-sb__seg.is-clickable{cursor:pointer}.chc-sb__seg.is-clickable:hover{filter:brightness(1.1)}.chc-sb.has-active .chc-sb__seg:not(.is-active){opacity:.35}
1
+ .court-line{stroke:color-mix(in srgb, var(--chc-accent-indigo,#667eea) 70%, transparent);stroke-width:1.5px;fill:none;vector-effect:non-scaling-stroke}.court--tennis .court-line{stroke:color-mix(in srgb, var(--chc-accent-indigo,#667eea) 80%, transparent)}.court--basketball .court-line{stroke:color-mix(in srgb, var(--chc-accent-purple,#f093fb) 70%, transparent)}.court--baseball .court-line{stroke:color-mix(in srgb, var(--chc-accent-red,#f5576c) 70%, transparent)}.court--hockey .court-line{stroke:color-mix(in srgb, var(--chc-accent-blue,#4facfe) 75%, transparent)}.court--pickleball .court-line{stroke:color-mix(in srgb, var(--chc-accent-green,#43e97b) 70%, transparent)}.court--badminton .court-line{stroke:color-mix(in srgb, var(--chc-accent-teal,#38f9d7) 70%, transparent)}.court--padel .court-line{stroke:color-mix(in srgb, var(--chc-accent-orange,#ffb74d) 75%, transparent)}.chc-sb{flex-direction:row;align-items:stretch;gap:2px;min-width:0;height:1.5em;display:none;overflow:hidden}.chc-sb__seg{background:var(--seg-bg,var(--chc-text-muted));color:#fff;border-radius:2px;flex:0 0 0;justify-content:center;align-items:center;min-width:0;padding:0;font-size:.85em;font-weight:600;line-height:1;transition:opacity .15s;display:flex;overflow:hidden}.chc-sb__seg.is-clickable{cursor:pointer}.chc-sb__seg.is-clickable:hover{filter:brightness(1.1)}.chc-sb.has-active .chc-sb__seg:not(.is-active){opacity:.35}
2
2
  /*$vite$:1*/
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  export { renderParticipant } from './components/renderStructure/renderParticipant';
2
2
  export { renderParticipantInput } from './components/renderStructure/renderParticipantInput';
3
3
  export { renderRoundHeader } from './components/renderStructure/renderRoundHeader';
4
- export { renderStructure } from './components/renderStructure/renderStructure';
4
+ export { renderStructure, applyFavourites } from './components/renderStructure/renderStructure';
5
5
  export { renderContainer } from './components/renderStructure/renderContainer';
6
+ export { renderMatchUpInPlace } from './components/renderStructure/renderMatchUpInPlace';
7
+ export { renderRoundPager } from './components/renderStructure/renderRoundPager';
6
8
  export { renderMatchUp } from './components/renderStructure/renderMatchUp';
7
9
  export { compositions } from './compositions/compositions';
8
10
  export { resolvePublishedComposition } from './compositions/resolvePublishedComposition';
@@ -11,7 +13,7 @@ export { renderRound } from './components/renderStructure/renderRound';
11
13
  export { buildStructureMinimap } from './components/renderStructure/renderStructureMinimap';
12
14
  export type { StructureMinimapOptions } from './components/renderStructure/renderStructureMinimap';
13
15
  export { renderSchematicStructure, renderSchematicRound, renderSchematicMatchUp } from './components/renderSchematicStructure';
14
- export type { SchematicMatchUp } from './components/renderSchematicStructure';
16
+ export type { SchematicMatchUp, SchematicOptions } from './components/renderSchematicStructure';
15
17
  export { cModal } from './components/modal/cmodal';
16
18
  export { getMockParticipantsModal } from './components/modal/mockParticipants';
17
19
  export type { MockParticipantsConfig } from './components/modal/mockParticipants';
@@ -28,14 +30,14 @@ export { getCategoryModal } from './components/categories/category/category';
28
30
  export type { CategoryConfig, Category } from './components/categories/category/category';
29
31
  export { getFlightProfileModal } from './components/flightProfile/flightProfileNew';
30
32
  export type { FlightProfileConfig } from './components/flightProfile/flightProfileNew';
31
- export { scoringModal } from './components/scoring/scoringModal';
32
- export { setScoringConfig, getScoringConfig, resetScoringConfig } from './components/scoring/config';
33
- export type { ScoringModalParams, ScoringModalLabels, ScoreOutcome, SetScore } from './components/scoring/types';
34
33
  export type { StatusCodeGroups, StatusCodeEntry } from './components/scoring/logic/statusCodes';
34
+ export type { SetScore } from './components/scoring/types';
35
35
  export { openScoreEntryDialog } from './components/scoring/scoreEntryDialog';
36
36
  export type { ScoreEntryDialogParams, ScoreEntryApproach, ScoreEntryDialog } from './components/scoring/scoreEntryDialog';
37
37
  export type { ScoreEntryOutcome, ScoreEntryCard } from './components/scoring/scoreEntryCard';
38
38
  export { toEngineOutcome } from './components/scoring/logic/engineOutcome';
39
+ export { SCORE_ENTRY_TEXT, scoreEntryText } from './components/scoring/logic/scoreEntryText';
40
+ export type { ScoreEntryTextKey, ScoreEntryLabels } from './components/scoring/logic/scoreEntryText';
39
41
  export type { EngineOutcome as ScoreEntryEngineOutcome } from './components/scoring/logic/engineOutcome';
40
42
  export { getSetFormatForIndex, isSetTiebreakOnly, isSetTimed, getMaxAllowedScore, isSetComplete, getSetWinner, isMatchComplete, getMatchWinner, calculateComplement, shouldApplySmartComplement, shouldShowTiebreak, shouldCreateNextSet, buildSetScore } from './components/scoring/logic/dynamicSetsLogic';
41
43
  export type { SetFormat, MatchUpConfig, SmartComplementResult } from './components/scoring/logic/dynamicSetsLogic';
@@ -1,4 +1,4 @@
1
- //#region node_modules/.pnpm/timepicker-ui@4.6.0/node_modules/timepicker-ui/dist/plugins/range.js
1
+ // node_modules/.pnpm/timepicker-ui@4.6.0/node_modules/timepicker-ui/dist/plugins/range.js
2
2
  var e = /^(0?[1-9]|1[0-2]):([0-5]?\d)(?::([0-5]?\d))?\s*(AM|PM)$/i, t = /^([01]?\d|2[0-3]):([0-5]?\d)(?::([0-5]?\d))?$/, n = /^\s*\d{1,2}:\d{1,2}:\d{1,2}/, r = (e) => String(e).padStart(2, "0");
3
3
  function i(n, i) {
4
4
  let a = n.trim().match(i.clockType === "12h" ? e : t);
@@ -627,5 +627,4 @@ var G = class {
627
627
  name: "range",
628
628
  factory: (e, t) => new G(e, t)
629
629
  };
630
- //#endregion
631
630
  export { K as RangePlugin };
@@ -1,4 +1,4 @@
1
- //#region src/components/segmentedBar/buildSegmentedBar.ts
1
+ // src/components/segmentedBar/buildSegmentedBar.ts
2
2
  function e(e) {
3
3
  let { segments: t, onSegmentClick: n } = e, r = document.createElement("div");
4
4
  r.className = "chc-sb";
@@ -23,5 +23,4 @@ function e(e) {
23
23
  }
24
24
  };
25
25
  }
26
- //#endregion
27
26
  export { e as buildSegmentedBar };
@@ -2,4 +2,10 @@
2
2
  * Theme system — plain CSS class names.
3
3
  * Replaces Stitches createTheme(). Theme classes are defined in themes.css.
4
4
  */
5
+ /**
6
+ * @deprecated `overrides` is ignored: the theme is the CSS class this returns, styled in themes.css.
7
+ * Change a composition's look with its `colors` (`CompositionColors`) or the `--chc-*` CSS tokens.
8
+ *
9
+ * Still returns the class name; kept until a later major decides its removal.
10
+ */
5
11
  export declare function createTheme(name: string, _overrides: Record<string, any>): string;
package/dist/types.d.ts CHANGED
@@ -1,5 +1,11 @@
1
- import { SideExitProvenance } from 'tods-competition-factory';
2
- export type { SideExitProvenance, SideExitProvenanceEntry } from 'tods-competition-factory';
1
+ import { OnlineResource, SideExitProvenance } from 'tods-competition-factory';
2
+ export type { OnlineResource, SideExitProvenance, SideExitProvenanceEntry } from 'tods-competition-factory';
3
+ /**
4
+ * The `resourceSubType`s the structure renders an icon for, on a matchUp's `onlineResources` entry
5
+ * with `resourceType: 'URL'`. A CODES convention (CA, 2026-10-25), documented in the factory docs
6
+ * (CODES › Online resources): a recording, a live stream, a statistics page of THAT matchUp.
7
+ */
8
+ export type OnlineResourceSubType = 'VIDEO' | 'STREAM' | 'STATS';
3
9
  export interface MatchUp {
4
10
  matchUpId: string;
5
11
  matchUpType?: 'SINGLES' | 'DOUBLES' | 'TEAM' | 'HYBRID';
@@ -38,6 +44,13 @@ export interface MatchUp {
38
44
  schedule?: Schedule;
39
45
  readyToScore?: boolean;
40
46
  sideExitProvenance?: SideExitProvenance;
47
+ /** A recording, stream or stats page of this matchUp; see `OnlineResourceSubType`. */
48
+ onlineResources?: OnlineResource[];
49
+ /** The side serving the next point, the factory's own name for it (ScoringEngine `getNextServer() + 1`). */
50
+ serverSideNumber?: 1 | 2;
51
+ /** On a hydrated (inContext) matchUp; `configuration.scheduleInfo.eventRound` shows it. */
52
+ eventName?: string;
53
+ roundName?: string;
41
54
  [key: string]: any;
42
55
  }
43
56
  export interface Side {
@@ -150,6 +163,12 @@ export interface SideScore {
150
163
  export interface Schedule {
151
164
  scheduledDate?: string;
152
165
  scheduledTime?: string;
166
+ /**
167
+ * Playing time so far, from the factory's `getMatchUpScheduleDetails` (`matchUpDuration`): suspensions are
168
+ * excluded, and a live matchUp is counted to the moment it was hydrated. `configuration.scheduleInfo.elapsed`
169
+ * reads it before `startTime` / `endTime`.
170
+ */
171
+ milliseconds?: number;
153
172
  startTime?: string;
154
173
  endTime?: string;
155
174
  courtId?: string;
@@ -157,9 +176,46 @@ export interface Schedule {
157
176
  venueId?: string;
158
177
  venueAbbreviation?: string;
159
178
  }
179
+ export interface ScheduleInfoOptions {
180
+ /** Playing time (`h:mm`) in place of the date, once the matchUp has started. */
181
+ elapsed?: boolean;
182
+ /** The event and round: `Men's Singles - R32` (split layout) or two more `·` parts (inline layout). */
183
+ eventRound?: boolean;
184
+ /**
185
+ * `split` (default): time on the left, location on the right — or, with `eventRound`, icons, time and location
186
+ * left and the event and round right. `inline`: one line of `·`-separated parts led by `Live` while in progress:
187
+ * `Live · 0:16 · RMTA Court 8 · Men's Singles · R32`.
188
+ */
189
+ layout?: 'split' | 'inline';
190
+ }
191
+ /** Actions under the card, each rendered only when it can do something. */
192
+ export interface MatchUpActions {
193
+ /** A `Watch` button when the matchUp has a STREAM or VIDEO resource; it opens it as the header icons do. */
194
+ watch?: boolean;
195
+ /** A share button, when the host supplies `eventHandlers.matchUpShare`. */
196
+ share?: boolean;
197
+ }
198
+ export type SideColors = {
199
+ 1?: string;
200
+ 2?: string;
201
+ } | ((params: {
202
+ matchUp: MatchUp;
203
+ sideNumber: 1 | 2;
204
+ }) => string | undefined);
160
205
  export interface Configuration {
161
206
  flags?: boolean;
207
+ /**
208
+ * @deprecated Declared but never read. Use `flags`.
209
+ *
210
+ * Kept, inert, until a later major decides its removal (structure rendering vNext, CA 2026-10-25).
211
+ */
162
212
  flag?: boolean;
213
+ /**
214
+ * @deprecated Renders a demo logo hashed from the participantId, not the participant's own data.
215
+ * A participant slot renderer is the planned replacement (structure rendering vNext, item 6).
216
+ *
217
+ * Still works as before; kept until a later major decides its removal.
218
+ */
163
219
  teamLogo?: boolean;
164
220
  roundHeader?: boolean;
165
221
  winnerChevron?: boolean;
@@ -175,7 +231,27 @@ export interface Configuration {
175
231
  allDrawPositions?: boolean;
176
232
  drawPositionColor?: string;
177
233
  bracketedSeeds?: boolean | 'square';
178
- scheduleInfo?: boolean;
234
+ /** The header above the card: date and time, then location. The object form adds to it (all off by default). */
235
+ scheduleInfo?: boolean | ScheduleInfoOptions;
236
+ /**
237
+ * A colour per side: `{ 1: '#0047d4', 2: '#dd5d13' }`, or a function the host answers per matchUp (a team's
238
+ * colour, say). Sets `--chc-side-color` on each side, which colours the winner's or server's name, the sets a
239
+ * side won, the point score, the tick, and tints the winner's row. Off by default.
240
+ */
241
+ sideColors?: SideColors;
242
+ /**
243
+ * A serve indicator from `matchUp.serverSideNumber`, while the matchUp is unfinished. Off by default.
244
+ * `true` / `'column'`: a column on both sides, so the scores stay aligned, filled on the server's.
245
+ * `'name'`: a dot just after the serving side's name.
246
+ */
247
+ serverIndicator?: boolean | 'column' | 'name';
248
+ /** Watch and share actions under the card. Off by default. */
249
+ matchUpActions?: MatchUpActions;
250
+ /**
251
+ * The `LIVE` pill on each side of an in-progress matchUp. On unless set `false`: a scoreboard whose header and
252
+ * point score already say the matchUp is live turns it off. Inline scoring's own live chip is not affected.
253
+ */
254
+ liveStatusPill?: boolean;
179
255
  matchUpFooter?: boolean;
180
256
  showAddress?: boolean;
181
257
  seedingElement?: 'sup' | 'span';
@@ -187,6 +263,37 @@ export interface Configuration {
187
263
  * Set `false` where a consumer renders its own explanation elsewhere.
188
264
  */
189
265
  seedingBasisMarker?: boolean;
266
+ /**
267
+ * The side's entry status beside its seed: `[1, WC]` inside the seed's brackets when `bracketedSeeds` is
268
+ * set, otherwise a small tag. `true` shows every status but direct acceptance; `'all'` shows that too.
269
+ * Off by default. Lucky losers keep their own `LL` badge.
270
+ */
271
+ entryStatus?: boolean | 'all';
272
+ /**
273
+ * A ▲ before the winner's tick when a seed was beaten in a fully scored result (COMPLETED, every set finished;
274
+ * not a retirement, walkover or default) by an unseeded
275
+ * side or a lower seed. Off by default. `.tmx-m` carries `data-upset` either way.
276
+ */
277
+ upsetMarker?: boolean;
278
+ /**
279
+ * Hovering a participant also marks their path through the structure: every matchUp they appear in
280
+ * (`.chc-path`), the connectors out of the matchUps they won, and, while they are still alive, the
281
+ * matchUps ahead of them by draw position (`.chc-path--projected`, dashed). Nothing is projected in
282
+ * round robin, ad hoc or lucky draws. Off by default; the hovered sides highlight either way.
283
+ */
284
+ pathHighlight?: boolean;
285
+ /**
286
+ * Host renderers for named slots in the structure. Each returns an element, or nothing to leave the slot
287
+ * empty; the element is wrapped in `.chc-slot.chc-slot--<name>` and never modified. Runtime functions,
288
+ * so they are set by the host, not stored in a published composition. See `StructureRenderers`.
289
+ */
290
+ renderers?: StructureRenderers;
291
+ /**
292
+ * @deprecated Adds the class `chc-matchup--custom-hover`, which no CSS rule styles, so it changes
293
+ * nothing on screen. Use `colors.borderHover` on the composition.
294
+ *
295
+ * Still adds the class; kept until a later major decides its removal.
296
+ */
190
297
  matchUpHover?: boolean | string;
191
298
  participantDetail?: string;
192
299
  inlineAssignment?: boolean;
@@ -204,6 +311,12 @@ export interface Configuration {
204
311
  isDirty?: boolean;
205
312
  situationText?: string;
206
313
  };
314
+ /**
315
+ * @deprecated Declared but never read. Which name renders is decided by the participant's own
316
+ * `useOtherName`.
317
+ *
318
+ * Kept, inert, until a later major decides its removal.
319
+ */
207
320
  useParticipantName?: boolean;
208
321
  genderColor?: boolean | string;
209
322
  winnerColor?: boolean | string;
@@ -212,6 +325,36 @@ export interface Configuration {
212
325
  bye?: string;
213
326
  qualifier?: string;
214
327
  };
328
+ /**
329
+ * Length in px of the connector line between rounds. Default 16. Sets `--chc-connector-w`, which the
330
+ * connector pseudo-elements and the round gap read.
331
+ */
332
+ connectorWidth?: number;
333
+ /**
334
+ * `'compact'` tightens the structure: less space between matchUps and rounds, shorter and narrower sides,
335
+ * smaller names and scores. `'comfortable'` (the default) is the existing token set. Both are `--chc-*`
336
+ * tokens (`--chc-space-matchup`, `--chc-round-gap`, `--chc-participant-min-height`,
337
+ * `--chc-participant-min-width`, `--chc-participant-name-size`, `--chc-font-size-1`), so a host can set
338
+ * any one of them instead.
339
+ */
340
+ density?: 'compact' | 'comfortable';
341
+ /**
342
+ * Rounded corners: the matchUp card, the connector elbows, the status pills and boxed scores. Off by
343
+ * default. Backed by the tokens `--chc-radius-matchup`, `--chc-radius-connector`, `--chc-radius-pill`
344
+ * and `--chc-radius-score`; set them on `.chc-rounded` to change the radii.
345
+ */
346
+ rounded?: boolean;
347
+ /**
348
+ * An icon for each of the matchUp's online resources: play for a VIDEO, a live dot for a STREAM, a
349
+ * chart for STATS. Off by default. `true` shows all three; `{ subTypes }` narrows it. In the schedule
350
+ * header's right-hand group when `scheduleInfo` is on, otherwise a badge on the card's top corner.
351
+ *
352
+ * A click calls `eventHandlers.onlineResourceClick` when given, otherwise opens the resource's
353
+ * `identifier` in a new tab (http and https only).
354
+ */
355
+ onlineResources?: boolean | {
356
+ subTypes?: OnlineResourceSubType[];
357
+ };
215
358
  scaleAttributes?: {
216
359
  scaleColor?: string;
217
360
  scaleType?: string;
@@ -222,6 +365,77 @@ export interface Configuration {
222
365
  scalePosition?: 'left' | 'right';
223
366
  rawValue?: any;
224
367
  };
368
+ /**
369
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
370
+ * `ModalConfiguration`.
371
+ */
372
+ clickAway?: ModalConfiguration['clickAway'];
373
+ /**
374
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
375
+ * `ModalConfiguration`.
376
+ */
377
+ backdrop?: ModalConfiguration['backdrop'];
378
+ /**
379
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
380
+ * `ModalConfiguration`.
381
+ */
382
+ maxWidth?: ModalConfiguration['maxWidth'];
383
+ /**
384
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
385
+ * `ModalConfiguration`.
386
+ */
387
+ fontSize?: ModalConfiguration['fontSize'];
388
+ /**
389
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
390
+ * `ModalConfiguration`.
391
+ */
392
+ padding?: ModalConfiguration['padding'];
393
+ /**
394
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
395
+ * `ModalConfiguration`.
396
+ */
397
+ className?: ModalConfiguration['className'];
398
+ /**
399
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
400
+ * `ModalConfiguration`.
401
+ */
402
+ style?: ModalConfiguration['style'];
403
+ /**
404
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
405
+ * `ModalConfiguration`.
406
+ */
407
+ info?: ModalConfiguration['info'];
408
+ /**
409
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
410
+ * `ModalConfiguration`.
411
+ */
412
+ menu?: ModalConfiguration['menu'];
413
+ /**
414
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
415
+ * `ModalConfiguration`.
416
+ */
417
+ title?: ModalConfiguration['title'];
418
+ /**
419
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
420
+ * `ModalConfiguration`.
421
+ */
422
+ content?: ModalConfiguration['content'];
423
+ /**
424
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
425
+ * `ModalConfiguration`.
426
+ */
427
+ footer?: ModalConfiguration['footer'];
428
+ /**
429
+ * @deprecated A modal key, read only by `cModal`; it has no effect on a structure. Use
430
+ * `ModalConfiguration`.
431
+ */
432
+ dictionary?: ModalConfiguration['dictionary'];
433
+ }
434
+ /**
435
+ * The modal's own options (`cModal.open({ config })`). They used to be declared on the structure's
436
+ * `Configuration`, which they have nothing to do with; their copies there are deprecated.
437
+ */
438
+ export interface ModalConfiguration {
225
439
  clickAway?: boolean;
226
440
  backdrop?: boolean;
227
441
  maxWidth?: number;
@@ -251,6 +465,41 @@ export interface Configuration {
251
465
  close?: string;
252
466
  };
253
467
  }
468
+ /**
469
+ * The structure's slots. `matchUpHeader` and `matchUpFooter` add height to the card: until the connector
470
+ * rework (structure rendering vNext item 10), give every matchUp the same header/footer height or the
471
+ * connectors drift by the difference.
472
+ */
473
+ export interface StructureRenderers {
474
+ /** Top of the card, above the schedule header. */
475
+ matchUpHeader?: (ctx: {
476
+ matchUp: MatchUp;
477
+ }) => HTMLElement | undefined | null;
478
+ /**
479
+ * Small status badges: first in the schedule header's right-hand group when `scheduleInfo` is on, else a
480
+ * badge on the card's top end corner.
481
+ */
482
+ matchUpBadges?: (ctx: {
483
+ matchUp: MatchUp;
484
+ }) => HTMLElement | undefined | null;
485
+ /** After the participant's name and seed: a rating, a club, an avatar. */
486
+ participantSuffix?: (ctx: {
487
+ individualParticipant?: IndividualParticipant;
488
+ sideNumber?: number;
489
+ matchUp?: MatchUp;
490
+ side?: Side;
491
+ }) => HTMLElement | undefined | null;
492
+ /** The card's footer. Replaces the round label when `configuration.matchUpFooter` is on; shows on its own otherwise. */
493
+ matchUpFooter?: (ctx: {
494
+ matchUp: MatchUp;
495
+ }) => HTMLElement | undefined | null;
496
+ /** Inside the round header, after the round's name. Needs `configuration.roundHeader`. */
497
+ roundHeader?: (ctx: {
498
+ roundNumber: number;
499
+ roundProfile?: any;
500
+ roundMatchUps?: MatchUp[];
501
+ }) => HTMLElement | undefined | null;
502
+ }
254
503
  export interface CompositionColors {
255
504
  /** matchUp border color — sets `--chc-color-border` on the draw container */
256
505
  border?: string;
@@ -355,8 +604,47 @@ export interface EventHandlers {
355
604
  inlineSubmit?: (params: {
356
605
  matchUpId: string;
357
606
  }) => void;
607
+ /** `configuration.matchUpActions.share`: the host shares the matchUp (a link, a native share sheet, …). */
608
+ matchUpShare?: (params: {
609
+ pointerEvent: MouseEvent;
610
+ matchUp: MatchUp;
611
+ }) => void;
612
+ onlineResourceClick?: (params: {
613
+ pointerEvent: MouseEvent;
614
+ matchUp: MatchUp;
615
+ onlineResource: OnlineResource;
616
+ }) => void;
617
+ centerInfoClick?: (params: {
618
+ pointerEvent: MouseEvent;
619
+ matchUp: MatchUp;
620
+ sideNumber: number;
621
+ }) => void;
622
+ scheduleClick?: (params: {
623
+ pointerEvent: MouseEvent;
624
+ matchUp?: MatchUp;
625
+ }) => void;
626
+ venueClick?: (params: {
627
+ pointerEvent: MouseEvent;
628
+ matchUp?: MatchUp;
629
+ }) => void;
630
+ roundHeaderClick?: (params: RoundHeaderEventParams) => void;
631
+ roundVisibilityClick?: (params: RoundHeaderEventParams) => void;
632
+ groupHeaderClick?: (params: {
633
+ pointerEvent: MouseEvent;
634
+ structureId: string;
635
+ containerStructureId?: string;
636
+ drawId?: string;
637
+ }) => void;
638
+ /** Every key the renderers read is declared above; this admits a host's own keys. */
358
639
  [key: string]: any;
359
640
  }
641
+ export interface RoundHeaderEventParams {
642
+ pointerEvent: MouseEvent;
643
+ roundNumber: number;
644
+ roundProfile?: any;
645
+ roundMatchUps?: MatchUp[];
646
+ context?: any;
647
+ }
360
648
  export interface ModalButton {
361
649
  label?: string;
362
650
  text?: string;
@@ -373,7 +661,12 @@ export interface ModalButton {
373
661
  className?: string;
374
662
  };
375
663
  }
376
- export interface ModalConfig extends Configuration {
664
+ /**
665
+ * Accepts exactly the keys it always has: the modal's own, plus the structure keys it used to inherit,
666
+ * which the modal ignores. The modal keys come from `ModalConfiguration`, so they are not deprecated
667
+ * here.
668
+ */
669
+ export interface ModalConfig extends ModalConfiguration, Omit<Configuration, keyof ModalConfiguration> {
377
670
  onClose?: (params: {
378
671
  content?: any;
379
672
  }) => void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "courthive-components",
3
- "packageManager": "pnpm@12.14.0",
4
- "version": "6.14.0",
3
+ "packageManager": "pnpm@12.15.0",
4
+ "version": "7.1.0",
5
5
  "engines": {
6
6
  "node": ">=24"
7
7
  },
@@ -81,8 +81,8 @@
81
81
  },
82
82
  "devDependencies": {
83
83
  "@chromatic-com/storybook": "^5.0.0",
84
- "@commitlint/cli": "21.2.3",
85
- "@commitlint/config-conventional": "21.2.3",
84
+ "@commitlint/cli": "21.2.4",
85
+ "@commitlint/config-conventional": "21.2.4",
86
86
  "@eslint/js": "^10.0.1",
87
87
  "@fortawesome/fontawesome-free": "^7.2.0",
88
88
  "@storybook/addon-docs": "^10.2.17",
@@ -91,8 +91,8 @@
91
91
  "@types/d3": "^7.4.3",
92
92
  "@types/leaflet": "^1.9.12",
93
93
  "@types/vanillajs-datepicker": "^1.3.5",
94
- "@typescript-eslint/eslint-plugin": "8.71.2",
95
- "@typescript-eslint/parser": "8.71.2",
94
+ "@typescript-eslint/eslint-plugin": "8.72.0",
95
+ "@typescript-eslint/parser": "8.72.0",
96
96
  "@vitest/browser": "^5.0.3",
97
97
  "@vitest/browser-playwright": "^5.0.3",
98
98
  "@vitest/coverage-v8": "^5.0.0",
@@ -110,10 +110,10 @@
110
110
  "prettier": "^3.8.1",
111
111
  "semver": "7.8.5",
112
112
  "storybook": "^10.2.17",
113
- "tabulator-tables": "6.6.1",
114
- "tods-competition-factory": "7.21.0",
113
+ "tabulator-tables": "6.7.1",
114
+ "tods-competition-factory": "7.23.0",
115
115
  "typescript": "^6.0.2",
116
- "vite": "8.3.4",
116
+ "vite": "8.3.5",
117
117
  "vite-plugin-dts": "^5.0.0",
118
118
  "vitest": "^5.0.0"
119
119
  },