courthive-components 0.9.6 → 0.9.8
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.
- package/README.md +413 -1
- package/dist/courthive-components.es.js +11808 -10986
- package/dist/courthive-components.umd.js +65 -31
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,3 +1,415 @@
|
|
|
1
1
|
# courthive-components
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Vanilla JavaScript UI components for tennis tournament management and competition displays.
|
|
4
|
+
|
|
5
|
+
[](https://courthive.github.io/courthive-components/)
|
|
6
|
+
[](https://www.npmjs.com/package/courthive-components)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
This library provides a comprehensive set of UI components for building tournament management applications. Components are framework-agnostic (vanilla JavaScript) and designed to work seamlessly with the [Competition Factory](https://github.com/CourtHive/tods-competition-factory) engine.
|
|
12
|
+
|
|
13
|
+
**Used by:**
|
|
14
|
+
|
|
15
|
+
- **TMX** (Tournament Management eXperience) - Production tournament management application
|
|
16
|
+
- **Competition Factory Documentation** - Interactive examples and demonstrations
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install courthive-components
|
|
22
|
+
# or
|
|
23
|
+
yarn add courthive-components
|
|
24
|
+
# or
|
|
25
|
+
pnpm add courthive-components
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
import { renderMatchUp, scoringModal, compositions } from 'courthive-components';
|
|
32
|
+
|
|
33
|
+
// Render a match display
|
|
34
|
+
const matchUpElement = renderMatchUp({
|
|
35
|
+
matchUp: myMatchUpData,
|
|
36
|
+
composition: compositions.Australian
|
|
37
|
+
});
|
|
38
|
+
document.getElementById('container').appendChild(matchUpElement);
|
|
39
|
+
|
|
40
|
+
// Open scoring modal
|
|
41
|
+
scoringModal({
|
|
42
|
+
matchUp: myMatchUpData,
|
|
43
|
+
callback: (outcome) => {
|
|
44
|
+
console.log('Score submitted:', outcome);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Components
|
|
50
|
+
|
|
51
|
+
### Display Components
|
|
52
|
+
|
|
53
|
+
#### **renderMatchUp**
|
|
54
|
+
|
|
55
|
+
Display a single match with scores, participants, and status indicators.
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
import { renderMatchUp, compositions } from 'courthive-components';
|
|
59
|
+
|
|
60
|
+
const element = renderMatchUp({
|
|
61
|
+
matchUp: matchUpData,
|
|
62
|
+
composition: compositions.Wimbledon,
|
|
63
|
+
isLucky: false
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### **renderStructure**
|
|
68
|
+
|
|
69
|
+
Display a complete draw structure (bracket, round robin, etc.).
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
import { renderStructure } from 'courthive-components';
|
|
73
|
+
|
|
74
|
+
const element = renderStructure({
|
|
75
|
+
structure: drawStructure,
|
|
76
|
+
config: { showSeeds: true }
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
#### **renderRound**
|
|
81
|
+
|
|
82
|
+
Display a single round of matches within a structure.
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
import { renderRound } from 'courthive-components';
|
|
86
|
+
|
|
87
|
+
const element = renderRound({
|
|
88
|
+
round: roundData,
|
|
89
|
+
roundNumber: 1
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### **renderParticipant**
|
|
94
|
+
|
|
95
|
+
Display participant information (name, rating, country, etc.).
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
import { renderParticipant } from 'courthive-components';
|
|
99
|
+
|
|
100
|
+
const element = renderParticipant({
|
|
101
|
+
participant: participantData,
|
|
102
|
+
showRating: true
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### **renderRoundHeader**
|
|
107
|
+
|
|
108
|
+
Display round headers for draw structures.
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
import { renderRoundHeader } from 'courthive-components';
|
|
112
|
+
|
|
113
|
+
const element = renderRoundHeader({
|
|
114
|
+
roundName: 'Quarterfinals',
|
|
115
|
+
roundNumber: 3
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### **renderContainer**
|
|
120
|
+
|
|
121
|
+
Wrapper component for draw containers with scrolling and layout.
|
|
122
|
+
|
|
123
|
+
### Input Components
|
|
124
|
+
|
|
125
|
+
#### **renderParticipantInput**
|
|
126
|
+
|
|
127
|
+
Autocomplete input for participant selection.
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
import { renderParticipantInput } from 'courthive-components';
|
|
131
|
+
|
|
132
|
+
const input = renderParticipantInput({
|
|
133
|
+
participants: participantsList,
|
|
134
|
+
onSelect: (participant) => console.log('Selected:', participant)
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Modal Components
|
|
139
|
+
|
|
140
|
+
#### **cModal**
|
|
141
|
+
|
|
142
|
+
Base modal system with flexible configuration.
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
import { cModal } from 'courthive-components';
|
|
146
|
+
|
|
147
|
+
cModal.open({
|
|
148
|
+
title: 'Confirm Action',
|
|
149
|
+
content: 'Are you sure?',
|
|
150
|
+
buttons: [
|
|
151
|
+
{ label: 'Cancel', close: true },
|
|
152
|
+
{ label: 'Confirm', onClick: handleConfirm, close: true }
|
|
153
|
+
]
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### **scoringModal**
|
|
158
|
+
|
|
159
|
+
Interactive score entry with multiple input approaches.
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
import { scoringModal, setScoringConfig } from 'courthive-components';
|
|
163
|
+
|
|
164
|
+
// Configure scoring behavior
|
|
165
|
+
setScoringConfig({
|
|
166
|
+
scoringApproach: 'dynamicSets', // 'dynamicSets' | 'freeScore' | 'dialPad'
|
|
167
|
+
smartComplements: true,
|
|
168
|
+
composition: 'Australian'
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Open scoring modal
|
|
172
|
+
scoringModal({
|
|
173
|
+
matchUp: matchUpData,
|
|
174
|
+
callback: (outcome) => {
|
|
175
|
+
// outcome: { isValid, sets, winningSide, matchUpStatus }
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Scoring Approaches:**
|
|
181
|
+
|
|
182
|
+
- **dynamicSets** - Set-by-set entry with real-time validation
|
|
183
|
+
- **freeScore** - Flexible text-based entry (e.g., "6-4 6-3")
|
|
184
|
+
- **dialPad** - Touch-friendly numeric keypad
|
|
185
|
+
|
|
186
|
+
#### **getMatchUpFormatModal**
|
|
187
|
+
|
|
188
|
+
Interactive modal for selecting/editing match formats.
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
import { getMatchUpFormatModal } from 'courthive-components';
|
|
192
|
+
|
|
193
|
+
getMatchUpFormatModal({
|
|
194
|
+
existingMatchUpFormat: 'SET3-S:6/TB7',
|
|
195
|
+
callback: (newFormat) => {
|
|
196
|
+
console.log('Format:', newFormat);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Form Components
|
|
202
|
+
|
|
203
|
+
#### **renderForm**
|
|
204
|
+
|
|
205
|
+
Render dynamic forms from configuration.
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
import { renderForm } from 'courthive-components';
|
|
209
|
+
|
|
210
|
+
const inputs = renderForm(container, [
|
|
211
|
+
{ field: 'name', label: 'Name', type: 'text' },
|
|
212
|
+
{ field: 'age', label: 'Age', type: 'number' }
|
|
213
|
+
]);
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### **renderField**
|
|
217
|
+
|
|
218
|
+
Render individual form fields.
|
|
219
|
+
|
|
220
|
+
#### **renderButtons**
|
|
221
|
+
|
|
222
|
+
Render button groups with consistent styling.
|
|
223
|
+
|
|
224
|
+
#### **renderMenu**
|
|
225
|
+
|
|
226
|
+
Render dropdown/context menus.
|
|
227
|
+
|
|
228
|
+
#### **validator**
|
|
229
|
+
|
|
230
|
+
Form validation utilities.
|
|
231
|
+
|
|
232
|
+
### UI Components
|
|
233
|
+
|
|
234
|
+
#### **drawer**
|
|
235
|
+
|
|
236
|
+
Slide-out drawer component for side panels.
|
|
237
|
+
|
|
238
|
+
```javascript
|
|
239
|
+
import { drawer, initDrawer } from 'courthive-components';
|
|
240
|
+
|
|
241
|
+
initDrawer(); // Initialize once
|
|
242
|
+
|
|
243
|
+
drawer.open({
|
|
244
|
+
title: 'Details',
|
|
245
|
+
content: myContent,
|
|
246
|
+
side: 'right' // 'left' | 'right'
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
#### **tipster**
|
|
251
|
+
|
|
252
|
+
Tooltip/popover system using Tippy.js.
|
|
253
|
+
|
|
254
|
+
```javascript
|
|
255
|
+
import { tipster } from 'courthive-components';
|
|
256
|
+
|
|
257
|
+
tipster({
|
|
258
|
+
target: buttonElement,
|
|
259
|
+
content: 'Click to edit',
|
|
260
|
+
placement: 'top'
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Compositions
|
|
265
|
+
|
|
266
|
+
Pre-configured visual themes matching Grand Slam tournaments:
|
|
267
|
+
|
|
268
|
+
```javascript
|
|
269
|
+
import { compositions } from 'courthive-components';
|
|
270
|
+
|
|
271
|
+
// Available compositions:
|
|
272
|
+
compositions.Australian; // Australian Open colors
|
|
273
|
+
compositions.French; // Roland Garros colors
|
|
274
|
+
compositions.Wimbledon; // Wimbledon colors
|
|
275
|
+
compositions.US; // US Open colors
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Constants
|
|
279
|
+
|
|
280
|
+
#### **MATCH_FORMATS**
|
|
281
|
+
|
|
282
|
+
Pre-defined match format codes.
|
|
283
|
+
|
|
284
|
+
```javascript
|
|
285
|
+
import { MATCH_FORMATS } from 'courthive-components';
|
|
286
|
+
|
|
287
|
+
console.log(MATCH_FORMATS.BEST_OF_3_TB7);
|
|
288
|
+
// 'SET3-S:6/TB7'
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Utilities
|
|
292
|
+
|
|
293
|
+
#### **courthiveComponentsVersion**
|
|
294
|
+
|
|
295
|
+
Get the current package version.
|
|
296
|
+
|
|
297
|
+
```javascript
|
|
298
|
+
import { courthiveComponentsVersion } from 'courthive-components';
|
|
299
|
+
|
|
300
|
+
console.log(courthiveComponentsVersion());
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Documentation
|
|
304
|
+
|
|
305
|
+
📚 **Interactive Documentation:** [Storybook](https://courthive.github.io/courthive-components/)
|
|
306
|
+
|
|
307
|
+
The Storybook includes:
|
|
308
|
+
|
|
309
|
+
- Live component demos
|
|
310
|
+
- Interactive examples
|
|
311
|
+
- Configuration options
|
|
312
|
+
- Usage patterns
|
|
313
|
+
- Integration guides
|
|
314
|
+
|
|
315
|
+
## Styling
|
|
316
|
+
|
|
317
|
+
Components use Bulma CSS framework. Include Bulma in your project:
|
|
318
|
+
|
|
319
|
+
```html
|
|
320
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.4/css/bulma.min.css" />
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Or import the bundled CSS:
|
|
324
|
+
|
|
325
|
+
```javascript
|
|
326
|
+
import 'courthive-components/dist/courthive-components.css';
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## TypeScript Support
|
|
330
|
+
|
|
331
|
+
The package includes TypeScript definitions:
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
import { renderMatchUp, ScoringModalParams, ScoreOutcome } from 'courthive-components';
|
|
335
|
+
|
|
336
|
+
const params: ScoringModalParams = {
|
|
337
|
+
matchUp: myMatchUp,
|
|
338
|
+
callback: (outcome: ScoreOutcome) => {
|
|
339
|
+
if (outcome.isValid) {
|
|
340
|
+
console.log('Winner:', outcome.winningSide);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
## Integration with Competition Factory
|
|
347
|
+
|
|
348
|
+
Components are designed to work with TODS (Tennis Open Data Standards) data structures from [tods-competition-factory](https://www.npmjs.com/package/tods-competition-factory):
|
|
349
|
+
|
|
350
|
+
```javascript
|
|
351
|
+
import { tournamentEngine } from 'tods-competition-factory';
|
|
352
|
+
import { renderMatchUp, scoringModal } from 'courthive-components';
|
|
353
|
+
|
|
354
|
+
// Get match data from factory
|
|
355
|
+
const { matchUp } = tournamentEngine.findMatchUp({ matchUpId });
|
|
356
|
+
|
|
357
|
+
// Render with components
|
|
358
|
+
const display = renderMatchUp({ matchUp });
|
|
359
|
+
|
|
360
|
+
// Score with modal
|
|
361
|
+
scoringModal({
|
|
362
|
+
matchUp,
|
|
363
|
+
callback: (outcome) => {
|
|
364
|
+
// Update tournament using factory
|
|
365
|
+
tournamentEngine.setMatchUpStatus({
|
|
366
|
+
matchUpId,
|
|
367
|
+
outcome: {
|
|
368
|
+
score: { sets: outcome.sets },
|
|
369
|
+
winningSide: outcome.winningSide,
|
|
370
|
+
matchUpStatus: outcome.matchUpStatus
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Development
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
# Install dependencies
|
|
381
|
+
pnpm install
|
|
382
|
+
|
|
383
|
+
# Start Storybook
|
|
384
|
+
pnpm storybook
|
|
385
|
+
|
|
386
|
+
# Build library
|
|
387
|
+
pnpm build
|
|
388
|
+
|
|
389
|
+
# Run tests
|
|
390
|
+
pnpm test
|
|
391
|
+
|
|
392
|
+
# Build Storybook for deployment
|
|
393
|
+
pnpm build-storybook
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Contributing
|
|
397
|
+
|
|
398
|
+
Contributions are welcome! This library is actively used in production tournament management applications.
|
|
399
|
+
|
|
400
|
+
### Guidelines
|
|
401
|
+
|
|
402
|
+
- Maintain framework-agnostic vanilla JavaScript
|
|
403
|
+
- Follow existing component patterns
|
|
404
|
+
- Add Storybook stories for new components
|
|
405
|
+
- Include TypeScript types
|
|
406
|
+
- Test with Competition Factory integration
|
|
407
|
+
|
|
408
|
+
## License
|
|
409
|
+
|
|
410
|
+
MIT © Charles Allen
|
|
411
|
+
|
|
412
|
+
## Links
|
|
413
|
+
|
|
414
|
+
- **Competition Factory:** <https://github.com/CourtHive/tods-competition-factory>
|
|
415
|
+
- **TMX:** <https://github.com/CourtHive/tmx>
|