courthive-components 3.2.0 → 3.4.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 (23) hide show
  1. package/dist/components/policy-catalog/editors/scoring/domain/scoringProjections.d.ts +23 -0
  2. package/dist/components/policy-catalog/editors/scoring/index.d.ts +3 -0
  3. package/dist/components/policy-catalog/editors/scoring/scoringEditorControl.d.ts +21 -0
  4. package/dist/components/policy-catalog/editors/scoring/scoringEditorPanel.d.ts +6 -0
  5. package/dist/components/policy-catalog/editors/scoring/scoringEditorStore.d.ts +33 -0
  6. package/dist/components/policy-catalog/editors/scoring/sections/allowedFormatsSection.d.ts +6 -0
  7. package/dist/components/policy-catalog/editors/scoring/sections/defaultsSection.d.ts +6 -0
  8. package/dist/components/policy-catalog/editors/scoring/sections/matchUpFormatPicker.d.ts +35 -0
  9. package/dist/components/policy-catalog/editors/scoring/sections/statusCodesSection.d.ts +6 -0
  10. package/dist/components/policy-catalog/editors/scoring/sections/tagListEditor.d.ts +24 -0
  11. package/dist/components/policy-catalog/editors/scoring/types.d.ts +60 -0
  12. package/dist/components/policy-catalog/engine/policyCatalogStore.d.ts +11 -0
  13. package/dist/components/policy-catalog/index.d.ts +2 -0
  14. package/dist/components/policy-catalog/types.d.ts +13 -1
  15. package/dist/components/policy-catalog/ui/editorShell.d.ts +1 -0
  16. package/dist/components/schedule-page/types.d.ts +7 -1
  17. package/dist/courthive-components.css +1 -1
  18. package/dist/courthive-components.es.js +2080 -987
  19. package/dist/courthive-components.umd.js +14 -14
  20. package/dist/{dist-CwJOJWf0.mjs → dist-DiYU0jFr.mjs} +529 -487
  21. package/dist/{range-CBX41Ttl.mjs → range-CRxwaxeo.mjs} +125 -58
  22. package/dist/types.d.ts +14 -2
  23. package/package.json +6 -6
@@ -0,0 +1,23 @@
1
+ import { ScoringPolicyData, AllowedFormatEntry } from '../types';
2
+ type RegistryEntry = {
3
+ key?: string;
4
+ name?: string;
5
+ format?: string;
6
+ desc?: string;
7
+ desc2?: string;
8
+ };
9
+ export declare function lookupRegistryFormat(format: string | undefined): RegistryEntry | undefined;
10
+ export declare const MATCH_UP_FORMAT_REGISTRY_SORTED: RegistryEntry[];
11
+ export declare function formatStringOf(entry: AllowedFormatEntry): string;
12
+ export declare function formatNameOf(entry: AllowedFormatEntry): string;
13
+ export declare function formatDescriptionOf(entry: AllowedFormatEntry): string;
14
+ export declare function asMatchUpFormatEntry(entry: AllowedFormatEntry): {
15
+ name?: string;
16
+ description?: string;
17
+ matchUpFormat: string;
18
+ categoryNames?: string[];
19
+ categoryTypes?: string[];
20
+ };
21
+ export declare const FORMAT_STANDARD = "SET3-S:6/TB7";
22
+ export declare function emptyScoringPolicy(): ScoringPolicyData;
23
+ export {};
@@ -0,0 +1,3 @@
1
+ export { ScoringEditorControl, createScoringEditor } from './scoringEditorControl';
2
+ export type { ScoringPolicyData, ScoringEditorConfig, MatchUpStatusKey, MatchUpFormatEntry, AllowedFormatEntry, } from './types';
3
+ export { MATCH_UP_FORMAT_REGISTRY_SORTED, lookupRegistryFormat, emptyScoringPolicy, FORMAT_STANDARD, } from './domain/scoringProjections';
@@ -0,0 +1,21 @@
1
+ import { ScoringEditorStore } from './scoringEditorStore';
2
+ import { ScoringPolicyData, ScoringEditorConfig } from './types';
3
+ import { PolicyEditorInstance as CatalogEditorInstance } from '../../types';
4
+ export declare class ScoringEditorControl {
5
+ private readonly store;
6
+ private readonly panel;
7
+ private readonly unsubscribe;
8
+ private container;
9
+ constructor(config: ScoringEditorConfig);
10
+ render(container: HTMLElement): void;
11
+ destroy(): void;
12
+ getData(): ScoringPolicyData;
13
+ setData(data: ScoringPolicyData): void;
14
+ getStore(): ScoringEditorStore;
15
+ static createEditorInstance(config: {
16
+ initialData: Record<string, unknown>;
17
+ onChange: (data: Record<string, unknown>) => void;
18
+ readonly?: boolean;
19
+ }): CatalogEditorInstance;
20
+ }
21
+ export declare function createScoringEditor(config: ScoringEditorConfig, container: HTMLElement): ScoringEditorControl;
@@ -0,0 +1,6 @@
1
+ import { ScoringEditorState } from './types';
2
+ import { ScoringEditorStore } from './scoringEditorStore';
3
+ export declare function buildScoringEditorPanel(store: ScoringEditorStore): {
4
+ element: HTMLElement;
5
+ update(state: ScoringEditorState): void;
6
+ };
@@ -0,0 +1,33 @@
1
+ import { ScoringPolicyData, ScoringEditorState, ScoringEditorSection, ScoringEditorChangeListener, ScoringEditorConfig, MatchUpStatusKey, AllowedFormatField, MatchUpFormatEntry } from './types';
2
+ export declare class ScoringEditorStore {
3
+ private state;
4
+ private readonly listeners;
5
+ private readonly config;
6
+ constructor(config: ScoringEditorConfig);
7
+ isReadonly(): boolean;
8
+ getState(): ScoringEditorState;
9
+ getData(): ScoringPolicyData;
10
+ setData(data: ScoringPolicyData): void;
11
+ toggleSection(sectionId: ScoringEditorSection): void;
12
+ toggleStatus(key: MatchUpStatusKey): void;
13
+ setAdvancedOpen(value: boolean): void;
14
+ setDefaultMatchUpFormat(value: string): void;
15
+ setRequireParticipants(value: boolean): void;
16
+ setRequireAllPositions(value: 'default' | 'true' | 'false'): void;
17
+ setAllowChangePropagation(value: boolean): void;
18
+ setAllowDeletionDraws(value: boolean): void;
19
+ setAllowDeletionStructures(value: boolean): void;
20
+ addAllowedFormat(seed?: Partial<MatchUpFormatEntry>): void;
21
+ removeAllowedFormat(index: number): void;
22
+ setAllowedFormatField(index: number, field: AllowedFormatField, value: string): void;
23
+ isAllowedFormatDuplicate(format: string, excludeIndex?: number): boolean;
24
+ addAllowedFormatCategory(index: number, kind: 'categoryNames' | 'categoryTypes', value: string): void;
25
+ removeAllowedFormatCategory(index: number, kind: 'categoryNames' | 'categoryTypes', valueIndex: number): void;
26
+ addStatusCode(status: MatchUpStatusKey, value: string): void;
27
+ removeStatusCode(status: MatchUpStatusKey, index: number): void;
28
+ addProcessCode(value: string): void;
29
+ removeProcessCode(index: number): void;
30
+ subscribe(listener: ScoringEditorChangeListener): () => void;
31
+ private commitDraft;
32
+ private emit;
33
+ }
@@ -0,0 +1,6 @@
1
+ import { ScoringEditorState } from '../types';
2
+ import { ScoringEditorStore } from '../scoringEditorStore';
3
+ export declare function buildAllowedFormatsSection(store: ScoringEditorStore): {
4
+ element: HTMLElement;
5
+ update(state: ScoringEditorState): void;
6
+ };
@@ -0,0 +1,6 @@
1
+ import { ScoringEditorState } from '../types';
2
+ import { ScoringEditorStore } from '../scoringEditorStore';
3
+ export declare function buildDefaultsSection(store: ScoringEditorStore): {
4
+ element: HTMLElement;
5
+ update(state: ScoringEditorState): void;
6
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * MatchUp Format Picker — Preset dropdown + free-text + structured builder.
3
+ *
4
+ * V1 UX:
5
+ * ┌─ Preset ──────────────────────────────────────────┐
6
+ * │ [Standard (BO3, sets to 6, TB7) ▾] │
7
+ * │ ↳ shows the matching preset when the underlying │
8
+ * │ format string is one we ship; "Custom" when │
9
+ * │ it isn't. │
10
+ * ├─ Custom format (visible only on "Custom" preset) ─┤
11
+ * │ [SET3-S:6/TB7 ] [✓] │
12
+ * ├─ Build ▾ (collapsible structured editor) ────────┤
13
+ * │ bestOf [3 ▾] │
14
+ * │ set type ◉ Standard ○ Tiebreak ○ Timed │
15
+ * │ …conditional fields per set type… │
16
+ * │ [ ] Different final-set rules │
17
+ * │ Result: SET3-S:6/TB7 [✓ valid] │
18
+ * └──────────────────────────────────────────────────┘
19
+ *
20
+ * The structured builder targets the SET-rooted tennis-family case (which
21
+ * covers 95%+ of the consumers' real-world formats). Sports with other
22
+ * roots (HAL, QTR, RND, MAP…) still set the value via the free-text
23
+ * field; the picker round-trips them but exposes no specialized UI.
24
+ */
25
+ export interface MatchUpFormatPickerConfig {
26
+ initialValue?: string;
27
+ readonly?: boolean;
28
+ onChange: (value: string) => void;
29
+ }
30
+ export interface MatchUpFormatPickerHandle {
31
+ element: HTMLElement;
32
+ setValue(value: string): void;
33
+ destroy(): void;
34
+ }
35
+ export declare function buildMatchUpFormatPicker(config: MatchUpFormatPickerConfig): MatchUpFormatPickerHandle;
@@ -0,0 +1,6 @@
1
+ import { ScoringEditorState } from '../types';
2
+ import { ScoringEditorStore } from '../scoringEditorStore';
3
+ export declare function buildStatusCodesSection(store: ScoringEditorStore): {
4
+ element: HTMLElement;
5
+ update(state: ScoringEditorState): void;
6
+ };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Small chip-list editor used by the "Allowed match-up formats" section
3
+ * and each of the six status-code refinement groups. Repeats the same
4
+ * UX: existing items render as removable chips, a single text input +
5
+ * Add button appends new values.
6
+ *
7
+ * The host owns the array — the editor only emits add(value) /
8
+ * remove(index). State for the input text is purely local DOM.
9
+ */
10
+ export interface TagListEditorConfig {
11
+ values: string[];
12
+ placeholder?: string;
13
+ readonly?: boolean;
14
+ validate?: (value: string) => boolean;
15
+ invalidMessage?: string;
16
+ onAdd: (value: string) => void;
17
+ onRemove: (index: number) => void;
18
+ }
19
+ export interface TagListEditorHandle {
20
+ element: HTMLElement;
21
+ setValues(values: string[]): void;
22
+ destroy(): void;
23
+ }
24
+ export declare function buildTagListEditor(config: TagListEditorConfig): TagListEditorHandle;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Scoring Policy Editor — Type Definitions
3
+ *
4
+ * Mirrors the factory's scoring policy data shape (see
5
+ * factory/src/fixtures/policies/POLICY_SCORING_DEFAULT.ts).
6
+ *
7
+ * The factory does not export a TypeScript interface for the scoring
8
+ * policy itself — the fixture defines the shape via runtime defaults.
9
+ * We re-derive the shape here so the editor can stay type-safe without
10
+ * dragging factory internals into courthive-components.
11
+ */
12
+ export type MatchUpStatusKey = 'ABANDONED' | 'CANCELLED' | 'DEFAULTED' | 'INCOMPLETE' | 'RETIRED' | 'WALKOVER';
13
+ export declare const MATCH_UP_STATUS_KEYS: MatchUpStatusKey[];
14
+ export type RequireAllPositionsTriState = 'default' | 'true' | 'false';
15
+ export interface AllowDeletionWithScoresPresent {
16
+ drawDefinitions?: boolean;
17
+ structures?: boolean;
18
+ }
19
+ export interface StageSequenceOverride {
20
+ requireAllPositionsAssigned?: boolean;
21
+ }
22
+ export interface MatchUpFormatEntry {
23
+ name?: string;
24
+ description?: string;
25
+ matchUpFormat: string;
26
+ categoryNames?: string[];
27
+ categoryTypes?: string[];
28
+ }
29
+ export type AllowedFormatEntry = string | MatchUpFormatEntry;
30
+ export type AllowedFormatField = 'name' | 'description' | 'matchUpFormat';
31
+ export interface ScoringPolicyData {
32
+ policyName?: string;
33
+ defaultMatchUpFormat?: string;
34
+ matchUpFormats?: AllowedFormatEntry[];
35
+ requireParticipantsForScoring?: boolean;
36
+ requireAllPositionsAssigned?: boolean;
37
+ allowChangePropagation?: boolean;
38
+ allowDeletionWithScoresPresent?: AllowDeletionWithScoresPresent;
39
+ matchUpStatusCodes?: Partial<Record<MatchUpStatusKey, string[]>>;
40
+ stage?: Record<string, {
41
+ stageSequence?: Record<string, StageSequenceOverride>;
42
+ }>;
43
+ processCodes?: {
44
+ incompleteAssignmentsOnDefault?: string[];
45
+ };
46
+ }
47
+ export type ScoringEditorSection = 'defaults' | 'allowedFormats' | 'statusCodes';
48
+ export interface ScoringEditorState {
49
+ draft: ScoringPolicyData;
50
+ expandedSections: Set<ScoringEditorSection>;
51
+ expandedStatuses: Set<MatchUpStatusKey>;
52
+ advancedOpen: boolean;
53
+ dirty: boolean;
54
+ }
55
+ export type ScoringEditorChangeListener = (state: ScoringEditorState) => void;
56
+ export interface ScoringEditorConfig {
57
+ initialPolicy?: ScoringPolicyData;
58
+ readonly?: boolean;
59
+ onChange?: (policy: ScoringPolicyData) => void;
60
+ }
@@ -10,6 +10,7 @@ export declare class PolicyCatalogStore {
10
10
  setCatalogGroupBy(mode: CatalogGroupBy): void;
11
11
  selectPolicy(id: string): void;
12
12
  clearSelection(): void;
13
+ renamePolicy(name: string): void;
13
14
  updateEditorDraft(data: Record<string, unknown>): void;
14
15
  markDirty(): void;
15
16
  markClean(): void;
@@ -18,8 +19,18 @@ export declare class PolicyCatalogStore {
18
19
  applyPolicy(): void;
19
20
  addNewPolicy(policyType: string): string;
20
21
  duplicatePolicy(sourceId: string): string | null;
22
+ /**
23
+ * Swap a placeholder id (returned from addNewPolicy/duplicatePolicy) for a
24
+ * canonical id assigned by the persistence backend. Idempotent and a no-op
25
+ * when the placeholder is gone (e.g. user deleted before reconciliation).
26
+ */
27
+ reconcilePolicyId(localId: string, serverId: string): void;
21
28
  deletePolicy(id: string): void;
22
29
  subscribe(listener: PolicyCatalogChangeListener): () => void;
23
30
  private setState;
24
31
  private emit;
32
+ private localIdCounter;
33
+ private nextLocalId;
34
+ private appendAndSelect;
35
+ private runCreateAndReconcile;
25
36
  }
@@ -17,6 +17,8 @@ export { buildJsonEditor } from './ui/jsonEditor';
17
17
  export { SchedulingEditorControl, createSchedulingEditor, SchedulingEditorStore, validateSchedulingPolicy, formatCodeLabel, emptySchedulingPolicy, buildSchedulingEditorPanel } from './editors/scheduling';
18
18
  export { RankingPointsEditorControl, createRankingPointsEditor, RankingPointsEditorStore, buildRankingPointsEditorPanel, emptyRankingPolicy } from './editors/ranking';
19
19
  export { SeedingEditorControl, createSeedingEditor, SeedingEditorStore, buildSeedingEditorPanel, emptySeedingPolicy, POSITIONING_OPTIONS, DRAW_TYPE_OPTIONS } from './editors/seeding';
20
+ export { ScoringEditorControl, createScoringEditor, MATCH_UP_FORMAT_REGISTRY_SORTED, lookupRegistryFormat, emptyScoringPolicy, FORMAT_STANDARD, } from './editors/scoring';
21
+ export type { ScoringPolicyData, ScoringEditorConfig, MatchUpStatusKey, MatchUpFormatEntry, AllowedFormatEntry, } from './editors/scoring';
20
22
  export type { PolicyCatalogItem, PolicyCatalogState, PolicyCatalogChangeListener, PolicyCatalogConfig, PolicyEditorInstance, PolicyEditorPlugin, PolicySource, PolicyTypeGroup, PolicyTypeMeta, CatalogGroupBy, UIPanel } from './types';
21
23
  export type { SchedulingPolicyData, SchedulingEditorState, SchedulingEditorSection, SchedulingEditorChangeListener, SchedulingEditorConfig, SchedulingValidationResult, ValidationSeverity, MinutesEntry, AverageTimeEntry, RecoveryTimeEntry, MatchUpAverageTime, MatchUpRecoveryTime } from './editors/scheduling';
22
24
  export type { RankingPolicyData, RankingPointsEditorState, RankingEditorSection, RankingPointsEditorChangeListener, RankingPointsEditorConfig, AwardProfileData, QualityWinProfileData, AggregationRulesData, TableLayout } from './editors/ranking';
@@ -25,6 +25,12 @@ export interface PolicyCatalogState {
25
25
  groupBy: CatalogGroupBy;
26
26
  selectedId: string | null;
27
27
  editorDraft: Record<string, unknown> | null;
28
+ /**
29
+ * Live name buffer for the selected policy. Populated on selection from the
30
+ * catalog item and mutated by the rename input so renames survive across
31
+ * editor remounts. `savePolicy` writes this back to the catalog item.
32
+ */
33
+ editedName: string | null;
28
34
  dirty: boolean;
29
35
  }
30
36
  export type PolicyCatalogChangeListener = (state: PolicyCatalogState) => void;
@@ -47,7 +53,13 @@ export interface PolicyCatalogConfig {
47
53
  editorPlugins?: PolicyEditorPlugin[];
48
54
  onPolicySaved?: (item: PolicyCatalogItem) => void;
49
55
  onPolicyApplied?: (item: PolicyCatalogItem) => void;
50
- onPolicyCreated?: (item: PolicyCatalogItem) => void;
56
+ /**
57
+ * Fired when "+" creates a new policy. If the host persists the new policy
58
+ * to a backend that mints its own canonical id, return that id (sync or
59
+ * Promise) — the store will reconcile the local placeholder id so subsequent
60
+ * Save calls hit the right backend record. Return void to keep the local id.
61
+ */
62
+ onPolicyCreated?: (item: PolicyCatalogItem) => string | void | Promise<string | void>;
51
63
  onPolicyDeleted?: (id: string) => void;
52
64
  onSelectionChanged?: (item: PolicyCatalogItem | null) => void;
53
65
  }
@@ -4,6 +4,7 @@ export interface EditorShellCallbacks {
4
4
  onReset: () => void;
5
5
  onApply: () => void;
6
6
  onDuplicate: () => void;
7
+ onRename: (name: string) => void;
7
8
  }
8
9
  export interface EditorShellPanel extends UIPanel<PolicyCatalogState> {
9
10
  bodyElement: HTMLElement;
@@ -17,6 +17,12 @@ export interface CatalogMatchUpItem {
17
17
  drawId: string;
18
18
  drawName?: string;
19
19
  structureId: string;
20
+ /** Human-readable structure label set by the factory (e.g. "Main",
21
+ * "Consolation", "Compass NE"). Optional because some structures
22
+ * ship without one — the catalog falls back to a labeled stage and
23
+ * finally the eventName alone so the "by structure" group header
24
+ * never shows a raw structureId GUID. */
25
+ structureName?: string;
20
26
  /** Draw stage — MAIN / CONSOLATION / PLAYOFF / QUALIFYING / ROUND_ROBIN /
21
27
  * etc. Rendered as a chip when present and not MAIN so a Quarterfinal in
22
28
  * the consolation bracket reads distinctly from a Quarterfinal in the
@@ -53,7 +59,7 @@ export interface ScheduleIssue {
53
59
  /** All matchUpIds involved in this conflict (for click-to-scroll fallback) */
54
60
  conflictMatchUpIds?: string[];
55
61
  }
56
- export type MatchUpCatalogGroupBy = 'event' | 'draw' | 'round' | 'structure';
62
+ export type MatchUpCatalogGroupBy = 'event' | 'draw' | 'round' | 'structure' | 'time';
57
63
  export interface CatalogFilters {
58
64
  eventType?: string;
59
65
  eventName?: string;