courthive-components 1.1.1 → 1.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.
@@ -11,6 +11,9 @@ export declare class SchedulePageControl {
11
11
  setMatchUpCatalog(catalog: CatalogMatchUpItem[]): void;
12
12
  setScheduleDates(dates: ScheduleDate[]): void;
13
13
  setIssues(issues: ScheduleIssue[]): void;
14
+ setActiveStripVisible(visible: boolean): void;
15
+ toggleActiveStrip(): void;
16
+ get activeStripVisible(): boolean;
14
17
  save(): PendingScheduleAction[];
15
18
  discardPending(): void;
16
19
  get hasUnsavedChanges(): boolean;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Schedule Page — Active Strip
3
+ *
4
+ * The active strip is a one-row summary that sits above the court grid and
5
+ * shows, for each court, what is "actively" happening: the in-progress
6
+ * matchUp if any, otherwise the next pending matchUp, otherwise the most
7
+ * recent completed matchUp, otherwise free.
8
+ *
9
+ * Two pure functions:
10
+ *
11
+ * - computeActiveStrip(grid)
12
+ * Picks the cell to surface per court column.
13
+ *
14
+ * - computeActiveStripDropTarget(grid, courtId, dragged)
15
+ * Picks a row when a matchUp is dropped onto a court's strip cell.
16
+ * It infers a "temporal floor" from the existing grid:
17
+ * (a) any row across all courts where the dragged matchUp's
18
+ * participants already appear — the dragged matchUp must land
19
+ * below those rows;
20
+ * (b) within the same draw, any row holding a lower-round matchUp —
21
+ * the dragged matchUp must land below those rows too.
22
+ * The dragged matchUp's own existing cell is ignored (relocation).
23
+ *
24
+ * Both functions are framework-free and DOM-free; tests do not require a UI.
25
+ */
26
+ export interface ActiveStripGridMatchUp {
27
+ matchUpId: string;
28
+ drawId?: string;
29
+ roundNumber?: number;
30
+ matchUpStatus?: string;
31
+ winningSide?: number;
32
+ /** True when at least one set/score has been entered. */
33
+ hasScore?: boolean;
34
+ participantIds: string[];
35
+ /**
36
+ * Consumer-defined opaque payload, passed through unchanged.
37
+ * Useful so the cell renderer can reach the full grid-cell data.
38
+ */
39
+ payload?: unknown;
40
+ }
41
+ export interface ActiveStripCourtColumn {
42
+ courtId: string;
43
+ /** Ordered cells from row 0 (top) downward. `null` marks an empty row. */
44
+ cells: (ActiveStripGridMatchUp | null)[];
45
+ }
46
+ export interface ActiveStripGrid {
47
+ columns: ActiveStripCourtColumn[];
48
+ }
49
+ export type ActiveStripCellState = 'free' | 'in-progress' | 'next' | 'completed';
50
+ export interface ActiveStripCell {
51
+ courtId: string;
52
+ state: ActiveStripCellState;
53
+ matchUp?: ActiveStripGridMatchUp;
54
+ rowIndex?: number;
55
+ }
56
+ export interface ActiveStripDropCandidate {
57
+ matchUpId: string;
58
+ drawId?: string;
59
+ roundNumber?: number;
60
+ participantIds: string[];
61
+ }
62
+ export interface ActiveStripDropTarget {
63
+ courtId: string;
64
+ rowIndex: number;
65
+ }
66
+ export interface ActiveStripStatusOptions {
67
+ inProgressStatuses?: ReadonlySet<string>;
68
+ completedStatuses?: ReadonlySet<string>;
69
+ }
70
+ export declare function computeActiveStripCell(column: ActiveStripCourtColumn, options?: ActiveStripStatusOptions): ActiveStripCell;
71
+ export declare function computeActiveStrip(grid: ActiveStripGrid, options?: ActiveStripStatusOptions): ActiveStripCell[];
72
+ export declare function computeActiveStripDropTarget(grid: ActiveStripGrid, targetCourtId: string, dragged: ActiveStripDropCandidate): ActiveStripDropTarget;
@@ -28,6 +28,8 @@ export declare class SchedulePageStore {
28
28
  setShowCompleted(show: boolean): void;
29
29
  setShowScheduled(show: boolean): void;
30
30
  toggleLeftPanel(): void;
31
+ setActiveStripVisible(visible: boolean): void;
32
+ toggleActiveStrip(): void;
31
33
  subscribe(listener: SchedulePageChangeListener): () => void;
32
34
  private setState;
33
35
  private emit;
@@ -10,6 +10,8 @@ export { SchedulePageStore } from './engine/schedulePageStore';
10
10
  export { filterMatchUpCatalog, groupMatchUpCatalog, isCompletedStatus } from './domain/matchUpCatalogProjections';
11
11
  export { buildScheduleIssueIndex } from './domain/scheduleIssues';
12
12
  export { matchUpLabel, participantLabel, matchUpSearchKey, deepClone } from './domain/utils';
13
+ export { computeActiveStrip, computeActiveStripCell, computeActiveStripDropTarget } from './domain/activeStrip';
14
+ export type { ActiveStripCell, ActiveStripCellState, ActiveStripCourtColumn, ActiveStripDropCandidate, ActiveStripDropTarget, ActiveStripGrid, ActiveStripGridMatchUp, ActiveStripStatusOptions } from './domain/activeStrip';
13
15
  export { buildScheduleDateStrip } from './ui/dateStrip';
14
16
  export { buildScheduleIssuesPanel } from './ui/issuesPanel';
15
17
  export { buildMatchUpCatalog } from './ui/matchUpCatalog';
@@ -17,6 +19,8 @@ export { buildMatchUpCard } from './ui/matchUpCard';
17
19
  export { buildScheduleInspectorPanel } from './ui/inspectorPanel';
18
20
  export { buildCourtGridSlot } from './ui/courtGridSlot';
19
21
  export { buildSchedulePageLayout } from './ui/schedulePageLayout';
22
+ export { buildActiveStripPanel } from './ui/activeStrip';
23
+ export type { ActiveStripPanel, ActiveStripPanelCallbacks, ActiveStripPanelData, ActiveStripPanelOptions, ActiveStripCourtMeta } from './ui/activeStrip';
20
24
  export { buildScheduleGridCell, mapMatchUpToCellData, DEFAULT_SCHEDULE_CELL_CONFIG } from './ui/scheduleGridCell';
21
25
  export { activateScheduleCellTypeAhead } from './ui/scheduleCellTypeAhead';
22
26
  export type { ScheduleCellTypeAheadOptions } from './ui/scheduleCellTypeAhead';
@@ -95,6 +95,8 @@ export interface SchedulePageConfig {
95
95
  catalogSide?: 'left' | 'right';
96
96
  scheduledBehavior?: ScheduledBehavior;
97
97
  schedulingMode?: SchedulingMode;
98
+ /** Initial visibility of the active strip (one-row court summary above the grid). Defaults to true. */
99
+ activeStripVisible?: boolean;
98
100
  onDateSelected?: (date: string) => void;
99
101
  onMatchUpDrop?: (payload: SchedulePageDragPayload, event: DragEvent) => void;
100
102
  onMatchUpRemove?: (matchUpId: string) => void;
@@ -119,6 +121,7 @@ export interface SchedulePageState {
119
121
  hasUnsavedChanges: boolean;
120
122
  leftCollapsed: boolean;
121
123
  hideLeft: boolean;
124
+ activeStripVisible: boolean;
122
125
  }
123
126
  export type SchedulePageChangeListener = (state: SchedulePageState) => void;
124
127
  export interface ScheduleIssueCounts {
@@ -0,0 +1,46 @@
1
+ import { SchedulePageDragPayload, SchedulePageState, UIPanel } from '../types';
2
+ import { ActiveStripDropTarget, ActiveStripGrid, ActiveStripGridMatchUp, ActiveStripStatusOptions } from '../domain/activeStrip';
3
+ export interface ActiveStripCourtMeta {
4
+ courtId: string;
5
+ label: string;
6
+ }
7
+ export interface ActiveStripPanelData {
8
+ /** Court columns, in display order. The strip computes one cell per column. */
9
+ grid: ActiveStripGrid;
10
+ /** Optional display labels per courtId. Falls back to courtId. */
11
+ courts?: ActiveStripCourtMeta[];
12
+ /**
13
+ * CSS grid-template-columns applied to the strip root. When provided, the
14
+ * strip lays out as `display: grid` with a leading spacer occupying the
15
+ * first column, so its court cells align with the grid below.
16
+ */
17
+ gridTemplateColumns?: string;
18
+ /**
19
+ * Explicit min-width applied to the strip root, e.g. to match the grid
20
+ * below so both scroll horizontally as one when wrapped in a shared
21
+ * scroll container.
22
+ */
23
+ minWidth?: string;
24
+ }
25
+ export interface ActiveStripPanelCallbacks {
26
+ /**
27
+ * Called when a matchUp is dropped onto a court's strip cell.
28
+ * The target carries the courtId and the inferred rowIndex.
29
+ * Consumer is responsible for committing the schedule mutation.
30
+ */
31
+ onMatchUpDrop?: (payload: SchedulePageDragPayload, target: ActiveStripDropTarget, event: DragEvent) => void;
32
+ }
33
+ export type ActiveStripCellRenderer = (matchUp: ActiveStripGridMatchUp) => HTMLElement | null;
34
+ export interface ActiveStripPanelOptions {
35
+ statusOptions?: ActiveStripStatusOptions;
36
+ /** Min-height applied to each strip cell. Match the grid row height for visual parity. */
37
+ cellHeight?: string;
38
+ /** Optional renderer for cells with a matchUp. Receives the cell's matchUp (incl. opaque payload). */
39
+ renderCell?: ActiveStripCellRenderer;
40
+ /** Small label rendered inside the leading spacer (e.g. "Now"). Hidden when omitted. */
41
+ spacerLabel?: string;
42
+ }
43
+ export interface ActiveStripPanel extends UIPanel<SchedulePageState> {
44
+ setData: (data: ActiveStripPanelData) => void;
45
+ }
46
+ export declare function buildActiveStripPanel(callbacks?: ActiveStripPanelCallbacks, options?: ActiveStripPanelOptions): ActiveStripPanel;